diff --git a/Makefile.inc1 b/Makefile.inc1 index 4723d142bf48..0cc3c2a23678 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -76,6 +76,9 @@ SUBDIR+=secure SUBDIR+=share .endif SUBDIR+=sys usr.bin usr.sbin +.if ${MK_OFED} != "no" +SUBDIR+=contrib/ofed +.endif # # We must do etc/ last for install/distribute to work. # @@ -1210,7 +1213,11 @@ _prebuild_libs= ${_kerberos5_lib_libasn1} ${_kerberos5_lib_libheimntlm} \ _lib_libthr= lib/libthr .endif -_generic_libs= ${_cddl_lib} gnu/lib ${_kerberos5_lib} lib ${_secure_lib} usr.bin/lex/lib +.if ${MK_OFED} != "no" +_ofed_lib= contrib/ofed/usr.lib/ +.endif + +_generic_libs= ${_cddl_lib} gnu/lib ${_kerberos5_lib} lib ${_secure_lib} usr.bin/lex/lib ${_ofed_lib} lib/libopie__L lib/libtacplus__L: lib/libmd__L diff --git a/contrib/ofed/Makefile b/contrib/ofed/Makefile new file mode 100644 index 000000000000..3d593e2e1251 --- /dev/null +++ b/contrib/ofed/Makefile @@ -0,0 +1,5 @@ +.include + +SUBDIR = include usr.lib usr.bin + +.include diff --git a/contrib/ofed/include/Makefile b/contrib/ofed/include/Makefile new file mode 100644 index 000000000000..ccc151c4bbd5 --- /dev/null +++ b/contrib/ofed/include/Makefile @@ -0,0 +1,5 @@ +.include + +SUBDIR = infiniband rdma + +.include diff --git a/contrib/ofed/include/infiniband/Makefile b/contrib/ofed/include/infiniband/Makefile new file mode 100644 index 000000000000..5d48013b3e9b --- /dev/null +++ b/contrib/ofed/include/infiniband/Makefile @@ -0,0 +1,107 @@ +.include + +INCS= +IBINCS= byteorder.h byteswap.h endian.h types.h +IBINCSDIR= ${INCLUDEDIR}/infiniband + +IBVERBS= ${.CURDIR}/../../libibverbs/include/infiniband +VERBINCS= ${IBVERBS}/arch.h ${IBVERBS}/driver.h ${IBVERBS}/kern-abi.h +VERBINCS+= ${IBVERBS}/marshall.h ${IBVERBS}/opcode.h +VERBINCS+= ${IBVERBS}/sa-kern-abi.h ${IBVERBS}/sa.h ${IBVERBS}/verbs.h +VERBINCSDIR= ${INCLUDEDIR}/infiniband + +IBCOMMON= ${.CURDIR}/../../management/libibcommon/include/infiniband +COMMONINCS= ${IBCOMMON}/common.h +COMMONINCSDIR= ${INCLUDEDIR}/infiniband + +IBMAD= ${.CURDIR}/../../management/libibmad/include/infiniband +MADINCS= ${IBMAD}/mad.h +MADINCSDIR= ${INCLUDEDIR}/infiniband + +IBUMAD= ${.CURDIR}/../../management/libibumad/include/infiniband +UMADINCS= ${IBUMAD}/umad.h +UMADINCSDIR= ${INCLUDEDIR}/infiniband + +COMPLIB= ${.CURDIR}/../../management/opensm/include/complib +COMPLIBINCS= ${COMPLIB}/cl_atomic.h ${COMPLIB}/cl_atomic_osd.h +COMPLIBINCS+= ${COMPLIB}/cl_byteswap.h ${COMPLIB}/cl_byteswap_osd.h +COMPLIBINCS+= ${COMPLIB}/cl_comppool.h ${COMPLIB}/cl_debug.h +COMPLIBINCS+= ${COMPLIB}/cl_debug_osd.h ${COMPLIB}/cl_dispatcher.h +COMPLIBINCS+= ${COMPLIB}/cl_event.h ${COMPLIB}/cl_event_osd.h +COMPLIBINCS+= ${COMPLIB}/cl_event_wheel.h ${COMPLIB}/cl_fleximap.h +COMPLIBINCS+= ${COMPLIB}/cl_list.h ${COMPLIB}/cl_log.h +COMPLIBINCS+= ${COMPLIB}/cl_map.h ${COMPLIB}/cl_math.h +COMPLIBINCS+= ${COMPLIB}/cl_nodenamemap.h ${COMPLIB}/cl_packoff.h +COMPLIBINCS+= ${COMPLIB}/cl_packon.h ${COMPLIB}/cl_passivelock.h +COMPLIBINCS+= ${COMPLIB}/cl_pool.h ${COMPLIB}/cl_ptr_vector.h +COMPLIBINCS+= ${COMPLIB}/cl_qcomppool.h ${COMPLIB}/cl_qlist.h +COMPLIBINCS+= ${COMPLIB}/cl_qmap.h ${COMPLIB}/cl_qpool.h +COMPLIBINCS+= ${COMPLIB}/cl_spinlock.h ${COMPLIB}/cl_spinlock_osd.h +COMPLIBINCS+= ${COMPLIB}/cl_thread.h ${COMPLIB}/cl_thread_osd.h +COMPLIBINCS+= ${COMPLIB}/cl_threadpool.h ${COMPLIB}/cl_timer.h +COMPLIBINCS+= ${COMPLIB}/cl_timer_osd.h ${COMPLIB}/cl_types.h +COMPLIBINCS+= ${COMPLIB}/cl_types_osd.h ${COMPLIB}/cl_vector.h +COMPLIBINCSDIR= ${INCLUDEDIR}/infiniband/complib + +IBADIR= ${.CURDIR}/../../management/opensm/include/iba +IBAINCS= ${IBADIR}/ib_cm_types.h ${IBADIR}/ib_types.h +IBAINCSDIR= ${INCLUDEDIR}/infiniband/iba + +OPENSM= ${.CURDIR}/../../management/opensm/include/opensm + +OPENSMINCS= ${OPENSM}/osm_attrib_req.h ${OPENSM}/osm_base.h +OPENSMINCS+= ${OPENSM}/osm_config.h ${OPENSM}/osm_console.h +OPENSMINCS+= ${OPENSM}/osm_console_io.h ${OPENSM}/osm_db.h +OPENSMINCS+= ${OPENSM}/osm_db_pack.h ${OPENSM}/osm_errors.h +OPENSMINCS+= ${OPENSM}/osm_event_plugin.h ${OPENSM}/osm_helper.h +OPENSMINCS+= ${OPENSM}/osm_inform.h ${OPENSM}/osm_lid_mgr.h +OPENSMINCS+= ${OPENSM}/osm_log.h ${OPENSM}/osm_mad_pool.h +OPENSMINCS+= ${OPENSM}/osm_madw.h ${OPENSM}/osm_mcast_tbl.h +OPENSMINCS+= ${OPENSM}/osm_mcm_info.h ${OPENSM}/osm_mcm_port.h +OPENSMINCS+= ${OPENSM}/osm_msgdef.h ${OPENSM}/osm_mtree.h +OPENSMINCS+= ${OPENSM}/osm_multicast.h ${OPENSM}/osm_node.h +OPENSMINCS+= ${OPENSM}/osm_opensm.h ${OPENSM}/osm_partition.h +OPENSMINCS+= ${OPENSM}/osm_path.h ${OPENSM}/osm_perfmgr.h +OPENSMINCS+= ${OPENSM}/osm_perfmgr_db.h ${OPENSM}/osm_pkey.h +OPENSMINCS+= ${OPENSM}/osm_pkey_mgr.h ${OPENSM}/osm_port.h +OPENSMINCS+= ${OPENSM}/osm_port_profile.h ${OPENSM}/osm_prefix_route.h +OPENSMINCS+= ${OPENSM}/osm_qos_policy.h ${OPENSM}/osm_remote_sm.h +OPENSMINCS+= ${OPENSM}/osm_router.h ${OPENSM}/osm_sa.h +OPENSMINCS+= ${OPENSM}/osm_sa_mad_ctrl.h ${OPENSM}/osm_service.h +OPENSMINCS+= ${OPENSM}/osm_sm.h ${OPENSM}/osm_sm_mad_ctrl.h +OPENSMINCS+= ${OPENSM}/osm_stats.h ${OPENSM}/osm_subnet.h +OPENSMINCS+= ${OPENSM}/osm_switch.h ${OPENSM}/osm_ucast_cache.h +OPENSMINCS+= ${OPENSM}/osm_ucast_mgr.h ${OPENSM}/osm_version.h +OPENSMINCS+= ${OPENSM}/osm_vl15intf.h ${OPENSM}/st.h +OPENSMINCSDIR= ${INCLUDEDIR}/infiniband/opensm + +VENDOR= ${.CURDIR}/../../management/opensm/include/vendor +VENDORINCS= ${VENDOR}/osm_mtl_bind.h ${VENDOR}/osm_pkt_randomizer.h +VENDORINCS+= ${VENDOR}/osm_ts_useraccess.h ${VENDOR}/osm_umadt.h +VENDORINCS+= ${VENDOR}/osm_vendor.h ${VENDOR}/osm_vendor_al.h +VENDORINCS+= ${VENDOR}/osm_vendor_api.h ${VENDOR}/osm_vendor_ibumad.h +VENDORINCS+= ${VENDOR}/osm_vendor_mlx.h ${VENDOR}/osm_vendor_mlx_defs.h +VENDORINCS+= ${VENDOR}/osm_vendor_mlx_dispatcher.h +VENDORINCS+= ${VENDOR}/osm_vendor_mlx_hca.h +VENDORINCS+= ${VENDOR}/osm_vendor_mlx_inout.h +VENDORINCS+= ${VENDOR}/osm_vendor_mlx_rmpp_ctx.h +VENDORINCS+= ${VENDOR}/osm_vendor_mlx_sar.h ${VENDOR}/osm_vendor_mlx_sender.h +VENDORINCS+= ${VENDOR}/osm_vendor_mlx_svc.h +VENDORINCS+= ${VENDOR}/osm_vendor_mlx_transport.h +VENDORINCS+= ${VENDOR}/osm_vendor_mlx_transport_anafa.h +VENDORINCS+= ${VENDOR}/osm_vendor_mlx_txn.h +VENDORINCS+= ${VENDOR}/osm_vendor_mtl.h ${VENDOR}/osm_vendor_mtl_hca_guid.h +VENDORINCS+= ${VENDOR}/osm_vendor_mtl_transaction_mgr.h +VENDORINCS+= ${VENDOR}/osm_vendor_sa_api.h +VENDORINCS+= ${VENDOR}/osm_vendor_test.h ${VENDOR}/osm_vendor_ts.h +VENDORINCS+= ${VENDOR}/osm_vendor_umadt.h +VENDORINCSDIR= ${INCLUDEDIR}/infiniband/vendor + +IBCM= ${.CURDIR}/../../libibcm/include/infiniband +IBCMINCS= ${IBCM}/cm.h ${IBCM}/cm_abi.h +IBCMINCSDIR= ${INCLUDEDIR}/infiniband + +INCSGROUPS= INCS VERBINCS COMMONINCS MADINCS UMADINCS COMPLIBINCS IBAINCS +INCSGROUPS+= OPENSMINCS VENDORINCS IBCMINCS IBINCS + +.include diff --git a/contrib/ofed/include/infiniband/byteorder.h b/contrib/ofed/include/infiniband/byteorder.h new file mode 100644 index 000000000000..a7326e49234f --- /dev/null +++ b/contrib/ofed/include/infiniband/byteorder.h @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _INFINIBAND_BYTEORDER_H_ +#define _INFINIBAND_BYTEORDER_H_ + +#include +#include + +#if BYTE_ORDER == LITTLE_ENDIAN +#define __LITTLE_ENDIAN +#else +#define __BIG_ENDIAN +#endif + +#define cpu_to_le64 htole64 +#define le64_to_cpu le64toh +#define cpu_to_le32 htole32 +#define le32_to_cpu le32toh +#define cpu_to_le16 htole16 +#define le16_to_cpu le16toh +#define cpu_to_be64 htobe64 +#define be64_to_cpu be64toh +#define cpu_to_be32 htobe32 +#define be32_to_cpu be32toh +#define cpu_to_be16 htobe16 +#define be16_to_cpu be16toh +#define __be16_to_cpu be16toh + +#define cpu_to_le64p(x) htole64(*((uint64_t *)x)) +#define le64_to_cpup(x) le64toh(*((uint64_t *)x)) +#define cpu_to_le32p(x) htole32(*((uint32_t *)x)) +#define le32_to_cpup(x) le32toh(*((uint32_t *)x)) +#define cpu_to_le16p(x) htole16(*((uint16_t *)x)) +#define le16_to_cpup(x) le16toh(*((uint16_t *)x)) +#define cpu_to_be64p(x) htobe64(*((uint64_t *)x)) +#define be64_to_cpup(x) be64toh(*((uint64_t *)x)) +#define cpu_to_be32p(x) htobe32(*((uint32_t *)x)) +#define be32_to_cpup(x) be32toh(*((uint32_t *)x)) +#define cpu_to_be16p(x) htobe16(*((uint16_t *)x)) +#define be16_to_cpup(x) be16toh(*((uint16_t *)x)) + +#define cpu_to_le64s(x) do { *((uint64_t *)x) = cpu_to_le64p((x)) } while (0) +#define le64_to_cpus(x) do { *((uint64_t *)x) = le64_to_cpup((x)) } while (0) +#define cpu_to_le32s(x) do { *((uint32_t *)x) = cpu_to_le32p((x)) } while (0) +#define le32_to_cpus(x) do { *((uint32_t *)x) = le32_to_cpup((x)) } while (0) +#define cpu_to_le16s(x) do { *((uint16_t *)x) = cpu_to_le16p((x)) } while (0) +#define le16_to_cpus(x) do { *((uint16_t *)x) = le16_to_cpup((x)) } while (0) +#define cpu_to_be64s(x) do { *((uint64_t *)x) = cpu_to_be64p((x)) } while (0) +#define be64_to_cpus(x) do { *((uint64_t *)x) = be64_to_cpup((x)) } while (0) +#define cpu_to_be32s(x) do { *((uint32_t *)x) = cpu_to_be32p((x)) } while (0) +#define be32_to_cpus(x) do { *((uint32_t *)x) = be32_to_cpup((x)) } while (0) +#define cpu_to_be16s(x) do { *((uint16_t *)x) = cpu_to_be16p((x)) } while (0) +#define be16_to_cpus(x) do { *((uint16_t *)x) = be16_to_cpup((x)) } while (0) + +#define swab16 bswap16 +#define swab32 bswap32 +#define swab64 bswap64 + +#endif /* _INFINIBAND_BYTEORDER_H_ */ diff --git a/contrib/ofed/include/infiniband/byteswap.h b/contrib/ofed/include/infiniband/byteswap.h new file mode 100644 index 000000000000..29f10049b9e5 --- /dev/null +++ b/contrib/ofed/include/infiniband/byteswap.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _INFINIBAND_BYTESWAP_H_ +#define _INFINIBAND_BYTESWAP_H_ +/* + * This file is included for compatibility with the userland libraries + * accompanying the infiniband stack. + */ +#include +#include + +#define bswap_16 bswap16 +#define bswap_32 bswap32 +#define bswap_64 bswap64 + +#endif /* _INFINIBAND_BYTESWAP_H_ */ diff --git a/contrib/ofed/include/infiniband/endian.h b/contrib/ofed/include/infiniband/endian.h new file mode 100644 index 000000000000..dd1acdc01815 --- /dev/null +++ b/contrib/ofed/include/infiniband/endian.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * This file is included for compatibility with the userland libraries + * accompanying the infiniband stack. + */ + +#ifndef _INFINIBAND_ENDIAN_H_ +#define _INFINIBAND_ENDIAN_H_ + +#include +#include +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN +#define __BYTE_ORDER _BYTE_ORDER + +#endif /* _INFINIBAND_ENDIAN_H_ */ diff --git a/contrib/ofed/include/infiniband/types.h b/contrib/ofed/include/infiniband/types.h new file mode 100644 index 000000000000..ae60fa374f92 --- /dev/null +++ b/contrib/ofed/include/infiniband/types.h @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _INFINIBAND_TYPES_H_ +#define _INFINIBAND_TYPES_H_ + +#include +#include + +typedef int8_t s8; +typedef uint8_t u8; +typedef int8_t __s8; +typedef uint8_t __u8; + +typedef int16_t s16; +typedef uint16_t u16; +typedef int16_t __s16; +typedef uint16_t __u16; + +typedef int32_t s32; +typedef uint32_t u32; +typedef int32_t __s32; +typedef uint32_t __u32; + +typedef int64_t s64; +typedef uint64_t u64; +typedef int64_t __s64; +typedef uint64_t __u64; + +typedef uint16_t __le16; +typedef uint16_t __be16; +typedef uint32_t __le32; +typedef uint32_t __be32; +typedef uint64_t __le64; +typedef uint64_t __be64; + +typedef unsigned int uint; + +#endif /* _INFINIBAND_TYPES_H_ */ diff --git a/contrib/ofed/include/rdma/Makefile b/contrib/ofed/include/rdma/Makefile new file mode 100644 index 000000000000..366790f15c76 --- /dev/null +++ b/contrib/ofed/include/rdma/Makefile @@ -0,0 +1,10 @@ +.include + +INCS= +RDMACM= ${.CURDIR}/../../librdmacm/include/rdma +RDMACMINCS= ${RDMACM}/rdma_cma.h ${RDMACM}/rdma_cma_abi.h +RDMACMINCSDIR= ${INCLUDEDIR}/rdma + +INCSGROUPS= RDMACMINCS + +.include diff --git a/contrib/ofed/libibcm/AUTHORS b/contrib/ofed/libibcm/AUTHORS new file mode 100644 index 000000000000..a694ab7046b6 --- /dev/null +++ b/contrib/ofed/libibcm/AUTHORS @@ -0,0 +1,2 @@ +Sean Hefty +Libor Michalek diff --git a/contrib/ofed/libibcm/COPYING b/contrib/ofed/libibcm/COPYING new file mode 100644 index 000000000000..ee1a79ffabf6 --- /dev/null +++ b/contrib/ofed/libibcm/COPYING @@ -0,0 +1,378 @@ +This software is available to you under a choice of one of two +licenses. You may choose to be licensed under the terms of the the +OpenIB.org BSD license or the GNU General Public License (GPL) Version +2, both included below. + +Copyright (c) 2004 Topspin Communications. All rights reserved. + +================================================================== + + OpenIB.org BSD license + +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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +================================================================== + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/ofed/libibcm/ChangeLog b/contrib/ofed/libibcm/ChangeLog new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ofed/libibcm/INSTALL b/contrib/ofed/libibcm/INSTALL new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ofed/libibcm/Makefile.am b/contrib/ofed/libibcm/Makefile.am new file mode 100644 index 000000000000..4b2ad7489016 --- /dev/null +++ b/contrib/ofed/libibcm/Makefile.am @@ -0,0 +1,34 @@ +INCLUDES = -I$(srcdir)/include + +lib_LTLIBRARIES = src/libibcm.la + +AM_CFLAGS = -g -Wall -D_GNU_SOURCE + +src_libibcm_la_CFLAGS = $(AM_CFLAGS) + +if HAVE_LD_VERSION_SCRIPT + ibcm_version_script = -Wl,--version-script=$(srcdir)/src/libibcm.map +else + ibcm_version_script = +endif + +src_libibcm_la_SOURCES = src/cm.c +src_libibcm_la_LDFLAGS = -version-info 1 -export-dynamic \ + $(libibcm_version_script) +src_libibcm_la_DEPENDENCIES = $(srcdir)/src/libibcm.map + +# Sample program requires use if librdmacm. +#bin_PROGRAMS = examples/ucmpost +#examples_ucmpost_SOURCES = examples/cmpost.c +#examples_ucmpost_LDADD = $(top_builddir)/src/libibcm.la + +libibcmincludedir = $(includedir)/infiniband + +libibcminclude_HEADERS = include/infiniband/cm_abi.h \ + include/infiniband/cm.h + +EXTRA_DIST = include/infiniband/cm_abi.h include/infiniband/cm.h \ + src/libibcm.map libibcm.spec.in + +dist-hook: libibcm.spec + cp libibcm.spec $(distdir) diff --git a/contrib/ofed/libibcm/Makefile.in b/contrib/ofed/libibcm/Makefile.in new file mode 100644 index 000000000000..23e15d15ef26 --- /dev/null +++ b/contrib/ofed/libibcm/Makefile.in @@ -0,0 +1,660 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = . +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +DIST_COMMON = README $(am__configure_deps) $(libibcminclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/config.h.in $(srcdir)/libibcm.spec.in \ + $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \ + config/compile config/config.guess config/config.sub \ + config/depcomp config/install-sh config/ltmain.sh \ + config/missing +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno configure.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = libibcm.spec +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" \ + "$(DESTDIR)$(libibcmincludedir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +src_libibcm_la_LIBADD = +am_src_libibcm_la_OBJECTS = src_libibcm_la-cm.lo +src_libibcm_la_OBJECTS = $(am_src_libibcm_la_OBJECTS) +am__dirstamp = $(am__leading_dot)dirstamp +DEFAULT_INCLUDES = -I. -I$(srcdir) -I. +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(src_libibcm_la_SOURCES) +DIST_SOURCES = $(src_libibcm_la_SOURCES) +libibcmincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(libibcminclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +HAVE_LD_VERSION_SCRIPT_FALSE = @HAVE_LD_VERSION_SCRIPT_FALSE@ +HAVE_LD_VERSION_SCRIPT_TRUE = @HAVE_LD_VERSION_SCRIPT_TRUE@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +INCLUDES = -I$(srcdir)/include +lib_LTLIBRARIES = src/libibcm.la +AM_CFLAGS = -g -Wall -D_GNU_SOURCE +src_libibcm_la_CFLAGS = $(AM_CFLAGS) +@HAVE_LD_VERSION_SCRIPT_FALSE@ibcm_version_script = +@HAVE_LD_VERSION_SCRIPT_TRUE@ibcm_version_script = -Wl,--version-script=$(srcdir)/src/libibcm.map +src_libibcm_la_SOURCES = src/cm.c +src_libibcm_la_LDFLAGS = -version-info 1 -export-dynamic \ + $(libibcm_version_script) + +src_libibcm_la_DEPENDENCIES = $(srcdir)/src/libibcm.map + +# Sample program requires use if librdmacm. +#bin_PROGRAMS = examples/ucmpost +#examples_ucmpost_SOURCES = examples/cmpost.c +#examples_ucmpost_LDADD = $(top_builddir)/src/libibcm.la +libibcmincludedir = $(includedir)/infiniband +libibcminclude_HEADERS = include/infiniband/cm_abi.h \ + include/infiniband/cm.h + +EXTRA_DIST = include/infiniband/cm_abi.h include/infiniband/cm.h \ + src/libibcm.map libibcm.spec.in + +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ + cd $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: $(am__configure_deps) + cd $(top_srcdir) && $(AUTOHEADER) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +libibcm.spec: $(top_builddir)/config.status $(srcdir)/libibcm.spec.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +src/$(am__dirstamp): + @$(mkdir_p) src + @: > src/$(am__dirstamp) +src/libibcm.la: $(src_libibcm_la_OBJECTS) $(src_libibcm_la_DEPENDENCIES) src/$(am__dirstamp) + $(LINK) -rpath $(libdir) $(src_libibcm_la_LDFLAGS) $(src_libibcm_la_OBJECTS) $(src_libibcm_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/src_libibcm_la-cm.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +src_libibcm_la-cm.lo: src/cm.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libibcm_la_CFLAGS) $(CFLAGS) -MT src_libibcm_la-cm.lo -MD -MP -MF "$(DEPDIR)/src_libibcm_la-cm.Tpo" -c -o src_libibcm_la-cm.lo `test -f 'src/cm.c' || echo '$(srcdir)/'`src/cm.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/src_libibcm_la-cm.Tpo" "$(DEPDIR)/src_libibcm_la-cm.Plo"; else rm -f "$(DEPDIR)/src_libibcm_la-cm.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='src/cm.c' object='src_libibcm_la-cm.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_libibcm_la_CFLAGS) $(CFLAGS) -c -o src_libibcm_la-cm.lo `test -f 'src/cm.c' || echo '$(srcdir)/'`src/cm.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf src/.libs src/_libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +install-libibcmincludeHEADERS: $(libibcminclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(libibcmincludedir)" || $(mkdir_p) "$(DESTDIR)$(libibcmincludedir)" + @list='$(libibcminclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(libibcmincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(libibcmincludedir)/$$f'"; \ + $(libibcmincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(libibcmincludedir)/$$f"; \ + done + +uninstall-libibcmincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(libibcminclude_HEADERS)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(libibcmincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(libibcmincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + $(mkdir_p) $(distdir)/. $(distdir)/config $(distdir)/include/infiniband $(distdir)/src + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) config.h +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libibcmincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -rm -f src/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-libibcmincludeHEADERS + +install-exec-am: install-libLTLIBRARIES + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES \ + uninstall-libibcmincludeHEADERS + +.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ + clean-generic clean-libLTLIBRARIES clean-libtool ctags dist \ + dist-all dist-bzip2 dist-gzip dist-hook dist-shar dist-tarZ \ + dist-zip distcheck distclean distclean-compile \ + distclean-generic distclean-hdr distclean-libtool \ + distclean-tags distcleancheck distdir distuninstallcheck dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-libLTLIBRARIES \ + install-libibcmincludeHEADERS install-man install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ + uninstall-libLTLIBRARIES uninstall-libibcmincludeHEADERS + + +dist-hook: libibcm.spec + cp libibcm.spec $(distdir) +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ofed/libibcm/NEWS b/contrib/ofed/libibcm/NEWS new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ofed/libibcm/README b/contrib/ofed/libibcm/README new file mode 100644 index 000000000000..4dda13c185eb --- /dev/null +++ b/contrib/ofed/libibcm/README @@ -0,0 +1,28 @@ +This README is for userspace cm library. + +Building + +To make this directory, run: +./autogen.sh && ./configure && make && make install + +Typically the autogen and configure steps only need be done the first +time unless configure.in or Makefile.am changes. + +Libraries are installed by default at /usr/local/lib. + +Device files + +The userspace CM uses a device file per adapter present. + +To create the appropriate character device file automatically with +udev, a rule like + + KERNEL="ucm*", NAME="infiniband/%k", MODE="0666" + +can be used. This will create the device node named + + /dev/infiniband/ucm0 + +for the first HCA in the system, or you can create it manually + + mknod /dev/infiniband/ucm0 c 231 224 diff --git a/contrib/ofed/libibcm/aclocal.m4 b/contrib/ofed/libibcm/aclocal.m4 new file mode 100644 index 000000000000..5baa59e69de2 --- /dev/null +++ b/contrib/ofed/libibcm/aclocal.m4 @@ -0,0 +1,7267 @@ +# generated automatically by aclocal 1.9.6 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- + +# serial 48 Debian 1.5.22-2 AC_PROG_LIBTOOL + + +# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) +# ----------------------------------------------------------- +# If this macro is not defined by Autoconf, define it here. +m4_ifdef([AC_PROVIDE_IFELSE], + [], + [m4_define([AC_PROVIDE_IFELSE], + [m4_ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + + +# AC_PROG_LIBTOOL +# --------------- +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX + ])]) +dnl And a similar setup for Fortran 77 support + AC_PROVIDE_IFELSE([AC_PROG_F77], + [AC_LIBTOOL_F77], + [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], + defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) +])])# AC_PROG_LIBTOOL + + +# _AC_PROG_LIBTOOL +# ---------------- +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +])# _AC_PROG_LIBTOOL + + +# AC_LIBTOOL_SETUP +# ---------------- +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl + +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +AC_LIBTOOL_SYS_MAX_CMD_LEN +AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +AC_LIBTOOL_OBJDIR + +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +_LT_AC_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +AC_CHECK_TOOL(AR, ar, false) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +AC_ARG_WITH([pic], + [AC_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +AC_LIBTOOL_LANG_C_CONFIG +_LT_AC_TAGCONFIG +])# AC_LIBTOOL_SETUP + + +# _LT_AC_SYS_COMPILER +# ------------------- +AC_DEFUN([_LT_AC_SYS_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_AC_SYS_COMPILER + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +AC_DEFUN([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +AC_DEFUN([_LT_COMPILER_BOILERPLATE], +[ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +AC_DEFUN([_LT_LINKER_BOILERPLATE], +[ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* +])# _LT_LINKER_BOILERPLATE + + +# _LT_AC_SYS_LIBPATH_AIX +# ---------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], +[AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_AC_SYS_LIBPATH_AIX + + +# _LT_AC_SHELL_INIT(ARG) +# ---------------------- +AC_DEFUN([_LT_AC_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_AC_SHELL_INIT + + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[_LT_AC_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1 && unset CDPATH + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string=`eval $cmd`) 2>/dev/null && + echo_test_string=`eval $cmd` && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +])])# _LT_AC_PROG_ECHO_BACKSLASH + + +# _LT_AC_LOCK +# ----------- +AC_DEFUN([_LT_AC_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) LD="${LD-ld} -64" ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; + ]) +esac + +need_locks="$enable_libtool_lock" + +])# _LT_AC_LOCK + + +# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED]) +AC_CACHE_CHECK([$1], [$2], + [$2=no + ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $rm conftest* +]) + +if test x"[$]$2" = xyes; then + ifelse([$5], , :, [$5]) +else + ifelse([$6], , :, [$6]) +fi +])# AC_LIBTOOL_COMPILER_OPTION + + +# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ------------------------------------------------------------ +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], +[AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$4], , :, [$4]) +else + ifelse([$5], , :, [$5]) +fi +])# AC_LIBTOOL_LINKER_OPTION + + +# AC_LIBTOOL_SYS_MAX_CMD_LEN +# -------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], +[# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \ + = "XX$teststring") >/dev/null 2>&1 && + new_result=`expr "X$teststring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + teststring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +])# AC_LIBTOOL_SYS_MAX_CMD_LEN + + +# _LT_AC_CHECK_DLFCN +# ------------------ +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h)dnl +])# _LT_AC_CHECK_DLFCN + + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# --------------------------------------------------------------------- +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + + +# AC_LIBTOOL_DLOPEN_SELF +# ---------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + + +# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) +# --------------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler +AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* +]) +])# AC_LIBTOOL_PROG_CC_C_O + + +# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) +# ----------------------------------------- +# Check to see if we can do hard links to lock some files if needed +AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], +[AC_REQUIRE([_LT_AC_LOCK])dnl + +hard_links="nottested" +if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS + + +# AC_LIBTOOL_OBJDIR +# ----------------- +AC_DEFUN([AC_LIBTOOL_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +])# AC_LIBTOOL_OBJDIR + + +# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) +# ---------------------------------------------- +# Check hardcoding attributes. +AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_AC_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ + test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \ + test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_AC_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_AC_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_AC_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH + + +# AC_LIBTOOL_SYS_LIB_STRIP +# ------------------------ +AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], +[striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +])# AC_LIBTOOL_SYS_LIB_STRIP + + +# AC_LIBTOOL_SYS_DYNAMIC_LINKER +# ----------------------------- +# PORTME Fill in your ld.so characteristics +AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], +[AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + freebsd*) # from 4.6 on + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix3*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi +])# AC_LIBTOOL_SYS_DYNAMIC_LINKER + + +# _LT_AC_TAGCONFIG +# ---------------- +AC_DEFUN([_LT_AC_TAGCONFIG], +[AC_ARG_WITH([tags], + [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], + [include additional configurations @<:@automatic@:>@])], + [tagnames="$withval"]) + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + if test -z "$LTCFLAGS"; then + eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in + "") ;; + *) AC_MSG_ERROR([invalid tag name: $tagname]) + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + AC_MSG_ERROR([tag name \"$tagname\" already exists]) + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_LIBTOOL_LANG_CXX_CONFIG + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + else + tagname="" + fi + ;; + + RC) + AC_LIBTOOL_LANG_RC_CONFIG + ;; + + *) + AC_MSG_ERROR([Unsupported tag name: $tagname]) + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + fi +fi +])# _LT_AC_TAGCONFIG + + +# AC_LIBTOOL_DLOPEN +# ----------------- +# enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], + [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_DLOPEN + + +# AC_LIBTOOL_WIN32_DLL +# -------------------- +# declare package support for building win32 DLLs +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_WIN32_DLL + + +# AC_ENABLE_SHARED([DEFAULT]) +# --------------------------- +# implement the --enable-shared flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([shared], + [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]AC_ENABLE_SHARED_DEFAULT) +])# AC_ENABLE_SHARED + + +# AC_DISABLE_SHARED +# ----------------- +# set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no) +])# AC_DISABLE_SHARED + + +# AC_ENABLE_STATIC([DEFAULT]) +# --------------------------- +# implement the --enable-static flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([static], + [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]AC_ENABLE_STATIC_DEFAULT) +])# AC_ENABLE_STATIC + + +# AC_DISABLE_STATIC +# ----------------- +# set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no) +])# AC_DISABLE_STATIC + + +# AC_ENABLE_FAST_INSTALL([DEFAULT]) +# --------------------------------- +# implement the --enable-fast-install flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([fast-install], + [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) +])# AC_ENABLE_FAST_INSTALL + + +# AC_DISABLE_FAST_INSTALL +# ----------------------- +# set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no) +])# AC_DISABLE_FAST_INSTALL + + +# AC_LIBTOOL_PICMODE([MODE]) +# -------------------------- +# implement the --with-pic flag +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default) +])# AC_LIBTOOL_PICMODE + + +# AC_PROG_EGREP +# ------------- +# This is predefined starting with Autoconf 2.54, so this conditional +# definition can be removed once we require Autoconf 2.54 or later. +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], +[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], + [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi]) + EGREP=$ac_cv_prog_egrep + AC_SUBST([EGREP]) +])]) + + +# AC_PATH_TOOL_PREFIX +# ------------------- +# find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +])# AC_PATH_TOOL_PREFIX + + +# AC_PATH_MAGIC +# ------------- +# find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# AC_PATH_MAGIC + + +# AC_PROG_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH([gnu-ld], + [AC_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no]) +AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix3*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown +])# AC_DEPLIBS_CHECK_METHOD + + +# AC_PROG_NM +# ---------- +# find the pathname to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +])# AC_PROG_NM + + +# AC_CHECK_LIBM +# ------------- +# check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +])# AC_CHECK_LIBM + + +# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, +# it is assumed to be `libltdl'. LIBLTDL will be prefixed with +# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/' +# (note the single quotes!). If your package is not flat and you're not +# using automake, define top_builddir and top_srcdir appropriately in +# the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_CONVENIENCE + + +# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl installable library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, +# and an installed libltdl is not found, it is assumed to be `libltdl'. +# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and top_srcdir +# appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, lt_dlinit, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_INSTALLABLE + + +# AC_LIBTOOL_CXX +# -------------- +# enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], +[AC_REQUIRE([_LT_AC_LANG_CXX]) +])# AC_LIBTOOL_CXX + + +# _LT_AC_LANG_CXX +# --------------- +AC_DEFUN([_LT_AC_LANG_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) +])# _LT_AC_LANG_CXX + +# _LT_AC_PROG_CXXCPP +# ------------------ +AC_DEFUN([_LT_AC_PROG_CXXCPP], +[ +AC_REQUIRE([AC_PROG_CXX]) +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +fi +])# _LT_AC_PROG_CXXCPP + +# AC_LIBTOOL_F77 +# -------------- +# enable support for Fortran 77 libraries +AC_DEFUN([AC_LIBTOOL_F77], +[AC_REQUIRE([_LT_AC_LANG_F77]) +])# AC_LIBTOOL_F77 + + +# _LT_AC_LANG_F77 +# --------------- +AC_DEFUN([_LT_AC_LANG_F77], +[AC_REQUIRE([AC_PROG_F77]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) +])# _LT_AC_LANG_F77 + + +# AC_LIBTOOL_GCJ +# -------------- +# enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ], +[AC_REQUIRE([_LT_AC_LANG_GCJ]) +])# AC_LIBTOOL_GCJ + + +# _LT_AC_LANG_GCJ +# --------------- +AC_DEFUN([_LT_AC_LANG_GCJ], +[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) +])# _LT_AC_LANG_GCJ + + +# AC_LIBTOOL_RC +# ------------- +# enable support for Windows resource files +AC_DEFUN([AC_LIBTOOL_RC], +[AC_REQUIRE([LT_AC_PROG_RC]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) +])# AC_LIBTOOL_RC + + +# AC_LIBTOOL_LANG_C_CONFIG +# ------------------------ +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) +AC_DEFUN([_LT_AC_LANG_C_CONFIG], +[lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}\n' + +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF + +# Report which library types will actually be built +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_C_CONFIG + + +# AC_LIBTOOL_LANG_CXX_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) +AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], +[AC_LANG_PUSH(C++) +AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Dependencies to place before and after the object being linked: +_LT_AC_TAGVAR(predep_objects, $1)= +_LT_AC_TAGVAR(postdep_objects, $1)= +_LT_AC_TAGVAR(predeps, $1)= +_LT_AC_TAGVAR(postdeps, $1)= +_LT_AC_TAGVAR(compiler_lib_search_path, $1)= + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + $as_unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + $as_unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' +else + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + AC_PROG_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +_LT_AC_TAGVAR(ld_shlibs, $1)=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes ; then + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + freebsd-elf*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + ;; + gnu*) + ;; + hpux9*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + ;; + *) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + interix3*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + linux*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc*) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC*) + # Portland Group C++ compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + m88k*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + openbsd2*) + # C++ shared libraries are fairly broken + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd='echo' + ;; + osf3*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ + $rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. We must also pass each convience library through + # to the system linker between allextract/defaultextract. + # The C++ compiler will combine linker options so we + # cannot just pass the convience library names through + # without $wl. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + # So that behaviour is only enabled if SCOABSPATH is set to a + # non-empty value in the environment. Most likely only useful for + # creating official distributions of packages. + # This is a hack until libtool officially supports absolute path + # names for shared libraries. + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; +esac +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_AC_TAGVAR(GCC, $1)="$GXX" +_LT_AC_TAGVAR(LD, $1)="$LD" + +AC_LIBTOOL_POSTDEP_PREDEP($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +])# AC_LIBTOOL_LANG_CXX_CONFIG + +# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) +# ------------------------------------ +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" +ifelse([$1], [], +[#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e 1s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG], +[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) + +# Is the compiler the GNU C compiler? +with_gcc=$_LT_AC_TAGVAR(GCC, $1) + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_[]_LT_AC_TAGVAR(LD, $1) + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) + +# Commands used to build and install a shared archive. +archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) +archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) +module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" + +# Set to yes if exported symbols are required. +always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) + +# The commands to list exported symbols. +export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) + +# Symbols that must always be exported. +include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) + +ifelse([$1],[], +[# ### END LIBTOOL CONFIG], +[# ### END LIBTOOL TAG CONFIG: $tagname]) + +__EOF__ + +ifelse([$1],[], [ + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +]) +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi +])# AC_LIBTOOL_CONFIG + + +# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl + +_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI + + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +linux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDGIRSTW]]' + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[[]] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + + +# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) +# --------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], +[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) + ifelse([$1],[CXX],[ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + icpc* | ecpc*) + # Intel C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC*) + # Portland Group C++ compiler. + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + newsos6) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + linux*) + case $cc_basename in + icc* | ecc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then + AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), + [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\" +AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) +]) + + +# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) +# ------------------------------------ +# See if the linker supports building shared libraries. +AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], +[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +ifelse([$1],[CXX],[ + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + ;; + kfreebsd*-gnu) + _LT_AC_TAGVAR(link_all_deplibs, $1)=no + ;; + linux*) + _LT_AC_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +],[ + runpath_var= + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)= + _LT_AC_TAGVAR(archive_expsym_cmds, $1)= + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown + _LT_AC_TAGVAR(hardcode_automatic, $1)=no + _LT_AC_TAGVAR(module_cmds, $1)= + _LT_AC_TAGVAR(module_expsym_cmds, $1)= + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_AC_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + _LT_CC_BASENAME([$compiler]) + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix3*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=no + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + # see comment about different semantics on the GNU ld section + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + bsdi[[45]]*) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' + _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # GNU/kFreeBSD uses gcc -shared to do shared libraries. + kfreebsd*-gnu) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(link_all_deplibs, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine linker options so we + # cannot just pass the convience library names through + # without $wl, iff we do not link with $LD. + # Luckily, gcc supports the same syntax we need for Sun Studio. + # Supported since Solaris 2.6 (maybe 2.5.1?) + case $wlarc in + '') + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; + *) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; + esac ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_AC_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac +])# AC_LIBTOOL_PROG_LD_SHLIBS + + +# _LT_AC_FILE_LTDLL_C +# ------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ +])# _LT_AC_FILE_LTDLL_C + + +# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) +# --------------------------------- +AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) + + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +AC_DEFUN([LT_AC_PROG_RC], +[AC_CHECK_TOOL(RC, windres, no) +]) + +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_MSG_RESULT([$SED]) +]) + +# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.9.6])]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 7 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH]) +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 3 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 12 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.58])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $1 | $1:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. +# +# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories +# created by `make install' are always world readable, even if the +# installer happens to have an overly restrictive umask (e.g. 077). +# This was a mistake. There are at least two reasons why we must not +# use `-m 0755': +# - it causes special bits like SGID to be ignored, +# - it may be too restrictive (some setups expect 775 directories). +# +# Do not use -m 0755 and let people choose whatever they expect by +# setting umask. +# +# We cannot accept any implementation of `mkdir' that recognizes `-p'. +# Some implementations (such as Solaris 8's) are not thread-safe: if a +# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c' +# concurrently, both version can detect that a/ is missing, but only +# one can create it and the other will error out. Consequently we +# restrict ourselves to GNU make (using the --version option ensures +# this.) +AC_DEFUN([AM_PROG_MKDIR_P], +[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi +AC_SUBST([mkdir_p])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + diff --git a/contrib/ofed/libibcm/config.h.in b/contrib/ofed/libibcm/config.h.in new file mode 100644 index 000000000000..48a9db81e429 --- /dev/null +++ b/contrib/ofed/libibcm/config.h.in @@ -0,0 +1,67 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `ibverbs' library (-libverbs). */ +#undef HAVE_LIBIBVERBS + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 to enable valgrind annotations */ +#undef INCLUDE_VALGRIND + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of a `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const diff --git a/contrib/ofed/libibcm/config/compile b/contrib/ofed/libibcm/config/compile new file mode 100755 index 000000000000..1b1d23216958 --- /dev/null +++ b/contrib/ofed/libibcm/config/compile @@ -0,0 +1,142 @@ +#! /bin/sh +# Wrapper for compilers which do not understand `-c -o'. + +scriptversion=2005-05-14.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand `-c -o'. +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file `INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; +esac + +ofile= +cfile= +eat= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as `compile cc -o foo foo.c'. + # So we strip `-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no `-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # `.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` + +# Create the lock directory. +# Note: use `[/.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/contrib/ofed/libibcm/config/config.guess b/contrib/ofed/libibcm/config/config.guess new file mode 100755 index 000000000000..ad5281e66e9d --- /dev/null +++ b/contrib/ofed/libibcm/config/config.guess @@ -0,0 +1,1466 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-08-03' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerppc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + *86) UNAME_PROCESSOR=i686 ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/contrib/ofed/libibcm/config/config.sub b/contrib/ofed/libibcm/config/config.sub new file mode 100755 index 000000000000..1c366dfde9ab --- /dev/null +++ b/contrib/ofed/libibcm/config/config.sub @@ -0,0 +1,1579 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-07-08' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | ms1 \ + | msp430 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m32c) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | ms1-* \ + | msp430-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + m32c-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/contrib/ofed/libibcm/config/depcomp b/contrib/ofed/libibcm/config/depcomp new file mode 100755 index 000000000000..04701da536f3 --- /dev/null +++ b/contrib/ofed/libibcm/config/depcomp @@ -0,0 +1,530 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2005-07-09.11 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + stat=$? + + if test -f "$tmpdepfile"; then : + else + stripped=`echo "$stripped" | sed 's,^.*/,,'` + tmpdepfile="$stripped.u" + fi + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + outname="$stripped.o" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mecanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/contrib/ofed/libibcm/config/install-sh b/contrib/ofed/libibcm/config/install-sh new file mode 100755 index 000000000000..4d4a9519eaf8 --- /dev/null +++ b/contrib/ofed/libibcm/config/install-sh @@ -0,0 +1,323 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2005-05-14.22 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# 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 +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +chmodcmd="$chmodprog 0755" +chowncmd= +chgrpcmd= +stripcmd= +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src= +dst= +dir_arg= +dstarg= +no_target_directory= + +usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: +-c (ignored) +-d create directories instead of installing files. +-g GROUP $chgrpprog installed files to GROUP. +-m MODE $chmodprog installed files to MODE. +-o USER $chownprog installed files to USER. +-s $stripprog installed files. +-t DIRECTORY install into DIRECTORY. +-T report an error if DSTFILE is a directory. +--help display this help and exit. +--version display version info and exit. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG +" + +while test -n "$1"; do + case $1 in + -c) shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + --help) echo "$usage"; exit $?;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t) dstarg=$2 + shift + shift + continue;; + + -T) no_target_directory=true + shift + continue;; + + --version) echo "$0 $scriptversion"; exit $?;; + + *) # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + test -n "$dir_arg$dstarg" && break + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dstarg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dstarg" + shift # fnord + fi + shift # arg + dstarg=$arg + done + break;; + esac +done + +if test -z "$1"; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src ;; + esac + + if test -n "$dir_arg"; then + dst=$src + src= + + if test -d "$dst"; then + mkdircmd=: + chmodcmd= + else + mkdircmd=$mkdirprog + fi + else + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dstarg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dstarg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst ;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dstarg: Is a directory" >&2 + exit 1 + fi + dst=$dst/`basename "$src"` + fi + fi + + # This sed command emulates the dirname command. + dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` + + # Make sure that the destination directory exists. + + # Skip lots of stat calls in the usual case. + if test ! -d "$dstdir"; then + defaultIFS=' + ' + IFS="${IFS-$defaultIFS}" + + oIFS=$IFS + # Some sh's can't handle IFS=/ for some reason. + IFS='%' + set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` + shift + IFS=$oIFS + + pathcomp= + + while test $# -ne 0 ; do + pathcomp=$pathcomp$1 + shift + if test ! -d "$pathcomp"; then + $mkdirprog "$pathcomp" + # mkdir can fail with a `File exist' error in case several + # install-sh are creating the directory concurrently. This + # is OK. + test -d "$pathcomp" || exit + fi + pathcomp=$pathcomp/ + done + fi + + if test -n "$dir_arg"; then + $doit $mkdircmd "$dst" \ + && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } + + else + dstfile=`basename "$dst"` + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + trap '(exit $?); exit' 1 2 13 15 + + # Copy the file name to the temp name. + $doit $cpprog "$src" "$dsttmp" && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && + + # Now rename the file to the real destination. + { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ + || { + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + if test -f "$dstdir/$dstfile"; then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ + || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ + || { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit 1 + } + else + : + fi + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + } + } + fi || { (exit 1); exit 1; } +done + +# The final little trick to "correctly" pass the exit status to the exit trap. +{ + (exit 0); exit 0 +} + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/contrib/ofed/libibcm/config/ltmain.sh b/contrib/ofed/libibcm/config/ltmain.sh new file mode 100644 index 000000000000..8fc56db8fc6e --- /dev/null +++ b/contrib/ofed/libibcm/config/ltmain.sh @@ -0,0 +1,6871 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun configure. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +basename="s,^.*/,,g" + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +progname=`echo "$progpath" | $SED $basename` +modename="$progname" + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION="1.5.22 Debian 1.5.22-2" +TIMESTAMP=" (1.1220.2.365 2005/12/18 22:14:06)" + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes. +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +duplicate_deps=no +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" + +##################################### +# Shell function definitions: +# This seems to be the best place for them + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $mkdir "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || { + $echo "cannot create temporary directory \`$my_tmpdir'" 1>&2 + exit $EXIT_FAILURE + } + fi + + $echo "X$my_tmpdir" | $Xsed +} + + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ + $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | \ + $SED -n -e '1,100{/ I /{s,.*,import,;p;q;};}'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $echo $win32_libid_type +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case "$@ " in + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + $echo "$modename: unable to infer tagged configuration" + $echo "$modename: specify a tag with \`--tag'" 1>&2 + exit $EXIT_FAILURE +# else +# $echo "$modename: using $tagname tagged configuration" + fi + ;; + esac + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + + $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)" + $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $? + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2 + exit $EXIT_FAILURE + fi +} + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + my_status="" + + $show "${rm}r $my_gentop" + $run ${rm}r "$my_gentop" + $show "$mkdir $my_gentop" + $run $mkdir "$my_gentop" + my_status=$? + if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then + exit $my_status + fi + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'` + my_xdir="$my_gentop/$my_xlib" + + $show "${rm}r $my_xdir" + $run ${rm}r "$my_xdir" + $show "$mkdir $my_xdir" + $run $mkdir "$my_xdir" + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$my_xdir"; then + exit $exit_status + fi + case $host in + *-darwin*) + $show "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + if test -z "$run"; then + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'` + darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null` + if test -n "$darwin_arches"; then + darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + $show "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we have a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + lipo -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + ${rm}r unfat-$$ + cd "$darwin_orig_dir" + else + cd "$darwin_orig_dir" + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + fi # $run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + func_extract_archives_result="$my_oldobjs" +} +# End of Shell function definitions +##################################### + +# Darwin sucks +eval std_shrext=\"$shrext_cmds\" + +disable_libs=no + +# Parse our command line options once, thoroughly. +while test "$#" -gt 0 +do + arg="$1" + shift + + case $arg in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + execute_dlfiles) + execute_dlfiles="$execute_dlfiles $arg" + ;; + tag) + tagname="$arg" + preserve_args="${preserve_args}=$arg" + + # Check whether tagname contains only valid characters + case $tagname in + *[!-_A-Za-z0-9,/]*) + $echo "$progname: invalid tag name: $tagname" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $tagname in + CC) + # Don't test for the "default" C tag, as we know, it's there, but + # not specially marked. + ;; + *) + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then + taglist="$taglist $tagname" + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`" + else + $echo "$progname: ignoring unknown tag $tagname" 1>&2 + fi + ;; + esac + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case $arg in + --help) + show_help=yes + ;; + + --version) + $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" + $echo + $echo "Copyright (C) 2005 Free Software Foundation, Inc." + $echo "This is free software; see the source for copying conditions. There is NO" + $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + exit $? + ;; + + --config) + ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath + # Now print the configurations for the tags. + for tagname in $taglist; do + ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath" + done + exit $? + ;; + + --debug) + $echo "$progname: enabling shell trace mode" + set -x + preserve_args="$preserve_args $arg" + ;; + + --dry-run | -n) + run=: + ;; + + --features) + $echo "host: $host" + if test "$build_libtool_libs" = yes; then + $echo "enable shared libraries" + else + $echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $echo "enable static libraries" + else + $echo "disable static libraries" + fi + exit $? + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --preserve-dup-deps) duplicate_deps="yes" ;; + + --quiet | --silent) + show=: + preserve_args="$preserve_args $arg" + ;; + + --tag) + prevopt="--tag" + prev=tag + preserve_args="$preserve_args --tag" + ;; + --tag=*) + set tag "$optarg" ${1+"$@"} + shift + prev=tag + preserve_args="$preserve_args --tag" + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE +fi + +case $disable_libs in +no) + ;; +shared) + build_libtool_libs=no + build_old_libs=yes + ;; +static) + build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` + ;; +esac + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 + $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2 + case $nonopt in + *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) + mode=link + for arg + do + case $arg in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case $mode in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + if test -n "$libobj" ; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit $EXIT_FAILURE + fi + arg_mode=target + continue + ;; + + -static | -prefer-pic | -prefer-non-pic) + later="$later $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + lastarg="$lastarg $arg" + done + IFS="$save_ifs" + lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` + + # Add the arguments to base_compile. + base_compile="$base_compile $lastarg" + continue + ;; + + * ) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + case $lastarg in + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, and some SunOS ksh mistreat backslash-escaping + # in scan sets (worked around with variable expansion), + # and furthermore cannot handle '|' '&' '(' ')' in scan sets + # at all, so we specify them separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + lastarg="\"$lastarg\"" + ;; + esac + + base_compile="$base_compile $lastarg" + done # for arg + + case $arg_mode in + arg) + $echo "$modename: you must specify an argument for -Xcompile" + exit $EXIT_FAILURE + ;; + target) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit $EXIT_FAILURE + ;; + *) + # Get the name of the library object. + [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSifmso]' + case $libobj in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.ii) xform=ii ;; + *.class) xform=class ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + *.java) xform=java ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case $libobj in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -static) + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"` + case $qlibobj in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qlibobj="\"$qlibobj\"" ;; + esac + test "X$libobj" != "X$qlibobj" \ + && $echo "X$libobj" | grep '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && $echo "$modename: libobj name \`$libobj' may not contain shell special characters." + objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir= + else + xdir=$xdir/ + fi + lobj=${xdir}$objdir/$objname + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $run ln "$progpath" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + $echo "$srcfile" > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"` + case $qsrcfile in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qsrcfile="\"$qsrcfile\"" ;; + esac + + $run $rm "$libobj" "${libobj}T" + + # Create a libtool object file (analogous to a ".la" file), + # but don't create it if we're doing a dry run. + test -z "$run" && cat > ${libobj}T </dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + $show "$mv $output_obj $lobj" + if $run $mv $output_obj $lobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the PIC object to the libtool object file. + test -z "$run" && cat >> ${libobj}T <> ${libobj}T </dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the non-PIC object the libtool object file. + # Only append if the libtool object file exists. + test -z "$run" && cat >> ${libobj}T <> ${libobj}T <&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + else + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + fi + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test + ;; + *) qarg=$arg ;; + esac + libtool_args="$libtool_args $qarg" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit $EXIT_FAILURE + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat $save_arg` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + done + else + $echo "$modename: link input file \`$save_arg' does not exist" + exit $EXIT_FAILURE + fi + arg=$save_arg + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + compile_command="$compile_command $wl$qarg" + finalize_command="$finalize_command $wl$qarg" + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + darwin_framework|darwin_framework_skip) + test "$prev" = "darwin_framework" && compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: more than one -exported-symbols argument is not allowed" + exit $EXIT_FAILURE + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework|-arch|-isysroot) + case " $CC " in + *" ${arg} ${1} "* | *" ${arg} ${1} "*) + prev=darwin_framework_skip ;; + *) compiler_flags="$compiler_flags $arg" + prev=darwin_framework ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + ;; + esac + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + notinst_path="$notinst_path $dir" + fi + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + testbindir=`$echo "X$dir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs -framework System" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + -model) + compile_command="$compile_command $arg" + compiler_flags="$compiler_flags $arg" + finalize_command="$finalize_command $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) + compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m* pass through architecture-specific compiler args for GCC + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -pg pass through profiling flag for GCC + # @file GCC response files + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \ + -t[45]*|-txscale*|@*) + + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # The PATH hackery in wrapper scripts is required on Windows + # in order for the loader to find any dlls it needs. + $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 + $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Wl,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $wl$flag" + linker_flags="$linker_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done # argument parsing loop + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + # Create the object directory. + if test ! -d "$output_objdir"; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$output_objdir"; then + exit $exit_status + fi + fi + + # Determine the type of output + case $output in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + case $host in + *cygwin* | *mingw* | *pw32*) + # don't eliminate duplications in $postdeps and $predeps + duplicate_compiler_generated_deps=yes + ;; + *) + duplicate_compiler_generated_deps=$duplicate_deps + ;; + esac + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if test "X$duplicate_deps" = "Xyes" ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + case $linkmode in + lib) + passes="conv link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + for pass in $passes; do + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 + continue + fi + name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` + for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if (${SED} -e '2q' $lib | + grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + library_names= + old_library= + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + *) + $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + if eval $echo \"$deplib\" 2>/dev/null \ + | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $echo + $echo "*** Warning: Trying to link with static lib archive $deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because the file extensions .$libext of this argument makes me believe" + $echo "*** that it is just a static archive that I should not used here." + else + $echo + $echo "*** Warning: Linking the shared library $output against the" + $echo "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + if test "$found" = yes || test -f "$lib"; then : + else + $echo "$modename: cannot find the library \`$lib' or unhandled argument \`$deplib'" 1>&2 + exit $EXIT_FAILURE + fi + + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + $echo "$modename: \`$lib' is not a convenience library" 1>&2 + exit $EXIT_FAILURE + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + abs_ladir="$ladir" + fi + ;; + esac + laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + $echo "$modename: warning: library \`$lib' was moved." 1>&2 + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *" $absdir "*) ;; + *) temp_rpath="$temp_rpath $absdir" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes ; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + # This is a shared library + + # Warn about portability, can't link against -module's on + # some systems (darwin) + if test "$shouldnotlink" = yes && test "$pass" = link ; then + $echo + if test "$linkmode" = prog; then + $echo "*** Warning: Linking the executable $output against the loadable module" + else + $echo "*** Warning: Linking the shared library $output against the loadable module" + fi + $echo "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + realname="$2" + shift; shift + libname=`eval \\$echo \"$libname_spec\"` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw*) + major=`expr $current - $age` + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + soname=`$echo $soroot | ${SED} -e 's/^.*\///'` + newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + $show "extracting exported symbol list from \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$extract_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + $show "generating import library for \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$old_archive_from_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a module then we can not link against + # it, someone is ignoring the new warnings I added + if /usr/bin/file -L $add 2> /dev/null | + $EGREP ": [^:]* bundle" >/dev/null ; then + $echo "** Warning, lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $echo + $echo "** And there doesn't seem to be a static archive available" + $echo "** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit $EXIT_FAILURE + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $echo + $echo "*** Warning: This system can not link to static lib archive $lib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $echo "*** But as you try to build a module library, libtool will still create " + $echo "*** a static module, that should work as long as the dlopening application" + $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$deplib" && dir="." + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + fi + ;; + esac + if grep "^installed=no" $deplib > /dev/null; then + path="$absdir/$objdir" + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + if test "$absdir" != "$libdir"; then + $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 + fi + path="$absdir" + fi + depdepl= + case $host in + *-*-darwin*) + # we do not want to link against static libs, + # but need to link against shared + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$path/$depdepl" ; then + depdepl="$path/$depdepl" + fi + # do not add paths which are already there + case " $newlib_search_path " in + *" $path "*) ;; + *) newlib_search_path="$newlib_search_path $path";; + esac + fi + path="" + ;; + *) + path="-L$path" + ;; + esac + ;; + -l*) + case $host in + *-*-darwin*) + # Again, we only want to link against shared libraries + eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` + for tmp in $newlib_search_path ; do + if test -f "$tmp/lib$tmp_libs.dylib" ; then + eval depdepl="$tmp/lib$tmp_libs.dylib" + break + fi + done + path="" + ;; + *) continue ;; + esac + ;; + *) continue ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + case " $deplibs " in + *" $depdepl "*) ;; + *) deplibs="$depdepl $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 + exit $EXIT_FAILURE + else + $echo + $echo "*** Warning: Linking the shared library $output against the non-libtool" + $echo "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + if test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test "$#" -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$2" + number_minor="$3" + number_revision="$4" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows) + current=`expr $number_major + $number_minor` + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + current=`expr $number_major + $number_minor - 1` + age="$number_minor" + revision="$number_minor" + ;; + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE + ;; + esac + ;; + no) + current="$2" + revision="$3" + age="$4" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test "$age" -gt "$current"; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + minor_current=`expr $current + 1` + verstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + irix | nonstopux) + major=`expr $current - $age + 1` + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=.`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + major=`expr $current - $age` + versuffix="-$major" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + fi + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$echo "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + if test -n "$removelist"; then + $show "${rm}r $removelist" + $run ${rm}r $removelist + fi + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + for path in $notinst_path; do + lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"` + deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"` + dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"` + done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs -framework System" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for file magic test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a file magic. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name=`expr $a_deplib : '-l\(.*\)'` + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval $echo \"$potent_lib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a regex pattern. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` + done + fi + if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ + | grep . >/dev/null; then + $echo + if test "X$deplibs_check_method" = "Xnone"; then + $echo "*** Warning: inter-library dependencies are not supported in this platform." + else + $echo "*** Warning: inter-library dependencies are not known to be supported." + fi + $echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $echo + $echo "*** Warning: libtool could not satisfy all declared inter-library" + $echo "*** dependencies of module $libname. Therefore, libtool will create" + $echo "*** a static module, that should work as long as the dlopening" + $echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $echo "*** The inter-library dependencies that have been dropped here will be" + $echo "*** automatically added whenever a program is linked with this library" + $echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $echo + $echo "*** Since this library must not contain undefined symbols," + $echo "*** because either the platform does not support them or" + $echo "*** it was explicitly requested with -no-undefined," + $echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + if len=`expr "X$cmd" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + $show "$cmd" + $run eval "$cmd" || exit $? + skipped_export=false + else + # The command line is too long to execute in one step. + $show "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise. + $echo "creating reloadable object files..." + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$echo "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + delfiles= + last_robj= + k=1 + output=$output_objdir/$output_la-${k}.$objext + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + eval test_cmds=\"$reload_cmds $objlist $last_robj\" + if test "X$objlist" = X || + { len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len"; }; then + objlist="$objlist $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + k=`expr $k + 1` + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + len=1 + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + + if ${skipped_export-false}; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + libobjs=$output + # Append the command to create the export file. + eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" + fi + + # Set up a command to remove the reloadable object files + # after they are used. + i=0 + while test "$i" -lt "$k" + do + i=`expr $i + 1` + delfiles="$delfiles $output_objdir/$output_la-${i}.$objext" + done + + $echo "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + + # Append the command to remove the reloadable object files + # to the just-reset $cmds. + eval cmds=\"\$cmds~\$rm $delfiles\" + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case $output in + *.lo) + if test -n "$objs$old_deplibs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit $EXIT_FAILURE + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $run eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; + esac + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + case $host in + *darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + if test "$tagname" = CXX ; then + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + fi + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case $dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $run $rm $export_symbols + $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* ) + $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + $run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + else + $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* ) + $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + $run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` + $run eval '$echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + $echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +" + + case $host in + *cygwin* | *mingw* ) + $echo >> "$output_objdir/$dlsyms" "\ +/* DATA imports from DLLs on WIN32 can't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs */ +struct { +" + ;; + * ) + $echo >> "$output_objdir/$dlsyms" "\ +const struct { +" + ;; + esac + + + $echo >> "$output_objdir/$dlsyms" "\ + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[] = +{\ +" + + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + case $host in + *cygwin* | *mingw* ) + if test -f "$output_objdir/${outputname}.def" ; then + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"` + else + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + fi + ;; + * ) + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + ;; + esac + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + exit_status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $exit_status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $run $rm $output + # Link the executable and exit + $show "$link_command" + $run eval "$link_command" || exit $? + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + output_name=`basename $output` + output_path=`dirname $output` + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $rm $cwrappersource $cwrapper + trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + cat > $cwrappersource <> $cwrappersource<<"EOF" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +/* -DDEBUG is fairly common in CFLAGS. */ +#undef DEBUG +#if defined DEBUGWRAPPER +# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__) +#else +# define DEBUG(format, ...) +#endif + +const char *program_name = NULL; + +void * xmalloc (size_t num); +char * xstrdup (const char *string); +const char * base_name (const char *name); +char * find_executable(const char *wrapper); +int check_executable(const char *path); +char * strendzap(char *str, const char *pat); +void lt_fatal (const char *message, ...); + +int +main (int argc, char *argv[]) +{ + char **newargz; + int i; + + program_name = (char *) xstrdup (base_name (argv[0])); + DEBUG("(main) argv[0] : %s\n",argv[0]); + DEBUG("(main) program_name : %s\n",program_name); + newargz = XMALLOC(char *, argc+2); +EOF + + cat >> $cwrappersource <> $cwrappersource <<"EOF" + newargz[1] = find_executable(argv[0]); + if (newargz[1] == NULL) + lt_fatal("Couldn't find %s", argv[0]); + DEBUG("(main) found exe at : %s\n",newargz[1]); + /* we know the script has the same name, without the .exe */ + /* so make sure newargz[1] doesn't end in .exe */ + strendzap(newargz[1],".exe"); + for (i = 1; i < argc; i++) + newargz[i+1] = xstrdup(argv[i]); + newargz[argc+1] = NULL; + + for (i=0; i> $cwrappersource <> $cwrappersource <> $cwrappersource <<"EOF" + return 127; +} + +void * +xmalloc (size_t num) +{ + void * p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL +; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char)name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable(const char * path) +{ + struct stat st; + + DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!"); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) && + ( + /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */ +#if defined (S_IXOTH) + ((st.st_mode & S_IXOTH) == S_IXOTH) || +#endif +#if defined (S_IXGRP) + ((st.st_mode & S_IXGRP) == S_IXGRP) || +#endif + ((st.st_mode & S_IXUSR) == S_IXUSR)) + ) + return 1; + else + return 0; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise */ +char * +find_executable (const char* wrapper) +{ + int has_slash = 0; + const char* p; + const char* p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char* concat_name; + + DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char* path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char* q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR(*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen(tmp); + concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen(tmp); + concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + return NULL; +} + +char * +strendzap(char *str, const char *pat) +{ + size_t len, patlen; + + assert(str != NULL); + assert(pat != NULL); + + len = strlen(str); + patlen = strlen(pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp(str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char * mode, + const char * message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} +EOF + # we should really use a build-platform specific compiler + # here, but OTOH, the wrappers (shell script and this C one) + # are only useful if you want to execute the "real" binary. + # Since the "real" binary is built for $host, then this + # wrapper might as well be built for $host, too. + $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource + ;; + esac + $rm $output + trap "$rm $output; exit $EXIT_FAILURE" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $echo >> $output "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + $echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $echo \"\$relink_command_output\" >&2 + $rm \"\$progdir/\$file\" + exit $EXIT_FAILURE + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + $echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" + exit $EXIT_FAILURE + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + $echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit $EXIT_FAILURE + fi +fi\ +" + chmod +x $output + fi + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + $echo "X$obj" | $Xsed -e 's%^.*/%%' + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "copying selected object files to avoid basename conflicts..." + + if test -z "$gentop"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "$mkdir $gentop" + $run $mkdir "$gentop" + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$gentop"; then + exit $exit_status + fi + fi + + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + counter=`expr $counter + 1` + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + $run ln "$obj" "$gentop/$newobj" || + $run cp "$obj" "$gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + + eval cmds=\"$old_archive_cmds\" + + if len=`expr "X$cmds" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + $echo "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + for obj in $save_oldobjs + do + oldobjs="$objlist $obj" + objlist="$objlist $obj" + eval test_cmds=\"$old_archive_cmds\" + if len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + eval cmd=\"$cmd\" + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + for lib in $dlfiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlfiles="$newdlfiles $libdir/$name" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlprefiles="$newdlprefiles $libdir/$name" + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $rm $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $echo >> $output "\ +relink_command=\"$relink_command\"" + fi + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? + ;; + esac + exit $EXIT_SUCCESS + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $echo "X$nonopt" | grep shtool > /dev/null; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + case " $install_prog " in + *[\\\ /]cp\ *) ;; + *) prev=$arg ;; + esac + ;; + -g | -m | -o) prev=$arg ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test "$#" -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + library_names= + old_library= + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + if test "$inst_prefix_dir" = "$destdir"; then + $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + $echo "$modename: warning: relinking \`$file'" 1>&2 + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + exit $EXIT_FAILURE + fi + fi + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$srcname $destdir/$realname" + $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? + if test -n "$stripme" && test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run eval "$striplib $destdir/$realname" || exit $? + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" + $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + cmds=$postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + file=`$echo $file|${SED} 's,.exe$,,'` + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin*|*mingw*) + wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` + ;; + *) + wrapper=$file + ;; + esac + if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then + notinst_deplibs= + relink_command= + + # Note that it is not necessary on cygwin/mingw to append a dot to + # foo even if both foo and FILE.exe exist: automatic-append-.exe + # behavior happens only for exec(3), not for open(2)! Also, sourcing + # `FILE.' does not work on cygwin managed mounts. + # + # If there is no directory component, then add one. + case $wrapper in + */* | *\\*) . ${wrapper} ;; + *) . ./${wrapper} ;; + esac + + # Check the variables that should have been set. + if test -z "$notinst_deplibs"; then + $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 + exit $EXIT_FAILURE + fi + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + relink_command= + # Note that it is not necessary on cygwin/mingw to append a dot to + # foo even if both foo and FILE.exe exist: automatic-append-.exe + # behavior happens only for exec(3), not for open(2)! Also, sourcing + # `FILE.' does not work on cygwin managed mounts. + # + # If there is no directory component, then add one. + case $wrapper in + */* | *\\*) . ${wrapper} ;; + *) . ./${wrapper} ;; + esac + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir=`func_mktempdir` + file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` + ;; + esac + ;; + esac + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + if test -n "$stripme" && test -n "$old_striplib"; then + $show "$old_striplib $oldlib" + $run eval "$old_striplib $oldlib" || exit $? + fi + + # Do each command in the postinstall commands. + cmds=$old_postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + cmds=$finish_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = : && exit $EXIT_SUCCESS + + $echo "X----------------------------------------------------------------------" | $Xsed + $echo "Libraries have been installed in:" + for libdir in $libdirs; do + $echo " $libdir" + done + $echo + $echo "If you ever happen to want to link against installed libraries" + $echo "in a given directory, LIBDIR, you must either use libtool, and" + $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + $echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + $echo " during execution" + fi + if test -n "$runpath_var"; then + $echo " - add LIBDIR to the \`$runpath_var' environment variable" + $echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $echo + $echo "See any operating system documentation about shared libraries for" + $echo "more information, such as the ld(1) and ld.so(8) manual pages." + $echo "X----------------------------------------------------------------------" | $Xsed + exit $EXIT_SUCCESS + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit $EXIT_FAILURE + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit $EXIT_FAILURE + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + if test "${save_LC_ALL+set}" = set; then + LC_ALL="$save_LC_ALL"; export LC_ALL + fi + if test "${save_LANG+set}" = set; then + LANG="$save_LANG"; export LANG + fi + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit $EXIT_SUCCESS + fi + ;; + + # libtool clean and uninstall mode + clean | uninstall) + modename="$modename: $mode" + rm="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) rm="$rm $arg"; rmforce=yes ;; + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$file"; then + dir=. + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if (test -L "$file") >/dev/null 2>&1 \ + || (test -h "$file") >/dev/null 2>&1 \ + || test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + cmds=$postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + cmds=$old_postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + + # Read the .lo file + . $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" \ + && test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" \ + && test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + file=`$echo $file|${SED} 's,.exe$,,'` + noexename=`$echo $name|${SED} 's,.exe$,,'` + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + relink_command= + . $dir/$noexename + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + $show "$rm $rmfiles" + $run $rm $rmfiles || exit_status=1 + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + $show "rmdir $dir" + $run rmdir $dir >/dev/null 2>&1 + fi + done + + exit $exit_status + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test -z "$exec_cmd"; then + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + fi +fi # test -z "$show_help" + +if test -n "$exec_cmd"; then + eval exec $exec_cmd + exit $EXIT_FAILURE +fi + +# We need to display help for each of the modes. +case $mode in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --tag=TAG use configuration variables from tag TAG + --version print version information + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE. + +Report bugs to ." + exit $EXIT_SUCCESS + ;; + +clean) + $echo \ +"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; +esac + +$echo +$echo "Try \`$modename --help' for more information about other modes." + +exit $? + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +disable_libs=shared +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +disable_libs=static +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/contrib/ofed/libibcm/config/missing b/contrib/ofed/libibcm/config/missing new file mode 100755 index 000000000000..894e786e16c1 --- /dev/null +++ b/contrib/ofed/libibcm/config/missing @@ -0,0 +1,360 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2005-06-08.21 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case "$1" in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/contrib/ofed/libibcm/configure b/contrib/ofed/libibcm/configure new file mode 100755 index 000000000000..2735510a88f6 --- /dev/null +++ b/contrib/ofed/libibcm/configure @@ -0,0 +1,22105 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59 for libibcm 1.0.5. +# +# Report bugs to . +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +echo=${ECHO-echo} +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1 && unset CDPATH + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string=`eval $cmd`) 2>/dev/null && + echo_test_string=`eval $cmd` && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL $0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + + + + +tagnames=${tagnames+${tagnames},}CXX + +tagnames=${tagnames+${tagnames},}F77 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME='libibcm' +PACKAGE_TARNAME='libibcm' +PACKAGE_VERSION='1.0.5' +PACKAGE_STRING='libibcm 1.0.5' +PACKAGE_BUGREPORT='general@lists@openfabrics.org' + +ac_unique_file="src/cm.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL HAVE_LD_VERSION_SCRIPT_TRUE HAVE_LD_VERSION_SCRIPT_FALSE LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP +ac_env_CXX_set=${CXX+set} +ac_env_CXX_value=$CXX +ac_cv_env_CXX_set=${CXX+set} +ac_cv_env_CXX_value=$CXX +ac_env_CXXFLAGS_set=${CXXFLAGS+set} +ac_env_CXXFLAGS_value=$CXXFLAGS +ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set} +ac_cv_env_CXXFLAGS_value=$CXXFLAGS +ac_env_CXXCPP_set=${CXXCPP+set} +ac_env_CXXCPP_value=$CXXCPP +ac_cv_env_CXXCPP_set=${CXXCPP+set} +ac_cv_env_CXXCPP_value=$CXXCPP +ac_env_F77_set=${F77+set} +ac_env_F77_value=$F77 +ac_cv_env_F77_set=${F77+set} +ac_cv_env_F77_value=$F77 +ac_env_FFLAGS_set=${FFLAGS+set} +ac_env_FFLAGS_value=$FFLAGS +ac_cv_env_FFLAGS_set=${FFLAGS+set} +ac_cv_env_FFLAGS_value=$FFLAGS + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures libibcm 1.0.5 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of libibcm 1.0.5:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-shared[=PKGS] + build shared libraries [default=yes] + --enable-static[=PKGS] + build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --disable-libtool-lock avoid locking (might break parallel builds) + --disable-libcheck do not test for presence of ib libraries + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-tags[=TAGS] + include additional configurations [automatic] + --with-valgrind Enable valgrind annotations - default NO + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CXXCPP C++ preprocessor + F77 Fortran 77 compiler command + FFLAGS Fortran 77 compiler flags + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd "$ac_popdir" + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF +libibcm configure 1.0.5 +generated by GNU Autoconf 2.59 + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by libibcm $as_me 1.0.5, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + + + + + + + + +ac_aux_dir= +for ac_dir in config $srcdir/config; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in config $srcdir/config" >&5 +echo "$as_me: error: cannot find install-sh or install.sh in config $srcdir/config" >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + + ac_config_headers="$ac_config_headers config.h" + +am__api_version="1.9" +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +test "$program_prefix" != NONE && + program_transform_name="s,^,$program_prefix,;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$,$program_suffix,;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm conftest.sed + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$AWK" && break +done + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE=libibcm + VERSION=1.0.5 + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +install_sh=${install_sh-"$am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + + +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi; + +# Check whether --enable-static or --disable-static was given. +if test "${enable_static+set}" = set; then + enableval="$enable_static" + p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi; + +# Check whether --enable-fast-install or --disable-fast-install was given. +if test "${enable_fast_install+set}" = set; then + enableval="$enable_fast_install" + p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi; + +# Make sure we can run config.sub. +$ac_config_sub sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 +echo "$as_me: error: cannot run $ac_config_sub" >&2;} + { (exit 1); exit 1; }; } + +echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6 +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_build_alias=$build_alias +test -z "$ac_cv_build_alias" && + ac_cv_build_alias=`$ac_config_guess` +test -z "$ac_cv_build_alias" && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6 +build=$ac_cv_build +build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6 +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_host_alias=$host_alias +test -z "$ac_cv_host_alias" && + ac_cv_host_alias=$ac_cv_build_alias +ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6 +host=$ac_cv_host +host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +DEPDIR="${am__leading_dot}deps" + + ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6 +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6 +rm -f confinc confmf + +# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval="$enable_dependency_tracking" + +fi; +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + + +if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CC" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5 +echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6 +if test "${lt_cv_path_SED+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done + +fi + +SED=$lt_cv_path_SED +echo "$as_me:$LINENO: result: $SED" >&5 +echo "${ECHO_T}$SED" >&6 + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi; +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo "$as_me:$LINENO: checking for ld used by $CC" >&5 +echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6 + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6 +else + echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6 +fi +if test "${lt_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +echo "${ECHO_T}$LD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6 +if test "${lt_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6 +with_gnu_ld=$lt_cv_prog_gnu_ld + + +echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5 +echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6 +if test "${lt_cv_ld_reload_flag+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_ld_reload_flag='-r' +fi +echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5 +echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6 +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + +echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5 +echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6 +if test "${lt_cv_path_NM+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi +fi +echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5 +echo "${ECHO_T}$lt_cv_path_NM" >&6 +NM="$lt_cv_path_NM" + +echo "$as_me:$LINENO: checking whether ln -s works" >&5 +echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:$LINENO: result: no, using $LN_S" >&5 +echo "${ECHO_T}no, using $LN_S" >&6 +fi + +echo "$as_me:$LINENO: checking how to recognise dependent libraries" >&5 +echo $ECHO_N "checking how to recognise dependent libraries... $ECHO_C" >&6 +if test "${lt_cv_deplibs_check_method+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix4* | aix5*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump'. + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | kfreebsd*-gnu | dragonfly*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix3*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5 +echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6 +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check whether --enable-libtool-lock or --disable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval="$enable_libtool_lock" + +fi; +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 3673 "configure"' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5 +echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6 +if test "${lt_cv_cc_needs_belf+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + lt_cv_cc_needs_belf=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +lt_cv_cc_needs_belf=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5 +echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6 + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) LD="${LD-ld} -64" ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + + +esac + +need_locks="$enable_libtool_lock" + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in dlfcn.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------- ## +## Report this to general@lists@openfabrics.org ## +## -------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CXX" && break +done +test -n "$ac_ct_CXX" || ac_ct_CXX="g++" + + CXX=$ac_ct_CXX +fi + + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6 +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6 +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +CXXFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cxx_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +depcc="$CXX" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6 +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + + +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 +echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6 +if test -z "$CXXCPP"; then + if test "${ac_cv_prog_CXXCPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_cxx_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_cxx_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +echo "$as_me:$LINENO: result: $CXXCPP" >&5 +echo "${ECHO_T}$CXXCPP" >&6 +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_cxx_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_cxx_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +fi + + +ac_ext=f +ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' +ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_f77_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$F77"; then + ac_cv_prog_F77="$F77" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_F77="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +F77=$ac_cv_prog_F77 +if test -n "$F77"; then + echo "$as_me:$LINENO: result: $F77" >&5 +echo "${ECHO_T}$F77" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$F77" && break + done +fi +if test -z "$F77"; then + ac_ct_F77=$F77 + for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_F77"; then + ac_cv_prog_ac_ct_F77="$ac_ct_F77" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_F77="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_F77=$ac_cv_prog_ac_ct_F77 +if test -n "$ac_ct_F77"; then + echo "$as_me:$LINENO: result: $ac_ct_F77" >&5 +echo "${ECHO_T}$ac_ct_F77" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_F77" && break +done + + F77=$ac_ct_F77 +fi + + +# Provide some information about the compiler. +echo "$as_me:5264:" \ + "checking for Fortran 77 compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +rm -f a.out + +# If we don't use `.F' as extension, the preprocessor is not run on the +# input file. (Note that this only needs to work for GNU compilers.) +ac_save_ext=$ac_ext +ac_ext=F +echo "$as_me:$LINENO: checking whether we are using the GNU Fortran 77 compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU Fortran 77 compiler... $ECHO_C" >&6 +if test "${ac_cv_f77_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF + program main +#ifndef __GNUC__ + choke me +#endif + + end +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_f77_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_f77_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_f77_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_f77_compiler_gnu" >&6 +ac_ext=$ac_save_ext +ac_test_FFLAGS=${FFLAGS+set} +ac_save_FFLAGS=$FFLAGS +FFLAGS= +echo "$as_me:$LINENO: checking whether $F77 accepts -g" >&5 +echo $ECHO_N "checking whether $F77 accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_f77_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + FFLAGS=-g +cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_f77_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_f77_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_f77_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_f77_g" >&5 +echo "${ECHO_T}$ac_cv_prog_f77_g" >&6 +if test "$ac_test_FFLAGS" = set; then + FFLAGS=$ac_save_FFLAGS +elif test $ac_cv_prog_f77_g = yes; then + if test "x$ac_cv_f77_compiler_gnu" = xyes; then + FFLAGS="-g -O2" + else + FFLAGS="-g" + fi +else + if test "x$ac_cv_f77_compiler_gnu" = xyes; then + FFLAGS="-O2" + else + FFLAGS= + fi +fi + +G77=`test $ac_compiler_gnu = yes && echo yes` +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! + +# find the maximum length of command line arguments +echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5 +echo $ECHO_N "checking the maximum length of command line arguments... $ECHO_C" >&6 +if test "${lt_cv_sys_max_cmd_len+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + while (test "X"`$SHELL $0 --fallback-echo "X$teststring" 2>/dev/null` \ + = "XX$teststring") >/dev/null 2>&1 && + new_result=`expr "X$teststring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + teststring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5 +echo "${ECHO_T}$lt_cv_sys_max_cmd_len" >&6 +else + echo "$as_me:$LINENO: result: none" >&5 +echo "${ECHO_T}none" >&6 +fi + + + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5 +echo $ECHO_N "checking command to parse $NM output from $compiler object... $ECHO_C" >&6 +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32*) + symcode='[ABCDGISTW]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +linux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDGIRSTW]' + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + echo "$as_me:$LINENO: result: failed" >&5 +echo "${ECHO_T}failed" >&6 +else + echo "$as_me:$LINENO: result: ok" >&5 +echo "${ECHO_T}ok" >&6 +fi + +echo "$as_me:$LINENO: checking for objdir" >&5 +echo $ECHO_N "checking for objdir... $ECHO_C" >&6 +if test "${lt_cv_objdir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5 +echo "${ECHO_T}$lt_cv_objdir" >&6 +objdir=$lt_cv_objdir + + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + echo "$as_me:$LINENO: result: $AR" >&5 +echo "${ECHO_T}$AR" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_AR" && ac_cv_prog_ac_ct_AR="false" +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + echo "$as_me:$LINENO: result: $ac_ct_AR" >&5 +echo "${ECHO_T}$ac_ct_AR" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + AR=$ac_ct_AR +else + AR="$ac_cv_prog_AR" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5 +echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6 +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + echo "$as_me:$LINENO: checking for file" >&5 +echo $ECHO_N "checking for file... $ECHO_C" >&6 +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +enable_dlopen=no +enable_win32_dll=no + +# Check whether --enable-libtool-lock or --disable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval="$enable_libtool_lock" + +fi; +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + + +# Check whether --with-pic or --without-pic was given. +if test "${with_pic+set}" = set; then + withval="$with_pic" + pic_mode="$withval" +else + pic_mode=default +fi; +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}\n' + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag=' -fno-builtin' + + +echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:6325: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:6329: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6 + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + +lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + +echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic='-qnocommon' + lt_prog_compiler_wl='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + linux*) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic" >&6 + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + +echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic works... $ECHO_C" >&6 +if test "${lt_prog_compiler_pic_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:6593: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:6597: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_pic_works=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works" >&6 + +if test x"$lt_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6 +if test "${lt_prog_compiler_static_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_static_works=yes + fi + else + lt_prog_compiler_static_works=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works" >&5 +echo "${ECHO_T}$lt_prog_compiler_static_works" >&6 + +if test x"$lt_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + +echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_c_o+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:6697: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:6701: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o" >&6 + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 + + runpath_var= + allow_undefined_flag= + enable_shared_with_static_runtimes=no + archive_cmds= + archive_expsym_cmds= + old_archive_From_new_cmds= + old_archive_from_expsyms_cmds= + export_dynamic_flag_spec= + whole_archive_flag_spec= + thread_safe_flag_spec= + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_direct=no + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + link_all_deplibs=unknown + hardcode_automatic=no + module_cmds= + module_expsym_cmds= + always_export_symbols=no + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + interix3*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + archive_cmds='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + link_all_deplibs=no + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct=yes + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + whole_archive_flag_spec='' + link_all_deplibs=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # GNU/kFreeBSD uses gcc -shared to do shared libraries. + kfreebsd*-gnu) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + link_all_deplibs=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + hardcode_direct=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld='-rpath $libdir' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + link_all_deplibs=yes + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + openbsd*) + hardcode_direct=yes + hardcode_shlibpath_var=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine linker options so we + # cannot just pass the convience library names through + # without $wl, iff we do not link with $LD. + # Luckily, gcc supports the same syntax we need for Sun Studio. + # Supported since Solaris 2.6 (maybe 2.5.1?) + case $wlarc in + '') + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; + *) + whole_archive_flag_spec='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; + esac ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $ld_shlibs" >&5 +echo "${ECHO_T}$ld_shlibs" >&6 +test "$ld_shlibs" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc=no + else + archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5 +echo "${ECHO_T}$archive_cmds_need_lc" >&6 + ;; + esac + fi + ;; +esac + +echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + freebsd*) # from 4.6 on + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix3*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test -n "$runpath_var" || \ + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +echo "$as_me:$LINENO: result: $hardcode_action" >&5 +echo "${ECHO_T}$hardcode_action" >&6 + +if test "$hardcode_action" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +striplib= +old_striplib= +echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 +echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6 +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + ;; + *) + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + ;; + esac +fi + +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + echo "$as_me:$LINENO: checking for shl_load" >&5 +echo $ECHO_N "checking for shl_load... $ECHO_C" >&6 +if test "${ac_cv_func_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define shl_load to an innocuous variant, in case declares shl_load. + For example, HP-UX 11i declares gettimeofday. */ +#define shl_load innocuous_shl_load + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shl_load (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef shl_load + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shl_load (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_shl_load) || defined (__stub___shl_load) +choke me +#else +char (*f) () = shl_load; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != shl_load; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_shl_load=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 +echo "${ECHO_T}$ac_cv_func_shl_load" >&6 +if test $ac_cv_func_shl_load = yes; then + lt_cv_dlopen="shl_load" +else + echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 +echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shl_load (); +int +main () +{ +shl_load (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dld_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dld_shl_load=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6 +if test $ac_cv_lib_dld_shl_load = yes; then + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" +else + echo "$as_me:$LINENO: checking for dlopen" >&5 +echo $ECHO_N "checking for dlopen... $ECHO_C" >&6 +if test "${ac_cv_func_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define dlopen to an innocuous variant, in case declares dlopen. + For example, HP-UX 11i declares gettimeofday. */ +#define dlopen innocuous_dlopen + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char dlopen (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef dlopen + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_dlopen) || defined (__stub___dlopen) +choke me +#else +char (*f) () = dlopen; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != dlopen; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 +echo "${ECHO_T}$ac_cv_func_dlopen" >&6 +if test $ac_cv_func_dlopen = yes; then + lt_cv_dlopen="dlopen" +else + echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 +echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6 +if test "${ac_cv_lib_svld_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_svld_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_svld_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6 +if test $ac_cv_lib_svld_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 +echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_dld_link+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dld_link (); +int +main () +{ +dld_link (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dld_dld_link=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dld_dld_link=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6 +if test $ac_cv_lib_dld_dld_link = yes; then + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 +echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self" >&6 + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 +echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self_static+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6 + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + +# Report which library types will actually be built +echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 +echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $can_build_shared" >&5 +echo "${ECHO_T}$can_build_shared" >&6 + +echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 +echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6 +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +echo "$as_me:$LINENO: result: $enable_shared" >&5 +echo "${ECHO_T}$enable_shared" >&6 + +echo "$as_me:$LINENO: checking whether to build static libraries" >&5 +echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6 +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +echo "$as_me:$LINENO: result: $enable_static" >&5 +echo "${ECHO_T}$enable_static" >&6 + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler \ + CC \ + LD \ + lt_prog_compiler_wl \ + lt_prog_compiler_pic \ + lt_prog_compiler_static \ + lt_prog_compiler_no_builtin_flag \ + export_dynamic_flag_spec \ + thread_safe_flag_spec \ + whole_archive_flag_spec \ + enable_shared_with_static_runtimes \ + old_archive_cmds \ + old_archive_from_new_cmds \ + predep_objects \ + postdep_objects \ + predeps \ + postdeps \ + compiler_lib_search_path \ + archive_cmds \ + archive_expsym_cmds \ + postinstall_cmds \ + postuninstall_cmds \ + old_archive_from_expsyms_cmds \ + allow_undefined_flag \ + no_undefined_flag \ + export_symbols_cmds \ + hardcode_libdir_flag_spec \ + hardcode_libdir_flag_spec_ld \ + hardcode_libdir_separator \ + hardcode_automatic \ + module_cmds \ + module_expsym_cmds \ + lt_cv_prog_compiler_c_o \ + exclude_expsyms \ + include_expsyms; do + + case $var in + old_archive_cmds | \ + old_archive_from_new_cmds | \ + archive_cmds | \ + archive_expsym_cmds | \ + module_cmds | \ + module_expsym_cmds | \ + old_archive_from_expsyms_cmds | \ + export_symbols_cmds | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="${ofile}T" + trap "$rm \"$cfgfile\"; exit 1" 1 2 15 + $rm -f "$cfgfile" + { echo "$as_me:$LINENO: creating $ofile" >&5 +echo "$as_me: creating $ofile" >&6;} + + cat <<__EOF__ >> "$cfgfile" +#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e 1s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU C compiler? +with_gcc=$GCC + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# ### END LIBTOOL CONFIG + +__EOF__ + + + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + +# Check whether --with-tags or --without-tags was given. +if test "${with_tags+set}" = set; then + withval="$with_tags" + tagnames="$withval" +fi; + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not exist" >&5 +echo "$as_me: WARNING: output file \`$ofile' does not exist" >&2;} + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not look like a libtool script" >&5 +echo "$as_me: WARNING: output file \`$ofile' does not look like a libtool script" >&2;} + else + { echo "$as_me:$LINENO: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&5 +echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;} + fi + fi + if test -z "$LTCFLAGS"; then + eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]::g'` in + "") ;; + *) { { echo "$as_me:$LINENO: error: invalid tag name: $tagname" >&5 +echo "$as_me: error: invalid tag name: $tagname" >&2;} + { (exit 1); exit 1; }; } + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + { { echo "$as_me:$LINENO: error: tag name \"$tagname\" already exists" >&5 +echo "$as_me: error: tag name \"$tagname\" already exists" >&2;} + { (exit 1); exit 1; }; } + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_flag_spec_ld_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + $as_unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + $as_unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +compiler_CXX=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' +else + lt_prog_compiler_no_builtin_flag_CXX= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi; +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo "$as_me:$LINENO: checking for ld used by $CC" >&5 +echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6 + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6 +else + echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6 +fi +if test "${lt_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +echo "${ECHO_T}$LD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6 +if test "${lt_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6 +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 +ld_shlibs_CXX=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct_CXX=yes + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag_CXX='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag_CXX='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + whole_archive_flag_spec_CXX='' + link_all_deplibs_CXX=yes + + if test "$GXX" = yes ; then + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + archive_cmds_CXX='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + archive_cmds_CXX='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_CXX='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_CXX=no + ;; + esac + fi + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + freebsd[12]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + ld_shlibs_CXX=no + ;; + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + gnu*) + ;; + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[-]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_libdir_flag_spec_ld_CXX='+b $libdir' + ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + interix3*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + ;; + linux*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc*) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC*) + # Portland Group C++ compiler + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + openbsd*) + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd='echo' + ;; + osf3*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ + $rm $lib.exp' + + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. We must also pass each convience library through + # to the system linker between allextract/defaultextract. + # The C++ compiler will combine linker options so we + # cannot just pass the convience library names through + # without $wl. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + # So that behaviour is only enabled if SCOABSPATH is set to a + # non-empty value in the environment. Most likely only useful for + # creating official distributions of packages. + # This is a hack until libtool officially supports absolute path + # names for shared libraries. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; +esac +echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 +echo "${ECHO_T}$ld_shlibs_CXX" >&6 +test "$ld_shlibs_CXX" = no && can_build_shared=no + +GCC_CXX="$GXX" +LD_CXX="$LD" + + +cat > conftest.$ac_ext <&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + # The `*' in the case matches for architectures that use `case' in + # $output_verbose_cmd can trigger glob expansion during the loop + # eval without this substitution. + output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"` + + for p in `eval $output_verbose_link_cmd`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" \ + || test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$rm -f confest.$objext + +# PORTME: override above test on systems where it is broken +case $host_os in +interix3*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +solaris*) + case $cc_basename in + CC*) + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + postdeps_CXX='-lCstd -lCrun' + ;; + esac + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + +lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + +echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic_CXX='-qnocommon' + lt_prog_compiler_wl_CXX='-Wl,' + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + icpc* | ecpc*) + # Intel C++ + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC*) + # Portland Group C++ compiler. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_CXX" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_CXX" >&6 + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + +echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... $ECHO_C" >&6 +if test "${lt_prog_compiler_pic_works_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:11493: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:11497: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_pic_works_CXX=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_CXX" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works_CXX" >&6 + +if test x"$lt_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6 +if test "${lt_prog_compiler_static_works_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_static_works_CXX=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_static_works_CXX=yes + fi + else + lt_prog_compiler_static_works_CXX=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_CXX" >&5 +echo "${ECHO_T}$lt_prog_compiler_static_works_CXX" >&6 + +if test x"$lt_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +fi + + +echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:11597: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:11601: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_CXX" >&6 + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw*) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([^ ]*\) [^ ]*/\1 DATA/;/^I /d;/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' + ;; + kfreebsd*-gnu) + link_all_deplibs_CXX=no + ;; + linux*) + link_all_deplibs_CXX=no + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + +echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 +echo "${ECHO_T}$ld_shlibs_CXX" >&6 +test "$ld_shlibs_CXX" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_CXX=no + else + archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + echo "$as_me:$LINENO: result: $archive_cmds_need_lc_CXX" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_CXX" >&6 + ;; + esac + fi + ;; +esac + +echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + freebsd*) # from 4.6 on + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix3*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || \ + test -n "$runpath_var_CXX" || \ + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +echo "$as_me:$LINENO: result: $hardcode_action_CXX" >&5 +echo "${ECHO_T}$hardcode_action_CXX" >&6 + +if test "$hardcode_action_CXX" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_CXX \ + CC_CXX \ + LD_CXX \ + lt_prog_compiler_wl_CXX \ + lt_prog_compiler_pic_CXX \ + lt_prog_compiler_static_CXX \ + lt_prog_compiler_no_builtin_flag_CXX \ + export_dynamic_flag_spec_CXX \ + thread_safe_flag_spec_CXX \ + whole_archive_flag_spec_CXX \ + enable_shared_with_static_runtimes_CXX \ + old_archive_cmds_CXX \ + old_archive_from_new_cmds_CXX \ + predep_objects_CXX \ + postdep_objects_CXX \ + predeps_CXX \ + postdeps_CXX \ + compiler_lib_search_path_CXX \ + archive_cmds_CXX \ + archive_expsym_cmds_CXX \ + postinstall_cmds_CXX \ + postuninstall_cmds_CXX \ + old_archive_from_expsyms_cmds_CXX \ + allow_undefined_flag_CXX \ + no_undefined_flag_CXX \ + export_symbols_cmds_CXX \ + hardcode_libdir_flag_spec_CXX \ + hardcode_libdir_flag_spec_ld_CXX \ + hardcode_libdir_separator_CXX \ + hardcode_automatic_CXX \ + module_cmds_CXX \ + module_expsym_cmds_CXX \ + lt_cv_prog_compiler_c_o_CXX \ + exclude_expsyms_CXX \ + include_expsyms_CXX; do + + case $var in + old_archive_cmds_CXX | \ + old_archive_from_new_cmds_CXX | \ + archive_cmds_CXX | \ + archive_expsym_cmds_CXX | \ + module_cmds_CXX | \ + module_expsym_cmds_CXX | \ + old_archive_from_expsyms_cmds_CXX | \ + export_symbols_cmds_CXX | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_CXX + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_CXX + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_CXX +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_CXX + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_CXX + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_CXX + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path_CXX" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld + + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + +ac_ext=f +ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' +ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_f77_compiler_gnu + + +archive_cmds_need_lc_F77=no +allow_undefined_flag_F77= +always_export_symbols_F77=no +archive_expsym_cmds_F77= +export_dynamic_flag_spec_F77= +hardcode_direct_F77=no +hardcode_libdir_flag_spec_F77= +hardcode_libdir_flag_spec_ld_F77= +hardcode_libdir_separator_F77= +hardcode_minus_L_F77=no +hardcode_automatic_F77=no +module_cmds_F77= +module_expsym_cmds_F77= +link_all_deplibs_F77=unknown +old_archive_cmds_F77=$old_archive_cmds +no_undefined_flag_F77= +whole_archive_flag_spec_F77= +enable_shared_with_static_runtimes_F77=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +objext_F77=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code=" subroutine t\n return\n end\n" + +# Code to be used in simple link tests +lt_simple_link_test_code=" program t\n end\n" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${F77-"f77"} +compiler=$CC +compiler_F77=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 +echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $can_build_shared" >&5 +echo "${ECHO_T}$can_build_shared" >&6 + +echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 +echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6 +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +echo "$as_me:$LINENO: result: $enable_shared" >&5 +echo "${ECHO_T}$enable_shared" >&6 + +echo "$as_me:$LINENO: checking whether to build static libraries" >&5 +echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6 +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +echo "$as_me:$LINENO: result: $enable_static" >&5 +echo "${ECHO_T}$enable_static" >&6 + +GCC_F77="$G77" +LD_F77="$LD" + +lt_prog_compiler_wl_F77= +lt_prog_compiler_pic_F77= +lt_prog_compiler_static_F77= + +echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 + + if test "$GCC" = yes; then + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_static_F77='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_F77='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_F77='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_F77='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_F77='-fno-common' + ;; + + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared_F77=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_F77=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_F77='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic_F77='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl_F77='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_F77='-Bstatic' + else + lt_prog_compiler_static_F77='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic_F77='-qnocommon' + lt_prog_compiler_wl_F77='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_F77='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl_F77='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_F77='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static_F77='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl_F77='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static_F77='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + linux*) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-fpic' + lt_prog_compiler_static_F77='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl_F77='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static_F77='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl_F77='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static_F77='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl_F77='-Qoption ld ';; + *) + lt_prog_compiler_wl_F77='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl_F77='-Qoption ld ' + lt_prog_compiler_pic_F77='-PIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic_F77='-Kconform_pic' + lt_prog_compiler_static_F77='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_can_build_shared_F77=no + ;; + + uts4*) + lt_prog_compiler_pic_F77='-pic' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared_F77=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_F77" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_F77" >&6 + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_F77"; then + +echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works... $ECHO_C" >&6 +if test "${lt_prog_compiler_pic_works_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works_F77=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_F77" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:13185: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:13189: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_pic_works_F77=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_F77" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works_F77" >&6 + +if test x"$lt_prog_compiler_pic_works_F77" = xyes; then + case $lt_prog_compiler_pic_F77 in + "" | " "*) ;; + *) lt_prog_compiler_pic_F77=" $lt_prog_compiler_pic_F77" ;; + esac +else + lt_prog_compiler_pic_F77= + lt_prog_compiler_can_build_shared_F77=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_F77= + ;; + *) + lt_prog_compiler_pic_F77="$lt_prog_compiler_pic_F77" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_F77 eval lt_tmp_static_flag=\"$lt_prog_compiler_static_F77\" +echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6 +if test "${lt_prog_compiler_static_works_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_static_works_F77=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_static_works_F77=yes + fi + else + lt_prog_compiler_static_works_F77=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_F77" >&5 +echo "${ECHO_T}$lt_prog_compiler_static_works_F77" >&6 + +if test x"$lt_prog_compiler_static_works_F77" = xyes; then + : +else + lt_prog_compiler_static_F77= +fi + + +echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_c_o_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_F77=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:13289: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:13293: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_F77=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_F77" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_F77" >&6 + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_F77" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 + + runpath_var= + allow_undefined_flag_F77= + enable_shared_with_static_runtimes_F77=no + archive_cmds_F77= + archive_expsym_cmds_F77= + old_archive_From_new_cmds_F77= + old_archive_from_expsyms_cmds_F77= + export_dynamic_flag_spec_F77= + whole_archive_flag_spec_F77= + thread_safe_flag_spec_F77= + hardcode_libdir_flag_spec_F77= + hardcode_libdir_flag_spec_ld_F77= + hardcode_libdir_separator_F77= + hardcode_direct_F77=no + hardcode_minus_L_F77=no + hardcode_shlibpath_var_F77=unsupported + link_all_deplibs_F77=unknown + hardcode_automatic_F77=no + module_cmds_F77= + module_expsym_cmds_F77= + always_export_symbols_F77=no + export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms_F77= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms_F77="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs_F77=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_F77='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_F77='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_F77= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs_F77=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs_F77=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_F77=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_F77='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_F77=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, F77) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_F77='-L$libdir' + allow_undefined_flag_F77=unsupported + always_export_symbols_F77=no + enable_shared_with_static_runtimes_F77=yes + export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_F77=no + fi + ;; + + interix3*) + hardcode_direct_F77=no + hardcode_shlibpath_var_F77=no + hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' + export_dynamic_flag_spec_F77='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_F77='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + archive_cmds_F77='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + archive_expsym_cmds_F77='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + link_all_deplibs_F77=no + else + ld_shlibs_F77=no + fi + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_F77='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs_F77=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_F77=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs_F77=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec_F77='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + ld_shlibs_F77=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds_F77='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_F77=no + fi + ;; + esac + + if test "$ld_shlibs_F77" = no; then + runpath_var= + hardcode_libdir_flag_spec_F77= + export_dynamic_flag_spec_F77= + whole_archive_flag_spec_F77= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag_F77=unsupported + always_export_symbols_F77=yes + archive_expsym_cmds_F77='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L_F77=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct_F77=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_F77='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_F77='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_F77='' + hardcode_direct_F77=yes + hardcode_libdir_separator_F77=':' + link_all_deplibs_F77=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct_F77=yes + else + # We have old collect2 + hardcode_direct_F77=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_F77=yes + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_libdir_separator_F77= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_F77=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_F77='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_f77_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds_F77="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_F77='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_F77="-z nodefs" + archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_f77_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_F77=' ${wl}-bernotok' + allow_undefined_flag_F77=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_F77='$convenience' + archive_cmds_need_lc_F77=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + # see comment about different semantics on the GNU ld section + ld_shlibs_F77=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec_F77=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_F77=' ' + allow_undefined_flag_F77=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds_F77='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds_F77='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds_F77='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path_F77='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes_F77=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag_F77='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag_F77='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc_F77=no + hardcode_direct_F77=no + hardcode_automatic_F77=yes + hardcode_shlibpath_var_F77=unsupported + whole_archive_flag_spec_F77='' + link_all_deplibs_F77=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds_F77='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_F77='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_F77=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_shlibpath_var_F77=no + ;; + + freebsd1*) + ld_shlibs_F77=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes + hardcode_minus_L_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + # GNU/kFreeBSD uses gcc -shared to do shared libraries. + kfreebsd*-gnu) + archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + link_all_deplibs_F77=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds_F77='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds_F77='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_F77=: + hardcode_direct_F77=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + export_dynamic_flag_spec_F77='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_F77=: + + hardcode_direct_F77=yes + export_dynamic_flag_spec_F77='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_F77=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_libdir_flag_spec_ld_F77='+b $libdir' + hardcode_direct_F77=no + hardcode_shlibpath_var_F77=no + ;; + *) + hardcode_direct_F77=yes + export_dynamic_flag_spec_F77='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_F77='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld_F77='-rpath $libdir' + fi + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + link_all_deplibs_F77=yes + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds_F77='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + newsos6) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + hardcode_shlibpath_var_F77=no + ;; + + openbsd*) + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' + export_dynamic_flag_spec_F77='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-R$libdir' + ;; + *) + archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + allow_undefined_flag_F77=unsupported + archive_cmds_F77='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds_F77='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag_F77=' -expect_unresolved \*' + archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag_F77=' -expect_unresolved \*' + archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_F77='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec_F77='-rpath $libdir' + fi + hardcode_libdir_separator_F77=: + ;; + + solaris*) + no_undefined_flag_F77=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_shlibpath_var_F77=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine linker options so we + # cannot just pass the convience library names through + # without $wl, iff we do not link with $LD. + # Luckily, gcc supports the same syntax we need for Sun Studio. + # Supported since Solaris 2.6 (maybe 2.5.1?) + case $wlarc in + '') + whole_archive_flag_spec_F77='-z allextract$convenience -z defaultextract' ;; + *) + whole_archive_flag_spec_F77='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; + esac ;; + esac + link_all_deplibs_F77=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds_F77='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_direct_F77=yes + hardcode_minus_L_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds_F77='$CC -r -o $output$reload_objs' + hardcode_direct_F77=no + ;; + motorola) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var_F77=no + ;; + + sysv4.3*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_F77=no + export_dynamic_flag_spec_F77='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_F77=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs_F77=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) + no_undefined_flag_F77='${wl}-z,text' + archive_cmds_need_lc_F77=no + hardcode_shlibpath_var_F77=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_F77='${wl}-z,text' + allow_undefined_flag_F77='${wl}-z,nodefs' + archive_cmds_need_lc_F77=no + hardcode_shlibpath_var_F77=no + hardcode_libdir_flag_spec_F77='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator_F77=':' + link_all_deplibs_F77=yes + export_dynamic_flag_spec_F77='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_shlibpath_var_F77=no + ;; + + *) + ld_shlibs_F77=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $ld_shlibs_F77" >&5 +echo "${ECHO_T}$ld_shlibs_F77" >&6 +test "$ld_shlibs_F77" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_F77" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_F77=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_F77 in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_F77 + pic_flag=$lt_prog_compiler_pic_F77 + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_F77 + allow_undefined_flag_F77= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_F77=no + else + archive_cmds_need_lc_F77=yes + fi + allow_undefined_flag_F77=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + echo "$as_me:$LINENO: result: $archive_cmds_need_lc_F77" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_F77" >&6 + ;; + esac + fi + ;; +esac + +echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + freebsd*) # from 4.6 on + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix3*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 +hardcode_action_F77= +if test -n "$hardcode_libdir_flag_spec_F77" || \ + test -n "$runpath_var_F77" || \ + test "X$hardcode_automatic_F77" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_F77" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, F77)" != no && + test "$hardcode_minus_L_F77" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_F77=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_F77=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_F77=unsupported +fi +echo "$as_me:$LINENO: result: $hardcode_action_F77" >&5 +echo "${ECHO_T}$hardcode_action_F77" >&6 + +if test "$hardcode_action_F77" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_F77 \ + CC_F77 \ + LD_F77 \ + lt_prog_compiler_wl_F77 \ + lt_prog_compiler_pic_F77 \ + lt_prog_compiler_static_F77 \ + lt_prog_compiler_no_builtin_flag_F77 \ + export_dynamic_flag_spec_F77 \ + thread_safe_flag_spec_F77 \ + whole_archive_flag_spec_F77 \ + enable_shared_with_static_runtimes_F77 \ + old_archive_cmds_F77 \ + old_archive_from_new_cmds_F77 \ + predep_objects_F77 \ + postdep_objects_F77 \ + predeps_F77 \ + postdeps_F77 \ + compiler_lib_search_path_F77 \ + archive_cmds_F77 \ + archive_expsym_cmds_F77 \ + postinstall_cmds_F77 \ + postuninstall_cmds_F77 \ + old_archive_from_expsyms_cmds_F77 \ + allow_undefined_flag_F77 \ + no_undefined_flag_F77 \ + export_symbols_cmds_F77 \ + hardcode_libdir_flag_spec_F77 \ + hardcode_libdir_flag_spec_ld_F77 \ + hardcode_libdir_separator_F77 \ + hardcode_automatic_F77 \ + module_cmds_F77 \ + module_expsym_cmds_F77 \ + lt_cv_prog_compiler_c_o_F77 \ + exclude_expsyms_F77 \ + include_expsyms_F77; do + + case $var in + old_archive_cmds_F77 | \ + old_archive_from_new_cmds_F77 | \ + archive_cmds_F77 | \ + archive_expsym_cmds_F77 | \ + module_cmds_F77 | \ + module_expsym_cmds_F77 | \ + old_archive_from_expsyms_cmds_F77 | \ + export_symbols_cmds_F77 | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_F77 + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_F77 + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_F77 + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_F77 + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_F77 + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_F77 + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_F77 +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_F77 + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_F77 + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_F77 + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_F77 + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_F77 + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_F77 + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_F77 +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_F77 + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_F77 + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_F77 +archive_expsym_cmds=$lt_archive_expsym_cmds_F77 +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_F77 +module_expsym_cmds=$lt_module_expsym_cmds_F77 + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_F77 + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_F77 + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_F77 + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_F77 + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_F77 + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_F77 + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_F77 + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_F77 + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_F77 + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_F77 + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_F77 + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_F77 + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_F77 + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_F77 + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_F77 + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_F77 + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path_F77" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_F77 + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_F77 + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_F77 + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_F77 + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + + + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +objext_GCJ=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[] argv) {}; }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${GCJ-"gcj"} +compiler=$CC +compiler_GCJ=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +archive_cmds_need_lc_GCJ=no + +old_archive_cmds_GCJ=$old_archive_cmds + + +lt_prog_compiler_no_builtin_flag_GCJ= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag_GCJ=' -fno-builtin' + + +echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:15512: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:15516: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6 + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag_GCJ="$lt_prog_compiler_no_builtin_flag_GCJ -fno-rtti -fno-exceptions" +else + : +fi + +fi + +lt_prog_compiler_wl_GCJ= +lt_prog_compiler_pic_GCJ= +lt_prog_compiler_static_GCJ= + +echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 + + if test "$GCC" = yes; then + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_static_GCJ='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_GCJ='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_GCJ='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_GCJ='-fno-common' + ;; + + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared_GCJ=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_GCJ=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_GCJ='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic_GCJ='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl_GCJ='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_GCJ='-Bstatic' + else + lt_prog_compiler_static_GCJ='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic_GCJ='-qnocommon' + lt_prog_compiler_wl_GCJ='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl_GCJ='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_GCJ='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static_GCJ='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl_GCJ='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + linux*) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-fpic' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl_GCJ='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl_GCJ='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl_GCJ='-Qoption ld ';; + *) + lt_prog_compiler_wl_GCJ='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl_GCJ='-Qoption ld ' + lt_prog_compiler_pic_GCJ='-PIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic_GCJ='-Kconform_pic' + lt_prog_compiler_static_GCJ='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_can_build_shared_GCJ=no + ;; + + uts4*) + lt_prog_compiler_pic_GCJ='-pic' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared_GCJ=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_GCJ" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_GCJ" >&6 + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_GCJ"; then + +echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works... $ECHO_C" >&6 +if test "${lt_prog_compiler_pic_works_GCJ+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works_GCJ=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_GCJ" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:15780: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:15784: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_pic_works_GCJ=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_GCJ" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works_GCJ" >&6 + +if test x"$lt_prog_compiler_pic_works_GCJ" = xyes; then + case $lt_prog_compiler_pic_GCJ in + "" | " "*) ;; + *) lt_prog_compiler_pic_GCJ=" $lt_prog_compiler_pic_GCJ" ;; + esac +else + lt_prog_compiler_pic_GCJ= + lt_prog_compiler_can_build_shared_GCJ=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_GCJ= + ;; + *) + lt_prog_compiler_pic_GCJ="$lt_prog_compiler_pic_GCJ" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_GCJ eval lt_tmp_static_flag=\"$lt_prog_compiler_static_GCJ\" +echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6 +if test "${lt_prog_compiler_static_works_GCJ+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_static_works_GCJ=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_static_works_GCJ=yes + fi + else + lt_prog_compiler_static_works_GCJ=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_GCJ" >&5 +echo "${ECHO_T}$lt_prog_compiler_static_works_GCJ" >&6 + +if test x"$lt_prog_compiler_static_works_GCJ" = xyes; then + : +else + lt_prog_compiler_static_GCJ= +fi + + +echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_c_o_GCJ+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_GCJ=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:15884: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:15888: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_GCJ=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_GCJ" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_GCJ" >&6 + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_GCJ" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 + + runpath_var= + allow_undefined_flag_GCJ= + enable_shared_with_static_runtimes_GCJ=no + archive_cmds_GCJ= + archive_expsym_cmds_GCJ= + old_archive_From_new_cmds_GCJ= + old_archive_from_expsyms_cmds_GCJ= + export_dynamic_flag_spec_GCJ= + whole_archive_flag_spec_GCJ= + thread_safe_flag_spec_GCJ= + hardcode_libdir_flag_spec_GCJ= + hardcode_libdir_flag_spec_ld_GCJ= + hardcode_libdir_separator_GCJ= + hardcode_direct_GCJ=no + hardcode_minus_L_GCJ=no + hardcode_shlibpath_var_GCJ=unsupported + link_all_deplibs_GCJ=unknown + hardcode_automatic_GCJ=no + module_cmds_GCJ= + module_expsym_cmds_GCJ= + always_export_symbols_GCJ=no + export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms_GCJ= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms_GCJ="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs_GCJ=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_GCJ='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_GCJ='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_GCJ="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_GCJ= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs_GCJ=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs_GCJ=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_GCJ=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_GCJ='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, GCJ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_GCJ='-L$libdir' + allow_undefined_flag_GCJ=unsupported + always_export_symbols_GCJ=no + enable_shared_with_static_runtimes_GCJ=yes + export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_GCJ='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_GCJ=no + fi + ;; + + interix3*) + hardcode_direct_GCJ=no + hardcode_shlibpath_var_GCJ=no + hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' + export_dynamic_flag_spec_GCJ='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_GCJ='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_GCJ='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec_GCJ='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec_GCJ='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + archive_cmds_GCJ='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + archive_expsym_cmds_GCJ='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + link_all_deplibs_GCJ=no + else + ld_shlibs_GCJ=no + fi + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_GCJ='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs_GCJ=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs_GCJ=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec_GCJ='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds_GCJ='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + esac + + if test "$ld_shlibs_GCJ" = no; then + runpath_var= + hardcode_libdir_flag_spec_GCJ= + export_dynamic_flag_spec_GCJ= + whole_archive_flag_spec_GCJ= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag_GCJ=unsupported + always_export_symbols_GCJ=yes + archive_expsym_cmds_GCJ='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L_GCJ=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct_GCJ=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_GCJ='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_GCJ='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_GCJ='' + hardcode_direct_GCJ=yes + hardcode_libdir_separator_GCJ=':' + link_all_deplibs_GCJ=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct_GCJ=yes + else + # We have old collect2 + hardcode_direct_GCJ=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_GCJ=yes + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_libdir_separator_GCJ= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_GCJ=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_GCJ='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds_GCJ="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_GCJ='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_GCJ="-z nodefs" + archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_GCJ=' ${wl}-bernotok' + allow_undefined_flag_GCJ=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_GCJ='$convenience' + archive_cmds_need_lc_GCJ=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + # see comment about different semantics on the GNU ld section + ld_shlibs_GCJ=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec_GCJ=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_GCJ=' ' + allow_undefined_flag_GCJ=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds_GCJ='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds_GCJ='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds_GCJ='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path_GCJ='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes_GCJ=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag_GCJ='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag_GCJ='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc_GCJ=no + hardcode_direct_GCJ=no + hardcode_automatic_GCJ=yes + hardcode_shlibpath_var_GCJ=unsupported + whole_archive_flag_spec_GCJ='' + link_all_deplibs_GCJ=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds_GCJ='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_GCJ='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_GCJ=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_shlibpath_var_GCJ=no + ;; + + freebsd1*) + ld_shlibs_GCJ=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes + hardcode_minus_L_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + # GNU/kFreeBSD uses gcc -shared to do shared libraries. + kfreebsd*-gnu) + archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + link_all_deplibs_GCJ=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds_GCJ='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds_GCJ='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + hardcode_direct_GCJ=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + + hardcode_direct_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_libdir_flag_spec_ld_GCJ='+b $libdir' + hardcode_direct_GCJ=no + hardcode_shlibpath_var_GCJ=no + ;; + *) + hardcode_direct_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_GCJ='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld_GCJ='-rpath $libdir' + fi + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + link_all_deplibs_GCJ=yes + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds_GCJ='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + newsos6) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + hardcode_shlibpath_var_GCJ=no + ;; + + openbsd*) + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' + export_dynamic_flag_spec_GCJ='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + ;; + *) + archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + allow_undefined_flag_GCJ=unsupported + archive_cmds_GCJ='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds_GCJ='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag_GCJ=' -expect_unresolved \*' + archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag_GCJ=' -expect_unresolved \*' + archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_GCJ='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec_GCJ='-rpath $libdir' + fi + hardcode_libdir_separator_GCJ=: + ;; + + solaris*) + no_undefined_flag_GCJ=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_shlibpath_var_GCJ=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine linker options so we + # cannot just pass the convience library names through + # without $wl, iff we do not link with $LD. + # Luckily, gcc supports the same syntax we need for Sun Studio. + # Supported since Solaris 2.6 (maybe 2.5.1?) + case $wlarc in + '') + whole_archive_flag_spec_GCJ='-z allextract$convenience -z defaultextract' ;; + *) + whole_archive_flag_spec_GCJ='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; + esac ;; + esac + link_all_deplibs_GCJ=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds_GCJ='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_direct_GCJ=yes + hardcode_minus_L_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds_GCJ='$CC -r -o $output$reload_objs' + hardcode_direct_GCJ=no + ;; + motorola) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var_GCJ=no + ;; + + sysv4.3*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_GCJ=no + export_dynamic_flag_spec_GCJ='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_GCJ=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs_GCJ=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) + no_undefined_flag_GCJ='${wl}-z,text' + archive_cmds_need_lc_GCJ=no + hardcode_shlibpath_var_GCJ=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_GCJ='${wl}-z,text' + allow_undefined_flag_GCJ='${wl}-z,nodefs' + archive_cmds_need_lc_GCJ=no + hardcode_shlibpath_var_GCJ=no + hardcode_libdir_flag_spec_GCJ='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator_GCJ=':' + link_all_deplibs_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_shlibpath_var_GCJ=no + ;; + + *) + ld_shlibs_GCJ=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $ld_shlibs_GCJ" >&5 +echo "${ECHO_T}$ld_shlibs_GCJ" >&6 +test "$ld_shlibs_GCJ" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_GCJ" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_GCJ=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_GCJ in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_GCJ + pic_flag=$lt_prog_compiler_pic_GCJ + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_GCJ + allow_undefined_flag_GCJ= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_GCJ=no + else + archive_cmds_need_lc_GCJ=yes + fi + allow_undefined_flag_GCJ=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + echo "$as_me:$LINENO: result: $archive_cmds_need_lc_GCJ" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_GCJ" >&6 + ;; + esac + fi + ;; +esac + +echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + freebsd*) # from 4.6 on + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix3*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 +hardcode_action_GCJ= +if test -n "$hardcode_libdir_flag_spec_GCJ" || \ + test -n "$runpath_var_GCJ" || \ + test "X$hardcode_automatic_GCJ" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_GCJ" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, GCJ)" != no && + test "$hardcode_minus_L_GCJ" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_GCJ=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_GCJ=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_GCJ=unsupported +fi +echo "$as_me:$LINENO: result: $hardcode_action_GCJ" >&5 +echo "${ECHO_T}$hardcode_action_GCJ" >&6 + +if test "$hardcode_action_GCJ" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_GCJ \ + CC_GCJ \ + LD_GCJ \ + lt_prog_compiler_wl_GCJ \ + lt_prog_compiler_pic_GCJ \ + lt_prog_compiler_static_GCJ \ + lt_prog_compiler_no_builtin_flag_GCJ \ + export_dynamic_flag_spec_GCJ \ + thread_safe_flag_spec_GCJ \ + whole_archive_flag_spec_GCJ \ + enable_shared_with_static_runtimes_GCJ \ + old_archive_cmds_GCJ \ + old_archive_from_new_cmds_GCJ \ + predep_objects_GCJ \ + postdep_objects_GCJ \ + predeps_GCJ \ + postdeps_GCJ \ + compiler_lib_search_path_GCJ \ + archive_cmds_GCJ \ + archive_expsym_cmds_GCJ \ + postinstall_cmds_GCJ \ + postuninstall_cmds_GCJ \ + old_archive_from_expsyms_cmds_GCJ \ + allow_undefined_flag_GCJ \ + no_undefined_flag_GCJ \ + export_symbols_cmds_GCJ \ + hardcode_libdir_flag_spec_GCJ \ + hardcode_libdir_flag_spec_ld_GCJ \ + hardcode_libdir_separator_GCJ \ + hardcode_automatic_GCJ \ + module_cmds_GCJ \ + module_expsym_cmds_GCJ \ + lt_cv_prog_compiler_c_o_GCJ \ + exclude_expsyms_GCJ \ + include_expsyms_GCJ; do + + case $var in + old_archive_cmds_GCJ | \ + old_archive_from_new_cmds_GCJ | \ + archive_cmds_GCJ | \ + archive_expsym_cmds_GCJ | \ + module_cmds_GCJ | \ + module_expsym_cmds_GCJ | \ + old_archive_from_expsyms_cmds_GCJ | \ + export_symbols_cmds_GCJ | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_GCJ + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_GCJ + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_GCJ + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_GCJ + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_GCJ + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_GCJ + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_GCJ +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GCJ + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_GCJ + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_GCJ + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_GCJ + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_GCJ + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_GCJ + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_GCJ +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_GCJ + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_GCJ + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_GCJ +archive_expsym_cmds=$lt_archive_expsym_cmds_GCJ +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_GCJ +module_expsym_cmds=$lt_module_expsym_cmds_GCJ + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_GCJ + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_GCJ + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_GCJ + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_GCJ + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_GCJ + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_GCJ + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_GCJ + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_GCJ + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_GCJ + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_GCJ + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_GCJ + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_GCJ + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_GCJ + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_GCJ + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_GCJ + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_GCJ + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path_GCJ" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_GCJ + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_GCJ + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_GCJ + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_GCJ + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + else + tagname="" + fi + ;; + + RC) + + + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +objext_RC=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${RC-"windres"} +compiler=$CC +compiler_RC=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + +lt_cv_prog_compiler_c_o_RC=yes + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_RC \ + CC_RC \ + LD_RC \ + lt_prog_compiler_wl_RC \ + lt_prog_compiler_pic_RC \ + lt_prog_compiler_static_RC \ + lt_prog_compiler_no_builtin_flag_RC \ + export_dynamic_flag_spec_RC \ + thread_safe_flag_spec_RC \ + whole_archive_flag_spec_RC \ + enable_shared_with_static_runtimes_RC \ + old_archive_cmds_RC \ + old_archive_from_new_cmds_RC \ + predep_objects_RC \ + postdep_objects_RC \ + predeps_RC \ + postdeps_RC \ + compiler_lib_search_path_RC \ + archive_cmds_RC \ + archive_expsym_cmds_RC \ + postinstall_cmds_RC \ + postuninstall_cmds_RC \ + old_archive_from_expsyms_cmds_RC \ + allow_undefined_flag_RC \ + no_undefined_flag_RC \ + export_symbols_cmds_RC \ + hardcode_libdir_flag_spec_RC \ + hardcode_libdir_flag_spec_ld_RC \ + hardcode_libdir_separator_RC \ + hardcode_automatic_RC \ + module_cmds_RC \ + module_expsym_cmds_RC \ + lt_cv_prog_compiler_c_o_RC \ + exclude_expsyms_RC \ + include_expsyms_RC; do + + case $var in + old_archive_cmds_RC | \ + old_archive_from_new_cmds_RC | \ + archive_cmds_RC | \ + archive_expsym_cmds_RC | \ + module_cmds_RC | \ + module_expsym_cmds_RC | \ + old_archive_from_expsyms_cmds_RC | \ + export_symbols_cmds_RC | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_RC + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_RC + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_RC + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_RC + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_RC + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_RC + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_RC +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_RC + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_RC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_RC + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_RC + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_RC + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_RC + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_RC +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_RC + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_RC + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_RC +archive_expsym_cmds=$lt_archive_expsym_cmds_RC +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_RC +module_expsym_cmds=$lt_module_expsym_cmds_RC + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_RC + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_RC + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_RC + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_RC + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_RC + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_RC + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_RC + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_RC + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_RC + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_RC + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_RC + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_RC + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_RC + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_RC + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_RC + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_RC + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path_RC" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_RC + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_RC + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_RC + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_RC + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + ;; + + *) + { { echo "$as_me:$LINENO: error: Unsupported tag name: $tagname" >&5 +echo "$as_me: error: Unsupported tag name: $tagname" >&2;} + { (exit 1); exit 1; }; } + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + { { echo "$as_me:$LINENO: error: unable to update list of available tagged configurations." >&5 +echo "$as_me: error: unable to update list of available tagged configurations." >&2;} + { (exit 1); exit 1; }; } + fi +fi + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + +# Prevent multiple expansion + + + + + + + + + + + + + + + + + + + + + + +# Check whether --with-valgrind or --without-valgrind was given. +if test "${with_valgrind+set}" = set; then + withval="$with_valgrind" + +fi; + +if test "$with_valgrind" != "" && test "$with_valgrind" != "no"; then + +cat >>confdefs.h <<\_ACEOF +#define INCLUDE_VALGRIND 1 +_ACEOF + + if test -d $with_valgrind; then + CPPFLAGS="$CPPLFAGS -I$with_valgrind/include" + fi +fi + +# Check whether --enable-libcheck or --disable-libcheck was given. +if test "${enable_libcheck+set}" = set; then + enableval="$enable_libcheck" + if test "$enableval" = "no"; then + disable_libcheck=yes + fi + +fi; + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CC" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for long" >&5 +echo $ECHO_N "checking for long... $ECHO_C" >&6 +if test "${ac_cv_type_long+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((long *) 0) + return 0; +if (sizeof (long)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_long=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_long=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5 +echo "${ECHO_T}$ac_cv_type_long" >&6 + +echo "$as_me:$LINENO: checking size of long" >&5 +echo $ECHO_N "checking size of long... $ECHO_C" >&6 +if test "${ac_cv_sizeof_long+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$ac_cv_type_long" = yes; then + # The cast to unsigned long works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects + # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo= ac_hi= +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr '(' $ac_mid ')' + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_long=$ac_lo;; +'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (long), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } ;; +esac +else + if test "$cross_compiling" = yes; then + { { echo "$as_me:$LINENO: error: internal error: not reached in cross-compile" >&5 +echo "$as_me: error: internal error: not reached in cross-compile" >&2;} + { (exit 1); exit 1; }; } +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +long longval () { return (long) (sizeof (long)); } +unsigned long ulongval () { return (long) (sizeof (long)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + exit (1); + if (((long) (sizeof (long))) < 0) + { + long i = longval (); + if (i != ((long) (sizeof (long)))) + exit (1); + fprintf (f, "%ld\n", i); + } + else + { + unsigned long i = ulongval (); + if (i != ((long) (sizeof (long)))) + exit (1); + fprintf (f, "%lu\n", i); + } + exit (ferror (f) || fclose (f) != 0); + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_long=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (long), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +rm -f conftest.val +else + ac_cv_sizeof_long=0 +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5 +echo "${ECHO_T}$ac_cv_sizeof_long" >&6 +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG $ac_cv_sizeof_long +_ACEOF + + + +if test "$disable_libcheck" != "yes"; then + +echo "$as_me:$LINENO: checking for ibv_get_device_list in -libverbs" >&5 +echo $ECHO_N "checking for ibv_get_device_list in -libverbs... $ECHO_C" >&6 +if test "${ac_cv_lib_ibverbs_ibv_get_device_list+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-libverbs $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char ibv_get_device_list (); +int +main () +{ +ibv_get_device_list (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_ibverbs_ibv_get_device_list=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_ibverbs_ibv_get_device_list=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_ibverbs_ibv_get_device_list" >&5 +echo "${ECHO_T}$ac_cv_lib_ibverbs_ibv_get_device_list" >&6 +if test $ac_cv_lib_ibverbs_ibv_get_device_list = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBIBVERBS 1 +_ACEOF + + LIBS="-libverbs $LIBS" + +else + { { echo "$as_me:$LINENO: error: ibv_get_device_list() not found. libibcm requires libibverbs." >&5 +echo "$as_me: error: ibv_get_device_list() not found. libibcm requires libibverbs." >&2;} + { (exit 1); exit 1; }; } +fi + +#Need librdmacm for cmpost test program. +#AC_CHECK_LIB(rdmacm, rdma_create_id, [], +# AC_MSG_ERROR([rdma_create_id() not found. ucmpost requires librdmacm.])) +fi + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +if test "$disable_libcheck" != "yes"; then +if test "${ac_cv_header_infiniband_verbs_h+set}" = set; then + echo "$as_me:$LINENO: checking for infiniband/verbs.h" >&5 +echo $ECHO_N "checking for infiniband/verbs.h... $ECHO_C" >&6 +if test "${ac_cv_header_infiniband_verbs_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_infiniband_verbs_h" >&5 +echo "${ECHO_T}$ac_cv_header_infiniband_verbs_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking infiniband/verbs.h usability" >&5 +echo $ECHO_N "checking infiniband/verbs.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking infiniband/verbs.h presence" >&5 +echo $ECHO_N "checking infiniband/verbs.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------- ## +## Report this to general@lists@openfabrics.org ## +## -------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for infiniband/verbs.h" >&5 +echo $ECHO_N "checking for infiniband/verbs.h... $ECHO_C" >&6 +if test "${ac_cv_header_infiniband_verbs_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_infiniband_verbs_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_infiniband_verbs_h" >&5 +echo "${ECHO_T}$ac_cv_header_infiniband_verbs_h" >&6 + +fi +if test $ac_cv_header_infiniband_verbs_h = yes; then + : +else + { { echo "$as_me:$LINENO: error: not found. Is libibverbs installed?" >&5 +echo "$as_me: error: not found. Is libibverbs installed?" >&2;} + { (exit 1); exit 1; }; } +fi + + +if test "${ac_cv_header_infiniband_marshall_h+set}" = set; then + echo "$as_me:$LINENO: checking for infiniband/marshall.h" >&5 +echo $ECHO_N "checking for infiniband/marshall.h... $ECHO_C" >&6 +if test "${ac_cv_header_infiniband_marshall_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_infiniband_marshall_h" >&5 +echo "${ECHO_T}$ac_cv_header_infiniband_marshall_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking infiniband/marshall.h usability" >&5 +echo $ECHO_N "checking infiniband/marshall.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking infiniband/marshall.h presence" >&5 +echo $ECHO_N "checking infiniband/marshall.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: infiniband/marshall.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: infiniband/marshall.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/marshall.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: infiniband/marshall.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: infiniband/marshall.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: infiniband/marshall.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/marshall.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: infiniband/marshall.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/marshall.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: infiniband/marshall.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/marshall.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: infiniband/marshall.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/marshall.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: infiniband/marshall.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/marshall.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: infiniband/marshall.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------- ## +## Report this to general@lists@openfabrics.org ## +## -------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for infiniband/marshall.h" >&5 +echo $ECHO_N "checking for infiniband/marshall.h... $ECHO_C" >&6 +if test "${ac_cv_header_infiniband_marshall_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_infiniband_marshall_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_infiniband_marshall_h" >&5 +echo "${ECHO_T}$ac_cv_header_infiniband_marshall_h" >&6 + +fi +if test $ac_cv_header_infiniband_marshall_h = yes; then + : +else + { { echo "$as_me:$LINENO: error: not found. Is libibverbs installed?" >&5 +echo "$as_me: error: not found. Is libibverbs installed?" >&2;} + { (exit 1); exit 1; }; } +fi + + + +if test "$with_valgrind" != "" && test "$with_valgrind" != "no"; then +if test "${ac_cv_header_valgrind_memcheck_h+set}" = set; then + echo "$as_me:$LINENO: checking for valgrind/memcheck.h" >&5 +echo $ECHO_N "checking for valgrind/memcheck.h... $ECHO_C" >&6 +if test "${ac_cv_header_valgrind_memcheck_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_valgrind_memcheck_h" >&5 +echo "${ECHO_T}$ac_cv_header_valgrind_memcheck_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking valgrind/memcheck.h usability" >&5 +echo $ECHO_N "checking valgrind/memcheck.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking valgrind/memcheck.h presence" >&5 +echo $ECHO_N "checking valgrind/memcheck.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------- ## +## Report this to general@lists@openfabrics.org ## +## -------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for valgrind/memcheck.h" >&5 +echo $ECHO_N "checking for valgrind/memcheck.h... $ECHO_C" >&6 +if test "${ac_cv_header_valgrind_memcheck_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_valgrind_memcheck_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_valgrind_memcheck_h" >&5 +echo "${ECHO_T}$ac_cv_header_valgrind_memcheck_h" >&6 + +fi +if test $ac_cv_header_valgrind_memcheck_h = yes; then + : +else + { { echo "$as_me:$LINENO: error: valgrind requested but not found." >&5 +echo "$as_me: error: valgrind requested but not found." >&2;} + { (exit 1); exit 1; }; } +fi + + +fi + +fi + +echo "$as_me:$LINENO: checking whether ld accepts --version-script" >&5 +echo $ECHO_N "checking whether ld accepts --version-script... $ECHO_C" >&6 +if test "${ac_cv_version_script+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then + ac_cv_version_script=yes + else + ac_cv_version_script=no + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_version_script" >&5 +echo "${ECHO_T}$ac_cv_version_script" >&6 + + + +if test "$ac_cv_version_script" = "yes"; then + HAVE_LD_VERSION_SCRIPT_TRUE= + HAVE_LD_VERSION_SCRIPT_FALSE='#' +else + HAVE_LD_VERSION_SCRIPT_TRUE='#' + HAVE_LD_VERSION_SCRIPT_FALSE= +fi + + + ac_config_files="$ac_config_files Makefile libibcm.spec" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${HAVE_LD_VERSION_SCRIPT_TRUE}" && test -z "${HAVE_LD_VERSION_SCRIPT_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"HAVE_LD_VERSION_SCRIPT\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"HAVE_LD_VERSION_SCRIPT\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by libibcm $as_me 1.0.5, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +libibcm config.status 1.0.5 +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS section. +# + +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "libibcm.spec" ) CONFIG_FILES="$CONFIG_FILES libibcm.spec" ;; + "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@CYGPATH_W@,$CYGPATH_W,;t t +s,@PACKAGE@,$PACKAGE,;t t +s,@VERSION@,$VERSION,;t t +s,@ACLOCAL@,$ACLOCAL,;t t +s,@AUTOCONF@,$AUTOCONF,;t t +s,@AUTOMAKE@,$AUTOMAKE,;t t +s,@AUTOHEADER@,$AUTOHEADER,;t t +s,@MAKEINFO@,$MAKEINFO,;t t +s,@install_sh@,$install_sh,;t t +s,@STRIP@,$STRIP,;t t +s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t +s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t +s,@mkdir_p@,$mkdir_p,;t t +s,@AWK@,$AWK,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@am__leading_dot@,$am__leading_dot,;t t +s,@AMTAR@,$AMTAR,;t t +s,@am__tar@,$am__tar,;t t +s,@am__untar@,$am__untar,;t t +s,@build@,$build,;t t +s,@build_cpu@,$build_cpu,;t t +s,@build_vendor@,$build_vendor,;t t +s,@build_os@,$build_os,;t t +s,@host@,$host,;t t +s,@host_cpu@,$host_cpu,;t t +s,@host_vendor@,$host_vendor,;t t +s,@host_os@,$host_os,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@DEPDIR@,$DEPDIR,;t t +s,@am__include@,$am__include,;t t +s,@am__quote@,$am__quote,;t t +s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t +s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t +s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t +s,@CCDEPMODE@,$CCDEPMODE,;t t +s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t +s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t +s,@EGREP@,$EGREP,;t t +s,@LN_S@,$LN_S,;t t +s,@ECHO@,$ECHO,;t t +s,@AR@,$AR,;t t +s,@ac_ct_AR@,$ac_ct_AR,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@CPP@,$CPP,;t t +s,@CXX@,$CXX,;t t +s,@CXXFLAGS@,$CXXFLAGS,;t t +s,@ac_ct_CXX@,$ac_ct_CXX,;t t +s,@CXXDEPMODE@,$CXXDEPMODE,;t t +s,@am__fastdepCXX_TRUE@,$am__fastdepCXX_TRUE,;t t +s,@am__fastdepCXX_FALSE@,$am__fastdepCXX_FALSE,;t t +s,@CXXCPP@,$CXXCPP,;t t +s,@F77@,$F77,;t t +s,@FFLAGS@,$FFLAGS,;t t +s,@ac_ct_F77@,$ac_ct_F77,;t t +s,@LIBTOOL@,$LIBTOOL,;t t +s,@HAVE_LD_VERSION_SCRIPT_TRUE@,$HAVE_LD_VERSION_SCRIPT_TRUE,;t t +s,@HAVE_LD_VERSION_SCRIPT_FALSE@,$HAVE_LD_VERSION_SCRIPT_FALSE,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +# Compute $ac_file's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $ac_file | $ac_file:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $ac_file" >`(dirname $ac_file) 2>/dev/null || +$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X$ac_file : 'X\(//\)[^/]' \| \ + X$ac_file : 'X\(//\)$' \| \ + X$ac_file : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X$ac_file | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'`/stamp-h$_am_stamp_count +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_COMMANDS section. +# +for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue + ac_dest=`echo "$ac_file" | sed 's,:.*,,'` + ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_dir=`(dirname "$ac_dest") 2>/dev/null || +$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_dest" : 'X\(//\)[^/]' \| \ + X"$ac_dest" : 'X\(//\)$' \| \ + X"$ac_dest" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_dest" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 +echo "$as_me: executing $ac_dest commands" >&6;} + case $ac_dest in + depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`(dirname "$mf") 2>/dev/null || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`(dirname "$file") 2>/dev/null || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p $dirpart/$fdir + else + as_dir=$dirpart/$fdir + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5 +echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;} + { (exit 1); exit 1; }; }; } + + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + esac +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/contrib/ofed/libibcm/configure.in b/contrib/ofed/libibcm/configure.in new file mode 100644 index 000000000000..271296940914 --- /dev/null +++ b/contrib/ofed/libibcm/configure.in @@ -0,0 +1,71 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(libibcm, 1.0.5, general@lists@openfabrics.org) +AC_CONFIG_SRCDIR([src/cm.c]) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(libibcm, 1.0.5) + +AM_PROG_LIBTOOL + +AC_ARG_WITH([valgrind], + AC_HELP_STRING([--with-valgrind], + [Enable valgrind annotations - default NO])) + +if test "$with_valgrind" != "" && test "$with_valgrind" != "no"; then + AC_DEFINE([INCLUDE_VALGRIND], 1, + [Define to 1 to enable valgrind annotations]) + if test -d $with_valgrind; then + CPPFLAGS="$CPPLFAGS -I$with_valgrind/include" + fi +fi + +AC_ARG_ENABLE(libcheck, [ --disable-libcheck do not test for presence of ib libraries], +[ if test "$enableval" = "no"; then + disable_libcheck=yes + fi +]) + +dnl Checks for programs +AC_PROG_CC + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_CHECK_SIZEOF(long) + +dnl Checks for libraries +if test "$disable_libcheck" != "yes"; then +AC_CHECK_LIB(ibverbs, ibv_get_device_list, [], + AC_MSG_ERROR([ibv_get_device_list() not found. libibcm requires libibverbs.])) +#Need librdmacm for cmpost test program. +#AC_CHECK_LIB(rdmacm, rdma_create_id, [], +# AC_MSG_ERROR([rdma_create_id() not found. ucmpost requires librdmacm.])) +fi + +dnl Checks for header files. +AC_HEADER_STDC +if test "$disable_libcheck" != "yes"; then +AC_CHECK_HEADER(infiniband/verbs.h, [], + AC_MSG_ERROR([ not found. Is libibverbs installed?])) +AC_CHECK_HEADER(infiniband/marshall.h, [], + AC_MSG_ERROR([ not found. Is libibverbs installed?])) + +if test "$with_valgrind" != "" && test "$with_valgrind" != "no"; then +AC_CHECK_HEADER(valgrind/memcheck.h, [], + AC_MSG_ERROR([valgrind requested but not found.])) +fi + +fi + +AC_CACHE_CHECK(whether ld accepts --version-script, ac_cv_version_script, + if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then + ac_cv_version_script=yes + else + ac_cv_version_script=no + fi) + +AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$ac_cv_version_script" = "yes") + +AC_CONFIG_FILES([Makefile libibcm.spec]) +AC_OUTPUT diff --git a/contrib/ofed/libibcm/include/infiniband/cm.h b/contrib/ofed/libibcm/include/infiniband/cm.h new file mode 100644 index 000000000000..7fd2e485fc7e --- /dev/null +++ b/contrib/ofed/libibcm/include/infiniband/cm.h @@ -0,0 +1,586 @@ +/* + * Copyright (c) 2004-2006 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ +#if !defined(CM_H) +#define CM_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum ib_cm_event_type { + IB_CM_REQ_ERROR, + IB_CM_REQ_RECEIVED, + IB_CM_REP_ERROR, + IB_CM_REP_RECEIVED, + IB_CM_RTU_RECEIVED, + IB_CM_USER_ESTABLISHED, + IB_CM_DREQ_ERROR, + IB_CM_DREQ_RECEIVED, + IB_CM_DREP_RECEIVED, + IB_CM_TIMEWAIT_EXIT, + IB_CM_MRA_RECEIVED, + IB_CM_REJ_RECEIVED, + IB_CM_LAP_ERROR, + IB_CM_LAP_RECEIVED, + IB_CM_APR_RECEIVED, + IB_CM_SIDR_REQ_ERROR, + IB_CM_SIDR_REQ_RECEIVED, + IB_CM_SIDR_REP_RECEIVED +}; + +enum ib_cm_data_size { + IB_CM_REQ_PRIVATE_DATA_SIZE = 92, + IB_CM_MRA_PRIVATE_DATA_SIZE = 222, + IB_CM_REJ_PRIVATE_DATA_SIZE = 148, + IB_CM_REP_PRIVATE_DATA_SIZE = 196, + IB_CM_RTU_PRIVATE_DATA_SIZE = 224, + IB_CM_DREQ_PRIVATE_DATA_SIZE = 220, + IB_CM_DREP_PRIVATE_DATA_SIZE = 224, + IB_CM_REJ_ARI_LENGTH = 72, + IB_CM_LAP_PRIVATE_DATA_SIZE = 168, + IB_CM_APR_PRIVATE_DATA_SIZE = 148, + IB_CM_APR_INFO_LENGTH = 72, + IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE = 216, + IB_CM_SIDR_REP_PRIVATE_DATA_SIZE = 136, + IB_CM_SIDR_REP_INFO_LENGTH = 72 +}; + +struct ib_cm_device { + struct ibv_context *device_context; + int fd; +}; + +struct ib_cm_id { + void *context; + struct ib_cm_device *device; + uint32_t handle; +}; + +struct ib_cm_req_event_param { + struct ib_cm_id *listen_id; + uint8_t port; + + struct ibv_sa_path_rec *primary_path; + struct ibv_sa_path_rec *alternate_path; + + uint64_t remote_ca_guid; /* netork-byte order */ + uint32_t remote_qkey; + uint32_t remote_qpn; + enum ibv_qp_type qp_type; + + uint32_t starting_psn; + uint8_t responder_resources; + uint8_t initiator_depth; + unsigned int local_cm_response_timeout:5; + unsigned int flow_control:1; + unsigned int remote_cm_response_timeout:5; + unsigned int retry_count:3; + unsigned int rnr_retry_count:3; + unsigned int srq:1; +}; + +struct ib_cm_rep_event_param { + uint64_t remote_ca_guid; /* network-byte order */ + uint32_t remote_qkey; + uint32_t remote_qpn; + uint32_t starting_psn; + uint8_t responder_resources; + uint8_t initiator_depth; + unsigned int target_ack_delay:5; + unsigned int failover_accepted:2; + unsigned int flow_control:1; + unsigned int rnr_retry_count:3; + unsigned int srq:1; +}; + +enum ib_cm_rej_reason { + IB_CM_REJ_NO_QP = 1, + IB_CM_REJ_NO_EEC = 2, + IB_CM_REJ_NO_RESOURCES = 3, + IB_CM_REJ_TIMEOUT = 4, + IB_CM_REJ_UNSUPPORTED = 5, + IB_CM_REJ_INVALID_COMM_ID = 6, + IB_CM_REJ_INVALID_COMM_INSTANCE = 7, + IB_CM_REJ_INVALID_SERVICE_ID = 8, + IB_CM_REJ_INVALID_TRANSPORT_TYPE = 9, + IB_CM_REJ_STALE_CONN = 10, + IB_CM_REJ_RDC_NOT_EXIST = 11, + IB_CM_REJ_INVALID_GID = 12, + IB_CM_REJ_INVALID_LID = 13, + IB_CM_REJ_INVALID_SL = 14, + IB_CM_REJ_INVALID_TRAFFIC_CLASS = 15, + IB_CM_REJ_INVALID_HOP_LIMIT = 16, + IB_CM_REJ_INVALID_PACKET_RATE = 17, + IB_CM_REJ_INVALID_ALT_GID = 18, + IB_CM_REJ_INVALID_ALT_LID = 19, + IB_CM_REJ_INVALID_ALT_SL = 20, + IB_CM_REJ_INVALID_ALT_TRAFFIC_CLASS = 21, + IB_CM_REJ_INVALID_ALT_HOP_LIMIT = 22, + IB_CM_REJ_INVALID_ALT_PACKET_RATE = 23, + IB_CM_REJ_PORT_CM_REDIRECT = 24, + IB_CM_REJ_PORT_REDIRECT = 25, + IB_CM_REJ_INVALID_MTU = 26, + IB_CM_REJ_INSUFFICIENT_RESP_RESOURCES = 27, + IB_CM_REJ_CONSUMER_DEFINED = 28, + IB_CM_REJ_INVALID_RNR_RETRY = 29, + IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID = 30, + IB_CM_REJ_INVALID_CLASS_VERSION = 31, + IB_CM_REJ_INVALID_FLOW_LABEL = 32, + IB_CM_REJ_INVALID_ALT_FLOW_LABEL = 33 +}; + +struct ib_cm_rej_event_param { + enum ib_cm_rej_reason reason; + void *ari; + uint8_t ari_length; +}; + +struct ib_cm_mra_event_param { + uint8_t service_timeout; +}; + +struct ib_cm_lap_event_param { + struct ibv_sa_path_rec *alternate_path; +}; + +enum ib_cm_apr_status { + IB_CM_APR_SUCCESS, + IB_CM_APR_INVALID_COMM_ID, + IB_CM_APR_UNSUPPORTED, + IB_CM_APR_REJECT, + IB_CM_APR_REDIRECT, + IB_CM_APR_IS_CURRENT, + IB_CM_APR_INVALID_QPN_EECN, + IB_CM_APR_INVALID_LID, + IB_CM_APR_INVALID_GID, + IB_CM_APR_INVALID_FLOW_LABEL, + IB_CM_APR_INVALID_TCLASS, + IB_CM_APR_INVALID_HOP_LIMIT, + IB_CM_APR_INVALID_PACKET_RATE, + IB_CM_APR_INVALID_SL +}; + +struct ib_cm_apr_event_param { + enum ib_cm_apr_status ap_status; + void *apr_info; + uint8_t info_len; +}; + +struct ib_cm_sidr_req_event_param { + struct ib_cm_id *listen_id; + uint8_t port; + uint16_t pkey; +}; + +enum ib_cm_sidr_status { + IB_SIDR_SUCCESS, + IB_SIDR_UNSUPPORTED, + IB_SIDR_REJECT, + IB_SIDR_NO_QP, + IB_SIDR_REDIRECT, + IB_SIDR_UNSUPPORTED_VERSION +}; + +struct ib_cm_sidr_rep_event_param { + enum ib_cm_sidr_status status; + uint32_t qkey; + uint32_t qpn; + void *info; + uint8_t info_len; +}; + +struct ib_cm_event { + struct ib_cm_id *cm_id; + enum ib_cm_event_type event; + union { + struct ib_cm_req_event_param req_rcvd; + struct ib_cm_rep_event_param rep_rcvd; + /* No data for RTU received events. */ + struct ib_cm_rej_event_param rej_rcvd; + struct ib_cm_mra_event_param mra_rcvd; + struct ib_cm_lap_event_param lap_rcvd; + struct ib_cm_apr_event_param apr_rcvd; + /* No data for DREQ/DREP received events. */ + struct ib_cm_sidr_req_event_param sidr_req_rcvd; + struct ib_cm_sidr_rep_event_param sidr_rep_rcvd; + enum ibv_wc_status send_status; + } param; + + void *private_data; +}; + +/** + * ib_cm_get_event - Retrieves the next pending communications event, + * if no event is pending waits for an event. + * @device: CM device to retrieve the event. + * @event: Allocated information about the next communication event. + * Event should be freed using ib_cm_ack_event() + * + * IB_CM_REQ_RECEIVED and IB_CM_SIDR_REQ_RECEIVED communication events + * generated as a result of listen requests result in the allocation of a + * new @cm_id. + * Clients are responsible for destroying the new @cm_id. For peer-to-peer + * IB_CM_REQ_RECEIVED and all other events, the returned @cm_id corresponds + * to a user's existing communication identifier. + */ +int ib_cm_get_event(struct ib_cm_device *device, struct ib_cm_event **event); + +/** + * ib_cm_ack_event - Free a communications event. + * @event: Event to be released. + * + * All events which are allocated by ib_cm_get_event() must be released, + * there should be a one-to-one correspondence between successful gets + * and puts. + */ +int ib_cm_ack_event(struct ib_cm_event *event); + +/** + * ib_cm_open_device - Returns the device the CM uses to submit requests + * and retrieve events, corresponding to the specified verbs device. + * + * The CM device contains the file descriptor that the CM uses to + * communicate with the kernel CM component. The primary use of the + * file descriptor is to test for CM readiness events. When the CM + * becomes ready to READ there is a pending event ready, and a subsequent + * call to ib_cm_get_event will not block. + * Note: The user should not read or write directly to the CM file + * descriptor, it will likely result in an error or unexpected + * results. + */ +struct ib_cm_device* ib_cm_open_device(struct ibv_context *device_context); + +/** + * ib_cm_close_device - Close a CM device. + * @device: Device to close. + */ +void ib_cm_close_device(struct ib_cm_device *device); + +/** + * ib_cm_create_id - Allocate a communication identifier. + * + * Communication identifiers are used to track connection states, service + * ID resolution requests, and listen requests. + */ +int ib_cm_create_id(struct ib_cm_device *device, + struct ib_cm_id **cm_id, void *context); + +/** + * ib_cm_destroy_id - Destroy a connection identifier. + * @cm_id: Connection identifier to destroy. + */ +int ib_cm_destroy_id(struct ib_cm_id *cm_id); + +struct ib_cm_attr_param { + uint64_t service_id; /* network-byte order */ + uint64_t service_mask; /* network-byte order */ + uint32_t local_id; + uint32_t remote_id; +}; + +/** + * ib_cm_attr_id - Get connection identifier attributes. + * @cm_id: Connection identifier to retrieve attributes. + * @param: Destination of retreived parameters. + * + * Not all parameters are valid during all connection states. + */ +int ib_cm_attr_id(struct ib_cm_id *cm_id, + struct ib_cm_attr_param *param); + +#define IB_CM_ASSIGN_SERVICE_ID_MASK __constant_cpu_to_be64(0xFF00000000000000ULL) +#define IB_CM_ASSIGN_SERVICE_ID __constant_cpu_to_be64(0x0200000000000000ULL) + +/** + * ib_cm_listen - Initiates listening on the specified service ID for + * connection and service ID resolution requests. + * @cm_id: Connection identifier associated with the listen request. + * @service_id: Service identifier matched against incoming connection + * and service ID resolution requests. The service ID should be specified + * network-byte order. + * @service_mask: Mask applied to service ID used to listen across a + * range of service IDs. If set to 0, the service ID is matched + * exactly. + */ +int ib_cm_listen(struct ib_cm_id *cm_id, + uint64_t service_id, + uint64_t service_mask); + +struct ib_cm_req_param { + struct ibv_sa_path_rec *primary_path; + struct ibv_sa_path_rec *alternate_path; + uint64_t service_id; /* network-byte order */ + uint32_t qp_num; + enum ibv_qp_type qp_type; + uint32_t starting_psn; + void *private_data; + uint8_t private_data_len; + uint8_t peer_to_peer; + uint8_t responder_resources; + uint8_t initiator_depth; + uint8_t remote_cm_response_timeout; + uint8_t flow_control; + uint8_t local_cm_response_timeout; + uint8_t retry_count; + uint8_t rnr_retry_count; + uint8_t max_cm_retries; + uint8_t srq; +}; + +/** + * ib_cm_send_req - Sends a connection request to the remote node. + * @cm_id: Connection identifier that will be associated with the + * connection request. + * @param: Connection request information needed to establish the + * connection. + */ +int ib_cm_send_req(struct ib_cm_id *cm_id, + struct ib_cm_req_param *param); + +struct ib_cm_rep_param { + uint32_t qp_num; + uint32_t starting_psn; + void *private_data; + uint8_t private_data_len; + uint8_t responder_resources; + uint8_t initiator_depth; + uint8_t target_ack_delay; + uint8_t failover_accepted; + uint8_t flow_control; + uint8_t rnr_retry_count; + uint8_t srq; +}; + +/** + * ib_cm_send_rep - Sends a connection reply in response to a connection + * request. + * @cm_id: Connection identifier that will be associated with the + * connection request. + * @param: Connection reply information needed to establish the + * connection. + */ +int ib_cm_send_rep(struct ib_cm_id *cm_id, + struct ib_cm_rep_param *param); + +/** + * ib_cm_send_rtu - Sends a connection ready to use message in response + * to a connection reply message. + * @cm_id: Connection identifier associated with the connection request. + * @private_data: Optional user-defined private data sent with the + * ready to use message. + * @private_data_len: Size of the private data buffer, in bytes. + */ +int ib_cm_send_rtu(struct ib_cm_id *cm_id, + void *private_data, + uint8_t private_data_len); + +/** + * ib_cm_send_dreq - Sends a disconnection request for an existing + * connection. + * @cm_id: Connection identifier associated with the connection being + * released. + * @private_data: Optional user-defined private data sent with the + * disconnection request message. + * @private_data_len: Size of the private data buffer, in bytes. + */ +int ib_cm_send_dreq(struct ib_cm_id *cm_id, + void *private_data, + uint8_t private_data_len); + +/** + * ib_cm_send_drep - Sends a disconnection reply to a disconnection request. + * @cm_id: Connection identifier associated with the connection being + * released. + * @private_data: Optional user-defined private data sent with the + * disconnection reply message. + * @private_data_len: Size of the private data buffer, in bytes. + */ +int ib_cm_send_drep(struct ib_cm_id *cm_id, + void *private_data, + uint8_t private_data_len); + +/** + * ib_cm_notify - Notifies the CM of an event reported to the consumer. + * @cm_id: Connection identifier to transition to established. + * @event: Type of event. + * + * This routine should be invoked by users to notify the CM of relevant + * communication events. Events that should be reported to the CM and + * when to report them are: + * + * IBV_EVENT_COMM_EST - Used when a message is received on a connected + * QP before an RTU has been received. + * IBV_EVENT_PATH_MIG - Notifies the CM that the connection has failed over + * to the alternate path. + */ +int ib_cm_notify(struct ib_cm_id *cm_id, enum ibv_event_type event); + +/** + * ib_cm_send_rej - Sends a connection rejection message to the + * remote node. + * @cm_id: Connection identifier associated with the connection being + * rejected. + * @reason: Reason for the connection request rejection. + * @ari: Optional additional rejection information. + * @ari_length: Size of the additional rejection information, in bytes. + * @private_data: Optional user-defined private data sent with the + * rejection message. + * @private_data_len: Size of the private data buffer, in bytes. + */ +int ib_cm_send_rej(struct ib_cm_id *cm_id, + enum ib_cm_rej_reason reason, + void *ari, + uint8_t ari_length, + void *private_data, + uint8_t private_data_len); + +/** + * ib_cm_send_mra - Sends a message receipt acknowledgement to a connection + * message. + * @cm_id: Connection identifier associated with the connection message. + * @service_timeout: The maximum time required for the sender to reply to + * to the connection message. + * @private_data: Optional user-defined private data sent with the + * message receipt acknowledgement. + * @private_data_len: Size of the private data buffer, in bytes. + */ +int ib_cm_send_mra(struct ib_cm_id *cm_id, + uint8_t service_timeout, + void *private_data, + uint8_t private_data_len); + +/** + * ib_cm_send_lap - Sends a load alternate path request. + * @cm_id: Connection identifier associated with the load alternate path + * message. + * @alternate_path: A path record that identifies the alternate path to + * load. + * @private_data: Optional user-defined private data sent with the + * load alternate path message. + * @private_data_len: Size of the private data buffer, in bytes. + */ +int ib_cm_send_lap(struct ib_cm_id *cm_id, + struct ibv_sa_path_rec *alternate_path, + void *private_data, + uint8_t private_data_len); + +/** + * ib_cm_init_qp_attr - Initializes the QP attributes for use in transitioning + * to a specified QP state. + * @cm_id: Communication identifier associated with the QP attributes to + * initialize. + * @qp_attr: On input, specifies the desired QP state. On output, the + * mandatory and desired optional attributes will be set in order to + * modify the QP to the specified state. + * @qp_attr_mask: The QP attribute mask that may be used to transition the + * QP to the specified state. + * + * Users must set the @qp_attr->qp_state to the desired QP state. This call + * will set all required attributes for the given transition, along with + * known optional attributes. Users may override the attributes returned from + * this call before calling ib_modify_qp. + */ +int ib_cm_init_qp_attr(struct ib_cm_id *cm_id, + struct ibv_qp_attr *qp_attr, + int *qp_attr_mask); + +/** + * ib_cm_send_apr - Sends an alternate path response message in response to + * a load alternate path request. + * @cm_id: Connection identifier associated with the alternate path response. + * @status: Reply status sent with the alternate path response. + * @info: Optional additional information sent with the alternate path + * response. + * @info_length: Size of the additional information, in bytes. + * @private_data: Optional user-defined private data sent with the + * alternate path response message. + * @private_data_len: Size of the private data buffer, in bytes. + */ +int ib_cm_send_apr(struct ib_cm_id *cm_id, + enum ib_cm_apr_status status, + void *info, + uint8_t info_length, + void *private_data, + uint8_t private_data_len); + +struct ib_cm_sidr_req_param { + struct ibv_sa_path_rec *path; + uint64_t service_id; /* network-byte order */ + int timeout_ms; + void *private_data; + uint8_t private_data_len; + uint8_t max_cm_retries; +}; + +/** + * ib_cm_send_sidr_req - Sends a service ID resolution request to the + * remote node. + * @cm_id: Communication identifier that will be associated with the + * service ID resolution request. + * @param: Service ID resolution request information. + */ +int ib_cm_send_sidr_req(struct ib_cm_id *cm_id, + struct ib_cm_sidr_req_param *param); + +struct ib_cm_sidr_rep_param { + uint32_t qp_num; + uint32_t qkey; + enum ib_cm_sidr_status status; + void *info; + uint8_t info_length; + void *private_data; + uint8_t private_data_len; +}; + +/** + * ib_cm_send_sidr_rep - Sends a service ID resolution reply to the + * remote node. + * @cm_id: Communication identifier associated with the received service ID + * resolution request. + * @param: Service ID resolution reply information. + */ +int ib_cm_send_sidr_rep(struct ib_cm_id *cm_id, + struct ib_cm_sidr_rep_param *param); + +#ifdef __cplusplus +} +#endif + +#endif /* CM_H */ diff --git a/contrib/ofed/libibcm/include/infiniband/cm_abi.h b/contrib/ofed/libibcm/include/infiniband/cm_abi.h new file mode 100644 index 000000000000..d998b6972669 --- /dev/null +++ b/contrib/ofed/libibcm/include/infiniband/cm_abi.h @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#ifndef CM_ABI_H +#define CM_ABI_H + +#include +#include +#include + +/* + * This file must be kept in sync with the kernel's version of ib_user_cm.h + */ + +#define IB_USER_CM_MIN_ABI_VERSION 4 +#define IB_USER_CM_MAX_ABI_VERSION 5 + +enum { + IB_USER_CM_CMD_CREATE_ID, + IB_USER_CM_CMD_DESTROY_ID, + IB_USER_CM_CMD_ATTR_ID, + + IB_USER_CM_CMD_LISTEN, + IB_USER_CM_CMD_NOTIFY, + IB_USER_CM_CMD_ESTABLISH = IB_USER_CM_CMD_NOTIFY, /* ABI 4 support */ + + IB_USER_CM_CMD_SEND_REQ, + IB_USER_CM_CMD_SEND_REP, + IB_USER_CM_CMD_SEND_RTU, + IB_USER_CM_CMD_SEND_DREQ, + IB_USER_CM_CMD_SEND_DREP, + IB_USER_CM_CMD_SEND_REJ, + IB_USER_CM_CMD_SEND_MRA, + IB_USER_CM_CMD_SEND_LAP, + IB_USER_CM_CMD_SEND_APR, + IB_USER_CM_CMD_SEND_SIDR_REQ, + IB_USER_CM_CMD_SEND_SIDR_REP, + + IB_USER_CM_CMD_EVENT, + IB_USER_CM_CMD_INIT_QP_ATTR, +}; +/* + * command ABI structures. + */ +struct cm_abi_cmd_hdr { + __u32 cmd; + __u16 in; + __u16 out; +}; + +struct cm_abi_create_id { + __u64 uid; + __u64 response; +}; + +struct cm_abi_create_id_resp { + __u32 id; +}; + +struct cm_abi_destroy_id { + __u64 response; + __u32 id; + __u32 reserved; +}; + +struct cm_abi_destroy_id_resp { + __u32 events_reported; +}; + +struct cm_abi_attr_id { + __u64 response; + __u32 id; + __u32 reserved; +}; + +struct cm_abi_attr_id_resp { + __u64 service_id; + __u64 service_mask; + __u32 local_id; + __u32 remote_id; +}; + +struct cm_abi_init_qp_attr { + __u64 response; + __u32 id; + __u32 qp_state; +}; + +struct cm_abi_listen { + __u64 service_id; + __u64 service_mask; + __u32 id; + __u32 reserved; +}; + +struct cm_abi_establish { /* ABI 4 support */ + __u32 id; +}; + +struct cm_abi_notify { + __u32 id; + __u32 event; +}; + +struct cm_abi_private_data { + __u64 data; + __u32 id; + __u8 len; + __u8 reserved[3]; +}; + +struct cm_abi_req { + __u32 id; + __u32 qpn; + __u32 qp_type; + __u32 psn; + __u64 sid; + __u64 data; + __u64 primary_path; + __u64 alternate_path; + __u8 len; + __u8 peer_to_peer; + __u8 responder_resources; + __u8 initiator_depth; + __u8 remote_cm_response_timeout; + __u8 flow_control; + __u8 local_cm_response_timeout; + __u8 retry_count; + __u8 rnr_retry_count; + __u8 max_cm_retries; + __u8 srq; + __u8 reserved[5]; +}; + +struct cm_abi_rep { + __u64 uid; + __u64 data; + __u32 id; + __u32 qpn; + __u32 psn; + __u8 len; + __u8 responder_resources; + __u8 initiator_depth; + __u8 target_ack_delay; + __u8 failover_accepted; + __u8 flow_control; + __u8 rnr_retry_count; + __u8 srq; + __u8 reserved[4]; +}; + +struct cm_abi_info { + __u32 id; + __u32 status; + __u64 info; + __u64 data; + __u8 info_len; + __u8 data_len; + __u8 reserved[6]; +}; + +struct cm_abi_mra { + __u64 data; + __u32 id; + __u8 len; + __u8 timeout; + __u8 reserved[2]; +}; + +struct cm_abi_lap { + __u64 path; + __u64 data; + __u32 id; + __u8 len; + __u8 reserved[3]; +}; + +struct cm_abi_sidr_req { + __u32 id; + __u32 timeout; + __u64 sid; + __u64 data; + __u64 path; + __u16 pkey; + __u8 len; + __u8 max_cm_retries; + __u8 reserved[4]; +}; + +struct cm_abi_sidr_rep { + __u32 id; + __u32 qpn; + __u32 qkey; + __u32 status; + __u64 info; + __u64 data; + __u8 info_len; + __u8 data_len; + __u8 reserved[6]; +}; +/* + * event notification ABI structures. + */ +struct cm_abi_event_get { + __u64 response; + __u64 data; + __u64 info; + __u8 data_len; + __u8 info_len; + __u8 reserved[6]; +}; + +struct cm_abi_req_event_resp { + struct ibv_kern_path_rec primary_path; + struct ibv_kern_path_rec alternate_path; + __u64 remote_ca_guid; + __u32 remote_qkey; + __u32 remote_qpn; + __u32 qp_type; + __u32 starting_psn; + __u8 responder_resources; + __u8 initiator_depth; + __u8 local_cm_response_timeout; + __u8 flow_control; + __u8 remote_cm_response_timeout; + __u8 retry_count; + __u8 rnr_retry_count; + __u8 srq; + __u8 port; + __u8 reserved[7]; +}; + +struct cm_abi_rep_event_resp { + __u64 remote_ca_guid; + __u32 remote_qkey; + __u32 remote_qpn; + __u32 starting_psn; + __u8 responder_resources; + __u8 initiator_depth; + __u8 target_ack_delay; + __u8 failover_accepted; + __u8 flow_control; + __u8 rnr_retry_count; + __u8 srq; + __u8 reserved[5]; +}; + +struct cm_abi_rej_event_resp { + __u32 reason; + /* ari in cm_abi_event_get info field. */ +}; + +struct cm_abi_mra_event_resp { + __u8 timeout; + __u8 reserved[3]; +}; + +struct cm_abi_lap_event_resp { + struct ibv_kern_path_rec path; +}; + +struct cm_abi_apr_event_resp { + __u32 status; + /* apr info in cm_abi_event_get info field. */ +}; + +struct cm_abi_sidr_req_event_resp { + __u16 pkey; + __u8 port; + __u8 reserved; +}; + +struct cm_abi_sidr_rep_event_resp { + __u32 status; + __u32 qkey; + __u32 qpn; + /* info in cm_abi_event_get info field. */ +}; + +#define CM_ABI_PRES_DATA 0x01 +#define CM_ABI_PRES_INFO 0x02 +#define CM_ABI_PRES_PRIMARY 0x04 +#define CM_ABI_PRES_ALTERNATE 0x08 + +struct cm_abi_event_resp { + __u64 uid; + __u32 id; + __u32 event; + __u32 present; + __u32 reserved; + union { + struct cm_abi_req_event_resp req_resp; + struct cm_abi_rep_event_resp rep_resp; + struct cm_abi_rej_event_resp rej_resp; + struct cm_abi_mra_event_resp mra_resp; + struct cm_abi_lap_event_resp lap_resp; + struct cm_abi_apr_event_resp apr_resp; + + struct cm_abi_sidr_req_event_resp sidr_req_resp; + struct cm_abi_sidr_rep_event_resp sidr_rep_resp; + + __u32 send_status; + } u; +}; + +#endif /* CM_ABI_H */ diff --git a/contrib/ofed/libibcm/libibcm.spec b/contrib/ofed/libibcm/libibcm.spec new file mode 100644 index 000000000000..6d893ebf9d5e --- /dev/null +++ b/contrib/ofed/libibcm/libibcm.spec @@ -0,0 +1,53 @@ +%define ver 1.0.5 + +Name: libibcm +Version: 1.0.5 +Release: 1%{?dist} +Summary: Userspace InfiniBand Communication Manager. + +Group: System Environment/Libraries +License: GPL/BSD +Url: http://www.openfabrics.org/ +Source: http://www.openfabrics.org/downloads/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +%description +libibcm provides a userspace InfiniBand Communication Managment library. + +%package devel +Summary: Development files for the libibcm library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} %{_includedir}/infiniband/verbs.h + +%description devel +Development files for the libibcm library. + +%prep +%setup -q -n %{name}-%{ver} + +%build +%configure +make %{?_smp_mflags} + +%install +rm -rf $RPM_BUILD_ROOT +%makeinstall +# remove unpackaged files from the buildroot +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig + +%files +%defattr(-,root,root,-) +%{_libdir}/libibcm*.so.* +%doc AUTHORS COPYING ChangeLog README + +%files devel +%defattr(-,root,root,-) +%{_libdir}/lib*.so +%{_libdir}/*.a +%{_includedir}/* diff --git a/contrib/ofed/libibcm/libibcm.spec.in b/contrib/ofed/libibcm/libibcm.spec.in new file mode 100644 index 000000000000..ce082726e7dc --- /dev/null +++ b/contrib/ofed/libibcm/libibcm.spec.in @@ -0,0 +1,53 @@ +%define ver @VERSION@ + +Name: libibcm +Version: 1.0.5 +Release: 1%{?dist} +Summary: Userspace InfiniBand Communication Manager. + +Group: System Environment/Libraries +License: GPL/BSD +Url: http://www.openfabrics.org/ +Source: http://www.openfabrics.org/downloads/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +%description +libibcm provides a userspace InfiniBand Communication Managment library. + +%package devel +Summary: Development files for the libibcm library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} %{_includedir}/infiniband/verbs.h + +%description devel +Development files for the libibcm library. + +%prep +%setup -q -n %{name}-%{ver} + +%build +%configure +make %{?_smp_mflags} + +%install +rm -rf $RPM_BUILD_ROOT +%makeinstall +# remove unpackaged files from the buildroot +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig + +%files +%defattr(-,root,root,-) +%{_libdir}/libibcm*.so.* +%doc AUTHORS COPYING ChangeLog README + +%files devel +%defattr(-,root,root,-) +%{_libdir}/lib*.so +%{_libdir}/*.a +%{_includedir}/* diff --git a/contrib/ofed/libibcm/src/cm.c b/contrib/ofed/libibcm/src/cm.c new file mode 100644 index 000000000000..1de3d8d9079c --- /dev/null +++ b/contrib/ofed/libibcm/src/cm.c @@ -0,0 +1,1047 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef INCLUDE_VALGRIND +# include +# ifndef VALGRIND_MAKE_MEM_DEFINED +# warning "Valgrind requested, but VALGRIND_MAKE_MEM_DEFINED undefined" +# endif +#endif + +#ifndef VALGRIND_MAKE_MEM_DEFINED +# define VALGRIND_MAKE_MEM_DEFINED(addr,len) +#endif + +#define PFX "libibcm: " + +static int abi_ver; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + +enum { + IB_UCM_MAX_DEVICES = 32 +}; + +static inline int ERR(int err) +{ + errno = err; + return -1; +} + + +#define CM_CREATE_MSG_CMD_RESP(msg, cmd, resp, type, size) \ +do { \ + struct cm_abi_cmd_hdr *hdr; \ + \ + size = sizeof(*hdr) + sizeof(*cmd); \ + msg = alloca(size); \ + if (!msg) \ + return ERR(ENOMEM); \ + hdr = msg; \ + cmd = msg + sizeof(*hdr); \ + hdr->cmd = type; \ + hdr->in = sizeof(*cmd); \ + hdr->out = sizeof(*resp); \ + memset(cmd, 0, sizeof(*cmd)); \ + resp = alloca(sizeof(*resp)); \ + if (!resp) \ + return ERR(ENOMEM); \ + cmd->response = (uintptr_t)resp;\ +} while (0) + +#define CM_CREATE_MSG_CMD(msg, cmd, type, size) \ +do { \ + struct cm_abi_cmd_hdr *hdr; \ + \ + size = sizeof(*hdr) + sizeof(*cmd); \ + msg = alloca(size); \ + if (!msg) \ + return ERR(ENOMEM); \ + hdr = msg; \ + cmd = msg + sizeof(*hdr); \ + hdr->cmd = type; \ + hdr->in = sizeof(*cmd); \ + hdr->out = 0; \ + memset(cmd, 0, sizeof(*cmd)); \ +} while (0) + +struct cm_id_private { + struct ib_cm_id id; + int events_completed; + pthread_cond_t cond; + pthread_mutex_t mut; +}; + +#define container_of(ptr, type, field) \ + ((type *) ((void *)ptr - offsetof(type, field))) + +static int check_abi_version(void) +{ + char value[8]; + + if (ibv_read_sysfs_file(ibv_get_sysfs_path(), + "class/infiniband_cm/abi_version", + value, sizeof value) < 0) { + fprintf(stderr, PFX "couldn't read ABI version\n"); + return 0; + } + + abi_ver = strtol(value, NULL, 10); + if (abi_ver < IB_USER_CM_MIN_ABI_VERSION || + abi_ver > IB_USER_CM_MAX_ABI_VERSION) { + fprintf(stderr, PFX "kernel ABI version %d " + "doesn't match library version %d.\n", + abi_ver, IB_USER_CM_MAX_ABI_VERSION); + return -1; + } + return 0; +} + +static int ucm_init(void) +{ + int ret = 0; + + pthread_mutex_lock(&mut); + if (!abi_ver) + ret = check_abi_version(); + pthread_mutex_unlock(&mut); + + return ret; +} + +static int ucm_get_dev_index(char *dev_name) +{ + char *dev_path; + char ibdev[IBV_SYSFS_NAME_MAX]; + int i, ret; + + for (i = 0; i < IB_UCM_MAX_DEVICES; i++) { + ret = asprintf(&dev_path, "/sys/class/infiniband_cm/ucm%d", i); + if (ret < 0) + return -1; + + ret = ibv_read_sysfs_file(dev_path, "ibdev", ibdev, sizeof ibdev); + if (ret < 0) + continue; + + if (!strcmp(dev_name, ibdev)) { + free(dev_path); + return i; + } + + free(dev_path); + } + return -1; +} + +struct ib_cm_device* ib_cm_open_device(struct ibv_context *device_context) +{ + struct ib_cm_device *dev; + char *dev_path; + int index, ret; + + if (ucm_init()) + return NULL; + + index = ucm_get_dev_index(device_context->device->name); + if (index < 0) + return NULL; + + dev = malloc(sizeof *dev); + if (!dev) + return NULL; + + dev->device_context = device_context; + + ret = asprintf(&dev_path, "/dev/infiniband/ucm%d", index); + if (ret < 0) + goto err1; + + dev->fd = open(dev_path, O_RDWR); + if (dev->fd < 0) + goto err2; + + free(dev_path); + return dev; + +err2: + free(dev_path); +err1: + free(dev); + return NULL; +} + +void ib_cm_close_device(struct ib_cm_device *device) +{ + close(device->fd); + free(device); +} + +static void ib_cm_free_id(struct cm_id_private *cm_id_priv) +{ + pthread_cond_destroy(&cm_id_priv->cond); + pthread_mutex_destroy(&cm_id_priv->mut); + free(cm_id_priv); +} + +static struct cm_id_private *ib_cm_alloc_id(struct ib_cm_device *device, + void *context) +{ + struct cm_id_private *cm_id_priv; + + cm_id_priv = malloc(sizeof *cm_id_priv); + if (!cm_id_priv) + return NULL; + + memset(cm_id_priv, 0, sizeof *cm_id_priv); + cm_id_priv->id.device = device; + cm_id_priv->id.context = context; + pthread_mutex_init(&cm_id_priv->mut, NULL); + if (pthread_cond_init(&cm_id_priv->cond, NULL)) + goto err; + + return cm_id_priv; + +err: ib_cm_free_id(cm_id_priv); + return NULL; +} + +int ib_cm_create_id(struct ib_cm_device *device, + struct ib_cm_id **cm_id, void *context) +{ + struct cm_abi_create_id_resp *resp; + struct cm_abi_create_id *cmd; + struct cm_id_private *cm_id_priv; + void *msg; + int result; + int size; + + cm_id_priv = ib_cm_alloc_id(device, context); + if (!cm_id_priv) + return ERR(ENOMEM); + + CM_CREATE_MSG_CMD_RESP(msg, cmd, resp, IB_USER_CM_CMD_CREATE_ID, size); + cmd->uid = (uintptr_t) cm_id_priv; + + result = write(device->fd, msg, size); + if (result != size) + goto err; + + VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp); + + cm_id_priv->id.handle = resp->id; + *cm_id = &cm_id_priv->id; + return 0; + +err: ib_cm_free_id(cm_id_priv); + return result; +} + +int ib_cm_destroy_id(struct ib_cm_id *cm_id) +{ + struct cm_abi_destroy_id_resp *resp; + struct cm_abi_destroy_id *cmd; + struct cm_id_private *cm_id_priv; + void *msg; + int result; + int size; + + CM_CREATE_MSG_CMD_RESP(msg, cmd, resp, IB_USER_CM_CMD_DESTROY_ID, size); + cmd->id = cm_id->handle; + + result = write(cm_id->device->fd, msg, size); + if (result != size) + return (result >= 0) ? ERR(ECONNREFUSED) : -1; + + VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp); + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + + pthread_mutex_lock(&cm_id_priv->mut); + while (cm_id_priv->events_completed < resp->events_reported) + pthread_cond_wait(&cm_id_priv->cond, &cm_id_priv->mut); + pthread_mutex_unlock(&cm_id_priv->mut); + + ib_cm_free_id(cm_id_priv); + return 0; +} + +int ib_cm_attr_id(struct ib_cm_id *cm_id, struct ib_cm_attr_param *param) +{ + struct cm_abi_attr_id_resp *resp; + struct cm_abi_attr_id *cmd; + void *msg; + int result; + int size; + + if (!param) + return ERR(EINVAL); + + CM_CREATE_MSG_CMD_RESP(msg, cmd, resp, IB_USER_CM_CMD_ATTR_ID, size); + cmd->id = cm_id->handle; + + result = write(cm_id->device->fd, msg, size); + if (result != size) + return (result >= 0) ? ERR(ECONNREFUSED) : -1; + + VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp); + + param->service_id = resp->service_id; + param->service_mask = resp->service_mask; + param->local_id = resp->local_id; + param->remote_id = resp->remote_id; + return 0; +} + +int ib_cm_init_qp_attr(struct ib_cm_id *cm_id, + struct ibv_qp_attr *qp_attr, + int *qp_attr_mask) +{ + struct ibv_kern_qp_attr *resp; + struct cm_abi_init_qp_attr *cmd; + void *msg; + int result; + int size; + + if (!qp_attr || !qp_attr_mask) + return ERR(EINVAL); + + CM_CREATE_MSG_CMD_RESP(msg, cmd, resp, IB_USER_CM_CMD_INIT_QP_ATTR, size); + cmd->id = cm_id->handle; + cmd->qp_state = qp_attr->qp_state; + + result = write(cm_id->device->fd, msg, size); + if (result != size) + return (result >= 0) ? ERR(ECONNREFUSED) : result; + + VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp); + + *qp_attr_mask = resp->qp_attr_mask; + ibv_copy_qp_attr_from_kern(qp_attr, resp); + + return 0; +} + +int ib_cm_listen(struct ib_cm_id *cm_id, + uint64_t service_id, + uint64_t service_mask) +{ + struct cm_abi_listen *cmd; + void *msg; + int result; + int size; + + CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_LISTEN, size); + cmd->id = cm_id->handle; + cmd->service_id = service_id; + cmd->service_mask = service_mask; + + result = write(cm_id->device->fd, msg, size); + if (result != size) + return (result >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +int ib_cm_send_req(struct ib_cm_id *cm_id, struct ib_cm_req_param *param) +{ + struct ibv_kern_path_rec *p_path; + struct ibv_kern_path_rec *a_path; + struct cm_abi_req *cmd; + void *msg; + int result; + int size; + + if (!param) + return ERR(EINVAL); + + CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_REQ, size); + cmd->id = cm_id->handle; + cmd->qpn = param->qp_num; + cmd->qp_type = param->qp_type; + cmd->psn = param->starting_psn; + cmd->sid = param->service_id; + cmd->peer_to_peer = param->peer_to_peer; + cmd->responder_resources = param->responder_resources; + cmd->initiator_depth = param->initiator_depth; + cmd->remote_cm_response_timeout = param->remote_cm_response_timeout; + cmd->flow_control = param->flow_control; + cmd->local_cm_response_timeout = param->local_cm_response_timeout; + cmd->retry_count = param->retry_count; + cmd->rnr_retry_count = param->rnr_retry_count; + cmd->max_cm_retries = param->max_cm_retries; + cmd->srq = param->srq; + + if (param->primary_path) { + p_path = alloca(sizeof(*p_path)); + if (!p_path) + return ERR(ENOMEM); + + ibv_copy_path_rec_to_kern(p_path, param->primary_path); + cmd->primary_path = (uintptr_t) p_path; + } + + if (param->alternate_path) { + a_path = alloca(sizeof(*a_path)); + if (!a_path) + return ERR(ENOMEM); + + ibv_copy_path_rec_to_kern(a_path, param->alternate_path); + cmd->alternate_path = (uintptr_t) a_path; + } + + if (param->private_data && param->private_data_len) { + cmd->data = (uintptr_t) param->private_data; + cmd->len = param->private_data_len; + } + + result = write(cm_id->device->fd, msg, size); + if (result != size) + return (result >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +int ib_cm_send_rep(struct ib_cm_id *cm_id, struct ib_cm_rep_param *param) +{ + struct cm_abi_rep *cmd; + void *msg; + int result; + int size; + + if (!param) + return ERR(EINVAL); + + CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_REP, size); + cmd->uid = (uintptr_t) container_of(cm_id, struct cm_id_private, id); + cmd->id = cm_id->handle; + cmd->qpn = param->qp_num; + cmd->psn = param->starting_psn; + cmd->responder_resources = param->responder_resources; + cmd->initiator_depth = param->initiator_depth; + cmd->target_ack_delay = param->target_ack_delay; + cmd->failover_accepted = param->failover_accepted; + cmd->flow_control = param->flow_control; + cmd->rnr_retry_count = param->rnr_retry_count; + cmd->srq = param->srq; + + if (param->private_data && param->private_data_len) { + cmd->data = (uintptr_t) param->private_data; + cmd->len = param->private_data_len; + } + + result = write(cm_id->device->fd, msg, size); + if (result != size) + return (result >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +static inline int cm_send_private_data(struct ib_cm_id *cm_id, + uint32_t type, + void *private_data, + uint8_t private_data_len) +{ + struct cm_abi_private_data *cmd; + void *msg; + int result; + int size; + + CM_CREATE_MSG_CMD(msg, cmd, type, size); + cmd->id = cm_id->handle; + + if (private_data && private_data_len) { + cmd->data = (uintptr_t) private_data; + cmd->len = private_data_len; + } + + result = write(cm_id->device->fd, msg, size); + if (result != size) + return (result >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +int ib_cm_send_rtu(struct ib_cm_id *cm_id, + void *private_data, + uint8_t private_data_len) +{ + return cm_send_private_data(cm_id, IB_USER_CM_CMD_SEND_RTU, + private_data, private_data_len); +} + +int ib_cm_send_dreq(struct ib_cm_id *cm_id, + void *private_data, + uint8_t private_data_len) +{ + return cm_send_private_data(cm_id, IB_USER_CM_CMD_SEND_DREQ, + private_data, private_data_len); +} + +int ib_cm_send_drep(struct ib_cm_id *cm_id, + void *private_data, + uint8_t private_data_len) +{ + return cm_send_private_data(cm_id, IB_USER_CM_CMD_SEND_DREP, + private_data, private_data_len); +} + +static int cm_establish(struct ib_cm_id *cm_id) +{ + struct cm_abi_establish *cmd; + void *msg; + int result; + int size; + + CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_ESTABLISH, size); + cmd->id = cm_id->handle; + + result = write(cm_id->device->fd, msg, size); + if (result != size) + return (result >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +int ib_cm_notify(struct ib_cm_id *cm_id, enum ibv_event_type event) +{ + struct cm_abi_notify *cmd; + void *msg; + int result; + int size; + + if (abi_ver == 4) { + if (event == IBV_EVENT_COMM_EST) + return cm_establish(cm_id); + else + return ERR(EINVAL); + } + + CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_NOTIFY, size); + cmd->id = cm_id->handle; + cmd->event = event; + + result = write(cm_id->device->fd, msg, size); + if (result != size) + return (result >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +static inline int cm_send_status(struct ib_cm_id *cm_id, + uint32_t type, + int status, + void *info, + uint8_t info_length, + void *private_data, + uint8_t private_data_len) +{ + struct cm_abi_info *cmd; + void *msg; + int result; + int size; + + CM_CREATE_MSG_CMD(msg, cmd, type, size); + cmd->id = cm_id->handle; + cmd->status = status; + + if (private_data && private_data_len) { + cmd->data = (uintptr_t) private_data; + cmd->data_len = private_data_len; + } + + if (info && info_length) { + cmd->info = (uintptr_t) info; + cmd->info_len = info_length; + } + + result = write(cm_id->device->fd, msg, size); + if (result != size) + return (result >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +int ib_cm_send_rej(struct ib_cm_id *cm_id, + enum ib_cm_rej_reason reason, + void *ari, + uint8_t ari_length, + void *private_data, + uint8_t private_data_len) +{ + return cm_send_status(cm_id, IB_USER_CM_CMD_SEND_REJ, reason, + ari, ari_length, + private_data, private_data_len); +} + +int ib_cm_send_apr(struct ib_cm_id *cm_id, + enum ib_cm_apr_status status, + void *info, + uint8_t info_length, + void *private_data, + uint8_t private_data_len) +{ + return cm_send_status(cm_id, IB_USER_CM_CMD_SEND_APR, status, + info, info_length, + private_data, private_data_len); +} + +int ib_cm_send_mra(struct ib_cm_id *cm_id, + uint8_t service_timeout, + void *private_data, + uint8_t private_data_len) +{ + struct cm_abi_mra *cmd; + void *msg; + int result; + int size; + + CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_MRA, size); + cmd->id = cm_id->handle; + cmd->timeout = service_timeout; + + if (private_data && private_data_len) { + cmd->data = (uintptr_t) private_data; + cmd->len = private_data_len; + } + + result = write(cm_id->device->fd, msg, size); + if (result != size) + return (result >= 0) ? ERR(ECONNREFUSED) : result; + + return 0; +} + +int ib_cm_send_lap(struct ib_cm_id *cm_id, + struct ibv_sa_path_rec *alternate_path, + void *private_data, + uint8_t private_data_len) +{ + struct ibv_kern_path_rec *abi_path; + struct cm_abi_lap *cmd; + void *msg; + int result; + int size; + + CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_LAP, size); + cmd->id = cm_id->handle; + + if (alternate_path) { + abi_path = alloca(sizeof(*abi_path)); + if (!abi_path) + return ERR(ENOMEM); + + ibv_copy_path_rec_to_kern(abi_path, alternate_path); + cmd->path = (uintptr_t) abi_path; + } + + if (private_data && private_data_len) { + cmd->data = (uintptr_t) private_data; + cmd->len = private_data_len; + } + + result = write(cm_id->device->fd, msg, size); + if (result != size) + return (result >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +int ib_cm_send_sidr_req(struct ib_cm_id *cm_id, + struct ib_cm_sidr_req_param *param) +{ + struct ibv_kern_path_rec *abi_path; + struct cm_abi_sidr_req *cmd; + void *msg; + int result; + int size; + + if (!param) + return ERR(EINVAL); + + CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_SIDR_REQ, size); + cmd->id = cm_id->handle; + cmd->sid = param->service_id; + cmd->timeout = param->timeout_ms; + cmd->pkey = param->path->pkey; + cmd->max_cm_retries = param->max_cm_retries; + + if (param->path) { + abi_path = alloca(sizeof(*abi_path)); + if (!abi_path) + return ERR(ENOMEM); + + ibv_copy_path_rec_to_kern(abi_path, param->path); + cmd->path = (uintptr_t) abi_path; + } + + if (param->private_data && param->private_data_len) { + cmd->data = (uintptr_t) param->private_data; + cmd->len = param->private_data_len; + } + + result = write(cm_id->device->fd, msg, size); + if (result != size) + return (result >= 0) ? ERR(ECONNREFUSED) : result; + + return 0; +} + +int ib_cm_send_sidr_rep(struct ib_cm_id *cm_id, + struct ib_cm_sidr_rep_param *param) +{ + struct cm_abi_sidr_rep *cmd; + void *msg; + int result; + int size; + + if (!param) + return ERR(EINVAL); + + CM_CREATE_MSG_CMD(msg, cmd, IB_USER_CM_CMD_SEND_SIDR_REP, size); + cmd->id = cm_id->handle; + cmd->qpn = param->qp_num; + cmd->qkey = param->qkey; + cmd->status = param->status; + + if (param->private_data && param->private_data_len) { + cmd->data = (uintptr_t) param->private_data; + cmd->data_len = param->private_data_len; + } + + if (param->info && param->info_length) { + cmd->info = (uintptr_t) param->info; + cmd->info_len = param->info_length; + } + + result = write(cm_id->device->fd, msg, size); + if (result != size) + return (result >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +static void cm_event_req_get(struct ib_cm_req_event_param *ureq, + struct cm_abi_req_event_resp *kreq) +{ + ureq->remote_ca_guid = kreq->remote_ca_guid; + ureq->remote_qkey = kreq->remote_qkey; + ureq->remote_qpn = kreq->remote_qpn; + ureq->qp_type = kreq->qp_type; + ureq->starting_psn = kreq->starting_psn; + ureq->responder_resources = kreq->responder_resources; + ureq->initiator_depth = kreq->initiator_depth; + ureq->local_cm_response_timeout = kreq->local_cm_response_timeout; + ureq->flow_control = kreq->flow_control; + ureq->remote_cm_response_timeout = kreq->remote_cm_response_timeout; + ureq->retry_count = kreq->retry_count; + ureq->rnr_retry_count = kreq->rnr_retry_count; + ureq->srq = kreq->srq; + ureq->port = kreq->port; + + ibv_copy_path_rec_from_kern(ureq->primary_path, &kreq->primary_path); + if (ureq->alternate_path) + ibv_copy_path_rec_from_kern(ureq->alternate_path, + &kreq->alternate_path); +} + +static void cm_event_rep_get(struct ib_cm_rep_event_param *urep, + struct cm_abi_rep_event_resp *krep) +{ + urep->remote_ca_guid = krep->remote_ca_guid; + urep->remote_qkey = krep->remote_qkey; + urep->remote_qpn = krep->remote_qpn; + urep->starting_psn = krep->starting_psn; + urep->responder_resources = krep->responder_resources; + urep->initiator_depth = krep->initiator_depth; + urep->target_ack_delay = krep->target_ack_delay; + urep->failover_accepted = krep->failover_accepted; + urep->flow_control = krep->flow_control; + urep->rnr_retry_count = krep->rnr_retry_count; + urep->srq = krep->srq; +} + +static void cm_event_sidr_rep_get(struct ib_cm_sidr_rep_event_param *urep, + struct cm_abi_sidr_rep_event_resp *krep) +{ + urep->status = krep->status; + urep->qkey = krep->qkey; + urep->qpn = krep->qpn; +}; + +int ib_cm_get_event(struct ib_cm_device *device, struct ib_cm_event **event) +{ + struct cm_id_private *cm_id_priv; + struct cm_abi_cmd_hdr *hdr; + struct cm_abi_event_get *cmd; + struct cm_abi_event_resp *resp; + struct ib_cm_event *evt = NULL; + struct ibv_sa_path_rec *path_a = NULL; + struct ibv_sa_path_rec *path_b = NULL; + void *data = NULL; + void *info = NULL; + void *msg; + int result = 0; + int size; + + if (!event) + return ERR(EINVAL); + + size = sizeof(*hdr) + sizeof(*cmd); + msg = alloca(size); + if (!msg) + return ERR(ENOMEM); + + hdr = msg; + cmd = msg + sizeof(*hdr); + + hdr->cmd = IB_USER_CM_CMD_EVENT; + hdr->in = sizeof(*cmd); + hdr->out = sizeof(*resp); + + memset(cmd, 0, sizeof(*cmd)); + + resp = alloca(sizeof(*resp)); + if (!resp) + return ERR(ENOMEM); + + cmd->response = (uintptr_t) resp; + cmd->data_len = (uint8_t)(~0U); + cmd->info_len = (uint8_t)(~0U); + + data = malloc(cmd->data_len); + if (!data) { + result = ERR(ENOMEM); + goto done; + } + + info = malloc(cmd->info_len); + if (!info) { + result = ERR(ENOMEM); + goto done; + } + + cmd->data = (uintptr_t) data; + cmd->info = (uintptr_t) info; + + result = write(device->fd, msg, size); + if (result != size) { + result = (result >= 0) ? ERR(ECONNREFUSED) : -1; + goto done; + } + + VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp); + + /* + * decode event. + */ + evt = malloc(sizeof(*evt)); + if (!evt) { + result = ERR(ENOMEM); + goto done; + } + memset(evt, 0, sizeof(*evt)); + evt->cm_id = (void *) (uintptr_t) resp->uid; + evt->event = resp->event; + + if (resp->present & CM_ABI_PRES_PRIMARY) { + path_a = malloc(sizeof(*path_a)); + if (!path_a) { + result = ERR(ENOMEM); + goto done; + } + } + + if (resp->present & CM_ABI_PRES_ALTERNATE) { + path_b = malloc(sizeof(*path_b)); + if (!path_b) { + result = ERR(ENOMEM); + goto done; + } + } + + switch (evt->event) { + case IB_CM_REQ_RECEIVED: + evt->param.req_rcvd.listen_id = evt->cm_id; + cm_id_priv = ib_cm_alloc_id(evt->cm_id->device, + evt->cm_id->context); + if (!cm_id_priv) { + result = ERR(ENOMEM); + goto done; + } + cm_id_priv->id.handle = resp->id; + evt->cm_id = &cm_id_priv->id; + evt->param.req_rcvd.primary_path = path_a; + evt->param.req_rcvd.alternate_path = path_b; + path_a = NULL; + path_b = NULL; + cm_event_req_get(&evt->param.req_rcvd, &resp->u.req_resp); + break; + case IB_CM_REP_RECEIVED: + cm_event_rep_get(&evt->param.rep_rcvd, &resp->u.rep_resp); + break; + case IB_CM_MRA_RECEIVED: + evt->param.mra_rcvd.service_timeout = resp->u.mra_resp.timeout; + break; + case IB_CM_REJ_RECEIVED: + evt->param.rej_rcvd.reason = resp->u.rej_resp.reason; + evt->param.rej_rcvd.ari = info; + info = NULL; + break; + case IB_CM_LAP_RECEIVED: + evt->param.lap_rcvd.alternate_path = path_b; + path_b = NULL; + ibv_copy_path_rec_from_kern(evt->param.lap_rcvd.alternate_path, + &resp->u.lap_resp.path); + break; + case IB_CM_APR_RECEIVED: + evt->param.apr_rcvd.ap_status = resp->u.apr_resp.status; + evt->param.apr_rcvd.apr_info = info; + info = NULL; + break; + case IB_CM_SIDR_REQ_RECEIVED: + evt->param.sidr_req_rcvd.listen_id = evt->cm_id; + cm_id_priv = ib_cm_alloc_id(evt->cm_id->device, + evt->cm_id->context); + if (!cm_id_priv) { + result = ERR(ENOMEM); + goto done; + } + cm_id_priv->id.handle = resp->id; + evt->cm_id = &cm_id_priv->id; + evt->param.sidr_req_rcvd.pkey = resp->u.sidr_req_resp.pkey; + evt->param.sidr_req_rcvd.port = resp->u.sidr_req_resp.port; + break; + case IB_CM_SIDR_REP_RECEIVED: + cm_event_sidr_rep_get(&evt->param.sidr_rep_rcvd, + &resp->u.sidr_rep_resp); + evt->param.sidr_rep_rcvd.info = info; + info = NULL; + break; + default: + evt->param.send_status = resp->u.send_status; + break; + } + + if (resp->present & CM_ABI_PRES_DATA) { + evt->private_data = data; + data = NULL; + } + + *event = evt; + evt = NULL; + result = 0; +done: + if (data) + free(data); + if (info) + free(info); + if (path_a) + free(path_a); + if (path_b) + free(path_b); + if (evt) + free(evt); + + return result; +} + +int ib_cm_ack_event(struct ib_cm_event *event) +{ + struct cm_id_private *cm_id_priv; + + if (!event) + return ERR(EINVAL); + + if (event->private_data) + free(event->private_data); + + cm_id_priv = container_of(event->cm_id, struct cm_id_private, id); + + switch (event->event) { + case IB_CM_REQ_RECEIVED: + cm_id_priv = container_of(event->param.req_rcvd.listen_id, + struct cm_id_private, id); + free(event->param.req_rcvd.primary_path); + if (event->param.req_rcvd.alternate_path) + free(event->param.req_rcvd.alternate_path); + break; + case IB_CM_REJ_RECEIVED: + if (event->param.rej_rcvd.ari) + free(event->param.rej_rcvd.ari); + break; + case IB_CM_LAP_RECEIVED: + free(event->param.lap_rcvd.alternate_path); + break; + case IB_CM_APR_RECEIVED: + if (event->param.apr_rcvd.apr_info) + free(event->param.apr_rcvd.apr_info); + break; + case IB_CM_SIDR_REQ_RECEIVED: + cm_id_priv = container_of(event->param.sidr_req_rcvd.listen_id, + struct cm_id_private, id); + break; + case IB_CM_SIDR_REP_RECEIVED: + if (event->param.sidr_rep_rcvd.info) + free(event->param.sidr_rep_rcvd.info); + default: + break; + } + + pthread_mutex_lock(&cm_id_priv->mut); + cm_id_priv->events_completed++; + pthread_cond_signal(&cm_id_priv->cond); + pthread_mutex_unlock(&cm_id_priv->mut); + + free(event); + return 0; +} diff --git a/contrib/ofed/libibcm/src/libibcm.map b/contrib/ofed/libibcm/src/libibcm.map new file mode 100644 index 000000000000..3d83e481a6bb --- /dev/null +++ b/contrib/ofed/libibcm/src/libibcm.map @@ -0,0 +1,25 @@ +IBCM_1.0 { + global: + ib_cm_open_device; + ib_cm_close_device; + ib_cm_get_event; + ib_cm_ack_event; + ib_cm_create_id; + ib_cm_destroy_id; + ib_cm_attr_id; + ib_cm_listen; + ib_cm_send_req; + ib_cm_send_rep; + ib_cm_send_rtu; + ib_cm_send_dreq; + ib_cm_send_drep; + ib_cm_notify; + ib_cm_send_rej; + ib_cm_send_mra; + ib_cm_send_lap; + ib_cm_send_apr; + ib_cm_send_sidr_req; + ib_cm_send_sidr_rep; + ib_cm_init_qp_attr; + local: *; +}; diff --git a/contrib/ofed/libibverbs/AUTHORS b/contrib/ofed/libibverbs/AUTHORS new file mode 100644 index 000000000000..e2dc2989250e --- /dev/null +++ b/contrib/ofed/libibverbs/AUTHORS @@ -0,0 +1,4 @@ +Roland Dreier +Dotan Barak +Sean Hefty +Michael S. Tsirkin diff --git a/contrib/ofed/libibverbs/COPYING b/contrib/ofed/libibverbs/COPYING new file mode 100644 index 000000000000..ee1a79ffabf6 --- /dev/null +++ b/contrib/ofed/libibverbs/COPYING @@ -0,0 +1,378 @@ +This software is available to you under a choice of one of two +licenses. You may choose to be licensed under the terms of the the +OpenIB.org BSD license or the GNU General Public License (GPL) Version +2, both included below. + +Copyright (c) 2004 Topspin Communications. All rights reserved. + +================================================================== + + OpenIB.org BSD license + +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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +================================================================== + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/ofed/libibverbs/ChangeLog b/contrib/ofed/libibverbs/ChangeLog new file mode 100644 index 000000000000..27ee956ddac8 --- /dev/null +++ b/contrib/ofed/libibverbs/ChangeLog @@ -0,0 +1,583 @@ +2006-10-30 Jack Morgenstein + + * src/cmd.c (ibv_cmd_query_qp): Unmarshall sq_draining instead of + en_sqd_async_notify. + + * include/infiniband/kern-abi.h: Change en_sqd_async_notify member + of struct ibv_query_qp_resp to sq_draining. + +2006-10-30 Roland Dreier + + * src/init.c (find_drivers): Make find_drivers() take a const + directory name, and tweak how we strip trailing /s so that we + don't have to modify the directory name passed in. Constify + default_path too. + +2006-10-25 Roland Dreier + + * src/init.c (init_drivers): Remove assignment to dev->driver now + that it is gone for good. + + * include/infiniband/verbs.h: Remove .driver member of struct + ibv_device, since it is never really used. + +2006-10-17 Roland Dreier + + * include/infiniband/arch.h: Update i386 and x86_64 memory barrier + macros to be more than compiler barriers, to guard against + out-of-order speculative reads. + + * include/infiniband/arch.h: Add rmb() and wmb() macros in + addition to the full mb(), so that low-level drivers can ask for + weaker ordering if that's all that is needed. + +2006-10-03 Roland Dreier + + * src/cmd.c (ibv_cmd_get_context_v2, ibv_cmd_get_context) + (ibv_cmd_query_device, ibv_cmd_query_port, ibv_cmd_alloc_pd) + (ibv_cmd_reg_mr, ibv_cmd_create_cq_v2, ibv_cmd_create_cq) + (ibv_cmd_poll_cq, ibv_cmd_resize_cq, ibv_cmd_destroy_cq) + (ibv_cmd_create_srq, ibv_cmd_create_qp, ibv_cmd_post_send) + (ibv_cmd_post_recv, ibv_cmd_post_srq_recv, ibv_cmd_create_ah) + (ibv_cmd_destroy_qp): Annotate so that Valgrind knows responses + are defined after write() succeeds. The kernel writes into the + response structure directly, so without these, Valgrind thinks + that response structures are undefined memory. This is based on + patches and suggestions by Rainer Keller , Jeff + Squyres and Siqing Fan. + + * src/ibverbs.h: Add wrapper for VALGRIND_MAKE_MEM_DEFINED so that + it can be used in .c files without worrying about whether Valgrind + is installed or enabled. + + * configure.in: Add support for Valgrind annotation (enabled with + --with-valgrind option to configure). + + * src/cmd.c (ibv_cmd_query_port, ibv_cmd_create_cq, + ibv_cmd_modify_qp): Set reserved fields to 0 to avoid future + problems and also to make Valgrind a little quieter. + + * src/init.c (init_drivers): Set node_type and transport_type + values of device being created. + + * include/infiniband/verbs.h: Add ibv_node_type enum value + IBV_NODE_RNIC, and add enum ibv_transport_type. Add node_type and + transport_type fields to struct ibv_device. + +2006-09-12 Roland Dreier + + * include/infiniband/verbs.h: Swap wr_id and next members of + struct ibv_send_wr and struct ibv_recv_wr. This allows wr_id to + be naturally aligned without padding on 32-bit platforms. + +2006-08-23 Roland Dreier + + * include/infiniband/driver.h: Add a definition of the macro + IBV_CMD_RESIZE_CQ_HAS_RESP_PARAMS so that low-level driver plugins + can detect the changed signature of ibv_cmd_resize_cq(). + +2006-08-23 Ralph Campbell + + * src/cmd.c (ibv_cmd_resize_cq): Add resp and resp_size parameters + so that the low-level driver in the kernel can return + device-specific information from the resize CQ operation. + +2006-07-26 Roland Dreier + + * src/verbs.c (ibv_reg_mr, ibv_dereg_mr): Add calls to + ibv_dontfork_range() and ibv_dofork_range() for memory regions + registered by library consumers. + + * include/infiniband/verbs.h: Add declaration of ibv_fork_init(). + + * include/infiniband/driver.h: Add declarations of + ibv_dontfork_range() and ibv_dofork_range(). + + * src/memory.c: Rewrite to use a red-black tree instead of a + linked list. Change from doing mlock()/munlock() to + madvise(..., MADV_DONTFORK) and madvise(..., MADV_DOFORK), and + change the name of the entry points to ibv_dontfork_range() and + ibv_dofork_range(). Add ibv_fork_init() for applications to + request fork-safe behavior. + + * src/ibverbs.h: Kill off unused declarations. + + * src/init.c (ibverbs_init): Get rid of call to ibv_init_mem_map(). + + * include/infiniband/verbs.h: Add addr and length field to struct + ibv_mr so that memory regions can be madvised(). This changes the + ABI, since the layout of struct ibv_mr is changed. + +2006-07-04 Roland Dreier + + * include/infiniband/arch.h: Fix typo in sparc mb() + implementation: the asm should just be empty -- the "sync" + instruction was mistakenly cut and pasted from the ppc version. + +2006-06-07 Sean Hefty + + * src/verbs.c include/infiniband/verbs.h: Add new routines: + ibv_init_ah_from_wc() and ibv_create_ah_from_wc() to simplify UD QP + communication. + + * src/marshall.c include/infiniband/marshall.h: Expose + ibv_copy_ah_attr_from_kern to retrieve ibv_ah_attr from kernel for + a UD QP. + +2006-06-01 Roland Dreier + + * src/device.c (ibv_get_device_list): Actually return a + NULL-terminated array as the documentation promises. + +2006-05-31 Roland Dreier + + * src/init.c (find_drivers): Fix memory leak: the result of + asprintf() needs to be freed when we're done with it. + + * examples/asyncwatch.c (event_name_str): Print human-readable + form of IBV_EVENT_CLIENT_REREGISTER. + +2006-05-31 Leonid Arsh + + * include/infiniband/verbs.h: Add IBV_EVENT_CLIENT_REREGISTER. + +2006-05-22 Roland Dreier + + * examples/devinfo.c (print_hca_cap): Read board_id attribute from + sysfs using ibv_read_sysfs_file() instead of libsysfs. + + * src/cmd.c, src/marshall.c, src/sysfs.c: Include , + since it is no longer implicitly included via . + + * include/infiniband/driver.h, include/infiniband/verbs.h, + src/device.c, src/init.c, src/verbs.c: Remove dependency on + libsysfs by implementing what is required directly on top of + filesystem operations. + + * include/infiniband/driver.h, src/init.c: Change name of driver + entry point to ibv_driver_init(), and update prototype to remove + libsysfs dependency. + + * src/marshall.c, include/infiniband/marshall.h, + include/infiniband/sa.h: Remove deprecated ib_xxx symbols. + + * Makefile.am: Bump SONAME to 2, since libibverbs 1.1 will be + ABI-incompatible with libibverbs 1.0. + + * Create libibverbs 1.1 branch and bump version number to 1.1-pre1. + +2006-05-22 Michael S. Tsirkin + + * include/infiniband/verbs.h: Remove trailing commas from + enumerators to quiet warnings from obsolete compilers. + +2006-05-02 Roland Dreier + + * Release version 1.0.3. + +2006-05-01 Roland Dreier + + * include/infiniband/arch.h: Only SPARC V9 ISA supports membar. + So just use generic memory barrier for older sparc archs. + +2006-04-11 Roland Dreier + + * src/sysfs.c (ibv_read_sysfs_file): Fix memory leak if open fails. + + * src/device.c (ibv_get_device_guid), src/verbs.c (ibv_query_gid, + ibv_query_pkey), src/init.c (init_drivers, check_abi_version): Use + libibverbs functions instead of libsysfs functions to get to sysfs. + + * src/sysfs.c (ibv_get_sysfs_path, ibv_read_sysfs_file): Add some + simple functions for accessing sysfs without using libsysfs. + + * include/infiniband/sa-kern-abi.h: Deprecate struct + ib_kern_path_rec name; struct ibv_kern_path_rec is now preferred. + + * include/infiniband/sa.h: Deprecate struct ib_sa_XXX names; + struct ibv_sa_XXX is now preferred. + + * src/marshall.c, include/infiniband/marshall.h: Deprecate + ib_copy_XXX() names; ibv_copy_XXX() is preferred. Add stub + wrappers with the old names so old binaries still work. + +2006-04-11 Hoang-Nam Nguyen + + * src/verbs.c (ibv_rate_to_mult, mult_to_ibv_rate): Add new + functions to convert between IB rate enums and multiples of the + base 2.5 Gb/sec rate. + +2006-04-11 Roland Dreier + + * include/infiniband/verbs.h: Add __attribute_const macro to + portably mark functions as __attribute__((const)) + +2006-03-28 Roland Dreier + + * src/init.c (load_driver): Print warning if dlopen() of a driver + plugin fails. + +2006-03-22 Dotan Barak + + * examples/asyncwatch.c: Print asynchronous event name as well as + raw integer value. + +2006-03-22 Roland Dreier + + * include/infiniband/verbs.h (ibv_req_notify_cq): Document + parameters better. + +2006-03-16 Roland Dreier + + * src/cmd.c, src/device.c, src/memory.c, src/verbs.c: Add include + of to get a declaration of free() and avoid compile + warnings. + +2006-03-14 Roland Dreier + + * Release version 1.0.2. + + * Makefile.am (EXTRA_DIST): Remove debian/ directory from + tarballs, since Debian policy is that upstream tarballs should not + include it. + +2006-03-13 Roland Dreier + + * Release version 1.0.1. + + * src/init.c (check_abi_version), src/verbs.c (ibv_query_gid, + ibv_query_pkey): Use sysfs_open_attribute() and + sysfs_read_attribute() instead of the deprecated function + sysfs_read_attribute_value(), which is no longer present in + libsysfs2 (which is already in Debian and Ubuntu). + + * Release version 1.0. + +2006-03-06 Roland Dreier + + * include/infiniband/verbs.h: Add enum ibv_rate to define encoding + of static_rate field (based on a patch from Jack Morgenstein + ). + +2006-03-06 Ralph Campbell + + * src/init.c (find_drivers): Fix minor memory leak: call + globfree() to free memory allocated by glob(). + +2006-02-23 Dotan Barak + + * src/cmd.c (ibv_cmd_create_srq): Add support for kernel ABI + version 6 (take SRQ capacity from kernel response to create SRQ). + +2006-02-16 Roland Dreier + + * Release version 1.0-rc7. + + * src/cmd.c (ibv_cmd_create_qp): Add support for kernel ABI + version 5 (properly aligned struct ibv_create_qp_resp). + +2006-02-15 Roland Dreier + + * src/cmd.c (ibv_cmd_create_qp): Allow userspace device-specific + driver to pass in a response buffer, so that the low-level driver + in the kernel can pass back device-specific information. This + changes the userspace driver API, since the signature of + ibv_cmd_create_qp() is changed. + +2006-02-14 Roland Dreier + + * Release version 1.0-rc6. + +2006-02-13 Dotan Barak + + * examples/devinfo.c (print_hca_cap): Print board_id from sysfs, + if present. + +2006-02-13 Roland Dreier + + * examples/asyncwatch.c, examples/device_list.c, + examples/devinfo.c: Remove cpu_to_be64()/be64_to_cpu() and use + htonll()/ntohll() from . + +2006-02-13 Dotan Barak + + * src/cmd.c (ibv_cmd_query_qp, ibv_cmd_query_srq), + include/infiniband/driver.h: Add driver interface for calling + query QP and query SRQ kernel commands. + + * include/infiniband/kern-abi.h: Add kernel ABI for query QP and + query SRQ. + + * src/verbs.c (ibv_query_qp, ibv_query_srq), + include/infiniband/verbs.h: Add query QP and query SRQ library + APIs. This changes the provider ABI, since new fields are added + to struct ibv_context_ops; source compatibility with provider + libraries is preserved, but binaries will have to be recompiled. + Neither source nor binary compatibility with consumers of + libibverbs is affected. + +2006-02-01 Roland Dreier + + * examples/rc_pingpong.c, examples/uc_pingpong.c, + examples/ud_pingpong.c, examples/srq_pingpong.c: Fix bug in + searching for device by name when there's more than one device. + +2006-01-31 Roland Dreier + + * include/infiniband/verbs.h, include/infiniband/driver.h: Remove + useless "extern" from function declarations. + +2006-01-26 Roland Dreier + + * include/infiniband/driver.h, src/cmd.c (ibv_cmd_resize_cq): Add + driver interface for calling resize CQ kernel command. + + * include/infiniband/kern-abi.h: Add resize CQ kernel ABI. + + * include/infiniband/verbs.h, src/verbs.c (ibv_resize_cq): Add + resize CQ library API. This changes the provider ABI, since a new + field is added to struct ibv_context_ops; source compatibility + with provider libraries is preserved, but binaries will have to be + recompiled. Neither source nor binary compatibility with + consumers of libibverbs is affected. + +2006-01-25 Roland Dreier + + * examples/pingpong.c, examples/pingpong.h, + examples/rc_pingpong.c, examples/uc_pingpong.c, + examples/srq_pingpong.c: Move pp_get_local_lid() to pingpong.c to + reduce code duplication. + +2006-01-22 Roland Dreier + + * Release version 1.0-rc5. + +2006-01-22 Dotan Barak + + * examples/devinfo.c (main): Make ibv_devinfo list all IB devices + by default, rather than the first device only. + +2006-01-20 Roland Dreier + + * examples/rc_pingpong.c, examples/uc_pingpong.c, + examples/srq_pingpong.c: Add "-m/--mtu=" option to set path MTU. + (Based on a patch from Ralph Campbell ) + + * examples/pingpong.c, examples/pingpong.h: Create generic + pingpong files so that we can start factoring out common code from + the pingpong examples. Start with functions to convert MTU to an + IBV enum value. + +2006-01-17 Ralph Campbell + + * examples/rc_pingpong.c (main), examples/srq_pingpong.c (main), + examples/uc_pingpong.c (main), examples/ud_pingpong.c (main): Fix + race when using CQ events by arming CQ before allowing remote side + to start sending. + +2006-01-06 Roland Dreier + + * examples/srq_pingpong.c (main): Fix SRQ example to avoid + problems with many QPs and events. Based on a patch from Dotan + Barak (who also found the problem). + +2006-01-06 Ralph Campbell + + * examples/rc_pingpong.c (main), examples/srq_pingpong.c (main), + examples/uc_pingpong.c (main), examples/ud_pingpong.c (main): Fix + test of return value of ibv_poll_cq(). + +2006-01-04 Dotan Barak + + * include/infiniband/verbs.h: Fix mask names in description of + ibv_modify_srq. + +2006-01-04 Michael S. Tsirkin + + * src/init.c (ibverbs_init): Fix ibverbs_init for multiple adapters. + Noted by Christoph Raisch. + +2005-12-15 Roland Dreier + + * include/infiniband/verbs.h: Document that devices must be opened + before calling ibv_free_device_list(). + + * src/verbs.c (ibv_create_srq): Not all provider libraries will + support SRQs, so check if the create_srq method is defined before + calling it. (Based on a patch from Shirley Ma ) + +2005-11-11 Roland Dreier + + * examples/asyncwatch.c, examples/rc_pingpong.c, + examples/srq_pingpong.c, examples/uc_pingpong.c, + examples/ud_pingpong.c, examples/device_list.c, + examples/devinfo.c: Update examples to match new API. + + * include/infiniband/verbs.h, src/device.c, src/init.c, + src/ibverbs.h: Change from dlist-based ibv_get_devices() API to + simpler ibv_get_device_list() and ibv_free_device_list() API. + +2005-11-10 Sean Hefty + + * include/infiniband/sa-kern-abi.h: New include file to contain + definitions of SA structures passed between userspace and kernel. + + * include/infiniband/sa.h: New include file for definitions of + SA structures used by multiple libraries. + + * include/infiniband/marshall.h src/marshall.c: New files to define + routines used to exchange data with kernel modules. + + * include/infiniband/kern-abi.h: Added data structures used to exchange + QP attribute with kernel modules. + +2005-11-09 Michael S. Tsirkin + + * src/device.c (ibv_get_devices): Make function reentrant by using + a mutex to make sure we initialize the device list at most once. + +2005-11-08 Roland Dreier + + * src/cmd.c (ibv_cmd_create_qp): Add handling for new create QP + interface, which has the kernel return QP capabilities. + + * src/cmd.c (ibv_cmd_modify_srq): Split off handling of modify SRQ + for ABI versions 3 and older, which passed max_sge as part of command. + +2005-10-30 Roland Dreier + + * examples/srq_pingpong.c (pp_init_ctx): Create CQ with rx_depth + + num_qp entries, instead of just rx_depth + 1 entries, because + there can be one send completion pending for each QP. + +2005-10-25 Roland Dreier + + * Release version 1.0-rc4. + + * examples/uc_pingpong.c (pp_connect_ctx): Fix QP attribute masks + used to modify QP to RTR and RTS -- we should not be setting + RDMA/atomic attributes for UC QPs. Now that the mthca kernel + driver bug is fixed, the error is exposed here. + + * examples/rc_pingpong.c, examples/srq_pingpong.c, + examples/uc_pingpong.c, examples/ud_pingpong.c: Keep track of + whether send and/or receive is pending. This avoids failures when + the remote side receives data and posts a send very quickly, and + the local side completes the receive before the previous send. + With the old code, this could result in posting a send before the + previous send completed, and therefore overrun the send queue. + +2005-10-23 Roland Dreier + + * src/cmd.c (ibv_cmd_get_context_v2): Correct silly mistake in + computation of size of buffer for old ABI command: we need to use + sizeof *cmd instead of sizeof cmd, since cmd is a pointer. + +2005-10-21 Roland Dreier + + * src/cmd.c (ibv_cmd_post_send, ibv_cmd_post_recv, + ibv_cmd_post_srq_recv): Correct value that we check write() return + value against so that we check against the size we actually try to + write, instead of just sizeof cmd. + +2005-10-19 Roland Dreier + + * src/cmd.c (ibv_cmd_req_notify_cq): Correct how we pass + solicited_only flag into the kernel. + +2005-10-13 Roland Dreier + + * include/infiniband/driver.h, src/cmd.c, src/libibverbs.map: Add + command functions for calling new kernel commands. + + * include/infiniband/verbs.h: Add qp_type to struct ibv_qp so that + we know when we're posting a send on a UD QP, and add kernel + handle member to struct ibv_ah so we can handle drivers that do + create AH and destroy AH operations in the kernel. + + * include/infiniband/kern-abi.h: Add new command structures for + poll CQ, request notification for CQ, post send, post receive, + post SRQ receive, create AH and destroy AH commands. These will + be used by the PathScale userspace driver. + +2005-10-12 Roland Dreier + + * examples/srq_pingpong.c (main): Zero out unused entries in + my_dest array to avoid string overflows when we send to the other + side. + +2005-10-09 Roland Dreier + + * examples/devinfo.c (print_hca_cap): Only print max_mr_size and + page_size_cap if verbose is set. + +2005-10-05 Roland Dreier + + * src/cmd.c (ibv_cmd_modify_srq): Add function for marshalling + modify SRQ command. + +2005-09-29 Roland Dreier + + * examples/devinfo.c (print_hca_cap): Get rid of formatting of + firmware version in what should be device-independent code. + + * include/infiniband/driver.h, include/infiniband/verbs.h, + src/cmd.c (ibv_cmd_query_device): Change firmware version in + struct ibv_device_attr to be a string formatted by device-specific + library. + +2005-09-25 Roland Dreier + + * examples/rc_pingpong.c, examples/srq_pingpong.c, + examples/uc_pingpong.c, examples/ud_pingpong.c: Update to match + new completion channel and CQ creation API. + + * include/infiniband/driver.h, include/infiniband/verbs.h, + src/device.c, src/ibverbs.h, src/verbs.c, src/cmd.c: Add notion of + "completion channel" that allows consumers to dynamically create + and destroy file descriptors for retrieving completion events. + Completion channels are handled natively with kernel ABI version 3 + and simulated with backwards compatibility implementations for ABI + versions 1 and 2. + + * include/infiniband/kern-abi.h: Update to match kernel ABI + version 3. + +2005-09-07 Roland Dreier + + * src/device.c (ibv_get_device_guid): Use htonll() instead of + relying on pointer aliasing (which seems to break for some gcc + versions). + + * include/infiniband/arch.h: Add htonll() and ntohll() functions. + +2005-09-06 Roland Dreier + + * include/infiniband/kern-abi.h, include/infiniband/verbs.h, + src/cmd.c, src/device.c, src/verbs.c, examples/asyncwatch.c: + Update to handle new kernel ABI for avoiding stale completion + events. This is completely analogous to the previous asynchronous + event change. + +2005-08-31 Roland Dreier + + * include/infiniband/kern-abi.h, include/infiniband/verbs.h, + src/cmd.c, src/device.c, src/ibverbs.h, src/init.c, src/verbs.c, + examples/asyncwatch.c: Update to handle new kernel ABI for + avoiding stale asynchronous events. When a CQ, QP or SRQ is + destroyed, the kernel reports the number of events it has given to + userspace, and we wait until we've handled the same number of + events. + + This does introduce a library API change: consumers are now + required to call ibv_put_async_event() to release every + asynchronous event that they retrieve via ibv_get_async_event(). + +2005-08-30 Roland Dreier + + * man/ibv_asyncwatch.1, man/ibv_devices.1, man/ibv_devinfo.1, + man/ibv_rc_pingpong.1, man/ibv_srq_pingpong.1, + man/ibv_uc_pingpong.1, man/ibv_ud_pingpong.1: Add man pages for + example programs. + + * examples/devinfo.c: Merge with Dotan Barak's vstat tool. diff --git a/contrib/ofed/libibverbs/Makefile.am b/contrib/ofed/libibverbs/Makefile.am new file mode 100644 index 000000000000..5f9c45cbddda --- /dev/null +++ b/contrib/ofed/libibverbs/Makefile.am @@ -0,0 +1,114 @@ +INCLUDES = -I$(srcdir)/include + +lib_LTLIBRARIES = src/libibverbs.la + +AM_CFLAGS = -g -Wall -D_GNU_SOURCE + +src_libibverbs_la_CFLAGS = $(AM_CFLAGS) -DIBV_CONFIG_DIR=\"$(sysconfdir)/libibverbs.d\" + +libibverbs_version_script = @LIBIBVERBS_VERSION_SCRIPT@ + +src_libibverbs_la_SOURCES = src/cmd.c src/compat-1_0.c src/device.c src/init.c \ + src/marshall.c src/memory.c src/sysfs.c src/verbs.c \ + src/enum_strs.c +src_libibverbs_la_LDFLAGS = -version-info 1 -export-dynamic \ + $(libibverbs_version_script) +src_libibverbs_la_DEPENDENCIES = $(srcdir)/src/libibverbs.map + +bin_PROGRAMS = examples/ibv_devices examples/ibv_devinfo \ + examples/ibv_asyncwatch examples/ibv_rc_pingpong examples/ibv_uc_pingpong \ + examples/ibv_ud_pingpong examples/ibv_srq_pingpong +examples_ibv_devices_SOURCES = examples/device_list.c +examples_ibv_devices_LDADD = $(top_builddir)/src/libibverbs.la +examples_ibv_devinfo_SOURCES = examples/devinfo.c +examples_ibv_devinfo_LDADD = $(top_builddir)/src/libibverbs.la +examples_ibv_rc_pingpong_SOURCES = examples/rc_pingpong.c examples/pingpong.c +examples_ibv_rc_pingpong_LDADD = $(top_builddir)/src/libibverbs.la +examples_ibv_uc_pingpong_SOURCES = examples/uc_pingpong.c examples/pingpong.c +examples_ibv_uc_pingpong_LDADD = $(top_builddir)/src/libibverbs.la +examples_ibv_ud_pingpong_SOURCES = examples/ud_pingpong.c examples/pingpong.c +examples_ibv_ud_pingpong_LDADD = $(top_builddir)/src/libibverbs.la +examples_ibv_srq_pingpong_SOURCES = examples/srq_pingpong.c examples/pingpong.c +examples_ibv_srq_pingpong_LDADD = $(top_builddir)/src/libibverbs.la +examples_ibv_asyncwatch_SOURCES = examples/asyncwatch.c +examples_ibv_asyncwatch_LDADD = $(top_builddir)/src/libibverbs.la + +libibverbsincludedir = $(includedir)/infiniband + +libibverbsinclude_HEADERS = include/infiniband/arch.h include/infiniband/driver.h \ + include/infiniband/kern-abi.h include/infiniband/opcode.h include/infiniband/verbs.h \ + include/infiniband/sa-kern-abi.h include/infiniband/sa.h include/infiniband/marshall.h + +man_MANS = man/ibv_asyncwatch.1 man/ibv_devices.1 man/ibv_devinfo.1 \ + man/ibv_rc_pingpong.1 man/ibv_uc_pingpong.1 man/ibv_ud_pingpong.1 \ + man/ibv_srq_pingpong.1 man/ibv_alloc_pd.3 man/ibv_attach_mcast.3 \ + man/ibv_create_ah.3 man/ibv_create_ah_from_wc.3 \ + man/ibv_create_comp_channel.3 man/ibv_create_cq.3 \ + man/ibv_create_qp.3 man/ibv_create_srq.3 \ + man/ibv_create_xrc_rcv_qp.3 man/ibv_event_type_str.3 \ + man/ibv_fork_init.3 man/ibv_get_async_event.3 \ + man/ibv_get_cq_event.3 man/ibv_get_device_guid.3 \ + man/ibv_get_device_list.3 man/ibv_get_device_name.3 \ + man/ibv_modify_qp.3 man/ibv_modify_srq.3 man/ibv_modify_xrc_rcv_qp.3 \ + man/ibv_open_device.3 man/ibv_open_xrc_domain.3 \ + man/ibv_poll_cq.3 man/ibv_post_recv.3 man/ibv_post_send.3 \ + man/ibv_post_srq_recv.3 man/ibv_query_device.3 man/ibv_query_gid.3 \ + man/ibv_query_pkey.3 man/ibv_query_port.3 man/ibv_query_qp.3 \ + man/ibv_query_srq.3 man/ibv_query_xrc_rcv_qp.3 \ + man/ibv_rate_to_mult.3 man/ibv_reg_mr.3 man/ibv_reg_xrc_rcv_qp.3 \ + man/ibv_req_notify_cq.3 man/ibv_resize_cq.3 man/verbs.7 + +DEBIAN = debian/changelog debian/compat debian/control debian/copyright \ + debian/ibverbs-utils.install debian/libibverbs1.install \ + debian/libibverbs1.postinst debian/libibverbs-dev.install \ + debian/rules + +EXTRA_DIST = include/infiniband/driver.h include/infiniband/kern-abi.h \ + include/infiniband/opcode.h include/infiniband/verbs.h include/infiniband/marshall.h \ + include/infiniband/sa-kern-abi.h include/infiniband/sa.h \ + src/ibverbs.h examples/pingpong.h \ + src/libibverbs.map libibverbs.spec.in $(man_MANS) + +dist-hook: libibverbs.spec + cp libibverbs.spec $(distdir) + +install-data-hook: + cd $(DESTDIR)$(mandir)/man3 && \ + $(RM) ibv_ack_async_event.3 && \ + $(RM) ibv_ack_cq_events.3 && \ + $(RM) ibv_close_device.3 && \ + $(RM) ibv_close_xrc_domain.3 && \ + $(RM) ibv_create_xrc_srq.3 && \ + $(RM) ibv_dealloc_pd.3 && \ + $(RM) ibv_dereg_mr.3 && \ + $(RM) ibv_destroy_ah.3 && \ + $(RM) ibv_destroy_comp_channel.3 && \ + $(RM) ibv_destroy_cq.3 && \ + $(RM) ibv_destroy_qp.3 && \ + $(RM) ibv_destroy_srq.3 && \ + $(RM) ibv_detach_mcast.3 && \ + $(RM) ibv_free_device_list.3 && \ + $(RM) ibv_init_ah_from_wc.3 && \ + $(RM) ibv_unreg_xrc_rcv_qp.3 && \ + $(RM) mult_to_ibv_rate.3 && \ + $(RM) ibv_node_type_str.3 && \ + $(RM) ibv_port_state_str.3 && \ + $(LN_S) ibv_get_async_event.3 ibv_ack_async_event.3 && \ + $(LN_S) ibv_get_cq_event.3 ibv_ack_cq_events.3 && \ + $(LN_S) ibv_open_device.3 ibv_close_device.3 && \ + $(LN_S) ibv_open_xrc_domain.3 ibv_close_xrc_domain.3 && \ + $(LN_S) ibv_create_srq.3 ibv_create_xrc_srq.3 && \ + $(LN_S) ibv_alloc_pd.3 ibv_dealloc_pd.3 && \ + $(LN_S) ibv_reg_mr.3 ibv_dereg_mr.3 && \ + $(LN_S) ibv_create_ah.3 ibv_destroy_ah.3 && \ + $(LN_S) ibv_create_comp_channel.3 ibv_destroy_comp_channel.3 && \ + $(LN_S) ibv_create_cq.3 ibv_destroy_cq.3 && \ + $(LN_S) ibv_create_qp.3 ibv_destroy_qp.3 && \ + $(LN_S) ibv_create_srq.3 ibv_destroy_srq.3 && \ + $(LN_S) ibv_attach_mcast.3 ibv_detach_mcast.3 && \ + $(LN_S) ibv_get_device_list.3 ibv_free_device_list.3 && \ + $(LN_S) ibv_create_ah_from_wc.3 ibv_init_ah_from_wc.3 && \ + $(LN_S) ibv_reg_xrc_rcv_qp.3 ibv_unreg_xrc_rcv_qp.3 && \ + $(LN_S) ibv_rate_to_mult.3 mult_to_ibv_rate.3 && \ + $(LN_S) ibv_event_type_str.3 ibv_node_type_str.3 && \ + $(LN_S) ibv_event_type_str.3 ibv_port_state_str.3 diff --git a/contrib/ofed/libibverbs/README b/contrib/ofed/libibverbs/README new file mode 100644 index 000000000000..848eb05917fb --- /dev/null +++ b/contrib/ofed/libibverbs/README @@ -0,0 +1,164 @@ +Introduction +============ + +libibverbs is a library that allows programs to use RDMA "verbs" for +direct access to RDMA (currently InfiniBand and iWARP) hardware from +userspace. For more information on RDMA verbs, see the InfiniBand +Architecture Specification vol. 1, especially chapter 11, and the RDMA +Consortium's RDMA Protocol Verbs Specification. + +Using libibverbs +================ + +Device nodes +------------ + +The verbs library expects special character device files named +/dev/infiniband/uverbsN to be created. When you load the kernel +modules, including both the low-level driver for your IB hardware as +well as the ib_uverbs module, you should see one or more uverbsN +entries in /sys/class/infiniband_verbs in addition to the +/dev/infiniband/uverbsN character device files. + +To create the appropriate character device files automatically with +udev, a rule like + + KERNEL="uverbs*", NAME="infiniband/%k" + +can be used. This will create device nodes named + + /dev/infiniband/uverbs0 + +and so on. Since the RDMA userspace verbs should be safe for use by +non-privileged users, you may want to add an appropriate MODE or GROUP +to your udev rule. + +Permissions +----------- + +To use IB verbs from userspace, a process must be able to access the +appropriate /dev/infiniband/uverbsN special device file. You can +check the permissions on this file with the command + + ls -l /dev/infiniband/uverbs* + +Make sure that the permissions on these files are such that the +user/group that your verbs program runs as can access the device file. + +To use IB verbs from userspace, a process must also have permission to +tell the kernel to lock sufficient memory for all of your registered +memory regions as well as the memory used internally by IB resources +such as queue pairs (QPs) and completion queues (CQs). To check your +resource limits, use the command + + ulimit -l + +(or "limit memorylocked" for csh-like shells). + +If you see a small number such as 32 (the units are KB) then you will +need to increase this limit. This is usually done for ordinary users +via the file /etc/security/limits.conf. More configuration may be +necessary if you are logging in via OpenSSH and your sshd is +configured to use privilege separation. + +Valgrind support +---------------- + +When running applications that use libibverbs under the Valgrind +memory-checking debugger, Valgrind will falsely report "read from +uninitialized" for memory that was initialized by the kernel drivers. +Specifically, Valgrind cannot see when kernel drivers write to +userspace memory, so when the process reads from that memory, Valgrind +incorrectly assumes that the memory contents are uninitialized, and +therefore raises a warning. + +libibverbs can be built with specific support for the Valgrind +memory-checking debugger by specifying the --with-valgrind command +line argument to configure. This flag enables code in libibverbs to +tell Valgrind "this memory may look uninitialized, but it's really +OK," which therefore suppresses the incorrect "read from +uninitialized" warnings. This code adds trivial overhead to the +critical performance path, so it is disabled by default. The intent +is that production users can use a "normal" build of libibverbs and +developers can use the "valgrind debug" build by simply switching +their LD_LIBRARY_PATH environment variables. + +Libibverbs needs some header files from Valgrind in order to compile +this support; it is important to use the header files from the same +version of Valgrind that will be used at run time. You may need to +specify the directory where Valgrind's header files are installed as +an argument to --with-valgrind. For example + + ./configure --with-valgrind=/opt/valgrind + +will make the libibverbs build look for valgrind headers in +/opt/valgrind/include + +Reporting bugs +============== + +Bugs should be reported to the OpenFabrics mailing list +. In your bug report, please include: + + * Information about your system: + - Linux distribution and version + - Linux kernel and version + - InfiniBand/iWARP hardware and firmware version + - ... any other relevant information + + * How to reproduce the bug. Command line arguments for a libibverbs + example program or source code that other developers can + compile and run is most convenient. + + * If the bug is a crash, the exact output printed out when the crash + occurred, including any kernel messages produced. + + * If a verbs call is mysteriously returning an error or failing, the + output of "strace -ewrite -ewrite=all ". + +Submitting patches +================== + +Patches should also be submitted to the OpenFabrics mailing list +. Please use unified diff form (the -u +option to GNU diff), and include a good description of what your patch +does and why it should be applied. If your patch fixes a bug, please +make sure to describe the bug and how your fix works. + +Please include a change to the ChangeLog file (in standard GNU +changelog format) as part of your patch. + +Make sure that your contribution can be licensed under the same +license as the original code you are patching, and that you have all +necessary permissions to release your work. + +TODO +==== + +1.1 series +---------- + +The libibverbs API and ABI are frozen for all releases in the 1.1 +series. Methods were added to struct ibv_context to implement the +following features, so it should be possible to add them in a future +release in the 1.1 series: + + * Memory window (MW) support. + + * Implement the reregister memory region (MR) verb. We will add an + extension to the IB spec to allow the application to indicate that + the region is only being extended, and that operations in progress + should _not_ fail (contrary to the IB spec, which states that + reregister must be implemented so that it behaves equivalently to a + deregister followed by a register). + +Other possibilities +------------------- + +There are no plans to implement the following features, which would be +needed for completeness but don't seem particularly useful. However, +if there is demand from application developers or an implementation is +contributed, then the feature may be added. + + * Implement the query address handle (AH) verb. + * Implement the query memory region (MR) verb. diff --git a/contrib/ofed/libibverbs/autogen.sh b/contrib/ofed/libibverbs/autogen.sh new file mode 100755 index 000000000000..fd47839cae8c --- /dev/null +++ b/contrib/ofed/libibverbs/autogen.sh @@ -0,0 +1,8 @@ +#! /bin/sh + +set -x +aclocal -I config +libtoolize --force --copy +autoheader +automake --foreign --add-missing --copy +autoconf diff --git a/contrib/ofed/libibverbs/configure.in b/contrib/ofed/libibverbs/configure.in new file mode 100644 index 000000000000..d0678c89bfc6 --- /dev/null +++ b/contrib/ofed/libibverbs/configure.in @@ -0,0 +1,77 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(libibverbs, 1.1.4, general@lists.openfabrics.org) +AC_CONFIG_SRCDIR([src/ibverbs.h]) +AC_CONFIG_AUX_DIR(config) +AC_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(libibverbs, 1.1.4) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +dnl Checks for programs +AC_PROG_CC +AC_GNU_SOURCE +AC_PROG_LN_S + +AC_PROG_LIBTOOL +LT_INIT + +AC_ARG_WITH([valgrind], + AC_HELP_STRING([--with-valgrind], + [Enable Valgrind annotations (small runtime overhead, default NO)])) +if test x$with_valgrind = x || test x$with_valgrind = xno; then + want_valgrind=no + AC_DEFINE([NVALGRIND], 1, [Define to 1 to disable Valgrind annotations.]) +else + want_valgrind=yes + if test -d $with_valgrind; then + CPPFLAGS="$CPPFLAGS -I$with_valgrind/include" + fi +fi + +dnl Checks for programs +AC_PROG_CC +AC_PROG_LN_S + +dnl Checks for libraries +AC_CHECK_LIB(dl, dlsym, [], + AC_MSG_ERROR([dlsym() not found. libibverbs requires libdl.])) +AC_CHECK_LIB(pthread, pthread_mutex_init, [], + AC_MSG_ERROR([pthread_mutex_init() not found. libibverbs requires libpthread.])) + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADER(valgrind/memcheck.h, + [AC_DEFINE(HAVE_VALGRIND_MEMCHECK_H, 1, + [Define to 1 if you have the header file.])], + [if test $want_valgrind = yes; then + AC_MSG_ERROR([Valgrind memcheck support requested, but not found.]) + fi]) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +AC_CACHE_CHECK(whether ld accepts --version-script, ac_cv_version_script, + [if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then + ac_cv_version_script=yes + else + ac_cv_version_script=no + fi]) + +if test $ac_cv_version_script = yes; then + LIBIBVERBS_VERSION_SCRIPT='-Wl,--version-script=$(srcdir)/src/libibverbs.map' +else + LIBIBVERBS_VERSION_SCRIPT= +fi +AC_SUBST(LIBIBVERBS_VERSION_SCRIPT) + +AC_CACHE_CHECK(for .symver assembler support, ac_cv_asm_symver_support, + [AC_TRY_COMPILE(, [asm("symbol:\n.symver symbol, api@ABI\n");], + ac_cv_asm_symver_support=yes, + ac_cv_asm_symver_support=no)]) +if test $ac_cv_asm_symver_support = yes; then + AC_DEFINE([HAVE_SYMVER_SUPPORT], 1, [assembler has .symver support]) +fi + +AC_CONFIG_FILES([Makefile libibverbs.spec]) +AC_OUTPUT diff --git a/contrib/ofed/libibverbs/debian/changelog b/contrib/ofed/libibverbs/debian/changelog new file mode 100644 index 000000000000..2278511a93e7 --- /dev/null +++ b/contrib/ofed/libibverbs/debian/changelog @@ -0,0 +1,78 @@ +libibverbs (1.1.2-1) unstable; urgency=low + + * New upstream release. + - Fix memory registration failure cause by too-big madvise() + - Fix many Valgrind false positives + - Add functions to convert enum values to strings + * Replace deprecated ${Source-Version} with ${binary:Version} + * Use DEB_DH_MAKESHLIBS_ARGS_ALL to pass appropriate -V option to + dh_makeshlibs, since new symbols were added in libibverbs 1.1.2. + (Closes: #465435) + * Add debian/watch file. + * Update control file to talk about generic RDMA and iWARP, not just + InfiniBand, since libibverbs works with both IB and iWARP. + * Acknowledge NMU (Closes: #442638). + + -- Roland Dreier Fri, 18 Apr 2008 15:08:52 -0700 + +libibverbs (1.1.1-1.1) unstable; urgency=low + + * Non-maintainer upload. + * Re-generated autotools files to fix double build bug, closes: #442638 + * Bumped Standards-Version to 3.7.3, no change needed. + + -- Michael Meskes Mon, 14 Apr 2008 10:07:58 +0000 + +libibverbs (1.1.1-1) unstable; urgency=low + + * New upstream release. + - Initialize state of newly created QPs to RESET (fixes problems + with libmlx4/ConnectX HCAs). + - Don't warn root about RLIMIT_MEMLOCK, since it doesn't matter. + - Fix free() errors in ibv_xx_pingpong examples. + + -- Roland Dreier Fri, 15 Jun 2007 12:49:02 -0700 + +libibverbs (1.1-1) unstable; urgency=low + + * New upstream release. + - Add support for use of fork() in applications. + - Add manual pages documenting API in section 3. + - New method of finding and loading device-specific drivers. + - Add basic support for iWARP devices. + - Provide compatible ABI for applications linked against libibverbs 1.0. + * Update libtool during build to avoid setting RPATH in binaries on amd64. + + -- Roland Dreier Sat, 28 Apr 2007 14:15:29 -0700 + +libibverbs (1.0.4-1) unstable; urgency=low + + * New upstream release. + - Fix static linking so it has a chance of working. + - Fix cut-and-paste error in sparc mb() macro. + - Other miscellaneous fixes. + * Improve package description. + + -- Roland Dreier Tue, 31 Oct 2006 15:04:33 -0800 + +libibverbs (1.0.3-1) unstable; urgency=low + + * Change priority to extra, since libibverbs depends on libsysfs2, which + has priority extra. (Debian policy section 2.5 states that a package + may not depend on another package of lower priority) + * New upstream release: + - For sparc, only generate membar instruction if compiling for V9 + instruction set. (Closes: #365559) + - Reduce (but not yet eliminate) dependency on libsysfs. + - Deprecate some ib_XXX symbol names and introduce ibv_XXX + replacements for internal consistency. + - Other minor fixes. + * Update to Standards-Version: 3.7.2. + + -- Roland Dreier Tue, 2 May 2006 15:33:14 -0700 + +libibverbs (1.0.2-1) unstable; urgency=low + + * Initial Release. (Closes: #325752) + + -- Roland Dreier Wed, 15 Feb 2006 11:21:59 -0700 diff --git a/contrib/ofed/libibverbs/debian/compat b/contrib/ofed/libibverbs/debian/compat new file mode 100644 index 000000000000..7ed6ff82de6b --- /dev/null +++ b/contrib/ofed/libibverbs/debian/compat @@ -0,0 +1 @@ +5 diff --git a/contrib/ofed/libibverbs/debian/control.in b/contrib/ofed/libibverbs/debian/control.in new file mode 100644 index 000000000000..d86c0b305827 --- /dev/null +++ b/contrib/ofed/libibverbs/debian/control.in @@ -0,0 +1,80 @@ +Source: libibverbs +Priority: extra +Maintainer: Roland Dreier +Build-Depends: @cdbs@, dpkg-dev (>= 1.13.19) +Standards-Version: 3.7.3 +Section: libs +Homepage: http://www.openfabrics.org/ + +Package: libibverbs1 +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, adduser +Description: A library for direct userspace use of RDMA (InfiniBand/iWARP) + libibverbs is a library that allows userspace processes to use RDMA + "verbs" as described in the InfiniBand Architecture Specification and + the RDMA Protocol Verbs Specification. iWARP ethernet NICs support + RDMA over hardware-offloaded TCP/IP, while InfiniBand is a + high-throughput, low-latency networking technology. InfiniBand host + channel adapters (HCAs) and iWARP NICs commonly support direct + hardware access from userspace (kernel bypass), and libibverbs + supports this when available. + . + For this library to be useful, a device-specific plug-in module + should also be installed. + . + This package contains the shared library. + +Package: libibverbs-dev +Section: libdevel +Architecture: any +Depends: ${misc:Depends}, libibverbs1 (= ${binary:Version}) +Description: Development files for the libibverbs library + libibverbs is a library that allows userspace processes to use RDMA + "verbs" as described in the InfiniBand Architecture Specification and + the RDMA Protocol Verbs Specification. iWARP ethernet NICs support + RDMA over hardware-offloaded TCP/IP, while InfiniBand is a + high-throughput, low-latency networking technology. InfiniBand host + channel adapters (HCAs) and iWARP NICs commonly support direct + hardware access from userspace (kernel bypass), and libibverbs + supports this when available. + . + This package is needed to compile programs against libibverbs1. + It contains the header files and static libraries (optionally) + needed for compiling. + +Package: libibverbs1-dbg +Section: libdevel +Priority: extra +Architecture: any +Depends: ${misc:Depends}, libibverbs1 (= ${binary:Version}) +Description: Debugging symbols for the libibverbs library + libibverbs is a library that allows userspace processes to use RDMA + "verbs" as described in the InfiniBand Architecture Specification and + the RDMA Protocol Verbs Specification. iWARP ethernet NICs support + RDMA over hardware-offloaded TCP/IP, while InfiniBand is a + high-throughput, low-latency networking technology. InfiniBand host + channel adapters (HCAs) and iWARP NICs commonly support direct + hardware access from userspace (kernel bypass), and libibverbs + supports this when available. + . + This package contains the debugging symbols associated with + libibverbs1. They will automatically be used by gdb for debugging + libibverbs-related issues. + +Package: ibverbs-utils +Section: net +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Examples for the libibverbs library + libibverbs is a library that allows userspace processes to use RDMA + "verbs" as described in the InfiniBand Architecture Specification and + the RDMA Protocol Verbs Specification. iWARP ethernet NICs support + RDMA over hardware-offloaded TCP/IP, while InfiniBand is a + high-throughput, low-latency networking technology. InfiniBand host + channel adapters (HCAs) and iWARP NICs commonly support direct + hardware access from userspace (kernel bypass), and libibverbs + supports this when available. + . + This package contains useful libibverbs1 example programs such as + ibv_devinfo, which displays information about InfiniBand devices. diff --git a/contrib/ofed/libibverbs/debian/copyright b/contrib/ofed/libibverbs/debian/copyright new file mode 100644 index 000000000000..58a8e6c02638 --- /dev/null +++ b/contrib/ofed/libibverbs/debian/copyright @@ -0,0 +1,49 @@ +Initial Debianization: +This package was debianized by Roland Dreier on +Mon, 25 Apr 2005 10:21:08 -0700. + +Source: +It was downloaded from the OpenIB web site at + + +Authors: + Roland Dreier + Dotan Barak + Sean Hefty + Michael S. Tsirkin + +Portions are copyrighted by: + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + +libibverbs is licensed under a choice of one of two licenses. You may +choose to be licensed under the terms of the GNU General Public +License (GPL) Version 2, available from the file +/usr/share/common-licenses/GPL-2 on your Debian system, or the +OpenIB.org BSD license below: + + Redistribution and use in source and binary forms, with or + without modification, are permitted provided that the following + conditions are met: + + - Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + - Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/contrib/ofed/libibverbs/debian/ibverbs-utils.install b/contrib/ofed/libibverbs/debian/ibverbs-utils.install new file mode 100644 index 000000000000..98d15831b4c5 --- /dev/null +++ b/contrib/ofed/libibverbs/debian/ibverbs-utils.install @@ -0,0 +1,2 @@ +usr/bin +usr/share/man/man1 diff --git a/contrib/ofed/libibverbs/debian/libibverbs-dev.install b/contrib/ofed/libibverbs/debian/libibverbs-dev.install new file mode 100644 index 000000000000..d4b7db7ebc92 --- /dev/null +++ b/contrib/ofed/libibverbs/debian/libibverbs-dev.install @@ -0,0 +1,3 @@ +usr/include +usr/lib/libibverbs*.{a,la,so} +usr/share/man/man3 diff --git a/contrib/ofed/libibverbs/debian/libibverbs-dev.links b/contrib/ofed/libibverbs/debian/libibverbs-dev.links new file mode 100644 index 000000000000..702902885798 --- /dev/null +++ b/contrib/ofed/libibverbs/debian/libibverbs-dev.links @@ -0,0 +1,16 @@ +usr/share/man/man3/ibv_get_async_event.3 usr/share/man/man3/ibv_ack_async_event.3 +usr/share/man/man3/ibv_get_cq_event.3 usr/share/man/man3/ibv_ack_cq_events.3 +usr/share/man/man3/ibv_open_device.3 usr/share/man/man3/ibv_close_device.3 +usr/share/man/man3/ibv_alloc_pd.3 usr/share/man/man3/ibv_dealloc_pd.3 +usr/share/man/man3/ibv_reg_mr.3 usr/share/man/man3/ibv_dereg_mr.3 +usr/share/man/man3/ibv_create_ah.3 usr/share/man/man3/ibv_destroy_ah.3 +usr/share/man/man3/ibv_create_comp_channel.3 usr/share/man/man3/ibv_destroy_comp_channel.3 +usr/share/man/man3/ibv_create_cq.3 usr/share/man/man3/ibv_destroy_cq.3 +usr/share/man/man3/ibv_create_qp.3 usr/share/man/man3/ibv_destroy_qp.3 +usr/share/man/man3/ibv_create_srq.3 usr/share/man/man3/ibv_destroy_srq.3 +usr/share/man/man3/ibv_attach_mcast.3 usr/share/man/man3/ibv_detach_mcast.3 +usr/share/man/man3/ibv_get_device_list.3 usr/share/man/man3/ibv_free_device_list.3 +usr/share/man/man3/ibv_create_ah_from_wc.3 usr/share/man/man3/ibv_init_ah_from_wc.3 +usr/share/man/man3/ibv_rate_to_mult.3 usr/share/man/man3/mult_to_ibv_rate.3 +usr/share/man/man3/ibv_event_type_str.3 usr/share/man/man3/ibv_node_type_str.3 +usr/share/man/man3/ibv_event_type_str.3 usr/share/man/man3/ibv_port_state_str.3 diff --git a/contrib/ofed/libibverbs/debian/libibverbs1.install b/contrib/ofed/libibverbs/debian/libibverbs1.install new file mode 100644 index 000000000000..0f3523db5354 --- /dev/null +++ b/contrib/ofed/libibverbs/debian/libibverbs1.install @@ -0,0 +1 @@ +usr/lib/libibverbs*.so.* diff --git a/contrib/ofed/libibverbs/debian/libibverbs1.postinst b/contrib/ofed/libibverbs/debian/libibverbs1.postinst new file mode 100644 index 000000000000..f7d2ee6f801a --- /dev/null +++ b/contrib/ofed/libibverbs/debian/libibverbs1.postinst @@ -0,0 +1,12 @@ +#!/bin/sh +# postinst script for libibverbs1 + +set -e + +if [ "$1" != configure ]; then + exit 0 +fi + +getent group rdma > /dev/null 2>&1 || addgroup --system --quiet rdma + +#DEBHELPER# diff --git a/contrib/ofed/libibverbs/debian/rules b/contrib/ofed/libibverbs/debian/rules new file mode 100755 index 000000000000..5b4038839eea --- /dev/null +++ b/contrib/ofed/libibverbs/debian/rules @@ -0,0 +1,9 @@ +#!/usr/bin/make -f +# -*- mode: makefile; coding: utf-8 -*- + +DEB_DH_INSTALL_SOURCEDIR := debian/tmp +DEB_AUTO_UPDATE_LIBTOOL := post +DEB_DH_MAKESHLIBS_ARGS_ALL := -V 'libibverbs1 (>= 1.1.2)' + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/autotools.mk diff --git a/contrib/ofed/libibverbs/debian/watch b/contrib/ofed/libibverbs/debian/watch new file mode 100644 index 000000000000..eff271adabca --- /dev/null +++ b/contrib/ofed/libibverbs/debian/watch @@ -0,0 +1,3 @@ +version=3 +opts="uversionmangle=s/-rc/~rc/" \ + http://www.openfabrics.org/downloads/verbs/libibverbs-(.+)\.tar\.gz diff --git a/contrib/ofed/libibverbs/examples/Makefile b/contrib/ofed/libibverbs/examples/Makefile new file mode 100644 index 000000000000..06da51161e16 --- /dev/null +++ b/contrib/ofed/libibverbs/examples/Makefile @@ -0,0 +1,28 @@ +CFLAGS= -I../../../../sys/ofed/include -libverbs -lmlx4 -lmthca -pthread + +all: asyncwatch devinfo device_list rc_pingpong srq_pingpong uc_pingpong ud_pingpong + +clean: + rm asyncwatch devinfo device_list rc_pingpong srq_pingpong uc_pingpong ud_pingpong + +asyncwatch: + gcc -o asyncwatch asyncwatch.c ${CFLAGS} + +devinfo: + gcc -o devinfo devinfo.c ${CFLAGS} + +device_list: + gcc -o device_list device_list.c ${CFLAGS} + +rc_pingpong: + gcc -o rc_pingpong rc_pingpong.c pingpong.c ${CFLAGS} + +srq_pingpong: + gcc -o srq_pingpong srq_pingpong.c pingpong.c ${CFLAGS} + +uc_pingpong: + gcc -o uc_pingpong uc_pingpong.c pingpong.c ${CFLAGS} + +ud_pingpong: + gcc -o ud_pingpong ud_pingpong.c pingpong.c ${CFLAGS} + diff --git a/contrib/ofed/libibverbs/examples/asyncwatch.c b/contrib/ofed/libibverbs/examples/asyncwatch.c new file mode 100644 index 000000000000..da7ebd42a328 --- /dev/null +++ b/contrib/ofed/libibverbs/examples/asyncwatch.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include + +static const char *event_name_str(enum ibv_event_type event_type) +{ + switch (event_type) { + case IBV_EVENT_DEVICE_FATAL: + return "IBV_EVENT_DEVICE_FATAL"; + case IBV_EVENT_PORT_ACTIVE: + return "IBV_EVENT_PORT_ACTIVE"; + case IBV_EVENT_PORT_ERR: + return "IBV_EVENT_PORT_ERR"; + case IBV_EVENT_LID_CHANGE: + return "IBV_EVENT_LID_CHANGE"; + case IBV_EVENT_PKEY_CHANGE: + return "IBV_EVENT_PKEY_CHANGE"; + case IBV_EVENT_SM_CHANGE: + return "IBV_EVENT_SM_CHANGE"; + case IBV_EVENT_CLIENT_REREGISTER: + return "IBV_EVENT_CLIENT_REREGISTER"; + case IBV_EVENT_GID_CHANGE: + return "IBV_EVENT_GID_CHANGE"; + + case IBV_EVENT_CQ_ERR: + case IBV_EVENT_QP_FATAL: + case IBV_EVENT_QP_REQ_ERR: + case IBV_EVENT_QP_ACCESS_ERR: + case IBV_EVENT_COMM_EST: + case IBV_EVENT_SQ_DRAINED: + case IBV_EVENT_PATH_MIG: + case IBV_EVENT_PATH_MIG_ERR: + case IBV_EVENT_SRQ_ERR: + case IBV_EVENT_SRQ_LIMIT_REACHED: + case IBV_EVENT_QP_LAST_WQE_REACHED: + default: + return "unexpected"; + } +} + +int main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct ibv_context *context; + struct ibv_async_event event; + + /* Force line-buffering in case stdout is redirected */ + setvbuf(stdout, NULL, _IOLBF, 0); + + dev_list = ibv_get_device_list(NULL); + if (!dev_list) { + perror("Failed to get IB devices list"); + return 1; + } + + if (!*dev_list) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + + context = ibv_open_device(*dev_list); + if (!context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(*dev_list)); + return 1; + } + + printf("%s: async event FD %d\n", + ibv_get_device_name(*dev_list), context->async_fd); + + while (1) { + if (ibv_get_async_event(context, &event)) + return 1; + + printf(" event_type %s (%d), port %d\n", + event_name_str(event.event_type), + event.event_type, event.element.port_num); + + ibv_ack_async_event(&event); + } + + return 0; +} diff --git a/contrib/ofed/libibverbs/examples/device_list.c b/contrib/ofed/libibverbs/examples/device_list.c new file mode 100644 index 000000000000..70c3af51b6c3 --- /dev/null +++ b/contrib/ofed/libibverbs/examples/device_list.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#include +#include + +#include +#include + +int main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + int num_devices, i; + + dev_list = ibv_get_device_list(&num_devices); + if (!dev_list) { + perror("Failed to get IB devices list"); + return 1; + } + + printf(" %-16s\t node GUID\n", "device"); + printf(" %-16s\t----------------\n", "------"); + + for (i = 0; i < num_devices; ++i) { + printf(" %-16s\t%016llx\n", + ibv_get_device_name(dev_list[i]), + (unsigned long long) ntohll(ibv_get_device_guid(dev_list[i]))); + } + + ibv_free_device_list(dev_list); + + return 0; +} diff --git a/contrib/ofed/libibverbs/examples/devinfo.c b/contrib/ofed/libibverbs/examples/devinfo.c new file mode 100644 index 000000000000..393ec042a5d8 --- /dev/null +++ b/contrib/ofed/libibverbs/examples/devinfo.c @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static int verbose; + +static int null_gid(union ibv_gid *gid) +{ + return !(gid->raw[8] | gid->raw[9] | gid->raw[10] | gid->raw[11] | + gid->raw[12] | gid->raw[13] | gid->raw[14] | gid->raw[15]); +} + +static const char *guid_str(uint64_t node_guid, char *str) +{ + node_guid = ntohll(node_guid); + sprintf(str, "%04x:%04x:%04x:%04x", + (unsigned) (node_guid >> 48) & 0xffff, + (unsigned) (node_guid >> 32) & 0xffff, + (unsigned) (node_guid >> 16) & 0xffff, + (unsigned) (node_guid >> 0) & 0xffff); + return str; +} + +static const char *transport_str(enum ibv_transport_type transport) +{ + switch (transport) { + case IBV_TRANSPORT_IB: return "InfiniBand"; + case IBV_TRANSPORT_IWARP: return "iWARP"; + default: return "invalid transport"; + } +} + +static const char *port_state_str(enum ibv_port_state pstate) +{ + switch (pstate) { + case IBV_PORT_DOWN: return "PORT_DOWN"; + case IBV_PORT_INIT: return "PORT_INIT"; + case IBV_PORT_ARMED: return "PORT_ARMED"; + case IBV_PORT_ACTIVE: return "PORT_ACTIVE"; + default: return "invalid state"; + } +} + +static const char *port_phy_state_str(uint8_t phys_state) +{ + switch (phys_state) { + case 1: return "SLEEP"; + case 2: return "POLLING"; + case 3: return "DISABLED"; + case 4: return "PORT_CONFIGURATION TRAINNING"; + case 5: return "LINK_UP"; + case 6: return "LINK_ERROR_RECOVERY"; + case 7: return "PHY TEST"; + default: return "invalid physical state"; + } +} + +static const char *atomic_cap_str(enum ibv_atomic_cap atom_cap) +{ + switch (atom_cap) { + case IBV_ATOMIC_NONE: return "ATOMIC_NONE"; + case IBV_ATOMIC_HCA: return "ATOMIC_HCA"; + case IBV_ATOMIC_GLOB: return "ATOMIC_GLOB"; + default: return "invalid atomic capability"; + } +} + +static const char *mtu_str(enum ibv_mtu max_mtu) +{ + switch (max_mtu) { + case IBV_MTU_256: return "256"; + case IBV_MTU_512: return "512"; + case IBV_MTU_1024: return "1024"; + case IBV_MTU_2048: return "2048"; + case IBV_MTU_4096: return "4096"; + default: return "invalid MTU"; + } +} + +static const char *width_str(uint8_t width) +{ + switch (width) { + case 1: return "1"; + case 2: return "4"; + case 4: return "8"; + case 8: return "12"; + default: return "invalid width"; + } +} + +static const char *speed_str(uint8_t speed) +{ + switch (speed) { + case 1: return "2.5 Gbps"; + case 2: return "5.0 Gbps"; + case 4: return "10.0 Gbps"; + default: return "invalid speed"; + } +} + +static const char *vl_str(uint8_t vl_num) +{ + switch (vl_num) { + case 1: return "1"; + case 2: return "2"; + case 3: return "4"; + case 4: return "8"; + case 5: return "15"; + default: return "invalid value"; + } +} + +static int print_all_port_gids(struct ibv_context *ctx, uint8_t port_num, int tbl_len) +{ + union ibv_gid gid; + int rc = 0; + int i; + + for (i = 0; i < tbl_len; i++) { + rc = ibv_query_gid(ctx, port_num, i, &gid); + if (rc) { + fprintf(stderr, "Failed to query gid to port %d, index %d\n", + port_num, i); + return rc; + } + if (!null_gid(&gid)) + printf("\t\t\tGID[%3d]:\t\t%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", + i, + gid.raw[ 0], gid.raw[ 1], + gid.raw[ 2], gid.raw[ 3], + gid.raw[ 4], gid.raw[ 5], + gid.raw[ 6], gid.raw[ 7], + gid.raw[ 8], gid.raw[ 9], + gid.raw[10], gid.raw[11], + gid.raw[12], gid.raw[13], + gid.raw[14], gid.raw[15]); + } + return rc; +} + +static const char *link_layer_str(uint8_t link_layer) +{ + switch (link_layer) { + case IBV_LINK_LAYER_UNSPECIFIED: + case IBV_LINK_LAYER_INFINIBAND: + return "IB"; + case IBV_LINK_LAYER_ETHERNET: + return "Ethernet"; + default: + return "Unknown"; + } +} + +static int print_hca_cap(struct ibv_device *ib_dev, uint8_t ib_port) +{ + struct ibv_context *ctx; + struct ibv_device_attr device_attr; + struct ibv_port_attr port_attr; + int rc = 0; + uint8_t port; + char buf[256]; + + ctx = ibv_open_device(ib_dev); + if (!ctx) { + fprintf(stderr, "Failed to open device\n"); + rc = 1; + goto cleanup; + } + if (ibv_query_device(ctx, &device_attr)) { + fprintf(stderr, "Failed to query device props"); + rc = 2; + goto cleanup; + } + + printf("hca_id:\t%s\n", ibv_get_device_name(ib_dev)); + printf("\ttransport:\t\t\t%s (%d)\n", + transport_str(ib_dev->transport_type), ib_dev->transport_type); + if (strlen(device_attr.fw_ver)) + printf("\tfw_ver:\t\t\t\t%s\n", device_attr.fw_ver); + printf("\tnode_guid:\t\t\t%s\n", guid_str(device_attr.node_guid, buf)); + printf("\tsys_image_guid:\t\t\t%s\n", guid_str(device_attr.sys_image_guid, buf)); + printf("\tvendor_id:\t\t\t0x%04x\n", device_attr.vendor_id); + printf("\tvendor_part_id:\t\t\t%d\n", device_attr.vendor_part_id); + printf("\thw_ver:\t\t\t\t0x%X\n", device_attr.hw_ver); + + if (ibv_read_sysfs_file(ib_dev->ibdev_path, "board_id", buf, sizeof buf) > 0) + printf("\tboard_id:\t\t\t%s\n", buf); + + printf("\tphys_port_cnt:\t\t\t%d\n", device_attr.phys_port_cnt); + + if (verbose) { + printf("\tmax_mr_size:\t\t\t0x%llx\n", + (unsigned long long) device_attr.max_mr_size); + printf("\tpage_size_cap:\t\t\t0x%llx\n", + (unsigned long long) device_attr.page_size_cap); + printf("\tmax_qp:\t\t\t\t%d\n", device_attr.max_qp); + printf("\tmax_qp_wr:\t\t\t%d\n", device_attr.max_qp_wr); + printf("\tdevice_cap_flags:\t\t0x%08x\n", device_attr.device_cap_flags); + printf("\tmax_sge:\t\t\t%d\n", device_attr.max_sge); + printf("\tmax_sge_rd:\t\t\t%d\n", device_attr.max_sge_rd); + printf("\tmax_cq:\t\t\t\t%d\n", device_attr.max_cq); + printf("\tmax_cqe:\t\t\t%d\n", device_attr.max_cqe); + printf("\tmax_mr:\t\t\t\t%d\n", device_attr.max_mr); + printf("\tmax_pd:\t\t\t\t%d\n", device_attr.max_pd); + printf("\tmax_qp_rd_atom:\t\t\t%d\n", device_attr.max_qp_rd_atom); + printf("\tmax_ee_rd_atom:\t\t\t%d\n", device_attr.max_ee_rd_atom); + printf("\tmax_res_rd_atom:\t\t%d\n", device_attr.max_res_rd_atom); + printf("\tmax_qp_init_rd_atom:\t\t%d\n", device_attr.max_qp_init_rd_atom); + printf("\tmax_ee_init_rd_atom:\t\t%d\n", device_attr.max_ee_init_rd_atom); + printf("\tatomic_cap:\t\t\t%s (%d)\n", + atomic_cap_str(device_attr.atomic_cap), device_attr.atomic_cap); + printf("\tmax_ee:\t\t\t\t%d\n", device_attr.max_ee); + printf("\tmax_rdd:\t\t\t%d\n", device_attr.max_rdd); + printf("\tmax_mw:\t\t\t\t%d\n", device_attr.max_mw); + printf("\tmax_raw_ipv6_qp:\t\t%d\n", device_attr.max_raw_ipv6_qp); + printf("\tmax_raw_ethy_qp:\t\t%d\n", device_attr.max_raw_ethy_qp); + printf("\tmax_mcast_grp:\t\t\t%d\n", device_attr.max_mcast_grp); + printf("\tmax_mcast_qp_attach:\t\t%d\n", device_attr.max_mcast_qp_attach); + printf("\tmax_total_mcast_qp_attach:\t%d\n", + device_attr.max_total_mcast_qp_attach); + printf("\tmax_ah:\t\t\t\t%d\n", device_attr.max_ah); + printf("\tmax_fmr:\t\t\t%d\n", device_attr.max_fmr); + if (device_attr.max_fmr) + printf("\tmax_map_per_fmr:\t\t%d\n", device_attr.max_map_per_fmr); + printf("\tmax_srq:\t\t\t%d\n", device_attr.max_srq); + if (device_attr.max_srq) { + printf("\tmax_srq_wr:\t\t\t%d\n", device_attr.max_srq_wr); + printf("\tmax_srq_sge:\t\t\t%d\n", device_attr.max_srq_sge); + } + printf("\tmax_pkeys:\t\t\t%d\n", device_attr.max_pkeys); + printf("\tlocal_ca_ack_delay:\t\t%d\n", device_attr.local_ca_ack_delay); + } + + for (port = 1; port <= device_attr.phys_port_cnt; ++port) { + /* if in the command line the user didn't ask for info about this port */ + if ((ib_port) && (port != ib_port)) + continue; + + rc = ibv_query_port(ctx, port, &port_attr); + if (rc) { + fprintf(stderr, "Failed to query port %u props\n", port); + goto cleanup; + } + printf("\t\tport:\t%d\n", port); + printf("\t\t\tstate:\t\t\t%s (%d)\n", + port_state_str(port_attr.state), port_attr.state); + printf("\t\t\tmax_mtu:\t\t%s (%d)\n", + mtu_str(port_attr.max_mtu), port_attr.max_mtu); + printf("\t\t\tactive_mtu:\t\t%s (%d)\n", + mtu_str(port_attr.active_mtu), port_attr.active_mtu); + printf("\t\t\tsm_lid:\t\t\t%d\n", port_attr.sm_lid); + printf("\t\t\tport_lid:\t\t%d\n", port_attr.lid); + printf("\t\t\tport_lmc:\t\t0x%02x\n", port_attr.lmc); + printf("\t\t\tlink_layer:\t\t%s\n", link_layer_str(port_attr.link_layer)); + + if (verbose) { + printf("\t\t\tmax_msg_sz:\t\t0x%x\n", port_attr.max_msg_sz); + printf("\t\t\tport_cap_flags:\t\t0x%08x\n", port_attr.port_cap_flags); + printf("\t\t\tmax_vl_num:\t\t%s (%d)\n", + vl_str(port_attr.max_vl_num), port_attr.max_vl_num); + printf("\t\t\tbad_pkey_cntr:\t\t0x%x\n", port_attr.bad_pkey_cntr); + printf("\t\t\tqkey_viol_cntr:\t\t0x%x\n", port_attr.qkey_viol_cntr); + printf("\t\t\tsm_sl:\t\t\t%d\n", port_attr.sm_sl); + printf("\t\t\tpkey_tbl_len:\t\t%d\n", port_attr.pkey_tbl_len); + printf("\t\t\tgid_tbl_len:\t\t%d\n", port_attr.gid_tbl_len); + printf("\t\t\tsubnet_timeout:\t\t%d\n", port_attr.subnet_timeout); + printf("\t\t\tinit_type_reply:\t%d\n", port_attr.init_type_reply); + printf("\t\t\tactive_width:\t\t%sX (%d)\n", + width_str(port_attr.active_width), port_attr.active_width); + printf("\t\t\tactive_speed:\t\t%s (%d)\n", + speed_str(port_attr.active_speed), port_attr.active_speed); + printf("\t\t\tphys_state:\t\t%s (%d)\n", + port_phy_state_str(port_attr.phys_state), port_attr.phys_state); + + if (print_all_port_gids(ctx, port, port_attr.gid_tbl_len)) + goto cleanup; + } + printf("\n"); + } +cleanup: + if (ctx) + if (ibv_close_device(ctx)) { + fprintf(stderr, "Failed to close device"); + rc = 3; + } + return rc; +} + +static void usage(const char *argv0) +{ + printf("Usage: %s print the ca attributes\n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -d, --ib-dev= use IB device (default first device found)\n"); + printf(" -i, --ib-port= use port of IB device (default all ports)\n"); + printf(" -l, --list print only the IB devices names\n"); + printf(" -v, --verbose print all the attributes of the IB device(s)\n"); +} + +int main(int argc, char *argv[]) +{ + char *ib_devname = NULL; + int ret = 0; + struct ibv_device **dev_list, **orig_dev_list; + int num_of_hcas; + int ib_port = 0; + + /* parse command line options */ + while (1) { + int c; + static struct option long_options[] = { + { .name = "ib-dev", .has_arg = 1, .val = 'd' }, + { .name = "ib-port", .has_arg = 1, .val = 'i' }, + { .name = "list", .has_arg = 0, .val = 'l' }, + { .name = "verbose", .has_arg = 0, .val = 'v' }, + { 0, 0, 0, 0} + }; + + c = getopt_long(argc, argv, "d:i:lv", long_options, NULL); + if (c == -1) + break; + + switch (c) { + case 'd': + ib_devname = strdup(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 'v': + verbose = 1; + break; + + case 'l': + dev_list = orig_dev_list = ibv_get_device_list(&num_of_hcas); + if (!dev_list) { + perror("Failed to get IB devices list"); + return -1; + } + + printf("%d HCA%s found:\n", num_of_hcas, + num_of_hcas != 1 ? "s" : ""); + + while (*dev_list) { + printf("\t%s\n", ibv_get_device_name(*dev_list)); + ++dev_list; + } + + printf("\n"); + + ibv_free_device_list(orig_dev_list); + + return 0; + + default: + usage(argv[0]); + return -1; + } + } + + dev_list = orig_dev_list = ibv_get_device_list(NULL); + if (!dev_list) { + perror("Failed to get IB devices list"); + return -1; + } + + if (ib_devname) { + while (*dev_list) { + if (!strcmp(ibv_get_device_name(*dev_list), ib_devname)) + break; + ++dev_list; + } + + if (!*dev_list) { + fprintf(stderr, "IB device '%s' wasn't found\n", ib_devname); + return -1; + } + + ret |= print_hca_cap(*dev_list, ib_port); + } else { + if (!*dev_list) { + fprintf(stderr, "No IB devices found\n"); + return -1; + } + + while (*dev_list) { + ret |= print_hca_cap(*dev_list, ib_port); + ++dev_list; + } + } + + if (ib_devname) + free(ib_devname); + + ibv_free_device_list(orig_dev_list); + + return ret; +} diff --git a/contrib/ofed/libibverbs/examples/pingpong.c b/contrib/ofed/libibverbs/examples/pingpong.c new file mode 100644 index 000000000000..806f44687db6 --- /dev/null +++ b/contrib/ofed/libibverbs/examples/pingpong.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "pingpong.h" +#include +#include +#include +#include + +enum ibv_mtu pp_mtu_to_enum(int mtu) +{ + switch (mtu) { + case 256: return IBV_MTU_256; + case 512: return IBV_MTU_512; + case 1024: return IBV_MTU_1024; + case 2048: return IBV_MTU_2048; + case 4096: return IBV_MTU_4096; + default: return -1; + } +} + +uint16_t pp_get_local_lid(struct ibv_context *context, int port) +{ + struct ibv_port_attr attr; + + if (ibv_query_port(context, port, &attr)) + return 0; + + return attr.lid; +} + +int pp_get_port_info(struct ibv_context *context, int port, + struct ibv_port_attr *attr) +{ + return ibv_query_port(context, port, attr); +} + +void wire_gid_to_gid(const char *wgid, union ibv_gid *gid) +{ + char tmp[9]; + uint32_t v32; + int i; + + for (tmp[8] = 0, i = 0; i < 4; ++i) { + memcpy(tmp, wgid + i * 8, 8); + sscanf(tmp, "%x", &v32); + *(uint32_t *)(&gid->raw[i * 4]) = ntohl(v32); + } +} + +void gid_to_wire_gid(const union ibv_gid *gid, char wgid[]) +{ + int i; + + for (i = 0; i < 4; ++i) + sprintf(&wgid[i * 8], "%08x", htonl(*(uint32_t *)(gid->raw + i * 4))); +} diff --git a/contrib/ofed/libibverbs/examples/pingpong.h b/contrib/ofed/libibverbs/examples/pingpong.h new file mode 100644 index 000000000000..829ceee53018 --- /dev/null +++ b/contrib/ofed/libibverbs/examples/pingpong.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2006 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IBV_PINGPONG_H +#define IBV_PINGPONG_H + +#include + +#include + +enum ibv_mtu pp_mtu_to_enum(int mtu); +uint16_t pp_get_local_lid(struct ibv_context *context, int port); +int pp_get_port_info(struct ibv_context *context, int port, + struct ibv_port_attr *attr); +void wire_gid_to_gid(const char *wgid, union ibv_gid *gid); +void gid_to_wire_gid(const union ibv_gid *gid, char wgid[]); + +#endif /* IBV_PINGPONG_H */ diff --git a/contrib/ofed/libibverbs/examples/rc_pingpong.c b/contrib/ofed/libibverbs/examples/rc_pingpong.c new file mode 100644 index 000000000000..ced719243f20 --- /dev/null +++ b/contrib/ofed/libibverbs/examples/rc_pingpong.c @@ -0,0 +1,827 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pingpong.h" + +enum { + PINGPONG_RECV_WRID = 1, + PINGPONG_SEND_WRID = 2, +}; + +static int page_size; + +struct pingpong_context { + struct ibv_context *context; + struct ibv_comp_channel *channel; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *cq; + struct ibv_qp *qp; + void *buf; + int size; + int rx_depth; + int pending; + struct ibv_port_attr portinfo; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; + union ibv_gid gid; +}; + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + enum ibv_mtu mtu, int sl, + struct pingpong_dest *dest, int sgid_idx) +{ + struct ibv_qp_attr attr = { + .qp_state = IBV_QPS_RTR, + .path_mtu = mtu, + .dest_qp_num = dest->qpn, + .rq_psn = dest->psn, + .max_dest_rd_atomic = 1, + .min_rnr_timer = 12, + .ah_attr = { + .is_global = 0, + .dlid = dest->lid, + .sl = sl, + .src_path_bits = 0, + .port_num = port + } + }; + + if (dest->gid.global.interface_id) { + attr.ah_attr.is_global = 1; + attr.ah_attr.grh.hop_limit = 1; + attr.ah_attr.grh.dgid = dest->gid; + attr.ah_attr.grh.sgid_index = sgid_idx; + } + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + 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)) { + fprintf(stderr, "Failed to modify QP to RTR\n"); + return 1; + } + + attr.qp_state = IBV_QPS_RTS; + attr.timeout = 14; + attr.retry_cnt = 7; + attr.rnr_retry = 7; + attr.sq_psn = my_psn; + attr.max_rd_atomic = 1; + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_TIMEOUT | + IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | + IBV_QP_SQ_PSN | + IBV_QP_MAX_QP_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify QP to RTS\n"); + return 1; + } + + return 0; +} + +static struct pingpong_dest *pp_client_exch_dest(const char *servername, int port, + const struct pingpong_dest *my_dest) +{ + struct addrinfo *res, *t; + struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM + }; + char *service; + char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int sockfd = -1; + struct pingpong_dest *rem_dest = NULL; + char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; + + n = getaddrinfo(servername, service, &hints, &res); + + if (n < 0) { + fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), servername, port); + free(service); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd >= 0) { + if (!connect(sockfd, t->ai_addr, t->ai_addrlen)) + break; + close(sockfd); + sockfd = -1; + } + } + + freeaddrinfo(res); + free(service); + + if (sockfd < 0) { + fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port); + return NULL; + } + + gid_to_wire_gid(&my_dest->gid, gid); + sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid); + if (write(sockfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + goto out; + } + + if (read(sockfd, msg, sizeof msg) != sizeof msg) { + perror("client read"); + fprintf(stderr, "Couldn't read remote address\n"); + goto out; + } + + write(sockfd, "done", sizeof "done"); + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid); + wire_gid_to_gid(gid, &rem_dest->gid); + +out: + close(sockfd); + return rem_dest; +} + +static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx, + int ib_port, enum ibv_mtu mtu, + int port, int sl, + const struct pingpong_dest *my_dest, + int sgid_idx) +{ + struct addrinfo *res, *t; + struct addrinfo hints = { + .ai_flags = AI_PASSIVE, + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM + }; + char *service; + char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int sockfd = -1, connfd; + struct pingpong_dest *rem_dest = NULL; + char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; + + n = getaddrinfo(NULL, service, &hints, &res); + + if (n < 0) { + fprintf(stderr, "%s for port %d\n", gai_strerror(n), port); + free(service); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd >= 0) { + n = 1; + + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n); + + if (!bind(sockfd, t->ai_addr, t->ai_addrlen)) + break; + close(sockfd); + sockfd = -1; + } + } + + freeaddrinfo(res); + free(service); + + if (sockfd < 0) { + fprintf(stderr, "Couldn't listen to port %d\n", port); + return NULL; + } + + listen(sockfd, 1); + connfd = accept(sockfd, NULL, 0); + close(sockfd); + if (connfd < 0) { + fprintf(stderr, "accept() failed\n"); + return NULL; + } + + n = read(connfd, msg, sizeof msg); + if (n != sizeof msg) { + perror("server read"); + fprintf(stderr, "%d/%d: Couldn't read remote address\n", n, (int) sizeof msg); + goto out; + } + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid); + wire_gid_to_gid(gid, &rem_dest->gid); + + if (pp_connect_ctx(ctx, ib_port, my_dest->psn, mtu, sl, rem_dest, sgid_idx)) { + fprintf(stderr, "Couldn't connect to remote QP\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + + gid_to_wire_gid(&my_dest->gid, gid); + sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid); + if (write(connfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + read(connfd, msg, sizeof msg); + +out: + close(connfd); + return rem_dest; +} + +#include + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size, + int rx_depth, int port, + int use_event, int is_server) +{ + struct pingpong_context *ctx; + + ctx = calloc(1, sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = size; + ctx->rx_depth = rx_depth; + + ctx->buf = malloc(roundup(size, page_size)); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0x7b + is_server, size); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + + if (use_event) { + ctx->channel = ibv_create_comp_channel(ctx->context); + if (!ctx->channel) { + fprintf(stderr, "Couldn't create completion channel\n"); + return NULL; + } + } else + ctx->channel = NULL; + + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size, IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't register MR\n"); + return NULL; + } + + ctx->cq = ibv_create_cq(ctx->context, rx_depth + 1, NULL, + ctx->channel, 0); + if (!ctx->cq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + + { + struct ibv_qp_init_attr attr = { + .send_cq = ctx->cq, + .recv_cq = ctx->cq, + .cap = { + .max_send_wr = 1, + .max_recv_wr = rx_depth, + .max_send_sge = 1, + .max_recv_sge = 1 + }, + .qp_type = IBV_QPT_RC + }; + + ctx->qp = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + } + + { + struct ibv_qp_attr attr = { + .qp_state = IBV_QPS_INIT, + .pkey_index = 0, + .port_num = port, + .qp_access_flags = 0 + }; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + + return ctx; +} + +int pp_close_ctx(struct pingpong_context *ctx) +{ + if (ibv_destroy_qp(ctx->qp)) { + fprintf(stderr, "Couldn't destroy QP\n"); + return 1; + } + + if (ibv_destroy_cq(ctx->cq)) { + fprintf(stderr, "Couldn't destroy CQ\n"); + return 1; + } + + if (ibv_dereg_mr(ctx->mr)) { + fprintf(stderr, "Couldn't deregister MR\n"); + return 1; + } + + if (ibv_dealloc_pd(ctx->pd)) { + fprintf(stderr, "Couldn't deallocate PD\n"); + return 1; + } + + if (ctx->channel) { + if (ibv_destroy_comp_channel(ctx->channel)) { + fprintf(stderr, "Couldn't destroy completion channel\n"); + return 1; + } + } + + if (ibv_close_device(ctx->context)) { + fprintf(stderr, "Couldn't release context\n"); + return 1; + } + + free(ctx->buf); + free(ctx); + + return 0; +} + +static int pp_post_recv(struct pingpong_context *ctx, int n) +{ + struct ibv_sge list = { + .addr = (uintptr_t) ctx->buf, + .length = ctx->size, + .lkey = ctx->mr->lkey + }; + struct ibv_recv_wr wr = { + .wr_id = PINGPONG_RECV_WRID, + .sg_list = &list, + .num_sge = 1, + }; + struct ibv_recv_wr *bad_wr; + int i; + + for (i = 0; i < n; ++i) + if (ibv_post_recv(ctx->qp, &wr, &bad_wr)) + break; + + return i; +} + +static int pp_post_send(struct pingpong_context *ctx) +{ + struct ibv_sge list = { + .addr = (uintptr_t) ctx->buf, + .length = ctx->size, + .lkey = ctx->mr->lkey + }; + struct ibv_send_wr wr = { + .wr_id = PINGPONG_SEND_WRID, + .sg_list = &list, + .num_sge = 1, + .opcode = IBV_WR_SEND, + .send_flags = IBV_SEND_SIGNALED, + }; + struct ibv_send_wr *bad_wr; + + return ibv_post_send(ctx->qp, &wr, &bad_wr); +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p, --port= listen on/connect to port (default 18515)\n"); + printf(" -d, --ib-dev= use IB device (default first device found)\n"); + printf(" -i, --ib-port= use port of IB device (default 1)\n"); + printf(" -s, --size= size of message to exchange (default 4096)\n"); + printf(" -m, --mtu= path MTU (default 1024)\n"); + printf(" -r, --rx-depth= number of receives to post at a time (default 500)\n"); + printf(" -n, --iters= number of exchanges (default 1000)\n"); + printf(" -l, --sl= service level value\n"); + printf(" -e, --events sleep on CQ events (default poll)\n"); + printf(" -g, --gid-idx= local port gid index\n"); +} + +int main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct ibv_device *ib_dev; + struct pingpong_context *ctx; + struct pingpong_dest my_dest; + struct pingpong_dest *rem_dest; + struct timeval start, end; + char *ib_devname = NULL; + char *servername = NULL; + int port = 18515; + int ib_port = 1; + int size = 4096; + enum ibv_mtu mtu = IBV_MTU_1024; + int rx_depth = 500; + int iters = 1000; + int use_event = 0; + int routs; + int rcnt, scnt; + int num_cq_events = 0; + int sl = 0; + int gidx = -1; + char gid[33]; + + srand48(getpid() * time(NULL)); + + while (1) { + int c; + + static struct option long_options[] = { + { .name = "port", .has_arg = 1, .val = 'p' }, + { .name = "ib-dev", .has_arg = 1, .val = 'd' }, + { .name = "ib-port", .has_arg = 1, .val = 'i' }, + { .name = "size", .has_arg = 1, .val = 's' }, + { .name = "mtu", .has_arg = 1, .val = 'm' }, + { .name = "rx-depth", .has_arg = 1, .val = 'r' }, + { .name = "iters", .has_arg = 1, .val = 'n' }, + { .name = "sl", .has_arg = 1, .val = 'l' }, + { .name = "events", .has_arg = 0, .val = 'e' }, + { .name = "gid-idx", .has_arg = 1, .val = 'g' }, + { 0 } + }; + + c = getopt_long(argc, argv, "p:d:i:s:m:r:n:l:eg:", long_options, NULL); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = strdup(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + break; + + case 'm': + mtu = pp_mtu_to_enum(strtol(optarg, NULL, 0)); + if (mtu < 0) { + usage(argv[0]); + return 1; + } + break; + + case 'r': + rx_depth = strtol(optarg, NULL, 0); + break; + + case 'n': + iters = strtol(optarg, NULL, 0); + break; + + case 'l': + sl = strtol(optarg, NULL, 0); + break; + + case 'e': + ++use_event; + break; + + case 'g': + gidx = strtol(optarg, NULL, 0); + break; + + default: + usage(argv[0]); + return 1; + } + } + + if (optind == argc - 1) + servername = strdup(argv[optind]); + else if (optind < argc) { + usage(argv[0]); + return 1; + } + + page_size = sysconf(_SC_PAGESIZE); + + dev_list = ibv_get_device_list(NULL); + if (!dev_list) { + perror("Failed to get IB devices list"); + return 1; + } + + if (!ib_devname) { + ib_dev = *dev_list; + if (!ib_dev) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + } else { + int i; + for (i = 0; dev_list[i]; ++i) + if (!strcmp(ibv_get_device_name(dev_list[i]), ib_devname)) + break; + ib_dev = dev_list[i]; + if (!ib_dev) { + fprintf(stderr, "IB device %s not found\n", ib_devname); + return 1; + } + } + + ctx = pp_init_ctx(ib_dev, size, rx_depth, ib_port, use_event, !servername); + if (!ctx) + return 1; + + routs = pp_post_recv(ctx, ctx->rx_depth); + if (routs < ctx->rx_depth) { + fprintf(stderr, "Couldn't post receive (%d)\n", routs); + return 1; + } + + if (use_event) + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + + + if (pp_get_port_info(ctx->context, ib_port, &ctx->portinfo)) { + fprintf(stderr, "Couldn't get port info\n"); + return 1; + } + + my_dest.lid = ctx->portinfo.lid; + if (ctx->portinfo.link_layer == IBV_LINK_LAYER_INFINIBAND && !my_dest.lid) { + fprintf(stderr, "Couldn't get local LID\n"); + return 1; + } + + if (gidx >= 0) { + if (ibv_query_gid(ctx->context, ib_port, gidx, &my_dest.gid)) { + fprintf(stderr, "Could not get local gid for gid index %d\n", gidx); + return 1; + } + } else + memset(&my_dest.gid, 0, sizeof my_dest.gid); + + my_dest.qpn = ctx->qp->qp_num; + my_dest.psn = lrand48() & 0xffffff; + inet_ntop(AF_INET6, &my_dest.gid, gid, sizeof gid); + printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", + my_dest.lid, my_dest.qpn, my_dest.psn, gid); + + + if (servername) + rem_dest = pp_client_exch_dest(servername, port, &my_dest); + else + rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, &my_dest, gidx); + + if (!rem_dest) + return 1; + + inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof gid); + printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", + rem_dest->lid, rem_dest->qpn, rem_dest->psn, gid); + + if (servername) + if (pp_connect_ctx(ctx, ib_port, my_dest.psn, mtu, sl, rem_dest, gidx)) + return 1; + + ctx->pending = PINGPONG_RECV_WRID; + + if (servername) { + if (pp_post_send(ctx)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending |= PINGPONG_SEND_WRID; + } + + if (gettimeofday(&start, NULL)) { + perror("gettimeofday"); + return 1; + } + + rcnt = scnt = 0; + while (rcnt < iters || scnt < iters) { + if (use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\n"); + return 1; + } + + ++num_cq_events; + + if (ev_cq != ctx->cq) { + fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq); + return 1; + } + + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + + { + struct ibv_wc wc[2]; + int ne, i; + + do { + ne = ibv_poll_cq(ctx->cq, 2, wc); + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } + + } while (!use_event && ne < 1); + + for (i = 0; i < ne; ++i) { + if (wc[i].status != IBV_WC_SUCCESS) { + fprintf(stderr, "Failed status %s (%d) for wr_id %d\n", + ibv_wc_status_str(wc[i].status), + wc[i].status, (int) wc[i].wr_id); + return 1; + } + + switch ((int) wc[i].wr_id) { + case PINGPONG_SEND_WRID: + ++scnt; + break; + + case PINGPONG_RECV_WRID: + if (--routs <= 1) { + routs += pp_post_recv(ctx, ctx->rx_depth - routs); + if (routs < ctx->rx_depth) { + fprintf(stderr, + "Couldn't post receive (%d)\n", + routs); + return 1; + } + } + + ++rcnt; + break; + + default: + fprintf(stderr, "Completion for unknown wr_id %d\n", + (int) wc[i].wr_id); + return 1; + } + + ctx->pending &= ~(int) wc[i].wr_id; + if (scnt < iters && !ctx->pending) { + if (pp_post_send(ctx)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending = PINGPONG_RECV_WRID | + PINGPONG_SEND_WRID; + } + } + } + } + + if (gettimeofday(&end, NULL)) { + perror("gettimeofday"); + return 1; + } + + { + float usec = (end.tv_sec - start.tv_sec) * 1000000 + + (end.tv_usec - start.tv_usec); + long long bytes = (long long) size * iters * 2; + + printf("%lld bytes in %.2f seconds = %.2f Mbit/sec\n", + bytes, usec / 1000000., bytes * 8. / usec); + printf("%d iters in %.2f seconds = %.2f usec/iter\n", + iters, usec / 1000000., usec / iters); + } + + ibv_ack_cq_events(ctx->cq, num_cq_events); + + if (pp_close_ctx(ctx)) + return 1; + + ibv_free_device_list(dev_list); + free(rem_dest); + + return 0; +} diff --git a/contrib/ofed/libibverbs/examples/srq_pingpong.c b/contrib/ofed/libibverbs/examples/srq_pingpong.c new file mode 100644 index 000000000000..907eaf6a94de --- /dev/null +++ b/contrib/ofed/libibverbs/examples/srq_pingpong.c @@ -0,0 +1,925 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pingpong.h" + +enum { + PINGPONG_RECV_WRID = 1, + PINGPONG_SEND_WRID = 2, + + MAX_QP = 256, +}; + +static int page_size; + +struct pingpong_context { + struct ibv_context *context; + struct ibv_comp_channel *channel; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *cq; + struct ibv_srq *srq; + struct ibv_qp *qp[MAX_QP]; + void *buf; + int size; + int num_qp; + int rx_depth; + int pending[MAX_QP]; + struct ibv_port_attr portinfo; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; + union ibv_gid gid; +}; + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, enum ibv_mtu mtu, + int sl, const struct pingpong_dest *my_dest, + const struct pingpong_dest *dest, int sgid_idx) +{ + int i; + + for (i = 0; i < ctx->num_qp; ++i) { + struct ibv_qp_attr attr = { + .qp_state = IBV_QPS_RTR, + .path_mtu = mtu, + .dest_qp_num = dest[i].qpn, + .rq_psn = dest[i].psn, + .max_dest_rd_atomic = 1, + .min_rnr_timer = 12, + .ah_attr = { + .is_global = 0, + .dlid = dest[i].lid, + .sl = sl, + .src_path_bits = 0, + .port_num = port + } + }; + + if (dest->gid.global.interface_id) { + attr.ah_attr.is_global = 1; + attr.ah_attr.grh.hop_limit = 1; + attr.ah_attr.grh.dgid = dest->gid; + attr.ah_attr.grh.sgid_index = sgid_idx; + } + if (ibv_modify_qp(ctx->qp[i], &attr, + IBV_QP_STATE | + 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)) { + fprintf(stderr, "Failed to modify QP[%d] to RTR\n", i); + return 1; + } + + attr.qp_state = IBV_QPS_RTS; + attr.timeout = 14; + attr.retry_cnt = 7; + attr.rnr_retry = 7; + attr.sq_psn = my_dest[i].psn; + attr.max_rd_atomic = 1; + if (ibv_modify_qp(ctx->qp[i], &attr, + IBV_QP_STATE | + IBV_QP_TIMEOUT | + IBV_QP_RETRY_CNT | + IBV_QP_RNR_RETRY | + IBV_QP_SQ_PSN | + IBV_QP_MAX_QP_RD_ATOMIC)) { + fprintf(stderr, "Failed to modify QP[%d] to RTS\n", i); + return 1; + } + } + + return 0; +} + +static struct pingpong_dest *pp_client_exch_dest(const char *servername, int port, + const struct pingpong_dest *my_dest) +{ + struct addrinfo *res, *t; + struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM + }; + char *service; + char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int r; + int i; + int sockfd = -1; + struct pingpong_dest *rem_dest = NULL; + char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; + + n = getaddrinfo(servername, service, &hints, &res); + + if (n < 0) { + fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), servername, port); + free(service); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd >= 0) { + if (!connect(sockfd, t->ai_addr, t->ai_addrlen)) + break; + close(sockfd); + sockfd = -1; + } + } + + freeaddrinfo(res); + free(service); + + if (sockfd < 0) { + fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port); + return NULL; + } + + for (i = 0; i < MAX_QP; ++i) { + gid_to_wire_gid(&my_dest[i].gid, gid); + sprintf(msg, "%04x:%06x:%06x:%s", my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, gid); + if (write(sockfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + goto out; + } + } + + rem_dest = malloc(MAX_QP * sizeof *rem_dest); + if (!rem_dest) + goto out; + + for (i = 0; i < MAX_QP; ++i) { + n = 0; + while (n < sizeof msg) { + r = read(sockfd, msg + n, sizeof msg - n); + if (r < 0) { + perror("client read"); + fprintf(stderr, "%d/%d: Couldn't read remote address [%d]\n", + n, (int) sizeof msg, i); + goto out; + } + n += r; + } + + sscanf(msg, "%x:%x:%x:%s", + &rem_dest[i].lid, &rem_dest[i].qpn, &rem_dest[i].psn, gid); + wire_gid_to_gid(gid, &rem_dest[i].gid); + } + + write(sockfd, "done", sizeof "done"); + +out: + close(sockfd); + return rem_dest; +} + +static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx, + int ib_port, enum ibv_mtu mtu, + int port, int sl, + const struct pingpong_dest *my_dest, + int sgid_idx) +{ + struct addrinfo *res, *t; + struct addrinfo hints = { + .ai_flags = AI_PASSIVE, + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM + }; + char *service; + char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int r; + int i; + int sockfd = -1, connfd; + struct pingpong_dest *rem_dest = NULL; + char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; + + n = getaddrinfo(NULL, service, &hints, &res); + + if (n < 0) { + fprintf(stderr, "%s for port %d\n", gai_strerror(n), port); + free(service); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd >= 0) { + n = 1; + + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n); + + if (!bind(sockfd, t->ai_addr, t->ai_addrlen)) + break; + close(sockfd); + sockfd = -1; + } + } + + freeaddrinfo(res); + free(service); + + if (sockfd < 0) { + fprintf(stderr, "Couldn't listen to port %d\n", port); + return NULL; + } + + listen(sockfd, 1); + connfd = accept(sockfd, NULL, 0); + close(sockfd); + if (connfd < 0) { + fprintf(stderr, "accept() failed\n"); + return NULL; + } + + rem_dest = malloc(MAX_QP * sizeof *rem_dest); + if (!rem_dest) + goto out; + + for (i = 0; i < MAX_QP; ++i) { + n = 0; + while (n < sizeof msg) { + r = read(connfd, msg + n, sizeof msg - n); + if (r < 0) { + perror("server read"); + fprintf(stderr, "%d/%d: Couldn't read remote address [%d]\n", + n, (int) sizeof msg, i); + goto out; + } + n += r; + } + + sscanf(msg, "%x:%x:%x:%s", + &rem_dest[i].lid, &rem_dest[i].qpn, &rem_dest[i].psn, gid); + wire_gid_to_gid(gid, &rem_dest[i].gid); + } + + if (pp_connect_ctx(ctx, ib_port, mtu, sl, my_dest, rem_dest, sgid_idx)) { + fprintf(stderr, "Couldn't connect to remote QP\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + for (i = 0; i < MAX_QP; ++i) { + gid_to_wire_gid(&my_dest[i].gid, gid); + sprintf(msg, "%04x:%06x:%06x:%s", my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, gid); + if (write(connfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + } + + read(connfd, msg, sizeof msg); + +out: + close(connfd); + return rem_dest; +} + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size, + int num_qp, int rx_depth, int port, + int use_event) +{ + struct pingpong_context *ctx; + int i; + + ctx = calloc(1, sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = size; + ctx->num_qp = num_qp; + ctx->rx_depth = rx_depth; + + ctx->buf = malloc(roundup(size, page_size)); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + + if (use_event) { + ctx->channel = ibv_create_comp_channel(ctx->context); + if (!ctx->channel) { + fprintf(stderr, "Couldn't create completion channel\n"); + return NULL; + } + } else + ctx->channel = NULL; + + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size, IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't register MR\n"); + return NULL; + } + + ctx->cq = ibv_create_cq(ctx->context, rx_depth + num_qp, NULL, + ctx->channel, 0); + if (!ctx->cq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + + { + struct ibv_srq_init_attr attr = { + .attr = { + .max_wr = rx_depth, + .max_sge = 1 + } + }; + + ctx->srq = ibv_create_srq(ctx->pd, &attr); + if (!ctx->srq) { + fprintf(stderr, "Couldn't create SRQ\n"); + return NULL; + } + } + + for (i = 0; i < num_qp; ++i) { + struct ibv_qp_init_attr attr = { + .send_cq = ctx->cq, + .recv_cq = ctx->cq, + .srq = ctx->srq, + .cap = { + .max_send_wr = 1, + .max_send_sge = 1, + }, + .qp_type = IBV_QPT_RC + }; + + ctx->qp[i] = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp[i]) { + fprintf(stderr, "Couldn't create QP[%d]\n", i); + return NULL; + } + } + + for (i = 0; i < num_qp; ++i) { + struct ibv_qp_attr attr = { + .qp_state = IBV_QPS_INIT, + .pkey_index = 0, + .port_num = port, + .qp_access_flags = 0 + }; + + if (ibv_modify_qp(ctx->qp[i], &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP[%d] to INIT\n", i); + return NULL; + } + } + + return ctx; +} + +int pp_close_ctx(struct pingpong_context *ctx, int num_qp) +{ + int i; + + for (i = 0; i < num_qp; ++i) { + if (ibv_destroy_qp(ctx->qp[i])) { + fprintf(stderr, "Couldn't destroy QP[%d]\n", i); + return 1; + } + } + + if (ibv_destroy_srq(ctx->srq)) { + fprintf(stderr, "Couldn't destroy SRQ\n"); + return 1; + } + + if (ibv_destroy_cq(ctx->cq)) { + fprintf(stderr, "Couldn't destroy CQ\n"); + return 1; + } + + if (ibv_dereg_mr(ctx->mr)) { + fprintf(stderr, "Couldn't deregister MR\n"); + return 1; + } + + if (ibv_dealloc_pd(ctx->pd)) { + fprintf(stderr, "Couldn't deallocate PD\n"); + return 1; + } + + if (ctx->channel) { + if (ibv_destroy_comp_channel(ctx->channel)) { + fprintf(stderr, "Couldn't destroy completion channel\n"); + return 1; + } + } + + if (ibv_close_device(ctx->context)) { + fprintf(stderr, "Couldn't release context\n"); + return 1; + } + + free(ctx->buf); + free(ctx); + + return 0; +} + +static int pp_post_recv(struct pingpong_context *ctx, int n) +{ + struct ibv_sge list = { + .addr = (uintptr_t) ctx->buf, + .length = ctx->size, + .lkey = ctx->mr->lkey + }; + struct ibv_recv_wr wr = { + .wr_id = PINGPONG_RECV_WRID, + .sg_list = &list, + .num_sge = 1, + }; + struct ibv_recv_wr *bad_wr; + int i; + + for (i = 0; i < n; ++i) + if (ibv_post_srq_recv(ctx->srq, &wr, &bad_wr)) + break; + + return i; +} + +static int pp_post_send(struct pingpong_context *ctx, int qp_index) +{ + struct ibv_sge list = { + .addr = (uintptr_t) ctx->buf, + .length = ctx->size, + .lkey = ctx->mr->lkey + }; + struct ibv_send_wr wr = { + .wr_id = PINGPONG_SEND_WRID, + .sg_list = &list, + .num_sge = 1, + .opcode = IBV_WR_SEND, + .send_flags = IBV_SEND_SIGNALED, + }; + struct ibv_send_wr *bad_wr; + + return ibv_post_send(ctx->qp[qp_index], &wr, &bad_wr); +} + +static int find_qp(int qpn, struct pingpong_context *ctx, int num_qp) +{ + int i; + + for (i = 0; i < num_qp; ++i) + if (ctx->qp[i]->qp_num == qpn) + return i; + + return -1; +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p, --port= listen on/connect to port (default 18515)\n"); + printf(" -d, --ib-dev= use IB device (default first device found)\n"); + printf(" -i, --ib-port= use port of IB device (default 1)\n"); + printf(" -s, --size= size of message to exchange (default 4096)\n"); + printf(" -m, --mtu= path MTU (default 1024)\n"); + printf(" -q, --num-qp= number of QPs to use (default 16)\n"); + printf(" -r, --rx-depth= number of receives to post at a time (default 500)\n"); + printf(" -n, --iters= number of exchanges per QP(default 1000)\n"); + printf(" -l, --sl= service level value\n"); + printf(" -e, --events sleep on CQ events (default poll)\n"); + printf(" -g, --gid-idx= local port gid index\n"); +} + +int main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct ibv_device *ib_dev; + struct ibv_wc *wc; + struct pingpong_context *ctx; + struct pingpong_dest my_dest[MAX_QP]; + struct pingpong_dest *rem_dest; + struct timeval start, end; + char *ib_devname = NULL; + char *servername = NULL; + int port = 18515; + int ib_port = 1; + int size = 4096; + enum ibv_mtu mtu = IBV_MTU_1024; + int num_qp = 16; + int rx_depth = 500; + int iters = 1000; + int use_event = 0; + int routs; + int rcnt, scnt; + int num_wc; + int i; + int num_cq_events = 0; + int sl = 0; + int gidx = -1; + char gid[33]; + + srand48(getpid() * time(NULL)); + + while (1) { + int c; + + static struct option long_options[] = { + { .name = "port", .has_arg = 1, .val = 'p' }, + { .name = "ib-dev", .has_arg = 1, .val = 'd' }, + { .name = "ib-port", .has_arg = 1, .val = 'i' }, + { .name = "size", .has_arg = 1, .val = 's' }, + { .name = "mtu", .has_arg = 1, .val = 'm' }, + { .name = "num-qp", .has_arg = 1, .val = 'q' }, + { .name = "rx-depth", .has_arg = 1, .val = 'r' }, + { .name = "iters", .has_arg = 1, .val = 'n' }, + { .name = "sl", .has_arg = 1, .val = 'l' }, + { .name = "events", .has_arg = 0, .val = 'e' }, + { .name = "gid-idx", .has_arg = 1, .val = 'g' }, + { 0 } + }; + + c = getopt_long(argc, argv, "p:d:i:s:m:q:r:n:l:eg:", long_options, NULL); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = strdup(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + break; + + case 'm': + mtu = pp_mtu_to_enum(strtol(optarg, NULL, 0)); + if (mtu < 0) { + usage(argv[0]); + return 1; + } + break; + + case 'q': + num_qp = strtol(optarg, NULL, 0); + break; + + case 'r': + rx_depth = strtol(optarg, NULL, 0); + break; + + case 'n': + iters = strtol(optarg, NULL, 0); + break; + + case 'l': + sl = strtol(optarg, NULL, 0); + break; + + case 'e': + ++use_event; + break; + + case 'g': + gidx = strtol(optarg, NULL, 0); + break; + + default: + usage(argv[0]); + return 1; + } + } + + if (optind == argc - 1) + servername = strdup(argv[optind]); + else if (optind < argc) { + usage(argv[0]); + return 1; + } + + if (num_qp > rx_depth) { + fprintf(stderr, "rx_depth %d is too small for %d QPs -- " + "must have at least one receive per QP.\n", + rx_depth, num_qp); + return 1; + } + + num_wc = num_qp + rx_depth; + wc = alloca(num_wc * sizeof *wc); + + page_size = sysconf(_SC_PAGESIZE); + + dev_list = ibv_get_device_list(NULL); + if (!dev_list) { + perror("Failed to get IB devices list"); + return 1; + } + + if (!ib_devname) { + ib_dev = *dev_list; + if (!ib_dev) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + } else { + int i; + for (i = 0; dev_list[i]; ++i) + if (!strcmp(ibv_get_device_name(dev_list[i]), ib_devname)) + break; + ib_dev = dev_list[i]; + if (!ib_dev) { + fprintf(stderr, "IB device %s not found\n", ib_devname); + return 1; + } + } + + ctx = pp_init_ctx(ib_dev, size, num_qp, rx_depth, ib_port, use_event); + if (!ctx) + return 1; + + routs = pp_post_recv(ctx, ctx->rx_depth); + if (routs < ctx->rx_depth) { + fprintf(stderr, "Couldn't post receive (%d)\n", routs); + return 1; + } + + if (use_event) + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + + memset(my_dest, 0, sizeof my_dest); + + if (pp_get_port_info(ctx->context, ib_port, &ctx->portinfo)) { + fprintf(stderr, "Couldn't get port info\n"); + return 1; + } + for (i = 0; i < num_qp; ++i) { + my_dest[i].qpn = ctx->qp[i]->qp_num; + my_dest[i].psn = lrand48() & 0xffffff; + my_dest[i].lid = ctx->portinfo.lid; + if (ctx->portinfo.link_layer == IBV_LINK_LAYER_INFINIBAND && !my_dest[i].lid) { + fprintf(stderr, "Couldn't get local LID\n"); + return 1; + } + + if (gidx >= 0) { + if (ibv_query_gid(ctx->context, ib_port, gidx, &my_dest[i].gid)) { + fprintf(stderr, "Could not get local gid for gid index %d\n", gidx); + return 1; + } + } else + memset(&my_dest[i].gid, 0, sizeof my_dest[i].gid); + + inet_ntop(AF_INET6, &my_dest[i].gid, gid, sizeof gid); + printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", + my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, gid); + } + + if (servername) + rem_dest = pp_client_exch_dest(servername, port, my_dest); + else + rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, my_dest, gidx); + + if (!rem_dest) + return 1; + + inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof gid); + + for (i = 0; i < num_qp; ++i) { + inet_ntop(AF_INET6, &rem_dest[i].gid, gid, sizeof gid); + printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", + rem_dest[i].lid, rem_dest[i].qpn, rem_dest[i].psn, gid); + } + + if (servername) + if (pp_connect_ctx(ctx, ib_port, mtu, sl, my_dest, rem_dest, gidx)) + return 1; + + if (servername) + for (i = 0; i < num_qp; ++i) { + if (pp_post_send(ctx, i)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending[i] = PINGPONG_SEND_WRID | PINGPONG_RECV_WRID; + } + else + for (i = 0; i < num_qp; ++i) + ctx->pending[i] = PINGPONG_RECV_WRID; + + if (gettimeofday(&start, NULL)) { + perror("gettimeofday"); + return 1; + } + + rcnt = scnt = 0; + while (rcnt < iters || scnt < iters) { + if (use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\n"); + return 1; + } + + ++num_cq_events; + + if (ev_cq != ctx->cq) { + fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq); + return 1; + } + + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + + { + int ne, qp_ind; + + do { + ne = ibv_poll_cq(ctx->cq, num_wc, wc); + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } + } while (!use_event && ne < 1); + + for (i = 0; i < ne; ++i) { + if (wc[i].status != IBV_WC_SUCCESS) { + fprintf(stderr, "Failed status %s (%d) for wr_id %d\n", + ibv_wc_status_str(wc[i].status), + wc[i].status, (int) wc[i].wr_id); + return 1; + } + + qp_ind = find_qp(wc[i].qp_num, ctx, num_qp); + if (qp_ind < 0) { + fprintf(stderr, "Couldn't find QPN %06x\n", + wc[i].qp_num); + return 1; + } + + switch ((int) wc[i].wr_id) { + case PINGPONG_SEND_WRID: + ++scnt; + break; + + case PINGPONG_RECV_WRID: + if (--routs <= num_qp) { + routs += pp_post_recv(ctx, ctx->rx_depth - routs); + if (routs < ctx->rx_depth) { + fprintf(stderr, + "Couldn't post receive (%d)\n", + routs); + return 1; + } + } + + ++rcnt; + break; + + default: + fprintf(stderr, "Completion for unknown wr_id %d\n", + (int) wc[i].wr_id); + return 1; + } + + ctx->pending[qp_ind] &= ~(int) wc[i].wr_id; + if (scnt < iters && !ctx->pending[qp_ind]) { + if (pp_post_send(ctx, qp_ind)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending[qp_ind] = PINGPONG_RECV_WRID | + PINGPONG_SEND_WRID; + } + + } + } + } + + if (gettimeofday(&end, NULL)) { + perror("gettimeofday"); + return 1; + } + + { + float usec = (end.tv_sec - start.tv_sec) * 1000000 + + (end.tv_usec - start.tv_usec); + long long bytes = (long long) size * iters * 2; + + printf("%lld bytes in %.2f seconds = %.2f Mbit/sec\n", + bytes, usec / 1000000., bytes * 8. / usec); + printf("%d iters in %.2f seconds = %.2f usec/iter\n", + iters, usec / 1000000., usec / iters); + } + + ibv_ack_cq_events(ctx->cq, num_cq_events); + + if (pp_close_ctx(ctx, num_qp)) + return 1; + + ibv_free_device_list(dev_list); + free(rem_dest); + + return 0; +} diff --git a/contrib/ofed/libibverbs/examples/uc_pingpong.c b/contrib/ofed/libibverbs/examples/uc_pingpong.c new file mode 100644 index 000000000000..85bdcdaafb76 --- /dev/null +++ b/contrib/ofed/libibverbs/examples/uc_pingpong.c @@ -0,0 +1,809 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pingpong.h" + +enum { + PINGPONG_RECV_WRID = 1, + PINGPONG_SEND_WRID = 2, +}; + +static int page_size; + +struct pingpong_context { + struct ibv_context *context; + struct ibv_comp_channel *channel; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *cq; + struct ibv_qp *qp; + void *buf; + int size; + int rx_depth; + int pending; + struct ibv_port_attr portinfo; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; + union ibv_gid gid; +}; + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + enum ibv_mtu mtu, int sl, + struct pingpong_dest *dest, int sgid_idx) +{ + struct ibv_qp_attr attr = { + .qp_state = IBV_QPS_RTR, + .path_mtu = mtu, + .dest_qp_num = dest->qpn, + .rq_psn = dest->psn, + .ah_attr = { + .is_global = 0, + .dlid = dest->lid, + .sl = sl, + .src_path_bits = 0, + .port_num = port + } + }; + + if (dest->gid.global.interface_id) { + attr.ah_attr.is_global = 1; + attr.ah_attr.grh.hop_limit = 1; + attr.ah_attr.grh.dgid = dest->gid; + attr.ah_attr.grh.sgid_index = sgid_idx; + } + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | + IBV_QP_PATH_MTU | + IBV_QP_DEST_QPN | + IBV_QP_RQ_PSN)) { + fprintf(stderr, "Failed to modify QP to RTR\n"); + return 1; + } + + attr.qp_state = IBV_QPS_RTS; + attr.sq_psn = my_psn; + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN)) { + fprintf(stderr, "Failed to modify QP to RTS\n"); + return 1; + } + + return 0; +} + +static struct pingpong_dest *pp_client_exch_dest(const char *servername, int port, + const struct pingpong_dest *my_dest) +{ + struct addrinfo *res, *t; + struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM + }; + char *service; + char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int sockfd = -1; + struct pingpong_dest *rem_dest = NULL; + char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; + + n = getaddrinfo(servername, service, &hints, &res); + + if (n < 0) { + fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), servername, port); + free(service); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd >= 0) { + if (!connect(sockfd, t->ai_addr, t->ai_addrlen)) + break; + close(sockfd); + sockfd = -1; + } + } + + freeaddrinfo(res); + free(service); + + if (sockfd < 0) { + fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port); + return NULL; + } + + gid_to_wire_gid(&my_dest->gid, gid); + sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid); + if (write(sockfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + goto out; + } + + if (read(sockfd, msg, sizeof msg) != sizeof msg) { + perror("client read"); + fprintf(stderr, "Couldn't read remote address\n"); + goto out; + } + + write(sockfd, "done", sizeof "done"); + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid); + wire_gid_to_gid(gid, &rem_dest->gid); + +out: + close(sockfd); + return rem_dest; +} + +static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx, + int ib_port, enum ibv_mtu mtu, + int port, int sl, + const struct pingpong_dest *my_dest, + int sgid_idx) +{ + struct addrinfo *res, *t; + struct addrinfo hints = { + .ai_flags = AI_PASSIVE, + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM + }; + char *service; + char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int sockfd = -1, connfd; + struct pingpong_dest *rem_dest = NULL; + char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; + + n = getaddrinfo(NULL, service, &hints, &res); + + if (n < 0) { + fprintf(stderr, "%s for port %d\n", gai_strerror(n), port); + free(service); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd >= 0) { + n = 1; + + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n); + + if (!bind(sockfd, t->ai_addr, t->ai_addrlen)) + break; + close(sockfd); + sockfd = -1; + } + } + + freeaddrinfo(res); + free(service); + + if (sockfd < 0) { + fprintf(stderr, "Couldn't listen to port %d\n", port); + return NULL; + } + + listen(sockfd, 1); + connfd = accept(sockfd, NULL, 0); + close(sockfd); + if (connfd < 0) { + fprintf(stderr, "accept() failed\n"); + return NULL; + } + + n = read(connfd, msg, sizeof msg); + if (n != sizeof msg) { + perror("server read"); + fprintf(stderr, "%d/%d: Couldn't read remote address\n", n, (int) sizeof msg); + goto out; + } + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid); + wire_gid_to_gid(gid, &rem_dest->gid); + + if (pp_connect_ctx(ctx, ib_port, my_dest->psn, mtu, sl, rem_dest, sgid_idx)) { + fprintf(stderr, "Couldn't connect to remote QP\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + gid_to_wire_gid(&my_dest->gid, gid); + sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid); + if (write(connfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + read(connfd, msg, sizeof msg); + +out: + close(connfd); + return rem_dest; +} + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size, + int rx_depth, int port, + int use_event) +{ + struct pingpong_context *ctx; + + ctx = calloc(1, sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = size; + ctx->rx_depth = rx_depth; + + ctx->buf = malloc(roundup(size, page_size)); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + + if (use_event) { + ctx->channel = ibv_create_comp_channel(ctx->context); + if (!ctx->channel) { + fprintf(stderr, "Couldn't create completion channel\n"); + return NULL; + } + } else + ctx->channel = NULL; + + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size, IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't register MR\n"); + return NULL; + } + + ctx->cq = ibv_create_cq(ctx->context, rx_depth + 1, NULL, + ctx->channel, 0); + if (!ctx->cq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + + { + struct ibv_qp_init_attr attr = { + .send_cq = ctx->cq, + .recv_cq = ctx->cq, + .cap = { + .max_send_wr = 1, + .max_recv_wr = rx_depth, + .max_send_sge = 1, + .max_recv_sge = 1 + }, + .qp_type = IBV_QPT_UC + }; + + ctx->qp = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + } + + { + struct ibv_qp_attr attr = { + .qp_state = IBV_QPS_INIT, + .pkey_index = 0, + .port_num = port, + .qp_access_flags = 0 + }; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_ACCESS_FLAGS)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + + return ctx; +} + +int pp_close_ctx(struct pingpong_context *ctx) +{ + if (ibv_destroy_qp(ctx->qp)) { + fprintf(stderr, "Couldn't destroy QP\n"); + return 1; + } + + if (ibv_destroy_cq(ctx->cq)) { + fprintf(stderr, "Couldn't destroy CQ\n"); + return 1; + } + + if (ibv_dereg_mr(ctx->mr)) { + fprintf(stderr, "Couldn't deregister MR\n"); + return 1; + } + + if (ibv_dealloc_pd(ctx->pd)) { + fprintf(stderr, "Couldn't deallocate PD\n"); + return 1; + } + + if (ctx->channel) { + if (ibv_destroy_comp_channel(ctx->channel)) { + fprintf(stderr, "Couldn't destroy completion channel\n"); + return 1; + } + } + + if (ibv_close_device(ctx->context)) { + fprintf(stderr, "Couldn't release context\n"); + return 1; + } + + free(ctx->buf); + free(ctx); + + return 0; +} + +static int pp_post_recv(struct pingpong_context *ctx, int n) +{ + struct ibv_sge list = { + .addr = (uintptr_t) ctx->buf, + .length = ctx->size, + .lkey = ctx->mr->lkey + }; + struct ibv_recv_wr wr = { + .wr_id = PINGPONG_RECV_WRID, + .sg_list = &list, + .num_sge = 1, + }; + struct ibv_recv_wr *bad_wr; + int i; + + for (i = 0; i < n; ++i) + if (ibv_post_recv(ctx->qp, &wr, &bad_wr)) + break; + + return i; +} + +static int pp_post_send(struct pingpong_context *ctx) +{ + struct ibv_sge list = { + .addr = (uintptr_t) ctx->buf, + .length = ctx->size, + .lkey = ctx->mr->lkey + }; + struct ibv_send_wr wr = { + .wr_id = PINGPONG_SEND_WRID, + .sg_list = &list, + .num_sge = 1, + .opcode = IBV_WR_SEND, + .send_flags = IBV_SEND_SIGNALED, + }; + struct ibv_send_wr *bad_wr; + + return ibv_post_send(ctx->qp, &wr, &bad_wr); +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p, --port= listen on/connect to port (default 18515)\n"); + printf(" -d, --ib-dev= use IB device (default first device found)\n"); + printf(" -i, --ib-port= use port of IB device (default 1)\n"); + printf(" -s, --size= size of message to exchange (default 4096)\n"); + printf(" -m, --mtu= path MTU (default 1024)\n"); + printf(" -r, --rx-depth= number of receives to post at a time (default 500)\n"); + printf(" -n, --iters= number of exchanges (default 1000)\n"); + printf(" -l, --sl= service level value\n"); + printf(" -e, --events sleep on CQ events (default poll)\n"); + printf(" -g, --gid-idx= local port gid index\n"); +} + +int main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct ibv_device *ib_dev; + struct pingpong_context *ctx; + struct pingpong_dest my_dest; + struct pingpong_dest *rem_dest; + struct timeval start, end; + char *ib_devname = NULL; + char *servername = NULL; + int port = 18515; + int ib_port = 1; + int size = 4096; + enum ibv_mtu mtu = IBV_MTU_1024; + int rx_depth = 500; + int iters = 1000; + int use_event = 0; + int routs; + int rcnt, scnt; + int num_cq_events = 0; + int sl = 0; + int gidx = -1; + char gid[33]; + + srand48(getpid() * time(NULL)); + + while (1) { + int c; + + static struct option long_options[] = { + { .name = "port", .has_arg = 1, .val = 'p' }, + { .name = "ib-dev", .has_arg = 1, .val = 'd' }, + { .name = "ib-port", .has_arg = 1, .val = 'i' }, + { .name = "size", .has_arg = 1, .val = 's' }, + { .name = "mtu", .has_arg = 1, .val = 'm' }, + { .name = "rx-depth", .has_arg = 1, .val = 'r' }, + { .name = "iters", .has_arg = 1, .val = 'n' }, + { .name = "sl", .has_arg = 1, .val = 'l' }, + { .name = "events", .has_arg = 0, .val = 'e' }, + { .name = "gid-idx", .has_arg = 1, .val = 'g' }, + { 0 } + }; + + c = getopt_long(argc, argv, "p:d:i:s:m:r:n:l:eg:", long_options, NULL); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = strdup(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + break; + + case 'm': + mtu = pp_mtu_to_enum(strtol(optarg, NULL, 0)); + if (mtu < 0) { + usage(argv[0]); + return 1; + } + break; + + case 'r': + rx_depth = strtol(optarg, NULL, 0); + break; + + case 'n': + iters = strtol(optarg, NULL, 0); + break; + + case 'l': + sl = strtol(optarg, NULL, 0); + break; + + case 'e': + ++use_event; + break; + + case 'g': + gidx = strtol(optarg, NULL, 0); + break; + + default: + usage(argv[0]); + return 1; + } + } + + if (optind == argc - 1) + servername = strdup(argv[optind]); + else if (optind < argc) { + usage(argv[0]); + return 1; + } + + page_size = sysconf(_SC_PAGESIZE); + + dev_list = ibv_get_device_list(NULL); + if (!dev_list) { + perror("Failed to get IB devices list"); + return 1; + } + + if (!ib_devname) { + ib_dev = *dev_list; + if (!ib_dev) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + } else { + int i; + for (i = 0; dev_list[i]; ++i) + if (!strcmp(ibv_get_device_name(dev_list[i]), ib_devname)) + break; + ib_dev = dev_list[i]; + if (!ib_dev) { + fprintf(stderr, "IB device %s not found\n", ib_devname); + return 1; + } + } + + ctx = pp_init_ctx(ib_dev, size, rx_depth, ib_port, use_event); + if (!ctx) + return 1; + + routs = pp_post_recv(ctx, ctx->rx_depth); + if (routs < ctx->rx_depth) { + fprintf(stderr, "Couldn't post receive (%d)\n", routs); + return 1; + } + + if (use_event) + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + + if (pp_get_port_info(ctx->context, ib_port, &ctx->portinfo)) { + fprintf(stderr, "Couldn't get port info\n"); + return 1; + } + + my_dest.lid = ctx->portinfo.lid; + if (ctx->portinfo.link_layer == IBV_LINK_LAYER_INFINIBAND && !my_dest.lid) { + fprintf(stderr, "Couldn't get local LID\n"); + return 1; + } + + if (gidx >= 0) { + if (ibv_query_gid(ctx->context, ib_port, gidx, &my_dest.gid)) { + fprintf(stderr, "Could not get local gid for gid index %d\n", gidx); + return 1; + } + } else + memset(&my_dest.gid, 0, sizeof my_dest.gid); + + my_dest.qpn = ctx->qp->qp_num; + my_dest.psn = lrand48() & 0xffffff; + inet_ntop(AF_INET6, &my_dest.gid, gid, sizeof gid); + printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", + my_dest.lid, my_dest.qpn, my_dest.psn, gid); + + if (servername) + rem_dest = pp_client_exch_dest(servername, port, &my_dest); + else + rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, &my_dest, gidx); + + if (!rem_dest) + return 1; + + inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof gid); + printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", + rem_dest->lid, rem_dest->qpn, rem_dest->psn, gid); + + if (servername) + if (pp_connect_ctx(ctx, ib_port, my_dest.psn, mtu, sl, rem_dest, gidx)) + return 1; + + ctx->pending = PINGPONG_RECV_WRID; + + if (servername) { + if (pp_post_send(ctx)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending |= PINGPONG_SEND_WRID; + } + + if (gettimeofday(&start, NULL)) { + perror("gettimeofday"); + return 1; + } + + rcnt = scnt = 0; + while (rcnt < iters || scnt < iters) { + if (use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\n"); + return 1; + } + + ++num_cq_events; + + if (ev_cq != ctx->cq) { + fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq); + return 1; + } + + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + + { + struct ibv_wc wc[2]; + int ne, i; + + do { + ne = ibv_poll_cq(ctx->cq, 2, wc); + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } + } while (!use_event && ne < 1); + + for (i = 0; i < ne; ++i) { + if (wc[i].status != IBV_WC_SUCCESS) { + fprintf(stderr, "Failed status %s (%d) for wr_id %d\n", + ibv_wc_status_str(wc[i].status), + wc[i].status, (int) wc[i].wr_id); + return 1; + } + + switch ((int) wc[i].wr_id) { + case PINGPONG_SEND_WRID: + ++scnt; + break; + + case PINGPONG_RECV_WRID: + if (--routs <= 1) { + routs += pp_post_recv(ctx, ctx->rx_depth - routs); + if (routs < ctx->rx_depth) { + fprintf(stderr, + "Couldn't post receive (%d)\n", + routs); + return 1; + } + } + + ++rcnt; + break; + + default: + fprintf(stderr, "Completion for unknown wr_id %d\n", + (int) wc[i].wr_id); + return 1; + } + + ctx->pending &= ~(int) wc[i].wr_id; + if (scnt < iters && !ctx->pending) { + if (pp_post_send(ctx)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending = PINGPONG_RECV_WRID | + PINGPONG_SEND_WRID; + } + } + } + } + + if (gettimeofday(&end, NULL)) { + perror("gettimeofday"); + return 1; + } + + { + float usec = (end.tv_sec - start.tv_sec) * 1000000 + + (end.tv_usec - start.tv_usec); + long long bytes = (long long) size * iters * 2; + + printf("%lld bytes in %.2f seconds = %.2f Mbit/sec\n", + bytes, usec / 1000000., bytes * 8. / usec); + printf("%d iters in %.2f seconds = %.2f usec/iter\n", + iters, usec / 1000000., usec / iters); + } + + ibv_ack_cq_events(ctx->cq, num_cq_events); + + if (pp_close_ctx(ctx)) + return 1; + + ibv_free_device_list(dev_list); + free(rem_dest); + + return 0; +} diff --git a/contrib/ofed/libibverbs/examples/ud_pingpong.c b/contrib/ofed/libibverbs/examples/ud_pingpong.c new file mode 100644 index 000000000000..d7c10592a2b2 --- /dev/null +++ b/contrib/ofed/libibverbs/examples/ud_pingpong.c @@ -0,0 +1,803 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pingpong.h" + +enum { + PINGPONG_RECV_WRID = 1, + PINGPONG_SEND_WRID = 2, +}; + +static int page_size; + +struct pingpong_context { + struct ibv_context *context; + struct ibv_comp_channel *channel; + struct ibv_pd *pd; + struct ibv_mr *mr; + struct ibv_cq *cq; + struct ibv_qp *qp; + struct ibv_ah *ah; + void *buf; + int size; + int rx_depth; + int pending; + struct ibv_port_attr portinfo; +}; + +struct pingpong_dest { + int lid; + int qpn; + int psn; + union ibv_gid gid; +}; + +static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + int sl, struct pingpong_dest *dest, int sgid_idx) +{ + struct ibv_ah_attr ah_attr = { + .is_global = 0, + .dlid = dest->lid, + .sl = sl, + .src_path_bits = 0, + .port_num = port + }; + struct ibv_qp_attr attr = { + .qp_state = IBV_QPS_RTR + }; + + if (ibv_modify_qp(ctx->qp, &attr, IBV_QP_STATE)) { + fprintf(stderr, "Failed to modify QP to RTR\n"); + return 1; + } + + attr.qp_state = IBV_QPS_RTS; + attr.sq_psn = my_psn; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_SQ_PSN)) { + fprintf(stderr, "Failed to modify QP to RTS\n"); + return 1; + } + + if (dest->gid.global.interface_id) { + ah_attr.is_global = 1; + ah_attr.grh.hop_limit = 1; + ah_attr.grh.dgid = dest->gid; + ah_attr.grh.sgid_index = sgid_idx; + } + + ctx->ah = ibv_create_ah(ctx->pd, &ah_attr); + if (!ctx->ah) { + fprintf(stderr, "Failed to create AH\n"); + return 1; + } + + return 0; +} + +static struct pingpong_dest *pp_client_exch_dest(const char *servername, int port, + const struct pingpong_dest *my_dest) +{ + struct addrinfo *res, *t; + struct addrinfo hints = { + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM + }; + char *service; + char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int sockfd = -1; + struct pingpong_dest *rem_dest = NULL; + char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; + + n = getaddrinfo(servername, service, &hints, &res); + + if (n < 0) { + fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), servername, port); + free(service); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd >= 0) { + if (!connect(sockfd, t->ai_addr, t->ai_addrlen)) + break; + close(sockfd); + sockfd = -1; + } + } + + freeaddrinfo(res); + free(service); + + if (sockfd < 0) { + fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port); + return NULL; + } + + gid_to_wire_gid(&my_dest->gid, gid); + sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid); + if (write(sockfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + goto out; + } + + if (read(sockfd, msg, sizeof msg) != sizeof msg) { + perror("client read"); + fprintf(stderr, "Couldn't read remote address\n"); + goto out; + } + + write(sockfd, "done", sizeof "done"); + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid); + wire_gid_to_gid(gid, &rem_dest->gid); + +out: + close(sockfd); + return rem_dest; +} + +static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx, + int ib_port, int port, int sl, + const struct pingpong_dest *my_dest, + int sgid_idx) +{ + struct addrinfo *res, *t; + struct addrinfo hints = { + .ai_flags = AI_PASSIVE, + .ai_family = AF_INET, + .ai_socktype = SOCK_STREAM + }; + char *service; + char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int sockfd = -1, connfd; + struct pingpong_dest *rem_dest = NULL; + char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; + + n = getaddrinfo(NULL, service, &hints, &res); + + if (n < 0) { + fprintf(stderr, "%s for port %d\n", gai_strerror(n), port); + free(service); + return NULL; + } + + for (t = res; t; t = t->ai_next) { + sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); + if (sockfd >= 0) { + n = 1; + + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n); + + if (!bind(sockfd, t->ai_addr, t->ai_addrlen)) + break; + close(sockfd); + sockfd = -1; + } + } + + freeaddrinfo(res); + free(service); + + if (sockfd < 0) { + fprintf(stderr, "Couldn't listen to port %d\n", port); + return NULL; + } + + listen(sockfd, 1); + connfd = accept(sockfd, NULL, 0); + close(sockfd); + if (connfd < 0) { + fprintf(stderr, "accept() failed\n"); + return NULL; + } + + n = read(connfd, msg, sizeof msg); + if (n != sizeof msg) { + perror("server read"); + fprintf(stderr, "%d/%d: Couldn't read remote address\n", n, (int) sizeof msg); + goto out; + } + + rem_dest = malloc(sizeof *rem_dest); + if (!rem_dest) + goto out; + + sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid); + wire_gid_to_gid(gid, &rem_dest->gid); + + if (pp_connect_ctx(ctx, ib_port, my_dest->psn, sl, rem_dest, sgid_idx)) { + fprintf(stderr, "Couldn't connect to remote QP\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + gid_to_wire_gid(&my_dest->gid, gid); + sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid); + if (write(connfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + + read(connfd, msg, sizeof msg); + +out: + close(connfd); + return rem_dest; +} + +static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size, + int rx_depth, int port, + int use_event) +{ + struct pingpong_context *ctx; + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + ctx->size = size; + ctx->rx_depth = rx_depth; + + ctx->buf = malloc(roundup(size + 40, page_size)); + if (!ctx->buf) { + fprintf(stderr, "Couldn't allocate work buf.\n"); + return NULL; + } + + memset(ctx->buf, 0, size + 40); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { + fprintf(stderr, "Couldn't get context for %s\n", + ibv_get_device_name(ib_dev)); + return NULL; + } + + if (use_event) { + ctx->channel = ibv_create_comp_channel(ctx->context); + if (!ctx->channel) { + fprintf(stderr, "Couldn't create completion channel\n"); + return NULL; + } + } else + ctx->channel = NULL; + + ctx->pd = ibv_alloc_pd(ctx->context); + if (!ctx->pd) { + fprintf(stderr, "Couldn't allocate PD\n"); + return NULL; + } + + ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size + 40, IBV_ACCESS_LOCAL_WRITE); + if (!ctx->mr) { + fprintf(stderr, "Couldn't register MR\n"); + return NULL; + } + + ctx->cq = ibv_create_cq(ctx->context, rx_depth + 1, NULL, + ctx->channel, 0); + if (!ctx->cq) { + fprintf(stderr, "Couldn't create CQ\n"); + return NULL; + } + + { + struct ibv_qp_init_attr attr = { + .send_cq = ctx->cq, + .recv_cq = ctx->cq, + .cap = { + .max_send_wr = 1, + .max_recv_wr = rx_depth, + .max_send_sge = 1, + .max_recv_sge = 1 + }, + .qp_type = IBV_QPT_UD, + }; + + ctx->qp = ibv_create_qp(ctx->pd, &attr); + if (!ctx->qp) { + fprintf(stderr, "Couldn't create QP\n"); + return NULL; + } + } + + { + struct ibv_qp_attr attr = { + .qp_state = IBV_QPS_INIT, + .pkey_index = 0, + .port_num = port, + .qkey = 0x11111111 + }; + + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_PKEY_INDEX | + IBV_QP_PORT | + IBV_QP_QKEY)) { + fprintf(stderr, "Failed to modify QP to INIT\n"); + return NULL; + } + } + + return ctx; +} + +int pp_close_ctx(struct pingpong_context *ctx) +{ + if (ibv_destroy_qp(ctx->qp)) { + fprintf(stderr, "Couldn't destroy QP\n"); + return 1; + } + + if (ibv_destroy_cq(ctx->cq)) { + fprintf(stderr, "Couldn't destroy CQ\n"); + return 1; + } + + if (ibv_dereg_mr(ctx->mr)) { + fprintf(stderr, "Couldn't deregister MR\n"); + return 1; + } + + if (ibv_destroy_ah(ctx->ah)) { + fprintf(stderr, "Couldn't destroy AH\n"); + return 1; + } + + if (ibv_dealloc_pd(ctx->pd)) { + fprintf(stderr, "Couldn't deallocate PD\n"); + return 1; + } + + if (ctx->channel) { + if (ibv_destroy_comp_channel(ctx->channel)) { + fprintf(stderr, "Couldn't destroy completion channel\n"); + return 1; + } + } + + if (ibv_close_device(ctx->context)) { + fprintf(stderr, "Couldn't release context\n"); + return 1; + } + + free(ctx->buf); + free(ctx); + + return 0; +} + +static int pp_post_recv(struct pingpong_context *ctx, int n) +{ + struct ibv_sge list = { + .addr = (uintptr_t) ctx->buf, + .length = ctx->size + 40, + .lkey = ctx->mr->lkey + }; + struct ibv_recv_wr wr = { + .wr_id = PINGPONG_RECV_WRID, + .sg_list = &list, + .num_sge = 1, + }; + struct ibv_recv_wr *bad_wr; + int i; + + for (i = 0; i < n; ++i) + if (ibv_post_recv(ctx->qp, &wr, &bad_wr)) + break; + + return i; +} + +static int pp_post_send(struct pingpong_context *ctx, uint32_t qpn) +{ + struct ibv_sge list = { + .addr = (uintptr_t) ctx->buf + 40, + .length = ctx->size, + .lkey = ctx->mr->lkey + }; + struct ibv_send_wr wr = { + .wr_id = PINGPONG_SEND_WRID, + .sg_list = &list, + .num_sge = 1, + .opcode = IBV_WR_SEND, + .send_flags = IBV_SEND_SIGNALED, + .wr = { + .ud = { + .ah = ctx->ah, + .remote_qpn = qpn, + .remote_qkey = 0x11111111 + } + } + }; + struct ibv_send_wr *bad_wr; + + return ibv_post_send(ctx->qp, &wr, &bad_wr); +} + +static void usage(const char *argv0) +{ + printf("Usage:\n"); + printf(" %s start a server and wait for connection\n", argv0); + printf(" %s connect to server at \n", argv0); + printf("\n"); + printf("Options:\n"); + printf(" -p, --port= listen on/connect to port (default 18515)\n"); + printf(" -d, --ib-dev= use IB device (default first device found)\n"); + printf(" -i, --ib-port= use port of IB device (default 1)\n"); + printf(" -s, --size= size of message to exchange (default 1024)\n"); + printf(" -r, --rx-depth= number of receives to post at a time (default 500)\n"); + printf(" -n, --iters= number of exchanges (default 1000)\n"); + printf(" -e, --events sleep on CQ events (default poll)\n"); + printf(" -g, --gid-idx= local port gid index\n"); +} + +int main(int argc, char *argv[]) +{ + struct ibv_device **dev_list; + struct ibv_device *ib_dev; + struct pingpong_context *ctx; + struct pingpong_dest my_dest; + struct pingpong_dest *rem_dest; + struct timeval start, end; + char *ib_devname = NULL; + char *servername = NULL; + int port = 18515; + int ib_port = 1; + int size = 1024; + int rx_depth = 500; + int iters = 1000; + int use_event = 0; + int routs; + int rcnt, scnt; + int num_cq_events = 0; + int sl = 0; + int gidx = -1; + char gid[33]; + + srand48(getpid() * time(NULL)); + + while (1) { + int c; + + static struct option long_options[] = { + { .name = "port", .has_arg = 1, .val = 'p' }, + { .name = "ib-dev", .has_arg = 1, .val = 'd' }, + { .name = "ib-port", .has_arg = 1, .val = 'i' }, + { .name = "size", .has_arg = 1, .val = 's' }, + { .name = "rx-depth", .has_arg = 1, .val = 'r' }, + { .name = "iters", .has_arg = 1, .val = 'n' }, + { .name = "sl", .has_arg = 1, .val = 'l' }, + { .name = "events", .has_arg = 0, .val = 'e' }, + { .name = "gid-idx", .has_arg = 1, .val = 'g' }, + { 0 } + }; + + c = getopt_long(argc, argv, "p:d:i:s:r:n:l:eg:", long_options, NULL); + if (c == -1) + break; + + switch (c) { + case 'p': + port = strtol(optarg, NULL, 0); + if (port < 0 || port > 65535) { + usage(argv[0]); + return 1; + } + break; + + case 'd': + ib_devname = strdup(optarg); + break; + + case 'i': + ib_port = strtol(optarg, NULL, 0); + if (ib_port < 0) { + usage(argv[0]); + return 1; + } + break; + + case 's': + size = strtol(optarg, NULL, 0); + break; + + case 'r': + rx_depth = strtol(optarg, NULL, 0); + break; + + case 'n': + iters = strtol(optarg, NULL, 0); + break; + + case 'l': + sl = strtol(optarg, NULL, 0); + break; + + case 'e': + ++use_event; + break; + + case 'g': + gidx = strtol(optarg, NULL, 0); + break; + + default: + usage(argv[0]); + return 1; + } + } + + if (optind == argc - 1) + servername = strdup(argv[optind]); + else if (optind < argc) { + usage(argv[0]); + return 1; + } + + page_size = sysconf(_SC_PAGESIZE); + + dev_list = ibv_get_device_list(NULL); + if (!dev_list) { + perror("Failed to get IB devices list"); + return 1; + } + + if (!ib_devname) { + ib_dev = *dev_list; + if (!ib_dev) { + fprintf(stderr, "No IB devices found\n"); + return 1; + } + } else { + int i; + for (i = 0; dev_list[i]; ++i) + if (!strcmp(ibv_get_device_name(dev_list[i]), ib_devname)) + break; + ib_dev = dev_list[i]; + if (!ib_dev) { + fprintf(stderr, "IB device %s not found\n", ib_devname); + return 1; + } + } + + ctx = pp_init_ctx(ib_dev, size, rx_depth, ib_port, use_event); + if (!ctx) + return 1; + + routs = pp_post_recv(ctx, ctx->rx_depth); + if (routs < ctx->rx_depth) { + fprintf(stderr, "Couldn't post receive (%d)\n", routs); + return 1; + } + + if (use_event) + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + + if (pp_get_port_info(ctx->context, ib_port, &ctx->portinfo)) { + fprintf(stderr, "Couldn't get port info\n"); + return 1; + } + my_dest.lid = ctx->portinfo.lid; + + my_dest.qpn = ctx->qp->qp_num; + my_dest.psn = lrand48() & 0xffffff; + + if (gidx >= 0) { + if (ibv_query_gid(ctx->context, ib_port, gidx, &my_dest.gid)) { + fprintf(stderr, "Could not get local gid for gid index %d\n", gidx); + return 1; + } + } else + memset(&my_dest.gid, 0, sizeof my_dest.gid); + + inet_ntop(AF_INET6, &my_dest.gid, gid, sizeof gid); + printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x: GID %s\n", + my_dest.lid, my_dest.qpn, my_dest.psn, gid); + + if (servername) + rem_dest = pp_client_exch_dest(servername, port, &my_dest); + else + rem_dest = pp_server_exch_dest(ctx, ib_port, port, sl, &my_dest, gidx); + + if (!rem_dest) + return 1; + + inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof gid); + printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", + rem_dest->lid, rem_dest->qpn, rem_dest->psn, gid); + + if (servername) + if (pp_connect_ctx(ctx, ib_port, my_dest.psn, sl, rem_dest, gidx)) + return 1; + + ctx->pending = PINGPONG_RECV_WRID; + + if (servername) { + if (pp_post_send(ctx, rem_dest->qpn)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending |= PINGPONG_SEND_WRID; + } + + if (gettimeofday(&start, NULL)) { + perror("gettimeofday"); + return 1; + } + + rcnt = scnt = 0; + while (rcnt < iters || scnt < iters) { + if (use_event) { + struct ibv_cq *ev_cq; + void *ev_ctx; + + if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\n"); + return 1; + } + + ++num_cq_events; + + if (ev_cq != ctx->cq) { + fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq); + return 1; + } + + if (ibv_req_notify_cq(ctx->cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\n"); + return 1; + } + } + + { + struct ibv_wc wc[2]; + int ne, i; + + do { + ne = ibv_poll_cq(ctx->cq, 2, wc); + if (ne < 0) { + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } + } while (!use_event && ne < 1); + + for (i = 0; i < ne; ++i) { + if (wc[i].status != IBV_WC_SUCCESS) { + fprintf(stderr, "Failed status %s (%d) for wr_id %d\n", + ibv_wc_status_str(wc[i].status), + wc[i].status, (int) wc[i].wr_id); + return 1; + } + + switch ((int) wc[i].wr_id) { + case PINGPONG_SEND_WRID: + ++scnt; + break; + + case PINGPONG_RECV_WRID: + if (--routs <= 1) { + routs += pp_post_recv(ctx, ctx->rx_depth - routs); + if (routs < ctx->rx_depth) { + fprintf(stderr, + "Couldn't post receive (%d)\n", + routs); + return 1; + } + } + + ++rcnt; + break; + + default: + fprintf(stderr, "Completion for unknown wr_id %d\n", + (int) wc[i].wr_id); + return 1; + } + + ctx->pending &= ~(int) wc[i].wr_id; + if (scnt < iters && !ctx->pending) { + if (pp_post_send(ctx, rem_dest->qpn)) { + fprintf(stderr, "Couldn't post send\n"); + return 1; + } + ctx->pending = PINGPONG_RECV_WRID | + PINGPONG_SEND_WRID; + } + } + } + } + + if (gettimeofday(&end, NULL)) { + perror("gettimeofday"); + return 1; + } + + { + float usec = (end.tv_sec - start.tv_sec) * 1000000 + + (end.tv_usec - start.tv_usec); + long long bytes = (long long) size * iters * 2; + + printf("%lld bytes in %.2f seconds = %.2f Mbit/sec\n", + bytes, usec / 1000000., bytes * 8. / usec); + printf("%d iters in %.2f seconds = %.2f usec/iter\n", + iters, usec / 1000000., usec / iters); + } + + ibv_ack_cq_events(ctx->cq, num_cq_events); + + if (pp_close_ctx(ctx)) + return 1; + + ibv_free_device_list(dev_list); + free(rem_dest); + + return 0; +} diff --git a/contrib/ofed/libibverbs/fixes/XRC_RCV_QP.patch b/contrib/ofed/libibverbs/fixes/XRC_RCV_QP.patch new file mode 100644 index 000000000000..bfa6cc9996ae --- /dev/null +++ b/contrib/ofed/libibverbs/fixes/XRC_RCV_QP.patch @@ -0,0 +1,702 @@ +Added support for XRC receive-only QPs. +(OFED 1.3 libibverbs commit 6e99cddf835d4715ea7ca3641944e6285f27f2df) + +V2: +1. checkpatch.pl cleanups +2. Fixed u64 alignment problems in kern-abi.h +3. eliminated unneeded default_symvers +4. Added ibv_xrc_rcv_xxx lines to libibverbs.map IBVERBS_1.1 + +Signed-off-by: Jack Morgenstein +--- + include/infiniband/driver.h | 12 ++- + include/infiniband/kern-abi.h | 99 +++++++++++++++++++- + include/infiniband/verbs.h | 123 +++++++++++++++++++++++ + src/cmd.c | 215 +++++++++++++++++++++++++++++++++++++++++ + src/device.c | 52 +++++----- + src/libibverbs.map | 10 ++ + src/verbs.c | 59 +++++++++++ + 7 files changed, 543 insertions(+), 27 deletions(-) + +Index: libibverbs/include/infiniband/driver.h +=================================================================== +--- libibverbs.orig/include/infiniband/driver.h 2009-11-01 15:18:20.624171000 +0200 ++++ libibverbs/include/infiniband/driver.h 2009-11-01 15:18:24.572283000 +0200 +@@ -144,7 +144,17 @@ int ibv_cmd_open_xrc_domain(struct ibv_c + struct ibv_open_xrc_domain_resp *resp, + size_t resp_size); + int ibv_cmd_close_xrc_domain(struct ibv_xrc_domain *d); +- ++int ibv_cmd_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, ++ uint32_t *xrc_rcv_qpn); ++int ibv_cmd_modify_xrc_rcv_qp(struct ibv_xrc_domain *d, uint32_t xrc_rcv_qpn, ++ struct ibv_qp_attr *attr, int attr_mask); ++int ibv_cmd_query_xrc_rcv_qp(struct ibv_xrc_domain *d, uint32_t xrc_rcv_qpn, ++ struct ibv_qp_attr *attr, int attr_mask, ++ struct ibv_qp_init_attr *init_attr); ++int ibv_cmd_reg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num); ++int ibv_cmd_unreg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num); + + /* + * sysfs helper functions +Index: libibverbs/include/infiniband/kern-abi.h +=================================================================== +--- libibverbs.orig/include/infiniband/kern-abi.h 2009-11-01 15:18:20.629168000 +0200 ++++ libibverbs/include/infiniband/kern-abi.h 2009-11-01 15:18:24.577283000 +0200 +@@ -88,7 +88,12 @@ enum { + IB_USER_VERBS_CMD_POST_SRQ_RECV, + IB_USER_VERBS_CMD_CREATE_XRC_SRQ, + IB_USER_VERBS_CMD_OPEN_XRC_DOMAIN, +- IB_USER_VERBS_CMD_CLOSE_XRC_DOMAIN ++ IB_USER_VERBS_CMD_CLOSE_XRC_DOMAIN, ++ IB_USER_VERBS_CMD_CREATE_XRC_RCV_QP, ++ IB_USER_VERBS_CMD_MODIFY_XRC_RCV_QP, ++ IB_USER_VERBS_CMD_QUERY_XRC_RCV_QP, ++ IB_USER_VERBS_CMD_REG_XRC_RCV_QP, ++ IB_USER_VERBS_CMD_UNREG_XRC_RCV_QP, + }; + + /* +@@ -570,6 +575,93 @@ struct ibv_destroy_qp_resp { + __u32 events_reported; + }; + ++struct ibv_create_xrc_rcv_qp { ++ __u32 command; ++ __u16 in_words; ++ __u16 out_words; ++ __u64 response; ++ __u64 user_handle; ++ __u32 xrc_domain_handle; ++ __u32 max_send_wr; ++ __u32 max_recv_wr; ++ __u32 max_send_sge; ++ __u32 max_recv_sge; ++ __u32 max_inline_data; ++ __u8 sq_sig_all; ++ __u8 qp_type; ++ __u8 reserved[6]; ++ __u64 driver_data[0]; ++}; ++ ++struct ibv_create_xrc_rcv_qp_resp { ++ __u32 qpn; ++ __u32 reserved; ++}; ++ ++struct ibv_modify_xrc_rcv_qp { ++ __u32 command; ++ __u16 in_words; ++ __u16 out_words; ++ __u32 xrc_domain_handle; ++ __u32 qp_num; ++ struct ibv_qp_dest dest; ++ struct ibv_qp_dest alt_dest; ++ __u32 attr_mask; ++ __u32 qkey; ++ __u32 rq_psn; ++ __u32 sq_psn; ++ __u32 dest_qp_num; ++ __u32 qp_access_flags; ++ __u16 pkey_index; ++ __u16 alt_pkey_index; ++ __u8 qp_state; ++ __u8 cur_qp_state; ++ __u8 path_mtu; ++ __u8 path_mig_state; ++ __u8 en_sqd_async_notify; ++ __u8 max_rd_atomic; ++ __u8 max_dest_rd_atomic; ++ __u8 min_rnr_timer; ++ __u8 port_num; ++ __u8 timeout; ++ __u8 retry_cnt; ++ __u8 rnr_retry; ++ __u8 alt_port_num; ++ __u8 alt_timeout; ++ __u8 reserved[6]; ++ __u64 driver_data[0]; ++}; ++ ++struct ibv_query_xrc_rcv_qp { ++ __u32 command; ++ __u16 in_words; ++ __u16 out_words; ++ __u64 response; ++ __u32 xrc_domain_handle; ++ __u32 qp_num; ++ __u32 attr_mask; ++ __u32 reserved; ++ __u64 driver_data[0]; ++}; ++ ++struct ibv_reg_xrc_rcv_qp { ++ __u32 command; ++ __u16 in_words; ++ __u16 out_words; ++ __u32 xrc_domain_handle; ++ __u32 qp_num; ++ __u64 driver_data[0]; ++}; ++ ++struct ibv_unreg_xrc_rcv_qp { ++ __u32 command; ++ __u16 in_words; ++ __u16 out_words; ++ __u32 xrc_domain_handle; ++ __u32 qp_num; ++ __u64 driver_data[0]; ++}; ++ + struct ibv_kern_send_wr { + __u64 wr_id; + __u32 num_sge; +@@ -848,6 +940,11 @@ enum { + IB_USER_VERBS_CMD_CREATE_XRC_SRQ_V2 = -1, + IB_USER_VERBS_CMD_OPEN_XRC_DOMAIN_V2 = -1, + IB_USER_VERBS_CMD_CLOSE_XRC_DOMAIN_V2 = -1, ++ IB_USER_VERBS_CMD_CREATE_XRC_RCV_QP_V2 = -1, ++ IB_USER_VERBS_CMD_MODIFY_XRC_RCV_QP_V2 = -1, ++ IB_USER_VERBS_CMD_QUERY_XRC_RCV_QP_V2 = -1, ++ IB_USER_VERBS_CMD_REG_XRC_RCV_QP_V2 = -1, ++ IB_USER_VERBS_CMD_UNREG_XRC_RCV_QP_V2 = -1, + }; + + struct ibv_destroy_cq_v1 { +Index: libibverbs/include/infiniband/verbs.h +=================================================================== +--- libibverbs.orig/include/infiniband/verbs.h 2009-11-01 15:18:20.635171000 +0200 ++++ libibverbs/include/infiniband/verbs.h 2009-11-01 15:18:24.585280000 +0200 +@@ -205,12 +205,17 @@ enum ibv_event_type { + IBV_EVENT_CLIENT_REREGISTER + }; + ++enum ibv_event_flags { ++ IBV_XRC_QP_EVENT_FLAG = 0x80000000, ++}; ++ + struct ibv_async_event { + union { + struct ibv_cq *cq; + struct ibv_qp *qp; + struct ibv_srq *srq; + int port_num; ++ uint32_t xrc_qp_num; + } element; + enum ibv_event_type event_type; + }; +@@ -648,6 +653,22 @@ struct ibv_more_ops { + struct ibv_xrc_domain * (*open_xrc_domain)(struct ibv_context *context, + int fd, int oflag); + int (*close_xrc_domain)(struct ibv_xrc_domain *d); ++ int (*create_xrc_rcv_qp)(struct ibv_qp_init_attr *init_attr, ++ uint32_t *xrc_qp_num); ++ int (*modify_xrc_rcv_qp)(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num, ++ struct ibv_qp_attr *attr, ++ int attr_mask); ++ int (*query_xrc_rcv_qp)(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num, ++ struct ibv_qp_attr *attr, ++ int attr_mask, ++ struct ibv_qp_init_attr *init_attr); ++ int (*reg_xrc_rcv_qp)(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num); ++ int (*unreg_xrc_rcv_qp)(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num); ++ + }; + + struct ibv_context_ops { +@@ -1174,6 +1195,108 @@ struct ibv_xrc_domain *ibv_open_xrc_doma + */ + int ibv_close_xrc_domain(struct ibv_xrc_domain *d); + ++/** ++ * ibv_create_xrc_rcv_qp - creates an XRC QP for serving as a receive-side-only QP, ++ * ++ * This QP is created in kernel space, and persists until the last process ++ * registered for the QP calls ibv_unreg_xrc_rcv_qp() (at which time the QP ++ * is destroyed). ++ * ++ * @init_attr: init attributes to use for QP. xrc domain MUST be included here. ++ * All other fields are ignored. ++ * ++ * @xrc_rcv_qpn: qp_num of created QP (if success). To be passed to the ++ * remote node (sender). The remote node will use xrc_rcv_qpn ++ * in ibv_post_send when sending to XRC SRQ's on this host ++ * in the same xrc domain. ++ * ++ * RETURNS: success (0), or a (negative) error value. ++ * ++ * NOTE: this verb also registers the calling user-process with the QP at its ++ * creation time (implicit call to ibv_reg_xrc_rcv_qp), to avoid race ++ * conditions. The creating process will need to call ibv_unreg_xrc_qp() ++ * for the QP to release it from this process. ++ */ ++int ibv_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, ++ uint32_t *xrc_rcv_qpn); ++ ++/** ++ * ibv_modify_xrc_rcv_qp - modifies an xrc_rcv qp. ++ * ++ * @xrc_domain: xrc domain the QP belongs to (for verification). ++ * @xrc_qp_num: The (24 bit) number of the XRC QP. ++ * @attr: modify-qp attributes. The following fields must be specified: ++ * for RESET_2_INIT: qp_state, pkey_index , port, qp_access_flags ++ * for INIT_2_RTR: qp_state, path_mtu, dest_qp_num, rq_psn, ++ * max_dest_rd_atomic, min_rnr_timer, ah_attr ++ * The QP need not be brought to RTS for the QP to operate as a ++ * receive-only QP. ++ * @attr_mask: bitmap indicating which attributes are provided in the attr ++ * struct. Used for validity checking. ++ * The following bits must be set: ++ * for RESET_2_INIT: IBV_QP_PKEY_INDEX, IBV_QP_PORT, ++ * IBV_QP_ACCESS_FLAGS, IBV_QP_STATE ++ * for INIT_2_RTR: 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, IBV_QP_STATE ++ * ++ * RETURNS: success (0), or a (positive) error value. ++ * ++ */ ++int ibv_modify_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num, ++ struct ibv_qp_attr *attr, int attr_mask); ++ ++/** ++ * ibv_query_xrc_rcv_qp - queries an xrc_rcv qp. ++ * ++ * @xrc_domain: xrc domain the QP belongs to (for verification). ++ * @xrc_qp_num: The (24 bit) number of the XRC QP. ++ * @attr: for returning qp attributes. ++ * @attr_mask: bitmap indicating which attributes to return. ++ * @init_attr: for returning the init attributes ++ * ++ * RETURNS: success (0), or a (positive) error value. ++ * ++ */ ++int ibv_query_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num, ++ struct ibv_qp_attr *attr, int attr_mask, ++ struct ibv_qp_init_attr *init_attr); ++ ++/** ++ * ibv_reg_xrc_rcv_qp: registers a user process with an XRC QP which serves as ++ * a receive-side only QP. ++ * ++ * @xrc_domain: xrc domain the QP belongs to (for verification). ++ * @xrc_qp_num: The (24 bit) number of the XRC QP. ++ * ++ * RETURNS: success (0), ++ * or error (EINVAL), if: ++ * 1. There is no such QP_num allocated. ++ * 2. The QP is allocated, but is not an receive XRC QP ++ * 3. The XRC QP does not belong to the given domain. ++ */ ++int ibv_reg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num); ++ ++/** ++ * ibv_unreg_xrc_rcv_qp: detaches a user process from an XRC QP serving as ++ * a receive-side only QP. If as a result, there are no remaining ++ * userspace processes registered for this XRC QP, it is destroyed. ++ * ++ * @xrc_domain: xrc domain the QP belongs to (for verification). ++ * @xrc_qp_num: The (24 bit) number of the XRC QP. ++ * ++ * RETURNS: success (0), ++ * or error (EINVAL), if: ++ * 1. There is no such QP_num allocated. ++ * 2. The QP is allocated, but is not an XRC QP ++ * 3. The XRC QP does not belong to the given domain. ++ * NOTE: There is no reason to return a special code if the QP is destroyed. ++ * The unregister simply succeeds. ++ */ ++int ibv_unreg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num); ++ + END_C_DECLS + + # undef __attribute_const +Index: libibverbs/src/cmd.c +=================================================================== +--- libibverbs.orig/src/cmd.c 2009-11-01 15:18:20.643167000 +0200 ++++ libibverbs/src/cmd.c 2009-11-01 15:18:24.592284000 +0200 +@@ -828,6 +828,188 @@ int ibv_cmd_modify_qp(struct ibv_qp *qp, + return 0; + } + ++int ibv_cmd_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, ++ uint32_t *xrc_rcv_qpn) ++{ ++ struct ibv_create_xrc_rcv_qp cmd; ++ struct ibv_create_xrc_rcv_qp_resp resp; ++ ++ if (abi_ver < 6) ++ return ENOSYS; ++ ++ IBV_INIT_CMD_RESP(&cmd, sizeof cmd, CREATE_XRC_RCV_QP, &resp, ++ sizeof resp); ++ ++ cmd.xrc_domain_handle = init_attr->xrc_domain->handle; ++ cmd.max_send_wr = init_attr->cap.max_send_wr; ++ cmd.max_recv_wr = init_attr->cap.max_recv_wr; ++ cmd.max_send_sge = init_attr->cap.max_send_sge; ++ cmd.max_recv_sge = init_attr->cap.max_recv_sge; ++ cmd.max_inline_data = init_attr->cap.max_inline_data; ++ cmd.sq_sig_all = init_attr->sq_sig_all; ++ cmd.qp_type = init_attr->qp_type; ++ cmd.reserved[0] = cmd.reserved[1] = 0; ++ ++ if (write(init_attr->xrc_domain->context->cmd_fd, &cmd, sizeof cmd) != ++ sizeof cmd) ++ return errno; ++ ++ *xrc_rcv_qpn = resp.qpn; ++ ++ return 0; ++} ++ ++int ibv_cmd_modify_xrc_rcv_qp(struct ibv_xrc_domain *d, uint32_t xrc_qp_num, ++ struct ibv_qp_attr *attr, int attr_mask) ++{ ++ struct ibv_modify_xrc_rcv_qp cmd; ++ ++ if (abi_ver < 6) ++ return ENOSYS; ++ ++ IBV_INIT_CMD(&cmd, sizeof cmd, MODIFY_XRC_RCV_QP); ++ ++ cmd.xrc_domain_handle = d->handle; ++ cmd.qp_num = xrc_qp_num; ++ cmd.attr_mask = attr_mask; ++ cmd.qkey = attr->qkey; ++ cmd.rq_psn = attr->rq_psn; ++ cmd.sq_psn = attr->sq_psn; ++ cmd.dest_qp_num = attr->dest_qp_num; ++ cmd.qp_access_flags = attr->qp_access_flags; ++ cmd.pkey_index = attr->pkey_index; ++ cmd.alt_pkey_index = attr->alt_pkey_index; ++ cmd.qp_state = attr->qp_state; ++ cmd.cur_qp_state = attr->cur_qp_state; ++ cmd.path_mtu = attr->path_mtu; ++ cmd.path_mig_state = attr->path_mig_state; ++ cmd.en_sqd_async_notify = attr->en_sqd_async_notify; ++ cmd.max_rd_atomic = attr->max_rd_atomic; ++ cmd.max_dest_rd_atomic = attr->max_dest_rd_atomic; ++ cmd.min_rnr_timer = attr->min_rnr_timer; ++ cmd.port_num = attr->port_num; ++ cmd.timeout = attr->timeout; ++ cmd.retry_cnt = attr->retry_cnt; ++ cmd.rnr_retry = attr->rnr_retry; ++ cmd.alt_port_num = attr->alt_port_num; ++ cmd.alt_timeout = attr->alt_timeout; ++ ++ memcpy(cmd.dest.dgid, attr->ah_attr.grh.dgid.raw, 16); ++ cmd.dest.flow_label = attr->ah_attr.grh.flow_label; ++ cmd.dest.dlid = attr->ah_attr.dlid; ++ cmd.dest.reserved = 0; ++ cmd.dest.sgid_index = attr->ah_attr.grh.sgid_index; ++ cmd.dest.hop_limit = attr->ah_attr.grh.hop_limit; ++ cmd.dest.traffic_class = attr->ah_attr.grh.traffic_class; ++ cmd.dest.sl = attr->ah_attr.sl; ++ cmd.dest.src_path_bits = attr->ah_attr.src_path_bits; ++ cmd.dest.static_rate = attr->ah_attr.static_rate; ++ cmd.dest.is_global = attr->ah_attr.is_global; ++ cmd.dest.port_num = attr->ah_attr.port_num; ++ ++ memcpy(cmd.alt_dest.dgid, attr->alt_ah_attr.grh.dgid.raw, 16); ++ cmd.alt_dest.flow_label = attr->alt_ah_attr.grh.flow_label; ++ cmd.alt_dest.dlid = attr->alt_ah_attr.dlid; ++ cmd.alt_dest.reserved = 0; ++ cmd.alt_dest.sgid_index = attr->alt_ah_attr.grh.sgid_index; ++ cmd.alt_dest.hop_limit = attr->alt_ah_attr.grh.hop_limit; ++ cmd.alt_dest.traffic_class = attr->alt_ah_attr.grh.traffic_class; ++ cmd.alt_dest.sl = attr->alt_ah_attr.sl; ++ cmd.alt_dest.src_path_bits = attr->alt_ah_attr.src_path_bits; ++ cmd.alt_dest.static_rate = attr->alt_ah_attr.static_rate; ++ cmd.alt_dest.is_global = attr->alt_ah_attr.is_global; ++ cmd.alt_dest.port_num = attr->alt_ah_attr.port_num; ++ ++ cmd.reserved[0] = cmd.reserved[1] = 0; ++ ++ if (write(d->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) ++ return errno; ++ ++ return 0; ++} ++ ++int ibv_cmd_query_xrc_rcv_qp(struct ibv_xrc_domain *d, uint32_t xrc_qp_num, ++ struct ibv_qp_attr *attr, int attr_mask, ++ struct ibv_qp_init_attr *init_attr) ++{ ++ struct ibv_query_xrc_rcv_qp cmd; ++ struct ibv_query_qp_resp resp; ++ ++ if (abi_ver < 6) ++ return ENOSYS; ++ ++ IBV_INIT_CMD_RESP(&cmd, sizeof cmd, QUERY_XRC_RCV_QP, &resp, ++ sizeof resp); ++ cmd.xrc_domain_handle = d->handle; ++ cmd.qp_num = xrc_qp_num; ++ cmd.attr_mask = attr_mask; ++ ++ if (write(d->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) ++ return errno; ++ ++ VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); ++ ++ attr->qkey = resp.qkey; ++ attr->rq_psn = resp.rq_psn; ++ attr->sq_psn = resp.sq_psn; ++ attr->dest_qp_num = resp.dest_qp_num; ++ attr->qp_access_flags = resp.qp_access_flags; ++ attr->pkey_index = resp.pkey_index; ++ attr->alt_pkey_index = resp.alt_pkey_index; ++ attr->qp_state = resp.qp_state; ++ attr->cur_qp_state = resp.cur_qp_state; ++ attr->path_mtu = resp.path_mtu; ++ attr->path_mig_state = resp.path_mig_state; ++ attr->sq_draining = resp.sq_draining; ++ attr->max_rd_atomic = resp.max_rd_atomic; ++ attr->max_dest_rd_atomic = resp.max_dest_rd_atomic; ++ attr->min_rnr_timer = resp.min_rnr_timer; ++ attr->port_num = resp.port_num; ++ attr->timeout = resp.timeout; ++ attr->retry_cnt = resp.retry_cnt; ++ attr->rnr_retry = resp.rnr_retry; ++ attr->alt_port_num = resp.alt_port_num; ++ attr->alt_timeout = resp.alt_timeout; ++ attr->cap.max_send_wr = resp.max_send_wr; ++ attr->cap.max_recv_wr = resp.max_recv_wr; ++ attr->cap.max_send_sge = resp.max_send_sge; ++ attr->cap.max_recv_sge = resp.max_recv_sge; ++ attr->cap.max_inline_data = resp.max_inline_data; ++ ++ memcpy(attr->ah_attr.grh.dgid.raw, resp.dest.dgid, 16); ++ attr->ah_attr.grh.flow_label = resp.dest.flow_label; ++ attr->ah_attr.dlid = resp.dest.dlid; ++ attr->ah_attr.grh.sgid_index = resp.dest.sgid_index; ++ attr->ah_attr.grh.hop_limit = resp.dest.hop_limit; ++ attr->ah_attr.grh.traffic_class = resp.dest.traffic_class; ++ attr->ah_attr.sl = resp.dest.sl; ++ attr->ah_attr.src_path_bits = resp.dest.src_path_bits; ++ attr->ah_attr.static_rate = resp.dest.static_rate; ++ attr->ah_attr.is_global = resp.dest.is_global; ++ attr->ah_attr.port_num = resp.dest.port_num; ++ ++ memcpy(attr->alt_ah_attr.grh.dgid.raw, resp.alt_dest.dgid, 16); ++ attr->alt_ah_attr.grh.flow_label = resp.alt_dest.flow_label; ++ attr->alt_ah_attr.dlid = resp.alt_dest.dlid; ++ attr->alt_ah_attr.grh.sgid_index = resp.alt_dest.sgid_index; ++ attr->alt_ah_attr.grh.hop_limit = resp.alt_dest.hop_limit; ++ attr->alt_ah_attr.grh.traffic_class = resp.alt_dest.traffic_class; ++ attr->alt_ah_attr.sl = resp.alt_dest.sl; ++ attr->alt_ah_attr.src_path_bits = resp.alt_dest.src_path_bits; ++ attr->alt_ah_attr.static_rate = resp.alt_dest.static_rate; ++ attr->alt_ah_attr.is_global = resp.alt_dest.is_global; ++ attr->alt_ah_attr.port_num = resp.alt_dest.port_num; ++ ++ init_attr->cap.max_send_wr = resp.max_send_wr; ++ init_attr->cap.max_recv_wr = resp.max_recv_wr; ++ init_attr->cap.max_send_sge = resp.max_send_sge; ++ init_attr->cap.max_recv_sge = resp.max_recv_sge; ++ init_attr->cap.max_inline_data = resp.max_inline_data; ++ init_attr->sq_sig_all = resp.sq_sig_all; ++ ++ return 0; ++} ++ + static int ibv_cmd_destroy_qp_v1(struct ibv_qp *qp) + { + struct ibv_destroy_qp_v1 cmd; +@@ -1192,3 +1374,36 @@ int ibv_cmd_close_xrc_domain(struct ibv_ + return 0; + } + ++int ibv_cmd_reg_xrc_rcv_qp(struct ibv_xrc_domain *d, uint32_t xrc_qp_num) ++{ ++ struct ibv_reg_xrc_rcv_qp cmd; ++ ++ if (abi_ver < 6) ++ return ENOSYS; ++ ++ IBV_INIT_CMD(&cmd, sizeof cmd, REG_XRC_RCV_QP); ++ cmd.xrc_domain_handle = d->handle; ++ cmd.qp_num = xrc_qp_num; ++ ++ if (write(d->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) ++ return errno; ++ return 0; ++} ++ ++int ibv_cmd_unreg_xrc_rcv_qp(struct ibv_xrc_domain *d, uint32_t xrc_qp_num) ++{ ++ struct ibv_unreg_xrc_rcv_qp cmd; ++ ++ if (abi_ver < 6) ++ return ENOSYS; ++ ++ IBV_INIT_CMD(&cmd, sizeof cmd, UNREG_XRC_RCV_QP); ++ cmd.xrc_domain_handle = d->handle; ++ cmd.qp_num = xrc_qp_num; ++ ++ if (write(d->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) ++ return errno; ++ return 0; ++} ++ ++ +Index: libibverbs/src/device.c +=================================================================== +--- libibverbs.orig/src/device.c 2009-11-01 15:18:17.794116000 +0200 ++++ libibverbs/src/device.c 2009-11-01 15:18:24.597279000 +0200 +@@ -191,31 +191,33 @@ int __ibv_get_async_event(struct ibv_con + + event->event_type = ev.event_type; + +- switch (event->event_type) { +- case IBV_EVENT_CQ_ERR: +- event->element.cq = (void *) (uintptr_t) ev.element; +- break; +- +- case IBV_EVENT_QP_FATAL: +- case IBV_EVENT_QP_REQ_ERR: +- case IBV_EVENT_QP_ACCESS_ERR: +- case IBV_EVENT_COMM_EST: +- case IBV_EVENT_SQ_DRAINED: +- case IBV_EVENT_PATH_MIG: +- case IBV_EVENT_PATH_MIG_ERR: +- case IBV_EVENT_QP_LAST_WQE_REACHED: +- event->element.qp = (void *) (uintptr_t) ev.element; +- break; +- +- case IBV_EVENT_SRQ_ERR: +- case IBV_EVENT_SRQ_LIMIT_REACHED: +- event->element.srq = (void *) (uintptr_t) ev.element; +- break; +- +- default: +- event->element.port_num = ev.element; +- break; +- } ++ if (event->event_type & IBV_XRC_QP_EVENT_FLAG) { ++ event->element.xrc_qp_num = ev.element; ++ } else ++ switch (event->event_type) { ++ case IBV_EVENT_CQ_ERR: ++ event->element.cq = (void *) (uintptr_t) ev.element; ++ break; ++ ++ case IBV_EVENT_QP_FATAL: ++ case IBV_EVENT_QP_REQ_ERR: ++ case IBV_EVENT_QP_ACCESS_ERR: ++ case IBV_EVENT_COMM_EST: ++ case IBV_EVENT_SQ_DRAINED: ++ case IBV_EVENT_PATH_MIG: ++ case IBV_EVENT_PATH_MIG_ERR: ++ case IBV_EVENT_QP_LAST_WQE_REACHED: ++ event->element.qp = (void *) (uintptr_t) ev.element; ++ break; ++ ++ case IBV_EVENT_SRQ_ERR: ++ case IBV_EVENT_SRQ_LIMIT_REACHED: ++ event->element.srq = (void *) (uintptr_t) ev.element; ++ break; ++ default: ++ event->element.port_num = ev.element; ++ break; ++ } + + if (context->ops.async_event) + context->ops.async_event(event); +Index: libibverbs/src/libibverbs.map +=================================================================== +--- libibverbs.orig/src/libibverbs.map 2009-11-01 15:18:20.646169000 +0200 ++++ libibverbs/src/libibverbs.map 2009-11-01 15:18:24.600279000 +0200 +@@ -97,6 +97,16 @@ IBVERBS_1.1 { + ibv_cmd_open_xrc_domain; + ibv_close_xrc_domain; + ibv_cmd_close_xrc_domain; ++ ibv_create_xrc_rcv_qp; ++ ibv_cmd_create_xrc_rcv_qp; ++ ibv_modify_xrc_rcv_qp; ++ ibv_cmd_modify_xrc_rcv_qp; ++ ibv_query_xrc_rcv_qp; ++ ibv_cmd_query_xrc_rcv_qp; ++ ibv_reg_xrc_rcv_qp; ++ ibv_cmd_reg_xrc_rcv_qp; ++ ibv_unreg_xrc_rcv_qp; ++ ibv_cmd_unreg_xrc_rcv_qp; + + ibv_node_type_str; + ibv_port_state_str; +Index: libibverbs/src/verbs.c +=================================================================== +--- libibverbs.orig/src/verbs.c 2009-11-01 15:18:20.650169000 +0200 ++++ libibverbs/src/verbs.c 2009-11-01 15:18:24.604279000 +0200 +@@ -597,3 +597,62 @@ int ibv_close_xrc_domain(struct ibv_xrc_ + + return d->context->more_ops->close_xrc_domain(d); + } ++ ++int ibv_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, ++ uint32_t *xrc_rcv_qpn) ++{ ++ struct ibv_context *c; ++ if (!init_attr || !(init_attr->xrc_domain)) ++ return EINVAL; ++ ++ c = init_attr->xrc_domain->context; ++ if (!c->more_ops) ++ return ENOSYS; ++ ++ return c->more_ops->create_xrc_rcv_qp(init_attr, ++ xrc_rcv_qpn); ++} ++ ++int ibv_modify_xrc_rcv_qp(struct ibv_xrc_domain *d, ++ uint32_t xrc_rcv_qpn, ++ struct ibv_qp_attr *attr, ++ int attr_mask) ++{ ++ if (!d || !attr) ++ return EINVAL; ++ ++ if (!d->context->more_ops) ++ return ENOSYS; ++ ++ return d->context->more_ops->modify_xrc_rcv_qp(d, xrc_rcv_qpn, attr, ++ attr_mask); ++} ++ ++int ibv_query_xrc_rcv_qp(struct ibv_xrc_domain *d, ++ uint32_t xrc_rcv_qpn, ++ struct ibv_qp_attr *attr, ++ int attr_mask, ++ struct ibv_qp_init_attr *init_attr) ++{ ++ if (!d) ++ return EINVAL; ++ ++ if (!d->context->more_ops) ++ return ENOSYS; ++ ++ return d->context->more_ops->query_xrc_rcv_qp(d, xrc_rcv_qpn, attr, ++ attr_mask, init_attr); ++} ++ ++int ibv_reg_xrc_rcv_qp(struct ibv_xrc_domain *d, ++ uint32_t xrc_rcv_qpn) ++{ ++ return d->context->more_ops->reg_xrc_rcv_qp(d, xrc_rcv_qpn); ++} ++ ++int ibv_unreg_xrc_rcv_qp(struct ibv_xrc_domain *d, ++ uint32_t xrc_rcv_qpn) ++{ ++ return d->context->more_ops->unreg_xrc_rcv_qp(d, xrc_rcv_qpn); ++} ++ diff --git a/contrib/ofed/libibverbs/fixes/XRC_base_implementation.patch b/contrib/ofed/libibverbs/fixes/XRC_base_implementation.patch new file mode 100644 index 000000000000..b4706a840ea0 --- /dev/null +++ b/contrib/ofed/libibverbs/fixes/XRC_base_implementation.patch @@ -0,0 +1,503 @@ +This patch includes the following commits from OFED 1.3 libibverbs: +Implement eXtended Reliable Connections (a7df4af8eb84738f36db4161a4272fa02fc6741e) +Re-define IBV_DEVICE_XRC to conform to its new position (5042a9cab0ae2f7ad61bdf88dfed6fb10b700797) +Set "is_srq" flag only when the QP has an SRQ (6f6d29e74ca0c19a8821990aad603e3c575b7f4d) +for XRC QPs, return xrc_domain in ibv_query_qp (018c44a44ff0344dfe7cf5f6598f81d81769164e) + +V2: +1. checkpatch.pl cleanups +2. fixed u64 alignment problems in uverbs.h ABI structs +3. eliminated unnecessary default_symvers +4. modified xrc_ops to more_ops + +Signed-off-by: Jack Morgenstein + include/infiniband/driver.h | 11 +++++ + include/infiniband/kern-abi.h | 47 ++++++++++++++++++++++- + include/infiniband/verbs.h | 85 ++++++++++++++++++++++++++++++++++++++++- + src/cmd.c | 72 ++++++++++++++++++++++++++++++++++- + src/libibverbs.map | 6 +++ + src/verbs.c | 54 ++++++++++++++++++++++++++ + 6 files changed, 271 insertions(+), 4 deletions(-) + +Index: libibverbs/include/infiniband/driver.h +=================================================================== +--- libibverbs.orig/include/infiniband/driver.h 2009-11-01 15:18:17.920111000 +0200 ++++ libibverbs/include/infiniband/driver.h 2009-11-01 15:18:20.624171000 +0200 +@@ -99,6 +99,11 @@ int ibv_cmd_create_srq(struct ibv_pd *pd + struct ibv_srq *srq, struct ibv_srq_init_attr *attr, + struct ibv_create_srq *cmd, size_t cmd_size, + struct ibv_create_srq_resp *resp, size_t resp_size); ++int ibv_cmd_create_xrc_srq(struct ibv_pd *pd, ++ struct ibv_srq *srq, struct ibv_srq_init_attr *attr, ++ uint32_t xrc_domain, uint32_t xrc_cq, ++ struct ibv_create_xrc_srq *cmd, size_t cmd_size, ++ struct ibv_create_srq_resp *resp, size_t resp_size); + int ibv_cmd_modify_srq(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + int srq_attr_mask, +@@ -134,6 +139,12 @@ int ibv_cmd_detach_mcast(struct ibv_qp * + + int ibv_dontfork_range(void *base, size_t size); + int ibv_dofork_range(void *base, size_t size); ++int ibv_cmd_open_xrc_domain(struct ibv_context *context, int fd, int oflag, ++ struct ibv_xrc_domain *d, ++ struct ibv_open_xrc_domain_resp *resp, ++ size_t resp_size); ++int ibv_cmd_close_xrc_domain(struct ibv_xrc_domain *d); ++ + + /* + * sysfs helper functions +Index: libibverbs/include/infiniband/kern-abi.h +=================================================================== +--- libibverbs.orig/include/infiniband/kern-abi.h 2009-11-01 15:18:17.921121000 +0200 ++++ libibverbs/include/infiniband/kern-abi.h 2009-11-01 15:18:20.629168000 +0200 +@@ -85,7 +85,10 @@ enum { + IB_USER_VERBS_CMD_MODIFY_SRQ, + IB_USER_VERBS_CMD_QUERY_SRQ, + IB_USER_VERBS_CMD_DESTROY_SRQ, +- IB_USER_VERBS_CMD_POST_SRQ_RECV ++ IB_USER_VERBS_CMD_POST_SRQ_RECV, ++ IB_USER_VERBS_CMD_CREATE_XRC_SRQ, ++ IB_USER_VERBS_CMD_OPEN_XRC_DOMAIN, ++ IB_USER_VERBS_CMD_CLOSE_XRC_DOMAIN + }; + + /* +@@ -706,6 +709,21 @@ struct ibv_create_srq { + __u64 driver_data[0]; + }; + ++struct ibv_create_xrc_srq { ++ __u32 command; ++ __u16 in_words; ++ __u16 out_words; ++ __u64 response; ++ __u64 user_handle; ++ __u32 pd_handle; ++ __u32 max_wr; ++ __u32 max_sge; ++ __u32 srq_limit; ++ __u32 xrcd_handle; ++ __u32 xrc_cq; ++ __u64 driver_data[0]; ++}; ++ + struct ibv_create_srq_resp { + __u32 srq_handle; + __u32 max_wr; +@@ -754,6 +772,30 @@ struct ibv_destroy_srq_resp { + __u32 events_reported; + }; + ++struct ibv_open_xrc_domain { ++ __u32 command; ++ __u16 in_words; ++ __u16 out_words; ++ __u64 response; ++ __u32 fd; ++ __u32 oflags; ++ __u64 driver_data[0]; ++}; ++ ++struct ibv_open_xrc_domain_resp { ++ __u32 xrcd_handle; ++}; ++ ++struct ibv_close_xrc_domain { ++ __u32 command; ++ __u16 in_words; ++ __u16 out_words; ++ __u64 response; ++ __u32 xrcd_handle; ++ __u32 reserved; ++ __u64 driver_data[0]; ++}; ++ + /* + * Compatibility with older ABI versions + */ +@@ -803,6 +845,9 @@ enum { + * trick opcodes in IBV_INIT_CMD() doesn't break. + */ + IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL_V2 = -1, ++ IB_USER_VERBS_CMD_CREATE_XRC_SRQ_V2 = -1, ++ IB_USER_VERBS_CMD_OPEN_XRC_DOMAIN_V2 = -1, ++ IB_USER_VERBS_CMD_CLOSE_XRC_DOMAIN_V2 = -1, + }; + + struct ibv_destroy_cq_v1 { +Index: libibverbs/include/infiniband/verbs.h +=================================================================== +--- libibverbs.orig/include/infiniband/verbs.h 2009-11-01 15:18:17.924118000 +0200 ++++ libibverbs/include/infiniband/verbs.h 2009-11-01 15:18:20.635171000 +0200 +@@ -92,7 +92,8 @@ enum ibv_device_cap_flags { + IBV_DEVICE_SYS_IMAGE_GUID = 1 << 11, + IBV_DEVICE_RC_RNR_NAK_GEN = 1 << 12, + IBV_DEVICE_SRQ_RESIZE = 1 << 13, +- IBV_DEVICE_N_NOTIFY_CQ = 1 << 14 ++ IBV_DEVICE_N_NOTIFY_CQ = 1 << 14, ++ IBV_DEVICE_XRC = 1 << 20 + }; + + enum ibv_atomic_cap { +@@ -371,6 +372,11 @@ struct ibv_ah_attr { + uint8_t port_num; + }; + ++struct ibv_xrc_domain { ++ struct ibv_context *context; ++ uint32_t handle; ++}; ++ + enum ibv_srq_attr_mask { + IBV_SRQ_MAX_WR = 1 << 0, + IBV_SRQ_LIMIT = 1 << 1 +@@ -390,7 +396,8 @@ struct ibv_srq_init_attr { + enum ibv_qp_type { + IBV_QPT_RC = 2, + IBV_QPT_UC, +- IBV_QPT_UD ++ IBV_QPT_UD, ++ IBV_QPT_XRC + }; + + struct ibv_qp_cap { +@@ -409,6 +416,7 @@ struct ibv_qp_init_attr { + struct ibv_qp_cap cap; + enum ibv_qp_type qp_type; + int sq_sig_all; ++ struct ibv_xrc_domain *xrc_domain; + }; + + enum ibv_qp_attr_mask { +@@ -527,6 +535,7 @@ struct ibv_send_wr { + uint32_t remote_qkey; + } ud; + } wr; ++ uint32_t xrc_remote_srq_num; + }; + + struct ibv_recv_wr { +@@ -554,6 +563,10 @@ struct ibv_srq { + pthread_mutex_t mutex; + pthread_cond_t cond; + uint32_t events_completed; ++ ++ uint32_t xrc_srq_num; ++ struct ibv_xrc_domain *xrc_domain; ++ struct ibv_cq *xrc_cq; + }; + + struct ibv_qp { +@@ -571,6 +584,8 @@ struct ibv_qp { + pthread_mutex_t mutex; + pthread_cond_t cond; + uint32_t events_completed; ++ ++ struct ibv_xrc_domain *xrc_domain; + }; + + struct ibv_comp_channel { +@@ -625,6 +640,16 @@ struct ibv_device { + char ibdev_path[IBV_SYSFS_PATH_MAX]; + }; + ++struct ibv_more_ops { ++ struct ibv_srq * (*create_xrc_srq)(struct ibv_pd *pd, ++ struct ibv_xrc_domain *xrc_domain, ++ struct ibv_cq *xrc_cq, ++ struct ibv_srq_init_attr *srq_init_attr); ++ struct ibv_xrc_domain * (*open_xrc_domain)(struct ibv_context *context, ++ int fd, int oflag); ++ int (*close_xrc_domain)(struct ibv_xrc_domain *d); ++}; ++ + struct ibv_context_ops { + int (*query_device)(struct ibv_context *context, + struct ibv_device_attr *device_attr); +@@ -691,6 +716,7 @@ struct ibv_context { + int num_comp_vectors; + pthread_mutex_t mutex; + void *abi_compat; ++ struct ibv_more_ops *more_ops; + }; + + /** +@@ -913,6 +939,25 @@ struct ibv_srq *ibv_create_srq(struct ib + struct ibv_srq_init_attr *srq_init_attr); + + /** ++ * ibv_create_xrc_srq - Creates a SRQ associated with the specified protection ++ * domain and xrc domain. ++ * @pd: The protection domain associated with the SRQ. ++ * @xrc_domain: The XRC domain associated with the SRQ. ++ * @xrc_cq: CQ to report completions for XRC packets on. ++ * ++ * @srq_init_attr: A list of initial attributes required to create the SRQ. ++ * ++ * srq_attr->max_wr and srq_attr->max_sge are read the determine the ++ * requested size of the SRQ, and set to the actual values allocated ++ * on return. If ibv_create_srq() succeeds, then max_wr and max_sge ++ * will always be at least as large as the requested values. ++ */ ++struct ibv_srq *ibv_create_xrc_srq(struct ibv_pd *pd, ++ struct ibv_xrc_domain *xrc_domain, ++ struct ibv_cq *xrc_cq, ++ struct ibv_srq_init_attr *srq_init_attr); ++ ++/** + * ibv_modify_srq - Modifies the attributes for the specified SRQ. + * @srq: The SRQ to modify. + * @srq_attr: On input, specifies the SRQ attributes to modify. On output, +@@ -1093,6 +1138,42 @@ const char *ibv_port_state_str(enum ibv_ + */ + const char *ibv_event_type_str(enum ibv_event_type event); + ++/** ++ * ibv_open_xrc_domain - open an XRC domain ++ * Returns a reference to an XRC domain. ++ * ++ * @context: Device context ++ * @fd: descriptor for inode associated with the domain ++ * If fd == -1, no inode is associated with the domain; in this ca= se, ++ * the only legal value for oflag is O_CREAT ++ * ++ * @oflag: oflag values are constructed by OR-ing flags from the following list ++ * ++ * O_CREAT ++ * If a domain belonging to device named by context is already associated ++ * with the inode, this flag has no effect, except as noted under O_EXCL ++ * below. Otherwise, a new XRC domain is created and is associated with ++ * inode specified by fd. ++ * ++ * O_EXCL ++ * If O_EXCL and O_CREAT are set, open will fail if a domain associated with ++ * the inode exists. The check for the existence of the domain and creation ++ * of the domain if it does not exist is atomic with respect to other ++ * processes executing open with fd naming the same inode. ++ */ ++struct ibv_xrc_domain *ibv_open_xrc_domain(struct ibv_context *context, ++ int fd, int oflag); ++ ++/** ++ * ibv_close_xrc_domain - close an XRC domain ++ * If this is the last reference, destroys the domain. ++ * ++ * @d: reference to XRC domain to close ++ * ++ * close is implicitly performed at process exit. ++ */ ++int ibv_close_xrc_domain(struct ibv_xrc_domain *d); ++ + END_C_DECLS + + # undef __attribute_const +Index: libibverbs/src/cmd.c +=================================================================== +--- libibverbs.orig/src/cmd.c 2009-11-01 15:18:17.927111000 +0200 ++++ libibverbs/src/cmd.c 2009-11-01 15:18:20.643167000 +0200 +@@ -483,6 +483,34 @@ int ibv_cmd_create_srq(struct ibv_pd *pd + return 0; + } + ++int ibv_cmd_create_xrc_srq(struct ibv_pd *pd, ++ struct ibv_srq *srq, struct ibv_srq_init_attr *attr, ++ uint32_t xrcd_handle, uint32_t xrc_cq, ++ struct ibv_create_xrc_srq *cmd, size_t cmd_size, ++ struct ibv_create_srq_resp *resp, size_t resp_size) ++{ ++ IBV_INIT_CMD_RESP(cmd, cmd_size, CREATE_XRC_SRQ, resp, resp_size); ++ cmd->user_handle = (uintptr_t) srq; ++ cmd->pd_handle = pd->handle; ++ cmd->max_wr = attr->attr.max_wr; ++ cmd->max_sge = attr->attr.max_sge; ++ cmd->srq_limit = attr->attr.srq_limit; ++ cmd->xrcd_handle = xrcd_handle; ++ cmd->xrc_cq = xrc_cq; ++ ++ if (write(pd->context->cmd_fd, cmd, cmd_size) != cmd_size) ++ return errno; ++ ++ VALGRIND_MAKE_MEM_DEFINED(resp, resp_size); ++ ++ srq->handle = resp->srq_handle; ++ srq->context = pd->context; ++ attr->attr.max_wr = resp->max_wr; ++ attr->attr.max_sge = resp->max_sge; ++ ++ return 0; ++} ++ + static int ibv_cmd_modify_srq_v3(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + int srq_attr_mask, +@@ -603,7 +631,6 @@ int ibv_cmd_create_qp(struct ibv_pd *pd, + cmd->pd_handle = pd->handle; + cmd->send_cq_handle = attr->send_cq->handle; + cmd->recv_cq_handle = attr->recv_cq->handle; +- cmd->srq_handle = attr->srq ? attr->srq->handle : 0; + cmd->max_send_wr = attr->cap.max_send_wr; + cmd->max_recv_wr = attr->cap.max_recv_wr; + cmd->max_send_sge = attr->cap.max_send_sge; +@@ -612,6 +639,9 @@ int ibv_cmd_create_qp(struct ibv_pd *pd, + cmd->sq_sig_all = attr->sq_sig_all; + cmd->qp_type = attr->qp_type; + cmd->is_srq = !!attr->srq; ++ cmd->srq_handle = attr->qp_type == IBV_QPT_XRC ? ++ (attr->xrc_domain ? attr->xrc_domain->handle : 0) : ++ (attr->srq ? attr->srq->handle : 0); + cmd->reserved = 0; + + if (write(pd->context->cmd_fd, cmd, cmd_size) != cmd_size) +@@ -722,6 +752,8 @@ int ibv_cmd_query_qp(struct ibv_qp *qp, + init_attr->recv_cq = qp->recv_cq; + init_attr->srq = qp->srq; + init_attr->qp_type = qp->qp_type; ++ if (qp->qp_type == IBV_QPT_XRC) ++ init_attr->xrc_domain = qp->xrc_domain; + init_attr->cap.max_send_wr = resp.max_send_wr; + init_attr->cap.max_recv_wr = resp.max_recv_wr; + init_attr->cap.max_send_sge = resp.max_send_sge; +@@ -1122,3 +1154,41 @@ int ibv_cmd_detach_mcast(struct ibv_qp * + + return 0; + } ++ ++int ibv_cmd_open_xrc_domain(struct ibv_context *context, int fd, int oflag, ++ struct ibv_xrc_domain *d, ++ struct ibv_open_xrc_domain_resp *resp, ++ size_t resp_size) ++{ ++ struct ibv_open_xrc_domain cmd; ++ ++ if (abi_ver < 6) ++ return ENOSYS; ++ ++ IBV_INIT_CMD_RESP(&cmd, sizeof cmd, OPEN_XRC_DOMAIN, resp, resp_size); ++ cmd.fd = fd; ++ cmd.oflags = oflag; ++ ++ if (write(context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) ++ return errno; ++ ++ d->handle = resp->xrcd_handle; ++ ++ return 0; ++} ++ ++int ibv_cmd_close_xrc_domain(struct ibv_xrc_domain *d) ++{ ++ struct ibv_close_xrc_domain cmd; ++ ++ if (abi_ver < 6) ++ return ENOSYS; ++ ++ IBV_INIT_CMD(&cmd, sizeof cmd, CLOSE_XRC_DOMAIN); ++ cmd.xrcd_handle = d->handle; ++ ++ if (write(d->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) ++ return errno; ++ return 0; ++} ++ +Index: libibverbs/src/libibverbs.map +=================================================================== +--- libibverbs.orig/src/libibverbs.map 2009-11-01 15:18:17.928115000 +0200 ++++ libibverbs/src/libibverbs.map 2009-11-01 15:18:20.646169000 +0200 +@@ -91,6 +91,12 @@ IBVERBS_1.1 { + ibv_dontfork_range; + ibv_dofork_range; + ibv_register_driver; ++ ibv_create_xrc_srq; ++ ibv_cmd_create_xrc_srq; ++ ibv_open_xrc_domain; ++ ibv_cmd_open_xrc_domain; ++ ibv_close_xrc_domain; ++ ibv_cmd_close_xrc_domain; + + ibv_node_type_str; + ibv_port_state_str; +Index: libibverbs/src/verbs.c +=================================================================== +--- libibverbs.orig/src/verbs.c 2009-11-01 15:18:17.931119000 +0200 ++++ libibverbs/src/verbs.c 2009-11-01 15:18:20.650169000 +0200 +@@ -366,6 +366,9 @@ struct ibv_srq *__ibv_create_srq(struct + srq->context = pd->context; + srq->srq_context = srq_init_attr->srq_context; + srq->pd = pd; ++ srq->xrc_domain = NULL; ++ srq->xrc_cq = NULL; ++ srq->xrc_srq_num = 0; + srq->events_completed = 0; + pthread_mutex_init(&srq->mutex, NULL); + pthread_cond_init(&srq->cond, NULL); +@@ -375,6 +378,32 @@ struct ibv_srq *__ibv_create_srq(struct + } + default_symver(__ibv_create_srq, ibv_create_srq); + ++struct ibv_srq *ibv_create_xrc_srq(struct ibv_pd *pd, ++ struct ibv_xrc_domain *xrc_domain, ++ struct ibv_cq *xrc_cq, ++ struct ibv_srq_init_attr *srq_init_attr) ++{ ++ struct ibv_srq *srq; ++ ++ if (!pd->context->more_ops) ++ return NULL; ++ ++ srq = pd->context->more_ops->create_xrc_srq(pd, xrc_domain, ++ xrc_cq, srq_init_attr); ++ if (srq) { ++ srq->context = pd->context; ++ srq->srq_context = srq_init_attr->srq_context; ++ srq->pd = pd; ++ srq->xrc_domain = xrc_domain; ++ srq->xrc_cq = xrc_cq; ++ srq->events_completed = 0; ++ pthread_mutex_init(&srq->mutex, NULL); ++ pthread_cond_init(&srq->cond, NULL); ++ } ++ ++ return srq; ++} ++ + int __ibv_modify_srq(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + int srq_attr_mask) +@@ -410,6 +439,8 @@ struct ibv_qp *__ibv_create_qp(struct ib + qp->qp_type = qp_init_attr->qp_type; + qp->state = IBV_QPS_RESET; + qp->events_completed = 0; ++ qp->xrc_domain = qp_init_attr->qp_type == IBV_QPT_XRC ? ++ qp_init_attr->xrc_domain : NULL; + pthread_mutex_init(&qp->mutex, NULL); + pthread_cond_init(&qp->cond, NULL); + } +@@ -543,3 +574,26 @@ int __ibv_detach_mcast(struct ibv_qp *qp + return qp->context->ops.detach_mcast(qp, gid, lid); + } + default_symver(__ibv_detach_mcast, ibv_detach_mcast); ++ ++struct ibv_xrc_domain *ibv_open_xrc_domain(struct ibv_context *context, ++ int fd, int oflag) ++{ ++ struct ibv_xrc_domain *d; ++ ++ if (!context->more_ops) ++ return NULL; ++ ++ d = context->more_ops->open_xrc_domain(context, fd, oflag); ++ if (d) ++ d->context = context; ++ ++ return d; ++} ++ ++int ibv_close_xrc_domain(struct ibv_xrc_domain *d) ++{ ++ if (!d->context->more_ops) ++ return 0; ++ ++ return d->context->more_ops->close_xrc_domain(d); ++} diff --git a/contrib/ofed/libibverbs/fixes/XRC_man_pages.patch b/contrib/ofed/libibverbs/fixes/XRC_man_pages.patch new file mode 100644 index 000000000000..d332fd0a5ce6 --- /dev/null +++ b/contrib/ofed/libibverbs/fixes/XRC_man_pages.patch @@ -0,0 +1,686 @@ +commit b7c5820ce48a4fc3c8464872f0a554df6e7bbb47 +Author: Dotan Barak +Date: Mon Feb 25 16:50:38 2008 +0200 + + Add XRC (eXtended Reliable Connection) support to all of the relevant man pages + and add new man pages to new XRC verbs. + + Signed-off-by: Dotan Barak + Signed-off-by: Jack Morgenstein + +diff --git a/man/ibv_create_qp.3 b/man/ibv_create_qp.3 +index abd5449..fb6f041 100644 +Index: libibverbs/man/ibv_create_qp.3 +=================================================================== +--- libibverbs.orig/man/ibv_create_qp.3 2008-06-05 15:21:54.000000000 +0300 ++++ libibverbs/man/ibv_create_qp.3 2008-06-05 16:25:21.000000000 +0300 +@@ -28,8 +28,9 @@ struct ibv_cq *send_cq; + struct ibv_cq *recv_cq; /* CQ to be associated with the Receive Queue (RQ) */ + struct ibv_srq *srq; /* SRQ handle if QP is to be associated with an SRQ, otherwise NULL */ + struct ibv_qp_cap cap; /* QP capabilities */ +-enum ibv_qp_type qp_type; /* QP Transport Service Type: IBV_QPT_RC, IBV_QPT_UC, or IBV_QPT_UD */ ++enum ibv_qp_type qp_type; /* QP Transport Service Type: IBV_QPT_RC, IBV_QPT_UC, IBV_QPT_UD or IBV_QPT_XRC */ + int sq_sig_all; /* If set, each Work Request (WR) submitted to the SQ generates a completion entry */ ++struct ibv_xrc_domain *xrc_domain; /* XRC domain the QP will be associated with (valid only for IBV_QPT_XRC QP), otherwise NULL */ + .in -8 + }; + .sp +Index: libibverbs/man/ibv_create_srq.3 +=================================================================== +--- libibverbs.orig/man/ibv_create_srq.3 2008-06-05 15:21:54.000000000 +0300 ++++ libibverbs/man/ibv_create_srq.3 2008-06-05 16:25:21.000000000 +0300 +@@ -10,12 +10,26 @@ ibv_create_srq, ibv_destroy_srq \- creat + .BI "struct ibv_srq *ibv_create_srq(struct ibv_pd " "*pd" ", struct " + .BI " ibv_srq_init_attr " "*srq_init_attr" ); + .sp ++.BI "struct ibv_srq *ibv_create_xrc_srq(struct ibv_pd " "*pd" ", ++.BI " struct ibv_xrc_domain " "*xrc_domain" ", ++.BI " struct ibv_cq " "*xrc_cq" ", ++.BI " struct ibv_srq_init_attr " "*srq_init_attr" ); ++.sp + .BI "int ibv_destroy_srq(struct ibv_srq " "*srq" ); + .fi + .SH "DESCRIPTION" + .B ibv_create_srq() + creates a shared receive queue (SRQ) associated with the protection domain + .I pd\fR. ++.PP ++.B ibv_create_xrc_srq() ++creates an XRC shared receive queue (SRQ) associated with the protection domain ++.I pd\fR, ++the XRC domain ++.I xrc_domain ++and the CQ which will hold the XRC completion ++.I xrc_cq\fR. ++.PP + The argument + .I srq_init_attr + is an ibv_srq_init_attr struct, as defined in . +Index: libibverbs/man/ibv_create_xrc_rcv_qp.3 +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ libibverbs/man/ibv_create_xrc_rcv_qp.3 2008-06-05 16:25:21.000000000 +0300 +@@ -0,0 +1,70 @@ ++.\" -*- nroff -*- ++.\" ++.TH IBV_CREATE_XRC_RCV_QP 3 2008-02-10 libibverbs "Libibverbs Programmer's Manual" ++.SH "NAME" ++ibv_create_xrc_rcv_qp \- create an XRC queue pair (QP) for serving as a receive-side only QP ++.SH "SYNOPSIS" ++.nf ++.B #include ++.sp ++.BI "int ibv_create_xrc_rcv_qp(struct ibv_qp_init_attr " "*init_attr" , ++.BI " uint32_t " "*xrc_rcv_qpn" ); ++.fi ++.SH "DESCRIPTION" ++.B ibv_create_xrc_rcv_qp() ++creates an XRC queue pair (QP) for serving as a receive-side only QP and returns its number through the pointer ++.I xrc_rcv_qpn\fR. ++This QP number should be passed to the remote node (sender). ++The remote node will use ++.I xrc_rcv_qpn ++in ++.B ibv_post_send() ++when sending to an XRC SRQ on this host in the same xrc domain as the XRC receive QP. ++This QP is created in kernel space, and persists until the last process registered for the QP ++calls ++.B ibv_unreg_xrc_rcv_qp() ++(at which time the QP is destroyed). ++.PP ++The process which creates this QP is automatically registered for it, and should also call ++.B ibv_unreg_xrc_rcv_qp() ++at some point, to unregister. ++ ++Processes which wish to receive on an XRC SRQ via this QP should call ++.B ibv_reg_xrc_rcv_qp() ++for this QP, to guarantee that the QP will not be destroyed while they are still using it for receiving on the XRC SRQ. ++.PP ++The argument ++.I qp_init_attr ++is an ibv_qp_init_attr struct, as defined in . ++.PP ++.nf ++struct ibv_qp_init_attr { ++.in +8 ++void *qp_context; /* value is being ignored */ ++struct ibv_cq *send_cq; /* value is being ignored */ ++struct ibv_cq *recv_cq; /* value is being ignored */ ++struct ibv_srq *srq; /* value is being ignored */ ++struct ibv_qp_cap cap; /* value is being ignored */ ++enum ibv_qp_type qp_type; /* value is being ignored */ ++int sq_sig_all; /* value is being ignored */ ++struct ibv_xrc_domain *xrc_domain; /* XRC domain the QP will be associated with */ ++.in -8 ++}; ++.fi ++.PP ++Most of the attributes in ++.I qp_init_attr ++are being ignored because this QP is a receive only QP and all RR are being posted to an SRQ. ++.SH "RETURN VALUE" ++.B ibv_create_xrc_rcv_qp() ++returns 0 on success, or the value of errno on failure (which indicates the failure reason). ++.SH "SEE ALSO" ++.BR ibv_open_xrc_domain (3), ++.BR ibv_modify_xrc_rcv_qp (3), ++.BR ibv_query_xrc_rcv_qp (3), ++.BR ibv_reg_xrc_rcv_qp (3), ++.BR ibv_unreg_xrc_rcv_qp (3), ++.BR ibv_post_send (3) ++.SH "AUTHORS" ++.TP ++Dotan Barak +Index: libibverbs/man/ibv_modify_xrc_rcv_qp.3 +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ libibverbs/man/ibv_modify_xrc_rcv_qp.3 2008-06-05 16:25:21.000000000 +0300 +@@ -0,0 +1,141 @@ ++.\" -*- nroff -*- ++.\" ++.TH IBV_MODIFY_XRC_RCV_QP 3 2008-02-10 libibverbs "Libibverbs Programmer's Manual" ++.SH "NAME" ++ibv_modify_xrc_rcv_qp \- modify the attributes of an XRC receive queue pair (QP) ++.SH "SYNOPSIS" ++.nf ++.B #include ++.sp ++.BI "int ibv_modify_xrc_rcv_qp(struct ibv_xrc_domain " "*xrc_domain" ", uint32_t " "xrc_qp_num" , ++.BI " struct ibv_qp_attr " "*attr" ", int " "attr_mask" ); ++.fi ++.SH "DESCRIPTION" ++.B ibv_modify_qp() ++modifies the attributes of an XRC receive QP with the number ++.I xrc_qp_num ++which is associated with the XRC domain ++.I xrc_domain ++with the attributes in ++.I attr ++according to the mask ++.I attr_mask ++and move the QP state through the following transitions: Reset -> Init -> RTR. ++.I attr_mask ++should indicate all of the attributes which will be used in this QP transition and the following masks (at least) should be set: ++.PP ++.nf ++Next state Required attributes ++\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- ++Init \fB IBV_QP_STATE, IBV_QP_PKEY_INDEX, IBV_QP_PORT, \fR ++ \fB IBV_QP_ACCESS_FLAGS \fR ++RTR \fB IBV_QP_STATE, IBV_QP_AV, IBV_QP_PATH_MTU, \fR ++ \fB IBV_QP_DEST_QPN, IBV_QP_RQ_PSN, \fR ++ \fB IBV_QP_MAX_DEST_RD_ATOMIC, IBV_QP_MIN_RNR_TIMER \fR ++.fi ++.PP ++The user can add optional attributes as well. ++.PP ++The argument \fIattr\fR is an ibv_qp_attr struct, as defined in . ++.PP ++.nf ++struct ibv_qp_attr { ++.in +8 ++enum ibv_qp_state qp_state; /* Move the QP to this state */ ++enum ibv_qp_state cur_qp_state; /* Assume this is the current QP state */ ++enum ibv_mtu path_mtu; /* Path MTU (valid only for RC/UC QPs) */ ++enum ibv_mig_state path_mig_state; /* Path migration state (valid if HCA supports APM) */ ++uint32_t qkey; /* Q_Key for the QP (valid only for UD QPs) */ ++uint32_t rq_psn; /* PSN for receive queue (valid only for RC/UC QPs) */ ++uint32_t sq_psn; /* PSN for send queue (valid only for RC/UC QPs) */ ++uint32_t dest_qp_num; /* Destination QP number (valid only for RC/UC QPs) */ ++int qp_access_flags; /* Mask of enabled remote access operations (valid only for RC/UC QPs) */ ++struct ibv_qp_cap cap; /* QP capabilities (valid if HCA supports QP resizing) */ ++struct ibv_ah_attr ah_attr; /* Primary path address vector (valid only for RC/UC QPs) */ ++struct ibv_ah_attr alt_ah_attr; /* Alternate path address vector (valid only for RC/UC QPs) */ ++uint16_t pkey_index; /* Primary P_Key index */ ++uint16_t alt_pkey_index; /* Alternate P_Key index */ ++uint8_t en_sqd_async_notify; /* Enable SQD.drained async notification (Valid only if qp_state is SQD) */ ++uint8_t sq_draining; /* Is the QP draining? Irrelevant for ibv_modify_qp() */ ++uint8_t max_rd_atomic; /* Number of outstanding RDMA reads & atomic operations on the destination QP (valid only for RC QPs) */ ++uint8_t max_dest_rd_atomic; /* Number of responder resources for handling incoming RDMA reads & atomic operations (valid only for RC QPs) */ ++uint8_t min_rnr_timer; /* Minimum RNR NAK timer (valid only for RC QPs) */ ++uint8_t port_num; /* Primary port number */ ++uint8_t timeout; /* Local ack timeout for primary path (valid only for RC QPs) */ ++uint8_t retry_cnt; /* Retry count (valid only for RC QPs) */ ++uint8_t rnr_retry; /* RNR retry (valid only for RC QPs) */ ++uint8_t alt_port_num; /* Alternate port number */ ++uint8_t alt_timeout; /* Local ack timeout for alternate path (valid only for RC QPs) */ ++.in -8 ++}; ++.fi ++.PP ++For details on struct ibv_qp_cap see the description of ++.B ibv_create_qp()\fR. ++For details on struct ibv_ah_attr see the description of ++.B ibv_create_ah()\fR. ++.PP ++The argument ++.I attr_mask ++specifies the QP attributes to be modified. ++The argument is either 0 or the bitwise OR of one or more of the following flags: ++.PP ++.TP ++.B IBV_QP_STATE \fR Modify qp_state ++.TP ++.B IBV_QP_CUR_STATE \fR Set cur_qp_state ++.TP ++.B IBV_QP_EN_SQD_ASYNC_NOTIFY \fR Set en_sqd_async_notify ++.TP ++.B IBV_QP_ACCESS_FLAGS \fR Set qp_access_flags ++.TP ++.B IBV_QP_PKEY_INDEX \fR Set pkey_index ++.TP ++.B IBV_QP_PORT \fR Set port_num ++.TP ++.B IBV_QP_QKEY \fR Set qkey ++.TP ++.B IBV_QP_AV \fR Set ah_attr ++.TP ++.B IBV_QP_PATH_MTU \fR Set path_mtu ++.TP ++.B IBV_QP_TIMEOUT \fR Set timeout ++.TP ++.B IBV_QP_RETRY_CNT \fR Set retry_cnt ++.TP ++.B IBV_QP_RNR_RETRY \fR Set rnr_retry ++.TP ++.B IBV_QP_RQ_PSN \fR Set rq_psn ++.TP ++.B IBV_QP_MAX_QP_RD_ATOMIC \fR Set max_rd_atomic ++.TP ++.B IBV_QP_ALT_PATH \fR Set the alternative path via: alt_ah_attr, alt_pkey_index, alt_port_num, alt_timeout ++.TP ++.B IBV_QP_MIN_RNR_TIMER \fR Set min_rnr_timer ++.TP ++.B IBV_QP_SQ_PSN \fR Set sq_psn ++.TP ++.B IBV_QP_MAX_DEST_RD_ATOMIC \fR Set max_dest_rd_atomic ++.TP ++.B IBV_QP_PATH_MIG_STATE \fR Set path_mig_state ++.TP ++.B IBV_QP_CAP \fR Set cap ++.TP ++.B IBV_QP_DEST_QPN \fR Set dest_qp_num ++.SH "RETURN VALUE" ++.B ibv_modify_xrc_rcv_qp() ++returns 0 on success, or the value of errno on failure (which indicates the failure reason). ++.SH "NOTES" ++If any of the modify attributes or the modify mask are invalid, none ++of the attributes will be modified (including the QP state). ++.PP ++Not all devices support alternate paths. To check if a device supports it, check if the ++.B IBV_DEVICE_AUTO_PATH_MIG ++bit is set in the device capabilities flags. ++.SH "SEE ALSO" ++.BR ibv_open_xrc_domain (3), ++.BR ibv_create_xrc_rcv_qp (3), ++.BR ibv_query_xrc_rcv_qp (3) ++.SH "AUTHORS" ++.TP ++Dotan Barak +Index: libibverbs/man/ibv_open_xrc_domain.3 +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ libibverbs/man/ibv_open_xrc_domain.3 2008-06-05 16:25:21.000000000 +0300 +@@ -0,0 +1,80 @@ ++.\" -*- nroff -*- ++.\" ++.TH IBV_OPEN_XRC_DOMAIN 3 2008-02-10 libibverbs "Libibverbs Programmer's Manual" ++.SH "NAME" ++ibv_open_xrc_domain, ibv_close_xrc_domain \- open or close an eXtended Reliable Connection (XRC) domain ++.SH "SYNOPSIS" ++.nf ++.B #include ++.B #include ++.sp ++.BI "struct ibv_xrc_domain *ibv_open_xrc_domain(struct ibv_context " "*context" "," ++.BI " int " "fd" ", int " "oflag" ); ++.nl ++.BI "int ibv_close_xrc_domain(struct ibv_xrc_domain " "*d" ); ++.fi ++.SH "DESCRIPTION" ++.B ibv_open_xrc_domain() ++open an XRC domain for the InfiniBand device context ++.I context ++or return a reference to an opened one\fR. ++.I fd ++is the file descriptor to be associated with the XRC domain. ++The argument ++.I oflag ++describes the desired file creation attributes; it is either 0 or the bitwise OR of one or more of the following flags: ++.PP ++.TP ++.B O_CREAT ++If a domain belonging to device named by context is already associated with the inode, this flag has ++no effect, except as noted under ++.BR O_EXCL ++below. Otherwise, a new XRC domain is created and is associated with inode specified by ++.IR fd\fR. ++.TP ++.B O_EXCL ++If ++.BR O_EXCL ++and ++.BR O_CREAT ++are set, open will fail if a domain associated with the inode exists. ++The check for the existence of the domain and creation ++of the domain if it does not exist is atomic with respect to other ++processes executing open with ++.IR fd ++naming the same inode. ++.PP ++If ++.I fd ++equals -1, no inode is is associated with the domain, and the only valid value for ++.I oflag ++is ++.B O_CREAT\fR. ++.PP ++.B ibv_close_xrc_domain() ++closes the XRC domain ++.I d\fR. ++If this is the last reference, the XRC domain will be destroyed. ++.SH "RETURN VALUE" ++.B ibv_open_xrc_domain() ++returns a pointer to an opened XRC, or NULL if the request fails. ++.PP ++.B ibv_close_xrc_domain() ++returns 0 on success, or the value of errno on failure (which indicates the failure reason). ++.SH "NOTES" ++Not all devices support XRC. To check if a device supports it, check if the ++.B IBV_DEVICE_XRC ++bit is set in the device capabilities flags. ++.PP ++.B ibv_close_xrc_domain() ++may fail if any QP or SRQ are still associated with the XRC domain being closed. ++.SH "SEE ALSO" ++.BR ibv_create_xrc_srq (3), ++.BR ibv_create_qp (3), ++.BR ibv_create_xrc_rcv_qp (3), ++.BR ibv_modify_xrc_rcv_qp (3), ++.BR ibv_query_xrc_rcv_qp (3), ++.BR ibv_reg_xrc_rcv_qp (3) ++.SH "AUTHORS" ++.TP ++Dotan Barak +Index: libibverbs/man/ibv_post_send.3 +=================================================================== +--- libibverbs.orig/man/ibv_post_send.3 2008-06-05 15:21:55.000000000 +0300 ++++ libibverbs/man/ibv_post_send.3 2008-06-05 16:25:21.000000000 +0300 +@@ -60,6 +60,7 @@ uint32_t remote_qkey; /* Q_Key + } ud; + .in -8 + } wr; ++uint32_t xrc_remote_srq_num; /* SRQ number of the destination XRC */ + .in -8 + }; + .sp +@@ -76,15 +77,15 @@ uint32_t lkey; + Each QP Transport Service Type supports a specific set of opcodes, as shown in the following table: + .PP + .nf +-OPCODE | IBV_QPT_UD | IBV_QPT_UC | IBV_QPT_RC +-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\- +-IBV_WR_SEND | X | X | X +-IBV_WR_SEND_WITH_IMM | X | X | X +-IBV_WR_RDMA_WRITE | | X | X +-IBV_WR_RDMA_WRITE_WITH_IMM | | X | X +-IBV_WR_RDMA_READ | | | X +-IBV_WR_ATOMIC_CMP_AND_SWP | | | X +-IBV_WR_ATOMIC_FETCH_AND_ADD | | | X ++OPCODE | IBV_QPT_UD | IBV_QPT_UC | IBV_QPT_RC | IBV_QPT_XRC ++\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\- ++IBV_WR_SEND | X | X | X | X ++IBV_WR_SEND_WITH_IMM | X | X | X | X ++IBV_WR_RDMA_WRITE | | X | X | X ++IBV_WR_RDMA_WRITE_WITH_IMM | | X | X | X ++IBV_WR_RDMA_READ | | | X | X ++IBV_WR_ATOMIC_CMP_AND_SWP | | | X | X ++IBV_WR_ATOMIC_FETCH_AND_ADD | | | X | X + .fi + .PP + The attribute send_flags describes the properties of the \s-1WR\s0. It is either 0 or the bitwise \s-1OR\s0 of one or more of the following flags: +@@ -114,6 +115,7 @@ IBV_SEND_INLINE flag was set, the buffer + after the call returns. + .SH "SEE ALSO" + .BR ibv_create_qp (3), ++.BR ibv_create_xrc_rcv_qp (3), + .BR ibv_create_ah (3), + .BR ibv_post_recv (3), + .BR ibv_post_srq_recv (3), +Index: libibverbs/man/ibv_query_xrc_rcv_qp.3 +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ libibverbs/man/ibv_query_xrc_rcv_qp.3 2008-06-05 16:25:21.000000000 +0300 +@@ -0,0 +1,89 @@ ++.\" -*- nroff -*- ++.\" ++.TH IBV_QUERY_XRC_RCV_QP 3 2008-02-10 libibverbs "Libibverbs Programmer's Manual" ++.SH "NAME" ++ibv_query_xrc_rcv_qp \- get the attributes of an XRC receive queue pair (QP) ++.SH "SYNOPSIS" ++.nf ++.B #include ++.sp ++.BI "int ibv_query_xrc_rcv_qp(struct ibv_xrc_domain " "*xrc_domain" ", uint32_t " "xrc_qp_num" , ++.BI " struct ibv_qp_attr " "*attr" ", int " "attr_mask" , ++.BI " struct ibv_qp_init_attr " "*init_attr" ); ++.fi ++.SH "DESCRIPTION" ++.B ibv_query_xrc_rcv_qp() ++gets the attributes specified in ++.I attr_mask ++for the XRC receive QP with the number ++.I xrc_qp_num ++which is associated with the XRC domain ++.I xrc_domain ++and returns them through the pointers ++.I attr ++and ++.I init_attr\fR. ++The argument ++.I attr ++is an ibv_qp_attr struct, as defined in . ++.PP ++.nf ++struct ibv_qp_attr { ++.in +8 ++enum ibv_qp_state qp_state; /* Current QP state */ ++enum ibv_qp_state cur_qp_state; /* Current QP state - irrelevant for ibv_query_qp */ ++enum ibv_mtu path_mtu; /* Path MTU (valid only for RC/UC QPs) */ ++enum ibv_mig_state path_mig_state; /* Path migration state (valid if HCA supports APM) */ ++uint32_t qkey; /* Q_Key of the QP (valid only for UD QPs) */ ++uint32_t rq_psn; /* PSN for receive queue (valid only for RC/UC QPs) */ ++uint32_t sq_psn; /* PSN for send queue (valid only for RC/UC QPs) */ ++uint32_t dest_qp_num; /* Destination QP number (valid only for RC/UC QPs) */ ++int qp_access_flags; /* Mask of enabled remote access operations (valid only for RC/UC QPs) */ ++struct ibv_qp_cap cap; /* QP capabilities */ ++struct ibv_ah_attr ah_attr; /* Primary path address vector (valid only for RC/UC QPs) */ ++struct ibv_ah_attr alt_ah_attr; /* Alternate path address vector (valid only for RC/UC QPs) */ ++uint16_t pkey_index; /* Primary P_Key index */ ++uint16_t alt_pkey_index; /* Alternate P_Key index */ ++uint8_t en_sqd_async_notify; /* Enable SQD.drained async notification - irrelevant for ibv_query_qp */ ++uint8_t sq_draining; /* Is the QP draining? (Valid only if qp_state is SQD) */ ++uint8_t max_rd_atomic; /* Number of outstanding RDMA reads & atomic operations on the destination QP (valid only for RC QPs) */ ++uint8_t max_dest_rd_atomic; /* Number of responder resources for handling incoming RDMA reads & atomic operations (valid only for RC QPs) */ ++uint8_t min_rnr_timer; /* Minimum RNR NAK timer (valid only for RC QPs) */ ++uint8_t port_num; /* Primary port number */ ++uint8_t timeout; /* Local ack timeout for primary path (valid only for RC QPs) */ ++uint8_t retry_cnt; /* Retry count (valid only for RC QPs) */ ++uint8_t rnr_retry; /* RNR retry (valid only for RC QPs) */ ++uint8_t alt_port_num; /* Alternate port number */ ++uint8_t alt_timeout; /* Local ack timeout for alternate path (valid only for RC QPs) */ ++.in -8 ++}; ++.fi ++.PP ++For details on struct ibv_qp_cap see the description of ++.B ibv_create_qp()\fR. ++For details on struct ibv_ah_attr see the description of ++.B ibv_create_ah()\fR. ++.SH "RETURN VALUE" ++.B ibv_query_xrc_rcv_qp() ++returns 0 on success, or the value of errno on failure (which indicates the failure reason). ++.SH "NOTES" ++The argument ++.I attr_mask ++is a hint that specifies the minimum list of attributes to retrieve. ++Some InfiniBand devices may return extra attributes not requested, for ++example if the value can be returned cheaply. ++.PP ++Attribute values are valid if they have been set using ++.B ibv_modify_xrc_rcv_qp()\fR. ++The exact list of valid attributes depends on the QP state. ++.PP ++Multiple calls to ++.B ibv_query_xrc_rcv_qp() ++may yield some differences in the values returned for the following attributes: qp_state, path_mig_state, sq_draining, ah_attr (if APM is enabled). ++.SH "SEE ALSO" ++.BR ibv_open_xrc_domain (3), ++.BR ibv_create_xrc_rcv_qp (3), ++.BR ibv_modify_xrc_rcv_qp (3) ++.SH "AUTHORS" ++.TP ++Dotan Barak +Index: libibverbs/man/ibv_reg_xrc_rcv_qp.3 +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ libibverbs/man/ibv_reg_xrc_rcv_qp.3 2008-06-05 16:25:21.000000000 +0300 +@@ -0,0 +1,57 @@ ++.\" -*- nroff -*- ++.\" ++.TH IBV_REG_XRC_RCV_QP 3 2008-10-02 libibverbs "Libibverbs Programmer's Manual" ++.SH "NAME" ++ibv_reg_xrc_rcv_qp, ibv_unreg_xrc_rcv_qp \- register and unregister a user process with an XRC receive queue pair (QP) ++.SH "SYNOPSIS" ++.nf ++.B #include ++.sp ++.BI "int ibv_reg_xrc_rcv_qp(struct ibv_xrc_domain " "*xrc_domain" ", uint32_t " "xrc_qp_num" "); ++.nl ++.BI "int ibv_unreg_xrc_rcv_qp(struct ibv_xrc_domain " "*xrc_domain" ", uint32_t " "xrc_qp_num" "); ++.fi ++.SH "DESCRIPTION" ++.B ibv_reg_xrc_rcv_qp() ++registers a user process with the XRC receive QP (created via ++.B ibv_create_xrc_rcv_qp() ++) whose number is ++.I xrc_qp_num\fR, ++and which is associated with the XRC domain ++.I xrc_domain\fR. ++.PP ++.B ibv_unreg_xrc_rcv_qp() ++unregisters a user process from the XRC receive QP number ++.I xrc_qp_num\fR, ++which is associated with the XRC domain ++.I xrc_domain\fR. ++When the number of user processes registered with this XRC receive QP drops to zero, the QP is destroyed. ++.SH "RETURN VALUE" ++.B ibv_reg_xrc_rcv_qp() ++and ++.B ibv_unreg_xrc_rcv_qp() ++returns 0 on success, or the value of errno on failure (which indicates the failure reason). ++.SH "NOTES" ++.B ibv_reg_xrc_rcv_qp() ++and ++.B ibv_unreg_xrc_rcv_qp() ++may fail if the number ++.I xrc_qp_num ++is not a number of a valid XRC receive QP (the QP is not allocated or it is the number of a non-XRC QP), or ++the XRC receive QP was created with an XRC domain other than ++.I xrc_domain\fR. ++ ++If a process is still registered with any XRC RCV QPs belonging to some domain, ++.B ibv_close_xrc_domain() ++will return failure if called for that domain in that process. ++ ++.B ibv_create_xrc_rcv_qp() ++performs an implicit registration for the creating process; when that process is finished with the XRC RCV QP, it should call ++.B ibv_unreg_xrc_rcv_qp() ++for that QP. Note that if no other processes are registered with the QP at this time, its registration count will drop to zero and it will be destroyed. ++.SH "SEE ALSO" ++.BR ibv_open_xrc_domain (3), ++.BR ibv_create_xrc_rcv_qp (3) ++.SH "AUTHORS" ++.TP ++Dotan Barak +Index: libibverbs/man/verbs.7 +=================================================================== +--- libibverbs.orig/man/verbs.7 2008-06-05 15:24:00.000000000 +0300 ++++ libibverbs/man/verbs.7 2008-06-05 16:25:21.000000000 +0300 +@@ -1,6 +1,6 @@ + .\" -*- nroff -*- + .\" +-.TH VERBS 7 2008-01-17 libibverbs "Libibverbs Programmer's Manual" ++.TH VERBS 7 2008-02-25 libibverbs "Libibverbs Programmer's Manual" + .SH "NAME" + verbs \- Infiniband verbs library + .SH "SYNOPSIS" +@@ -8,7 +8,7 @@ verbs \- Infiniband verbs library + .B #include + .fi + .SH "DESCRIPTION" +-This library is an implementation of the verbs according to the Infiniband specification volume 1.2. It handles the control path of creating, modifying, querying and destroying resources such as Protection Domains (PD), Completion Queues (CQ), Queue-Pairs (QP), Shared Receive Queues (SRQ), Address Handles (AH), Memory Regions (MR). It also handles sending and receiving data posted to QPs and SRQs, getting completions from CQs using polling and completions events. ++This library is an implementation of the verbs based on the Infiniband specification volume 1.2 chapter 11. It handles the control path of creating, modifying, querying and destroying resources such as Protection Domains (PD), Completion Queues (CQ), Queue-Pairs (QP), Shared Receive Queues (SRQ), Address Handles (AH), Memory Regions (MR). It also handles sending and receiving data posted to QPs and SRQs, getting completions from CQs using polling and completions events. + + The control path is implemented through system calls to the uverbs kernel module which further calls the low level HW driver. The data path is implemented through calls made to low level HW library which in most cases interacts directly with the HW providing kernel and network stack bypass (saving context/mode switches) along with zero copy and an asynchronous I/O model. + +@@ -117,6 +117,25 @@ int ibv_modify_srq(struct ibv_srq *srq, + enum ibv_srq_attr_mask srq_attr_mask); + int ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr); + ++.B eXtended Reliable Connection control ++ ++struct ibv_xrc_domain *ibv_open_xrc_domain(struct ibv_context *context, ++ int fd, int oflag); ++int ibv_close_xrc_domain(struct ibv_xrc_domain *d); ++struct ibv_srq *ibv_create_xrc_srq(struct ibv_pd *pd, ++ struct ibv_xrc_domain *xrc_domain, ++ struct ibv_cq *xrc_cq, ++ struct ibv_srq_init_attr *srq_init_attr); ++int ibv_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, ++ uint32_t *xrc_rcv_qpn); ++int ibv_modify_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num, ++ struct ibv_qp_attr *attr, int attr_mask); ++int ibv_query_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num, ++ struct ibv_qp_attr *attr, int attr_mask, ++ struct ibv_qp_init_attr *init_attr); ++int ibv_reg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num); ++int ibv_unreg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num); ++ + .B Queue Pair control + + struct ibv_qp *ibv_create_qp(struct ibv_pd *pd, +@@ -183,6 +202,14 @@ enum ibv_rate mult_to_ibv_rate(int mult) + \fIibv_destroy_srq\fP(), + \fIibv_modify_srq\fP(), + \fIibv_query_srq\fP(), ++\fIibv_open_xrc_domain\fP(), ++\fIibv_close_xrc_domain\fP(), ++\fIibv_create_xrc_srq\fP(), ++\fIibv_create_xrc_rcv_qp\fP(), ++\fIibv_modify_xrc_rcv_qp\fP(), ++\fIibv_query_xrc_rcv_qp\fP(), ++\fIibv_reg_xrc_rcv_qp\fP(), ++\fIibv_unreg_xrc_rcv_qp\fP(), + \fIibv_post_srq_recv\fP(), + \fIibv_create_qp\fP(), + \fIibv_destroy_qp\fP(), +Index: libibverbs/Makefile.am +=================================================================== +--- libibverbs.orig/Makefile.am 2008-06-05 15:24:00.000000000 +0300 ++++ libibverbs/Makefile.am 2008-06-05 16:39:27.000000000 +0300 +@@ -44,15 +44,18 @@ man_MANS = man/ibv_asyncwatch.1 man/ibv_ + man/ibv_srq_pingpong.1 man/ibv_alloc_pd.3 man/ibv_attach_mcast.3 \ + man/ibv_create_ah.3 man/ibv_create_ah_from_wc.3 \ + man/ibv_create_comp_channel.3 man/ibv_create_cq.3 \ +- man/ibv_create_qp.3 man/ibv_create_srq.3 man/ibv_event_type_str.3 \ ++ man/ibv_create_qp.3 man/ibv_create_srq.3 \ ++ man/ibv_create_xrc_rcv_qp.3 man/ibv_event_type_str.3 \ + man/ibv_fork_init.3 man/ibv_get_async_event.3 \ + man/ibv_get_cq_event.3 man/ibv_get_device_guid.3 \ + man/ibv_get_device_list.3 man/ibv_get_device_name.3 \ +- man/ibv_modify_qp.3 man/ibv_modify_srq.3 man/ibv_open_device.3 \ ++ man/ibv_modify_qp.3 man/ibv_modify_srq.3 man/ibv_modify_xrc_rcv_qp.3 \ ++ man/ibv_open_device.3 man/ibv_open_xrc_domain.3 \ + man/ibv_poll_cq.3 man/ibv_post_recv.3 man/ibv_post_send.3 \ + man/ibv_post_srq_recv.3 man/ibv_query_device.3 man/ibv_query_gid.3 \ + man/ibv_query_pkey.3 man/ibv_query_port.3 man/ibv_query_qp.3 \ +- man/ibv_query_srq.3 man/ibv_rate_to_mult.3 man/ibv_reg_mr.3 \ ++ man/ibv_query_srq.3 man/ibv_query_xrc_rcv_qp.3 \ ++ man/ibv_rate_to_mult.3 man/ibv_reg_mr.3 man/ibv_reg_xrc_rcv_qp.3 \ + man/ibv_req_notify_cq.3 man/ibv_resize_cq.3 man/verbs.7 + + DEBIAN = debian/changelog debian/compat debian/control debian/copyright \ +@@ -74,6 +77,8 @@ install-data-hook: + $(RM) ibv_ack_async_event.3 && \ + $(RM) ibv_ack_cq_events.3 && \ + $(RM) ibv_close_device.3 && \ ++ $(RM) ibv_close_xrc_domain.3 && \ ++ $(RM) ibv_create_xrc_srq.3 && \ + $(RM) ibv_dealloc_pd.3 && \ + $(RM) ibv_dereg_mr.3 && \ + $(RM) ibv_destroy_ah.3 && \ +@@ -84,12 +89,15 @@ install-data-hook: + $(RM) ibv_detach_mcast.3 && \ + $(RM) ibv_free_device_list.3 && \ + $(RM) ibv_init_ah_from_wc.3 && \ ++ $(RM) ibv_unreg_xrc_rcv_qp.3 && \ + $(RM) mult_to_ibv_rate.3 && \ + $(RM) ibv_node_type_str.3 && \ + $(RM) ibv_port_state_str.3 && \ + $(LN_S) ibv_get_async_event.3 ibv_ack_async_event.3 && \ + $(LN_S) ibv_get_cq_event.3 ibv_ack_cq_events.3 && \ + $(LN_S) ibv_open_device.3 ibv_close_device.3 && \ ++ $(LN_S) ibv_open_xrc_domain.3 ibv_close_xrc_domain.3 && \ ++ $(LN_S) ibv_create_srq.3 ibv_create_xrc_srq.3 && \ + $(LN_S) ibv_alloc_pd.3 ibv_dealloc_pd.3 && \ + $(LN_S) ibv_reg_mr.3 ibv_dereg_mr.3 && \ + $(LN_S) ibv_create_ah.3 ibv_destroy_ah.3 && \ +@@ -100,6 +108,7 @@ install-data-hook: + $(LN_S) ibv_attach_mcast.3 ibv_detach_mcast.3 && \ + $(LN_S) ibv_get_device_list.3 ibv_free_device_list.3 && \ + $(LN_S) ibv_create_ah_from_wc.3 ibv_init_ah_from_wc.3 && \ ++ $(LN_S) ibv_reg_xrc_rcv_qp.3 ibv_unreg_xrc_rcv_qp.3 && \ + $(LN_S) ibv_rate_to_mult.3 mult_to_ibv_rate.3 && \ + $(LN_S) ibv_event_type_str.3 ibv_node_type_str.3 && \ + $(LN_S) ibv_event_type_str.3 ibv_port_state_str.3 diff --git a/contrib/ofed/libibverbs/fixes/configure_in-AC_PROG_LIBTOOL-for-automake.patch b/contrib/ofed/libibverbs/fixes/configure_in-AC_PROG_LIBTOOL-for-automake.patch new file mode 100644 index 000000000000..caf8a98981c6 --- /dev/null +++ b/contrib/ofed/libibverbs/fixes/configure_in-AC_PROG_LIBTOOL-for-automake.patch @@ -0,0 +1,25 @@ +From 8f2b7717984fe025d357023bdd2e1b17cd7bcb0b Mon Sep 17 00:00:00 2001 +From: Jack Morgenstein +Date: Mon, 7 Jun 2010 18:21:53 +0300 +Subject: configure.in -- add AC_PROG_LIBTOOL for earlier versions of automake. + +Signed-off-by: Jack Morgenstein +--- + configure.in | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) + +diff --git a/configure.in b/configure.in +index 83368a9..d0678c8 100644 +--- a/configure.in ++++ b/configure.in +@@ -13,6 +13,7 @@ AC_PROG_CC + AC_GNU_SOURCE + AC_PROG_LN_S + ++AC_PROG_LIBTOOL + LT_INIT + + AC_ARG_WITH([valgrind], +-- +1.6.3.2 + diff --git a/contrib/ofed/libibverbs/fixes/pthread_cond_t_fields.patch b/contrib/ofed/libibverbs/fixes/pthread_cond_t_fields.patch new file mode 100644 index 000000000000..4a62b14ca419 --- /dev/null +++ b/contrib/ofed/libibverbs/fixes/pthread_cond_t_fields.patch @@ -0,0 +1,62 @@ +move pthread_cond_t fields to the end of structs, because +their size changed from RHAS4 to RHAS5. In all the cases, +the intervening entries were not accessed outside libibverbs +(in non-XRC applications). + +The structs modified are: ibv_cq, ibv_srq, and ibv_qp. +(OFED 1.3 libibverbs commit 4c29c266a3c0932cd06e8f2b4e238aecd3c65dcc) + +Pointed out by: Changqing Tang + +Signed-off-by: Jack Morgenstein + +Index: libibverbs/include/infiniband/verbs.h +=================================================================== +--- libibverbs.orig/include/infiniband/verbs.h 2009-11-01 15:18:24.585280000 +0200 ++++ libibverbs/include/infiniband/verbs.h 2009-11-01 15:18:28.759417000 +0200 +@@ -565,13 +565,14 @@ struct ibv_srq { + struct ibv_pd *pd; + uint32_t handle; + +- pthread_mutex_t mutex; +- pthread_cond_t cond; + uint32_t events_completed; + + uint32_t xrc_srq_num; + struct ibv_xrc_domain *xrc_domain; + struct ibv_cq *xrc_cq; ++ ++ pthread_mutex_t mutex; ++ pthread_cond_t cond; + }; + + struct ibv_qp { +@@ -586,11 +587,12 @@ struct ibv_qp { + enum ibv_qp_state state; + enum ibv_qp_type qp_type; + +- pthread_mutex_t mutex; +- pthread_cond_t cond; + uint32_t events_completed; + + struct ibv_xrc_domain *xrc_domain; ++ ++ pthread_mutex_t mutex; ++ pthread_cond_t cond; + }; + + struct ibv_comp_channel { +@@ -606,10 +608,11 @@ struct ibv_cq { + uint32_t handle; + int cqe; + +- pthread_mutex_t mutex; +- pthread_cond_t cond; + uint32_t comp_events_completed; + uint32_t async_events_completed; ++ ++ pthread_mutex_t mutex; ++ pthread_cond_t cond; + }; + + struct ibv_ah { diff --git a/contrib/ofed/libibverbs/fixes/qpt_raw_eth.patch b/contrib/ofed/libibverbs/fixes/qpt_raw_eth.patch new file mode 100644 index 000000000000..67869f417af2 --- /dev/null +++ b/contrib/ofed/libibverbs/fixes/qpt_raw_eth.patch @@ -0,0 +1,28 @@ +libibverbs: add raw ethernet QP type IBV_QPT_RAW_ETH=7 + +The patch enables usage of L2 raw ethernet QP type for user-space +applications. + +Miroslaw Walukiewicz + + +Signed-off-by: Mirek Walukiewicz +--- + include/infiniband/verbs.h | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + + +diff --git a/include/infiniband/verbs.h b/include/infiniband/verbs.h +index fe9ab62..a340ffb 100644 +--- a/include/infiniband/verbs.h ++++ b/include/infiniband/verbs.h +@@ -397,7 +397,8 @@ enum ibv_qp_type { + IBV_QPT_RC = 2, + IBV_QPT_UC, + IBV_QPT_UD, +- IBV_QPT_XRC ++ IBV_QPT_XRC, ++ IBV_QPT_RAW_ETH = 8 + }; + + struct ibv_qp_cap { diff --git a/contrib/ofed/libibverbs/fixes/rocee_examples.patch b/contrib/ofed/libibverbs/fixes/rocee_examples.patch new file mode 100644 index 000000000000..eda5a401a342 --- /dev/null +++ b/contrib/ofed/libibverbs/fixes/rocee_examples.patch @@ -0,0 +1,1051 @@ +[PATCH 4/4] libibverbs: Update examples + +Since RDMAoE requires usage of GRH, update ibv_*_pinpong examples to accept +GIDs. GIDs are given as an index to the local port's table and are exchanged +between the client and the server through the socket connection. + +Signed-off-by: Eli Cohen +--- + examples/devinfo.c | 14 ++++++++ + examples/pingpong.c | 31 ++++++++++++++++++ + examples/pingpong.h | 4 ++ + examples/rc_pingpong.c | 79 +++++++++++++++++++++++++++++++++++----------- + examples/srq_pingpong.c | 72 ++++++++++++++++++++++++++++++++---------- + examples/uc_pingpong.c | 70 ++++++++++++++++++++++++++++++++--------- + examples/ud_pingpong.c | 69 ++++++++++++++++++++++++++++++----------- + 7 files changed, 269 insertions(+), 70 deletions(-) + +Index: libibverbs/examples/devinfo.c +=================================================================== +--- libibverbs.orig/examples/devinfo.c 2010-02-08 15:04:24.369329000 +0200 ++++ libibverbs/examples/devinfo.c 2010-03-17 14:08:48.404754000 +0200 +@@ -184,6 +184,19 @@ static int print_all_port_gids(struct ib + return rc; + } + ++static const char *link_layer_str(uint8_t link_layer) ++{ ++ switch (link_layer) { ++ case IBV_LINK_LAYER_UNSPECIFIED: ++ case IBV_LINK_LAYER_INFINIBAND: ++ return "IB"; ++ case IBV_LINK_LAYER_ETHERNET: ++ return "Ethernet"; ++ default: ++ return "Unknown"; ++ } ++} ++ + static int print_hca_cap(struct ibv_device *ib_dev, uint8_t ib_port) + { + struct ibv_context *ctx; +@@ -284,6 +297,7 @@ static int print_hca_cap(struct ibv_devi + printf("\t\t\tsm_lid:\t\t\t%d\n", port_attr.sm_lid); + printf("\t\t\tport_lid:\t\t%d\n", port_attr.lid); + printf("\t\t\tport_lmc:\t\t0x%02x\n", port_attr.lmc); ++ printf("\t\t\tlink_layer:\t\t%s\n", link_layer_str(port_attr.link_layer)); + + if (verbose) { + printf("\t\t\tmax_msg_sz:\t\t0x%x\n", port_attr.max_msg_sz); +Index: libibverbs/examples/pingpong.c +=================================================================== +--- libibverbs.orig/examples/pingpong.c 2010-02-08 15:04:24.372330000 +0200 ++++ libibverbs/examples/pingpong.c 2010-03-17 14:08:48.433754000 +0200 +@@ -31,6 +31,10 @@ + */ + + #include "pingpong.h" ++#include ++#include ++#include ++#include + + enum ibv_mtu pp_mtu_to_enum(int mtu) + { +@@ -53,3 +57,30 @@ uint16_t pp_get_local_lid(struct ibv_con + + return attr.lid; + } ++ ++int pp_get_port_info(struct ibv_context *context, int port, ++ struct ibv_port_attr *attr) ++{ ++ return ibv_query_port(context, port, attr); ++} ++ ++void wire_gid_to_gid(const char *wgid, union ibv_gid *gid) ++{ ++ char tmp[9]; ++ uint32_t v32; ++ int i; ++ ++ for (tmp[8] = 0, i = 0; i < 4; ++i) { ++ memcpy(tmp, wgid + i * 8, 8); ++ sscanf(tmp, "%x", &v32); ++ *(uint32_t *)(&gid->raw[i * 4]) = ntohl(v32); ++ } ++} ++ ++void gid_to_wire_gid(const union ibv_gid *gid, char wgid[]) ++{ ++ int i; ++ ++ for (i = 0; i < 4; ++i) ++ sprintf(&wgid[i * 8], "%08x", htonl(*(uint32_t *)(gid->raw + i * 4))); ++} +Index: libibverbs/examples/pingpong.h +=================================================================== +--- libibverbs.orig/examples/pingpong.h 2010-02-08 15:04:24.375328000 +0200 ++++ libibverbs/examples/pingpong.h 2010-03-17 14:08:48.443756000 +0200 +@@ -37,5 +37,9 @@ + + enum ibv_mtu pp_mtu_to_enum(int mtu); + uint16_t pp_get_local_lid(struct ibv_context *context, int port); ++int pp_get_port_info(struct ibv_context *context, int port, ++ struct ibv_port_attr *attr); ++void wire_gid_to_gid(const char *wgid, union ibv_gid *gid); ++void gid_to_wire_gid(const union ibv_gid *gid, char wgid[]); + + #endif /* IBV_PINGPONG_H */ +Index: libibverbs/examples/rc_pingpong.c +=================================================================== +--- libibverbs.orig/examples/rc_pingpong.c 2010-02-08 15:04:24.378329000 +0200 ++++ libibverbs/examples/rc_pingpong.c 2010-03-17 14:11:16.145313000 +0200 +@@ -67,17 +67,19 @@ struct pingpong_context { + int size; + int rx_depth; + int pending; ++ struct ibv_port_attr portinfo; + }; + + struct pingpong_dest { + int lid; + int qpn; + int psn; ++ union ibv_gid gid; + }; + + static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + enum ibv_mtu mtu, int sl, +- struct pingpong_dest *dest) ++ struct pingpong_dest *dest, int sgid_idx) + { + struct ibv_qp_attr attr = { + .qp_state = IBV_QPS_RTR, +@@ -94,6 +96,13 @@ static int pp_connect_ctx(struct pingpon + .port_num = port + } + }; ++ ++ if (dest->gid.global.interface_id) { ++ attr.ah_attr.is_global = 1; ++ attr.ah_attr.grh.hop_limit = 1; ++ attr.ah_attr.grh.dgid = dest->gid; ++ attr.ah_attr.grh.sgid_index = sgid_idx; ++ } + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | +@@ -135,10 +144,11 @@ static struct pingpong_dest *pp_client_e + .ai_socktype = SOCK_STREAM + }; + char *service; +- char msg[sizeof "0000:000000:000000"]; ++ char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int sockfd = -1; + struct pingpong_dest *rem_dest = NULL; ++ char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; +@@ -169,7 +179,8 @@ static struct pingpong_dest *pp_client_e + return NULL; + } + +- sprintf(msg, "%04x:%06x:%06x", my_dest->lid, my_dest->qpn, my_dest->psn); ++ gid_to_wire_gid(&my_dest->gid, gid); ++ sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid); + if (write(sockfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + goto out; +@@ -187,7 +198,8 @@ static struct pingpong_dest *pp_client_e + if (!rem_dest) + goto out; + +- sscanf(msg, "%x:%x:%x", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn); ++ sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid); ++ wire_gid_to_gid(gid, &rem_dest->gid); + + out: + close(sockfd); +@@ -197,7 +209,8 @@ out: + static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx, + int ib_port, enum ibv_mtu mtu, + int port, int sl, +- const struct pingpong_dest *my_dest) ++ const struct pingpong_dest *my_dest, ++ int sgid_idx) + { + struct addrinfo *res, *t; + struct addrinfo hints = { +@@ -206,10 +219,11 @@ static struct pingpong_dest *pp_server_e + .ai_socktype = SOCK_STREAM + }; + char *service; +- char msg[sizeof "0000:000000:000000"]; ++ char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int sockfd = -1, connfd; + struct pingpong_dest *rem_dest = NULL; ++ char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; +@@ -263,16 +277,19 @@ static struct pingpong_dest *pp_server_e + if (!rem_dest) + goto out; + +- sscanf(msg, "%x:%x:%x", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn); ++ sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid); ++ wire_gid_to_gid(gid, &rem_dest->gid); + +- if (pp_connect_ctx(ctx, ib_port, my_dest->psn, mtu, sl, rem_dest)) { ++ if (pp_connect_ctx(ctx, ib_port, my_dest->psn, mtu, sl, rem_dest, sgid_idx)) { + fprintf(stderr, "Couldn't connect to remote QP\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + +- sprintf(msg, "%04x:%06x:%06x", my_dest->lid, my_dest->qpn, my_dest->psn); ++ ++ gid_to_wire_gid(&my_dest->gid, gid); ++ sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid); + if (write(connfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); +@@ -289,11 +306,11 @@ out: + + static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size, + int rx_depth, int port, +- int use_event) ++ int use_event, int is_server) + { + struct pingpong_context *ctx; + +- ctx = malloc(sizeof *ctx); ++ ctx = calloc(1, sizeof *ctx); + if (!ctx) + return NULL; + +@@ -306,7 +323,7 @@ static struct pingpong_context *pp_init_ + return NULL; + } + +- memset(ctx->buf, 0, size); ++ memset(ctx->buf, 0x7b + is_server, size); + + ctx->context = ibv_open_device(ib_dev); + if (!ctx->context) { +@@ -481,6 +498,7 @@ static void usage(const char *argv0) + printf(" -n, --iters= number of exchanges (default 1000)\n"); + printf(" -l, --sl= service level value\n"); + printf(" -e, --events sleep on CQ events (default poll)\n"); ++ printf(" -g, --gid-idx= local port gid index\n"); + } + + int main(int argc, char *argv[]) +@@ -504,6 +522,8 @@ int main(int argc, char *argv[]) + int rcnt, scnt; + int num_cq_events = 0; + int sl = 0; ++ int gidx = -1; ++ char gid[33]; + + srand48(getpid() * time(NULL)); + +@@ -520,10 +540,11 @@ int main(int argc, char *argv[]) + { .name = "iters", .has_arg = 1, .val = 'n' }, + { .name = "sl", .has_arg = 1, .val = 'l' }, + { .name = "events", .has_arg = 0, .val = 'e' }, ++ { .name = "gid-idx", .has_arg = 1, .val = 'g' }, + { 0 } + }; + +- c = getopt_long(argc, argv, "p:d:i:s:m:r:n:l:e", long_options, NULL); ++ c = getopt_long(argc, argv, "p:d:i:s:m:r:n:l:eg:", long_options, NULL); + if (c == -1) + break; + +@@ -576,6 +597,10 @@ int main(int argc, char *argv[]) + ++use_event; + break; + ++ case 'g': ++ gidx = strtol(optarg, NULL, 0); ++ break; ++ + default: + usage(argv[0]); + return 1; +@@ -615,7 +640,7 @@ int main(int argc, char *argv[]) + } + } + +- ctx = pp_init_ctx(ib_dev, size, rx_depth, ib_port, use_event); ++ ctx = pp_init_ctx(ib_dev, size, rx_depth, ib_port, use_event, !servername); + if (!ctx) + return 1; + +@@ -631,30 +656,47 @@ int main(int argc, char *argv[]) + return 1; + } + +- my_dest.lid = pp_get_local_lid(ctx->context, ib_port); +- my_dest.qpn = ctx->qp->qp_num; +- my_dest.psn = lrand48() & 0xffffff; +- if (!my_dest.lid) { ++ ++ if (pp_get_port_info(ctx->context, ib_port, &ctx->portinfo)) { ++ fprintf(stderr, "Couldn't get port info\n"); ++ return 1; ++ } ++ ++ my_dest.lid = ctx->portinfo.lid; ++ if (ctx->portinfo.link_layer == IBV_LINK_LAYER_INFINIBAND && !my_dest.lid) { + fprintf(stderr, "Couldn't get local LID\n"); + return 1; + } + +- printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", +- my_dest.lid, my_dest.qpn, my_dest.psn); ++ if (gidx >= 0) { ++ if (ibv_query_gid(ctx->context, ib_port, gidx, &my_dest.gid)) { ++ fprintf(stderr, "Could not get local gid for gid index %d\n", gidx); ++ return 1; ++ } ++ } else ++ memset(&my_dest.gid, 0, sizeof my_dest.gid); ++ ++ my_dest.qpn = ctx->qp->qp_num; ++ my_dest.psn = lrand48() & 0xffffff; ++ inet_ntop(AF_INET6, &my_dest.gid, gid, sizeof gid); ++ printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", ++ my_dest.lid, my_dest.qpn, my_dest.psn, gid); ++ + + if (servername) + rem_dest = pp_client_exch_dest(servername, port, &my_dest); + else +- rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, &my_dest); ++ rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, &my_dest, gidx); + + if (!rem_dest) + return 1; + +- printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", +- rem_dest->lid, rem_dest->qpn, rem_dest->psn); ++ inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof gid); ++ printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", ++ rem_dest->lid, rem_dest->qpn, rem_dest->psn, gid); + + if (servername) +- if (pp_connect_ctx(ctx, ib_port, my_dest.psn, mtu, sl, rem_dest)) ++ if (pp_connect_ctx(ctx, ib_port, my_dest.psn, mtu, sl, rem_dest, gidx)) + return 1; + + ctx->pending = PINGPONG_RECV_WRID; +@@ -706,6 +748,7 @@ int main(int argc, char *argv[]) + fprintf(stderr, "poll CQ failed %d\n", ne); + return 1; + } ++ + } while (!use_event && ne < 1); + + for (i = 0; i < ne; ++i) { +Index: libibverbs/examples/srq_pingpong.c +=================================================================== +--- libibverbs.orig/examples/srq_pingpong.c 2010-02-08 15:04:24.382329000 +0200 ++++ libibverbs/examples/srq_pingpong.c 2010-03-17 14:13:22.332220000 +0200 +@@ -71,17 +71,19 @@ struct pingpong_context { + int num_qp; + int rx_depth; + int pending[MAX_QP]; ++ struct ibv_port_attr portinfo; + }; + + struct pingpong_dest { + int lid; + int qpn; + int psn; ++ union ibv_gid gid; + }; + + static int pp_connect_ctx(struct pingpong_context *ctx, int port, enum ibv_mtu mtu, + int sl, const struct pingpong_dest *my_dest, +- const struct pingpong_dest *dest) ++ const struct pingpong_dest *dest, int sgid_idx) + { + int i; + +@@ -101,6 +103,13 @@ static int pp_connect_ctx(struct pingpon + .port_num = port + } + }; ++ ++ if (dest->gid.global.interface_id) { ++ attr.ah_attr.is_global = 1; ++ attr.ah_attr.grh.hop_limit = 1; ++ attr.ah_attr.grh.dgid = dest->gid; ++ attr.ah_attr.grh.sgid_index = sgid_idx; ++ } + if (ibv_modify_qp(ctx->qp[i], &attr, + IBV_QP_STATE | + IBV_QP_AV | +@@ -143,12 +152,13 @@ static struct pingpong_dest *pp_client_e + .ai_socktype = SOCK_STREAM + }; + char *service; +- char msg[sizeof "0000:000000:000000"]; ++ char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int r; + int i; + int sockfd = -1; + struct pingpong_dest *rem_dest = NULL; ++ char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; +@@ -180,7 +190,8 @@ static struct pingpong_dest *pp_client_e + } + + for (i = 0; i < MAX_QP; ++i) { +- sprintf(msg, "%04x:%06x:%06x", my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn); ++ gid_to_wire_gid(&my_dest[i].gid, gid); ++ sprintf(msg, "%04x:%06x:%06x:%s", my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, gid); + if (write(sockfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + goto out; +@@ -204,8 +215,9 @@ static struct pingpong_dest *pp_client_e + n += r; + } + +- sscanf(msg, "%x:%x:%x", +- &rem_dest[i].lid, &rem_dest[i].qpn, &rem_dest[i].psn); ++ sscanf(msg, "%x:%x:%x:%s", ++ &rem_dest[i].lid, &rem_dest[i].qpn, &rem_dest[i].psn, gid); ++ wire_gid_to_gid(gid, &rem_dest[i].gid); + } + + write(sockfd, "done", sizeof "done"); +@@ -218,7 +230,8 @@ out: + static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx, + int ib_port, enum ibv_mtu mtu, + int port, int sl, +- const struct pingpong_dest *my_dest) ++ const struct pingpong_dest *my_dest, ++ int sgid_idx) + { + struct addrinfo *res, *t; + struct addrinfo hints = { +@@ -227,12 +240,13 @@ static struct pingpong_dest *pp_server_e + .ai_socktype = SOCK_STREAM + }; + char *service; +- char msg[sizeof "0000:000000:000000"]; ++ char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int r; + int i; + int sockfd = -1, connfd; + struct pingpong_dest *rem_dest = NULL; ++ char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; +@@ -292,11 +306,12 @@ static struct pingpong_dest *pp_server_e + n += r; + } + +- sscanf(msg, "%x:%x:%x", +- &rem_dest[i].lid, &rem_dest[i].qpn, &rem_dest[i].psn); ++ sscanf(msg, "%x:%x:%x:%s", ++ &rem_dest[i].lid, &rem_dest[i].qpn, &rem_dest[i].psn, gid); ++ wire_gid_to_gid(gid, &rem_dest[i].gid); + } + +- if (pp_connect_ctx(ctx, ib_port, mtu, sl, my_dest, rem_dest)) { ++ if (pp_connect_ctx(ctx, ib_port, mtu, sl, my_dest, rem_dest, sgid_idx)) { + fprintf(stderr, "Couldn't connect to remote QP\n"); + free(rem_dest); + rem_dest = NULL; +@@ -304,7 +319,8 @@ static struct pingpong_dest *pp_server_e + } + + for (i = 0; i < MAX_QP; ++i) { +- sprintf(msg, "%04x:%06x:%06x", my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn); ++ gid_to_wire_gid(&my_dest[i].gid, gid); ++ sprintf(msg, "%04x:%06x:%06x:%s", my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, gid); + if (write(connfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); +@@ -327,7 +343,7 @@ static struct pingpong_context *pp_init_ + struct pingpong_context *ctx; + int i; + +- ctx = malloc(sizeof *ctx); ++ ctx = calloc(1, sizeof *ctx); + if (!ctx) + return NULL; + +@@ -551,6 +567,7 @@ static void usage(const char *argv0) + printf(" -n, --iters= number of exchanges per QP(default 1000)\n"); + printf(" -l, --sl= service level value\n"); + printf(" -e, --events sleep on CQ events (default poll)\n"); ++ printf(" -g, --gid-idx= local port gid index\n"); + } + + int main(int argc, char *argv[]) +@@ -578,6 +595,8 @@ int main(int argc, char *argv[]) + int i; + int num_cq_events = 0; + int sl = 0; ++ int gidx = -1; ++ char gid[33]; + + srand48(getpid() * time(NULL)); + +@@ -595,10 +614,11 @@ int main(int argc, char *argv[]) + { .name = "iters", .has_arg = 1, .val = 'n' }, + { .name = "sl", .has_arg = 1, .val = 'l' }, + { .name = "events", .has_arg = 0, .val = 'e' }, ++ { .name = "gid-idx", .has_arg = 1, .val = 'g' }, + { 0 } + }; + +- c = getopt_long(argc, argv, "p:d:i:s:m:q:r:n:l:e", long_options, NULL); ++ c = getopt_long(argc, argv, "p:d:i:s:m:q:r:n:l:eg:", long_options, NULL); + if (c == -1) + break; + +@@ -655,6 +675,10 @@ int main(int argc, char *argv[]) + ++use_event; + break; + ++ case 'g': ++ gidx = strtol(optarg, NULL, 0); ++ break; ++ + default: + usage(argv[0]); + return 1; +@@ -722,33 +746,50 @@ int main(int argc, char *argv[]) + + memset(my_dest, 0, sizeof my_dest); + ++ if (pp_get_port_info(ctx->context, ib_port, &ctx->portinfo)) { ++ fprintf(stderr, "Couldn't get port info\n"); ++ return 1; ++ } + for (i = 0; i < num_qp; ++i) { + my_dest[i].qpn = ctx->qp[i]->qp_num; + my_dest[i].psn = lrand48() & 0xffffff; +- my_dest[i].lid = pp_get_local_lid(ctx->context, ib_port); +- if (!my_dest[i].lid) { ++ my_dest[i].lid = ctx->portinfo.lid; ++ if (ctx->portinfo.link_layer == IBV_LINK_LAYER_INFINIBAND && !my_dest[i].lid) { + fprintf(stderr, "Couldn't get local LID\n"); + return 1; + } + +- printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", +- my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn); ++ if (gidx >= 0) { ++ if (ibv_query_gid(ctx->context, ib_port, gidx, &my_dest[i].gid)) { ++ fprintf(stderr, "Could not get local gid for gid index %d\n", gidx); ++ return 1; ++ } ++ } else ++ memset(&my_dest[i].gid, 0, sizeof my_dest[i].gid); ++ ++ inet_ntop(AF_INET6, &my_dest[i].gid, gid, sizeof gid); ++ printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", ++ my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn, gid); + } + + if (servername) + rem_dest = pp_client_exch_dest(servername, port, my_dest); + else +- rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, my_dest); ++ rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, my_dest, gidx); + + if (!rem_dest) + return 1; + +- for (i = 0; i < num_qp; ++i) +- printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", +- rem_dest[i].lid, rem_dest[i].qpn, rem_dest[i].psn); ++ inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof gid); ++ ++ for (i = 0; i < num_qp; ++i) { ++ inet_ntop(AF_INET6, &rem_dest[i].gid, gid, sizeof gid); ++ printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", ++ rem_dest[i].lid, rem_dest[i].qpn, rem_dest[i].psn, gid); ++ } + + if (servername) +- if (pp_connect_ctx(ctx, ib_port, mtu, sl, my_dest, rem_dest)) ++ if (pp_connect_ctx(ctx, ib_port, mtu, sl, my_dest, rem_dest, gidx)) + return 1; + + if (servername) +Index: libibverbs/examples/uc_pingpong.c +=================================================================== +--- libibverbs.orig/examples/uc_pingpong.c 2010-02-08 15:04:24.386328000 +0200 ++++ libibverbs/examples/uc_pingpong.c 2010-03-17 14:14:23.573114000 +0200 +@@ -67,17 +67,19 @@ struct pingpong_context { + int size; + int rx_depth; + int pending; ++ struct ibv_port_attr portinfo; + }; + + struct pingpong_dest { + int lid; + int qpn; + int psn; ++ union ibv_gid gid; + }; + + static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, + enum ibv_mtu mtu, int sl, +- struct pingpong_dest *dest) ++ struct pingpong_dest *dest, int sgid_idx) + { + struct ibv_qp_attr attr = { + .qp_state = IBV_QPS_RTR, +@@ -92,6 +94,14 @@ static int pp_connect_ctx(struct pingpon + .port_num = port + } + }; ++ ++ if (dest->gid.global.interface_id) { ++ attr.ah_attr.is_global = 1; ++ attr.ah_attr.grh.hop_limit = 1; ++ attr.ah_attr.grh.dgid = dest->gid; ++ attr.ah_attr.grh.sgid_index = sgid_idx; ++ } ++ + if (ibv_modify_qp(ctx->qp, &attr, + IBV_QP_STATE | + IBV_QP_AV | +@@ -123,10 +133,11 @@ static struct pingpong_dest *pp_client_e + .ai_socktype = SOCK_STREAM + }; + char *service; +- char msg[sizeof "0000:000000:000000"]; ++ char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int sockfd = -1; + struct pingpong_dest *rem_dest = NULL; ++ char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; +@@ -157,7 +168,8 @@ static struct pingpong_dest *pp_client_e + return NULL; + } + +- sprintf(msg, "%04x:%06x:%06x", my_dest->lid, my_dest->qpn, my_dest->psn); ++ gid_to_wire_gid(&my_dest->gid, gid); ++ sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid); + if (write(sockfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + goto out; +@@ -175,7 +187,8 @@ static struct pingpong_dest *pp_client_e + if (!rem_dest) + goto out; + +- sscanf(msg, "%x:%x:%x", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn); ++ sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid); ++ wire_gid_to_gid(gid, &rem_dest->gid); + + out: + close(sockfd); +@@ -185,7 +198,8 @@ out: + static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx, + int ib_port, enum ibv_mtu mtu, + int port, int sl, +- const struct pingpong_dest *my_dest) ++ const struct pingpong_dest *my_dest, ++ int sgid_idx) + { + struct addrinfo *res, *t; + struct addrinfo hints = { +@@ -194,10 +208,11 @@ static struct pingpong_dest *pp_server_e + .ai_socktype = SOCK_STREAM + }; + char *service; +- char msg[sizeof "0000:000000:000000"]; ++ char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int sockfd = -1, connfd; + struct pingpong_dest *rem_dest = NULL; ++ char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; +@@ -251,16 +266,18 @@ static struct pingpong_dest *pp_server_e + if (!rem_dest) + goto out; + +- sscanf(msg, "%x:%x:%x", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn); ++ sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid); ++ wire_gid_to_gid(gid, &rem_dest->gid); + +- if (pp_connect_ctx(ctx, ib_port, my_dest->psn, mtu, sl, rem_dest)) { ++ if (pp_connect_ctx(ctx, ib_port, my_dest->psn, mtu, sl, rem_dest, sgid_idx)) { + fprintf(stderr, "Couldn't connect to remote QP\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + +- sprintf(msg, "%04x:%06x:%06x", my_dest->lid, my_dest->qpn, my_dest->psn); ++ gid_to_wire_gid(&my_dest->gid, gid); ++ sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid); + if (write(connfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); +@@ -281,7 +298,7 @@ static struct pingpong_context *pp_init_ + { + struct pingpong_context *ctx; + +- ctx = malloc(sizeof *ctx); ++ ctx = calloc(1, sizeof *ctx); + if (!ctx) + return NULL; + +@@ -469,6 +486,7 @@ static void usage(const char *argv0) + printf(" -n, --iters= number of exchanges (default 1000)\n"); + printf(" -l, --sl= service level value\n"); + printf(" -e, --events sleep on CQ events (default poll)\n"); ++ printf(" -g, --gid-idx= local port gid index\n"); + } + + int main(int argc, char *argv[]) +@@ -492,6 +510,8 @@ int main(int argc, char *argv[]) + int rcnt, scnt; + int num_cq_events = 0; + int sl = 0; ++ int gidx = -1; ++ char gid[33]; + + srand48(getpid() * time(NULL)); + +@@ -508,10 +528,11 @@ int main(int argc, char *argv[]) + { .name = "iters", .has_arg = 1, .val = 'n' }, + { .name = "sl", .has_arg = 1, .val = 'l' }, + { .name = "events", .has_arg = 0, .val = 'e' }, ++ { .name = "gid-idx", .has_arg = 1, .val = 'g' }, + { 0 } + }; + +- c = getopt_long(argc, argv, "p:d:i:s:m:r:n:l:e", long_options, NULL); ++ c = getopt_long(argc, argv, "p:d:i:s:m:r:n:l:eg:", long_options, NULL); + if (c == -1) + break; + +@@ -564,6 +585,10 @@ int main(int argc, char *argv[]) + ++use_event; + break; + ++ case 'g': ++ gidx = strtol(optarg, NULL, 0); ++ break; ++ + default: + usage(argv[0]); + return 1; +@@ -619,30 +644,45 @@ int main(int argc, char *argv[]) + return 1; + } + +- my_dest.lid = pp_get_local_lid(ctx->context, ib_port); +- my_dest.qpn = ctx->qp->qp_num; +- my_dest.psn = lrand48() & 0xffffff; +- if (!my_dest.lid) { ++ if (pp_get_port_info(ctx->context, ib_port, &ctx->portinfo)) { ++ fprintf(stderr, "Couldn't get port info\n"); ++ return 1; ++ } ++ ++ my_dest.lid = ctx->portinfo.lid; ++ if (ctx->portinfo.link_layer == IBV_LINK_LAYER_INFINIBAND && !my_dest.lid) { + fprintf(stderr, "Couldn't get local LID\n"); + return 1; + } + +- printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", +- my_dest.lid, my_dest.qpn, my_dest.psn); ++ if (gidx >= 0) { ++ if (ibv_query_gid(ctx->context, ib_port, gidx, &my_dest.gid)) { ++ fprintf(stderr, "Could not get local gid for gid index %d\n", gidx); ++ return 1; ++ } ++ } else ++ memset(&my_dest.gid, 0, sizeof my_dest.gid); ++ ++ my_dest.qpn = ctx->qp->qp_num; ++ my_dest.psn = lrand48() & 0xffffff; ++ inet_ntop(AF_INET6, &my_dest.gid, gid, sizeof gid); ++ printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", ++ my_dest.lid, my_dest.qpn, my_dest.psn, gid); + + if (servername) + rem_dest = pp_client_exch_dest(servername, port, &my_dest); + else +- rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, &my_dest); ++ rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, &my_dest, gidx); + + if (!rem_dest) + return 1; + +- printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", +- rem_dest->lid, rem_dest->qpn, rem_dest->psn); ++ inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof gid); ++ printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", ++ rem_dest->lid, rem_dest->qpn, rem_dest->psn, gid); + + if (servername) +- if (pp_connect_ctx(ctx, ib_port, my_dest.psn, mtu, sl, rem_dest)) ++ if (pp_connect_ctx(ctx, ib_port, my_dest.psn, mtu, sl, rem_dest, gidx)) + return 1; + + ctx->pending = PINGPONG_RECV_WRID; +Index: libibverbs/examples/ud_pingpong.c +=================================================================== +--- libibverbs.orig/examples/ud_pingpong.c 2010-02-08 15:04:24.389329000 +0200 ++++ libibverbs/examples/ud_pingpong.c 2010-03-17 14:08:48.502754000 +0200 +@@ -68,16 +68,18 @@ struct pingpong_context { + int size; + int rx_depth; + int pending; ++ struct ibv_port_attr portinfo; + }; + + struct pingpong_dest { + int lid; + int qpn; + int psn; ++ union ibv_gid gid; + }; + + static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, +- int sl, struct pingpong_dest *dest) ++ int sl, struct pingpong_dest *dest, int sgid_idx) + { + struct ibv_ah_attr ah_attr = { + .is_global = 0, +@@ -105,6 +107,13 @@ static int pp_connect_ctx(struct pingpon + return 1; + } + ++ if (dest->gid.global.interface_id) { ++ ah_attr.is_global = 1; ++ ah_attr.grh.hop_limit = 1; ++ ah_attr.grh.dgid = dest->gid; ++ ah_attr.grh.sgid_index = sgid_idx; ++ } ++ + ctx->ah = ibv_create_ah(ctx->pd, &ah_attr); + if (!ctx->ah) { + fprintf(stderr, "Failed to create AH\n"); +@@ -123,10 +132,11 @@ static struct pingpong_dest *pp_client_e + .ai_socktype = SOCK_STREAM + }; + char *service; +- char msg[sizeof "0000:000000:000000"]; ++ char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int sockfd = -1; + struct pingpong_dest *rem_dest = NULL; ++ char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; +@@ -157,7 +167,8 @@ static struct pingpong_dest *pp_client_e + return NULL; + } + +- sprintf(msg, "%04x:%06x:%06x", my_dest->lid, my_dest->qpn, my_dest->psn); ++ gid_to_wire_gid(&my_dest->gid, gid); ++ sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid); + if (write(sockfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + goto out; +@@ -175,7 +186,8 @@ static struct pingpong_dest *pp_client_e + if (!rem_dest) + goto out; + +- sscanf(msg, "%x:%x:%x", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn); ++ sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid); ++ wire_gid_to_gid(gid, &rem_dest->gid); + + out: + close(sockfd); +@@ -184,7 +196,8 @@ out: + + static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx, + int ib_port, int port, int sl, +- const struct pingpong_dest *my_dest) ++ const struct pingpong_dest *my_dest, ++ int sgid_idx) + { + struct addrinfo *res, *t; + struct addrinfo hints = { +@@ -193,10 +206,11 @@ static struct pingpong_dest *pp_server_e + .ai_socktype = SOCK_STREAM + }; + char *service; +- char msg[sizeof "0000:000000:000000"]; ++ char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; + int n; + int sockfd = -1, connfd; + struct pingpong_dest *rem_dest = NULL; ++ char gid[33]; + + if (asprintf(&service, "%d", port) < 0) + return NULL; +@@ -250,16 +264,18 @@ static struct pingpong_dest *pp_server_e + if (!rem_dest) + goto out; + +- sscanf(msg, "%x:%x:%x", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn); ++ sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, &rem_dest->psn, gid); ++ wire_gid_to_gid(gid, &rem_dest->gid); + +- if (pp_connect_ctx(ctx, ib_port, my_dest->psn, sl, rem_dest)) { ++ if (pp_connect_ctx(ctx, ib_port, my_dest->psn, sl, rem_dest, sgid_idx)) { + fprintf(stderr, "Couldn't connect to remote QP\n"); + free(rem_dest); + rem_dest = NULL; + goto out; + } + +- sprintf(msg, "%04x:%06x:%06x", my_dest->lid, my_dest->qpn, my_dest->psn); ++ gid_to_wire_gid(&my_dest->gid, gid); ++ sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, my_dest->psn, gid); + if (write(connfd, msg, sizeof msg) != sizeof msg) { + fprintf(stderr, "Couldn't send local address\n"); + free(rem_dest); +@@ -474,10 +490,11 @@ static void usage(const char *argv0) + printf(" -p, --port= listen on/connect to port (default 18515)\n"); + printf(" -d, --ib-dev= use IB device (default first device found)\n"); + printf(" -i, --ib-port= use port of IB device (default 1)\n"); +- printf(" -s, --size= size of message to exchange (default 2048)\n"); ++ printf(" -s, --size= size of message to exchange (default 1024)\n"); + printf(" -r, --rx-depth= number of receives to post at a time (default 500)\n"); + printf(" -n, --iters= number of exchanges (default 1000)\n"); + printf(" -e, --events sleep on CQ events (default poll)\n"); ++ printf(" -g, --gid-idx= local port gid index\n"); + } + + int main(int argc, char *argv[]) +@@ -492,7 +509,7 @@ int main(int argc, char *argv[]) + char *servername = NULL; + int port = 18515; + int ib_port = 1; +- int size = 2048; ++ int size = 1024; + int rx_depth = 500; + int iters = 1000; + int use_event = 0; +@@ -500,6 +517,8 @@ int main(int argc, char *argv[]) + int rcnt, scnt; + int num_cq_events = 0; + int sl = 0; ++ int gidx = -1; ++ char gid[33]; + + srand48(getpid() * time(NULL)); + +@@ -515,10 +534,11 @@ int main(int argc, char *argv[]) + { .name = "iters", .has_arg = 1, .val = 'n' }, + { .name = "sl", .has_arg = 1, .val = 'l' }, + { .name = "events", .has_arg = 0, .val = 'e' }, ++ { .name = "gid-idx", .has_arg = 1, .val = 'g' }, + { 0 } + }; + +- c = getopt_long(argc, argv, "p:d:i:s:r:n:l:e", long_options, NULL); ++ c = getopt_long(argc, argv, "p:d:i:s:r:n:l:eg:", long_options, NULL); + if (c == -1) + break; + +@@ -563,6 +583,10 @@ int main(int argc, char *argv[]) + ++use_event; + break; + ++ case 'g': ++ gidx = strtol(optarg, NULL, 0); ++ break; ++ + default: + usage(argv[0]); + return 1; +@@ -618,30 +642,41 @@ int main(int argc, char *argv[]) + return 1; + } + +- my_dest.lid = pp_get_local_lid(ctx->context, ib_port); +- my_dest.qpn = ctx->qp->qp_num; +- my_dest.psn = lrand48() & 0xffffff; +- if (!my_dest.lid) { +- fprintf(stderr, "Couldn't get local LID\n"); ++ if (pp_get_port_info(ctx->context, ib_port, &ctx->portinfo)) { ++ fprintf(stderr, "Couldn't get port info\n"); + return 1; + } ++ my_dest.lid = ctx->portinfo.lid; ++ ++ my_dest.qpn = ctx->qp->qp_num; ++ my_dest.psn = lrand48() & 0xffffff; ++ ++ if (gidx >= 0) { ++ if (ibv_query_gid(ctx->context, ib_port, gidx, &my_dest.gid)) { ++ fprintf(stderr, "Could not get local gid for gid index %d\n", gidx); ++ return 1; ++ } ++ } else ++ memset(&my_dest.gid, 0, sizeof my_dest.gid); + +- printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", +- my_dest.lid, my_dest.qpn, my_dest.psn); ++ inet_ntop(AF_INET6, &my_dest.gid, gid, sizeof gid); ++ printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x: GID %s\n", ++ my_dest.lid, my_dest.qpn, my_dest.psn, gid); + + if (servername) + rem_dest = pp_client_exch_dest(servername, port, &my_dest); + else +- rem_dest = pp_server_exch_dest(ctx, ib_port, port, sl, &my_dest); ++ rem_dest = pp_server_exch_dest(ctx, ib_port, port, sl, &my_dest, gidx); + + if (!rem_dest) + return 1; + +- printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x\n", +- rem_dest->lid, rem_dest->qpn, rem_dest->psn); ++ inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof gid); ++ printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", ++ rem_dest->lid, rem_dest->qpn, rem_dest->psn, gid); + + if (servername) +- if (pp_connect_ctx(ctx, ib_port, my_dest.psn, sl, rem_dest)) ++ if (pp_connect_ctx(ctx, ib_port, my_dest.psn, sl, rem_dest, gidx)) + return 1; + + ctx->pending = PINGPONG_RECV_WRID; diff --git a/contrib/ofed/libibverbs/fixes/rocee_get_mac.patch b/contrib/ofed/libibverbs/fixes/rocee_get_mac.patch new file mode 100644 index 000000000000..cd1198f25579 --- /dev/null +++ b/contrib/ofed/libibverbs/fixes/rocee_get_mac.patch @@ -0,0 +1,112 @@ +[PATCHv7 3/4] libibverbs: Add API to retrieve eth MAC + +Add a command to retrieve the MAC address of a port's GID. This is required by +libraries to build work requests when the port's link layer is Ethernet. + +Signed-off-by: Eli Cohen +--- + include/infiniband/driver.h | 1 + + include/infiniband/kern-abi.h | 20 +++++++++++++++++++- + src/cmd.c | 19 +++++++++++++++++++ + src/libibverbs.map | 1 + + 4 files changed, 40 insertions(+), 1 deletions(-) + +Index: libibverbs/include/infiniband/driver.h +=================================================================== +--- libibverbs.orig/include/infiniband/driver.h 2010-02-18 13:48:37.000000000 +0200 ++++ libibverbs/include/infiniband/driver.h 2010-02-18 13:50:53.000000000 +0200 +@@ -136,6 +136,11 @@ int ibv_cmd_create_ah(struct ibv_pd *pd, + int ibv_cmd_destroy_ah(struct ibv_ah *ah); + int ibv_cmd_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid); + int ibv_cmd_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid); ++int ibv_cmd_get_eth_l2_addr(struct ibv_pd *pd, uint8_t port, const union ibv_gid *gid, ++ int sgid_idx, uint8_t *mac, uint16_t *vlan_id); ++ ++int ibv_cmd_get_eth_l2_addr(struct ibv_pd *pd, uint8_t port, const union ibv_gid *gid, ++ int sgid_idx, uint8_t *mac, uint16_t *vlan_id); + + int ibv_dontfork_range(void *base, size_t size); + int ibv_dofork_range(void *base, size_t size); +Index: libibverbs/include/infiniband/kern-abi.h +=================================================================== +--- libibverbs.orig/include/infiniband/kern-abi.h 2010-02-18 13:48:46.000000000 +0200 ++++ libibverbs/include/infiniband/kern-abi.h 2010-02-18 13:50:53.000000000 +0200 +@@ -94,6 +94,7 @@ enum { + IB_USER_VERBS_CMD_QUERY_XRC_RCV_QP, + IB_USER_VERBS_CMD_REG_XRC_RCV_QP, + IB_USER_VERBS_CMD_UNREG_XRC_RCV_QP, ++ IB_USER_VERBS_CMD_GET_ETH_L2_ADDR, + }; + + /* +@@ -946,6 +947,7 @@ enum { + IB_USER_VERBS_CMD_QUERY_XRC_RCV_QP_V2 = -1, + IB_USER_VERBS_CMD_REG_XRC_RCV_QP_V2 = -1, + IB_USER_VERBS_CMD_UNREG_XRC_RCV_QP_V2 = -1, ++ IB_USER_VERBS_CMD_GET_ETH_L2_ADDR_V2 = -1, + }; + + struct ibv_destroy_cq_v1 { +@@ -1021,4 +1023,21 @@ struct ibv_create_srq_resp_v5 { + __u32 srq_handle; + }; + ++struct ibv_get_eth_l2_addr { ++ __u32 command; ++ __u16 in_words; ++ __u16 out_words; ++ __u64 response; ++ __u32 pd_handle; ++ __u8 port; ++ __u8 sgid_idx; ++ __u8 reserved[2]; ++ __u8 dgid[16]; ++}; ++ ++struct ibv_get_eth_l2_addr_resp { ++ __u8 mac[6]; ++ __u16 vlan_id; ++}; ++ + #endif /* KERN_ABI_H */ +Index: libibverbs/src/cmd.c +=================================================================== +--- libibverbs.orig/src/cmd.c 2010-02-18 13:48:46.000000000 +0200 ++++ libibverbs/src/cmd.c 2010-02-18 13:50:53.000000000 +0200 +@@ -1407,4 +1407,24 @@ int ibv_cmd_unreg_xrc_rcv_qp(struct ibv_ + return 0; + } + ++int ibv_cmd_get_eth_l2_addr(struct ibv_pd *pd, uint8_t port, const union ibv_gid *gid, ++ int sgid_idx, uint8_t *mac, uint16_t *vlan_id) ++{ ++ struct ibv_get_eth_l2_addr cmd; ++ struct ibv_get_eth_l2_addr_resp resp; ++ ++ IBV_INIT_CMD_RESP(&cmd, sizeof cmd, GET_ETH_L2_ADDR, &resp, sizeof resp); ++ memcpy(cmd.dgid, gid, sizeof cmd.dgid); ++ cmd.pd_handle = pd->handle; ++ cmd.port = port; ++ cmd.sgid_idx = sgid_idx; ++ ++ if (write(pd->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) ++ return errno; ++ ++ memcpy(mac, resp.mac, 6); ++ *vlan_id = resp.vlan_id; ++ ++ return 0; ++} + +Index: libibverbs/src/libibverbs.map +=================================================================== +--- libibverbs.orig/src/libibverbs.map 2010-02-18 13:48:37.000000000 +0200 ++++ libibverbs/src/libibverbs.map 2010-02-18 13:50:53.000000000 +0200 +@@ -64,6 +64,7 @@ IBVERBS_1.0 { + ibv_cmd_destroy_ah; + ibv_cmd_attach_mcast; + ibv_cmd_detach_mcast; ++ ibv_cmd_get_eth_l2_addr; + ibv_copy_qp_attr_from_kern; + ibv_copy_path_rec_from_kern; + ibv_copy_path_rec_to_kern; diff --git a/contrib/ofed/libibverbs/fixes/rocee_kernel_accept_link_layer.patch b/contrib/ofed/libibverbs/fixes/rocee_kernel_accept_link_layer.patch new file mode 100644 index 000000000000..02981f42aaf7 --- /dev/null +++ b/contrib/ofed/libibverbs/fixes/rocee_kernel_accept_link_layer.patch @@ -0,0 +1,50 @@ +[PATCHv7 2/4] libibverbs: change kernel API to accept link layer + +Modify the code to allow passing the link layer of a port from kernel to user. +Update ibv_query_port.3 man page with the change. + +Signed-off-by: Eli Cohen +--- + include/infiniband/kern-abi.h | 3 ++- + man/ibv_query_port.3 | 1 + + src/cmd.c | 1 + + 3 files changed, 4 insertions(+), 1 deletions(-) + +Index: libibverbs/include/infiniband/kern-abi.h +=================================================================== +--- libibverbs.orig/include/infiniband/kern-abi.h 2010-06-08 11:08:57.895171000 +0300 ++++ libibverbs/include/infiniband/kern-abi.h 2010-06-08 11:09:10.172540000 +0300 +@@ -231,7 +231,8 @@ struct ibv_query_port_resp { + __u8 active_width; + __u8 active_speed; + __u8 phys_state; +- __u8 reserved[3]; ++ __u8 link_layer; ++ __u8 reserved[2]; + }; + + struct ibv_alloc_pd { +Index: libibverbs/man/ibv_query_port.3 +=================================================================== +--- libibverbs.orig/man/ibv_query_port.3 2010-06-08 11:08:57.951172000 +0300 ++++ libibverbs/man/ibv_query_port.3 2010-06-08 11:09:10.177543000 +0300 +@@ -44,6 +44,7 @@ uint8_t init_type_reply; + uint8_t active_width; /* Currently active link width */ + uint8_t active_speed; /* Currently active link speed */ + uint8_t phys_state; /* Physical port state */ ++uint8_t link_layer; /* link layer protocol of the port */ + .in -8 + }; + .sp +Index: libibverbs/src/cmd.c +=================================================================== +--- libibverbs.orig/src/cmd.c 2010-06-08 11:08:57.999167000 +0300 ++++ libibverbs/src/cmd.c 2010-06-08 11:09:10.186539000 +0300 +@@ -196,6 +196,7 @@ int ibv_cmd_query_port(struct ibv_contex + port_attr->active_width = resp.active_width; + port_attr->active_speed = resp.active_speed; + port_attr->phys_state = resp.phys_state; ++ port_attr->link_layer = resp.link_layer; + + return 0; + } diff --git a/contrib/ofed/libibverbs/fixes/rocee_link_layer.patch b/contrib/ofed/libibverbs/fixes/rocee_link_layer.patch new file mode 100644 index 000000000000..226aaa3595d1 --- /dev/null +++ b/contrib/ofed/libibverbs/fixes/rocee_link_layer.patch @@ -0,0 +1,70 @@ +[PATCHv7 1/4] libibverbs: Add link layer field to ibv_port_attr + +This field can have one of the values - IBV_LINK_LAYER_UNSPECIFIED, +IBV_LINK_LAYER_INFINIBAND, IBV_LINK_LAYER_ETHERNET. It can be used by +applications to know the link layer used by the port, which can be either +Infiniband or Ethernet. The addition of the new field does not change the size +of struct ibv_port_attr due to alignment of the preceding field. Binary +compatibility is not compromised either since new apps with old libraries will +determine the link layer as IB while old applications with new a new library do +not read this field. + +Solution suggested by: + Roland Dreier + Jason Gunthorpe +Signed-off-by: Eli Cohen +--- + include/infiniband/verbs.h | 21 +++++++++++++++++++++ + 1 files changed, 21 insertions(+), 0 deletions(-) + +Index: libibverbs/include/infiniband/verbs.h +=================================================================== +--- libibverbs.orig/include/infiniband/verbs.h 2010-06-08 11:00:05.575721000 +0300 ++++ libibverbs/include/infiniband/verbs.h 2010-06-08 11:00:39.442737000 +0300 +@@ -162,6 +162,12 @@ enum ibv_port_state { + IBV_PORT_ACTIVE_DEFER = 5 + }; + ++enum { ++ IBV_LINK_LAYER_UNSPECIFIED, ++ IBV_LINK_LAYER_INFINIBAND, ++ IBV_LINK_LAYER_ETHERNET, ++}; ++ + struct ibv_port_attr { + enum ibv_port_state state; + enum ibv_mtu max_mtu; +@@ -182,6 +188,8 @@ struct ibv_port_attr { + uint8_t active_width; + uint8_t active_speed; + uint8_t phys_state; ++ uint8_t link_layer; ++ uint8_t pad; + }; + + enum ibv_event_type { +@@ -743,6 +751,16 @@ struct ibv_context { + struct ibv_more_ops *more_ops; + }; + ++static inline int ___ibv_query_port(struct ibv_context *context, ++ uint8_t port_num, ++ struct ibv_port_attr *port_attr) ++{ ++ port_attr->link_layer = IBV_LINK_LAYER_UNSPECIFIED; ++ port_attr->pad = 0; ++ ++ return context->ops.query_port(context, port_num, port_attr); ++} ++ + /** + * ibv_get_device_list - Get list of IB devices currently available + * @num_devices: optional. if non-NULL, set to the number of devices +@@ -1304,4 +1322,7 @@ END_C_DECLS + + # undef __attribute_const + ++#define ibv_query_port(context, port_num, port_attr) \ ++ ___ibv_query_port(context, port_num, port_attr) ++ + #endif /* INFINIBAND_VERBS_H */ diff --git a/contrib/ofed/libibverbs/fixes/rpm_spec_changelog_fix.patch b/contrib/ofed/libibverbs/fixes/rpm_spec_changelog_fix.patch new file mode 100644 index 000000000000..06eee7284aeb --- /dev/null +++ b/contrib/ofed/libibverbs/fixes/rpm_spec_changelog_fix.patch @@ -0,0 +1,13 @@ +diff --git a/libibverbs.spec.in b/libibverbs.spec.in +index d8cc4ee..daa3051 100644 +--- a/libibverbs.spec.in ++++ b/libibverbs.spec.in +@@ -85,7 +85,7 @@ rm -rf $RPM_BUILD_ROOT + %{_mandir}/man1/* + + %changelog +-* Thu Jun 3 Roland Dreier - 1.1.4-1 ++* Thu Jun 3 2010 Roland Dreier - 1.1.4-1 + - New upstream release + + * Thu Oct 29 2009 Roland Dreier - 1.1.3-1 diff --git a/contrib/ofed/libibverbs/fixes/series b/contrib/ofed/libibverbs/fixes/series new file mode 100644 index 000000000000..e3fa53afc644 --- /dev/null +++ b/contrib/ofed/libibverbs/fixes/series @@ -0,0 +1,14 @@ +verbs_man_page.patch +XRC_man_pages.patch +XRC_base_implementation.patch +XRC_RCV_QP.patch +pthread_cond_t_fields.patch +rocee_link_layer.patch +rocee_kernel_accept_link_layer.patch +rocee_get_mac.patch +rocee_examples.patch +qpt_raw_eth.patch +configure_in-AC_PROG_LIBTOOL-for-automake.patch +rpm_spec_changelog_fix.patch +iboe_adapt_new_api.patch +support_gid_change.patch diff --git a/contrib/ofed/libibverbs/fixes/verbs_man_page.patch b/contrib/ofed/libibverbs/fixes/verbs_man_page.patch new file mode 100644 index 000000000000..e2fa8041f22e --- /dev/null +++ b/contrib/ofed/libibverbs/fixes/verbs_man_page.patch @@ -0,0 +1,242 @@ +commit ebc306b0ad2a8a873a195b26ebafe704da001981 +Author: Dotan Barak +Date: Sun Feb 3 17:58:53 2008 +0200 + + libibverbs: Added the man page verbs.7 + + Added the man page verbs.7 which is an introduction to libibverbs man pages. + + Signed-off-by: Dotan Barak + Signed-off-by: Or Gerlitz + +Index: libibverbs/Makefile.am +=================================================================== +--- libibverbs.orig/Makefile.am 2010-06-07 18:38:19.088451000 +0300 ++++ libibverbs/Makefile.am 2010-06-08 10:58:10.061113000 +0300 +@@ -53,7 +53,7 @@ man_MANS = man/ibv_asyncwatch.1 man/ibv_ + man/ibv_post_srq_recv.3 man/ibv_query_device.3 man/ibv_query_gid.3 \ + man/ibv_query_pkey.3 man/ibv_query_port.3 man/ibv_query_qp.3 \ + man/ibv_query_srq.3 man/ibv_rate_to_mult.3 man/ibv_reg_mr.3 \ +- man/ibv_req_notify_cq.3 man/ibv_resize_cq.3 ++ man/ibv_req_notify_cq.3 man/ibv_resize_cq.3 man/verbs.7 + + DEBIAN = debian/changelog debian/compat debian/control debian/copyright \ + debian/ibverbs-utils.install debian/libibverbs1.install \ +Index: libibverbs/libibverbs.spec.in +=================================================================== +--- libibverbs.orig/libibverbs.spec.in 2010-06-08 10:47:13.106792000 +0300 ++++ libibverbs/libibverbs.spec.in 2010-06-08 10:58:10.160119000 +0300 +@@ -74,6 +74,7 @@ rm -rf $RPM_BUILD_ROOT + %{_libdir}/lib*.so + %{_includedir}/* + %{_mandir}/man3/* ++%{_mandir}/man7/* + + %files devel-static + %defattr(-,root,root,-) +Index: libibverbs/man/verbs.7 +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ libibverbs/man/verbs.7 2010-06-08 10:58:10.360115000 +0300 +@@ -0,0 +1,201 @@ ++.\" -*- nroff -*- ++.\" ++.TH VERBS 7 2008-01-17 libibverbs "Libibverbs Programmer's Manual" ++.SH "NAME" ++verbs \- Infiniband verbs library ++.SH "SYNOPSIS" ++.nf ++.B #include ++.fi ++.SH "DESCRIPTION" ++This library is an implementation of the verbs according to the Infiniband specification volume 1.2. It handles the control path of creating, modifying, querying and destroying resources such as Protection Domains (PD), Completion Queues (CQ), Queue-Pairs (QP), Shared Receive Queues (SRQ), Address Handles (AH), Memory Regions (MR). It also handles sending and receiving data posted to QPs and SRQs, getting completions from CQs using polling and completions events. ++ ++The control path is implemented through system calls to the uverbs kernel module which further calls the low level HW driver. The data path is implemented through calls made to low level HW library which in most cases interacts directly with the HW providing kernel and network stack bypass (saving context/mode switches) along with zero copy and an asynchronous I/O model. ++ ++ ++Typically, under network and RDMA programming, there are operations which involve interaction with remote peers (such as address resolution and connection establishment) and remote entities (such as route resolution and joining a multicast group under IB), where a resource managed through IB verbs such as QP or AH would be eventually created or effected from this interaction. In such cases, applications whose addressing semantics is based on IP can use librdmacm (see rdma_cm(7)) which works in conjunction with libibverbs. ++ ++This library is thread safe library and verbs can be called from every thread in the process (the same resource can even be handled from different threads, for example: ibv_poll_cq can be called from more than one thread). ++ ++However, it is up to the user to stop working with a resource after it was destroyed (by the same thread or by any other thread), this may result a segmentation fault. ++ ++If fork (or any other system call that perform fork directly or indirectly) is being used, please see ibv_fork_init(3). ++ ++.LP ++The following shall be declared as functions and may also be defined ++as macros. Function prototypes shall be provided. ++.RS ++.nf ++ ++\fB ++.B Library functions ++ ++int ibv_fork_init(void); ++ ++.B Device functions ++ ++struct ibv_device **ibv_get_device_list(int *num_devices); ++void ibv_free_device_list(struct ibv_device **list); ++const char *ibv_get_device_name(struct ibv_device *device); ++uint64_t ibv_get_device_guid(struct ibv_device *device); ++ ++.B Context functions ++ ++struct ibv_context *ibv_open_device(struct ibv_device *device); ++int ibv_close_device(struct ibv_context *context); ++ ++.B Queries ++ ++int ibv_query_device(struct ibv_context *context, ++ struct ibv_device_attr *device_attr); ++int ibv_query_port(struct ibv_context *context, uint8_t port_num, ++ struct ibv_port_attr *port_attr); ++int ibv_query_pkey(struct ibv_context *context, uint8_t port_num, ++ int index, uint16_t *pkey); ++int ibv_query_gid(struct ibv_context *context, uint8_t port_num, ++ int index, union ibv_gid *gid); ++ ++.B Asynchronous events ++ ++int ibv_get_async_event(struct ibv_context *context, ++ struct ibv_async_event *event); ++void ibv_ack_async_event(struct ibv_async_event *event); ++ ++.B Protection Domains ++ ++struct ibv_pd *ibv_alloc_pd(struct ibv_context *context); ++int ibv_dealloc_pd(struct ibv_pd *pd); ++ ++.B Memory Regions ++ ++struct ibv_mr *ibv_reg_mr(struct ibv_pd *pd, void *addr, ++ size_t length, enum ibv_access_flags access); ++int ibv_dereg_mr(struct ibv_mr *mr); ++ ++.B Address Handles ++ ++struct ibv_ah *ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr); ++int ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num, ++ struct ibv_wc *wc, struct ibv_grh *grh, ++ struct ibv_ah_attr *ah_attr); ++struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc, ++ struct ibv_grh *grh, uint8_t port_num); ++int ibv_destroy_ah(struct ibv_ah *ah); ++ ++.B Completion event channels ++ ++struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context *context); ++int ibv_destroy_comp_channel(struct ibv_comp_channel *channel); ++ ++.B Completion Queues Control ++ ++struct ibv_cq *ibv_create_cq(struct ibv_context *context, int cqe, ++ void *cq_context, ++ struct ibv_comp_channel *channel, ++ int comp_vector); ++int ibv_destroy_cq(struct ibv_cq *cq); ++int ibv_resize_cq(struct ibv_cq *cq, int cqe); ++ ++.B Reading Completions from CQ ++ ++int ibv_poll_cq(struct ibv_cq *cq, int num_entries, struct ibv_wc *wc); ++ ++.B Requesting / Managing CQ events ++ ++int ibv_req_notify_cq(struct ibv_cq *cq, int solicited_only); ++int ibv_get_cq_event(struct ibv_comp_channel *channel, ++ struct ibv_cq **cq, void **cq_context); ++void ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents); ++ ++.B Shared Receive Queue control ++ ++struct ibv_srq *ibv_create_srq(struct ibv_pd *pd, ++ struct ibv_srq_init_attr *srq_init_attr); ++int ibv_destroy_srq(struct ibv_srq *srq); ++int ibv_modify_srq(struct ibv_srq *srq, ++ struct ibv_srq_attr *srq_attr, ++ enum ibv_srq_attr_mask srq_attr_mask); ++int ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr); ++ ++.B Queue Pair control ++ ++struct ibv_qp *ibv_create_qp(struct ibv_pd *pd, ++ struct ibv_qp_init_attr *qp_init_attr); ++int ibv_destroy_qp(struct ibv_qp *qp); ++int ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, ++ enum ibv_qp_attr_mask attr_mask); ++int ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, ++ enum ibv_qp_attr_mask attr_mask, ++ struct ibv_qp_init_attr *init_attr); ++ ++.B posting Work Requests to QPs/SRQs ++int ibv_post_send(struct ibv_qp *qp, struct ibv_send_wr *wr, ++ struct ibv_send_wr **bad_wr); ++int ibv_post_recv(struct ibv_qp *qp, struct ibv_recv_wr *wr, ++ struct ibv_recv_wr **bad_wr); ++int ibv_post_srq_recv(struct ibv_srq *srq, ++ struct ibv_recv_wr *recv_wr, ++ struct ibv_recv_wr **bad_recv_wr); ++ ++.B Multicast group ++ ++int ibv_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid); ++int ibv_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid); ++ ++.B General functions ++ ++int ibv_rate_to_mult(enum ibv_rate rate); ++enum ibv_rate mult_to_ibv_rate(int mult); ++\fP ++.SH "SEE ALSO" ++.LP ++\fIibv_fork_init\fP(), ++\fIibv_get_device_list\fP(), ++\fIibv_free_device_list\fP(), ++\fIibv_get_device_name\fP(), ++\fIibv_get_device_guid\fP(), ++\fIibv_open_device\fP(), ++\fIibv_close_device\fP(), ++\fIibv_query_device\fP(), ++\fIibv_query_port\fP(), ++\fIibv_query_pkey\fP(), ++\fIibv_query_gid\fP(), ++\fIibv_get_async_event\fP(), ++\fIibv_ack_async_event\fP(), ++\fIibv_alloc_pd\fP(), ++\fIibv_dealloc_pd\fP(), ++\fIibv_reg_mr\fP(), ++\fIibv_dereg_mr\fP(), ++\fIibv_create_ah\fP(), ++\fIibv_init_ah_from_wc\fP(), ++\fIibv_create_ah_from_wc\fP(), ++\fIibv_destroy_ah\fP(), ++\fIibv_create_comp_channel\fP(), ++\fIibv_destroy_comp_channel\fP(), ++\fIibv_create_cq\fP(), ++\fIibv_destroy_cq\fP(), ++\fIibv_resize_cq\fP(), ++\fIibv_poll_cq\fP(), ++\fIibv_req_notify_cq\fP(), ++\fIibv_get_cq_event\fP(), ++\fIibv_ack_cq_events\fP(), ++\fIibv_create_srq\fP(), ++\fIibv_destroy_srq\fP(), ++\fIibv_modify_srq\fP(), ++\fIibv_query_srq\fP(), ++\fIibv_post_srq_recv\fP(), ++\fIibv_create_qp\fP(), ++\fIibv_destroy_qp\fP(), ++\fIibv_modify_qp\fP(), ++\fIibv_query_qp\fP(), ++\fIibv_post_send\fP(), ++\fIibv_post_recv\fP(), ++\fIibv_attach_mcast\fP(), ++\fIibv_detach_mcast\fP(), ++\fIibv_rate_to_mult\fP(), ++\fImult_to_ibv_rate\fP() ++.SH "AUTHORS" ++.TP ++Dotan Barak ++.TP ++Or Gerlitz diff --git a/contrib/ofed/libibverbs/include/infiniband/arch.h b/contrib/ofed/libibverbs/include/infiniband/arch.h new file mode 100644 index 000000000000..ce77fd55c394 --- /dev/null +++ b/contrib/ofed/libibverbs/include/infiniband/arch.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef INFINIBAND_ARCH_H +#define INFINIBAND_ARCH_H + +#include +#include +#include + +#if __BYTE_ORDER == __LITTLE_ENDIAN +static inline uint64_t htonll(uint64_t x) { return bswap_64(x); } +static inline uint64_t ntohll(uint64_t x) { return bswap_64(x); } +#elif __BYTE_ORDER == __BIG_ENDIAN +static inline uint64_t htonll(uint64_t x) { return x; } +static inline uint64_t ntohll(uint64_t x) { return x; } +#else +#error __BYTE_ORDER is neither __LITTLE_ENDIAN nor __BIG_ENDIAN +#endif + +/* + * Architecture-specific defines. Currently, an architecture is + * required to implement the following operations: + * + * mb() - memory barrier. No loads or stores may be reordered across + * this macro by either the compiler or the CPU. + * rmb() - read memory barrier. No loads may be reordered across this + * macro by either the compiler or the CPU. + * wmb() - write memory barrier. No stores may be reordered across + * this macro by either the compiler or the CPU. + * wc_wmb() - flush write combine buffers. No write-combined writes + * will be reordered across this macro by either the compiler or + * the CPU. + */ + +#if defined(__i386__) + +#define mb() asm volatile("lock; addl $0,0(%%esp) " ::: "memory") +#define rmb() mb() +#define wmb() asm volatile("" ::: "memory") +#define wc_wmb() mb() + +#elif defined(__x86_64__) + +/* + * Only use lfence for mb() and rmb() because we don't care about + * ordering against non-temporal stores (for now at least). + */ +#define mb() asm volatile("lfence" ::: "memory") +#define rmb() mb() +#define wmb() asm volatile("" ::: "memory") +#define wc_wmb() asm volatile("sfence" ::: "memory") + +#elif defined(__PPC64__) + +#define mb() asm volatile("sync" ::: "memory") +#define rmb() asm volatile("lwsync" ::: "memory") +#define wmb() mb() +#define wc_wmb() wmb() + +#elif defined(__ia64__) + +#define mb() asm volatile("mf" ::: "memory") +#define rmb() mb() +#define wmb() mb() +#define wc_wmb() asm volatile("fwb" ::: "memory") + +#elif defined(__PPC__) + +#define mb() asm volatile("sync" ::: "memory") +#define rmb() mb() +#define wmb() mb() +#define wc_wmb() wmb() + +#elif defined(__sparc_v9__) + +#define mb() asm volatile("membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad" ::: "memory") +#define rmb() asm volatile("membar #LoadLoad" ::: "memory") +#define wmb() asm volatile("membar #StoreStore" ::: "memory") +#define wc_wmb() wmb() + +#elif defined(__sparc__) + +#define mb() asm volatile("" ::: "memory") +#define rmb() mb() +#define wmb() mb() +#define wc_wmb() wmb() + +#else + +#warning No architecture specific defines found. Using generic implementation. + +#define mb() asm volatile("" ::: "memory") +#define rmb() mb() +#define wmb() mb() +#define wc_wmb() wmb() + +#endif + +#endif /* INFINIBAND_ARCH_H */ diff --git a/contrib/ofed/libibverbs/include/infiniband/driver.h b/contrib/ofed/libibverbs/include/infiniband/driver.h new file mode 100644 index 000000000000..593ac3c1cd6f --- /dev/null +++ b/contrib/ofed/libibverbs/include/infiniband/driver.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef INFINIBAND_DRIVER_H +#define INFINIBAND_DRIVER_H + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +/* + * Extension that low-level drivers should add to their .so filename + * (probably via libtool "-release" option). For example a low-level + * driver named "libfoo" should build a plug-in named "libfoo-rdmav2.so". + */ +#define IBV_DEVICE_LIBRARY_EXTENSION rdmav2 + +typedef struct ibv_device *(*ibv_driver_init_func)(const char *uverbs_sys_path, + int abi_version); + +void ibv_register_driver(const char *name, ibv_driver_init_func init_func); +int ibv_cmd_get_context(struct ibv_context *context, struct ibv_get_context *cmd, + size_t cmd_size, struct ibv_get_context_resp *resp, + size_t resp_size); +int ibv_cmd_query_device(struct ibv_context *context, + struct ibv_device_attr *device_attr, + uint64_t *raw_fw_ver, + struct ibv_query_device *cmd, size_t cmd_size); +int ibv_cmd_query_port(struct ibv_context *context, uint8_t port_num, + struct ibv_port_attr *port_attr, + struct ibv_query_port *cmd, size_t cmd_size); +int ibv_cmd_query_gid(struct ibv_context *context, uint8_t port_num, + int index, union ibv_gid *gid); +int ibv_cmd_query_pkey(struct ibv_context *context, uint8_t port_num, + int index, uint16_t *pkey); +int ibv_cmd_alloc_pd(struct ibv_context *context, struct ibv_pd *pd, + struct ibv_alloc_pd *cmd, size_t cmd_size, + struct ibv_alloc_pd_resp *resp, size_t resp_size); +int ibv_cmd_dealloc_pd(struct ibv_pd *pd); +#define IBV_CMD_REG_MR_HAS_RESP_PARAMS +int ibv_cmd_reg_mr(struct ibv_pd *pd, void *addr, size_t length, + uint64_t hca_va, int access, + struct ibv_mr *mr, struct ibv_reg_mr *cmd, + size_t cmd_size, + struct ibv_reg_mr_resp *resp, size_t resp_size); +int ibv_cmd_dereg_mr(struct ibv_mr *mr); +int ibv_cmd_create_cq(struct ibv_context *context, int cqe, + struct ibv_comp_channel *channel, + int comp_vector, struct ibv_cq *cq, + struct ibv_create_cq *cmd, size_t cmd_size, + struct ibv_create_cq_resp *resp, size_t resp_size); +int ibv_cmd_poll_cq(struct ibv_cq *cq, int ne, struct ibv_wc *wc); +int ibv_cmd_req_notify_cq(struct ibv_cq *cq, int solicited_only); +#define IBV_CMD_RESIZE_CQ_HAS_RESP_PARAMS +int ibv_cmd_resize_cq(struct ibv_cq *cq, int cqe, + struct ibv_resize_cq *cmd, size_t cmd_size, + struct ibv_resize_cq_resp *resp, size_t resp_size); +int ibv_cmd_destroy_cq(struct ibv_cq *cq); + +int ibv_cmd_create_srq(struct ibv_pd *pd, + struct ibv_srq *srq, struct ibv_srq_init_attr *attr, + struct ibv_create_srq *cmd, size_t cmd_size, + struct ibv_create_srq_resp *resp, size_t resp_size); +int ibv_cmd_create_xrc_srq(struct ibv_pd *pd, + struct ibv_srq *srq, struct ibv_srq_init_attr *attr, + uint32_t xrc_domain, uint32_t xrc_cq, + struct ibv_create_xrc_srq *cmd, size_t cmd_size, + struct ibv_create_srq_resp *resp, size_t resp_size); +int ibv_cmd_modify_srq(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + int srq_attr_mask, + struct ibv_modify_srq *cmd, size_t cmd_size); +int ibv_cmd_query_srq(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + struct ibv_query_srq *cmd, size_t cmd_size); +int ibv_cmd_destroy_srq(struct ibv_srq *srq); + +int ibv_cmd_create_qp(struct ibv_pd *pd, + struct ibv_qp *qp, struct ibv_qp_init_attr *attr, + struct ibv_create_qp *cmd, size_t cmd_size, + struct ibv_create_qp_resp *resp, size_t resp_size); +int ibv_cmd_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *qp_attr, + int attr_mask, + struct ibv_qp_init_attr *qp_init_attr, + struct ibv_query_qp *cmd, size_t cmd_size); +int ibv_cmd_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask, + struct ibv_modify_qp *cmd, size_t cmd_size); +int ibv_cmd_destroy_qp(struct ibv_qp *qp); +int ibv_cmd_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr, + struct ibv_send_wr **bad_wr); +int ibv_cmd_post_recv(struct ibv_qp *ibqp, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr); +int ibv_cmd_post_srq_recv(struct ibv_srq *srq, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr); +int ibv_cmd_create_ah(struct ibv_pd *pd, struct ibv_ah *ah, + struct ibv_ah_attr *attr); +int ibv_cmd_destroy_ah(struct ibv_ah *ah); +int ibv_cmd_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid); +int ibv_cmd_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid); + +int ibv_dontfork_range(void *base, size_t size); +int ibv_dofork_range(void *base, size_t size); +int ibv_cmd_open_xrc_domain(struct ibv_context *context, int fd, int oflag, + struct ibv_xrc_domain *d, + struct ibv_open_xrc_domain_resp *resp, + size_t resp_size); +int ibv_cmd_close_xrc_domain(struct ibv_xrc_domain *d); +int ibv_cmd_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, + uint32_t *xrc_rcv_qpn); +int ibv_cmd_modify_xrc_rcv_qp(struct ibv_xrc_domain *d, uint32_t xrc_rcv_qpn, + struct ibv_qp_attr *attr, int attr_mask); +int ibv_cmd_query_xrc_rcv_qp(struct ibv_xrc_domain *d, uint32_t xrc_rcv_qpn, + struct ibv_qp_attr *attr, int attr_mask, + struct ibv_qp_init_attr *init_attr); +int ibv_cmd_reg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num); +int ibv_cmd_unreg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num); + +/* + * sysfs helper functions + */ +const char *ibv_get_sysfs_path(void); + +int ibv_read_sysfs_file(const char *dir, const char *file, + char *buf, size_t size); + +int ibv_resolve_eth_gid(const struct ibv_pd *pd, uint8_t port_num, + union ibv_gid *dgid, uint8_t sgid_index, + uint8_t mac[], uint16_t *vlan, uint8_t *tagged, + uint8_t *is_mcast); + +#endif /* INFINIBAND_DRIVER_H */ diff --git a/contrib/ofed/libibverbs/include/infiniband/kern-abi.h b/contrib/ofed/libibverbs/include/infiniband/kern-abi.h new file mode 100644 index 000000000000..ee6f70070c9f --- /dev/null +++ b/contrib/ofed/libibverbs/include/infiniband/kern-abi.h @@ -0,0 +1,1024 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef KERN_ABI_H +#define KERN_ABI_H + +#include + +/* + * This file must be kept in sync with the kernel's version of + * drivers/infiniband/include/ib_user_verbs.h + */ + +/* + * The minimum and maximum kernel ABI that we can handle. + */ +#define IB_USER_VERBS_MIN_ABI_VERSION 1 +#define IB_USER_VERBS_MAX_ABI_VERSION 6 + +enum { + IB_USER_VERBS_CMD_GET_CONTEXT, + IB_USER_VERBS_CMD_QUERY_DEVICE, + IB_USER_VERBS_CMD_QUERY_PORT, + IB_USER_VERBS_CMD_ALLOC_PD, + IB_USER_VERBS_CMD_DEALLOC_PD, + IB_USER_VERBS_CMD_CREATE_AH, + IB_USER_VERBS_CMD_MODIFY_AH, + IB_USER_VERBS_CMD_QUERY_AH, + IB_USER_VERBS_CMD_DESTROY_AH, + IB_USER_VERBS_CMD_REG_MR, + IB_USER_VERBS_CMD_REG_SMR, + IB_USER_VERBS_CMD_REREG_MR, + IB_USER_VERBS_CMD_QUERY_MR, + IB_USER_VERBS_CMD_DEREG_MR, + IB_USER_VERBS_CMD_ALLOC_MW, + IB_USER_VERBS_CMD_BIND_MW, + IB_USER_VERBS_CMD_DEALLOC_MW, + IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL, + IB_USER_VERBS_CMD_CREATE_CQ, + IB_USER_VERBS_CMD_RESIZE_CQ, + IB_USER_VERBS_CMD_DESTROY_CQ, + IB_USER_VERBS_CMD_POLL_CQ, + IB_USER_VERBS_CMD_PEEK_CQ, + IB_USER_VERBS_CMD_REQ_NOTIFY_CQ, + IB_USER_VERBS_CMD_CREATE_QP, + IB_USER_VERBS_CMD_QUERY_QP, + IB_USER_VERBS_CMD_MODIFY_QP, + IB_USER_VERBS_CMD_DESTROY_QP, + IB_USER_VERBS_CMD_POST_SEND, + IB_USER_VERBS_CMD_POST_RECV, + IB_USER_VERBS_CMD_ATTACH_MCAST, + IB_USER_VERBS_CMD_DETACH_MCAST, + IB_USER_VERBS_CMD_CREATE_SRQ, + IB_USER_VERBS_CMD_MODIFY_SRQ, + IB_USER_VERBS_CMD_QUERY_SRQ, + IB_USER_VERBS_CMD_DESTROY_SRQ, + IB_USER_VERBS_CMD_POST_SRQ_RECV, + IB_USER_VERBS_CMD_CREATE_XRC_SRQ, + IB_USER_VERBS_CMD_OPEN_XRC_DOMAIN, + IB_USER_VERBS_CMD_CLOSE_XRC_DOMAIN, + IB_USER_VERBS_CMD_CREATE_XRC_RCV_QP, + IB_USER_VERBS_CMD_MODIFY_XRC_RCV_QP, + IB_USER_VERBS_CMD_QUERY_XRC_RCV_QP, + IB_USER_VERBS_CMD_REG_XRC_RCV_QP, + IB_USER_VERBS_CMD_UNREG_XRC_RCV_QP, +}; + +/* + * Make sure that all structs defined in this file remain laid out so + * that they pack the same way on 32-bit and 64-bit architectures (to + * avoid incompatibility between 32-bit userspace and 64-bit kernels). + * Specifically: + * - Do not use pointer types -- pass pointers in __u64 instead. + * - Make sure that any structure larger than 4 bytes is padded to a + * multiple of 8 bytes. Otherwise the structure size will be + * different between 32-bit and 64-bit architectures. + */ + +struct ibv_kern_async_event { + __u64 element; + __u32 event_type; + __u32 reserved; +}; + +struct ibv_comp_event { + __u64 cq_handle; +}; + +/* + * All commands from userspace should start with a __u32 command field + * followed by __u16 in_words and out_words fields (which give the + * length of the command block and response buffer if any in 32-bit + * words). The kernel driver will read these fields first and read + * the rest of the command struct based on these value. + */ + +struct ibv_query_params { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; +}; + +struct ibv_query_params_resp { + __u32 num_cq_events; +}; + +struct ibv_get_context { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u64 driver_data[0]; +}; + +struct ibv_get_context_resp { + __u32 async_fd; + __u32 num_comp_vectors; +}; + +struct ibv_query_device { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u64 driver_data[0]; +}; + +struct ibv_query_device_resp { + __u64 fw_ver; + __u64 node_guid; + __u64 sys_image_guid; + __u64 max_mr_size; + __u64 page_size_cap; + __u32 vendor_id; + __u32 vendor_part_id; + __u32 hw_ver; + __u32 max_qp; + __u32 max_qp_wr; + __u32 device_cap_flags; + __u32 max_sge; + __u32 max_sge_rd; + __u32 max_cq; + __u32 max_cqe; + __u32 max_mr; + __u32 max_pd; + __u32 max_qp_rd_atom; + __u32 max_ee_rd_atom; + __u32 max_res_rd_atom; + __u32 max_qp_init_rd_atom; + __u32 max_ee_init_rd_atom; + __u32 atomic_cap; + __u32 max_ee; + __u32 max_rdd; + __u32 max_mw; + __u32 max_raw_ipv6_qp; + __u32 max_raw_ethy_qp; + __u32 max_mcast_grp; + __u32 max_mcast_qp_attach; + __u32 max_total_mcast_qp_attach; + __u32 max_ah; + __u32 max_fmr; + __u32 max_map_per_fmr; + __u32 max_srq; + __u32 max_srq_wr; + __u32 max_srq_sge; + __u16 max_pkeys; + __u8 local_ca_ack_delay; + __u8 phys_port_cnt; + __u8 reserved[4]; +}; + +struct ibv_query_port { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u8 port_num; + __u8 reserved[7]; + __u64 driver_data[0]; +}; + +struct ibv_query_port_resp { + __u32 port_cap_flags; + __u32 max_msg_sz; + __u32 bad_pkey_cntr; + __u32 qkey_viol_cntr; + __u32 gid_tbl_len; + __u16 pkey_tbl_len; + __u16 lid; + __u16 sm_lid; + __u8 state; + __u8 max_mtu; + __u8 active_mtu; + __u8 lmc; + __u8 max_vl_num; + __u8 sm_sl; + __u8 subnet_timeout; + __u8 init_type_reply; + __u8 active_width; + __u8 active_speed; + __u8 phys_state; + __u8 link_layer; + __u8 reserved[2]; +}; + +struct ibv_alloc_pd { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u64 driver_data[0]; +}; + +struct ibv_alloc_pd_resp { + __u32 pd_handle; +}; + +struct ibv_dealloc_pd { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 pd_handle; +}; + +struct ibv_reg_mr { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u64 start; + __u64 length; + __u64 hca_va; + __u32 pd_handle; + __u32 access_flags; + __u64 driver_data[0]; +}; + +struct ibv_reg_mr_resp { + __u32 mr_handle; + __u32 lkey; + __u32 rkey; +}; + +struct ibv_dereg_mr { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 mr_handle; +}; + +struct ibv_create_comp_channel { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; +}; + +struct ibv_create_comp_channel_resp { + __u32 fd; +}; + +struct ibv_create_cq { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u64 user_handle; + __u32 cqe; + __u32 comp_vector; + __s32 comp_channel; + __u32 reserved; + __u64 driver_data[0]; +}; + +struct ibv_create_cq_resp { + __u32 cq_handle; + __u32 cqe; +}; + +struct ibv_kern_wc { + __u64 wr_id; + __u32 status; + __u32 opcode; + __u32 vendor_err; + __u32 byte_len; + __u32 imm_data; + __u32 qp_num; + __u32 src_qp; + __u32 wc_flags; + __u16 pkey_index; + __u16 slid; + __u8 sl; + __u8 dlid_path_bits; + __u8 port_num; + __u8 reserved; +}; + +struct ibv_poll_cq { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u32 cq_handle; + __u32 ne; +}; + +struct ibv_poll_cq_resp { + __u32 count; + __u32 reserved; + struct ibv_kern_wc wc[0]; +}; + +struct ibv_req_notify_cq { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 cq_handle; + __u32 solicited; +}; + +struct ibv_resize_cq { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u32 cq_handle; + __u32 cqe; + __u64 driver_data[0]; +}; + +struct ibv_resize_cq_resp { + __u32 cqe; + __u32 reserved; + __u64 driver_data[0]; +}; + +struct ibv_destroy_cq { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u32 cq_handle; + __u32 reserved; +}; + +struct ibv_destroy_cq_resp { + __u32 comp_events_reported; + __u32 async_events_reported; +}; + +struct ibv_kern_global_route { + __u8 dgid[16]; + __u32 flow_label; + __u8 sgid_index; + __u8 hop_limit; + __u8 traffic_class; + __u8 reserved; +}; + +struct ibv_kern_ah_attr { + struct ibv_kern_global_route grh; + __u16 dlid; + __u8 sl; + __u8 src_path_bits; + __u8 static_rate; + __u8 is_global; + __u8 port_num; + __u8 reserved; +}; + +struct ibv_kern_qp_attr { + __u32 qp_attr_mask; + __u32 qp_state; + __u32 cur_qp_state; + __u32 path_mtu; + __u32 path_mig_state; + __u32 qkey; + __u32 rq_psn; + __u32 sq_psn; + __u32 dest_qp_num; + __u32 qp_access_flags; + + struct ibv_kern_ah_attr ah_attr; + struct ibv_kern_ah_attr alt_ah_attr; + + /* ib_qp_cap */ + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_send_sge; + __u32 max_recv_sge; + __u32 max_inline_data; + + __u16 pkey_index; + __u16 alt_pkey_index; + __u8 en_sqd_async_notify; + __u8 sq_draining; + __u8 max_rd_atomic; + __u8 max_dest_rd_atomic; + __u8 min_rnr_timer; + __u8 port_num; + __u8 timeout; + __u8 retry_cnt; + __u8 rnr_retry; + __u8 alt_port_num; + __u8 alt_timeout; + __u8 reserved[5]; +}; + +struct ibv_create_qp { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u64 user_handle; + __u32 pd_handle; + __u32 send_cq_handle; + __u32 recv_cq_handle; + __u32 srq_handle; + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_send_sge; + __u32 max_recv_sge; + __u32 max_inline_data; + __u8 sq_sig_all; + __u8 qp_type; + __u8 is_srq; + __u8 reserved; + __u64 driver_data[0]; +}; + +struct ibv_create_qp_resp { + __u32 qp_handle; + __u32 qpn; + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_send_sge; + __u32 max_recv_sge; + __u32 max_inline_data; + __u32 reserved; +}; + +struct ibv_qp_dest { + __u8 dgid[16]; + __u32 flow_label; + __u16 dlid; + __u16 reserved; + __u8 sgid_index; + __u8 hop_limit; + __u8 traffic_class; + __u8 sl; + __u8 src_path_bits; + __u8 static_rate; + __u8 is_global; + __u8 port_num; +}; + +struct ibv_query_qp { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u32 qp_handle; + __u32 attr_mask; + __u64 driver_data[0]; +}; + +struct ibv_query_qp_resp { + struct ibv_qp_dest dest; + struct ibv_qp_dest alt_dest; + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_send_sge; + __u32 max_recv_sge; + __u32 max_inline_data; + __u32 qkey; + __u32 rq_psn; + __u32 sq_psn; + __u32 dest_qp_num; + __u32 qp_access_flags; + __u16 pkey_index; + __u16 alt_pkey_index; + __u8 qp_state; + __u8 cur_qp_state; + __u8 path_mtu; + __u8 path_mig_state; + __u8 sq_draining; + __u8 max_rd_atomic; + __u8 max_dest_rd_atomic; + __u8 min_rnr_timer; + __u8 port_num; + __u8 timeout; + __u8 retry_cnt; + __u8 rnr_retry; + __u8 alt_port_num; + __u8 alt_timeout; + __u8 sq_sig_all; + __u8 reserved[5]; + __u64 driver_data[0]; +}; + +struct ibv_modify_qp { + __u32 command; + __u16 in_words; + __u16 out_words; + struct ibv_qp_dest dest; + struct ibv_qp_dest alt_dest; + __u32 qp_handle; + __u32 attr_mask; + __u32 qkey; + __u32 rq_psn; + __u32 sq_psn; + __u32 dest_qp_num; + __u32 qp_access_flags; + __u16 pkey_index; + __u16 alt_pkey_index; + __u8 qp_state; + __u8 cur_qp_state; + __u8 path_mtu; + __u8 path_mig_state; + __u8 en_sqd_async_notify; + __u8 max_rd_atomic; + __u8 max_dest_rd_atomic; + __u8 min_rnr_timer; + __u8 port_num; + __u8 timeout; + __u8 retry_cnt; + __u8 rnr_retry; + __u8 alt_port_num; + __u8 alt_timeout; + __u8 reserved[2]; + __u64 driver_data[0]; +}; + +struct ibv_destroy_qp { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u32 qp_handle; + __u32 reserved; +}; + +struct ibv_destroy_qp_resp { + __u32 events_reported; +}; + +struct ibv_create_xrc_rcv_qp { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u64 user_handle; + __u32 xrc_domain_handle; + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_send_sge; + __u32 max_recv_sge; + __u32 max_inline_data; + __u8 sq_sig_all; + __u8 qp_type; + __u8 reserved[6]; + __u64 driver_data[0]; +}; + +struct ibv_create_xrc_rcv_qp_resp { + __u32 qpn; + __u32 reserved; +}; + +struct ibv_modify_xrc_rcv_qp { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 xrc_domain_handle; + __u32 qp_num; + struct ibv_qp_dest dest; + struct ibv_qp_dest alt_dest; + __u32 attr_mask; + __u32 qkey; + __u32 rq_psn; + __u32 sq_psn; + __u32 dest_qp_num; + __u32 qp_access_flags; + __u16 pkey_index; + __u16 alt_pkey_index; + __u8 qp_state; + __u8 cur_qp_state; + __u8 path_mtu; + __u8 path_mig_state; + __u8 en_sqd_async_notify; + __u8 max_rd_atomic; + __u8 max_dest_rd_atomic; + __u8 min_rnr_timer; + __u8 port_num; + __u8 timeout; + __u8 retry_cnt; + __u8 rnr_retry; + __u8 alt_port_num; + __u8 alt_timeout; + __u8 reserved[6]; + __u64 driver_data[0]; +}; + +struct ibv_query_xrc_rcv_qp { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u32 xrc_domain_handle; + __u32 qp_num; + __u32 attr_mask; + __u32 reserved; + __u64 driver_data[0]; +}; + +struct ibv_reg_xrc_rcv_qp { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 xrc_domain_handle; + __u32 qp_num; + __u64 driver_data[0]; +}; + +struct ibv_unreg_xrc_rcv_qp { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 xrc_domain_handle; + __u32 qp_num; + __u64 driver_data[0]; +}; + +struct ibv_kern_send_wr { + __u64 wr_id; + __u32 num_sge; + __u32 opcode; + __u32 send_flags; + __u32 imm_data; + union { + struct { + __u64 remote_addr; + __u32 rkey; + __u32 reserved; + } rdma; + struct { + __u64 remote_addr; + __u64 compare_add; + __u64 swap; + __u32 rkey; + __u32 reserved; + } atomic; + struct { + __u32 ah; + __u32 remote_qpn; + __u32 remote_qkey; + __u32 reserved; + } ud; + } wr; +}; + +struct ibv_post_send { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u32 qp_handle; + __u32 wr_count; + __u32 sge_count; + __u32 wqe_size; + struct ibv_kern_send_wr send_wr[0]; +}; + +struct ibv_post_send_resp { + __u32 bad_wr; +}; + +struct ibv_kern_recv_wr { + __u64 wr_id; + __u32 num_sge; + __u32 reserved; +}; + +struct ibv_post_recv { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u32 qp_handle; + __u32 wr_count; + __u32 sge_count; + __u32 wqe_size; + struct ibv_kern_recv_wr recv_wr[0]; +}; + +struct ibv_post_recv_resp { + __u32 bad_wr; +}; + +struct ibv_post_srq_recv { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u32 srq_handle; + __u32 wr_count; + __u32 sge_count; + __u32 wqe_size; + struct ibv_kern_recv_wr recv_wr[0]; +}; + +struct ibv_post_srq_recv_resp { + __u32 bad_wr; +}; + +struct ibv_create_ah { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u64 user_handle; + __u32 pd_handle; + __u32 reserved; + struct ibv_kern_ah_attr attr; +}; + +struct ibv_create_ah_resp { + __u32 handle; +}; + +struct ibv_destroy_ah { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 ah_handle; +}; + +struct ibv_attach_mcast { + __u32 command; + __u16 in_words; + __u16 out_words; + __u8 gid[16]; + __u32 qp_handle; + __u16 mlid; + __u16 reserved; + __u64 driver_data[0]; +}; + +struct ibv_detach_mcast { + __u32 command; + __u16 in_words; + __u16 out_words; + __u8 gid[16]; + __u32 qp_handle; + __u16 mlid; + __u16 reserved; + __u64 driver_data[0]; +}; + +struct ibv_create_srq { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u64 user_handle; + __u32 pd_handle; + __u32 max_wr; + __u32 max_sge; + __u32 srq_limit; + __u64 driver_data[0]; +}; + +struct ibv_create_xrc_srq { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u64 user_handle; + __u32 pd_handle; + __u32 max_wr; + __u32 max_sge; + __u32 srq_limit; + __u32 xrcd_handle; + __u32 xrc_cq; + __u64 driver_data[0]; +}; + +struct ibv_create_srq_resp { + __u32 srq_handle; + __u32 max_wr; + __u32 max_sge; + __u32 reserved; +}; + +struct ibv_modify_srq { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 srq_handle; + __u32 attr_mask; + __u32 max_wr; + __u32 srq_limit; + __u64 driver_data[0]; +}; + +struct ibv_query_srq { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u32 srq_handle; + __u32 reserved; + __u64 driver_data[0]; +}; + +struct ibv_query_srq_resp { + __u32 max_wr; + __u32 max_sge; + __u32 srq_limit; + __u32 reserved; +}; + +struct ibv_destroy_srq { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u32 srq_handle; + __u32 reserved; +}; + +struct ibv_destroy_srq_resp { + __u32 events_reported; +}; + +struct ibv_open_xrc_domain { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u32 fd; + __u32 oflags; + __u64 driver_data[0]; +}; + +struct ibv_open_xrc_domain_resp { + __u32 xrcd_handle; +}; + +struct ibv_close_xrc_domain { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u32 xrcd_handle; + __u32 reserved; + __u64 driver_data[0]; +}; + +/* + * Compatibility with older ABI versions + */ + +enum { + IB_USER_VERBS_CMD_QUERY_PARAMS_V2, + IB_USER_VERBS_CMD_GET_CONTEXT_V2, + IB_USER_VERBS_CMD_QUERY_DEVICE_V2, + IB_USER_VERBS_CMD_QUERY_PORT_V2, + IB_USER_VERBS_CMD_QUERY_GID_V2, + IB_USER_VERBS_CMD_QUERY_PKEY_V2, + IB_USER_VERBS_CMD_ALLOC_PD_V2, + IB_USER_VERBS_CMD_DEALLOC_PD_V2, + IB_USER_VERBS_CMD_CREATE_AH_V2, + IB_USER_VERBS_CMD_MODIFY_AH_V2, + IB_USER_VERBS_CMD_QUERY_AH_V2, + IB_USER_VERBS_CMD_DESTROY_AH_V2, + IB_USER_VERBS_CMD_REG_MR_V2, + IB_USER_VERBS_CMD_REG_SMR_V2, + IB_USER_VERBS_CMD_REREG_MR_V2, + IB_USER_VERBS_CMD_QUERY_MR_V2, + IB_USER_VERBS_CMD_DEREG_MR_V2, + IB_USER_VERBS_CMD_ALLOC_MW_V2, + IB_USER_VERBS_CMD_BIND_MW_V2, + IB_USER_VERBS_CMD_DEALLOC_MW_V2, + IB_USER_VERBS_CMD_CREATE_CQ_V2, + IB_USER_VERBS_CMD_RESIZE_CQ_V2, + IB_USER_VERBS_CMD_DESTROY_CQ_V2, + IB_USER_VERBS_CMD_POLL_CQ_V2, + IB_USER_VERBS_CMD_PEEK_CQ_V2, + IB_USER_VERBS_CMD_REQ_NOTIFY_CQ_V2, + IB_USER_VERBS_CMD_CREATE_QP_V2, + IB_USER_VERBS_CMD_QUERY_QP_V2, + IB_USER_VERBS_CMD_MODIFY_QP_V2, + IB_USER_VERBS_CMD_DESTROY_QP_V2, + IB_USER_VERBS_CMD_POST_SEND_V2, + IB_USER_VERBS_CMD_POST_RECV_V2, + IB_USER_VERBS_CMD_ATTACH_MCAST_V2, + IB_USER_VERBS_CMD_DETACH_MCAST_V2, + IB_USER_VERBS_CMD_CREATE_SRQ_V2, + IB_USER_VERBS_CMD_MODIFY_SRQ_V2, + IB_USER_VERBS_CMD_QUERY_SRQ_V2, + IB_USER_VERBS_CMD_DESTROY_SRQ_V2, + IB_USER_VERBS_CMD_POST_SRQ_RECV_V2, + /* + * Set commands that didn't exist to -1 so our compile-time + * trick opcodes in IBV_INIT_CMD() doesn't break. + */ + IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL_V2 = -1, + IB_USER_VERBS_CMD_CREATE_XRC_SRQ_V2 = -1, + IB_USER_VERBS_CMD_OPEN_XRC_DOMAIN_V2 = -1, + IB_USER_VERBS_CMD_CLOSE_XRC_DOMAIN_V2 = -1, + IB_USER_VERBS_CMD_CREATE_XRC_RCV_QP_V2 = -1, + IB_USER_VERBS_CMD_MODIFY_XRC_RCV_QP_V2 = -1, + IB_USER_VERBS_CMD_QUERY_XRC_RCV_QP_V2 = -1, + IB_USER_VERBS_CMD_REG_XRC_RCV_QP_V2 = -1, + IB_USER_VERBS_CMD_UNREG_XRC_RCV_QP_V2 = -1, +}; + +struct ibv_destroy_cq_v1 { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 cq_handle; +}; + +struct ibv_destroy_qp_v1 { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 qp_handle; +}; + +struct ibv_destroy_srq_v1 { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 srq_handle; +}; + +struct ibv_get_context_v2 { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u64 cq_fd_tab; + __u64 driver_data[0]; +}; + +struct ibv_create_cq_v2 { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; + __u64 user_handle; + __u32 cqe; + __u32 event_handler; + __u64 driver_data[0]; +}; + +struct ibv_modify_srq_v3 { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 srq_handle; + __u32 attr_mask; + __u32 max_wr; + __u32 max_sge; + __u32 srq_limit; + __u32 reserved; + __u64 driver_data[0]; +}; + +struct ibv_create_qp_resp_v3 { + __u32 qp_handle; + __u32 qpn; +}; + +struct ibv_create_qp_resp_v4 { + __u32 qp_handle; + __u32 qpn; + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_send_sge; + __u32 max_recv_sge; + __u32 max_inline_data; +}; + +struct ibv_create_srq_resp_v5 { + __u32 srq_handle; +}; + +#endif /* KERN_ABI_H */ diff --git a/contrib/ofed/libibverbs/include/infiniband/marshall.h b/contrib/ofed/libibverbs/include/infiniband/marshall.h new file mode 100644 index 000000000000..8be76c5444d2 --- /dev/null +++ b/contrib/ofed/libibverbs/include/infiniband/marshall.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef INFINIBAND_MARSHALL_H +#define INFINIBAND_MARSHALL_H + +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +void ibv_copy_qp_attr_from_kern(struct ibv_qp_attr *dst, + struct ibv_kern_qp_attr *src); + +void ibv_copy_ah_attr_from_kern(struct ibv_ah_attr *dst, + struct ibv_kern_ah_attr *src); + +void ibv_copy_path_rec_from_kern(struct ibv_sa_path_rec *dst, + struct ibv_kern_path_rec *src); + +void ibv_copy_path_rec_to_kern(struct ibv_kern_path_rec *dst, + struct ibv_sa_path_rec *src); + +END_C_DECLS + +#endif /* INFINIBAND_MARSHALL_H */ diff --git a/contrib/ofed/libibverbs/include/infiniband/opcode.h b/contrib/ofed/libibverbs/include/infiniband/opcode.h new file mode 100644 index 000000000000..fd4bc96a2c96 --- /dev/null +++ b/contrib/ofed/libibverbs/include/infiniband/opcode.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef INFINIBAND_OPCODE_H +#define INFINIBAND_OPCODE_H + +/* + * This macro cleans up the definitions of constants for BTH opcodes. + * It is used to define constants such as IBV_OPCODE_UD_SEND_ONLY, + * which becomes IBV_OPCODE_UD + IBV_OPCODE_SEND_ONLY, and this gives + * the correct value. + * + * In short, user code should use the constants defined using the + * macro rather than worrying about adding together other constants. +*/ +#define IBV_OPCODE(transport, op) \ + IBV_OPCODE_ ## transport ## _ ## op = \ + IBV_OPCODE_ ## transport + IBV_OPCODE_ ## op + +enum { + /* transport types -- just used to define real constants */ + IBV_OPCODE_RC = 0x00, + IBV_OPCODE_UC = 0x20, + IBV_OPCODE_RD = 0x40, + IBV_OPCODE_UD = 0x60, + + /* operations -- just used to define real constants */ + IBV_OPCODE_SEND_FIRST = 0x00, + IBV_OPCODE_SEND_MIDDLE = 0x01, + IBV_OPCODE_SEND_LAST = 0x02, + IBV_OPCODE_SEND_LAST_WITH_IMMEDIATE = 0x03, + IBV_OPCODE_SEND_ONLY = 0x04, + IBV_OPCODE_SEND_ONLY_WITH_IMMEDIATE = 0x05, + IBV_OPCODE_RDMA_WRITE_FIRST = 0x06, + IBV_OPCODE_RDMA_WRITE_MIDDLE = 0x07, + IBV_OPCODE_RDMA_WRITE_LAST = 0x08, + IBV_OPCODE_RDMA_WRITE_LAST_WITH_IMMEDIATE = 0x09, + IBV_OPCODE_RDMA_WRITE_ONLY = 0x0a, + IBV_OPCODE_RDMA_WRITE_ONLY_WITH_IMMEDIATE = 0x0b, + IBV_OPCODE_RDMA_READ_REQUEST = 0x0c, + IBV_OPCODE_RDMA_READ_RESPONSE_FIRST = 0x0d, + IBV_OPCODE_RDMA_READ_RESPONSE_MIDDLE = 0x0e, + IBV_OPCODE_RDMA_READ_RESPONSE_LAST = 0x0f, + IBV_OPCODE_RDMA_READ_RESPONSE_ONLY = 0x10, + IBV_OPCODE_ACKNOWLEDGE = 0x11, + IBV_OPCODE_ATOMIC_ACKNOWLEDGE = 0x12, + IBV_OPCODE_COMPARE_SWAP = 0x13, + IBV_OPCODE_FETCH_ADD = 0x14, + + /* real constants follow -- see comment about above IBV_OPCODE() + macro for more details */ + + /* RC */ + IBV_OPCODE(RC, SEND_FIRST), + IBV_OPCODE(RC, SEND_MIDDLE), + IBV_OPCODE(RC, SEND_LAST), + IBV_OPCODE(RC, SEND_LAST_WITH_IMMEDIATE), + IBV_OPCODE(RC, SEND_ONLY), + IBV_OPCODE(RC, SEND_ONLY_WITH_IMMEDIATE), + IBV_OPCODE(RC, RDMA_WRITE_FIRST), + IBV_OPCODE(RC, RDMA_WRITE_MIDDLE), + IBV_OPCODE(RC, RDMA_WRITE_LAST), + IBV_OPCODE(RC, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IBV_OPCODE(RC, RDMA_WRITE_ONLY), + IBV_OPCODE(RC, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + IBV_OPCODE(RC, RDMA_READ_REQUEST), + IBV_OPCODE(RC, RDMA_READ_RESPONSE_FIRST), + IBV_OPCODE(RC, RDMA_READ_RESPONSE_MIDDLE), + IBV_OPCODE(RC, RDMA_READ_RESPONSE_LAST), + IBV_OPCODE(RC, RDMA_READ_RESPONSE_ONLY), + IBV_OPCODE(RC, ACKNOWLEDGE), + IBV_OPCODE(RC, ATOMIC_ACKNOWLEDGE), + IBV_OPCODE(RC, COMPARE_SWAP), + IBV_OPCODE(RC, FETCH_ADD), + + /* UC */ + IBV_OPCODE(UC, SEND_FIRST), + IBV_OPCODE(UC, SEND_MIDDLE), + IBV_OPCODE(UC, SEND_LAST), + IBV_OPCODE(UC, SEND_LAST_WITH_IMMEDIATE), + IBV_OPCODE(UC, SEND_ONLY), + IBV_OPCODE(UC, SEND_ONLY_WITH_IMMEDIATE), + IBV_OPCODE(UC, RDMA_WRITE_FIRST), + IBV_OPCODE(UC, RDMA_WRITE_MIDDLE), + IBV_OPCODE(UC, RDMA_WRITE_LAST), + IBV_OPCODE(UC, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IBV_OPCODE(UC, RDMA_WRITE_ONLY), + IBV_OPCODE(UC, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + + /* RD */ + IBV_OPCODE(RD, SEND_FIRST), + IBV_OPCODE(RD, SEND_MIDDLE), + IBV_OPCODE(RD, SEND_LAST), + IBV_OPCODE(RD, SEND_LAST_WITH_IMMEDIATE), + IBV_OPCODE(RD, SEND_ONLY), + IBV_OPCODE(RD, SEND_ONLY_WITH_IMMEDIATE), + IBV_OPCODE(RD, RDMA_WRITE_FIRST), + IBV_OPCODE(RD, RDMA_WRITE_MIDDLE), + IBV_OPCODE(RD, RDMA_WRITE_LAST), + IBV_OPCODE(RD, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IBV_OPCODE(RD, RDMA_WRITE_ONLY), + IBV_OPCODE(RD, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + IBV_OPCODE(RD, RDMA_READ_REQUEST), + IBV_OPCODE(RD, RDMA_READ_RESPONSE_FIRST), + IBV_OPCODE(RD, RDMA_READ_RESPONSE_MIDDLE), + IBV_OPCODE(RD, RDMA_READ_RESPONSE_LAST), + IBV_OPCODE(RD, RDMA_READ_RESPONSE_ONLY), + IBV_OPCODE(RD, ACKNOWLEDGE), + IBV_OPCODE(RD, ATOMIC_ACKNOWLEDGE), + IBV_OPCODE(RD, COMPARE_SWAP), + IBV_OPCODE(RD, FETCH_ADD), + + /* UD */ + IBV_OPCODE(UD, SEND_ONLY), + IBV_OPCODE(UD, SEND_ONLY_WITH_IMMEDIATE) +}; + +#endif /* INFINIBAND_OPCODE_H */ diff --git a/contrib/ofed/libibverbs/include/infiniband/sa-kern-abi.h b/contrib/ofed/libibverbs/include/infiniband/sa-kern-abi.h new file mode 100644 index 000000000000..3faa52a60d25 --- /dev/null +++ b/contrib/ofed/libibverbs/include/infiniband/sa-kern-abi.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef INFINIBAND_SA_KERN_ABI_H +#define INFINIBAND_SA_KERN_ABI_H + +#include + +/* + * Obsolete, deprecated names. Will be removed in libibverbs 1.1. + */ +#define ib_kern_path_rec ibv_kern_path_rec + +struct ibv_kern_path_rec { + __u8 dgid[16]; + __u8 sgid[16]; + __u16 dlid; + __u16 slid; + __u32 raw_traffic; + __u32 flow_label; + __u32 reversible; + __u32 mtu; + __u16 pkey; + __u8 hop_limit; + __u8 traffic_class; + __u8 numb_path; + __u8 sl; + __u8 mtu_selector; + __u8 rate_selector; + __u8 rate; + __u8 packet_life_time_selector; + __u8 packet_life_time; + __u8 preference; +}; + +#endif /* INFINIBAND_SA_KERN_ABI_H */ diff --git a/contrib/ofed/libibverbs/include/infiniband/sa.h b/contrib/ofed/libibverbs/include/infiniband/sa.h new file mode 100644 index 000000000000..1153e94306c8 --- /dev/null +++ b/contrib/ofed/libibverbs/include/infiniband/sa.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef INFINIBAND_SA_H +#define INFINIBAND_SA_H + +#include + +struct ibv_sa_path_rec { + /* reserved */ + /* reserved */ + union ibv_gid dgid; + union ibv_gid sgid; + uint16_t dlid; + uint16_t slid; + int raw_traffic; + /* reserved */ + uint32_t flow_label; + uint8_t hop_limit; + uint8_t traffic_class; + int reversible; + uint8_t numb_path; + uint16_t pkey; + /* reserved */ + uint8_t sl; + uint8_t mtu_selector; + uint8_t mtu; + uint8_t rate_selector; + uint8_t rate; + uint8_t packet_life_time_selector; + uint8_t packet_life_time; + uint8_t preference; +}; + +struct ibv_sa_mcmember_rec { + union ibv_gid mgid; + union ibv_gid port_gid; + uint32_t qkey; + uint16_t mlid; + uint8_t mtu_selector; + uint8_t mtu; + uint8_t traffic_class; + uint16_t pkey; + uint8_t rate_selector; + uint8_t rate; + uint8_t packet_life_time_selector; + uint8_t packet_life_time; + uint8_t sl; + uint32_t flow_label; + uint8_t hop_limit; + uint8_t scope; + uint8_t join_state; + int proxy_join; +}; + +struct ibv_sa_service_rec { + uint64_t id; + union ibv_gid gid; + uint16_t pkey; + /* uint16_t resv; */ + uint32_t lease; + uint8_t key[16]; + uint8_t name[64]; + uint8_t data8[16]; + uint16_t data16[8]; + uint32_t data32[4]; + uint64_t data64[2]; +}; + +#define IBV_PATH_RECORD_REVERSIBLE 0x80 + +struct ibv_path_record { + uint64_t service_id; + union ibv_gid dgid; + union ibv_gid sgid; + uint16_t dlid; + uint16_t slid; + uint32_t flowlabel_hoplimit; /* resv-31:28 flow label-27:8 hop limit-7:0*/ + uint8_t tclass; + uint8_t reversible_numpath; /* reversible-7:7 num path-6:0 */ + uint16_t pkey; + uint16_t qosclass_sl; /* qos class-15:4 sl-3:0 */ + uint8_t mtu; /* mtu selector-7:6 mtu-5:0 */ + uint8_t rate; /* rate selector-7:6 rate-5:0 */ + uint8_t packetlifetime; /* lifetime selector-7:6 lifetime-5:0 */ + uint8_t preference; + uint8_t reserved[6]; +}; + +#define IBV_PATH_FLAG_GMP (1<<0) +#define IBV_PATH_FLAG_PRIMARY (1<<1) +#define IBV_PATH_FLAG_ALTERNATE (1<<2) +#define IBV_PATH_FLAG_OUTBOUND (1<<3) +#define IBV_PATH_FLAG_INBOUND (1<<4) +#define IBV_PATH_FLAG_INBOUND_REVERSE (1<<5) +#define IBV_PATH_FLAG_BIDIRECTIONAL (IBV_PATH_FLAG_OUTBOUND | \ + IBV_PATH_FLAG_INBOUND_REVERSE) + +struct ibv_path_data { + uint32_t flags; + uint32_t reserved; + struct ibv_path_record path; +}; + +#endif /* INFINIBAND_SA_H */ diff --git a/contrib/ofed/libibverbs/include/infiniband/verbs.h b/contrib/ofed/libibverbs/include/infiniband/verbs.h new file mode 100644 index 000000000000..929e4009dceb --- /dev/null +++ b/contrib/ofed/libibverbs/include/infiniband/verbs.h @@ -0,0 +1,1330 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef INFINIBAND_VERBS_H +#define INFINIBAND_VERBS_H + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +#if __GNUC__ >= 3 +# define __attribute_const __attribute__((const)) +#else +# define __attribute_const +#endif + +BEGIN_C_DECLS + +union ibv_gid { + uint8_t raw[16]; + struct { + uint64_t subnet_prefix; + uint64_t interface_id; + } global; +}; + +enum ibv_node_type { + IBV_NODE_UNKNOWN = -1, + IBV_NODE_CA = 1, + IBV_NODE_SWITCH, + IBV_NODE_ROUTER, + IBV_NODE_RNIC +}; + +enum ibv_transport_type { + IBV_TRANSPORT_UNKNOWN = -1, + IBV_TRANSPORT_IB = 0, + IBV_TRANSPORT_IWARP +}; + +enum ibv_device_cap_flags { + IBV_DEVICE_RESIZE_MAX_WR = 1, + IBV_DEVICE_BAD_PKEY_CNTR = 1 << 1, + IBV_DEVICE_BAD_QKEY_CNTR = 1 << 2, + IBV_DEVICE_RAW_MULTI = 1 << 3, + IBV_DEVICE_AUTO_PATH_MIG = 1 << 4, + IBV_DEVICE_CHANGE_PHY_PORT = 1 << 5, + IBV_DEVICE_UD_AV_PORT_ENFORCE = 1 << 6, + IBV_DEVICE_CURR_QP_STATE_MOD = 1 << 7, + IBV_DEVICE_SHUTDOWN_PORT = 1 << 8, + IBV_DEVICE_INIT_TYPE = 1 << 9, + IBV_DEVICE_PORT_ACTIVE_EVENT = 1 << 10, + IBV_DEVICE_SYS_IMAGE_GUID = 1 << 11, + IBV_DEVICE_RC_RNR_NAK_GEN = 1 << 12, + IBV_DEVICE_SRQ_RESIZE = 1 << 13, + IBV_DEVICE_N_NOTIFY_CQ = 1 << 14, + IBV_DEVICE_XRC = 1 << 20 +}; + +enum ibv_atomic_cap { + IBV_ATOMIC_NONE, + IBV_ATOMIC_HCA, + IBV_ATOMIC_GLOB +}; + +struct ibv_device_attr { + char fw_ver[64]; + uint64_t node_guid; + uint64_t sys_image_guid; + uint64_t max_mr_size; + uint64_t page_size_cap; + uint32_t vendor_id; + uint32_t vendor_part_id; + uint32_t hw_ver; + int max_qp; + int max_qp_wr; + int device_cap_flags; + int max_sge; + int max_sge_rd; + int max_cq; + int max_cqe; + int max_mr; + int max_pd; + int max_qp_rd_atom; + int max_ee_rd_atom; + int max_res_rd_atom; + int max_qp_init_rd_atom; + int max_ee_init_rd_atom; + enum ibv_atomic_cap atomic_cap; + int max_ee; + int max_rdd; + int max_mw; + int max_raw_ipv6_qp; + int max_raw_ethy_qp; + int max_mcast_grp; + int max_mcast_qp_attach; + int max_total_mcast_qp_attach; + int max_ah; + int max_fmr; + int max_map_per_fmr; + int max_srq; + int max_srq_wr; + int max_srq_sge; + uint16_t max_pkeys; + uint8_t local_ca_ack_delay; + uint8_t phys_port_cnt; +}; + +enum ibv_mtu { + IBV_MTU_256 = 1, + IBV_MTU_512 = 2, + IBV_MTU_1024 = 3, + IBV_MTU_2048 = 4, + IBV_MTU_4096 = 5 +}; + +enum ibv_port_state { + IBV_PORT_NOP = 0, + IBV_PORT_DOWN = 1, + IBV_PORT_INIT = 2, + IBV_PORT_ARMED = 3, + IBV_PORT_ACTIVE = 4, + IBV_PORT_ACTIVE_DEFER = 5 +}; + +enum { + IBV_LINK_LAYER_UNSPECIFIED, + IBV_LINK_LAYER_INFINIBAND, + IBV_LINK_LAYER_ETHERNET, +}; + +struct ibv_port_attr { + enum ibv_port_state state; + enum ibv_mtu max_mtu; + enum ibv_mtu active_mtu; + int gid_tbl_len; + uint32_t port_cap_flags; + uint32_t max_msg_sz; + uint32_t bad_pkey_cntr; + uint32_t qkey_viol_cntr; + uint16_t pkey_tbl_len; + uint16_t lid; + uint16_t sm_lid; + uint8_t lmc; + uint8_t max_vl_num; + uint8_t sm_sl; + uint8_t subnet_timeout; + uint8_t init_type_reply; + uint8_t active_width; + uint8_t active_speed; + uint8_t phys_state; + uint8_t link_layer; + uint8_t pad; +}; + +enum ibv_event_type { + IBV_EVENT_CQ_ERR, + IBV_EVENT_QP_FATAL, + IBV_EVENT_QP_REQ_ERR, + IBV_EVENT_QP_ACCESS_ERR, + IBV_EVENT_COMM_EST, + IBV_EVENT_SQ_DRAINED, + IBV_EVENT_PATH_MIG, + IBV_EVENT_PATH_MIG_ERR, + IBV_EVENT_DEVICE_FATAL, + IBV_EVENT_PORT_ACTIVE, + IBV_EVENT_PORT_ERR, + IBV_EVENT_LID_CHANGE, + IBV_EVENT_PKEY_CHANGE, + IBV_EVENT_SM_CHANGE, + IBV_EVENT_SRQ_ERR, + IBV_EVENT_SRQ_LIMIT_REACHED, + IBV_EVENT_QP_LAST_WQE_REACHED, + IBV_EVENT_CLIENT_REREGISTER, + IBV_EVENT_GID_CHANGE, +}; + +enum ibv_event_flags { + IBV_XRC_QP_EVENT_FLAG = 0x80000000, +}; + +struct ibv_async_event { + union { + struct ibv_cq *cq; + struct ibv_qp *qp; + struct ibv_srq *srq; + int port_num; + uint32_t xrc_qp_num; + } element; + enum ibv_event_type event_type; +}; + +enum ibv_wc_status { + IBV_WC_SUCCESS, + IBV_WC_LOC_LEN_ERR, + IBV_WC_LOC_QP_OP_ERR, + IBV_WC_LOC_EEC_OP_ERR, + IBV_WC_LOC_PROT_ERR, + IBV_WC_WR_FLUSH_ERR, + IBV_WC_MW_BIND_ERR, + IBV_WC_BAD_RESP_ERR, + IBV_WC_LOC_ACCESS_ERR, + IBV_WC_REM_INV_REQ_ERR, + IBV_WC_REM_ACCESS_ERR, + IBV_WC_REM_OP_ERR, + IBV_WC_RETRY_EXC_ERR, + IBV_WC_RNR_RETRY_EXC_ERR, + IBV_WC_LOC_RDD_VIOL_ERR, + IBV_WC_REM_INV_RD_REQ_ERR, + IBV_WC_REM_ABORT_ERR, + IBV_WC_INV_EECN_ERR, + IBV_WC_INV_EEC_STATE_ERR, + IBV_WC_FATAL_ERR, + IBV_WC_RESP_TIMEOUT_ERR, + IBV_WC_GENERAL_ERR +}; +const char *ibv_wc_status_str(enum ibv_wc_status status); + +enum ibv_wc_opcode { + IBV_WC_SEND, + IBV_WC_RDMA_WRITE, + IBV_WC_RDMA_READ, + IBV_WC_COMP_SWAP, + IBV_WC_FETCH_ADD, + IBV_WC_BIND_MW, +/* + * Set value of IBV_WC_RECV so consumers can test if a completion is a + * receive by testing (opcode & IBV_WC_RECV). + */ + IBV_WC_RECV = 1 << 7, + IBV_WC_RECV_RDMA_WITH_IMM +}; + +enum ibv_wc_flags { + IBV_WC_GRH = 1 << 0, + IBV_WC_WITH_IMM = 1 << 1 +}; + +struct ibv_wc { + uint64_t wr_id; + enum ibv_wc_status status; + enum ibv_wc_opcode opcode; + uint32_t vendor_err; + uint32_t byte_len; + uint32_t imm_data; /* in network byte order */ + uint32_t qp_num; + uint32_t src_qp; + int wc_flags; + uint16_t pkey_index; + uint16_t slid; + uint8_t sl; + uint8_t dlid_path_bits; +}; + +enum ibv_access_flags { + IBV_ACCESS_LOCAL_WRITE = 1, + IBV_ACCESS_REMOTE_WRITE = (1<<1), + IBV_ACCESS_REMOTE_READ = (1<<2), + IBV_ACCESS_REMOTE_ATOMIC = (1<<3), + IBV_ACCESS_MW_BIND = (1<<4) +}; + +struct ibv_pd { + struct ibv_context *context; + uint32_t handle; +}; + +enum ibv_rereg_mr_flags { + IBV_REREG_MR_CHANGE_TRANSLATION = (1 << 0), + IBV_REREG_MR_CHANGE_PD = (1 << 1), + IBV_REREG_MR_CHANGE_ACCESS = (1 << 2), + IBV_REREG_MR_KEEP_VALID = (1 << 3) +}; + +struct ibv_mr { + struct ibv_context *context; + struct ibv_pd *pd; + void *addr; + size_t length; + uint32_t handle; + uint32_t lkey; + uint32_t rkey; +}; + +enum ibv_mw_type { + IBV_MW_TYPE_1 = 1, + IBV_MW_TYPE_2 = 2 +}; + +struct ibv_mw { + struct ibv_context *context; + struct ibv_pd *pd; + uint32_t rkey; +}; + +struct ibv_global_route { + union ibv_gid dgid; + uint32_t flow_label; + uint8_t sgid_index; + uint8_t hop_limit; + uint8_t traffic_class; +}; + +struct ibv_grh { + uint32_t version_tclass_flow; + uint16_t paylen; + uint8_t next_hdr; + uint8_t hop_limit; + union ibv_gid sgid; + union ibv_gid dgid; +}; + +enum ibv_rate { + IBV_RATE_MAX = 0, + IBV_RATE_2_5_GBPS = 2, + IBV_RATE_5_GBPS = 5, + IBV_RATE_10_GBPS = 3, + IBV_RATE_20_GBPS = 6, + IBV_RATE_30_GBPS = 4, + IBV_RATE_40_GBPS = 7, + IBV_RATE_60_GBPS = 8, + IBV_RATE_80_GBPS = 9, + IBV_RATE_120_GBPS = 10 +}; + +/** + * ibv_rate_to_mult - Convert the IB rate enum to a multiple of the + * base rate of 2.5 Gbit/sec. For example, IBV_RATE_5_GBPS will be + * converted to 2, since 5 Gbit/sec is 2 * 2.5 Gbit/sec. + * @rate: rate to convert. + */ +int ibv_rate_to_mult(enum ibv_rate rate) __attribute_const; + +/** + * mult_to_ibv_rate - Convert a multiple of 2.5 Gbit/sec to an IB rate enum. + * @mult: multiple to convert. + */ +enum ibv_rate mult_to_ibv_rate(int mult) __attribute_const; + +struct ibv_ah_attr { + struct ibv_global_route grh; + uint16_t dlid; + uint8_t sl; + uint8_t src_path_bits; + uint8_t static_rate; + uint8_t is_global; + uint8_t port_num; +}; + +struct ibv_xrc_domain { + struct ibv_context *context; + uint32_t handle; +}; + +enum ibv_srq_attr_mask { + IBV_SRQ_MAX_WR = 1 << 0, + IBV_SRQ_LIMIT = 1 << 1 +}; + +struct ibv_srq_attr { + uint32_t max_wr; + uint32_t max_sge; + uint32_t srq_limit; +}; + +struct ibv_srq_init_attr { + void *srq_context; + struct ibv_srq_attr attr; +}; + +enum ibv_qp_type { + IBV_QPT_RC = 2, + IBV_QPT_UC, + IBV_QPT_UD, + IBV_QPT_XRC, + IBV_QPT_RAW_ETH = 8 +}; + +struct ibv_qp_cap { + uint32_t max_send_wr; + uint32_t max_recv_wr; + uint32_t max_send_sge; + uint32_t max_recv_sge; + uint32_t max_inline_data; +}; + +struct ibv_qp_init_attr { + void *qp_context; + struct ibv_cq *send_cq; + struct ibv_cq *recv_cq; + struct ibv_srq *srq; + struct ibv_qp_cap cap; + enum ibv_qp_type qp_type; + int sq_sig_all; + struct ibv_xrc_domain *xrc_domain; +}; + +enum ibv_qp_attr_mask { + IBV_QP_STATE = 1 << 0, + IBV_QP_CUR_STATE = 1 << 1, + IBV_QP_EN_SQD_ASYNC_NOTIFY = 1 << 2, + IBV_QP_ACCESS_FLAGS = 1 << 3, + IBV_QP_PKEY_INDEX = 1 << 4, + IBV_QP_PORT = 1 << 5, + IBV_QP_QKEY = 1 << 6, + IBV_QP_AV = 1 << 7, + IBV_QP_PATH_MTU = 1 << 8, + IBV_QP_TIMEOUT = 1 << 9, + IBV_QP_RETRY_CNT = 1 << 10, + IBV_QP_RNR_RETRY = 1 << 11, + IBV_QP_RQ_PSN = 1 << 12, + IBV_QP_MAX_QP_RD_ATOMIC = 1 << 13, + IBV_QP_ALT_PATH = 1 << 14, + IBV_QP_MIN_RNR_TIMER = 1 << 15, + IBV_QP_SQ_PSN = 1 << 16, + IBV_QP_MAX_DEST_RD_ATOMIC = 1 << 17, + IBV_QP_PATH_MIG_STATE = 1 << 18, + IBV_QP_CAP = 1 << 19, + IBV_QP_DEST_QPN = 1 << 20 +}; + +enum ibv_qp_state { + IBV_QPS_RESET, + IBV_QPS_INIT, + IBV_QPS_RTR, + IBV_QPS_RTS, + IBV_QPS_SQD, + IBV_QPS_SQE, + IBV_QPS_ERR +}; + +enum ibv_mig_state { + IBV_MIG_MIGRATED, + IBV_MIG_REARM, + IBV_MIG_ARMED +}; + +struct ibv_qp_attr { + enum ibv_qp_state qp_state; + enum ibv_qp_state cur_qp_state; + enum ibv_mtu path_mtu; + enum ibv_mig_state path_mig_state; + uint32_t qkey; + uint32_t rq_psn; + uint32_t sq_psn; + uint32_t dest_qp_num; + int qp_access_flags; + struct ibv_qp_cap cap; + struct ibv_ah_attr ah_attr; + struct ibv_ah_attr alt_ah_attr; + uint16_t pkey_index; + uint16_t alt_pkey_index; + uint8_t en_sqd_async_notify; + uint8_t sq_draining; + uint8_t max_rd_atomic; + uint8_t max_dest_rd_atomic; + uint8_t min_rnr_timer; + uint8_t port_num; + uint8_t timeout; + uint8_t retry_cnt; + uint8_t rnr_retry; + uint8_t alt_port_num; + uint8_t alt_timeout; +}; + +enum ibv_wr_opcode { + IBV_WR_RDMA_WRITE, + IBV_WR_RDMA_WRITE_WITH_IMM, + IBV_WR_SEND, + IBV_WR_SEND_WITH_IMM, + IBV_WR_RDMA_READ, + IBV_WR_ATOMIC_CMP_AND_SWP, + IBV_WR_ATOMIC_FETCH_AND_ADD +}; + +enum ibv_send_flags { + IBV_SEND_FENCE = 1 << 0, + IBV_SEND_SIGNALED = 1 << 1, + IBV_SEND_SOLICITED = 1 << 2, + IBV_SEND_INLINE = 1 << 3 +}; + +struct ibv_sge { + uint64_t addr; + uint32_t length; + uint32_t lkey; +}; + +struct ibv_send_wr { + uint64_t wr_id; + struct ibv_send_wr *next; + struct ibv_sge *sg_list; + int num_sge; + enum ibv_wr_opcode opcode; + int send_flags; + uint32_t imm_data; /* in network byte order */ + union { + struct { + uint64_t remote_addr; + uint32_t rkey; + } rdma; + struct { + uint64_t remote_addr; + uint64_t compare_add; + uint64_t swap; + uint32_t rkey; + } atomic; + struct { + struct ibv_ah *ah; + uint32_t remote_qpn; + uint32_t remote_qkey; + } ud; + } wr; + uint32_t xrc_remote_srq_num; +}; + +struct ibv_recv_wr { + uint64_t wr_id; + struct ibv_recv_wr *next; + struct ibv_sge *sg_list; + int num_sge; +}; + +struct ibv_mw_bind { + uint64_t wr_id; + struct ibv_mr *mr; + void *addr; + size_t length; + int send_flags; + int mw_access_flags; +}; + +struct ibv_srq { + struct ibv_context *context; + void *srq_context; + struct ibv_pd *pd; + uint32_t handle; + + uint32_t events_completed; + + uint32_t xrc_srq_num; + struct ibv_xrc_domain *xrc_domain; + struct ibv_cq *xrc_cq; + + pthread_mutex_t mutex; + pthread_cond_t cond; +}; + +struct ibv_qp { + struct ibv_context *context; + void *qp_context; + struct ibv_pd *pd; + struct ibv_cq *send_cq; + struct ibv_cq *recv_cq; + struct ibv_srq *srq; + uint32_t handle; + uint32_t qp_num; + enum ibv_qp_state state; + enum ibv_qp_type qp_type; + + uint32_t events_completed; + + struct ibv_xrc_domain *xrc_domain; + + pthread_mutex_t mutex; + pthread_cond_t cond; +}; + +struct ibv_comp_channel { + struct ibv_context *context; + int fd; + int refcnt; +}; + +struct ibv_cq { + struct ibv_context *context; + struct ibv_comp_channel *channel; + void *cq_context; + uint32_t handle; + int cqe; + + uint32_t comp_events_completed; + uint32_t async_events_completed; + + pthread_mutex_t mutex; + pthread_cond_t cond; +}; + +struct ibv_ah { + struct ibv_context *context; + struct ibv_pd *pd; + uint32_t handle; +}; + +struct ibv_device; +struct ibv_context; + +struct ibv_device_ops { + struct ibv_context * (*alloc_context)(struct ibv_device *device, int cmd_fd); + void (*free_context)(struct ibv_context *context); +}; + +enum { + IBV_SYSFS_NAME_MAX = 64, + IBV_SYSFS_PATH_MAX = 256 +}; + +struct ibv_device { + struct ibv_device_ops ops; + enum ibv_node_type node_type; + enum ibv_transport_type transport_type; + /* Name of underlying kernel IB device, eg "mthca0" */ + char name[IBV_SYSFS_NAME_MAX]; + /* Name of uverbs device, eg "uverbs0" */ + char dev_name[IBV_SYSFS_NAME_MAX]; + /* Path to infiniband_verbs class device in sysfs */ + char dev_path[IBV_SYSFS_PATH_MAX]; + /* Path to infiniband class device in sysfs */ + char ibdev_path[IBV_SYSFS_PATH_MAX]; +}; + +struct ibv_more_ops { + struct ibv_srq * (*create_xrc_srq)(struct ibv_pd *pd, + struct ibv_xrc_domain *xrc_domain, + struct ibv_cq *xrc_cq, + struct ibv_srq_init_attr *srq_init_attr); + struct ibv_xrc_domain * (*open_xrc_domain)(struct ibv_context *context, + int fd, int oflag); + int (*close_xrc_domain)(struct ibv_xrc_domain *d); + int (*create_xrc_rcv_qp)(struct ibv_qp_init_attr *init_attr, + uint32_t *xrc_qp_num); + int (*modify_xrc_rcv_qp)(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num, + struct ibv_qp_attr *attr, + int attr_mask); + int (*query_xrc_rcv_qp)(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num, + struct ibv_qp_attr *attr, + int attr_mask, + struct ibv_qp_init_attr *init_attr); + int (*reg_xrc_rcv_qp)(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num); + int (*unreg_xrc_rcv_qp)(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num); + +}; + +struct ibv_context_ops { + int (*query_device)(struct ibv_context *context, + struct ibv_device_attr *device_attr); + int (*query_port)(struct ibv_context *context, uint8_t port_num, + struct ibv_port_attr *port_attr); + struct ibv_pd * (*alloc_pd)(struct ibv_context *context); + int (*dealloc_pd)(struct ibv_pd *pd); + struct ibv_mr * (*reg_mr)(struct ibv_pd *pd, void *addr, size_t length, + int access); + struct ibv_mr * (*rereg_mr)(struct ibv_mr *mr, + int flags, + struct ibv_pd *pd, void *addr, + size_t length, + int access); + int (*dereg_mr)(struct ibv_mr *mr); + struct ibv_mw * (*alloc_mw)(struct ibv_pd *pd, enum ibv_mw_type type); + int (*bind_mw)(struct ibv_qp *qp, struct ibv_mw *mw, + struct ibv_mw_bind *mw_bind); + int (*dealloc_mw)(struct ibv_mw *mw); + struct ibv_cq * (*create_cq)(struct ibv_context *context, int cqe, + struct ibv_comp_channel *channel, + int comp_vector); + int (*poll_cq)(struct ibv_cq *cq, int num_entries, struct ibv_wc *wc); + int (*req_notify_cq)(struct ibv_cq *cq, int solicited_only); + void (*cq_event)(struct ibv_cq *cq); + int (*resize_cq)(struct ibv_cq *cq, int cqe); + int (*destroy_cq)(struct ibv_cq *cq); + struct ibv_srq * (*create_srq)(struct ibv_pd *pd, + struct ibv_srq_init_attr *srq_init_attr); + int (*modify_srq)(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + int srq_attr_mask); + int (*query_srq)(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr); + int (*destroy_srq)(struct ibv_srq *srq); + int (*post_srq_recv)(struct ibv_srq *srq, + struct ibv_recv_wr *recv_wr, + struct ibv_recv_wr **bad_recv_wr); + struct ibv_qp * (*create_qp)(struct ibv_pd *pd, struct ibv_qp_init_attr *attr); + int (*query_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask, + struct ibv_qp_init_attr *init_attr); + int (*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask); + int (*destroy_qp)(struct ibv_qp *qp); + int (*post_send)(struct ibv_qp *qp, struct ibv_send_wr *wr, + struct ibv_send_wr **bad_wr); + int (*post_recv)(struct ibv_qp *qp, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr); + struct ibv_ah * (*create_ah)(struct ibv_pd *pd, struct ibv_ah_attr *attr); + int (*destroy_ah)(struct ibv_ah *ah); + int (*attach_mcast)(struct ibv_qp *qp, const union ibv_gid *gid, + uint16_t lid); + int (*detach_mcast)(struct ibv_qp *qp, const union ibv_gid *gid, + uint16_t lid); + void (*async_event)(struct ibv_async_event *event); +}; + +struct ibv_context { + struct ibv_device *device; + struct ibv_context_ops ops; + int cmd_fd; + int async_fd; + int num_comp_vectors; + pthread_mutex_t mutex; + void *abi_compat; + struct ibv_more_ops *more_ops; +}; + +static inline int ___ibv_query_port(struct ibv_context *context, + uint8_t port_num, + struct ibv_port_attr *port_attr) +{ + port_attr->link_layer = IBV_LINK_LAYER_UNSPECIFIED; + port_attr->pad = 0; + + return context->ops.query_port(context, port_num, port_attr); +} + +/** + * ibv_get_device_list - Get list of IB devices currently available + * @num_devices: optional. if non-NULL, set to the number of devices + * returned in the array. + * + * Return a NULL-terminated array of IB devices. The array can be + * released with ibv_free_device_list(). + */ +struct ibv_device **ibv_get_device_list(int *num_devices); + +/** + * ibv_free_device_list - Free list from ibv_get_device_list() + * + * Free an array of devices returned from ibv_get_device_list(). Once + * the array is freed, pointers to devices that were not opened with + * ibv_open_device() are no longer valid. Client code must open all + * devices it intends to use before calling ibv_free_device_list(). + */ +void ibv_free_device_list(struct ibv_device **list); + +/** + * ibv_get_device_name - Return kernel device name + */ +const char *ibv_get_device_name(struct ibv_device *device); + +/** + * ibv_get_device_guid - Return device's node GUID + */ +uint64_t ibv_get_device_guid(struct ibv_device *device); + +/** + * ibv_open_device - Initialize device for use + */ +struct ibv_context *ibv_open_device(struct ibv_device *device); + +/** + * ibv_close_device - Release device + */ +int ibv_close_device(struct ibv_context *context); + +/** + * ibv_get_async_event - Get next async event + * @event: Pointer to use to return async event + * + * All async events returned by ibv_get_async_event() must eventually + * be acknowledged with ibv_ack_async_event(). + */ +int ibv_get_async_event(struct ibv_context *context, + struct ibv_async_event *event); + +/** + * ibv_ack_async_event - Acknowledge an async event + * @event: Event to be acknowledged. + * + * All async events which are returned by ibv_get_async_event() must + * be acknowledged. To avoid races, destroying an object (CQ, SRQ or + * QP) will wait for all affiliated events to be acknowledged, so + * there should be a one-to-one correspondence between acks and + * successful gets. + */ +void ibv_ack_async_event(struct ibv_async_event *event); + +/** + * ibv_query_device - Get device properties + */ +int ibv_query_device(struct ibv_context *context, + struct ibv_device_attr *device_attr); + +/** + * ibv_query_port - Get port properties + */ +int ibv_query_port(struct ibv_context *context, uint8_t port_num, + struct ibv_port_attr *port_attr); + +/** + * ibv_query_gid - Get a GID table entry + */ +int ibv_query_gid(struct ibv_context *context, uint8_t port_num, + int index, union ibv_gid *gid); + +/** + * ibv_query_pkey - Get a P_Key table entry + */ +int ibv_query_pkey(struct ibv_context *context, uint8_t port_num, + int index, uint16_t *pkey); + +/** + * ibv_alloc_pd - Allocate a protection domain + */ +struct ibv_pd *ibv_alloc_pd(struct ibv_context *context); + +/** + * ibv_dealloc_pd - Free a protection domain + */ +int ibv_dealloc_pd(struct ibv_pd *pd); + +/** + * ibv_reg_mr - Register a memory region + */ +struct ibv_mr *ibv_reg_mr(struct ibv_pd *pd, void *addr, + size_t length, int access); + +/** + * ibv_dereg_mr - Deregister a memory region + */ +int ibv_dereg_mr(struct ibv_mr *mr); + +/** + * ibv_create_comp_channel - Create a completion event channel + */ +struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context *context); + +/** + * ibv_destroy_comp_channel - Destroy a completion event channel + */ +int ibv_destroy_comp_channel(struct ibv_comp_channel *channel); + +/** + * ibv_create_cq - Create a completion queue + * @context - Context CQ will be attached to + * @cqe - Minimum number of entries required for CQ + * @cq_context - Consumer-supplied context returned for completion events + * @channel - Completion channel where completion events will be queued. + * May be NULL if completion events will not be used. + * @comp_vector - Completion vector used to signal completion events. + * Must be >= 0 and < context->num_comp_vectors. + */ +struct ibv_cq *ibv_create_cq(struct ibv_context *context, int cqe, + void *cq_context, + struct ibv_comp_channel *channel, + int comp_vector); + +/** + * ibv_resize_cq - Modifies the capacity of the CQ. + * @cq: The CQ to resize. + * @cqe: The minimum size of the CQ. + * + * Users can examine the cq structure to determine the actual CQ size. + */ +int ibv_resize_cq(struct ibv_cq *cq, int cqe); + +/** + * ibv_destroy_cq - Destroy a completion queue + */ +int ibv_destroy_cq(struct ibv_cq *cq); + +/** + * ibv_get_cq_event - Read next CQ event + * @channel: Channel to get next event from. + * @cq: Used to return pointer to CQ. + * @cq_context: Used to return consumer-supplied CQ context. + * + * All completion events returned by ibv_get_cq_event() must + * eventually be acknowledged with ibv_ack_cq_events(). + */ +int ibv_get_cq_event(struct ibv_comp_channel *channel, + struct ibv_cq **cq, void **cq_context); + +/** + * ibv_ack_cq_events - Acknowledge CQ completion events + * @cq: CQ to acknowledge events for + * @nevents: Number of events to acknowledge. + * + * All completion events which are returned by ibv_get_cq_event() must + * be acknowledged. To avoid races, ibv_destroy_cq() will wait for + * all completion events to be acknowledged, so there should be a + * one-to-one correspondence between acks and successful gets. An + * application may accumulate multiple completion events and + * acknowledge them in a single call to ibv_ack_cq_events() by passing + * the number of events to ack in @nevents. + */ +void ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents); + +/** + * ibv_poll_cq - Poll a CQ for work completions + * @cq:the CQ being polled + * @num_entries:maximum number of completions to return + * @wc:array of at least @num_entries of &struct ibv_wc where completions + * will be returned + * + * Poll a CQ for (possibly multiple) completions. If the return value + * is < 0, an error occurred. If the return value is >= 0, it is the + * number of completions returned. If the return value is + * non-negative and strictly less than num_entries, then the CQ was + * emptied. + */ +static inline int ibv_poll_cq(struct ibv_cq *cq, int num_entries, struct ibv_wc *wc) +{ + return cq->context->ops.poll_cq(cq, num_entries, wc); +} + +/** + * ibv_req_notify_cq - Request completion notification on a CQ. An + * event will be added to the completion channel associated with the + * CQ when an entry is added to the CQ. + * @cq: The completion queue to request notification for. + * @solicited_only: If non-zero, an event will be generated only for + * the next solicited CQ entry. If zero, any CQ entry, solicited or + * not, will generate an event. + */ +static inline int ibv_req_notify_cq(struct ibv_cq *cq, int solicited_only) +{ + return cq->context->ops.req_notify_cq(cq, solicited_only); +} + +/** + * ibv_create_srq - Creates a SRQ associated with the specified protection + * domain. + * @pd: The protection domain associated with the SRQ. + * @srq_init_attr: A list of initial attributes required to create the SRQ. + * + * srq_attr->max_wr and srq_attr->max_sge are read the determine the + * requested size of the SRQ, and set to the actual values allocated + * on return. If ibv_create_srq() succeeds, then max_wr and max_sge + * will always be at least as large as the requested values. + */ +struct ibv_srq *ibv_create_srq(struct ibv_pd *pd, + struct ibv_srq_init_attr *srq_init_attr); + +/** + * ibv_create_xrc_srq - Creates a SRQ associated with the specified protection + * domain and xrc domain. + * @pd: The protection domain associated with the SRQ. + * @xrc_domain: The XRC domain associated with the SRQ. + * @xrc_cq: CQ to report completions for XRC packets on. + * + * @srq_init_attr: A list of initial attributes required to create the SRQ. + * + * srq_attr->max_wr and srq_attr->max_sge are read the determine the + * requested size of the SRQ, and set to the actual values allocated + * on return. If ibv_create_srq() succeeds, then max_wr and max_sge + * will always be at least as large as the requested values. + */ +struct ibv_srq *ibv_create_xrc_srq(struct ibv_pd *pd, + struct ibv_xrc_domain *xrc_domain, + struct ibv_cq *xrc_cq, + struct ibv_srq_init_attr *srq_init_attr); + +/** + * ibv_modify_srq - Modifies the attributes for the specified SRQ. + * @srq: The SRQ to modify. + * @srq_attr: On input, specifies the SRQ attributes to modify. On output, + * the current values of selected SRQ attributes are returned. + * @srq_attr_mask: A bit-mask used to specify which attributes of the SRQ + * are being modified. + * + * The mask may contain IBV_SRQ_MAX_WR to resize the SRQ and/or + * IBV_SRQ_LIMIT to set the SRQ's limit and request notification when + * the number of receives queued drops below the limit. + */ +int ibv_modify_srq(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + int srq_attr_mask); + +/** + * ibv_query_srq - Returns the attribute list and current values for the + * specified SRQ. + * @srq: The SRQ to query. + * @srq_attr: The attributes of the specified SRQ. + */ +int ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr); + +/** + * ibv_destroy_srq - Destroys the specified SRQ. + * @srq: The SRQ to destroy. + */ +int ibv_destroy_srq(struct ibv_srq *srq); + +/** + * ibv_post_srq_recv - Posts a list of work requests to the specified SRQ. + * @srq: The SRQ to post the work request on. + * @recv_wr: A list of work requests to post on the receive queue. + * @bad_recv_wr: On an immediate failure, this parameter will reference + * the work request that failed to be posted on the QP. + */ +static inline int ibv_post_srq_recv(struct ibv_srq *srq, + struct ibv_recv_wr *recv_wr, + struct ibv_recv_wr **bad_recv_wr) +{ + return srq->context->ops.post_srq_recv(srq, recv_wr, bad_recv_wr); +} + +/** + * ibv_create_qp - Create a queue pair. + */ +struct ibv_qp *ibv_create_qp(struct ibv_pd *pd, + struct ibv_qp_init_attr *qp_init_attr); + +/** + * ibv_modify_qp - Modify a queue pair. + */ +int ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask); + +/** + * ibv_query_qp - Returns the attribute list and current values for the + * specified QP. + * @qp: The QP to query. + * @attr: The attributes of the specified QP. + * @attr_mask: A bit-mask used to select specific attributes to query. + * @init_attr: Additional attributes of the selected QP. + * + * The qp_attr_mask may be used to limit the query to gathering only the + * selected attributes. + */ +int ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask, + struct ibv_qp_init_attr *init_attr); + +/** + * ibv_destroy_qp - Destroy a queue pair. + */ +int ibv_destroy_qp(struct ibv_qp *qp); + +/** + * ibv_post_send - Post a list of work requests to a send queue. + * + * If IBV_SEND_INLINE flag is set, the data buffers can be reused + * immediately after the call returns. + */ +static inline int ibv_post_send(struct ibv_qp *qp, struct ibv_send_wr *wr, + struct ibv_send_wr **bad_wr) +{ + return qp->context->ops.post_send(qp, wr, bad_wr); +} + +/** + * ibv_post_recv - Post a list of work requests to a receive queue. + */ +static inline int ibv_post_recv(struct ibv_qp *qp, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr) +{ + return qp->context->ops.post_recv(qp, wr, bad_wr); +} + +/** + * ibv_create_ah - Create an address handle. + */ +struct ibv_ah *ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr); + +/** + * ibv_init_ah_from_wc - Initializes address handle attributes from a + * work completion. + * @context: Device context on which the received message arrived. + * @port_num: Port on which the received message arrived. + * @wc: Work completion associated with the received message. + * @grh: References the received global route header. This parameter is + * ignored unless the work completion indicates that the GRH is valid. + * @ah_attr: Returned attributes that can be used when creating an address + * handle for replying to the message. + */ +int ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num, + struct ibv_wc *wc, struct ibv_grh *grh, + struct ibv_ah_attr *ah_attr); + +/** + * ibv_create_ah_from_wc - Creates an address handle associated with the + * sender of the specified work completion. + * @pd: The protection domain associated with the address handle. + * @wc: Work completion information associated with a received message. + * @grh: References the received global route header. This parameter is + * ignored unless the work completion indicates that the GRH is valid. + * @port_num: The outbound port number to associate with the address. + * + * The address handle is used to reference a local or global destination + * in all UD QP post sends. + */ +struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc, + struct ibv_grh *grh, uint8_t port_num); + +/** + * ibv_destroy_ah - Destroy an address handle. + */ +int ibv_destroy_ah(struct ibv_ah *ah); + +/** + * ibv_attach_mcast - Attaches the specified QP to a multicast group. + * @qp: QP to attach to the multicast group. The QP must be a UD QP. + * @gid: Multicast group GID. + * @lid: Multicast group LID in host byte order. + * + * In order to route multicast packets correctly, subnet + * administration must have created the multicast group and configured + * the fabric appropriately. The port associated with the specified + * QP must also be a member of the multicast group. + */ +int ibv_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid); + +/** + * ibv_detach_mcast - Detaches the specified QP from a multicast group. + * @qp: QP to detach from the multicast group. + * @gid: Multicast group GID. + * @lid: Multicast group LID in host byte order. + */ +int ibv_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid); + +/** + * ibv_fork_init - Prepare data structures so that fork() may be used + * safely. If this function is not called or returns a non-zero + * status, then libibverbs data structures are not fork()-safe and the + * effect of an application calling fork() is undefined. + */ +int ibv_fork_init(void); + +/** + * ibv_node_type_str - Return string describing node_type enum value + */ +const char *ibv_node_type_str(enum ibv_node_type node_type); + +/** + * ibv_port_state_str - Return string describing port_state enum value + */ +const char *ibv_port_state_str(enum ibv_port_state port_state); + +/** + * ibv_event_type_str - Return string describing event_type enum value + */ +const char *ibv_event_type_str(enum ibv_event_type event); + +/** + * ibv_open_xrc_domain - open an XRC domain + * Returns a reference to an XRC domain. + * + * @context: Device context + * @fd: descriptor for inode associated with the domain + * If fd == -1, no inode is associated with the domain; in this ca= se, + * the only legal value for oflag is O_CREAT + * + * @oflag: oflag values are constructed by OR-ing flags from the following list + * + * O_CREAT + * If a domain belonging to device named by context is already associated + * with the inode, this flag has no effect, except as noted under O_EXCL + * below. Otherwise, a new XRC domain is created and is associated with + * inode specified by fd. + * + * O_EXCL + * If O_EXCL and O_CREAT are set, open will fail if a domain associated with + * the inode exists. The check for the existence of the domain and creation + * of the domain if it does not exist is atomic with respect to other + * processes executing open with fd naming the same inode. + */ +struct ibv_xrc_domain *ibv_open_xrc_domain(struct ibv_context *context, + int fd, int oflag); + +/** + * ibv_close_xrc_domain - close an XRC domain + * If this is the last reference, destroys the domain. + * + * @d: reference to XRC domain to close + * + * close is implicitly performed at process exit. + */ +int ibv_close_xrc_domain(struct ibv_xrc_domain *d); + +/** + * ibv_create_xrc_rcv_qp - creates an XRC QP for serving as a receive-side-only QP, + * + * This QP is created in kernel space, and persists until the last process + * registered for the QP calls ibv_unreg_xrc_rcv_qp() (at which time the QP + * is destroyed). + * + * @init_attr: init attributes to use for QP. xrc domain MUST be included here. + * All other fields are ignored. + * + * @xrc_rcv_qpn: qp_num of created QP (if success). To be passed to the + * remote node (sender). The remote node will use xrc_rcv_qpn + * in ibv_post_send when sending to XRC SRQ's on this host + * in the same xrc domain. + * + * RETURNS: success (0), or a (negative) error value. + * + * NOTE: this verb also registers the calling user-process with the QP at its + * creation time (implicit call to ibv_reg_xrc_rcv_qp), to avoid race + * conditions. The creating process will need to call ibv_unreg_xrc_qp() + * for the QP to release it from this process. + */ +int ibv_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, + uint32_t *xrc_rcv_qpn); + +/** + * ibv_modify_xrc_rcv_qp - modifies an xrc_rcv qp. + * + * @xrc_domain: xrc domain the QP belongs to (for verification). + * @xrc_qp_num: The (24 bit) number of the XRC QP. + * @attr: modify-qp attributes. The following fields must be specified: + * for RESET_2_INIT: qp_state, pkey_index , port, qp_access_flags + * for INIT_2_RTR: qp_state, path_mtu, dest_qp_num, rq_psn, + * max_dest_rd_atomic, min_rnr_timer, ah_attr + * The QP need not be brought to RTS for the QP to operate as a + * receive-only QP. + * @attr_mask: bitmap indicating which attributes are provided in the attr + * struct. Used for validity checking. + * The following bits must be set: + * for RESET_2_INIT: IBV_QP_PKEY_INDEX, IBV_QP_PORT, + * IBV_QP_ACCESS_FLAGS, IBV_QP_STATE + * for INIT_2_RTR: 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, IBV_QP_STATE + * + * RETURNS: success (0), or a (positive) error value. + * + */ +int ibv_modify_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num, + struct ibv_qp_attr *attr, int attr_mask); + +/** + * ibv_query_xrc_rcv_qp - queries an xrc_rcv qp. + * + * @xrc_domain: xrc domain the QP belongs to (for verification). + * @xrc_qp_num: The (24 bit) number of the XRC QP. + * @attr: for returning qp attributes. + * @attr_mask: bitmap indicating which attributes to return. + * @init_attr: for returning the init attributes + * + * RETURNS: success (0), or a (positive) error value. + * + */ +int ibv_query_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num, + struct ibv_qp_attr *attr, int attr_mask, + struct ibv_qp_init_attr *init_attr); + +/** + * ibv_reg_xrc_rcv_qp: registers a user process with an XRC QP which serves as + * a receive-side only QP. + * + * @xrc_domain: xrc domain the QP belongs to (for verification). + * @xrc_qp_num: The (24 bit) number of the XRC QP. + * + * RETURNS: success (0), + * or error (EINVAL), if: + * 1. There is no such QP_num allocated. + * 2. The QP is allocated, but is not an receive XRC QP + * 3. The XRC QP does not belong to the given domain. + */ +int ibv_reg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num); + +/** + * ibv_unreg_xrc_rcv_qp: detaches a user process from an XRC QP serving as + * a receive-side only QP. If as a result, there are no remaining + * userspace processes registered for this XRC QP, it is destroyed. + * + * @xrc_domain: xrc domain the QP belongs to (for verification). + * @xrc_qp_num: The (24 bit) number of the XRC QP. + * + * RETURNS: success (0), + * or error (EINVAL), if: + * 1. There is no such QP_num allocated. + * 2. The QP is allocated, but is not an XRC QP + * 3. The XRC QP does not belong to the given domain. + * NOTE: There is no reason to return a special code if the QP is destroyed. + * The unregister simply succeeds. + */ +int ibv_unreg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num); + +END_C_DECLS + +# undef __attribute_const + +#define ibv_query_port(context, port_num, port_attr) \ + ___ibv_query_port(context, port_num, port_attr) + +#endif /* INFINIBAND_VERBS_H */ diff --git a/contrib/ofed/libibverbs/libibverbs.spec.in b/contrib/ofed/libibverbs/libibverbs.spec.in new file mode 100644 index 000000000000..d122afa8703b --- /dev/null +++ b/contrib/ofed/libibverbs/libibverbs.spec.in @@ -0,0 +1,146 @@ +Name: libibverbs +Version: 1.1.4 +Release: 1%{?dist} +Summary: A library for direct userspace use of RDMA (InfiniBand/iWARP) hardware + +Group: System Environment/Libraries +License: GPLv2 or BSD +Url: http://openfabrics.org/ +Source: http://openfabrics.org/downloads/verbs/libibverbs-1.1.4.tar.gz +BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description +libibverbs is a library that allows userspace processes to use RDMA +"verbs" as described in the InfiniBand Architecture Specification and +the RDMA Protocol Verbs Specification. This includes direct hardware +access from userspace to InfiniBand/iWARP adapters (kernel bypass) for +fast path operations. + +For this library to be useful, a device-specific plug-in module should +also be installed. + +%package devel +Summary: Development files for the libibverbs library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +Header files for the libibverbs library. + +%package devel-static +Summary: Static development files for the libibverbs library +Group: System Environment/Libraries + +%description devel-static +Static libraries for the libibverbs library. + +%package utils +Summary: Examples for the libibverbs library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} + +%description utils +Useful libibverbs1 example programs such as ibv_devinfo, which +displays information about RDMA devices. + +%prep +%setup -q -n %{name}-@VERSION@ + +%build +%configure +make %{?_smp_mflags} + +%install +rm -rf $RPM_BUILD_ROOT +make DESTDIR=%{buildroot} install +# remove unpackaged files from the buildroot +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig + +%files +%defattr(-,root,root,-) +%{_libdir}/libibverbs*.so.* +%doc AUTHORS COPYING ChangeLog README + +%files devel +%defattr(-,root,root,-) +%{_libdir}/lib*.so +%{_includedir}/* +%{_mandir}/man3/* +%{_mandir}/man7/* + +%files devel-static +%defattr(-,root,root,-) +%{_libdir}/*.a + +%files utils +%defattr(-,root,root,-) +%{_bindir}/* +%{_mandir}/man1/* + +%changelog +* Thu Jun 3 2010 Roland Dreier - 1.1.4-1 +- New upstream release + +* Thu Oct 29 2009 Roland Dreier - 1.1.3-1 +- New upstream release + +* Fri Jul 24 2009 Fedora Release Engineering - 1.1.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Wed Feb 25 2009 Fedora Release Engineering - 1.1.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Wed Apr 16 2008 Roland Dreier - 1.1.2-1 +- New upstream release +- Update description to mention RDMA and iWARP, not just InfiniBand +- Add "Requires" tag for libibverbs base package to -devel + +* Fri Jun 15 2007 Roland Dreier - 1.1.1-1 +- New upstream release + +* Wed Apr 11 2007 Roland Dreier - 1.1-1 +- New upstream release + +* Mon May 22 2006 Roland Dreier - 1.1-0.1.rc2 +- New upstream release +- Remove dependency on libsysfs, since it is no longer used +- Put section 3 manpages in devel package. +- Spec file cleanups: remove unused ver macro, improve BuildRoot, add + Requires for /sbin/ldconfig, split static libraries into + devel-static package, and don't use makeinstall any more (all + suggested by Doug Ledford ). + +* Thu May 4 2006 Roland Dreier - 1.0.4-1 +- New upstream release + +* Mon Mar 14 2006 Roland Dreier - 1.0.3-1 +- New upstream release + +* Mon Mar 13 2006 Roland Dreier - 1.0.1-1 +- New upstream release + +* Thu Feb 16 2006 Roland Dreier - 1.0-1 +- New upstream release + +* Wed Feb 15 2006 Roland Dreier - 1.0-0.5.rc7 +- New upstream release + +* Sun Jan 22 2006 Roland Dreier - 1.0-0.4.rc6 +- New upstream release + +* Tue Oct 25 2005 Roland Dreier - 1.0-0.3.rc5 +- New upstream release + +* Wed Oct 5 2005 Roland Dreier - 1.0-0.2.rc4 +- Update to upstream 1.0-rc4 release + +* Mon Sep 26 2005 Roland Dreier - 1.0-0.1.rc3 +- Initial attempt at Fedora Extras-compliant spec file diff --git a/contrib/ofed/libibverbs/man/ibv_alloc_pd.3 b/contrib/ofed/libibverbs/man/ibv_alloc_pd.3 new file mode 100644 index 000000000000..c3afd1aa7ee2 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_alloc_pd.3 @@ -0,0 +1,40 @@ +.\" -*- nroff -*- +.\" +.TH IBV_ALLOC_PD 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_alloc_pd, ibv_dealloc_pd \- allocate or deallocate a protection domain (PDs) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "struct ibv_pd *ibv_alloc_pd(struct ibv_context " "*context" ); +.sp +.BI "int ibv_dealloc_pd(struct ibv_pd " "*pd" ); +.fi +.SH "DESCRIPTION" +.B ibv_alloc_pd() +allocates a PD for the RDMA device context +.I context\fR. +.PP +.B ibv_dealloc_pd() +deallocates the PD +.I pd\fR. +.SH "RETURN VALUE" +.B ibv_alloc_pd() +returns a pointer to the allocated PD, or NULL if the request fails. +.PP +.B ibv_dealloc_pd() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +.B ibv_dealloc_pd() +may fail if any other resource is still associated with the PD being +freed. +.SH "SEE ALSO" +.BR ibv_reg_mr (3), +.BR ibv_create_srq (3), +.BR ibv_create_qp (3), +.BR ibv_create_ah (3), +.BR ibv_create_ah_from_wc (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_asyncwatch.1 b/contrib/ofed/libibverbs/man/ibv_asyncwatch.1 new file mode 100644 index 000000000000..ece25f88af91 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_asyncwatch.1 @@ -0,0 +1,16 @@ +.TH IBV_ASYNCWATCH 1 "August 30, 2005" "libibverbs" "USER COMMANDS" + +.SH NAME +ibv_asyncwatch \- display asynchronous events + +.SH SYNOPSIS +.B ibv_asyncwatch + +.SH DESCRIPTION +.PP +Display asynchronous events forwarded to userspace for an RDMA device. + +.SH AUTHORS +.TP +Roland Dreier +.RI < rolandd@cisco.com > diff --git a/contrib/ofed/libibverbs/man/ibv_attach_mcast.3 b/contrib/ofed/libibverbs/man/ibv_attach_mcast.3 new file mode 100644 index 000000000000..9f6213e6cf78 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_attach_mcast.3 @@ -0,0 +1,53 @@ +.\" -*- nroff -*- +.\" +.TH IBV_ATTACH_MCAST 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_attach_mcast, ibv_detach_mcast \- attach and detach a queue pair +(QPs) to/from a multicast group +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_attach_mcast(struct ibv_qp " "*qp" ", const union ibv_gid " "*gid" ", +.BI " uint16_t " "lid" "); +.sp +.BI "int ibv_detach_mcast(struct ibv_qp " "*qp" ", const union ibv_gid " "*gid" ", +.BI " uint16_t " "lid" "); +.fi +.SH "DESCRIPTION" +.B ibv_attach_mcast() +attaches the QP +.I qp +to the multicast group having MGID +.I gid +and MLID +.I lid\fR. +.PP +.B ibv_detach_mcast() +detaches the QP +.I qp +to the multicast group having MGID +.I gid +and MLID +.I lid\fR. +.SH "RETURN VALUE" +.B ibv_attach_mcast() +and +.B ibv_detach_mcast() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +Only QPs of Transport Service Type +.BR IBV_QPT_UD +may be attached to multicast groups. +.PP +If a QP is attached to the same multicast group multiple times, the QP will still receive a single copy of a multicast message. +.PP +In order to receive multicast messages, a join request for the +multicast group must be sent to the subnet administrator (SA), so that +the fabric's multicast routing is configured to deliver messages to +the local port. +.SH "SEE ALSO" +.BR ibv_create_qp (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_create_ah.3 b/contrib/ofed/libibverbs/man/ibv_create_ah.3 new file mode 100644 index 000000000000..0260f0f53de0 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_create_ah.3 @@ -0,0 +1,64 @@ +.\" -*- nroff -*- +.\" +.TH IBV_CREATE_AH 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_create_ah, ibv_destroy_ah \- create or destroy an address handle (AH) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "struct ibv_ah *ibv_create_ah(struct ibv_pd " "*pd" ", +.BI " struct ibv_ah_attr " "*attr" "); +.sp +.BI "int ibv_destroy_ah(struct ibv_ah " "*ah" "); +.fi +.SH "DESCRIPTION" +.B ibv_create_ah() +creates an address handle (AH) associated with the protection domain +.I pd\fR. +The argument +.I attr +is an ibv_ah_attr struct, as defined in . +.PP +.nf +struct ibv_ah_attr { +.in +8 +struct ibv_global_route grh; /* Global Routing Header (GRH) attributes */ +uint16_t dlid; /* Destination LID */ +uint8_t sl; /* Service Level */ +uint8_t src_path_bits; /* Source path bits */ +uint8_t static_rate; /* Maximum static rate */ +uint8_t is_global; /* GRH attributes are valid */ +uint8_t port_num; /* Physical port number */ +.in -8 +}; +.sp +.nf +struct ibv_global_route { +.in +8 +union ibv_gid dgid; /* Destination GID or MGID */ +uint32_t flow_label; /* Flow label */ +uint8_t sgid_index; /* Source GID index */ +uint8_t hop_limit; /* Hop limit */ +uint8_t traffic_class; /* Traffic class */ +.in -8 +}; +.fi +.sp +.PP +.B ibv_destroy_ah() +destroys the AH +.I ah\fR. +.SH "RETURN VALUE" +.B ibv_create_ah() +returns a pointer to the created AH, or NULL if the request fails. +.PP +.B ibv_destroy_ah() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "SEE ALSO" +.BR ibv_alloc_pd (3), +.BR ibv_init_ah_from_wc (3), +.BR ibv_create_ah_from_wc (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_create_ah_from_wc.3 b/contrib/ofed/libibverbs/man/ibv_create_ah_from_wc.3 new file mode 100644 index 000000000000..eb20dd3e7139 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_create_ah_from_wc.3 @@ -0,0 +1,63 @@ +.\" -*- nroff -*- +.\" +.TH IBV_CREATE_AH_FROM_WC 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_init_ah_from_wc, ibv_create_ah_from_wc \- initialize or create an +address handle (AH) from a work completion +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_init_ah_from_wc(struct ibv_context " "*context" ", uint8_t " "port_num" , +.BI " struct ibv_wc " "*wc" ", struct ibv_grh " "*grh" , +.BI " struct ibv_ah_attr " "*ah_attr" ); +.sp +.BI "struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd " "*pd" , +.BI " struct ibv_wc " "*wc" , +.BI " struct ibv_grh " "*grh" , +.BI " uint8_t " "port_num" ); +.fi +.SH "DESCRIPTION" +.B ibv_init_ah_from_wc() +initializes the address handle (AH) attribute structure +.I ah_attr +for the RDMA device context +.I context +using the port number +.I port_num\fR, +using attributes from the work completion +.I wc +and the Global Routing Header (GRH) structure +.I grh\fR. +.PP +.B ibv_create_ah_from_wc() +creates an AH associated with the protection domain +.I pd +using the port number +.I port_num\fR, +using attributes from the work completion +.I wc +and the Global Routing Header (GRH) structure +.I grh\fR. +.SH "RETURN VALUE" +.B ibv_init_ah_from_wc() +returns 0 on success, and \-1 on error. +.PP +.B ibv_create_ah_from_wc() +returns a pointer to the created AH, or NULL if the request fails. +.SH "NOTES" +The filled structure +.I ah_attr +returned from +.B ibv_init_ah_from_wc() +can be used to create a new AH using +.B ibv_create_ah()\fR. +.SH "SEE ALSO" +.BR ibv_open_device (3), +.BR ibv_alloc_pd (3), +.BR ibv_create_ah (3), +.BR ibv_destroy_ah (3), +.BR ibv_poll_cq (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_create_comp_channel.3 b/contrib/ofed/libibverbs/man/ibv_create_comp_channel.3 new file mode 100644 index 000000000000..285ee04571ee --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_create_comp_channel.3 @@ -0,0 +1,50 @@ +.\" -*- nroff -*- +.\" +.TH IBV_CREATE_COMP_CHANNEL 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_create_comp_channel, ibv_destroy_comp_channel \- create or +destroy a completion event channel +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context +.BI " " "*context" ); +.sp +.BI "int ibv_destroy_comp_channel(struct ibv_comp_channel " "*channel" ); +.fi +.SH "DESCRIPTION" +.B ibv_create_comp_channel() +creates a completion event channel for the RDMA device context +.I context\fR. +.PP +.B ibv_destroy_comp_channel() +destroys the completion event channel +.I channel\fR. +.SH "RETURN VALUE" +.B ibv_create_comp_channel() +returns a pointer to the created completion event channel, or NULL if the request fails. +.PP +.B ibv_destroy_comp_channel() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +A "completion channel" is an abstraction introduced by libibverbs that +does not exist in the InfiniBand Architecture verbs specification or +RDMA Protocol Verbs Specification. A completion channel is +essentially file descriptor that is used to deliver completion +notifications to a userspace process. When a completion event is +generated for a completion queue (CQ), the event is delivered via the +completion channel attached to that CQ. This may be useful to steer +completion events to different threads by using multiple completion +channels. +.PP +.B ibv_destroy_comp_channel() +fails if any CQs are still associated with the completion event +channel being destroyed. +.SH "SEE ALSO" +.BR ibv_open_device (3), +.BR ibv_create_cq (3), +.BR ibv_get_cq_event (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_create_cq.3 b/contrib/ofed/libibverbs/man/ibv_create_cq.3 new file mode 100644 index 000000000000..cfa5f3e1af8d --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_create_cq.3 @@ -0,0 +1,58 @@ +.\" -*- nroff -*- +.\" +.TH IBV_CREATE_CQ 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_create_cq, ibv_destroy_cq \- create or destroy a completion queue (CQ) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "struct ibv_cq *ibv_create_cq(struct ibv_context " "*context" ", int " "cqe" , +.BI " void " "*cq_context" , +.BI " struct ibv_comp_channel " "*channel" , +.BI " int " "comp_vector" ); +.sp +.BI "int ibv_destroy_cq(struct ibv_cq " "*cq" ); +.fi +.SH "DESCRIPTION" +.B ibv_create_cq() +creates a completion queue (CQ) with at least +.I cqe +entries for the RDMA device context +.I context\fR. +The pointer +.I cq_context +will be used to set user context pointer of the CQ structure. The argument +.I channel +is optional; if not NULL, the completion channel +.I channel +will be used to return completion events. The CQ will use the +completion vector +.I comp_vector +for signaling completion events; it must be at least zero and less than +.I context\fR->num_comp_vectors. +.PP +.B ibv_destroy_cq() +destroys the CQ +.I cq\fR. +.SH "RETURN VALUE" +.B ibv_create_cq() +returns a pointer to the CQ, or NULL if the request fails. +.PP +.B ibv_destroy_cq() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +.B ibv_create_cq() +may create a CQ with size greater than or equal to the requested +size. Check the cqe attribute in the returned CQ for the actual size. +.PP +.B ibv_destroy_cq() +fails if any queue pair is still associated with this CQ. +.SH "SEE ALSO" +.BR ibv_resize_cq (3), +.BR ibv_req_notify_cq (3), +.BR ibv_ack_cq_events (3), +.BR ibv_create_qp (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_create_qp.3 b/contrib/ofed/libibverbs/man/ibv_create_qp.3 new file mode 100644 index 000000000000..106b31cece99 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_create_qp.3 @@ -0,0 +1,86 @@ +.\" -*- nroff -*- +.\" +.TH IBV_CREATE_QP 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_create_qp, ibv_destroy_qp \- create or destroy a queue pair (QP) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "struct ibv_qp *ibv_create_qp(struct ibv_pd " "*pd" , +.BI " struct ibv_qp_init_attr " "*qp_init_attr" ); +.sp +.BI "int ibv_destroy_qp(struct ibv_qp " "*qp" ); +.fi +.SH "DESCRIPTION" +.B ibv_create_qp() +creates a queue pair (QP) associated with the protection domain +.I pd\fR. +The argument +.I qp_init_attr +is an ibv_qp_init_attr struct, as defined in . +.PP +.nf +struct ibv_qp_init_attr { +.in +8 +void *qp_context; /* Associated context of the QP */ +struct ibv_cq *send_cq; /* CQ to be associated with the Send Queue (SQ) */ +struct ibv_cq *recv_cq; /* CQ to be associated with the Receive Queue (RQ) */ +struct ibv_srq *srq; /* SRQ handle if QP is to be associated with an SRQ, otherwise NULL */ +struct ibv_qp_cap cap; /* QP capabilities */ +enum ibv_qp_type qp_type; /* QP Transport Service Type: IBV_QPT_RC, IBV_QPT_UC, IBV_QPT_UD or IBV_QPT_XRC */ +int sq_sig_all; /* If set, each Work Request (WR) submitted to the SQ generates a completion entry */ +struct ibv_xrc_domain *xrc_domain; /* XRC domain the QP will be associated with (valid only for IBV_QPT_XRC QP), otherwise NULL */ +.in -8 +}; +.sp +.nf +struct ibv_qp_cap { +.in +8 +uint32_t max_send_wr; /* Requested max number of outstanding WRs in the SQ */ +uint32_t max_recv_wr; /* Requested max number of outstanding WRs in the RQ */ +uint32_t max_send_sge; /* Requested max number of scatter/gather (s/g) elements in a WR in the SQ */ +uint32_t max_recv_sge; /* Requested max number of s/g elements in a WR in the SQ */ +uint32_t max_inline_data;/* Requested max number of data (bytes) that can be posted inline to the SQ, otherwise 0 */ +.in -8 +}; +.fi +.PP +The function +.B ibv_create_qp() +will update the +.I qp_init_attr\fB\fR->cap +struct with the actual \s-1QP\s0 values of the QP that was created; +the values will be greater than or equal to the values requested. +.PP +.B ibv_destroy_qp() +destroys the QP +.I qp\fR. +.SH "RETURN VALUE" +.B ibv_create_qp() +returns a pointer to the created QP, or NULL if the request fails. +Check the QP number (\fBqp_num\fR) in the returned QP. +.PP +.B ibv_destroy_qp() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +.B ibv_create_qp() +will fail if a it is asked to create QP of a type other than +.B IBV_QPT_RC +or +.B IBV_QPT_UD +associated with an SRQ. +.PP +The attributes max_recv_wr and max_recv_sge are ignored by +.B ibv_create_qp() +if the QP is to be associated with an SRQ. +.PP +.B ibv_destroy_qp() +fails if the QP is attached to a multicast group. +.SH "SEE ALSO" +.BR ibv_alloc_pd (3), +.BR ibv_modify_qp (3), +.BR ibv_query_qp (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_create_srq.3 b/contrib/ofed/libibverbs/man/ibv_create_srq.3 new file mode 100644 index 000000000000..fae9c0c59802 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_create_srq.3 @@ -0,0 +1,81 @@ +.\" -*- nroff -*- +.\" +.TH IBV_CREATE_SRQ 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_create_srq, ibv_destroy_srq \- create or destroy a shared receive queue (SRQ) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "struct ibv_srq *ibv_create_srq(struct ibv_pd " "*pd" ", struct " +.BI " ibv_srq_init_attr " "*srq_init_attr" ); +.sp +.BI "struct ibv_srq *ibv_create_xrc_srq(struct ibv_pd " "*pd" ", +.BI " struct ibv_xrc_domain " "*xrc_domain" ", +.BI " struct ibv_cq " "*xrc_cq" ", +.BI " struct ibv_srq_init_attr " "*srq_init_attr" ); +.sp +.BI "int ibv_destroy_srq(struct ibv_srq " "*srq" ); +.fi +.SH "DESCRIPTION" +.B ibv_create_srq() +creates a shared receive queue (SRQ) associated with the protection domain +.I pd\fR. +.PP +.B ibv_create_xrc_srq() +creates an XRC shared receive queue (SRQ) associated with the protection domain +.I pd\fR, +the XRC domain +.I xrc_domain +and the CQ which will hold the XRC completion +.I xrc_cq\fR. +.PP +The argument +.I srq_init_attr +is an ibv_srq_init_attr struct, as defined in . +.PP +.nf +struct ibv_srq_init_attr { +.in +8 +void *srq_context; /* Associated context of the SRQ */ +struct ibv_srq_attr attr; /* SRQ attributes */ +.in -8 +}; +.sp +.nf +struct ibv_srq_attr { +.in +8 +uint32_t max_wr; /* Requested max number of outstanding work requests (WRs) in the SRQ */ +uint32_t max_sge; /* Requested max number of scatter elements per WR */ +uint32_t srq_limit; /* The limit value of the SRQ (irrelevant for ibv_create_srq) */ +.in -8 +}; +.fi +.PP +The function +.B ibv_create_srq() +will update the +.I srq_init_attr +struct with the original values of the SRQ that was created; the +values of max_wr and max_sge will be greater than or equal to the +values requested. +.PP +.B ibv_destroy_srq() +destroys the SRQ +.I srq\fR. +.SH "RETURN VALUE" +.B ibv_create_srq() +returns a pointer to the created SRQ, or NULL if the request fails. +.PP +.B ibv_destroy_srq() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +.B ibv_destroy_srq() +fails if any queue pair is still associated with this SRQ. +.SH "SEE ALSO" +.BR ibv_alloc_pd (3), +.BR ibv_modify_srq (3), +.BR ibv_query_srq (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_create_xrc_rcv_qp.3 b/contrib/ofed/libibverbs/man/ibv_create_xrc_rcv_qp.3 new file mode 100644 index 000000000000..2877c15b3559 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_create_xrc_rcv_qp.3 @@ -0,0 +1,70 @@ +.\" -*- nroff -*- +.\" +.TH IBV_CREATE_XRC_RCV_QP 3 2008-02-10 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_create_xrc_rcv_qp \- create an XRC queue pair (QP) for serving as a receive-side only QP +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_create_xrc_rcv_qp(struct ibv_qp_init_attr " "*init_attr" , +.BI " uint32_t " "*xrc_rcv_qpn" ); +.fi +.SH "DESCRIPTION" +.B ibv_create_xrc_rcv_qp() +creates an XRC queue pair (QP) for serving as a receive-side only QP and returns its number through the pointer +.I xrc_rcv_qpn\fR. +This QP number should be passed to the remote node (sender). +The remote node will use +.I xrc_rcv_qpn +in +.B ibv_post_send() +when sending to an XRC SRQ on this host in the same xrc domain as the XRC receive QP. +This QP is created in kernel space, and persists until the last process registered for the QP +calls +.B ibv_unreg_xrc_rcv_qp() +(at which time the QP is destroyed). +.PP +The process which creates this QP is automatically registered for it, and should also call +.B ibv_unreg_xrc_rcv_qp() +at some point, to unregister. + +Processes which wish to receive on an XRC SRQ via this QP should call +.B ibv_reg_xrc_rcv_qp() +for this QP, to guarantee that the QP will not be destroyed while they are still using it for receiving on the XRC SRQ. +.PP +The argument +.I qp_init_attr +is an ibv_qp_init_attr struct, as defined in . +.PP +.nf +struct ibv_qp_init_attr { +.in +8 +void *qp_context; /* value is being ignored */ +struct ibv_cq *send_cq; /* value is being ignored */ +struct ibv_cq *recv_cq; /* value is being ignored */ +struct ibv_srq *srq; /* value is being ignored */ +struct ibv_qp_cap cap; /* value is being ignored */ +enum ibv_qp_type qp_type; /* value is being ignored */ +int sq_sig_all; /* value is being ignored */ +struct ibv_xrc_domain *xrc_domain; /* XRC domain the QP will be associated with */ +.in -8 +}; +.fi +.PP +Most of the attributes in +.I qp_init_attr +are being ignored because this QP is a receive only QP and all RR are being posted to an SRQ. +.SH "RETURN VALUE" +.B ibv_create_xrc_rcv_qp() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "SEE ALSO" +.BR ibv_open_xrc_domain (3), +.BR ibv_modify_xrc_rcv_qp (3), +.BR ibv_query_xrc_rcv_qp (3), +.BR ibv_reg_xrc_rcv_qp (3), +.BR ibv_unreg_xrc_rcv_qp (3), +.BR ibv_post_send (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_devices.1 b/contrib/ofed/libibverbs/man/ibv_devices.1 new file mode 100644 index 000000000000..99b27e5c3b9d --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_devices.1 @@ -0,0 +1,19 @@ +.TH IBV_DEVICES 1 "August 30, 2005" "libibverbs" "USER COMMANDS" + +.SH NAME +ibv_devices \- list RDMA devices + +.SH SYNOPSIS +.B ibv_devices + +.SH DESCRIPTION +.PP +List RDMA devices available for use from userspace. + +.SH SEE ALSO +.BR ibv_devinfo (1) + +.SH AUTHORS +.TP +Roland Dreier +.RI < rolandd@cisco.com > diff --git a/contrib/ofed/libibverbs/man/ibv_devinfo.1 b/contrib/ofed/libibverbs/man/ibv_devinfo.1 new file mode 100644 index 000000000000..41878b2c0696 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_devinfo.1 @@ -0,0 +1,39 @@ +.TH IBV_DEVINFO 1 "August 30, 2005" "libibverbs" "USER COMMANDS" + +.SH NAME +ibv_devinfo \- query RDMA devices + +.SH SYNOPSIS +.B ibv_devinfo +[\-d device] [\-i port] [\-l] [\-v] + +.SH DESCRIPTION +.PP +Print information about RDMA devices available for use from userspace. + +.SH OPTIONS + +.PP +.TP +\fB\-d\fR, \fB\-\-ib\-dev\fR=\fIDEVICE\fR +use IB device \fIDEVICE\fR (default first device found) + +\fB\-i\fR, \fB\-\-ib\-port\fR=\fIPORT\fR +query port \fIPORT\fR (default all ports) + +\fB\-l\fR, \fB\-\-list\fR +only list names of RDMA devices + +\fB\-v\fR, \fB\-\-verbose\fR +print all available information about RDMA devices + +.SH SEE ALSO +.BR ibv_devices (1) + +.SH AUTHORS +.TP +Dotan Barak +.RI < dotanb@mellanox.co.il > +.TP +Roland Dreier +.RI < rolandd@cisco.com > diff --git a/contrib/ofed/libibverbs/man/ibv_event_type_str.3 b/contrib/ofed/libibverbs/man/ibv_event_type_str.3 new file mode 100644 index 000000000000..f9ebc35bbacc --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_event_type_str.3 @@ -0,0 +1,40 @@ +.\" -*- nroff -*- +.\" +.TH IBV_EVENT_TYPE_STR 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +.nf +ibv_event_type_str \- Return string describing event_type enum value +.sp +ibv_node_type_str \- Return string describing node_type enum value +.sp +ibv_port_state_str \- Return string describing port_state enum value +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "const char *ibv_event_type_str(enum ibv_event_type " "event_type"); +.sp +.BI "const char *ibv_node_type_str(enum ibv_node_type " "node_type"); +.sp +.BI "const char *ibv_port_state_str(enum ibv_port_state " "port_state"); +.fi +.SH "DESCRIPTION" +.B ibv_node_type_str() +returns a string describing the node type enum value +.IR node_type . +.PP +.B ibv_port_state_str() +returns a string describing the port state enum value +.IR port_state . +.PP +.B ibv_event_type_str() +returns a string describing the event type enum value +.IR event_type . +.SH "RETURN VALUE" +These functions return a constant string that describes the enum value +passed as their argument. +.SH "AUTHOR" +.TP +Roland Dreier +.RI < rolandd@cisco.com > + diff --git a/contrib/ofed/libibverbs/man/ibv_fork_init.3 b/contrib/ofed/libibverbs/man/ibv_fork_init.3 new file mode 100644 index 000000000000..b34f71f19b17 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_fork_init.3 @@ -0,0 +1,58 @@ +.\" -*- nroff -*- +.\" +.TH IBV_FORK_INIT 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_fork_init \- initialize libibverbs to support fork() +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_fork_init(void); +.fi +.SH "DESCRIPTION" +.B ibv_fork_init() +initializes libibverbs's data structures to handle +.B fork() +function calls correctly and avoid data corruption, whether +.B fork() +is called explicitly or implicitly (such as in +.B system()\fR). +.PP +It is not necessary to use this function if all parent process threads +are always blocked until all child processes end or change address +spaces via an +.B exec() +operation. +.SH "RETURN VALUE" +.B ibv_fork_init() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +.B ibv_fork_init() +works on Linux kernels supporting the +.BR MADV_DONTFORK +flag for +.B madvise() +(2.6.17 and higher). +.PP +Setting the environment variable +.BR RDMAV_FORK_SAFE +or +.BR IBV_FORK_SAFE +has the same effect as calling +.B ibv_fork_init()\fR. +.PP +Calling +.B ibv_fork_init() +will reduce performance due to an extra system call for every memory +registration, and the additional memory allocated to track memory +regions. The precise performance impact depends on the workload and +usually will not be significant. +.SH "SEE ALSO" +.BR fork (2), +.BR wait (2), +.BR system (3), +.BR exec (3), +.BR ibv_get_device_list (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_get_async_event.3 b/contrib/ofed/libibverbs/man/ibv_get_async_event.3 new file mode 100644 index 000000000000..7426f4da0729 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_get_async_event.3 @@ -0,0 +1,162 @@ +.\" -*- nroff -*- +.\" +.TH IBV_GET_ASYNC_EVENT 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_get_async_event, ibv_ack_async_event \- get or acknowledge asynchronous events +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_get_async_event(struct ibv_context " "*context" , +.BI " struct ibv_async_event " "*event" ); +.sp +.BI "void ibv_ack_async_event(struct ibv_async_event " "*event" ); +.fi +.SH "DESCRIPTION" +.B ibv_get_async_event() +waits for the next async event of the RDMA device context +.I context +and returns it through the pointer +.I event\fR, +which is an ibv_async_event struct, as defined in . +.PP +.nf +struct ibv_async_event { +.in +8 +union { +.in +8 +struct ibv_cq *cq; /* CQ that got the event */ +struct ibv_qp *qp; /* QP that got the event */ +struct ibv_srq *srq; /* SRQ that got the event */ +int port_num; /* port number that got the event */ +.in -8 +} element; +enum ibv_event_type event_type; /* type of the event */ +.in -8 +}; +.fi +.PP +One member of the element union will be valid, depending on the +event_type member of the structure. event_type will be one of the +following events: +.PP +.I QP events: +.TP +.B IBV_EVENT_QP_FATAL \fR Error occurred on a QP and it transitioned to error state +.TP +.B IBV_EVENT_QP_REQ_ERR \fR Invalid Request Local Work Queue Error +.TP +.B IBV_EVENT_QP_ACCESS_ERR \fR Local access violation error +.TP +.B IBV_EVENT_COMM_EST \fR Communication was established on a QP +.TP +.B IBV_EVENT_SQ_DRAINED \fR Send Queue was drained of outstanding messages in progress +.TP +.B IBV_EVENT_PATH_MIG \fR A connection has migrated to the alternate path +.TP +.B IBV_EVENT_PATH_MIG_ERR \fR A connection failed to migrate to the alternate path +.TP +.B IBV_EVENT_QP_LAST_WQE_REACHED \fR Last WQE Reached on a QP associated with an SRQ +.PP +.I CQ events: +.TP +.B IBV_EVENT_CQ_ERR \fR CQ is in error (CQ overrun) +.PP +.I SRQ events: +.TP +.B IBV_EVENT_SRQ_ERR \fR Error occurred on an SRQ +.TP +.B IBV_EVENT_SRQ_LIMIT_REACHED \fR SRQ limit was reached +.PP +.I Port events: +.TP +.B IBV_EVENT_PORT_ACTIVE \fR Link became active on a port +.TP +.B IBV_EVENT_PORT_ERR \fR Link became unavailable on a port +.TP +.B IBV_EVENT_LID_CHANGE \fR LID was changed on a port +.TP +.B IBV_EVENT_PKEY_CHANGE \fR P_Key table was changed on a port +.TP +.B IBV_EVENT_SM_CHANGE \fR SM was changed on a port +.TP +.B IBV_EVENT_CLIENT_REREGISTER \fR SM sent a CLIENT_REREGISTER request to a port +.PP +.I CA events: +.TP +.B IBV_EVENT_DEVICE_FATAL \fR CA is in FATAL state +.PP +.B ibv_ack_async_event() +acknowledge the async event +.I event\fR. +.SH "RETURN VALUE" +.B ibv_get_async_event() +returns 0 on success, and \-1 on error. +.PP +.B ibv_ack_async_event() +returns no value. +.SH "NOTES" +All async events that +.B ibv_get_async_event() +returns must be acknowledged using +.B ibv_ack_async_event()\fR. +To avoid races, destroying an object (CQ, SRQ or QP) will wait for all +affiliated events for the object to be acknowledged; this avoids an +application retrieving an affiliated event after the corresponding +object has already been destroyed. +.PP +.B ibv_get_async_event() +is a blocking function. If multiple threads call this function +simultaneously, then when an async event occurs, only one thread will +receive it, and it is not possible to predict which thread will +receive it. +.SH "EXAMPLES" +The following code example demonstrates one possible way to work with async events in non-blocking mode. +It performs the following steps: +.PP +1. Set the async events queue work mode to be non-blocked +.br +2. Poll the queue until it has an async event +.br +3. Get the async event and ack it +.PP +.nf +/* change the blocking mode of the async event queue */ +flags = fcntl(ctx->async_fd, F_GETFL); +rc = fcntl(ctx->async_fd, F_SETFL, flags | O_NONBLOCK); +if (rc < 0) { + fprintf(stderr, "Failed to change file descriptor of async event queue\en"); + return 1; +} + +/* + * poll the queue until it has an event and sleep ms_timeout + * milliseconds between any iteration + */ +my_pollfd.fd = ctx->async_fd; +my_pollfd.events = POLLIN; +my_pollfd.revents = 0; + +do { + rc = poll(&my_pollfd, 1, ms_timeout); +} while (rc == 0); +if (rc < 0) { + fprintf(stderr, "poll failed\en"); + return 1; +} + +/* Get the async event */ +if (ibv_get_async_event(ctx, &async_event)) { + fprintf(stderr, "Failed to get async_event\en"); + return 1; +} + +/* Ack the event */ +ibv_ack_async_event(&async_event); + +.fi +.SH "SEE ALSO" +.BR ibv_open_device (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_get_cq_event.3 b/contrib/ofed/libibverbs/man/ibv_get_cq_event.3 new file mode 100644 index 000000000000..58c744a87d0e --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_get_cq_event.3 @@ -0,0 +1,185 @@ +.\" -*- nroff -*- +.\" +.TH IBV_GET_CQ_EVENT 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_get_cq_event, ibv_ack_cq_events \- get and acknowledge completion queue (CQ) events + +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_get_cq_event(struct ibv_comp_channel " "*channel" , +.BI " struct ibv_cq " "**cq" ", void " "**cq_context" ); +.sp +.BI "void ibv_ack_cq_events(struct ibv_cq " "*cq" ", unsigned int " "nevents" ); +.fi + +.SH "DESCRIPTION" +.B ibv_get_cq_event() +waits for the next completion event in the completion event channel +.I channel\fR. +Fills the arguments +.I cq +with the CQ that got the event and +.I cq_context +with the CQ's context\fR. +.PP +.B ibv_ack_cq_events() +acknowledges +.I nevents +events on the CQ +.I cq\fR. + +.SH "RETURN VALUE" +.B ibv_get_cq_event() +returns 0 on success, and \-1 on error. +.PP +.B ibv_ack_cq_events() +returns no value. +.SH "NOTES" +All completion events that +.B ibv_get_cq_event() +returns must be acknowledged using +.B ibv_ack_cq_events()\fR. +To avoid races, destroying a CQ will wait for all completion events to +be acknowledged; this guarantees a one-to-one correspondence between +acks and successful gets. +.PP +Calling +.B ibv_ack_cq_events() +may be relatively expensive in the datapath, since it must take a +mutex. Therefore it may be better to amortize this cost by +keeping a count of the number of events needing acknowledgement and +acking several completion events in one call to +.B ibv_ack_cq_events()\fR. +.SH "EXAMPLES" +The following code example demonstrates one possible way to work with +completion events. It performs the following steps: +.PP +Stage I: Preparation +.br +1. Creates a CQ +.br +2. Requests for notification upon a new (first) completion event +.PP +Stage II: Completion Handling Routine +.br +3. Wait for the completion event and ack it +.br +4. Request for notification upon the next completion event +.br +5. Empty the CQ +.PP +Note that an extra event may be triggered without having a +corresponding completion entry in the CQ. This occurs if a completion +entry is added to the CQ between Step 4 and Step 5, and the CQ is then +emptied (polled) in Step 5. +.PP +.nf +cq = ibv_create_cq(ctx, 1, ev_ctx, channel, 0); +if (!cq) { + fprintf(stderr, "Failed to create CQ\en"); + return 1; +} +.PP +/* Request notification before any completion can be created */ +if (ibv_req_notify_cq(cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\en"); + return 1; +} +.PP +\&. +\&. +\&. +.PP +/* Wait for the completion event */ +if (ibv_get_cq_event(channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\en"); + return 1; +} + +/* Ack the event */ +ibv_ack_cq_events(ev_cq, 1); +.PP +/* Request notification upon the next completion event */ +if (ibv_req_notify_cq(ev_cq, 0)) { + fprintf(stderr, "Couldn't request CQ notification\en"); + return 1; +} +.PP +/* Empty the CQ: poll all of the completions from the CQ (if any exist) */ +do { + ne = ibv_poll_cq(cq, 1, &wc); + if (ne < 0) { + fprintf(stderr, "Failed to poll completions from the CQ\en"); + return 1; + } + + /* there may be an extra event with no completion in the CQ */ + if (ne == 0) + continue; +.PP + if (wc.status != IBV_WC_SUCCESS) { + fprintf(stderr, "Completion with status 0x%x was found\en", wc.status); + return 1; + } +} while (ne); +.fi + +The following code example demonstrates one possible way to work with +completion events in non-blocking mode. It performs the following +steps: +.PP +1. Set the completion event channel to be non-blocked +.br +2. Poll the channel until there it has a completion event +.br +3. Get the completion event and ack it +.PP +.nf +/* change the blocking mode of the completion channel */ +flags = fcntl(channel->fd, F_GETFL); +rc = fcntl(channel->fd, F_SETFL, flags | O_NONBLOCK); +if (rc < 0) { + fprintf(stderr, "Failed to change file descriptor of completion event channel\en"); + return 1; +} + + +/* + * poll the channel until it has an event and sleep ms_timeout + * milliseconds between any iteration + */ +my_pollfd.fd = channel->fd; +my_pollfd.events = POLLIN; +my_pollfd.revents = 0; + +do { + rc = poll(&my_pollfd, 1, ms_timeout); +} while (rc == 0); +if (rc < 0) { + fprintf(stderr, "poll failed\en"); + return 1; +} +ev_cq = cq; + +/* Wait for the completion event */ +if (ibv_get_cq_event(channel, &ev_cq, &ev_ctx)) { + fprintf(stderr, "Failed to get cq_event\en"); + return 1; +} + +/* Ack the event */ +ibv_ack_cq_events(ev_cq, 1); + +.fi +.SH "SEE ALSO" +.BR ibv_create_comp_channel (3), +.BR ibv_create_cq (3), +.BR ibv_req_notify_cq (3), +.BR ibv_poll_cq (3) + +.SH "AUTHORS" +.TP +Dotan Barak +.RI < dotanb@mellanox.co.il > diff --git a/contrib/ofed/libibverbs/man/ibv_get_device_guid.3 b/contrib/ofed/libibverbs/man/ibv_get_device_guid.3 new file mode 100644 index 000000000000..98c0499b9ec0 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_get_device_guid.3 @@ -0,0 +1,25 @@ +.\" -*- nroff -*- +.\" +.TH IBV_GET_DEVICE_GUID 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_get_device_guid \- get an RDMA device's GUID +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "uint64_t ibv_get_device_guid(struct ibv_device " "*device" "); +.fi +.SH "DESCRIPTION" +.B ibv_get_device_name() +returns the Global Unique IDentifier (GUID) of the RDMA device +.I device\fR. +.SH "RETURN VALUE" +.B ibv_get_device_guid() +returns the GUID of the device in network byte order. +.SH "SEE ALSO" +.BR ibv_get_device_list (3), +.BR ibv_get_device_name (3), +.BR ibv_open_device (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_get_device_list.3 b/contrib/ofed/libibverbs/man/ibv_get_device_list.3 new file mode 100644 index 000000000000..399beea845d5 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_get_device_list.3 @@ -0,0 +1,60 @@ +.\" -*- nroff -*- +.\" +.TH IBV_GET_DEVICE_LIST 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_get_device_list, ibv_free_device_list \- get and release list of available RDMA devices +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "struct ibv_device **ibv_get_device_list(int " "*num_devices" ); +.sp +.BI "void ibv_free_device_list(struct ibv_device " "**list" ); +.fi +.SH "DESCRIPTION" +.B ibv_get_device_list() +returns a NULL-terminated array of RDMA devices currently available. +The argument +.I num_devices +is optional; if not NULL, it is set to the number of devices returned in the array. +.PP +.B ibv_free_device_list() +frees the array of devices +.I list +returned by +.B ibv_get_device_list()\fR. +.SH "RETURN VALUE" +.B ibv_get_device_list() +returns the array of available RDMA devices, or sets +.I errno +and returns NULL if the request fails. If no devices are found then +.I num_devices +is set to 0, and non-NULL is returned. +.PP +.B ibv_free_device_list() +returns no value. +.SH "ERRORS" +.TP +.B EPERM +Permission denied. +.TP +.B ENOSYS +No kernel support for RDMA. +.TP +.B ENOMEM +Insufficient memory to complete the operation. +.SH "NOTES" +Client code should open all the devices it intends to use with +.B ibv_open_device()\fR before calling +.B ibv_free_device_list()\fR. +Once it frees the array with +.B ibv_free_device_list()\fR, +it will be able to use only the open devices; pointers to unopened devices will no longer be valid. +.SH "SEE ALSO" +.BR ibv_fork_init (3), +.BR ibv_get_device_name (3), +.BR ibv_get_device_guid (3), +.BR ibv_open_device (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_get_device_name.3 b/contrib/ofed/libibverbs/man/ibv_get_device_name.3 new file mode 100644 index 000000000000..284ea9f937eb --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_get_device_name.3 @@ -0,0 +1,25 @@ +.\" -*- nroff -*- +.\" +.TH IBV_GET_DEVICE_NAME 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_get_device_name \- get an RDMA device's name +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "const char *ibv_get_device_name(struct ibv_device " "*device" "); +.fi +.SH "DESCRIPTION" +.B ibv_get_device_name() +returns a human-readable name associated with the RDMA device +.I device\fR. +.SH "RETURN VALUE" +.B ibv_get_device_name() +returns a pointer to the device name, or NULL if the request fails. +.SH "SEE ALSO" +.BR ibv_get_device_list (3), +.BR ibv_get_device_guid (3), +.BR ibv_open_device (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_modify_qp.3 b/contrib/ofed/libibverbs/man/ibv_modify_qp.3 new file mode 100644 index 000000000000..864ffe69c1a3 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_modify_qp.3 @@ -0,0 +1,169 @@ +.\" -*- nroff -*- +.\" +.TH IBV_MODIFY_QP 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_modify_qp \- modify the attributes of a queue pair (QP) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_modify_qp(struct ibv_qp " "*qp" ", struct ibv_qp_attr " "*attr" , +.BI " int " "attr_mask" ); +.fi +.SH "DESCRIPTION" +.B ibv_modify_qp() +modifies the attributes of QP +.I qp +with the attributes in +.I attr +according to the mask +.I attr_mask\fR. +The argument \fIattr\fR is an ibv_qp_attr struct, as defined in . +.PP +.nf +struct ibv_qp_attr { +.in +8 +enum ibv_qp_state qp_state; /* Move the QP to this state */ +enum ibv_qp_state cur_qp_state; /* Assume this is the current QP state */ +enum ibv_mtu path_mtu; /* Path MTU (valid only for RC/UC QPs) */ +enum ibv_mig_state path_mig_state; /* Path migration state (valid if HCA supports APM) */ +uint32_t qkey; /* Q_Key for the QP (valid only for UD QPs) */ +uint32_t rq_psn; /* PSN for receive queue (valid only for RC/UC QPs) */ +uint32_t sq_psn; /* PSN for send queue (valid only for RC/UC QPs) */ +uint32_t dest_qp_num; /* Destination QP number (valid only for RC/UC QPs) */ +int qp_access_flags; /* Mask of enabled remote access operations (valid only for RC/UC QPs) */ +struct ibv_qp_cap cap; /* QP capabilities (valid if HCA supports QP resizing) */ +struct ibv_ah_attr ah_attr; /* Primary path address vector (valid only for RC/UC QPs) */ +struct ibv_ah_attr alt_ah_attr; /* Alternate path address vector (valid only for RC/UC QPs) */ +uint16_t pkey_index; /* Primary P_Key index */ +uint16_t alt_pkey_index; /* Alternate P_Key index */ +uint8_t en_sqd_async_notify; /* Enable SQD.drained async notification (Valid only if qp_state is SQD) */ +uint8_t sq_draining; /* Is the QP draining? Irrelevant for ibv_modify_qp() */ +uint8_t max_rd_atomic; /* Number of outstanding RDMA reads & atomic operations on the destination QP (valid only for RC QPs) */ +uint8_t max_dest_rd_atomic; /* Number of responder resources for handling incoming RDMA reads & atomic operations (valid only for RC QPs) */ +uint8_t min_rnr_timer; /* Minimum RNR NAK timer (valid only for RC QPs) */ +uint8_t port_num; /* Primary port number */ +uint8_t timeout; /* Local ack timeout for primary path (valid only for RC QPs) */ +uint8_t retry_cnt; /* Retry count (valid only for RC QPs) */ +uint8_t rnr_retry; /* RNR retry (valid only for RC QPs) */ +uint8_t alt_port_num; /* Alternate port number */ +uint8_t alt_timeout; /* Local ack timeout for alternate path (valid only for RC QPs) */ +.in -8 +}; +.fi +.PP +For details on struct ibv_qp_cap see the description of +.B ibv_create_qp()\fR. +For details on struct ibv_ah_attr see the description of +.B ibv_create_ah()\fR. +.PP +The argument +.I attr_mask +specifies the QP attributes to be modified. +The argument is either 0 or the bitwise OR of one or more of the following flags: +.PP +.TP +.B IBV_QP_STATE \fR Modify qp_state +.TP +.B IBV_QP_CUR_STATE \fR Set cur_qp_state +.TP +.B IBV_QP_EN_SQD_ASYNC_NOTIFY \fR Set en_sqd_async_notify +.TP +.B IBV_QP_ACCESS_FLAGS \fR Set qp_access_flags +.TP +.B IBV_QP_PKEY_INDEX \fR Set pkey_index +.TP +.B IBV_QP_PORT \fR Set port_num +.TP +.B IBV_QP_QKEY \fR Set qkey +.TP +.B IBV_QP_AV \fR Set ah_attr +.TP +.B IBV_QP_PATH_MTU \fR Set path_mtu +.TP +.B IBV_QP_TIMEOUT \fR Set timeout +.TP +.B IBV_QP_RETRY_CNT \fR Set retry_cnt +.TP +.B IBV_QP_RNR_RETRY \fR Set rnr_retry +.TP +.B IBV_QP_RQ_PSN \fR Set rq_psn +.TP +.B IBV_QP_MAX_QP_RD_ATOMIC \fR Set max_rd_atomic +.TP +.B IBV_QP_ALT_PATH \fR Set the alternative path via: alt_ah_attr, alt_pkey_index, alt_port_num, alt_timeout +.TP +.B IBV_QP_MIN_RNR_TIMER \fR Set min_rnr_timer +.TP +.B IBV_QP_SQ_PSN \fR Set sq_psn +.TP +.B IBV_QP_MAX_DEST_RD_ATOMIC \fR Set max_dest_rd_atomic +.TP +.B IBV_QP_PATH_MIG_STATE \fR Set path_mig_state +.TP +.B IBV_QP_CAP \fR Set cap +.TP +.B IBV_QP_DEST_QPN \fR Set dest_qp_num +.SH "RETURN VALUE" +.B ibv_modify_qp() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +If any of the modify attributes or the modify mask are invalid, none +of the attributes will be modified (including the QP state). +.PP +Not all devices support resizing QPs. To check if a device supports it, check if the +.B IBV_DEVICE_RESIZE_MAX_WR +bit is set in the device capabilities flags. +.PP +Not all devices support alternate paths. To check if a device supports it, check if the +.B IBV_DEVICE_AUTO_PATH_MIG +bit is set in the device capabilities flags. +.PP +The following tables indicate for each QP Transport Service Type, the +minimum list of attributes that must be changed upon transitioning QP +state from: Reset \-\-> Init \-\-> RTR \-\-> RTS. +.PP +.nf +For QP Transport Service Type \fB IBV_QPT_UD\fR: +.sp +Next state Required attributes +\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- +Init \fB IBV_QP_STATE, IBV_QP_PKEY_INDEX, IBV_QP_PORT, \fR + \fB IBV_QP_QKEY \fR +RTR \fB IBV_QP_STATE \fR +RTS \fB IBV_QP_STATE, IBV_QP_SQ_PSN \fR +.fi +.PP +.nf +For QP Transport Service Type \fB IBV_QPT_UC\fR: +.sp +Next state Required attributes +\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- +Init \fB IBV_QP_STATE, IBV_QP_PKEY_INDEX, IBV_QP_PORT, \fR + \fB IBV_QP_ACCESS_FLAGS \fR +RTR \fB IBV_QP_STATE, IBV_QP_AV, IBV_QP_PATH_MTU, \fR + \fB IBV_QP_DEST_QPN, IBV_QP_RQ_PSN \fR +RTS \fB IBV_QP_STATE, IBV_QP_SQ_PSN \fR +.fi +.PP +.nf +For QP Transport Service Type \fB IBV_QPT_RC\fR: +.sp +Next state Required attributes +\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- +Init \fB IBV_QP_STATE, IBV_QP_PKEY_INDEX, IBV_QP_PORT, \fR + \fB IBV_QP_ACCESS_FLAGS \fR +RTR \fB IBV_QP_STATE, IBV_QP_AV, IBV_QP_PATH_MTU, \fR + \fB IBV_QP_DEST_QPN, IBV_QP_RQ_PSN, \fR + \fB IBV_QP_MAX_DEST_RD_ATOMIC, IBV_QP_MIN_RNR_TIMER \fR +RTS \fB IBV_QP_STATE, IBV_QP_SQ_PSN, IBV_QP_MAX_QP_RD_ATOMIC, \fR + \fB IBV_QP_RETRY_CNT, IBV_QP_RNR_RETRY, IBV_QP_TIMEOUT \fR +.fi +.SH "SEE ALSO" +.BR ibv_create_qp (3), +.BR ibv_destroy_qp (3), +.BR ibv_query_qp (3), +.BR ibv_create_ah (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_modify_srq.3 b/contrib/ofed/libibverbs/man/ibv_modify_srq.3 new file mode 100644 index 000000000000..184af5ffb2c4 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_modify_srq.3 @@ -0,0 +1,63 @@ +.\" -*- nroff -*- +.\" +.TH IBV_MODIFY_SRQ 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_modify_srq \- modify attributes of a shared receive queue (SRQ) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_modify_srq(struct ibv_srq " "*srq" , +.BI " struct ibv_srq_attr " "*srq_attr" , +.BI " int " "srq_attr_mask" ); +.fi +.SH "DESCRIPTION" +.B ibv_modify_srq() +modifies the attributes of SRQ +.I srq +with the attributes in +.I srq_attr +according to the mask +.I srq_attr_mask\fR. +The argument \fIsrq_attr\fR is an ibv_srq_attr struct, as defined in . +.PP +.nf +struct ibv_srq_attr { +.in +8 +uint32_t max_wr; /* maximum number of outstanding work requests (WRs) in the SRQ */ +uint32_t max_sge; /* number of scatter elements per WR (irrelevant for ibv_modify_srq) */ +uint32_t srq_limit; /* the limit value of the SRQ */ +.in -8 +}; +.fi +.PP +The argument +.I srq_attr_mask +specifies the SRQ attributes to be modified. +The argument is either 0 or the bitwise OR of one or more of the following flags: +.PP +.TP +.B IBV_SRQ_MAX_WR \fR Resize the SRQ +.TP +.B IBV_SRQ_LIMIT \fR Set the SRQ limit +.SH "RETURN VALUE" +.B ibv_modify_srq() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +If any of the modify attributes is invalid, none of the attributes will be modified. +.PP +Not all devices support resizing SRQs. To check if a device supports it, check if the +.B IBV_DEVICE_SRQ_RESIZE +bit is set in the device capabilities flags. +.PP +Modifying the srq_limit arms the SRQ to produce an +.B IBV_EVENT_SRQ_LIMIT_REACHED +"low watermark" asynchronous event once the number of WRs in the SRQ drops below srq_limit. +.SH "SEE ALSO" +.BR ibv_query_device (3), +.BR ibv_create_srq (3), +.BR ibv_destroy_srq (3), +.BR ibv_query_srq (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_modify_xrc_rcv_qp.3 b/contrib/ofed/libibverbs/man/ibv_modify_xrc_rcv_qp.3 new file mode 100644 index 000000000000..cebe5b7dfdc7 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_modify_xrc_rcv_qp.3 @@ -0,0 +1,141 @@ +.\" -*- nroff -*- +.\" +.TH IBV_MODIFY_XRC_RCV_QP 3 2008-02-10 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_modify_xrc_rcv_qp \- modify the attributes of an XRC receive queue pair (QP) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_modify_xrc_rcv_qp(struct ibv_xrc_domain " "*xrc_domain" ", uint32_t " "xrc_qp_num" , +.BI " struct ibv_qp_attr " "*attr" ", int " "attr_mask" ); +.fi +.SH "DESCRIPTION" +.B ibv_modify_qp() +modifies the attributes of an XRC receive QP with the number +.I xrc_qp_num +which is associated with the XRC domain +.I xrc_domain +with the attributes in +.I attr +according to the mask +.I attr_mask +and move the QP state through the following transitions: Reset -> Init -> RTR. +.I attr_mask +should indicate all of the attributes which will be used in this QP transition and the following masks (at least) should be set: +.PP +.nf +Next state Required attributes +\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- +Init \fB IBV_QP_STATE, IBV_QP_PKEY_INDEX, IBV_QP_PORT, \fR + \fB IBV_QP_ACCESS_FLAGS \fR +RTR \fB IBV_QP_STATE, IBV_QP_AV, IBV_QP_PATH_MTU, \fR + \fB IBV_QP_DEST_QPN, IBV_QP_RQ_PSN, \fR + \fB IBV_QP_MAX_DEST_RD_ATOMIC, IBV_QP_MIN_RNR_TIMER \fR +.fi +.PP +The user can add optional attributes as well. +.PP +The argument \fIattr\fR is an ibv_qp_attr struct, as defined in . +.PP +.nf +struct ibv_qp_attr { +.in +8 +enum ibv_qp_state qp_state; /* Move the QP to this state */ +enum ibv_qp_state cur_qp_state; /* Assume this is the current QP state */ +enum ibv_mtu path_mtu; /* Path MTU (valid only for RC/UC QPs) */ +enum ibv_mig_state path_mig_state; /* Path migration state (valid if HCA supports APM) */ +uint32_t qkey; /* Q_Key for the QP (valid only for UD QPs) */ +uint32_t rq_psn; /* PSN for receive queue (valid only for RC/UC QPs) */ +uint32_t sq_psn; /* PSN for send queue (valid only for RC/UC QPs) */ +uint32_t dest_qp_num; /* Destination QP number (valid only for RC/UC QPs) */ +int qp_access_flags; /* Mask of enabled remote access operations (valid only for RC/UC QPs) */ +struct ibv_qp_cap cap; /* QP capabilities (valid if HCA supports QP resizing) */ +struct ibv_ah_attr ah_attr; /* Primary path address vector (valid only for RC/UC QPs) */ +struct ibv_ah_attr alt_ah_attr; /* Alternate path address vector (valid only for RC/UC QPs) */ +uint16_t pkey_index; /* Primary P_Key index */ +uint16_t alt_pkey_index; /* Alternate P_Key index */ +uint8_t en_sqd_async_notify; /* Enable SQD.drained async notification (Valid only if qp_state is SQD) */ +uint8_t sq_draining; /* Is the QP draining? Irrelevant for ibv_modify_qp() */ +uint8_t max_rd_atomic; /* Number of outstanding RDMA reads & atomic operations on the destination QP (valid only for RC QPs) */ +uint8_t max_dest_rd_atomic; /* Number of responder resources for handling incoming RDMA reads & atomic operations (valid only for RC QPs) */ +uint8_t min_rnr_timer; /* Minimum RNR NAK timer (valid only for RC QPs) */ +uint8_t port_num; /* Primary port number */ +uint8_t timeout; /* Local ack timeout for primary path (valid only for RC QPs) */ +uint8_t retry_cnt; /* Retry count (valid only for RC QPs) */ +uint8_t rnr_retry; /* RNR retry (valid only for RC QPs) */ +uint8_t alt_port_num; /* Alternate port number */ +uint8_t alt_timeout; /* Local ack timeout for alternate path (valid only for RC QPs) */ +.in -8 +}; +.fi +.PP +For details on struct ibv_qp_cap see the description of +.B ibv_create_qp()\fR. +For details on struct ibv_ah_attr see the description of +.B ibv_create_ah()\fR. +.PP +The argument +.I attr_mask +specifies the QP attributes to be modified. +The argument is either 0 or the bitwise OR of one or more of the following flags: +.PP +.TP +.B IBV_QP_STATE \fR Modify qp_state +.TP +.B IBV_QP_CUR_STATE \fR Set cur_qp_state +.TP +.B IBV_QP_EN_SQD_ASYNC_NOTIFY \fR Set en_sqd_async_notify +.TP +.B IBV_QP_ACCESS_FLAGS \fR Set qp_access_flags +.TP +.B IBV_QP_PKEY_INDEX \fR Set pkey_index +.TP +.B IBV_QP_PORT \fR Set port_num +.TP +.B IBV_QP_QKEY \fR Set qkey +.TP +.B IBV_QP_AV \fR Set ah_attr +.TP +.B IBV_QP_PATH_MTU \fR Set path_mtu +.TP +.B IBV_QP_TIMEOUT \fR Set timeout +.TP +.B IBV_QP_RETRY_CNT \fR Set retry_cnt +.TP +.B IBV_QP_RNR_RETRY \fR Set rnr_retry +.TP +.B IBV_QP_RQ_PSN \fR Set rq_psn +.TP +.B IBV_QP_MAX_QP_RD_ATOMIC \fR Set max_rd_atomic +.TP +.B IBV_QP_ALT_PATH \fR Set the alternative path via: alt_ah_attr, alt_pkey_index, alt_port_num, alt_timeout +.TP +.B IBV_QP_MIN_RNR_TIMER \fR Set min_rnr_timer +.TP +.B IBV_QP_SQ_PSN \fR Set sq_psn +.TP +.B IBV_QP_MAX_DEST_RD_ATOMIC \fR Set max_dest_rd_atomic +.TP +.B IBV_QP_PATH_MIG_STATE \fR Set path_mig_state +.TP +.B IBV_QP_CAP \fR Set cap +.TP +.B IBV_QP_DEST_QPN \fR Set dest_qp_num +.SH "RETURN VALUE" +.B ibv_modify_xrc_rcv_qp() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +If any of the modify attributes or the modify mask are invalid, none +of the attributes will be modified (including the QP state). +.PP +Not all devices support alternate paths. To check if a device supports it, check if the +.B IBV_DEVICE_AUTO_PATH_MIG +bit is set in the device capabilities flags. +.SH "SEE ALSO" +.BR ibv_open_xrc_domain (3), +.BR ibv_create_xrc_rcv_qp (3), +.BR ibv_query_xrc_rcv_qp (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_open_device.3 b/contrib/ofed/libibverbs/man/ibv_open_device.3 new file mode 100644 index 000000000000..d5149a54875b --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_open_device.3 @@ -0,0 +1,43 @@ +.\" -*- nroff -*- +.\" +.TH IBV_OPEN_DEVICE 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_open_device, ibv_close_device \- open and close an RDMA device context +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "struct ibv_context *ibv_open_device(struct ibv_device " "*device" "); +.sp +.BI "int ibv_close_device(struct ibv_context " "*context" "); +.fi +.SH "DESCRIPTION" +.B ibv_open_device() +opens the device +.I device +and creates a context for further use. +.PP +.B ibv_close_device() +closes the device context +.I context\fR. +.SH "RETURN VALUE" +.B ibv_open_device() +returns a pointer to the allocated device context, or NULL if the request fails. +.PP +.B ibv_close_device() +returns 0 on success, \-1 on failure. +.SH "NOTES" +.B ibv_close_device() +does not release all the resources allocated using context +.I context\fR. +To avoid resource leaks, the user should release all associated +resources before closing a context. +.SH "SEE ALSO" +.BR ibv_get_device_list (3), +.BR ibv_query_device (3), +.BR ibv_query_port (3), +.BR ibv_query_gid (3), +.BR ibv_query_pkey (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_open_xrc_domain.3 b/contrib/ofed/libibverbs/man/ibv_open_xrc_domain.3 new file mode 100644 index 000000000000..874e582422ed --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_open_xrc_domain.3 @@ -0,0 +1,80 @@ +.\" -*- nroff -*- +.\" +.TH IBV_OPEN_XRC_DOMAIN 3 2008-02-10 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_open_xrc_domain, ibv_close_xrc_domain \- open or close an eXtended Reliable Connection (XRC) domain +.SH "SYNOPSIS" +.nf +.B #include +.B #include +.sp +.BI "struct ibv_xrc_domain *ibv_open_xrc_domain(struct ibv_context " "*context" "," +.BI " int " "fd" ", int " "oflag" ); +.nl +.BI "int ibv_close_xrc_domain(struct ibv_xrc_domain " "*d" ); +.fi +.SH "DESCRIPTION" +.B ibv_open_xrc_domain() +open an XRC domain for the InfiniBand device context +.I context +or return a reference to an opened one\fR. +.I fd +is the file descriptor to be associated with the XRC domain. +The argument +.I oflag +describes the desired file creation attributes; it is either 0 or the bitwise OR of one or more of the following flags: +.PP +.TP +.B O_CREAT +If a domain belonging to device named by context is already associated with the inode, this flag has +no effect, except as noted under +.BR O_EXCL +below. Otherwise, a new XRC domain is created and is associated with inode specified by +.IR fd\fR. +.TP +.B O_EXCL +If +.BR O_EXCL +and +.BR O_CREAT +are set, open will fail if a domain associated with the inode exists. +The check for the existence of the domain and creation +of the domain if it does not exist is atomic with respect to other +processes executing open with +.IR fd +naming the same inode. +.PP +If +.I fd +equals -1, no inode is is associated with the domain, and the only valid value for +.I oflag +is +.B O_CREAT\fR. +.PP +.B ibv_close_xrc_domain() +closes the XRC domain +.I d\fR. +If this is the last reference, the XRC domain will be destroyed. +.SH "RETURN VALUE" +.B ibv_open_xrc_domain() +returns a pointer to an opened XRC, or NULL if the request fails. +.PP +.B ibv_close_xrc_domain() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +Not all devices support XRC. To check if a device supports it, check if the +.B IBV_DEVICE_XRC +bit is set in the device capabilities flags. +.PP +.B ibv_close_xrc_domain() +may fail if any QP or SRQ are still associated with the XRC domain being closed. +.SH "SEE ALSO" +.BR ibv_create_xrc_srq (3), +.BR ibv_create_qp (3), +.BR ibv_create_xrc_rcv_qp (3), +.BR ibv_modify_xrc_rcv_qp (3), +.BR ibv_query_xrc_rcv_qp (3), +.BR ibv_reg_xrc_rcv_qp (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_poll_cq.3 b/contrib/ofed/libibverbs/man/ibv_poll_cq.3 new file mode 100644 index 000000000000..6a669559e218 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_poll_cq.3 @@ -0,0 +1,77 @@ +.\" -*- nroff -*- +.\" +.TH IBV_POLL_CQ 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_poll_cq \- poll a completion queue (CQ) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_poll_cq(struct ibv_cq " "*cq" ", int " "num_entries" , +.BI " struct ibv_wc " "*wc" ); +.fi +.SH "DESCRIPTION" +.B ibv_poll_cq() +polls the CQ +.I cq +for work completions and returns the first +.I num_entries +(or all available completions if the CQ contains fewer than this number) in the array +.I wc\fR. +The argument +.I wc +is a pointer to an array of ibv_wc structs, as defined in . +.PP +.nf +struct ibv_wc { +.in +8 +uint64_t wr_id; /* ID of the completed Work Request (WR) */ +enum ibv_wc_status status; /* Status of the operation */ +enum ibv_wc_opcode opcode; /* Operation type specified in the completed WR */ +uint32_t vendor_err; /* Vendor error syndrome */ +uint32_t byte_len; /* Number of bytes transferred */ +uint32_t imm_data; /* Immediate data (in network byte order) */ +uint32_t qp_num; /* Local QP number of completed WR */ +uint32_t src_qp; /* Source QP number (remote QP number) of completed WR (valid only for UD QPs) */ +int wc_flags; /* Flags of the completed WR */ +uint16_t pkey_index; /* P_Key index (valid only for GSI QPs) */ +uint16_t slid; /* Source LID */ +uint8_t sl; /* Service Level */ +uint8_t dlid_path_bits; /* DLID path bits (not applicable for multicast messages) */ +.in -8 +}; +.sp +.fi +.PP +The attribute wc_flags describes the properties of the work completion. +It is either 0 or the bitwise OR of one or more of the following flags: +.PP +.TP +.B IBV_WC_GRH \fR GRH is present (valid only for UD QPs) +.TP +.B IBV_WC_WITH_IMM \fR Immediate data value is valid +.PP +Not all +.I wc +attributes are always valid. If the completion status is other than +.B IBV_WC_SUCCESS\fR, +only the following attributes are valid: wr_id, status, qp_num, and vendor_err. +.SH "RETURN VALUE" +On success, +.B ibv_poll_cq() +returns a non-negative value equal to the number of completions +found. On failure, a negative value is returned. +.SH "NOTES" +.PP +Each polled completion is removed from the CQ and cannot be returned to it. +.PP +The user should consume work completions at a rate that prevents CQ +overrun from occurrence. In case of a CQ overrun, the async event +.B IBV_EVENT_CQ_ERR +will be triggered, and the CQ cannot be used. +.SH "SEE ALSO" +.BR ibv_post_send (3), +.BR ibv_post_recv (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_post_recv.3 b/contrib/ofed/libibverbs/man/ibv_post_recv.3 new file mode 100644 index 000000000000..46a630bc652a --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_post_recv.3 @@ -0,0 +1,76 @@ +.\" -*- nroff -*- +.\" +.TH IBV_POST_RECV 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_post_recv \- post a list of work requests (WRs) to a receive queue +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_post_recv(struct ibv_qp " "*qp" ", struct ibv_recv_wr " "*wr" , +.BI " struct ibv_recv_wr " "**bad_wr" ); +.fi +.SH "DESCRIPTION" +.B ibv_post_recv() +posts the linked list of work requests (WRs) starting with +.I wr +to the receive queue of the queue pair +.I qp\fR. +It stops processing WRs from this list at the first failure (that can +be detected immediately while requests are being posted), and returns +this failing WR through +.I bad_wr\fR. +.PP +The argument +.I wr +is an ibv_recv_wr struct, as defined in . +.PP +.nf +struct ibv_recv_wr { +.in +8 +uint64_t wr_id; /* User defined WR ID */ +struct ibv_recv_wr *next; /* Pointer to next WR in list, NULL if last WR */ +struct ibv_sge *sg_list; /* Pointer to the s/g array */ +int num_sge; /* Size of the s/g array */ +.in -8 +}; +.sp +.nf +struct ibv_sge { +.in +8 +uint64_t addr; /* Start address of the local memory buffer */ +uint32_t length; /* Length of the buffer */ +uint32_t lkey; /* Key of the local Memory Region */ +.in -8 +}; +.fi +.SH "RETURN VALUE" +.B ibv_post_recv() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +The buffers used by a WR can only be safely reused after WR the +request is fully executed and a work completion has been retrieved +from the corresponding completion queue (CQ). +.PP +If the QP +.I qp +is associated with a shared receive queue, you must use the function +.B ibv_post_srq_recv()\fR, +and not +.B ibv_post_recv()\fR, +since the QP's own receive queue will not be used. +.PP +If a WR is being posted to a UD QP, the Global Routing Header (GRH) of +the incoming message will be placed in the first 40 bytes of the +buffer(s) in the scatter list. If no GRH is present in the incoming +message, then the first bytes will be undefined. This means that in +all cases, the actual data of the incoming message will start at an +offset of 40 bytes into the buffer(s) in the scatter list. +.SH "SEE ALSO" +.BR ibv_create_qp (3), +.BR ibv_post_send (3), +.BR ibv_post_srq_recv (3), +.BR ibv_poll_cq (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_post_send.3 b/contrib/ofed/libibverbs/man/ibv_post_send.3 new file mode 100644 index 000000000000..d2c6e07e0868 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_post_send.3 @@ -0,0 +1,125 @@ +.\" -*- nroff -*- +.\" +.TH IBV_POST_SEND 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_post_send \- post a list of work requests (WRs) to a send queue +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_post_send(struct ibv_qp " "*qp" ", struct ibv_send_wr " "*wr" , +.BI " struct ibv_send_wr " "**bad_wr" ); +.fi +.SH "DESCRIPTION" +.B ibv_post_send() +posts the linked list of work requests (WRs) starting with +.I wr +to the send queue of the queue pair +.I qp\fR. +It stops processing WRs from this list at the first failure (that can +be detected immediately while requests are being posted), and returns +this failing WR through +.I bad_wr\fR. +.PP +The argument +.I wr +is an ibv_send_wr struct, as defined in . +.PP +.nf +struct ibv_send_wr { +.in +8 +uint64_t wr_id; /* User defined WR ID */ +struct ibv_send_wr *next; /* Pointer to next WR in list, NULL if last WR */ +struct ibv_sge *sg_list; /* Pointer to the s/g array */ +int num_sge; /* Size of the s/g array */ +enum ibv_wr_opcode opcode; /* Operation type */ +int send_flags; /* Flags of the WR properties */ +uint32_t imm_data; /* Immediate data (in network byte order) */ +union { +.in +8 +struct { +.in +8 +uint64_t remote_addr; /* Start address of remote memory buffer */ +uint32_t rkey; /* Key of the remote Memory Region */ +.in -8 +} rdma; +struct { +.in +8 +uint64_t remote_addr; /* Start address of remote memory buffer */ +uint64_t compare_add; /* Compare operand */ +uint64_t swap; /* Swap operand */ +uint32_t rkey; /* Key of the remote Memory Region */ +.in -8 +} atomic; +struct { +.in +8 +struct ibv_ah *ah; /* Address handle (AH) for the remote node address */ +uint32_t remote_qpn; /* QP number of the destination QP */ +uint32_t remote_qkey; /* Q_Key number of the destination QP */ +.in -8 +} ud; +.in -8 +} wr; +uint32_t xrc_remote_srq_num; /* SRQ number of the destination XRC */ +.in -8 +}; +.sp +.nf +struct ibv_sge { +.in +8 +uint64_t addr; /* Start address of the local memory buffer */ +uint32_t length; /* Length of the buffer */ +uint32_t lkey; /* Key of the local Memory Region */ +.in -8 +}; +.fi +.PP +Each QP Transport Service Type supports a specific set of opcodes, as shown in the following table: +.PP +.nf +OPCODE | IBV_QPT_UD | IBV_QPT_UC | IBV_QPT_RC | IBV_QPT_XRC +\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\- +IBV_WR_SEND | X | X | X | X +IBV_WR_SEND_WITH_IMM | X | X | X | X +IBV_WR_RDMA_WRITE | | X | X | X +IBV_WR_RDMA_WRITE_WITH_IMM | | X | X | X +IBV_WR_RDMA_READ | | | X | X +IBV_WR_ATOMIC_CMP_AND_SWP | | | X | X +IBV_WR_ATOMIC_FETCH_AND_ADD | | | X | X +.fi +.PP +The attribute send_flags describes the properties of the \s-1WR\s0. It is either 0 or the bitwise \s-1OR\s0 of one or more of the following flags: +.PP +.TP +.B IBV_SEND_FENCE \fR Set the fence indicator. Valid only for QPs with Transport Service Type \fBIBV_QPT_RC +.TP +.B IBV_SEND_SIGNALED \fR Set the completion notification indicator. Relevant only if QP was created with sq_sig_all=0 +.TP +.B IBV_SEND_SOLICITED \fR Set the solicited event indicator. Valid only for Send and RDMA Write with immediate +.TP +.B IBV_SEND_INLINE \fR Send data in given gather list as inline data +in a send WQE. Valid only for Send and RDMA Write. The L_Key will not be checked. +.SH "RETURN VALUE" +.B ibv_post_send() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +The user should not alter or destroy AHs associated with WRs until +request is fully executed and a work completion has been retrieved +from the corresponding completion queue (CQ) to avoid unexpected +behavior. +.PP +The buffers used by a WR can only be safely reused after WR the +request is fully executed and a work completion has been retrieved +from the corresponding completion queue (CQ). However, if the +IBV_SEND_INLINE flag was set, the buffer can be reused immediately +after the call returns. +.SH "SEE ALSO" +.BR ibv_create_qp (3), +.BR ibv_create_xrc_rcv_qp (3), +.BR ibv_create_ah (3), +.BR ibv_post_recv (3), +.BR ibv_post_srq_recv (3), +.BR ibv_poll_cq (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_post_srq_recv.3 b/contrib/ofed/libibverbs/man/ibv_post_srq_recv.3 new file mode 100644 index 000000000000..65877cda63e1 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_post_srq_recv.3 @@ -0,0 +1,68 @@ +.\" -*- nroff -*- +.\" +.TH IBV_POST_SRQ_RECV 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_post_srq_recv \- post a list of work requests (WRs) to a shared receive queue (SRQ) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_post_srq_recv(struct ibv_srq " "*srq" ", struct ibv_recv_wr " "*wr" , +.BI " struct ibv_recv_wr " "**bad_wr" ); +.fi +.SH "DESCRIPTION" +.B ibv_post_srq_recv() +posts the linked list of work requests (WRs) starting with +.I wr +to the shared receive queue (SRQ) +.I srq\fR. +It stops processing WRs from this list at the first failure (that can +be detected immediately while requests are being posted), and returns +this failing WR through +.I bad_wr\fR. +.PP +The argument +.I wr +is an ibv_recv_wr struct, as defined in . +.PP +.nf +struct ibv_recv_wr { +.in +8 +uint64_t wr_id; /* User defined WR ID */ +struct ibv_recv_wr *next; /* Pointer to next WR in list, NULL if last WR */ +struct ibv_sge *sg_list; /* Pointer to the s/g array */ +int num_sge; /* Size of the s/g array */ +.in -8 +}; +.sp +.nf +struct ibv_sge { +.in +8 +uint64_t addr; /* Start address of the local memory buffer */ +uint32_t length; /* Length of the buffer */ +uint32_t lkey; /* Key of the local Memory Region */ +.in -8 +}; +.fi +.SH "RETURN VALUE" +.B ibv_post_srq_recv() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +The buffers used by a WR can only be safely reused after WR the +request is fully executed and a work completion has been retrieved +from the corresponding completion queue (CQ). +.PP +If a WR is being posted to a UD QP, the Global Routing Header (GRH) of +the incoming message will be placed in the first 40 bytes of the +buffer(s) in the scatter list. If no GRH is present in the incoming +message, then the first bytes will be undefined. This means that in +all cases, the actual data of the incoming message will start at an +offset of 40 bytes into the buffer(s) in the scatter list. +.SH "SEE ALSO" +.BR ibv_create_qp (3), +.BR ibv_post_send (3), +.BR ibv_post_recv (3), +.BR ibv_poll_cq (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_query_device.3 b/contrib/ofed/libibverbs/man/ibv_query_device.3 new file mode 100644 index 000000000000..3bf7511a614b --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_query_device.3 @@ -0,0 +1,84 @@ +.\" -*- nroff -*- +.\" +.TH IBV_QUERY_DEVICE 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_query_device \- query an RDMA device's attributes +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_query_device(struct ibv_context " "*context", +.BI " struct ibv_device_attr " "*device_attr" ); +.fi +.SH "DESCRIPTION" +.B ibv_query_device() +returns the attributes of the device with context +.I context\fR. +The argument +.I device_attr +is a pointer to an ibv_device_attr struct, as defined in . +.PP +.nf +struct ibv_device_attr { +.in +8 +char fw_ver[64]; /* FW version */ +uint64_t node_guid; /* Node GUID (in network byte order) */ +uint64_t sys_image_guid; /* System image GUID (in network byte order) */ +uint64_t max_mr_size; /* Largest contiguous block that can be registered */ +uint64_t page_size_cap; /* Supported memory shift sizes */ +uint32_t vendor_id; /* Vendor ID, per IEEE */ +uint32_t vendor_part_id; /* Vendor supplied part ID */ +uint32_t hw_ver; /* Hardware version */ +int max_qp; /* Maximum number of supported QPs */ +int max_qp_wr; /* Maximum number of outstanding WR on any work queue */ +int device_cap_flags; /* HCA capabilities mask */ +int max_sge; /* Maximum number of s/g per WR for non-RD QPs */ +int max_sge_rd; /* Maximum number of s/g per WR for RD QPs */ +int max_cq; /* Maximum number of supported CQs */ +int max_cqe; /* Maximum number of CQE capacity per CQ */ +int max_mr; /* Maximum number of supported MRs */ +int max_pd; /* Maximum number of supported PDs */ +int max_qp_rd_atom; /* Maximum number of RDMA Read & Atomic operations that can be outstanding per QP */ +int max_ee_rd_atom; /* Maximum number of RDMA Read & Atomic operations that can be outstanding per EEC */ +int max_res_rd_atom; /* Maximum number of resources used for RDMA Read & Atomic operations by this HCA as the Target */ +int max_qp_init_rd_atom; /* Maximum depth per QP for initiation of RDMA Read & Atomic operations */ +int max_ee_init_rd_atom; /* Maximum depth per EEC for initiation of RDMA Read & Atomic operations */ +enum ibv_atomic_cap atomic_cap; /* Atomic operations support level */ +int max_ee; /* Maximum number of supported EE contexts */ +int max_rdd; /* Maximum number of supported RD domains */ +int max_mw; /* Maximum number of supported MWs */ +int max_raw_ipv6_qp; /* Maximum number of supported raw IPv6 datagram QPs */ +int max_raw_ethy_qp; /* Maximum number of supported Ethertype datagram QPs */ +int max_mcast_grp; /* Maximum number of supported multicast groups */ +int max_mcast_qp_attach; /* Maximum number of QPs per multicast group which can be attached */ +int max_total_mcast_qp_attach;/* Maximum number of QPs which can be attached to multicast groups */ +int max_ah; /* Maximum number of supported address handles */ +int max_fmr; /* Maximum number of supported FMRs */ +int max_map_per_fmr; /* Maximum number of (re)maps per FMR before an unmap operation in required */ +int max_srq; /* Maximum number of supported SRQs */ +int max_srq_wr; /* Maximum number of WRs per SRQ */ +int max_srq_sge; /* Maximum number of s/g per SRQ */ +uint16_t max_pkeys; /* Maximum number of partitions */ +uint8_t local_ca_ack_delay; /* Local CA ack delay */ +uint8_t phys_port_cnt; /* Number of physical ports */ +.in -8 +}; +.fi +.SH "RETURN VALUE" +.B ibv_query_device() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +The maximum values returned by this function are the upper limits of +supported resources by the device. However, it may not be possible to +use these maximum values, since the actual number of any resource that +can be created may be limited by the machine configuration, the amount +of host memory, user permissions, and the amount of resources already +in use by other users/processes. +.SH "SEE ALSO" +.BR ibv_open_device (3), +.BR ibv_query_port (3), +.BR ibv_query_pkey (3), +.BR ibv_query_gid (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_query_gid.3 b/contrib/ofed/libibverbs/man/ibv_query_gid.3 new file mode 100644 index 000000000000..df3ac1010544 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_query_gid.3 @@ -0,0 +1,33 @@ +.\" -*- nroff -*- +.\" +.TH IBV_QUERY_GID 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_query_gid \- query an InfiniBand port's GID table +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_query_gid(struct ibv_context " "*context" ", uint8_t " "port_num" , +.BI " int " "index" ", union ibv_gid " "*gid" ); +.fi +.SH "DESCRIPTION" +.B ibv_query_gid() +returns the GID value in entry +.I index +of port +.I port_num +for device context +.I context +through the pointer +.I gid\fR. +.SH "RETURN VALUE" +.B ibv_query_gid() +returns 0 on success, and \-1 on error. +.SH "SEE ALSO" +.BR ibv_open_device (3), +.BR ibv_query_device (3), +.BR ibv_query_port (3), +.BR ibv_query_pkey (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_query_pkey.3 b/contrib/ofed/libibverbs/man/ibv_query_pkey.3 new file mode 100644 index 000000000000..fcdfe6c6f529 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_query_pkey.3 @@ -0,0 +1,33 @@ +.\" -*- nroff -*- +.\" +.TH IBV_QUERY_PKEY 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_query_pkey \- query an InfiniBand port's P_Key table +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_query_pkey(struct ibv_context " "*context" ", uint8_t " "port_num" , +.BI " int " "index" ", uint16_t " "*pkey" "); +.fi +.SH "DESCRIPTION" +.B ibv_query_pkey() +returns the P_Key value (in network byte order) in entry +.I index +of port +.I port_num +for device context +.I context +through the pointer +.I pkey\fR. +.SH "RETURN VALUE" +.B ibv_query_pkey() +returns 0 on success, and \-1 on error. +.SH "SEE ALSO" +.BR ibv_open_device (3), +.BR ibv_query_device (3), +.BR ibv_query_port (3), +.BR ibv_query_gid (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_query_port.3 b/contrib/ofed/libibverbs/man/ibv_query_port.3 new file mode 100644 index 000000000000..f4bdf2f91093 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_query_port.3 @@ -0,0 +1,62 @@ +.\" -*- nroff -*- +.\" +.TH IBV_QUERY_PORT 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_query_port \- query an RDMA port's attributes +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_query_port(struct ibv_context " "*context" ", uint8_t " "port_num" , +.BI " struct ibv_port_attr " "*port_attr" "); +.fi +.SH "DESCRIPTION" +.B ibv_query_port() +returns the attributes of port +.I port_num +for device context +.I context +through the pointer +.I port_attr\fR. +The argument +.I port_attr +is an ibv_port_attr struct, as defined in . +.PP +.nf +struct ibv_port_attr { +.in +8 +enum ibv_port_state state; /* Logical port state */ +enum ibv_mtu max_mtu; /* Max MTU supported by port */ +enum ibv_mtu active_mtu; /* Actual MTU */ +int gid_tbl_len; /* Length of source GID table */ +uint32_t port_cap_flags; /* Port capabilities */ +uint32_t max_msg_sz; /* Maximum message size */ +uint32_t bad_pkey_cntr; /* Bad P_Key counter */ +uint32_t qkey_viol_cntr; /* Q_Key violation counter */ +uint16_t pkey_tbl_len; /* Length of partition table */ +uint16_t lid; /* Base port LID */ +uint16_t sm_lid; /* SM LID */ +uint8_t lmc; /* LMC of LID */ +uint8_t max_vl_num; /* Maximum number of VLs */ +uint8_t sm_sl; /* SM service level */ +uint8_t subnet_timeout; /* Subnet propagation delay */ +uint8_t init_type_reply;/* Type of initialization performed by SM */ +uint8_t active_width; /* Currently active link width */ +uint8_t active_speed; /* Currently active link speed */ +uint8_t phys_state; /* Physical port state */ +uint8_t link_layer; /* link layer protocol of the port */ +.in -8 +}; +.sp +.fi +.SH "RETURN VALUE" +.B ibv_query_port() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "SEE ALSO" +.BR ibv_create_qp (3), +.BR ibv_destroy_qp (3), +.BR ibv_query_qp (3), +.BR ibv_create_ah (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_query_qp.3 b/contrib/ofed/libibverbs/man/ibv_query_qp.3 new file mode 100644 index 000000000000..2c4ceaf2c4a5 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_query_qp.3 @@ -0,0 +1,90 @@ +.\" -*- nroff -*- +.\" +.TH IBV_QUERY_QP 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_query_qp \- get the attributes of a queue pair (QP) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_query_qp(struct ibv_qp " "*qp" ", struct ibv_qp_attr " "*attr" , +.BI " int " "attr_mask" , +.BI " struct ibv_qp_init_attr " "*init_attr" ); +.fi +.SH "DESCRIPTION" +.B ibv_query_qp() +gets the attributes specified in +.I attr_mask +for the QP +.I qp +and returns them through the pointers +.I attr +and +.I init_attr\fR. +The argument +.I attr +is an ibv_qp_attr struct, as defined in . +.PP +.nf +struct ibv_qp_attr { +.in +8 +enum ibv_qp_state qp_state; /* Current QP state */ +enum ibv_qp_state cur_qp_state; /* Current QP state - irrelevant for ibv_query_qp */ +enum ibv_mtu path_mtu; /* Path MTU (valid only for RC/UC QPs) */ +enum ibv_mig_state path_mig_state; /* Path migration state (valid if HCA supports APM) */ +uint32_t qkey; /* Q_Key of the QP (valid only for UD QPs) */ +uint32_t rq_psn; /* PSN for receive queue (valid only for RC/UC QPs) */ +uint32_t sq_psn; /* PSN for send queue (valid only for RC/UC QPs) */ +uint32_t dest_qp_num; /* Destination QP number (valid only for RC/UC QPs) */ +int qp_access_flags; /* Mask of enabled remote access operations (valid only for RC/UC QPs) */ +struct ibv_qp_cap cap; /* QP capabilities */ +struct ibv_ah_attr ah_attr; /* Primary path address vector (valid only for RC/UC QPs) */ +struct ibv_ah_attr alt_ah_attr; /* Alternate path address vector (valid only for RC/UC QPs) */ +uint16_t pkey_index; /* Primary P_Key index */ +uint16_t alt_pkey_index; /* Alternate P_Key index */ +uint8_t en_sqd_async_notify; /* Enable SQD.drained async notification - irrelevant for ibv_query_qp */ +uint8_t sq_draining; /* Is the QP draining? (Valid only if qp_state is SQD) */ +uint8_t max_rd_atomic; /* Number of outstanding RDMA reads & atomic operations on the destination QP (valid only for RC QPs) */ +uint8_t max_dest_rd_atomic; /* Number of responder resources for handling incoming RDMA reads & atomic operations (valid only for RC QPs) */ +uint8_t min_rnr_timer; /* Minimum RNR NAK timer (valid only for RC QPs) */ +uint8_t port_num; /* Primary port number */ +uint8_t timeout; /* Local ack timeout for primary path (valid only for RC QPs) */ +uint8_t retry_cnt; /* Retry count (valid only for RC QPs) */ +uint8_t rnr_retry; /* RNR retry (valid only for RC QPs) */ +uint8_t alt_port_num; /* Alternate port number */ +uint8_t alt_timeout; /* Local ack timeout for alternate path (valid only for RC QPs) */ +.in -8 +}; +.fi +.PP +For details on struct ibv_qp_cap see the description of +.B ibv_create_qp()\fR. +For details on struct ibv_ah_attr see the description of +.B ibv_create_ah()\fR. +.SH "RETURN VALUE" +.B ibv_query_qp() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +The argument +.I attr_mask +is a hint that specifies the minimum list of attributes to retrieve. +Some RDMA devices may return extra attributes not requested, for +example if the value can be returned cheaply. This has the same +form as in +.B ibv_modify_qp()\fR. +.PP +Attribute values are valid if they have been set using +.B ibv_modify_qp()\fR. +The exact list of valid attributes depends on the QP state. +.PP +Multiple calls to +.B ibv_query_qp() +may yield some differences in the values returned for the following attributes: qp_state, path_mig_state, sq_draining, ah_attr (if APM is enabled). +.SH "SEE ALSO" +.BR ibv_create_qp (3), +.BR ibv_destroy_qp (3), +.BR ibv_modify_qp (3), +.BR ibv_create_ah (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_query_srq.3 b/contrib/ofed/libibverbs/man/ibv_query_srq.3 new file mode 100644 index 000000000000..56db4fa0df49 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_query_srq.3 @@ -0,0 +1,44 @@ +.\" -*- nroff -*- +.\" +.TH IBV_QUERY_SRQ 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_query_srq \- get the attributes of a shared receive queue (SRQ) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_query_srq(struct ibv_srq " "*srq" ", struct ibv_srq_attr " "*srq_attr" ); +.fi +.SH "DESCRIPTION" +.B ibv_query_srq() +gets the attributes of the SRQ +.I srq +and returns them through the pointer +.I srq_attr\fR. +The argument +.I srq_attr +is an ibv_srq_attr struct, as defined in . +.PP +.nf +struct ibv_srq_attr { +.in +8 +uint32_t max_wr; /* maximum number of outstanding work requests (WRs) in the SRQ */ +uint32_t max_sge; /* maximum number of scatter elements per WR */ +uint32_t srq_limit; /* the limit value of the SRQ */ +.in -8 +}; +.fi +.SH "RETURN VALUE" +.B ibv_query_srq() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +If the value returned for srq_limit is 0, then the SRQ limit reached +("low watermark") event is not (or no longer) armed, and no +asynchronous events will be generated until the event is rearmed. +.SH "SEE ALSO" +.BR ibv_create_srq (3), +.BR ibv_destroy_srq (3), +.BR ibv_modify_srq (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_query_xrc_rcv_qp.3 b/contrib/ofed/libibverbs/man/ibv_query_xrc_rcv_qp.3 new file mode 100644 index 000000000000..d2429be683b7 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_query_xrc_rcv_qp.3 @@ -0,0 +1,89 @@ +.\" -*- nroff -*- +.\" +.TH IBV_QUERY_XRC_RCV_QP 3 2008-02-10 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_query_xrc_rcv_qp \- get the attributes of an XRC receive queue pair (QP) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_query_xrc_rcv_qp(struct ibv_xrc_domain " "*xrc_domain" ", uint32_t " "xrc_qp_num" , +.BI " struct ibv_qp_attr " "*attr" ", int " "attr_mask" , +.BI " struct ibv_qp_init_attr " "*init_attr" ); +.fi +.SH "DESCRIPTION" +.B ibv_query_xrc_rcv_qp() +gets the attributes specified in +.I attr_mask +for the XRC receive QP with the number +.I xrc_qp_num +which is associated with the XRC domain +.I xrc_domain +and returns them through the pointers +.I attr +and +.I init_attr\fR. +The argument +.I attr +is an ibv_qp_attr struct, as defined in . +.PP +.nf +struct ibv_qp_attr { +.in +8 +enum ibv_qp_state qp_state; /* Current QP state */ +enum ibv_qp_state cur_qp_state; /* Current QP state - irrelevant for ibv_query_qp */ +enum ibv_mtu path_mtu; /* Path MTU (valid only for RC/UC QPs) */ +enum ibv_mig_state path_mig_state; /* Path migration state (valid if HCA supports APM) */ +uint32_t qkey; /* Q_Key of the QP (valid only for UD QPs) */ +uint32_t rq_psn; /* PSN for receive queue (valid only for RC/UC QPs) */ +uint32_t sq_psn; /* PSN for send queue (valid only for RC/UC QPs) */ +uint32_t dest_qp_num; /* Destination QP number (valid only for RC/UC QPs) */ +int qp_access_flags; /* Mask of enabled remote access operations (valid only for RC/UC QPs) */ +struct ibv_qp_cap cap; /* QP capabilities */ +struct ibv_ah_attr ah_attr; /* Primary path address vector (valid only for RC/UC QPs) */ +struct ibv_ah_attr alt_ah_attr; /* Alternate path address vector (valid only for RC/UC QPs) */ +uint16_t pkey_index; /* Primary P_Key index */ +uint16_t alt_pkey_index; /* Alternate P_Key index */ +uint8_t en_sqd_async_notify; /* Enable SQD.drained async notification - irrelevant for ibv_query_qp */ +uint8_t sq_draining; /* Is the QP draining? (Valid only if qp_state is SQD) */ +uint8_t max_rd_atomic; /* Number of outstanding RDMA reads & atomic operations on the destination QP (valid only for RC QPs) */ +uint8_t max_dest_rd_atomic; /* Number of responder resources for handling incoming RDMA reads & atomic operations (valid only for RC QPs) */ +uint8_t min_rnr_timer; /* Minimum RNR NAK timer (valid only for RC QPs) */ +uint8_t port_num; /* Primary port number */ +uint8_t timeout; /* Local ack timeout for primary path (valid only for RC QPs) */ +uint8_t retry_cnt; /* Retry count (valid only for RC QPs) */ +uint8_t rnr_retry; /* RNR retry (valid only for RC QPs) */ +uint8_t alt_port_num; /* Alternate port number */ +uint8_t alt_timeout; /* Local ack timeout for alternate path (valid only for RC QPs) */ +.in -8 +}; +.fi +.PP +For details on struct ibv_qp_cap see the description of +.B ibv_create_qp()\fR. +For details on struct ibv_ah_attr see the description of +.B ibv_create_ah()\fR. +.SH "RETURN VALUE" +.B ibv_query_xrc_rcv_qp() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +The argument +.I attr_mask +is a hint that specifies the minimum list of attributes to retrieve. +Some InfiniBand devices may return extra attributes not requested, for +example if the value can be returned cheaply. +.PP +Attribute values are valid if they have been set using +.B ibv_modify_xrc_rcv_qp()\fR. +The exact list of valid attributes depends on the QP state. +.PP +Multiple calls to +.B ibv_query_xrc_rcv_qp() +may yield some differences in the values returned for the following attributes: qp_state, path_mig_state, sq_draining, ah_attr (if APM is enabled). +.SH "SEE ALSO" +.BR ibv_open_xrc_domain (3), +.BR ibv_create_xrc_rcv_qp (3), +.BR ibv_modify_xrc_rcv_qp (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_rate_to_mult.3 b/contrib/ofed/libibverbs/man/ibv_rate_to_mult.3 new file mode 100644 index 000000000000..1346d754cf4d --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_rate_to_mult.3 @@ -0,0 +1,46 @@ +.\" -*- nroff -*- +.\" +.TH IBV_RATE_TO_MULT 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +.nf +ibv_rate_to_mult \- convert IB rate enumeration to multiplier of 2.5 Gbit/sec +.sp +mult_to_ibv_rate \- convert multiplier of 2.5 Gbit/sec to an IB rate enumeration +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_rate_to_mult(enum ibv_rate " "rate" "); +.sp +.BI "enum ibv_rate mult_to_ibv_rate(int " "mult" "); +.fi +.SH "DESCRIPTION" +.B ibv_rate_to_mult() +converts the IB transmission rate enumeration +.I rate +to a multiple of 2.5 Gbit/sec (the base rate). For example, if +.I rate +is +.BR IBV_RATE_5_GBPS\fR, +the value 2 will be returned (5 Gbit/sec = 2 * 2.5 Gbit/sec). +.PP +.B mult_to_ibv_rate() +converts the multiplier value (of 2.5 Gbit/sec) +.I mult +to an IB transmission rate enumeration. For example, if +.I mult +is 2, the rate enumeration +.BR IBV_RATE_5_GBPS +will be returned. +.SH "RETURN VALUE" +.B +ibv_rate_to_mult() +returns the multiplier of the base rate 2.5 Gbit/sec. +.PP +.B mult_to_ibv_rate() +returns the enumeration representing the IB transmission rate. +.SH "SEE ALSO" +.BR ibv_query_port (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_rc_pingpong.1 b/contrib/ofed/libibverbs/man/ibv_rc_pingpong.1 new file mode 100644 index 000000000000..d213c6ffab9e --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_rc_pingpong.1 @@ -0,0 +1,64 @@ +.TH IBV_RC_PINGPONG 1 "August 30, 2005" "libibverbs" "USER COMMANDS" + +.SH NAME +ibv_rc_pingpong \- simple InfiniBand RC transport test + +.SH SYNOPSIS +.B ibv_rc_pingpong +[\-p port] [\-d device] [\-i ib port] [\-s size] [\-r rx depth] +[\-n iters] [\-l sl] [\-e] \fBHOSTNAME\fR + +.B ibv_rc_pingpong +[\-p port] [\-d device] [\-i ib port] [\-s size] [\-r rx depth] +[\-n iters] [\-l sl] [\-e] + +.SH DESCRIPTION +.PP +Run a simple ping-pong test over InfiniBand via the reliable +connected (RC) transport. + +.SH OPTIONS + +.PP +.TP +\fB\-p\fR, \fB\-\-port\fR=\fIPORT\fR +use TCP port \fIPORT\fR for initial synchronization (default 18515) +.TP +\fB\-d\fR, \fB\-\-ib\-dev\fR=\fIDEVICE\fR +use IB device \fIDEVICE\fR (default first device found) +.TP +\fB\-i\fR, \fB\-\-ib\-port\fR=\fIPORT\fR +use IB port \fIPORT\fR (default port 1) +.TP +\fB\-s\fR, \fB\-\-size\fR=\fISIZE\fR +ping-pong messages of size \fISIZE\fR (default 4096) +.TP +\fB\-r\fR, \fB\-\-rx\-depth\fR=\fIDEPTH\fR +post \fIDEPTH\fR receives at a time (default 1000) +.TP +\fB\-n\fR, \fB\-\-iters\fR=\fIITERS\fR +perform \fIITERS\fR message exchanges (default 1000) +.TP +\fB\-l\fR, \fB\-\-sl\fR=\fISL\fR +use \fISL\fR as the service level value of the QP (default 0) +.TP +\fB\-e\fR, \fB\-\-events\fR +sleep while waiting for work completion events (default is to poll for +completions) + +.SH SEE ALSO +.BR ibv_uc_pingpong (1), +.BR ibv_ud_pingpong (1), +.BR ibv_srq_pingpong (1) + +.SH AUTHORS +.TP +Roland Dreier +.RI < rolandd@cisco.com > + +.SH BUGS +The network synchronization between client and server instances is +weak, and does not prevent incompatible options from being used on the +two instances. The method used for retrieving work completions is not +strictly correct, and race conditions may cause failures on some +systems. diff --git a/contrib/ofed/libibverbs/man/ibv_reg_mr.3 b/contrib/ofed/libibverbs/man/ibv_reg_mr.3 new file mode 100644 index 000000000000..7bc6c013e2b7 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_reg_mr.3 @@ -0,0 +1,76 @@ +.\" -*- nroff -*- +.\" +.TH IBV_REG_MR 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_reg_mr, ibv_dereg_mr \- register or deregister a memory region (MR) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "struct ibv_mr *ibv_reg_mr(struct ibv_pd " "*pd" ", void " "*addr" , +.BI " size_t " "length" ", int " "access" ); +.sp +.BI "int ibv_dereg_mr(struct ibv_mr " "*mr" ); +.fi +.SH "DESCRIPTION" +.B ibv_reg_mr() +registers a memory region (MR) associated with the protection domain +.I pd\fR. +The MR's starting address is +.I addr +and its size is +.I length\fR. +The argument +.I access +describes the desired memory protection attributes; it is either 0 or the bitwise OR of one or more of the following flags: +.PP +.TP +.B IBV_ACCESS_LOCAL_WRITE \fR Enable Local Write Access +.TP +.B IBV_ACCESS_REMOTE_WRITE \fR Enable Remote Write Access +.TP +.B IBV_ACCESS_REMOTE_READ\fR Enable Remote Read Access +.TP +.B IBV_ACCESS_REMOTE_ATOMIC\fR Enable Remote Atomic Operation Access (if supported) +.TP +.B IBV_ACCESS_MW_BIND\fR Enable Memory Window Binding +.PP +If +.B IBV_ACCESS_REMOTE_WRITE +or +.B IBV_ACCESS_REMOTE_ATOMIC +is set, then +.B IBV_ACCESS_LOCAL_WRITE +must be set too. +.PP +Local read access is always enabled for the MR. +.PP +.B ibv_dereg_mr() +deregisters the MR +.I mr\fR. +.SH "RETURN VALUE" +.B ibv_reg_mr() +returns a pointer to the registered MR, or NULL if the request fails. +The local key (\fBL_Key\fR) field +.B lkey +is used as the lkey field of struct ibv_sge when posting buffers with +ibv_post_* verbs, and the the remote key (\fBR_Key\fR) +field +.B rkey +is used by remote processes to perform Atomic and RDMA operations. The remote process places this +.B rkey +as the rkey field of struct ibv_send_wr passed to the ibv_post_send function. +.PP +.B ibv_dereg_mr() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +.B ibv_dereg_mr() +fails if any memory window is still bound to this MR. +.SH "SEE ALSO" +.BR ibv_alloc_pd (3), +.BR ibv_post_send (3), +.BR ibv_post_recv (3), +.BR ibv_post_srq_recv (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_reg_xrc_rcv_qp.3 b/contrib/ofed/libibverbs/man/ibv_reg_xrc_rcv_qp.3 new file mode 100644 index 000000000000..7519ba7a92fd --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_reg_xrc_rcv_qp.3 @@ -0,0 +1,57 @@ +.\" -*- nroff -*- +.\" +.TH IBV_REG_XRC_RCV_QP 3 2008-10-02 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_reg_xrc_rcv_qp, ibv_unreg_xrc_rcv_qp \- register and unregister a user process with an XRC receive queue pair (QP) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_reg_xrc_rcv_qp(struct ibv_xrc_domain " "*xrc_domain" ", uint32_t " "xrc_qp_num" "); +.nl +.BI "int ibv_unreg_xrc_rcv_qp(struct ibv_xrc_domain " "*xrc_domain" ", uint32_t " "xrc_qp_num" "); +.fi +.SH "DESCRIPTION" +.B ibv_reg_xrc_rcv_qp() +registers a user process with the XRC receive QP (created via +.B ibv_create_xrc_rcv_qp() +) whose number is +.I xrc_qp_num\fR, +and which is associated with the XRC domain +.I xrc_domain\fR. +.PP +.B ibv_unreg_xrc_rcv_qp() +unregisters a user process from the XRC receive QP number +.I xrc_qp_num\fR, +which is associated with the XRC domain +.I xrc_domain\fR. +When the number of user processes registered with this XRC receive QP drops to zero, the QP is destroyed. +.SH "RETURN VALUE" +.B ibv_reg_xrc_rcv_qp() +and +.B ibv_unreg_xrc_rcv_qp() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +.B ibv_reg_xrc_rcv_qp() +and +.B ibv_unreg_xrc_rcv_qp() +may fail if the number +.I xrc_qp_num +is not a number of a valid XRC receive QP (the QP is not allocated or it is the number of a non-XRC QP), or +the XRC receive QP was created with an XRC domain other than +.I xrc_domain\fR. + +If a process is still registered with any XRC RCV QPs belonging to some domain, +.B ibv_close_xrc_domain() +will return failure if called for that domain in that process. + +.B ibv_create_xrc_rcv_qp() +performs an implicit registration for the creating process; when that process is finished with the XRC RCV QP, it should call +.B ibv_unreg_xrc_rcv_qp() +for that QP. Note that if no other processes are registered with the QP at this time, its registration count will drop to zero and it will be destroyed. +.SH "SEE ALSO" +.BR ibv_open_xrc_domain (3), +.BR ibv_create_xrc_rcv_qp (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_req_notify_cq.3 b/contrib/ofed/libibverbs/man/ibv_req_notify_cq.3 new file mode 100644 index 000000000000..eda58011a714 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_req_notify_cq.3 @@ -0,0 +1,43 @@ +.\" -*- nroff -*- +.\" +.TH IBV_REQ_NOTIFY_CQ 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_req_notify_cq \- request completion notification on a completion queue (CQ) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_req_notify_cq(struct ibv_cq " "*cq" ", int " "solicited_only" "); +.SH "DESCRIPTION" +.B ibv_req_notify_cq() +requests a completion notification on the completion queue (CQ) +.I cq\fR. +.PP +Upon the addition of a new CQ entry (CQE) to +.I cq\fR, +a completion event will be added to the completion channel associated +with the CQ. +If the argument +.I solicited_only +is zero, a completion event is generated for any new CQE. If +.I solicited_only +is non\-zero, an event is only generated for a new CQE with that is +considered "solicited." A CQE is solicited if it is a receive +completion for a message with the Solicited Event header bit set, or +if the status is not successful. All other successful receive +completions, or any successful send completion is unsolicited. +.SH "RETURN VALUE" +.B +ibv_req_notify_cq() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +The request for notification is "one shot." Only one completion event +will be generated for each call to +.B ibv_req_notify_cq()\fR. +.SH "SEE ALSO" +.BR ibv_create_comp_channel (3), +.BR ibv_create_cq (3), +.BR ibv_get_cq_event (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_resize_cq.3 b/contrib/ofed/libibverbs/man/ibv_resize_cq.3 new file mode 100644 index 000000000000..0563f56d7411 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_resize_cq.3 @@ -0,0 +1,42 @@ +.\" -*- nroff -*- +.\" +.TH IBV_RESIZE_CQ 3 2006-10-31 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +ibv_resize_cq \- resize a completion queue (CQ) +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int ibv_resize_cq(struct ibv_cq " "*cq" ", int " "cqe" "); +.fi +.SH "DESCRIPTION" +.B ibv_resize_cq() +resizes the completion queue (CQ) +.I cq +to have at least +.I cqe +entries. +.I cqe +must be at least the number of unpolled entries in the CQ +.I cq\fR. +If +.I cqe +is a valid value less than the current CQ size, +.B ibv_resize_cq() +may not do anything, since this function is only guaranteed to resize +the CQ to a size at least as big as the requested size. +.SH "RETURN VALUE" +.B ibv_resize_cq() +returns 0 on success, or the value of errno on failure (which indicates the failure reason). +.SH "NOTES" +.B ibv_resize_cq() +may assign a CQ size greater than or equal to the requested size. +The cqe member of +.I cq +will be updated to the actual size. +.SH "SEE ALSO" +.BR ibv_create_cq (3) +.BR ibv_destroy_cq (3) +.SH "AUTHORS" +.TP +Dotan Barak diff --git a/contrib/ofed/libibverbs/man/ibv_srq_pingpong.1 b/contrib/ofed/libibverbs/man/ibv_srq_pingpong.1 new file mode 100644 index 000000000000..d50f70e63315 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_srq_pingpong.1 @@ -0,0 +1,68 @@ +.TH IBV_SRQ_PINGPONG 1 "August 30, 2005" "libibverbs" "USER COMMANDS" + +.SH NAME +ibv_srq_pingpong \- simple InfiniBand shared receive queue test + +.SH SYNOPSIS +.B ibv_srq_pingpong +[\-p port] [\-d device] [\-i ib port] [\-s size] [\-q num QPs] [\-r rx depth] +[\-n iters] [\-l sl] [\-e] \fBHOSTNAME\fR + +.B ibv_srq_pingpong +[\-p port] [\-d device] [\-i ib port] [\-s size] [\-q num QPs] [\-r rx depth] +[\-n iters] [\-l sl] [\-e] + +.SH DESCRIPTION +.PP +Run a simple ping-pong test over InfiniBand via the reliable +connected (RC) transport, using multiple queue pairs (QPs) and a +single shared receive queue (SRQ). + +.SH OPTIONS + +.PP +.TP +\fB\-p\fR, \fB\-\-port\fR=\fIPORT\fR +use TCP port \fIPORT\fR for initial synchronization (default 18515) +.TP +\fB\-d\fR, \fB\-\-ib\-dev\fR=\fIDEVICE\fR +use IB device \fIDEVICE\fR (default first device found) +.TP +\fB\-i\fR, \fB\-\-ib\-port\fR=\fIPORT\fR +use IB port \fIPORT\fR (default port 1) +.TP +\fB\-s\fR, \fB\-\-size\fR=\fISIZE\fR +ping-pong messages of size \fISIZE\fR (default 4096) +.TP +\fB\-q\fR, \fB\-\-num\-qp\fR=\fINUM\fR +use \fINUM\fR queue pairs for test (default 16) +.TP +\fB\-r\fR, \fB\-\-rx\-depth\fR=\fIDEPTH\fR +post \fIDEPTH\fR receives at a time (default 1000) +.TP +\fB\-n\fR, \fB\-\-iters\fR=\fIITERS\fR +perform \fIITERS\fR message exchanges (default 1000) +.TP +\fB\-l\fR, \fB\-\-sl\fR=\fISL\fR +use \fISL\fR as the service level value of the QPs (default 0) +.TP +\fB\-e\fR, \fB\-\-events\fR +sleep while waiting for work completion events (default is to poll for +completions) + +.SH SEE ALSO +.BR ibv_rc_pingpong (1), +.BR ibv_uc_pingpong (1), +.BR ibv_ud_pingpong (1) + +.SH AUTHORS +.TP +Roland Dreier +.RI < rolandd@cisco.com > + +.SH BUGS +The network synchronization between client and server instances is +weak, and does not prevent incompatible options from being used on the +two instances. The method used for retrieving work completions is not +strictly correct, and race conditions may cause failures on some +systems. diff --git a/contrib/ofed/libibverbs/man/ibv_uc_pingpong.1 b/contrib/ofed/libibverbs/man/ibv_uc_pingpong.1 new file mode 100644 index 000000000000..ec97eb0a54f6 --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_uc_pingpong.1 @@ -0,0 +1,64 @@ +.TH IBV_UC_PINGPONG 1 "August 30, 2005" "libibverbs" "USER COMMANDS" + +.SH NAME +ibv_uc_pingpong \- simple InfiniBand UC transport test + +.SH SYNOPSIS +.B ibv_uc_pingpong +[\-p port] [\-d device] [\-i ib port] [\-s size] [\-r rx depth] +[\-n iters] [\-l sl] [\-e] \fBHOSTNAME\fR + +.B ibv_uc_pingpong +[\-p port] [\-d device] [\-i ib port] [\-s size] [\-r rx depth] +[\-n iters] [\-l sl] [\-e] + +.SH DESCRIPTION +.PP +Run a simple ping-pong test over InfiniBand via the reliable +connected (RC) transport. + +.SH OPTIONS + +.PP +.TP +\fB\-p\fR, \fB\-\-port\fR=\fIPORT\fR +use TCP port \fIPORT\fR for initial synchronization (default 18515) +.TP +\fB\-d\fR, \fB\-\-ib\-dev\fR=\fIDEVICE\fR +use IB device \fIDEVICE\fR (default first device found) +.TP +\fB\-i\fR, \fB\-\-ib\-port\fR=\fIPORT\fR +use IB port \fIPORT\fR (default port 1) +.TP +\fB\-s\fR, \fB\-\-size\fR=\fISIZE\fR +ping-pong messages of size \fISIZE\fR (default 4096) +.TP +\fB\-r\fR, \fB\-\-rx\-depth\fR=\fIDEPTH\fR +post \fIDEPTH\fR receives at a time (default 1000) +.TP +\fB\-n\fR, \fB\-\-iters\fR=\fIITERS\fR +perform \fIITERS\fR message exchanges (default 1000) +.TP +\fB\-l\fR, \fB\-\-sl\fR=\fISL\fR +use \fISL\fR as the service level value of the QP (default 0) +.TP +\fB\-e\fR, \fB\-\-events\fR +sleep while waiting for work completion events (default is to poll for +completions) + +.SH SEE ALSO +.BR ibv_rc_pingpong (1), +.BR ibv_ud_pingpong (1), +.BR ibv_srq_pingpong (1) + +.SH AUTHORS +.TP +Roland Dreier +.RI < rolandd@cisco.com > + +.SH BUGS +The network synchronization between client and server instances is +weak, and does not prevent incompatible options from being used on the +two instances. The method used for retrieving work completions is not +strictly correct, and race conditions may cause failures on some +systems. diff --git a/contrib/ofed/libibverbs/man/ibv_ud_pingpong.1 b/contrib/ofed/libibverbs/man/ibv_ud_pingpong.1 new file mode 100644 index 000000000000..a05af8d6b80f --- /dev/null +++ b/contrib/ofed/libibverbs/man/ibv_ud_pingpong.1 @@ -0,0 +1,64 @@ +.TH IBV_UD_PINGPONG 1 "August 30, 2005" "libibverbs" "USER COMMANDS" + +.SH NAME +ibv_ud_pingpong \- simple InfiniBand UD transport test + +.SH SYNOPSIS +.B ibv_ud_pingpong +[\-p port] [\-d device] [\-i ib port] [\-s size] [\-r rx depth] +[\-n iters] [\-l sl] [\-e] \fBHOSTNAME\fR + +.B ibv_ud_pingpong +[\-p port] [\-d device] [\-i ib port] [\-s size] [\-r rx depth] +[\-n iters] [\-l sl] [\-e] + +.SH DESCRIPTION +.PP +Run a simple ping-pong test over InfiniBand via the unreliable +datagram (UD) transport. + +.SH OPTIONS + +.PP +.TP +\fB\-p\fR, \fB\-\-port\fR=\fIPORT\fR +use TCP port \fIPORT\fR for initial synchronization (default 18515) +.TP +\fB\-d\fR, \fB\-\-ib\-dev\fR=\fIDEVICE\fR +use IB device \fIDEVICE\fR (default first device found) +.TP +\fB\-i\fR, \fB\-\-ib\-port\fR=\fIPORT\fR +use IB port \fIPORT\fR (default port 1) +.TP +\fB\-s\fR, \fB\-\-size\fR=\fISIZE\fR +ping-pong messages of size \fISIZE\fR (default 2048) +.TP +\fB\-r\fR, \fB\-\-rx\-depth\fR=\fIDEPTH\fR +post \fIDEPTH\fR receives at a time (default 500) +.TP +\fB\-n\fR, \fB\-\-iters\fR=\fIITERS\fR +perform \fIITERS\fR message exchanges (default 1000) +.TP +\fB\-l\fR, \fB\-\-sl\fR=\fISL\fR +send messages with service level \fISL\fR (default 0) +.TP +\fB\-e\fR, \fB\-\-events\fR +sleep while waiting for work completion events (default is to poll for +completions) + +.SH SEE ALSO +.BR ibv_rc_pingpong (1), +.BR ibv_uc_pingpong (1), +.BR ibv_srq_pingpong (1) + +.SH AUTHORS +.TP +Roland Dreier +.RI < rolandd@cisco.com > + +.SH BUGS +The network synchronization between client and server instances is +weak, and does not prevent incompatible options from being used on the +two instances. The method used for retrieving work completions is not +strictly correct, and race conditions may cause failures on some +systems. diff --git a/contrib/ofed/libibverbs/man/verbs.7 b/contrib/ofed/libibverbs/man/verbs.7 new file mode 100644 index 000000000000..eab44637526e --- /dev/null +++ b/contrib/ofed/libibverbs/man/verbs.7 @@ -0,0 +1,228 @@ +.\" -*- nroff -*- +.\" +.TH VERBS 7 2008-02-25 libibverbs "Libibverbs Programmer's Manual" +.SH "NAME" +verbs \- Infiniband verbs library +.SH "SYNOPSIS" +.nf +.B #include +.fi +.SH "DESCRIPTION" +This library is an implementation of the verbs based on the Infiniband specification volume 1.2 chapter 11. It handles the control path of creating, modifying, querying and destroying resources such as Protection Domains (PD), Completion Queues (CQ), Queue-Pairs (QP), Shared Receive Queues (SRQ), Address Handles (AH), Memory Regions (MR). It also handles sending and receiving data posted to QPs and SRQs, getting completions from CQs using polling and completions events. + +The control path is implemented through system calls to the uverbs kernel module which further calls the low level HW driver. The data path is implemented through calls made to low level HW library which in most cases interacts directly with the HW providing kernel and network stack bypass (saving context/mode switches) along with zero copy and an asynchronous I/O model. + + +Typically, under network and RDMA programming, there are operations which involve interaction with remote peers (such as address resolution and connection establishment) and remote entities (such as route resolution and joining a multicast group under IB), where a resource managed through IB verbs such as QP or AH would be eventually created or effected from this interaction. In such cases, applications whose addressing semantics is based on IP can use librdmacm (see rdma_cm(7)) which works in conjunction with libibverbs. + +This library is thread safe library and verbs can be called from every thread in the process (the same resource can even be handled from different threads, for example: ibv_poll_cq can be called from more than one thread). + +However, it is up to the user to stop working with a resource after it was destroyed (by the same thread or by any other thread), this may result a segmentation fault. + +If fork (or any other system call that perform fork directly or indirectly) is being used, please see ibv_fork_init(3). + +.LP +The following shall be declared as functions and may also be defined +as macros. Function prototypes shall be provided. +.RS +.nf + +\fB +.B Library functions + +int ibv_fork_init(void); + +.B Device functions + +struct ibv_device **ibv_get_device_list(int *num_devices); +void ibv_free_device_list(struct ibv_device **list); +const char *ibv_get_device_name(struct ibv_device *device); +uint64_t ibv_get_device_guid(struct ibv_device *device); + +.B Context functions + +struct ibv_context *ibv_open_device(struct ibv_device *device); +int ibv_close_device(struct ibv_context *context); + +.B Queries + +int ibv_query_device(struct ibv_context *context, + struct ibv_device_attr *device_attr); +int ibv_query_port(struct ibv_context *context, uint8_t port_num, + struct ibv_port_attr *port_attr); +int ibv_query_pkey(struct ibv_context *context, uint8_t port_num, + int index, uint16_t *pkey); +int ibv_query_gid(struct ibv_context *context, uint8_t port_num, + int index, union ibv_gid *gid); + +.B Asynchronous events + +int ibv_get_async_event(struct ibv_context *context, + struct ibv_async_event *event); +void ibv_ack_async_event(struct ibv_async_event *event); + +.B Protection Domains + +struct ibv_pd *ibv_alloc_pd(struct ibv_context *context); +int ibv_dealloc_pd(struct ibv_pd *pd); + +.B Memory Regions + +struct ibv_mr *ibv_reg_mr(struct ibv_pd *pd, void *addr, + size_t length, enum ibv_access_flags access); +int ibv_dereg_mr(struct ibv_mr *mr); + +.B Address Handles + +struct ibv_ah *ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr); +int ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num, + struct ibv_wc *wc, struct ibv_grh *grh, + struct ibv_ah_attr *ah_attr); +struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc, + struct ibv_grh *grh, uint8_t port_num); +int ibv_destroy_ah(struct ibv_ah *ah); + +.B Completion event channels + +struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context *context); +int ibv_destroy_comp_channel(struct ibv_comp_channel *channel); + +.B Completion Queues Control + +struct ibv_cq *ibv_create_cq(struct ibv_context *context, int cqe, + void *cq_context, + struct ibv_comp_channel *channel, + int comp_vector); +int ibv_destroy_cq(struct ibv_cq *cq); +int ibv_resize_cq(struct ibv_cq *cq, int cqe); + +.B Reading Completions from CQ + +int ibv_poll_cq(struct ibv_cq *cq, int num_entries, struct ibv_wc *wc); + +.B Requesting / Managing CQ events + +int ibv_req_notify_cq(struct ibv_cq *cq, int solicited_only); +int ibv_get_cq_event(struct ibv_comp_channel *channel, + struct ibv_cq **cq, void **cq_context); +void ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents); + +.B Shared Receive Queue control + +struct ibv_srq *ibv_create_srq(struct ibv_pd *pd, + struct ibv_srq_init_attr *srq_init_attr); +int ibv_destroy_srq(struct ibv_srq *srq); +int ibv_modify_srq(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + enum ibv_srq_attr_mask srq_attr_mask); +int ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr); + +.B eXtended Reliable Connection control + +struct ibv_xrc_domain *ibv_open_xrc_domain(struct ibv_context *context, + int fd, int oflag); +int ibv_close_xrc_domain(struct ibv_xrc_domain *d); +struct ibv_srq *ibv_create_xrc_srq(struct ibv_pd *pd, + struct ibv_xrc_domain *xrc_domain, + struct ibv_cq *xrc_cq, + struct ibv_srq_init_attr *srq_init_attr); +int ibv_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, + uint32_t *xrc_rcv_qpn); +int ibv_modify_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num, + struct ibv_qp_attr *attr, int attr_mask); +int ibv_query_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num, + struct ibv_qp_attr *attr, int attr_mask, + struct ibv_qp_init_attr *init_attr); +int ibv_reg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num); +int ibv_unreg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, uint32_t xrc_qp_num); + +.B Queue Pair control + +struct ibv_qp *ibv_create_qp(struct ibv_pd *pd, + struct ibv_qp_init_attr *qp_init_attr); +int ibv_destroy_qp(struct ibv_qp *qp); +int ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + enum ibv_qp_attr_mask attr_mask); +int ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + enum ibv_qp_attr_mask attr_mask, + struct ibv_qp_init_attr *init_attr); + +.B posting Work Requests to QPs/SRQs +int ibv_post_send(struct ibv_qp *qp, struct ibv_send_wr *wr, + struct ibv_send_wr **bad_wr); +int ibv_post_recv(struct ibv_qp *qp, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr); +int ibv_post_srq_recv(struct ibv_srq *srq, + struct ibv_recv_wr *recv_wr, + struct ibv_recv_wr **bad_recv_wr); + +.B Multicast group + +int ibv_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid); +int ibv_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid); + +.B General functions + +int ibv_rate_to_mult(enum ibv_rate rate); +enum ibv_rate mult_to_ibv_rate(int mult); +\fP +.SH "SEE ALSO" +.LP +\fIibv_fork_init\fP(), +\fIibv_get_device_list\fP(), +\fIibv_free_device_list\fP(), +\fIibv_get_device_name\fP(), +\fIibv_get_device_guid\fP(), +\fIibv_open_device\fP(), +\fIibv_close_device\fP(), +\fIibv_query_device\fP(), +\fIibv_query_port\fP(), +\fIibv_query_pkey\fP(), +\fIibv_query_gid\fP(), +\fIibv_get_async_event\fP(), +\fIibv_ack_async_event\fP(), +\fIibv_alloc_pd\fP(), +\fIibv_dealloc_pd\fP(), +\fIibv_reg_mr\fP(), +\fIibv_dereg_mr\fP(), +\fIibv_create_ah\fP(), +\fIibv_init_ah_from_wc\fP(), +\fIibv_create_ah_from_wc\fP(), +\fIibv_destroy_ah\fP(), +\fIibv_create_comp_channel\fP(), +\fIibv_destroy_comp_channel\fP(), +\fIibv_create_cq\fP(), +\fIibv_destroy_cq\fP(), +\fIibv_resize_cq\fP(), +\fIibv_poll_cq\fP(), +\fIibv_req_notify_cq\fP(), +\fIibv_get_cq_event\fP(), +\fIibv_ack_cq_events\fP(), +\fIibv_create_srq\fP(), +\fIibv_destroy_srq\fP(), +\fIibv_modify_srq\fP(), +\fIibv_query_srq\fP(), +\fIibv_open_xrc_domain\fP(), +\fIibv_close_xrc_domain\fP(), +\fIibv_create_xrc_srq\fP(), +\fIibv_create_xrc_rcv_qp\fP(), +\fIibv_modify_xrc_rcv_qp\fP(), +\fIibv_query_xrc_rcv_qp\fP(), +\fIibv_reg_xrc_rcv_qp\fP(), +\fIibv_unreg_xrc_rcv_qp\fP(), +\fIibv_post_srq_recv\fP(), +\fIibv_create_qp\fP(), +\fIibv_destroy_qp\fP(), +\fIibv_modify_qp\fP(), +\fIibv_query_qp\fP(), +\fIibv_post_send\fP(), +\fIibv_post_recv\fP(), +\fIibv_attach_mcast\fP(), +\fIibv_detach_mcast\fP(), +\fIibv_rate_to_mult\fP(), +\fImult_to_ibv_rate\fP() +.SH "AUTHORS" +.TP +Dotan Barak +.TP +Or Gerlitz diff --git a/contrib/ofed/libibverbs/src/cmd.c b/contrib/ofed/libibverbs/src/cmd.c new file mode 100644 index 000000000000..fa67df2f765a --- /dev/null +++ b/contrib/ofed/libibverbs/src/cmd.c @@ -0,0 +1,1409 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. + * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include "ibverbs.h" + +static int ibv_cmd_get_context_v2(struct ibv_context *context, + struct ibv_get_context *new_cmd, + size_t new_cmd_size, + struct ibv_get_context_resp *resp, + size_t resp_size) +{ + struct ibv_abi_compat_v2 *t; + struct ibv_get_context_v2 *cmd; + size_t cmd_size; + uint32_t cq_fd; + + t = malloc(sizeof *t); + if (!t) + return ENOMEM; + pthread_mutex_init(&t->in_use, NULL); + + cmd_size = sizeof *cmd + new_cmd_size - sizeof *new_cmd; + cmd = alloca(cmd_size); + memcpy(cmd->driver_data, new_cmd->driver_data, new_cmd_size - sizeof *new_cmd); + + IBV_INIT_CMD_RESP(cmd, cmd_size, GET_CONTEXT, resp, resp_size); + cmd->cq_fd_tab = (uintptr_t) &cq_fd; + + if (write(context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(resp, resp_size); + + context->async_fd = resp->async_fd; + context->num_comp_vectors = 1; + t->channel.context = context; + t->channel.fd = cq_fd; + t->channel.refcnt = 0; + context->abi_compat = t; + + return 0; +} + +int ibv_cmd_get_context(struct ibv_context *context, struct ibv_get_context *cmd, + size_t cmd_size, struct ibv_get_context_resp *resp, + size_t resp_size) +{ + if (abi_ver <= 2) + return ibv_cmd_get_context_v2(context, cmd, cmd_size, resp, resp_size); + + IBV_INIT_CMD_RESP(cmd, cmd_size, GET_CONTEXT, resp, resp_size); + + if (write(context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(resp, resp_size); + + context->async_fd = resp->async_fd; + context->num_comp_vectors = resp->num_comp_vectors; + + return 0; +} + +int ibv_cmd_query_device(struct ibv_context *context, + struct ibv_device_attr *device_attr, + uint64_t *raw_fw_ver, + struct ibv_query_device *cmd, size_t cmd_size) +{ + struct ibv_query_device_resp resp; + + IBV_INIT_CMD_RESP(cmd, cmd_size, QUERY_DEVICE, &resp, sizeof resp); + + if (write(context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); + + memset(device_attr->fw_ver, 0, sizeof device_attr->fw_ver); + *raw_fw_ver = resp.fw_ver; + device_attr->node_guid = resp.node_guid; + device_attr->sys_image_guid = resp.sys_image_guid; + device_attr->max_mr_size = resp.max_mr_size; + device_attr->page_size_cap = resp.page_size_cap; + device_attr->vendor_id = resp.vendor_id; + device_attr->vendor_part_id = resp.vendor_part_id; + device_attr->hw_ver = resp.hw_ver; + device_attr->max_qp = resp.max_qp; + device_attr->max_qp_wr = resp.max_qp_wr; + device_attr->device_cap_flags = resp.device_cap_flags; + device_attr->max_sge = resp.max_sge; + device_attr->max_sge_rd = resp.max_sge_rd; + device_attr->max_cq = resp.max_cq; + device_attr->max_cqe = resp.max_cqe; + device_attr->max_mr = resp.max_mr; + device_attr->max_pd = resp.max_pd; + device_attr->max_qp_rd_atom = resp.max_qp_rd_atom; + device_attr->max_ee_rd_atom = resp.max_ee_rd_atom; + device_attr->max_res_rd_atom = resp.max_res_rd_atom; + device_attr->max_qp_init_rd_atom = resp.max_qp_init_rd_atom; + device_attr->max_ee_init_rd_atom = resp.max_ee_init_rd_atom; + device_attr->atomic_cap = resp.atomic_cap; + device_attr->max_ee = resp.max_ee; + device_attr->max_rdd = resp.max_rdd; + device_attr->max_mw = resp.max_mw; + device_attr->max_raw_ipv6_qp = resp.max_raw_ipv6_qp; + device_attr->max_raw_ethy_qp = resp.max_raw_ethy_qp; + device_attr->max_mcast_grp = resp.max_mcast_grp; + device_attr->max_mcast_qp_attach = resp.max_mcast_qp_attach; + device_attr->max_total_mcast_qp_attach = resp.max_total_mcast_qp_attach; + device_attr->max_ah = resp.max_ah; + device_attr->max_fmr = resp.max_fmr; + device_attr->max_map_per_fmr = resp.max_map_per_fmr; + device_attr->max_srq = resp.max_srq; + device_attr->max_srq_wr = resp.max_srq_wr; + device_attr->max_srq_sge = resp.max_srq_sge; + device_attr->max_pkeys = resp.max_pkeys; + device_attr->local_ca_ack_delay = resp.local_ca_ack_delay; + device_attr->phys_port_cnt = resp.phys_port_cnt; + + return 0; +} + +int ibv_cmd_query_port(struct ibv_context *context, uint8_t port_num, + struct ibv_port_attr *port_attr, + struct ibv_query_port *cmd, size_t cmd_size) +{ + struct ibv_query_port_resp resp; + + IBV_INIT_CMD_RESP(cmd, cmd_size, QUERY_PORT, &resp, sizeof resp); + cmd->port_num = port_num; + memset(cmd->reserved, 0, sizeof cmd->reserved); + + if (write(context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); + + port_attr->state = resp.state; + port_attr->max_mtu = resp.max_mtu; + port_attr->active_mtu = resp.active_mtu; + port_attr->gid_tbl_len = resp.gid_tbl_len; + port_attr->port_cap_flags = resp.port_cap_flags; + port_attr->max_msg_sz = resp.max_msg_sz; + port_attr->bad_pkey_cntr = resp.bad_pkey_cntr; + port_attr->qkey_viol_cntr = resp.qkey_viol_cntr; + port_attr->pkey_tbl_len = resp.pkey_tbl_len; + port_attr->lid = resp.lid; + port_attr->sm_lid = resp.sm_lid; + port_attr->lmc = resp.lmc; + port_attr->max_vl_num = resp.max_vl_num; + port_attr->sm_sl = resp.sm_sl; + port_attr->subnet_timeout = resp.subnet_timeout; + port_attr->init_type_reply = resp.init_type_reply; + port_attr->active_width = resp.active_width; + port_attr->active_speed = resp.active_speed; + port_attr->phys_state = resp.phys_state; + port_attr->link_layer = resp.link_layer; + + return 0; +} + +int ibv_cmd_alloc_pd(struct ibv_context *context, struct ibv_pd *pd, + struct ibv_alloc_pd *cmd, size_t cmd_size, + struct ibv_alloc_pd_resp *resp, size_t resp_size) +{ + IBV_INIT_CMD_RESP(cmd, cmd_size, ALLOC_PD, resp, resp_size); + + if (write(context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(resp, resp_size); + + pd->handle = resp->pd_handle; + pd->context = context; + + return 0; +} + +int ibv_cmd_dealloc_pd(struct ibv_pd *pd) +{ + struct ibv_dealloc_pd cmd; + + IBV_INIT_CMD(&cmd, sizeof cmd, DEALLOC_PD); + cmd.pd_handle = pd->handle; + + if (write(pd->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + return 0; +} + +int ibv_cmd_reg_mr(struct ibv_pd *pd, void *addr, size_t length, + uint64_t hca_va, int access, + struct ibv_mr *mr, struct ibv_reg_mr *cmd, + size_t cmd_size, + struct ibv_reg_mr_resp *resp, size_t resp_size) +{ + + IBV_INIT_CMD_RESP(cmd, cmd_size, REG_MR, resp, resp_size); + + cmd->start = (uintptr_t) addr; + cmd->length = length; + cmd->hca_va = hca_va; + cmd->pd_handle = pd->handle; + cmd->access_flags = access; + + if (write(pd->context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(resp, resp_size); + + mr->handle = resp->mr_handle; + mr->lkey = resp->lkey; + mr->rkey = resp->rkey; + mr->context = pd->context; + + return 0; +} + +int ibv_cmd_dereg_mr(struct ibv_mr *mr) +{ + struct ibv_dereg_mr cmd; + + IBV_INIT_CMD(&cmd, sizeof cmd, DEREG_MR); + cmd.mr_handle = mr->handle; + + if (write(mr->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + return 0; +} + +static int ibv_cmd_create_cq_v2(struct ibv_context *context, int cqe, + struct ibv_cq *cq, + struct ibv_create_cq *new_cmd, size_t new_cmd_size, + struct ibv_create_cq_resp *resp, size_t resp_size) +{ + struct ibv_create_cq_v2 *cmd; + size_t cmd_size; + + cmd_size = sizeof *cmd + new_cmd_size - sizeof *new_cmd; + cmd = alloca(cmd_size); + memcpy(cmd->driver_data, new_cmd->driver_data, new_cmd_size - sizeof *new_cmd); + + IBV_INIT_CMD_RESP(cmd, cmd_size, CREATE_CQ, resp, resp_size); + cmd->user_handle = (uintptr_t) cq; + cmd->cqe = cqe; + cmd->event_handler = 0; + + if (write(context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(resp, resp_size); + + cq->handle = resp->cq_handle; + cq->cqe = resp->cqe; + cq->context = context; + + return 0; +} + +int ibv_cmd_create_cq(struct ibv_context *context, int cqe, + struct ibv_comp_channel *channel, + int comp_vector, struct ibv_cq *cq, + struct ibv_create_cq *cmd, size_t cmd_size, + struct ibv_create_cq_resp *resp, size_t resp_size) +{ + if (abi_ver <= 2) + return ibv_cmd_create_cq_v2(context, cqe, cq, + cmd, cmd_size, resp, resp_size); + + IBV_INIT_CMD_RESP(cmd, cmd_size, CREATE_CQ, resp, resp_size); + cmd->user_handle = (uintptr_t) cq; + cmd->cqe = cqe; + cmd->comp_vector = comp_vector; + cmd->comp_channel = channel ? channel->fd : -1; + cmd->reserved = 0; + + if (write(context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(resp, resp_size); + + cq->handle = resp->cq_handle; + cq->cqe = resp->cqe; + cq->context = context; + + return 0; +} + +int ibv_cmd_poll_cq(struct ibv_cq *ibcq, int ne, struct ibv_wc *wc) +{ + struct ibv_poll_cq cmd; + struct ibv_poll_cq_resp *resp; + int i; + int rsize; + int ret; + + rsize = sizeof *resp + ne * sizeof(struct ibv_kern_wc); + resp = malloc(rsize); + if (!resp) + return -1; + + IBV_INIT_CMD_RESP(&cmd, sizeof cmd, POLL_CQ, resp, rsize); + cmd.cq_handle = ibcq->handle; + cmd.ne = ne; + + if (write(ibcq->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) { + ret = -1; + goto out; + } + + VALGRIND_MAKE_MEM_DEFINED(resp, rsize); + + for (i = 0; i < resp->count; i++) { + wc[i].wr_id = resp->wc[i].wr_id; + wc[i].status = resp->wc[i].status; + wc[i].opcode = resp->wc[i].opcode; + wc[i].vendor_err = resp->wc[i].vendor_err; + wc[i].byte_len = resp->wc[i].byte_len; + wc[i].imm_data = resp->wc[i].imm_data; + wc[i].qp_num = resp->wc[i].qp_num; + wc[i].src_qp = resp->wc[i].src_qp; + wc[i].wc_flags = resp->wc[i].wc_flags; + wc[i].pkey_index = resp->wc[i].pkey_index; + wc[i].slid = resp->wc[i].slid; + wc[i].sl = resp->wc[i].sl; + wc[i].dlid_path_bits = resp->wc[i].dlid_path_bits; + } + + ret = resp->count; + +out: + free(resp); + return ret; +} + +int ibv_cmd_req_notify_cq(struct ibv_cq *ibcq, int solicited_only) +{ + struct ibv_req_notify_cq cmd; + + IBV_INIT_CMD(&cmd, sizeof cmd, REQ_NOTIFY_CQ); + cmd.cq_handle = ibcq->handle; + cmd.solicited = !!solicited_only; + + if (write(ibcq->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + return 0; +} + +int ibv_cmd_resize_cq(struct ibv_cq *cq, int cqe, + struct ibv_resize_cq *cmd, size_t cmd_size, + struct ibv_resize_cq_resp *resp, size_t resp_size) +{ + + IBV_INIT_CMD_RESP(cmd, cmd_size, RESIZE_CQ, resp, resp_size); + cmd->cq_handle = cq->handle; + cmd->cqe = cqe; + + if (write(cq->context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(resp, resp_size); + + cq->cqe = resp->cqe; + + return 0; +} + +static int ibv_cmd_destroy_cq_v1(struct ibv_cq *cq) +{ + struct ibv_destroy_cq_v1 cmd; + + IBV_INIT_CMD(&cmd, sizeof cmd, DESTROY_CQ); + cmd.cq_handle = cq->handle; + + if (write(cq->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + return 0; +} + +int ibv_cmd_destroy_cq(struct ibv_cq *cq) +{ + struct ibv_destroy_cq cmd; + struct ibv_destroy_cq_resp resp; + + if (abi_ver == 1) + return ibv_cmd_destroy_cq_v1(cq); + + IBV_INIT_CMD_RESP(&cmd, sizeof cmd, DESTROY_CQ, &resp, sizeof resp); + cmd.cq_handle = cq->handle; + cmd.reserved = 0; + + if (write(cq->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); + + pthread_mutex_lock(&cq->mutex); + while (cq->comp_events_completed != resp.comp_events_reported || + cq->async_events_completed != resp.async_events_reported) + pthread_cond_wait(&cq->cond, &cq->mutex); + pthread_mutex_unlock(&cq->mutex); + + return 0; +} + +int ibv_cmd_create_srq(struct ibv_pd *pd, + struct ibv_srq *srq, struct ibv_srq_init_attr *attr, + struct ibv_create_srq *cmd, size_t cmd_size, + struct ibv_create_srq_resp *resp, size_t resp_size) +{ + IBV_INIT_CMD_RESP(cmd, cmd_size, CREATE_SRQ, resp, resp_size); + cmd->user_handle = (uintptr_t) srq; + cmd->pd_handle = pd->handle; + cmd->max_wr = attr->attr.max_wr; + cmd->max_sge = attr->attr.max_sge; + cmd->srq_limit = attr->attr.srq_limit; + + if (write(pd->context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(resp, resp_size); + + srq->handle = resp->srq_handle; + srq->context = pd->context; + + if (abi_ver > 5) { + attr->attr.max_wr = resp->max_wr; + attr->attr.max_sge = resp->max_sge; + } else { + struct ibv_create_srq_resp_v5 *resp_v5 = + (struct ibv_create_srq_resp_v5 *) resp; + + memmove((void *) resp + sizeof *resp, + (void *) resp_v5 + sizeof *resp_v5, + resp_size - sizeof *resp); + } + + return 0; +} + +int ibv_cmd_create_xrc_srq(struct ibv_pd *pd, + struct ibv_srq *srq, struct ibv_srq_init_attr *attr, + uint32_t xrcd_handle, uint32_t xrc_cq, + struct ibv_create_xrc_srq *cmd, size_t cmd_size, + struct ibv_create_srq_resp *resp, size_t resp_size) +{ + IBV_INIT_CMD_RESP(cmd, cmd_size, CREATE_XRC_SRQ, resp, resp_size); + cmd->user_handle = (uintptr_t) srq; + cmd->pd_handle = pd->handle; + cmd->max_wr = attr->attr.max_wr; + cmd->max_sge = attr->attr.max_sge; + cmd->srq_limit = attr->attr.srq_limit; + cmd->xrcd_handle = xrcd_handle; + cmd->xrc_cq = xrc_cq; + + if (write(pd->context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(resp, resp_size); + + srq->handle = resp->srq_handle; + srq->context = pd->context; + attr->attr.max_wr = resp->max_wr; + attr->attr.max_sge = resp->max_sge; + + return 0; +} + +static int ibv_cmd_modify_srq_v3(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + int srq_attr_mask, + struct ibv_modify_srq *new_cmd, + size_t new_cmd_size) +{ + struct ibv_modify_srq_v3 *cmd; + size_t cmd_size; + + cmd_size = sizeof *cmd + new_cmd_size - sizeof *new_cmd; + cmd = alloca(cmd_size); + memcpy(cmd->driver_data, new_cmd->driver_data, new_cmd_size - sizeof *new_cmd); + + IBV_INIT_CMD(cmd, cmd_size, MODIFY_SRQ); + + cmd->srq_handle = srq->handle; + cmd->attr_mask = srq_attr_mask; + cmd->max_wr = srq_attr->max_wr; + cmd->srq_limit = srq_attr->srq_limit; + cmd->max_sge = 0; + cmd->reserved = 0; + + if (write(srq->context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + return 0; +} + +int ibv_cmd_modify_srq(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + int srq_attr_mask, + struct ibv_modify_srq *cmd, size_t cmd_size) +{ + if (abi_ver == 3) + return ibv_cmd_modify_srq_v3(srq, srq_attr, srq_attr_mask, + cmd, cmd_size); + + IBV_INIT_CMD(cmd, cmd_size, MODIFY_SRQ); + + cmd->srq_handle = srq->handle; + cmd->attr_mask = srq_attr_mask; + cmd->max_wr = srq_attr->max_wr; + cmd->srq_limit = srq_attr->srq_limit; + + if (write(srq->context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + return 0; +} + +int ibv_cmd_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr, + struct ibv_query_srq *cmd, size_t cmd_size) +{ + struct ibv_query_srq_resp resp; + + IBV_INIT_CMD_RESP(cmd, cmd_size, QUERY_SRQ, &resp, sizeof resp); + cmd->srq_handle = srq->handle; + cmd->reserved = 0; + + if (write(srq->context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); + + srq_attr->max_wr = resp.max_wr; + srq_attr->max_sge = resp.max_sge; + srq_attr->srq_limit = resp.srq_limit; + + return 0; +} + +static int ibv_cmd_destroy_srq_v1(struct ibv_srq *srq) +{ + struct ibv_destroy_srq_v1 cmd; + + IBV_INIT_CMD(&cmd, sizeof cmd, DESTROY_SRQ); + cmd.srq_handle = srq->handle; + + if (write(srq->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + return 0; +} + +int ibv_cmd_destroy_srq(struct ibv_srq *srq) +{ + struct ibv_destroy_srq cmd; + struct ibv_destroy_srq_resp resp; + + if (abi_ver == 1) + return ibv_cmd_destroy_srq_v1(srq); + + IBV_INIT_CMD_RESP(&cmd, sizeof cmd, DESTROY_SRQ, &resp, sizeof resp); + cmd.srq_handle = srq->handle; + cmd.reserved = 0; + + if (write(srq->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); + + pthread_mutex_lock(&srq->mutex); + while (srq->events_completed != resp.events_reported) + pthread_cond_wait(&srq->cond, &srq->mutex); + pthread_mutex_unlock(&srq->mutex); + + return 0; +} + +int ibv_cmd_create_qp(struct ibv_pd *pd, + struct ibv_qp *qp, struct ibv_qp_init_attr *attr, + struct ibv_create_qp *cmd, size_t cmd_size, + struct ibv_create_qp_resp *resp, size_t resp_size) +{ + IBV_INIT_CMD_RESP(cmd, cmd_size, CREATE_QP, resp, resp_size); + + cmd->user_handle = (uintptr_t) qp; + cmd->pd_handle = pd->handle; + cmd->send_cq_handle = attr->send_cq->handle; + cmd->recv_cq_handle = attr->recv_cq->handle; + cmd->max_send_wr = attr->cap.max_send_wr; + cmd->max_recv_wr = attr->cap.max_recv_wr; + cmd->max_send_sge = attr->cap.max_send_sge; + cmd->max_recv_sge = attr->cap.max_recv_sge; + cmd->max_inline_data = attr->cap.max_inline_data; + cmd->sq_sig_all = attr->sq_sig_all; + cmd->qp_type = attr->qp_type; + cmd->is_srq = !!attr->srq; + cmd->srq_handle = attr->qp_type == IBV_QPT_XRC ? + (attr->xrc_domain ? attr->xrc_domain->handle : 0) : + (attr->srq ? attr->srq->handle : 0); + cmd->reserved = 0; + + if (write(pd->context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(resp, resp_size); + + qp->handle = resp->qp_handle; + qp->qp_num = resp->qpn; + qp->context = pd->context; + + if (abi_ver > 3) { + attr->cap.max_recv_sge = resp->max_recv_sge; + attr->cap.max_send_sge = resp->max_send_sge; + attr->cap.max_recv_wr = resp->max_recv_wr; + attr->cap.max_send_wr = resp->max_send_wr; + attr->cap.max_inline_data = resp->max_inline_data; + } + + if (abi_ver == 4) { + struct ibv_create_qp_resp_v4 *resp_v4 = + (struct ibv_create_qp_resp_v4 *) resp; + + memmove((void *) resp + sizeof *resp, + (void *) resp_v4 + sizeof *resp_v4, + resp_size - sizeof *resp); + } else if (abi_ver <= 3) { + struct ibv_create_qp_resp_v3 *resp_v3 = + (struct ibv_create_qp_resp_v3 *) resp; + + memmove((void *) resp + sizeof *resp, + (void *) resp_v3 + sizeof *resp_v3, + resp_size - sizeof *resp); + } + + return 0; +} + +int ibv_cmd_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask, + struct ibv_qp_init_attr *init_attr, + struct ibv_query_qp *cmd, size_t cmd_size) +{ + struct ibv_query_qp_resp resp; + + IBV_INIT_CMD_RESP(cmd, cmd_size, QUERY_QP, &resp, sizeof resp); + cmd->qp_handle = qp->handle; + cmd->attr_mask = attr_mask; + + if (write(qp->context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); + + attr->qkey = resp.qkey; + attr->rq_psn = resp.rq_psn; + attr->sq_psn = resp.sq_psn; + attr->dest_qp_num = resp.dest_qp_num; + attr->qp_access_flags = resp.qp_access_flags; + attr->pkey_index = resp.pkey_index; + attr->alt_pkey_index = resp.alt_pkey_index; + attr->qp_state = resp.qp_state; + attr->cur_qp_state = resp.cur_qp_state; + attr->path_mtu = resp.path_mtu; + attr->path_mig_state = resp.path_mig_state; + attr->sq_draining = resp.sq_draining; + attr->max_rd_atomic = resp.max_rd_atomic; + attr->max_dest_rd_atomic = resp.max_dest_rd_atomic; + attr->min_rnr_timer = resp.min_rnr_timer; + attr->port_num = resp.port_num; + attr->timeout = resp.timeout; + attr->retry_cnt = resp.retry_cnt; + attr->rnr_retry = resp.rnr_retry; + attr->alt_port_num = resp.alt_port_num; + attr->alt_timeout = resp.alt_timeout; + attr->cap.max_send_wr = resp.max_send_wr; + attr->cap.max_recv_wr = resp.max_recv_wr; + attr->cap.max_send_sge = resp.max_send_sge; + attr->cap.max_recv_sge = resp.max_recv_sge; + attr->cap.max_inline_data = resp.max_inline_data; + + memcpy(attr->ah_attr.grh.dgid.raw, resp.dest.dgid, 16); + attr->ah_attr.grh.flow_label = resp.dest.flow_label; + attr->ah_attr.dlid = resp.dest.dlid; + attr->ah_attr.grh.sgid_index = resp.dest.sgid_index; + attr->ah_attr.grh.hop_limit = resp.dest.hop_limit; + attr->ah_attr.grh.traffic_class = resp.dest.traffic_class; + attr->ah_attr.sl = resp.dest.sl; + attr->ah_attr.src_path_bits = resp.dest.src_path_bits; + attr->ah_attr.static_rate = resp.dest.static_rate; + attr->ah_attr.is_global = resp.dest.is_global; + attr->ah_attr.port_num = resp.dest.port_num; + + memcpy(attr->alt_ah_attr.grh.dgid.raw, resp.alt_dest.dgid, 16); + attr->alt_ah_attr.grh.flow_label = resp.alt_dest.flow_label; + attr->alt_ah_attr.dlid = resp.alt_dest.dlid; + attr->alt_ah_attr.grh.sgid_index = resp.alt_dest.sgid_index; + attr->alt_ah_attr.grh.hop_limit = resp.alt_dest.hop_limit; + attr->alt_ah_attr.grh.traffic_class = resp.alt_dest.traffic_class; + attr->alt_ah_attr.sl = resp.alt_dest.sl; + attr->alt_ah_attr.src_path_bits = resp.alt_dest.src_path_bits; + attr->alt_ah_attr.static_rate = resp.alt_dest.static_rate; + attr->alt_ah_attr.is_global = resp.alt_dest.is_global; + attr->alt_ah_attr.port_num = resp.alt_dest.port_num; + + init_attr->qp_context = qp->qp_context; + init_attr->send_cq = qp->send_cq; + init_attr->recv_cq = qp->recv_cq; + init_attr->srq = qp->srq; + init_attr->qp_type = qp->qp_type; + if (qp->qp_type == IBV_QPT_XRC) + init_attr->xrc_domain = qp->xrc_domain; + init_attr->cap.max_send_wr = resp.max_send_wr; + init_attr->cap.max_recv_wr = resp.max_recv_wr; + init_attr->cap.max_send_sge = resp.max_send_sge; + init_attr->cap.max_recv_sge = resp.max_recv_sge; + init_attr->cap.max_inline_data = resp.max_inline_data; + init_attr->sq_sig_all = resp.sq_sig_all; + + return 0; +} + +int ibv_cmd_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask, + struct ibv_modify_qp *cmd, size_t cmd_size) +{ + IBV_INIT_CMD(cmd, cmd_size, MODIFY_QP); + + cmd->qp_handle = qp->handle; + cmd->attr_mask = attr_mask; + cmd->qkey = attr->qkey; + cmd->rq_psn = attr->rq_psn; + cmd->sq_psn = attr->sq_psn; + cmd->dest_qp_num = attr->dest_qp_num; + cmd->qp_access_flags = attr->qp_access_flags; + cmd->pkey_index = attr->pkey_index; + cmd->alt_pkey_index = attr->alt_pkey_index; + cmd->qp_state = attr->qp_state; + cmd->cur_qp_state = attr->cur_qp_state; + cmd->path_mtu = attr->path_mtu; + cmd->path_mig_state = attr->path_mig_state; + cmd->en_sqd_async_notify = attr->en_sqd_async_notify; + cmd->max_rd_atomic = attr->max_rd_atomic; + cmd->max_dest_rd_atomic = attr->max_dest_rd_atomic; + cmd->min_rnr_timer = attr->min_rnr_timer; + cmd->port_num = attr->port_num; + cmd->timeout = attr->timeout; + cmd->retry_cnt = attr->retry_cnt; + cmd->rnr_retry = attr->rnr_retry; + cmd->alt_port_num = attr->alt_port_num; + cmd->alt_timeout = attr->alt_timeout; + + memcpy(cmd->dest.dgid, attr->ah_attr.grh.dgid.raw, 16); + cmd->dest.flow_label = attr->ah_attr.grh.flow_label; + cmd->dest.dlid = attr->ah_attr.dlid; + cmd->dest.reserved = 0; + cmd->dest.sgid_index = attr->ah_attr.grh.sgid_index; + cmd->dest.hop_limit = attr->ah_attr.grh.hop_limit; + cmd->dest.traffic_class = attr->ah_attr.grh.traffic_class; + cmd->dest.sl = attr->ah_attr.sl; + cmd->dest.src_path_bits = attr->ah_attr.src_path_bits; + cmd->dest.static_rate = attr->ah_attr.static_rate; + cmd->dest.is_global = attr->ah_attr.is_global; + cmd->dest.port_num = attr->ah_attr.port_num; + + memcpy(cmd->alt_dest.dgid, attr->alt_ah_attr.grh.dgid.raw, 16); + cmd->alt_dest.flow_label = attr->alt_ah_attr.grh.flow_label; + cmd->alt_dest.dlid = attr->alt_ah_attr.dlid; + cmd->alt_dest.reserved = 0; + cmd->alt_dest.sgid_index = attr->alt_ah_attr.grh.sgid_index; + cmd->alt_dest.hop_limit = attr->alt_ah_attr.grh.hop_limit; + cmd->alt_dest.traffic_class = attr->alt_ah_attr.grh.traffic_class; + cmd->alt_dest.sl = attr->alt_ah_attr.sl; + cmd->alt_dest.src_path_bits = attr->alt_ah_attr.src_path_bits; + cmd->alt_dest.static_rate = attr->alt_ah_attr.static_rate; + cmd->alt_dest.is_global = attr->alt_ah_attr.is_global; + cmd->alt_dest.port_num = attr->alt_ah_attr.port_num; + + cmd->reserved[0] = cmd->reserved[1] = 0; + + if (write(qp->context->cmd_fd, cmd, cmd_size) != cmd_size) + return errno; + + return 0; +} + +int ibv_cmd_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, + uint32_t *xrc_rcv_qpn) +{ + struct ibv_create_xrc_rcv_qp cmd; + struct ibv_create_xrc_rcv_qp_resp resp; + + if (abi_ver < 6) + return ENOSYS; + + IBV_INIT_CMD_RESP(&cmd, sizeof cmd, CREATE_XRC_RCV_QP, &resp, + sizeof resp); + + cmd.xrc_domain_handle = init_attr->xrc_domain->handle; + cmd.max_send_wr = init_attr->cap.max_send_wr; + cmd.max_recv_wr = init_attr->cap.max_recv_wr; + cmd.max_send_sge = init_attr->cap.max_send_sge; + cmd.max_recv_sge = init_attr->cap.max_recv_sge; + cmd.max_inline_data = init_attr->cap.max_inline_data; + cmd.sq_sig_all = init_attr->sq_sig_all; + cmd.qp_type = init_attr->qp_type; + cmd.reserved[0] = cmd.reserved[1] = 0; + + if (write(init_attr->xrc_domain->context->cmd_fd, &cmd, sizeof cmd) != + sizeof cmd) + return errno; + + *xrc_rcv_qpn = resp.qpn; + + return 0; +} + +int ibv_cmd_modify_xrc_rcv_qp(struct ibv_xrc_domain *d, uint32_t xrc_qp_num, + struct ibv_qp_attr *attr, int attr_mask) +{ + struct ibv_modify_xrc_rcv_qp cmd; + + if (abi_ver < 6) + return ENOSYS; + + IBV_INIT_CMD(&cmd, sizeof cmd, MODIFY_XRC_RCV_QP); + + cmd.xrc_domain_handle = d->handle; + cmd.qp_num = xrc_qp_num; + cmd.attr_mask = attr_mask; + cmd.qkey = attr->qkey; + cmd.rq_psn = attr->rq_psn; + cmd.sq_psn = attr->sq_psn; + cmd.dest_qp_num = attr->dest_qp_num; + cmd.qp_access_flags = attr->qp_access_flags; + cmd.pkey_index = attr->pkey_index; + cmd.alt_pkey_index = attr->alt_pkey_index; + cmd.qp_state = attr->qp_state; + cmd.cur_qp_state = attr->cur_qp_state; + cmd.path_mtu = attr->path_mtu; + cmd.path_mig_state = attr->path_mig_state; + cmd.en_sqd_async_notify = attr->en_sqd_async_notify; + cmd.max_rd_atomic = attr->max_rd_atomic; + cmd.max_dest_rd_atomic = attr->max_dest_rd_atomic; + cmd.min_rnr_timer = attr->min_rnr_timer; + cmd.port_num = attr->port_num; + cmd.timeout = attr->timeout; + cmd.retry_cnt = attr->retry_cnt; + cmd.rnr_retry = attr->rnr_retry; + cmd.alt_port_num = attr->alt_port_num; + cmd.alt_timeout = attr->alt_timeout; + + memcpy(cmd.dest.dgid, attr->ah_attr.grh.dgid.raw, 16); + cmd.dest.flow_label = attr->ah_attr.grh.flow_label; + cmd.dest.dlid = attr->ah_attr.dlid; + cmd.dest.reserved = 0; + cmd.dest.sgid_index = attr->ah_attr.grh.sgid_index; + cmd.dest.hop_limit = attr->ah_attr.grh.hop_limit; + cmd.dest.traffic_class = attr->ah_attr.grh.traffic_class; + cmd.dest.sl = attr->ah_attr.sl; + cmd.dest.src_path_bits = attr->ah_attr.src_path_bits; + cmd.dest.static_rate = attr->ah_attr.static_rate; + cmd.dest.is_global = attr->ah_attr.is_global; + cmd.dest.port_num = attr->ah_attr.port_num; + + memcpy(cmd.alt_dest.dgid, attr->alt_ah_attr.grh.dgid.raw, 16); + cmd.alt_dest.flow_label = attr->alt_ah_attr.grh.flow_label; + cmd.alt_dest.dlid = attr->alt_ah_attr.dlid; + cmd.alt_dest.reserved = 0; + cmd.alt_dest.sgid_index = attr->alt_ah_attr.grh.sgid_index; + cmd.alt_dest.hop_limit = attr->alt_ah_attr.grh.hop_limit; + cmd.alt_dest.traffic_class = attr->alt_ah_attr.grh.traffic_class; + cmd.alt_dest.sl = attr->alt_ah_attr.sl; + cmd.alt_dest.src_path_bits = attr->alt_ah_attr.src_path_bits; + cmd.alt_dest.static_rate = attr->alt_ah_attr.static_rate; + cmd.alt_dest.is_global = attr->alt_ah_attr.is_global; + cmd.alt_dest.port_num = attr->alt_ah_attr.port_num; + + cmd.reserved[0] = cmd.reserved[1] = 0; + + if (write(d->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + return 0; +} + +int ibv_cmd_query_xrc_rcv_qp(struct ibv_xrc_domain *d, uint32_t xrc_qp_num, + struct ibv_qp_attr *attr, int attr_mask, + struct ibv_qp_init_attr *init_attr) +{ + struct ibv_query_xrc_rcv_qp cmd; + struct ibv_query_qp_resp resp; + + if (abi_ver < 6) + return ENOSYS; + + IBV_INIT_CMD_RESP(&cmd, sizeof cmd, QUERY_XRC_RCV_QP, &resp, + sizeof resp); + cmd.xrc_domain_handle = d->handle; + cmd.qp_num = xrc_qp_num; + cmd.attr_mask = attr_mask; + + if (write(d->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); + + attr->qkey = resp.qkey; + attr->rq_psn = resp.rq_psn; + attr->sq_psn = resp.sq_psn; + attr->dest_qp_num = resp.dest_qp_num; + attr->qp_access_flags = resp.qp_access_flags; + attr->pkey_index = resp.pkey_index; + attr->alt_pkey_index = resp.alt_pkey_index; + attr->qp_state = resp.qp_state; + attr->cur_qp_state = resp.cur_qp_state; + attr->path_mtu = resp.path_mtu; + attr->path_mig_state = resp.path_mig_state; + attr->sq_draining = resp.sq_draining; + attr->max_rd_atomic = resp.max_rd_atomic; + attr->max_dest_rd_atomic = resp.max_dest_rd_atomic; + attr->min_rnr_timer = resp.min_rnr_timer; + attr->port_num = resp.port_num; + attr->timeout = resp.timeout; + attr->retry_cnt = resp.retry_cnt; + attr->rnr_retry = resp.rnr_retry; + attr->alt_port_num = resp.alt_port_num; + attr->alt_timeout = resp.alt_timeout; + attr->cap.max_send_wr = resp.max_send_wr; + attr->cap.max_recv_wr = resp.max_recv_wr; + attr->cap.max_send_sge = resp.max_send_sge; + attr->cap.max_recv_sge = resp.max_recv_sge; + attr->cap.max_inline_data = resp.max_inline_data; + + memcpy(attr->ah_attr.grh.dgid.raw, resp.dest.dgid, 16); + attr->ah_attr.grh.flow_label = resp.dest.flow_label; + attr->ah_attr.dlid = resp.dest.dlid; + attr->ah_attr.grh.sgid_index = resp.dest.sgid_index; + attr->ah_attr.grh.hop_limit = resp.dest.hop_limit; + attr->ah_attr.grh.traffic_class = resp.dest.traffic_class; + attr->ah_attr.sl = resp.dest.sl; + attr->ah_attr.src_path_bits = resp.dest.src_path_bits; + attr->ah_attr.static_rate = resp.dest.static_rate; + attr->ah_attr.is_global = resp.dest.is_global; + attr->ah_attr.port_num = resp.dest.port_num; + + memcpy(attr->alt_ah_attr.grh.dgid.raw, resp.alt_dest.dgid, 16); + attr->alt_ah_attr.grh.flow_label = resp.alt_dest.flow_label; + attr->alt_ah_attr.dlid = resp.alt_dest.dlid; + attr->alt_ah_attr.grh.sgid_index = resp.alt_dest.sgid_index; + attr->alt_ah_attr.grh.hop_limit = resp.alt_dest.hop_limit; + attr->alt_ah_attr.grh.traffic_class = resp.alt_dest.traffic_class; + attr->alt_ah_attr.sl = resp.alt_dest.sl; + attr->alt_ah_attr.src_path_bits = resp.alt_dest.src_path_bits; + attr->alt_ah_attr.static_rate = resp.alt_dest.static_rate; + attr->alt_ah_attr.is_global = resp.alt_dest.is_global; + attr->alt_ah_attr.port_num = resp.alt_dest.port_num; + + init_attr->cap.max_send_wr = resp.max_send_wr; + init_attr->cap.max_recv_wr = resp.max_recv_wr; + init_attr->cap.max_send_sge = resp.max_send_sge; + init_attr->cap.max_recv_sge = resp.max_recv_sge; + init_attr->cap.max_inline_data = resp.max_inline_data; + init_attr->sq_sig_all = resp.sq_sig_all; + + return 0; +} + +static int ibv_cmd_destroy_qp_v1(struct ibv_qp *qp) +{ + struct ibv_destroy_qp_v1 cmd; + + IBV_INIT_CMD(&cmd, sizeof cmd, DESTROY_QP); + cmd.qp_handle = qp->handle; + + if (write(qp->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + return 0; +} + +int ibv_cmd_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr, + struct ibv_send_wr **bad_wr) +{ + struct ibv_post_send *cmd; + struct ibv_post_send_resp resp; + struct ibv_send_wr *i; + struct ibv_kern_send_wr *n, *tmp; + struct ibv_sge *s; + unsigned wr_count = 0; + unsigned sge_count = 0; + int cmd_size; + int ret = 0; + + for (i = wr; i; i = i->next) { + wr_count++; + sge_count += i->num_sge; + } + + cmd_size = sizeof *cmd + wr_count * sizeof *n + sge_count * sizeof *s; + cmd = alloca(cmd_size); + + IBV_INIT_CMD_RESP(cmd, cmd_size, POST_SEND, &resp, sizeof resp); + cmd->qp_handle = ibqp->handle; + cmd->wr_count = wr_count; + cmd->sge_count = sge_count; + cmd->wqe_size = sizeof *n; + + n = (struct ibv_kern_send_wr *) ((void *) cmd + sizeof *cmd); + s = (struct ibv_sge *) (n + wr_count); + + tmp = n; + for (i = wr; i; i = i->next) { + tmp->wr_id = i->wr_id; + tmp->num_sge = i->num_sge; + tmp->opcode = i->opcode; + tmp->send_flags = i->send_flags; + tmp->imm_data = i->imm_data; + if (ibqp->qp_type == IBV_QPT_UD) { + tmp->wr.ud.ah = i->wr.ud.ah->handle; + tmp->wr.ud.remote_qpn = i->wr.ud.remote_qpn; + tmp->wr.ud.remote_qkey = i->wr.ud.remote_qkey; + } else { + switch (i->opcode) { + case IBV_WR_RDMA_WRITE: + case IBV_WR_RDMA_WRITE_WITH_IMM: + case IBV_WR_RDMA_READ: + tmp->wr.rdma.remote_addr = + i->wr.rdma.remote_addr; + tmp->wr.rdma.rkey = i->wr.rdma.rkey; + break; + case IBV_WR_ATOMIC_CMP_AND_SWP: + case IBV_WR_ATOMIC_FETCH_AND_ADD: + tmp->wr.atomic.remote_addr = + i->wr.atomic.remote_addr; + tmp->wr.atomic.compare_add = + i->wr.atomic.compare_add; + tmp->wr.atomic.swap = i->wr.atomic.swap; + tmp->wr.atomic.rkey = i->wr.atomic.rkey; + break; + default: + break; + } + } + + if (tmp->num_sge) { + memcpy(s, i->sg_list, tmp->num_sge * sizeof *s); + s += tmp->num_sge; + } + + tmp++; + } + + resp.bad_wr = 0; + if (write(ibqp->context->cmd_fd, cmd, cmd_size) != cmd_size) + ret = errno; + + VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); + + wr_count = resp.bad_wr; + if (wr_count) { + i = wr; + while (--wr_count) + i = i->next; + *bad_wr = i; + } else if (ret) + *bad_wr = wr; + + return ret; +} + +int ibv_cmd_post_recv(struct ibv_qp *ibqp, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr) +{ + struct ibv_post_recv *cmd; + struct ibv_post_recv_resp resp; + struct ibv_recv_wr *i; + struct ibv_kern_recv_wr *n, *tmp; + struct ibv_sge *s; + unsigned wr_count = 0; + unsigned sge_count = 0; + int cmd_size; + int ret = 0; + + for (i = wr; i; i = i->next) { + wr_count++; + sge_count += i->num_sge; + } + + cmd_size = sizeof *cmd + wr_count * sizeof *n + sge_count * sizeof *s; + cmd = alloca(cmd_size); + + IBV_INIT_CMD_RESP(cmd, cmd_size, POST_RECV, &resp, sizeof resp); + cmd->qp_handle = ibqp->handle; + cmd->wr_count = wr_count; + cmd->sge_count = sge_count; + cmd->wqe_size = sizeof *n; + + n = (struct ibv_kern_recv_wr *) ((void *) cmd + sizeof *cmd); + s = (struct ibv_sge *) (n + wr_count); + + tmp = n; + for (i = wr; i; i = i->next) { + tmp->wr_id = i->wr_id; + tmp->num_sge = i->num_sge; + + if (tmp->num_sge) { + memcpy(s, i->sg_list, tmp->num_sge * sizeof *s); + s += tmp->num_sge; + } + + tmp++; + } + + resp.bad_wr = 0; + if (write(ibqp->context->cmd_fd, cmd, cmd_size) != cmd_size) + ret = errno; + + VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); + + wr_count = resp.bad_wr; + if (wr_count) { + i = wr; + while (--wr_count) + i = i->next; + *bad_wr = i; + } else if (ret) + *bad_wr = wr; + + return ret; +} + +int ibv_cmd_post_srq_recv(struct ibv_srq *srq, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr) +{ + struct ibv_post_srq_recv *cmd; + struct ibv_post_srq_recv_resp resp; + struct ibv_recv_wr *i; + struct ibv_kern_recv_wr *n, *tmp; + struct ibv_sge *s; + unsigned wr_count = 0; + unsigned sge_count = 0; + int cmd_size; + int ret = 0; + + for (i = wr; i; i = i->next) { + wr_count++; + sge_count += i->num_sge; + } + + cmd_size = sizeof *cmd + wr_count * sizeof *n + sge_count * sizeof *s; + cmd = alloca(cmd_size); + + IBV_INIT_CMD_RESP(cmd, cmd_size, POST_SRQ_RECV, &resp, sizeof resp); + cmd->srq_handle = srq->handle; + cmd->wr_count = wr_count; + cmd->sge_count = sge_count; + cmd->wqe_size = sizeof *n; + + n = (struct ibv_kern_recv_wr *) ((void *) cmd + sizeof *cmd); + s = (struct ibv_sge *) (n + wr_count); + + tmp = n; + for (i = wr; i; i = i->next) { + tmp->wr_id = i->wr_id; + tmp->num_sge = i->num_sge; + + if (tmp->num_sge) { + memcpy(s, i->sg_list, tmp->num_sge * sizeof *s); + s += tmp->num_sge; + } + + tmp++; + } + + resp.bad_wr = 0; + if (write(srq->context->cmd_fd, cmd, cmd_size) != cmd_size) + ret = errno; + + VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); + + wr_count = resp.bad_wr; + if (wr_count) { + i = wr; + while (--wr_count) + i = i->next; + *bad_wr = i; + } else if (ret) + *bad_wr = wr; + + return ret; +} + +int ibv_cmd_create_ah(struct ibv_pd *pd, struct ibv_ah *ah, + struct ibv_ah_attr *attr) +{ + struct ibv_create_ah cmd; + struct ibv_create_ah_resp resp; + + IBV_INIT_CMD_RESP(&cmd, sizeof cmd, CREATE_AH, &resp, sizeof resp); + cmd.user_handle = (uintptr_t) ah; + cmd.pd_handle = pd->handle; + cmd.attr.dlid = attr->dlid; + cmd.attr.sl = attr->sl; + cmd.attr.src_path_bits = attr->src_path_bits; + cmd.attr.static_rate = attr->static_rate; + cmd.attr.is_global = attr->is_global; + cmd.attr.port_num = attr->port_num; + cmd.attr.grh.flow_label = attr->grh.flow_label; + cmd.attr.grh.sgid_index = attr->grh.sgid_index; + cmd.attr.grh.hop_limit = attr->grh.hop_limit; + cmd.attr.grh.traffic_class = attr->grh.traffic_class; + memcpy(cmd.attr.grh.dgid, attr->grh.dgid.raw, 16); + + if (write(pd->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); + + ah->handle = resp.handle; + ah->context = pd->context; + + return 0; +} + +int ibv_cmd_destroy_ah(struct ibv_ah *ah) +{ + struct ibv_destroy_ah cmd; + + IBV_INIT_CMD(&cmd, sizeof cmd, DESTROY_AH); + cmd.ah_handle = ah->handle; + + if (write(ah->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + return 0; +} + +int ibv_cmd_destroy_qp(struct ibv_qp *qp) +{ + struct ibv_destroy_qp cmd; + struct ibv_destroy_qp_resp resp; + + if (abi_ver == 1) + return ibv_cmd_destroy_qp_v1(qp); + + IBV_INIT_CMD_RESP(&cmd, sizeof cmd, DESTROY_QP, &resp, sizeof resp); + cmd.qp_handle = qp->handle; + cmd.reserved = 0; + + if (write(qp->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); + + pthread_mutex_lock(&qp->mutex); + while (qp->events_completed != resp.events_reported) + pthread_cond_wait(&qp->cond, &qp->mutex); + pthread_mutex_unlock(&qp->mutex); + + return 0; +} + +int ibv_cmd_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid) +{ + struct ibv_attach_mcast cmd; + + IBV_INIT_CMD(&cmd, sizeof cmd, ATTACH_MCAST); + memcpy(cmd.gid, gid->raw, sizeof cmd.gid); + cmd.qp_handle = qp->handle; + cmd.mlid = lid; + cmd.reserved = 0; + + if (write(qp->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + return 0; +} + +int ibv_cmd_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid) +{ + struct ibv_detach_mcast cmd; + + IBV_INIT_CMD(&cmd, sizeof cmd, DETACH_MCAST); + memcpy(cmd.gid, gid->raw, sizeof cmd.gid); + cmd.qp_handle = qp->handle; + cmd.mlid = lid; + cmd.reserved = 0; + + if (write(qp->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + return 0; +} + +int ibv_cmd_open_xrc_domain(struct ibv_context *context, int fd, int oflag, + struct ibv_xrc_domain *d, + struct ibv_open_xrc_domain_resp *resp, + size_t resp_size) +{ + struct ibv_open_xrc_domain cmd; + + if (abi_ver < 6) + return ENOSYS; + + IBV_INIT_CMD_RESP(&cmd, sizeof cmd, OPEN_XRC_DOMAIN, resp, resp_size); + cmd.fd = fd; + cmd.oflags = oflag; + + if (write(context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + d->handle = resp->xrcd_handle; + + return 0; +} + +int ibv_cmd_close_xrc_domain(struct ibv_xrc_domain *d) +{ + struct ibv_close_xrc_domain cmd; + + if (abi_ver < 6) + return ENOSYS; + + IBV_INIT_CMD(&cmd, sizeof cmd, CLOSE_XRC_DOMAIN); + cmd.xrcd_handle = d->handle; + + if (write(d->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + return 0; +} + +int ibv_cmd_reg_xrc_rcv_qp(struct ibv_xrc_domain *d, uint32_t xrc_qp_num) +{ + struct ibv_reg_xrc_rcv_qp cmd; + + if (abi_ver < 6) + return ENOSYS; + + IBV_INIT_CMD(&cmd, sizeof cmd, REG_XRC_RCV_QP); + cmd.xrc_domain_handle = d->handle; + cmd.qp_num = xrc_qp_num; + + if (write(d->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + return 0; +} + +int ibv_cmd_unreg_xrc_rcv_qp(struct ibv_xrc_domain *d, uint32_t xrc_qp_num) +{ + struct ibv_unreg_xrc_rcv_qp cmd; + + if (abi_ver < 6) + return ENOSYS; + + IBV_INIT_CMD(&cmd, sizeof cmd, UNREG_XRC_RCV_QP); + cmd.xrc_domain_handle = d->handle; + cmd.qp_num = xrc_qp_num; + + if (write(d->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + return 0; +} + diff --git a/contrib/ofed/libibverbs/src/compat-1_0.c b/contrib/ofed/libibverbs/src/compat-1_0.c new file mode 100644 index 000000000000..3f5ff35ef881 --- /dev/null +++ b/contrib/ofed/libibverbs/src/compat-1_0.c @@ -0,0 +1,898 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include "ibverbs.h" + +struct ibv_pd_1_0 { + struct ibv_context_1_0 *context; + uint32_t handle; + + struct ibv_pd *real_pd; +}; + +struct ibv_mr_1_0 { + struct ibv_context_1_0 *context; + struct ibv_pd_1_0 *pd; + uint32_t handle; + uint32_t lkey; + uint32_t rkey; + + struct ibv_mr *real_mr; +}; + +struct ibv_srq_1_0 { + struct ibv_context_1_0 *context; + void *srq_context; + struct ibv_pd_1_0 *pd; + uint32_t handle; + + pthread_mutex_t mutex; + pthread_cond_t cond; + uint32_t events_completed; + + struct ibv_srq *real_srq; +}; + +struct ibv_qp_init_attr_1_0 { + void *qp_context; + struct ibv_cq_1_0 *send_cq; + struct ibv_cq_1_0 *recv_cq; + struct ibv_srq_1_0 *srq; + struct ibv_qp_cap cap; + enum ibv_qp_type qp_type; + int sq_sig_all; +}; + +struct ibv_send_wr_1_0 { + struct ibv_send_wr_1_0 *next; + uint64_t wr_id; + struct ibv_sge *sg_list; + int num_sge; + enum ibv_wr_opcode opcode; + int send_flags; + uint32_t imm_data; /* in network byte order */ + union { + struct { + uint64_t remote_addr; + uint32_t rkey; + } rdma; + struct { + uint64_t remote_addr; + uint64_t compare_add; + uint64_t swap; + uint32_t rkey; + } atomic; + struct { + struct ibv_ah_1_0 *ah; + uint32_t remote_qpn; + uint32_t remote_qkey; + } ud; + } wr; +}; + +struct ibv_recv_wr_1_0 { + struct ibv_recv_wr_1_0 *next; + uint64_t wr_id; + struct ibv_sge *sg_list; + int num_sge; +}; + +struct ibv_qp_1_0 { + struct ibv_context_1_0 *context; + void *qp_context; + struct ibv_pd_1_0 *pd; + struct ibv_cq_1_0 *send_cq; + struct ibv_cq_1_0 *recv_cq; + struct ibv_srq_1_0 *srq; + uint32_t handle; + uint32_t qp_num; + enum ibv_qp_state state; + enum ibv_qp_type qp_type; + + pthread_mutex_t mutex; + pthread_cond_t cond; + uint32_t events_completed; + + struct ibv_qp *real_qp; +}; + +struct ibv_cq_1_0 { + struct ibv_context_1_0 *context; + void *cq_context; + uint32_t handle; + int cqe; + + pthread_mutex_t mutex; + pthread_cond_t cond; + uint32_t comp_events_completed; + uint32_t async_events_completed; + + struct ibv_cq *real_cq; +}; + +struct ibv_ah_1_0 { + struct ibv_context_1_0 *context; + struct ibv_pd_1_0 *pd; + uint32_t handle; + + struct ibv_ah *real_ah; +}; + +struct ibv_device_1_0 { + void *obsolete_sysfs_dev; + void *obsolete_sysfs_ibdev; + struct ibv_device *real_device; /* was obsolete driver member */ + struct ibv_device_ops ops; +}; + +struct ibv_context_ops_1_0 { + int (*query_device)(struct ibv_context *context, + struct ibv_device_attr *device_attr); + int (*query_port)(struct ibv_context *context, uint8_t port_num, + struct ibv_port_attr *port_attr); + struct ibv_pd * (*alloc_pd)(struct ibv_context *context); + int (*dealloc_pd)(struct ibv_pd *pd); + struct ibv_mr * (*reg_mr)(struct ibv_pd *pd, void *addr, size_t length, + int access); + int (*dereg_mr)(struct ibv_mr *mr); + struct ibv_cq * (*create_cq)(struct ibv_context *context, int cqe, + struct ibv_comp_channel *channel, + int comp_vector); + int (*poll_cq)(struct ibv_cq_1_0 *cq, int num_entries, + struct ibv_wc *wc); + int (*req_notify_cq)(struct ibv_cq_1_0 *cq, + int solicited_only); + void (*cq_event)(struct ibv_cq *cq); + int (*resize_cq)(struct ibv_cq *cq, int cqe); + int (*destroy_cq)(struct ibv_cq *cq); + struct ibv_srq * (*create_srq)(struct ibv_pd *pd, + struct ibv_srq_init_attr *srq_init_attr); + int (*modify_srq)(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + int srq_attr_mask); + int (*query_srq)(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr); + int (*destroy_srq)(struct ibv_srq *srq); + int (*post_srq_recv)(struct ibv_srq_1_0 *srq, + struct ibv_recv_wr_1_0 *recv_wr, + struct ibv_recv_wr_1_0 **bad_recv_wr); + struct ibv_qp * (*create_qp)(struct ibv_pd *pd, struct ibv_qp_init_attr *attr); + int (*query_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask, + struct ibv_qp_init_attr *init_attr); + int (*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask); + int (*destroy_qp)(struct ibv_qp *qp); + int (*post_send)(struct ibv_qp_1_0 *qp, + struct ibv_send_wr_1_0 *wr, + struct ibv_send_wr_1_0 **bad_wr); + int (*post_recv)(struct ibv_qp_1_0 *qp, + struct ibv_recv_wr_1_0 *wr, + struct ibv_recv_wr_1_0 **bad_wr); + struct ibv_ah * (*create_ah)(struct ibv_pd *pd, struct ibv_ah_attr *attr); + int (*destroy_ah)(struct ibv_ah *ah); + int (*attach_mcast)(struct ibv_qp *qp, union ibv_gid *gid, + uint16_t lid); + int (*detach_mcast)(struct ibv_qp *qp, union ibv_gid *gid, + uint16_t lid); +}; + +struct ibv_context_1_0 { + struct ibv_device_1_0 *device; + struct ibv_context_ops_1_0 ops; + int cmd_fd; + int async_fd; + int num_comp_vectors; + + struct ibv_context *real_context; /* was abi_compat member */ +}; + +struct ibv_device_1_0 **__ibv_get_device_list_1_0(int *num) +{ + struct ibv_device **real_list; + struct ibv_device_1_0 **l; + int i, n; + + real_list = ibv_get_device_list(&n); + if (!real_list) + return NULL; + + l = calloc(n + 2, sizeof (struct ibv_device_1_0 *)); + if (!l) + return NULL; + + l[0] = (void *) real_list; + + for (i = 0; i < n; ++i) { + l[i + 1] = calloc(1, sizeof (struct ibv_device_1_0)); + if (!l[i + 1]) + goto fail; + l[i + 1]->real_device = real_list[i]; + } + + if (num) + *num = n; + + return l + 1; + +fail: + for (i = 1; i <= n; ++i) + if (l[i]) + free(l[i]); + ibv_free_device_list(real_list); + return NULL; +} +symver(__ibv_get_device_list_1_0, ibv_get_device_list, IBVERBS_1.0); + +void __ibv_free_device_list_1_0(struct ibv_device_1_0 **list) +{ + struct ibv_device_1_0 **l = list; + + while (*l) { + free(*l); + ++l; + } + + ibv_free_device_list((void *) list[-1]); + free(list - 1); +} +symver(__ibv_free_device_list_1_0, ibv_free_device_list, IBVERBS_1.0); + +const char *__ibv_get_device_name_1_0(struct ibv_device_1_0 *device) +{ + return ibv_get_device_name(device->real_device); +} +symver(__ibv_get_device_name_1_0, ibv_get_device_name, IBVERBS_1.0); + +uint64_t __ibv_get_device_guid_1_0(struct ibv_device_1_0 *device) +{ + return ibv_get_device_guid(device->real_device); +} +symver(__ibv_get_device_guid_1_0, ibv_get_device_guid, IBVERBS_1.0); + +static int poll_cq_wrapper_1_0(struct ibv_cq_1_0 *cq, int num_entries, + struct ibv_wc *wc) +{ + return cq->context->real_context->ops.poll_cq(cq->real_cq, num_entries, wc); +} + +static int req_notify_cq_wrapper_1_0(struct ibv_cq_1_0 *cq, int sol_only) +{ + return cq->context->real_context->ops.req_notify_cq(cq->real_cq, sol_only); +} + +static int post_srq_recv_wrapper_1_0(struct ibv_srq_1_0 *srq, struct ibv_recv_wr_1_0 *wr, + struct ibv_recv_wr_1_0 **bad_wr) +{ + struct ibv_recv_wr_1_0 *w; + struct ibv_recv_wr *real_wr, *head_wr = NULL, *tail_wr = NULL, *real_bad_wr; + int ret; + + for (w = wr; w; w = w->next) { + real_wr = alloca(sizeof *real_wr); + real_wr->wr_id = w->wr_id; + real_wr->sg_list = w->sg_list; + real_wr->num_sge = w->num_sge; + real_wr->next = NULL; + if (tail_wr) + tail_wr->next = real_wr; + else + head_wr = real_wr; + + tail_wr = real_wr; + } + + ret = srq->context->real_context->ops.post_srq_recv(srq->real_srq, head_wr, + &real_bad_wr); + + if (ret) { + for (real_wr = head_wr, w = wr; + real_wr; + real_wr = real_wr->next, w = w->next) + if (real_wr == real_bad_wr) { + *bad_wr = w; + break; + } + } + + return ret; +} + +static int post_send_wrapper_1_0(struct ibv_qp_1_0 *qp, struct ibv_send_wr_1_0 *wr, + struct ibv_send_wr_1_0 **bad_wr) +{ + struct ibv_send_wr_1_0 *w; + struct ibv_send_wr *real_wr, *head_wr = NULL, *tail_wr = NULL, *real_bad_wr; + int is_ud = qp->qp_type == IBV_QPT_UD; + int ret; + + for (w = wr; w; w = w->next) { + real_wr = alloca(sizeof *real_wr); + real_wr->wr_id = w->wr_id; + real_wr->next = NULL; + + memcpy(&real_wr->sg_list, &w->sg_list, + sizeof *w - offsetof(struct ibv_send_wr, sg_list)); + + if (is_ud) + real_wr->wr.ud.ah = w->wr.ud.ah->real_ah; + + if (tail_wr) + tail_wr->next = real_wr; + else + head_wr = real_wr; + + tail_wr = real_wr; + } + + ret = qp->context->real_context->ops.post_send(qp->real_qp, head_wr, + &real_bad_wr); + + if (ret) { + for (real_wr = head_wr, w = wr; + real_wr; + real_wr = real_wr->next, w = w->next) + if (real_wr == real_bad_wr) { + *bad_wr = w; + break; + } + } + + return ret; +} + +static int post_recv_wrapper_1_0(struct ibv_qp_1_0 *qp, struct ibv_recv_wr_1_0 *wr, + struct ibv_recv_wr_1_0 **bad_wr) +{ + struct ibv_recv_wr_1_0 *w; + struct ibv_recv_wr *real_wr, *head_wr = NULL, *tail_wr = NULL, *real_bad_wr; + int ret; + + for (w = wr; w; w = w->next) { + real_wr = alloca(sizeof *real_wr); + real_wr->wr_id = w->wr_id; + real_wr->sg_list = w->sg_list; + real_wr->num_sge = w->num_sge; + real_wr->next = NULL; + if (tail_wr) + tail_wr->next = real_wr; + else + head_wr = real_wr; + + tail_wr = real_wr; + } + + ret = qp->context->real_context->ops.post_recv(qp->real_qp, head_wr, + &real_bad_wr); + + if (ret) { + for (real_wr = head_wr, w = wr; + real_wr; + real_wr = real_wr->next, w = w->next) + if (real_wr == real_bad_wr) { + *bad_wr = w; + break; + } + } + + return ret; +} + +struct ibv_context_1_0 *__ibv_open_device_1_0(struct ibv_device_1_0 *device) +{ + struct ibv_context *real_ctx; + struct ibv_context_1_0 *ctx; + + ctx = malloc(sizeof *ctx); + if (!ctx) + return NULL; + + real_ctx = ibv_open_device(device->real_device); + if (!real_ctx) { + free(ctx); + return NULL; + } + + ctx->device = device; + ctx->real_context = real_ctx; + + ctx->ops.poll_cq = poll_cq_wrapper_1_0; + ctx->ops.req_notify_cq = req_notify_cq_wrapper_1_0; + ctx->ops.post_send = post_send_wrapper_1_0; + ctx->ops.post_recv = post_recv_wrapper_1_0; + ctx->ops.post_srq_recv = post_srq_recv_wrapper_1_0; + + return ctx; +} +symver(__ibv_open_device_1_0, ibv_open_device, IBVERBS_1.0); + +int __ibv_close_device_1_0(struct ibv_context_1_0 *context) +{ + int ret; + + ret = ibv_close_device(context->real_context); + if (ret) + return ret; + + free(context); + return 0; +} +symver(__ibv_close_device_1_0, ibv_close_device, IBVERBS_1.0); + +int __ibv_get_async_event_1_0(struct ibv_context_1_0 *context, + struct ibv_async_event *event) +{ + int ret; + + ret = ibv_get_async_event(context->real_context, event); + if (ret) + return ret; + + switch (event->event_type) { + case IBV_EVENT_CQ_ERR: + event->element.cq = event->element.cq->cq_context; + break; + + case IBV_EVENT_QP_FATAL: + case IBV_EVENT_QP_REQ_ERR: + case IBV_EVENT_QP_ACCESS_ERR: + case IBV_EVENT_COMM_EST: + case IBV_EVENT_SQ_DRAINED: + case IBV_EVENT_PATH_MIG: + case IBV_EVENT_PATH_MIG_ERR: + case IBV_EVENT_QP_LAST_WQE_REACHED: + event->element.qp = event->element.qp->qp_context; + break; + + case IBV_EVENT_SRQ_ERR: + case IBV_EVENT_SRQ_LIMIT_REACHED: + event->element.srq = event->element.srq->srq_context; + break; + + default: + break; + } + + return ret; +} +symver(__ibv_get_async_event_1_0, ibv_get_async_event, IBVERBS_1.0); + +void __ibv_ack_async_event_1_0(struct ibv_async_event *event) +{ + struct ibv_async_event real_event = *event; + + switch (event->event_type) { + case IBV_EVENT_CQ_ERR: + real_event.element.cq = + ((struct ibv_cq_1_0 *) event->element.cq)->real_cq; + break; + + case IBV_EVENT_QP_FATAL: + case IBV_EVENT_QP_REQ_ERR: + case IBV_EVENT_QP_ACCESS_ERR: + case IBV_EVENT_COMM_EST: + case IBV_EVENT_SQ_DRAINED: + case IBV_EVENT_PATH_MIG: + case IBV_EVENT_PATH_MIG_ERR: + case IBV_EVENT_QP_LAST_WQE_REACHED: + real_event.element.qp = + ((struct ibv_qp_1_0 *) event->element.qp)->real_qp; + break; + + case IBV_EVENT_SRQ_ERR: + case IBV_EVENT_SRQ_LIMIT_REACHED: + real_event.element.srq = + ((struct ibv_srq_1_0 *) event->element.srq)->real_srq; + break; + + default: + break; + } + + ibv_ack_async_event(&real_event); +} +symver(__ibv_ack_async_event_1_0, ibv_ack_async_event, IBVERBS_1.0); + +int __ibv_query_device_1_0(struct ibv_context_1_0 *context, + struct ibv_device_attr *device_attr) +{ + return ibv_query_device(context->real_context, device_attr); +} +symver(__ibv_query_device_1_0, ibv_query_device, IBVERBS_1.0); + +int __ibv_query_port_1_0(struct ibv_context_1_0 *context, uint8_t port_num, + struct ibv_port_attr *port_attr) +{ + return ibv_query_port(context->real_context, port_num, port_attr); +} +symver(__ibv_query_port_1_0, ibv_query_port, IBVERBS_1.0); + +int __ibv_query_gid_1_0(struct ibv_context_1_0 *context, uint8_t port_num, + int index, union ibv_gid *gid) +{ + return ibv_query_gid(context->real_context, port_num, index, gid); +} +symver(__ibv_query_gid_1_0, ibv_query_gid, IBVERBS_1.0); + +int __ibv_query_pkey_1_0(struct ibv_context_1_0 *context, uint8_t port_num, + int index, uint16_t *pkey) +{ + return ibv_query_pkey(context->real_context, port_num, index, pkey); +} +symver(__ibv_query_pkey_1_0, ibv_query_pkey, IBVERBS_1.0); + +struct ibv_pd_1_0 *__ibv_alloc_pd_1_0(struct ibv_context_1_0 *context) +{ + struct ibv_pd *real_pd; + struct ibv_pd_1_0 *pd; + + pd = malloc(sizeof *pd); + if (!pd) + return NULL; + + real_pd = ibv_alloc_pd(context->real_context); + if (!real_pd) { + free(pd); + return NULL; + } + + pd->context = context; + pd->real_pd = real_pd; + + return pd; +} +symver(__ibv_alloc_pd_1_0, ibv_alloc_pd, IBVERBS_1.0); + +int __ibv_dealloc_pd_1_0(struct ibv_pd_1_0 *pd) +{ + int ret; + + ret = ibv_dealloc_pd(pd->real_pd); + if (ret) + return ret; + + free(pd); + return 0; +} +symver(__ibv_dealloc_pd_1_0, ibv_dealloc_pd, IBVERBS_1.0); + +struct ibv_mr_1_0 *__ibv_reg_mr_1_0(struct ibv_pd_1_0 *pd, void *addr, + size_t length, int access) +{ + struct ibv_mr *real_mr; + struct ibv_mr_1_0 *mr; + + mr = malloc(sizeof *mr); + if (!mr) + return NULL; + + real_mr = ibv_reg_mr(pd->real_pd, addr, length, access); + if (!real_mr) { + free(mr); + return NULL; + } + + mr->context = pd->context; + mr->pd = pd; + mr->lkey = real_mr->lkey; + mr->rkey = real_mr->rkey; + mr->real_mr = real_mr; + + return mr; +} +symver(__ibv_reg_mr_1_0, ibv_reg_mr, IBVERBS_1.0); + +int __ibv_dereg_mr_1_0(struct ibv_mr_1_0 *mr) +{ + int ret; + + ret = ibv_dereg_mr(mr->real_mr); + if (ret) + return ret; + + free(mr); + return 0; +} +symver(__ibv_dereg_mr_1_0, ibv_dereg_mr, IBVERBS_1.0); + +struct ibv_cq_1_0 *__ibv_create_cq_1_0(struct ibv_context_1_0 *context, int cqe, + void *cq_context, + struct ibv_comp_channel *channel, + int comp_vector) +{ + struct ibv_cq *real_cq; + struct ibv_cq_1_0 *cq; + + cq = malloc(sizeof *cq); + if (!cq) + return NULL; + + real_cq = ibv_create_cq(context->real_context, cqe, cq_context, + channel, comp_vector); + if (!real_cq) { + free(cq); + return NULL; + } + + cq->context = context; + cq->cq_context = cq_context; + cq->cqe = cqe; + cq->real_cq = real_cq; + + real_cq->cq_context = cq; + + return cq; +} +symver(__ibv_create_cq_1_0, ibv_create_cq, IBVERBS_1.0); + +int __ibv_resize_cq_1_0(struct ibv_cq_1_0 *cq, int cqe) +{ + return ibv_resize_cq(cq->real_cq, cqe); +} +symver(__ibv_resize_cq_1_0, ibv_resize_cq, IBVERBS_1.0); + +int __ibv_destroy_cq_1_0(struct ibv_cq_1_0 *cq) +{ + int ret; + + ret = ibv_destroy_cq(cq->real_cq); + if (ret) + return ret; + + free(cq); + return 0; +} +symver(__ibv_destroy_cq_1_0, ibv_destroy_cq, IBVERBS_1.0); + +int __ibv_get_cq_event_1_0(struct ibv_comp_channel *channel, + struct ibv_cq_1_0 **cq, void **cq_context) +{ + struct ibv_cq *real_cq; + void *cq_ptr; + int ret; + + ret = ibv_get_cq_event(channel, &real_cq, &cq_ptr); + if (ret) + return ret; + + *cq = cq_ptr; + *cq_context = (*cq)->cq_context; + + return 0; +} +symver(__ibv_get_cq_event_1_0, ibv_get_cq_event, IBVERBS_1.0); + +void __ibv_ack_cq_events_1_0(struct ibv_cq_1_0 *cq, unsigned int nevents) +{ + ibv_ack_cq_events(cq->real_cq, nevents); +} +symver(__ibv_ack_cq_events_1_0, ibv_ack_cq_events, IBVERBS_1.0); + +struct ibv_srq_1_0 *__ibv_create_srq_1_0(struct ibv_pd_1_0 *pd, + struct ibv_srq_init_attr *srq_init_attr) +{ + struct ibv_srq *real_srq; + struct ibv_srq_1_0 *srq; + + srq = malloc(sizeof *srq); + if (!srq) + return NULL; + + real_srq = ibv_create_srq(pd->real_pd, srq_init_attr); + if (!real_srq) { + free(srq); + return NULL; + } + + srq->context = pd->context; + srq->srq_context = srq_init_attr->srq_context; + srq->pd = pd; + srq->real_srq = real_srq; + + real_srq->srq_context = srq; + + return srq; +} +symver(__ibv_create_srq_1_0, ibv_create_srq, IBVERBS_1.0); + +int __ibv_modify_srq_1_0(struct ibv_srq_1_0 *srq, + struct ibv_srq_attr *srq_attr, + int srq_attr_mask) +{ + return ibv_modify_srq(srq->real_srq, srq_attr, srq_attr_mask); +} +symver(__ibv_modify_srq_1_0, ibv_modify_srq, IBVERBS_1.0); + +int __ibv_query_srq_1_0(struct ibv_srq_1_0 *srq, struct ibv_srq_attr *srq_attr) +{ + return ibv_query_srq(srq->real_srq, srq_attr); +} +symver(__ibv_query_srq_1_0, ibv_query_srq, IBVERBS_1.0); + +int __ibv_destroy_srq_1_0(struct ibv_srq_1_0 *srq) +{ + int ret; + + ret = ibv_destroy_srq(srq->real_srq); + if (ret) + return ret; + + free(srq); + return 0; +} +symver(__ibv_destroy_srq_1_0, ibv_destroy_srq, IBVERBS_1.0); + +struct ibv_qp_1_0 *__ibv_create_qp_1_0(struct ibv_pd_1_0 *pd, + struct ibv_qp_init_attr_1_0 *qp_init_attr) +{ + struct ibv_qp *real_qp; + struct ibv_qp_1_0 *qp; + struct ibv_qp_init_attr real_init_attr; + + qp = malloc(sizeof *qp); + if (!qp) + return NULL; + + real_init_attr.qp_context = qp_init_attr->qp_context; + real_init_attr.send_cq = qp_init_attr->send_cq->real_cq; + real_init_attr.recv_cq = qp_init_attr->recv_cq->real_cq; + real_init_attr.srq = qp_init_attr->srq ? + qp_init_attr->srq->real_srq : NULL; + real_init_attr.cap = qp_init_attr->cap; + real_init_attr.qp_type = qp_init_attr->qp_type; + real_init_attr.sq_sig_all = qp_init_attr->sq_sig_all; + + real_qp = ibv_create_qp(pd->real_pd, &real_init_attr); + if (!real_qp) { + free(qp); + return NULL; + } + + qp->context = pd->context; + qp->qp_context = qp_init_attr->qp_context; + qp->pd = pd; + qp->send_cq = qp_init_attr->send_cq; + qp->recv_cq = qp_init_attr->recv_cq; + qp->srq = qp_init_attr->srq; + qp->qp_type = qp_init_attr->qp_type; + qp->qp_num = real_qp->qp_num; + qp->real_qp = real_qp; + + qp_init_attr->cap = real_init_attr.cap; + + real_qp->qp_context = qp; + + return qp; +} +symver(__ibv_create_qp_1_0, ibv_create_qp, IBVERBS_1.0); + +int __ibv_query_qp_1_0(struct ibv_qp_1_0 *qp, struct ibv_qp_attr *attr, + int attr_mask, + struct ibv_qp_init_attr_1_0 *init_attr) +{ + struct ibv_qp_init_attr real_init_attr; + int ret; + + ret = ibv_query_qp(qp->real_qp, attr, attr_mask, &real_init_attr); + if (ret) + return ret; + + init_attr->qp_context = qp->qp_context; + init_attr->send_cq = real_init_attr.send_cq->cq_context; + init_attr->recv_cq = real_init_attr.recv_cq->cq_context; + init_attr->srq = real_init_attr.srq->srq_context; + init_attr->qp_type = real_init_attr.qp_type; + init_attr->cap = real_init_attr.cap; + init_attr->sq_sig_all = real_init_attr.sq_sig_all; + + return 0; +} +symver(__ibv_query_qp_1_0, ibv_query_qp, IBVERBS_1.0); + +int __ibv_modify_qp_1_0(struct ibv_qp_1_0 *qp, struct ibv_qp_attr *attr, + int attr_mask) +{ + return ibv_modify_qp(qp->real_qp, attr, attr_mask); +} +symver(__ibv_modify_qp_1_0, ibv_modify_qp, IBVERBS_1.0); + +int __ibv_destroy_qp_1_0(struct ibv_qp_1_0 *qp) +{ + int ret; + + ret = ibv_destroy_qp(qp->real_qp); + if (ret) + return ret; + + free(qp); + return 0; +} +symver(__ibv_destroy_qp_1_0, ibv_destroy_qp, IBVERBS_1.0); + +struct ibv_ah_1_0 *__ibv_create_ah_1_0(struct ibv_pd_1_0 *pd, + struct ibv_ah_attr *attr) +{ + struct ibv_ah *real_ah; + struct ibv_ah_1_0 *ah; + + ah = malloc(sizeof *ah); + if (!ah) + return NULL; + + real_ah = ibv_create_ah(pd->real_pd, attr); + if (!real_ah) { + free(ah); + return NULL; + } + + ah->context = pd->context; + ah->pd = pd; + ah->real_ah = real_ah; + + return ah; +} +symver(__ibv_create_ah_1_0, ibv_create_ah, IBVERBS_1.0); + +int __ibv_destroy_ah_1_0(struct ibv_ah_1_0 *ah) +{ + int ret; + + ret = ibv_destroy_ah(ah->real_ah); + if (ret) + return ret; + + free(ah); + return 0; +} +symver(__ibv_destroy_ah_1_0, ibv_destroy_ah, IBVERBS_1.0); + +int __ibv_attach_mcast_1_0(struct ibv_qp_1_0 *qp, union ibv_gid *gid, uint16_t lid) +{ + return ibv_attach_mcast(qp->real_qp, gid, lid); +} +symver(__ibv_attach_mcast_1_0, ibv_attach_mcast, IBVERBS_1.0); + +int __ibv_detach_mcast_1_0(struct ibv_qp_1_0 *qp, union ibv_gid *gid, uint16_t lid) +{ + return ibv_detach_mcast(qp->real_qp, gid, lid); +} +symver(__ibv_detach_mcast_1_0, ibv_detach_mcast, IBVERBS_1.0); diff --git a/contrib/ofed/libibverbs/src/device.c b/contrib/ofed/libibverbs/src/device.c new file mode 100644 index 000000000000..c2bca68443b7 --- /dev/null +++ b/contrib/ofed/libibverbs/src/device.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ibverbs.h" + +static pthread_mutex_t device_list_lock = PTHREAD_MUTEX_INITIALIZER; +static int num_devices; +static struct ibv_device **device_list; + +struct ibv_device **__ibv_get_device_list(int *num) +{ + struct ibv_device **l = 0; + int i; + + if (num) + *num = 0; + + pthread_mutex_lock(&device_list_lock); + + if (!num_devices) + num_devices = ibverbs_init(&device_list); + + if (num_devices < 0) { + errno = -num_devices; + goto out; + } + + l = calloc(num_devices + 1, sizeof (struct ibv_device *)); + if (!l) { + errno = ENOMEM; + goto out; + } + + for (i = 0; i < num_devices; ++i) + l[i] = device_list[i]; + if (num) + *num = num_devices; + +out: + pthread_mutex_unlock(&device_list_lock); + return l; +} +default_symver(__ibv_get_device_list, ibv_get_device_list); + +void __ibv_free_device_list(struct ibv_device **list) +{ + free(list); +} +default_symver(__ibv_free_device_list, ibv_free_device_list); + +const char *__ibv_get_device_name(struct ibv_device *device) +{ + return device->name; +} +default_symver(__ibv_get_device_name, ibv_get_device_name); + +uint64_t __ibv_get_device_guid(struct ibv_device *device) +{ + char attr[24]; + uint64_t guid = 0; + uint16_t parts[4]; + int i; + + if (ibv_read_sysfs_file(device->ibdev_path, "node_guid", + attr, sizeof attr) < 0) + return 0; + + if (sscanf(attr, "%hx:%hx:%hx:%hx", + parts, parts + 1, parts + 2, parts + 3) != 4) + return 0; + + for (i = 0; i < 4; ++i) + guid = (guid << 16) | parts[i]; + + return htonll(guid); +} +default_symver(__ibv_get_device_guid, ibv_get_device_guid); + +struct ibv_context *__ibv_open_device(struct ibv_device *device) +{ + char *devpath; + int cmd_fd; + struct ibv_context *context; + + if (asprintf(&devpath, "/dev/%s", device->dev_name) < 0) + return NULL; + + /* + * We'll only be doing writes, but we need O_RDWR in case the + * provider needs to mmap() the file. + */ + cmd_fd = open(devpath, O_RDWR); + free(devpath); + + if (cmd_fd < 0) + return NULL; + + context = device->ops.alloc_context(device, cmd_fd); + if (!context) + goto err; + + context->device = device; + context->cmd_fd = cmd_fd; + pthread_mutex_init(&context->mutex, NULL); + + return context; + +err: + close(cmd_fd); + + return NULL; +} +default_symver(__ibv_open_device, ibv_open_device); + +int __ibv_close_device(struct ibv_context *context) +{ + int async_fd = context->async_fd; + int cmd_fd = context->cmd_fd; + int cq_fd = -1; + + if (abi_ver <= 2) { + struct ibv_abi_compat_v2 *t = context->abi_compat; + cq_fd = t->channel.fd; + free(context->abi_compat); + } + + context->device->ops.free_context(context); + + close(async_fd); + close(cmd_fd); + if (abi_ver <= 2) + close(cq_fd); + + return 0; +} +default_symver(__ibv_close_device, ibv_close_device); + +int __ibv_get_async_event(struct ibv_context *context, + struct ibv_async_event *event) +{ + struct ibv_kern_async_event ev; + + if (read(context->async_fd, &ev, sizeof ev) != sizeof ev) + return -1; + + event->event_type = ev.event_type; + + if (event->event_type & IBV_XRC_QP_EVENT_FLAG) { + event->element.xrc_qp_num = ev.element; + } else + switch (event->event_type) { + case IBV_EVENT_CQ_ERR: + event->element.cq = (void *) (uintptr_t) ev.element; + break; + + case IBV_EVENT_QP_FATAL: + case IBV_EVENT_QP_REQ_ERR: + case IBV_EVENT_QP_ACCESS_ERR: + case IBV_EVENT_COMM_EST: + case IBV_EVENT_SQ_DRAINED: + case IBV_EVENT_PATH_MIG: + case IBV_EVENT_PATH_MIG_ERR: + case IBV_EVENT_QP_LAST_WQE_REACHED: + event->element.qp = (void *) (uintptr_t) ev.element; + break; + + case IBV_EVENT_SRQ_ERR: + case IBV_EVENT_SRQ_LIMIT_REACHED: + event->element.srq = (void *) (uintptr_t) ev.element; + break; + default: + event->element.port_num = ev.element; + break; + } + + if (context->ops.async_event) + context->ops.async_event(event); + + return 0; +} +default_symver(__ibv_get_async_event, ibv_get_async_event); + +void __ibv_ack_async_event(struct ibv_async_event *event) +{ + switch (event->event_type) { + case IBV_EVENT_CQ_ERR: + { + struct ibv_cq *cq = event->element.cq; + + pthread_mutex_lock(&cq->mutex); + ++cq->async_events_completed; + pthread_cond_signal(&cq->cond); + pthread_mutex_unlock(&cq->mutex); + + return; + } + + case IBV_EVENT_QP_FATAL: + case IBV_EVENT_QP_REQ_ERR: + case IBV_EVENT_QP_ACCESS_ERR: + case IBV_EVENT_COMM_EST: + case IBV_EVENT_SQ_DRAINED: + case IBV_EVENT_PATH_MIG: + case IBV_EVENT_PATH_MIG_ERR: + case IBV_EVENT_QP_LAST_WQE_REACHED: + { + struct ibv_qp *qp = event->element.qp; + + pthread_mutex_lock(&qp->mutex); + ++qp->events_completed; + pthread_cond_signal(&qp->cond); + pthread_mutex_unlock(&qp->mutex); + + return; + } + + case IBV_EVENT_SRQ_ERR: + case IBV_EVENT_SRQ_LIMIT_REACHED: + { + struct ibv_srq *srq = event->element.srq; + + pthread_mutex_lock(&srq->mutex); + ++srq->events_completed; + pthread_cond_signal(&srq->cond); + pthread_mutex_unlock(&srq->mutex); + + return; + } + + default: + return; + } +} +default_symver(__ibv_ack_async_event, ibv_ack_async_event); diff --git a/contrib/ofed/libibverbs/src/enum_strs.c b/contrib/ofed/libibverbs/src/enum_strs.c new file mode 100644 index 000000000000..c57feaa66bde --- /dev/null +++ b/contrib/ofed/libibverbs/src/enum_strs.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2008 Lawrence Livermore National Laboratory + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +const char *ibv_node_type_str(enum ibv_node_type node_type) +{ + static const char *const node_type_str[] = { + [IBV_NODE_CA] = "InfiniBand channel adapter", + [IBV_NODE_SWITCH] = "InfiniBand switch", + [IBV_NODE_ROUTER] = "InfiniBand router", + [IBV_NODE_RNIC] = "iWARP NIC" + }; + + if (node_type < IBV_NODE_CA || node_type > IBV_NODE_RNIC) + return "unknown"; + + return node_type_str[node_type]; +} + +const char *ibv_port_state_str(enum ibv_port_state port_state) +{ + static const char *const port_state_str[] = { + [IBV_PORT_NOP] = "no state change (NOP)", + [IBV_PORT_DOWN] = "down", + [IBV_PORT_INIT] = "init", + [IBV_PORT_ARMED] = "armed", + [IBV_PORT_ACTIVE] = "active", + [IBV_PORT_ACTIVE_DEFER] = "active defer" + }; + + if (port_state < IBV_PORT_NOP || port_state > IBV_PORT_ACTIVE_DEFER) + return "unknown"; + + return port_state_str[port_state]; +} + +const char *ibv_event_type_str(enum ibv_event_type event) +{ + static const char *const event_type_str[] = { + [IBV_EVENT_CQ_ERR] = "CQ error", + [IBV_EVENT_QP_FATAL] = "local work queue catastrophic error", + [IBV_EVENT_QP_REQ_ERR] = "invalid request local work queue error", + [IBV_EVENT_QP_ACCESS_ERR] = "local access violation work queue error", + [IBV_EVENT_COMM_EST] = "communication established", + [IBV_EVENT_SQ_DRAINED] = "send queue drained", + [IBV_EVENT_PATH_MIG] = "path migrated", + [IBV_EVENT_PATH_MIG_ERR] = "path migration request error", + [IBV_EVENT_DEVICE_FATAL] = "local catastrophic error", + [IBV_EVENT_PORT_ACTIVE] = "port active", + [IBV_EVENT_PORT_ERR] = "port error", + [IBV_EVENT_LID_CHANGE] = "LID change", + [IBV_EVENT_PKEY_CHANGE] = "P_Key change", + [IBV_EVENT_SM_CHANGE] = "SM change", + [IBV_EVENT_SRQ_ERR] = "SRQ catastrophic error", + [IBV_EVENT_SRQ_LIMIT_REACHED] = "SRQ limit reached", + [IBV_EVENT_QP_LAST_WQE_REACHED] = "last WQE reached", + [IBV_EVENT_CLIENT_REREGISTER] = "client reregistration", + }; + + if (event < IBV_EVENT_CQ_ERR || event > IBV_EVENT_CLIENT_REREGISTER) + return "unknown"; + + return event_type_str[event]; +} + +const char *ibv_wc_status_str(enum ibv_wc_status status) +{ + static const char *const wc_status_str[] = { + [IBV_WC_SUCCESS] = "success", + [IBV_WC_LOC_LEN_ERR] = "local length error", + [IBV_WC_LOC_QP_OP_ERR] = "local QP operation error", + [IBV_WC_LOC_EEC_OP_ERR] = "local EE context operation error", + [IBV_WC_LOC_PROT_ERR] = "local protection error", + [IBV_WC_WR_FLUSH_ERR] = "Work Request Flushed Error", + [IBV_WC_MW_BIND_ERR] = "memory management operation error", + [IBV_WC_BAD_RESP_ERR] = "bad response error", + [IBV_WC_LOC_ACCESS_ERR] = "local access error", + [IBV_WC_REM_INV_REQ_ERR] = "remote invalid request error", + [IBV_WC_REM_ACCESS_ERR] = "remote access error", + [IBV_WC_REM_OP_ERR] = "remote operation error", + [IBV_WC_RETRY_EXC_ERR] = "transport retry counter exceeded", + [IBV_WC_RNR_RETRY_EXC_ERR] = "RNR retry counter exceeded", + [IBV_WC_LOC_RDD_VIOL_ERR] = "local RDD violation error", + [IBV_WC_REM_INV_RD_REQ_ERR] = "remote invalid RD request", + [IBV_WC_REM_ABORT_ERR] = "aborted error", + [IBV_WC_INV_EECN_ERR] = "invalid EE context number", + [IBV_WC_INV_EEC_STATE_ERR] = "invalid EE context state", + [IBV_WC_FATAL_ERR] = "fatal error", + [IBV_WC_RESP_TIMEOUT_ERR] = "response timeout error", + [IBV_WC_GENERAL_ERR] = "general error" + }; + + if (status < IBV_WC_SUCCESS || status > IBV_WC_GENERAL_ERR) + return "unknown"; + + return wc_status_str[status]; +} diff --git a/contrib/ofed/libibverbs/src/ibverbs.h b/contrib/ofed/libibverbs/src/ibverbs.h new file mode 100644 index 000000000000..6a6e3c848cca --- /dev/null +++ b/contrib/ofed/libibverbs/src/ibverbs.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IB_VERBS_H +#define IB_VERBS_H + +#include + +#include + +#ifdef HAVE_VALGRIND_MEMCHECK_H + +# include + +# ifndef VALGRIND_MAKE_MEM_DEFINED +# warning "Valgrind support requested, but VALGRIND_MAKE_MEM_DEFINED not available" +# endif + +#endif /* HAVE_VALGRIND_MEMCHECK_H */ + +#ifndef VALGRIND_MAKE_MEM_DEFINED +# define VALGRIND_MAKE_MEM_DEFINED(addr, len) +#endif + +#define HIDDEN __attribute__((visibility ("hidden"))) + +#define INIT __attribute__((constructor)) +#define FINI __attribute__((destructor)) + +#define DEFAULT_ABI "IBVERBS_1.1" + +#ifdef HAVE_SYMVER_SUPPORT +# define symver(name, api, ver) \ + asm(".symver " #name "," #api "@" #ver) +# define default_symver(name, api) \ + asm(".symver " #name "," #api "@@" DEFAULT_ABI) +#else +# define symver(name, api, ver) +# define default_symver(name, api) \ + extern __typeof(name) api __attribute__((alias(#name))) +#endif /* HAVE_SYMVER_SUPPORT */ + +#define PFX "libibverbs: " + +struct ibv_abi_compat_v2 { + struct ibv_comp_channel channel; + pthread_mutex_t in_use; +}; + +extern HIDDEN int abi_ver; + +HIDDEN int ibverbs_init(struct ibv_device ***list); + +#define IBV_INIT_CMD(cmd, size, opcode) \ + do { \ + if (abi_ver > 2) \ + (cmd)->command = IB_USER_VERBS_CMD_##opcode; \ + else \ + (cmd)->command = IB_USER_VERBS_CMD_##opcode##_V2; \ + (cmd)->in_words = (size) / 4; \ + (cmd)->out_words = 0; \ + } while (0) + +#define IBV_INIT_CMD_RESP(cmd, size, opcode, out, outsize) \ + do { \ + if (abi_ver > 2) \ + (cmd)->command = IB_USER_VERBS_CMD_##opcode; \ + else \ + (cmd)->command = IB_USER_VERBS_CMD_##opcode##_V2; \ + (cmd)->in_words = (size) / 4; \ + (cmd)->out_words = (outsize) / 4; \ + (cmd)->response = (uintptr_t) (out); \ + } while (0) + +#endif /* IB_VERBS_H */ diff --git a/contrib/ofed/libibverbs/src/init.c b/contrib/ofed/libibverbs/src/init.c new file mode 100644 index 000000000000..d48ad189b9ae --- /dev/null +++ b/contrib/ofed/libibverbs/src/init.c @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ibverbs.h" + +HIDDEN int abi_ver; + +struct ibv_sysfs_dev { + char sysfs_name[IBV_SYSFS_NAME_MAX]; + char ibdev_name[IBV_SYSFS_NAME_MAX]; + char sysfs_path[IBV_SYSFS_PATH_MAX]; + char ibdev_path[IBV_SYSFS_PATH_MAX]; + struct ibv_sysfs_dev *next; + int abi_ver; + int have_driver; +}; + +struct ibv_driver_name { + char *name; + struct ibv_driver_name *next; +}; + +struct ibv_driver { + const char *name; + ibv_driver_init_func init_func; + struct ibv_driver *next; +}; + +static struct ibv_sysfs_dev *sysfs_dev_list; +static struct ibv_driver_name *driver_name_list; +static struct ibv_driver *head_driver, *tail_driver; + +static int find_sysfs_devs(void) +{ +#ifdef __linux__ + char class_path[IBV_SYSFS_PATH_MAX]; + DIR *class_dir; + struct dirent *dent; + struct ibv_sysfs_dev *sysfs_dev = NULL; + char value[8]; + int ret = 0; + + snprintf(class_path, sizeof class_path, "%s/class/infiniband_verbs", + ibv_get_sysfs_path()); + + class_dir = opendir(class_path); + if (!class_dir) + return ENOSYS; + + while ((dent = readdir(class_dir))) { + struct stat buf; + + if (dent->d_name[0] == '.') + continue; + + if (!sysfs_dev) + sysfs_dev = malloc(sizeof *sysfs_dev); + if (!sysfs_dev) { + ret = ENOMEM; + goto out; + } + + snprintf(sysfs_dev->sysfs_path, sizeof sysfs_dev->sysfs_path, + "%s/%s", class_path, dent->d_name); + + if (stat(sysfs_dev->sysfs_path, &buf)) { + fprintf(stderr, PFX "Warning: couldn't stat '%s'.\n", + sysfs_dev->sysfs_path); + continue; + } + + if (!S_ISDIR(buf.st_mode)) + continue; + + snprintf(sysfs_dev->sysfs_name, sizeof sysfs_dev->sysfs_name, + "%s", dent->d_name); + + if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "ibdev", + sysfs_dev->ibdev_name, + sizeof sysfs_dev->ibdev_name) < 0) { + fprintf(stderr, PFX "Warning: no ibdev class attr for '%s'.\n", + dent->d_name); + continue; + } + + snprintf(sysfs_dev->ibdev_path, sizeof sysfs_dev->ibdev_path, + "%s/class/infiniband/%s", ibv_get_sysfs_path(), + sysfs_dev->ibdev_name); + + sysfs_dev->next = sysfs_dev_list; + sysfs_dev->have_driver = 0; + if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "abi_version", + value, sizeof value) > 0) + sysfs_dev->abi_ver = strtol(value, NULL, 10); + else + sysfs_dev->abi_ver = 0; + + sysfs_dev_list = sysfs_dev; + sysfs_dev = NULL; + } + + out: + if (sysfs_dev) + free(sysfs_dev); + + closedir(class_dir); + return ret; +#else + char class_path[IBV_SYSFS_PATH_MAX]; + struct ibv_sysfs_dev *sysfs_dev = NULL; + char value[8]; + int ret = 0; + int i; + + snprintf(class_path, sizeof class_path, "%s/class/infiniband_verbs", + ibv_get_sysfs_path()); + + for (i = 0; i < 256; i++) { + if (!sysfs_dev) + sysfs_dev = malloc(sizeof *sysfs_dev); + if (!sysfs_dev) { + ret = ENOMEM; + goto out; + } + + snprintf(sysfs_dev->sysfs_path, sizeof sysfs_dev->sysfs_path, + "%s/uverbs%d", class_path, i); + + snprintf(sysfs_dev->sysfs_name, sizeof sysfs_dev->sysfs_name, + "uverbs%d", i); + + if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "ibdev", + sysfs_dev->ibdev_name, + sizeof sysfs_dev->ibdev_name) < 0) + continue; + + snprintf(sysfs_dev->ibdev_path, sizeof sysfs_dev->ibdev_path, + "%s/class/infiniband/%s", ibv_get_sysfs_path(), + sysfs_dev->ibdev_name); + + sysfs_dev->next = sysfs_dev_list; + sysfs_dev->have_driver = 0; + if (ibv_read_sysfs_file(sysfs_dev->sysfs_path, "abi_version", + value, sizeof value) > 0) + sysfs_dev->abi_ver = strtol(value, NULL, 10); + else + sysfs_dev->abi_ver = 0; + + sysfs_dev_list = sysfs_dev; + sysfs_dev = NULL; + } + + out: + if (sysfs_dev) + free(sysfs_dev); + + return ret; + +#endif +} + +void ibv_register_driver(const char *name, ibv_driver_init_func init_func) +{ + struct ibv_driver *driver; + + driver = malloc(sizeof *driver); + if (!driver) { + fprintf(stderr, PFX "Warning: couldn't allocate driver for %s\n", name); + return; + } + + driver->name = name; + driver->init_func = init_func; + driver->next = NULL; + + if (tail_driver) + tail_driver->next = driver; + else + head_driver = driver; + tail_driver = driver; +} + +static void load_driver(const char *name) +{ + char *so_name; + void *dlhandle; + +#define __IBV_QUOTE(x) #x +#define IBV_QUOTE(x) __IBV_QUOTE(x) + + if (asprintf(&so_name, + name[0] == '/' ? + "%s-" IBV_QUOTE(IBV_DEVICE_LIBRARY_EXTENSION) ".so" : + "lib%s-" IBV_QUOTE(IBV_DEVICE_LIBRARY_EXTENSION) ".so", + name) < 0) { + fprintf(stderr, PFX "Warning: couldn't load driver '%s'.\n", + name); + return; + } + + dlhandle = dlopen(so_name, RTLD_NOW); + if (!dlhandle) { + fprintf(stderr, PFX "Warning: couldn't load driver '%s': %s\n", + name, dlerror()); + goto out; + } + +out: + free(so_name); +} + +static void load_drivers(void) +{ + struct ibv_driver_name *name, *next_name; + const char *env; + char *list, *env_name; + + /* + * Only use drivers passed in through the calling user's + * environment if we're not running setuid. + */ + if (getuid() == geteuid()) { + if ((env = getenv("RDMAV_DRIVERS"))) { + list = strdupa(env); + while ((env_name = strsep(&list, ":;"))) + load_driver(env_name); + } else if ((env = getenv("IBV_DRIVERS"))) { + list = strdupa(env); + while ((env_name = strsep(&list, ":;"))) + load_driver(env_name); + } + } + + for (name = driver_name_list, next_name = name ? name->next : NULL; + name; + name = next_name, next_name = name ? name->next : NULL) { + load_driver(name->name); + free(name->name); + free(name); + } +} + +static void read_config_file(const char *path) +{ + FILE *conf; + char *line = NULL; + char *config; + char *field; + size_t buflen = 0; + ssize_t len; + + conf = fopen(path, "r"); + if (!conf) { + fprintf(stderr, PFX "Warning: couldn't read config file %s.\n", + path); + return; + } + + while ((len = getline(&line, &buflen, conf)) != -1) { + config = line + strspn(line, "\t "); + if (config[0] == '\n' || config[0] == '#') + continue; + + field = strsep(&config, "\n\t "); + + if (strcmp(field, "driver") == 0) { + struct ibv_driver_name *driver_name; + + config += strspn(config, "\t "); + field = strsep(&config, "\n\t "); + + driver_name = malloc(sizeof *driver_name); + if (!driver_name) { + fprintf(stderr, PFX "Warning: couldn't allocate " + "driver name '%s'.\n", field); + continue; + } + + driver_name->name = strdup(field); + if (!driver_name->name) { + fprintf(stderr, PFX "Warning: couldn't allocate " + "driver name '%s'.\n", field); + free(driver_name); + continue; + } + + driver_name->next = driver_name_list; + driver_name_list = driver_name; + } else + fprintf(stderr, PFX "Warning: ignoring bad config directive " + "'%s' in file '%s'.\n", field, path); + } + + if (line) + free(line); + fclose(conf); +} + +static void read_config(void) +{ + DIR *conf_dir; + struct dirent *dent; + char *path; + + conf_dir = opendir(IBV_CONFIG_DIR); + if (!conf_dir) { + fprintf(stderr, PFX "Warning: couldn't open config directory '%s'.\n", + IBV_CONFIG_DIR); + return; + } + + while ((dent = readdir(conf_dir))) { + struct stat buf; + + if (asprintf(&path, "%s/%s", IBV_CONFIG_DIR, dent->d_name) < 0) { + fprintf(stderr, PFX "Warning: couldn't read config file %s/%s.\n", + IBV_CONFIG_DIR, dent->d_name); + return; + } + + if (stat(path, &buf)) { + fprintf(stderr, PFX "Warning: couldn't stat config file '%s'.\n", + path); + goto next; + } + + if (!S_ISREG(buf.st_mode)) + goto next; + + read_config_file(path); +next: + free(path); + } + + closedir(conf_dir); +} + +static struct ibv_device *try_driver(struct ibv_driver *driver, + struct ibv_sysfs_dev *sysfs_dev) +{ + struct ibv_device *dev; + char value[8]; + + dev = driver->init_func(sysfs_dev->sysfs_path, sysfs_dev->abi_ver); + if (!dev) + return NULL; + + if (ibv_read_sysfs_file(sysfs_dev->ibdev_path, "node_type", value, sizeof value) < 0) { + fprintf(stderr, PFX "Warning: no node_type attr under %s.\n", + sysfs_dev->ibdev_path); + dev->node_type = IBV_NODE_UNKNOWN; + } else { + dev->node_type = strtol(value, NULL, 10); + if (dev->node_type < IBV_NODE_CA || dev->node_type > IBV_NODE_RNIC) + dev->node_type = IBV_NODE_UNKNOWN; + } +out: + + switch (dev->node_type) { + case IBV_NODE_CA: + case IBV_NODE_SWITCH: + case IBV_NODE_ROUTER: + dev->transport_type = IBV_TRANSPORT_IB; + break; + case IBV_NODE_RNIC: + dev->transport_type = IBV_TRANSPORT_IWARP; + break; + default: + dev->transport_type = IBV_TRANSPORT_UNKNOWN; + break; + } + + strcpy(dev->dev_name, sysfs_dev->sysfs_name); + strcpy(dev->dev_path, sysfs_dev->sysfs_path); + strcpy(dev->name, sysfs_dev->ibdev_name); + strcpy(dev->ibdev_path, sysfs_dev->ibdev_path); + + return dev; +} + +static struct ibv_device *try_drivers(struct ibv_sysfs_dev *sysfs_dev) +{ + struct ibv_driver *driver; + struct ibv_device *dev; + + for (driver = head_driver; driver; driver = driver->next) { + dev = try_driver(driver, sysfs_dev); + if (dev) + return dev; + } + + return NULL; +} + +static int check_abi_version(const char *path) +{ + char value[8]; + + if (ibv_read_sysfs_file(path, "class/infiniband_verbs/abi_version", + value, sizeof value) < 0) { + return ENOSYS; + } + + abi_ver = strtol(value, NULL, 10); + + if (abi_ver < IB_USER_VERBS_MIN_ABI_VERSION || + abi_ver > IB_USER_VERBS_MAX_ABI_VERSION) { + fprintf(stderr, PFX "Fatal: kernel ABI version %d " + "doesn't match library version %d.\n", + abi_ver, IB_USER_VERBS_MAX_ABI_VERSION); + return ENOSYS; + } + + return 0; +} + +static void check_memlock_limit(void) +{ + struct rlimit rlim; + + if (!geteuid()) + return; + + if (getrlimit(RLIMIT_MEMLOCK, &rlim)) { + fprintf(stderr, PFX "Warning: getrlimit(RLIMIT_MEMLOCK) failed."); + return; + } + + if (rlim.rlim_cur <= 32768) + fprintf(stderr, PFX "Warning: RLIMIT_MEMLOCK is %lu bytes.\n" + " This will severely limit memory registrations.\n", + rlim.rlim_cur); +} + +static void add_device(struct ibv_device *dev, + struct ibv_device ***dev_list, + int *num_devices, + int *list_size) +{ + struct ibv_device **new_list; + + if (*list_size <= *num_devices) { + *list_size = *list_size ? *list_size * 2 : 1; + new_list = realloc(*dev_list, *list_size * sizeof (struct ibv_device *)); + if (!new_list) + return; + *dev_list = new_list; + } + + (*dev_list)[(*num_devices)++] = dev; +} + +HIDDEN int ibverbs_init(struct ibv_device ***list) +{ + const char *sysfs_path; + struct ibv_sysfs_dev *sysfs_dev, *next_dev; + struct ibv_device *device; + int num_devices = 0; + int list_size = 0; + int statically_linked = 0; + int no_driver = 0; + int ret; + + *list = NULL; + + if (getenv("RDMAV_FORK_SAFE") || getenv("IBV_FORK_SAFE")) + if (ibv_fork_init()) + fprintf(stderr, PFX "Warning: fork()-safety requested " + "but init failed\n"); + + sysfs_path = ibv_get_sysfs_path(); + if (!sysfs_path) + return -ENOSYS; + + ret = check_abi_version(sysfs_path); + if (ret) + return -ret; + + check_memlock_limit(); + + read_config(); + + ret = find_sysfs_devs(); + if (ret) + return -ret; + + for (sysfs_dev = sysfs_dev_list; sysfs_dev; sysfs_dev = sysfs_dev->next) { + device = try_drivers(sysfs_dev); + if (device) { + add_device(device, list, &num_devices, &list_size); + sysfs_dev->have_driver = 1; + } else + no_driver = 1; + } + + if (!no_driver) + goto out; + + /* + * Check if we can dlopen() ourselves. If this fails, + * libibverbs is probably statically linked into the + * executable, and we should just give up, since trying to + * dlopen() a driver module will fail spectacularly (loading a + * driver .so will bring in dynamic copies of libibverbs and + * libdl to go along with the static copies the executable + * has, which quickly leads to a crash. + */ + { + void *hand = dlopen(NULL, RTLD_NOW); + if (!hand) { + fprintf(stderr, PFX "Warning: dlopen(NULL) failed, " + "assuming static linking.\n"); + statically_linked = 1; + goto out; + } + dlclose(hand); + } + + load_drivers(); + + for (sysfs_dev = sysfs_dev_list; sysfs_dev; sysfs_dev = sysfs_dev->next) { + if (sysfs_dev->have_driver) + continue; + + device = try_drivers(sysfs_dev); + if (device) { + add_device(device, list, &num_devices, &list_size); + sysfs_dev->have_driver = 1; + } + } + +out: + for (sysfs_dev = sysfs_dev_list, + next_dev = sysfs_dev ? sysfs_dev->next : NULL; + sysfs_dev; + sysfs_dev = next_dev, next_dev = sysfs_dev ? sysfs_dev->next : NULL) { + if (!sysfs_dev->have_driver) { + fprintf(stderr, PFX "Warning: no userspace device-specific " + "driver found for %s\n", sysfs_dev->sysfs_path); + if (statically_linked) + fprintf(stderr, " When linking libibverbs statically, " + "driver must be statically linked too.\n"); + } + free(sysfs_dev); + } + + return num_devices; +} diff --git a/contrib/ofed/libibverbs/src/kern_abi.h b/contrib/ofed/libibverbs/src/kern_abi.h new file mode 100644 index 000000000000..e055e7502ccd --- /dev/null +++ b/contrib/ofed/libibverbs/src/kern_abi.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef KERN_ABI_H +#define KERN_ABI_H + +#include + +/* + * Increment this value if any changes that break userspace ABI + * compatibility are made. + */ +#define IB_USER_VERBS_ABI_VERSION 1 + +enum { + IB_USER_VERBS_CMD_GET_CONTEXT, + IB_USER_VERBS_CMD_GET_EVENT_FDS, + IB_USER_VERBS_CMD_ALLOC_PD, + IB_USER_VERBS_CMD_DEALLOC_PD, + IB_USER_VERBS_CMD_REG_MR, + IB_USER_VERBS_CMD_DEREG_MR +}; + +/* + * Make sure that all structs defined in this file remain laid out so + * that they pack the same way on 32-bit and 64-bit architectures (to + * avoid incompatibility between 32-bit userspace and 64-bit kernels). + * In particular do not use pointer types -- pass pointers in __u64 + * instead. + */ + +struct ibv_kern_async_event { + __u32 event_type; + __u32 element; +}; + +struct ibv_comp_event { + __u32 cq_handle; +}; + +/* + * All commands from userspace should start with a __u32 command field + * followed by __u16 in_words and out_words fields (which give the + * length of the command block and response buffer if any in 32-bit + * words). The kernel driver will read these fields first and read + * the rest of the command struct based on these value. + */ + +struct ibv_get_context { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; +}; + +struct ibv_get_context_resp { + __u32 num_cq_events; +}; + +struct ibv_get_event_fds { + __u32 command; + __u16 in_words; + __u16 out_words; + __u64 response; +}; + +struct ibv_get_event_fds_resp { + __u32 async_fd; + __u32 cq_fd[1]; +}; + +#endif /* KERN_ABI_H */ diff --git a/contrib/ofed/libibverbs/src/libibverbs.map b/contrib/ofed/libibverbs/src/libibverbs.map new file mode 100644 index 000000000000..127dc7674788 --- /dev/null +++ b/contrib/ofed/libibverbs/src/libibverbs.map @@ -0,0 +1,116 @@ +IBVERBS_1.0 { + global: + ibv_get_device_list; + ibv_free_device_list; + ibv_get_device_name; + ibv_get_device_guid; + ibv_open_device; + ibv_close_device; + ibv_get_async_event; + ibv_ack_async_event; + ibv_query_device; + ibv_query_port; + ibv_query_gid; + ibv_query_pkey; + ibv_alloc_pd; + ibv_dealloc_pd; + ibv_reg_mr; + ibv_dereg_mr; + ibv_create_comp_channel; + ibv_destroy_comp_channel; + ibv_create_cq; + ibv_resize_cq; + ibv_destroy_cq; + ibv_get_cq_event; + ibv_ack_cq_events; + ibv_create_srq; + ibv_modify_srq; + ibv_query_srq; + ibv_destroy_srq; + ibv_create_qp; + ibv_query_qp; + ibv_modify_qp; + ibv_destroy_qp; + ibv_create_ah; + ibv_destroy_ah; + ibv_attach_mcast; + ibv_detach_mcast; + ibv_cmd_get_context; + ibv_cmd_query_device; + ibv_cmd_query_port; + ibv_cmd_query_gid; + ibv_cmd_query_pkey; + ibv_cmd_alloc_pd; + ibv_cmd_dealloc_pd; + ibv_cmd_reg_mr; + ibv_cmd_dereg_mr; + ibv_cmd_create_cq; + ibv_cmd_poll_cq; + ibv_cmd_req_notify_cq; + ibv_cmd_resize_cq; + ibv_cmd_destroy_cq; + ibv_cmd_create_srq; + ibv_cmd_modify_srq; + ibv_cmd_query_srq; + ibv_cmd_destroy_srq; + ibv_cmd_create_qp; + ibv_cmd_query_qp; + ibv_cmd_modify_qp; + ibv_cmd_destroy_qp; + ibv_cmd_post_send; + ibv_cmd_post_recv; + ibv_cmd_post_srq_recv; + ibv_cmd_create_ah; + ibv_cmd_destroy_ah; + ibv_cmd_attach_mcast; + ibv_cmd_detach_mcast; + ibv_copy_qp_attr_from_kern; + ibv_copy_path_rec_from_kern; + ibv_copy_path_rec_to_kern; + ibv_rate_to_mult; + mult_to_ibv_rate; + ibv_get_sysfs_path; + ibv_read_sysfs_file; + + local: *; +}; + +IBVERBS_1.1 { + global: + ibv_get_device_list; + ibv_free_device_list; + ibv_get_device_name; + ibv_get_device_guid; + ibv_open_device; + ibv_close_device; + ibv_resolve_eth_gid; + + ibv_init_ah_from_wc; + ibv_create_ah_from_wc; + ibv_copy_ah_attr_from_kern; + ibv_fork_init; + ibv_dontfork_range; + ibv_dofork_range; + ibv_register_driver; + ibv_create_xrc_srq; + ibv_cmd_create_xrc_srq; + ibv_open_xrc_domain; + ibv_cmd_open_xrc_domain; + ibv_close_xrc_domain; + ibv_cmd_close_xrc_domain; + ibv_create_xrc_rcv_qp; + ibv_cmd_create_xrc_rcv_qp; + ibv_modify_xrc_rcv_qp; + ibv_cmd_modify_xrc_rcv_qp; + ibv_query_xrc_rcv_qp; + ibv_cmd_query_xrc_rcv_qp; + ibv_reg_xrc_rcv_qp; + ibv_cmd_reg_xrc_rcv_qp; + ibv_unreg_xrc_rcv_qp; + ibv_cmd_unreg_xrc_rcv_qp; + + ibv_node_type_str; + ibv_port_state_str; + ibv_event_type_str; + ibv_wc_status_str; +} IBVERBS_1.0; diff --git a/contrib/ofed/libibverbs/src/marshall.c b/contrib/ofed/libibverbs/src/marshall.c new file mode 100644 index 000000000000..577b4b1ec2f9 --- /dev/null +++ b/contrib/ofed/libibverbs/src/marshall.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#include + +void ibv_copy_ah_attr_from_kern(struct ibv_ah_attr *dst, + struct ibv_kern_ah_attr *src) +{ + memcpy(dst->grh.dgid.raw, src->grh.dgid, sizeof dst->grh.dgid); + dst->grh.flow_label = src->grh.flow_label; + dst->grh.sgid_index = src->grh.sgid_index; + dst->grh.hop_limit = src->grh.hop_limit; + dst->grh.traffic_class = src->grh.traffic_class; + + dst->dlid = src->dlid; + dst->sl = src->sl; + dst->src_path_bits = src->src_path_bits; + dst->static_rate = src->static_rate; + dst->is_global = src->is_global; + dst->port_num = src->port_num; +} + +void ibv_copy_qp_attr_from_kern(struct ibv_qp_attr *dst, + struct ibv_kern_qp_attr *src) +{ + dst->cur_qp_state = src->cur_qp_state; + dst->path_mtu = src->path_mtu; + dst->path_mig_state = src->path_mig_state; + dst->qkey = src->qkey; + dst->rq_psn = src->rq_psn; + dst->sq_psn = src->sq_psn; + dst->dest_qp_num = src->dest_qp_num; + dst->qp_access_flags = src->qp_access_flags; + + dst->cap.max_send_wr = src->max_send_wr; + dst->cap.max_recv_wr = src->max_recv_wr; + dst->cap.max_send_sge = src->max_send_sge; + dst->cap.max_recv_sge = src->max_recv_sge; + dst->cap.max_inline_data = src->max_inline_data; + + ibv_copy_ah_attr_from_kern(&dst->ah_attr, &src->ah_attr); + ibv_copy_ah_attr_from_kern(&dst->alt_ah_attr, &src->alt_ah_attr); + + dst->pkey_index = src->pkey_index; + dst->alt_pkey_index = src->alt_pkey_index; + dst->en_sqd_async_notify = src->en_sqd_async_notify; + dst->sq_draining = src->sq_draining; + dst->max_rd_atomic = src->max_rd_atomic; + dst->max_dest_rd_atomic = src->max_dest_rd_atomic; + dst->min_rnr_timer = src->min_rnr_timer; + dst->port_num = src->port_num; + dst->timeout = src->timeout; + dst->retry_cnt = src->retry_cnt; + dst->rnr_retry = src->rnr_retry; + dst->alt_port_num = src->alt_port_num; + dst->alt_timeout = src->alt_timeout; +} + +void ibv_copy_path_rec_from_kern(struct ibv_sa_path_rec *dst, + struct ibv_kern_path_rec *src) +{ + memcpy(dst->dgid.raw, src->dgid, sizeof dst->dgid); + memcpy(dst->sgid.raw, src->sgid, sizeof dst->sgid); + + dst->dlid = src->dlid; + dst->slid = src->slid; + dst->raw_traffic = src->raw_traffic; + dst->flow_label = src->flow_label; + dst->hop_limit = src->hop_limit; + dst->traffic_class = src->traffic_class; + dst->reversible = src->reversible; + dst->numb_path = src->numb_path; + dst->pkey = src->pkey; + dst->sl = src->sl; + dst->mtu_selector = src->mtu_selector; + dst->mtu = src->mtu; + dst->rate_selector = src->rate_selector; + dst->rate = src->rate; + dst->packet_life_time = src->packet_life_time; + dst->preference = src->preference; + dst->packet_life_time_selector = src->packet_life_time_selector; +} + +void ibv_copy_path_rec_to_kern(struct ibv_kern_path_rec *dst, + struct ibv_sa_path_rec *src) +{ + memcpy(dst->dgid, src->dgid.raw, sizeof src->dgid); + memcpy(dst->sgid, src->sgid.raw, sizeof src->sgid); + + dst->dlid = src->dlid; + dst->slid = src->slid; + dst->raw_traffic = src->raw_traffic; + dst->flow_label = src->flow_label; + dst->hop_limit = src->hop_limit; + dst->traffic_class = src->traffic_class; + dst->reversible = src->reversible; + dst->numb_path = src->numb_path; + dst->pkey = src->pkey; + dst->sl = src->sl; + dst->mtu_selector = src->mtu_selector; + dst->mtu = src->mtu; + dst->rate_selector = src->rate_selector; + dst->rate = src->rate; + dst->packet_life_time = src->packet_life_time; + dst->preference = src->preference; + dst->packet_life_time_selector = src->packet_life_time_selector; +} diff --git a/contrib/ofed/libibverbs/src/memory.c b/contrib/ofed/libibverbs/src/memory.c new file mode 100644 index 000000000000..405dd5a4a8d0 --- /dev/null +++ b/contrib/ofed/libibverbs/src/memory.c @@ -0,0 +1,642 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include "ibverbs.h" + +/* + * Most distro's headers don't have these yet. + */ +#ifdef __linux__ +#ifndef MADV_DONTFORK +#define MADV_DONTFORK 10 +#endif + +#ifndef MADV_DOFORK +#define MADV_DOFORK 11 +#endif +#else +#define MADV_DONTFORK INHERIT_NONE +#define MADV_DOFORK INHERIT_SHARE +#endif + +struct ibv_mem_node { + enum { + IBV_RED, + IBV_BLACK + } color; + struct ibv_mem_node *parent; + struct ibv_mem_node *left, *right; + uintptr_t start, end; + int refcnt; +}; + +static struct ibv_mem_node *mm_root; +static pthread_mutex_t mm_mutex = PTHREAD_MUTEX_INITIALIZER; +static int page_size; +static int too_late; + +int ibv_fork_init(void) +{ +#ifdef __linux__ + void *tmp; + int ret; +#endif + + if (mm_root) + return 0; + + if (too_late) + return EINVAL; + + page_size = sysconf(_SC_PAGESIZE); + if (page_size < 0) + return errno; + +#ifdef __linux__ + if (posix_memalign(&tmp, page_size, page_size)) + return ENOMEM; + + ret = madvise(tmp, page_size, MADV_DONTFORK) || + madvise(tmp, page_size, MADV_DOFORK); + + free(tmp); + + if (ret) + return ENOSYS; +#endif + + mm_root = malloc(sizeof *mm_root); + if (!mm_root) + return ENOMEM; + + mm_root->parent = NULL; + mm_root->left = NULL; + mm_root->right = NULL; + mm_root->color = IBV_BLACK; + mm_root->start = 0; + mm_root->end = UINTPTR_MAX; + mm_root->refcnt = 0; + + return 0; +} + +static struct ibv_mem_node *__mm_prev(struct ibv_mem_node *node) +{ + if (node->left) { + node = node->left; + while (node->right) + node = node->right; + } else { + while (node->parent && node == node->parent->left) + node = node->parent; + + node = node->parent; + } + + return node; +} + +static struct ibv_mem_node *__mm_next(struct ibv_mem_node *node) +{ + if (node->right) { + node = node->right; + while (node->left) + node = node->left; + } else { + while (node->parent && node == node->parent->right) + node = node->parent; + + node = node->parent; + } + + return node; +} + +static void __mm_rotate_right(struct ibv_mem_node *node) +{ + struct ibv_mem_node *tmp; + + tmp = node->left; + + node->left = tmp->right; + if (node->left) + node->left->parent = node; + + if (node->parent) { + if (node->parent->right == node) + node->parent->right = tmp; + else + node->parent->left = tmp; + } else + mm_root = tmp; + + tmp->parent = node->parent; + + tmp->right = node; + node->parent = tmp; +} + +static void __mm_rotate_left(struct ibv_mem_node *node) +{ + struct ibv_mem_node *tmp; + + tmp = node->right; + + node->right = tmp->left; + if (node->right) + node->right->parent = node; + + if (node->parent) { + if (node->parent->right == node) + node->parent->right = tmp; + else + node->parent->left = tmp; + } else + mm_root = tmp; + + tmp->parent = node->parent; + + tmp->left = node; + node->parent = tmp; +} + +static int verify(struct ibv_mem_node *node) +{ + int hl, hr; + + if (!node) + return 1; + + hl = verify(node->left); + hr = verify(node->left); + + if (!hl || !hr) + return 0; + if (hl != hr) + return 0; + + if (node->color == IBV_RED) { + if (node->left && node->left->color != IBV_BLACK) + return 0; + if (node->right && node->right->color != IBV_BLACK) + return 0; + return hl; + } + + return hl + 1; +} + +static void __mm_add_rebalance(struct ibv_mem_node *node) +{ + struct ibv_mem_node *parent, *gp, *uncle; + + while (node->parent && node->parent->color == IBV_RED) { + parent = node->parent; + gp = node->parent->parent; + + if (parent == gp->left) { + uncle = gp->right; + + if (uncle && uncle->color == IBV_RED) { + parent->color = IBV_BLACK; + uncle->color = IBV_BLACK; + gp->color = IBV_RED; + + node = gp; + } else { + if (node == parent->right) { + __mm_rotate_left(parent); + node = parent; + parent = node->parent; + } + + parent->color = IBV_BLACK; + gp->color = IBV_RED; + + __mm_rotate_right(gp); + } + } else { + uncle = gp->left; + + if (uncle && uncle->color == IBV_RED) { + parent->color = IBV_BLACK; + uncle->color = IBV_BLACK; + gp->color = IBV_RED; + + node = gp; + } else { + if (node == parent->left) { + __mm_rotate_right(parent); + node = parent; + parent = node->parent; + } + + parent->color = IBV_BLACK; + gp->color = IBV_RED; + + __mm_rotate_left(gp); + } + } + } + + mm_root->color = IBV_BLACK; +} + +static void __mm_add(struct ibv_mem_node *new) +{ + struct ibv_mem_node *node, *parent = NULL; + + node = mm_root; + while (node) { + parent = node; + if (node->start < new->start) + node = node->right; + else + node = node->left; + } + + if (parent->start < new->start) + parent->right = new; + else + parent->left = new; + + new->parent = parent; + new->left = NULL; + new->right = NULL; + + new->color = IBV_RED; + __mm_add_rebalance(new); +} + +static void __mm_remove(struct ibv_mem_node *node) +{ + struct ibv_mem_node *child, *parent, *sib, *tmp; + int nodecol; + + if (node->left && node->right) { + tmp = node->left; + while (tmp->right) + tmp = tmp->right; + + nodecol = tmp->color; + child = tmp->left; + tmp->color = node->color; + + if (tmp->parent != node) { + parent = tmp->parent; + parent->right = tmp->left; + if (tmp->left) + tmp->left->parent = parent; + + tmp->left = node->left; + node->left->parent = tmp; + } else + parent = tmp; + + tmp->right = node->right; + node->right->parent = tmp; + + tmp->parent = node->parent; + if (node->parent) { + if (node->parent->left == node) + node->parent->left = tmp; + else + node->parent->right = tmp; + } else + mm_root = tmp; + } else { + nodecol = node->color; + + child = node->left ? node->left : node->right; + parent = node->parent; + + if (child) + child->parent = parent; + if (parent) { + if (parent->left == node) + parent->left = child; + else + parent->right = child; + } else + mm_root = child; + } + + free(node); + + if (nodecol == IBV_RED) + return; + + while ((!child || child->color == IBV_BLACK) && child != mm_root) { + if (parent->left == child) { + sib = parent->right; + + if (sib->color == IBV_RED) { + parent->color = IBV_RED; + sib->color = IBV_BLACK; + __mm_rotate_left(parent); + sib = parent->right; + } + + if ((!sib->left || sib->left->color == IBV_BLACK) && + (!sib->right || sib->right->color == IBV_BLACK)) { + sib->color = IBV_RED; + child = parent; + parent = child->parent; + } else { + if (!sib->right || sib->right->color == IBV_BLACK) { + if (sib->left) + sib->left->color = IBV_BLACK; + sib->color = IBV_RED; + __mm_rotate_right(sib); + sib = parent->right; + } + + sib->color = parent->color; + parent->color = IBV_BLACK; + if (sib->right) + sib->right->color = IBV_BLACK; + __mm_rotate_left(parent); + child = mm_root; + break; + } + } else { + sib = parent->left; + + if (sib->color == IBV_RED) { + parent->color = IBV_RED; + sib->color = IBV_BLACK; + __mm_rotate_right(parent); + sib = parent->left; + } + + if ((!sib->left || sib->left->color == IBV_BLACK) && + (!sib->right || sib->right->color == IBV_BLACK)) { + sib->color = IBV_RED; + child = parent; + parent = child->parent; + } else { + if (!sib->left || sib->left->color == IBV_BLACK) { + if (sib->right) + sib->right->color = IBV_BLACK; + sib->color = IBV_RED; + __mm_rotate_left(sib); + sib = parent->left; + } + + sib->color = parent->color; + parent->color = IBV_BLACK; + if (sib->left) + sib->left->color = IBV_BLACK; + __mm_rotate_right(parent); + child = mm_root; + break; + } + } + } + + if (child) + child->color = IBV_BLACK; +} + +static struct ibv_mem_node *__mm_find_start(uintptr_t start, uintptr_t end) +{ + struct ibv_mem_node *node = mm_root; + + while (node) { + if (node->start <= start && node->end >= start) + break; + + if (node->start < start) + node = node->right; + else + node = node->left; + } + + return node; +} + +static struct ibv_mem_node *merge_ranges(struct ibv_mem_node *node, + struct ibv_mem_node *prev) +{ + prev->end = node->end; + prev->refcnt = node->refcnt; + __mm_remove(node); + + return prev; +} + +static struct ibv_mem_node *split_range(struct ibv_mem_node *node, + uintptr_t cut_line) +{ + struct ibv_mem_node *new_node = NULL; + + new_node = malloc(sizeof *new_node); + if (!new_node) + return NULL; + new_node->start = cut_line; + new_node->end = node->end; + new_node->refcnt = node->refcnt; + node->end = cut_line - 1; + __mm_add(new_node); + + return new_node; +} + +static struct ibv_mem_node *get_start_node(uintptr_t start, uintptr_t end, + int inc) +{ + struct ibv_mem_node *node, *tmp = NULL; + + node = __mm_find_start(start, end); + if (node->start < start) + node = split_range(node, start); + else { + tmp = __mm_prev(node); + if (tmp && tmp->refcnt == node->refcnt + inc) + node = merge_ranges(node, tmp); + } + return node; +} + +/* + * This function is called if madvise() fails to undo merging/splitting + * operations performed on the node. + */ +static struct ibv_mem_node *undo_node(struct ibv_mem_node *node, + uintptr_t start, int inc) +{ + struct ibv_mem_node *tmp = NULL; + + /* + * This condition can be true only if we merged this + * node with the previous one, so we need to split them. + */ + if (start > node->start) { + tmp = split_range(node, start); + if (tmp) { + node->refcnt += inc; + node = tmp; + } else + return NULL; + } + + tmp = __mm_prev(node); + if (tmp && tmp->refcnt == node->refcnt) + node = merge_ranges(node, tmp); + + tmp = __mm_next(node); + if (tmp && tmp->refcnt == node->refcnt) + node = merge_ranges(tmp, node); + + return node; +} + +static int ibv_madvise_range(void *base, size_t size, int advice) +{ + uintptr_t start, end; + struct ibv_mem_node *node, *tmp; + int inc; + int rolling_back = 0; + int ret = 0; + + if (!size) + return 0; + + start = (uintptr_t) base & ~(page_size - 1); + end = ((uintptr_t) (base + size + page_size - 1) & + ~(page_size - 1)) - 1; + + pthread_mutex_lock(&mm_mutex); +again: + inc = advice == MADV_DONTFORK ? 1 : -1; + + node = get_start_node(start, end, inc); + if (!node) { + ret = -1; + goto out; + } + + while (node && node->start <= end) { + if (node->end > end) { + if (!split_range(node, end + 1)) { + ret = -1; + goto out; + } + } + + if ((inc == -1 && node->refcnt == 1) || + (inc == 1 && node->refcnt == 0)) { + /* + * If this is the first time through the loop, + * and we merged this node with the previous + * one, then we only want to do the madvise() + * on start ... node->end (rather than + * starting at node->start). + * + * Otherwise we end up doing madvise() on + * bigger region than we're being asked to, + * and that may lead to a spurious failure. + */ + if (start > node->start) + ret = minherit((void *) start, node->end - start + 1, + advice); + else + ret = minherit((void *) node->start, + node->end - node->start + 1, + advice); + if (ret) { + node = undo_node(node, start, inc); + + if (rolling_back || !node) + goto out; + + /* madvise failed, roll back previous changes */ + rolling_back = 1; + advice = advice == MADV_DONTFORK ? + MADV_DOFORK : MADV_DONTFORK; + tmp = __mm_prev(node); + if (!tmp || start > tmp->end) + goto out; + end = tmp->end; + goto again; + } + } + + node->refcnt += inc; + node = __mm_next(node); + } + + if (node) { + tmp = __mm_prev(node); + if (tmp && node->refcnt == tmp->refcnt) + node = merge_ranges(node, tmp); + } + +out: + if (rolling_back) + ret = -1; + + pthread_mutex_unlock(&mm_mutex); + + return ret; +} + +int ibv_dontfork_range(void *base, size_t size) +{ + if (mm_root) + return ibv_madvise_range(base, size, MADV_DONTFORK); + else { + too_late = 1; + return 0; + } +} + +int ibv_dofork_range(void *base, size_t size) +{ + if (mm_root) + return ibv_madvise_range(base, size, MADV_DOFORK); + else { + too_late = 1; + return 0; + } +} diff --git a/contrib/ofed/libibverbs/src/sysfs.c b/contrib/ofed/libibverbs/src/sysfs.c new file mode 100644 index 000000000000..bbf05c52f684 --- /dev/null +++ b/contrib/ofed/libibverbs/src/sysfs.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ibverbs.h" + +static char *sysfs_path; + +const char *ibv_get_sysfs_path(void) +{ + char *env = NULL; + + if (sysfs_path) + return sysfs_path; + + /* + * Only follow use path passed in through the calling user's + * environment if we're not running SUID. + */ + if (getuid() == geteuid()) + env = getenv("SYSFS_PATH"); + + if (env) { + int len; + + sysfs_path = strndup(env, IBV_SYSFS_PATH_MAX); + len = strlen(sysfs_path); + while (len > 0 && sysfs_path[len - 1] == '/') { + --len; + sysfs_path[len] = '\0'; + } + } else + sysfs_path = "/sys"; + + return sysfs_path; +} + +int ibv_read_sysfs_file(const char *dir, const char *file, + char *buf, size_t size) +{ + char *path, *s; + int fd; + size_t len; + + if (asprintf(&path, "%s/%s", dir, file) < 0) + return -1; + + for (s = &path[0]; *s != '\0'; s++) + if (*s == '/') + *s = '.'; + + len = size; + if (sysctlbyname(&path[1], buf, &len, NULL, 0) == -1) + return -1; + + free(path); + + if (len > 0 && buf[len - 1] == '\n') + buf[--len] = '\0'; + + return len; +} diff --git a/contrib/ofed/libibverbs/src/verbs.c b/contrib/ofed/libibverbs/src/verbs.c new file mode 100644 index 000000000000..9cbe73bb1850 --- /dev/null +++ b/contrib/ofed/libibverbs/src/verbs.c @@ -0,0 +1,754 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include "ibverbs.h" + +int ibv_rate_to_mult(enum ibv_rate rate) +{ + switch (rate) { + case IBV_RATE_2_5_GBPS: return 1; + case IBV_RATE_5_GBPS: return 2; + case IBV_RATE_10_GBPS: return 4; + case IBV_RATE_20_GBPS: return 8; + case IBV_RATE_30_GBPS: return 12; + case IBV_RATE_40_GBPS: return 16; + case IBV_RATE_60_GBPS: return 24; + case IBV_RATE_80_GBPS: return 32; + case IBV_RATE_120_GBPS: return 48; + default: return -1; + } +} + +enum ibv_rate mult_to_ibv_rate(int mult) +{ + switch (mult) { + case 1: return IBV_RATE_2_5_GBPS; + case 2: return IBV_RATE_5_GBPS; + case 4: return IBV_RATE_10_GBPS; + case 8: return IBV_RATE_20_GBPS; + case 12: return IBV_RATE_30_GBPS; + case 16: return IBV_RATE_40_GBPS; + case 24: return IBV_RATE_60_GBPS; + case 32: return IBV_RATE_80_GBPS; + case 48: return IBV_RATE_120_GBPS; + default: return IBV_RATE_MAX; + } +} + +int __ibv_query_device(struct ibv_context *context, + struct ibv_device_attr *device_attr) +{ + return context->ops.query_device(context, device_attr); +} +default_symver(__ibv_query_device, ibv_query_device); + +int __ibv_query_port(struct ibv_context *context, uint8_t port_num, + struct ibv_port_attr *port_attr) +{ + return context->ops.query_port(context, port_num, port_attr); +} +default_symver(__ibv_query_port, ibv_query_port); + +int __ibv_query_gid(struct ibv_context *context, uint8_t port_num, + int index, union ibv_gid *gid) +{ + char name[24]; + char attr[41]; + uint16_t val; + int i; + + snprintf(name, sizeof name, "ports/%d/gids/%d", port_num, index); + + if (ibv_read_sysfs_file(context->device->ibdev_path, name, + attr, sizeof attr) < 0) + return -1; + + for (i = 0; i < 8; ++i) { + if (sscanf(attr + i * 5, "%hx", &val) != 1) + return -1; + gid->raw[i * 2 ] = val >> 8; + gid->raw[i * 2 + 1] = val & 0xff; + } + + return 0; +} +default_symver(__ibv_query_gid, ibv_query_gid); + +int __ibv_query_pkey(struct ibv_context *context, uint8_t port_num, + int index, uint16_t *pkey) +{ + char name[24]; + char attr[8]; + uint16_t val; + + snprintf(name, sizeof name, "ports/%d/pkeys/%d", port_num, index); + + if (ibv_read_sysfs_file(context->device->ibdev_path, name, + attr, sizeof attr) < 0) + return -1; + + if (sscanf(attr, "%hx", &val) != 1) + return -1; + + *pkey = htons(val); + return 0; +} +default_symver(__ibv_query_pkey, ibv_query_pkey); + +struct ibv_pd *__ibv_alloc_pd(struct ibv_context *context) +{ + struct ibv_pd *pd; + + pd = context->ops.alloc_pd(context); + if (pd) + pd->context = context; + + return pd; +} +default_symver(__ibv_alloc_pd, ibv_alloc_pd); + +int __ibv_dealloc_pd(struct ibv_pd *pd) +{ + return pd->context->ops.dealloc_pd(pd); +} +default_symver(__ibv_dealloc_pd, ibv_dealloc_pd); + +struct ibv_mr *__ibv_reg_mr(struct ibv_pd *pd, void *addr, + size_t length, int access) +{ + struct ibv_mr *mr; + + if (ibv_dontfork_range(addr, length)) + return NULL; + + mr = pd->context->ops.reg_mr(pd, addr, length, access); + if (mr) { + mr->context = pd->context; + mr->pd = pd; + mr->addr = addr; + mr->length = length; + } else + ibv_dofork_range(addr, length); + + return mr; +} +default_symver(__ibv_reg_mr, ibv_reg_mr); + +int __ibv_dereg_mr(struct ibv_mr *mr) +{ + int ret; + void *addr = mr->addr; + size_t length = mr->length; + + ret = mr->context->ops.dereg_mr(mr); + if (!ret) + ibv_dofork_range(addr, length); + + return ret; +} +default_symver(__ibv_dereg_mr, ibv_dereg_mr); + +static struct ibv_comp_channel *ibv_create_comp_channel_v2(struct ibv_context *context) +{ + struct ibv_abi_compat_v2 *t = context->abi_compat; + static int warned; + + if (!pthread_mutex_trylock(&t->in_use)) + return &t->channel; + + if (!warned) { + fprintf(stderr, PFX "Warning: kernel's ABI version %d limits capacity.\n" + " Only one completion channel can be created per context.\n", + abi_ver); + ++warned; + } + + return NULL; +} + +struct ibv_comp_channel *ibv_create_comp_channel(struct ibv_context *context) +{ + struct ibv_comp_channel *channel; + struct ibv_create_comp_channel cmd; + struct ibv_create_comp_channel_resp resp; + + if (abi_ver <= 2) + return ibv_create_comp_channel_v2(context); + + channel = malloc(sizeof *channel); + if (!channel) + return NULL; + + IBV_INIT_CMD_RESP(&cmd, sizeof cmd, CREATE_COMP_CHANNEL, &resp, sizeof resp); + if (write(context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) { + free(channel); + return NULL; + } + + VALGRIND_MAKE_MEM_DEFINED(&resp, sizeof resp); + + channel->context = context; + channel->fd = resp.fd; + channel->refcnt = 0; + + return channel; +} + +static int ibv_destroy_comp_channel_v2(struct ibv_comp_channel *channel) +{ + struct ibv_abi_compat_v2 *t = (struct ibv_abi_compat_v2 *) channel; + pthread_mutex_unlock(&t->in_use); + return 0; +} + +int ibv_destroy_comp_channel(struct ibv_comp_channel *channel) +{ + struct ibv_context *context; + int ret; + + context = channel->context; + pthread_mutex_lock(&context->mutex); + + if (channel->refcnt) { + ret = EBUSY; + goto out; + } + + if (abi_ver <= 2) { + ret = ibv_destroy_comp_channel_v2(channel); + goto out; + } + + close(channel->fd); + free(channel); + ret = 0; + +out: + pthread_mutex_unlock(&context->mutex); + + return ret; +} + +struct ibv_cq *__ibv_create_cq(struct ibv_context *context, int cqe, void *cq_context, + struct ibv_comp_channel *channel, int comp_vector) +{ + struct ibv_cq *cq; + + pthread_mutex_lock(&context->mutex); + + cq = context->ops.create_cq(context, cqe, channel, comp_vector); + + if (cq) { + cq->context = context; + cq->channel = channel; + if (channel) + ++channel->refcnt; + cq->cq_context = cq_context; + cq->comp_events_completed = 0; + cq->async_events_completed = 0; + pthread_mutex_init(&cq->mutex, NULL); + pthread_cond_init(&cq->cond, NULL); + } + + pthread_mutex_unlock(&context->mutex); + + return cq; +} +default_symver(__ibv_create_cq, ibv_create_cq); + +int __ibv_resize_cq(struct ibv_cq *cq, int cqe) +{ + if (!cq->context->ops.resize_cq) + return ENOSYS; + + return cq->context->ops.resize_cq(cq, cqe); +} +default_symver(__ibv_resize_cq, ibv_resize_cq); + +int __ibv_destroy_cq(struct ibv_cq *cq) +{ + struct ibv_comp_channel *channel = cq->channel; + int ret; + + if (channel) + pthread_mutex_lock(&channel->context->mutex); + + ret = cq->context->ops.destroy_cq(cq); + + if (channel) { + if (!ret) + --channel->refcnt; + pthread_mutex_unlock(&channel->context->mutex); + } + + return ret; +} +default_symver(__ibv_destroy_cq, ibv_destroy_cq); + +int __ibv_get_cq_event(struct ibv_comp_channel *channel, + struct ibv_cq **cq, void **cq_context) +{ + struct ibv_comp_event ev; + + if (read(channel->fd, &ev, sizeof ev) != sizeof ev) + return -1; + + *cq = (struct ibv_cq *) (uintptr_t) ev.cq_handle; + *cq_context = (*cq)->cq_context; + + if ((*cq)->context->ops.cq_event) + (*cq)->context->ops.cq_event(*cq); + + return 0; +} +default_symver(__ibv_get_cq_event, ibv_get_cq_event); + +void __ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents) +{ + pthread_mutex_lock(&cq->mutex); + cq->comp_events_completed += nevents; + pthread_cond_signal(&cq->cond); + pthread_mutex_unlock(&cq->mutex); +} +default_symver(__ibv_ack_cq_events, ibv_ack_cq_events); + +struct ibv_srq *__ibv_create_srq(struct ibv_pd *pd, + struct ibv_srq_init_attr *srq_init_attr) +{ + struct ibv_srq *srq; + + if (!pd->context->ops.create_srq) + return NULL; + + srq = pd->context->ops.create_srq(pd, srq_init_attr); + if (srq) { + srq->context = pd->context; + srq->srq_context = srq_init_attr->srq_context; + srq->pd = pd; + srq->xrc_domain = NULL; + srq->xrc_cq = NULL; + srq->xrc_srq_num = 0; + srq->events_completed = 0; + pthread_mutex_init(&srq->mutex, NULL); + pthread_cond_init(&srq->cond, NULL); + } + + return srq; +} +default_symver(__ibv_create_srq, ibv_create_srq); + +struct ibv_srq *ibv_create_xrc_srq(struct ibv_pd *pd, + struct ibv_xrc_domain *xrc_domain, + struct ibv_cq *xrc_cq, + struct ibv_srq_init_attr *srq_init_attr) +{ + struct ibv_srq *srq; + + if (!pd->context->more_ops) + return NULL; + + srq = pd->context->more_ops->create_xrc_srq(pd, xrc_domain, + xrc_cq, srq_init_attr); + if (srq) { + srq->context = pd->context; + srq->srq_context = srq_init_attr->srq_context; + srq->pd = pd; + srq->xrc_domain = xrc_domain; + srq->xrc_cq = xrc_cq; + srq->events_completed = 0; + pthread_mutex_init(&srq->mutex, NULL); + pthread_cond_init(&srq->cond, NULL); + } + + return srq; +} + +int __ibv_modify_srq(struct ibv_srq *srq, + struct ibv_srq_attr *srq_attr, + int srq_attr_mask) +{ + return srq->context->ops.modify_srq(srq, srq_attr, srq_attr_mask); +} +default_symver(__ibv_modify_srq, ibv_modify_srq); + +int __ibv_query_srq(struct ibv_srq *srq, struct ibv_srq_attr *srq_attr) +{ + return srq->context->ops.query_srq(srq, srq_attr); +} +default_symver(__ibv_query_srq, ibv_query_srq); + +int __ibv_destroy_srq(struct ibv_srq *srq) +{ + return srq->context->ops.destroy_srq(srq); +} +default_symver(__ibv_destroy_srq, ibv_destroy_srq); + +struct ibv_qp *__ibv_create_qp(struct ibv_pd *pd, + struct ibv_qp_init_attr *qp_init_attr) +{ + struct ibv_qp *qp = pd->context->ops.create_qp(pd, qp_init_attr); + + if (qp) { + qp->context = pd->context; + qp->qp_context = qp_init_attr->qp_context; + qp->pd = pd; + qp->send_cq = qp_init_attr->send_cq; + qp->recv_cq = qp_init_attr->recv_cq; + qp->srq = qp_init_attr->srq; + qp->qp_type = qp_init_attr->qp_type; + qp->state = IBV_QPS_RESET; + qp->events_completed = 0; + qp->xrc_domain = qp_init_attr->qp_type == IBV_QPT_XRC ? + qp_init_attr->xrc_domain : NULL; + pthread_mutex_init(&qp->mutex, NULL); + pthread_cond_init(&qp->cond, NULL); + } + + return qp; +} +default_symver(__ibv_create_qp, ibv_create_qp); + +int __ibv_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask, + struct ibv_qp_init_attr *init_attr) +{ + int ret; + + ret = qp->context->ops.query_qp(qp, attr, attr_mask, init_attr); + if (ret) + return ret; + + if (attr_mask & IBV_QP_STATE) + qp->state = attr->qp_state; + + return 0; +} +default_symver(__ibv_query_qp, ibv_query_qp); + +int __ibv_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + int attr_mask) +{ + int ret; + + ret = qp->context->ops.modify_qp(qp, attr, attr_mask); + if (ret) + return ret; + + if (attr_mask & IBV_QP_STATE) + qp->state = attr->qp_state; + + return 0; +} +default_symver(__ibv_modify_qp, ibv_modify_qp); + +int __ibv_destroy_qp(struct ibv_qp *qp) +{ + return qp->context->ops.destroy_qp(qp); +} +default_symver(__ibv_destroy_qp, ibv_destroy_qp); + +struct ibv_ah *__ibv_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr) +{ + struct ibv_ah *ah = pd->context->ops.create_ah(pd, attr); + + if (ah) { + ah->context = pd->context; + ah->pd = pd; + } + + return ah; +} +default_symver(__ibv_create_ah, ibv_create_ah); + +static int ibv_find_gid_index(struct ibv_context *context, uint8_t port_num, + union ibv_gid *gid) +{ + union ibv_gid sgid; + int i = 0, ret; + + do { + ret = ibv_query_gid(context, port_num, i++, &sgid); + } while (!ret && memcmp(&sgid, gid, sizeof *gid)); + + return ret ? ret : i - 1; +} + +int ibv_init_ah_from_wc(struct ibv_context *context, uint8_t port_num, + struct ibv_wc *wc, struct ibv_grh *grh, + struct ibv_ah_attr *ah_attr) +{ + uint32_t flow_class; + int ret; + + memset(ah_attr, 0, sizeof *ah_attr); + ah_attr->dlid = wc->slid; + ah_attr->sl = wc->sl; + ah_attr->src_path_bits = wc->dlid_path_bits; + ah_attr->port_num = port_num; + + if (wc->wc_flags & IBV_WC_GRH) { + ah_attr->is_global = 1; + ah_attr->grh.dgid = grh->sgid; + + ret = ibv_find_gid_index(context, port_num, &grh->dgid); + if (ret < 0) + return ret; + + ah_attr->grh.sgid_index = (uint8_t) ret; + flow_class = ntohl(grh->version_tclass_flow); + ah_attr->grh.flow_label = flow_class & 0xFFFFF; + ah_attr->grh.hop_limit = grh->hop_limit; + ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF; + } + return 0; +} + +struct ibv_ah *ibv_create_ah_from_wc(struct ibv_pd *pd, struct ibv_wc *wc, + struct ibv_grh *grh, uint8_t port_num) +{ + struct ibv_ah_attr ah_attr; + int ret; + + ret = ibv_init_ah_from_wc(pd->context, port_num, wc, grh, &ah_attr); + if (ret) + return NULL; + + return ibv_create_ah(pd, &ah_attr); +} + +int __ibv_destroy_ah(struct ibv_ah *ah) +{ + return ah->context->ops.destroy_ah(ah); +} +default_symver(__ibv_destroy_ah, ibv_destroy_ah); + +int __ibv_attach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid) +{ + return qp->context->ops.attach_mcast(qp, gid, lid); +} +default_symver(__ibv_attach_mcast, ibv_attach_mcast); + +int __ibv_detach_mcast(struct ibv_qp *qp, const union ibv_gid *gid, uint16_t lid) +{ + return qp->context->ops.detach_mcast(qp, gid, lid); +} +default_symver(__ibv_detach_mcast, ibv_detach_mcast); + +struct ibv_xrc_domain *ibv_open_xrc_domain(struct ibv_context *context, + int fd, int oflag) +{ + struct ibv_xrc_domain *d; + + if (!context->more_ops) + return NULL; + + d = context->more_ops->open_xrc_domain(context, fd, oflag); + if (d) + d->context = context; + + return d; +} + +int ibv_close_xrc_domain(struct ibv_xrc_domain *d) +{ + if (!d->context->more_ops) + return 0; + + return d->context->more_ops->close_xrc_domain(d); +} + +int ibv_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, + uint32_t *xrc_rcv_qpn) +{ + struct ibv_context *c; + if (!init_attr || !(init_attr->xrc_domain)) + return EINVAL; + + c = init_attr->xrc_domain->context; + if (!c->more_ops) + return ENOSYS; + + return c->more_ops->create_xrc_rcv_qp(init_attr, + xrc_rcv_qpn); +} + +int ibv_modify_xrc_rcv_qp(struct ibv_xrc_domain *d, + uint32_t xrc_rcv_qpn, + struct ibv_qp_attr *attr, + int attr_mask) +{ + if (!d || !attr) + return EINVAL; + + if (!d->context->more_ops) + return ENOSYS; + + return d->context->more_ops->modify_xrc_rcv_qp(d, xrc_rcv_qpn, attr, + attr_mask); +} + +int ibv_query_xrc_rcv_qp(struct ibv_xrc_domain *d, + uint32_t xrc_rcv_qpn, + struct ibv_qp_attr *attr, + int attr_mask, + struct ibv_qp_init_attr *init_attr) +{ + if (!d) + return EINVAL; + + if (!d->context->more_ops) + return ENOSYS; + + return d->context->more_ops->query_xrc_rcv_qp(d, xrc_rcv_qpn, attr, + attr_mask, init_attr); +} + +int ibv_reg_xrc_rcv_qp(struct ibv_xrc_domain *d, + uint32_t xrc_rcv_qpn) +{ + return d->context->more_ops->reg_xrc_rcv_qp(d, xrc_rcv_qpn); +} + +int ibv_unreg_xrc_rcv_qp(struct ibv_xrc_domain *d, + uint32_t xrc_rcv_qpn) +{ + return d->context->more_ops->unreg_xrc_rcv_qp(d, xrc_rcv_qpn); +} + + +static uint16_t get_vlan_id(const union ibv_gid *dgid) +{ + return dgid->raw[11] << 8 | dgid->raw[12]; +} + +static void get_ll_mac(const union ibv_gid *gid, uint8_t *mac) +{ + memcpy(mac, &gid->raw[8], 3); + memcpy(mac + 3, &gid->raw[13], 3); + mac[0] ^= 2; +} + +static int is_multicast_gid(const union ibv_gid *gid) +{ + return gid->raw[0] == 0xff; +} + +static void get_mcast_mac(const union ibv_gid *gid, uint8_t *mac) +{ + int i; + + mac[0] = 0x33; + mac[1] = 0x33; + for (i = 2; i < 6; ++i) + mac[i] = gid->raw[i + 10]; +} + +static int is_link_local_gid(const union ibv_gid *gid) +{ + uint32_t hi = *(uint32_t *)(gid->raw); + uint32_t lo = *(uint32_t *)(gid->raw + 4); + if (hi == htonl(0xfe800000) && lo == 0) + return 1; + + return 0; +} + +static int resolve_gid(const union ibv_gid *dgid, uint8_t *mac, uint8_t *is_mcast) +{ + if (is_link_local_gid(dgid)) { + get_ll_mac(dgid, mac); + *is_mcast = 0; + } else if (is_multicast_gid(dgid)) { + get_mcast_mac(dgid, mac); + *is_mcast = 1; + } else + return -EINVAL; + + return 0; +} + +static int is_tagged_vlan(const union ibv_gid *gid) +{ + uint16_t tag; + + tag = gid->raw[11] << 8 | gid->raw[12]; + + return tag < 0x1000; +} + +int __ibv_resolve_eth_gid(const struct ibv_pd *pd, uint8_t port_num, + union ibv_gid *dgid, uint8_t sgid_index, + uint8_t mac[], uint16_t *vlan, uint8_t *tagged, + uint8_t *is_mcast) +{ + int err; + union ibv_gid sgid; + int stagged, svlan; + + err = resolve_gid(dgid, mac, is_mcast); + if (err) + return err; + + err = ibv_query_gid(pd->context, port_num, sgid_index, &sgid); + if (err) + return err; + + stagged = is_tagged_vlan(&sgid); + if (stagged) { + if (!is_tagged_vlan(dgid) && !is_mcast) + return -1; + + svlan = get_vlan_id(&sgid); + if (svlan != get_vlan_id(dgid) && !is_mcast) + return -1; + + *tagged = 1; + *vlan = svlan; + } else + *tagged = 0; + + return 0; +} +default_symver(__ibv_resolve_eth_gid, ibv_resolve_eth_gid); + diff --git a/contrib/ofed/libmlx4/AUTHORS b/contrib/ofed/libmlx4/AUTHORS new file mode 100644 index 000000000000..ffe1800452fe --- /dev/null +++ b/contrib/ofed/libmlx4/AUTHORS @@ -0,0 +1 @@ +Roland Dreier diff --git a/contrib/ofed/libmlx4/COPYING b/contrib/ofed/libmlx4/COPYING new file mode 100644 index 000000000000..add3d1990bc1 --- /dev/null +++ b/contrib/ofed/libmlx4/COPYING @@ -0,0 +1,378 @@ +This software is available to you under a choice of one of two +licenses. You may choose to be licensed under the terms of the the +OpenIB.org BSD license or the GNU General Public License (GPL) Version +2, both included below. + +Copyright (c) 2007 Cisco, Inc. All rights reserved. + +================================================================== + + OpenIB.org BSD license + +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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +================================================================== + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/ofed/libmlx4/Makefile.am b/contrib/ofed/libmlx4/Makefile.am new file mode 100644 index 000000000000..a7afb14c61f5 --- /dev/null +++ b/contrib/ofed/libmlx4/Makefile.am @@ -0,0 +1,26 @@ +AM_CFLAGS = -g -Wall -D_GNU_SOURCE + +mlx4_version_script = @MLX4_VERSION_SCRIPT@ + +MLX4_SOURCES = src/buf.c src/cq.c src/dbrec.c src/mlx4.c src/qp.c \ + src/srq.c src/verbs.c + +if HAVE_IBV_DEVICE_LIBRARY_EXTENSION + lib_LTLIBRARIES = src/libmlx4.la + src_libmlx4_la_SOURCES = $(MLX4_SOURCES) + src_libmlx4_la_LDFLAGS = -avoid-version -release @IBV_DEVICE_LIBRARY_EXTENSION@ \ + $(mlx4_version_script) + mlx4confdir = $(sysconfdir)/libibverbs.d + mlx4conf_DATA = mlx4.driver +else + mlx4libdir = $(libdir)/infiniband + mlx4lib_LTLIBRARIES = src/mlx4.la + src_mlx4_la_SOURCES = $(MLX4_SOURCES) + src_mlx4_la_LDFLAGS = -avoid-version -module $(mlx4_version_script) +endif + +EXTRA_DIST = src/doorbell.h src/mlx4.h src/mlx4-abi.h src/wqe.h \ + src/mlx4.map libmlx4.spec.in mlx4.driver + +dist-hook: libmlx4.spec + cp libmlx4.spec $(distdir) diff --git a/contrib/ofed/libmlx4/README b/contrib/ofed/libmlx4/README new file mode 100644 index 000000000000..5c027ef80360 --- /dev/null +++ b/contrib/ofed/libmlx4/README @@ -0,0 +1,58 @@ +Introduction +============ + +libmlx4 is a userspace driver for Mellanox ConnectX InfiniBand HCAs. +It is a plug-in module for libibverbs that allows programs to use +Mellanox hardware directly from userspace. See the libibverbs package +for more information. + +Using libmlx4 +============== + +libmlx4 will be loaded and used automatically by programs linked with +libibverbs. The mlx4_ib kernel module must be loaded for HCA devices +to be detected and used. + +Supported Hardware +================== + +libmlx4 currently supports HCAs based on the following Mellanox chip: + + MT25408 ConnectX (PCI Express) + +These HCAs use the mlx4_ib kernel driver. Support for other Mellanox +HCAs, which use the ib_mthca kernel driver, is provided by the +libmthca userspace driver. + +Valgrind Support +================ + +When running applications that use libibverbs under the Valgrind +memory-checking debugger, Valgrind will falsely report "read from +uninitialized" for memory that was initialized by the kernel drivers +or HCA hardware. Specifically, Valgrind cannot see when kernel +drivers or HCA hardware write to userspace memory, so when the process +reads from that memory, Valgrind incorrectly assumes that the memory +contents are uninitialized, and therefore raises a warning. + +libmlx4 can be built with specific support for the Valgrind +memory-checking debugger by specifying the --with-valgrind command +line argument to configure. This flag enables code in libibverbs to +tell Valgrind "this memory may look uninitialized, but it's really +OK," which therefore suppresses the incorrect "read from +uninitialized" warnings. This code adds trivial overhead to the +critical performance path, so it is disabled by default. The intent +is that production users can use a "normal" build of libmlx4 and +developers can use the "valgrind debug" build by simply switching +their OPENIB_DRIVER_PATH environment variables. + +Libmlx4 needs some header files from Valgrind in order to compile this +support; it is important to use the header files from the same version +of Valgrind that will be used at run time. You may need to specify +the directory where Valgrind's header files are installed as an +argument to --with-valgrind. For example + + ./configure --with-valgrind=/opt/valgrind + +will make the libmlx4 build look for valgrind headers in +/opt/valgrind/include diff --git a/contrib/ofed/libmlx4/autogen.sh b/contrib/ofed/libmlx4/autogen.sh new file mode 100755 index 000000000000..fd47839cae8c --- /dev/null +++ b/contrib/ofed/libmlx4/autogen.sh @@ -0,0 +1,8 @@ +#! /bin/sh + +set -x +aclocal -I config +libtoolize --force --copy +autoheader +automake --foreign --add-missing --copy +autoconf diff --git a/contrib/ofed/libmlx4/configure.in b/contrib/ofed/libmlx4/configure.in new file mode 100644 index 000000000000..46a3a6474596 --- /dev/null +++ b/contrib/ofed/libmlx4/configure.in @@ -0,0 +1,84 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(libmlx4, 1.0, general@lists.openfabrics.org) +AC_CONFIG_SRCDIR([src/mlx4.h]) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(libmlx4, 1.0) +AM_PROG_LIBTOOL + +AC_ARG_WITH([valgrind], + AC_HELP_STRING([--with-valgrind], + [Enable Valgrind annotations (small runtime overhead, default NO)])) +if test x$with_valgrind = x || test x$with_valgrind = xno; then + want_valgrind=no + AC_DEFINE([NVALGRIND], 1, [Define to 1 to disable Valgrind annotations.]) +else + want_valgrind=yes + if test -d $with_valgrind; then + CPPFLAGS="$CPPFLAGS -I$with_valgrind/include" + fi +fi + +dnl Checks for programs +AC_PROG_CC + +dnl Checks for libraries +AC_CHECK_LIB(ibverbs, ibv_get_device_list, [], + AC_MSG_ERROR([ibv_get_device_list() not found. libmlx4 requires libibverbs.])) + +dnl Checks for header files. +AC_CHECK_HEADER(infiniband/driver.h, [], + AC_MSG_ERROR([ not found. libmlx4 requires libibverbs.])) +AC_HEADER_STDC +AC_CHECK_HEADER(valgrind/memcheck.h, + [AC_DEFINE(HAVE_VALGRIND_MEMCHECK_H, 1, + [Define to 1 if you have the header file.])], + [if test $want_valgrind = yes; then + AC_MSG_ERROR([Valgrind memcheck support requested, but not found.]) + fi]) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_CHECK_SIZEOF(long) +AC_CHECK_MEMBER(struct ibv_context.more_ops, + [AC_DEFINE([HAVE_IBV_MORE_OPS], 1, [Define to 1 if more_ops is a member of ibv_context])],, + [#include ]) +AC_CHECK_MEMBER(struct ibv_more_ops.create_xrc_srq, + [AC_DEFINE([HAVE_IBV_XRC_OPS], 1, [Define to 1 if have xrc ops])],, + [#include ]) + +dnl Checks for library functions +AC_CHECK_FUNC(ibv_read_sysfs_file, [], + AC_MSG_ERROR([ibv_read_sysfs_file() not found. libmlx4 requires libibverbs >= 1.0.3.])) +AC_CHECK_FUNCS(ibv_dontfork_range ibv_dofork_range ibv_register_driver) + +dnl Now check if for libibverbs 1.0 vs 1.1 +dummy=if$$ +cat < $dummy.c +#include +IBV_DEVICE_LIBRARY_EXTENSION +IBV_VERSION +IBV_DEVICE_LIBRARY_EXTENSION=`$CC $CPPFLAGS -E $dummy.c 2> /dev/null | tail -1` +rm -f $dummy.c +AM_CONDITIONAL(HAVE_IBV_DEVICE_LIBRARY_EXTENSION, + test $IBV_DEVICE_LIBRARY_EXTENSION != IBV_DEVICE_LIBRARY_EXTENSION) +AC_SUBST(IBV_DEVICE_LIBRARY_EXTENSION) + +AC_CACHE_CHECK(whether ld accepts --version-script, ac_cv_version_script, + [if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then + ac_cv_version_script=yes + else + ac_cv_version_script=no + fi]) + +if test $ac_cv_version_script = yes; then + MLX4_VERSION_SCRIPT='-Wl,--version-script=$(srcdir)/src/mlx4.map' +else + MLX4_VERSION_SCRIPT= +fi +AC_SUBST(MLX4_VERSION_SCRIPT) + +AC_CONFIG_FILES([Makefile libmlx4.spec]) +AC_OUTPUT diff --git a/contrib/ofed/libmlx4/debian/changelog b/contrib/ofed/libmlx4/debian/changelog new file mode 100644 index 000000000000..74cbef70cd96 --- /dev/null +++ b/contrib/ofed/libmlx4/debian/changelog @@ -0,0 +1,11 @@ +libmlx4 (1.0-2) unstable; urgency=low + + * Add debian/watch file + + -- Roland Dreier Wed, 12 Mar 2008 10:40:19 -0700 + +libmlx4 (1.0-1) unstable; urgency=low + + * Initial release. (Closes: #456355) + + -- Roland Dreier Fri, 14 Dec 2007 09:51:39 -0800 diff --git a/contrib/ofed/libmlx4/debian/compat b/contrib/ofed/libmlx4/debian/compat new file mode 100644 index 000000000000..7ed6ff82de6b --- /dev/null +++ b/contrib/ofed/libmlx4/debian/compat @@ -0,0 +1 @@ +5 diff --git a/contrib/ofed/libmlx4/debian/control.in b/contrib/ofed/libmlx4/debian/control.in new file mode 100644 index 000000000000..2cafc8515250 --- /dev/null +++ b/contrib/ofed/libmlx4/debian/control.in @@ -0,0 +1,47 @@ +Source: libmlx4 +Priority: extra +Maintainer: Roland Dreier +Build-Depends: @cdbs@, libibverbs-dev (>= 1.0) +Standards-Version: 3.7.3 +Section: libs +Homepage: http://www.openfabrics.org/ + +Package: libmlx4-1 +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: A userspace driver for Mellanox ConnectX InfiniBand HCAs + libmlx4 is a device-specific driver for Mellanox ConnectX InfiniBand + host channel adapters (HCAs) for the libibverbs library. This allows + userspace processes to access Mellanox HCA hardware directly with + low latency and low overhead. + . + This package contains the loadable plug-in. + +Package: libmlx4-dev +Section: libdevel +Architecture: any +Depends: ${misc:Depends}, libmlx4-1 (= ${binary:Version}) +Description: Development files for the libmlx4 driver + libmlx4 is a device-specific driver for Mellanox ConnectX InfiniBand + host channel adapters (HCAs) for the libibverbs library. This allows + userspace processes to access Mellanox HCA hardware directly with + low latency and low overhead. + . + This package contains static versions of libmlx4 that may be linked + directly to an application, which may be useful for debugging. + +Package: libmlx4-1-dbg +Section: libdevel +Priority: extra +Architecture: any +Depends: ${misc:Depends}, libmlx4-1 (= ${binary:Version}) +Description: Debugging symbols for the libmlx4 driver + libmlx4 is a device-specific driver for Mellanox ConnectX InfiniBand + host channel adapters (HCAs) for the libibverbs library. This allows + userspace processes to access Mellanox HCA hardware directly with + low latency and low overhead. + . + This package contains the debugging symbols associated with + libmlx4-1. They will automatically be used by gdb for debugging + libmlx4-related issues. diff --git a/contrib/ofed/libmlx4/debian/copyright b/contrib/ofed/libmlx4/debian/copyright new file mode 100644 index 000000000000..db07a25fcbf1 --- /dev/null +++ b/contrib/ofed/libmlx4/debian/copyright @@ -0,0 +1,43 @@ +Initial Debianization: +This package was debianized by Roland Dreier on +Fri, 6 Apr 2007 10:04:57 -0700 + +Source: +It was downloaded from the OpenFabrics web site at + + +Authors: + Roland Dreier + +Portions are copyrighted by: + * Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved. + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + +libmlx4 is licensed under a choice of one of two licenses. You may +choose to be licensed under the terms of the GNU General Public +License (GPL) Version 2, available from the file +/usr/share/common-licenses/GPL-2 on your Debian system, or the +OpenIB.org BSD license below: + + Redistribution and use in source and binary forms, with or + without modification, are permitted provided that the following + conditions are met: + + - Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + - Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/contrib/ofed/libmlx4/debian/libmlx4-1.install b/contrib/ofed/libmlx4/debian/libmlx4-1.install new file mode 100644 index 000000000000..a64e17db7794 --- /dev/null +++ b/contrib/ofed/libmlx4/debian/libmlx4-1.install @@ -0,0 +1,2 @@ +usr/lib/libmlx4-rdmav2.so +etc/libibverbs.d/mlx4.driver diff --git a/contrib/ofed/libmlx4/debian/libmlx4-dev.install b/contrib/ofed/libmlx4/debian/libmlx4-dev.install new file mode 100644 index 000000000000..4e1f3feb59ab --- /dev/null +++ b/contrib/ofed/libmlx4/debian/libmlx4-dev.install @@ -0,0 +1 @@ +usr/lib/libmlx4.{a,la} diff --git a/contrib/ofed/libmlx4/debian/rules b/contrib/ofed/libmlx4/debian/rules new file mode 100755 index 000000000000..3e70bc38f907 --- /dev/null +++ b/contrib/ofed/libmlx4/debian/rules @@ -0,0 +1,8 @@ +#!/usr/bin/make -f +# -*- mode: makefile; coding: utf-8 -*- + +DEB_DH_INSTALL_SOURCEDIR := debian/tmp +DEB_AUTO_UPDATE_LIBTOOL := post + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/autotools.mk diff --git a/contrib/ofed/libmlx4/debian/watch b/contrib/ofed/libmlx4/debian/watch new file mode 100644 index 000000000000..06bae51d7eb3 --- /dev/null +++ b/contrib/ofed/libmlx4/debian/watch @@ -0,0 +1,3 @@ +version=3 +opts="uversionmangle=s/-rc/~rc/" \ + http://www.openfabrics.org/downloads/mlx4/libmlx4-(.+)\.tar\.gz diff --git a/contrib/ofed/libmlx4/fixes/add_supported_devices.patch b/contrib/ofed/libmlx4/fixes/add_supported_devices.patch new file mode 100644 index 000000000000..85b4a663f6be --- /dev/null +++ b/contrib/ofed/libmlx4/fixes/add_supported_devices.patch @@ -0,0 +1,35 @@ +Index: libmlx4/src/mlx4.c +=================================================================== +--- libmlx4.orig/src/mlx4.c 2010-02-08 15:43:35.000000000 +0200 ++++ libmlx4/src/mlx4.c 2010-02-08 15:43:53.000000000 +0200 +@@ -66,6 +66,30 @@ struct { + HCA(MELLANOX, 0x6354), /* MT25408 "Hermon" QDR */ + HCA(MELLANOX, 0x6732), /* MT25408 "Hermon" DDR PCIe gen2 */ + HCA(MELLANOX, 0x673c), /* MT25408 "Hermon" QDR PCIe gen2 */ ++ HCA(MELLANOX, 0x6368), /* MT25448 [ConnectX EN 10GigE, PCIe 2.0 2.5GT/s] */ ++ HCA(MELLANOX, 0x6750), /* MT26448 [ConnectX EN 10GigE, PCIe 2.0 5GT/s] */ ++ HCA(MELLANOX, 0x6372), /* MT25408 [ConnectX EN 10GigE 10GBaseT, PCIe 2.0 2.5GT/s] */ ++ HCA(MELLANOX, 0x675a), /* MT25408 [ConnectX EN 10GigE 10GBaseT, PCIe Gen2 5GT/s] */ ++ HCA(MELLANOX, 0x6764), /* MT26468 [ConnectX EN 10GigE, PCIe 2.0 5GT/s] */ ++ HCA(MELLANOX, 0x6746), /* MT26438 ConnectX VPI PCIe 2.0 5GT/s - IB QDR / 10GigE Virt+ */ ++ HCA(MELLANOX, 0x676e), /* MT26478 ConnectX EN 40GigE PCIe 2.0 5GT/s */ ++ HCA(MELLANOX, 0x6778), /* MT26488 ConnectX VPI PCIe 2.0 5GT/s - IB DDR / 10GigE Virt+ */ ++ HCA(MELLANOX, 0x1000), ++ HCA(MELLANOX, 0x1001), ++ HCA(MELLANOX, 0x1002), ++ HCA(MELLANOX, 0x1003), ++ HCA(MELLANOX, 0x1004), ++ HCA(MELLANOX, 0x1005), ++ HCA(MELLANOX, 0x1006), ++ HCA(MELLANOX, 0x1007), ++ HCA(MELLANOX, 0x1008), ++ HCA(MELLANOX, 0x1009), ++ HCA(MELLANOX, 0x100a), ++ HCA(MELLANOX, 0x100b), ++ HCA(MELLANOX, 0x100c), ++ HCA(MELLANOX, 0x100d), ++ HCA(MELLANOX, 0x100e), ++ HCA(MELLANOX, 0x100f), + }; + + #ifdef HAVE_IBV_MORE_OPS diff --git a/contrib/ofed/libmlx4/fixes/fix_inline_size.patch b/contrib/ofed/libmlx4/fixes/fix_inline_size.patch new file mode 100644 index 000000000000..e01abb2999fe --- /dev/null +++ b/contrib/ofed/libmlx4/fixes/fix_inline_size.patch @@ -0,0 +1,126 @@ +From 6f9c7b5c83a832884b3e47a6ce52145991073586 Mon Sep 17 00:00:00 2001 +From: Eli Cohen +Date: Sun, 19 Sep 2010 11:28:40 +0200 +Subject: [PATCH] libmlx4: fix possible inline size + +The current driver checks required inline size by making sure it does not +exceed 1024. This is wrong since the whole WQE is limited to 1008 bytes. +Moreover, a more careful claculation is required to avoid cases where the +application requests inline support in a certain size that when used later +could cause connections to stall due to bad WQEs. This patch takes into account +the size of the WQE, the segements used to create a WQE and the overhead +incured by the inline segments themselves. + +Signed-off-by: Eli Cohen +--- + src/verbs.c | 45 ++++++++++++++++++++++++++++++++++++++++----- + 1 files changed, 40 insertions(+), 5 deletions(-) + +Index: libmlx4/src/verbs.c +=================================================================== +--- libmlx4.orig/src/verbs.c 2010-09-29 11:10:17.691587848 +0200 ++++ libmlx4/src/verbs.c 2010-09-29 11:16:11.031586721 +0200 +@@ -402,6 +402,44 @@ int mlx4_destroy_srq(struct ibv_srq *ibs + return 0; + } + ++static int verify_sizes(struct ibv_qp_init_attr *attr, struct mlx4_context *context) ++{ ++ int size; ++ int nsegs; ++ ++ if (attr->cap.max_send_wr > context->max_qp_wr || ++ attr->cap.max_recv_wr > context->max_qp_wr || ++ attr->cap.max_send_sge > context->max_sge || ++ attr->cap.max_recv_sge > context->max_sge) ++ return -1; ++ ++ if (attr->cap.max_inline_data) { ++ nsegs = num_inline_segs(attr->cap.max_inline_data, attr->qp_type); ++ size = MLX4_MAX_WQE_SIZE - nsegs * sizeof (struct mlx4_wqe_inline_seg); ++ switch (attr->qp_type) { ++ case IBV_QPT_UD: ++ size -= (sizeof (struct mlx4_wqe_ctrl_seg) + ++ sizeof (struct mlx4_wqe_datagram_seg)); ++ break; ++ ++ case IBV_QPT_RC: ++ case IBV_QPT_UC: ++ case IBV_QPT_XRC: ++ size -= (sizeof (struct mlx4_wqe_ctrl_seg) + ++ sizeof (struct mlx4_wqe_raddr_seg)); ++ break; ++ ++ default: ++ return 0; ++ } ++ ++ if (attr->cap.max_inline_data > size) ++ return -1; ++ } ++ ++ return 0; ++} ++ + struct ibv_qp *mlx4_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *attr) + { + struct mlx4_create_qp cmd; +@@ -412,11 +450,7 @@ struct ibv_qp *mlx4_create_qp(struct ibv + + + /* Sanity check QP size before proceeding */ +- if (attr->cap.max_send_wr > context->max_qp_wr || +- attr->cap.max_recv_wr > context->max_qp_wr || +- attr->cap.max_send_sge > context->max_sge || +- attr->cap.max_recv_sge > context->max_sge || +- attr->cap.max_inline_data > 1024) ++ if (verify_sizes(attr, context)) + return NULL; + + qp = malloc(sizeof *qp); +Index: libmlx4/src/mlx4.h +=================================================================== +--- libmlx4.orig/src/mlx4.h 2010-09-29 11:10:17.691587848 +0200 ++++ libmlx4/src/mlx4.h 2010-09-29 11:11:35.559586971 +0200 +@@ -159,6 +159,10 @@ enum { + MLX4_CQE_OPCODE_RESIZE = 0x16, + }; + ++enum { ++ MLX4_MAX_WQE_SIZE = 1008 ++}; ++ + struct mlx4_device { + struct ibv_device ibv_dev; + int page_size; +@@ -410,6 +414,7 @@ int mlx4_post_recv(struct ibv_qp *ibqp, + struct ibv_recv_wr **bad_wr); + void mlx4_calc_sq_wqe_size(struct ibv_qp_cap *cap, enum ibv_qp_type type, + struct mlx4_qp *qp); ++int num_inline_segs(int data, enum ibv_qp_type type); + int mlx4_alloc_qp_buf(struct ibv_pd *pd, struct ibv_qp_cap *cap, + enum ibv_qp_type type, struct mlx4_qp *qp); + void mlx4_set_sq_sizes(struct mlx4_qp *qp, struct ibv_qp_cap *cap, +Index: libmlx4/src/qp.c +=================================================================== +--- libmlx4.orig/src/qp.c 2010-09-29 11:10:17.691587848 +0200 ++++ libmlx4/src/qp.c 2010-09-29 11:12:14.931587492 +0200 +@@ -505,7 +505,7 @@ out: + return ret; + } + +-static int num_inline_segs(int data, enum ibv_qp_type type) ++int num_inline_segs(int data, enum ibv_qp_type type) + { + /* + * Inline data segments are not allowed to cross 64 byte +@@ -634,7 +634,8 @@ void mlx4_set_sq_sizes(struct mlx4_qp *q + int wqe_size; + struct mlx4_context *ctx = to_mctx(qp->ibv_qp.context); + +- wqe_size = (1 << qp->sq.wqe_shift) - sizeof (struct mlx4_wqe_ctrl_seg); ++ wqe_size = min((1 << qp->sq.wqe_shift), MLX4_MAX_WQE_SIZE) - ++ sizeof (struct mlx4_wqe_ctrl_seg); + switch (type) { + case IBV_QPT_UD: + wqe_size -= sizeof (struct mlx4_wqe_datagram_seg); diff --git a/contrib/ofed/libmlx4/fixes/lim_qp_resources.patch b/contrib/ofed/libmlx4/fixes/lim_qp_resources.patch new file mode 100644 index 000000000000..b9ce37e157ce --- /dev/null +++ b/contrib/ofed/libmlx4/fixes/lim_qp_resources.patch @@ -0,0 +1,72 @@ +Limit qp resources accepted for ibv_create_qp() + +to the limits reported in ib_query_device(). +Make sure that the limits returned to the caller following +qp creation also lie within the reported device limits. +(OFED 1.3 libmlx4 commit b612592e2c43472895ccc495183aa63980d8e7a5) + +Signed-off-by: Jack Morgenstein + +Index: libmlx4/src/qp.c +=================================================================== +--- libmlx4.orig/src/qp.c 2008-06-04 08:24:45.000000000 +0300 ++++ libmlx4/src/qp.c 2008-06-04 08:24:49.000000000 +0300 +@@ -619,6 +619,7 @@ void mlx4_set_sq_sizes(struct mlx4_qp *q + enum ibv_qp_type type) + { + int wqe_size; ++ struct mlx4_context *ctx = to_mctx(qp->ibv_qp.context); + + wqe_size = (1 << qp->sq.wqe_shift) - sizeof (struct mlx4_wqe_ctrl_seg); + switch (type) { +@@ -636,8 +637,9 @@ void mlx4_set_sq_sizes(struct mlx4_qp *q + } + + qp->sq.max_gs = wqe_size / sizeof (struct mlx4_wqe_data_seg); +- cap->max_send_sge = qp->sq.max_gs; +- qp->sq.max_post = qp->sq.wqe_cnt - qp->sq_spare_wqes; ++ cap->max_send_sge = min(ctx->max_sge, qp->sq.max_gs); ++ qp->sq.max_post = min(ctx->max_qp_wr, ++ qp->sq.wqe_cnt - qp->sq_spare_wqes); + cap->max_send_wr = qp->sq.max_post; + + /* +Index: libmlx4/src/verbs.c +=================================================================== +--- libmlx4.orig/src/verbs.c 2008-06-04 08:24:45.000000000 +0300 ++++ libmlx4/src/verbs.c 2008-06-04 08:24:49.000000000 +0300 +@@ -390,12 +390,14 @@ struct ibv_qp *mlx4_create_qp(struct ibv + struct ibv_create_qp_resp resp; + struct mlx4_qp *qp; + int ret; ++ struct mlx4_context *context = to_mctx(pd->context); ++ + + /* Sanity check QP size before proceeding */ +- if (attr->cap.max_send_wr > 65536 || +- attr->cap.max_recv_wr > 65536 || +- attr->cap.max_send_sge > 64 || +- attr->cap.max_recv_sge > 64 || ++ if (attr->cap.max_send_wr > context->max_qp_wr || ++ attr->cap.max_recv_wr > context->max_qp_wr || ++ attr->cap.max_send_sge > context->max_sge || ++ attr->cap.max_recv_sge > context->max_sge || + attr->cap.max_inline_data > 1024) + return NULL; + +@@ -461,8 +463,14 @@ struct ibv_qp *mlx4_create_qp(struct ibv + goto err_destroy; + pthread_mutex_unlock(&to_mctx(pd->context)->qp_table_mutex); + +- qp->rq.wqe_cnt = qp->rq.max_post = attr->cap.max_recv_wr; ++ qp->rq.wqe_cnt = attr->cap.max_recv_wr; + qp->rq.max_gs = attr->cap.max_recv_sge; ++ ++ /* adjust rq maxima to not exceed reported device maxima */ ++ attr->cap.max_recv_wr = min(context->max_qp_wr, attr->cap.max_recv_wr); ++ attr->cap.max_recv_sge = min(context->max_sge, attr->cap.max_recv_sge); ++ ++ qp->rq.max_post = attr->cap.max_recv_wr; + mlx4_set_sq_sizes(qp, &attr->cap, attr->qp_type); + + qp->doorbell_qpn = htonl(qp->ibv_qp.qp_num << 8); diff --git a/contrib/ofed/libmlx4/fixes/post_rcv_end_of_sg.patch b/contrib/ofed/libmlx4/fixes/post_rcv_end_of_sg.patch new file mode 100644 index 000000000000..aa11d9d4fee1 --- /dev/null +++ b/contrib/ofed/libmlx4/fixes/post_rcv_end_of_sg.patch @@ -0,0 +1,29 @@ +As in libmthca, need to initialize SRQ WQE scatter entries to the +invalid lkey at work queue creation time. + +Signed-off-by: Jack Morgenstein + +Index: libmlx4/src/srq.c +=================================================================== +--- libmlx4.orig/src/srq.c 2009-12-09 15:08:52.000000000 +0200 ++++ libmlx4/src/srq.c 2009-12-09 18:44:32.000000000 +0200 +@@ -128,6 +128,7 @@ int mlx4_alloc_srq_buf(struct ibv_pd *pd + struct mlx4_srq *srq) + { + struct mlx4_wqe_srq_next_seg *next; ++ struct mlx4_wqe_data_seg *scatter; + int size; + int buf_size; + int i; +@@ -160,6 +161,11 @@ int mlx4_alloc_srq_buf(struct ibv_pd *pd + for (i = 0; i < srq->max; ++i) { + next = get_wqe(srq, i); + next->next_wqe_index = htons((i + 1) & (srq->max - 1)); ++ ++ for (scatter = (void *) (next + 1); ++ (void *) scatter < (void *) next + (1 << srq->wqe_shift); ++ ++scatter) ++ scatter->lkey = htonl(MLX4_INVALID_LKEY); + } + + srq->head = 0; diff --git a/contrib/ofed/libmlx4/fixes/rocee_add_support.patch b/contrib/ofed/libmlx4/fixes/rocee_add_support.patch new file mode 100644 index 000000000000..017b075d639a --- /dev/null +++ b/contrib/ofed/libmlx4/fixes/rocee_add_support.patch @@ -0,0 +1,145 @@ +[PATCHv7 1/2] libmlx4: Add RoCEE support + +Modify libmlx4 to support RoCEE. The change involves retrieving the MAC address +of a port based on its GID through a new system call, ibv_cmd_get_mac(), and +embedding the MAC in the address vector representation of mlx4. + +Signed-off-by: Eli Cohen +--- + src/mlx4.h | 3 +++ + src/qp.c | 2 ++ + src/verbs.c | 29 +++++++++++++++++++++++++++++ + src/wqe.h | 3 ++- + 4 files changed, 36 insertions(+), 1 deletions(-) + +Index: libmlx4/src/mlx4.h +=================================================================== +--- libmlx4.orig/src/mlx4.h 2010-08-23 08:07:47.599964446 +0300 ++++ libmlx4/src/mlx4.h 2010-08-23 08:08:32.039462057 +0300 +@@ -277,11 +277,15 @@ struct mlx4_av { + uint8_t hop_limit; + uint32_t sl_tclass_flowlabel; + uint8_t dgid[16]; ++ uint8_t mac[8]; + }; + + struct mlx4_ah { + struct ibv_ah ibv_ah; + struct mlx4_av av; ++ uint16_t vlan; ++ uint8_t mac[6]; ++ uint8_t tagged; + }; + + struct mlx4_xrc_domain { +Index: libmlx4/src/qp.c +=================================================================== +--- libmlx4.orig/src/qp.c 2010-08-23 08:07:46.283963844 +0300 ++++ libmlx4/src/qp.c 2010-08-23 08:08:32.039462057 +0300 +@@ -143,6 +143,8 @@ static void set_datagram_seg(struct mlx4 + memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av)); + dseg->dqpn = htonl(wr->wr.ud.remote_qpn); + dseg->qkey = htonl(wr->wr.ud.remote_qkey); ++ dseg->vlan = htons(to_mah(wr->wr.ud.ah)->vlan); ++ memcpy(dseg->mac, to_mah(wr->wr.ud.ah)->mac, 6); + } + + static void __set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ibv_sge *sg) +@@ -284,6 +286,11 @@ int mlx4_post_send(struct ibv_qp *ibqp, + set_datagram_seg(wqe, wr); + wqe += sizeof (struct mlx4_wqe_datagram_seg); + size += sizeof (struct mlx4_wqe_datagram_seg) / 16; ++ if (to_mah(wr->wr.ud.ah)->tagged) { ++ ctrl->ins_vlan = 1 << 6; ++ ctrl->vlan_tag = htons(to_mah(wr->wr.ud.ah)->vlan); ++ } ++ + break; + + default: +@@ -396,7 +403,7 @@ out: + + if (nreq == 1 && inl && size > 1 && size < ctx->bf_buf_size / 16) { + ctrl->owner_opcode |= htonl((qp->sq.head & 0xffff) << 8); +- *(uint32_t *) ctrl->reserved |= qp->doorbell_qpn; ++ *(uint32_t *) (&ctrl->vlan_tag) |= qp->doorbell_qpn; + /* + * Make sure that descriptor is written to memory + * before writing to BlueFlame page. +Index: libmlx4/src/verbs.c +=================================================================== +--- libmlx4.orig/src/verbs.c 2010-08-23 08:07:48.451964305 +0300 ++++ libmlx4/src/verbs.c 2010-08-23 08:08:32.039462057 +0300 +@@ -643,12 +643,14 @@ int mlx4_destroy_qp(struct ibv_qp *ibqp) + struct ibv_ah *mlx4_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr) + { + struct mlx4_ah *ah; ++ struct ibv_port_attr port_attr; ++ uint8_t is_mcast; + + ah = malloc(sizeof *ah); + if (!ah) + return NULL; + +- memset(&ah->av, 0, sizeof ah->av); ++ memset(ah, 0, sizeof *ah); + + ah->av.port_pd = htonl(to_mpd(pd)->pdn | (attr->port_num << 24)); + ah->av.g_slid = attr->src_path_bits; +@@ -668,7 +670,32 @@ struct ibv_ah *mlx4_create_ah(struct ibv + memcpy(ah->av.dgid, attr->grh.dgid.raw, 16); + } + ++ if (ibv_query_port(pd->context, attr->port_num, &port_attr)) ++ goto err; ++ ++ if (port_attr.link_layer == IBV_LINK_LAYER_ETHERNET) { ++ if (ibv_resolve_eth_gid(pd, attr->port_num, ++ (union ibv_gid *)ah->av.dgid, ++ attr->grh.sgid_index, ++ ah->mac, &ah->vlan, ++ &ah->tagged, &is_mcast)) ++ goto err; ++ ++ if (is_mcast) { ++ ah->av.dlid = htons(0xc000); ++ ah->av.port_pd |= htonl(1 << 31); ++ } ++ if (ah->tagged) { ++ ah->av.port_pd |= htonl(1 << 29); ++ ah->vlan |= (attr->sl & 7) << 13; ++ } ++ } ++ ++ + return &ah->ibv_ah; ++err: ++ free(ah); ++ return NULL; + } + + int mlx4_destroy_ah(struct ibv_ah *ah) +Index: libmlx4/src/wqe.h +=================================================================== +--- libmlx4.orig/src/wqe.h 2010-08-23 08:07:46.287962570 +0300 ++++ libmlx4/src/wqe.h 2010-08-23 08:07:50.231963413 +0300 +@@ -54,7 +54,8 @@ enum { + + struct mlx4_wqe_ctrl_seg { + uint32_t owner_opcode; +- uint8_t reserved[3]; ++ uint16_t vlan_tag; ++ uint8_t ins_vlan; + uint8_t fence_size; + /* + * High 24 bits are SRC remote buffer; low 8 bits are flags: +@@ -78,7 +79,8 @@ struct mlx4_wqe_datagram_seg { + uint32_t av[8]; + uint32_t dqpn; + uint32_t qkey; +- uint32_t reserved[2]; ++ uint16_t vlan; ++ uint8_t mac[6]; + }; + + struct mlx4_wqe_data_seg { diff --git a/contrib/ofed/libmlx4/fixes/series b/contrib/ofed/libmlx4/fixes/series new file mode 100644 index 000000000000..83516ec4b04b --- /dev/null +++ b/contrib/ofed/libmlx4/fixes/series @@ -0,0 +1,10 @@ +userspace_dev_lims.patch +lim_qp_resources.patch +xrc_consolidated_v2.patch +xrc_rcv_qp_v2.patch +xrc_fix_close_domain.patch +xrc_kernel_user_mismatch.patch +rocee_add_support.patch +add_supported_devices.patch +post_rcv_end_of_sg.patch +fix_inline_size.patch diff --git a/contrib/ofed/libmlx4/fixes/userspace_dev_lims.patch b/contrib/ofed/libmlx4/fixes/userspace_dev_lims.patch new file mode 100644 index 000000000000..07cf6388259c --- /dev/null +++ b/contrib/ofed/libmlx4/fixes/userspace_dev_lims.patch @@ -0,0 +1,79 @@ +When creating a new user context, query device for + +various limits, for use in sanity checks and +other resource limitation needs. + +Passing needed info back to userspace in this manner is +preferable to breaking the ABI. +(OFED 1.3 commit 43ca5e9225658b22ef8180bf0eff4faa7f5940cf) + +Signed-off-by: Jack Morgenstein + +Index: libmlx4/src/mlx4.c +=================================================================== +--- libmlx4.orig/src/mlx4.c 2008-06-03 15:45:18.000000000 +0300 ++++ libmlx4/src/mlx4.c 2008-06-04 08:24:10.000000000 +0300 +@@ -104,6 +104,7 @@ static struct ibv_context *mlx4_alloc_co + struct ibv_get_context cmd; + struct mlx4_alloc_ucontext_resp resp; + int i; ++ struct ibv_device_attr dev_attrs; + + context = calloc(1, sizeof *context); + if (!context) +@@ -156,8 +157,20 @@ static struct ibv_context *mlx4_alloc_co + + context->ibv_ctx.ops = mlx4_ctx_ops; + ++ if (mlx4_query_device(&context->ibv_ctx, &dev_attrs)) ++ goto query_free; ++ ++ context->max_qp_wr = dev_attrs.max_qp_wr; ++ context->max_sge = dev_attrs.max_sge; ++ context->max_cqe = dev_attrs.max_cqe; ++ + return &context->ibv_ctx; + ++query_free: ++ munmap(context->uar, to_mdev(ibdev)->page_size); ++ if (context->bf_page) ++ munmap(context->bf_page, to_mdev(ibdev)->page_size); ++ + err_free: + free(context); + return NULL; +Index: libmlx4/src/mlx4.h +=================================================================== +--- libmlx4.orig/src/mlx4.h 2008-06-03 15:45:18.000000000 +0300 ++++ libmlx4/src/mlx4.h 2008-06-04 08:24:10.000000000 +0300 +@@ -83,6 +83,20 @@ + + #define PFX "mlx4: " + ++#ifndef max ++#define max(a,b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a > _b ? _a : _b; }) ++#endif ++ ++#ifndef min ++#define min(a,b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a < _b ? _a : _b; }) ++#endif ++ + enum { + MLX4_CQ_ENTRY_SIZE = 0x20 + }; +@@ -156,6 +170,9 @@ struct mlx4_context { + int num_qps; + int qp_table_shift; + int qp_table_mask; ++ int max_qp_wr; ++ int max_sge; ++ int max_cqe; + + struct mlx4_db_page *db_list[MLX4_NUM_DB_TYPE]; + pthread_mutex_t db_list_mutex; diff --git a/contrib/ofed/libmlx4/fixes/xrc_consolidated_v2.patch b/contrib/ofed/libmlx4/fixes/xrc_consolidated_v2.patch new file mode 100644 index 000000000000..9fe6c4386063 --- /dev/null +++ b/contrib/ofed/libmlx4/fixes/xrc_consolidated_v2.patch @@ -0,0 +1,620 @@ +XRC implementation, consolidated (version 2): + +xrc ops were moved to their own structure at the end of +struct ibv_context (to preserve binary compatibility). + +Check for ibv_context.xrc_ops member via AC_CHECK_MEMBER + +XRC QPs have MSB set in qp number, for identification in +completion handling. + +Various bug fixes. +(OFED 1.3 commit 39fe7f47e8fc07f356098df048d00740ba585fc5) + +Signed-off-by: Jack Morgenstein +--- +V2: +1. checkpatch.pl cleanup +2. Changed xrc_ops to more ops +3. Check for xrc verbs in ibv_more_ops via AC_CHECK_MEMBER + +diff --git a/configure.in b/configure.in +index 25f27f7..46a3a64 100644 +--- a/configure.in ++++ b/configure.in +@@ -42,6 +42,12 @@ AC_CHECK_HEADER(valgrind/memcheck.h, + dnl Checks for typedefs, structures, and compiler characteristics. + AC_C_CONST + AC_CHECK_SIZEOF(long) ++AC_CHECK_MEMBER(struct ibv_context.more_ops, ++ [AC_DEFINE([HAVE_IBV_MORE_OPS], 1, [Define to 1 if more_ops is a member of ibv_context])],, ++ [#include ]) ++AC_CHECK_MEMBER(struct ibv_more_ops.create_xrc_srq, ++ [AC_DEFINE([HAVE_IBV_XRC_OPS], 1, [Define to 1 if have xrc ops])],, ++ [#include ]) + + dnl Checks for library functions + AC_CHECK_FUNC(ibv_read_sysfs_file, [], +diff --git a/src/cq.c b/src/cq.c +index 68e16e9..c598b87 100644 +--- a/src/cq.c ++++ b/src/cq.c +@@ -194,8 +194,9 @@ static int mlx4_poll_one(struct mlx4_cq *cq, + { + struct mlx4_wq *wq; + struct mlx4_cqe *cqe; +- struct mlx4_srq *srq; ++ struct mlx4_srq *srq = NULL; + uint32_t qpn; ++ uint32_t srqn; + uint32_t g_mlpath_rqpn; + uint16_t wqe_index; + int is_error; +@@ -221,20 +223,29 @@ static int mlx4_poll_one(struct mlx4_cq *cq, + is_error = (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == + MLX4_CQE_OPCODE_ERROR; + +- if (!*cur_qp || +- (ntohl(cqe->my_qpn) & 0xffffff) != (*cur_qp)->ibv_qp.qp_num) { ++ if (qpn & MLX4_XRC_QPN_BIT && !is_send) { ++ srqn = ntohl(cqe->g_mlpath_rqpn) & 0xffffff; ++ /* ++ * We do not have to take the XRC SRQ table lock here, ++ * because CQs will be locked while XRC SRQs are removed ++ * from the table. ++ */ ++ srq = mlx4_find_xrc_srq(to_mctx(cq->ibv_cq.context), srqn); ++ if (!srq) ++ return CQ_POLL_ERR; ++ } else if (!*cur_qp || (qpn & 0xffffff) != (*cur_qp)->ibv_qp.qp_num) { + /* + * We do not have to take the QP table lock here, + * because CQs will be locked while QPs are removed + * from the table. + */ + *cur_qp = mlx4_find_qp(to_mctx(cq->ibv_cq.context), +- ntohl(cqe->my_qpn) & 0xffffff); ++ qpn & 0xffffff); + if (!*cur_qp) + return CQ_POLL_ERR; + } + +- wc->qp_num = (*cur_qp)->ibv_qp.qp_num; ++ wc->qp_num = qpn & 0xffffff; + + if (is_send) { + wq = &(*cur_qp)->sq; +@@ -242,6 +254,10 @@ static int mlx4_poll_one(struct mlx4_cq *cq, + wq->tail += (uint16_t) (wqe_index - (uint16_t) wq->tail); + wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; + ++wq->tail; ++ } else if (srq) { ++ wqe_index = htons(cqe->wqe_index); ++ wc->wr_id = srq->wrid[wqe_index]; ++ mlx4_free_srq_wqe(srq, wqe_index); + } else if ((*cur_qp)->ibv_qp.srq) { + srq = to_msrq((*cur_qp)->ibv_qp.srq); + wqe_index = htons(cqe->wqe_index); +@@ -387,6 +403,10 @@ void __mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn, struct mlx4_srq *srq) + uint32_t prod_index; + uint8_t owner_bit; + int nfreed = 0; ++ int is_xrc_srq = 0; ++ ++ if (srq && srq->ibv_srq.xrc_cq) ++ is_xrc_srq = 1; + + /* + * First we need to find the current producer index, so we +@@ -405,7 +425,12 @@ void __mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn, struct mlx4_srq *srq) + */ + while ((int) --prod_index - (int) cq->cons_index >= 0) { + cqe = get_cqe(cq, prod_index & cq->ibv_cq.cqe); +- if ((ntohl(cqe->my_qpn) & 0xffffff) == qpn) { ++ if (is_xrc_srq && ++ (ntohl(cqe->g_mlpath_rqpn & 0xffffff) == srq->srqn) && ++ !(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK)) { ++ mlx4_free_srq_wqe(srq, ntohs(cqe->wqe_index)); ++ ++nfreed; ++ } else if ((ntohl(cqe->my_qpn) & 0xffffff) == qpn) { + if (srq && !(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK)) + mlx4_free_srq_wqe(srq, ntohs(cqe->wqe_index)); + ++nfreed; +diff --git a/src/mlx4-abi.h b/src/mlx4-abi.h +index 20a40c9..1b1253c 100644 +--- a/src/mlx4-abi.h ++++ b/src/mlx4-abi.h +@@ -68,6 +68,14 @@ struct mlx4_resize_cq { + __u64 buf_addr; + }; + ++#ifdef HAVE_IBV_XRC_OPS ++struct mlx4_create_xrc_srq { ++ struct ibv_create_xrc_srq ibv_cmd; ++ __u64 buf_addr; ++ __u64 db_addr; ++}; ++#endif ++ + struct mlx4_create_srq { + struct ibv_create_srq ibv_cmd; + __u64 buf_addr; +@@ -90,4 +98,12 @@ struct mlx4_create_qp { + __u8 reserved[5]; + }; + ++#ifdef HAVE_IBV_XRC_OPS ++struct mlx4_open_xrc_domain_resp { ++ struct ibv_open_xrc_domain_resp ibv_resp; ++ __u32 xrcdn; ++ __u32 reserved; ++}; ++#endif ++ + #endif /* MLX4_ABI_H */ +diff --git a/src/mlx4.c b/src/mlx4.c +index 671e849..27ca75d 100644 +--- a/src/mlx4.c ++++ b/src/mlx4.c +@@ -68,6 +68,16 @@ struct { + HCA(MELLANOX, 0x673c), /* MT25408 "Hermon" QDR PCIe gen2 */ + }; + ++#ifdef HAVE_IBV_MORE_OPS ++static struct ibv_more_ops mlx4_more_ops = { ++#ifdef HAVE_IBV_XRC_OPS ++ .create_xrc_srq = mlx4_create_xrc_srq, ++ .open_xrc_domain = mlx4_open_xrc_domain, ++ .close_xrc_domain = mlx4_close_xrc_domain, ++#endif ++}; ++#endif ++ + static struct ibv_context_ops mlx4_ctx_ops = { + .query_device = mlx4_query_device, + .query_port = mlx4_query_port, +@@ -124,6 +134,15 @@ static struct ibv_context *mlx4_alloc_context(struct ibv_device *ibdev, int cmd_ + for (i = 0; i < MLX4_QP_TABLE_SIZE; ++i) + context->qp_table[i].refcnt = 0; + ++ context->num_xrc_srqs = resp.qp_tab_size; ++ context->xrc_srq_table_shift = ffs(context->num_xrc_srqs) - 1 ++ - MLX4_XRC_SRQ_TABLE_BITS; ++ context->xrc_srq_table_mask = (1 << context->xrc_srq_table_shift) - 1; ++ ++ pthread_mutex_init(&context->xrc_srq_table_mutex, NULL); ++ for (i = 0; i < MLX4_XRC_SRQ_TABLE_SIZE; ++i) ++ context->xrc_srq_table[i].refcnt = 0; ++ + for (i = 0; i < MLX4_NUM_DB_TYPE; ++i) + context->db_list[i] = NULL; + +@@ -156,6 +175,9 @@ static struct ibv_context *mlx4_alloc_context(struct ibv_device *ibdev, int cmd_ + pthread_spin_init(&context->uar_lock, PTHREAD_PROCESS_PRIVATE); + + context->ibv_ctx.ops = mlx4_ctx_ops; ++#ifdef HAVE_IBV_XRC_OPS ++ context->ibv_ctx.more_ops = &mlx4_more_ops; ++#endif + + if (mlx4_query_device(&context->ibv_ctx, &dev_attrs)) + goto query_free; +diff --git a/src/mlx4.h b/src/mlx4.h +index 8643d8f..3eadb98 100644 +--- a/src/mlx4.h ++++ b/src/mlx4.h +@@ -79,6 +79,11 @@ + + #endif + ++#ifndef HAVE_IBV_MORE_OPS ++#undef HAVE_IBV_XRC_OPS ++#undef HAVE_IBV_CREATE_QP_EXP ++#endif ++ + #define HIDDEN __attribute__((visibility ("hidden"))) + + #define PFX "mlx4: " +@@ -111,6 +116,16 @@ enum { + MLX4_QP_TABLE_MASK = MLX4_QP_TABLE_SIZE - 1 + }; + ++enum { ++ MLX4_XRC_SRQ_TABLE_BITS = 8, ++ MLX4_XRC_SRQ_TABLE_SIZE = 1 << MLX4_XRC_SRQ_TABLE_BITS, ++ MLX4_XRC_SRQ_TABLE_MASK = MLX4_XRC_SRQ_TABLE_SIZE - 1 ++}; ++ ++enum { ++ MLX4_XRC_QPN_BIT = (1 << 23) ++}; ++ + enum mlx4_db_type { + MLX4_DB_TYPE_CQ, + MLX4_DB_TYPE_RQ, +@@ -174,6 +189,15 @@ struct mlx4_context { + int max_sge; + int max_cqe; + ++ struct { ++ struct mlx4_srq **table; ++ int refcnt; ++ } xrc_srq_table[MLX4_XRC_SRQ_TABLE_SIZE]; ++ pthread_mutex_t xrc_srq_table_mutex; ++ int num_xrc_srqs; ++ int xrc_srq_table_shift; ++ int xrc_srq_table_mask; ++ + struct mlx4_db_page *db_list[MLX4_NUM_DB_TYPE]; + pthread_mutex_t db_list_mutex; + }; +@@ -260,6 +284,11 @@ struct mlx4_ah { + struct mlx4_av av; + }; + ++struct mlx4_xrc_domain { ++ struct ibv_xrc_domain ibv_xrcd; ++ uint32_t xrcdn; ++}; ++ + static inline unsigned long align(unsigned long val, unsigned long align) + { + return (val + align - 1) & ~(align - 1); +@@ -304,6 +333,13 @@ static inline struct mlx4_ah *to_mah(struct ibv_ah *ibah) + return to_mxxx(ah, ah); + } + ++#ifdef HAVE_IBV_XRC_OPS ++static inline struct mlx4_xrc_domain *to_mxrcd(struct ibv_xrc_domain *ibxrcd) ++{ ++ return to_mxxx(xrcd, xrc_domain); ++} ++#endif ++ + int mlx4_alloc_buf(struct mlx4_buf *buf, size_t size, int page_size); + void mlx4_free_buf(struct mlx4_buf *buf); + +@@ -350,6 +386,10 @@ void mlx4_free_srq_wqe(struct mlx4_srq *srq, int ind); + int mlx4_post_srq_recv(struct ibv_srq *ibsrq, + struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr); ++struct mlx4_srq *mlx4_find_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn); ++int mlx4_store_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn, ++ struct mlx4_srq *srq); ++void mlx4_clear_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn); + + struct ibv_qp *mlx4_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *attr); + int mlx4_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, +@@ -380,5 +420,16 @@ int mlx4_alloc_av(struct mlx4_pd *pd, struct ibv_ah_attr *attr, + int mlx4_alloc_av(struct mlx4_pd *pd, struct ibv_ah_attr *attr, + struct mlx4_ah *ah); + void mlx4_free_av(struct mlx4_ah *ah); ++#ifdef HAVE_IBV_XRC_OPS ++struct ibv_srq *mlx4_create_xrc_srq(struct ibv_pd *pd, ++ struct ibv_xrc_domain *xrc_domain, ++ struct ibv_cq *xrc_cq, ++ struct ibv_srq_init_attr *attr); ++struct ibv_xrc_domain *mlx4_open_xrc_domain(struct ibv_context *context, ++ int fd, int oflag); ++ ++int mlx4_close_xrc_domain(struct ibv_xrc_domain *d); ++#endif ++ + + #endif /* MLX4_H */ +diff --git a/src/qp.c b/src/qp.c +index 01e8580..2f02430 100644 +--- a/src/qp.c ++++ b/src/qp.c +@@ -226,7 +226,7 @@ int mlx4_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr, + ctrl = wqe = get_send_wqe(qp, ind & (qp->sq.wqe_cnt - 1)); + qp->sq.wrid[ind & (qp->sq.wqe_cnt - 1)] = wr->wr_id; + +- ctrl->srcrb_flags = ++ ctrl->xrcrb_flags = + (wr->send_flags & IBV_SEND_SIGNALED ? + htonl(MLX4_WQE_CTRL_CQ_UPDATE) : 0) | + (wr->send_flags & IBV_SEND_SOLICITED ? +@@ -243,6 +243,9 @@ int mlx4_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr, + size = sizeof *ctrl / 16; + + switch (ibqp->qp_type) { ++ case IBV_QPT_XRC: ++ ctrl->xrcrb_flags |= htonl(wr->xrc_remote_srq_num << 8); ++ /* fall thru */ + case IBV_QPT_RC: + case IBV_QPT_UC: + switch (wr->opcode) { +@@ -543,6 +546,7 @@ void mlx4_calc_sq_wqe_size(struct ibv_qp_cap *cap, enum ibv_qp_type type, + size += sizeof (struct mlx4_wqe_raddr_seg); + break; + ++ case IBV_QPT_XRC: + case IBV_QPT_RC: + size += sizeof (struct mlx4_wqe_raddr_seg); + /* +@@ -631,6 +635,7 @@ void mlx4_set_sq_sizes(struct mlx4_qp *qp, struct ibv_qp_cap *cap, + + case IBV_QPT_UC: + case IBV_QPT_RC: ++ case IBV_QPT_XRC: + wqe_size -= sizeof (struct mlx4_wqe_raddr_seg); + break; + +diff --git a/src/srq.c b/src/srq.c +index ba2ceb9..1350792 100644 +--- a/src/srq.c ++++ b/src/srq.c +@@ -167,3 +167,53 @@ int mlx4_alloc_srq_buf(struct ibv_pd *pd, struct ibv_srq_attr *attr, + + return 0; + } ++ ++struct mlx4_srq *mlx4_find_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn) ++{ ++ int tind = (xrc_srqn & (ctx->num_xrc_srqs - 1)) >> ctx->xrc_srq_table_shift; ++ ++ if (ctx->xrc_srq_table[tind].refcnt) ++ return ctx->xrc_srq_table[tind].table[xrc_srqn & ctx->xrc_srq_table_mask]; ++ else ++ return NULL; ++} ++ ++int mlx4_store_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn, ++ struct mlx4_srq *srq) ++{ ++ int tind = (xrc_srqn & (ctx->num_xrc_srqs - 1)) >> ctx->xrc_srq_table_shift; ++ int ret = 0; ++ ++ pthread_mutex_lock(&ctx->xrc_srq_table_mutex); ++ ++ if (!ctx->xrc_srq_table[tind].refcnt) { ++ ctx->xrc_srq_table[tind].table = calloc(ctx->xrc_srq_table_mask + 1, ++ sizeof(struct mlx4_srq *)); ++ if (!ctx->xrc_srq_table[tind].table) { ++ ret = -1; ++ goto out; ++ } ++ } ++ ++ ++ctx->xrc_srq_table[tind].refcnt; ++ ctx->xrc_srq_table[tind].table[xrc_srqn & ctx->xrc_srq_table_mask] = srq; ++ ++out: ++ pthread_mutex_unlock(&ctx->xrc_srq_table_mutex); ++ return ret; ++} ++ ++void mlx4_clear_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn) ++{ ++ int tind = (xrc_srqn & (ctx->num_xrc_srqs - 1)) >> ctx->xrc_srq_table_shift; ++ ++ pthread_mutex_lock(&ctx->xrc_srq_table_mutex); ++ ++ if (!--ctx->xrc_srq_table[tind].refcnt) ++ free(ctx->xrc_srq_table[tind].table); ++ else ++ ctx->xrc_srq_table[tind].table[xrc_srqn & ctx->xrc_srq_table_mask] = NULL; ++ ++ pthread_mutex_unlock(&ctx->xrc_srq_table_mutex); ++} ++ +diff --git a/src/verbs.c b/src/verbs.c +index 400050c..b7c9c8e 100644 +--- a/src/verbs.c ++++ b/src/verbs.c +@@ -368,18 +368,36 @@ int mlx4_query_srq(struct ibv_srq *srq, + return ibv_cmd_query_srq(srq, attr, &cmd, sizeof cmd); + } + +-int mlx4_destroy_srq(struct ibv_srq *srq) ++int mlx4_destroy_srq(struct ibv_srq *ibsrq) + { ++ struct mlx4_srq *srq = to_msrq(ibsrq); ++ struct mlx4_cq *mcq = NULL; + int ret; + +- ret = ibv_cmd_destroy_srq(srq); +- if (ret) ++ if (ibsrq->xrc_cq) { ++ /* is an xrc_srq */ ++ mcq = to_mcq(ibsrq->xrc_cq); ++ mlx4_cq_clean(mcq, 0, srq); ++ pthread_spin_lock(&mcq->lock); ++ mlx4_clear_xrc_srq(to_mctx(ibsrq->context), srq->srqn); ++ pthread_spin_unlock(&mcq->lock); ++ } ++ ++ ret = ibv_cmd_destroy_srq(ibsrq); ++ if (ret) { ++ if (ibsrq->xrc_cq) { ++ pthread_spin_lock(&mcq->lock); ++ mlx4_store_xrc_srq(to_mctx(ibsrq->context), ++ srq->srqn, srq); ++ pthread_spin_unlock(&mcq->lock); ++ } + return ret; ++ } + +- mlx4_free_db(to_mctx(srq->context), MLX4_DB_TYPE_RQ, to_msrq(srq)->db); +- mlx4_free_buf(&to_msrq(srq)->buf); +- free(to_msrq(srq)->wrid); +- free(to_msrq(srq)); ++ mlx4_free_db(to_mctx(ibsrq->context), MLX4_DB_TYPE_RQ, srq->db); ++ mlx4_free_buf(&srq->buf); ++ free(srq->wrid); ++ free(srq); + + return 0; + } +@@ -415,7 +433,7 @@ struct ibv_qp *mlx4_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *attr) + qp->sq.wqe_cnt = align_queue_size(attr->cap.max_send_wr + qp->sq_spare_wqes); + qp->rq.wqe_cnt = align_queue_size(attr->cap.max_recv_wr); + +- if (attr->srq) ++ if (attr->srq || attr->qp_type == IBV_QPT_XRC) + attr->cap.max_recv_wr = qp->rq.wqe_cnt = 0; + else { + if (attr->cap.max_recv_sge < 1) +@@ -433,7 +451,7 @@ struct ibv_qp *mlx4_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *attr) + pthread_spin_init(&qp->rq.lock, PTHREAD_PROCESS_PRIVATE)) + goto err_free; + +- if (!attr->srq) { ++ if (!attr->srq && attr->qp_type != IBV_QPT_XRC) { + qp->db = mlx4_alloc_db(to_mctx(pd->context), MLX4_DB_TYPE_RQ); + if (!qp->db) + goto err_free; +@@ -442,7 +460,7 @@ struct ibv_qp *mlx4_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *attr) + } + + cmd.buf_addr = (uintptr_t) qp->buf.buf; +- if (attr->srq) ++ if (attr->srq || attr->qp_type == IBV_QPT_XRC) + cmd.db_addr = 0; + else + cmd.db_addr = (uintptr_t) qp->db; +@@ -485,7 +503,7 @@ err_destroy: + + err_rq_db: + pthread_mutex_unlock(&to_mctx(pd->context)->qp_table_mutex); +- if (!attr->srq) ++ if (!attr->srq && attr->qp_type != IBV_QPT_XRC) + mlx4_free_db(to_mctx(pd->context), MLX4_DB_TYPE_RQ, qp->db); + + err_free: +@@ -544,7 +562,7 @@ int mlx4_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + mlx4_cq_clean(to_mcq(qp->send_cq), qp->qp_num, NULL); + + mlx4_init_qp_indices(to_mqp(qp)); +- if (!qp->srq) ++ if (!qp->srq && qp->qp_type != IBV_QPT_XRC) + *to_mqp(qp)->db = 0; + } + +@@ -603,7 +621,7 @@ int mlx4_destroy_qp(struct ibv_qp *ibqp) + mlx4_unlock_cqs(ibqp); + pthread_mutex_unlock(&to_mctx(ibqp->context)->qp_table_mutex); + +- if (!ibqp->srq) ++ if (!ibqp->srq && ibqp->qp_type != IBV_QPT_XRC) + mlx4_free_db(to_mctx(ibqp->context), MLX4_DB_TYPE_RQ, qp->db); + free(qp->sq.wrid); + if (qp->rq.wqe_cnt) +@@ -661,3 +679,103 @@ int mlx4_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid) + + return 0; + } ++ ++#ifdef HAVE_IBV_XRC_OPS ++struct ibv_srq *mlx4_create_xrc_srq(struct ibv_pd *pd, ++ struct ibv_xrc_domain *xrc_domain, ++ struct ibv_cq *xrc_cq, ++ struct ibv_srq_init_attr *attr) ++{ ++ struct mlx4_create_xrc_srq cmd; ++ struct mlx4_create_srq_resp resp; ++ struct mlx4_srq *srq; ++ int ret; ++ ++ /* Sanity check SRQ size before proceeding */ ++ if (attr->attr.max_wr > 1 << 16 || attr->attr.max_sge > 64) ++ return NULL; ++ ++ srq = malloc(sizeof *srq); ++ if (!srq) ++ return NULL; ++ ++ if (pthread_spin_init(&srq->lock, PTHREAD_PROCESS_PRIVATE)) ++ goto err; ++ ++ srq->max = align_queue_size(attr->attr.max_wr + 1); ++ srq->max_gs = attr->attr.max_sge; ++ srq->counter = 0; ++ ++ if (mlx4_alloc_srq_buf(pd, &attr->attr, srq)) ++ goto err; ++ ++ srq->db = mlx4_alloc_db(to_mctx(pd->context), MLX4_DB_TYPE_RQ); ++ if (!srq->db) ++ goto err_free; ++ ++ *srq->db = 0; ++ ++ cmd.buf_addr = (uintptr_t) srq->buf.buf; ++ cmd.db_addr = (uintptr_t) srq->db; ++ ++ ret = ibv_cmd_create_xrc_srq(pd, &srq->ibv_srq, attr, ++ xrc_domain->handle, ++ xrc_cq->handle, ++ &cmd.ibv_cmd, sizeof cmd, ++ &resp.ibv_resp, sizeof resp); ++ if (ret) ++ goto err_db; ++ ++ srq->ibv_srq.xrc_srq_num = srq->srqn = resp.srqn; ++ ++ ret = mlx4_store_xrc_srq(to_mctx(pd->context), srq->ibv_srq.xrc_srq_num, srq); ++ if (ret) ++ goto err_destroy; ++ ++ return &srq->ibv_srq; ++ ++err_destroy: ++ ibv_cmd_destroy_srq(&srq->ibv_srq); ++ ++err_db: ++ mlx4_free_db(to_mctx(pd->context), MLX4_DB_TYPE_RQ, srq->db); ++ ++err_free: ++ free(srq->wrid); ++ mlx4_free_buf(&srq->buf); ++ ++err: ++ free(srq); ++ ++ return NULL; ++} ++ ++struct ibv_xrc_domain *mlx4_open_xrc_domain(struct ibv_context *context, ++ int fd, int oflag) ++{ ++ int ret; ++ struct mlx4_open_xrc_domain_resp resp; ++ struct mlx4_xrc_domain *xrcd; ++ ++ xrcd = malloc(sizeof *xrcd); ++ if (!xrcd) ++ return NULL; ++ ++ ret = ibv_cmd_open_xrc_domain(context, fd, oflag, &xrcd->ibv_xrcd, ++ &resp.ibv_resp, sizeof resp); ++ if (ret) { ++ free(xrcd); ++ return NULL; ++ } ++ ++ xrcd->xrcdn = resp.xrcdn; ++ return &xrcd->ibv_xrcd; ++} ++ ++int mlx4_close_xrc_domain(struct ibv_xrc_domain *d) ++{ ++ ibv_cmd_close_xrc_domain(d); ++ free(d); ++ return 0; ++} ++#endif +diff --git a/src/wqe.h b/src/wqe.h +index 6f7f309..fa2f8ac 100644 +--- a/src/wqe.h ++++ b/src/wqe.h +@@ -65,7 +65,7 @@ struct mlx4_wqe_ctrl_seg { + * [1] SE (solicited event) + * [0] FL (force loopback) + */ +- uint32_t srcrb_flags; ++ uint32_t xrcrb_flags; + /* + * imm is immediate data for send/RDMA write w/ immediate; + * also invalidation key for send with invalidate; input diff --git a/contrib/ofed/libmlx4/fixes/xrc_fix_close_domain.patch b/contrib/ofed/libmlx4/fixes/xrc_fix_close_domain.patch new file mode 100644 index 000000000000..dfad7ac78ee3 --- /dev/null +++ b/contrib/ofed/libmlx4/fixes/xrc_fix_close_domain.patch @@ -0,0 +1,27 @@ +Pass return code to caller in mlx4_close_xrc_domain. + +ibv_cmd_close_xrc_domain() can return a busy or invalid error code. +Need to pass this upward to caller. +(Bugzilla 999) + +Signed-off-by: Jack Morgenstein + +Index: libmlx4/src/verbs.c +=================================================================== +--- libmlx4.orig/src/verbs.c 2008-09-01 10:51:11.000000000 +0300 ++++ libmlx4/src/verbs.c 2008-09-01 10:52:40.000000000 +0300 +@@ -774,9 +774,11 @@ + + int mlx4_close_xrc_domain(struct ibv_xrc_domain *d) + { +- ibv_cmd_close_xrc_domain(d); +- free(d); +- return 0; ++ int ret; ++ ret = ibv_cmd_close_xrc_domain(d); ++ if (!ret) ++ free(d); ++ return ret; + } + + int mlx4_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, diff --git a/contrib/ofed/libmlx4/fixes/xrc_kernel_user_mismatch.patch b/contrib/ofed/libmlx4/fixes/xrc_kernel_user_mismatch.patch new file mode 100644 index 000000000000..41a0edb7eabe --- /dev/null +++ b/contrib/ofed/libmlx4/fixes/xrc_kernel_user_mismatch.patch @@ -0,0 +1,22 @@ +When creating a new user context, exit if the kernel +does not support XRC. (OFED libmlx4 has a compatibility problem). + +Signed-off-by: Jack Morgenstein + +Index: libmlx4/src/mlx4.c +=================================================================== +--- libmlx4.orig/src/mlx4.c 2009-05-10 12:16:33.000000000 +0300 ++++ libmlx4/src/mlx4.c 2009-05-10 12:30:06.000000000 +0300 +@@ -190,6 +190,12 @@ + context->max_qp_wr = dev_attrs.max_qp_wr; + context->max_sge = dev_attrs.max_sge; + context->max_cqe = dev_attrs.max_cqe; ++ if (!(dev_attrs.device_cap_flags & IBV_DEVICE_XRC)) { ++ fprintf(stderr, PFX "There is a mismatch between " ++ "the kernel and the userspace libraries: " ++ "Kernel does not support XRC. Exiting.\n"); ++ goto query_free; ++ } + + return &context->ibv_ctx; + diff --git a/contrib/ofed/libmlx4/fixes/xrc_rcv_qp_v2.patch b/contrib/ofed/libmlx4/fixes/xrc_rcv_qp_v2.patch new file mode 100644 index 000000000000..311c5009922d --- /dev/null +++ b/contrib/ofed/libmlx4/fixes/xrc_rcv_qp_v2.patch @@ -0,0 +1,113 @@ +Added support for XRC receive-only QPs (version 2). + +Signed-off-by: Jack Morgenstein +--- +V2: +1. xrc_ops changed to more_ops + +diff --git a/src/mlx4.c b/src/mlx4.c +index 27ca75d..e5ded78 100644 +--- a/src/mlx4.c ++++ b/src/mlx4.c +@@ -74,6 +74,11 @@ static struct ibv_more_ops mlx4_more_ops = { + .create_xrc_srq = mlx4_create_xrc_srq, + .open_xrc_domain = mlx4_open_xrc_domain, + .close_xrc_domain = mlx4_close_xrc_domain, ++ .create_xrc_rcv_qp = mlx4_create_xrc_rcv_qp, ++ .modify_xrc_rcv_qp = mlx4_modify_xrc_rcv_qp, ++ .query_xrc_rcv_qp = mlx4_query_xrc_rcv_qp, ++ .reg_xrc_rcv_qp = mlx4_reg_xrc_rcv_qp, ++ .unreg_xrc_rcv_qp = mlx4_unreg_xrc_rcv_qp, + #endif + }; + #endif +diff --git a/src/mlx4.h b/src/mlx4.h +index 3eadb98..6307a2d 100644 +--- a/src/mlx4.h ++++ b/src/mlx4.h +@@ -429,6 +429,21 @@ struct ibv_xrc_domain *mlx4_open_xrc_domain(struct ibv_context *context, + int fd, int oflag); + + int mlx4_close_xrc_domain(struct ibv_xrc_domain *d); ++int mlx4_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, ++ uint32_t *xrc_qp_num); ++int mlx4_modify_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num, ++ struct ibv_qp_attr *attr, ++ int attr_mask); ++int mlx4_query_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num, ++ struct ibv_qp_attr *attr, ++ int attr_mask, ++ struct ibv_qp_init_attr *init_attr); ++int mlx4_reg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num); ++int mlx4_unreg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num); + #endif + + +diff --git a/src/verbs.c b/src/verbs.c +index b7c9c8e..8261eae 100644 +--- a/src/verbs.c ++++ b/src/verbs.c +@@ -778,4 +778,59 @@ int mlx4_close_xrc_domain(struct ibv_xrc_domain *d) + free(d); + return 0; + } ++ ++int mlx4_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, ++ uint32_t *xrc_qp_num) ++{ ++ ++ return ibv_cmd_create_xrc_rcv_qp(init_attr, xrc_qp_num); ++} ++ ++int mlx4_modify_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num, ++ struct ibv_qp_attr *attr, ++ int attr_mask) ++{ ++ return ibv_cmd_modify_xrc_rcv_qp(xrc_domain, xrc_qp_num, ++ attr, attr_mask); ++} ++ ++int mlx4_query_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num, ++ struct ibv_qp_attr *attr, ++ int attr_mask, ++ struct ibv_qp_init_attr *init_attr) ++{ ++ int ret; ++ ++ ret = ibv_cmd_query_xrc_rcv_qp(xrc_domain, xrc_qp_num, ++ attr, attr_mask, init_attr); ++ if (ret) ++ return ret; ++ ++ init_attr->cap.max_send_wr = init_attr->cap.max_send_sge = 1; ++ init_attr->cap.max_recv_sge = init_attr->cap.max_recv_wr = 0; ++ init_attr->cap.max_inline_data = 0; ++ init_attr->recv_cq = init_attr->send_cq = NULL; ++ init_attr->srq = NULL; ++ init_attr->xrc_domain = xrc_domain; ++ init_attr->qp_type = IBV_QPT_XRC; ++ init_attr->qp_context = NULL; ++ attr->cap = init_attr->cap; ++ ++ return 0; ++} ++ ++int mlx4_reg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num) ++{ ++ return ibv_cmd_reg_xrc_rcv_qp(xrc_domain, xrc_qp_num); ++} ++ ++int mlx4_unreg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, ++ uint32_t xrc_qp_num) ++{ ++ return ibv_cmd_unreg_xrc_rcv_qp(xrc_domain, xrc_qp_num); ++} ++ + #endif diff --git a/contrib/ofed/libmlx4/libmlx4.spec.in b/contrib/ofed/libmlx4/libmlx4.spec.in new file mode 100644 index 000000000000..04c362502c46 --- /dev/null +++ b/contrib/ofed/libmlx4/libmlx4.spec.in @@ -0,0 +1,65 @@ +Name: libmlx4 +Version: 1.0 +Release: 2%{?dist} +Summary: Mellanox ConnectX InfiniBand HCA Userspace Driver + +Group: System Environment/Libraries +License: GPLv2 or BSD +Url: http://openfabrics.org/ +Source: http://openfabrics.org/downloads/mlx4/libmlx4-1.0.tar.gz +BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) + +BuildRequires: libibverbs-devel >= 1.1-0.1.rc2 + +%description +libmlx4 provides a device-specific userspace driver for Mellanox +ConnectX HCAs for use with the libibverbs library. + +%package devel +Summary: Development files for the libmlx4 driver +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} +Provides: libmlx4-static = %{version}-%{release} + +%description devel +Static version of libmlx4 that may be linked directly to an +application, which may be useful for debugging. + +%prep +%setup -q -n %{name}-@VERSION@ + +%build +%configure +make %{?_smp_mflags} + +%install +rm -rf $RPM_BUILD_ROOT +make DESTDIR=%{buildroot} install +# remove unpackaged files from the buildroot +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la $RPM_BUILD_ROOT%{_libdir}/libmlx4.so + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,-) +%{_libdir}/libmlx4-rdmav2.so +%{_sysconfdir}/libibverbs.d/mlx4.driver +%doc AUTHORS COPYING README + +%files devel +%defattr(-,root,root,-) +%{_libdir}/libmlx4.a + +%changelog +* Sun Jan 27 2008 Roland Dreier - 1.0-2 +- Spec file cleanups, based on Fedora review: don't mark + libmlx4.driver as a config file, since it is not user modifiable, + and change the name of the -devel-static package to plain -devel, + since it would be empty without the static library. + +* Sun Dec 9 2007 Roland Dreier - 1.0-1 +- New upstream release + +* Fri Apr 6 2007 Roland Dreier - 1.0-0.1.rc1 +- Initial Fedora spec file diff --git a/contrib/ofed/libmlx4/mlx4.driver b/contrib/ofed/libmlx4/mlx4.driver new file mode 100644 index 000000000000..4d29fa818afe --- /dev/null +++ b/contrib/ofed/libmlx4/mlx4.driver @@ -0,0 +1 @@ +driver mlx4 diff --git a/contrib/ofed/libmlx4/src/buf.c b/contrib/ofed/libmlx4/src/buf.c new file mode 100644 index 000000000000..1ebc9980cead --- /dev/null +++ b/contrib/ofed/libmlx4/src/buf.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2006, 2007 Cisco, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include "mlx4.h" + +#if !(defined(HAVE_IBV_DONTFORK_RANGE) && defined(HAVE_IBV_DOFORK_RANGE)) + +/* + * If libibverbs isn't exporting these functions, then there's no + * point in doing it here, because the rest of libibverbs isn't going + * to be fork-safe anyway. + */ +static int ibv_dontfork_range(void *base, size_t size) +{ + return 0; +} + +static int ibv_dofork_range(void *base, size_t size) +{ + return 0; +} + +#endif /* HAVE_IBV_DONTFORK_RANGE && HAVE_IBV_DOFORK_RANGE */ + +int mlx4_alloc_buf(struct mlx4_buf *buf, size_t size, int page_size) +{ + int ret; + + buf->length = align(size, page_size); + buf->buf = mmap(NULL, buf->length, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (buf->buf == MAP_FAILED) + return errno; + + ret = ibv_dontfork_range(buf->buf, size); + if (ret) + munmap(buf->buf, buf->length); + + return ret; +} + +void mlx4_free_buf(struct mlx4_buf *buf) +{ + ibv_dofork_range(buf->buf, buf->length); + munmap(buf->buf, buf->length); +} diff --git a/contrib/ofed/libmlx4/src/cq.c b/contrib/ofed/libmlx4/src/cq.c new file mode 100644 index 000000000000..eef1e0258253 --- /dev/null +++ b/contrib/ofed/libmlx4/src/cq.c @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include + +#include "mlx4.h" +#include "doorbell.h" + +enum { + MLX4_CQ_DOORBELL = 0x20 +}; + +enum { + CQ_OK = 0, + CQ_EMPTY = -1, + CQ_POLL_ERR = -2 +}; + +#define MLX4_CQ_DB_REQ_NOT_SOL (1 << 24) +#define MLX4_CQ_DB_REQ_NOT (2 << 24) + +enum { + MLX4_CQE_OWNER_MASK = 0x80, + MLX4_CQE_IS_SEND_MASK = 0x40, + MLX4_CQE_OPCODE_MASK = 0x1f +}; + +enum { + MLX4_CQE_SYNDROME_LOCAL_LENGTH_ERR = 0x01, + MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR = 0x02, + MLX4_CQE_SYNDROME_LOCAL_PROT_ERR = 0x04, + MLX4_CQE_SYNDROME_WR_FLUSH_ERR = 0x05, + MLX4_CQE_SYNDROME_MW_BIND_ERR = 0x06, + MLX4_CQE_SYNDROME_BAD_RESP_ERR = 0x10, + MLX4_CQE_SYNDROME_LOCAL_ACCESS_ERR = 0x11, + MLX4_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR = 0x12, + MLX4_CQE_SYNDROME_REMOTE_ACCESS_ERR = 0x13, + MLX4_CQE_SYNDROME_REMOTE_OP_ERR = 0x14, + MLX4_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR = 0x15, + MLX4_CQE_SYNDROME_RNR_RETRY_EXC_ERR = 0x16, + MLX4_CQE_SYNDROME_REMOTE_ABORTED_ERR = 0x22, +}; + +struct mlx4_cqe { + uint32_t my_qpn; + uint32_t immed_rss_invalid; + uint32_t g_mlpath_rqpn; + uint8_t sl; + uint8_t reserved1; + uint16_t rlid; + uint32_t reserved2; + uint32_t byte_cnt; + uint16_t wqe_index; + uint16_t checksum; + uint8_t reserved3[3]; + uint8_t owner_sr_opcode; +}; + +struct mlx4_err_cqe { + uint32_t my_qpn; + uint32_t reserved1[5]; + uint16_t wqe_index; + uint8_t vendor_err; + uint8_t syndrome; + uint8_t reserved2[3]; + uint8_t owner_sr_opcode; +}; + +static struct mlx4_cqe *get_cqe(struct mlx4_cq *cq, int entry) +{ + return cq->buf.buf + entry * MLX4_CQ_ENTRY_SIZE; +} + +static void *get_sw_cqe(struct mlx4_cq *cq, int n) +{ + struct mlx4_cqe *cqe = get_cqe(cq, n & cq->ibv_cq.cqe); + + return (!!(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK) ^ + !!(n & (cq->ibv_cq.cqe + 1))) ? NULL : cqe; +} + +static struct mlx4_cqe *next_cqe_sw(struct mlx4_cq *cq) +{ + return get_sw_cqe(cq, cq->cons_index); +} + +static void update_cons_index(struct mlx4_cq *cq) +{ + *cq->set_ci_db = htonl(cq->cons_index & 0xffffff); +} + +static void mlx4_handle_error_cqe(struct mlx4_err_cqe *cqe, struct ibv_wc *wc) +{ + if (cqe->syndrome == MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR) + printf(PFX "local QP operation err " + "(QPN %06x, WQE index %x, vendor syndrome %02x, " + "opcode = %02x)\n", + htonl(cqe->my_qpn), htonl(cqe->wqe_index), + cqe->vendor_err, + cqe->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK); + + switch (cqe->syndrome) { + case MLX4_CQE_SYNDROME_LOCAL_LENGTH_ERR: + wc->status = IBV_WC_LOC_LEN_ERR; + break; + case MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR: + wc->status = IBV_WC_LOC_QP_OP_ERR; + break; + case MLX4_CQE_SYNDROME_LOCAL_PROT_ERR: + wc->status = IBV_WC_LOC_PROT_ERR; + break; + case MLX4_CQE_SYNDROME_WR_FLUSH_ERR: + wc->status = IBV_WC_WR_FLUSH_ERR; + break; + case MLX4_CQE_SYNDROME_MW_BIND_ERR: + wc->status = IBV_WC_MW_BIND_ERR; + break; + case MLX4_CQE_SYNDROME_BAD_RESP_ERR: + wc->status = IBV_WC_BAD_RESP_ERR; + break; + case MLX4_CQE_SYNDROME_LOCAL_ACCESS_ERR: + wc->status = IBV_WC_LOC_ACCESS_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR: + wc->status = IBV_WC_REM_INV_REQ_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_ACCESS_ERR: + wc->status = IBV_WC_REM_ACCESS_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_OP_ERR: + wc->status = IBV_WC_REM_OP_ERR; + break; + case MLX4_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR: + wc->status = IBV_WC_RETRY_EXC_ERR; + break; + case MLX4_CQE_SYNDROME_RNR_RETRY_EXC_ERR: + wc->status = IBV_WC_RNR_RETRY_EXC_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_ABORTED_ERR: + wc->status = IBV_WC_REM_ABORT_ERR; + break; + default: + wc->status = IBV_WC_GENERAL_ERR; + break; + } + + wc->vendor_err = cqe->vendor_err; +} + +static int mlx4_poll_one(struct mlx4_cq *cq, + struct mlx4_qp **cur_qp, + struct ibv_wc *wc) +{ + struct mlx4_wq *wq; + struct mlx4_cqe *cqe; + struct mlx4_srq *srq = NULL; + uint32_t qpn; + uint32_t srqn; + uint32_t g_mlpath_rqpn; + uint16_t wqe_index; + int is_error; + int is_send; + + cqe = next_cqe_sw(cq); + if (!cqe) + return CQ_EMPTY; + + ++cq->cons_index; + + VALGRIND_MAKE_MEM_DEFINED(cqe, sizeof *cqe); + + /* + * Make sure we read CQ entry contents after we've checked the + * ownership bit. + */ + rmb(); + + qpn = ntohl(cqe->my_qpn); + + is_send = cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK; + is_error = (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == + MLX4_CQE_OPCODE_ERROR; + + if (qpn & MLX4_XRC_QPN_BIT && !is_send) { + srqn = ntohl(cqe->g_mlpath_rqpn) & 0xffffff; + /* + * We do not have to take the XRC SRQ table lock here, + * because CQs will be locked while XRC SRQs are removed + * from the table. + */ + srq = mlx4_find_xrc_srq(to_mctx(cq->ibv_cq.context), srqn); + if (!srq) + return CQ_POLL_ERR; + } else if (!*cur_qp || (qpn & 0xffffff) != (*cur_qp)->ibv_qp.qp_num) { + /* + * We do not have to take the QP table lock here, + * because CQs will be locked while QPs are removed + * from the table. + */ + *cur_qp = mlx4_find_qp(to_mctx(cq->ibv_cq.context), + qpn & 0xffffff); + if (!*cur_qp) + return CQ_POLL_ERR; + } + + wc->qp_num = qpn & 0xffffff; + + if (is_send) { + wq = &(*cur_qp)->sq; + wqe_index = ntohs(cqe->wqe_index); + wq->tail += (uint16_t) (wqe_index - (uint16_t) wq->tail); + wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; + ++wq->tail; + } else if (srq) { + wqe_index = htons(cqe->wqe_index); + wc->wr_id = srq->wrid[wqe_index]; + mlx4_free_srq_wqe(srq, wqe_index); + } else if ((*cur_qp)->ibv_qp.srq) { + srq = to_msrq((*cur_qp)->ibv_qp.srq); + wqe_index = htons(cqe->wqe_index); + wc->wr_id = srq->wrid[wqe_index]; + mlx4_free_srq_wqe(srq, wqe_index); + } else { + wq = &(*cur_qp)->rq; + wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; + ++wq->tail; + } + + if (is_error) { + mlx4_handle_error_cqe((struct mlx4_err_cqe *) cqe, wc); + return CQ_OK; + } + + wc->status = IBV_WC_SUCCESS; + + if (is_send) { + wc->wc_flags = 0; + switch (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) { + case MLX4_OPCODE_RDMA_WRITE_IMM: + wc->wc_flags |= IBV_WC_WITH_IMM; + case MLX4_OPCODE_RDMA_WRITE: + wc->opcode = IBV_WC_RDMA_WRITE; + break; + case MLX4_OPCODE_SEND_IMM: + wc->wc_flags |= IBV_WC_WITH_IMM; + case MLX4_OPCODE_SEND: + wc->opcode = IBV_WC_SEND; + break; + case MLX4_OPCODE_RDMA_READ: + wc->opcode = IBV_WC_RDMA_READ; + wc->byte_len = ntohl(cqe->byte_cnt); + break; + case MLX4_OPCODE_ATOMIC_CS: + wc->opcode = IBV_WC_COMP_SWAP; + wc->byte_len = 8; + break; + case MLX4_OPCODE_ATOMIC_FA: + wc->opcode = IBV_WC_FETCH_ADD; + wc->byte_len = 8; + break; + case MLX4_OPCODE_BIND_MW: + wc->opcode = IBV_WC_BIND_MW; + break; + default: + /* assume it's a send completion */ + wc->opcode = IBV_WC_SEND; + break; + } + } else { + wc->byte_len = ntohl(cqe->byte_cnt); + + switch (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) { + case MLX4_RECV_OPCODE_RDMA_WRITE_IMM: + wc->opcode = IBV_WC_RECV_RDMA_WITH_IMM; + wc->wc_flags = IBV_WC_WITH_IMM; + wc->imm_data = cqe->immed_rss_invalid; + break; + case MLX4_RECV_OPCODE_SEND: + wc->opcode = IBV_WC_RECV; + wc->wc_flags = 0; + break; + case MLX4_RECV_OPCODE_SEND_IMM: + wc->opcode = IBV_WC_RECV; + wc->wc_flags = IBV_WC_WITH_IMM; + wc->imm_data = cqe->immed_rss_invalid; + break; + } + + wc->slid = ntohs(cqe->rlid); + wc->sl = cqe->sl >> 4; + g_mlpath_rqpn = ntohl(cqe->g_mlpath_rqpn); + wc->src_qp = g_mlpath_rqpn & 0xffffff; + wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f; + wc->wc_flags |= g_mlpath_rqpn & 0x80000000 ? IBV_WC_GRH : 0; + wc->pkey_index = ntohl(cqe->immed_rss_invalid) & 0x7f; + } + + return CQ_OK; +} + +int mlx4_poll_cq(struct ibv_cq *ibcq, int ne, struct ibv_wc *wc) +{ + struct mlx4_cq *cq = to_mcq(ibcq); + struct mlx4_qp *qp = NULL; + int npolled; + int err = CQ_OK; + + pthread_spin_lock(&cq->lock); + + for (npolled = 0; npolled < ne; ++npolled) { + err = mlx4_poll_one(cq, &qp, wc + npolled); + if (err != CQ_OK) + break; + } + + if (npolled) + update_cons_index(cq); + + pthread_spin_unlock(&cq->lock); + + return err == CQ_POLL_ERR ? err : npolled; +} + +int mlx4_arm_cq(struct ibv_cq *ibvcq, int solicited) +{ + struct mlx4_cq *cq = to_mcq(ibvcq); + uint32_t doorbell[2]; + uint32_t sn; + uint32_t ci; + uint32_t cmd; + + sn = cq->arm_sn & 3; + ci = cq->cons_index & 0xffffff; + cmd = solicited ? MLX4_CQ_DB_REQ_NOT_SOL : MLX4_CQ_DB_REQ_NOT; + + *cq->arm_db = htonl(sn << 28 | cmd | ci); + + /* + * Make sure that the doorbell record in host memory is + * written before ringing the doorbell via PCI MMIO. + */ + wmb(); + + doorbell[0] = htonl(sn << 28 | cmd | cq->cqn); + doorbell[1] = htonl(ci); + + mlx4_write64(doorbell, to_mctx(ibvcq->context), MLX4_CQ_DOORBELL); + + return 0; +} + +void mlx4_cq_event(struct ibv_cq *cq) +{ + to_mcq(cq)->arm_sn++; +} + +void __mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn, struct mlx4_srq *srq) +{ + struct mlx4_cqe *cqe, *dest; + uint32_t prod_index; + uint8_t owner_bit; + int nfreed = 0; + int is_xrc_srq = 0; + + if (srq && srq->ibv_srq.xrc_cq) + is_xrc_srq = 1; + + /* + * First we need to find the current producer index, so we + * know where to start cleaning from. It doesn't matter if HW + * adds new entries after this loop -- the QP we're worried + * about is already in RESET, so the new entries won't come + * from our QP and therefore don't need to be checked. + */ + for (prod_index = cq->cons_index; get_sw_cqe(cq, prod_index); ++prod_index) + if (prod_index == cq->cons_index + cq->ibv_cq.cqe) + break; + + /* + * Now sweep backwards through the CQ, removing CQ entries + * that match our QP by copying older entries on top of them. + */ + while ((int) --prod_index - (int) cq->cons_index >= 0) { + cqe = get_cqe(cq, prod_index & cq->ibv_cq.cqe); + if (is_xrc_srq && + (ntohl(cqe->g_mlpath_rqpn & 0xffffff) == srq->srqn) && + !(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK)) { + mlx4_free_srq_wqe(srq, ntohs(cqe->wqe_index)); + ++nfreed; + } else if ((ntohl(cqe->my_qpn) & 0xffffff) == qpn) { + if (srq && !(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK)) + mlx4_free_srq_wqe(srq, ntohs(cqe->wqe_index)); + ++nfreed; + } else if (nfreed) { + dest = get_cqe(cq, (prod_index + nfreed) & cq->ibv_cq.cqe); + owner_bit = dest->owner_sr_opcode & MLX4_CQE_OWNER_MASK; + memcpy(dest, cqe, sizeof *cqe); + dest->owner_sr_opcode = owner_bit | + (dest->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK); + } + } + + if (nfreed) { + cq->cons_index += nfreed; + /* + * Make sure update of buffer contents is done before + * updating consumer index. + */ + wmb(); + update_cons_index(cq); + } +} + +void mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn, struct mlx4_srq *srq) +{ + pthread_spin_lock(&cq->lock); + __mlx4_cq_clean(cq, qpn, srq); + pthread_spin_unlock(&cq->lock); +} + +int mlx4_get_outstanding_cqes(struct mlx4_cq *cq) +{ + uint32_t i; + + for (i = cq->cons_index; get_sw_cqe(cq, (i & cq->ibv_cq.cqe)); ++i) + ; + + return i - cq->cons_index; +} + +void mlx4_cq_resize_copy_cqes(struct mlx4_cq *cq, void *buf, int old_cqe) +{ + struct mlx4_cqe *cqe; + int i; + + i = cq->cons_index; + cqe = get_cqe(cq, (i & old_cqe)); + + while ((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) != MLX4_CQE_OPCODE_RESIZE) { + cqe->owner_sr_opcode = (cqe->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK) | + (((i + 1) & (cq->ibv_cq.cqe + 1)) ? MLX4_CQE_OWNER_MASK : 0); + memcpy(buf + ((i + 1) & cq->ibv_cq.cqe) * MLX4_CQ_ENTRY_SIZE, + cqe, MLX4_CQ_ENTRY_SIZE); + ++i; + cqe = get_cqe(cq, (i & old_cqe)); + } + + ++cq->cons_index; +} + +int mlx4_alloc_cq_buf(struct mlx4_device *dev, struct mlx4_buf *buf, int nent) +{ + if (mlx4_alloc_buf(buf, align(nent * MLX4_CQ_ENTRY_SIZE, dev->page_size), + dev->page_size)) + return -1; + memset(buf->buf, 0, nent * MLX4_CQ_ENTRY_SIZE); + + return 0; +} diff --git a/contrib/ofed/libmlx4/src/dbrec.c b/contrib/ofed/libmlx4/src/dbrec.c new file mode 100644 index 000000000000..02ef237b3921 --- /dev/null +++ b/contrib/ofed/libmlx4/src/dbrec.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include "mlx4.h" + +struct mlx4_db_page { + struct mlx4_db_page *prev, *next; + struct mlx4_buf buf; + int num_db; + int use_cnt; + unsigned long free[0]; +}; + +static const int db_size[] = { + [MLX4_DB_TYPE_CQ] = 8, + [MLX4_DB_TYPE_RQ] = 4, +}; + +static struct mlx4_db_page *__add_page(struct mlx4_context *context, + enum mlx4_db_type type) +{ + struct mlx4_db_page *page; + int ps = to_mdev(context->ibv_ctx.device)->page_size; + int pp; + int i; + + pp = ps / db_size[type]; + + page = malloc(sizeof *page + pp / 8); + if (!page) + return NULL; + + if (mlx4_alloc_buf(&page->buf, ps, ps)) { + free(page); + return NULL; + } + + page->num_db = pp; + page->use_cnt = 0; + for (i = 0; i < pp / (sizeof (long) * 8); ++i) + page->free[i] = ~0; + + page->prev = NULL; + page->next = context->db_list[type]; + context->db_list[type] = page; + if (page->next) + page->next->prev = page; + + return page; +} + +uint32_t *mlx4_alloc_db(struct mlx4_context *context, enum mlx4_db_type type) +{ + struct mlx4_db_page *page; + uint32_t *db = NULL; + int i, j; + + pthread_mutex_lock(&context->db_list_mutex); + + for (page = context->db_list[type]; page; page = page->next) + if (page->use_cnt < page->num_db) + goto found; + + page = __add_page(context, type); + if (!page) + goto out; + +found: + ++page->use_cnt; + + for (i = 0; !page->free[i]; ++i) + /* nothing */; + + j = ffsl(page->free[i]); + page->free[i] &= ~(1UL << (j - 1)); + db = page->buf.buf + (i * 8 * sizeof (long) + (j - 1)) * db_size[type]; + +out: + pthread_mutex_unlock(&context->db_list_mutex); + + return db; +} + +void mlx4_free_db(struct mlx4_context *context, enum mlx4_db_type type, uint32_t *db) +{ + struct mlx4_db_page *page; + uintptr_t ps = to_mdev(context->ibv_ctx.device)->page_size; + int i; + + pthread_mutex_lock(&context->db_list_mutex); + + for (page = context->db_list[type]; page; page = page->next) + if (((uintptr_t) db & ~(ps - 1)) == (uintptr_t) page->buf.buf) + break; + + if (!page) + goto out; + + i = ((void *) db - page->buf.buf) / db_size[type]; + page->free[i / (8 * sizeof (long))] |= 1UL << (i % (8 * sizeof (long))); + + if (!--page->use_cnt) { + if (page->prev) + page->prev->next = page->next; + else + context->db_list[type] = page->next; + if (page->next) + page->next->prev = page->prev; + + mlx4_free_buf(&page->buf); + free(page); + } + +out: + pthread_mutex_unlock(&context->db_list_mutex); +} diff --git a/contrib/ofed/libmlx4/src/doorbell.h b/contrib/ofed/libmlx4/src/doorbell.h new file mode 100644 index 000000000000..f0b30a9f2a9a --- /dev/null +++ b/contrib/ofed/libmlx4/src/doorbell.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007 Cisco, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef DOORBELL_H +#define DOORBELL_H + +#ifdef __LP64__ +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define MLX4_PAIR_TO_64(val) ((uint64_t) val[1] << 32 | val[0]) +#elif __BYTE_ORDER == __BIG_ENDIAN +# define MLX4_PAIR_TO_64(val) ((uint64_t) val[0] << 32 | val[1]) +#else +# error __BYTE_ORDER not defined +#endif + +static inline void mlx4_write64(uint32_t val[2], struct mlx4_context *ctx, int offset) +{ + *(volatile uint64_t *) (ctx->uar + offset) = MLX4_PAIR_TO_64(val); +} + +#else + +static inline void mlx4_write64(uint32_t val[2], struct mlx4_context *ctx, int offset) +{ + pthread_spin_lock(&ctx->uar_lock); + *(volatile uint32_t *) (ctx->uar + offset) = val[0]; + *(volatile uint32_t *) (ctx->uar + offset + 4) = val[1]; + pthread_spin_unlock(&ctx->uar_lock); +} + +#endif + +#endif /* DOORBELL_H */ diff --git a/contrib/ofed/libmlx4/src/mlx4-abi.h b/contrib/ofed/libmlx4/src/mlx4-abi.h new file mode 100644 index 000000000000..1b1253c764d8 --- /dev/null +++ b/contrib/ofed/libmlx4/src/mlx4-abi.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2007 Cisco, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_ABI_H +#define MLX4_ABI_H + +#include + +#define MLX4_UVERBS_MIN_ABI_VERSION 2 +#define MLX4_UVERBS_MAX_ABI_VERSION 3 + +struct mlx4_alloc_ucontext_resp { + struct ibv_get_context_resp ibv_resp; + __u32 qp_tab_size; + __u16 bf_reg_size; + __u16 bf_regs_per_page; +}; + +struct mlx4_alloc_pd_resp { + struct ibv_alloc_pd_resp ibv_resp; + __u32 pdn; + __u32 reserved; +}; + +struct mlx4_create_cq { + struct ibv_create_cq ibv_cmd; + __u64 buf_addr; + __u64 db_addr; +}; + +struct mlx4_create_cq_resp { + struct ibv_create_cq_resp ibv_resp; + __u32 cqn; + __u32 reserved; +}; + +struct mlx4_resize_cq { + struct ibv_resize_cq ibv_cmd; + __u64 buf_addr; +}; + +#ifdef HAVE_IBV_XRC_OPS +struct mlx4_create_xrc_srq { + struct ibv_create_xrc_srq ibv_cmd; + __u64 buf_addr; + __u64 db_addr; +}; +#endif + +struct mlx4_create_srq { + struct ibv_create_srq ibv_cmd; + __u64 buf_addr; + __u64 db_addr; +}; + +struct mlx4_create_srq_resp { + struct ibv_create_srq_resp ibv_resp; + __u32 srqn; + __u32 reserved; +}; + +struct mlx4_create_qp { + struct ibv_create_qp ibv_cmd; + __u64 buf_addr; + __u64 db_addr; + __u8 log_sq_bb_count; + __u8 log_sq_stride; + __u8 sq_no_prefetch; /* was reserved in ABI 2 */ + __u8 reserved[5]; +}; + +#ifdef HAVE_IBV_XRC_OPS +struct mlx4_open_xrc_domain_resp { + struct ibv_open_xrc_domain_resp ibv_resp; + __u32 xrcdn; + __u32 reserved; +}; +#endif + +#endif /* MLX4_ABI_H */ diff --git a/contrib/ofed/libmlx4/src/mlx4.c b/contrib/ofed/libmlx4/src/mlx4.c new file mode 100644 index 000000000000..17adb300a9a8 --- /dev/null +++ b/contrib/ofed/libmlx4/src/mlx4.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2007 Cisco, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef HAVE_IBV_REGISTER_DRIVER +#include +#endif + +#include "mlx4.h" +#include "mlx4-abi.h" + +#ifndef PCI_VENDOR_ID_MELLANOX +#define PCI_VENDOR_ID_MELLANOX 0x15b3 +#endif + +#define HCA(v, d) \ + { .vendor = PCI_VENDOR_ID_##v, \ + .device = d } + +struct { + unsigned vendor; + unsigned device; +} hca_table[] = { + HCA(MELLANOX, 0x6340), /* MT25408 "Hermon" SDR */ + HCA(MELLANOX, 0x634a), /* MT25408 "Hermon" DDR */ + HCA(MELLANOX, 0x6354), /* MT25408 "Hermon" QDR */ + HCA(MELLANOX, 0x6732), /* MT25408 "Hermon" DDR PCIe gen2 */ + HCA(MELLANOX, 0x673c), /* MT25408 "Hermon" QDR PCIe gen2 */ + HCA(MELLANOX, 0x6368), /* MT25448 [ConnectX EN 10GigE, PCIe 2.0 2.5GT/s] */ + HCA(MELLANOX, 0x6750), /* MT26448 [ConnectX EN 10GigE, PCIe 2.0 5GT/s] */ + HCA(MELLANOX, 0x6372), /* MT25408 [ConnectX EN 10GigE 10GBaseT, PCIe 2.0 2.5GT/s] */ + HCA(MELLANOX, 0x675a), /* MT25408 [ConnectX EN 10GigE 10GBaseT, PCIe Gen2 5GT/s] */ + HCA(MELLANOX, 0x6764), /* MT26468 [ConnectX EN 10GigE, PCIe 2.0 5GT/s] */ + HCA(MELLANOX, 0x6746), /* MT26438 ConnectX VPI PCIe 2.0 5GT/s - IB QDR / 10GigE Virt+ */ + HCA(MELLANOX, 0x676e), /* MT26478 ConnectX EN 40GigE PCIe 2.0 5GT/s */ + HCA(MELLANOX, 0x6778), /* MT26488 ConnectX VPI PCIe 2.0 5GT/s - IB DDR / 10GigE Virt+ */ + HCA(MELLANOX, 0x1000), + HCA(MELLANOX, 0x1001), + HCA(MELLANOX, 0x1002), + HCA(MELLANOX, 0x1003), + HCA(MELLANOX, 0x1004), + HCA(MELLANOX, 0x1005), + HCA(MELLANOX, 0x1006), + HCA(MELLANOX, 0x1007), + HCA(MELLANOX, 0x1008), + HCA(MELLANOX, 0x1009), + HCA(MELLANOX, 0x100a), + HCA(MELLANOX, 0x100b), + HCA(MELLANOX, 0x100c), + HCA(MELLANOX, 0x100d), + HCA(MELLANOX, 0x100e), + HCA(MELLANOX, 0x100f), +}; + +#ifdef HAVE_IBV_MORE_OPS +static struct ibv_more_ops mlx4_more_ops = { +#ifdef HAVE_IBV_XRC_OPS + .create_xrc_srq = mlx4_create_xrc_srq, + .open_xrc_domain = mlx4_open_xrc_domain, + .close_xrc_domain = mlx4_close_xrc_domain, + .create_xrc_rcv_qp = mlx4_create_xrc_rcv_qp, + .modify_xrc_rcv_qp = mlx4_modify_xrc_rcv_qp, + .query_xrc_rcv_qp = mlx4_query_xrc_rcv_qp, + .reg_xrc_rcv_qp = mlx4_reg_xrc_rcv_qp, + .unreg_xrc_rcv_qp = mlx4_unreg_xrc_rcv_qp, +#endif +}; +#endif + +static struct ibv_context_ops mlx4_ctx_ops = { + .query_device = mlx4_query_device, + .query_port = mlx4_query_port, + .alloc_pd = mlx4_alloc_pd, + .dealloc_pd = mlx4_free_pd, + .reg_mr = mlx4_reg_mr, + .dereg_mr = mlx4_dereg_mr, + .create_cq = mlx4_create_cq, + .poll_cq = mlx4_poll_cq, + .req_notify_cq = mlx4_arm_cq, + .cq_event = mlx4_cq_event, + .resize_cq = mlx4_resize_cq, + .destroy_cq = mlx4_destroy_cq, + .create_srq = mlx4_create_srq, + .modify_srq = mlx4_modify_srq, + .query_srq = mlx4_query_srq, + .destroy_srq = mlx4_destroy_srq, + .post_srq_recv = mlx4_post_srq_recv, + .create_qp = mlx4_create_qp, + .query_qp = mlx4_query_qp, + .modify_qp = mlx4_modify_qp, + .destroy_qp = mlx4_destroy_qp, + .post_send = mlx4_post_send, + .post_recv = mlx4_post_recv, + .create_ah = mlx4_create_ah, + .destroy_ah = mlx4_destroy_ah, + .attach_mcast = ibv_cmd_attach_mcast, + .detach_mcast = ibv_cmd_detach_mcast +}; + +static struct ibv_context *mlx4_alloc_context(struct ibv_device *ibdev, int cmd_fd) +{ + struct mlx4_context *context; + struct ibv_get_context cmd; + struct mlx4_alloc_ucontext_resp resp; + int i; + struct ibv_device_attr dev_attrs; + + context = calloc(1, sizeof *context); + if (!context) + return NULL; + + context->ibv_ctx.cmd_fd = cmd_fd; + + if (ibv_cmd_get_context(&context->ibv_ctx, &cmd, sizeof cmd, + &resp.ibv_resp, sizeof resp)) + goto err_free; + + context->num_qps = resp.qp_tab_size; + context->qp_table_shift = ffs(context->num_qps) - 1 - MLX4_QP_TABLE_BITS; + context->qp_table_mask = (1 << context->qp_table_shift) - 1; + + pthread_mutex_init(&context->qp_table_mutex, NULL); + for (i = 0; i < MLX4_QP_TABLE_SIZE; ++i) + context->qp_table[i].refcnt = 0; + + context->num_xrc_srqs = resp.qp_tab_size; + context->xrc_srq_table_shift = ffs(context->num_xrc_srqs) - 1 + - MLX4_XRC_SRQ_TABLE_BITS; + context->xrc_srq_table_mask = (1 << context->xrc_srq_table_shift) - 1; + + pthread_mutex_init(&context->xrc_srq_table_mutex, NULL); + for (i = 0; i < MLX4_XRC_SRQ_TABLE_SIZE; ++i) + context->xrc_srq_table[i].refcnt = 0; + + for (i = 0; i < MLX4_NUM_DB_TYPE; ++i) + context->db_list[i] = NULL; + + pthread_mutex_init(&context->db_list_mutex, NULL); + + context->uar = mmap(NULL, to_mdev(ibdev)->page_size, PROT_WRITE, + MAP_SHARED, cmd_fd, 0); + if (context->uar == MAP_FAILED) + goto err_free; + + if (resp.bf_reg_size) { + context->bf_page = mmap(NULL, to_mdev(ibdev)->page_size, + PROT_WRITE, MAP_SHARED, cmd_fd, + to_mdev(ibdev)->page_size); + if (context->bf_page == MAP_FAILED) { + fprintf(stderr, PFX "Warning: BlueFlame available, " + "but failed to mmap() BlueFlame page.\n"); + context->bf_page = NULL; + context->bf_buf_size = 0; + } else { + context->bf_buf_size = resp.bf_reg_size / 2; + context->bf_offset = 0; + pthread_spin_init(&context->bf_lock, PTHREAD_PROCESS_PRIVATE); + } + } else { + context->bf_page = NULL; + context->bf_buf_size = 0; + } + + pthread_spin_init(&context->uar_lock, PTHREAD_PROCESS_PRIVATE); + + context->ibv_ctx.ops = mlx4_ctx_ops; +#ifdef HAVE_IBV_XRC_OPS + context->ibv_ctx.more_ops = &mlx4_more_ops; +#endif + + if (mlx4_query_device(&context->ibv_ctx, &dev_attrs)) + goto query_free; + + context->max_qp_wr = dev_attrs.max_qp_wr; + context->max_sge = dev_attrs.max_sge; + context->max_cqe = dev_attrs.max_cqe; + if (!(dev_attrs.device_cap_flags & IBV_DEVICE_XRC)) { + fprintf(stderr, PFX "There is a mismatch between " + "the kernel and the userspace libraries: " + "Kernel does not support XRC. Exiting.\n"); + goto query_free; + } + + return &context->ibv_ctx; + +query_free: + munmap(context->uar, to_mdev(ibdev)->page_size); + if (context->bf_page) + munmap(context->bf_page, to_mdev(ibdev)->page_size); + +err_free: + free(context); + return NULL; +} + +static void mlx4_free_context(struct ibv_context *ibctx) +{ + struct mlx4_context *context = to_mctx(ibctx); + + munmap(context->uar, to_mdev(ibctx->device)->page_size); + if (context->bf_page) + munmap(context->bf_page, to_mdev(ibctx->device)->page_size); + free(context); +} + +static struct ibv_device_ops mlx4_dev_ops = { + .alloc_context = mlx4_alloc_context, + .free_context = mlx4_free_context +}; + +static struct ibv_device *mlx4_driver_init(const char *uverbs_sys_path, + int abi_version) +{ + char value[8]; + struct mlx4_device *dev; + unsigned vendor, device; + int i; + + if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor", + value, sizeof value) < 0) + return NULL; + sscanf(value, "%i", &vendor); + + if (ibv_read_sysfs_file(uverbs_sys_path, "device/device", + value, sizeof value) < 0) + return NULL; + sscanf(value, "%i", &device); + + for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i) + if (vendor == hca_table[i].vendor && + device == hca_table[i].device) + goto found; + + return NULL; + +found: + if (abi_version < MLX4_UVERBS_MIN_ABI_VERSION || + abi_version > MLX4_UVERBS_MAX_ABI_VERSION) { + fprintf(stderr, PFX "Fatal: ABI version %d of %s is not supported " + "(min supported %d, max supported %d)\n", + abi_version, uverbs_sys_path, + MLX4_UVERBS_MIN_ABI_VERSION, + MLX4_UVERBS_MAX_ABI_VERSION); + return NULL; + } + + dev = malloc(sizeof *dev); + if (!dev) { + fprintf(stderr, PFX "Fatal: couldn't allocate device for %s\n", + uverbs_sys_path); + return NULL; + } + + dev->ibv_dev.ops = mlx4_dev_ops; + dev->page_size = sysconf(_SC_PAGESIZE); + + return &dev->ibv_dev; +} + +#ifdef HAVE_IBV_REGISTER_DRIVER +static __attribute__((constructor)) void mlx4_register_driver(void) +{ + ibv_register_driver("mlx4", mlx4_driver_init); +} +#else +/* + * Export the old libsysfs sysfs_class_device-based driver entry point + * if libibverbs does not export an ibv_register_driver() function. + */ +struct ibv_device *openib_driver_init(struct sysfs_class_device *sysdev) +{ + int abi_ver = 0; + char value[8]; + + if (ibv_read_sysfs_file(sysdev->path, "abi_version", + value, sizeof value) > 0) + abi_ver = strtol(value, NULL, 10); + + return mlx4_driver_init(sysdev->path, abi_ver); +} +#endif /* HAVE_IBV_REGISTER_DRIVER */ diff --git a/contrib/ofed/libmlx4/src/mlx4.h b/contrib/ofed/libmlx4/src/mlx4.h new file mode 100644 index 000000000000..a349c5b805b4 --- /dev/null +++ b/contrib/ofed/libmlx4/src/mlx4.h @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_H +#define MLX4_H + +#include + +#include +#include + +#ifdef HAVE_VALGRIND_MEMCHECK_H + +# include + +# if !defined(VALGRIND_MAKE_MEM_DEFINED) || !defined(VALGRIND_MAKE_MEM_UNDEFINED) +# warning "Valgrind support requested, but VALGRIND_MAKE_MEM_(UN)DEFINED not available" +# endif + +#endif /* HAVE_VALGRIND_MEMCHECK_H */ + +#ifndef VALGRIND_MAKE_MEM_DEFINED +# define VALGRIND_MAKE_MEM_DEFINED(addr,len) +#endif + +#ifndef VALGRIND_MAKE_MEM_UNDEFINED +# define VALGRIND_MAKE_MEM_UNDEFINED(addr,len) +#endif + +#ifndef rmb +# define rmb() mb() +#endif + +#ifndef wmb +# define wmb() mb() +#endif + +#ifndef wc_wmb + +#if defined(__i386__) +#define wc_wmb() asm volatile("lock; addl $0,0(%%esp) " ::: "memory") +#elif defined(__x86_64__) +#define wc_wmb() asm volatile("sfence" ::: "memory") +#elif defined(__ia64__) +#define wc_wmb() asm volatile("fwb" ::: "memory") +#else +#define wc_wmb() wmb() +#endif + +#endif + +#ifndef HAVE_IBV_MORE_OPS +#undef HAVE_IBV_XRC_OPS +#undef HAVE_IBV_CREATE_QP_EXP +#endif + +#define HIDDEN __attribute__((visibility ("hidden"))) + +#define PFX "mlx4: " + +#ifndef max +#define max(a,b) \ + ({ typeof (a) _a = (a); \ + typeof (b) _b = (b); \ + _a > _b ? _a : _b; }) +#endif + +#ifndef min +#define min(a,b) \ + ({ typeof (a) _a = (a); \ + typeof (b) _b = (b); \ + _a < _b ? _a : _b; }) +#endif + +enum { + MLX4_CQ_ENTRY_SIZE = 0x20 +}; + +enum { + MLX4_STAT_RATE_OFFSET = 5 +}; + +enum { + MLX4_QP_TABLE_BITS = 8, + MLX4_QP_TABLE_SIZE = 1 << MLX4_QP_TABLE_BITS, + MLX4_QP_TABLE_MASK = MLX4_QP_TABLE_SIZE - 1 +}; + +enum { + MLX4_XRC_SRQ_TABLE_BITS = 8, + MLX4_XRC_SRQ_TABLE_SIZE = 1 << MLX4_XRC_SRQ_TABLE_BITS, + MLX4_XRC_SRQ_TABLE_MASK = MLX4_XRC_SRQ_TABLE_SIZE - 1 +}; + +enum { + MLX4_XRC_QPN_BIT = (1 << 23) +}; + +enum mlx4_db_type { + MLX4_DB_TYPE_CQ, + MLX4_DB_TYPE_RQ, + MLX4_NUM_DB_TYPE +}; + +enum { + MLX4_OPCODE_NOP = 0x00, + MLX4_OPCODE_SEND_INVAL = 0x01, + MLX4_OPCODE_RDMA_WRITE = 0x08, + MLX4_OPCODE_RDMA_WRITE_IMM = 0x09, + MLX4_OPCODE_SEND = 0x0a, + MLX4_OPCODE_SEND_IMM = 0x0b, + MLX4_OPCODE_LSO = 0x0e, + MLX4_OPCODE_RDMA_READ = 0x10, + MLX4_OPCODE_ATOMIC_CS = 0x11, + MLX4_OPCODE_ATOMIC_FA = 0x12, + MLX4_OPCODE_ATOMIC_MASK_CS = 0x14, + MLX4_OPCODE_ATOMIC_MASK_FA = 0x15, + MLX4_OPCODE_BIND_MW = 0x18, + MLX4_OPCODE_FMR = 0x19, + MLX4_OPCODE_LOCAL_INVAL = 0x1b, + MLX4_OPCODE_CONFIG_CMD = 0x1f, + + MLX4_RECV_OPCODE_RDMA_WRITE_IMM = 0x00, + MLX4_RECV_OPCODE_SEND = 0x01, + MLX4_RECV_OPCODE_SEND_IMM = 0x02, + MLX4_RECV_OPCODE_SEND_INVAL = 0x03, + + MLX4_CQE_OPCODE_ERROR = 0x1e, + MLX4_CQE_OPCODE_RESIZE = 0x16, +}; + +enum { + MLX4_MAX_WQE_SIZE = 1008 +}; + +struct mlx4_device { + struct ibv_device ibv_dev; + int page_size; +}; + +struct mlx4_db_page; + +struct mlx4_context { + struct ibv_context ibv_ctx; + + void *uar; + pthread_spinlock_t uar_lock; + + void *bf_page; + int bf_buf_size; + int bf_offset; + pthread_spinlock_t bf_lock; + + struct { + struct mlx4_qp **table; + int refcnt; + } qp_table[MLX4_QP_TABLE_SIZE]; + pthread_mutex_t qp_table_mutex; + int num_qps; + int qp_table_shift; + int qp_table_mask; + int max_qp_wr; + int max_sge; + int max_cqe; + + struct { + struct mlx4_srq **table; + int refcnt; + } xrc_srq_table[MLX4_XRC_SRQ_TABLE_SIZE]; + pthread_mutex_t xrc_srq_table_mutex; + int num_xrc_srqs; + int xrc_srq_table_shift; + int xrc_srq_table_mask; + + struct mlx4_db_page *db_list[MLX4_NUM_DB_TYPE]; + pthread_mutex_t db_list_mutex; +}; + +struct mlx4_buf { + void *buf; + size_t length; +}; + +struct mlx4_pd { + struct ibv_pd ibv_pd; + uint32_t pdn; +}; + +struct mlx4_cq { + struct ibv_cq ibv_cq; + struct mlx4_buf buf; + struct mlx4_buf resize_buf; + pthread_spinlock_t lock; + uint32_t cqn; + uint32_t cons_index; + uint32_t *set_ci_db; + uint32_t *arm_db; + int arm_sn; +}; + +struct mlx4_srq { + struct ibv_srq ibv_srq; + struct mlx4_buf buf; + pthread_spinlock_t lock; + uint64_t *wrid; + uint32_t srqn; + int max; + int max_gs; + int wqe_shift; + int head; + int tail; + uint32_t *db; + uint16_t counter; +}; + +struct mlx4_wq { + uint64_t *wrid; + pthread_spinlock_t lock; + int wqe_cnt; + int max_post; + unsigned head; + unsigned tail; + int max_gs; + int wqe_shift; + int offset; +}; + +struct mlx4_qp { + struct ibv_qp ibv_qp; + struct mlx4_buf buf; + int max_inline_data; + int buf_size; + + uint32_t doorbell_qpn; + uint32_t sq_signal_bits; + int sq_spare_wqes; + struct mlx4_wq sq; + + uint32_t *db; + struct mlx4_wq rq; +}; + +struct mlx4_av { + uint32_t port_pd; + uint8_t reserved1; + uint8_t g_slid; + uint16_t dlid; + uint8_t reserved2; + uint8_t gid_index; + uint8_t stat_rate; + uint8_t hop_limit; + uint32_t sl_tclass_flowlabel; + uint8_t dgid[16]; + uint8_t mac[8]; +}; + +struct mlx4_ah { + struct ibv_ah ibv_ah; + struct mlx4_av av; + uint16_t vlan; + uint8_t mac[6]; + uint8_t tagged; +}; + +struct mlx4_xrc_domain { + struct ibv_xrc_domain ibv_xrcd; + uint32_t xrcdn; +}; + +static inline unsigned long align(unsigned long val, unsigned long align) +{ + return (val + align - 1) & ~(align - 1); +} + +#define to_mxxx(xxx, type) \ + ((struct mlx4_##type *) \ + ((void *) ib##xxx - offsetof(struct mlx4_##type, ibv_##xxx))) + +static inline struct mlx4_device *to_mdev(struct ibv_device *ibdev) +{ + return to_mxxx(dev, device); +} + +static inline struct mlx4_context *to_mctx(struct ibv_context *ibctx) +{ + return to_mxxx(ctx, context); +} + +static inline struct mlx4_pd *to_mpd(struct ibv_pd *ibpd) +{ + return to_mxxx(pd, pd); +} + +static inline struct mlx4_cq *to_mcq(struct ibv_cq *ibcq) +{ + return to_mxxx(cq, cq); +} + +static inline struct mlx4_srq *to_msrq(struct ibv_srq *ibsrq) +{ + return to_mxxx(srq, srq); +} + +static inline struct mlx4_qp *to_mqp(struct ibv_qp *ibqp) +{ + return to_mxxx(qp, qp); +} + +static inline struct mlx4_ah *to_mah(struct ibv_ah *ibah) +{ + return to_mxxx(ah, ah); +} + +#ifdef HAVE_IBV_XRC_OPS +static inline struct mlx4_xrc_domain *to_mxrcd(struct ibv_xrc_domain *ibxrcd) +{ + return to_mxxx(xrcd, xrc_domain); +} +#endif + +int mlx4_alloc_buf(struct mlx4_buf *buf, size_t size, int page_size); +void mlx4_free_buf(struct mlx4_buf *buf); + +uint32_t *mlx4_alloc_db(struct mlx4_context *context, enum mlx4_db_type type); +void mlx4_free_db(struct mlx4_context *context, enum mlx4_db_type type, uint32_t *db); + +int mlx4_query_device(struct ibv_context *context, + struct ibv_device_attr *attr); +int mlx4_query_port(struct ibv_context *context, uint8_t port, + struct ibv_port_attr *attr); + +struct ibv_pd *mlx4_alloc_pd(struct ibv_context *context); +int mlx4_free_pd(struct ibv_pd *pd); + +struct ibv_mr *mlx4_reg_mr(struct ibv_pd *pd, void *addr, + size_t length, enum ibv_access_flags access); +int mlx4_dereg_mr(struct ibv_mr *mr); + +struct ibv_cq *mlx4_create_cq(struct ibv_context *context, int cqe, + struct ibv_comp_channel *channel, + int comp_vector); +int mlx4_alloc_cq_buf(struct mlx4_device *dev, struct mlx4_buf *buf, int nent); +int mlx4_resize_cq(struct ibv_cq *cq, int cqe); +int mlx4_destroy_cq(struct ibv_cq *cq); +int mlx4_poll_cq(struct ibv_cq *cq, int ne, struct ibv_wc *wc); +int mlx4_arm_cq(struct ibv_cq *cq, int solicited); +void mlx4_cq_event(struct ibv_cq *cq); +void __mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn, struct mlx4_srq *srq); +void mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn, struct mlx4_srq *srq); +int mlx4_get_outstanding_cqes(struct mlx4_cq *cq); +void mlx4_cq_resize_copy_cqes(struct mlx4_cq *cq, void *buf, int new_cqe); + +struct ibv_srq *mlx4_create_srq(struct ibv_pd *pd, + struct ibv_srq_init_attr *attr); +int mlx4_modify_srq(struct ibv_srq *srq, + struct ibv_srq_attr *attr, + enum ibv_srq_attr_mask mask); +int mlx4_query_srq(struct ibv_srq *srq, + struct ibv_srq_attr *attr); +int mlx4_destroy_srq(struct ibv_srq *srq); +int mlx4_alloc_srq_buf(struct ibv_pd *pd, struct ibv_srq_attr *attr, + struct mlx4_srq *srq); +void mlx4_free_srq_wqe(struct mlx4_srq *srq, int ind); +int mlx4_post_srq_recv(struct ibv_srq *ibsrq, + struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr); +struct mlx4_srq *mlx4_find_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn); +int mlx4_store_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn, + struct mlx4_srq *srq); +void mlx4_clear_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn); + +struct ibv_qp *mlx4_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *attr); +int mlx4_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + enum ibv_qp_attr_mask attr_mask, + struct ibv_qp_init_attr *init_attr); +int mlx4_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + enum ibv_qp_attr_mask attr_mask); +int mlx4_destroy_qp(struct ibv_qp *qp); +void mlx4_init_qp_indices(struct mlx4_qp *qp); +void mlx4_qp_init_sq_ownership(struct mlx4_qp *qp); +int mlx4_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr, + struct ibv_send_wr **bad_wr); +int mlx4_post_recv(struct ibv_qp *ibqp, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr); +void mlx4_calc_sq_wqe_size(struct ibv_qp_cap *cap, enum ibv_qp_type type, + struct mlx4_qp *qp); +int num_inline_segs(int data, enum ibv_qp_type type); +int mlx4_alloc_qp_buf(struct ibv_pd *pd, struct ibv_qp_cap *cap, + enum ibv_qp_type type, struct mlx4_qp *qp); +void mlx4_set_sq_sizes(struct mlx4_qp *qp, struct ibv_qp_cap *cap, + enum ibv_qp_type type); +struct mlx4_qp *mlx4_find_qp(struct mlx4_context *ctx, uint32_t qpn); +int mlx4_store_qp(struct mlx4_context *ctx, uint32_t qpn, struct mlx4_qp *qp); +void mlx4_clear_qp(struct mlx4_context *ctx, uint32_t qpn); +struct ibv_ah *mlx4_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr); +int mlx4_destroy_ah(struct ibv_ah *ah); +int mlx4_alloc_av(struct mlx4_pd *pd, struct ibv_ah_attr *attr, + struct mlx4_ah *ah); +void mlx4_free_av(struct mlx4_ah *ah); +#ifdef HAVE_IBV_XRC_OPS +struct ibv_srq *mlx4_create_xrc_srq(struct ibv_pd *pd, + struct ibv_xrc_domain *xrc_domain, + struct ibv_cq *xrc_cq, + struct ibv_srq_init_attr *attr); +struct ibv_xrc_domain *mlx4_open_xrc_domain(struct ibv_context *context, + int fd, int oflag); + +int mlx4_close_xrc_domain(struct ibv_xrc_domain *d); +int mlx4_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, + uint32_t *xrc_qp_num); +int mlx4_modify_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num, + struct ibv_qp_attr *attr, + int attr_mask); +int mlx4_query_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num, + struct ibv_qp_attr *attr, + int attr_mask, + struct ibv_qp_init_attr *init_attr); +int mlx4_reg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num); +int mlx4_unreg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num); +#endif + + +#endif /* MLX4_H */ diff --git a/contrib/ofed/libmlx4/src/mlx4.map b/contrib/ofed/libmlx4/src/mlx4.map new file mode 100644 index 000000000000..ae8ed861f956 --- /dev/null +++ b/contrib/ofed/libmlx4/src/mlx4.map @@ -0,0 +1,5 @@ +{ + global: + openib_driver_init; + local: *; +}; diff --git a/contrib/ofed/libmlx4/src/qp.c b/contrib/ofed/libmlx4/src/qp.c new file mode 100644 index 000000000000..4586ea711040 --- /dev/null +++ b/contrib/ofed/libmlx4/src/qp.c @@ -0,0 +1,706 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2007 Cisco, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include "mlx4.h" +#include "doorbell.h" +#include "wqe.h" + +static const uint32_t mlx4_ib_opcode[] = { + [IBV_WR_SEND] = MLX4_OPCODE_SEND, + [IBV_WR_SEND_WITH_IMM] = MLX4_OPCODE_SEND_IMM, + [IBV_WR_RDMA_WRITE] = MLX4_OPCODE_RDMA_WRITE, + [IBV_WR_RDMA_WRITE_WITH_IMM] = MLX4_OPCODE_RDMA_WRITE_IMM, + [IBV_WR_RDMA_READ] = MLX4_OPCODE_RDMA_READ, + [IBV_WR_ATOMIC_CMP_AND_SWP] = MLX4_OPCODE_ATOMIC_CS, + [IBV_WR_ATOMIC_FETCH_AND_ADD] = MLX4_OPCODE_ATOMIC_FA, +}; + +static void *get_recv_wqe(struct mlx4_qp *qp, int n) +{ + return qp->buf.buf + qp->rq.offset + (n << qp->rq.wqe_shift); +} + +static void *get_send_wqe(struct mlx4_qp *qp, int n) +{ + return qp->buf.buf + qp->sq.offset + (n << qp->sq.wqe_shift); +} + +/* + * Stamp a SQ WQE so that it is invalid if prefetched by marking the + * first four bytes of every 64 byte chunk with 0xffffffff, except for + * the very first chunk of the WQE. + */ +static void stamp_send_wqe(struct mlx4_qp *qp, int n) +{ + uint32_t *wqe = get_send_wqe(qp, n); + int i; + int ds = (((struct mlx4_wqe_ctrl_seg *)wqe)->fence_size & 0x3f) << 2; + + for (i = 16; i < ds; i += 16) + wqe[i] = 0xffffffff; +} + +void mlx4_init_qp_indices(struct mlx4_qp *qp) +{ + qp->sq.head = 0; + qp->sq.tail = 0; + qp->rq.head = 0; + qp->rq.tail = 0; +} + +void mlx4_qp_init_sq_ownership(struct mlx4_qp *qp) +{ + struct mlx4_wqe_ctrl_seg *ctrl; + int i; + + for (i = 0; i < qp->sq.wqe_cnt; ++i) { + ctrl = get_send_wqe(qp, i); + ctrl->owner_opcode = htonl(1 << 31); + ctrl->fence_size = 1 << (qp->sq.wqe_shift - 4); + + stamp_send_wqe(qp, i); + } +} + +static int wq_overflow(struct mlx4_wq *wq, int nreq, struct mlx4_cq *cq) +{ + unsigned cur; + + cur = wq->head - wq->tail; + if (cur + nreq < wq->max_post) + return 0; + + pthread_spin_lock(&cq->lock); + cur = wq->head - wq->tail; + pthread_spin_unlock(&cq->lock); + + return cur + nreq >= wq->max_post; +} + +static inline void set_raddr_seg(struct mlx4_wqe_raddr_seg *rseg, + uint64_t remote_addr, uint32_t rkey) +{ + rseg->raddr = htonll(remote_addr); + rseg->rkey = htonl(rkey); + rseg->reserved = 0; +} + +static void set_atomic_seg(struct mlx4_wqe_atomic_seg *aseg, struct ibv_send_wr *wr) +{ + if (wr->opcode == IBV_WR_ATOMIC_CMP_AND_SWP) { + aseg->swap_add = htonll(wr->wr.atomic.swap); + aseg->compare = htonll(wr->wr.atomic.compare_add); + } else { + aseg->swap_add = htonll(wr->wr.atomic.compare_add); + aseg->compare = 0; + } + +} + +static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg, + struct ibv_send_wr *wr) +{ + memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av)); + dseg->dqpn = htonl(wr->wr.ud.remote_qpn); + dseg->qkey = htonl(wr->wr.ud.remote_qkey); + dseg->vlan = htons(to_mah(wr->wr.ud.ah)->vlan); + memcpy(dseg->mac, to_mah(wr->wr.ud.ah)->mac, 6); +} + +static void __set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ibv_sge *sg) +{ + dseg->byte_count = htonl(sg->length); + dseg->lkey = htonl(sg->lkey); + dseg->addr = htonll(sg->addr); +} + +static void set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ibv_sge *sg) +{ + dseg->lkey = htonl(sg->lkey); + dseg->addr = htonll(sg->addr); + + /* + * Need a barrier here before writing the byte_count field to + * make sure that all the data is visible before the + * byte_count field is set. Otherwise, if the segment begins + * a new cacheline, the HCA prefetcher could grab the 64-byte + * chunk and get a valid (!= * 0xffffffff) byte count but + * stale data, and end up sending the wrong data. + */ + wmb(); + + dseg->byte_count = htonl(sg->length); +} + +/* + * Avoid using memcpy() to copy to BlueFlame page, since memcpy() + * implementations may use move-string-buffer assembler instructions, + * which do not guarantee order of copying. + */ +static void mlx4_bf_copy(unsigned long *dst, unsigned long *src, unsigned bytecnt) +{ + while (bytecnt > 0) { + *dst++ = *src++; + *dst++ = *src++; + bytecnt -= 2 * sizeof (long); + } +} + +int mlx4_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr, + struct ibv_send_wr **bad_wr) +{ + struct mlx4_context *ctx; + struct mlx4_qp *qp = to_mqp(ibqp); + void *wqe; + struct mlx4_wqe_ctrl_seg *ctrl; + int ind; + int nreq; + int inl = 0; + int ret = 0; + int size; + int i; + + pthread_spin_lock(&qp->sq.lock); + + /* XXX check that state is OK to post send */ + + ind = qp->sq.head; + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + if (wq_overflow(&qp->sq, nreq, to_mcq(qp->ibv_qp.send_cq))) { + ret = -1; + *bad_wr = wr; + goto out; + } + + if (wr->num_sge > qp->sq.max_gs) { + ret = -1; + *bad_wr = wr; + goto out; + } + + if (wr->opcode >= sizeof mlx4_ib_opcode / sizeof mlx4_ib_opcode[0]) { + ret = -1; + *bad_wr = wr; + goto out; + } + + ctrl = wqe = get_send_wqe(qp, ind & (qp->sq.wqe_cnt - 1)); + qp->sq.wrid[ind & (qp->sq.wqe_cnt - 1)] = wr->wr_id; + + ctrl->xrcrb_flags = + (wr->send_flags & IBV_SEND_SIGNALED ? + htonl(MLX4_WQE_CTRL_CQ_UPDATE) : 0) | + (wr->send_flags & IBV_SEND_SOLICITED ? + htonl(MLX4_WQE_CTRL_SOLICIT) : 0) | + qp->sq_signal_bits; + + if (wr->opcode == IBV_WR_SEND_WITH_IMM || + wr->opcode == IBV_WR_RDMA_WRITE_WITH_IMM) + ctrl->imm = wr->imm_data; + else + ctrl->imm = 0; + + wqe += sizeof *ctrl; + size = sizeof *ctrl / 16; + + switch (ibqp->qp_type) { + case IBV_QPT_XRC: + ctrl->xrcrb_flags |= htonl(wr->xrc_remote_srq_num << 8); + /* fall thru */ + case IBV_QPT_RC: + case IBV_QPT_UC: + switch (wr->opcode) { + case IBV_WR_ATOMIC_CMP_AND_SWP: + case IBV_WR_ATOMIC_FETCH_AND_ADD: + set_raddr_seg(wqe, wr->wr.atomic.remote_addr, + wr->wr.atomic.rkey); + wqe += sizeof (struct mlx4_wqe_raddr_seg); + + set_atomic_seg(wqe, wr); + wqe += sizeof (struct mlx4_wqe_atomic_seg); + size += (sizeof (struct mlx4_wqe_raddr_seg) + + sizeof (struct mlx4_wqe_atomic_seg)) / 16; + + break; + + case IBV_WR_RDMA_READ: + inl = 1; + /* fall through */ + case IBV_WR_RDMA_WRITE: + case IBV_WR_RDMA_WRITE_WITH_IMM: + set_raddr_seg(wqe, wr->wr.rdma.remote_addr, + wr->wr.rdma.rkey); + wqe += sizeof (struct mlx4_wqe_raddr_seg); + size += sizeof (struct mlx4_wqe_raddr_seg) / 16; + + break; + + default: + /* No extra segments required for sends */ + break; + } + break; + + case IBV_QPT_UD: + set_datagram_seg(wqe, wr); + wqe += sizeof (struct mlx4_wqe_datagram_seg); + size += sizeof (struct mlx4_wqe_datagram_seg) / 16; + if (to_mah(wr->wr.ud.ah)->tagged) { + ctrl->ins_vlan = 1 << 6; + ctrl->vlan_tag = htons(to_mah(wr->wr.ud.ah)->vlan); + } + + break; + + default: + break; + } + + if (wr->send_flags & IBV_SEND_INLINE && wr->num_sge) { + struct mlx4_wqe_inline_seg *seg; + void *addr; + int len, seg_len; + int num_seg; + int off, to_copy; + + inl = 0; + + seg = wqe; + wqe += sizeof *seg; + off = ((uintptr_t) wqe) & (MLX4_INLINE_ALIGN - 1); + num_seg = 0; + seg_len = 0; + + for (i = 0; i < wr->num_sge; ++i) { + addr = (void *) (uintptr_t) wr->sg_list[i].addr; + len = wr->sg_list[i].length; + inl += len; + + if (inl > qp->max_inline_data) { + inl = 0; + ret = -1; + *bad_wr = wr; + goto out; + } + + while (len >= MLX4_INLINE_ALIGN - off) { + to_copy = MLX4_INLINE_ALIGN - off; + memcpy(wqe, addr, to_copy); + len -= to_copy; + wqe += to_copy; + addr += to_copy; + seg_len += to_copy; + wmb(); /* see comment below */ + seg->byte_count = htonl(MLX4_INLINE_SEG | seg_len); + seg_len = 0; + seg = wqe; + wqe += sizeof *seg; + off = sizeof *seg; + ++num_seg; + } + + memcpy(wqe, addr, len); + wqe += len; + seg_len += len; + off += len; + } + + if (seg_len) { + ++num_seg; + /* + * Need a barrier here to make sure + * all the data is visible before the + * byte_count field is set. Otherwise + * the HCA prefetcher could grab the + * 64-byte chunk with this inline + * segment and get a valid (!= + * 0xffffffff) byte count but stale + * data, and end up sending the wrong + * data. + */ + wmb(); + seg->byte_count = htonl(MLX4_INLINE_SEG | seg_len); + } + + size += (inl + num_seg * sizeof * seg + 15) / 16; + } else { + struct mlx4_wqe_data_seg *seg = wqe; + + for (i = wr->num_sge - 1; i >= 0 ; --i) + set_data_seg(seg + i, wr->sg_list + i); + + size += wr->num_sge * (sizeof *seg / 16); + } + + ctrl->fence_size = (wr->send_flags & IBV_SEND_FENCE ? + MLX4_WQE_CTRL_FENCE : 0) | size; + + /* + * Make sure descriptor is fully written before + * setting ownership bit (because HW can start + * executing as soon as we do). + */ + wmb(); + + ctrl->owner_opcode = htonl(mlx4_ib_opcode[wr->opcode]) | + (ind & qp->sq.wqe_cnt ? htonl(1 << 31) : 0); + + /* + * We can improve latency by not stamping the last + * send queue WQE until after ringing the doorbell, so + * only stamp here if there are still more WQEs to post. + */ + if (wr->next) + stamp_send_wqe(qp, (ind + qp->sq_spare_wqes) & + (qp->sq.wqe_cnt - 1)); + + ++ind; + } + +out: + ctx = to_mctx(ibqp->context); + + if (nreq == 1 && inl && size > 1 && size < ctx->bf_buf_size / 16) { + ctrl->owner_opcode |= htonl((qp->sq.head & 0xffff) << 8); + *(uint32_t *) (&ctrl->vlan_tag) |= qp->doorbell_qpn; + /* + * Make sure that descriptor is written to memory + * before writing to BlueFlame page. + */ + wmb(); + + ++qp->sq.head; + + pthread_spin_lock(&ctx->bf_lock); + + mlx4_bf_copy(ctx->bf_page + ctx->bf_offset, (unsigned long *) ctrl, + align(size * 16, 64)); + wc_wmb(); + + ctx->bf_offset ^= ctx->bf_buf_size; + + pthread_spin_unlock(&ctx->bf_lock); + } else if (nreq) { + qp->sq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + + *(uint32_t *) (ctx->uar + MLX4_SEND_DOORBELL) = qp->doorbell_qpn; + } + + if (nreq) + stamp_send_wqe(qp, (ind + qp->sq_spare_wqes - 1) & + (qp->sq.wqe_cnt - 1)); + + pthread_spin_unlock(&qp->sq.lock); + + return ret; +} + +int mlx4_post_recv(struct ibv_qp *ibqp, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr) +{ + struct mlx4_qp *qp = to_mqp(ibqp); + struct mlx4_wqe_data_seg *scat; + int ret = 0; + int nreq; + int ind; + int i; + + pthread_spin_lock(&qp->rq.lock); + + /* XXX check that state is OK to post receive */ + + ind = qp->rq.head & (qp->rq.wqe_cnt - 1); + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + if (wq_overflow(&qp->rq, nreq, to_mcq(qp->ibv_qp.recv_cq))) { + ret = -1; + *bad_wr = wr; + goto out; + } + + if (wr->num_sge > qp->rq.max_gs) { + ret = -1; + *bad_wr = wr; + goto out; + } + + scat = get_recv_wqe(qp, ind); + + for (i = 0; i < wr->num_sge; ++i) + __set_data_seg(scat + i, wr->sg_list + i); + + if (i < qp->rq.max_gs) { + scat[i].byte_count = 0; + scat[i].lkey = htonl(MLX4_INVALID_LKEY); + scat[i].addr = 0; + } + + qp->rq.wrid[ind] = wr->wr_id; + + ind = (ind + 1) & (qp->rq.wqe_cnt - 1); + } + +out: + if (nreq) { + qp->rq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + + *qp->db = htonl(qp->rq.head & 0xffff); + } + + pthread_spin_unlock(&qp->rq.lock); + + return ret; +} + +int num_inline_segs(int data, enum ibv_qp_type type) +{ + /* + * Inline data segments are not allowed to cross 64 byte + * boundaries. For UD QPs, the data segments always start + * aligned to 64 bytes (16 byte control segment + 48 byte + * datagram segment); for other QPs, there will be a 16 byte + * control segment and possibly a 16 byte remote address + * segment, so in the worst case there will be only 32 bytes + * available for the first data segment. + */ + if (type == IBV_QPT_UD) + data += (sizeof (struct mlx4_wqe_ctrl_seg) + + sizeof (struct mlx4_wqe_datagram_seg)) % + MLX4_INLINE_ALIGN; + else + data += (sizeof (struct mlx4_wqe_ctrl_seg) + + sizeof (struct mlx4_wqe_raddr_seg)) % + MLX4_INLINE_ALIGN; + + return (data + MLX4_INLINE_ALIGN - sizeof (struct mlx4_wqe_inline_seg) - 1) / + (MLX4_INLINE_ALIGN - sizeof (struct mlx4_wqe_inline_seg)); +} + +void mlx4_calc_sq_wqe_size(struct ibv_qp_cap *cap, enum ibv_qp_type type, + struct mlx4_qp *qp) +{ + int size; + int max_sq_sge; + + max_sq_sge = align(cap->max_inline_data + + num_inline_segs(cap->max_inline_data, type) * + sizeof (struct mlx4_wqe_inline_seg), + sizeof (struct mlx4_wqe_data_seg)) / + sizeof (struct mlx4_wqe_data_seg); + if (max_sq_sge < cap->max_send_sge) + max_sq_sge = cap->max_send_sge; + + size = max_sq_sge * sizeof (struct mlx4_wqe_data_seg); + switch (type) { + case IBV_QPT_UD: + size += sizeof (struct mlx4_wqe_datagram_seg); + break; + + case IBV_QPT_UC: + size += sizeof (struct mlx4_wqe_raddr_seg); + break; + + case IBV_QPT_XRC: + case IBV_QPT_RC: + size += sizeof (struct mlx4_wqe_raddr_seg); + /* + * An atomic op will require an atomic segment, a + * remote address segment and one scatter entry. + */ + if (size < (sizeof (struct mlx4_wqe_atomic_seg) + + sizeof (struct mlx4_wqe_raddr_seg) + + sizeof (struct mlx4_wqe_data_seg))) + size = (sizeof (struct mlx4_wqe_atomic_seg) + + sizeof (struct mlx4_wqe_raddr_seg) + + sizeof (struct mlx4_wqe_data_seg)); + break; + + default: + break; + } + + /* Make sure that we have enough space for a bind request */ + if (size < sizeof (struct mlx4_wqe_bind_seg)) + size = sizeof (struct mlx4_wqe_bind_seg); + + size += sizeof (struct mlx4_wqe_ctrl_seg); + + for (qp->sq.wqe_shift = 6; 1 << qp->sq.wqe_shift < size; + qp->sq.wqe_shift++) + ; /* nothing */ +} + +int mlx4_alloc_qp_buf(struct ibv_pd *pd, struct ibv_qp_cap *cap, + enum ibv_qp_type type, struct mlx4_qp *qp) +{ + qp->rq.max_gs = cap->max_recv_sge; + + qp->sq.wrid = malloc(qp->sq.wqe_cnt * sizeof (uint64_t)); + if (!qp->sq.wrid) + return -1; + + if (qp->rq.wqe_cnt) { + qp->rq.wrid = malloc(qp->rq.wqe_cnt * sizeof (uint64_t)); + if (!qp->rq.wrid) { + free(qp->sq.wrid); + return -1; + } + } + + for (qp->rq.wqe_shift = 4; + 1 << qp->rq.wqe_shift < qp->rq.max_gs * sizeof (struct mlx4_wqe_data_seg); + qp->rq.wqe_shift++) + ; /* nothing */ + + qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) + + (qp->sq.wqe_cnt << qp->sq.wqe_shift); + if (qp->rq.wqe_shift > qp->sq.wqe_shift) { + qp->rq.offset = 0; + qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift; + } else { + qp->rq.offset = qp->sq.wqe_cnt << qp->sq.wqe_shift; + qp->sq.offset = 0; + } + + if (mlx4_alloc_buf(&qp->buf, + align(qp->buf_size, to_mdev(pd->context->device)->page_size), + to_mdev(pd->context->device)->page_size)) { + free(qp->sq.wrid); + free(qp->rq.wrid); + return -1; + } + + memset(qp->buf.buf, 0, qp->buf_size); + + return 0; +} + +void mlx4_set_sq_sizes(struct mlx4_qp *qp, struct ibv_qp_cap *cap, + enum ibv_qp_type type) +{ + int wqe_size; + struct mlx4_context *ctx = to_mctx(qp->ibv_qp.context); + + wqe_size = min((1 << qp->sq.wqe_shift), MLX4_MAX_WQE_SIZE) - + sizeof (struct mlx4_wqe_ctrl_seg); + switch (type) { + case IBV_QPT_UD: + wqe_size -= sizeof (struct mlx4_wqe_datagram_seg); + break; + + case IBV_QPT_UC: + case IBV_QPT_RC: + case IBV_QPT_XRC: + wqe_size -= sizeof (struct mlx4_wqe_raddr_seg); + break; + + default: + break; + } + + qp->sq.max_gs = wqe_size / sizeof (struct mlx4_wqe_data_seg); + cap->max_send_sge = min(ctx->max_sge, qp->sq.max_gs); + qp->sq.max_post = min(ctx->max_qp_wr, + qp->sq.wqe_cnt - qp->sq_spare_wqes); + cap->max_send_wr = qp->sq.max_post; + + /* + * Inline data segments can't cross a 64 byte boundary. So + * subtract off one segment header for each 64-byte chunk, + * taking into account the fact that wqe_size will be 32 mod + * 64 for non-UD QPs. + */ + qp->max_inline_data = wqe_size - + sizeof (struct mlx4_wqe_inline_seg) * + (align(wqe_size, MLX4_INLINE_ALIGN) / MLX4_INLINE_ALIGN); + cap->max_inline_data = qp->max_inline_data; +} + +struct mlx4_qp *mlx4_find_qp(struct mlx4_context *ctx, uint32_t qpn) +{ + int tind = (qpn & (ctx->num_qps - 1)) >> ctx->qp_table_shift; + + if (ctx->qp_table[tind].refcnt) + return ctx->qp_table[tind].table[qpn & ctx->qp_table_mask]; + else + return NULL; +} + +int mlx4_store_qp(struct mlx4_context *ctx, uint32_t qpn, struct mlx4_qp *qp) +{ + int tind = (qpn & (ctx->num_qps - 1)) >> ctx->qp_table_shift; + + if (!ctx->qp_table[tind].refcnt) { + ctx->qp_table[tind].table = calloc(ctx->qp_table_mask + 1, + sizeof (struct mlx4_qp *)); + if (!ctx->qp_table[tind].table) + return -1; + } + + ++ctx->qp_table[tind].refcnt; + ctx->qp_table[tind].table[qpn & ctx->qp_table_mask] = qp; + return 0; +} + +void mlx4_clear_qp(struct mlx4_context *ctx, uint32_t qpn) +{ + int tind = (qpn & (ctx->num_qps - 1)) >> ctx->qp_table_shift; + + if (!--ctx->qp_table[tind].refcnt) + free(ctx->qp_table[tind].table); + else + ctx->qp_table[tind].table[qpn & ctx->qp_table_mask] = NULL; +} diff --git a/contrib/ofed/libmlx4/src/srq.c b/contrib/ofed/libmlx4/src/srq.c new file mode 100644 index 000000000000..6dfbe1b902cc --- /dev/null +++ b/contrib/ofed/libmlx4/src/srq.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2007 Cisco, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include "mlx4.h" +#include "doorbell.h" +#include "wqe.h" + +static void *get_wqe(struct mlx4_srq *srq, int n) +{ + return srq->buf.buf + (n << srq->wqe_shift); +} + +void mlx4_free_srq_wqe(struct mlx4_srq *srq, int ind) +{ + struct mlx4_wqe_srq_next_seg *next; + + pthread_spin_lock(&srq->lock); + + next = get_wqe(srq, srq->tail); + next->next_wqe_index = htons(ind); + srq->tail = ind; + + pthread_spin_unlock(&srq->lock); +} + +int mlx4_post_srq_recv(struct ibv_srq *ibsrq, + struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr) +{ + struct mlx4_srq *srq = to_msrq(ibsrq); + struct mlx4_wqe_srq_next_seg *next; + struct mlx4_wqe_data_seg *scat; + int err = 0; + int nreq; + int i; + + pthread_spin_lock(&srq->lock); + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + if (wr->num_sge > srq->max_gs) { + err = -1; + *bad_wr = wr; + break; + } + + if (srq->head == srq->tail) { + /* SRQ is full*/ + err = -1; + *bad_wr = wr; + break; + } + + srq->wrid[srq->head] = wr->wr_id; + + next = get_wqe(srq, srq->head); + srq->head = ntohs(next->next_wqe_index); + scat = (struct mlx4_wqe_data_seg *) (next + 1); + + for (i = 0; i < wr->num_sge; ++i) { + scat[i].byte_count = htonl(wr->sg_list[i].length); + scat[i].lkey = htonl(wr->sg_list[i].lkey); + scat[i].addr = htonll(wr->sg_list[i].addr); + } + + if (i < srq->max_gs) { + scat[i].byte_count = 0; + scat[i].lkey = htonl(MLX4_INVALID_LKEY); + scat[i].addr = 0; + } + } + + if (nreq) { + srq->counter += nreq; + + /* + * Make sure that descriptors are written before + * we write doorbell record. + */ + wmb(); + + *srq->db = htonl(srq->counter); + } + + pthread_spin_unlock(&srq->lock); + + return err; +} + +int mlx4_alloc_srq_buf(struct ibv_pd *pd, struct ibv_srq_attr *attr, + struct mlx4_srq *srq) +{ + struct mlx4_wqe_srq_next_seg *next; + struct mlx4_wqe_data_seg *scatter; + int size; + int buf_size; + int i; + + srq->wrid = malloc(srq->max * sizeof (uint64_t)); + if (!srq->wrid) + return -1; + + size = sizeof (struct mlx4_wqe_srq_next_seg) + + srq->max_gs * sizeof (struct mlx4_wqe_data_seg); + + for (srq->wqe_shift = 5; 1 << srq->wqe_shift < size; ++srq->wqe_shift) + ; /* nothing */ + + buf_size = srq->max << srq->wqe_shift; + + if (mlx4_alloc_buf(&srq->buf, buf_size, + to_mdev(pd->context->device)->page_size)) { + free(srq->wrid); + return -1; + } + + memset(srq->buf.buf, 0, buf_size); + + /* + * Now initialize the SRQ buffer so that all of the WQEs are + * linked into the list of free WQEs. + */ + + for (i = 0; i < srq->max; ++i) { + next = get_wqe(srq, i); + next->next_wqe_index = htons((i + 1) & (srq->max - 1)); + + for (scatter = (void *) (next + 1); + (void *) scatter < (void *) next + (1 << srq->wqe_shift); + ++scatter) + scatter->lkey = htonl(MLX4_INVALID_LKEY); + } + + srq->head = 0; + srq->tail = srq->max - 1; + + return 0; +} + +struct mlx4_srq *mlx4_find_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn) +{ + int tind = (xrc_srqn & (ctx->num_xrc_srqs - 1)) >> ctx->xrc_srq_table_shift; + + if (ctx->xrc_srq_table[tind].refcnt) + return ctx->xrc_srq_table[tind].table[xrc_srqn & ctx->xrc_srq_table_mask]; + else + return NULL; +} + +int mlx4_store_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn, + struct mlx4_srq *srq) +{ + int tind = (xrc_srqn & (ctx->num_xrc_srqs - 1)) >> ctx->xrc_srq_table_shift; + int ret = 0; + + pthread_mutex_lock(&ctx->xrc_srq_table_mutex); + + if (!ctx->xrc_srq_table[tind].refcnt) { + ctx->xrc_srq_table[tind].table = calloc(ctx->xrc_srq_table_mask + 1, + sizeof(struct mlx4_srq *)); + if (!ctx->xrc_srq_table[tind].table) { + ret = -1; + goto out; + } + } + + ++ctx->xrc_srq_table[tind].refcnt; + ctx->xrc_srq_table[tind].table[xrc_srqn & ctx->xrc_srq_table_mask] = srq; + +out: + pthread_mutex_unlock(&ctx->xrc_srq_table_mutex); + return ret; +} + +void mlx4_clear_xrc_srq(struct mlx4_context *ctx, uint32_t xrc_srqn) +{ + int tind = (xrc_srqn & (ctx->num_xrc_srqs - 1)) >> ctx->xrc_srq_table_shift; + + pthread_mutex_lock(&ctx->xrc_srq_table_mutex); + + if (!--ctx->xrc_srq_table[tind].refcnt) + free(ctx->xrc_srq_table[tind].table); + else + ctx->xrc_srq_table[tind].table[xrc_srqn & ctx->xrc_srq_table_mask] = NULL; + + pthread_mutex_unlock(&ctx->xrc_srq_table_mutex); +} + diff --git a/contrib/ofed/libmlx4/src/verbs.c b/contrib/ofed/libmlx4/src/verbs.c new file mode 100644 index 000000000000..45e86935a37f --- /dev/null +++ b/contrib/ofed/libmlx4/src/verbs.c @@ -0,0 +1,897 @@ +/* + * Copyright (c) 2007 Cisco, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include "mlx4.h" +#include "mlx4-abi.h" +#include "wqe.h" + +int mlx4_query_device(struct ibv_context *context, struct ibv_device_attr *attr) +{ + struct ibv_query_device cmd; + uint64_t raw_fw_ver; + unsigned major, minor, sub_minor; + int ret; + + ret = ibv_cmd_query_device(context, attr, &raw_fw_ver, &cmd, sizeof cmd); + if (ret) + return ret; + + major = (raw_fw_ver >> 32) & 0xffff; + minor = (raw_fw_ver >> 16) & 0xffff; + sub_minor = raw_fw_ver & 0xffff; + + snprintf(attr->fw_ver, sizeof attr->fw_ver, + "%d.%d.%03d", major, minor, sub_minor); + + return 0; +} + +int mlx4_query_port(struct ibv_context *context, uint8_t port, + struct ibv_port_attr *attr) +{ + struct ibv_query_port cmd; + + return ibv_cmd_query_port(context, port, attr, &cmd, sizeof cmd); +} + +struct ibv_pd *mlx4_alloc_pd(struct ibv_context *context) +{ + struct ibv_alloc_pd cmd; + struct mlx4_alloc_pd_resp resp; + struct mlx4_pd *pd; + + pd = malloc(sizeof *pd); + if (!pd) + return NULL; + + if (ibv_cmd_alloc_pd(context, &pd->ibv_pd, &cmd, sizeof cmd, + &resp.ibv_resp, sizeof resp)) { + free(pd); + return NULL; + } + + pd->pdn = resp.pdn; + + return &pd->ibv_pd; +} + +int mlx4_free_pd(struct ibv_pd *pd) +{ + int ret; + + ret = ibv_cmd_dealloc_pd(pd); + if (ret) + return ret; + + free(to_mpd(pd)); + return 0; +} + +struct ibv_mr *mlx4_reg_mr(struct ibv_pd *pd, void *addr, size_t length, + enum ibv_access_flags access) +{ + struct ibv_mr *mr; + struct ibv_reg_mr cmd; + int ret; + + mr = malloc(sizeof *mr); + if (!mr) + return NULL; + +#ifdef IBV_CMD_REG_MR_HAS_RESP_PARAMS + { + struct ibv_reg_mr_resp resp; + + ret = ibv_cmd_reg_mr(pd, addr, length, (uintptr_t) addr, + access, mr, &cmd, sizeof cmd, + &resp, sizeof resp); + } +#else + ret = ibv_cmd_reg_mr(pd, addr, length, (uintptr_t) addr, access, mr, + &cmd, sizeof cmd); +#endif + if (ret) { + free(mr); + return NULL; + } + + return mr; +} + +int mlx4_dereg_mr(struct ibv_mr *mr) +{ + int ret; + + ret = ibv_cmd_dereg_mr(mr); + if (ret) + return ret; + + free(mr); + return 0; +} + +static int align_queue_size(int req) +{ + int nent; + + for (nent = 1; nent < req; nent <<= 1) + ; /* nothing */ + + return nent; +} + +struct ibv_cq *mlx4_create_cq(struct ibv_context *context, int cqe, + struct ibv_comp_channel *channel, + int comp_vector) +{ + struct mlx4_create_cq cmd; + struct mlx4_create_cq_resp resp; + struct mlx4_cq *cq; + int ret; + + /* Sanity check CQ size before proceeding */ + if (cqe > 0x3fffff) + return NULL; + + cq = malloc(sizeof *cq); + if (!cq) + return NULL; + + cq->cons_index = 0; + + if (pthread_spin_init(&cq->lock, PTHREAD_PROCESS_PRIVATE)) + goto err; + + cqe = align_queue_size(cqe + 1); + + if (mlx4_alloc_cq_buf(to_mdev(context->device), &cq->buf, cqe)) + goto err; + + cq->set_ci_db = mlx4_alloc_db(to_mctx(context), MLX4_DB_TYPE_CQ); + if (!cq->set_ci_db) + goto err_buf; + + cq->arm_db = cq->set_ci_db + 1; + *cq->arm_db = 0; + cq->arm_sn = 1; + *cq->set_ci_db = 0; + + cmd.buf_addr = (uintptr_t) cq->buf.buf; + cmd.db_addr = (uintptr_t) cq->set_ci_db; + + ret = ibv_cmd_create_cq(context, cqe - 1, channel, comp_vector, + &cq->ibv_cq, &cmd.ibv_cmd, sizeof cmd, + &resp.ibv_resp, sizeof resp); + if (ret) + goto err_db; + + cq->cqn = resp.cqn; + + return &cq->ibv_cq; + +err_db: + mlx4_free_db(to_mctx(context), MLX4_DB_TYPE_CQ, cq->set_ci_db); + +err_buf: + mlx4_free_buf(&cq->buf); + +err: + free(cq); + + return NULL; +} + +int mlx4_resize_cq(struct ibv_cq *ibcq, int cqe) +{ + struct mlx4_cq *cq = to_mcq(ibcq); + struct mlx4_resize_cq cmd; + struct mlx4_buf buf; + int old_cqe, outst_cqe, ret; + + /* Sanity check CQ size before proceeding */ + if (cqe > 0x3fffff) + return EINVAL; + + pthread_spin_lock(&cq->lock); + + cqe = align_queue_size(cqe + 1); + if (cqe == ibcq->cqe + 1) { + ret = 0; + goto out; + } + + /* Can't be smaller then the number of outstanding CQEs */ + outst_cqe = mlx4_get_outstanding_cqes(cq); + if (cqe < outst_cqe + 1) { + ret = 0; + goto out; + } + + ret = mlx4_alloc_cq_buf(to_mdev(ibcq->context->device), &buf, cqe); + if (ret) + goto out; + + old_cqe = ibcq->cqe; + cmd.buf_addr = (uintptr_t) buf.buf; + +#ifdef IBV_CMD_RESIZE_CQ_HAS_RESP_PARAMS + { + struct ibv_resize_cq_resp resp; + ret = ibv_cmd_resize_cq(ibcq, cqe - 1, &cmd.ibv_cmd, sizeof cmd, + &resp, sizeof resp); + } +#else + ret = ibv_cmd_resize_cq(ibcq, cqe - 1, &cmd.ibv_cmd, sizeof cmd); +#endif + if (ret) { + mlx4_free_buf(&buf); + goto out; + } + + mlx4_cq_resize_copy_cqes(cq, buf.buf, old_cqe); + + mlx4_free_buf(&cq->buf); + cq->buf = buf; + +out: + pthread_spin_unlock(&cq->lock); + return ret; +} + +int mlx4_destroy_cq(struct ibv_cq *cq) +{ + int ret; + + ret = ibv_cmd_destroy_cq(cq); + if (ret) + return ret; + + mlx4_free_db(to_mctx(cq->context), MLX4_DB_TYPE_CQ, to_mcq(cq)->set_ci_db); + mlx4_free_buf(&to_mcq(cq)->buf); + free(to_mcq(cq)); + + return 0; +} + +struct ibv_srq *mlx4_create_srq(struct ibv_pd *pd, + struct ibv_srq_init_attr *attr) +{ + struct mlx4_create_srq cmd; + struct mlx4_create_srq_resp resp; + struct mlx4_srq *srq; + int ret; + + /* Sanity check SRQ size before proceeding */ + if (attr->attr.max_wr > 1 << 16 || attr->attr.max_sge > 64) + return NULL; + + srq = malloc(sizeof *srq); + if (!srq) + return NULL; + + if (pthread_spin_init(&srq->lock, PTHREAD_PROCESS_PRIVATE)) + goto err; + + srq->max = align_queue_size(attr->attr.max_wr + 1); + srq->max_gs = attr->attr.max_sge; + srq->counter = 0; + + if (mlx4_alloc_srq_buf(pd, &attr->attr, srq)) + goto err; + + srq->db = mlx4_alloc_db(to_mctx(pd->context), MLX4_DB_TYPE_RQ); + if (!srq->db) + goto err_free; + + *srq->db = 0; + + cmd.buf_addr = (uintptr_t) srq->buf.buf; + cmd.db_addr = (uintptr_t) srq->db; + + ret = ibv_cmd_create_srq(pd, &srq->ibv_srq, attr, + &cmd.ibv_cmd, sizeof cmd, + &resp.ibv_resp, sizeof resp); + if (ret) + goto err_db; + + srq->srqn = resp.srqn; + + return &srq->ibv_srq; + +err_db: + mlx4_free_db(to_mctx(pd->context), MLX4_DB_TYPE_RQ, srq->db); + +err_free: + free(srq->wrid); + mlx4_free_buf(&srq->buf); + +err: + free(srq); + + return NULL; +} + +int mlx4_modify_srq(struct ibv_srq *srq, + struct ibv_srq_attr *attr, + enum ibv_srq_attr_mask attr_mask) +{ + struct ibv_modify_srq cmd; + + return ibv_cmd_modify_srq(srq, attr, attr_mask, &cmd, sizeof cmd); +} + +int mlx4_query_srq(struct ibv_srq *srq, + struct ibv_srq_attr *attr) +{ + struct ibv_query_srq cmd; + + return ibv_cmd_query_srq(srq, attr, &cmd, sizeof cmd); +} + +int mlx4_destroy_srq(struct ibv_srq *ibsrq) +{ + struct mlx4_srq *srq = to_msrq(ibsrq); + struct mlx4_cq *mcq = NULL; + int ret; + + if (ibsrq->xrc_cq) { + /* is an xrc_srq */ + mcq = to_mcq(ibsrq->xrc_cq); + mlx4_cq_clean(mcq, 0, srq); + pthread_spin_lock(&mcq->lock); + mlx4_clear_xrc_srq(to_mctx(ibsrq->context), srq->srqn); + pthread_spin_unlock(&mcq->lock); + } + + ret = ibv_cmd_destroy_srq(ibsrq); + if (ret) { + if (ibsrq->xrc_cq) { + pthread_spin_lock(&mcq->lock); + mlx4_store_xrc_srq(to_mctx(ibsrq->context), + srq->srqn, srq); + pthread_spin_unlock(&mcq->lock); + } + return ret; + } + + mlx4_free_db(to_mctx(ibsrq->context), MLX4_DB_TYPE_RQ, srq->db); + mlx4_free_buf(&srq->buf); + free(srq->wrid); + free(srq); + + return 0; +} + +static int verify_sizes(struct ibv_qp_init_attr *attr, struct mlx4_context *context) +{ + int size; + int nsegs; + + if (attr->cap.max_send_wr > context->max_qp_wr || + attr->cap.max_recv_wr > context->max_qp_wr || + attr->cap.max_send_sge > context->max_sge || + attr->cap.max_recv_sge > context->max_sge) + return -1; + + if (attr->cap.max_inline_data) { + nsegs = num_inline_segs(attr->cap.max_inline_data, attr->qp_type); + size = MLX4_MAX_WQE_SIZE - nsegs * sizeof (struct mlx4_wqe_inline_seg); + switch (attr->qp_type) { + case IBV_QPT_UD: + size -= (sizeof (struct mlx4_wqe_ctrl_seg) + + sizeof (struct mlx4_wqe_datagram_seg)); + break; + + case IBV_QPT_RC: + case IBV_QPT_UC: + case IBV_QPT_XRC: + size -= (sizeof (struct mlx4_wqe_ctrl_seg) + + sizeof (struct mlx4_wqe_raddr_seg)); + break; + + default: + return 0; + } + + if (attr->cap.max_inline_data > size) + return -1; + } + + return 0; +} + +struct ibv_qp *mlx4_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *attr) +{ + struct mlx4_create_qp cmd; + struct ibv_create_qp_resp resp; + struct mlx4_qp *qp; + int ret; + struct mlx4_context *context = to_mctx(pd->context); + + + /* Sanity check QP size before proceeding */ + if (verify_sizes(attr, context)) + return NULL; + + qp = malloc(sizeof *qp); + if (!qp) + return NULL; + + mlx4_calc_sq_wqe_size(&attr->cap, attr->qp_type, qp); + + /* + * We need to leave 2 KB + 1 WQE of headroom in the SQ to + * allow HW to prefetch. + */ + qp->sq_spare_wqes = (2048 >> qp->sq.wqe_shift) + 1; + qp->sq.wqe_cnt = align_queue_size(attr->cap.max_send_wr + qp->sq_spare_wqes); + qp->rq.wqe_cnt = align_queue_size(attr->cap.max_recv_wr); + + if (attr->srq || attr->qp_type == IBV_QPT_XRC) + attr->cap.max_recv_wr = qp->rq.wqe_cnt = 0; + else { + if (attr->cap.max_recv_sge < 1) + attr->cap.max_recv_sge = 1; + if (attr->cap.max_recv_wr < 1) + attr->cap.max_recv_wr = 1; + } + + if (mlx4_alloc_qp_buf(pd, &attr->cap, attr->qp_type, qp)) + goto err; + + mlx4_init_qp_indices(qp); + + if (pthread_spin_init(&qp->sq.lock, PTHREAD_PROCESS_PRIVATE) || + pthread_spin_init(&qp->rq.lock, PTHREAD_PROCESS_PRIVATE)) + goto err_free; + + if (!attr->srq && attr->qp_type != IBV_QPT_XRC) { + qp->db = mlx4_alloc_db(to_mctx(pd->context), MLX4_DB_TYPE_RQ); + if (!qp->db) + goto err_free; + + *qp->db = 0; + } + + cmd.buf_addr = (uintptr_t) qp->buf.buf; + if (attr->srq || attr->qp_type == IBV_QPT_XRC) + cmd.db_addr = 0; + else + cmd.db_addr = (uintptr_t) qp->db; + cmd.log_sq_stride = qp->sq.wqe_shift; + for (cmd.log_sq_bb_count = 0; + qp->sq.wqe_cnt > 1 << cmd.log_sq_bb_count; + ++cmd.log_sq_bb_count) + ; /* nothing */ + cmd.sq_no_prefetch = 0; /* OK for ABI 2: just a reserved field */ + memset(cmd.reserved, 0, sizeof cmd.reserved); + + pthread_mutex_lock(&to_mctx(pd->context)->qp_table_mutex); + + ret = ibv_cmd_create_qp(pd, &qp->ibv_qp, attr, &cmd.ibv_cmd, sizeof cmd, + &resp, sizeof resp); + if (ret) + goto err_rq_db; + + ret = mlx4_store_qp(to_mctx(pd->context), qp->ibv_qp.qp_num, qp); + if (ret) + goto err_destroy; + pthread_mutex_unlock(&to_mctx(pd->context)->qp_table_mutex); + + qp->rq.wqe_cnt = attr->cap.max_recv_wr; + qp->rq.max_gs = attr->cap.max_recv_sge; + + /* adjust rq maxima to not exceed reported device maxima */ + attr->cap.max_recv_wr = min(context->max_qp_wr, attr->cap.max_recv_wr); + attr->cap.max_recv_sge = min(context->max_sge, attr->cap.max_recv_sge); + + qp->rq.max_post = attr->cap.max_recv_wr; + mlx4_set_sq_sizes(qp, &attr->cap, attr->qp_type); + + qp->doorbell_qpn = htonl(qp->ibv_qp.qp_num << 8); + if (attr->sq_sig_all) + qp->sq_signal_bits = htonl(MLX4_WQE_CTRL_CQ_UPDATE); + else + qp->sq_signal_bits = 0; + + return &qp->ibv_qp; + +err_destroy: + ibv_cmd_destroy_qp(&qp->ibv_qp); + +err_rq_db: + pthread_mutex_unlock(&to_mctx(pd->context)->qp_table_mutex); + if (!attr->srq && attr->qp_type != IBV_QPT_XRC) + mlx4_free_db(to_mctx(pd->context), MLX4_DB_TYPE_RQ, qp->db); + +err_free: + free(qp->sq.wrid); + if (qp->rq.wqe_cnt) + free(qp->rq.wrid); + mlx4_free_buf(&qp->buf); + +err: + free(qp); + + return NULL; +} + +int mlx4_query_qp(struct ibv_qp *ibqp, struct ibv_qp_attr *attr, + enum ibv_qp_attr_mask attr_mask, + struct ibv_qp_init_attr *init_attr) +{ + struct ibv_query_qp cmd; + struct mlx4_qp *qp = to_mqp(ibqp); + int ret; + + ret = ibv_cmd_query_qp(ibqp, attr, attr_mask, init_attr, &cmd, sizeof cmd); + if (ret) + return ret; + + init_attr->cap.max_send_wr = qp->sq.max_post; + init_attr->cap.max_send_sge = qp->sq.max_gs; + init_attr->cap.max_inline_data = qp->max_inline_data; + + attr->cap = init_attr->cap; + + return 0; +} + +int mlx4_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + enum ibv_qp_attr_mask attr_mask) +{ + struct ibv_modify_qp cmd; + int ret; + + if (qp->state == IBV_QPS_RESET && + attr_mask & IBV_QP_STATE && + attr->qp_state == IBV_QPS_INIT) { + mlx4_qp_init_sq_ownership(to_mqp(qp)); + } + + ret = ibv_cmd_modify_qp(qp, attr, attr_mask, &cmd, sizeof cmd); + + if (!ret && + (attr_mask & IBV_QP_STATE) && + attr->qp_state == IBV_QPS_RESET) { + mlx4_cq_clean(to_mcq(qp->recv_cq), qp->qp_num, + qp->srq ? to_msrq(qp->srq) : NULL); + if (qp->send_cq != qp->recv_cq) + mlx4_cq_clean(to_mcq(qp->send_cq), qp->qp_num, NULL); + + mlx4_init_qp_indices(to_mqp(qp)); + if (!qp->srq && qp->qp_type != IBV_QPT_XRC) + *to_mqp(qp)->db = 0; + } + + return ret; +} + +static void mlx4_lock_cqs(struct ibv_qp *qp) +{ + struct mlx4_cq *send_cq = to_mcq(qp->send_cq); + struct mlx4_cq *recv_cq = to_mcq(qp->recv_cq); + + if (send_cq == recv_cq) + pthread_spin_lock(&send_cq->lock); + else if (send_cq->cqn < recv_cq->cqn) { + pthread_spin_lock(&send_cq->lock); + pthread_spin_lock(&recv_cq->lock); + } else { + pthread_spin_lock(&recv_cq->lock); + pthread_spin_lock(&send_cq->lock); + } +} + +static void mlx4_unlock_cqs(struct ibv_qp *qp) +{ + struct mlx4_cq *send_cq = to_mcq(qp->send_cq); + struct mlx4_cq *recv_cq = to_mcq(qp->recv_cq); + + if (send_cq == recv_cq) + pthread_spin_unlock(&send_cq->lock); + else if (send_cq->cqn < recv_cq->cqn) { + pthread_spin_unlock(&recv_cq->lock); + pthread_spin_unlock(&send_cq->lock); + } else { + pthread_spin_unlock(&send_cq->lock); + pthread_spin_unlock(&recv_cq->lock); + } +} + +int mlx4_destroy_qp(struct ibv_qp *ibqp) +{ + struct mlx4_qp *qp = to_mqp(ibqp); + int ret; + + pthread_mutex_lock(&to_mctx(ibqp->context)->qp_table_mutex); + ret = ibv_cmd_destroy_qp(ibqp); + if (ret) { + pthread_mutex_unlock(&to_mctx(ibqp->context)->qp_table_mutex); + return ret; + } + + mlx4_lock_cqs(ibqp); + + __mlx4_cq_clean(to_mcq(ibqp->recv_cq), ibqp->qp_num, + ibqp->srq ? to_msrq(ibqp->srq) : NULL); + if (ibqp->send_cq != ibqp->recv_cq) + __mlx4_cq_clean(to_mcq(ibqp->send_cq), ibqp->qp_num, NULL); + + mlx4_clear_qp(to_mctx(ibqp->context), ibqp->qp_num); + + mlx4_unlock_cqs(ibqp); + pthread_mutex_unlock(&to_mctx(ibqp->context)->qp_table_mutex); + + if (!ibqp->srq && ibqp->qp_type != IBV_QPT_XRC) + mlx4_free_db(to_mctx(ibqp->context), MLX4_DB_TYPE_RQ, qp->db); + free(qp->sq.wrid); + if (qp->rq.wqe_cnt) + free(qp->rq.wrid); + mlx4_free_buf(&qp->buf); + free(qp); + + return 0; +} + +struct ibv_ah *mlx4_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr) +{ + struct mlx4_ah *ah; + struct ibv_port_attr port_attr; + uint8_t is_mcast; + + ah = malloc(sizeof *ah); + if (!ah) + return NULL; + + memset(ah, 0, sizeof *ah); + + ah->av.port_pd = htonl(to_mpd(pd)->pdn | (attr->port_num << 24)); + ah->av.g_slid = attr->src_path_bits; + ah->av.dlid = htons(attr->dlid); + if (attr->static_rate) { + ah->av.stat_rate = attr->static_rate + MLX4_STAT_RATE_OFFSET; + /* XXX check rate cap? */ + } + ah->av.sl_tclass_flowlabel = htonl(attr->sl << 28); + if (attr->is_global) { + ah->av.g_slid |= 0x80; + ah->av.gid_index = attr->grh.sgid_index; + ah->av.hop_limit = attr->grh.hop_limit; + ah->av.sl_tclass_flowlabel |= + htonl((attr->grh.traffic_class << 20) | + attr->grh.flow_label); + memcpy(ah->av.dgid, attr->grh.dgid.raw, 16); + } + + if (ibv_query_port(pd->context, attr->port_num, &port_attr)) + goto err; + + if (port_attr.link_layer == IBV_LINK_LAYER_ETHERNET) { + if (ibv_resolve_eth_gid(pd, attr->port_num, + (union ibv_gid *)ah->av.dgid, + attr->grh.sgid_index, + ah->mac, &ah->vlan, + &ah->tagged, &is_mcast)) + goto err; + + if (is_mcast) { + ah->av.dlid = htons(0xc000); + ah->av.port_pd |= htonl(1 << 31); + } + if (ah->tagged) { + ah->av.port_pd |= htonl(1 << 29); + ah->vlan |= (attr->sl & 7) << 13; + } + } + + + return &ah->ibv_ah; +err: + free(ah); + return NULL; +} + +int mlx4_destroy_ah(struct ibv_ah *ah) +{ + free(to_mah(ah)); + + return 0; +} + +#ifdef HAVE_IBV_XRC_OPS +struct ibv_srq *mlx4_create_xrc_srq(struct ibv_pd *pd, + struct ibv_xrc_domain *xrc_domain, + struct ibv_cq *xrc_cq, + struct ibv_srq_init_attr *attr) +{ + struct mlx4_create_xrc_srq cmd; + struct mlx4_create_srq_resp resp; + struct mlx4_srq *srq; + int ret; + + /* Sanity check SRQ size before proceeding */ + if (attr->attr.max_wr > 1 << 16 || attr->attr.max_sge > 64) + return NULL; + + srq = malloc(sizeof *srq); + if (!srq) + return NULL; + + if (pthread_spin_init(&srq->lock, PTHREAD_PROCESS_PRIVATE)) + goto err; + + srq->max = align_queue_size(attr->attr.max_wr + 1); + srq->max_gs = attr->attr.max_sge; + srq->counter = 0; + + if (mlx4_alloc_srq_buf(pd, &attr->attr, srq)) + goto err; + + srq->db = mlx4_alloc_db(to_mctx(pd->context), MLX4_DB_TYPE_RQ); + if (!srq->db) + goto err_free; + + *srq->db = 0; + + cmd.buf_addr = (uintptr_t) srq->buf.buf; + cmd.db_addr = (uintptr_t) srq->db; + + ret = ibv_cmd_create_xrc_srq(pd, &srq->ibv_srq, attr, + xrc_domain->handle, + xrc_cq->handle, + &cmd.ibv_cmd, sizeof cmd, + &resp.ibv_resp, sizeof resp); + if (ret) + goto err_db; + + srq->ibv_srq.xrc_srq_num = srq->srqn = resp.srqn; + + ret = mlx4_store_xrc_srq(to_mctx(pd->context), srq->ibv_srq.xrc_srq_num, srq); + if (ret) + goto err_destroy; + + return &srq->ibv_srq; + +err_destroy: + ibv_cmd_destroy_srq(&srq->ibv_srq); + +err_db: + mlx4_free_db(to_mctx(pd->context), MLX4_DB_TYPE_RQ, srq->db); + +err_free: + free(srq->wrid); + mlx4_free_buf(&srq->buf); + +err: + free(srq); + + return NULL; +} + +struct ibv_xrc_domain *mlx4_open_xrc_domain(struct ibv_context *context, + int fd, int oflag) +{ + int ret; + struct mlx4_open_xrc_domain_resp resp; + struct mlx4_xrc_domain *xrcd; + + xrcd = malloc(sizeof *xrcd); + if (!xrcd) + return NULL; + + ret = ibv_cmd_open_xrc_domain(context, fd, oflag, &xrcd->ibv_xrcd, + &resp.ibv_resp, sizeof resp); + if (ret) { + free(xrcd); + return NULL; + } + + xrcd->xrcdn = resp.xrcdn; + return &xrcd->ibv_xrcd; +} + +int mlx4_close_xrc_domain(struct ibv_xrc_domain *d) +{ + int ret; + ret = ibv_cmd_close_xrc_domain(d); + if (!ret) + free(d); + return ret; +} + +int mlx4_create_xrc_rcv_qp(struct ibv_qp_init_attr *init_attr, + uint32_t *xrc_qp_num) +{ + + return ibv_cmd_create_xrc_rcv_qp(init_attr, xrc_qp_num); +} + +int mlx4_modify_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num, + struct ibv_qp_attr *attr, + int attr_mask) +{ + return ibv_cmd_modify_xrc_rcv_qp(xrc_domain, xrc_qp_num, + attr, attr_mask); +} + +int mlx4_query_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num, + struct ibv_qp_attr *attr, + int attr_mask, + struct ibv_qp_init_attr *init_attr) +{ + int ret; + + ret = ibv_cmd_query_xrc_rcv_qp(xrc_domain, xrc_qp_num, + attr, attr_mask, init_attr); + if (ret) + return ret; + + init_attr->cap.max_send_wr = init_attr->cap.max_send_sge = 1; + init_attr->cap.max_recv_sge = init_attr->cap.max_recv_wr = 0; + init_attr->cap.max_inline_data = 0; + init_attr->recv_cq = init_attr->send_cq = NULL; + init_attr->srq = NULL; + init_attr->xrc_domain = xrc_domain; + init_attr->qp_type = IBV_QPT_XRC; + init_attr->qp_context = NULL; + attr->cap = init_attr->cap; + + return 0; +} + +int mlx4_reg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num) +{ + return ibv_cmd_reg_xrc_rcv_qp(xrc_domain, xrc_qp_num); +} + +int mlx4_unreg_xrc_rcv_qp(struct ibv_xrc_domain *xrc_domain, + uint32_t xrc_qp_num) +{ + return ibv_cmd_unreg_xrc_rcv_qp(xrc_domain, xrc_qp_num); +} + +#endif diff --git a/contrib/ofed/libmlx4/src/wqe.h b/contrib/ofed/libmlx4/src/wqe.h new file mode 100644 index 000000000000..92f88dd907b2 --- /dev/null +++ b/contrib/ofed/libmlx4/src/wqe.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2007 Cisco, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef WQE_H +#define WQE_H + +enum { + MLX4_SEND_DOORBELL = 0x14, +}; + +enum { + MLX4_WQE_CTRL_FENCE = 1 << 6, + MLX4_WQE_CTRL_CQ_UPDATE = 3 << 2, + MLX4_WQE_CTRL_SOLICIT = 1 << 1, +}; + +enum { + MLX4_INLINE_SEG = 1 << 31, + MLX4_INLINE_ALIGN = 64, +}; + +enum { + MLX4_INVALID_LKEY = 0x100, +}; + +struct mlx4_wqe_ctrl_seg { + uint32_t owner_opcode; + uint16_t vlan_tag; + uint8_t ins_vlan; + uint8_t fence_size; + /* + * High 24 bits are SRC remote buffer; low 8 bits are flags: + * [7] SO (strong ordering) + * [5] TCP/UDP checksum + * [4] IP checksum + * [3:2] C (generate completion queue entry) + * [1] SE (solicited event) + * [0] FL (force loopback) + */ + uint32_t xrcrb_flags; + /* + * imm is immediate data for send/RDMA write w/ immediate; + * also invalidation key for send with invalidate; input + * modifier for WQEs on CCQs. + */ + uint32_t imm; +}; + +struct mlx4_wqe_datagram_seg { + uint32_t av[8]; + uint32_t dqpn; + uint32_t qkey; + uint16_t vlan; + uint8_t mac[6]; +}; + +struct mlx4_wqe_data_seg { + uint32_t byte_count; + uint32_t lkey; + uint64_t addr; +}; + +struct mlx4_wqe_inline_seg { + uint32_t byte_count; +}; + +struct mlx4_wqe_srq_next_seg { + uint16_t reserved1; + uint16_t next_wqe_index; + uint32_t reserved2[3]; +}; + +struct mlx4_wqe_raddr_seg { + uint64_t raddr; + uint32_t rkey; + uint32_t reserved; +}; + +struct mlx4_wqe_atomic_seg { + uint64_t swap_add; + uint64_t compare; +}; + +struct mlx4_wqe_bind_seg { + uint32_t flags1; + uint32_t flags2; + uint32_t new_rkey; + uint32_t lkey; + uint64_t addr; + uint64_t length; +}; + +#endif /* WQE_H */ diff --git a/contrib/ofed/libmthca/AUTHORS b/contrib/ofed/libmthca/AUTHORS new file mode 100644 index 000000000000..165aea78cd02 --- /dev/null +++ b/contrib/ofed/libmthca/AUTHORS @@ -0,0 +1,2 @@ +Roland Dreier +Michael S. Tsirkin diff --git a/contrib/ofed/libmthca/COPYING b/contrib/ofed/libmthca/COPYING new file mode 100644 index 000000000000..ee1a79ffabf6 --- /dev/null +++ b/contrib/ofed/libmthca/COPYING @@ -0,0 +1,378 @@ +This software is available to you under a choice of one of two +licenses. You may choose to be licensed under the terms of the the +OpenIB.org BSD license or the GNU General Public License (GPL) Version +2, both included below. + +Copyright (c) 2004 Topspin Communications. All rights reserved. + +================================================================== + + OpenIB.org BSD license + +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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +================================================================== + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/ofed/libmthca/ChangeLog b/contrib/ofed/libmthca/ChangeLog new file mode 100644 index 000000000000..015ed3881f05 --- /dev/null +++ b/contrib/ofed/libmthca/ChangeLog @@ -0,0 +1,378 @@ +2006-11-09 Roland Dreier + + * Release version 1.0.3. + +2006-10-17 Roland Dreier + + * src/cq.c, src/qp.c, src/srq.c: Convert existing uses of mb() to + rmb() or wmb() as appropriate. In fact all memory barriers were + really just wmb(), except for the barrier between reading a CQE's + ownership bit and contents, which should be rmb(). + + * src/mthca.h: Add compatibility defines of rmb()/wmb() so that + libmthca continues to build against old libibverbs releases. + +2006-10-03 Roland Dreier + + * src/cq.c (mthca_poll_one): Annotate so that Valgrind knows + contents of CQ entry are all valid after they are written by HCA. + (set_cqe_hw): Annotate so that CQ entries owned by hardware are + not defined. + + * src/mthca.h: Add wrapper for VALGRIND_MAKE_MEM_DEFINED so that + it can be used in .c files without worrying about whether Valgrind + is installed or enabled. + + * configure.in: Add support for Valgrind annotation (enabled with + --with-valgrind option to configure). + + * src/verbs.c (mthca_create_qp): Set reserved fields to 0 to avoid + future problems and also to make Valgrind a little quieter. + +2006-09-04 Roland Dreier + + * src/verbs.c (mthca_destroy_qp): Avoid potential AB-BA deadlock + when destroying QPs by always taking CQ locks in a consistent + order (lowest CQN first). The old code always took the send_cq + lock first, which is prone to deadlock if the send_cq of one QP is + the recv_cq of another QP destroyed at the same time. This bug + was pointed out by Dotan Barak and Jack Morgenstein. + +2006-08-23 Roland Dreier + + * src/verbs.c (mthca_resize_cq): Add a test for + IBV_CMD_RESIZE_CQ_HAS_RESP_PARAMS to make libmthca work with newer + libibverbs libraries that add two parameters to ibv_cmd_resize_cq(). + +2006-08-09 Michael S. Tsirkin + + * src/qp.c (mthca_tavor_post_send, mthca_arbel_post_send): Fence + bit must be set in both doorbell and WQE. + +2006-08-03 Jack Morgenstein + + * src/mthca.h: Include to get definition of offsetof(). + +2006-08-03 Michael S. Tsirkin + + * src/verbs.c (mthca_create_srq): Limit SRQ max_wr to avoid + integer overflow. + +2006-07-26 Roland Dreier + + * src/mthca.h, src/ah.c, src/cq.c, src/memfree.c, src/qp.c, + src/srq.c, src/verbs.c: Convert internal allocations for AH pages + (for non-memfree HCAs), CQ buffers, doorbell pages (for memfree + HCAs), QP buffers and SRQ buffers to use the new buffer + allocator. This makes libmthca fork()-clean when built against + libibverbs 1.1. + + * src/buf.c (mthca_alloc_buf, mthca_free_buf): Add new functions + to wrap up allocating page-aligned buffers. The new functions + will call ibv_dontfork_range()/ibv_dofork_range() to do proper + madvise()ing to handle fork(), if applicable. + + * configure.in: Check for ibv_dontfork_range() and ibv_dontfork_range(). + +2006-07-04 Dotan Barak + + * src/verbs.c (mthca_create_cq, mthca_resize_cq): Passing huge + size values to create_cq/resize_cq causes a hang in + align_cq_size(). Fix this by validating input, similiar to what + we do for mthca_create_qp() and mthca_create_srq(). + +2006-06-13 Roland Dreier + + * Release version 1.0.2. + +2006-06-13 Michael S. Tsirkin + + * src/cq.c (mthca_poll_one): Add workaround for MemFree FW bug + that causes wrong WQE addr to be reported. + +2006-05-24 Roland Dreier + + * src/mthca.c: If is detected, include it + explicitly. This lets things build when sysfs headers are + installed on the build system even when building against + libibverbs 1.1 (which does not include sysfs headers implicitly). + + * src/ah.c, src/cq.c, src/memfree.c, src/mthca.c, src/qp.c, + src/srq.c: Add include of , since it may no long be + implicitly included from libsysfs headers when building with + libibverbs 1.1. + +2006-05-24 Michael S. Tsirkin + + * src/srq.c (mthca_tavor_post_srq_recv): Fix posting of lists of + receives that have exactly a multiple of 256 entries (same as QP + bug fixed below). + +2006-05-22 Roland Dreier + + * configure.in, src/mthca.c (openib_driver_init): Check for the + presence of , and if it is not installed, don't + export the old openib_driver_init() entry point. + +2006-05-18 Michael S. Tsirkin + + * src/qp.c (mthca_tavor_post_recv): Fix posting of lists of + receives that have exactly a multiple of 256 entries. + +2006-05-08 Jack Morgenstein + + * src/mthca.c: Add include files needed for open() if + HAVE_IBV_READ_SYSFS_FILE is not defined (so libmthca includes a + private local definition of ibv_read_sysfs_file()). + +2006-04-11 Roland Dreier + + * src/mthca.c (ibv_driver_init, openib_driver_init): Add new + forward-compatible driver entry point. Make old entry point a + simple wrapper for the new one. + +2006-03-14 Roland Dreier + + * Release version 1.0.1. + + * Makefile.am (EXTRA_DIST): Remove debian/ directory from + tarballs, since Debian policy is that upstream tarballs should not + include it. + +2006-03-13 Roland Dreier + + * Release version 1.0. + +2006-02-27 Dotan Barak + + * src/qp.c (mthca_tavor_post_send, mthca_arbel_post_send): Add + support for IBV_SEND_FENCE flag. + +2006-02-16 Roland Dreier + + * src/memfree.c (mthca_alloc_db): Introduce a temporary variable + to pass to posix_memalign() to avoid "warning: dereferencing + type-punned pointer will break strict-aliasing rules." + + * Release version 1.0-rc7. + +2006-02-15 Roland Dreier + + * src/verbs.c (mthca_create_qp): Update to add new response and + response size parameters for libibverbs ibv_cmd_create_qp(). + +2006-02-14 Roland Dreier + + * Release version 1.0-rc6. + +2006-02-13 Dotan Barak + + * src/verbs.c (mthca_query_qp, mthca_query_srq): Add query QP and + query SRQ verbs. + +2006-01-31 Roland Dreier + + * src/mthca.h: Remove useless "extern" from function declarations. + +2006-01-30 Michael S. Tsirkin + + * src/qp.c (mthca_tavor_post_recv, mthca_arbel_post_recv): Pass + recv_cq to wq_overflow() so we lock the correct CQ. Noticed by + Yossi Leybovich. + +2006-01-26 Roland Dreier + + * src/mthca.h, src/verbs.c, src/cq.c, src/mthca.c: Add + implementation of resize CQ operation. + + * src/mthca-abi.h: Add mthca-specific resize CQ ABI. + +2006-01-22 Roland Dreier + + * Release version 1.0-rc5. + +2006-01-11 Jack Morgenstein + + * src/verbs.c (mthca_free_pd): Free pointer to correct structure + (we get lucky now, but don't rely on this). + * src/mthca.c (mthca_free_context): Free context's PD so we don't + leak it. + +2006-01-06 Michael S. Tsirkin + + * src/verbs.c (mthca_destroy_qp): Jack Morgenstein has discovered + the following race condition in libmthca: + + Thread A destroys QP A at the kernel side by calling + ibv_cmd_destroy_qp, but its time-slice is over before removing it + from the user-space qp_table removal. + + Thread B allocates QP B, receiving a QP number that matches the + just-destroyed QP A in the low 16 bits. Thread B will now + over-write the slot in qp_table which was used for QP A. + + Thread A wakes up and clears qp_table slot, in effect removing QP + B from qp_table. + + As a solution, remove the QP from qp_table before calling + ibv_cmd_destroy_qp. This also makes sense since operations are + performed in the reverse order in create_qp. + + * src/cq.c (handle_error_cqe): Fill in vendor_err field for + completions with error. + +2006-01-05 Jack Morgenstein + + * src/verbs.c (mthca_destroy_qp, mthca_destroy_srq): Free QP/SRQ + object to avoid memory leak. + +2005-12-15 Jack Morgenstein + + * src/cq.c (mthca_cq_clean): When cleaning up a CQ, we should free + an SRQ WQE if and only if the CQE is a receive. + +2005-12-15 Michael S. Tsirkin + + * src/qp.c (mthca_store_qp): Don't increment qp_table ref count if + allocation fails. + +2005-11-29 Michael S. Tsirkin + + * src/qp.c (mthca_arbel_post_send): Add handling for posting long + send lists for mem-free HCAs. + * src/qp.c (mthca_tavor_post_recv): Fix posting long receive + lists: nreq is set to zero early on, so we need to use + MTHCA_TAVOR_MAX_WQES_PER_RECV_DB as the increment to rq.head. + +2005-11-28 Roland Dreier + + * src/qp.c (mthca_init_qp_indices): Set qp->sq.last and + qp->rq.last so that QP is fully reset when the indices are + reinited on transition to RESET state. + (mthca_tavor_post_send, mthca_arbel_post_send): Don't create an + inline send segment when a work request is posted that has the + inline flag set but no gather entries included. + +2005-11-09 Roland Dreier + + * src/srq.c (mthca_tavor_post_srq_recv), src/qp.c + (mthca_tavor_post_recv): Fix bugs in long receive list handling; + need to set nreq to 0 and not put 256 credits into the second + doorbell word. + + * src/cq.c (mthca_cq_clean): Handle case where CQ indices wrap + around by treating signed comparisons of prod_index and + cq->cons_index carefully. + +2005-11-09 Michael S. Tsirkin + + * src/srq.c (mthca_tavor_post_srq_recv), src/qp.c + (mthca_tavor_post_recv): Tavor requires that a doorbell be rung + at least every 256 receives, so add code to ring doorbells in the + middle of posting a huge list of receives. + + * src/qp.c (mthca_tavor_post_send, mthca_tavor_post_send): When + posting atomic operations, could wqe size in "octowords" correctly. + + * src/ah.c (mthca_alloc_av): Don't free ah if page allocation + fails. It will be freed where it's allocated, in the caller. + +2005-11-08 Roland Dreier + + * src/qp.c, src/verbs.c, src/mthca.h: Delegate setting of QP + capabilities (max_sge, max_inline_data, etc) to kernel. + +2005-11-04 Roland Dreier + + * src/verbs.c (mthca_destroy_qp): Clean CQEs when we destroy a QP. + (mthca_modify_qp): Clean CQEs when we move a QP to RESET state, + and reset QP index pointers. + + * src/cq.c (mthca_cq_clean): Add function to clean out CQEs for + QPs that are being destroyed or reset. + +2005-10-30 Roland Dreier + + * src/srq.c (wqe_to_link): Change to use an offset of 12 (the imm + field), because posting an SRQ WQE may actually change the ee_nds + field and still cause free list corruption. A receive WQE will + never have immediate data, so using imm is definitely safe. + +2005-10-25 Roland Dreier + + * Release version 1.0-rc4. + +2005-10-23 Roland Dreier + + * src/qp.c (mthca_return_cap, mthca_alloc_qp_buf), src/verbs.c + (mthca_create_qp): Explicitly pass QP type to functions used while + creating QP, since we can't rely on ibv_qp.qp_type to be set until + after we return. This fixes breakage with UD QPs introduced in + the last change below. + +2005-10-19 Roland Dreier + + * src/mthca.h, src/verbs.c (mthca_create_qp), src/qp.c + (mthca_tavor_post_send, mthca_arbel_post_send, mthca_alloc_qp_buf, + mthca_return_cap): Eliminate struct mthca_qp.qpt field and use + struct ibv_qp.qp_type instead (now that that field has been added + in libibverbs). + +2005-10-18 Roland Dreier + + * src/cq.c (handle_error_cqe, mthca_poll_one): Dump CQEs for local + QP operation errors instead of all error statuses. + +2005-10-06 Roland Dreier + + * src/srq.c (mthca_free_srq_wqe): Pass index instead of WQE + address. The only caller already has the index handy, so there's + no need to recalculate it here. + + * src/srq.c (mthca_tavor_post_srq_recv, + mthca_arbel_post_srq_recv): Add an extra check so that we report + the SRQ as full before using the one extra WQE we need internally. + +2005-10-05 Roland Dreier + + * src/verbs.c (mthca_modify_srq): Fill in mthca_modify_srq(). + +2005-09-29 Roland Dreier + + * src/verbs.c (mthca_query_device): Update to match new libibverbs + API that requires device-specific libraries to format firmware version. + +2005-09-25 Roland Dreier + + * src/cq.c, src/mthca.c, src/mthca.h, src/verbs.c: Update to match + new libibverbs API introduced with completion channel implementation. + +2005-09-13 Roland Dreier + + * src/qp.c (mthca_tavor_post_send, mthca_tavor_post_recv, + mthca_arbel_post_send), src/srq.c (mthca_tavor_post_srq_recv): + Apply Michael S. Tsirkin's patch to fix linking of WQEs on + mem-free HCAs. While we're at it, simplify the Tavor WQE posting + code as well -- there's no need for a conditional, just always lik + the previous WQE. + +2005-09-07 Roland Dreier + + * src/mthca.h: Get rid of ntohll() and htonll() now that + libibverbs defines them in . + +2005-08-31 Roland Dreier + + * src/memfree.c (mthca_free_db): When we free a doorbell record, + really mark it as free in the free bitmap. This we we don't + eventually run out of doorbells if a consumer creates and frees a + lot of objects. + + * src/memfree.c (mthca_alloc_db): Introduce MTHCA_FREE_MAP_SIZE so + that we iterate over the correct number of entries in the mem-free + doorbell record free maps. This fixes some off-by-a-factor-of-8 + bugs that could lead to crashes. + + * src/verbs.c (mthca_create_cq): In the mem-free case, when + creating a CQ fails to allocate an arm doorbell, make sure we free + the set CI doorbell instead of the (non-existent) arm doorbell. diff --git a/contrib/ofed/libmthca/Makefile.am b/contrib/ofed/libmthca/Makefile.am new file mode 100644 index 000000000000..e9be461693cd --- /dev/null +++ b/contrib/ofed/libmthca/Makefile.am @@ -0,0 +1,29 @@ +AM_CFLAGS = -g -Wall -D_GNU_SOURCE + +mthca_version_script = @MTHCA_VERSION_SCRIPT@ + +MTHCA_SOURCES = src/ah.c src/buf.c src/cq.c src/memfree.c src/mthca.c \ + src/qp.c src/srq.c src/verbs.c + +if HAVE_IBV_DEVICE_LIBRARY_EXTENSION + lib_LTLIBRARIES = src/libmthca.la + src_libmthca_la_SOURCES = $(MTHCA_SOURCES) + src_libmthca_la_LDFLAGS = -avoid-version -release @IBV_DEVICE_LIBRARY_EXTENSION@ \ + $(mthca_version_script) + mthcaconfdir = $(sysconfdir)/libibverbs.d + mthcaconf_DATA = mthca.driver +else + mthcalibdir = $(libdir)/infiniband + mthcalib_LTLIBRARIES = src/mthca.la + src_mthca_la_SOURCES = $(MTHCA_SOURCES) + src_mthca_la_LDFLAGS = -avoid-version -module $(mthca_version_script) +endif + +DEBIAN = debian/changelog debian/compat debian/control debian/copyright \ + debian/libmthca1.install debian/libmthca-dev.install debian/rules + +EXTRA_DIST = src/doorbell.h src/mthca.h src/mthca-abi.h src/wqe.h \ + src/mthca.map libmthca.spec.in mthca.driver + +dist-hook: libmthca.spec + cp libmthca.spec $(distdir) diff --git a/contrib/ofed/libmthca/README b/contrib/ofed/libmthca/README new file mode 100644 index 000000000000..88636f8f6857 --- /dev/null +++ b/contrib/ofed/libmthca/README @@ -0,0 +1,59 @@ +Introduction +============ + +libmthca is a userspace driver for Mellanox InfiniBand HCAs. It works +as a plug-in module for libibverbs that allows programs to use +Mellanox hardware directly from userspace. See the libibverbs package +for more information. + +Using libmthca +============== + +libmthca will be loaded and used automatically by programs linked with +libibverbs. The ib_mthca kernel module must be loaded for HCA devices +to be detected and used. + +Supported Hardware +================== + +libmthca currently supports HCAs based on the following Mellanox chips: + + MT23108 InfiniHost (PCI-X) + MT25208 InfiniHost III Ex (PCI Express) + MT25204 InfiniHost III Lx (PCI Express) + +Both non-DDR and DDR HCAs are supported, and the MT25208 is supported +with both MT23108-compatible and native MemFree firmware. + +Valgrind Support +================ + +When running applications that use libibverbs under the Valgrind +memory-checking debugger, Valgrind will falsely report "read from +uninitialized" for memory that was initialized by the kernel drivers +or HCA hardware. Specifically, Valgrind cannot see when kernel +drivers or HCA hardware write to userspace memory, so when the process +reads from that memory, Valgrind incorrectly assumes that the memory +contents are uninitialized, and therefore raises a warning. + +libmthca can be built with specific support for the Valgrind +memory-checking debugger by specifying the --with-valgrind command +line argument to configure. This flag enables code in libibverbs to +tell Valgrind "this memory may look uninitialized, but it's really +OK," which therefore suppresses the incorrect "read from +uninitialized" warnings. This code adds trivial overhead to the +critical performance path, so it is disabled by default. The intent +is that production users can use a "normal" build of libmthca and +developers can use the "valgrind debug" build by simply switching +their OPENIB_DRIVER_PATH environment variables. + +Libmthca needs some header files from Valgrind in order to compile +this support; it is important to use the header files from the same +version of Valgrind that will be used at run time. You may need to +specify the directory where Valgrind's header files are installed as +an argument to --with-valgrind. For example + + ./configure --with-valgrind=/opt/valgrind + +will make the libmthca build look for valgrind headers in +/opt/valgrind/include diff --git a/contrib/ofed/libmthca/autogen.sh b/contrib/ofed/libmthca/autogen.sh new file mode 100755 index 000000000000..fd47839cae8c --- /dev/null +++ b/contrib/ofed/libmthca/autogen.sh @@ -0,0 +1,8 @@ +#! /bin/sh + +set -x +aclocal -I config +libtoolize --force --copy +autoheader +automake --foreign --add-missing --copy +autoconf diff --git a/contrib/ofed/libmthca/configure.in b/contrib/ofed/libmthca/configure.in new file mode 100644 index 000000000000..e3b38dd9fb7c --- /dev/null +++ b/contrib/ofed/libmthca/configure.in @@ -0,0 +1,77 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(libmthca, 1.0.5, openib-general@openib.org) +AC_CONFIG_SRCDIR([src/mthca.h]) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(libmthca, 1.0.5) +AM_PROG_LIBTOOL + +AC_ARG_WITH([valgrind], + AC_HELP_STRING([--with-valgrind], + [Enable Valgrind annotations (small runtime overhead, default NO)])) +if test x$with_valgrind = x || test x$with_valgrind = xno; then + want_valgrind=no + AC_DEFINE([NVALGRIND], 1, [Define to 1 to disable Valgrind annotations.]) +else + want_valgrind=yes + if test -d $with_valgrind; then + CPPFLAGS="$CPPFLAGS -I$with_valgrind/include" + fi +fi + +dnl Checks for programs +AC_PROG_CC + +dnl Checks for libraries +AC_CHECK_LIB(ibverbs, ibv_get_device_list, [], + AC_MSG_ERROR([ibv_get_device_list() not found. libmthca requires libibverbs.])) + +dnl Checks for header files. +AC_CHECK_HEADER(infiniband/driver.h, [], + AC_MSG_ERROR([ not found. libmthca requires libibverbs.])) +AC_HEADER_STDC +AC_CHECK_HEADER(valgrind/memcheck.h, + [AC_DEFINE(HAVE_VALGRIND_MEMCHECK_H, 1, + [Define to 1 if you have the header file.])], + [if test $want_valgrind = yes; then + AC_MSG_ERROR([Valgrind memcheck support requested, but not found.]) + fi]) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_CHECK_SIZEOF(long) + +dnl Checks for library functions +AC_CHECK_FUNCS(ibv_read_sysfs_file ibv_dontfork_range ibv_dofork_range \ + ibv_register_driver) + +dnl Now check if for libibverbs 1.0 vs 1.1 +dummy=if$$ +cat < $dummy.c +#include +IBV_DEVICE_LIBRARY_EXTENSION +IBV_VERSION +IBV_DEVICE_LIBRARY_EXTENSION=`$CC $CPPFLAGS -E $dummy.c 2> /dev/null | tail -1` +rm -f $dummy.c +AM_CONDITIONAL(HAVE_IBV_DEVICE_LIBRARY_EXTENSION, + test $IBV_DEVICE_LIBRARY_EXTENSION != IBV_DEVICE_LIBRARY_EXTENSION) +AC_SUBST(IBV_DEVICE_LIBRARY_EXTENSION) + +AC_CACHE_CHECK(whether ld accepts --version-script, ac_cv_version_script, + [if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then + ac_cv_version_script=yes + else + ac_cv_version_script=no + fi]) + +if test $ac_cv_version_script = yes; then + MTHCA_VERSION_SCRIPT='-Wl,--version-script=$(srcdir)/src/mthca.map' +else + MTHCA_VERSION_SCRIPT= +fi +AC_SUBST(MTHCA_VERSION_SCRIPT) + +AC_CONFIG_FILES([Makefile libmthca.spec]) +AC_OUTPUT diff --git a/contrib/ofed/libmthca/debian/changelog b/contrib/ofed/libmthca/debian/changelog new file mode 100644 index 000000000000..1e0c3f610d85 --- /dev/null +++ b/contrib/ofed/libmthca/debian/changelog @@ -0,0 +1,45 @@ +libmthca (1.0.5-1) unstable; urgency=low + + * New upstream release. + - Fix issues on non-mem-free HCAs. + - Fix problems with completion entry cleanup. + * Replace deprecated ${Source-Version} with ${binary:Version} + * Add debian/watch file. + * Update libtool during build to avoid setting RPATH in binaries on amd64. + + -- Roland Dreier Tue, 27 May 2008 14:19:55 -0700 + +libmthca (1.0.4-1) unstable; urgency=low + + * New upstream release. + * Rebuild against libibverbs 1.1. + + -- Roland Dreier Mon, 30 Apr 2007 17:11:51 -0700 + +libmthca (1.0.3-1) unstable; urgency=low + + * New upstream release. + - Fix various integer overflows. + - Fix potential AB-BA deadlock when destroying QPs. + - Add more forward compat against future libibverbs releases. + * Build against libibverbs 1.0.4, with fixed sparc mb() definition. + (Closes: #365559) + * Improve package description. + + -- Roland Dreier Thu, 9 Nov 2006 11:07:58 -0800 + +libmthca (1.0.2-1) unstable; urgency=low + + * New upstream release: + - Work around MemFree firmware bug in receive completions with error. + - Fix posting receive lists with exactly a multiple of 256 entries. + - Add forward compatibility for future libibverbs releases. + * Update to Standards-Version: 3.7.2. + + -- Roland Dreier Tue, 13 Jun 2006 11:33:32 -0700 + +libmthca (1.0.1-1) unstable; urgency=low + + * Initial Release. (Closes: #325753) + + -- Roland Dreier Wed, 15 Feb 2006 11:22:18 -0700 diff --git a/contrib/ofed/libmthca/debian/compat b/contrib/ofed/libmthca/debian/compat new file mode 100644 index 000000000000..7ed6ff82de6b --- /dev/null +++ b/contrib/ofed/libmthca/debian/compat @@ -0,0 +1 @@ +5 diff --git a/contrib/ofed/libmthca/debian/control.in b/contrib/ofed/libmthca/debian/control.in new file mode 100644 index 000000000000..e58114d00bc5 --- /dev/null +++ b/contrib/ofed/libmthca/debian/control.in @@ -0,0 +1,47 @@ +Source: libmthca +Priority: extra +Maintainer: Roland Dreier +Build-Depends: @cdbs@, dpkg-dev (>= 1.13.19), libibverbs-dev (>= 1.1) +Standards-Version: 3.7.3 +Section: libs +Homepage: http://www.openfabrics.org/ + +Package: libmthca1 +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: A userspace driver for Mellanox InfiniBand HCAs + libmthca is a device-specific driver for Mellanox InfiniBand host + channel adapters (HCAs) for the libibverbs library. This allows + userspace processes to access Mellanox HCA hardware directly with + low latency and low overhead. + . + This package contains the loadable plug-in. + +Package: libmthca-dev +Section: libdevel +Architecture: any +Depends: ${misc:Depends}, libmthca1 (= ${binary:Version}) +Description: Development files for the libmthca driver + libmthca is a device-specific driver for Mellanox InfiniBand host + channel adapters (HCAs) for the libibverbs library. This allows + userspace processes to access Mellanox HCA hardware directly with + low latency and low overhead. + . + This package contains static versions of libmthca that may be linked + directly to an application, which may be useful for debugging. + +Package: libmthca1-dbg +Section: libdevel +Priority: extra +Architecture: any +Depends: ${misc:Depends}, libmthca1 (= ${binary:Version}) +Description: Debugging symbols for the libmthca driver + libmthca is a device-specific driver for Mellanox InfiniBand host + channel adapters (HCAs) for the libibverbs library. This allows + userspace processes to access Mellanox HCA hardware directly with + low latency and low overhead. + . + This package contains the debugging symbols associated with + libmthca1. They will automatically be used by gdb for debugging + libmthca-related issues. diff --git a/contrib/ofed/libmthca/debian/copyright b/contrib/ofed/libmthca/debian/copyright new file mode 100644 index 000000000000..04abee0b74f7 --- /dev/null +++ b/contrib/ofed/libmthca/debian/copyright @@ -0,0 +1,44 @@ +Initial Debianization: +This package was debianized by Roland Dreier on +Thu, 28 Apr 2005 13:16:56 -0700. + +Source: +It was downloaded from the OpenIB web site at + + +Authors: + Roland Dreier + Michael S. Tsirkin + +Portions are copyrighted by: + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + +libmthca is licensed under a choice of one of two licenses. You may +choose to be licensed under the terms of the GNU General Public +License (GPL) Version 2, available from the file +/usr/share/common-licenses/GPL-2 on your Debian system, or the +OpenIB.org BSD license below: + + Redistribution and use in source and binary forms, with or + without modification, are permitted provided that the following + conditions are met: + + - Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + - Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/contrib/ofed/libmthca/debian/libmthca-dev.install b/contrib/ofed/libmthca/debian/libmthca-dev.install new file mode 100644 index 000000000000..5b815a361be9 --- /dev/null +++ b/contrib/ofed/libmthca/debian/libmthca-dev.install @@ -0,0 +1 @@ +usr/lib/libmthca.{a,la} diff --git a/contrib/ofed/libmthca/debian/libmthca1.install b/contrib/ofed/libmthca/debian/libmthca1.install new file mode 100644 index 000000000000..090fcc78f407 --- /dev/null +++ b/contrib/ofed/libmthca/debian/libmthca1.install @@ -0,0 +1,2 @@ +usr/lib/libmthca-rdmav2.so +etc/libibverbs.d/mthca.driver diff --git a/contrib/ofed/libmthca/debian/rules b/contrib/ofed/libmthca/debian/rules new file mode 100755 index 000000000000..3e70bc38f907 --- /dev/null +++ b/contrib/ofed/libmthca/debian/rules @@ -0,0 +1,8 @@ +#!/usr/bin/make -f +# -*- mode: makefile; coding: utf-8 -*- + +DEB_DH_INSTALL_SOURCEDIR := debian/tmp +DEB_AUTO_UPDATE_LIBTOOL := post + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/autotools.mk diff --git a/contrib/ofed/libmthca/debian/watch b/contrib/ofed/libmthca/debian/watch new file mode 100644 index 000000000000..8010f867b5d5 --- /dev/null +++ b/contrib/ofed/libmthca/debian/watch @@ -0,0 +1,3 @@ +version=3 +opts="uversionmangle=s/-rc/~rc/" \ + http://www.openfabrics.org/downloads/mthca/libmthca-(.+)\.tar\.gz diff --git a/contrib/ofed/libmthca/libmthca.spec.in b/contrib/ofed/libmthca/libmthca.spec.in new file mode 100644 index 000000000000..163b4816d622 --- /dev/null +++ b/contrib/ofed/libmthca/libmthca.spec.in @@ -0,0 +1,94 @@ +Name: libmthca +Version: 1.0.5 +Release: 1%{?dist} +Summary: Mellanox InfiniBand HCA Userspace Driver + +Group: System Environment/Libraries +License: GPLv2 or BSD +Url: http://openfabrics.org/ +Source: http://openfabrics.org/downloads/mthca/libmthca-1.0.5.tar.gz +BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) + +BuildRequires: libibverbs-devel >= 1.1-0.1.rc2 + +%description +libmthca provides a device-specific userspace driver for Mellanox HCAs +(MT23108 InfiniHost and MT25208 InfiniHost III Ex) for use with the +libibverbs library. + +%package devel-static +Summary: Development files for the libmthca driver +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel-static +Static version of libmthca that may be linked directly to an +application, which may be useful for debugging. + +%prep +%setup -q -n %{name}-@VERSION@ + +%build +%configure +make %{?_smp_mflags} + +%install +rm -rf $RPM_BUILD_ROOT +make DESTDIR=%{buildroot} install +# remove unpackaged files from the buildroot +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la $RPM_BUILD_ROOT%{_libdir}/libmthca.so + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,-) +%{_libdir}/libmthca-rdmav2.so +%{_sysconfdir}/libibverbs.d/mthca.driver +%doc AUTHORS COPYING ChangeLog README + +%files devel-static +%defattr(-,root,root,-) +%{_libdir}/libmthca.a + +%changelog +* Tue May 27 2008 Roland Dreier - 1.0.5-1 +- New upstream release +- Change openib.org URLs to openfabrics.org URLs + +* Thu May 22 2008 Todd Zullinger - 1.0.4-3 +- fix license tag + +* Mon Feb 18 2008 Fedora Release Engineering - 1.0.4-2 +- Autorebuild for GCC 4.3 + +* Thu Nov 9 2006 Roland Dreier - 1.0.4-1 +- New upstream release +- Depend on libibverbs 1.1, and package new library file names. +- Spec file cleanups: remove unused ver macro, improve BuildRoot, move + static libraries into devel-static package, and don't use makeinstall + any more (all suggested by Doug Ledford ). + +* Wed Jul 26 2006 Roland Dreier - 1.0.3-1 +- New upstream release + +* Mon Mar 14 2006 Roland Dreier - 1.0.2-1 +- New upstream release + +* Thu Feb 16 2006 Roland Dreier - 1.0-1 +- New upstream release + +* Sun Feb 15 2006 Roland Dreier - 1.0-0.5.rc7 +- New upstream release + +* Sun Jan 22 2006 Roland Dreier - 1.0-0.4.rc6 +- New upstream release + +* Tue Oct 25 2005 Roland Dreier - 1.0-0.3.rc5 +- New upstream release + +* Wed Oct 5 2005 Roland Dreier - 1.0-0.2.rc4 +- Update to upstream 1.0-rc4 release + +* Mon Sep 26 2005 Roland Dreier - 1.0-0.1.rc3 +- Initial attempt at Fedora Extras-compliant spec file diff --git a/contrib/ofed/libmthca/mthca.driver b/contrib/ofed/libmthca/mthca.driver new file mode 100644 index 000000000000..5880a477f9c4 --- /dev/null +++ b/contrib/ofed/libmthca/mthca.driver @@ -0,0 +1 @@ +driver mthca diff --git a/contrib/ofed/libmthca/src/ah.c b/contrib/ofed/libmthca/src/ah.c new file mode 100644 index 000000000000..d7494d57f960 --- /dev/null +++ b/contrib/ofed/libmthca/src/ah.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include "mthca.h" + +struct mthca_ah_page { + struct mthca_ah_page *prev, *next; + struct mthca_buf buf; + struct ibv_mr *mr; + int use_cnt; + unsigned free[0]; +}; + +static struct mthca_ah_page *__add_page(struct mthca_pd *pd, int page_size, int per_page) +{ + struct mthca_ah_page *page; + int i; + + page = malloc(sizeof *page + per_page * sizeof (int)); + if (!page) + return NULL; + + if (mthca_alloc_buf(&page->buf, page_size, page_size)) { + free(page); + return NULL; + } + + page->mr = mthca_reg_mr(&pd->ibv_pd, page->buf.buf, page_size, 0); + if (!page->mr) { + mthca_free_buf(&page->buf); + free(page); + return NULL; + } + + page->mr->context = pd->ibv_pd.context; + + page->use_cnt = 0; + for (i = 0; i < per_page; ++i) + page->free[i] = ~0; + + page->prev = NULL; + page->next = pd->ah_list; + pd->ah_list = page; + if (page->next) + page->next->prev = page; + + return page; +} + +int mthca_alloc_av(struct mthca_pd *pd, struct ibv_ah_attr *attr, + struct mthca_ah *ah) +{ + if (mthca_is_memfree(pd->ibv_pd.context)) { + ah->av = malloc(sizeof *ah->av); + if (!ah->av) + return -1; + } else { + struct mthca_ah_page *page; + int ps; + int pp; + int i, j; + + ps = to_mdev(pd->ibv_pd.context->device)->page_size; + pp = ps / (sizeof *ah->av * 8 * sizeof (int)); + + pthread_mutex_lock(&pd->ah_mutex); + for (page = pd->ah_list; page; page = page->next) + if (page->use_cnt < ps / sizeof *ah->av) + for (i = 0; i < pp; ++i) + if (page->free[i]) + goto found; + + page = __add_page(pd, ps, pp); + if (!page) { + pthread_mutex_unlock(&pd->ah_mutex); + return -1; + } + + found: + ++page->use_cnt; + + for (i = 0, j = -1; i < pp; ++i) + if (page->free[i]) { + j = ffs(page->free[i]); + page->free[i] &= ~(1 << (j - 1)); + ah->av = page->buf.buf + + (i * 8 * sizeof (int) + (j - 1)) * sizeof *ah->av; + break; + } + + ah->key = page->mr->lkey; + ah->page = page; + + pthread_mutex_unlock(&pd->ah_mutex); + } + + memset(ah->av, 0, sizeof *ah->av); + + ah->av->port_pd = htonl(pd->pdn | (attr->port_num << 24)); + ah->av->g_slid = attr->src_path_bits; + ah->av->dlid = htons(attr->dlid); + ah->av->msg_sr = (3 << 4) | /* 2K message */ + attr->static_rate; + ah->av->sl_tclass_flowlabel = htonl(attr->sl << 28); + if (attr->is_global) { + ah->av->g_slid |= 0x80; + /* XXX get gid_table length */ + ah->av->gid_index = (attr->port_num - 1) * 32 + + attr->grh.sgid_index; + ah->av->hop_limit = attr->grh.hop_limit; + ah->av->sl_tclass_flowlabel |= + htonl((attr->grh.traffic_class << 20) | + attr->grh.flow_label); + memcpy(ah->av->dgid, attr->grh.dgid.raw, 16); + } else { + /* Arbel workaround -- low byte of GID must be 2 */ + ah->av->dgid[3] = htonl(2); + } + + return 0; +} + +void mthca_free_av(struct mthca_ah *ah) +{ + if (mthca_is_memfree(ah->ibv_ah.context)) { + free(ah->av); + } else { + struct mthca_pd *pd = to_mpd(ah->ibv_ah.pd); + struct mthca_ah_page *page; + int i; + + pthread_mutex_lock(&pd->ah_mutex); + + page = ah->page; + i = ((void *) ah->av - page->buf.buf) / sizeof *ah->av; + page->free[i / (8 * sizeof (int))] |= 1 << (i % (8 * sizeof (int))); + + if (!--page->use_cnt) { + if (page->prev) + page->prev->next = page->next; + else + pd->ah_list = page->next; + if (page->next) + page->next->prev = page->prev; + + mthca_dereg_mr(page->mr); + mthca_free_buf(&page->buf); + free(page); + } + + pthread_mutex_unlock(&pd->ah_mutex); + } +} diff --git a/contrib/ofed/libmthca/src/buf.c b/contrib/ofed/libmthca/src/buf.c new file mode 100644 index 000000000000..6c1be4f72db8 --- /dev/null +++ b/contrib/ofed/libmthca/src/buf.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#include "mthca.h" + +#if !(defined(HAVE_IBV_DONTFORK_RANGE) && defined(HAVE_IBV_DOFORK_RANGE)) + +/* + * If libibverbs isn't exporting these functions, then there's no + * point in doing it here, because the rest of libibverbs isn't going + * to be fork-safe anyway. + */ +static int ibv_dontfork_range(void *base, size_t size) +{ + return 0; +} + +static int ibv_dofork_range(void *base, size_t size) +{ + return 0; +} + +#endif /* HAVE_IBV_DONTFORK_RANGE && HAVE_IBV_DOFORK_RANGE */ + +int mthca_alloc_buf(struct mthca_buf *buf, size_t size, int page_size) +{ + int ret; + + ret = posix_memalign(&buf->buf, page_size, align(size, page_size)); + if (ret) + return ret; + + ret = ibv_dontfork_range(buf->buf, size); + if (ret) + free(buf->buf); + + if (!ret) + buf->length = size; + + return ret; +} + +void mthca_free_buf(struct mthca_buf *buf) +{ + ibv_dofork_range(buf->buf, buf->length); + free(buf->buf); +} diff --git a/contrib/ofed/libmthca/src/cq.c b/contrib/ofed/libmthca/src/cq.c new file mode 100644 index 000000000000..24ff0aaaab64 --- /dev/null +++ b/contrib/ofed/libmthca/src/cq.c @@ -0,0 +1,633 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2006 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include + +#include "mthca.h" +#include "doorbell.h" + +enum { + MTHCA_CQ_DOORBELL = 0x20 +}; + +enum { + CQ_OK = 0, + CQ_EMPTY = -1, + CQ_POLL_ERR = -2 +}; + +#define MTHCA_TAVOR_CQ_DB_INC_CI (1 << 24) +#define MTHCA_TAVOR_CQ_DB_REQ_NOT (2 << 24) +#define MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL (3 << 24) +#define MTHCA_TAVOR_CQ_DB_SET_CI (4 << 24) +#define MTHCA_TAVOR_CQ_DB_REQ_NOT_MULT (5 << 24) + +#define MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL (1 << 24) +#define MTHCA_ARBEL_CQ_DB_REQ_NOT (2 << 24) +#define MTHCA_ARBEL_CQ_DB_REQ_NOT_MULT (3 << 24) + +enum { + MTHCA_CQ_ENTRY_OWNER_SW = 0x00, + MTHCA_CQ_ENTRY_OWNER_HW = 0x80, + MTHCA_ERROR_CQE_OPCODE_MASK = 0xfe +}; + +enum { + SYNDROME_LOCAL_LENGTH_ERR = 0x01, + SYNDROME_LOCAL_QP_OP_ERR = 0x02, + SYNDROME_LOCAL_EEC_OP_ERR = 0x03, + SYNDROME_LOCAL_PROT_ERR = 0x04, + SYNDROME_WR_FLUSH_ERR = 0x05, + SYNDROME_MW_BIND_ERR = 0x06, + SYNDROME_BAD_RESP_ERR = 0x10, + SYNDROME_LOCAL_ACCESS_ERR = 0x11, + SYNDROME_REMOTE_INVAL_REQ_ERR = 0x12, + SYNDROME_REMOTE_ACCESS_ERR = 0x13, + SYNDROME_REMOTE_OP_ERR = 0x14, + SYNDROME_RETRY_EXC_ERR = 0x15, + SYNDROME_RNR_RETRY_EXC_ERR = 0x16, + SYNDROME_LOCAL_RDD_VIOL_ERR = 0x20, + SYNDROME_REMOTE_INVAL_RD_REQ_ERR = 0x21, + SYNDROME_REMOTE_ABORTED_ERR = 0x22, + SYNDROME_INVAL_EECN_ERR = 0x23, + SYNDROME_INVAL_EEC_STATE_ERR = 0x24 +}; + +struct mthca_cqe { + uint32_t my_qpn; + uint32_t my_ee; + uint32_t rqpn; + uint16_t sl_g_mlpath; + uint16_t rlid; + uint32_t imm_etype_pkey_eec; + uint32_t byte_cnt; + uint32_t wqe; + uint8_t opcode; + uint8_t is_send; + uint8_t reserved; + uint8_t owner; +}; + +struct mthca_err_cqe { + uint32_t my_qpn; + uint32_t reserved1[3]; + uint8_t syndrome; + uint8_t vendor_err; + uint16_t db_cnt; + uint32_t reserved2; + uint32_t wqe; + uint8_t opcode; + uint8_t reserved3[2]; + uint8_t owner; +}; + +static inline struct mthca_cqe *get_cqe(struct mthca_cq *cq, int entry) +{ + return cq->buf.buf + entry * MTHCA_CQ_ENTRY_SIZE; +} + +static inline struct mthca_cqe *cqe_sw(struct mthca_cq *cq, int i) +{ + struct mthca_cqe *cqe = get_cqe(cq, i); + return MTHCA_CQ_ENTRY_OWNER_HW & cqe->owner ? NULL : cqe; +} + +static inline struct mthca_cqe *next_cqe_sw(struct mthca_cq *cq) +{ + return cqe_sw(cq, cq->cons_index & cq->ibv_cq.cqe); +} + +static inline void set_cqe_hw(struct mthca_cqe *cqe) +{ + VALGRIND_MAKE_MEM_UNDEFINED(cqe, sizeof *cqe); + cqe->owner = MTHCA_CQ_ENTRY_OWNER_HW; +} + +/* + * incr is ignored in native Arbel (mem-free) mode, so cq->cons_index + * should be correct before calling update_cons_index(). + */ +static inline void update_cons_index(struct mthca_cq *cq, int incr) +{ + uint32_t doorbell[2]; + + if (mthca_is_memfree(cq->ibv_cq.context)) { + *cq->set_ci_db = htonl(cq->cons_index); + wmb(); + } else { + doorbell[0] = htonl(MTHCA_TAVOR_CQ_DB_INC_CI | cq->cqn); + doorbell[1] = htonl(incr - 1); + + mthca_write64(doorbell, to_mctx(cq->ibv_cq.context), MTHCA_CQ_DOORBELL); + } +} + +static void dump_cqe(void *cqe_ptr) +{ + uint32_t *cqe = cqe_ptr; + int i; + + for (i = 0; i < 8; ++i) + printf(" [%2x] %08x\n", i * 4, ntohl(((uint32_t *) cqe)[i])); +} + +static int handle_error_cqe(struct mthca_cq *cq, + struct mthca_qp *qp, int wqe_index, int is_send, + struct mthca_err_cqe *cqe, + struct ibv_wc *wc, int *free_cqe) +{ + int err; + int dbd; + uint32_t new_wqe; + + if (cqe->syndrome == SYNDROME_LOCAL_QP_OP_ERR) { + printf("local QP operation err " + "(QPN %06x, WQE @ %08x, CQN %06x, index %d)\n", + ntohl(cqe->my_qpn), ntohl(cqe->wqe), + cq->cqn, cq->cons_index); + dump_cqe(cqe); + } + + /* + * For completions in error, only work request ID, status, vendor error + * (and freed resource count for RD) have to be set. + */ + switch (cqe->syndrome) { + case SYNDROME_LOCAL_LENGTH_ERR: + wc->status = IBV_WC_LOC_LEN_ERR; + break; + case SYNDROME_LOCAL_QP_OP_ERR: + wc->status = IBV_WC_LOC_QP_OP_ERR; + break; + case SYNDROME_LOCAL_EEC_OP_ERR: + wc->status = IBV_WC_LOC_EEC_OP_ERR; + break; + case SYNDROME_LOCAL_PROT_ERR: + wc->status = IBV_WC_LOC_PROT_ERR; + break; + case SYNDROME_WR_FLUSH_ERR: + wc->status = IBV_WC_WR_FLUSH_ERR; + break; + case SYNDROME_MW_BIND_ERR: + wc->status = IBV_WC_MW_BIND_ERR; + break; + case SYNDROME_BAD_RESP_ERR: + wc->status = IBV_WC_BAD_RESP_ERR; + break; + case SYNDROME_LOCAL_ACCESS_ERR: + wc->status = IBV_WC_LOC_ACCESS_ERR; + break; + case SYNDROME_REMOTE_INVAL_REQ_ERR: + wc->status = IBV_WC_REM_INV_REQ_ERR; + break; + case SYNDROME_REMOTE_ACCESS_ERR: + wc->status = IBV_WC_REM_ACCESS_ERR; + break; + case SYNDROME_REMOTE_OP_ERR: + wc->status = IBV_WC_REM_OP_ERR; + break; + case SYNDROME_RETRY_EXC_ERR: + wc->status = IBV_WC_RETRY_EXC_ERR; + break; + case SYNDROME_RNR_RETRY_EXC_ERR: + wc->status = IBV_WC_RNR_RETRY_EXC_ERR; + break; + case SYNDROME_LOCAL_RDD_VIOL_ERR: + wc->status = IBV_WC_LOC_RDD_VIOL_ERR; + break; + case SYNDROME_REMOTE_INVAL_RD_REQ_ERR: + wc->status = IBV_WC_REM_INV_RD_REQ_ERR; + break; + case SYNDROME_REMOTE_ABORTED_ERR: + wc->status = IBV_WC_REM_ABORT_ERR; + break; + case SYNDROME_INVAL_EECN_ERR: + wc->status = IBV_WC_INV_EECN_ERR; + break; + case SYNDROME_INVAL_EEC_STATE_ERR: + wc->status = IBV_WC_INV_EEC_STATE_ERR; + break; + default: + wc->status = IBV_WC_GENERAL_ERR; + break; + } + + wc->vendor_err = cqe->vendor_err; + + /* + * Mem-free HCAs always generate one CQE per WQE, even in the + * error case, so we don't have to check the doorbell count, etc. + */ + if (mthca_is_memfree(cq->ibv_cq.context)) + return 0; + + err = mthca_free_err_wqe(qp, is_send, wqe_index, &dbd, &new_wqe); + if (err) + return err; + + /* + * If we're at the end of the WQE chain, or we've used up our + * doorbell count, free the CQE. Otherwise just update it for + * the next poll operation. + * + * This doesn't apply to mem-free HCAs, which never use the + * doorbell count field. In that case we always free the CQE. + */ + if (mthca_is_memfree(cq->ibv_cq.context) || + !(new_wqe & htonl(0x3f)) || (!cqe->db_cnt && dbd)) + return 0; + + cqe->db_cnt = htons(ntohs(cqe->db_cnt) - dbd); + cqe->wqe = new_wqe; + cqe->syndrome = SYNDROME_WR_FLUSH_ERR; + + *free_cqe = 0; + + return 0; +} + +static inline int mthca_poll_one(struct mthca_cq *cq, + struct mthca_qp **cur_qp, + int *freed, + struct ibv_wc *wc) +{ + struct mthca_wq *wq; + struct mthca_cqe *cqe; + struct mthca_srq *srq; + uint32_t qpn; + uint32_t wqe; + int wqe_index; + int is_error; + int is_send; + int free_cqe = 1; + int err = 0; + + cqe = next_cqe_sw(cq); + if (!cqe) + return CQ_EMPTY; + + VALGRIND_MAKE_MEM_DEFINED(cqe, sizeof *cqe); + + /* + * Make sure we read CQ entry contents after we've checked the + * ownership bit. + */ + rmb(); + + qpn = ntohl(cqe->my_qpn); + + is_error = (cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) == + MTHCA_ERROR_CQE_OPCODE_MASK; + is_send = is_error ? cqe->opcode & 0x01 : cqe->is_send & 0x80; + + if (!*cur_qp || ntohl(cqe->my_qpn) != (*cur_qp)->ibv_qp.qp_num) { + /* + * We do not have to take the QP table lock here, + * because CQs will be locked while QPs are removed + * from the table. + */ + *cur_qp = mthca_find_qp(to_mctx(cq->ibv_cq.context), ntohl(cqe->my_qpn)); + if (!*cur_qp) { + err = CQ_POLL_ERR; + goto out; + } + } + + wc->qp_num = (*cur_qp)->ibv_qp.qp_num; + + if (is_send) { + wq = &(*cur_qp)->sq; + wqe_index = ((ntohl(cqe->wqe) - (*cur_qp)->send_wqe_offset) >> wq->wqe_shift); + wc->wr_id = (*cur_qp)->wrid[wqe_index + (*cur_qp)->rq.max]; + } else if ((*cur_qp)->ibv_qp.srq) { + srq = to_msrq((*cur_qp)->ibv_qp.srq); + wqe = htonl(cqe->wqe); + wq = NULL; + wqe_index = wqe >> srq->wqe_shift; + wc->wr_id = srq->wrid[wqe_index]; + mthca_free_srq_wqe(srq, wqe_index); + } else { + int32_t wqe; + wq = &(*cur_qp)->rq; + wqe = ntohl(cqe->wqe); + wqe_index = wqe >> wq->wqe_shift; + /* + * WQE addr == base - 1 might be reported by Sinai FW + * 1.0.800 and Arbel FW 5.1.400 in receive completion + * with error instead of (rq size - 1). This bug + * should be fixed in later FW revisions. + */ + if (wqe_index < 0) + wqe_index = wq->max - 1; + wc->wr_id = (*cur_qp)->wrid[wqe_index]; + } + + if (wq) { + if (wq->last_comp < wqe_index) + wq->tail += wqe_index - wq->last_comp; + else + wq->tail += wqe_index + wq->max - wq->last_comp; + + wq->last_comp = wqe_index; + } + + if (is_error) { + err = handle_error_cqe(cq, *cur_qp, wqe_index, is_send, + (struct mthca_err_cqe *) cqe, + wc, &free_cqe); + goto out; + } + + if (is_send) { + wc->wc_flags = 0; + switch (cqe->opcode) { + case MTHCA_OPCODE_RDMA_WRITE: + wc->opcode = IBV_WC_RDMA_WRITE; + break; + case MTHCA_OPCODE_RDMA_WRITE_IMM: + wc->opcode = IBV_WC_RDMA_WRITE; + wc->wc_flags |= IBV_WC_WITH_IMM; + break; + case MTHCA_OPCODE_SEND: + wc->opcode = IBV_WC_SEND; + break; + case MTHCA_OPCODE_SEND_IMM: + wc->opcode = IBV_WC_SEND; + wc->wc_flags |= IBV_WC_WITH_IMM; + break; + case MTHCA_OPCODE_RDMA_READ: + wc->opcode = IBV_WC_RDMA_READ; + wc->byte_len = ntohl(cqe->byte_cnt); + break; + case MTHCA_OPCODE_ATOMIC_CS: + wc->opcode = IBV_WC_COMP_SWAP; + wc->byte_len = ntohl(cqe->byte_cnt); + break; + case MTHCA_OPCODE_ATOMIC_FA: + wc->opcode = IBV_WC_FETCH_ADD; + wc->byte_len = ntohl(cqe->byte_cnt); + break; + case MTHCA_OPCODE_BIND_MW: + wc->opcode = IBV_WC_BIND_MW; + break; + default: + /* assume it's a send completion */ + wc->opcode = IBV_WC_SEND; + break; + } + } else { + wc->byte_len = ntohl(cqe->byte_cnt); + switch (cqe->opcode & 0x1f) { + case IBV_OPCODE_SEND_LAST_WITH_IMMEDIATE: + case IBV_OPCODE_SEND_ONLY_WITH_IMMEDIATE: + wc->wc_flags = IBV_WC_WITH_IMM; + wc->imm_data = cqe->imm_etype_pkey_eec; + wc->opcode = IBV_WC_RECV; + break; + case IBV_OPCODE_RDMA_WRITE_LAST_WITH_IMMEDIATE: + case IBV_OPCODE_RDMA_WRITE_ONLY_WITH_IMMEDIATE: + wc->wc_flags = IBV_WC_WITH_IMM; + wc->imm_data = cqe->imm_etype_pkey_eec; + wc->opcode = IBV_WC_RECV_RDMA_WITH_IMM; + break; + default: + wc->wc_flags = 0; + wc->opcode = IBV_WC_RECV; + break; + } + wc->slid = ntohs(cqe->rlid); + wc->sl = ntohs(cqe->sl_g_mlpath) >> 12; + wc->src_qp = ntohl(cqe->rqpn) & 0xffffff; + wc->dlid_path_bits = ntohs(cqe->sl_g_mlpath) & 0x7f; + wc->pkey_index = ntohl(cqe->imm_etype_pkey_eec) >> 16; + wc->wc_flags |= ntohs(cqe->sl_g_mlpath) & 0x80 ? + IBV_WC_GRH : 0; + } + + wc->status = IBV_WC_SUCCESS; + +out: + if (free_cqe) { + set_cqe_hw(cqe); + ++(*freed); + ++cq->cons_index; + } + + return err; +} + +int mthca_poll_cq(struct ibv_cq *ibcq, int ne, struct ibv_wc *wc) +{ + struct mthca_cq *cq = to_mcq(ibcq); + struct mthca_qp *qp = NULL; + int npolled; + int err = CQ_OK; + int freed = 0; + + pthread_spin_lock(&cq->lock); + + for (npolled = 0; npolled < ne; ++npolled) { + err = mthca_poll_one(cq, &qp, &freed, wc + npolled); + if (err != CQ_OK) + break; + } + + if (freed) { + wmb(); + update_cons_index(cq, freed); + } + + pthread_spin_unlock(&cq->lock); + + return err == CQ_POLL_ERR ? err : npolled; +} + +int mthca_tavor_arm_cq(struct ibv_cq *cq, int solicited) +{ + uint32_t doorbell[2]; + + doorbell[0] = htonl((solicited ? + MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL : + MTHCA_TAVOR_CQ_DB_REQ_NOT) | + to_mcq(cq)->cqn); + doorbell[1] = 0xffffffff; + + mthca_write64(doorbell, to_mctx(cq->context), MTHCA_CQ_DOORBELL); + + return 0; +} + +int mthca_arbel_arm_cq(struct ibv_cq *ibvcq, int solicited) +{ + struct mthca_cq *cq = to_mcq(ibvcq); + uint32_t doorbell[2]; + uint32_t sn; + uint32_t ci; + + sn = cq->arm_sn & 3; + ci = htonl(cq->cons_index); + + doorbell[0] = ci; + doorbell[1] = htonl((cq->cqn << 8) | (2 << 5) | (sn << 3) | + (solicited ? 1 : 2)); + + mthca_write_db_rec(doorbell, cq->arm_db); + + /* + * Make sure that the doorbell record in host memory is + * written before ringing the doorbell via PCI MMIO. + */ + wmb(); + + doorbell[0] = htonl((sn << 28) | + (solicited ? + MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL : + MTHCA_ARBEL_CQ_DB_REQ_NOT) | + cq->cqn); + doorbell[1] = ci; + + mthca_write64(doorbell, to_mctx(ibvcq->context), MTHCA_CQ_DOORBELL); + + return 0; +} + +void mthca_arbel_cq_event(struct ibv_cq *cq) +{ + to_mcq(cq)->arm_sn++; +} + +static inline int is_recv_cqe(struct mthca_cqe *cqe) +{ + if ((cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) == + MTHCA_ERROR_CQE_OPCODE_MASK) + return !(cqe->opcode & 0x01); + else + return !(cqe->is_send & 0x80); +} + +void __mthca_cq_clean(struct mthca_cq *cq, uint32_t qpn, struct mthca_srq *srq) +{ + struct mthca_cqe *cqe; + uint32_t prod_index; + int i, nfreed = 0; + + /* + * First we need to find the current producer index, so we + * know where to start cleaning from. It doesn't matter if HW + * adds new entries after this loop -- the QP we're worried + * about is already in RESET, so the new entries won't come + * from our QP and therefore don't need to be checked. + */ + for (prod_index = cq->cons_index; + cqe_sw(cq, prod_index & cq->ibv_cq.cqe); + ++prod_index) + if (prod_index == cq->cons_index + cq->ibv_cq.cqe) + break; + + /* + * Now sweep backwards through the CQ, removing CQ entries + * that match our QP by copying older entries on top of them. + */ + while ((int) --prod_index - (int) cq->cons_index >= 0) { + cqe = get_cqe(cq, prod_index & cq->ibv_cq.cqe); + if (cqe->my_qpn == htonl(qpn)) { + if (srq && is_recv_cqe(cqe)) + mthca_free_srq_wqe(srq, + ntohl(cqe->wqe) >> srq->wqe_shift); + ++nfreed; + } else if (nfreed) + memcpy(get_cqe(cq, (prod_index + nfreed) & cq->ibv_cq.cqe), + cqe, MTHCA_CQ_ENTRY_SIZE); + } + + if (nfreed) { + for (i = 0; i < nfreed; ++i) + set_cqe_hw(get_cqe(cq, (cq->cons_index + i) & cq->ibv_cq.cqe)); + wmb(); + cq->cons_index += nfreed; + update_cons_index(cq, nfreed); + } +} + +void mthca_cq_clean(struct mthca_cq *cq, uint32_t qpn, struct mthca_srq *srq) +{ + pthread_spin_lock(&cq->lock); + __mthca_cq_clean(cq, qpn, srq); + pthread_spin_unlock(&cq->lock); +} + +void mthca_cq_resize_copy_cqes(struct mthca_cq *cq, void *buf, int old_cqe) +{ + int i; + + /* + * In Tavor mode, the hardware keeps the consumer and producer + * indices mod the CQ size. Since we might be making the CQ + * bigger, we need to deal with the case where the producer + * index wrapped around before the CQ was resized. + */ + if (!mthca_is_memfree(cq->ibv_cq.context) && old_cqe < cq->ibv_cq.cqe) { + cq->cons_index &= old_cqe; + if (cqe_sw(cq, old_cqe)) + cq->cons_index -= old_cqe + 1; + } + + for (i = cq->cons_index; cqe_sw(cq, i & old_cqe); ++i) + memcpy(buf + (i & cq->ibv_cq.cqe) * MTHCA_CQ_ENTRY_SIZE, + get_cqe(cq, i & old_cqe), MTHCA_CQ_ENTRY_SIZE); +} + +int mthca_alloc_cq_buf(struct mthca_device *dev, struct mthca_buf *buf, int nent) +{ + int i; + + if (mthca_alloc_buf(buf, align(nent * MTHCA_CQ_ENTRY_SIZE, dev->page_size), + dev->page_size)) + return -1; + + for (i = 0; i < nent; ++i) + ((struct mthca_cqe *) buf->buf)[i].owner = MTHCA_CQ_ENTRY_OWNER_HW; + + return 0; +} diff --git a/contrib/ofed/libmthca/src/doorbell.h b/contrib/ofed/libmthca/src/doorbell.h new file mode 100644 index 000000000000..a3aa42a9c8ba --- /dev/null +++ b/contrib/ofed/libmthca/src/doorbell.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef DOORBELL_H +#define DOORBELL_H + +#ifdef __i386__ + +static inline void mthca_write64(uint32_t val[2], struct mthca_context *ctx, int offset) +{ + /* i386 stack is aligned to 8 bytes, so this should be OK: */ + uint8_t xmmsave[8] __attribute__((aligned(8))); + + asm volatile ( + "movlps %%xmm0,(%0); \n\t" + "movlps (%1),%%xmm0; \n\t" + "movlps %%xmm0,(%2); \n\t" + "movlps (%0),%%xmm0; \n\t" + : + : "r" (xmmsave), "r" (val), "r" (ctx->uar + offset) + : "memory" ); +} + +static inline void mthca_write_db_rec(uint32_t val[2], uint32_t *db) +{ + /* i386 stack is aligned to 8 bytes, so this should be OK: */ + uint8_t xmmsave[8] __attribute__((aligned(8))); + + asm volatile ( + "movlps %%xmm0,(%0); \n\t" + "movlps (%1),%%xmm0; \n\t" + "movlps %%xmm0,(%2); \n\t" + "movlps (%0),%%xmm0; \n\t" + : + : "r" (xmmsave), "r" (val), "r" (db) + : "memory" ); +} + +#elif SIZEOF_LONG == 8 + +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define MTHCA_PAIR_TO_64(val) ((uint64_t) val[1] << 32 | val[0]) +#elif __BYTE_ORDER == __BIG_ENDIAN +# define MTHCA_PAIR_TO_64(val) ((uint64_t) val[0] << 32 | val[1]) +#else +# error __BYTE_ORDER not defined +#endif + +static inline void mthca_write64(uint32_t val[2], struct mthca_context *ctx, int offset) +{ + *(volatile uint64_t *) (ctx->uar + offset) = MTHCA_PAIR_TO_64(val); +} + +static inline void mthca_write_db_rec(uint32_t val[2], uint32_t *db) +{ + *(volatile uint64_t *) db = MTHCA_PAIR_TO_64(val); +} + +#else + +static inline void mthca_write64(uint32_t val[2], struct mthca_context *ctx, int offset) +{ + pthread_spin_lock(&ctx->uar_lock); + *(volatile uint32_t *) (ctx->uar + offset) = val[0]; + *(volatile uint32_t *) (ctx->uar + offset + 4) = val[1]; + pthread_spin_unlock(&ctx->uar_lock); +} + +static inline void mthca_write_db_rec(uint32_t val[2], uint32_t *db) +{ + *(volatile uint32_t *) db = val[0]; + mb(); + *(volatile uint32_t *) (db + 1) = val[1]; +} + +#endif + +#endif /* MTHCA_H */ diff --git a/contrib/ofed/libmthca/src/memfree.c b/contrib/ofed/libmthca/src/memfree.c new file mode 100644 index 000000000000..987e14971379 --- /dev/null +++ b/contrib/ofed/libmthca/src/memfree.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include "mthca.h" + +#define MTHCA_FREE_MAP_SIZE (MTHCA_DB_REC_PER_PAGE / (SIZEOF_LONG * 8)) + +struct mthca_db_page { + unsigned long free[MTHCA_FREE_MAP_SIZE]; + struct mthca_buf db_rec; +}; + +struct mthca_db_table { + int npages; + int max_group1; + int min_group2; + pthread_mutex_t mutex; + struct mthca_db_page page[]; +}; + +int mthca_alloc_db(struct mthca_db_table *db_tab, enum mthca_db_type type, + uint32_t **db) +{ + int i, j, k; + int group, start, end, dir; + int ret = 0; + + pthread_mutex_lock(&db_tab->mutex); + + switch (type) { + case MTHCA_DB_TYPE_CQ_ARM: + case MTHCA_DB_TYPE_SQ: + group = 0; + start = 0; + end = db_tab->max_group1; + dir = 1; + break; + + case MTHCA_DB_TYPE_CQ_SET_CI: + case MTHCA_DB_TYPE_RQ: + case MTHCA_DB_TYPE_SRQ: + group = 1; + start = db_tab->npages - 1; + end = db_tab->min_group2; + dir = -1; + break; + + default: + ret = -1; + goto out; + } + + for (i = start; i != end; i += dir) + if (db_tab->page[i].db_rec.buf) + for (j = 0; j < MTHCA_FREE_MAP_SIZE; ++j) + if (db_tab->page[i].free[j]) + goto found; + + if (db_tab->max_group1 >= db_tab->min_group2 - 1) { + ret = -1; + goto out; + } + + if (mthca_alloc_buf(&db_tab->page[i].db_rec, + MTHCA_DB_REC_PAGE_SIZE, + MTHCA_DB_REC_PAGE_SIZE)) { + ret = -1; + goto out; + } + + memset(db_tab->page[i].db_rec.buf, 0, MTHCA_DB_REC_PAGE_SIZE); + memset(db_tab->page[i].free, 0xff, sizeof db_tab->page[i].free); + + if (group == 0) + ++db_tab->max_group1; + else + --db_tab->min_group2; + +found: + for (j = 0; j < MTHCA_FREE_MAP_SIZE; ++j) { + k = ffsl(db_tab->page[i].free[j]); + if (k) + break; + } + + if (!k) { + ret = -1; + goto out; + } + + --k; + db_tab->page[i].free[j] &= ~(1UL << k); + + j = j * SIZEOF_LONG * 8 + k; + if (group == 1) + j = MTHCA_DB_REC_PER_PAGE - 1 - j; + + ret = i * MTHCA_DB_REC_PER_PAGE + j; + *db = db_tab->page[i].db_rec.buf + j * 8; + +out: + pthread_mutex_unlock(&db_tab->mutex); + return ret; +} + +void mthca_set_db_qn(uint32_t *db, enum mthca_db_type type, uint32_t qn) +{ + db[1] = htonl((qn << 8) | (type << 5)); +} + +void mthca_free_db(struct mthca_db_table *db_tab, enum mthca_db_type type, int db_index) +{ + int i, j; + struct mthca_db_page *page; + + i = db_index / MTHCA_DB_REC_PER_PAGE; + j = db_index % MTHCA_DB_REC_PER_PAGE; + + page = db_tab->page + i; + + pthread_mutex_lock(&db_tab->mutex); + *(uint64_t *) (page->db_rec.buf + j * 8) = 0; + + if (i >= db_tab->min_group2) + j = MTHCA_DB_REC_PER_PAGE - 1 - j; + + page->free[j / (SIZEOF_LONG * 8)] |= 1UL << (j % (SIZEOF_LONG * 8)); + + pthread_mutex_unlock(&db_tab->mutex); +} + +struct mthca_db_table *mthca_alloc_db_tab(int uarc_size) +{ + struct mthca_db_table *db_tab; + int npages; + int i; + + npages = uarc_size / MTHCA_DB_REC_PAGE_SIZE; + db_tab = malloc(sizeof (struct mthca_db_table) + + npages * sizeof (struct mthca_db_page)); + + pthread_mutex_init(&db_tab->mutex, NULL); + + db_tab->npages = npages; + db_tab->max_group1 = 0; + db_tab->min_group2 = npages - 1; + + for (i = 0; i < npages; ++i) + db_tab->page[i].db_rec.buf = NULL; + + return db_tab; +} + +void mthca_free_db_tab(struct mthca_db_table *db_tab) +{ + int i; + + if (!db_tab) + return; + + for (i = 0; i < db_tab->npages; ++i) + if (db_tab->page[i].db_rec.buf) + mthca_free_buf(&db_tab->page[i].db_rec); + + free(db_tab); +} diff --git a/contrib/ofed/libmthca/src/mthca-abi.h b/contrib/ofed/libmthca/src/mthca-abi.h new file mode 100644 index 000000000000..4fbd98bc08c3 --- /dev/null +++ b/contrib/ofed/libmthca/src/mthca-abi.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2006 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MTHCA_ABI_H +#define MTHCA_ABI_H + +#include + +#define MTHCA_UVERBS_ABI_VERSION 1 + +struct mthca_alloc_ucontext_resp { + struct ibv_get_context_resp ibv_resp; + __u32 qp_tab_size; + __u32 uarc_size; +}; + +struct mthca_alloc_pd_resp { + struct ibv_alloc_pd_resp ibv_resp; + __u32 pdn; + __u32 reserved; +}; + +struct mthca_reg_mr { + struct ibv_reg_mr ibv_cmd; +/* + * Mark the memory region with a DMA attribute that causes + * in-flight DMA to be flushed when the region is written to: + */ +#define MTHCA_MR_DMASYNC 0x1 + __u32 mr_attrs; + __u32 reserved; +}; + +struct mthca_create_cq { + struct ibv_create_cq ibv_cmd; + __u32 lkey; + __u32 pdn; + __u64 arm_db_page; + __u64 set_db_page; + __u32 arm_db_index; + __u32 set_db_index; +}; + +struct mthca_create_cq_resp { + struct ibv_create_cq_resp ibv_resp; + __u32 cqn; + __u32 reserved; +}; + +struct mthca_resize_cq { + struct ibv_resize_cq ibv_cmd; + __u32 lkey; + __u32 reserved; +}; + +struct mthca_create_srq { + struct ibv_create_srq ibv_cmd; + __u32 lkey; + __u32 db_index; + __u64 db_page; +}; + +struct mthca_create_srq_resp { + struct ibv_create_srq_resp ibv_resp; + __u32 srqn; + __u32 reserved; +}; + +struct mthca_create_qp { + struct ibv_create_qp ibv_cmd; + __u32 lkey; + __u32 reserved; + __u64 sq_db_page; + __u64 rq_db_page; + __u32 sq_db_index; + __u32 rq_db_index; +}; + +#endif /* MTHCA_ABI_H */ diff --git a/contrib/ofed/libmthca/src/mthca.c b/contrib/ofed/libmthca/src/mthca.c new file mode 100644 index 000000000000..e00c4ee8153a --- /dev/null +++ b/contrib/ofed/libmthca/src/mthca.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2006 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef HAVE_IBV_REGISTER_DRIVER +#include +#endif + +#ifndef HAVE_IBV_READ_SYSFS_FILE +#include +#include +#include +#endif + +#include "mthca.h" +#include "mthca-abi.h" + +#ifndef PCI_VENDOR_ID_MELLANOX +#define PCI_VENDOR_ID_MELLANOX 0x15b3 +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_TAVOR +#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44 +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT +#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278 +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_ARBEL +#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282 +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_SINAI_OLD +#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c +#endif + +#ifndef PCI_DEVICE_ID_MELLANOX_SINAI +#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274 +#endif + +#ifndef PCI_VENDOR_ID_TOPSPIN +#define PCI_VENDOR_ID_TOPSPIN 0x1867 +#endif + +#define HCA(v, d, t) \ + { .vendor = PCI_VENDOR_ID_##v, \ + .device = PCI_DEVICE_ID_MELLANOX_##d, \ + .type = MTHCA_##t } + +struct { + unsigned vendor; + unsigned device; + enum mthca_hca_type type; +} hca_table[] = { + HCA(MELLANOX, TAVOR, TAVOR), + HCA(MELLANOX, ARBEL_COMPAT, TAVOR), + HCA(MELLANOX, ARBEL, ARBEL), + HCA(MELLANOX, SINAI_OLD, ARBEL), + HCA(MELLANOX, SINAI, ARBEL), + HCA(TOPSPIN, TAVOR, TAVOR), + HCA(TOPSPIN, ARBEL_COMPAT, TAVOR), + HCA(TOPSPIN, ARBEL, ARBEL), + HCA(TOPSPIN, SINAI_OLD, ARBEL), + HCA(TOPSPIN, SINAI, ARBEL), +}; + +static struct ibv_context_ops mthca_ctx_ops = { + .query_device = mthca_query_device, + .query_port = mthca_query_port, + .alloc_pd = mthca_alloc_pd, + .dealloc_pd = mthca_free_pd, + .reg_mr = mthca_reg_mr, + .dereg_mr = mthca_dereg_mr, + .create_cq = mthca_create_cq, + .poll_cq = mthca_poll_cq, + .resize_cq = mthca_resize_cq, + .destroy_cq = mthca_destroy_cq, + .create_srq = mthca_create_srq, + .modify_srq = mthca_modify_srq, + .query_srq = mthca_query_srq, + .destroy_srq = mthca_destroy_srq, + .create_qp = mthca_create_qp, + .query_qp = mthca_query_qp, + .modify_qp = mthca_modify_qp, + .destroy_qp = mthca_destroy_qp, + .create_ah = mthca_create_ah, + .destroy_ah = mthca_destroy_ah, + .attach_mcast = mthca_attach_mcast, + .detach_mcast = mthca_detach_mcast +}; + +static struct ibv_context *mthca_alloc_context(struct ibv_device *ibdev, int cmd_fd) +{ + struct mthca_context *context; + struct ibv_get_context cmd; + struct mthca_alloc_ucontext_resp resp; + int i; + + context = calloc(1, sizeof *context); + if (!context) + return NULL; + + context->ibv_ctx.cmd_fd = cmd_fd; + + if (ibv_cmd_get_context(&context->ibv_ctx, &cmd, sizeof cmd, + &resp.ibv_resp, sizeof resp)) + goto err_free; + + context->num_qps = resp.qp_tab_size; + context->qp_table_shift = ffs(context->num_qps) - 1 - MTHCA_QP_TABLE_BITS; + context->qp_table_mask = (1 << context->qp_table_shift) - 1; + + /* + * Need to set ibv_ctx.device because mthca_is_memfree() will + * look at it to figure out the HCA type. + */ + context->ibv_ctx.device = ibdev; + + if (mthca_is_memfree(&context->ibv_ctx)) { + context->db_tab = mthca_alloc_db_tab(resp.uarc_size); + if (!context->db_tab) + goto err_free; + } else + context->db_tab = NULL; + + pthread_mutex_init(&context->qp_table_mutex, NULL); + for (i = 0; i < MTHCA_QP_TABLE_SIZE; ++i) + context->qp_table[i].refcnt = 0; + + context->uar = mmap(NULL, to_mdev(ibdev)->page_size, PROT_WRITE, + MAP_SHARED, cmd_fd, 0); + if (context->uar == MAP_FAILED) + goto err_db_tab; + + pthread_spin_init(&context->uar_lock, PTHREAD_PROCESS_PRIVATE); + + context->pd = mthca_alloc_pd(&context->ibv_ctx); + if (!context->pd) + goto err_unmap; + + context->pd->context = &context->ibv_ctx; + + context->ibv_ctx.ops = mthca_ctx_ops; + + if (mthca_is_memfree(&context->ibv_ctx)) { + context->ibv_ctx.ops.req_notify_cq = mthca_arbel_arm_cq; + context->ibv_ctx.ops.cq_event = mthca_arbel_cq_event; + context->ibv_ctx.ops.post_send = mthca_arbel_post_send; + context->ibv_ctx.ops.post_recv = mthca_arbel_post_recv; + context->ibv_ctx.ops.post_srq_recv = mthca_arbel_post_srq_recv; + } else { + context->ibv_ctx.ops.req_notify_cq = mthca_tavor_arm_cq; + context->ibv_ctx.ops.cq_event = NULL; + context->ibv_ctx.ops.post_send = mthca_tavor_post_send; + context->ibv_ctx.ops.post_recv = mthca_tavor_post_recv; + context->ibv_ctx.ops.post_srq_recv = mthca_tavor_post_srq_recv; + } + + return &context->ibv_ctx; + +err_unmap: + munmap(context->uar, to_mdev(ibdev)->page_size); + +err_db_tab: + mthca_free_db_tab(context->db_tab); + +err_free: + free(context); + return NULL; +} + +static void mthca_free_context(struct ibv_context *ibctx) +{ + struct mthca_context *context = to_mctx(ibctx); + + mthca_free_pd(context->pd); + munmap(context->uar, to_mdev(ibctx->device)->page_size); + mthca_free_db_tab(context->db_tab); + free(context); +} + +static struct ibv_device_ops mthca_dev_ops = { + .alloc_context = mthca_alloc_context, + .free_context = mthca_free_context +}; + +/* + * Keep a private implementation of HAVE_IBV_READ_SYSFS_FILE to handle + * old versions of libibverbs that didn't implement it. This can be + * removed when libibverbs 1.0.3 or newer is available "everywhere." + */ +#ifndef HAVE_IBV_READ_SYSFS_FILE +static int ibv_read_sysfs_file(const char *dir, const char *file, + char *buf, size_t size) +{ + char path[256]; + int fd; + int len; + + snprintf(path, sizeof path, "%s/%s", dir, file); + + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + + len = read(fd, buf, size); + + close(fd); + + if (len > 0 && buf[len - 1] == '\n') + buf[--len] = '\0'; + + return len; +} +#endif /* HAVE_IBV_READ_SYSFS_FILE */ + +static struct ibv_device *mthca_driver_init(const char *uverbs_sys_path, + int abi_version) +{ + char value[8]; + struct mthca_device *dev; + unsigned vendor, device; + int i; + + if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor", + value, sizeof value) < 0) + return NULL; + sscanf(value, "%i", &vendor); + + if (ibv_read_sysfs_file(uverbs_sys_path, "device/device", + value, sizeof value) < 0) + return NULL; + sscanf(value, "%i", &device); + + for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i) + if (vendor == hca_table[i].vendor && + device == hca_table[i].device) + goto found; + + return NULL; + +found: + if (abi_version > MTHCA_UVERBS_ABI_VERSION) { + fprintf(stderr, PFX "Fatal: ABI version %d of %s is too new (expected %d)\n", + abi_version, uverbs_sys_path, MTHCA_UVERBS_ABI_VERSION); + return NULL; + } + + dev = malloc(sizeof *dev); + if (!dev) { + fprintf(stderr, PFX "Fatal: couldn't allocate device for %s\n", + uverbs_sys_path); + return NULL; + } + + dev->ibv_dev.ops = mthca_dev_ops; + dev->hca_type = hca_table[i].type; + dev->page_size = sysconf(_SC_PAGESIZE); + + return &dev->ibv_dev; +} + +#ifdef HAVE_IBV_REGISTER_DRIVER +static __attribute__((constructor)) void mthca_register_driver(void) +{ + ibv_register_driver("mthca", mthca_driver_init); +} +#else +/* + * Export the old libsysfs sysfs_class_device-based driver entry point + * if libibverbs does not export an ibv_register_driver() function. + */ +struct ibv_device *openib_driver_init(struct sysfs_class_device *sysdev) +{ + int abi_ver = 0; + char value[8]; + + if (ibv_read_sysfs_file(sysdev->path, "abi_version", + value, sizeof value) > 0) + abi_ver = strtol(value, NULL, 10); + + return mthca_driver_init(sysdev->path, abi_ver); +} +#endif /* HAVE_IBV_REGISTER_DRIVER */ diff --git a/contrib/ofed/libmthca/src/mthca.h b/contrib/ofed/libmthca/src/mthca.h new file mode 100644 index 000000000000..66751f348443 --- /dev/null +++ b/contrib/ofed/libmthca/src/mthca.h @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MTHCA_H +#define MTHCA_H + +#include + +#include +#include + +#ifdef HAVE_VALGRIND_MEMCHECK_H + +# include + +# if !defined(VALGRIND_MAKE_MEM_DEFINED) || !defined(VALGRIND_MAKE_MEM_UNDEFINED) +# warning "Valgrind support requested, but VALGRIND_MAKE_MEM_(UN)DEFINED not available" +# endif + +#endif /* HAVE_VALGRIND_MEMCHECK_H */ + +#ifndef VALGRIND_MAKE_MEM_DEFINED +# define VALGRIND_MAKE_MEM_DEFINED(addr,len) +#endif + +#ifndef VALGRIND_MAKE_MEM_UNDEFINED +# define VALGRIND_MAKE_MEM_UNDEFINED(addr,len) +#endif + +#ifndef rmb +# define rmb() mb() +#endif + +#ifndef wmb +# define wmb() mb() +#endif + +#define HIDDEN __attribute__((visibility ("hidden"))) + +#define PFX "mthca: " + +enum mthca_hca_type { + MTHCA_TAVOR, + MTHCA_ARBEL +}; + +enum { + MTHCA_CQ_ENTRY_SIZE = 0x20 +}; + +enum { + MTHCA_QP_TABLE_BITS = 8, + MTHCA_QP_TABLE_SIZE = 1 << MTHCA_QP_TABLE_BITS, + MTHCA_QP_TABLE_MASK = MTHCA_QP_TABLE_SIZE - 1 +}; + +enum { + MTHCA_DB_REC_PAGE_SIZE = 4096, + MTHCA_DB_REC_PER_PAGE = MTHCA_DB_REC_PAGE_SIZE / 8 +}; + +enum mthca_db_type { + MTHCA_DB_TYPE_INVALID = 0x0, + MTHCA_DB_TYPE_CQ_SET_CI = 0x1, + MTHCA_DB_TYPE_CQ_ARM = 0x2, + MTHCA_DB_TYPE_SQ = 0x3, + MTHCA_DB_TYPE_RQ = 0x4, + MTHCA_DB_TYPE_SRQ = 0x5, + MTHCA_DB_TYPE_GROUP_SEP = 0x7 +}; + +enum { + MTHCA_OPCODE_NOP = 0x00, + MTHCA_OPCODE_RDMA_WRITE = 0x08, + MTHCA_OPCODE_RDMA_WRITE_IMM = 0x09, + MTHCA_OPCODE_SEND = 0x0a, + MTHCA_OPCODE_SEND_IMM = 0x0b, + MTHCA_OPCODE_RDMA_READ = 0x10, + MTHCA_OPCODE_ATOMIC_CS = 0x11, + MTHCA_OPCODE_ATOMIC_FA = 0x12, + MTHCA_OPCODE_BIND_MW = 0x18, + MTHCA_OPCODE_INVALID = 0xff +}; + +struct mthca_ah_page; + +struct mthca_device { + struct ibv_device ibv_dev; + enum mthca_hca_type hca_type; + int page_size; +}; + +struct mthca_db_table; + +struct mthca_context { + struct ibv_context ibv_ctx; + void *uar; + pthread_spinlock_t uar_lock; + struct mthca_db_table *db_tab; + struct ibv_pd *pd; + struct { + struct mthca_qp **table; + int refcnt; + } qp_table[MTHCA_QP_TABLE_SIZE]; + pthread_mutex_t qp_table_mutex; + int num_qps; + int qp_table_shift; + int qp_table_mask; +}; + +struct mthca_buf { + void *buf; + size_t length; +}; + +struct mthca_pd { + struct ibv_pd ibv_pd; + struct mthca_ah_page *ah_list; + pthread_mutex_t ah_mutex; + uint32_t pdn; +}; + +struct mthca_cq { + struct ibv_cq ibv_cq; + struct mthca_buf buf; + pthread_spinlock_t lock; + struct ibv_mr *mr; + uint32_t cqn; + uint32_t cons_index; + + /* Next fields are mem-free only */ + int set_ci_db_index; + uint32_t *set_ci_db; + int arm_db_index; + uint32_t *arm_db; + int arm_sn; +}; + +struct mthca_srq { + struct ibv_srq ibv_srq; + struct mthca_buf buf; + void *last; + pthread_spinlock_t lock; + struct ibv_mr *mr; + uint64_t *wrid; + uint32_t srqn; + int max; + int max_gs; + int wqe_shift; + int first_free; + int last_free; + int buf_size; + + /* Next fields are mem-free only */ + int db_index; + uint32_t *db; + uint16_t counter; +}; + +struct mthca_wq { + pthread_spinlock_t lock; + int max; + unsigned next_ind; + unsigned last_comp; + unsigned head; + unsigned tail; + void *last; + int max_gs; + int wqe_shift; + + /* Next fields are mem-free only */ + int db_index; + uint32_t *db; +}; + +struct mthca_qp { + struct ibv_qp ibv_qp; + struct mthca_buf buf; + uint64_t *wrid; + int send_wqe_offset; + int max_inline_data; + int buf_size; + struct mthca_wq sq; + struct mthca_wq rq; + struct ibv_mr *mr; + int sq_sig_all; +}; + +struct mthca_av { + uint32_t port_pd; + uint8_t reserved1; + uint8_t g_slid; + uint16_t dlid; + uint8_t reserved2; + uint8_t gid_index; + uint8_t msg_sr; + uint8_t hop_limit; + uint32_t sl_tclass_flowlabel; + uint32_t dgid[4]; +}; + +struct mthca_ah { + struct ibv_ah ibv_ah; + struct mthca_av *av; + struct mthca_ah_page *page; + uint32_t key; +}; + +static inline unsigned long align(unsigned long val, unsigned long align) +{ + return (val + align - 1) & ~(align - 1); +} + +static inline uintptr_t db_align(uint32_t *db) +{ + return (uintptr_t) db & ~((uintptr_t) MTHCA_DB_REC_PAGE_SIZE - 1); +} + +#define to_mxxx(xxx, type) \ + ((struct mthca_##type *) \ + ((void *) ib##xxx - offsetof(struct mthca_##type, ibv_##xxx))) + +static inline struct mthca_device *to_mdev(struct ibv_device *ibdev) +{ + return to_mxxx(dev, device); +} + +static inline struct mthca_context *to_mctx(struct ibv_context *ibctx) +{ + return to_mxxx(ctx, context); +} + +static inline struct mthca_pd *to_mpd(struct ibv_pd *ibpd) +{ + return to_mxxx(pd, pd); +} + +static inline struct mthca_cq *to_mcq(struct ibv_cq *ibcq) +{ + return to_mxxx(cq, cq); +} + +static inline struct mthca_srq *to_msrq(struct ibv_srq *ibsrq) +{ + return to_mxxx(srq, srq); +} + +static inline struct mthca_qp *to_mqp(struct ibv_qp *ibqp) +{ + return to_mxxx(qp, qp); +} + +static inline struct mthca_ah *to_mah(struct ibv_ah *ibah) +{ + return to_mxxx(ah, ah); +} + +static inline int mthca_is_memfree(struct ibv_context *ibctx) +{ + return to_mdev(ibctx->device)->hca_type == MTHCA_ARBEL; +} + +int mthca_alloc_buf(struct mthca_buf *buf, size_t size, int page_size); +void mthca_free_buf(struct mthca_buf *buf); + +int mthca_alloc_db(struct mthca_db_table *db_tab, enum mthca_db_type type, + uint32_t **db); +void mthca_set_db_qn(uint32_t *db, enum mthca_db_type type, uint32_t qn); +void mthca_free_db(struct mthca_db_table *db_tab, enum mthca_db_type type, int db_index); +struct mthca_db_table *mthca_alloc_db_tab(int uarc_size); +void mthca_free_db_tab(struct mthca_db_table *db_tab); + +int mthca_query_device(struct ibv_context *context, + struct ibv_device_attr *attr); +int mthca_query_port(struct ibv_context *context, uint8_t port, + struct ibv_port_attr *attr); + +struct ibv_pd *mthca_alloc_pd(struct ibv_context *context); +int mthca_free_pd(struct ibv_pd *pd); + +struct ibv_mr *mthca_reg_mr(struct ibv_pd *pd, void *addr, + size_t length, enum ibv_access_flags access); +int mthca_dereg_mr(struct ibv_mr *mr); + +struct ibv_cq *mthca_create_cq(struct ibv_context *context, int cqe, + struct ibv_comp_channel *channel, + int comp_vector); +int mthca_resize_cq(struct ibv_cq *cq, int cqe); +int mthca_destroy_cq(struct ibv_cq *cq); +int mthca_poll_cq(struct ibv_cq *cq, int ne, struct ibv_wc *wc); +int mthca_tavor_arm_cq(struct ibv_cq *cq, int solicited); +int mthca_arbel_arm_cq(struct ibv_cq *cq, int solicited); +void mthca_arbel_cq_event(struct ibv_cq *cq); +void __mthca_cq_clean(struct mthca_cq *cq, uint32_t qpn, struct mthca_srq *srq); +void mthca_cq_clean(struct mthca_cq *cq, uint32_t qpn, struct mthca_srq *srq); +void mthca_cq_resize_copy_cqes(struct mthca_cq *cq, void *buf, int new_cqe); +int mthca_alloc_cq_buf(struct mthca_device *dev, struct mthca_buf *buf, int nent); + +struct ibv_srq *mthca_create_srq(struct ibv_pd *pd, + struct ibv_srq_init_attr *attr); +int mthca_modify_srq(struct ibv_srq *srq, + struct ibv_srq_attr *attr, + enum ibv_srq_attr_mask mask); +int mthca_query_srq(struct ibv_srq *srq, + struct ibv_srq_attr *attr); +int mthca_destroy_srq(struct ibv_srq *srq); +int mthca_alloc_srq_buf(struct ibv_pd *pd, struct ibv_srq_attr *attr, + struct mthca_srq *srq); +void mthca_free_srq_wqe(struct mthca_srq *srq, int ind); +int mthca_tavor_post_srq_recv(struct ibv_srq *ibsrq, + struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr); +int mthca_arbel_post_srq_recv(struct ibv_srq *ibsrq, + struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr); + +struct ibv_qp *mthca_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *attr); +int mthca_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + enum ibv_qp_attr_mask attr_mask, + struct ibv_qp_init_attr *init_attr); +int mthca_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + enum ibv_qp_attr_mask attr_mask); +int mthca_destroy_qp(struct ibv_qp *qp); +void mthca_init_qp_indices(struct mthca_qp *qp); +int mthca_tavor_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr, + struct ibv_send_wr **bad_wr); +int mthca_tavor_post_recv(struct ibv_qp *ibqp, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr); +int mthca_arbel_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr, + struct ibv_send_wr **bad_wr); +int mthca_arbel_post_recv(struct ibv_qp *ibqp, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr); +int mthca_alloc_qp_buf(struct ibv_pd *pd, struct ibv_qp_cap *cap, + enum ibv_qp_type type, struct mthca_qp *qp); +struct mthca_qp *mthca_find_qp(struct mthca_context *ctx, uint32_t qpn); +int mthca_store_qp(struct mthca_context *ctx, uint32_t qpn, struct mthca_qp *qp); +void mthca_clear_qp(struct mthca_context *ctx, uint32_t qpn); +int mthca_free_err_wqe(struct mthca_qp *qp, int is_send, + int index, int *dbd, uint32_t *new_wqe); +struct ibv_ah *mthca_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr); +int mthca_destroy_ah(struct ibv_ah *ah); +int mthca_alloc_av(struct mthca_pd *pd, struct ibv_ah_attr *attr, + struct mthca_ah *ah); +void mthca_free_av(struct mthca_ah *ah); +int mthca_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid); +int mthca_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid); + +#endif /* MTHCA_H */ diff --git a/contrib/ofed/libmthca/src/mthca.map b/contrib/ofed/libmthca/src/mthca.map new file mode 100644 index 000000000000..ae8ed861f956 --- /dev/null +++ b/contrib/ofed/libmthca/src/mthca.map @@ -0,0 +1,5 @@ +{ + global: + openib_driver_init; + local: *; +}; diff --git a/contrib/ofed/libmthca/src/qp.c b/contrib/ofed/libmthca/src/qp.c new file mode 100644 index 000000000000..84dd206d9125 --- /dev/null +++ b/contrib/ofed/libmthca/src/qp.c @@ -0,0 +1,963 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include "mthca.h" +#include "doorbell.h" +#include "wqe.h" + +enum { + MTHCA_SEND_DOORBELL_FENCE = 1 << 5 +}; + +static const uint8_t mthca_opcode[] = { + [IBV_WR_SEND] = MTHCA_OPCODE_SEND, + [IBV_WR_SEND_WITH_IMM] = MTHCA_OPCODE_SEND_IMM, + [IBV_WR_RDMA_WRITE] = MTHCA_OPCODE_RDMA_WRITE, + [IBV_WR_RDMA_WRITE_WITH_IMM] = MTHCA_OPCODE_RDMA_WRITE_IMM, + [IBV_WR_RDMA_READ] = MTHCA_OPCODE_RDMA_READ, + [IBV_WR_ATOMIC_CMP_AND_SWP] = MTHCA_OPCODE_ATOMIC_CS, + [IBV_WR_ATOMIC_FETCH_AND_ADD] = MTHCA_OPCODE_ATOMIC_FA, +}; + +static void *get_recv_wqe(struct mthca_qp *qp, int n) +{ + return qp->buf.buf + (n << qp->rq.wqe_shift); +} + +static void *get_send_wqe(struct mthca_qp *qp, int n) +{ + return qp->buf.buf + qp->send_wqe_offset + (n << qp->sq.wqe_shift); +} + +void mthca_init_qp_indices(struct mthca_qp *qp) +{ + qp->sq.next_ind = 0; + qp->sq.last_comp = qp->sq.max - 1; + qp->sq.head = 0; + qp->sq.tail = 0; + qp->sq.last = get_send_wqe(qp, qp->sq.max - 1); + + qp->rq.next_ind = 0; + qp->rq.last_comp = qp->rq.max - 1; + qp->rq.head = 0; + qp->rq.tail = 0; + qp->rq.last = get_recv_wqe(qp, qp->rq.max - 1); +} + +static inline int wq_overflow(struct mthca_wq *wq, int nreq, struct mthca_cq *cq) +{ + unsigned cur; + + cur = wq->head - wq->tail; + if (cur + nreq < wq->max) + return 0; + + pthread_spin_lock(&cq->lock); + cur = wq->head - wq->tail; + pthread_spin_unlock(&cq->lock); + + return cur + nreq >= wq->max; +} + +int mthca_tavor_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr, + struct ibv_send_wr **bad_wr) +{ + struct mthca_qp *qp = to_mqp(ibqp); + void *wqe, *prev_wqe; + int ind; + int nreq; + int ret = 0; + int size; + int size0 = 0; + int i; + /* + * f0 and op0 cannot be used unless nreq > 0, which means this + * function makes it through the loop at least once. So the + * code inside the if (!size0) will be executed, and f0 and + * op0 will be initialized. So any gcc warning about "may be + * used unitialized" is bogus. + */ + uint32_t f0; + uint32_t op0; + + pthread_spin_lock(&qp->sq.lock); + + ind = qp->sq.next_ind; + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + if (wq_overflow(&qp->sq, nreq, to_mcq(qp->ibv_qp.send_cq))) { + ret = -1; + *bad_wr = wr; + goto out; + } + + wqe = get_send_wqe(qp, ind); + prev_wqe = qp->sq.last; + qp->sq.last = wqe; + + ((struct mthca_next_seg *) wqe)->nda_op = 0; + ((struct mthca_next_seg *) wqe)->ee_nds = 0; + ((struct mthca_next_seg *) wqe)->flags = + ((wr->send_flags & IBV_SEND_SIGNALED) ? + htonl(MTHCA_NEXT_CQ_UPDATE) : 0) | + ((wr->send_flags & IBV_SEND_SOLICITED) ? + htonl(MTHCA_NEXT_SOLICIT) : 0) | + htonl(1); + if (wr->opcode == IBV_WR_SEND_WITH_IMM || + wr->opcode == IBV_WR_RDMA_WRITE_WITH_IMM) + ((struct mthca_next_seg *) wqe)->imm = wr->imm_data; + + wqe += sizeof (struct mthca_next_seg); + size = sizeof (struct mthca_next_seg) / 16; + + switch (ibqp->qp_type) { + case IBV_QPT_RC: + switch (wr->opcode) { + case IBV_WR_ATOMIC_CMP_AND_SWP: + case IBV_WR_ATOMIC_FETCH_AND_ADD: + ((struct mthca_raddr_seg *) wqe)->raddr = + htonll(wr->wr.atomic.remote_addr); + ((struct mthca_raddr_seg *) wqe)->rkey = + htonl(wr->wr.atomic.rkey); + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + + wqe += sizeof (struct mthca_raddr_seg); + + if (wr->opcode == IBV_WR_ATOMIC_CMP_AND_SWP) { + ((struct mthca_atomic_seg *) wqe)->swap_add = + htonll(wr->wr.atomic.swap); + ((struct mthca_atomic_seg *) wqe)->compare = + htonll(wr->wr.atomic.compare_add); + } else { + ((struct mthca_atomic_seg *) wqe)->swap_add = + htonll(wr->wr.atomic.compare_add); + ((struct mthca_atomic_seg *) wqe)->compare = 0; + } + + wqe += sizeof (struct mthca_atomic_seg); + size += (sizeof (struct mthca_raddr_seg) + + sizeof (struct mthca_atomic_seg)) / 16; + break; + + case IBV_WR_RDMA_WRITE: + case IBV_WR_RDMA_WRITE_WITH_IMM: + case IBV_WR_RDMA_READ: + ((struct mthca_raddr_seg *) wqe)->raddr = + htonll(wr->wr.rdma.remote_addr); + ((struct mthca_raddr_seg *) wqe)->rkey = + htonl(wr->wr.rdma.rkey); + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case IBV_QPT_UC: + switch (wr->opcode) { + case IBV_WR_RDMA_WRITE: + case IBV_WR_RDMA_WRITE_WITH_IMM: + ((struct mthca_raddr_seg *) wqe)->raddr = + htonll(wr->wr.rdma.remote_addr); + ((struct mthca_raddr_seg *) wqe)->rkey = + htonl(wr->wr.rdma.rkey); + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case IBV_QPT_UD: + ((struct mthca_tavor_ud_seg *) wqe)->lkey = + htonl(to_mah(wr->wr.ud.ah)->key); + ((struct mthca_tavor_ud_seg *) wqe)->av_addr = + htonll((uintptr_t) to_mah(wr->wr.ud.ah)->av); + ((struct mthca_tavor_ud_seg *) wqe)->dqpn = + htonl(wr->wr.ud.remote_qpn); + ((struct mthca_tavor_ud_seg *) wqe)->qkey = + htonl(wr->wr.ud.remote_qkey); + + wqe += sizeof (struct mthca_tavor_ud_seg); + size += sizeof (struct mthca_tavor_ud_seg) / 16; + break; + + default: + break; + } + + if (wr->num_sge > qp->sq.max_gs) { + ret = -1; + *bad_wr = wr; + goto out; + } + + if (wr->send_flags & IBV_SEND_INLINE) { + if (wr->num_sge) { + struct mthca_inline_seg *seg = wqe; + int s = 0; + + wqe += sizeof *seg; + for (i = 0; i < wr->num_sge; ++i) { + struct ibv_sge *sge = &wr->sg_list[i]; + + s += sge->length; + + if (s > qp->max_inline_data) { + ret = -1; + *bad_wr = wr; + goto out; + } + + memcpy(wqe, (void *) (intptr_t) sge->addr, + sge->length); + wqe += sge->length; + } + + seg->byte_count = htonl(MTHCA_INLINE_SEG | s); + size += align(s + sizeof *seg, 16) / 16; + } + } else { + struct mthca_data_seg *seg; + + for (i = 0; i < wr->num_sge; ++i) { + seg = wqe; + seg->byte_count = htonl(wr->sg_list[i].length); + seg->lkey = htonl(wr->sg_list[i].lkey); + seg->addr = htonll(wr->sg_list[i].addr); + wqe += sizeof *seg; + } + + size += wr->num_sge * (sizeof *seg / 16); + } + + qp->wrid[ind + qp->rq.max] = wr->wr_id; + + if (wr->opcode >= sizeof mthca_opcode / sizeof mthca_opcode[0]) { + ret = -1; + *bad_wr = wr; + goto out; + } + + ((struct mthca_next_seg *) prev_wqe)->nda_op = + htonl(((ind << qp->sq.wqe_shift) + + qp->send_wqe_offset) | + mthca_opcode[wr->opcode]); + /* + * Make sure that nda_op is written before setting ee_nds. + */ + wmb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + htonl((size0 ? 0 : MTHCA_NEXT_DBD) | size | + ((wr->send_flags & IBV_SEND_FENCE) ? + MTHCA_NEXT_FENCE : 0)); + + if (!size0) { + size0 = size; + op0 = mthca_opcode[wr->opcode]; + f0 = wr->send_flags & IBV_SEND_FENCE ? + MTHCA_SEND_DOORBELL_FENCE : 0; + } + + ++ind; + if (ind >= qp->sq.max) + ind -= qp->sq.max; + } + +out: + if (nreq) { + uint32_t doorbell[2]; + + doorbell[0] = htonl(((qp->sq.next_ind << qp->sq.wqe_shift) + + qp->send_wqe_offset) | f0 | op0); + doorbell[1] = htonl((ibqp->qp_num << 8) | size0); + + mthca_write64(doorbell, to_mctx(ibqp->context), MTHCA_SEND_DOORBELL); + } + + qp->sq.next_ind = ind; + qp->sq.head += nreq; + + pthread_spin_unlock(&qp->sq.lock); + return ret; +} + +int mthca_tavor_post_recv(struct ibv_qp *ibqp, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr) +{ + struct mthca_qp *qp = to_mqp(ibqp); + uint32_t doorbell[2]; + int ret = 0; + int nreq; + int i; + int size; + int size0 = 0; + int ind; + void *wqe; + void *prev_wqe; + + pthread_spin_lock(&qp->rq.lock); + + ind = qp->rq.next_ind; + + for (nreq = 0; wr; wr = wr->next) { + if (wq_overflow(&qp->rq, nreq, to_mcq(qp->ibv_qp.recv_cq))) { + ret = -1; + *bad_wr = wr; + goto out; + } + + wqe = get_recv_wqe(qp, ind); + prev_wqe = qp->rq.last; + qp->rq.last = wqe; + + ((struct mthca_next_seg *) wqe)->ee_nds = + htonl(MTHCA_NEXT_DBD); + ((struct mthca_next_seg *) wqe)->flags = + htonl(MTHCA_NEXT_CQ_UPDATE); + + wqe += sizeof (struct mthca_next_seg); + size = sizeof (struct mthca_next_seg) / 16; + + if (wr->num_sge > qp->rq.max_gs) { + ret = -1; + *bad_wr = wr; + goto out; + } + + for (i = 0; i < wr->num_sge; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + htonl(wr->sg_list[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + htonl(wr->sg_list[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + htonll(wr->sg_list[i].addr); + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + } + + qp->wrid[ind] = wr->wr_id; + + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + htonl(MTHCA_NEXT_DBD | size); + + if (!size0) + size0 = size; + + ++ind; + if (ind >= qp->rq.max) + ind -= qp->rq.max; + + ++nreq; + if (nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB) { + nreq = 0; + + doorbell[0] = htonl((qp->rq.next_ind << qp->rq.wqe_shift) | size0); + doorbell[1] = htonl(ibqp->qp_num << 8); + + /* + * Make sure that descriptors are written + * before doorbell is rung. + */ + wmb(); + + mthca_write64(doorbell, to_mctx(ibqp->context), MTHCA_RECV_DOORBELL); + + qp->rq.next_ind = ind; + qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB; + size0 = 0; + } + } + +out: + if (nreq) { + doorbell[0] = htonl((qp->rq.next_ind << qp->rq.wqe_shift) | size0); + doorbell[1] = htonl((ibqp->qp_num << 8) | nreq); + + /* + * Make sure that descriptors are written before + * doorbell is rung. + */ + wmb(); + + mthca_write64(doorbell, to_mctx(ibqp->context), MTHCA_RECV_DOORBELL); + } + + qp->rq.next_ind = ind; + qp->rq.head += nreq; + + pthread_spin_unlock(&qp->rq.lock); + return ret; +} + +int mthca_arbel_post_send(struct ibv_qp *ibqp, struct ibv_send_wr *wr, + struct ibv_send_wr **bad_wr) +{ + struct mthca_qp *qp = to_mqp(ibqp); + uint32_t doorbell[2]; + void *wqe, *prev_wqe; + int ind; + int nreq; + int ret = 0; + int size; + int size0 = 0; + int i; + /* + * f0 and op0 cannot be used unless nreq > 0, which means this + * function makes it through the loop at least once. So the + * code inside the if (!size0) will be executed, and f0 and + * op0 will be initialized. So any gcc warning about "may be + * used unitialized" is bogus. + */ + uint32_t f0; + uint32_t op0; + + pthread_spin_lock(&qp->sq.lock); + + /* XXX check that state is OK to post send */ + + ind = qp->sq.head & (qp->sq.max - 1); + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + if (nreq == MTHCA_ARBEL_MAX_WQES_PER_SEND_DB) { + nreq = 0; + + doorbell[0] = htonl((MTHCA_ARBEL_MAX_WQES_PER_SEND_DB << 24) | + ((qp->sq.head & 0xffff) << 8) | f0 | op0); + doorbell[1] = htonl((ibqp->qp_num << 8) | size0); + + qp->sq.head += MTHCA_ARBEL_MAX_WQES_PER_SEND_DB; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + *qp->sq.db = htonl(qp->sq.head & 0xffff); + + /* + * Make sure doorbell record is written before we + * write MMIO send doorbell. + */ + wmb(); + mthca_write64(doorbell, to_mctx(ibqp->context), MTHCA_SEND_DOORBELL); + + size0 = 0; + } + + if (wq_overflow(&qp->sq, nreq, to_mcq(qp->ibv_qp.send_cq))) { + ret = -1; + *bad_wr = wr; + goto out; + } + + wqe = get_send_wqe(qp, ind); + prev_wqe = qp->sq.last; + qp->sq.last = wqe; + + ((struct mthca_next_seg *) wqe)->flags = + ((wr->send_flags & IBV_SEND_SIGNALED) ? + htonl(MTHCA_NEXT_CQ_UPDATE) : 0) | + ((wr->send_flags & IBV_SEND_SOLICITED) ? + htonl(MTHCA_NEXT_SOLICIT) : 0) | + htonl(1); + if (wr->opcode == IBV_WR_SEND_WITH_IMM || + wr->opcode == IBV_WR_RDMA_WRITE_WITH_IMM) + ((struct mthca_next_seg *) wqe)->imm = wr->imm_data; + + wqe += sizeof (struct mthca_next_seg); + size = sizeof (struct mthca_next_seg) / 16; + + switch (ibqp->qp_type) { + case IBV_QPT_RC: + switch (wr->opcode) { + case IBV_WR_ATOMIC_CMP_AND_SWP: + case IBV_WR_ATOMIC_FETCH_AND_ADD: + ((struct mthca_raddr_seg *) wqe)->raddr = + htonll(wr->wr.atomic.remote_addr); + ((struct mthca_raddr_seg *) wqe)->rkey = + htonl(wr->wr.atomic.rkey); + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + + wqe += sizeof (struct mthca_raddr_seg); + + if (wr->opcode == IBV_WR_ATOMIC_CMP_AND_SWP) { + ((struct mthca_atomic_seg *) wqe)->swap_add = + htonll(wr->wr.atomic.swap); + ((struct mthca_atomic_seg *) wqe)->compare = + htonll(wr->wr.atomic.compare_add); + } else { + ((struct mthca_atomic_seg *) wqe)->swap_add = + htonll(wr->wr.atomic.compare_add); + ((struct mthca_atomic_seg *) wqe)->compare = 0; + } + + wqe += sizeof (struct mthca_atomic_seg); + size += (sizeof (struct mthca_raddr_seg) + + sizeof (struct mthca_atomic_seg)) / 16; + break; + + case IBV_WR_RDMA_WRITE: + case IBV_WR_RDMA_WRITE_WITH_IMM: + case IBV_WR_RDMA_READ: + ((struct mthca_raddr_seg *) wqe)->raddr = + htonll(wr->wr.rdma.remote_addr); + ((struct mthca_raddr_seg *) wqe)->rkey = + htonl(wr->wr.rdma.rkey); + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case IBV_QPT_UC: + switch (wr->opcode) { + case IBV_WR_RDMA_WRITE: + case IBV_WR_RDMA_WRITE_WITH_IMM: + ((struct mthca_raddr_seg *) wqe)->raddr = + htonll(wr->wr.rdma.remote_addr); + ((struct mthca_raddr_seg *) wqe)->rkey = + htonl(wr->wr.rdma.rkey); + ((struct mthca_raddr_seg *) wqe)->reserved = 0; + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case IBV_QPT_UD: + memcpy(((struct mthca_arbel_ud_seg *) wqe)->av, + to_mah(wr->wr.ud.ah)->av, sizeof (struct mthca_av)); + ((struct mthca_arbel_ud_seg *) wqe)->dqpn = + htonl(wr->wr.ud.remote_qpn); + ((struct mthca_arbel_ud_seg *) wqe)->qkey = + htonl(wr->wr.ud.remote_qkey); + + wqe += sizeof (struct mthca_arbel_ud_seg); + size += sizeof (struct mthca_arbel_ud_seg) / 16; + break; + + default: + break; + } + + if (wr->num_sge > qp->sq.max_gs) { + ret = -1; + *bad_wr = wr; + goto out; + } + + if (wr->send_flags & IBV_SEND_INLINE) { + if (wr->num_sge) { + struct mthca_inline_seg *seg = wqe; + int s = 0; + + wqe += sizeof *seg; + for (i = 0; i < wr->num_sge; ++i) { + struct ibv_sge *sge = &wr->sg_list[i]; + + s += sge->length; + + if (s > qp->max_inline_data) { + ret = -1; + *bad_wr = wr; + goto out; + } + + memcpy(wqe, (void *) (uintptr_t) sge->addr, + sge->length); + wqe += sge->length; + } + + seg->byte_count = htonl(MTHCA_INLINE_SEG | s); + size += align(s + sizeof *seg, 16) / 16; + } + } else { + struct mthca_data_seg *seg; + + for (i = 0; i < wr->num_sge; ++i) { + seg = wqe; + seg->byte_count = htonl(wr->sg_list[i].length); + seg->lkey = htonl(wr->sg_list[i].lkey); + seg->addr = htonll(wr->sg_list[i].addr); + wqe += sizeof *seg; + } + + size += wr->num_sge * (sizeof *seg / 16); + } + + qp->wrid[ind + qp->rq.max] = wr->wr_id; + + if (wr->opcode >= sizeof mthca_opcode / sizeof mthca_opcode[0]) { + ret = -1; + *bad_wr = wr; + goto out; + } + + ((struct mthca_next_seg *) prev_wqe)->nda_op = + htonl(((ind << qp->sq.wqe_shift) + + qp->send_wqe_offset) | + mthca_opcode[wr->opcode]); + wmb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + htonl(MTHCA_NEXT_DBD | size | + ((wr->send_flags & IBV_SEND_FENCE) ? + MTHCA_NEXT_FENCE : 0)); + + if (!size0) { + size0 = size; + op0 = mthca_opcode[wr->opcode]; + f0 = wr->send_flags & IBV_SEND_FENCE ? + MTHCA_SEND_DOORBELL_FENCE : 0; + } + + ++ind; + if (ind >= qp->sq.max) + ind -= qp->sq.max; + } + +out: + if (nreq) { + doorbell[0] = htonl((nreq << 24) | + ((qp->sq.head & 0xffff) << 8) | + f0 | op0); + doorbell[1] = htonl((ibqp->qp_num << 8) | size0); + + qp->sq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + *qp->sq.db = htonl(qp->sq.head & 0xffff); + + /* + * Make sure doorbell record is written before we + * write MMIO send doorbell. + */ + wmb(); + mthca_write64(doorbell, to_mctx(ibqp->context), MTHCA_SEND_DOORBELL); + } + + pthread_spin_unlock(&qp->sq.lock); + return ret; +} + +int mthca_arbel_post_recv(struct ibv_qp *ibqp, struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr) +{ + struct mthca_qp *qp = to_mqp(ibqp); + int ret = 0; + int nreq; + int ind; + int i; + void *wqe; + + pthread_spin_lock(&qp->rq.lock); + + /* XXX check that state is OK to post receive */ + + ind = qp->rq.head & (qp->rq.max - 1); + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + if (wq_overflow(&qp->rq, nreq, to_mcq(qp->ibv_qp.recv_cq))) { + ret = -1; + *bad_wr = wr; + goto out; + } + + wqe = get_recv_wqe(qp, ind); + + ((struct mthca_next_seg *) wqe)->flags = 0; + + wqe += sizeof (struct mthca_next_seg); + + if (wr->num_sge > qp->rq.max_gs) { + ret = -1; + *bad_wr = wr; + goto out; + } + + for (i = 0; i < wr->num_sge; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + htonl(wr->sg_list[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + htonl(wr->sg_list[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + htonll(wr->sg_list[i].addr); + wqe += sizeof (struct mthca_data_seg); + } + + if (i < qp->rq.max_gs) { + ((struct mthca_data_seg *) wqe)->byte_count = 0; + ((struct mthca_data_seg *) wqe)->lkey = htonl(MTHCA_INVAL_LKEY); + ((struct mthca_data_seg *) wqe)->addr = 0; + } + + qp->wrid[ind] = wr->wr_id; + + ++ind; + if (ind >= qp->rq.max) + ind -= qp->rq.max; + } +out: + if (nreq) { + qp->rq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + *qp->rq.db = htonl(qp->rq.head & 0xffff); + } + + pthread_spin_unlock(&qp->rq.lock); + return ret; +} + +int mthca_alloc_qp_buf(struct ibv_pd *pd, struct ibv_qp_cap *cap, + enum ibv_qp_type type, struct mthca_qp *qp) +{ + int size; + int max_sq_sge; + struct mthca_next_seg *next; + int i; + + qp->rq.max_gs = cap->max_recv_sge; + qp->sq.max_gs = cap->max_send_sge; + max_sq_sge = align(cap->max_inline_data + sizeof (struct mthca_inline_seg), + sizeof (struct mthca_data_seg)) / sizeof (struct mthca_data_seg); + if (max_sq_sge < cap->max_send_sge) + max_sq_sge = cap->max_send_sge; + + qp->wrid = malloc((qp->rq.max + qp->sq.max) * sizeof (uint64_t)); + if (!qp->wrid) + return -1; + + size = sizeof (struct mthca_next_seg) + + qp->rq.max_gs * sizeof (struct mthca_data_seg); + + for (qp->rq.wqe_shift = 6; 1 << qp->rq.wqe_shift < size; + qp->rq.wqe_shift++) + ; /* nothing */ + + size = max_sq_sge * sizeof (struct mthca_data_seg); + switch (type) { + case IBV_QPT_UD: + size += mthca_is_memfree(pd->context) ? + sizeof (struct mthca_arbel_ud_seg) : + sizeof (struct mthca_tavor_ud_seg); + break; + + case IBV_QPT_UC: + size += sizeof (struct mthca_raddr_seg); + break; + + case IBV_QPT_RC: + size += sizeof (struct mthca_raddr_seg); + /* + * An atomic op will require an atomic segment, a + * remote address segment and one scatter entry. + */ + if (size < (sizeof (struct mthca_atomic_seg) + + sizeof (struct mthca_raddr_seg) + + sizeof (struct mthca_data_seg))) + size = (sizeof (struct mthca_atomic_seg) + + sizeof (struct mthca_raddr_seg) + + sizeof (struct mthca_data_seg)); + break; + + default: + break; + } + + /* Make sure that we have enough space for a bind request */ + if (size < sizeof (struct mthca_bind_seg)) + size = sizeof (struct mthca_bind_seg); + + size += sizeof (struct mthca_next_seg); + + for (qp->sq.wqe_shift = 6; 1 << qp->sq.wqe_shift < size; + qp->sq.wqe_shift++) + ; /* nothing */ + + qp->send_wqe_offset = align(qp->rq.max << qp->rq.wqe_shift, + 1 << qp->sq.wqe_shift); + + qp->buf_size = qp->send_wqe_offset + (qp->sq.max << qp->sq.wqe_shift); + + if (mthca_alloc_buf(&qp->buf, + align(qp->buf_size, to_mdev(pd->context->device)->page_size), + to_mdev(pd->context->device)->page_size)) { + free(qp->wrid); + return -1; + } + + memset(qp->buf.buf, 0, qp->buf_size); + + if (mthca_is_memfree(pd->context)) { + struct mthca_data_seg *scatter; + uint32_t sz; + + sz = htonl((sizeof (struct mthca_next_seg) + + qp->rq.max_gs * sizeof (struct mthca_data_seg)) / 16); + + for (i = 0; i < qp->rq.max; ++i) { + next = get_recv_wqe(qp, i); + next->nda_op = htonl(((i + 1) & (qp->rq.max - 1)) << + qp->rq.wqe_shift); + next->ee_nds = sz; + + for (scatter = (void *) (next + 1); + (void *) scatter < (void *) next + (1 << qp->rq.wqe_shift); + ++scatter) + scatter->lkey = htonl(MTHCA_INVAL_LKEY); + } + + for (i = 0; i < qp->sq.max; ++i) { + next = get_send_wqe(qp, i); + next->nda_op = htonl((((i + 1) & (qp->sq.max - 1)) << + qp->sq.wqe_shift) + + qp->send_wqe_offset); + } + } else { + for (i = 0; i < qp->rq.max; ++i) { + next = get_recv_wqe(qp, i); + next->nda_op = htonl((((i + 1) % qp->rq.max) << + qp->rq.wqe_shift) | 1); + } + } + + qp->sq.last = get_send_wqe(qp, qp->sq.max - 1); + qp->rq.last = get_recv_wqe(qp, qp->rq.max - 1); + + return 0; +} + +struct mthca_qp *mthca_find_qp(struct mthca_context *ctx, uint32_t qpn) +{ + int tind = (qpn & (ctx->num_qps - 1)) >> ctx->qp_table_shift; + + if (ctx->qp_table[tind].refcnt) + return ctx->qp_table[tind].table[qpn & ctx->qp_table_mask]; + else + return NULL; +} + +int mthca_store_qp(struct mthca_context *ctx, uint32_t qpn, struct mthca_qp *qp) +{ + int tind = (qpn & (ctx->num_qps - 1)) >> ctx->qp_table_shift; + + if (!ctx->qp_table[tind].refcnt) { + ctx->qp_table[tind].table = calloc(ctx->qp_table_mask + 1, + sizeof (struct mthca_qp *)); + if (!ctx->qp_table[tind].table) + return -1; + } + + ++ctx->qp_table[tind].refcnt; + ctx->qp_table[tind].table[qpn & ctx->qp_table_mask] = qp; + return 0; +} + +void mthca_clear_qp(struct mthca_context *ctx, uint32_t qpn) +{ + int tind = (qpn & (ctx->num_qps - 1)) >> ctx->qp_table_shift; + + if (!--ctx->qp_table[tind].refcnt) + free(ctx->qp_table[tind].table); + else + ctx->qp_table[tind].table[qpn & ctx->qp_table_mask] = NULL; +} + +int mthca_free_err_wqe(struct mthca_qp *qp, int is_send, + int index, int *dbd, uint32_t *new_wqe) +{ + struct mthca_next_seg *next; + + /* + * For SRQs, all receive WQEs generate a CQE, so we're always + * at the end of the doorbell chain. + */ + if (qp->ibv_qp.srq && !is_send) { + *new_wqe = 0; + return 0; + } + + if (is_send) + next = get_send_wqe(qp, index); + else + next = get_recv_wqe(qp, index); + + *dbd = !!(next->ee_nds & htonl(MTHCA_NEXT_DBD)); + if (next->ee_nds & htonl(0x3f)) + *new_wqe = (next->nda_op & htonl(~0x3f)) | + (next->ee_nds & htonl(0x3f)); + else + *new_wqe = 0; + + return 0; +} + diff --git a/contrib/ofed/libmthca/src/srq.c b/contrib/ofed/libmthca/src/srq.c new file mode 100644 index 000000000000..97a0c743f5f7 --- /dev/null +++ b/contrib/ofed/libmthca/src/srq.c @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include "mthca.h" +#include "doorbell.h" +#include "wqe.h" + +static void *get_wqe(struct mthca_srq *srq, int n) +{ + return srq->buf.buf + (n << srq->wqe_shift); +} + +/* + * Return a pointer to the location within a WQE that we're using as a + * link when the WQE is in the free list. We use the imm field at an + * offset of 12 bytes because in the Tavor case, posting a WQE may + * overwrite the next segment of the previous WQE, but a receive WQE + * will never touch the imm field. This avoids corrupting our free + * list if the previous WQE has already completed and been put on the + * free list when we post the next WQE. + */ +static inline int *wqe_to_link(void *wqe) +{ + return (int *) (wqe + 12); +} + +void mthca_free_srq_wqe(struct mthca_srq *srq, int ind) +{ + struct mthca_next_seg *last_free; + + pthread_spin_lock(&srq->lock); + + last_free = get_wqe(srq, srq->last_free); + *wqe_to_link(last_free) = ind; + last_free->nda_op = htonl((ind << srq->wqe_shift) | 1); + *wqe_to_link(get_wqe(srq, ind)) = -1; + srq->last_free = ind; + + pthread_spin_unlock(&srq->lock); +} + +int mthca_tavor_post_srq_recv(struct ibv_srq *ibsrq, + struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr) +{ + struct mthca_srq *srq = to_msrq(ibsrq); + uint32_t doorbell[2]; + int err = 0; + int first_ind; + int ind; + int next_ind; + int nreq; + int i; + void *wqe; + void *prev_wqe; + + pthread_spin_lock(&srq->lock); + + first_ind = srq->first_free; + + for (nreq = 0; wr; wr = wr->next) { + ind = srq->first_free; + wqe = get_wqe(srq, ind); + next_ind = *wqe_to_link(wqe); + + if (next_ind < 0) { + err = -1; + *bad_wr = wr; + break; + } + + prev_wqe = srq->last; + srq->last = wqe; + + ((struct mthca_next_seg *) wqe)->ee_nds = 0; + /* flags field will always remain 0 */ + + wqe += sizeof (struct mthca_next_seg); + + if (wr->num_sge > srq->max_gs) { + err = -1; + *bad_wr = wr; + srq->last = prev_wqe; + break; + } + + for (i = 0; i < wr->num_sge; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + htonl(wr->sg_list[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + htonl(wr->sg_list[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + htonll(wr->sg_list[i].addr); + wqe += sizeof (struct mthca_data_seg); + } + + if (i < srq->max_gs) { + ((struct mthca_data_seg *) wqe)->byte_count = 0; + ((struct mthca_data_seg *) wqe)->lkey = htonl(MTHCA_INVAL_LKEY); + ((struct mthca_data_seg *) wqe)->addr = 0; + } + + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + htonl(MTHCA_NEXT_DBD); + + srq->wrid[ind] = wr->wr_id; + srq->first_free = next_ind; + + if (++nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB) { + nreq = 0; + + doorbell[0] = htonl(first_ind << srq->wqe_shift); + doorbell[1] = htonl(srq->srqn << 8); + + /* + * Make sure that descriptors are written + * before doorbell is rung. + */ + wmb(); + + mthca_write64(doorbell, to_mctx(ibsrq->context), MTHCA_RECV_DOORBELL); + + first_ind = srq->first_free; + } + } + + if (nreq) { + doorbell[0] = htonl(first_ind << srq->wqe_shift); + doorbell[1] = htonl((srq->srqn << 8) | nreq); + + /* + * Make sure that descriptors are written before + * doorbell is rung. + */ + wmb(); + + mthca_write64(doorbell, to_mctx(ibsrq->context), MTHCA_RECV_DOORBELL); + } + + pthread_spin_unlock(&srq->lock); + return err; +} + +int mthca_arbel_post_srq_recv(struct ibv_srq *ibsrq, + struct ibv_recv_wr *wr, + struct ibv_recv_wr **bad_wr) +{ + struct mthca_srq *srq = to_msrq(ibsrq); + int err = 0; + int ind; + int next_ind; + int nreq; + int i; + void *wqe; + + pthread_spin_lock(&srq->lock); + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + ind = srq->first_free; + wqe = get_wqe(srq, ind); + next_ind = *wqe_to_link(wqe); + + if (next_ind < 0) { + err = -1; + *bad_wr = wr; + break; + } + + ((struct mthca_next_seg *) wqe)->ee_nds = 0; + /* flags field will always remain 0 */ + + wqe += sizeof (struct mthca_next_seg); + + if (wr->num_sge > srq->max_gs) { + err = -1; + *bad_wr = wr; + break; + } + + for (i = 0; i < wr->num_sge; ++i) { + ((struct mthca_data_seg *) wqe)->byte_count = + htonl(wr->sg_list[i].length); + ((struct mthca_data_seg *) wqe)->lkey = + htonl(wr->sg_list[i].lkey); + ((struct mthca_data_seg *) wqe)->addr = + htonll(wr->sg_list[i].addr); + wqe += sizeof (struct mthca_data_seg); + } + + if (i < srq->max_gs) { + ((struct mthca_data_seg *) wqe)->byte_count = 0; + ((struct mthca_data_seg *) wqe)->lkey = htonl(MTHCA_INVAL_LKEY); + ((struct mthca_data_seg *) wqe)->addr = 0; + } + + srq->wrid[ind] = wr->wr_id; + srq->first_free = next_ind; + } + + if (nreq) { + srq->counter += nreq; + + /* + * Make sure that descriptors are written before + * we write doorbell record. + */ + wmb(); + *srq->db = htonl(srq->counter); + } + + pthread_spin_unlock(&srq->lock); + return err; +} + +int mthca_alloc_srq_buf(struct ibv_pd *pd, struct ibv_srq_attr *attr, + struct mthca_srq *srq) +{ + struct mthca_data_seg *scatter; + void *wqe; + int size; + int i; + + srq->wrid = malloc(srq->max * sizeof (uint64_t)); + if (!srq->wrid) + return -1; + + size = sizeof (struct mthca_next_seg) + + srq->max_gs * sizeof (struct mthca_data_seg); + + for (srq->wqe_shift = 6; 1 << srq->wqe_shift < size; ++srq->wqe_shift) + ; /* nothing */ + + srq->buf_size = srq->max << srq->wqe_shift; + + if (mthca_alloc_buf(&srq->buf, + align(srq->buf_size, to_mdev(pd->context->device)->page_size), + to_mdev(pd->context->device)->page_size)) { + free(srq->wrid); + return -1; + } + + memset(srq->buf.buf, 0, srq->buf_size); + + /* + * Now initialize the SRQ buffer so that all of the WQEs are + * linked into the list of free WQEs. In addition, set the + * scatter list L_Keys to the sentry value of 0x100. + */ + + for (i = 0; i < srq->max; ++i) { + struct mthca_next_seg *next; + + next = wqe = get_wqe(srq, i); + + if (i < srq->max - 1) { + *wqe_to_link(wqe) = i + 1; + next->nda_op = htonl(((i + 1) << srq->wqe_shift) | 1); + } else { + *wqe_to_link(wqe) = -1; + next->nda_op = 0; + } + + for (scatter = wqe + sizeof (struct mthca_next_seg); + (void *) scatter < wqe + (1 << srq->wqe_shift); + ++scatter) + scatter->lkey = htonl(MTHCA_INVAL_LKEY); + } + + srq->first_free = 0; + srq->last_free = srq->max - 1; + srq->last = get_wqe(srq, srq->max - 1); + + return 0; +} diff --git a/contrib/ofed/libmthca/src/verbs.c b/contrib/ofed/libmthca/src/verbs.c new file mode 100644 index 000000000000..b2ef3ec08ce2 --- /dev/null +++ b/contrib/ofed/libmthca/src/verbs.c @@ -0,0 +1,758 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include "mthca.h" +#include "mthca-abi.h" + +int mthca_query_device(struct ibv_context *context, struct ibv_device_attr *attr) +{ + struct ibv_query_device cmd; + uint64_t raw_fw_ver; + unsigned major, minor, sub_minor; + int ret; + + ret = ibv_cmd_query_device(context, attr, &raw_fw_ver, &cmd, sizeof cmd); + if (ret) + return ret; + + major = (raw_fw_ver >> 32) & 0xffff; + minor = (raw_fw_ver >> 16) & 0xffff; + sub_minor = raw_fw_ver & 0xffff; + + snprintf(attr->fw_ver, sizeof attr->fw_ver, + "%d.%d.%d", major, minor, sub_minor); + + return 0; +} + +int mthca_query_port(struct ibv_context *context, uint8_t port, + struct ibv_port_attr *attr) +{ + struct ibv_query_port cmd; + + return ibv_cmd_query_port(context, port, attr, &cmd, sizeof cmd); +} + +struct ibv_pd *mthca_alloc_pd(struct ibv_context *context) +{ + struct ibv_alloc_pd cmd; + struct mthca_alloc_pd_resp resp; + struct mthca_pd *pd; + + pd = malloc(sizeof *pd); + if (!pd) + return NULL; + + if (!mthca_is_memfree(context)) { + pd->ah_list = NULL; + if (pthread_mutex_init(&pd->ah_mutex, NULL)) { + free(pd); + return NULL; + } + } + + if (ibv_cmd_alloc_pd(context, &pd->ibv_pd, &cmd, sizeof cmd, + &resp.ibv_resp, sizeof resp)) { + free(pd); + return NULL; + } + + pd->pdn = resp.pdn; + + return &pd->ibv_pd; +} + +int mthca_free_pd(struct ibv_pd *pd) +{ + int ret; + + ret = ibv_cmd_dealloc_pd(pd); + if (ret) + return ret; + + free(to_mpd(pd)); + return 0; +} + +static struct ibv_mr *__mthca_reg_mr(struct ibv_pd *pd, void *addr, + size_t length, uint64_t hca_va, + enum ibv_access_flags access, + int dma_sync) +{ + struct ibv_mr *mr; + struct mthca_reg_mr cmd; + int ret; + + /* + * Old kernels just ignore the extra data we pass in with the + * reg_mr command structure, so there's no need to add an ABI + * version check here (and indeed the kernel ABI was not + * incremented due to this change). + */ + cmd.mr_attrs = dma_sync ? MTHCA_MR_DMASYNC : 0; + cmd.reserved = 0; + + mr = malloc(sizeof *mr); + if (!mr) + return NULL; + +#ifdef IBV_CMD_REG_MR_HAS_RESP_PARAMS + { + struct ibv_reg_mr_resp resp; + + ret = ibv_cmd_reg_mr(pd, addr, length, hca_va, access, mr, + &cmd.ibv_cmd, sizeof cmd, &resp, sizeof resp); + } +#else + ret = ibv_cmd_reg_mr(pd, addr, length, hca_va, access, mr, + &cmd.ibv_cmd, sizeof cmd); +#endif + if (ret) { + free(mr); + return NULL; + } + + return mr; +} + +struct ibv_mr *mthca_reg_mr(struct ibv_pd *pd, void *addr, + size_t length, enum ibv_access_flags access) +{ + return __mthca_reg_mr(pd, addr, length, (uintptr_t) addr, access, 0); +} + +int mthca_dereg_mr(struct ibv_mr *mr) +{ + int ret; + + ret = ibv_cmd_dereg_mr(mr); + if (ret) + return ret; + + free(mr); + return 0; +} + +static int align_cq_size(int cqe) +{ + int nent; + + for (nent = 1; nent <= cqe; nent <<= 1) + ; /* nothing */ + + return nent; +} + +struct ibv_cq *mthca_create_cq(struct ibv_context *context, int cqe, + struct ibv_comp_channel *channel, + int comp_vector) +{ + struct mthca_create_cq cmd; + struct mthca_create_cq_resp resp; + struct mthca_cq *cq; + int ret; + + /* Sanity check CQ size before proceeding */ + if (cqe > 131072) + return NULL; + + cq = malloc(sizeof *cq); + if (!cq) + return NULL; + + cq->cons_index = 0; + + if (pthread_spin_init(&cq->lock, PTHREAD_PROCESS_PRIVATE)) + goto err; + + cqe = align_cq_size(cqe); + if (mthca_alloc_cq_buf(to_mdev(context->device), &cq->buf, cqe)) + goto err; + + cq->mr = __mthca_reg_mr(to_mctx(context)->pd, cq->buf.buf, + cqe * MTHCA_CQ_ENTRY_SIZE, + 0, IBV_ACCESS_LOCAL_WRITE, 1); + if (!cq->mr) + goto err_buf; + + cq->mr->context = context; + + if (mthca_is_memfree(context)) { + cq->arm_sn = 1; + cq->set_ci_db_index = mthca_alloc_db(to_mctx(context)->db_tab, + MTHCA_DB_TYPE_CQ_SET_CI, + &cq->set_ci_db); + if (cq->set_ci_db_index < 0) + goto err_unreg; + + cq->arm_db_index = mthca_alloc_db(to_mctx(context)->db_tab, + MTHCA_DB_TYPE_CQ_ARM, + &cq->arm_db); + if (cq->arm_db_index < 0) + goto err_set_db; + + cmd.arm_db_page = db_align(cq->arm_db); + cmd.set_db_page = db_align(cq->set_ci_db); + cmd.arm_db_index = cq->arm_db_index; + cmd.set_db_index = cq->set_ci_db_index; + } else { + cmd.arm_db_page = cmd.set_db_page = + cmd.arm_db_index = cmd.set_db_index = 0; + } + + cmd.lkey = cq->mr->lkey; + cmd.pdn = to_mpd(to_mctx(context)->pd)->pdn; + ret = ibv_cmd_create_cq(context, cqe - 1, channel, comp_vector, + &cq->ibv_cq, &cmd.ibv_cmd, sizeof cmd, + &resp.ibv_resp, sizeof resp); + if (ret) + goto err_arm_db; + + cq->cqn = resp.cqn; + + if (mthca_is_memfree(context)) { + mthca_set_db_qn(cq->set_ci_db, MTHCA_DB_TYPE_CQ_SET_CI, cq->cqn); + mthca_set_db_qn(cq->arm_db, MTHCA_DB_TYPE_CQ_ARM, cq->cqn); + } + + return &cq->ibv_cq; + +err_arm_db: + if (mthca_is_memfree(context)) + mthca_free_db(to_mctx(context)->db_tab, MTHCA_DB_TYPE_CQ_ARM, + cq->arm_db_index); + +err_set_db: + if (mthca_is_memfree(context)) + mthca_free_db(to_mctx(context)->db_tab, MTHCA_DB_TYPE_CQ_SET_CI, + cq->set_ci_db_index); + +err_unreg: + mthca_dereg_mr(cq->mr); + +err_buf: + mthca_free_buf(&cq->buf); + +err: + free(cq); + + return NULL; +} + +int mthca_resize_cq(struct ibv_cq *ibcq, int cqe) +{ + struct mthca_cq *cq = to_mcq(ibcq); + struct mthca_resize_cq cmd; + struct ibv_mr *mr; + struct mthca_buf buf; + int old_cqe; + int ret; + + /* Sanity check CQ size before proceeding */ + if (cqe > 131072) + return EINVAL; + + pthread_spin_lock(&cq->lock); + + cqe = align_cq_size(cqe); + if (cqe == ibcq->cqe + 1) { + ret = 0; + goto out; + } + + ret = mthca_alloc_cq_buf(to_mdev(ibcq->context->device), &buf, cqe); + if (ret) + goto out; + + mr = __mthca_reg_mr(to_mctx(ibcq->context)->pd, buf.buf, + cqe * MTHCA_CQ_ENTRY_SIZE, + 0, IBV_ACCESS_LOCAL_WRITE, 1); + if (!mr) { + mthca_free_buf(&buf); + ret = ENOMEM; + goto out; + } + + mr->context = ibcq->context; + + old_cqe = ibcq->cqe; + + cmd.lkey = mr->lkey; +#ifdef IBV_CMD_RESIZE_CQ_HAS_RESP_PARAMS + { + struct ibv_resize_cq_resp resp; + ret = ibv_cmd_resize_cq(ibcq, cqe - 1, &cmd.ibv_cmd, sizeof cmd, + &resp, sizeof resp); + } +#else + ret = ibv_cmd_resize_cq(ibcq, cqe - 1, &cmd.ibv_cmd, sizeof cmd); +#endif + if (ret) { + mthca_dereg_mr(mr); + mthca_free_buf(&buf); + goto out; + } + + mthca_cq_resize_copy_cqes(cq, buf.buf, old_cqe); + + mthca_dereg_mr(cq->mr); + mthca_free_buf(&cq->buf); + + cq->buf = buf; + cq->mr = mr; + +out: + pthread_spin_unlock(&cq->lock); + return ret; +} + +int mthca_destroy_cq(struct ibv_cq *cq) +{ + int ret; + + ret = ibv_cmd_destroy_cq(cq); + if (ret) + return ret; + + if (mthca_is_memfree(cq->context)) { + mthca_free_db(to_mctx(cq->context)->db_tab, MTHCA_DB_TYPE_CQ_SET_CI, + to_mcq(cq)->set_ci_db_index); + mthca_free_db(to_mctx(cq->context)->db_tab, MTHCA_DB_TYPE_CQ_ARM, + to_mcq(cq)->arm_db_index); + } + + mthca_dereg_mr(to_mcq(cq)->mr); + mthca_free_buf(&to_mcq(cq)->buf); + free(to_mcq(cq)); + + return 0; +} + +static int align_queue_size(struct ibv_context *context, int size, int spare) +{ + int ret; + + /* + * If someone asks for a 0-sized queue, presumably they're not + * going to use it. So don't mess with their size. + */ + if (!size) + return 0; + + if (mthca_is_memfree(context)) { + for (ret = 1; ret < size + spare; ret <<= 1) + ; /* nothing */ + + return ret; + } else + return size + spare; +} + +struct ibv_srq *mthca_create_srq(struct ibv_pd *pd, + struct ibv_srq_init_attr *attr) +{ + struct mthca_create_srq cmd; + struct mthca_create_srq_resp resp; + struct mthca_srq *srq; + int ret; + + /* Sanity check SRQ size before proceeding */ + if (attr->attr.max_wr > 1 << 16 || attr->attr.max_sge > 64) + return NULL; + + srq = malloc(sizeof *srq); + if (!srq) + return NULL; + + if (pthread_spin_init(&srq->lock, PTHREAD_PROCESS_PRIVATE)) + goto err; + + srq->max = align_queue_size(pd->context, attr->attr.max_wr, 1); + srq->max_gs = attr->attr.max_sge; + srq->counter = 0; + + if (mthca_alloc_srq_buf(pd, &attr->attr, srq)) + goto err; + + srq->mr = __mthca_reg_mr(pd, srq->buf.buf, srq->buf_size, 0, 0, 0); + if (!srq->mr) + goto err_free; + + srq->mr->context = pd->context; + + if (mthca_is_memfree(pd->context)) { + srq->db_index = mthca_alloc_db(to_mctx(pd->context)->db_tab, + MTHCA_DB_TYPE_SRQ, &srq->db); + if (srq->db_index < 0) + goto err_unreg; + + cmd.db_page = db_align(srq->db); + cmd.db_index = srq->db_index; + } else { + cmd.db_page = cmd.db_index = 0; + } + + cmd.lkey = srq->mr->lkey; + + ret = ibv_cmd_create_srq(pd, &srq->ibv_srq, attr, + &cmd.ibv_cmd, sizeof cmd, + &resp.ibv_resp, sizeof resp); + if (ret) + goto err_db; + + srq->srqn = resp.srqn; + + if (mthca_is_memfree(pd->context)) + mthca_set_db_qn(srq->db, MTHCA_DB_TYPE_SRQ, srq->srqn); + + return &srq->ibv_srq; + +err_db: + if (mthca_is_memfree(pd->context)) + mthca_free_db(to_mctx(pd->context)->db_tab, MTHCA_DB_TYPE_SRQ, + srq->db_index); + +err_unreg: + mthca_dereg_mr(srq->mr); + +err_free: + free(srq->wrid); + mthca_free_buf(&srq->buf); + +err: + free(srq); + + return NULL; +} + +int mthca_modify_srq(struct ibv_srq *srq, + struct ibv_srq_attr *attr, + enum ibv_srq_attr_mask attr_mask) +{ + struct ibv_modify_srq cmd; + + return ibv_cmd_modify_srq(srq, attr, attr_mask, &cmd, sizeof cmd); +} + +int mthca_query_srq(struct ibv_srq *srq, + struct ibv_srq_attr *attr) +{ + struct ibv_query_srq cmd; + + return ibv_cmd_query_srq(srq, attr, &cmd, sizeof cmd); +} + +int mthca_destroy_srq(struct ibv_srq *srq) +{ + int ret; + + ret = ibv_cmd_destroy_srq(srq); + if (ret) + return ret; + + if (mthca_is_memfree(srq->context)) + mthca_free_db(to_mctx(srq->context)->db_tab, MTHCA_DB_TYPE_SRQ, + to_msrq(srq)->db_index); + + mthca_dereg_mr(to_msrq(srq)->mr); + + mthca_free_buf(&to_msrq(srq)->buf); + free(to_msrq(srq)->wrid); + free(to_msrq(srq)); + + return 0; +} + +struct ibv_qp *mthca_create_qp(struct ibv_pd *pd, struct ibv_qp_init_attr *attr) +{ + struct mthca_create_qp cmd; + struct ibv_create_qp_resp resp; + struct mthca_qp *qp; + int ret; + + /* Sanity check QP size before proceeding */ + if (attr->cap.max_send_wr > 65536 || + attr->cap.max_recv_wr > 65536 || + attr->cap.max_send_sge > 64 || + attr->cap.max_recv_sge > 64 || + attr->cap.max_inline_data > 1024) + return NULL; + + qp = malloc(sizeof *qp); + if (!qp) + return NULL; + + qp->sq.max = align_queue_size(pd->context, attr->cap.max_send_wr, 0); + qp->rq.max = align_queue_size(pd->context, attr->cap.max_recv_wr, 0); + + if (mthca_alloc_qp_buf(pd, &attr->cap, attr->qp_type, qp)) + goto err; + + mthca_init_qp_indices(qp); + + if (pthread_spin_init(&qp->sq.lock, PTHREAD_PROCESS_PRIVATE) || + pthread_spin_init(&qp->rq.lock, PTHREAD_PROCESS_PRIVATE)) + goto err_free; + + qp->mr = __mthca_reg_mr(pd, qp->buf.buf, qp->buf_size, 0, 0, 0); + if (!qp->mr) + goto err_free; + + qp->mr->context = pd->context; + + cmd.lkey = qp->mr->lkey; + cmd.reserved = 0; + + if (mthca_is_memfree(pd->context)) { + qp->sq.db_index = mthca_alloc_db(to_mctx(pd->context)->db_tab, + MTHCA_DB_TYPE_SQ, + &qp->sq.db); + if (qp->sq.db_index < 0) + goto err_unreg; + + qp->rq.db_index = mthca_alloc_db(to_mctx(pd->context)->db_tab, + MTHCA_DB_TYPE_RQ, + &qp->rq.db); + if (qp->rq.db_index < 0) + goto err_sq_db; + + cmd.sq_db_page = db_align(qp->sq.db); + cmd.rq_db_page = db_align(qp->rq.db); + cmd.sq_db_index = qp->sq.db_index; + cmd.rq_db_index = qp->rq.db_index; + } else { + cmd.sq_db_page = cmd.rq_db_page = + cmd.sq_db_index = cmd.rq_db_index = 0; + } + + pthread_mutex_lock(&to_mctx(pd->context)->qp_table_mutex); + ret = ibv_cmd_create_qp(pd, &qp->ibv_qp, attr, &cmd.ibv_cmd, sizeof cmd, + &resp, sizeof resp); + if (ret) + goto err_rq_db; + + if (mthca_is_memfree(pd->context)) { + mthca_set_db_qn(qp->sq.db, MTHCA_DB_TYPE_SQ, qp->ibv_qp.qp_num); + mthca_set_db_qn(qp->rq.db, MTHCA_DB_TYPE_RQ, qp->ibv_qp.qp_num); + } + + ret = mthca_store_qp(to_mctx(pd->context), qp->ibv_qp.qp_num, qp); + if (ret) + goto err_destroy; + pthread_mutex_unlock(&to_mctx(pd->context)->qp_table_mutex); + + qp->sq.max = attr->cap.max_send_wr; + qp->rq.max = attr->cap.max_recv_wr; + qp->sq.max_gs = attr->cap.max_send_sge; + qp->rq.max_gs = attr->cap.max_recv_sge; + qp->max_inline_data = attr->cap.max_inline_data; + + return &qp->ibv_qp; + +err_destroy: + ibv_cmd_destroy_qp(&qp->ibv_qp); + +err_rq_db: + pthread_mutex_unlock(&to_mctx(pd->context)->qp_table_mutex); + if (mthca_is_memfree(pd->context)) + mthca_free_db(to_mctx(pd->context)->db_tab, MTHCA_DB_TYPE_RQ, + qp->rq.db_index); + +err_sq_db: + if (mthca_is_memfree(pd->context)) + mthca_free_db(to_mctx(pd->context)->db_tab, MTHCA_DB_TYPE_SQ, + qp->sq.db_index); + +err_unreg: + mthca_dereg_mr(qp->mr); + +err_free: + free(qp->wrid); + mthca_free_buf(&qp->buf); + +err: + free(qp); + + return NULL; +} + +int mthca_query_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + enum ibv_qp_attr_mask attr_mask, + struct ibv_qp_init_attr *init_attr) +{ + struct ibv_query_qp cmd; + + return ibv_cmd_query_qp(qp, attr, attr_mask, init_attr, &cmd, sizeof cmd); +} + +int mthca_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, + enum ibv_qp_attr_mask attr_mask) +{ + struct ibv_modify_qp cmd; + int ret; + + ret = ibv_cmd_modify_qp(qp, attr, attr_mask, &cmd, sizeof cmd); + + if (!ret && + (attr_mask & IBV_QP_STATE) && + attr->qp_state == IBV_QPS_RESET) { + mthca_cq_clean(to_mcq(qp->recv_cq), qp->qp_num, + qp->srq ? to_msrq(qp->srq) : NULL); + if (qp->send_cq != qp->recv_cq) + mthca_cq_clean(to_mcq(qp->send_cq), qp->qp_num, NULL); + + mthca_init_qp_indices(to_mqp(qp)); + + if (mthca_is_memfree(qp->context)) { + *to_mqp(qp)->sq.db = 0; + *to_mqp(qp)->rq.db = 0; + } + } + + return ret; +} + +static void mthca_lock_cqs(struct ibv_qp *qp) +{ + struct mthca_cq *send_cq = to_mcq(qp->send_cq); + struct mthca_cq *recv_cq = to_mcq(qp->recv_cq); + + if (send_cq == recv_cq) + pthread_spin_lock(&send_cq->lock); + else if (send_cq->cqn < recv_cq->cqn) { + pthread_spin_lock(&send_cq->lock); + pthread_spin_lock(&recv_cq->lock); + } else { + pthread_spin_lock(&recv_cq->lock); + pthread_spin_lock(&send_cq->lock); + } +} + +static void mthca_unlock_cqs(struct ibv_qp *qp) +{ + struct mthca_cq *send_cq = to_mcq(qp->send_cq); + struct mthca_cq *recv_cq = to_mcq(qp->recv_cq); + + if (send_cq == recv_cq) + pthread_spin_unlock(&send_cq->lock); + else if (send_cq->cqn < recv_cq->cqn) { + pthread_spin_unlock(&recv_cq->lock); + pthread_spin_unlock(&send_cq->lock); + } else { + pthread_spin_unlock(&send_cq->lock); + pthread_spin_unlock(&recv_cq->lock); + } +} + +int mthca_destroy_qp(struct ibv_qp *qp) +{ + int ret; + + pthread_mutex_lock(&to_mctx(qp->context)->qp_table_mutex); + ret = ibv_cmd_destroy_qp(qp); + if (ret) { + pthread_mutex_unlock(&to_mctx(qp->context)->qp_table_mutex); + return ret; + } + + mthca_lock_cqs(qp); + + __mthca_cq_clean(to_mcq(qp->recv_cq), qp->qp_num, + qp->srq ? to_msrq(qp->srq) : NULL); + if (qp->send_cq != qp->recv_cq) + __mthca_cq_clean(to_mcq(qp->send_cq), qp->qp_num, NULL); + + mthca_clear_qp(to_mctx(qp->context), qp->qp_num); + + mthca_unlock_cqs(qp); + pthread_mutex_unlock(&to_mctx(qp->context)->qp_table_mutex); + + if (mthca_is_memfree(qp->context)) { + mthca_free_db(to_mctx(qp->context)->db_tab, MTHCA_DB_TYPE_RQ, + to_mqp(qp)->rq.db_index); + mthca_free_db(to_mctx(qp->context)->db_tab, MTHCA_DB_TYPE_SQ, + to_mqp(qp)->sq.db_index); + } + + mthca_dereg_mr(to_mqp(qp)->mr); + mthca_free_buf(&to_mqp(qp)->buf); + free(to_mqp(qp)->wrid); + free(to_mqp(qp)); + + return 0; +} + +struct ibv_ah *mthca_create_ah(struct ibv_pd *pd, struct ibv_ah_attr *attr) +{ + struct mthca_ah *ah; + + ah = malloc(sizeof *ah); + if (!ah) + return NULL; + + if (mthca_alloc_av(to_mpd(pd), attr, ah)) { + free(ah); + return NULL; + } + + return &ah->ibv_ah; +} + +int mthca_destroy_ah(struct ibv_ah *ah) +{ + mthca_free_av(to_mah(ah)); + free(to_mah(ah)); + + return 0; +} + +int mthca_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid) +{ + return ibv_cmd_attach_mcast(qp, gid, lid); +} + +int mthca_detach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid) +{ + return ibv_cmd_detach_mcast(qp, gid, lid); +} diff --git a/contrib/ofed/libmthca/src/wqe.h b/contrib/ofed/libmthca/src/wqe.h new file mode 100644 index 000000000000..602f512c90c4 --- /dev/null +++ b/contrib/ofed/libmthca/src/wqe.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef WQE_H +#define WQE_H + +enum { + MTHCA_SEND_DOORBELL = 0x10, + MTHCA_RECV_DOORBELL = 0x18 +}; + +enum { + MTHCA_NEXT_DBD = 1 << 7, + MTHCA_NEXT_FENCE = 1 << 6, + MTHCA_NEXT_CQ_UPDATE = 1 << 3, + MTHCA_NEXT_EVENT_GEN = 1 << 2, + MTHCA_NEXT_SOLICIT = 1 << 1, +}; + +enum { + MTHCA_INLINE_SEG = 1 << 31 +}; + +enum { + MTHCA_INVAL_LKEY = 0x100, + MTHCA_TAVOR_MAX_WQES_PER_RECV_DB = 256, + MTHCA_ARBEL_MAX_WQES_PER_SEND_DB = 255 +}; + +struct mthca_next_seg { + uint32_t nda_op; /* [31:6] next WQE [4:0] next opcode */ + uint32_t ee_nds; /* [31:8] next EE [7] DBD [6] F [5:0] next WQE size */ + uint32_t flags; /* [3] CQ [2] Event [1] Solicit */ + uint32_t imm; /* immediate data */ +}; + +struct mthca_tavor_ud_seg { + uint32_t reserved1; + uint32_t lkey; + uint64_t av_addr; + uint32_t reserved2[4]; + uint32_t dqpn; + uint32_t qkey; + uint32_t reserved3[2]; +}; + +struct mthca_arbel_ud_seg { + uint32_t av[8]; + uint32_t dqpn; + uint32_t qkey; + uint32_t reserved[2]; +}; + +struct mthca_bind_seg { + uint32_t flags; /* [31] Atomic [30] rem write [29] rem read */ + uint32_t reserved; + uint32_t new_rkey; + uint32_t lkey; + uint64_t addr; + uint64_t length; +}; + +struct mthca_raddr_seg { + uint64_t raddr; + uint32_t rkey; + uint32_t reserved; +}; + +struct mthca_atomic_seg { + uint64_t swap_add; + uint64_t compare; +}; + +struct mthca_data_seg { + uint32_t byte_count; + uint32_t lkey; + uint64_t addr; +}; + +struct mthca_inline_seg { + uint32_t byte_count; +}; + +#endif /* WQE_H */ diff --git a/contrib/ofed/librdmacm/AUTHORS b/contrib/ofed/librdmacm/AUTHORS new file mode 100644 index 000000000000..f76b870b4dba --- /dev/null +++ b/contrib/ofed/librdmacm/AUTHORS @@ -0,0 +1 @@ +Sean Hefty diff --git a/contrib/ofed/librdmacm/COPYING b/contrib/ofed/librdmacm/COPYING new file mode 100644 index 000000000000..39f3831585f2 --- /dev/null +++ b/contrib/ofed/librdmacm/COPYING @@ -0,0 +1,378 @@ +This software is available to you under a choice of one of two +licenses. You may choose to be licensed under the terms of the the +OpenIB.org BSD license or the GNU General Public License (GPL) Version +2, both included below. + +Copyright (c) 2005 Intel Corporation. All rights reserved. + +================================================================== + + OpenIB.org BSD license + +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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +================================================================== + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/ofed/librdmacm/ChangeLog b/contrib/ofed/librdmacm/ChangeLog new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ofed/librdmacm/INSTALL b/contrib/ofed/librdmacm/INSTALL new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ofed/librdmacm/Makefile.am b/contrib/ofed/librdmacm/Makefile.am new file mode 100644 index 000000000000..290cbc3f4b25 --- /dev/null +++ b/contrib/ofed/librdmacm/Makefile.am @@ -0,0 +1,74 @@ +INCLUDES = -I$(srcdir)/include + +lib_LTLIBRARIES = src/librdmacm.la + +AM_CFLAGS = -g -Wall -D_GNU_SOURCE + +src_librdmacm_la_CFLAGS = $(AM_CFLAGS) + +if HAVE_LD_VERSION_SCRIPT + librdmacm_version_script = -Wl,--version-script=$(srcdir)/src/librdmacm.map +else + librdmacm_version_script = +endif + +src_librdmacm_la_SOURCES = src/cma.c +src_librdmacm_la_LDFLAGS = -version-info 1 -export-dynamic \ + $(librdmacm_version_script) +src_librdmacm_la_DEPENDENCIES = $(srcdir)/src/librdmacm.map + +bin_PROGRAMS = examples/ucmatose examples/rping examples/udaddy examples/mckey +examples_ucmatose_SOURCES = examples/cmatose.c +examples_ucmatose_LDADD = $(top_builddir)/src/librdmacm.la +examples_rping_SOURCES = examples/rping.c +examples_rping_LDADD = $(top_builddir)/src/librdmacm.la +examples_udaddy_SOURCES = examples/udaddy.c +examples_udaddy_LDADD = $(top_builddir)/src/librdmacm.la +examples_mckey_SOURCES = examples/mckey.c +examples_mckey_LDADD = $(top_builddir)/src/librdmacm.la + +librdmacmincludedir = $(includedir)/rdma + +librdmacminclude_HEADERS = include/rdma/rdma_cma_abi.h \ + include/rdma/rdma_cma.h + +man_MANS = \ + man/rdma_accept.3 \ + man/rdma_ack_cm_event.3 \ + man/rdma_bind_addr.3 \ + man/rdma_connect.3 \ + man/rdma_create_event_channel.3 \ + man/rdma_create_id.3 \ + man/rdma_create_qp.3 \ + man/rdma_destroy_event_channel.3 \ + man/rdma_destroy_id.3 \ + man/rdma_destroy_qp.3 \ + man/rdma_disconnect.3 \ + man/rdma_free_devices.3 \ + man/rdma_get_cm_event.3 \ + man/rdma_get_devices.3 \ + man/rdma_get_src_port.3 \ + man/rdma_get_dst_port.3 \ + man/rdma_get_local_addr.3 \ + man/rdma_get_peer_addr.3 \ + man/rdma_join_multicast.3 \ + man/rdma_leave_multicast.3 \ + man/rdma_listen.3 \ + man/rdma_migrate_id.3 \ + man/rdma_notify.3 \ + man/rdma_reject.3 \ + man/rdma_resolve_addr.3 \ + man/rdma_resolve_route.3 \ + man/rdma_event_str.3 \ + man/rdma_set_option.3 \ + man/ucmatose.1 \ + man/udaddy.1 \ + man/mckey.1 \ + man/rping.1 \ + man/rdma_cm.7 + +EXTRA_DIST = include/rdma/rdma_cma_abi.h include/rdma/rdma_cma.h \ + src/librdmacm.map librdmacm.spec.in $(man_MANS) + +dist-hook: librdmacm.spec + cp librdmacm.spec $(distdir) diff --git a/contrib/ofed/librdmacm/Makefile.in b/contrib/ofed/librdmacm/Makefile.in new file mode 100644 index 000000000000..21cb41d9ed5a --- /dev/null +++ b/contrib/ofed/librdmacm/Makefile.in @@ -0,0 +1,974 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = . +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = examples/ucmatose$(EXEEXT) examples/rping$(EXEEXT) \ + examples/udaddy$(EXEEXT) examples/mckey$(EXEEXT) +DIST_COMMON = README $(am__configure_deps) $(librdmacminclude_HEADERS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/config.h.in $(srcdir)/librdmacm.spec.in \ + $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \ + config/compile config/config.guess config/config.sub \ + config/depcomp config/install-sh config/ltmain.sh \ + config/missing +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno configure.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = librdmacm.spec +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man3dir)" \ + "$(DESTDIR)$(man7dir)" "$(DESTDIR)$(librdmacmincludedir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +src_librdmacm_la_LIBADD = +am_src_librdmacm_la_OBJECTS = src_librdmacm_la-cma.lo +src_librdmacm_la_OBJECTS = $(am_src_librdmacm_la_OBJECTS) +am__dirstamp = $(am__leading_dot)dirstamp +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_examples_mckey_OBJECTS = mckey.$(OBJEXT) +examples_mckey_OBJECTS = $(am_examples_mckey_OBJECTS) +examples_mckey_DEPENDENCIES = $(top_builddir)/src/librdmacm.la +am_examples_rping_OBJECTS = rping.$(OBJEXT) +examples_rping_OBJECTS = $(am_examples_rping_OBJECTS) +examples_rping_DEPENDENCIES = $(top_builddir)/src/librdmacm.la +am_examples_ucmatose_OBJECTS = cmatose.$(OBJEXT) +examples_ucmatose_OBJECTS = $(am_examples_ucmatose_OBJECTS) +examples_ucmatose_DEPENDENCIES = $(top_builddir)/src/librdmacm.la +am_examples_udaddy_OBJECTS = udaddy.$(OBJEXT) +examples_udaddy_OBJECTS = $(am_examples_udaddy_OBJECTS) +examples_udaddy_DEPENDENCIES = $(top_builddir)/src/librdmacm.la +DEFAULT_INCLUDES = -I. -I$(srcdir) -I. +depcomp = $(SHELL) $(top_srcdir)/config/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(src_librdmacm_la_SOURCES) $(examples_mckey_SOURCES) \ + $(examples_rping_SOURCES) $(examples_ucmatose_SOURCES) \ + $(examples_udaddy_SOURCES) +DIST_SOURCES = $(src_librdmacm_la_SOURCES) $(examples_mckey_SOURCES) \ + $(examples_rping_SOURCES) $(examples_ucmatose_SOURCES) \ + $(examples_udaddy_SOURCES) +man1dir = $(mandir)/man1 +man3dir = $(mandir)/man3 +man7dir = $(mandir)/man7 +NROFF = nroff +MANS = $(man_MANS) +librdmacmincludeHEADERS_INSTALL = $(INSTALL_HEADER) +HEADERS = $(librdmacminclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +HAVE_LD_VERSION_SCRIPT_FALSE = @HAVE_LD_VERSION_SCRIPT_FALSE@ +HAVE_LD_VERSION_SCRIPT_TRUE = @HAVE_LD_VERSION_SCRIPT_TRUE@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +INCLUDES = -I$(srcdir)/include +lib_LTLIBRARIES = src/librdmacm.la +AM_CFLAGS = -g -Wall -D_GNU_SOURCE +src_librdmacm_la_CFLAGS = $(AM_CFLAGS) +@HAVE_LD_VERSION_SCRIPT_FALSE@librdmacm_version_script = +@HAVE_LD_VERSION_SCRIPT_TRUE@librdmacm_version_script = -Wl,--version-script=$(srcdir)/src/librdmacm.map +src_librdmacm_la_SOURCES = src/cma.c +src_librdmacm_la_LDFLAGS = -version-info 1 -export-dynamic \ + $(librdmacm_version_script) + +src_librdmacm_la_DEPENDENCIES = $(srcdir)/src/librdmacm.map +examples_ucmatose_SOURCES = examples/cmatose.c +examples_ucmatose_LDADD = $(top_builddir)/src/librdmacm.la +examples_rping_SOURCES = examples/rping.c +examples_rping_LDADD = $(top_builddir)/src/librdmacm.la +examples_udaddy_SOURCES = examples/udaddy.c +examples_udaddy_LDADD = $(top_builddir)/src/librdmacm.la +examples_mckey_SOURCES = examples/mckey.c +examples_mckey_LDADD = $(top_builddir)/src/librdmacm.la +librdmacmincludedir = $(includedir)/rdma +librdmacminclude_HEADERS = include/rdma/rdma_cma_abi.h \ + include/rdma/rdma_cma.h + +man_MANS = \ + man/rdma_accept.3 \ + man/rdma_ack_cm_event.3 \ + man/rdma_bind_addr.3 \ + man/rdma_connect.3 \ + man/rdma_create_event_channel.3 \ + man/rdma_create_id.3 \ + man/rdma_create_qp.3 \ + man/rdma_destroy_event_channel.3 \ + man/rdma_destroy_id.3 \ + man/rdma_destroy_qp.3 \ + man/rdma_disconnect.3 \ + man/rdma_free_devices.3 \ + man/rdma_get_cm_event.3 \ + man/rdma_get_devices.3 \ + man/rdma_get_src_port.3 \ + man/rdma_get_dst_port.3 \ + man/rdma_get_local_addr.3 \ + man/rdma_get_peer_addr.3 \ + man/rdma_join_multicast.3 \ + man/rdma_leave_multicast.3 \ + man/rdma_listen.3 \ + man/rdma_migrate_id.3 \ + man/rdma_notify.3 \ + man/rdma_reject.3 \ + man/rdma_resolve_addr.3 \ + man/rdma_resolve_route.3 \ + man/rdma_event_str.3 \ + man/rdma_set_option.3 \ + man/ucmatose.1 \ + man/udaddy.1 \ + man/mckey.1 \ + man/rping.1 \ + man/rdma_cm.7 + +EXTRA_DIST = include/rdma/rdma_cma_abi.h include/rdma/rdma_cma.h \ + src/librdmacm.map librdmacm.spec.in $(man_MANS) + +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign '; \ + cd $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: $(am__configure_deps) + cd $(top_srcdir) && $(AUTOHEADER) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +librdmacm.spec: $(top_builddir)/config.status $(srcdir)/librdmacm.spec.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +src/$(am__dirstamp): + @$(mkdir_p) src + @: > src/$(am__dirstamp) +src/librdmacm.la: $(src_librdmacm_la_OBJECTS) $(src_librdmacm_la_DEPENDENCIES) src/$(am__dirstamp) + $(LINK) -rpath $(libdir) $(src_librdmacm_la_LDFLAGS) $(src_librdmacm_la_OBJECTS) $(src_librdmacm_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + || test -f $$p1 \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +examples/$(am__dirstamp): + @$(mkdir_p) examples + @: > examples/$(am__dirstamp) +examples/mckey$(EXEEXT): $(examples_mckey_OBJECTS) $(examples_mckey_DEPENDENCIES) examples/$(am__dirstamp) + @rm -f examples/mckey$(EXEEXT) + $(LINK) $(examples_mckey_LDFLAGS) $(examples_mckey_OBJECTS) $(examples_mckey_LDADD) $(LIBS) +examples/rping$(EXEEXT): $(examples_rping_OBJECTS) $(examples_rping_DEPENDENCIES) examples/$(am__dirstamp) + @rm -f examples/rping$(EXEEXT) + $(LINK) $(examples_rping_LDFLAGS) $(examples_rping_OBJECTS) $(examples_rping_LDADD) $(LIBS) +examples/ucmatose$(EXEEXT): $(examples_ucmatose_OBJECTS) $(examples_ucmatose_DEPENDENCIES) examples/$(am__dirstamp) + @rm -f examples/ucmatose$(EXEEXT) + $(LINK) $(examples_ucmatose_LDFLAGS) $(examples_ucmatose_OBJECTS) $(examples_ucmatose_LDADD) $(LIBS) +examples/udaddy$(EXEEXT): $(examples_udaddy_OBJECTS) $(examples_udaddy_DEPENDENCIES) examples/$(am__dirstamp) + @rm -f examples/udaddy$(EXEEXT) + $(LINK) $(examples_udaddy_LDFLAGS) $(examples_udaddy_OBJECTS) $(examples_udaddy_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmatose.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mckey.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rping.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/src_librdmacm_la-cma.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/udaddy.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +src_librdmacm_la-cma.lo: src/cma.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_librdmacm_la_CFLAGS) $(CFLAGS) -MT src_librdmacm_la-cma.lo -MD -MP -MF "$(DEPDIR)/src_librdmacm_la-cma.Tpo" -c -o src_librdmacm_la-cma.lo `test -f 'src/cma.c' || echo '$(srcdir)/'`src/cma.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/src_librdmacm_la-cma.Tpo" "$(DEPDIR)/src_librdmacm_la-cma.Plo"; else rm -f "$(DEPDIR)/src_librdmacm_la-cma.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='src/cma.c' object='src_librdmacm_la-cma.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_librdmacm_la_CFLAGS) $(CFLAGS) -c -o src_librdmacm_la-cma.lo `test -f 'src/cma.c' || echo '$(srcdir)/'`src/cma.c + +mckey.o: examples/mckey.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mckey.o -MD -MP -MF "$(DEPDIR)/mckey.Tpo" -c -o mckey.o `test -f 'examples/mckey.c' || echo '$(srcdir)/'`examples/mckey.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/mckey.Tpo" "$(DEPDIR)/mckey.Po"; else rm -f "$(DEPDIR)/mckey.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='examples/mckey.c' object='mckey.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mckey.o `test -f 'examples/mckey.c' || echo '$(srcdir)/'`examples/mckey.c + +mckey.obj: examples/mckey.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mckey.obj -MD -MP -MF "$(DEPDIR)/mckey.Tpo" -c -o mckey.obj `if test -f 'examples/mckey.c'; then $(CYGPATH_W) 'examples/mckey.c'; else $(CYGPATH_W) '$(srcdir)/examples/mckey.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/mckey.Tpo" "$(DEPDIR)/mckey.Po"; else rm -f "$(DEPDIR)/mckey.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='examples/mckey.c' object='mckey.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mckey.obj `if test -f 'examples/mckey.c'; then $(CYGPATH_W) 'examples/mckey.c'; else $(CYGPATH_W) '$(srcdir)/examples/mckey.c'; fi` + +rping.o: examples/rping.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rping.o -MD -MP -MF "$(DEPDIR)/rping.Tpo" -c -o rping.o `test -f 'examples/rping.c' || echo '$(srcdir)/'`examples/rping.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/rping.Tpo" "$(DEPDIR)/rping.Po"; else rm -f "$(DEPDIR)/rping.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='examples/rping.c' object='rping.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rping.o `test -f 'examples/rping.c' || echo '$(srcdir)/'`examples/rping.c + +rping.obj: examples/rping.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rping.obj -MD -MP -MF "$(DEPDIR)/rping.Tpo" -c -o rping.obj `if test -f 'examples/rping.c'; then $(CYGPATH_W) 'examples/rping.c'; else $(CYGPATH_W) '$(srcdir)/examples/rping.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/rping.Tpo" "$(DEPDIR)/rping.Po"; else rm -f "$(DEPDIR)/rping.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='examples/rping.c' object='rping.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rping.obj `if test -f 'examples/rping.c'; then $(CYGPATH_W) 'examples/rping.c'; else $(CYGPATH_W) '$(srcdir)/examples/rping.c'; fi` + +cmatose.o: examples/cmatose.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cmatose.o -MD -MP -MF "$(DEPDIR)/cmatose.Tpo" -c -o cmatose.o `test -f 'examples/cmatose.c' || echo '$(srcdir)/'`examples/cmatose.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cmatose.Tpo" "$(DEPDIR)/cmatose.Po"; else rm -f "$(DEPDIR)/cmatose.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='examples/cmatose.c' object='cmatose.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cmatose.o `test -f 'examples/cmatose.c' || echo '$(srcdir)/'`examples/cmatose.c + +cmatose.obj: examples/cmatose.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cmatose.obj -MD -MP -MF "$(DEPDIR)/cmatose.Tpo" -c -o cmatose.obj `if test -f 'examples/cmatose.c'; then $(CYGPATH_W) 'examples/cmatose.c'; else $(CYGPATH_W) '$(srcdir)/examples/cmatose.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/cmatose.Tpo" "$(DEPDIR)/cmatose.Po"; else rm -f "$(DEPDIR)/cmatose.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='examples/cmatose.c' object='cmatose.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cmatose.obj `if test -f 'examples/cmatose.c'; then $(CYGPATH_W) 'examples/cmatose.c'; else $(CYGPATH_W) '$(srcdir)/examples/cmatose.c'; fi` + +udaddy.o: examples/udaddy.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT udaddy.o -MD -MP -MF "$(DEPDIR)/udaddy.Tpo" -c -o udaddy.o `test -f 'examples/udaddy.c' || echo '$(srcdir)/'`examples/udaddy.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/udaddy.Tpo" "$(DEPDIR)/udaddy.Po"; else rm -f "$(DEPDIR)/udaddy.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='examples/udaddy.c' object='udaddy.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o udaddy.o `test -f 'examples/udaddy.c' || echo '$(srcdir)/'`examples/udaddy.c + +udaddy.obj: examples/udaddy.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT udaddy.obj -MD -MP -MF "$(DEPDIR)/udaddy.Tpo" -c -o udaddy.obj `if test -f 'examples/udaddy.c'; then $(CYGPATH_W) 'examples/udaddy.c'; else $(CYGPATH_W) '$(srcdir)/examples/udaddy.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/udaddy.Tpo" "$(DEPDIR)/udaddy.Po"; else rm -f "$(DEPDIR)/udaddy.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='examples/udaddy.c' object='udaddy.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o udaddy.obj `if test -f 'examples/udaddy.c'; then $(CYGPATH_W) 'examples/udaddy.c'; else $(CYGPATH_W) '$(srcdir)/examples/udaddy.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf src/.libs src/_libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(mkdir_p) "$(DESTDIR)$(man1dir)" + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ + done +install-man3: $(man3_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man3dir)" || $(mkdir_p) "$(DESTDIR)$(man3dir)" + @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.3*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 3*) ;; \ + *) ext='3' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst"; \ + done +uninstall-man3: + @$(NORMAL_UNINSTALL) + @list='$(man3_MANS) $(dist_man3_MANS) $(nodist_man3_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.3*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 3*) ;; \ + *) ext='3' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man3dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man3dir)/$$inst"; \ + done +install-man7: $(man7_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man7dir)" || $(mkdir_p) "$(DESTDIR)$(man7dir)" + @list='$(man7_MANS) $(dist_man7_MANS) $(nodist_man7_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.7*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 7*) ;; \ + *) ext='7' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man7dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man7dir)/$$inst"; \ + done +uninstall-man7: + @$(NORMAL_UNINSTALL) + @list='$(man7_MANS) $(dist_man7_MANS) $(nodist_man7_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.7*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 7*) ;; \ + *) ext='7' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man7dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man7dir)/$$inst"; \ + done +install-librdmacmincludeHEADERS: $(librdmacminclude_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(librdmacmincludedir)" || $(mkdir_p) "$(DESTDIR)$(librdmacmincludedir)" + @list='$(librdmacminclude_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(librdmacmincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(librdmacmincludedir)/$$f'"; \ + $(librdmacmincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(librdmacmincludedir)/$$f"; \ + done + +uninstall-librdmacmincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(librdmacminclude_HEADERS)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(librdmacmincludedir)/$$f'"; \ + rm -f "$(DESTDIR)$(librdmacmincludedir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + $(mkdir_p) $(distdir)/. $(distdir)/config $(distdir)/include/rdma $(distdir)/man $(distdir)/src + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(MANS) $(HEADERS) \ + config.h +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(man7dir)" "$(DESTDIR)$(librdmacmincludedir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -rm -f examples/$(am__dirstamp) + -rm -f src/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-librdmacmincludeHEADERS install-man + +install-exec-am: install-binPROGRAMS install-libLTLIBRARIES + +install-info: install-info-am + +install-man: install-man1 install-man3 install-man7 + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am \ + uninstall-libLTLIBRARIES uninstall-librdmacmincludeHEADERS \ + uninstall-man + +uninstall-man: uninstall-man1 uninstall-man3 uninstall-man7 + +.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ + clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool ctags dist dist-all dist-bzip2 dist-gzip \ + dist-hook dist-shar dist-tarZ dist-zip distcheck distclean \ + distclean-compile distclean-generic distclean-hdr \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-libLTLIBRARIES \ + install-librdmacmincludeHEADERS install-man install-man1 \ + install-man3 install-man7 install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-info-am uninstall-libLTLIBRARIES \ + uninstall-librdmacmincludeHEADERS uninstall-man uninstall-man1 \ + uninstall-man3 uninstall-man7 + + +dist-hook: librdmacm.spec + cp librdmacm.spec $(distdir) +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/ofed/librdmacm/NEWS b/contrib/ofed/librdmacm/NEWS new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ofed/librdmacm/README b/contrib/ofed/librdmacm/README new file mode 100644 index 000000000000..4d104cde64e6 --- /dev/null +++ b/contrib/ofed/librdmacm/README @@ -0,0 +1,50 @@ +This README is for userspace RDMA cm library. + + +Building +======== +To make this directory, run: +./autogen.sh && ./configure && make && make install + +Typically the autogen and configure steps only need be done the first +time unless configure.in or Makefile.am changes. + +Libraries are installed by default at /usr/local/lib. + + +Device files +============ +The userspace CMA uses a single device file regardless of the number +of adapters or ports present. + +To create the appropriate character device file automatically with +udev, a rule like + + KERNEL="rdma_cm", NAME="infiniband/%k", MODE="0666" + +can be used. This will create the device node named + + /dev/infiniband/rdma_cm + +or you can create it manually + + mknod /dev/infiniband/rdma_cm c 231 255 + + +Common issues +============= + +Using multiple interfaces + The librdmacm does support multiple interfaces. To make use + of multiple interfaces, however, you need to instruct linux + to only send ARP reples on the interface targetted in the ARP + request. This can be done using a command similar to the + following: + + sysctl -w net.ipv4.conf.all.arp_ignore=2 + + Without this change, it's possible for linux to resopnd to ARP + requests on a different interface (IP address) than the IP + address carried in the ARP request. This causes the RDMA stack + to incorrectly map the remote IP address to the wrong RDMA + device. diff --git a/contrib/ofed/librdmacm/aclocal.m4 b/contrib/ofed/librdmacm/aclocal.m4 new file mode 100644 index 000000000000..5baa59e69de2 --- /dev/null +++ b/contrib/ofed/librdmacm/aclocal.m4 @@ -0,0 +1,7267 @@ +# generated automatically by aclocal 1.9.6 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- + +# serial 48 Debian 1.5.22-2 AC_PROG_LIBTOOL + + +# AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) +# ----------------------------------------------------------- +# If this macro is not defined by Autoconf, define it here. +m4_ifdef([AC_PROVIDE_IFELSE], + [], + [m4_define([AC_PROVIDE_IFELSE], + [m4_ifdef([AC_PROVIDE_$1], + [$2], [$3])])]) + + +# AC_PROG_LIBTOOL +# --------------- +AC_DEFUN([AC_PROG_LIBTOOL], +[AC_REQUIRE([_AC_PROG_LIBTOOL])dnl +dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX +dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [AC_LIBTOOL_CXX], + [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX + ])]) +dnl And a similar setup for Fortran 77 support + AC_PROVIDE_IFELSE([AC_PROG_F77], + [AC_LIBTOOL_F77], + [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 +])]) + +dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. +dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run +dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. + AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], + [AC_LIBTOOL_GCJ], + [ifdef([AC_PROG_GCJ], + [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([A][M_PROG_GCJ], + [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) + ifdef([LT_AC_PROG_GCJ], + [define([LT_AC_PROG_GCJ], + defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) +])])# AC_PROG_LIBTOOL + + +# _AC_PROG_LIBTOOL +# ---------------- +AC_DEFUN([_AC_PROG_LIBTOOL], +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl +AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl +AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl +AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Prevent multiple expansion +define([AC_PROG_LIBTOOL], []) +])# _AC_PROG_LIBTOOL + + +# AC_LIBTOOL_SETUP +# ---------------- +AC_DEFUN([AC_LIBTOOL_SETUP], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl +AC_REQUIRE([AC_PROG_NM])dnl + +AC_REQUIRE([AC_PROG_LN_S])dnl +AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! +AC_REQUIRE([AC_OBJEXT])dnl +AC_REQUIRE([AC_EXEEXT])dnl +dnl + +AC_LIBTOOL_SYS_MAX_CMD_LEN +AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +AC_LIBTOOL_OBJDIR + +AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +_LT_AC_PROG_ECHO_BACKSLASH + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +[sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] + +# Same as above, but do not quote variable references. +[double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +AC_CHECK_TOOL(AR, ar, false) +AC_CHECK_TOOL(RANLIB, ranlib, :) +AC_CHECK_TOOL(STRIP, strip, :) + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + AC_PATH_MAGIC + fi + ;; +esac + +AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +enable_win32_dll=yes, enable_win32_dll=no) + +AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +AC_ARG_WITH([pic], + [AC_HELP_STRING([--with-pic], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [pic_mode="$withval"], + [pic_mode=default]) +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +AC_LIBTOOL_LANG_C_CONFIG +_LT_AC_TAGCONFIG +])# AC_LIBTOOL_SETUP + + +# _LT_AC_SYS_COMPILER +# ------------------- +AC_DEFUN([_LT_AC_SYS_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_AC_SYS_COMPILER + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +AC_DEFUN([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +]) + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +AC_DEFUN([_LT_COMPILER_BOILERPLATE], +[ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +AC_DEFUN([_LT_LINKER_BOILERPLATE], +[ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* +])# _LT_LINKER_BOILERPLATE + + +# _LT_AC_SYS_LIBPATH_AIX +# ---------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], +[AC_LINK_IFELSE(AC_LANG_PROGRAM,[ +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi],[]) +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +])# _LT_AC_SYS_LIBPATH_AIX + + +# _LT_AC_SHELL_INIT(ARG) +# ---------------------- +AC_DEFUN([_LT_AC_SHELL_INIT], +[ifdef([AC_DIVERSION_NOTICE], + [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], + [AC_DIVERT_PUSH(NOTICE)]) +$1 +AC_DIVERT_POP +])# _LT_AC_SHELL_INIT + + +# _LT_AC_PROG_ECHO_BACKSLASH +# -------------------------- +# Add some code to the start of the generated configure script which +# will find an echo command which doesn't interpret backslashes. +AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], +[_LT_AC_SHELL_INIT([ +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` + ;; +esac + +echo=${ECHO-echo} +if test "X[$]1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X[$]1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} +fi + +if test "X[$]1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1 && unset CDPATH + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string=`eval $cmd`) 2>/dev/null && + echo_test_string=`eval $cmd` && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL [$]0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL [$]0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" +fi + +AC_SUBST(ECHO) +])])# _LT_AC_PROG_ECHO_BACKSLASH + + +# _LT_AC_LOCK +# ----------- +AC_DEFUN([_LT_AC_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AC_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) LD="${LD-ld} -64" ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw* | *-*-pw32*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; + ]) +esac + +need_locks="$enable_libtool_lock" + +])# _LT_AC_LOCK + + +# AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], +[AC_REQUIRE([LT_AC_PROG_SED]) +AC_CACHE_CHECK([$1], [$2], + [$2=no + ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $rm conftest* +]) + +if test x"[$]$2" = xyes; then + ifelse([$5], , :, [$5]) +else + ifelse([$6], , :, [$6]) +fi +])# AC_LIBTOOL_COMPILER_OPTION + + +# AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ------------------------------------------------------------ +# Check whether the given compiler option works +AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], +[AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + ifelse([$4], , :, [$4]) +else + ifelse([$5], , :, [$5]) +fi +])# AC_LIBTOOL_LINKER_OPTION + + +# AC_LIBTOOL_SYS_MAX_CMD_LEN +# -------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], +[# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \ + = "XX$teststring") >/dev/null 2>&1 && + new_result=`expr "X$teststring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + teststring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +])# AC_LIBTOOL_SYS_MAX_CMD_LEN + + +# _LT_AC_CHECK_DLFCN +# ------------------ +AC_DEFUN([_LT_AC_CHECK_DLFCN], +[AC_CHECK_HEADERS(dlfcn.h)dnl +])# _LT_AC_CHECK_DLFCN + + +# _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# --------------------------------------------------------------------- +AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +}] +EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_AC_TRY_DLOPEN_SELF + + +# AC_LIBTOOL_DLOPEN_SELF +# ---------------------- +AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], +[AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_AC_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +])# AC_LIBTOOL_DLOPEN_SELF + + +# AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) +# --------------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler +AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* +]) +])# AC_LIBTOOL_PROG_CC_C_O + + +# AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) +# ----------------------------------------- +# Check to see if we can do hard links to lock some files if needed +AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], +[AC_REQUIRE([_LT_AC_LOCK])dnl + +hard_links="nottested" +if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS + + +# AC_LIBTOOL_OBJDIR +# ----------------- +AC_DEFUN([AC_LIBTOOL_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +])# AC_LIBTOOL_OBJDIR + + +# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) +# ---------------------------------------------- +# Check hardcoding attributes. +AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_AC_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ + test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \ + test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_AC_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_AC_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_AC_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH + + +# AC_LIBTOOL_SYS_LIB_STRIP +# ------------------------ +AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], +[striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +])# AC_LIBTOOL_SYS_LIB_STRIP + + +# AC_LIBTOOL_SYS_DYNAMIC_LINKER +# ----------------------------- +# PORTME Fill in your ld.so characteristics +AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], +[AC_MSG_CHECKING([dynamic linker characteristics]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[123]]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + freebsd*) # from 4.6 on + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix3*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi +])# AC_LIBTOOL_SYS_DYNAMIC_LINKER + + +# _LT_AC_TAGCONFIG +# ---------------- +AC_DEFUN([_LT_AC_TAGCONFIG], +[AC_ARG_WITH([tags], + [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], + [include additional configurations @<:@automatic@:>@])], + [tagnames="$withval"]) + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + AC_MSG_WARN([output file `$ofile' does not exist]) + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) + else + AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) + fi + fi + if test -z "$LTCFLAGS"; then + eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in + "") ;; + *) AC_MSG_ERROR([invalid tag name: $tagname]) + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + AC_MSG_ERROR([tag name \"$tagname\" already exists]) + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_LIBTOOL_LANG_CXX_CONFIG + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + AC_LIBTOOL_LANG_F77_CONFIG + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + AC_LIBTOOL_LANG_GCJ_CONFIG + else + tagname="" + fi + ;; + + RC) + AC_LIBTOOL_LANG_RC_CONFIG + ;; + + *) + AC_MSG_ERROR([Unsupported tag name: $tagname]) + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + AC_MSG_ERROR([unable to update list of available tagged configurations.]) + fi +fi +])# _LT_AC_TAGCONFIG + + +# AC_LIBTOOL_DLOPEN +# ----------------- +# enable checks for dlopen support +AC_DEFUN([AC_LIBTOOL_DLOPEN], + [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_DLOPEN + + +# AC_LIBTOOL_WIN32_DLL +# -------------------- +# declare package support for building win32 DLLs +AC_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) +])# AC_LIBTOOL_WIN32_DLL + + +# AC_ENABLE_SHARED([DEFAULT]) +# --------------------------- +# implement the --enable-shared flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_SHARED], +[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([shared], + [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]AC_ENABLE_SHARED_DEFAULT) +])# AC_ENABLE_SHARED + + +# AC_DISABLE_SHARED +# ----------------- +# set the default shared flag to --disable-shared +AC_DEFUN([AC_DISABLE_SHARED], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no) +])# AC_DISABLE_SHARED + + +# AC_ENABLE_STATIC([DEFAULT]) +# --------------------------- +# implement the --enable-static flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_STATIC], +[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([static], + [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]AC_ENABLE_STATIC_DEFAULT) +])# AC_ENABLE_STATIC + + +# AC_DISABLE_STATIC +# ----------------- +# set the default static flag to --disable-static +AC_DEFUN([AC_DISABLE_STATIC], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no) +])# AC_DISABLE_STATIC + + +# AC_ENABLE_FAST_INSTALL([DEFAULT]) +# --------------------------------- +# implement the --enable-fast-install flag +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +AC_DEFUN([AC_ENABLE_FAST_INSTALL], +[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE([fast-install], + [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) +])# AC_ENABLE_FAST_INSTALL + + +# AC_DISABLE_FAST_INSTALL +# ----------------------- +# set the default to --disable-fast-install +AC_DEFUN([AC_DISABLE_FAST_INSTALL], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no) +])# AC_DISABLE_FAST_INSTALL + + +# AC_LIBTOOL_PICMODE([MODE]) +# -------------------------- +# implement the --with-pic flag +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +AC_DEFUN([AC_LIBTOOL_PICMODE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +pic_mode=ifelse($#,1,$1,default) +])# AC_LIBTOOL_PICMODE + + +# AC_PROG_EGREP +# ------------- +# This is predefined starting with Autoconf 2.54, so this conditional +# definition can be removed once we require Autoconf 2.54 or later. +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], +[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], + [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi]) + EGREP=$ac_cv_prog_egrep + AC_SUBST([EGREP]) +])]) + + +# AC_PATH_TOOL_PREFIX +# ------------------- +# find a file program which can recognise shared library +AC_DEFUN([AC_PATH_TOOL_PREFIX], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="ifelse([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +])# AC_PATH_TOOL_PREFIX + + +# AC_PATH_MAGIC +# ------------- +# find a file program which can recognise a shared library +AC_DEFUN([AC_PATH_MAGIC], +[AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# AC_PATH_MAGIC + + +# AC_PROG_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([AC_PROG_LD], +[AC_ARG_WITH([gnu-ld], + [AC_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no]) +AC_REQUIRE([LT_AC_PROG_SED])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix3*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown +])# AC_DEPLIBS_CHECK_METHOD + + +# AC_PROG_NM +# ---------- +# find the pathname to a BSD-compatible name lister +AC_DEFUN([AC_PROG_NM], +[AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi]) +NM="$lt_cv_path_NM" +])# AC_PROG_NM + + +# AC_CHECK_LIBM +# ------------- +# check for math library +AC_DEFUN([AC_CHECK_LIBM], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +])# AC_CHECK_LIBM + + +# AC_LIBLTDL_CONVENIENCE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl convenience library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-convenience to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, +# it is assumed to be `libltdl'. LIBLTDL will be prefixed with +# '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/' +# (note the single quotes!). If your package is not flat and you're not +# using automake, define top_builddir and top_srcdir appropriately in +# the Makefiles. +AC_DEFUN([AC_LIBLTDL_CONVENIENCE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case $enable_ltdl_convenience in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_CONVENIENCE + + +# AC_LIBLTDL_INSTALLABLE([DIRECTORY]) +# ----------------------------------- +# sets LIBLTDL to the link flags for the libltdl installable library and +# LTDLINCL to the include flags for the libltdl header and adds +# --enable-ltdl-install to the configure arguments. Note that +# AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, +# and an installed libltdl is not found, it is assumed to be `libltdl'. +# LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and top_srcdir +# appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN([AC_LIBLTDL_INSTALLABLE], +[AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, lt_dlinit, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + LTDLINCL= + fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" +])# AC_LIBLTDL_INSTALLABLE + + +# AC_LIBTOOL_CXX +# -------------- +# enable support for C++ libraries +AC_DEFUN([AC_LIBTOOL_CXX], +[AC_REQUIRE([_LT_AC_LANG_CXX]) +])# AC_LIBTOOL_CXX + + +# _LT_AC_LANG_CXX +# --------------- +AC_DEFUN([_LT_AC_LANG_CXX], +[AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) +])# _LT_AC_LANG_CXX + +# _LT_AC_PROG_CXXCPP +# ------------------ +AC_DEFUN([_LT_AC_PROG_CXXCPP], +[ +AC_REQUIRE([AC_PROG_CXX]) +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +fi +])# _LT_AC_PROG_CXXCPP + +# AC_LIBTOOL_F77 +# -------------- +# enable support for Fortran 77 libraries +AC_DEFUN([AC_LIBTOOL_F77], +[AC_REQUIRE([_LT_AC_LANG_F77]) +])# AC_LIBTOOL_F77 + + +# _LT_AC_LANG_F77 +# --------------- +AC_DEFUN([_LT_AC_LANG_F77], +[AC_REQUIRE([AC_PROG_F77]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) +])# _LT_AC_LANG_F77 + + +# AC_LIBTOOL_GCJ +# -------------- +# enable support for GCJ libraries +AC_DEFUN([AC_LIBTOOL_GCJ], +[AC_REQUIRE([_LT_AC_LANG_GCJ]) +])# AC_LIBTOOL_GCJ + + +# _LT_AC_LANG_GCJ +# --------------- +AC_DEFUN([_LT_AC_LANG_GCJ], +[AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], + [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], + [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], + [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], + [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) +])# _LT_AC_LANG_GCJ + + +# AC_LIBTOOL_RC +# ------------- +# enable support for Windows resource files +AC_DEFUN([AC_LIBTOOL_RC], +[AC_REQUIRE([LT_AC_PROG_RC]) +_LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) +])# AC_LIBTOOL_RC + + +# AC_LIBTOOL_LANG_C_CONFIG +# ------------------------ +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) +AC_DEFUN([_LT_AC_LANG_C_CONFIG], +[lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}\n' + +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) +AC_LIBTOOL_SYS_LIB_STRIP +AC_LIBTOOL_DLOPEN_SELF + +# Report which library types will actually be built +AC_MSG_CHECKING([if libtool supports shared libraries]) +AC_MSG_RESULT([$can_build_shared]) + +AC_MSG_CHECKING([whether to build shared libraries]) +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +AC_MSG_RESULT([$enable_shared]) + +AC_MSG_CHECKING([whether to build static libraries]) +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +AC_MSG_RESULT([$enable_static]) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC="$lt_save_CC" +])# AC_LIBTOOL_LANG_C_CONFIG + + +# AC_LIBTOOL_LANG_CXX_CONFIG +# -------------------------- +# Ensure that the configuration vars for the C compiler are +# suitably defined. Those variables are subsequently used by +# AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. +AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) +AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], +[AC_LANG_PUSH(C++) +AC_REQUIRE([AC_PROG_CXX]) +AC_REQUIRE([_LT_AC_PROG_CXXCPP]) + +_LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_AC_TAGVAR(allow_undefined_flag, $1)= +_LT_AC_TAGVAR(always_export_symbols, $1)=no +_LT_AC_TAGVAR(archive_expsym_cmds, $1)= +_LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_direct, $1)=no +_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= +_LT_AC_TAGVAR(hardcode_libdir_separator, $1)= +_LT_AC_TAGVAR(hardcode_minus_L, $1)=no +_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_AC_TAGVAR(hardcode_automatic, $1)=no +_LT_AC_TAGVAR(module_cmds, $1)= +_LT_AC_TAGVAR(module_expsym_cmds, $1)= +_LT_AC_TAGVAR(link_all_deplibs, $1)=unknown +_LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_AC_TAGVAR(no_undefined_flag, $1)= +_LT_AC_TAGVAR(whole_archive_flag_spec, $1)= +_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Dependencies to place before and after the object being linked: +_LT_AC_TAGVAR(predep_objects, $1)= +_LT_AC_TAGVAR(postdep_objects, $1)= +_LT_AC_TAGVAR(predeps, $1)= +_LT_AC_TAGVAR(postdeps, $1)= +_LT_AC_TAGVAR(compiler_lib_search_path, $1)= + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_AC_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_AC_SYS_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + $as_unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + $as_unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +_LT_AC_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' +else + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + AC_PROG_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +_LT_AC_TAGVAR(ld_shlibs, $1)=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GXX" = yes ; then + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + freebsd[[12]]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + freebsd-elf*) + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + ;; + gnu*) + ;; + hpux9*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + ;; + *) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + interix3*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + linux*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc*) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC*) + # Portland Group C++ compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + m88k*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + openbsd2*) + # C++ shared libraries are fairly broken + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd='echo' + ;; + osf3*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ + $rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. We must also pass each convience library through + # to the system linker between allextract/defaultextract. + # The C++ compiler will combine linker options so we + # cannot just pass the convience library names through + # without $wl. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' + ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + # So that behaviour is only enabled if SCOABSPATH is set to a + # non-empty value in the environment. Most likely only useful for + # creating official distributions of packages. + # This is a hack until libtool officially supports absolute path + # names for shared libraries. + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; +esac +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_AC_TAGVAR(GCC, $1)="$GXX" +_LT_AC_TAGVAR(LD, $1)="$LD" + +AC_LIBTOOL_POSTDEP_PREDEP($1) +AC_LIBTOOL_PROG_COMPILER_PIC($1) +AC_LIBTOOL_PROG_CC_C_O($1) +AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) +AC_LIBTOOL_PROG_LD_SHLIBS($1) +AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) +AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) + +AC_LIBTOOL_CONFIG($1) + +AC_LANG_POP +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +])# AC_LIBTOOL_LANG_CXX_CONFIG + +# AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) +# ------------------------------------ +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" +ifelse([$1], [], +[#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e 1s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG], +[# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) + +# Is the compiler the GNU C compiler? +with_gcc=$_LT_AC_TAGVAR(GCC, $1) + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_[]_LT_AC_TAGVAR(LD, $1) + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) + +# Commands used to build and install a shared archive. +archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) +archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) +module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_[]_LT_AC_TAGVAR(predep_objects, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_[]_LT_AC_TAGVAR(postdep_objects, $1) + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" + +# Set to yes if exported symbols are required. +always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) + +# The commands to list exported symbols. +export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) + +# Symbols that must always be exported. +include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) + +ifelse([$1],[], +[# ### END LIBTOOL CONFIG], +[# ### END LIBTOOL TAG CONFIG: $tagname]) + +__EOF__ + +ifelse([$1],[], [ + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +]) +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi +])# AC_LIBTOOL_CONFIG + + +# AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], +[AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl + +_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + + AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI + + +# AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE +# --------------------------------- +AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], +[AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_NM]) +AC_REQUIRE([AC_OBJEXT]) +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +linux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDGIRSTW]]' + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[[]] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi +]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE + + +# AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) +# --------------------------------------- +AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], +[_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_AC_TAGVAR(lt_prog_compiler_static, $1)= + +AC_MSG_CHECKING([for $compiler option to produce PIC]) + ifelse([$1],[CXX],[ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + icpc* | ecpc*) + # Intel C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC*) + # Portland Group C++ compiler. + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + newsos6) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + linux*) + case $cc_basename in + icc* | ecc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then + AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], + _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), + [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\" +AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) +]) + + +# AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) +# ------------------------------------ +# See if the linker supports building shared libraries. +AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], +[AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +ifelse([$1],[CXX],[ + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw*) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + ;; + kfreebsd*-gnu) + _LT_AC_TAGVAR(link_all_deplibs, $1)=no + ;; + linux*) + _LT_AC_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +],[ + runpath_var= + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_AC_TAGVAR(archive_cmds, $1)= + _LT_AC_TAGVAR(archive_expsym_cmds, $1)= + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= + _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_minus_L, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown + _LT_AC_TAGVAR(hardcode_automatic, $1)=no + _LT_AC_TAGVAR(module_cmds, $1)= + _LT_AC_TAGVAR(module_expsym_cmds, $1)= + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_AC_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + _LT_CC_BASENAME([$compiler]) + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=no + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + interix3*) + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + _LT_AC_TAGVAR(link_all_deplibs, $1)=no + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_AC_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + else + _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_AC_TAGVAR(archive_cmds, $1)='' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + else + # We have old collect2 + _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_AC_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + _LT_AC_SYS_LIBPATH_AIX + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + # see comment about different semantics on the GNU ld section + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + bsdi[[45]]*) + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' + _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' + _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[[012]]) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_automatic, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi + ;; + + dgux*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + freebsd1*) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # GNU/kFreeBSD uses gcc -shared to do shared libraries. + kfreebsd*-gnu) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(link_all_deplibs, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + openbsd*) + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine linker options so we + # cannot just pass the convience library names through + # without $wl, iff we do not link with $LD. + # Luckily, gcc supports the same syntax we need for Sun Studio. + # Supported since Solaris 2.6 (maybe 2.5.1?) + case $wlarc in + '') + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; + *) + _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; + esac ;; + esac + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes + _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_AC_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_AC_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7*) + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_AC_TAGVAR(link_all_deplibs, $1)=yes + _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_AC_TAGVAR(ld_shlibs, $1)=no + ;; + esac + fi +]) +AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) +test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_AC_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_MSG_CHECKING([whether -lc should be explicitly linked in]) + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) + _LT_AC_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) + then + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no + else + _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) + ;; + esac + fi + ;; +esac +])# AC_LIBTOOL_PROG_LD_SHLIBS + + +# _LT_AC_FILE_LTDLL_C +# ------------------- +# Be careful that the start marker always follows a newline. +AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ +])# _LT_AC_FILE_LTDLL_C + + +# _LT_AC_TAGVAR(VARNAME, [TAGNAME]) +# --------------------------------- +AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) + + +# old names +AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) +AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) +AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) +AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) +AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) + +# This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL]) + +AC_DEFUN([LT_AC_PROG_GCJ], +[AC_CHECK_TOOL(GCJ, gcj, no) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS) +]) + +AC_DEFUN([LT_AC_PROG_RC], +[AC_CHECK_TOOL(RC, windres, no) +]) + +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_MSG_RESULT([$SED]) +]) + +# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.9.6])]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 7 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH]) +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 3 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 12 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.58])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $1 | $1:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. +# +# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories +# created by `make install' are always world readable, even if the +# installer happens to have an overly restrictive umask (e.g. 077). +# This was a mistake. There are at least two reasons why we must not +# use `-m 0755': +# - it causes special bits like SGID to be ignored, +# - it may be too restrictive (some setups expect 775 directories). +# +# Do not use -m 0755 and let people choose whatever they expect by +# setting umask. +# +# We cannot accept any implementation of `mkdir' that recognizes `-p'. +# Some implementations (such as Solaris 8's) are not thread-safe: if a +# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c' +# concurrently, both version can detect that a/ is missing, but only +# one can create it and the other will error out. Consequently we +# restrict ourselves to GNU make (using the --version option ensures +# this.) +AC_DEFUN([AM_PROG_MKDIR_P], +[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi +AC_SUBST([mkdir_p])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + diff --git a/contrib/ofed/librdmacm/config.h.in b/contrib/ofed/librdmacm/config.h.in new file mode 100644 index 000000000000..48a9db81e429 --- /dev/null +++ b/contrib/ofed/librdmacm/config.h.in @@ -0,0 +1,67 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `ibverbs' library (-libverbs). */ +#undef HAVE_LIBIBVERBS + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 to enable valgrind annotations */ +#undef INCLUDE_VALGRIND + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of a `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const diff --git a/contrib/ofed/librdmacm/config/compile b/contrib/ofed/librdmacm/config/compile new file mode 100755 index 000000000000..1b1d23216958 --- /dev/null +++ b/contrib/ofed/librdmacm/config/compile @@ -0,0 +1,142 @@ +#! /bin/sh +# Wrapper for compilers which do not understand `-c -o'. + +scriptversion=2005-05-14.22 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand `-c -o'. +Remove `-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file `INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; +esac + +ofile= +cfile= +eat= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as `compile cc -o foo foo.c'. + # So we strip `-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no `-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # `.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` + +# Create the lock directory. +# Note: use `[/.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/contrib/ofed/librdmacm/config/config.guess b/contrib/ofed/librdmacm/config/config.guess new file mode 100755 index 000000000000..ad5281e66e9d --- /dev/null +++ b/contrib/ofed/librdmacm/config/config.guess @@ -0,0 +1,1466 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-08-03' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerppc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + *86) UNAME_PROCESSOR=i686 ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/contrib/ofed/librdmacm/config/config.sub b/contrib/ofed/librdmacm/config/config.sub new file mode 100755 index 000000000000..1c366dfde9ab --- /dev/null +++ b/contrib/ofed/librdmacm/config/config.sub @@ -0,0 +1,1579 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-07-08' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | ms1 \ + | msp430 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m32c) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | ms1-* \ + | msp430-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + m32c-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/contrib/ofed/librdmacm/config/depcomp b/contrib/ofed/librdmacm/config/depcomp new file mode 100755 index 000000000000..04701da536f3 --- /dev/null +++ b/contrib/ofed/librdmacm/config/depcomp @@ -0,0 +1,530 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2005-07-09.11 + +# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by `PROGRAMS ARGS'. + object Object file output by `PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputing dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts `$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + stat=$? + + if test -f "$tmpdepfile"; then : + else + stripped=`echo "$stripped" | sed 's,^.*/,,'` + tmpdepfile="$stripped.u" + fi + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + outname="$stripped.o" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler understands `-MD -MF file'. However on + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using \ : + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h', + # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + # Some versions of the HPUX 10.20 sed can't process this invocation + # correctly. Breaking it into two sed invocations is a workaround. + sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | + sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mecanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a tab and a space in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/contrib/ofed/librdmacm/config/install-sh b/contrib/ofed/librdmacm/config/install-sh new file mode 100755 index 000000000000..4d4a9519eaf8 --- /dev/null +++ b/contrib/ofed/librdmacm/config/install-sh @@ -0,0 +1,323 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2005-05-14.22 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# 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 +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +chmodcmd="$chmodprog 0755" +chowncmd= +chgrpcmd= +stripcmd= +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src= +dst= +dir_arg= +dstarg= +no_target_directory= + +usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: +-c (ignored) +-d create directories instead of installing files. +-g GROUP $chgrpprog installed files to GROUP. +-m MODE $chmodprog installed files to MODE. +-o USER $chownprog installed files to USER. +-s $stripprog installed files. +-t DIRECTORY install into DIRECTORY. +-T report an error if DSTFILE is a directory. +--help display this help and exit. +--version display version info and exit. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG +" + +while test -n "$1"; do + case $1 in + -c) shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + --help) echo "$usage"; exit $?;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t) dstarg=$2 + shift + shift + continue;; + + -T) no_target_directory=true + shift + continue;; + + --version) echo "$0 $scriptversion"; exit $?;; + + *) # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + test -n "$dir_arg$dstarg" && break + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dstarg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dstarg" + shift # fnord + fi + shift # arg + dstarg=$arg + done + break;; + esac +done + +if test -z "$1"; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src ;; + esac + + if test -n "$dir_arg"; then + dst=$src + src= + + if test -d "$dst"; then + mkdircmd=: + chmodcmd= + else + mkdircmd=$mkdirprog + fi + else + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dstarg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dstarg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst ;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dstarg: Is a directory" >&2 + exit 1 + fi + dst=$dst/`basename "$src"` + fi + fi + + # This sed command emulates the dirname command. + dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` + + # Make sure that the destination directory exists. + + # Skip lots of stat calls in the usual case. + if test ! -d "$dstdir"; then + defaultIFS=' + ' + IFS="${IFS-$defaultIFS}" + + oIFS=$IFS + # Some sh's can't handle IFS=/ for some reason. + IFS='%' + set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` + shift + IFS=$oIFS + + pathcomp= + + while test $# -ne 0 ; do + pathcomp=$pathcomp$1 + shift + if test ! -d "$pathcomp"; then + $mkdirprog "$pathcomp" + # mkdir can fail with a `File exist' error in case several + # install-sh are creating the directory concurrently. This + # is OK. + test -d "$pathcomp" || exit + fi + pathcomp=$pathcomp/ + done + fi + + if test -n "$dir_arg"; then + $doit $mkdircmd "$dst" \ + && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } + + else + dstfile=`basename "$dst"` + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + trap '(exit $?); exit' 1 2 13 15 + + # Copy the file name to the temp name. + $doit $cpprog "$src" "$dsttmp" && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ + && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ + && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ + && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && + + # Now rename the file to the real destination. + { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ + || { + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + if test -f "$dstdir/$dstfile"; then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ + || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ + || { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit 1 + } + else + : + fi + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + } + } + fi || { (exit 1); exit 1; } +done + +# The final little trick to "correctly" pass the exit status to the exit trap. +{ + (exit 0); exit 0 +} + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/contrib/ofed/librdmacm/config/ltmain.sh b/contrib/ofed/librdmacm/config/ltmain.sh new file mode 100644 index 000000000000..8fc56db8fc6e --- /dev/null +++ b/contrib/ofed/librdmacm/config/ltmain.sh @@ -0,0 +1,6871 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun configure. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +basename="s,^.*/,,g" + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + +# The name of this program: +progname=`echo "$progpath" | $SED $basename` +modename="$progname" + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 + +PROGRAM=ltmain.sh +PACKAGE=libtool +VERSION="1.5.22 Debian 1.5.22-2" +TIMESTAMP=" (1.1220.2.365 2005/12/18 22:14:06)" + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes. +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$progpath" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +duplicate_deps=no +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" + +##################################### +# Shell function definitions: +# This seems to be the best place for them + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $mkdir "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || { + $echo "cannot create temporary directory \`$my_tmpdir'" 1>&2 + exit $EXIT_FAILURE + } + fi + + $echo "X$my_tmpdir" | $Xsed +} + + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +func_win32_libid () +{ + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ + $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then + win32_nmres=`eval $NM -f posix -A $1 | \ + $SED -n -e '1,100{/ I /{s,.*,import,;p;q;};}'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $echo $win32_libid_type +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + CC_quoted="$CC_quoted $arg" + done + case "$@ " in + " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + $echo "$modename: unable to infer tagged configuration" + $echo "$modename: specify a tag with \`--tag'" 1>&2 + exit $EXIT_FAILURE +# else +# $echo "$modename: using $tagname tagged configuration" + fi + ;; + esac + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + + $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)" + $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $? + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2 + exit $EXIT_FAILURE + fi +} + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + my_status="" + + $show "${rm}r $my_gentop" + $run ${rm}r "$my_gentop" + $show "$mkdir $my_gentop" + $run $mkdir "$my_gentop" + my_status=$? + if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then + exit $my_status + fi + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'` + my_xdir="$my_gentop/$my_xlib" + + $show "${rm}r $my_xdir" + $run ${rm}r "$my_xdir" + $show "$mkdir $my_xdir" + $run $mkdir "$my_xdir" + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$my_xdir"; then + exit $exit_status + fi + case $host in + *-darwin*) + $show "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + if test -z "$run"; then + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'` + darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null` + if test -n "$darwin_arches"; then + darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + $show "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we have a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + lipo -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + ${rm}r unfat-$$ + cd "$darwin_orig_dir" + else + cd "$darwin_orig_dir" + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + fi # $run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + func_extract_archives_result="$my_oldobjs" +} +# End of Shell function definitions +##################################### + +# Darwin sucks +eval std_shrext=\"$shrext_cmds\" + +disable_libs=no + +# Parse our command line options once, thoroughly. +while test "$#" -gt 0 +do + arg="$1" + shift + + case $arg in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + execute_dlfiles) + execute_dlfiles="$execute_dlfiles $arg" + ;; + tag) + tagname="$arg" + preserve_args="${preserve_args}=$arg" + + # Check whether tagname contains only valid characters + case $tagname in + *[!-_A-Za-z0-9,/]*) + $echo "$progname: invalid tag name: $tagname" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $tagname in + CC) + # Don't test for the "default" C tag, as we know, it's there, but + # not specially marked. + ;; + *) + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then + taglist="$taglist $tagname" + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`" + else + $echo "$progname: ignoring unknown tag $tagname" 1>&2 + fi + ;; + esac + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case $arg in + --help) + show_help=yes + ;; + + --version) + $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" + $echo + $echo "Copyright (C) 2005 Free Software Foundation, Inc." + $echo "This is free software; see the source for copying conditions. There is NO" + $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + exit $? + ;; + + --config) + ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath + # Now print the configurations for the tags. + for tagname in $taglist; do + ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath" + done + exit $? + ;; + + --debug) + $echo "$progname: enabling shell trace mode" + set -x + preserve_args="$preserve_args $arg" + ;; + + --dry-run | -n) + run=: + ;; + + --features) + $echo "host: $host" + if test "$build_libtool_libs" = yes; then + $echo "enable shared libraries" + else + $echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + $echo "enable static libraries" + else + $echo "disable static libraries" + fi + exit $? + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --preserve-dup-deps) duplicate_deps="yes" ;; + + --quiet | --silent) + show=: + preserve_args="$preserve_args $arg" + ;; + + --tag) + prevopt="--tag" + prev=tag + preserve_args="$preserve_args --tag" + ;; + --tag=*) + set tag "$optarg" ${1+"$@"} + shift + prev=tag + preserve_args="$preserve_args --tag" + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE +fi + +case $disable_libs in +no) + ;; +shared) + build_libtool_libs=no + build_old_libs=yes + ;; +static) + build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` + ;; +esac + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 + $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2 + case $nonopt in + *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) + mode=link + for arg + do + case $arg in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case $mode in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + if test -n "$libobj" ; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit $EXIT_FAILURE + fi + arg_mode=target + continue + ;; + + -static | -prefer-pic | -prefer-non-pic) + later="$later $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + lastarg="$lastarg $arg" + done + IFS="$save_ifs" + lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` + + # Add the arguments to base_compile. + base_compile="$base_compile $lastarg" + continue + ;; + + * ) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + case $lastarg in + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, and some SunOS ksh mistreat backslash-escaping + # in scan sets (worked around with variable expansion), + # and furthermore cannot handle '|' '&' '(' ')' in scan sets + # at all, so we specify them separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + lastarg="\"$lastarg\"" + ;; + esac + + base_compile="$base_compile $lastarg" + done # for arg + + case $arg_mode in + arg) + $echo "$modename: you must specify an argument for -Xcompile" + exit $EXIT_FAILURE + ;; + target) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit $EXIT_FAILURE + ;; + *) + # Get the name of the library object. + [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSifmso]' + case $libobj in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.ii) xform=ii ;; + *.class) xform=class ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + *.java) xform=java ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case $libobj in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -static) + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"` + case $qlibobj in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qlibobj="\"$qlibobj\"" ;; + esac + test "X$libobj" != "X$qlibobj" \ + && $echo "X$libobj" | grep '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && $echo "$modename: libobj name \`$libobj' may not contain shell special characters." + objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir= + else + xdir=$xdir/ + fi + lobj=${xdir}$objdir/$objname + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $run ln "$progpath" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + $echo "$srcfile" > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"` + case $qsrcfile in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qsrcfile="\"$qsrcfile\"" ;; + esac + + $run $rm "$libobj" "${libobj}T" + + # Create a libtool object file (analogous to a ".la" file), + # but don't create it if we're doing a dry run. + test -z "$run" && cat > ${libobj}T </dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + $show "$mv $output_obj $lobj" + if $run $mv $output_obj $lobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the PIC object to the libtool object file. + test -z "$run" && cat >> ${libobj}T <> ${libobj}T </dev/null`" != "X$srcfile"; then + $echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Append the name of the non-PIC object the libtool object file. + # Only append if the libtool object file exists. + test -z "$run" && cat >> ${libobj}T <> ${libobj}T <&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + else + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + fi + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test + ;; + *) qarg=$arg ;; + esac + libtool_args="$libtool_args $qarg" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case $prev in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit $EXIT_FAILURE + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat $save_arg` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + done + else + $echo "$modename: link input file \`$save_arg' does not exist" + exit $EXIT_FAILURE + fi + arg=$save_arg + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + compile_command="$compile_command $wl$qarg" + finalize_command="$finalize_command $wl$qarg" + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + compile_command="$compile_command $qarg" + finalize_command="$finalize_command $qarg" + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + darwin_framework|darwin_framework_skip) + test "$prev" = "darwin_framework" && compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: more than one -exported-symbols argument is not allowed" + exit $EXIT_FAILURE + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework|-arch|-isysroot) + case " $CC " in + *" ${arg} ${1} "* | *" ${arg} ${1} "*) + prev=darwin_framework_skip ;; + *) compiler_flags="$compiler_flags $arg" + prev=darwin_framework ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + ;; + esac + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + notinst_path="$notinst_path $dir" + fi + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + testbindir=`$echo "X$dir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs -framework System" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + -model) + compile_command="$compile_command $arg" + compiler_flags="$compiler_flags $arg" + finalize_command="$finalize_command $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) + compiler_flags="$compiler_flags $arg" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m* pass through architecture-specific compiler args for GCC + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -pg pass through profiling flag for GCC + # @file GCC response files + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \ + -t[45]*|-txscale*|@*) + + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + # The PATH hackery in wrapper scripts is required on Windows + # in order for the loader to find any dlls it needs. + $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 + $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit $EXIT_FAILURE + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -Wc,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Wl,*) + args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + case $flag in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + flag="\"$flag\"" + ;; + esac + arg="$arg $wl$flag" + compiler_flags="$compiler_flags $wl$flag" + linker_flags="$linker_flags $flag" + done + IFS="$save_ifs" + arg=`$echo "X$arg" | $Xsed -e "s/^ //"` + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + pic_object= + non_pic_object= + + # Read the .lo file + # If there is no directory component, then add one. + case $arg in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + if test -z "$pic_object" || \ + test -z "$non_pic_object" || + test "$pic_object" = none && \ + test "$non_pic_object" = none; then + $echo "$modename: cannot find name of object for \`$arg'" 1>&2 + exit $EXIT_FAILURE + fi + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + libobjs="$libobjs $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + non_pic_objects="$non_pic_objects $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if test -z "$run"; then + $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 + exit $EXIT_FAILURE + else + # Dry-run case. + + # Extract subdirectory from the argument. + xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$arg"; then + xdir= + else + xdir="$xdir/" + fi + + pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` + non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` + libobjs="$libobjs $pic_object" + non_pic_objects="$non_pic_objects $non_pic_object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done # argument parsing loop + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + # Create the object directory. + if test ! -d "$output_objdir"; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$output_objdir"; then + exit $exit_status + fi + fi + + # Determine the type of output + case $output in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + case $host in + *cygwin* | *mingw* | *pw32*) + # don't eliminate duplications in $postdeps and $predeps + duplicate_compiler_generated_deps=yes + ;; + *) + duplicate_compiler_generated_deps=$duplicate_deps + ;; + esac + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if test "X$duplicate_deps" = "Xyes" ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + case $linkmode in + lib) + passes="conv link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + for pass in $passes; do + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 + continue + fi + name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` + for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if (${SED} -e '2q' $lib | + grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + library_names= + old_library= + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` + ;; + *) + $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + if eval $echo \"$deplib\" 2>/dev/null \ + | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + $echo + $echo "*** Warning: Trying to link with static lib archive $deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because the file extensions .$libext of this argument makes me believe" + $echo "*** that it is just a static archive that I should not used here." + else + $echo + $echo "*** Warning: Linking the shared library $output against the" + $echo "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + if test "$found" = yes || test -f "$lib"; then : + else + $echo "$modename: cannot find the library \`$lib' or unhandled argument \`$deplib'" 1>&2 + exit $EXIT_FAILURE + fi + + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + + ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` + test "X$ladir" = "X$lib" && ladir="." + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + $echo "$modename: \`$lib' is not a convenience library" 1>&2 + exit $EXIT_FAILURE + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + abs_ladir="$ladir" + fi + ;; + esac + laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + $echo "$modename: warning: library \`$lib' was moved." 1>&2 + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir"; then + $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 + exit $EXIT_FAILURE + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *" $absdir "*) ;; + *) temp_rpath="$temp_rpath $absdir" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes ; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + # This is a shared library + + # Warn about portability, can't link against -module's on + # some systems (darwin) + if test "$shouldnotlink" = yes && test "$pass" = link ; then + $echo + if test "$linkmode" = prog; then + $echo "*** Warning: Linking the executable $output against the loadable module" + else + $echo "*** Warning: Linking the shared library $output against the loadable module" + fi + $echo "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + realname="$2" + shift; shift + libname=`eval \\$echo \"$libname_spec\"` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw*) + major=`expr $current - $age` + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + soname=`$echo $soroot | ${SED} -e 's/^.*\///'` + newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + $show "extracting exported symbol list from \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$extract_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + $show "generating import library for \`$soname'" + save_ifs="$IFS"; IFS='~' + cmds=$old_archive_from_expsyms_cmds + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a module then we can not link against + # it, someone is ignoring the new warnings I added + if /usr/bin/file -L $add 2> /dev/null | + $EGREP ": [^:]* bundle" >/dev/null ; then + $echo "** Warning, lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + $echo + $echo "** And there doesn't seem to be a static archive available" + $echo "** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$dir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit $EXIT_FAILURE + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && \ + test "$hardcode_minus_L" != yes && \ + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + $echo + $echo "*** Warning: This system can not link to static lib archive $lib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + $echo "*** But as you try to build a module library, libtool will still create " + $echo "*** a static module, that should work as long as the dlopening application" + $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if test "X$duplicate_deps" = "Xyes" ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + case $deplib in + -L*) path="$deplib" ;; + *.la) + dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$deplib" && dir="." + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + absdir="$dir" + fi + ;; + esac + if grep "^installed=no" $deplib > /dev/null; then + path="$absdir/$objdir" + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + if test "$absdir" != "$libdir"; then + $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 + fi + path="$absdir" + fi + depdepl= + case $host in + *-*-darwin*) + # we do not want to link against static libs, + # but need to link against shared + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$path/$depdepl" ; then + depdepl="$path/$depdepl" + fi + # do not add paths which are already there + case " $newlib_search_path " in + *" $path "*) ;; + *) newlib_search_path="$newlib_search_path $path";; + esac + fi + path="" + ;; + *) + path="-L$path" + ;; + esac + ;; + -l*) + case $host in + *-*-darwin*) + # Again, we only want to link against shared libraries + eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` + for tmp in $newlib_search_path ; do + if test -f "$tmp/lib$tmp_libs.dylib" ; then + eval depdepl="$tmp/lib$tmp_libs.dylib" + break + fi + done + path="" + ;; + *) continue ;; + esac + ;; + *) continue ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + case " $deplibs " in + *" $depdepl "*) ;; + *) deplibs="$depdepl $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 + exit $EXIT_FAILURE + else + $echo + $echo "*** Warning: Linking the shared library $output against the non-libtool" + $echo "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + if test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test "$#" -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$2" + number_minor="$3" + number_revision="$4" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows) + current=`expr $number_major + $number_minor` + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + current=`expr $number_major + $number_minor - 1` + age="$number_minor" + revision="$number_minor" + ;; + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE + ;; + esac + ;; + no) + current="$2" + revision="$3" + age="$4" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test "$age" -gt "$current"; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit $EXIT_FAILURE + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + minor_current=`expr $current + 1` + verstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + irix | nonstopux) + major=`expr $current - $age + 1` + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=.`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + major=`expr $current - $age` + versuffix="-$major" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + fi + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$echo "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + if test -n "$removelist"; then + $show "${rm}r $removelist" + $run ${rm}r $removelist + fi + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + for path in $notinst_path; do + lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"` + deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"` + dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"` + done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs -framework System" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for file magic test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a file magic. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method + match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` + for a_deplib in $deplibs; do + name=`expr $a_deplib : '-l\(.*\)'` + # If $name is empty we are operating on a -L argument. + if test -n "$name" && test "$name" != "0"; then + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval \\$echo \"$libname_spec\"` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval $echo \"$potent_lib\" 2>/dev/null \ + | ${SED} 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + $echo + $echo "*** Warning: linker path does not have real file for library $a_deplib." + $echo "*** I have the capability to make that library automatically link in when" + $echo "*** you link to this library. But I can only do this if you have a" + $echo "*** shared version of the library, which you do not appear to have" + $echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $echo "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $echo "*** with $libname and none of the candidates passed a file format test" + $echo "*** using a regex pattern. Last file checked: $potlib" + fi + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` + done + fi + if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ + | grep . >/dev/null; then + $echo + if test "X$deplibs_check_method" = "Xnone"; then + $echo "*** Warning: inter-library dependencies are not supported in this platform." + else + $echo "*** Warning: inter-library dependencies are not known to be supported." + fi + $echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + $echo + $echo "*** Warning: libtool could not satisfy all declared inter-library" + $echo "*** dependencies of module $libname. Therefore, libtool will create" + $echo "*** a static module, that should work as long as the dlopening" + $echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + $echo + $echo "*** However, this would only work if libtool was able to extract symbol" + $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + $echo "*** not find such a program. So, this module is probably useless." + $echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + $echo "*** The inter-library dependencies that have been dropped here will be" + $echo "*** automatically added whenever a program is linked with this library" + $echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + $echo + $echo "*** Since this library must not contain undefined symbols," + $echo "*** because either the platform does not support them or" + $echo "*** it was explicitly requested with -no-undefined," + $echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" + else + eval dep_rpath=\"$hardcode_libdir_flag_spec\" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + if len=`expr "X$cmd" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + $show "$cmd" + $run eval "$cmd" || exit $? + skipped_export=false + else + # The command line is too long to execute in one step. + $show "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise. + $echo "creating reloadable object files..." + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + output_la=`$echo "X$output" | $Xsed -e "$basename"` + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + delfiles= + last_robj= + k=1 + output=$output_objdir/$output_la-${k}.$objext + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + eval test_cmds=\"$reload_cmds $objlist $last_robj\" + if test "X$objlist" = X || + { len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len"; }; then + objlist="$objlist $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. + eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + k=`expr $k + 1` + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj + len=1 + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + + if ${skipped_export-false}; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + libobjs=$output + # Append the command to create the export file. + eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" + fi + + # Set up a command to remove the reloadable object files + # after they are used. + i=0 + while test "$i" -lt "$k" + do + i=`expr $i + 1` + delfiles="$delfiles $output_objdir/$output_la-${i}.$objext" + done + + $echo "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + + # Append the command to remove the reloadable object files + # to the just-reset $cmds. + eval cmds=\"\$cmds~\$rm $delfiles\" + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case $output in + *.lo) + if test -n "$objs$old_deplibs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit $EXIT_FAILURE + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $run eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + cmds=$reload_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; + esac + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` + ;; + esac + + case $host in + *darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + if test "$tagname" = CXX ; then + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + fi + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) + testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case $dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $run $rm $export_symbols + $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* ) + $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + $run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + else + $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* ) + $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + $run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` + $run eval '$echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + $echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr void * +#else +# define lt_ptr char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +" + + case $host in + *cygwin* | *mingw* ) + $echo >> "$output_objdir/$dlsyms" "\ +/* DATA imports from DLLs on WIN32 can't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs */ +struct { +" + ;; + * ) + $echo >> "$output_objdir/$dlsyms" "\ +const struct { +" + ;; + esac + + + $echo >> "$output_objdir/$dlsyms" "\ + const char *name; + lt_ptr address; +} +lt_preloaded_symbols[] = +{\ +" + + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + case $host in + *cygwin* | *mingw* ) + if test -f "$output_objdir/${outputname}.def" ; then + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%"` + else + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + fi + ;; + * ) + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + ;; + esac + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit $EXIT_FAILURE + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + exit_status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $exit_status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $run $rm $output + # Link the executable and exit + $show "$link_command" + $run eval "$link_command" || exit $? + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then + case $progpath in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; + *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + output_name=`basename $output` + output_path=`dirname $output` + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $rm $cwrappersource $cwrapper + trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + cat > $cwrappersource <> $cwrappersource<<"EOF" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +/* -DDEBUG is fairly common in CFLAGS. */ +#undef DEBUG +#if defined DEBUGWRAPPER +# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__) +#else +# define DEBUG(format, ...) +#endif + +const char *program_name = NULL; + +void * xmalloc (size_t num); +char * xstrdup (const char *string); +const char * base_name (const char *name); +char * find_executable(const char *wrapper); +int check_executable(const char *path); +char * strendzap(char *str, const char *pat); +void lt_fatal (const char *message, ...); + +int +main (int argc, char *argv[]) +{ + char **newargz; + int i; + + program_name = (char *) xstrdup (base_name (argv[0])); + DEBUG("(main) argv[0] : %s\n",argv[0]); + DEBUG("(main) program_name : %s\n",program_name); + newargz = XMALLOC(char *, argc+2); +EOF + + cat >> $cwrappersource <> $cwrappersource <<"EOF" + newargz[1] = find_executable(argv[0]); + if (newargz[1] == NULL) + lt_fatal("Couldn't find %s", argv[0]); + DEBUG("(main) found exe at : %s\n",newargz[1]); + /* we know the script has the same name, without the .exe */ + /* so make sure newargz[1] doesn't end in .exe */ + strendzap(newargz[1],".exe"); + for (i = 1; i < argc; i++) + newargz[i+1] = xstrdup(argv[i]); + newargz[argc+1] = NULL; + + for (i=0; i> $cwrappersource <> $cwrappersource <> $cwrappersource <<"EOF" + return 127; +} + +void * +xmalloc (size_t num) +{ + void * p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL +; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char)name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable(const char * path) +{ + struct stat st; + + DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!"); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) && + ( + /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */ +#if defined (S_IXOTH) + ((st.st_mode & S_IXOTH) == S_IXOTH) || +#endif +#if defined (S_IXGRP) + ((st.st_mode & S_IXGRP) == S_IXGRP) || +#endif + ((st.st_mode & S_IXUSR) == S_IXUSR)) + ) + return 1; + else + return 0; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise */ +char * +find_executable (const char* wrapper) +{ + int has_slash = 0; + const char* p; + const char* p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char* concat_name; + + DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char* path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char* q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR(*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen(tmp); + concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen(tmp); + concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable(concat_name)) + return concat_name; + XFREE(concat_name); + return NULL; +} + +char * +strendzap(char *str, const char *pat) +{ + size_t len, patlen; + + assert(str != NULL); + assert(pat != NULL); + + len = strlen(str); + patlen = strlen(pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp(str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char * mode, + const char * message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} +EOF + # we should really use a build-platform specific compiler + # here, but OTOH, the wrappers (shell script and this C one) + # are only useful if you want to execute the "real" binary. + # Since the "real" binary is built for $host, then this + # wrapper might as well be built for $host, too. + $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource + ;; + esac + $rm $output + trap "$rm $output; exit $EXIT_FAILURE" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='${SED} -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $echo >> $output "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + $echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $echo \"\$relink_command_output\" >&2 + $rm \"\$progdir/\$file\" + exit $EXIT_FAILURE + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + $echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" + exit $EXIT_FAILURE + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + $echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit $EXIT_FAILURE + fi +fi\ +" + chmod +x $output + fi + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + $echo "X$obj" | $Xsed -e 's%^.*/%%' + done | sort | sort -uc >/dev/null 2>&1); then + : + else + $echo "copying selected object files to avoid basename conflicts..." + + if test -z "$gentop"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "$mkdir $gentop" + $run $mkdir "$gentop" + exit_status=$? + if test "$exit_status" -ne 0 && test ! -d "$gentop"; then + exit $exit_status + fi + fi + + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + counter=`expr $counter + 1` + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + $run ln "$obj" "$gentop/$newobj" || + $run cp "$obj" "$gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + + eval cmds=\"$old_archive_cmds\" + + if len=`expr "X$cmds" : ".*"` && + test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + $echo "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + for obj in $save_oldobjs + do + oldobjs="$objlist $obj" + objlist="$objlist $obj" + eval test_cmds=\"$old_archive_cmds\" + if len=`expr "X$test_cmds" : ".*" 2>/dev/null` && + test "$len" -le "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + eval cmd=\"$cmd\" + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` + relink_command="$var=\"$var_value\"; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + if test -z "$libdir"; then + $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + for lib in $dlfiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlfiles="$newdlfiles $libdir/$name" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + if test -z "$libdir"; then + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + exit $EXIT_FAILURE + fi + newdlprefiles="$newdlprefiles $libdir/$name" + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $rm $output + # place dlname in correct position for cygwin + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + esac + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $echo >> $output "\ +relink_command=\"$relink_command\"" + fi + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? + ;; + esac + exit $EXIT_SUCCESS + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + $echo "X$nonopt" | grep shtool > /dev/null; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + case " $install_prog " in + *[\\\ /]cp\ *) ;; + *) prev=$arg ;; + esac + ;; + -g | -m | -o) prev=$arg ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case $arg in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test "$#" -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + library_names= + old_library= + relink_command= + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + if test "$inst_prefix_dir" = "$destdir"; then + $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 + exit $EXIT_FAILURE + fi + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + $echo "$modename: warning: relinking \`$file'" 1>&2 + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + exit $EXIT_FAILURE + fi + fi + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$srcname $destdir/$realname" + $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? + if test -n "$stripme" && test -n "$striplib"; then + $show "$striplib $destdir/$realname" + $run eval "$striplib $destdir/$realname" || exit $? + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" + $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + cmds=$postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + file=`$echo $file|${SED} 's,.exe$,,'` + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin*|*mingw*) + wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` + ;; + *) + wrapper=$file + ;; + esac + if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then + notinst_deplibs= + relink_command= + + # Note that it is not necessary on cygwin/mingw to append a dot to + # foo even if both foo and FILE.exe exist: automatic-append-.exe + # behavior happens only for exec(3), not for open(2)! Also, sourcing + # `FILE.' does not work on cygwin managed mounts. + # + # If there is no directory component, then add one. + case $wrapper in + */* | *\\*) . ${wrapper} ;; + *) . ./${wrapper} ;; + esac + + # Check the variables that should have been set. + if test -z "$notinst_deplibs"; then + $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 + exit $EXIT_FAILURE + fi + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case $lib in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + relink_command= + # Note that it is not necessary on cygwin/mingw to append a dot to + # foo even if both foo and FILE.exe exist: automatic-append-.exe + # behavior happens only for exec(3), not for open(2)! Also, sourcing + # `FILE.' does not work on cygwin managed mounts. + # + # If there is no directory component, then add one. + case $wrapper in + */* | *\\*) . ${wrapper} ;; + *) . ./${wrapper} ;; + esac + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir=`func_mktempdir` + file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` + ;; + esac + ;; + esac + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + if test -n "$stripme" && test -n "$old_striplib"; then + $show "$old_striplib $oldlib" + $run eval "$old_striplib $oldlib" || exit $? + fi + + # Do each command in the postinstall commands. + cmds=$old_postinstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + cmds=$finish_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = : && exit $EXIT_SUCCESS + + $echo "X----------------------------------------------------------------------" | $Xsed + $echo "Libraries have been installed in:" + for libdir in $libdirs; do + $echo " $libdir" + done + $echo + $echo "If you ever happen to want to link against installed libraries" + $echo "in a given directory, LIBDIR, you must either use libtool, and" + $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + $echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + $echo " during execution" + fi + if test -n "$runpath_var"; then + $echo " - add LIBDIR to the \`$runpath_var' environment variable" + $echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + $echo + $echo "See any operating system documentation about shared libraries for" + $echo "more information, such as the ld(1) and ld.so(8) manual pages." + $echo "X----------------------------------------------------------------------" | $Xsed + exit $EXIT_SUCCESS + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit $EXIT_FAILURE + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit $EXIT_FAILURE + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case $file in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + if test "${save_LC_ALL+set}" = set; then + LC_ALL="$save_LC_ALL"; export LC_ALL + fi + if test "${save_LANG+set}" = set; then + LANG="$save_LANG"; export LANG + fi + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit $EXIT_SUCCESS + fi + ;; + + # libtool clean and uninstall mode + clean | uninstall) + modename="$modename: $mode" + rm="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) rm="$rm $arg"; rmforce=yes ;; + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + fi + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$file"; then + dir=. + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if (test -L "$file") >/dev/null 2>&1 \ + || (test -h "$file") >/dev/null 2>&1 \ + || test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + cmds=$postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + cmds=$old_postuninstall_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $show "$cmd" + $run eval "$cmd" + if test "$?" -ne 0 && test "$rmforce" != yes; then + exit_status=1 + fi + done + IFS="$save_ifs" + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + + # Read the .lo file + . $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" \ + && test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" \ + && test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + file=`$echo $file|${SED} 's,.exe$,,'` + noexename=`$echo $name|${SED} 's,.exe$,,'` + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + relink_command= + . $dir/$noexename + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + $show "$rm $rmfiles" + $run $rm $rmfiles || exit_status=1 + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + $show "rmdir $dir" + $run rmdir $dir >/dev/null 2>&1 + fi + done + + exit $exit_status + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + ;; + esac + + if test -z "$exec_cmd"; then + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit $EXIT_FAILURE + fi +fi # test -z "$show_help" + +if test -n "$exec_cmd"; then + eval exec $exec_cmd + exit $EXIT_FAILURE +fi + +# We need to display help for each of the modes. +case $mode in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --tag=TAG use configuration variables from tag TAG + --version print version information + +MODE must be one of the following: + + clean remove files from the build directory + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE. + +Report bugs to ." + exit $EXIT_SUCCESS + ;; + +clean) + $echo \ +"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit $EXIT_FAILURE + ;; +esac + +$echo +$echo "Try \`$modename --help' for more information about other modes." + +exit $? + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +disable_libs=shared +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +disable_libs=static +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff --git a/contrib/ofed/librdmacm/config/missing b/contrib/ofed/librdmacm/config/missing new file mode 100755 index 000000000000..894e786e16c1 --- /dev/null +++ b/contrib/ofed/librdmacm/config/missing @@ -0,0 +1,360 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2005-06-08.21 + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). +case "$1" in + lex|yacc) + # Not GNU programs, they don't have --version. + ;; + + tar) + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + exit 1 + fi + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + tar) + shift + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/contrib/ofed/librdmacm/configure b/contrib/ofed/librdmacm/configure new file mode 100755 index 000000000000..3c6ac08a5c65 --- /dev/null +++ b/contrib/ofed/librdmacm/configure @@ -0,0 +1,21957 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59 for librdmacm 1.0.11. +# +# Report bugs to . +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +echo=${ECHO-echo} +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null 2>&1 && unset CDPATH + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string=`eval $cmd`) 2>/dev/null && + echo_test_string=`eval $cmd` && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL $0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + + + + +tagnames=${tagnames+${tagnames},}CXX + +tagnames=${tagnames+${tagnames},}F77 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME='librdmacm' +PACKAGE_TARNAME='librdmacm' +PACKAGE_VERSION='1.0.11' +PACKAGE_STRING='librdmacm 1.0.11' +PACKAGE_BUGREPORT='general@lists.openfabrics.org' + +ac_unique_file="src/cma.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE EGREP LN_S ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL HAVE_LD_VERSION_SCRIPT_TRUE HAVE_LD_VERSION_SCRIPT_FALSE LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP +ac_env_CXX_set=${CXX+set} +ac_env_CXX_value=$CXX +ac_cv_env_CXX_set=${CXX+set} +ac_cv_env_CXX_value=$CXX +ac_env_CXXFLAGS_set=${CXXFLAGS+set} +ac_env_CXXFLAGS_value=$CXXFLAGS +ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set} +ac_cv_env_CXXFLAGS_value=$CXXFLAGS +ac_env_CXXCPP_set=${CXXCPP+set} +ac_env_CXXCPP_value=$CXXCPP +ac_cv_env_CXXCPP_set=${CXXCPP+set} +ac_cv_env_CXXCPP_value=$CXXCPP +ac_env_F77_set=${F77+set} +ac_env_F77_value=$F77 +ac_cv_env_F77_set=${F77+set} +ac_cv_env_F77_value=$F77 +ac_env_FFLAGS_set=${FFLAGS+set} +ac_env_FFLAGS_value=$FFLAGS +ac_cv_env_FFLAGS_set=${FFLAGS+set} +ac_cv_env_FFLAGS_value=$FFLAGS + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures librdmacm 1.0.11 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of librdmacm 1.0.11:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-shared[=PKGS] + build shared libraries [default=yes] + --enable-static[=PKGS] + build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --disable-libtool-lock avoid locking (might break parallel builds) + --disable-libcheck do not test for presence of ib libraries + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-tags[=TAGS] + include additional configurations [automatic] + --with-valgrind Enable valgrind annotations - default NO + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CXXCPP C++ preprocessor + F77 Fortran 77 compiler command + FFLAGS Fortran 77 compiler flags + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd "$ac_popdir" + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF +librdmacm configure 1.0.11 +generated by GNU Autoconf 2.59 + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by librdmacm $as_me 1.0.11, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + + + + + + + + +ac_aux_dir= +for ac_dir in config $srcdir/config; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in config $srcdir/config" >&5 +echo "$as_me: error: cannot find install-sh or install.sh in config $srcdir/config" >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + + ac_config_headers="$ac_config_headers config.h" + +am__api_version="1.9" +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL=$ac_install_sh + fi +fi +echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6 +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +test "$program_prefix" != NONE && + program_transform_name="s,^,$program_prefix,;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$,$program_suffix,;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm conftest.sed + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$AWK" && break +done + +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` +if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +all: + @echo 'ac_maketemp="$(MAKE)"' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftest.make +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + SET_MAKE= +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE=librdmacm + VERSION=1.0.11 + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +install_sh=${install_sh-"$am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + + +# Check whether --enable-shared or --disable-shared was given. +if test "${enable_shared+set}" = set; then + enableval="$enable_shared" + p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi; + +# Check whether --enable-static or --disable-static was given. +if test "${enable_static+set}" = set; then + enableval="$enable_static" + p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi; + +# Check whether --enable-fast-install or --disable-fast-install was given. +if test "${enable_fast_install+set}" = set; then + enableval="$enable_fast_install" + p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi; + +# Make sure we can run config.sub. +$ac_config_sub sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 +echo "$as_me: error: cannot run $ac_config_sub" >&2;} + { (exit 1); exit 1; }; } + +echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6 +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_build_alias=$build_alias +test -z "$ac_cv_build_alias" && + ac_cv_build_alias=`$ac_config_guess` +test -z "$ac_cv_build_alias" && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6 +build=$ac_cv_build +build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6 +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_host_alias=$host_alias +test -z "$ac_cv_host_alias" && + ac_cv_host_alias=$ac_cv_build_alias +ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6 +host=$ac_cv_host +host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +DEPDIR="${am__leading_dot}deps" + + ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6 +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6 +rm -f confinc confmf + +# Check whether --enable-dependency-tracking or --disable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval="$enable_dependency_tracking" + +fi; +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + + +if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CC" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5 +echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6 +if test "${lt_cv_path_SED+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done + +fi + +SED=$lt_cv_path_SED +echo "$as_me:$LINENO: result: $SED" >&5 +echo "${ECHO_T}$SED" >&6 + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi; +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo "$as_me:$LINENO: checking for ld used by $CC" >&5 +echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6 + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6 +else + echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6 +fi +if test "${lt_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +echo "${ECHO_T}$LD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6 +if test "${lt_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6 +with_gnu_ld=$lt_cv_prog_gnu_ld + + +echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5 +echo $ECHO_N "checking for $LD option to reload object files... $ECHO_C" >&6 +if test "${lt_cv_ld_reload_flag+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_ld_reload_flag='-r' +fi +echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5 +echo "${ECHO_T}$lt_cv_ld_reload_flag" >&6 +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + +echo "$as_me:$LINENO: checking for BSD-compatible nm" >&5 +echo $ECHO_N "checking for BSD-compatible nm... $ECHO_C" >&6 +if test "${lt_cv_path_NM+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm +fi +fi +echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5 +echo "${ECHO_T}$lt_cv_path_NM" >&6 +NM="$lt_cv_path_NM" + +echo "$as_me:$LINENO: checking whether ln -s works" >&5 +echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:$LINENO: result: no, using $LN_S" >&5 +echo "${ECHO_T}no, using $LN_S" >&6 +fi + +echo "$as_me:$LINENO: checking how to recognise dependent libraries" >&5 +echo $ECHO_N "checking how to recognise dependent libraries... $ECHO_C" >&6 +if test "${lt_cv_deplibs_check_method+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix4* | aix5*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump'. + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | kfreebsd*-gnu | dragonfly*) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix3*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +nto-qnx*) + lt_cv_deplibs_check_method=unknown + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5 +echo "${ECHO_T}$lt_cv_deplibs_check_method" >&6 +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check whether --enable-libtool-lock or --disable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval="$enable_libtool_lock" + +fi; +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line 3673 "configure"' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5 +echo $ECHO_N "checking whether the C compiler needs -belf... $ECHO_C" >&6 +if test "${lt_cv_cc_needs_belf+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + lt_cv_cc_needs_belf=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +lt_cv_cc_needs_belf=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5 +echo "${ECHO_T}$lt_cv_cc_needs_belf" >&6 + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) LD="${LD-ld} -64" ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + + +esac + +need_locks="$enable_libtool_lock" + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in dlfcn.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------- ## +## Report this to general@lists.openfabrics.org ## +## -------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CXX" && break +done +test -n "$ac_ct_CXX" || ac_ct_CXX="g++" + + CXX=$ac_ct_CXX +fi + + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6 +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6 +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +CXXFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cxx_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +depcc="$CXX" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6 +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + + +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 +echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6 +if test -z "$CXXCPP"; then + if test "${ac_cv_prog_CXXCPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_cxx_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_cxx_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +echo "$as_me:$LINENO: result: $CXXCPP" >&5 +echo "${ECHO_T}$CXXCPP" >&6 +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_cxx_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_cxx_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +fi + + +ac_ext=f +ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' +ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_f77_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$F77"; then + ac_cv_prog_F77="$F77" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_F77="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +F77=$ac_cv_prog_F77 +if test -n "$F77"; then + echo "$as_me:$LINENO: result: $F77" >&5 +echo "${ECHO_T}$F77" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$F77" && break + done +fi +if test -z "$F77"; then + ac_ct_F77=$F77 + for ac_prog in g77 f77 xlf frt pgf77 fort77 fl32 af77 f90 xlf90 pgf90 epcf90 f95 fort xlf95 ifc efc pgf95 lf95 gfortran +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_F77"; then + ac_cv_prog_ac_ct_F77="$ac_ct_F77" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_F77="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_F77=$ac_cv_prog_ac_ct_F77 +if test -n "$ac_ct_F77"; then + echo "$as_me:$LINENO: result: $ac_ct_F77" >&5 +echo "${ECHO_T}$ac_ct_F77" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_F77" && break +done + + F77=$ac_ct_F77 +fi + + +# Provide some information about the compiler. +echo "$as_me:5264:" \ + "checking for Fortran 77 compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +rm -f a.out + +# If we don't use `.F' as extension, the preprocessor is not run on the +# input file. (Note that this only needs to work for GNU compilers.) +ac_save_ext=$ac_ext +ac_ext=F +echo "$as_me:$LINENO: checking whether we are using the GNU Fortran 77 compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU Fortran 77 compiler... $ECHO_C" >&6 +if test "${ac_cv_f77_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF + program main +#ifndef __GNUC__ + choke me +#endif + + end +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_f77_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_f77_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_f77_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_f77_compiler_gnu" >&6 +ac_ext=$ac_save_ext +ac_test_FFLAGS=${FFLAGS+set} +ac_save_FFLAGS=$FFLAGS +FFLAGS= +echo "$as_me:$LINENO: checking whether $F77 accepts -g" >&5 +echo $ECHO_N "checking whether $F77 accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_f77_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + FFLAGS=-g +cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_f77_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_f77_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_f77_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_f77_g" >&5 +echo "${ECHO_T}$ac_cv_prog_f77_g" >&6 +if test "$ac_test_FFLAGS" = set; then + FFLAGS=$ac_save_FFLAGS +elif test $ac_cv_prog_f77_g = yes; then + if test "x$ac_cv_f77_compiler_gnu" = xyes; then + FFLAGS="-g -O2" + else + FFLAGS="-g" + fi +else + if test "x$ac_cv_f77_compiler_gnu" = xyes; then + FFLAGS="-O2" + else + FFLAGS= + fi +fi + +G77=`test $ac_compiler_gnu = yes && echo yes` +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +# Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! + +# find the maximum length of command line arguments +echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5 +echo $ECHO_N "checking the maximum length of command line arguments... $ECHO_C" >&6 +if test "${lt_cv_sys_max_cmd_len+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + while (test "X"`$SHELL $0 --fallback-echo "X$teststring" 2>/dev/null` \ + = "XX$teststring") >/dev/null 2>&1 && + new_result=`expr "X$teststring" : ".*" 2>&1` && + lt_cv_sys_max_cmd_len=$new_result && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + teststring= + # Add a significant safety factor because C++ compilers can tack on massive + # amounts of additional arguments before passing them to the linker. + # It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5 +echo "${ECHO_T}$lt_cv_sys_max_cmd_len" >&6 +else + echo "$as_me:$LINENO: result: none" >&5 +echo "${ECHO_T}none" >&6 +fi + + + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5 +echo $ECHO_N "checking command to parse $NM output from $compiler object... $ECHO_C" >&6 +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform an extracted symbol line into a proper C declaration +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32*) + symcode='[ABCDGISTW]' + ;; +hpux*) # Its linker distinguishes data from code symbols + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + ;; +linux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDGIRSTW]' + lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5 + (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if grep ' nm_test_var$' "$nlist" >/dev/null; then + if grep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' + + cat <> conftest.$ac_ext +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[] = +{ +EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext + cat <<\EOF >> conftest.$ac_ext + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -f conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + echo "$as_me:$LINENO: result: failed" >&5 +echo "${ECHO_T}failed" >&6 +else + echo "$as_me:$LINENO: result: ok" >&5 +echo "${ECHO_T}ok" >&6 +fi + +echo "$as_me:$LINENO: checking for objdir" >&5 +echo $ECHO_N "checking for objdir... $ECHO_C" >&6 +if test "${lt_cv_objdir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5 +echo "${ECHO_T}$lt_cv_objdir" >&6 +objdir=$lt_cv_objdir + + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +# Constants: +rm="rm -f" + +# Global variables: +default_ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a +ltmain="$ac_aux_dir/ltmain.sh" +ofile="$default_ofile" +with_gnu_ld="$lt_cv_prog_gnu_ld" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + echo "$as_me:$LINENO: result: $AR" >&5 +echo "${ECHO_T}$AR" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_AR" && ac_cv_prog_ac_ct_AR="false" +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + echo "$as_me:$LINENO: result: $ac_ct_AR" >&5 +echo "${ECHO_T}$ac_ct_AR" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + AR=$ac_ct_AR +else + AR="$ac_cv_prog_AR" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + RANLIB=$ac_ct_RANLIB +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_STRIP" && ac_cv_prog_ac_ct_STRIP=":" +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + STRIP=$ac_ct_STRIP +else + STRIP="$ac_cv_prog_STRIP" +fi + + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru +test -z "$AS" && AS=as +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$LD" && LD=ld +test -z "$LN_S" && LN_S="ln -s" +test -z "$MAGIC_CMD" && MAGIC_CMD=file +test -z "$NM" && NM=nm +test -z "$SED" && SED=sed +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$RANLIB" && RANLIB=: +test -z "$STRIP" && STRIP=: +test -z "$ac_objext" && ac_objext=o + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5 +echo $ECHO_N "checking for ${ac_tool_prefix}file... $ECHO_C" >&6 +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + echo "$as_me:$LINENO: checking for file" >&5 +echo $ECHO_N "checking for file... $ECHO_C" >&6 +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5 +echo "${ECHO_T}$MAGIC_CMD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +enable_dlopen=no +enable_win32_dll=no + +# Check whether --enable-libtool-lock or --disable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval="$enable_libtool_lock" + +fi; +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + + +# Check whether --with-pic or --without-pic was given. +if test "${with_pic+set}" = set; then + withval="$with_pic" + pic_mode="$withval" +else + pic_mode=default +fi; +test -z "$pic_mode" && pic_mode=default + +# Use C for the default configuration in the libtool script +tagname= +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}\n' + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag=' -fno-builtin' + + +echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:6325: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:6329: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6 + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + +lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + +echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic='-qnocommon' + lt_prog_compiler_wl='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + linux*) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic" >&6 + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + +echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic works... $ECHO_C" >&6 +if test "${lt_prog_compiler_pic_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:6593: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:6597: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_pic_works=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works" >&6 + +if test x"$lt_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6 +if test "${lt_prog_compiler_static_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_static_works=yes + fi + else + lt_prog_compiler_static_works=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works" >&5 +echo "${ECHO_T}$lt_prog_compiler_static_works" >&6 + +if test x"$lt_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + +echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_c_o+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:6697: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:6701: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o" >&6 + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 + + runpath_var= + allow_undefined_flag= + enable_shared_with_static_runtimes=no + archive_cmds= + archive_expsym_cmds= + old_archive_From_new_cmds= + old_archive_from_expsyms_cmds= + export_dynamic_flag_spec= + whole_archive_flag_spec= + thread_safe_flag_spec= + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_direct=no + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + link_all_deplibs=unknown + hardcode_automatic=no + module_cmds= + module_expsym_cmds= + always_export_symbols=no + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + interix3*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + archive_cmds='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + link_all_deplibs=no + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct=yes + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + whole_archive_flag_spec='' + link_all_deplibs=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # GNU/kFreeBSD uses gcc -shared to do shared libraries. + kfreebsd*-gnu) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + link_all_deplibs=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + hardcode_direct=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld='-rpath $libdir' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + link_all_deplibs=yes + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + openbsd*) + hardcode_direct=yes + hardcode_shlibpath_var=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine linker options so we + # cannot just pass the convience library names through + # without $wl, iff we do not link with $LD. + # Luckily, gcc supports the same syntax we need for Sun Studio. + # Supported since Solaris 2.6 (maybe 2.5.1?) + case $wlarc in + '') + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; + *) + whole_archive_flag_spec='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; + esac ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $ld_shlibs" >&5 +echo "${ECHO_T}$ld_shlibs" >&6 +test "$ld_shlibs" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc=no + else + archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5 +echo "${ECHO_T}$archive_cmds_need_lc" >&6 + ;; + esac + fi + ;; +esac + +echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + freebsd*) # from 4.6 on + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix3*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test -n "$runpath_var" || \ + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +echo "$as_me:$LINENO: result: $hardcode_action" >&5 +echo "${ECHO_T}$hardcode_action" >&6 + +if test "$hardcode_action" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +striplib= +old_striplib= +echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5 +echo $ECHO_N "checking whether stripping libraries is possible... $ECHO_C" >&6 +if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + ;; + *) + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + ;; + esac +fi + +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + echo "$as_me:$LINENO: checking for shl_load" >&5 +echo $ECHO_N "checking for shl_load... $ECHO_C" >&6 +if test "${ac_cv_func_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define shl_load to an innocuous variant, in case declares shl_load. + For example, HP-UX 11i declares gettimeofday. */ +#define shl_load innocuous_shl_load + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shl_load (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef shl_load + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shl_load (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_shl_load) || defined (__stub___shl_load) +choke me +#else +char (*f) () = shl_load; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != shl_load; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_shl_load=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5 +echo "${ECHO_T}$ac_cv_func_shl_load" >&6 +if test $ac_cv_func_shl_load = yes; then + lt_cv_dlopen="shl_load" +else + echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5 +echo $ECHO_N "checking for shl_load in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_shl_load+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char shl_load (); +int +main () +{ +shl_load (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dld_shl_load=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dld_shl_load=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_shl_load" >&6 +if test $ac_cv_lib_dld_shl_load = yes; then + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" +else + echo "$as_me:$LINENO: checking for dlopen" >&5 +echo $ECHO_N "checking for dlopen... $ECHO_C" >&6 +if test "${ac_cv_func_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define dlopen to an innocuous variant, in case declares dlopen. + For example, HP-UX 11i declares gettimeofday. */ +#define dlopen innocuous_dlopen + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char dlopen (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef dlopen + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_dlopen) || defined (__stub___dlopen) +choke me +#else +char (*f) () = dlopen; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != dlopen; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5 +echo "${ECHO_T}$ac_cv_func_dlopen" >&6 +if test $ac_cv_func_dlopen = yes; then + lt_cv_dlopen="dlopen" +else + echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5 +echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6 +if test "${ac_cv_lib_dl_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dl_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dl_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6 +if test $ac_cv_lib_dl_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5 +echo $ECHO_N "checking for dlopen in -lsvld... $ECHO_C" >&6 +if test "${ac_cv_lib_svld_dlopen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlopen (); +int +main () +{ +dlopen (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_svld_dlopen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_svld_dlopen=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5 +echo "${ECHO_T}$ac_cv_lib_svld_dlopen" >&6 +if test $ac_cv_lib_svld_dlopen = yes; then + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5 +echo $ECHO_N "checking for dld_link in -ldld... $ECHO_C" >&6 +if test "${ac_cv_lib_dld_dld_link+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dld_link (); +int +main () +{ +dld_link (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_dld_dld_link=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_dld_dld_link=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5 +echo "${ECHO_T}$ac_cv_lib_dld_dld_link" >&6 +if test $ac_cv_lib_dld_dld_link = yes; then + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5 +echo $ECHO_N "checking whether a program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self" >&6 + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5 +echo $ECHO_N "checking whether a statically linked program can dlopen itself... $ECHO_C" >&6 +if test "${lt_cv_dlopen_self_static+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +#ifdef __cplusplus +extern "C" void exit (int); +#endif + +void fnord() { int i=42;} +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + /* dlclose (self); */ + } + else + puts (dlerror ()); + + exit (status); +} +EOF + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5 +echo "${ECHO_T}$lt_cv_dlopen_self_static" >&6 + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + +# Report which library types will actually be built +echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 +echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $can_build_shared" >&5 +echo "${ECHO_T}$can_build_shared" >&6 + +echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 +echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6 +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +echo "$as_me:$LINENO: result: $enable_shared" >&5 +echo "${ECHO_T}$enable_shared" >&6 + +echo "$as_me:$LINENO: checking whether to build static libraries" >&5 +echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6 +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +echo "$as_me:$LINENO: result: $enable_static" >&5 +echo "${ECHO_T}$enable_static" >&6 + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler \ + CC \ + LD \ + lt_prog_compiler_wl \ + lt_prog_compiler_pic \ + lt_prog_compiler_static \ + lt_prog_compiler_no_builtin_flag \ + export_dynamic_flag_spec \ + thread_safe_flag_spec \ + whole_archive_flag_spec \ + enable_shared_with_static_runtimes \ + old_archive_cmds \ + old_archive_from_new_cmds \ + predep_objects \ + postdep_objects \ + predeps \ + postdeps \ + compiler_lib_search_path \ + archive_cmds \ + archive_expsym_cmds \ + postinstall_cmds \ + postuninstall_cmds \ + old_archive_from_expsyms_cmds \ + allow_undefined_flag \ + no_undefined_flag \ + export_symbols_cmds \ + hardcode_libdir_flag_spec \ + hardcode_libdir_flag_spec_ld \ + hardcode_libdir_separator \ + hardcode_automatic \ + module_cmds \ + module_expsym_cmds \ + lt_cv_prog_compiler_c_o \ + exclude_expsyms \ + include_expsyms; do + + case $var in + old_archive_cmds | \ + old_archive_from_new_cmds | \ + archive_cmds | \ + archive_expsym_cmds | \ + module_cmds | \ + module_expsym_cmds | \ + old_archive_from_expsyms_cmds | \ + export_symbols_cmds | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="${ofile}T" + trap "$rm \"$cfgfile\"; exit 1" 1 2 15 + $rm -f "$cfgfile" + { echo "$as_me:$LINENO: creating $ofile" >&5 +echo "$as_me: creating $ofile" >&6;} + + cat <<__EOF__ >> "$cfgfile" +#! $SHELL + +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# +# This file is part of GNU Libtool: +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="$SED -e 1s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# The names of the tagged configurations supported by this script. +available_tags= + +# ### BEGIN LIBTOOL CONFIG + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU C compiler? +with_gcc=$GCC + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# ### END LIBTOOL CONFIG + +__EOF__ + + + case $host_os in + aix3*) + cat <<\EOF >> "$cfgfile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || \ + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + +# Check whether --with-tags or --without-tags was given. +if test "${with_tags+set}" = set; then + withval="$with_tags" + tagnames="$withval" +fi; + +if test -f "$ltmain" && test -n "$tagnames"; then + if test ! -f "${ofile}"; then + { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not exist" >&5 +echo "$as_me: WARNING: output file \`$ofile' does not exist" >&2;} + fi + + if test -z "$LTCC"; then + eval "`$SHELL ${ofile} --config | grep '^LTCC='`" + if test -z "$LTCC"; then + { echo "$as_me:$LINENO: WARNING: output file \`$ofile' does not look like a libtool script" >&5 +echo "$as_me: WARNING: output file \`$ofile' does not look like a libtool script" >&2;} + else + { echo "$as_me:$LINENO: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&5 +echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;} + fi + fi + if test -z "$LTCFLAGS"; then + eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" + fi + + # Extract list of available tagged configurations in $ofile. + # Note that this assumes the entire list is on one line. + available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` + + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for tagname in $tagnames; do + IFS="$lt_save_ifs" + # Check whether tagname contains only valid characters + case `$echo "X$tagname" | $Xsed -e 's:[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]::g'` in + "") ;; + *) { { echo "$as_me:$LINENO: error: invalid tag name: $tagname" >&5 +echo "$as_me: error: invalid tag name: $tagname" >&2;} + { (exit 1); exit 1; }; } + ;; + esac + + if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null + then + { { echo "$as_me:$LINENO: error: tag name \"$tagname\" already exists" >&5 +echo "$as_me: error: tag name \"$tagname\" already exists" >&2;} + { (exit 1); exit 1; }; } + fi + + # Update the list of available tags. + if test -n "$tagname"; then + echo appending configuration tag \"$tagname\" to $ofile + + case $tagname in + CXX) + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_flag_spec_ld_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_LD=$LD +lt_save_GCC=$GCC +GCC=$GXX +lt_save_with_gnu_ld=$with_gnu_ld +lt_save_path_LD=$lt_cv_path_LD +if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx +else + $as_unset lt_cv_prog_gnu_ld +fi +if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX +else + $as_unset lt_cv_path_LD +fi +test -z "${LDCXX+set}" || LD=$LDCXX +CC=${CXX-"c++"} +compiler=$CC +compiler_CXX=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# We don't want -fno-exception wen compiling C++ code, so set the +# no_builtin_flag separately +if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' +else + lt_prog_compiler_no_builtin_flag_CXX= +fi + +if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + +# Check whether --with-gnu-ld or --without-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then + withval="$with_gnu_ld" + test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi; +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo "$as_me:$LINENO: checking for ld used by $CC" >&5 +echo $ECHO_N "checking for ld used by $CC... $ECHO_C" >&6 + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6 +else + echo "$as_me:$LINENO: checking for non-GNU ld" >&5 +echo $ECHO_N "checking for non-GNU ld... $ECHO_C" >&6 +fi +if test "${lt_cv_path_LD+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +echo "${ECHO_T}$LD" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +test -z "$LD" && { { echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5 +echo "$as_me: error: no acceptable ld found in \$PATH" >&2;} + { (exit 1); exit 1; }; } +echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5 +echo $ECHO_N "checking if the linker ($LD) is GNU ld... $ECHO_C" >&6 +if test "${lt_cv_prog_gnu_ld+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +echo "${ECHO_T}$lt_cv_prog_gnu_ld" >&6 +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ + grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + +else + GXX=no + with_gnu_ld=no + wlarc= +fi + +# PORTME: fill in a description of your system's C++ link characteristics +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 +ld_shlibs_CXX=yes +case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct_CXX=yes + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag_CXX='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag_CXX='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + whole_archive_flag_spec_CXX='' + link_all_deplibs_CXX=yes + + if test "$GXX" = yes ; then + lt_int_apple_cc_single_mod=no + output_verbose_link_cmd='echo' + if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then + lt_int_apple_cc_single_mod=yes + fi + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + archive_cmds_CXX='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + else + archive_cmds_CXX='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + fi + module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + if test "X$lt_int_apple_cc_single_mod" = Xyes ; then + archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_CXX='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_CXX=no + ;; + esac + fi + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + freebsd[12]*) + # C++ shared libraries reported to be fairly broken before switch to ELF + ld_shlibs_CXX=no + ;; + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + gnu*) + ;; + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[-]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_libdir_flag_spec_ld_CXX='+b $libdir' + ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + interix3*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + ;; + linux*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc*) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC*) + # Portland Group C++ compiler + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + esac + ;; + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + openbsd*) + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd='echo' + ;; + osf3*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ + $rm $lib.exp' + + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The C++ compiler is used as linker so we must use $wl + # flag to pass the commands to the underlying system + # linker. We must also pass each convience library through + # to the system linker between allextract/defaultextract. + # The C++ compiler will combine linker options so we + # cannot just pass the convience library names through + # without $wl. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='echo' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | grep -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + fi + ;; + esac + ;; + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + # So that behaviour is only enabled if SCOABSPATH is set to a + # non-empty value in the environment. Most likely only useful for + # creating official distributions of packages. + # This is a hack until libtool officially supports absolute path + # names for shared libraries. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; +esac +echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 +echo "${ECHO_T}$ld_shlibs_CXX" >&6 +test "$ld_shlibs_CXX" = no && can_build_shared=no + +GCC_CXX="$GXX" +LD_CXX="$LD" + + +cat > conftest.$ac_ext <&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + # The `*' in the case matches for architectures that use `case' in + # $output_verbose_cmd can trigger glob expansion during the loop + # eval without this substitution. + output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"` + + for p in `eval $output_verbose_link_cmd`; do + case $p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" \ + || test $p = "-R"; then + prev=$p + continue + else + prev= + fi + + if test "$pre_test_object_deps_done" = no; then + case $p in + -L* | -R*) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + ;; + + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$rm -f confest.$objext + +# PORTME: override above test on systems where it is broken +case $host_os in +interix3*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +solaris*) + case $cc_basename in + CC*) + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + postdeps_CXX='-lCstd -lCrun' + ;; + esac + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + +lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + +echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | os2* | pw32*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix4* | aix5*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_AC_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic_CXX='-qnocommon' + lt_prog_compiler_wl_CXX='-Wl,' + ;; + esac + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | kfreebsd*-gnu | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + icpc* | ecpc*) + # Intel C++ + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC*) + # Portland Group C++ compiler. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_CXX" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_CXX" >&6 + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + +echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... $ECHO_C" >&6 +if test "${lt_prog_compiler_pic_works_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:11493: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:11497: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_pic_works_CXX=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_CXX" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works_CXX" >&6 + +if test x"$lt_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6 +if test "${lt_prog_compiler_static_works_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_static_works_CXX=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_static_works_CXX=yes + fi + else + lt_prog_compiler_static_works_CXX=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_CXX" >&5 +echo "${ECHO_T}$lt_prog_compiler_static_works_CXX" >&6 + +if test x"$lt_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +fi + + +echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:11597: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:11601: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_CXX" >&6 + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + case $host_os in + aix4* | aix5*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw*) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([^ ]*\) [^ ]*/\1 DATA/;/^I /d;/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' + ;; + kfreebsd*-gnu) + link_all_deplibs_CXX=no + ;; + linux*) + link_all_deplibs_CXX=no + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + +echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5 +echo "${ECHO_T}$ld_shlibs_CXX" >&6 +test "$ld_shlibs_CXX" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_CXX=no + else + archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + echo "$as_me:$LINENO: result: $archive_cmds_need_lc_CXX" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_CXX" >&6 + ;; + esac + fi + ;; +esac + +echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + freebsd*) # from 4.6 on + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix3*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || \ + test -n "$runpath_var_CXX" || \ + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +echo "$as_me:$LINENO: result: $hardcode_action_CXX" >&5 +echo "${ECHO_T}$hardcode_action_CXX" >&6 + +if test "$hardcode_action_CXX" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_CXX \ + CC_CXX \ + LD_CXX \ + lt_prog_compiler_wl_CXX \ + lt_prog_compiler_pic_CXX \ + lt_prog_compiler_static_CXX \ + lt_prog_compiler_no_builtin_flag_CXX \ + export_dynamic_flag_spec_CXX \ + thread_safe_flag_spec_CXX \ + whole_archive_flag_spec_CXX \ + enable_shared_with_static_runtimes_CXX \ + old_archive_cmds_CXX \ + old_archive_from_new_cmds_CXX \ + predep_objects_CXX \ + postdep_objects_CXX \ + predeps_CXX \ + postdeps_CXX \ + compiler_lib_search_path_CXX \ + archive_cmds_CXX \ + archive_expsym_cmds_CXX \ + postinstall_cmds_CXX \ + postuninstall_cmds_CXX \ + old_archive_from_expsyms_cmds_CXX \ + allow_undefined_flag_CXX \ + no_undefined_flag_CXX \ + export_symbols_cmds_CXX \ + hardcode_libdir_flag_spec_CXX \ + hardcode_libdir_flag_spec_ld_CXX \ + hardcode_libdir_separator_CXX \ + hardcode_automatic_CXX \ + module_cmds_CXX \ + module_expsym_cmds_CXX \ + lt_cv_prog_compiler_c_o_CXX \ + exclude_expsyms_CXX \ + include_expsyms_CXX; do + + case $var in + old_archive_cmds_CXX | \ + old_archive_from_new_cmds_CXX | \ + archive_cmds_CXX | \ + archive_expsym_cmds_CXX | \ + module_cmds_CXX | \ + module_expsym_cmds_CXX | \ + old_archive_from_expsyms_cmds_CXX | \ + export_symbols_cmds_CXX | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_CXX + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_CXX + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_CXX +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_CXX + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_CXX + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_CXX + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path_CXX" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC=$lt_save_CC +LDCXX=$LD +LD=$lt_save_LD +GCC=$lt_save_GCC +with_gnu_ldcxx=$with_gnu_ld +with_gnu_ld=$lt_save_with_gnu_ld +lt_cv_path_LDCXX=$lt_cv_path_LD +lt_cv_path_LD=$lt_save_path_LD +lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld +lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld + + else + tagname="" + fi + ;; + + F77) + if test -n "$F77" && test "X$F77" != "Xno"; then + +ac_ext=f +ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' +ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_f77_compiler_gnu + + +archive_cmds_need_lc_F77=no +allow_undefined_flag_F77= +always_export_symbols_F77=no +archive_expsym_cmds_F77= +export_dynamic_flag_spec_F77= +hardcode_direct_F77=no +hardcode_libdir_flag_spec_F77= +hardcode_libdir_flag_spec_ld_F77= +hardcode_libdir_separator_F77= +hardcode_minus_L_F77=no +hardcode_automatic_F77=no +module_cmds_F77= +module_expsym_cmds_F77= +link_all_deplibs_F77=unknown +old_archive_cmds_F77=$old_archive_cmds +no_undefined_flag_F77= +whole_archive_flag_spec_F77= +enable_shared_with_static_runtimes_F77=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +objext_F77=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code=" subroutine t\n return\n end\n" + +# Code to be used in simple link tests +lt_simple_link_test_code=" program t\n end\n" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${F77-"f77"} +compiler=$CC +compiler_F77=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5 +echo $ECHO_N "checking if libtool supports shared libraries... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $can_build_shared" >&5 +echo "${ECHO_T}$can_build_shared" >&6 + +echo "$as_me:$LINENO: checking whether to build shared libraries" >&5 +echo $ECHO_N "checking whether to build shared libraries... $ECHO_C" >&6 +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case $host_os in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; +aix4* | aix5*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; +esac +echo "$as_me:$LINENO: result: $enable_shared" >&5 +echo "${ECHO_T}$enable_shared" >&6 + +echo "$as_me:$LINENO: checking whether to build static libraries" >&5 +echo $ECHO_N "checking whether to build static libraries... $ECHO_C" >&6 +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes +echo "$as_me:$LINENO: result: $enable_static" >&5 +echo "${ECHO_T}$enable_static" >&6 + +GCC_F77="$G77" +LD_F77="$LD" + +lt_prog_compiler_wl_F77= +lt_prog_compiler_pic_F77= +lt_prog_compiler_static_F77= + +echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 + + if test "$GCC" = yes; then + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_static_F77='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_F77='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_F77='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_F77='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_F77='-fno-common' + ;; + + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared_F77=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_F77=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_F77='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic_F77='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl_F77='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_F77='-Bstatic' + else + lt_prog_compiler_static_F77='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic_F77='-qnocommon' + lt_prog_compiler_wl_F77='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_F77='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl_F77='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_F77='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static_F77='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl_F77='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static_F77='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + linux*) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-fpic' + lt_prog_compiler_static_F77='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl_F77='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static_F77='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl_F77='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static_F77='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl_F77='-Qoption ld ';; + *) + lt_prog_compiler_wl_F77='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl_F77='-Qoption ld ' + lt_prog_compiler_pic_F77='-PIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic_F77='-Kconform_pic' + lt_prog_compiler_static_F77='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_pic_F77='-KPIC' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl_F77='-Wl,' + lt_prog_compiler_can_build_shared_F77=no + ;; + + uts4*) + lt_prog_compiler_pic_F77='-pic' + lt_prog_compiler_static_F77='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared_F77=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_F77" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_F77" >&6 + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_F77"; then + +echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works... $ECHO_C" >&6 +if test "${lt_prog_compiler_pic_works_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works_F77=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_F77" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:13185: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:13189: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_pic_works_F77=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_F77" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works_F77" >&6 + +if test x"$lt_prog_compiler_pic_works_F77" = xyes; then + case $lt_prog_compiler_pic_F77 in + "" | " "*) ;; + *) lt_prog_compiler_pic_F77=" $lt_prog_compiler_pic_F77" ;; + esac +else + lt_prog_compiler_pic_F77= + lt_prog_compiler_can_build_shared_F77=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_F77= + ;; + *) + lt_prog_compiler_pic_F77="$lt_prog_compiler_pic_F77" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_F77 eval lt_tmp_static_flag=\"$lt_prog_compiler_static_F77\" +echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6 +if test "${lt_prog_compiler_static_works_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_static_works_F77=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_static_works_F77=yes + fi + else + lt_prog_compiler_static_works_F77=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_F77" >&5 +echo "${ECHO_T}$lt_prog_compiler_static_works_F77" >&6 + +if test x"$lt_prog_compiler_static_works_F77" = xyes; then + : +else + lt_prog_compiler_static_F77= +fi + + +echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_c_o_F77+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_F77=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:13289: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:13293: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_F77=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_F77" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_F77" >&6 + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_F77" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 + + runpath_var= + allow_undefined_flag_F77= + enable_shared_with_static_runtimes_F77=no + archive_cmds_F77= + archive_expsym_cmds_F77= + old_archive_From_new_cmds_F77= + old_archive_from_expsyms_cmds_F77= + export_dynamic_flag_spec_F77= + whole_archive_flag_spec_F77= + thread_safe_flag_spec_F77= + hardcode_libdir_flag_spec_F77= + hardcode_libdir_flag_spec_ld_F77= + hardcode_libdir_separator_F77= + hardcode_direct_F77=no + hardcode_minus_L_F77=no + hardcode_shlibpath_var_F77=unsupported + link_all_deplibs_F77=unknown + hardcode_automatic_F77=no + module_cmds_F77= + module_expsym_cmds_F77= + always_export_symbols_F77=no + export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms_F77= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms_F77="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs_F77=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_F77='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_F77='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_F77= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs_F77=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs_F77=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_F77=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_F77='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_F77=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, F77) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_F77='-L$libdir' + allow_undefined_flag_F77=unsupported + always_export_symbols_F77=no + enable_shared_with_static_runtimes_F77=yes + export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_F77=no + fi + ;; + + interix3*) + hardcode_direct_F77=no + hardcode_shlibpath_var_F77=no + hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' + export_dynamic_flag_spec_F77='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_F77='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + archive_cmds_F77='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + archive_expsym_cmds_F77='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + link_all_deplibs_F77=no + else + ld_shlibs_F77=no + fi + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_F77='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs_F77=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_F77=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs_F77=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec_F77='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + ld_shlibs_F77=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds_F77='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_F77=no + fi + ;; + esac + + if test "$ld_shlibs_F77" = no; then + runpath_var= + hardcode_libdir_flag_spec_F77= + export_dynamic_flag_spec_F77= + whole_archive_flag_spec_F77= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag_F77=unsupported + always_export_symbols_F77=yes + archive_expsym_cmds_F77='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L_F77=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct_F77=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_F77='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_F77='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_F77='' + hardcode_direct_F77=yes + hardcode_libdir_separator_F77=':' + link_all_deplibs_F77=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct_F77=yes + else + # We have old collect2 + hardcode_direct_F77=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_F77=yes + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_libdir_separator_F77= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_F77=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_F77='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_f77_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds_F77="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_F77='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_F77="-z nodefs" + archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF + program main + + end +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_f77_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_F77=' ${wl}-bernotok' + allow_undefined_flag_F77=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_F77='$convenience' + archive_cmds_need_lc_F77=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + # see comment about different semantics on the GNU ld section + ld_shlibs_F77=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec_F77=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_F77=' ' + allow_undefined_flag_F77=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds_F77='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds_F77='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds_F77='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path_F77='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes_F77=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag_F77='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag_F77='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc_F77=no + hardcode_direct_F77=no + hardcode_automatic_F77=yes + hardcode_shlibpath_var_F77=unsupported + whole_archive_flag_spec_F77='' + link_all_deplibs_F77=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds_F77='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_F77='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_F77=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_shlibpath_var_F77=no + ;; + + freebsd1*) + ld_shlibs_F77=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes + hardcode_minus_L_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + # GNU/kFreeBSD uses gcc -shared to do shared libraries. + kfreebsd*-gnu) + archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + link_all_deplibs_F77=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds_F77='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds_F77='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_F77=: + hardcode_direct_F77=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + export_dynamic_flag_spec_F77='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_F77=: + + hardcode_direct_F77=yes + export_dynamic_flag_spec_F77='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_F77=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_libdir_flag_spec_ld_F77='+b $libdir' + hardcode_direct_F77=no + hardcode_shlibpath_var_F77=no + ;; + *) + hardcode_direct_F77=yes + export_dynamic_flag_spec_F77='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_F77=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_F77='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld_F77='-rpath $libdir' + fi + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + link_all_deplibs_F77=yes + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds_F77='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + newsos6) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + hardcode_shlibpath_var_F77=no + ;; + + openbsd*) + hardcode_direct_F77=yes + hardcode_shlibpath_var_F77=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' + export_dynamic_flag_spec_F77='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-R$libdir' + ;; + *) + archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_minus_L_F77=yes + allow_undefined_flag_F77=unsupported + archive_cmds_F77='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds_F77='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag_F77=' -expect_unresolved \*' + archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_F77=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag_F77=' -expect_unresolved \*' + archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_F77='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec_F77='-rpath $libdir' + fi + hardcode_libdir_separator_F77=: + ;; + + solaris*) + no_undefined_flag_F77=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec_F77='-R$libdir' + hardcode_shlibpath_var_F77=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine linker options so we + # cannot just pass the convience library names through + # without $wl, iff we do not link with $LD. + # Luckily, gcc supports the same syntax we need for Sun Studio. + # Supported since Solaris 2.6 (maybe 2.5.1?) + case $wlarc in + '') + whole_archive_flag_spec_F77='-z allextract$convenience -z defaultextract' ;; + *) + whole_archive_flag_spec_F77='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; + esac ;; + esac + link_all_deplibs_F77=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds_F77='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_direct_F77=yes + hardcode_minus_L_F77=yes + hardcode_shlibpath_var_F77=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds_F77='$CC -r -o $output$reload_objs' + hardcode_direct_F77=no + ;; + motorola) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_F77=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var_F77=no + ;; + + sysv4.3*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_F77=no + export_dynamic_flag_spec_F77='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_F77=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs_F77=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) + no_undefined_flag_F77='${wl}-z,text' + archive_cmds_need_lc_F77=no + hardcode_shlibpath_var_F77=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_F77='${wl}-z,text' + allow_undefined_flag_F77='${wl}-z,nodefs' + archive_cmds_need_lc_F77=no + hardcode_shlibpath_var_F77=no + hardcode_libdir_flag_spec_F77='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator_F77=':' + link_all_deplibs_F77=yes + export_dynamic_flag_spec_F77='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_F77='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_F77='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_F77='-L$libdir' + hardcode_shlibpath_var_F77=no + ;; + + *) + ld_shlibs_F77=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $ld_shlibs_F77" >&5 +echo "${ECHO_T}$ld_shlibs_F77" >&6 +test "$ld_shlibs_F77" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_F77" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_F77=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_F77 in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_F77 + pic_flag=$lt_prog_compiler_pic_F77 + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_F77 + allow_undefined_flag_F77= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_F77=no + else + archive_cmds_need_lc_F77=yes + fi + allow_undefined_flag_F77=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + echo "$as_me:$LINENO: result: $archive_cmds_need_lc_F77" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_F77" >&6 + ;; + esac + fi + ;; +esac + +echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + freebsd*) # from 4.6 on + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix3*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 +hardcode_action_F77= +if test -n "$hardcode_libdir_flag_spec_F77" || \ + test -n "$runpath_var_F77" || \ + test "X$hardcode_automatic_F77" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_F77" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, F77)" != no && + test "$hardcode_minus_L_F77" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_F77=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_F77=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_F77=unsupported +fi +echo "$as_me:$LINENO: result: $hardcode_action_F77" >&5 +echo "${ECHO_T}$hardcode_action_F77" >&6 + +if test "$hardcode_action_F77" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_F77 \ + CC_F77 \ + LD_F77 \ + lt_prog_compiler_wl_F77 \ + lt_prog_compiler_pic_F77 \ + lt_prog_compiler_static_F77 \ + lt_prog_compiler_no_builtin_flag_F77 \ + export_dynamic_flag_spec_F77 \ + thread_safe_flag_spec_F77 \ + whole_archive_flag_spec_F77 \ + enable_shared_with_static_runtimes_F77 \ + old_archive_cmds_F77 \ + old_archive_from_new_cmds_F77 \ + predep_objects_F77 \ + postdep_objects_F77 \ + predeps_F77 \ + postdeps_F77 \ + compiler_lib_search_path_F77 \ + archive_cmds_F77 \ + archive_expsym_cmds_F77 \ + postinstall_cmds_F77 \ + postuninstall_cmds_F77 \ + old_archive_from_expsyms_cmds_F77 \ + allow_undefined_flag_F77 \ + no_undefined_flag_F77 \ + export_symbols_cmds_F77 \ + hardcode_libdir_flag_spec_F77 \ + hardcode_libdir_flag_spec_ld_F77 \ + hardcode_libdir_separator_F77 \ + hardcode_automatic_F77 \ + module_cmds_F77 \ + module_expsym_cmds_F77 \ + lt_cv_prog_compiler_c_o_F77 \ + exclude_expsyms_F77 \ + include_expsyms_F77; do + + case $var in + old_archive_cmds_F77 | \ + old_archive_from_new_cmds_F77 | \ + archive_cmds_F77 | \ + archive_expsym_cmds_F77 | \ + module_cmds_F77 | \ + module_expsym_cmds_F77 | \ + old_archive_from_expsyms_cmds_F77 | \ + export_symbols_cmds_F77 | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_F77 + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_F77 + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_F77 + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_F77 + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_F77 + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_F77 + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_F77 +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_F77 + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_F77 + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_F77 + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_F77 + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_F77 + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_F77 + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_F77 +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_F77 + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_F77 + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_F77 +archive_expsym_cmds=$lt_archive_expsym_cmds_F77 +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_F77 +module_expsym_cmds=$lt_module_expsym_cmds_F77 + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_F77 + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_F77 + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_F77 + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_F77 + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_F77 + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_F77 + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_F77 + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_F77 + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_F77 + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_F77 + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_F77 + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_F77 + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_F77 + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_F77 + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_F77 + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_F77 + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path_F77" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_F77 + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_F77 + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_F77 + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_F77 + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + else + tagname="" + fi + ;; + + GCJ) + if test -n "$GCJ" && test "X$GCJ" != "Xno"; then + + + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +objext_GCJ=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}\n" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[] argv) {}; }\n' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${GCJ-"gcj"} +compiler=$CC +compiler_GCJ=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +archive_cmds_need_lc_GCJ=no + +old_archive_cmds_GCJ=$old_archive_cmds + + +lt_prog_compiler_no_builtin_flag_GCJ= + +if test "$GCC" = yes; then + lt_prog_compiler_no_builtin_flag_GCJ=' -fno-builtin' + + +echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:15512: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:15516: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_rtti_exceptions" >&6 + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag_GCJ="$lt_prog_compiler_no_builtin_flag_GCJ -fno-rtti -fno-exceptions" +else + : +fi + +fi + +lt_prog_compiler_wl_GCJ= +lt_prog_compiler_pic_GCJ= +lt_prog_compiler_static_GCJ= + +echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5 +echo $ECHO_N "checking for $compiler option to produce PIC... $ECHO_C" >&6 + + if test "$GCC" = yes; then + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_static_GCJ='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_GCJ='-Bstatic' + fi + ;; + + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_GCJ='-m68020 -resident32 -malways-restore-a4' + ;; + + beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_GCJ='-fno-common' + ;; + + interix3*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared_GCJ=no + enable_shared=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_GCJ=-Kconform_pic + fi + ;; + + hpux*) + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_GCJ='-fPIC' + ;; + esac + ;; + + *) + lt_prog_compiler_pic_GCJ='-fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl_GCJ='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_GCJ='-Bstatic' + else + lt_prog_compiler_static_GCJ='-bnso -bI:/lib/syscalls.exp' + fi + ;; + darwin*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + case $cc_basename in + xlc*) + lt_prog_compiler_pic_GCJ='-qnocommon' + lt_prog_compiler_wl_GCJ='-Wl,' + ;; + esac + ;; + + mingw* | pw32* | os2*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl_GCJ='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_GCJ='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static_GCJ='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl_GCJ='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + + newsos6) + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + linux*) + case $cc_basename in + icc* | ecc*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-fpic' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl_GCJ='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + esac + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl_GCJ='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static_GCJ='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl_GCJ='-Qoption ld ';; + *) + lt_prog_compiler_wl_GCJ='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl_GCJ='-Qoption ld ' + lt_prog_compiler_pic_GCJ='-PIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic_GCJ='-Kconform_pic' + lt_prog_compiler_static_GCJ='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_pic_GCJ='-KPIC' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl_GCJ='-Wl,' + lt_prog_compiler_can_build_shared_GCJ=no + ;; + + uts4*) + lt_prog_compiler_pic_GCJ='-pic' + lt_prog_compiler_static_GCJ='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared_GCJ=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_GCJ" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_GCJ" >&6 + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_GCJ"; then + +echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works" >&5 +echo $ECHO_N "checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works... $ECHO_C" >&6 +if test "${lt_prog_compiler_pic_works_GCJ+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_pic_works_GCJ=no + ac_outfile=conftest.$ac_objext + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_GCJ" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:15780: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:15784: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_pic_works_GCJ=yes + fi + fi + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_works_GCJ" >&5 +echo "${ECHO_T}$lt_prog_compiler_pic_works_GCJ" >&6 + +if test x"$lt_prog_compiler_pic_works_GCJ" = xyes; then + case $lt_prog_compiler_pic_GCJ in + "" | " "*) ;; + *) lt_prog_compiler_pic_GCJ=" $lt_prog_compiler_pic_GCJ" ;; + esac +else + lt_prog_compiler_pic_GCJ= + lt_prog_compiler_can_build_shared_GCJ=no +fi + +fi +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_GCJ= + ;; + *) + lt_prog_compiler_pic_GCJ="$lt_prog_compiler_pic_GCJ" + ;; +esac + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_GCJ eval lt_tmp_static_flag=\"$lt_prog_compiler_static_GCJ\" +echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +echo $ECHO_N "checking if $compiler static flag $lt_tmp_static_flag works... $ECHO_C" >&6 +if test "${lt_prog_compiler_static_works_GCJ+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_prog_compiler_static_works_GCJ=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + printf "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_prog_compiler_static_works_GCJ=yes + fi + else + lt_prog_compiler_static_works_GCJ=yes + fi + fi + $rm conftest* + LDFLAGS="$save_LDFLAGS" + +fi +echo "$as_me:$LINENO: result: $lt_prog_compiler_static_works_GCJ" >&5 +echo "${ECHO_T}$lt_prog_compiler_static_works_GCJ" >&6 + +if test x"$lt_prog_compiler_static_works_GCJ" = xyes; then + : +else + lt_prog_compiler_static_GCJ= +fi + + +echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5 +echo $ECHO_N "checking if $compiler supports -c -o file.$ac_objext... $ECHO_C" >&6 +if test "${lt_cv_prog_compiler_c_o_GCJ+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + lt_cv_prog_compiler_c_o_GCJ=no + $rm -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:15884: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:15888: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_GCJ=yes + fi + fi + chmod u+w . 2>&5 + $rm conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files + $rm out/* && rmdir out + cd .. + rmdir conftest + $rm conftest* + +fi +echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_GCJ" >&5 +echo "${ECHO_T}$lt_cv_prog_compiler_c_o_GCJ" >&6 + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_GCJ" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo "$as_me:$LINENO: checking if we can lock with hard links" >&5 +echo $ECHO_N "checking if we can lock with hard links... $ECHO_C" >&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$as_me:$LINENO: result: $hard_links" >&5 +echo "${ECHO_T}$hard_links" >&6 + if test "$hard_links" = no; then + { echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + +echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +echo $ECHO_N "checking whether the $compiler linker ($LD) supports shared libraries... $ECHO_C" >&6 + + runpath_var= + allow_undefined_flag_GCJ= + enable_shared_with_static_runtimes_GCJ=no + archive_cmds_GCJ= + archive_expsym_cmds_GCJ= + old_archive_From_new_cmds_GCJ= + old_archive_from_expsyms_cmds_GCJ= + export_dynamic_flag_spec_GCJ= + whole_archive_flag_spec_GCJ= + thread_safe_flag_spec_GCJ= + hardcode_libdir_flag_spec_GCJ= + hardcode_libdir_flag_spec_ld_GCJ= + hardcode_libdir_separator_GCJ= + hardcode_direct_GCJ=no + hardcode_minus_L_GCJ=no + hardcode_shlibpath_var_GCJ=unsupported + link_all_deplibs_GCJ=unknown + hardcode_automatic_GCJ=no + module_cmds_GCJ= + module_expsym_cmds_GCJ= + always_export_symbols_GCJ=no + export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms_GCJ= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms_GCJ="_GLOBAL_OFFSET_TABLE_" + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + extract_expsyms_cmds= + # Just being paranoid about ensuring that cc_basename is set. + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + + case $host_os in + cygwin* | mingw* | pw32*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs_GCJ=yes + if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_GCJ='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_GCJ='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_GCJ="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_GCJ= + fi + supports_anon_versioning=no + case `$LD -v 2>/dev/null` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix3* | aix4* | aix5*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs_GCJ=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + fi + ;; + + amigaos*) + archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can't use + # them. + ld_shlibs_GCJ=no + ;; + + beos*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_GCJ=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_GCJ='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + + cygwin* | mingw* | pw32*) + # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, GCJ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_GCJ='-L$libdir' + allow_undefined_flag_GCJ=unsupported + always_export_symbols_GCJ=no + enable_shared_with_static_runtimes_GCJ=yes + export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_GCJ='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_GCJ=no + fi + ;; + + interix3*) + hardcode_direct_GCJ=no + hardcode_shlibpath_var_GCJ=no + hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' + export_dynamic_flag_spec_GCJ='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_GCJ='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_GCJ='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + linux*) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + tmp_addflag= + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec_GCJ='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers + whole_archive_flag_spec_GCJ='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + esac + archive_cmds_GCJ='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test $supports_anon_versioning = yes; then + archive_expsym_cmds_GCJ='$echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + $echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + link_all_deplibs_GCJ=no + else + ld_shlibs_GCJ=no + fi + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_GCJ='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then + ld_shlibs_GCJ=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs_GCJ=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec_GCJ='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds_GCJ='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + *) + if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs_GCJ=no + fi + ;; + esac + + if test "$ld_shlibs_GCJ" = no; then + runpath_var= + hardcode_libdir_flag_spec_GCJ= + export_dynamic_flag_spec_GCJ= + whole_archive_flag_spec_GCJ= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag_GCJ=unsupported + always_export_symbols_GCJ=yes + archive_expsym_cmds_GCJ='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L_GCJ=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct_GCJ=unsupported + fi + ;; + + aix4* | aix5*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + if $NM -V 2>&1 | grep 'GNU' > /dev/null; then + export_symbols_cmds_GCJ='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_GCJ='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix5*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_GCJ='' + hardcode_direct_GCJ=yes + hardcode_libdir_separator_GCJ=':' + link_all_deplibs_GCJ=yes + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct_GCJ=yes + else + # We have old collect2 + hardcode_direct_GCJ=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_GCJ=yes + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_libdir_separator_GCJ= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols_GCJ=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_GCJ='-berok' + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds_GCJ="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_GCJ='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_GCJ="-z nodefs" + archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an empty executable. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } +}'`; fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_GCJ=' ${wl}-bernotok' + allow_undefined_flag_GCJ=' ${wl}-berok' + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_GCJ='$convenience' + archive_cmds_need_lc_GCJ=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + # see comment about different semantics on the GNU ld section + ld_shlibs_GCJ=no + ;; + + bsdi[45]*) + export_dynamic_flag_spec_GCJ=-rdynamic + ;; + + cygwin* | mingw* | pw32*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_GCJ=' ' + allow_undefined_flag_GCJ=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds_GCJ='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_From_new_cmds_GCJ='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds_GCJ='lib /OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path_GCJ='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes_GCJ=yes + ;; + + darwin* | rhapsody*) + case $host_os in + rhapsody* | darwin1.[012]) + allow_undefined_flag_GCJ='${wl}-undefined ${wl}suppress' + ;; + *) # Darwin 1.3 on + if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then + allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + else + case ${MACOSX_DEPLOYMENT_TARGET} in + 10.[012]) + allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' + ;; + 10.*) + allow_undefined_flag_GCJ='${wl}-undefined ${wl}dynamic_lookup' + ;; + esac + fi + ;; + esac + archive_cmds_need_lc_GCJ=no + hardcode_direct_GCJ=no + hardcode_automatic_GCJ=yes + hardcode_shlibpath_var_GCJ=unsupported + whole_archive_flag_spec_GCJ='' + link_all_deplibs_GCJ=yes + if test "$GCC" = yes ; then + output_verbose_link_cmd='echo' + archive_cmds_GCJ='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' + module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + else + case $cc_basename in + xlc*) + output_verbose_link_cmd='echo' + archive_cmds_GCJ='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' + module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' + # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds + archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' + ;; + *) + ld_shlibs_GCJ=no + ;; + esac + fi + ;; + + dgux*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_shlibpath_var_GCJ=no + ;; + + freebsd1*) + ld_shlibs_GCJ=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes + hardcode_minus_L_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + # GNU/kFreeBSD uses gcc -shared to do shared libraries. + kfreebsd*-gnu) + archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + link_all_deplibs_GCJ=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds_GCJ='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds_GCJ='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + hardcode_direct_GCJ=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + + hardcode_direct_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes -a "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_libdir_flag_spec_ld_GCJ='+b $libdir' + hardcode_direct_GCJ=no + hardcode_shlibpath_var_GCJ=no + ;; + *) + hardcode_direct_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L_GCJ=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_GCJ='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_ld_GCJ='-rpath $libdir' + fi + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + link_all_deplibs_GCJ=yes + ;; + + netbsd* | netbsdelf*-gnu | knetbsd*-gnu) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds_GCJ='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + newsos6) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + hardcode_shlibpath_var_GCJ=no + ;; + + openbsd*) + hardcode_direct_GCJ=yes + hardcode_shlibpath_var_GCJ=no + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' + export_dynamic_flag_spec_GCJ='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-R$libdir' + ;; + *) + archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' + ;; + esac + fi + ;; + + os2*) + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_minus_L_GCJ=yes + allow_undefined_flag_GCJ=unsupported + archive_cmds_GCJ='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_From_new_cmds_GCJ='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag_GCJ=' -expect_unresolved \*' + archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_GCJ=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag_GCJ=' -expect_unresolved \*' + archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_GCJ='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ + $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec_GCJ='-rpath $libdir' + fi + hardcode_libdir_separator_GCJ=: + ;; + + solaris*) + no_undefined_flag_GCJ=' -z text' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' + else + wlarc='' + archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' + fi + hardcode_libdir_flag_spec_GCJ='-R$libdir' + hardcode_shlibpath_var_GCJ=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine linker options so we + # cannot just pass the convience library names through + # without $wl, iff we do not link with $LD. + # Luckily, gcc supports the same syntax we need for Sun Studio. + # Supported since Solaris 2.6 (maybe 2.5.1?) + case $wlarc in + '') + whole_archive_flag_spec_GCJ='-z allextract$convenience -z defaultextract' ;; + *) + whole_archive_flag_spec_GCJ='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; + esac ;; + esac + link_all_deplibs_GCJ=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds_GCJ='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_direct_GCJ=yes + hardcode_minus_L_GCJ=yes + hardcode_shlibpath_var_GCJ=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds_GCJ='$CC -r -o $output$reload_objs' + hardcode_direct_GCJ=no + ;; + motorola) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct_GCJ=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var_GCJ=no + ;; + + sysv4.3*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_GCJ=no + export_dynamic_flag_spec_GCJ='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var_GCJ=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs_GCJ=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) + no_undefined_flag_GCJ='${wl}-z,text' + archive_cmds_need_lc_GCJ=no + hardcode_shlibpath_var_GCJ=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_GCJ='${wl}-z,text' + allow_undefined_flag_GCJ='${wl}-z,nodefs' + archive_cmds_need_lc_GCJ=no + hardcode_shlibpath_var_GCJ=no + hardcode_libdir_flag_spec_GCJ='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' + hardcode_libdir_separator_GCJ=':' + link_all_deplibs_GCJ=yes + export_dynamic_flag_spec_GCJ='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds_GCJ='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds_GCJ='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_GCJ='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec_GCJ='-L$libdir' + hardcode_shlibpath_var_GCJ=no + ;; + + *) + ld_shlibs_GCJ=no + ;; + esac + fi + +echo "$as_me:$LINENO: result: $ld_shlibs_GCJ" >&5 +echo "${ECHO_T}$ld_shlibs_GCJ" >&6 +test "$ld_shlibs_GCJ" = no && can_build_shared=no + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_GCJ" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_GCJ=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_GCJ in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5 +echo $ECHO_N "checking whether -lc should be explicitly linked in... $ECHO_C" >&6 + $rm conftest* + printf "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_GCJ + pic_flag=$lt_prog_compiler_pic_GCJ + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_GCJ + allow_undefined_flag_GCJ= + if { (eval echo "$as_me:$LINENO: \"$archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\"") >&5 + (eval $archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + then + archive_cmds_need_lc_GCJ=no + else + archive_cmds_need_lc_GCJ=yes + fi + allow_undefined_flag_GCJ=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $rm conftest* + echo "$as_me:$LINENO: result: $archive_cmds_need_lc_GCJ" >&5 +echo "${ECHO_T}$archive_cmds_need_lc_GCJ" >&6 + ;; + esac + fi + ;; +esac + +echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5 +echo $ECHO_N "checking dynamic linker characteristics... $ECHO_C" >&6 +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix4* | aix5*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $rm \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + ;; + mingw*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` + if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH printed by + # mingw gcc, but we are running on Cygwin. Gcc prints its search + # path with ; separators, and with drive letters. We can handle the + # drive letters (cygwin fileutils understands them), so leave them, + # especially as we might pass files found there to a mingw objdump, + # which wouldn't understand a cygwinified path. Ahh. + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. + if test "$GCC" = yes; then + sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` + else + sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' + fi + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd1*) + dynamic_linker=no + ;; + +kfreebsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[123]*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + freebsd*) # from 4.6 on + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + ;; + +interix3*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +knetbsd*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='GNU ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +nto-qnx*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + shlibpath_overrides_runpath=no + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + shlibpath_overrides_runpath=yes + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$as_me:$LINENO: result: $dynamic_linker" >&5 +echo "${ECHO_T}$dynamic_linker" >&6 +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5 +echo $ECHO_N "checking how to hardcode library paths into programs... $ECHO_C" >&6 +hardcode_action_GCJ= +if test -n "$hardcode_libdir_flag_spec_GCJ" || \ + test -n "$runpath_var_GCJ" || \ + test "X$hardcode_automatic_GCJ" = "Xyes" ; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct_GCJ" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, GCJ)" != no && + test "$hardcode_minus_L_GCJ" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_GCJ=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_GCJ=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_GCJ=unsupported +fi +echo "$as_me:$LINENO: result: $hardcode_action_GCJ" >&5 +echo "${ECHO_T}$hardcode_action_GCJ" >&6 + +if test "$hardcode_action_GCJ" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_GCJ \ + CC_GCJ \ + LD_GCJ \ + lt_prog_compiler_wl_GCJ \ + lt_prog_compiler_pic_GCJ \ + lt_prog_compiler_static_GCJ \ + lt_prog_compiler_no_builtin_flag_GCJ \ + export_dynamic_flag_spec_GCJ \ + thread_safe_flag_spec_GCJ \ + whole_archive_flag_spec_GCJ \ + enable_shared_with_static_runtimes_GCJ \ + old_archive_cmds_GCJ \ + old_archive_from_new_cmds_GCJ \ + predep_objects_GCJ \ + postdep_objects_GCJ \ + predeps_GCJ \ + postdeps_GCJ \ + compiler_lib_search_path_GCJ \ + archive_cmds_GCJ \ + archive_expsym_cmds_GCJ \ + postinstall_cmds_GCJ \ + postuninstall_cmds_GCJ \ + old_archive_from_expsyms_cmds_GCJ \ + allow_undefined_flag_GCJ \ + no_undefined_flag_GCJ \ + export_symbols_cmds_GCJ \ + hardcode_libdir_flag_spec_GCJ \ + hardcode_libdir_flag_spec_ld_GCJ \ + hardcode_libdir_separator_GCJ \ + hardcode_automatic_GCJ \ + module_cmds_GCJ \ + module_expsym_cmds_GCJ \ + lt_cv_prog_compiler_c_o_GCJ \ + exclude_expsyms_GCJ \ + include_expsyms_GCJ; do + + case $var in + old_archive_cmds_GCJ | \ + old_archive_from_new_cmds_GCJ | \ + archive_cmds_GCJ | \ + archive_expsym_cmds_GCJ | \ + module_cmds_GCJ | \ + module_expsym_cmds_GCJ | \ + old_archive_from_expsyms_cmds_GCJ | \ + export_symbols_cmds_GCJ | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_GCJ + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_GCJ + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_GCJ + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_GCJ + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_GCJ + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_GCJ + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_GCJ +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GCJ + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_GCJ + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_GCJ + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_GCJ + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_GCJ + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_GCJ + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_GCJ +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_GCJ + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_GCJ + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_GCJ +archive_expsym_cmds=$lt_archive_expsym_cmds_GCJ +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_GCJ +module_expsym_cmds=$lt_module_expsym_cmds_GCJ + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_GCJ + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_GCJ + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_GCJ + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_GCJ + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_GCJ + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_GCJ + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_GCJ + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_GCJ + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_GCJ + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_GCJ + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_GCJ + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_GCJ + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_GCJ + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_GCJ + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_GCJ + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_GCJ + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path_GCJ" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_GCJ + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_GCJ + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_GCJ + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_GCJ + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + else + tagname="" + fi + ;; + + RC) + + + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +objext_RC=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +printf "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$rm conftest* + +ac_outfile=conftest.$ac_objext +printf "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$rm conftest* + + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +CC=${RC-"windres"} +compiler=$CC +compiler_RC=$CC +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` + +lt_cv_prog_compiler_c_o_RC=yes + +# The else clause should only fire when bootstrapping the +# libtool distribution, otherwise you forgot to ship ltmain.sh +# with your package, and you will get complaints that there are +# no rules to generate ltmain.sh. +if test -f "$ltmain"; then + # See if we are running on zsh, and set the options which allow our commands through + # without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + # Now quote all the things that may contain metacharacters while being + # careful not to overquote the AC_SUBSTed values. We take copies of the + # variables and quote the copies for generation of the libtool script. + for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ + SED SHELL STRIP \ + libname_spec library_names_spec soname_spec extract_expsyms_cmds \ + old_striplib striplib file_magic_cmd finish_cmds finish_eval \ + deplibs_check_method reload_flag reload_cmds need_locks \ + lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ + lt_cv_sys_global_symbol_to_c_name_address \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + old_postinstall_cmds old_postuninstall_cmds \ + compiler_RC \ + CC_RC \ + LD_RC \ + lt_prog_compiler_wl_RC \ + lt_prog_compiler_pic_RC \ + lt_prog_compiler_static_RC \ + lt_prog_compiler_no_builtin_flag_RC \ + export_dynamic_flag_spec_RC \ + thread_safe_flag_spec_RC \ + whole_archive_flag_spec_RC \ + enable_shared_with_static_runtimes_RC \ + old_archive_cmds_RC \ + old_archive_from_new_cmds_RC \ + predep_objects_RC \ + postdep_objects_RC \ + predeps_RC \ + postdeps_RC \ + compiler_lib_search_path_RC \ + archive_cmds_RC \ + archive_expsym_cmds_RC \ + postinstall_cmds_RC \ + postuninstall_cmds_RC \ + old_archive_from_expsyms_cmds_RC \ + allow_undefined_flag_RC \ + no_undefined_flag_RC \ + export_symbols_cmds_RC \ + hardcode_libdir_flag_spec_RC \ + hardcode_libdir_flag_spec_ld_RC \ + hardcode_libdir_separator_RC \ + hardcode_automatic_RC \ + module_cmds_RC \ + module_expsym_cmds_RC \ + lt_cv_prog_compiler_c_o_RC \ + exclude_expsyms_RC \ + include_expsyms_RC; do + + case $var in + old_archive_cmds_RC | \ + old_archive_from_new_cmds_RC | \ + archive_cmds_RC | \ + archive_expsym_cmds_RC | \ + module_cmds_RC | \ + module_expsym_cmds_RC | \ + old_archive_from_expsyms_cmds_RC | \ + export_symbols_cmds_RC | \ + extract_expsyms_cmds | reload_cmds | finish_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case $lt_echo in + *'\$0 --fallback-echo"') + lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + +cfgfile="$ofile" + + cat <<__EOF__ >> "$cfgfile" +# ### BEGIN LIBTOOL TAG CONFIG: $tagname + +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_RC + +# Whether or not to disallow shared libs when runtime libs are static +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_RC + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# An echo program that does not interpret backslashes. +echo=$lt_echo + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A C compiler. +LTCC=$lt_LTCC + +# LTCC compiler flags. +LTCFLAGS=$lt_LTCFLAGS + +# A language-specific compiler. +CC=$lt_compiler_RC + +# Is the compiler the GNU C compiler? +with_gcc=$GCC_RC + +# An ERE matcher. +EGREP=$lt_EGREP + +# The linker used to build libraries. +LD=$lt_LD_RC + +# Whether we need hard or soft links. +LN_S=$lt_LN_S + +# A BSD-compatible nm program. +NM=$lt_NM + +# A symbol stripping program +STRIP=$lt_STRIP + +# Used to examine libraries when file_magic_cmd begins "file" +MAGIC_CMD=$MAGIC_CMD + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_RC + +# Object file suffix (normally "o"). +objext="$ac_objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Shared library suffix (normally ".so"). +shrext_cmds='$shrext_cmds' + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_RC +pic_mode=$pic_mode + +# What is the maximum length of a command? +max_cmd_len=$lt_cv_sys_max_cmd_len + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_RC + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_RC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_RC + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_RC + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_RC + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$lt_thread_safe_flag_spec_RC + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$lt_RANLIB +old_archive_cmds=$lt_old_archive_cmds_RC +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_RC + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_RC + +# Commands used to build and install a shared archive. +archive_cmds=$lt_archive_cmds_RC +archive_expsym_cmds=$lt_archive_expsym_cmds_RC +postinstall_cmds=$lt_postinstall_cmds +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to build a loadable module (assumed same as above if empty) +module_cmds=$lt_module_cmds_RC +module_expsym_cmds=$lt_module_expsym_cmds_RC + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + +# Dependencies to place before the objects being linked to create a +# shared library. +predep_objects=$lt_predep_objects_RC + +# Dependencies to place after the objects being linked to create a +# shared library. +postdep_objects=$lt_postdep_objects_RC + +# Dependencies to place before the objects being linked to create a +# shared library. +predeps=$lt_predeps_RC + +# Dependencies to place after the objects being linked to create a +# shared library. +postdeps=$lt_postdeps_RC + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_RC + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$lt_file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_RC + +# Flag that forces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_RC + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$lt_finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_RC + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_RC + +# If ld is used when linking, flag to hardcode \$libdir into +# a binary during linking. This must work even if \$libdir does +# not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_RC + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_RC + +# Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct_RC + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L_RC + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_RC + +# Set to yes if building a shared library automatically hardcodes DIR into the library +# and all subsequent libraries and executables linked against it. +hardcode_automatic=$hardcode_automatic_RC + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at relink time. +variables_saved_for_relink="$variables_saved_for_relink" + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_RC + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path_RC" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols_RC + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_RC + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_RC + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_RC + +# ### END LIBTOOL TAG CONFIG: $tagname + +__EOF__ + + +else + # If there is no Makefile yet, we rely on a make rule to execute + # `config.status --recheck' to rerun these tests and create the + # libtool script then. + ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` + if test -f "$ltmain_in"; then + test -f Makefile && make "$ltmain" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + ;; + + *) + { { echo "$as_me:$LINENO: error: Unsupported tag name: $tagname" >&5 +echo "$as_me: error: Unsupported tag name: $tagname" >&2;} + { (exit 1); exit 1; }; } + ;; + esac + + # Append the new tag name to the list of available tags. + if test -n "$tagname" ; then + available_tags="$available_tags $tagname" + fi + fi + done + IFS="$lt_save_ifs" + + # Now substitute the updated list of available tags. + if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then + mv "${ofile}T" "$ofile" + chmod +x "$ofile" + else + rm -f "${ofile}T" + { { echo "$as_me:$LINENO: error: unable to update list of available tagged configurations." >&5 +echo "$as_me: error: unable to update list of available tagged configurations." >&2;} + { (exit 1); exit 1; }; } + fi +fi + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + +# Prevent multiple expansion + + + + + + + + + + + + + + + + + + + + + + +# Check whether --with-valgrind or --without-valgrind was given. +if test "${with_valgrind+set}" = set; then + withval="$with_valgrind" + +fi; + +if test "$with_valgrind" != "" && test "$with_valgrind" != "no"; then + +cat >>confdefs.h <<\_ACEOF +#define INCLUDE_VALGRIND 1 +_ACEOF + + if test -d $with_valgrind; then + CPPFLAGS="$CPPLFAGS -I$with_valgrind/include" + fi +fi + +# Check whether --enable-libcheck or --disable-libcheck was given. +if test "${enable_libcheck+set}" = set; then + enableval="$enable_libcheck" + if test "$enableval" = "no"; then + disable_libcheck=yes + fi + +fi; + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CC" am_compiler_list= + +echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6 +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6 +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for long" >&5 +echo $ECHO_N "checking for long... $ECHO_C" >&6 +if test "${ac_cv_type_long+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((long *) 0) + return 0; +if (sizeof (long)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_long=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_long=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5 +echo "${ECHO_T}$ac_cv_type_long" >&6 + +echo "$as_me:$LINENO: checking size of long" >&5 +echo $ECHO_N "checking size of long... $ECHO_C" >&6 +if test "${ac_cv_sizeof_long+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$ac_cv_type_long" = yes; then + # The cast to unsigned long works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects + # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo= ac_hi= +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr '(' $ac_mid ')' + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_long=$ac_lo;; +'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (long), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } ;; +esac +else + if test "$cross_compiling" = yes; then + { { echo "$as_me:$LINENO: error: internal error: not reached in cross-compile" >&5 +echo "$as_me: error: internal error: not reached in cross-compile" >&2;} + { (exit 1); exit 1; }; } +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +long longval () { return (long) (sizeof (long)); } +unsigned long ulongval () { return (long) (sizeof (long)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + exit (1); + if (((long) (sizeof (long))) < 0) + { + long i = longval (); + if (i != ((long) (sizeof (long)))) + exit (1); + fprintf (f, "%ld\n", i); + } + else + { + unsigned long i = ulongval (); + if (i != ((long) (sizeof (long)))) + exit (1); + fprintf (f, "%lu\n", i); + } + exit (ferror (f) || fclose (f) != 0); + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_long=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (long), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +rm -f conftest.val +else + ac_cv_sizeof_long=0 +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5 +echo "${ECHO_T}$ac_cv_sizeof_long" >&6 +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG $ac_cv_sizeof_long +_ACEOF + + + +if test "$disable_libcheck" != "yes"; then + +echo "$as_me:$LINENO: checking for ibv_get_device_list in -libverbs" >&5 +echo $ECHO_N "checking for ibv_get_device_list in -libverbs... $ECHO_C" >&6 +if test "${ac_cv_lib_ibverbs_ibv_get_device_list+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-libverbs $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char ibv_get_device_list (); +int +main () +{ +ibv_get_device_list (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_ibverbs_ibv_get_device_list=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_ibverbs_ibv_get_device_list=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_ibverbs_ibv_get_device_list" >&5 +echo "${ECHO_T}$ac_cv_lib_ibverbs_ibv_get_device_list" >&6 +if test $ac_cv_lib_ibverbs_ibv_get_device_list = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBIBVERBS 1 +_ACEOF + + LIBS="-libverbs $LIBS" + +else + { { echo "$as_me:$LINENO: error: ibv_get_device_list() not found. librdmacm requires libibverbs." >&5 +echo "$as_me: error: ibv_get_device_list() not found. librdmacm requires libibverbs." >&2;} + { (exit 1); exit 1; }; } +fi + +fi + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +if test "$disable_libcheck" != "yes"; then +if test "${ac_cv_header_infiniband_verbs_h+set}" = set; then + echo "$as_me:$LINENO: checking for infiniband/verbs.h" >&5 +echo $ECHO_N "checking for infiniband/verbs.h... $ECHO_C" >&6 +if test "${ac_cv_header_infiniband_verbs_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_infiniband_verbs_h" >&5 +echo "${ECHO_T}$ac_cv_header_infiniband_verbs_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking infiniband/verbs.h usability" >&5 +echo $ECHO_N "checking infiniband/verbs.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking infiniband/verbs.h presence" >&5 +echo $ECHO_N "checking infiniband/verbs.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: infiniband/verbs.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: infiniband/verbs.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------- ## +## Report this to general@lists.openfabrics.org ## +## -------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for infiniband/verbs.h" >&5 +echo $ECHO_N "checking for infiniband/verbs.h... $ECHO_C" >&6 +if test "${ac_cv_header_infiniband_verbs_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_infiniband_verbs_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_infiniband_verbs_h" >&5 +echo "${ECHO_T}$ac_cv_header_infiniband_verbs_h" >&6 + +fi +if test $ac_cv_header_infiniband_verbs_h = yes; then + : +else + { { echo "$as_me:$LINENO: error: not found. Is libibverbs installed?" >&5 +echo "$as_me: error: not found. Is libibverbs installed?" >&2;} + { (exit 1); exit 1; }; } +fi + + + +if test "$with_valgrind" != "" && test "$with_valgrind" != "no"; then +if test "${ac_cv_header_valgrind_memcheck_h+set}" = set; then + echo "$as_me:$LINENO: checking for valgrind/memcheck.h" >&5 +echo $ECHO_N "checking for valgrind/memcheck.h... $ECHO_C" >&6 +if test "${ac_cv_header_valgrind_memcheck_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_valgrind_memcheck_h" >&5 +echo "${ECHO_T}$ac_cv_header_valgrind_memcheck_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking valgrind/memcheck.h usability" >&5 +echo $ECHO_N "checking valgrind/memcheck.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking valgrind/memcheck.h presence" >&5 +echo $ECHO_N "checking valgrind/memcheck.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: valgrind/memcheck.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: valgrind/memcheck.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## -------------------------------------------- ## +## Report this to general@lists.openfabrics.org ## +## -------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for valgrind/memcheck.h" >&5 +echo $ECHO_N "checking for valgrind/memcheck.h... $ECHO_C" >&6 +if test "${ac_cv_header_valgrind_memcheck_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_valgrind_memcheck_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_valgrind_memcheck_h" >&5 +echo "${ECHO_T}$ac_cv_header_valgrind_memcheck_h" >&6 + +fi +if test $ac_cv_header_valgrind_memcheck_h = yes; then + : +else + { { echo "$as_me:$LINENO: error: valgrind requested but not found." >&5 +echo "$as_me: error: valgrind requested but not found." >&2;} + { (exit 1); exit 1; }; } +fi + + +fi + +fi + +echo "$as_me:$LINENO: checking whether ld accepts --version-script" >&5 +echo $ECHO_N "checking whether ld accepts --version-script... $ECHO_C" >&6 +if test "${ac_cv_version_script+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then + ac_cv_version_script=yes + else + ac_cv_version_script=no + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_version_script" >&5 +echo "${ECHO_T}$ac_cv_version_script" >&6 + + + +if test "$ac_cv_version_script" = "yes"; then + HAVE_LD_VERSION_SCRIPT_TRUE= + HAVE_LD_VERSION_SCRIPT_FALSE='#' +else + HAVE_LD_VERSION_SCRIPT_TRUE='#' + HAVE_LD_VERSION_SCRIPT_FALSE= +fi + + + ac_config_files="$ac_config_files Makefile librdmacm.spec" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${HAVE_LD_VERSION_SCRIPT_TRUE}" && test -z "${HAVE_LD_VERSION_SCRIPT_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"HAVE_LD_VERSION_SCRIPT\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"HAVE_LD_VERSION_SCRIPT\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by librdmacm $as_me 1.0.11, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +librdmacm config.status 1.0.11 +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS section. +# + +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "librdmacm.spec" ) CONFIG_FILES="$CONFIG_FILES librdmacm.spec" ;; + "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@CYGPATH_W@,$CYGPATH_W,;t t +s,@PACKAGE@,$PACKAGE,;t t +s,@VERSION@,$VERSION,;t t +s,@ACLOCAL@,$ACLOCAL,;t t +s,@AUTOCONF@,$AUTOCONF,;t t +s,@AUTOMAKE@,$AUTOMAKE,;t t +s,@AUTOHEADER@,$AUTOHEADER,;t t +s,@MAKEINFO@,$MAKEINFO,;t t +s,@install_sh@,$install_sh,;t t +s,@STRIP@,$STRIP,;t t +s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t +s,@INSTALL_STRIP_PROGRAM@,$INSTALL_STRIP_PROGRAM,;t t +s,@mkdir_p@,$mkdir_p,;t t +s,@AWK@,$AWK,;t t +s,@SET_MAKE@,$SET_MAKE,;t t +s,@am__leading_dot@,$am__leading_dot,;t t +s,@AMTAR@,$AMTAR,;t t +s,@am__tar@,$am__tar,;t t +s,@am__untar@,$am__untar,;t t +s,@build@,$build,;t t +s,@build_cpu@,$build_cpu,;t t +s,@build_vendor@,$build_vendor,;t t +s,@build_os@,$build_os,;t t +s,@host@,$host,;t t +s,@host_cpu@,$host_cpu,;t t +s,@host_vendor@,$host_vendor,;t t +s,@host_os@,$host_os,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@DEPDIR@,$DEPDIR,;t t +s,@am__include@,$am__include,;t t +s,@am__quote@,$am__quote,;t t +s,@AMDEP_TRUE@,$AMDEP_TRUE,;t t +s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t +s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t +s,@CCDEPMODE@,$CCDEPMODE,;t t +s,@am__fastdepCC_TRUE@,$am__fastdepCC_TRUE,;t t +s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t +s,@EGREP@,$EGREP,;t t +s,@LN_S@,$LN_S,;t t +s,@ECHO@,$ECHO,;t t +s,@AR@,$AR,;t t +s,@ac_ct_AR@,$ac_ct_AR,;t t +s,@RANLIB@,$RANLIB,;t t +s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t +s,@CPP@,$CPP,;t t +s,@CXX@,$CXX,;t t +s,@CXXFLAGS@,$CXXFLAGS,;t t +s,@ac_ct_CXX@,$ac_ct_CXX,;t t +s,@CXXDEPMODE@,$CXXDEPMODE,;t t +s,@am__fastdepCXX_TRUE@,$am__fastdepCXX_TRUE,;t t +s,@am__fastdepCXX_FALSE@,$am__fastdepCXX_FALSE,;t t +s,@CXXCPP@,$CXXCPP,;t t +s,@F77@,$F77,;t t +s,@FFLAGS@,$FFLAGS,;t t +s,@ac_ct_F77@,$ac_ct_F77,;t t +s,@LIBTOOL@,$LIBTOOL,;t t +s,@HAVE_LD_VERSION_SCRIPT_TRUE@,$HAVE_LD_VERSION_SCRIPT_TRUE,;t t +s,@HAVE_LD_VERSION_SCRIPT_FALSE@,$HAVE_LD_VERSION_SCRIPT_FALSE,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +# Compute $ac_file's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $ac_file | $ac_file:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $ac_file" >`(dirname $ac_file) 2>/dev/null || +$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X$ac_file : 'X\(//\)[^/]' \| \ + X$ac_file : 'X\(//\)$' \| \ + X$ac_file : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X$ac_file | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'`/stamp-h$_am_stamp_count +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_COMMANDS section. +# +for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue + ac_dest=`echo "$ac_file" | sed 's,:.*,,'` + ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_dir=`(dirname "$ac_dest") 2>/dev/null || +$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_dest" : 'X\(//\)[^/]' \| \ + X"$ac_dest" : 'X\(//\)$' \| \ + X"$ac_dest" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_dest" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 +echo "$as_me: executing $ac_dest commands" >&6;} + case $ac_dest in + depfiles ) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`(dirname "$mf") 2>/dev/null || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`(dirname "$file") 2>/dev/null || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p $dirpart/$fdir + else + as_dir=$dirpart/$fdir + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5 +echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;} + { (exit 1); exit 1; }; }; } + + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + esac +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/contrib/ofed/librdmacm/configure.in b/contrib/ofed/librdmacm/configure.in new file mode 100644 index 000000000000..1122966be61b --- /dev/null +++ b/contrib/ofed/librdmacm/configure.in @@ -0,0 +1,66 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(librdmacm, 1.0.11, general@lists.openfabrics.org) +AC_CONFIG_SRCDIR([src/cma.c]) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(librdmacm, 1.0.11) + +AM_PROG_LIBTOOL + +AC_ARG_WITH([valgrind], + AC_HELP_STRING([--with-valgrind], + [Enable valgrind annotations - default NO])) + +if test "$with_valgrind" != "" && test "$with_valgrind" != "no"; then + AC_DEFINE([INCLUDE_VALGRIND], 1, + [Define to 1 to enable valgrind annotations]) + if test -d $with_valgrind; then + CPPFLAGS="$CPPLFAGS -I$with_valgrind/include" + fi +fi + +AC_ARG_ENABLE(libcheck, [ --disable-libcheck do not test for presence of ib libraries], +[ if test "$enableval" = "no"; then + disable_libcheck=yes + fi +]) + +dnl Checks for programs +AC_PROG_CC + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_CHECK_SIZEOF(long) + +dnl Checks for libraries +if test "$disable_libcheck" != "yes"; then +AC_CHECK_LIB(ibverbs, ibv_get_device_list, [], + AC_MSG_ERROR([ibv_get_device_list() not found. librdmacm requires libibverbs.])) +fi + +dnl Checks for header files. +AC_HEADER_STDC +if test "$disable_libcheck" != "yes"; then +AC_CHECK_HEADER(infiniband/verbs.h, [], + AC_MSG_ERROR([ not found. Is libibverbs installed?])) + +if test "$with_valgrind" != "" && test "$with_valgrind" != "no"; then +AC_CHECK_HEADER(valgrind/memcheck.h, [], + AC_MSG_ERROR([valgrind requested but not found.])) +fi + +fi + +AC_CACHE_CHECK(whether ld accepts --version-script, ac_cv_version_script, + if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then + ac_cv_version_script=yes + else + ac_cv_version_script=no + fi) + +AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$ac_cv_version_script" = "yes") + +AC_CONFIG_FILES([Makefile librdmacm.spec]) +AC_OUTPUT diff --git a/contrib/ofed/librdmacm/examples/cmatose.c b/contrib/ofed/librdmacm/examples/cmatose.c new file mode 100644 index 000000000000..84831ec8b5bc --- /dev/null +++ b/contrib/ofed/librdmacm/examples/cmatose.c @@ -0,0 +1,750 @@ +/* + * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if __BYTE_ORDER == __BIG_ENDIAN +static inline uint64_t cpu_to_be64(uint64_t x) { return x; } +static inline uint32_t cpu_to_be32(uint32_t x) { return x; } +#else +static inline uint64_t cpu_to_be64(uint64_t x) { return bswap_64(x); } +static inline uint32_t cpu_to_be32(uint32_t x) { return bswap_32(x); } +#endif + +struct cmatest_node { + int id; + struct rdma_cm_id *cma_id; + int connected; + struct ibv_pd *pd; + struct ibv_cq *cq[2]; + struct ibv_mr *mr; + void *mem; +}; + +enum CQ_INDEX { + SEND_CQ_INDEX, + RECV_CQ_INDEX +}; + +struct cmatest { + struct rdma_event_channel *channel; + struct cmatest_node *nodes; + int conn_index; + int connects_left; + int disconnects_left; + + struct rdma_addr addr; +}; + +static struct cmatest test; +static int connections = 1; +static int message_size = 100; +static int message_count = 10; +static uint16_t port = 7471; +static uint8_t set_tos = 0; +static uint8_t tos; +static uint8_t migrate = 0; +static char *dst_addr; +static char *src_addr; + +static int create_message(struct cmatest_node *node) +{ + if (!message_size) + message_count = 0; + + if (!message_count) + return 0; + + node->mem = malloc(message_size); + if (!node->mem) { + printf("failed message allocation\n"); + return -1; + } + node->mr = ibv_reg_mr(node->pd, node->mem, message_size, + IBV_ACCESS_LOCAL_WRITE); + if (!node->mr) { + printf("failed to reg MR\n"); + goto err; + } + return 0; +err: + free(node->mem); + return -1; +} + +static int init_node(struct cmatest_node *node) +{ + struct ibv_qp_init_attr init_qp_attr; + int cqe, ret; + + node->pd = ibv_alloc_pd(node->cma_id->verbs); + if (!node->pd) { + ret = -ENOMEM; + printf("cmatose: unable to allocate PD\n"); + goto out; + } + + cqe = message_count ? message_count : 1; + node->cq[SEND_CQ_INDEX] = ibv_create_cq(node->cma_id->verbs, cqe, node, 0, 0); + node->cq[RECV_CQ_INDEX] = ibv_create_cq(node->cma_id->verbs, cqe, node, 0, 0); + if (!node->cq[SEND_CQ_INDEX] || !node->cq[RECV_CQ_INDEX]) { + ret = -ENOMEM; + printf("cmatose: unable to create CQ\n"); + goto out; + } + + memset(&init_qp_attr, 0, sizeof init_qp_attr); + init_qp_attr.cap.max_send_wr = cqe; + init_qp_attr.cap.max_recv_wr = cqe; + init_qp_attr.cap.max_send_sge = 1; + init_qp_attr.cap.max_recv_sge = 1; + init_qp_attr.qp_context = node; + init_qp_attr.sq_sig_all = 1; + init_qp_attr.qp_type = IBV_QPT_RC; + init_qp_attr.send_cq = node->cq[SEND_CQ_INDEX]; + init_qp_attr.recv_cq = node->cq[RECV_CQ_INDEX]; + ret = rdma_create_qp(node->cma_id, node->pd, &init_qp_attr); + if (ret) { + perror("cmatose: unable to create QP"); + goto out; + } + + ret = create_message(node); + if (ret) { + printf("cmatose: failed to create messages: %d\n", ret); + goto out; + } +out: + return ret; +} + +static int post_recvs(struct cmatest_node *node) +{ + struct ibv_recv_wr recv_wr, *recv_failure; + struct ibv_sge sge; + int i, ret = 0; + + if (!message_count) + return 0; + + recv_wr.next = NULL; + recv_wr.sg_list = &sge; + recv_wr.num_sge = 1; + recv_wr.wr_id = (uintptr_t) node; + + sge.length = message_size; + sge.lkey = node->mr->lkey; + sge.addr = (uintptr_t) node->mem; + + for (i = 0; i < message_count && !ret; i++ ) { + ret = ibv_post_recv(node->cma_id->qp, &recv_wr, &recv_failure); + if (ret) { + printf("failed to post receives: %d\n", ret); + break; + } + } + return ret; +} + +static int post_sends(struct cmatest_node *node) +{ + struct ibv_send_wr send_wr, *bad_send_wr; + struct ibv_sge sge; + int i, ret = 0; + + if (!node->connected || !message_count) + return 0; + + send_wr.next = NULL; + send_wr.sg_list = &sge; + send_wr.num_sge = 1; + send_wr.opcode = IBV_WR_SEND; + send_wr.send_flags = 0; + send_wr.wr_id = (unsigned long)node; + + sge.length = message_size; + sge.lkey = node->mr->lkey; + sge.addr = (uintptr_t) node->mem; + + for (i = 0; i < message_count && !ret; i++) { + ret = ibv_post_send(node->cma_id->qp, &send_wr, &bad_send_wr); + if (ret) + printf("failed to post sends: %d\n", ret); + } + return ret; +} + +static void connect_error(void) +{ + test.disconnects_left--; + test.connects_left--; +} + +static int addr_handler(struct cmatest_node *node) +{ + int ret; + + if (set_tos) { + ret = rdma_set_option(node->cma_id, RDMA_OPTION_ID, + RDMA_OPTION_ID_TOS, &tos, sizeof tos); + if (ret) + perror("cmatose: set TOS option failed"); + } + + ret = rdma_resolve_route(node->cma_id, 2000); + if (ret) { + perror("cmatose: resolve route failed"); + connect_error(); + } + return ret; +} + +static int route_handler(struct cmatest_node *node) +{ + struct rdma_conn_param conn_param; + int ret; + + ret = init_node(node); + if (ret) + goto err; + + ret = post_recvs(node); + if (ret) + goto err; + + memset(&conn_param, 0, sizeof conn_param); + conn_param.responder_resources = 1; + conn_param.initiator_depth = 1; + conn_param.retry_count = 5; + ret = rdma_connect(node->cma_id, &conn_param); + if (ret) { + perror("cmatose: failure connecting"); + goto err; + } + return 0; +err: + connect_error(); + return ret; +} + +static int connect_handler(struct rdma_cm_id *cma_id) +{ + struct cmatest_node *node; + struct rdma_conn_param conn_param; + int ret; + + if (test.conn_index == connections) { + ret = -ENOMEM; + goto err1; + } + node = &test.nodes[test.conn_index++]; + + node->cma_id = cma_id; + cma_id->context = node; + + ret = init_node(node); + if (ret) + goto err2; + + ret = post_recvs(node); + if (ret) + goto err2; + + memset(&conn_param, 0, sizeof conn_param); + conn_param.responder_resources = 1; + conn_param.initiator_depth = 1; + ret = rdma_accept(node->cma_id, &conn_param); + if (ret) { + perror("cmatose: failure accepting"); + goto err2; + } + return 0; + +err2: + node->cma_id = NULL; + connect_error(); +err1: + printf("cmatose: failing connection request\n"); + rdma_reject(cma_id, NULL, 0); + return ret; +} + +static int cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) +{ + int ret = 0; + + switch (event->event) { + case RDMA_CM_EVENT_ADDR_RESOLVED: + ret = addr_handler(cma_id->context); + break; + case RDMA_CM_EVENT_ROUTE_RESOLVED: + ret = route_handler(cma_id->context); + break; + case RDMA_CM_EVENT_CONNECT_REQUEST: + ret = connect_handler(cma_id); + break; + case RDMA_CM_EVENT_ESTABLISHED: + ((struct cmatest_node *) cma_id->context)->connected = 1; + test.connects_left--; + break; + case RDMA_CM_EVENT_ADDR_ERROR: + case RDMA_CM_EVENT_ROUTE_ERROR: + case RDMA_CM_EVENT_CONNECT_ERROR: + case RDMA_CM_EVENT_UNREACHABLE: + case RDMA_CM_EVENT_REJECTED: + printf("cmatose: event: %s, error: %d\n", + rdma_event_str(event->event), event->status); + connect_error(); + break; + case RDMA_CM_EVENT_DISCONNECTED: + rdma_disconnect(cma_id); + test.disconnects_left--; + break; + case RDMA_CM_EVENT_DEVICE_REMOVAL: + /* Cleanup will occur after test completes. */ + break; + default: + break; + } + return ret; +} + +static void destroy_node(struct cmatest_node *node) +{ + if (!node->cma_id) + return; + + if (node->cma_id->qp) + rdma_destroy_qp(node->cma_id); + + if (node->cq[SEND_CQ_INDEX]) + ibv_destroy_cq(node->cq[SEND_CQ_INDEX]); + + if (node->cq[RECV_CQ_INDEX]) + ibv_destroy_cq(node->cq[RECV_CQ_INDEX]); + + if (node->mem) { + ibv_dereg_mr(node->mr); + free(node->mem); + } + + if (node->pd) + ibv_dealloc_pd(node->pd); + + /* Destroy the RDMA ID after all device resources */ + rdma_destroy_id(node->cma_id); +} + +static int alloc_nodes(void) +{ + int ret, i; + + test.nodes = malloc(sizeof *test.nodes * connections); + if (!test.nodes) { + printf("cmatose: unable to allocate memory for test nodes\n"); + return -ENOMEM; + } + memset(test.nodes, 0, sizeof *test.nodes * connections); + + for (i = 0; i < connections; i++) { + test.nodes[i].id = i; + if (dst_addr) { + ret = rdma_create_id(test.channel, + &test.nodes[i].cma_id, + &test.nodes[i], RDMA_PS_TCP); + if (ret) + goto err; + } + } + return 0; +err: + while (--i >= 0) + rdma_destroy_id(test.nodes[i].cma_id); + free(test.nodes); + return ret; +} + +static void destroy_nodes(void) +{ + int i; + + for (i = 0; i < connections; i++) + destroy_node(&test.nodes[i]); + free(test.nodes); +} + +static int poll_cqs(enum CQ_INDEX index) +{ + struct ibv_wc wc[8]; + int done, i, ret; + + for (i = 0; i < connections; i++) { + if (!test.nodes[i].connected) + continue; + + for (done = 0; done < message_count; done += ret) { + ret = ibv_poll_cq(test.nodes[i].cq[index], 8, wc); + if (ret < 0) { + printf("cmatose: failed polling CQ: %d\n", ret); + return ret; + } + } + } + return 0; +} + +static int connect_events(void) +{ + struct rdma_cm_event *event; + int err = 0, ret = 0; + + while (test.connects_left && !err) { + err = rdma_get_cm_event(test.channel, &event); + if (!err) { + cma_handler(event->id, event); + rdma_ack_cm_event(event); + } else { + perror("cmatose: failure in rdma_get_cm_event in connect events"); + ret = errno; + } + } + + return ret; +} + +static int disconnect_events(void) +{ + struct rdma_cm_event *event; + int err = 0, ret = 0; + + while (test.disconnects_left && !err) { + err = rdma_get_cm_event(test.channel, &event); + if (!err) { + cma_handler(event->id, event); + rdma_ack_cm_event(event); + } else { + perror("cmatose: failure in rdma_get_cm_event in disconnect events"); + ret = errno; + } + } + + return ret; +} + +static int migrate_channel(struct rdma_cm_id *listen_id) +{ + struct rdma_event_channel *channel; + int i, ret; + + printf("migrating to new event channel\n"); + + channel = rdma_create_event_channel(); + if (!channel) { + perror("cmatose: failed to create event channel"); + return -1; + } + + ret = 0; + if (listen_id) + ret = rdma_migrate_id(listen_id, channel); + + for (i = 0; i < connections && !ret; i++) + ret = rdma_migrate_id(test.nodes[i].cma_id, channel); + + if (!ret) { + rdma_destroy_event_channel(test.channel); + test.channel = channel; + } else + perror("cmatose: failure migrating to channel"); + + return ret; +} + +static int get_addr(char *dst, struct sockaddr *addr) +{ + struct addrinfo *res; + int ret; + + ret = getaddrinfo(dst, NULL, NULL, &res); + if (ret) { + printf("getaddrinfo failed - invalid hostname or IP address\n"); + return ret; + } + + if (res->ai_family == PF_INET) + memcpy(addr, res->ai_addr, sizeof(struct sockaddr_in)); + else if (res->ai_family == PF_INET6) + memcpy(addr, res->ai_addr, sizeof(struct sockaddr_in6)); + else + ret = -1; + + freeaddrinfo(res); + return ret; +} + +static int run_server(void) +{ + struct rdma_cm_id *listen_id; + int i, ret; + + printf("cmatose: starting server\n"); + ret = rdma_create_id(test.channel, &listen_id, &test, RDMA_PS_TCP); + if (ret) { + perror("cmatose: listen request failed"); + return ret; + } + + if (src_addr) { + ret = get_addr(src_addr, &test.addr.src_addr); + if (ret) + goto out; + if (test.addr.src_addr.sa_family == AF_INET) + ((struct sockaddr_in *) &test.addr.src_addr)->sin_port = port; + else + ((struct sockaddr_in6 *) &test.addr.src_addr)->sin6_port = port; + + } else { + test.addr.src_addr.sa_family = PF_INET; + ((struct sockaddr_in *) &test.addr.src_addr)->sin_port = port; + } + + ret = rdma_bind_addr(listen_id, &test.addr.src_addr); + + if (ret) { + perror("cmatose: bind address failed"); + goto out; + } + + ret = rdma_listen(listen_id, 0); + if (ret) { + perror("cmatose: failure trying to listen"); + goto out; + } + + ret = connect_events(); + if (ret) + goto out; + + if (message_count) { + printf("initiating data transfers\n"); + for (i = 0; i < connections; i++) { + ret = post_sends(&test.nodes[i]); + if (ret) + goto out; + } + + printf("completing sends\n"); + ret = poll_cqs(SEND_CQ_INDEX); + if (ret) + goto out; + + printf("receiving data transfers\n"); + ret = poll_cqs(RECV_CQ_INDEX); + if (ret) + goto out; + printf("data transfers complete\n"); + + } + + if (migrate) { + ret = migrate_channel(listen_id); + if (ret) + goto out; + } + + printf("cmatose: disconnecting\n"); + for (i = 0; i < connections; i++) { + if (!test.nodes[i].connected) + continue; + + test.nodes[i].connected = 0; + rdma_disconnect(test.nodes[i].cma_id); + } + + ret = disconnect_events(); + + printf("disconnected\n"); + +out: + rdma_destroy_id(listen_id); + return ret; +} + +static int run_client(void) +{ + int i, ret, ret2; + + printf("cmatose: starting client\n"); + if (src_addr) { + ret = get_addr(src_addr, &test.addr.src_addr); + if (ret) + return ret; + } + + ret = get_addr(dst_addr, &test.addr.dst_addr); + if (ret) + return ret; + + if (test.addr.dst_addr.sa_family == AF_INET) + ((struct sockaddr_in *) &test.addr.dst_addr)->sin_port = port; + else + ((struct sockaddr_in6 *) &test.addr.dst_addr)->sin6_port = port; + + printf("cmatose: connecting\n"); + for (i = 0; i < connections; i++) { + ret = rdma_resolve_addr(test.nodes[i].cma_id, + src_addr ? &test.addr.src_addr : NULL, + &test.addr.dst_addr, 2000); + if (ret) { + perror("cmatose: failure getting addr"); + connect_error(); + return ret; + } + } + + ret = connect_events(); + if (ret) + goto disc; + + if (message_count) { + printf("receiving data transfers\n"); + ret = poll_cqs(RECV_CQ_INDEX); + if (ret) + goto disc; + + printf("sending replies\n"); + for (i = 0; i < connections; i++) { + ret = post_sends(&test.nodes[i]); + if (ret) + goto disc; + } + + printf("data transfers complete\n"); + } + + ret = 0; + + if (migrate) { + ret = migrate_channel(NULL); + if (ret) + goto out; + } +disc: + ret2 = disconnect_events(); + if (ret2) + ret = ret2; +out: + return ret; +} + +int main(int argc, char **argv) +{ + int op, ret; + + while ((op = getopt(argc, argv, "s:b:c:C:S:t:p:m")) != -1) { + switch (op) { + case 's': + dst_addr = optarg; + break; + case 'b': + src_addr = optarg; + break; + case 'c': + connections = atoi(optarg); + break; + case 'C': + message_count = atoi(optarg); + break; + case 'S': + message_size = atoi(optarg); + break; + case 't': + set_tos = 1; + tos = (uint8_t) atoi(optarg); + break; + case 'p': + port = atoi(optarg); + break; + case 'm': + migrate = 1; + break; + default: + printf("usage: %s\n", argv[0]); + printf("\t[-s server_address]\n"); + printf("\t[-b bind_address]\n"); + printf("\t[-c connections]\n"); + printf("\t[-C message_count]\n"); + printf("\t[-S message_size]\n"); + printf("\t[-t type_of_service]\n"); + printf("\t[-p port_number]\n"); + printf("\t[-m(igrate)]\n"); + exit(1); + } + } + + test.connects_left = connections; + test.disconnects_left = connections; + + test.channel = rdma_create_event_channel(); + if (!test.channel) { + printf("failed to create event channel\n"); + exit(1); + } + + if (alloc_nodes()) + exit(1); + + if (dst_addr) + ret = run_client(); + else + ret = run_server(); + + printf("test complete\n"); + destroy_nodes(); + rdma_destroy_event_channel(test.channel); + + printf("return status %d\n", ret); + return ret; +} diff --git a/contrib/ofed/librdmacm/examples/mckey.c b/contrib/ofed/librdmacm/examples/mckey.c new file mode 100644 index 000000000000..ddc3495065a2 --- /dev/null +++ b/contrib/ofed/librdmacm/examples/mckey.c @@ -0,0 +1,616 @@ +/* + * Copyright (c) 2005-2007 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct cmatest_node { + int id; + struct rdma_cm_id *cma_id; + int connected; + struct ibv_pd *pd; + struct ibv_cq *cq; + struct ibv_mr *mr; + struct ibv_ah *ah; + uint32_t remote_qpn; + uint32_t remote_qkey; + void *mem; +}; + +struct cmatest { + struct rdma_event_channel *channel; + pthread_t cmathread; + struct cmatest_node *nodes; + int conn_index; + int connects_left; + + struct sockaddr_in6 dst_in; + struct sockaddr *dst_addr; + struct sockaddr_in6 src_in; + struct sockaddr *src_addr; +}; + +static struct cmatest test; +static int connections = 1; +static int message_size = 100; +static int message_count = 10; +static int is_sender; +static int unmapped_addr; +static char *dst_addr; +static char *src_addr; +static enum rdma_port_space port_space = RDMA_PS_UDP; + +static int create_message(struct cmatest_node *node) +{ + if (!message_size) + message_count = 0; + + if (!message_count) + return 0; + + node->mem = malloc(message_size + sizeof(struct ibv_grh)); + if (!node->mem) { + printf("failed message allocation\n"); + return -1; + } + node->mr = ibv_reg_mr(node->pd, node->mem, + message_size + sizeof(struct ibv_grh), + IBV_ACCESS_LOCAL_WRITE); + if (!node->mr) { + printf("failed to reg MR\n"); + goto err; + } + return 0; +err: + free(node->mem); + return -1; +} + +static int verify_test_params(struct cmatest_node *node) +{ + struct ibv_port_attr port_attr; + int ret; + + ret = ibv_query_port(node->cma_id->verbs, node->cma_id->port_num, + &port_attr); + if (ret) + return ret; + + if (message_count && message_size > (1 << (port_attr.active_mtu + 7))) { + printf("mckey: message_size %d is larger than active mtu %d\n", + message_size, 1 << (port_attr.active_mtu + 7)); + return -EINVAL; + } + + return 0; +} + +static int init_node(struct cmatest_node *node) +{ + struct ibv_qp_init_attr init_qp_attr; + int cqe, ret; + + node->pd = ibv_alloc_pd(node->cma_id->verbs); + if (!node->pd) { + ret = -ENOMEM; + printf("mckey: unable to allocate PD\n"); + goto out; + } + + cqe = message_count ? message_count * 2 : 2; + node->cq = ibv_create_cq(node->cma_id->verbs, cqe, node, 0, 0); + if (!node->cq) { + ret = -ENOMEM; + printf("mckey: unable to create CQ\n"); + goto out; + } + + memset(&init_qp_attr, 0, sizeof init_qp_attr); + init_qp_attr.cap.max_send_wr = message_count ? message_count : 1; + init_qp_attr.cap.max_recv_wr = message_count ? message_count : 1; + init_qp_attr.cap.max_send_sge = 1; + init_qp_attr.cap.max_recv_sge = 1; + init_qp_attr.qp_context = node; + init_qp_attr.sq_sig_all = 0; + init_qp_attr.qp_type = IBV_QPT_UD; + init_qp_attr.send_cq = node->cq; + init_qp_attr.recv_cq = node->cq; + ret = rdma_create_qp(node->cma_id, node->pd, &init_qp_attr); + if (ret) { + perror("mckey: unable to create QP"); + goto out; + } + + ret = create_message(node); + if (ret) { + printf("mckey: failed to create messages: %d\n", ret); + goto out; + } +out: + return ret; +} + +static int post_recvs(struct cmatest_node *node) +{ + struct ibv_recv_wr recv_wr, *recv_failure; + struct ibv_sge sge; + int i, ret = 0; + + if (!message_count) + return 0; + + recv_wr.next = NULL; + recv_wr.sg_list = &sge; + recv_wr.num_sge = 1; + recv_wr.wr_id = (uintptr_t) node; + + sge.length = message_size + sizeof(struct ibv_grh); + sge.lkey = node->mr->lkey; + sge.addr = (uintptr_t) node->mem; + + for (i = 0; i < message_count && !ret; i++ ) { + ret = ibv_post_recv(node->cma_id->qp, &recv_wr, &recv_failure); + if (ret) { + printf("failed to post receives: %d\n", ret); + break; + } + } + return ret; +} + +static int post_sends(struct cmatest_node *node, int signal_flag) +{ + struct ibv_send_wr send_wr, *bad_send_wr; + struct ibv_sge sge; + int i, ret = 0; + + if (!node->connected || !message_count) + return 0; + + send_wr.next = NULL; + send_wr.sg_list = &sge; + send_wr.num_sge = 1; + send_wr.opcode = IBV_WR_SEND_WITH_IMM; + send_wr.send_flags = signal_flag; + send_wr.wr_id = (unsigned long)node; + send_wr.imm_data = htonl(node->cma_id->qp->qp_num); + + send_wr.wr.ud.ah = node->ah; + send_wr.wr.ud.remote_qpn = node->remote_qpn; + send_wr.wr.ud.remote_qkey = node->remote_qkey; + + sge.length = message_size; + sge.lkey = node->mr->lkey; + sge.addr = (uintptr_t) node->mem; + + for (i = 0; i < message_count && !ret; i++) { + ret = ibv_post_send(node->cma_id->qp, &send_wr, &bad_send_wr); + if (ret) + printf("failed to post sends: %d\n", ret); + } + return ret; +} + +static void connect_error(void) +{ + test.connects_left--; +} + +static int addr_handler(struct cmatest_node *node) +{ + int ret; + + ret = verify_test_params(node); + if (ret) + goto err; + + ret = init_node(node); + if (ret) + goto err; + + if (!is_sender) { + ret = post_recvs(node); + if (ret) + goto err; + } + + ret = rdma_join_multicast(node->cma_id, test.dst_addr, node); + if (ret) { + perror("mckey: failure joining"); + goto err; + } + return 0; +err: + connect_error(); + return ret; +} + +static int join_handler(struct cmatest_node *node, + struct rdma_ud_param *param) +{ + char buf[40]; + + inet_ntop(AF_INET6, param->ah_attr.grh.dgid.raw, buf, 40); + printf("mckey: joined dgid: %s mlid 0x%x sl %d\n", buf, + param->ah_attr.dlid, param->ah_attr.sl); + + node->remote_qpn = param->qp_num; + node->remote_qkey = param->qkey; + node->ah = ibv_create_ah(node->pd, ¶m->ah_attr); + if (!node->ah) { + printf("mckey: failure creating address handle\n"); + goto err; + } + + node->connected = 1; + test.connects_left--; + return 0; +err: + connect_error(); + return -1; +} + +static int cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) +{ + int ret = 0; + + switch (event->event) { + case RDMA_CM_EVENT_ADDR_RESOLVED: + ret = addr_handler(cma_id->context); + break; + case RDMA_CM_EVENT_MULTICAST_JOIN: + ret = join_handler(cma_id->context, &event->param.ud); + break; + case RDMA_CM_EVENT_ADDR_ERROR: + case RDMA_CM_EVENT_ROUTE_ERROR: + case RDMA_CM_EVENT_MULTICAST_ERROR: + printf("mckey: event: %s, error: %d\n", + rdma_event_str(event->event), event->status); + connect_error(); + ret = event->status; + break; + case RDMA_CM_EVENT_DEVICE_REMOVAL: + /* Cleanup will occur after test completes. */ + break; + default: + break; + } + return ret; +} + +static void *cma_thread(void *arg) +{ + struct rdma_cm_event *event; + int ret; + + while (1) { + ret = rdma_get_cm_event(test.channel, &event); + if (ret) { + perror("rdma_get_cm_event"); + break; + } + + switch (event->event) { + case RDMA_CM_EVENT_MULTICAST_ERROR: + case RDMA_CM_EVENT_ADDR_CHANGE: + printf("mckey: event: %s, status: %d\n", + rdma_event_str(event->event), event->status); + break; + default: + break; + } + + rdma_ack_cm_event(event); + } + return NULL; +} + +static void destroy_node(struct cmatest_node *node) +{ + if (!node->cma_id) + return; + + if (node->ah) + ibv_destroy_ah(node->ah); + + if (node->cma_id->qp) + rdma_destroy_qp(node->cma_id); + + if (node->cq) + ibv_destroy_cq(node->cq); + + if (node->mem) { + ibv_dereg_mr(node->mr); + free(node->mem); + } + + if (node->pd) + ibv_dealloc_pd(node->pd); + + /* Destroy the RDMA ID after all device resources */ + rdma_destroy_id(node->cma_id); +} + +static int alloc_nodes(void) +{ + int ret, i; + + test.nodes = malloc(sizeof *test.nodes * connections); + if (!test.nodes) { + printf("mckey: unable to allocate memory for test nodes\n"); + return -ENOMEM; + } + memset(test.nodes, 0, sizeof *test.nodes * connections); + + for (i = 0; i < connections; i++) { + test.nodes[i].id = i; + ret = rdma_create_id(test.channel, &test.nodes[i].cma_id, + &test.nodes[i], port_space); + if (ret) + goto err; + } + return 0; +err: + while (--i >= 0) + rdma_destroy_id(test.nodes[i].cma_id); + free(test.nodes); + return ret; +} + +static void destroy_nodes(void) +{ + int i; + + for (i = 0; i < connections; i++) + destroy_node(&test.nodes[i]); + free(test.nodes); +} + +static int poll_cqs(void) +{ + struct ibv_wc wc[8]; + int done, i, ret; + + for (i = 0; i < connections; i++) { + if (!test.nodes[i].connected) + continue; + + for (done = 0; done < message_count; done += ret) { + ret = ibv_poll_cq(test.nodes[i].cq, 8, wc); + if (ret < 0) { + printf("mckey: failed polling CQ: %d\n", ret); + return ret; + } + } + } + return 0; +} + +static int connect_events(void) +{ + struct rdma_cm_event *event; + int ret = 0; + + while (test.connects_left && !ret) { + ret = rdma_get_cm_event(test.channel, &event); + if (!ret) { + ret = cma_handler(event->id, event); + rdma_ack_cm_event(event); + } + } + return ret; +} + +static int get_addr(char *dst, struct sockaddr *addr) +{ + struct addrinfo *res; + int ret; + + ret = getaddrinfo(dst, NULL, NULL, &res); + if (ret) { + printf("getaddrinfo failed - invalid hostname or IP address\n"); + return ret; + } + + memcpy(addr, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + return ret; +} + +static int run(void) +{ + int i, ret; + + printf("mckey: starting %s\n", is_sender ? "client" : "server"); + if (src_addr) { + ret = get_addr(src_addr, (struct sockaddr *) &test.src_in); + if (ret) + return ret; + } + + ret = get_addr(dst_addr, (struct sockaddr *) &test.dst_in); + if (ret) + return ret; + + printf("mckey: joining\n"); + for (i = 0; i < connections; i++) { + if (src_addr) { + ret = rdma_bind_addr(test.nodes[i].cma_id, + test.src_addr); + if (ret) { + perror("mckey: addr bind failure"); + connect_error(); + return ret; + } + } + + if (unmapped_addr) + ret = addr_handler(&test.nodes[i]); + else + ret = rdma_resolve_addr(test.nodes[i].cma_id, + test.src_addr, test.dst_addr, + 2000); + if (ret) { + perror("mckey: resolve addr failure"); + connect_error(); + return ret; + } + } + + ret = connect_events(); + if (ret) + goto out; + + pthread_create(&test.cmathread, NULL, cma_thread, NULL); + + /* + * Pause to give SM chance to configure switches. We don't want to + * handle reliability issue in this simple test program. + */ + sleep(3); + + if (message_count) { + if (is_sender) { + printf("initiating data transfers\n"); + for (i = 0; i < connections; i++) { + ret = post_sends(&test.nodes[i], 0); + if (ret) + goto out; + } + } else { + printf("receiving data transfers\n"); + ret = poll_cqs(); + if (ret) + goto out; + } + printf("data transfers complete\n"); + } +out: + for (i = 0; i < connections; i++) { + ret = rdma_leave_multicast(test.nodes[i].cma_id, + test.dst_addr); + if (ret) + perror("mckey: failure leaving"); + } + return ret; +} + +int main(int argc, char **argv) +{ + int op, ret; + + + while ((op = getopt(argc, argv, "m:M:sb:c:C:S:p:")) != -1) { + switch (op) { + case 'm': + dst_addr = optarg; + break; + case 'M': + unmapped_addr = 1; + dst_addr = optarg; + break; + case 's': + is_sender = 1; + break; + case 'b': + src_addr = optarg; + test.src_addr = (struct sockaddr *) &test.src_in; + break; + case 'c': + connections = atoi(optarg); + break; + case 'C': + message_count = atoi(optarg); + break; + case 'S': + message_size = atoi(optarg); + break; + case 'p': + port_space = strtol(optarg, NULL, 0); + break; + default: + printf("usage: %s\n", argv[0]); + printf("\t-m multicast_address\n"); + printf("\t[-M unmapped_multicast_address]\n" + "\t replaces -m and requires -b\n"); + printf("\t[-s(ender)]\n"); + printf("\t[-b bind_address]\n"); + printf("\t[-c connections]\n"); + printf("\t[-C message_count]\n"); + printf("\t[-S message_size]\n"); + printf("\t[-p port_space - %#x for UDP (default), " + "%#x for IPOIB]\n", RDMA_PS_UDP, RDMA_PS_IPOIB); + exit(1); + } + } + + if (unmapped_addr && !src_addr) { + printf("unmapped multicast address requires binding " + "to source address\n"); + exit(1); + } + + test.dst_addr = (struct sockaddr *) &test.dst_in; + test.connects_left = connections; + + test.channel = rdma_create_event_channel(); + if (!test.channel) { + perror("failed to create event channel"); + exit(1); + } + + if (alloc_nodes()) + exit(1); + + ret = run(); + + printf("test complete\n"); + destroy_nodes(); + rdma_destroy_event_channel(test.channel); + + printf("return status %d\n", ret); + return ret; +} diff --git a/contrib/ofed/librdmacm/examples/rping.c b/contrib/ofed/librdmacm/examples/rping.c new file mode 100644 index 000000000000..985f642e5182 --- /dev/null +++ b/contrib/ofed/librdmacm/examples/rping.c @@ -0,0 +1,1222 @@ +/* + * Copyright (c) 2005 Ammasso, Inc. All rights reserved. + * Copyright (c) 2006 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int debug = 0; +#define DEBUG_LOG if (debug) printf + +/* + * rping "ping/pong" loop: + * client sends source rkey/addr/len + * server receives source rkey/add/len + * server rdma reads "ping" data from source + * server sends "go ahead" on rdma read completion + * client sends sink rkey/addr/len + * server receives sink rkey/addr/len + * server rdma writes "pong" data to sink + * server sends "go ahead" on rdma write completion + * + */ + +/* + * These states are used to signal events between the completion handler + * and the main client or server thread. + * + * Once CONNECTED, they cycle through RDMA_READ_ADV, RDMA_WRITE_ADV, + * and RDMA_WRITE_COMPLETE for each ping. + */ +enum test_state { + IDLE = 1, + CONNECT_REQUEST, + ADDR_RESOLVED, + ROUTE_RESOLVED, + CONNECTED, + RDMA_READ_ADV, + RDMA_READ_COMPLETE, + RDMA_WRITE_ADV, + RDMA_WRITE_COMPLETE, + ERROR +}; + +struct rping_rdma_info { + uint64_t buf; + uint32_t rkey; + uint32_t size; +}; + +/* + * Default max buffer size for IO... + */ +#define RPING_BUFSIZE 64*1024 +#define RPING_SQ_DEPTH 16 + +/* Default string for print data and + * minimum buffer size + */ +#define _stringify( _x ) # _x +#define stringify( _x ) _stringify( _x ) + +#define RPING_MSG_FMT "rdma-ping-%d: " +#define RPING_MIN_BUFSIZE sizeof(stringify(INT_MAX)) + sizeof(RPING_MSG_FMT) + +/* + * Control block struct. + */ +struct rping_cb { + int server; /* 0 iff client */ + pthread_t cqthread; + pthread_t persistent_server_thread; + struct ibv_comp_channel *channel; + struct ibv_cq *cq; + struct ibv_pd *pd; + struct ibv_qp *qp; + + struct ibv_recv_wr rq_wr; /* recv work request record */ + struct ibv_sge recv_sgl; /* recv single SGE */ + struct rping_rdma_info recv_buf;/* malloc'd buffer */ + struct ibv_mr *recv_mr; /* MR associated with this buffer */ + + struct ibv_send_wr sq_wr; /* send work request record */ + struct ibv_sge send_sgl; + struct rping_rdma_info send_buf;/* single send buf */ + struct ibv_mr *send_mr; + + struct ibv_send_wr rdma_sq_wr; /* rdma work request record */ + struct ibv_sge rdma_sgl; /* rdma single SGE */ + char *rdma_buf; /* used as rdma sink */ + struct ibv_mr *rdma_mr; + + uint32_t remote_rkey; /* remote guys RKEY */ + uint64_t remote_addr; /* remote guys TO */ + uint32_t remote_len; /* remote guys LEN */ + + char *start_buf; /* rdma read src */ + struct ibv_mr *start_mr; + + enum test_state state; /* used for cond/signalling */ + sem_t sem; + + struct sockaddr_storage sin; + uint16_t port; /* dst port in NBO */ + int verbose; /* verbose logging */ + int count; /* ping count */ + int size; /* ping data size */ + int validate; /* validate ping data */ + + /* CM stuff */ + pthread_t cmthread; + struct rdma_event_channel *cm_channel; + struct rdma_cm_id *cm_id; /* connection on client side,*/ + /* listener on service side. */ + struct rdma_cm_id *child_cm_id; /* connection on server side */ +}; + +static int rping_cma_event_handler(struct rdma_cm_id *cma_id, + struct rdma_cm_event *event) +{ + int ret = 0; + struct rping_cb *cb = cma_id->context; + + DEBUG_LOG("cma_event type %s cma_id %p (%s)\n", + rdma_event_str(event->event), cma_id, + (cma_id == cb->cm_id) ? "parent" : "child"); + + switch (event->event) { + case RDMA_CM_EVENT_ADDR_RESOLVED: + cb->state = ADDR_RESOLVED; + ret = rdma_resolve_route(cma_id, 2000); + if (ret) { + cb->state = ERROR; + perror("rdma_resolve_route"); + sem_post(&cb->sem); + } + break; + + case RDMA_CM_EVENT_ROUTE_RESOLVED: + cb->state = ROUTE_RESOLVED; + sem_post(&cb->sem); + break; + + case RDMA_CM_EVENT_CONNECT_REQUEST: + cb->state = CONNECT_REQUEST; + cb->child_cm_id = cma_id; + DEBUG_LOG("child cma %p\n", cb->child_cm_id); + sem_post(&cb->sem); + break; + + case RDMA_CM_EVENT_ESTABLISHED: + DEBUG_LOG("ESTABLISHED\n"); + + /* + * Server will wake up when first RECV completes. + */ + if (!cb->server) { + cb->state = CONNECTED; + } + sem_post(&cb->sem); + break; + + case RDMA_CM_EVENT_ADDR_ERROR: + case RDMA_CM_EVENT_ROUTE_ERROR: + case RDMA_CM_EVENT_CONNECT_ERROR: + case RDMA_CM_EVENT_UNREACHABLE: + case RDMA_CM_EVENT_REJECTED: + fprintf(stderr, "cma event %s, error %d\n", + rdma_event_str(event->event), event->status); + sem_post(&cb->sem); + ret = -1; + break; + + case RDMA_CM_EVENT_DISCONNECTED: + fprintf(stderr, "%s DISCONNECT EVENT...\n", + cb->server ? "server" : "client"); + sem_post(&cb->sem); + break; + + case RDMA_CM_EVENT_DEVICE_REMOVAL: + fprintf(stderr, "cma detected device removal!!!!\n"); + ret = -1; + break; + + default: + fprintf(stderr, "unhandled event: %s, ignoring\n", + rdma_event_str(event->event)); + break; + } + + return ret; +} + +static int server_recv(struct rping_cb *cb, struct ibv_wc *wc) +{ + if (wc->byte_len != sizeof(cb->recv_buf)) { + fprintf(stderr, "Received bogus data, size %d\n", wc->byte_len); + return -1; + } + + cb->remote_rkey = ntohl(cb->recv_buf.rkey); + cb->remote_addr = ntohll(cb->recv_buf.buf); + cb->remote_len = ntohl(cb->recv_buf.size); + DEBUG_LOG("Received rkey %x addr %" PRIx64 " len %d from peer\n", + cb->remote_rkey, cb->remote_addr, cb->remote_len); + + if (cb->state <= CONNECTED || cb->state == RDMA_WRITE_COMPLETE) + cb->state = RDMA_READ_ADV; + else + cb->state = RDMA_WRITE_ADV; + + return 0; +} + +static int client_recv(struct rping_cb *cb, struct ibv_wc *wc) +{ + if (wc->byte_len != sizeof(cb->recv_buf)) { + fprintf(stderr, "Received bogus data, size %d\n", wc->byte_len); + return -1; + } + + if (cb->state == RDMA_READ_ADV) + cb->state = RDMA_WRITE_ADV; + else + cb->state = RDMA_WRITE_COMPLETE; + + return 0; +} + +static int rping_cq_event_handler(struct rping_cb *cb) +{ + struct ibv_wc wc; + struct ibv_recv_wr *bad_wr; + int ret; + + while ((ret = ibv_poll_cq(cb->cq, 1, &wc)) == 1) { + ret = 0; + + if (wc.status) { + fprintf(stderr, "cq completion failed status %d\n", + wc.status); + if (wc.status != IBV_WC_WR_FLUSH_ERR) + ret = -1; + goto error; + } + + switch (wc.opcode) { + case IBV_WC_SEND: + DEBUG_LOG("send completion\n"); + break; + + case IBV_WC_RDMA_WRITE: + DEBUG_LOG("rdma write completion\n"); + cb->state = RDMA_WRITE_COMPLETE; + sem_post(&cb->sem); + break; + + case IBV_WC_RDMA_READ: + DEBUG_LOG("rdma read completion\n"); + cb->state = RDMA_READ_COMPLETE; + sem_post(&cb->sem); + break; + + case IBV_WC_RECV: + DEBUG_LOG("recv completion\n"); + ret = cb->server ? server_recv(cb, &wc) : + client_recv(cb, &wc); + if (ret) { + fprintf(stderr, "recv wc error: %d\n", ret); + goto error; + } + + ret = ibv_post_recv(cb->qp, &cb->rq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "post recv error: %d\n", ret); + goto error; + } + sem_post(&cb->sem); + break; + + default: + DEBUG_LOG("unknown!!!!! completion\n"); + ret = -1; + goto error; + } + } + if (ret) { + fprintf(stderr, "poll error %d\n", ret); + goto error; + } + return 0; + +error: + cb->state = ERROR; + sem_post(&cb->sem); + return ret; +} + +static int rping_accept(struct rping_cb *cb) +{ + struct rdma_conn_param conn_param; + int ret; + + DEBUG_LOG("accepting client connection request\n"); + + memset(&conn_param, 0, sizeof conn_param); + conn_param.responder_resources = 1; + conn_param.initiator_depth = 1; + + ret = rdma_accept(cb->child_cm_id, &conn_param); + if (ret) { + perror("rdma_accept"); + return ret; + } + + sem_wait(&cb->sem); + if (cb->state == ERROR) { + fprintf(stderr, "wait for CONNECTED state %d\n", cb->state); + return -1; + } + return 0; +} + +static void rping_setup_wr(struct rping_cb *cb) +{ + cb->recv_sgl.addr = (uint64_t) (unsigned long) &cb->recv_buf; + cb->recv_sgl.length = sizeof cb->recv_buf; + cb->recv_sgl.lkey = cb->recv_mr->lkey; + cb->rq_wr.sg_list = &cb->recv_sgl; + cb->rq_wr.num_sge = 1; + + cb->send_sgl.addr = (uint64_t) (unsigned long) &cb->send_buf; + cb->send_sgl.length = sizeof cb->send_buf; + cb->send_sgl.lkey = cb->send_mr->lkey; + + cb->sq_wr.opcode = IBV_WR_SEND; + cb->sq_wr.send_flags = IBV_SEND_SIGNALED; + cb->sq_wr.sg_list = &cb->send_sgl; + cb->sq_wr.num_sge = 1; + + cb->rdma_sgl.addr = (uint64_t) (unsigned long) cb->rdma_buf; + cb->rdma_sgl.lkey = cb->rdma_mr->lkey; + cb->rdma_sq_wr.send_flags = IBV_SEND_SIGNALED; + cb->rdma_sq_wr.sg_list = &cb->rdma_sgl; + cb->rdma_sq_wr.num_sge = 1; +} + +static int rping_setup_buffers(struct rping_cb *cb) +{ + int ret; + + DEBUG_LOG("rping_setup_buffers called on cb %p\n", cb); + + cb->recv_mr = ibv_reg_mr(cb->pd, &cb->recv_buf, sizeof cb->recv_buf, + IBV_ACCESS_LOCAL_WRITE); + if (!cb->recv_mr) { + fprintf(stderr, "recv_buf reg_mr failed\n"); + return errno; + } + + cb->send_mr = ibv_reg_mr(cb->pd, &cb->send_buf, sizeof cb->send_buf, 0); + if (!cb->send_mr) { + fprintf(stderr, "send_buf reg_mr failed\n"); + ret = errno; + goto err1; + } + + cb->rdma_buf = malloc(cb->size); + if (!cb->rdma_buf) { + fprintf(stderr, "rdma_buf malloc failed\n"); + ret = -ENOMEM; + goto err2; + } + + cb->rdma_mr = ibv_reg_mr(cb->pd, cb->rdma_buf, cb->size, + IBV_ACCESS_LOCAL_WRITE | + IBV_ACCESS_REMOTE_READ | + IBV_ACCESS_REMOTE_WRITE); + if (!cb->rdma_mr) { + fprintf(stderr, "rdma_buf reg_mr failed\n"); + ret = errno; + goto err3; + } + + if (!cb->server) { + cb->start_buf = malloc(cb->size); + if (!cb->start_buf) { + fprintf(stderr, "start_buf malloc failed\n"); + ret = -ENOMEM; + goto err4; + } + + cb->start_mr = ibv_reg_mr(cb->pd, cb->start_buf, cb->size, + IBV_ACCESS_LOCAL_WRITE | + IBV_ACCESS_REMOTE_READ | + IBV_ACCESS_REMOTE_WRITE); + if (!cb->start_mr) { + fprintf(stderr, "start_buf reg_mr failed\n"); + ret = errno; + goto err5; + } + } + + rping_setup_wr(cb); + DEBUG_LOG("allocated & registered buffers...\n"); + return 0; + +err5: + free(cb->start_buf); +err4: + ibv_dereg_mr(cb->rdma_mr); +err3: + free(cb->rdma_buf); +err2: + ibv_dereg_mr(cb->send_mr); +err1: + ibv_dereg_mr(cb->recv_mr); + return ret; +} + +static void rping_free_buffers(struct rping_cb *cb) +{ + DEBUG_LOG("rping_free_buffers called on cb %p\n", cb); + ibv_dereg_mr(cb->recv_mr); + ibv_dereg_mr(cb->send_mr); + ibv_dereg_mr(cb->rdma_mr); + free(cb->rdma_buf); + if (!cb->server) { + ibv_dereg_mr(cb->start_mr); + free(cb->start_buf); + } +} + +static int rping_create_qp(struct rping_cb *cb) +{ + struct ibv_qp_init_attr init_attr; + int ret; + + memset(&init_attr, 0, sizeof(init_attr)); + init_attr.cap.max_send_wr = RPING_SQ_DEPTH; + init_attr.cap.max_recv_wr = 2; + init_attr.cap.max_recv_sge = 1; + init_attr.cap.max_send_sge = 1; + init_attr.qp_type = IBV_QPT_RC; + init_attr.send_cq = cb->cq; + init_attr.recv_cq = cb->cq; + + if (cb->server) { + ret = rdma_create_qp(cb->child_cm_id, cb->pd, &init_attr); + if (!ret) + cb->qp = cb->child_cm_id->qp; + } else { + ret = rdma_create_qp(cb->cm_id, cb->pd, &init_attr); + if (!ret) + cb->qp = cb->cm_id->qp; + } + + return ret; +} + +static void rping_free_qp(struct rping_cb *cb) +{ + ibv_destroy_qp(cb->qp); + ibv_destroy_cq(cb->cq); + ibv_destroy_comp_channel(cb->channel); + ibv_dealloc_pd(cb->pd); +} + +static int rping_setup_qp(struct rping_cb *cb, struct rdma_cm_id *cm_id) +{ + int ret; + + cb->pd = ibv_alloc_pd(cm_id->verbs); + if (!cb->pd) { + fprintf(stderr, "ibv_alloc_pd failed\n"); + return errno; + } + DEBUG_LOG("created pd %p\n", cb->pd); + + cb->channel = ibv_create_comp_channel(cm_id->verbs); + if (!cb->channel) { + fprintf(stderr, "ibv_create_comp_channel failed\n"); + ret = errno; + goto err1; + } + DEBUG_LOG("created channel %p\n", cb->channel); + + cb->cq = ibv_create_cq(cm_id->verbs, RPING_SQ_DEPTH * 2, cb, + cb->channel, 0); + if (!cb->cq) { + fprintf(stderr, "ibv_create_cq failed\n"); + ret = errno; + goto err2; + } + DEBUG_LOG("created cq %p\n", cb->cq); + + ret = ibv_req_notify_cq(cb->cq, 0); + if (ret) { + fprintf(stderr, "ibv_create_cq failed\n"); + ret = errno; + goto err3; + } + + ret = rping_create_qp(cb); + if (ret) { + perror("rdma_create_qp"); + goto err3; + } + DEBUG_LOG("created qp %p\n", cb->qp); + return 0; + +err3: + ibv_destroy_cq(cb->cq); +err2: + ibv_destroy_comp_channel(cb->channel); +err1: + ibv_dealloc_pd(cb->pd); + return ret; +} + +static void *cm_thread(void *arg) +{ + struct rping_cb *cb = arg; + struct rdma_cm_event *event; + int ret; + + while (1) { + ret = rdma_get_cm_event(cb->cm_channel, &event); + if (ret) { + perror("rdma_get_cm_event"); + exit(ret); + } + ret = rping_cma_event_handler(event->id, event); + rdma_ack_cm_event(event); + if (ret) + exit(ret); + } +} + +static void *cq_thread(void *arg) +{ + struct rping_cb *cb = arg; + struct ibv_cq *ev_cq; + void *ev_ctx; + int ret; + + DEBUG_LOG("cq_thread started.\n"); + + while (1) { + pthread_testcancel(); + + ret = ibv_get_cq_event(cb->channel, &ev_cq, &ev_ctx); + if (ret) { + fprintf(stderr, "Failed to get cq event!\n"); + pthread_exit(NULL); + } + if (ev_cq != cb->cq) { + fprintf(stderr, "Unknown CQ!\n"); + pthread_exit(NULL); + } + ret = ibv_req_notify_cq(cb->cq, 0); + if (ret) { + fprintf(stderr, "Failed to set notify!\n"); + pthread_exit(NULL); + } + ret = rping_cq_event_handler(cb); + ibv_ack_cq_events(cb->cq, 1); + if (ret) + pthread_exit(NULL); + } +} + +static void rping_format_send(struct rping_cb *cb, char *buf, struct ibv_mr *mr) +{ + struct rping_rdma_info *info = &cb->send_buf; + + info->buf = htonll((uint64_t) (unsigned long) buf); + info->rkey = htonl(mr->rkey); + info->size = htonl(cb->size); + + DEBUG_LOG("RDMA addr %" PRIx64" rkey %x len %d\n", + ntohll(info->buf), ntohl(info->rkey), ntohl(info->size)); +} + +static int rping_test_server(struct rping_cb *cb) +{ + struct ibv_send_wr *bad_wr; + int ret; + + while (1) { + /* Wait for client's Start STAG/TO/Len */ + sem_wait(&cb->sem); + if (cb->state != RDMA_READ_ADV) { + fprintf(stderr, "wait for RDMA_READ_ADV state %d\n", + cb->state); + ret = -1; + break; + } + + DEBUG_LOG("server received sink adv\n"); + + /* Issue RDMA Read. */ + cb->rdma_sq_wr.opcode = IBV_WR_RDMA_READ; + cb->rdma_sq_wr.wr.rdma.rkey = cb->remote_rkey; + cb->rdma_sq_wr.wr.rdma.remote_addr = cb->remote_addr; + cb->rdma_sq_wr.sg_list->length = cb->remote_len; + + ret = ibv_post_send(cb->qp, &cb->rdma_sq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "post send error %d\n", ret); + break; + } + DEBUG_LOG("server posted rdma read req \n"); + + /* Wait for read completion */ + sem_wait(&cb->sem); + if (cb->state != RDMA_READ_COMPLETE) { + fprintf(stderr, "wait for RDMA_READ_COMPLETE state %d\n", + cb->state); + ret = -1; + break; + } + DEBUG_LOG("server received read complete\n"); + + /* Display data in recv buf */ + if (cb->verbose) + printf("server ping data: %s\n", cb->rdma_buf); + + /* Tell client to continue */ + ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "post send error %d\n", ret); + break; + } + DEBUG_LOG("server posted go ahead\n"); + + /* Wait for client's RDMA STAG/TO/Len */ + sem_wait(&cb->sem); + if (cb->state != RDMA_WRITE_ADV) { + fprintf(stderr, "wait for RDMA_WRITE_ADV state %d\n", + cb->state); + ret = -1; + break; + } + DEBUG_LOG("server received sink adv\n"); + + /* RDMA Write echo data */ + cb->rdma_sq_wr.opcode = IBV_WR_RDMA_WRITE; + cb->rdma_sq_wr.wr.rdma.rkey = cb->remote_rkey; + cb->rdma_sq_wr.wr.rdma.remote_addr = cb->remote_addr; + cb->rdma_sq_wr.sg_list->length = strlen(cb->rdma_buf) + 1; + DEBUG_LOG("rdma write from lkey %x laddr %" PRIx64 " len %d\n", + cb->rdma_sq_wr.sg_list->lkey, + cb->rdma_sq_wr.sg_list->addr, + cb->rdma_sq_wr.sg_list->length); + + ret = ibv_post_send(cb->qp, &cb->rdma_sq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "post send error %d\n", ret); + break; + } + + /* Wait for completion */ + ret = sem_wait(&cb->sem); + if (cb->state != RDMA_WRITE_COMPLETE) { + fprintf(stderr, "wait for RDMA_WRITE_COMPLETE state %d\n", + cb->state); + ret = -1; + break; + } + DEBUG_LOG("server rdma write complete \n"); + + /* Tell client to begin again */ + ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "post send error %d\n", ret); + break; + } + DEBUG_LOG("server posted go ahead\n"); + } + + return ret; +} + +static int rping_bind_server(struct rping_cb *cb) +{ + int ret; + + if (cb->sin.ss_family == AF_INET) + ((struct sockaddr_in *) &cb->sin)->sin_port = cb->port; + else + ((struct sockaddr_in6 *) &cb->sin)->sin6_port = cb->port; + + ret = rdma_bind_addr(cb->cm_id, (struct sockaddr *) &cb->sin); + if (ret) { + perror("rdma_bind_addr"); + return ret; + } + DEBUG_LOG("rdma_bind_addr successful\n"); + + DEBUG_LOG("rdma_listen\n"); + ret = rdma_listen(cb->cm_id, 3); + if (ret) { + perror("rdma_listen"); + return ret; + } + + return 0; +} + +static struct rping_cb *clone_cb(struct rping_cb *listening_cb) +{ + struct rping_cb *cb = malloc(sizeof *cb); + if (!cb) + return NULL; + *cb = *listening_cb; + cb->child_cm_id->context = cb; + return cb; +} + +static void free_cb(struct rping_cb *cb) +{ + free(cb); +} + +static void *rping_persistent_server_thread(void *arg) +{ + struct rping_cb *cb = arg; + struct ibv_recv_wr *bad_wr; + int ret; + + ret = rping_setup_qp(cb, cb->child_cm_id); + if (ret) { + fprintf(stderr, "setup_qp failed: %d\n", ret); + goto err0; + } + + ret = rping_setup_buffers(cb); + if (ret) { + fprintf(stderr, "rping_setup_buffers failed: %d\n", ret); + goto err1; + } + + ret = ibv_post_recv(cb->qp, &cb->rq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "ibv_post_recv failed: %d\n", ret); + goto err2; + } + + pthread_create(&cb->cqthread, NULL, cq_thread, cb); + + ret = rping_accept(cb); + if (ret) { + fprintf(stderr, "connect error %d\n", ret); + goto err3; + } + + rping_test_server(cb); + rdma_disconnect(cb->child_cm_id); + rping_free_buffers(cb); + rping_free_qp(cb); + pthread_cancel(cb->cqthread); + pthread_join(cb->cqthread, NULL); + rdma_destroy_id(cb->child_cm_id); + free_cb(cb); + return NULL; +err3: + pthread_cancel(cb->cqthread); + pthread_join(cb->cqthread, NULL); +err2: + rping_free_buffers(cb); +err1: + rping_free_qp(cb); +err0: + free_cb(cb); + return NULL; +} + +static int rping_run_persistent_server(struct rping_cb *listening_cb) +{ + int ret; + struct rping_cb *cb; + + ret = rping_bind_server(listening_cb); + if (ret) + return ret; + + while (1) { + sem_wait(&listening_cb->sem); + if (listening_cb->state != CONNECT_REQUEST) { + fprintf(stderr, "wait for CONNECT_REQUEST state %d\n", + listening_cb->state); + return -1; + } + + cb = clone_cb(listening_cb); + if (!cb) + return -1; + pthread_create(&cb->persistent_server_thread, NULL, rping_persistent_server_thread, cb); + } + return 0; +} + +static int rping_run_server(struct rping_cb *cb) +{ + struct ibv_recv_wr *bad_wr; + int ret; + + ret = rping_bind_server(cb); + if (ret) + return ret; + + sem_wait(&cb->sem); + if (cb->state != CONNECT_REQUEST) { + fprintf(stderr, "wait for CONNECT_REQUEST state %d\n", + cb->state); + return -1; + } + + ret = rping_setup_qp(cb, cb->child_cm_id); + if (ret) { + fprintf(stderr, "setup_qp failed: %d\n", ret); + return ret; + } + + ret = rping_setup_buffers(cb); + if (ret) { + fprintf(stderr, "rping_setup_buffers failed: %d\n", ret); + goto err1; + } + + ret = ibv_post_recv(cb->qp, &cb->rq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "ibv_post_recv failed: %d\n", ret); + goto err2; + } + + pthread_create(&cb->cqthread, NULL, cq_thread, cb); + + ret = rping_accept(cb); + if (ret) { + fprintf(stderr, "connect error %d\n", ret); + goto err2; + } + + rping_test_server(cb); + rdma_disconnect(cb->child_cm_id); + rdma_destroy_id(cb->child_cm_id); +err2: + rping_free_buffers(cb); +err1: + rping_free_qp(cb); + + return ret; +} + +static int rping_test_client(struct rping_cb *cb) +{ + int ping, start, cc, i, ret = 0; + struct ibv_send_wr *bad_wr; + unsigned char c; + + start = 65; + for (ping = 0; !cb->count || ping < cb->count; ping++) { + cb->state = RDMA_READ_ADV; + + /* Put some ascii text in the buffer. */ + cc = sprintf(cb->start_buf, RPING_MSG_FMT, ping); + for (i = cc, c = start; i < cb->size; i++) { + cb->start_buf[i] = c; + c++; + if (c > 122) + c = 65; + } + start++; + if (start > 122) + start = 65; + cb->start_buf[cb->size - 1] = 0; + + rping_format_send(cb, cb->start_buf, cb->start_mr); + ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "post send error %d\n", ret); + break; + } + + /* Wait for server to ACK */ + sem_wait(&cb->sem); + if (cb->state != RDMA_WRITE_ADV) { + fprintf(stderr, "wait for RDMA_WRITE_ADV state %d\n", + cb->state); + ret = -1; + break; + } + + rping_format_send(cb, cb->rdma_buf, cb->rdma_mr); + ret = ibv_post_send(cb->qp, &cb->sq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "post send error %d\n", ret); + break; + } + + /* Wait for the server to say the RDMA Write is complete. */ + sem_wait(&cb->sem); + if (cb->state != RDMA_WRITE_COMPLETE) { + fprintf(stderr, "wait for RDMA_WRITE_COMPLETE state %d\n", + cb->state); + ret = -1; + break; + } + + if (cb->validate) + if (memcmp(cb->start_buf, cb->rdma_buf, cb->size)) { + fprintf(stderr, "data mismatch!\n"); + ret = -1; + break; + } + + if (cb->verbose) + printf("ping data: %s\n", cb->rdma_buf); + } + + return ret; +} + +static int rping_connect_client(struct rping_cb *cb) +{ + struct rdma_conn_param conn_param; + int ret; + + memset(&conn_param, 0, sizeof conn_param); + conn_param.responder_resources = 1; + conn_param.initiator_depth = 1; + conn_param.retry_count = 10; + + ret = rdma_connect(cb->cm_id, &conn_param); + if (ret) { + perror("rdma_connect"); + return ret; + } + + sem_wait(&cb->sem); + if (cb->state != CONNECTED) { + fprintf(stderr, "wait for CONNECTED state %d\n", cb->state); + return -1; + } + + DEBUG_LOG("rmda_connect successful\n"); + return 0; +} + +static int rping_bind_client(struct rping_cb *cb) +{ + int ret; + + if (cb->sin.ss_family == AF_INET) + ((struct sockaddr_in *) &cb->sin)->sin_port = cb->port; + else + ((struct sockaddr_in6 *) &cb->sin)->sin6_port = cb->port; + + ret = rdma_resolve_addr(cb->cm_id, NULL, (struct sockaddr *) &cb->sin, 2000); + if (ret) { + perror("rdma_resolve_addr"); + return ret; + } + + sem_wait(&cb->sem); + if (cb->state != ROUTE_RESOLVED) { + fprintf(stderr, "waiting for addr/route resolution state %d\n", + cb->state); + return -1; + } + + DEBUG_LOG("rdma_resolve_addr - rdma_resolve_route successful\n"); + return 0; +} + +static int rping_run_client(struct rping_cb *cb) +{ + struct ibv_recv_wr *bad_wr; + int ret; + + ret = rping_bind_client(cb); + if (ret) + return ret; + + ret = rping_setup_qp(cb, cb->cm_id); + if (ret) { + fprintf(stderr, "setup_qp failed: %d\n", ret); + return ret; + } + + ret = rping_setup_buffers(cb); + if (ret) { + fprintf(stderr, "rping_setup_buffers failed: %d\n", ret); + goto err1; + } + + ret = ibv_post_recv(cb->qp, &cb->rq_wr, &bad_wr); + if (ret) { + fprintf(stderr, "ibv_post_recv failed: %d\n", ret); + goto err2; + } + + pthread_create(&cb->cqthread, NULL, cq_thread, cb); + + ret = rping_connect_client(cb); + if (ret) { + fprintf(stderr, "connect error %d\n", ret); + goto err2; + } + + rping_test_client(cb); + rdma_disconnect(cb->cm_id); +err2: + rping_free_buffers(cb); +err1: + rping_free_qp(cb); + + return ret; +} + +static int get_addr(char *dst, struct sockaddr *addr) +{ + struct addrinfo *res; + int ret; + + ret = getaddrinfo(dst, NULL, NULL, &res); + if (ret) { + printf("getaddrinfo failed - invalid hostname or IP address\n"); + return ret; + } + + if (res->ai_family == PF_INET) + memcpy(addr, res->ai_addr, sizeof(struct sockaddr_in)); + else if (res->ai_family == PF_INET6) + memcpy(addr, res->ai_addr, sizeof(struct sockaddr_in6)); + else + ret = -1; + + freeaddrinfo(res); + return ret; +} + +static void usage(char *name) +{ + printf("%s -s [-vVd] [-S size] [-C count] [-a addr] [-p port]\n", + name); + printf("%s -c [-vVd] [-S size] [-C count] -a addr [-p port]\n", + name); + printf("\t-c\t\tclient side\n"); + printf("\t-s\t\tserver side. To bind to any address with IPv6 use -a ::0\n"); + printf("\t-v\t\tdisplay ping data to stdout\n"); + printf("\t-V\t\tvalidate ping data\n"); + printf("\t-d\t\tdebug printfs\n"); + printf("\t-S size \tping data size\n"); + printf("\t-C count\tping count times\n"); + printf("\t-a addr\t\taddress\n"); + printf("\t-p port\t\tport\n"); + printf("\t-P\t\tpersistent server mode allowing multiple connections\n"); +} + +int main(int argc, char *argv[]) +{ + struct rping_cb *cb; + int op; + int ret = 0; + int persistent_server = 0; + + cb = malloc(sizeof(*cb)); + if (!cb) + return -ENOMEM; + + memset(cb, 0, sizeof(*cb)); + cb->server = -1; + cb->state = IDLE; + cb->size = 64; + cb->sin.ss_family = PF_INET; + cb->port = htons(7174); + sem_init(&cb->sem, 0, 0); + + opterr = 0; + while ((op=getopt(argc, argv, "a:Pp:C:S:t:scvVd")) != -1) { + switch (op) { + case 'a': + ret = get_addr(optarg, (struct sockaddr *) &cb->sin); + break; + case 'P': + persistent_server = 1; + break; + case 'p': + cb->port = htons(atoi(optarg)); + DEBUG_LOG("port %d\n", (int) atoi(optarg)); + break; + case 's': + cb->server = 1; + DEBUG_LOG("server\n"); + break; + case 'c': + cb->server = 0; + DEBUG_LOG("client\n"); + break; + case 'S': + cb->size = atoi(optarg); + if ((cb->size < RPING_MIN_BUFSIZE) || + (cb->size > (RPING_BUFSIZE - 1))) { + fprintf(stderr, "Invalid size %d " + "(valid range is %Zd to %d)\n", + cb->size, RPING_MIN_BUFSIZE, RPING_BUFSIZE); + ret = EINVAL; + } else + DEBUG_LOG("size %d\n", (int) atoi(optarg)); + break; + case 'C': + cb->count = atoi(optarg); + if (cb->count < 0) { + fprintf(stderr, "Invalid count %d\n", + cb->count); + ret = EINVAL; + } else + DEBUG_LOG("count %d\n", (int) cb->count); + break; + case 'v': + cb->verbose++; + DEBUG_LOG("verbose\n"); + break; + case 'V': + cb->validate++; + DEBUG_LOG("validate data\n"); + break; + case 'd': + debug++; + break; + default: + usage("rping"); + ret = EINVAL; + goto out; + } + } + if (ret) + goto out; + + if (cb->server == -1) { + usage("rping"); + ret = EINVAL; + goto out; + } + + cb->cm_channel = rdma_create_event_channel(); + if (!cb->cm_channel) { + perror("rdma_create_event_channel"); + goto out; + } + + ret = rdma_create_id(cb->cm_channel, &cb->cm_id, cb, RDMA_PS_TCP); + if (ret) { + perror("rdma_create_id"); + goto out2; + } + DEBUG_LOG("created cm_id %p\n", cb->cm_id); + + pthread_create(&cb->cmthread, NULL, cm_thread, cb); + + if (cb->server) { + if (persistent_server) + ret = rping_run_persistent_server(cb); + else + ret = rping_run_server(cb); + } else + ret = rping_run_client(cb); + + DEBUG_LOG("destroy cm_id %p\n", cb->cm_id); + rdma_destroy_id(cb->cm_id); +out2: + rdma_destroy_event_channel(cb->cm_channel); +out: + free(cb); + return ret; +} diff --git a/contrib/ofed/librdmacm/examples/udaddy.c b/contrib/ofed/librdmacm/examples/udaddy.c new file mode 100644 index 000000000000..637306a571b2 --- /dev/null +++ b/contrib/ofed/librdmacm/examples/udaddy.c @@ -0,0 +1,701 @@ +/* + * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct cmatest_node { + int id; + struct rdma_cm_id *cma_id; + int connected; + struct ibv_pd *pd; + struct ibv_cq *cq; + struct ibv_mr *mr; + struct ibv_ah *ah; + uint32_t remote_qpn; + uint32_t remote_qkey; + void *mem; +}; + +struct cmatest { + struct rdma_event_channel *channel; + struct cmatest_node *nodes; + int conn_index; + int connects_left; + + struct sockaddr_in dst_in; + struct sockaddr *dst_addr; + struct sockaddr_in src_in; + struct sockaddr *src_addr; +}; + +static struct cmatest test; +static int connections = 1; +static int message_size = 100; +static int message_count = 10; +static uint16_t port = 7174; +static uint8_t set_tos = 0; +static uint8_t tos; +static char *dst_addr; +static char *src_addr; +static enum rdma_port_space port_space = RDMA_PS_UDP; + +static int create_message(struct cmatest_node *node) +{ + if (!message_size) + message_count = 0; + + if (!message_count) + return 0; + + node->mem = malloc(message_size + sizeof(struct ibv_grh)); + if (!node->mem) { + printf("failed message allocation\n"); + return -1; + } + node->mr = ibv_reg_mr(node->pd, node->mem, + message_size + sizeof(struct ibv_grh), + IBV_ACCESS_LOCAL_WRITE); + if (!node->mr) { + printf("failed to reg MR\n"); + goto err; + } + return 0; +err: + free(node->mem); + return -1; +} + +static int verify_test_params(struct cmatest_node *node) +{ + struct ibv_port_attr port_attr; + int ret; + + ret = ibv_query_port(node->cma_id->verbs, node->cma_id->port_num, + &port_attr); + if (ret) + return ret; + + if (message_count && message_size > (1 << (port_attr.active_mtu + 7))) { + printf("udaddy: message_size %d is larger than active mtu %d\n", + message_size, 1 << (port_attr.active_mtu + 7)); + return -EINVAL; + } + + return 0; +} + +static int init_node(struct cmatest_node *node) +{ + struct ibv_qp_init_attr init_qp_attr; + int cqe, ret; + + node->pd = ibv_alloc_pd(node->cma_id->verbs); + if (!node->pd) { + ret = -ENOMEM; + printf("udaddy: unable to allocate PD\n"); + goto out; + } + + cqe = message_count ? message_count * 2 : 2; + node->cq = ibv_create_cq(node->cma_id->verbs, cqe, node, 0, 0); + if (!node->cq) { + ret = -ENOMEM; + printf("udaddy: unable to create CQ\n"); + goto out; + } + + memset(&init_qp_attr, 0, sizeof init_qp_attr); + init_qp_attr.cap.max_send_wr = message_count ? message_count : 1; + init_qp_attr.cap.max_recv_wr = message_count ? message_count : 1; + init_qp_attr.cap.max_send_sge = 1; + init_qp_attr.cap.max_recv_sge = 1; + init_qp_attr.qp_context = node; + init_qp_attr.sq_sig_all = 0; + init_qp_attr.qp_type = IBV_QPT_UD; + init_qp_attr.send_cq = node->cq; + init_qp_attr.recv_cq = node->cq; + ret = rdma_create_qp(node->cma_id, node->pd, &init_qp_attr); + if (ret) { + perror("udaddy: unable to create QP"); + goto out; + } + + ret = create_message(node); + if (ret) { + printf("udaddy: failed to create messages: %d\n", ret); + goto out; + } +out: + return ret; +} + +static int post_recvs(struct cmatest_node *node) +{ + struct ibv_recv_wr recv_wr, *recv_failure; + struct ibv_sge sge; + int i, ret = 0; + + if (!message_count) + return 0; + + recv_wr.next = NULL; + recv_wr.sg_list = &sge; + recv_wr.num_sge = 1; + recv_wr.wr_id = (uintptr_t) node; + + sge.length = message_size + sizeof(struct ibv_grh); + sge.lkey = node->mr->lkey; + sge.addr = (uintptr_t) node->mem; + + for (i = 0; i < message_count && !ret; i++ ) { + ret = ibv_post_recv(node->cma_id->qp, &recv_wr, &recv_failure); + if (ret) { + printf("failed to post receives: %d\n", ret); + break; + } + } + return ret; +} + +static int post_sends(struct cmatest_node *node, int signal_flag) +{ + struct ibv_send_wr send_wr, *bad_send_wr; + struct ibv_sge sge; + int i, ret = 0; + + if (!node->connected || !message_count) + return 0; + + send_wr.next = NULL; + send_wr.sg_list = &sge; + send_wr.num_sge = 1; + send_wr.opcode = IBV_WR_SEND_WITH_IMM; + send_wr.send_flags = signal_flag; + send_wr.wr_id = (unsigned long)node; + send_wr.imm_data = htonl(node->cma_id->qp->qp_num); + + send_wr.wr.ud.ah = node->ah; + send_wr.wr.ud.remote_qpn = node->remote_qpn; + send_wr.wr.ud.remote_qkey = node->remote_qkey; + + sge.length = message_size; + sge.lkey = node->mr->lkey; + sge.addr = (uintptr_t) node->mem; + + for (i = 0; i < message_count && !ret; i++) { + ret = ibv_post_send(node->cma_id->qp, &send_wr, &bad_send_wr); + if (ret) + printf("failed to post sends: %d\n", ret); + } + return ret; +} + +static void connect_error(void) +{ + test.connects_left--; +} + +static int addr_handler(struct cmatest_node *node) +{ + int ret; + + if (set_tos) { + ret = rdma_set_option(node->cma_id, RDMA_OPTION_ID, + RDMA_OPTION_ID_TOS, &tos, sizeof tos); + if (ret) + perror("udaddy: set TOS option failed"); + } + + ret = rdma_resolve_route(node->cma_id, 2000); + if (ret) { + perror("udaddy: resolve route failed"); + connect_error(); + } + return ret; +} + +static int route_handler(struct cmatest_node *node) +{ + struct rdma_conn_param conn_param; + int ret; + + ret = verify_test_params(node); + if (ret) + goto err; + + ret = init_node(node); + if (ret) + goto err; + + ret = post_recvs(node); + if (ret) + goto err; + + memset(&conn_param, 0, sizeof conn_param); + ret = rdma_connect(node->cma_id, &conn_param); + if (ret) { + perror("udaddy: failure connecting"); + goto err; + } + return 0; +err: + connect_error(); + return ret; +} + +static int connect_handler(struct rdma_cm_id *cma_id) +{ + struct cmatest_node *node; + struct rdma_conn_param conn_param; + int ret; + + if (test.conn_index == connections) { + ret = -ENOMEM; + goto err1; + } + node = &test.nodes[test.conn_index++]; + + node->cma_id = cma_id; + cma_id->context = node; + + ret = verify_test_params(node); + if (ret) + goto err2; + + ret = init_node(node); + if (ret) + goto err2; + + ret = post_recvs(node); + if (ret) + goto err2; + + memset(&conn_param, 0, sizeof conn_param); + conn_param.qp_num = node->cma_id->qp->qp_num; + ret = rdma_accept(node->cma_id, &conn_param); + if (ret) { + perror("udaddy: failure accepting"); + goto err2; + } + node->connected = 1; + test.connects_left--; + return 0; + +err2: + node->cma_id = NULL; + connect_error(); +err1: + printf("udaddy: failing connection request\n"); + rdma_reject(cma_id, NULL, 0); + return ret; +} + +static int resolved_handler(struct cmatest_node *node, + struct rdma_cm_event *event) +{ + node->remote_qpn = event->param.ud.qp_num; + node->remote_qkey = event->param.ud.qkey; + node->ah = ibv_create_ah(node->pd, &event->param.ud.ah_attr); + if (!node->ah) { + printf("udaddy: failure creating address handle\n"); + goto err; + } + + node->connected = 1; + test.connects_left--; + return 0; +err: + connect_error(); + return -1; +} + +static int cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) +{ + int ret = 0; + + switch (event->event) { + case RDMA_CM_EVENT_ADDR_RESOLVED: + ret = addr_handler(cma_id->context); + break; + case RDMA_CM_EVENT_ROUTE_RESOLVED: + ret = route_handler(cma_id->context); + break; + case RDMA_CM_EVENT_CONNECT_REQUEST: + ret = connect_handler(cma_id); + break; + case RDMA_CM_EVENT_ESTABLISHED: + ret = resolved_handler(cma_id->context, event); + break; + case RDMA_CM_EVENT_ADDR_ERROR: + case RDMA_CM_EVENT_ROUTE_ERROR: + case RDMA_CM_EVENT_CONNECT_ERROR: + case RDMA_CM_EVENT_UNREACHABLE: + case RDMA_CM_EVENT_REJECTED: + printf("udaddy: event: %s, error: %d\n", + rdma_event_str(event->event), event->status); + connect_error(); + ret = event->status; + break; + case RDMA_CM_EVENT_DEVICE_REMOVAL: + /* Cleanup will occur after test completes. */ + break; + default: + break; + } + return ret; +} + +static void destroy_node(struct cmatest_node *node) +{ + if (!node->cma_id) + return; + + if (node->ah) + ibv_destroy_ah(node->ah); + + if (node->cma_id->qp) + rdma_destroy_qp(node->cma_id); + + if (node->cq) + ibv_destroy_cq(node->cq); + + if (node->mem) { + ibv_dereg_mr(node->mr); + free(node->mem); + } + + if (node->pd) + ibv_dealloc_pd(node->pd); + + /* Destroy the RDMA ID after all device resources */ + rdma_destroy_id(node->cma_id); +} + +static int alloc_nodes(void) +{ + int ret, i; + + test.nodes = malloc(sizeof *test.nodes * connections); + if (!test.nodes) { + printf("udaddy: unable to allocate memory for test nodes\n"); + return -ENOMEM; + } + memset(test.nodes, 0, sizeof *test.nodes * connections); + + for (i = 0; i < connections; i++) { + test.nodes[i].id = i; + if (dst_addr) { + ret = rdma_create_id(test.channel, + &test.nodes[i].cma_id, + &test.nodes[i], port_space); + if (ret) + goto err; + } + } + return 0; +err: + while (--i >= 0) + rdma_destroy_id(test.nodes[i].cma_id); + free(test.nodes); + return ret; +} + +static void destroy_nodes(void) +{ + int i; + + for (i = 0; i < connections; i++) + destroy_node(&test.nodes[i]); + free(test.nodes); +} + +static void create_reply_ah(struct cmatest_node *node, struct ibv_wc *wc) +{ + struct ibv_qp_attr attr; + struct ibv_qp_init_attr init_attr; + + node->ah = ibv_create_ah_from_wc(node->pd, wc, node->mem, + node->cma_id->port_num); + node->remote_qpn = ntohl(wc->imm_data); + + ibv_query_qp(node->cma_id->qp, &attr, IBV_QP_QKEY, &init_attr); + node->remote_qkey = attr.qkey; +} + +static int poll_cqs(void) +{ + struct ibv_wc wc[8]; + int done, i, ret; + + for (i = 0; i < connections; i++) { + if (!test.nodes[i].connected) + continue; + + for (done = 0; done < message_count; done += ret) { + ret = ibv_poll_cq(test.nodes[i].cq, 8, wc); + if (ret < 0) { + printf("udaddy: failed polling CQ: %d\n", ret); + return ret; + } + + if (ret && !test.nodes[i].ah) + create_reply_ah(&test.nodes[i], wc); + } + } + return 0; +} + +static int connect_events(void) +{ + struct rdma_cm_event *event; + int ret = 0; + + while (test.connects_left && !ret) { + ret = rdma_get_cm_event(test.channel, &event); + if (!ret) { + ret = cma_handler(event->id, event); + rdma_ack_cm_event(event); + } + } + return ret; +} + +static int get_addr(char *dst, struct sockaddr_in *addr) +{ + struct addrinfo *res; + int ret; + + ret = getaddrinfo(dst, NULL, NULL, &res); + if (ret) { + printf("getaddrinfo failed - invalid hostname or IP address\n"); + return ret; + } + + if (res->ai_family != PF_INET) { + ret = -1; + goto out; + } + + *addr = *(struct sockaddr_in *) res->ai_addr; +out: + freeaddrinfo(res); + return ret; +} + +static int run_server(void) +{ + struct rdma_cm_id *listen_id; + int i, ret; + + printf("udaddy: starting server\n"); + ret = rdma_create_id(test.channel, &listen_id, &test, port_space); + if (ret) { + perror("udaddy: listen request failed"); + return ret; + } + + if (src_addr) { + ret = get_addr(src_addr, &test.src_in); + if (ret) + goto out; + } else + test.src_in.sin_family = PF_INET; + + test.src_in.sin_port = port; + ret = rdma_bind_addr(listen_id, test.src_addr); + if (ret) { + perror("udaddy: bind address failed"); + return ret; + } + + ret = rdma_listen(listen_id, 0); + if (ret) { + perror("udaddy: failure trying to listen"); + goto out; + } + + connect_events(); + + if (message_count) { + printf("receiving data transfers\n"); + ret = poll_cqs(); + if (ret) + goto out; + + printf("sending replies\n"); + for (i = 0; i < connections; i++) { + ret = post_sends(&test.nodes[i], IBV_SEND_SIGNALED); + if (ret) + goto out; + } + + ret = poll_cqs(); + if (ret) + goto out; + printf("data transfers complete\n"); + } +out: + rdma_destroy_id(listen_id); + return ret; +} + +static int run_client(void) +{ + int i, ret; + + printf("udaddy: starting client\n"); + if (src_addr) { + ret = get_addr(src_addr, &test.src_in); + if (ret) + return ret; + } + + ret = get_addr(dst_addr, &test.dst_in); + if (ret) + return ret; + + test.dst_in.sin_port = port; + + printf("udaddy: connecting\n"); + for (i = 0; i < connections; i++) { + ret = rdma_resolve_addr(test.nodes[i].cma_id, + src_addr ? test.src_addr : NULL, + test.dst_addr, 2000); + if (ret) { + perror("udaddy: failure getting addr"); + connect_error(); + return ret; + } + } + + ret = connect_events(); + if (ret) + goto out; + + if (message_count) { + printf("initiating data transfers\n"); + for (i = 0; i < connections; i++) { + ret = post_sends(&test.nodes[i], 0); + if (ret) + goto out; + } + printf("receiving data transfers\n"); + ret = poll_cqs(); + if (ret) + goto out; + + printf("data transfers complete\n"); + } +out: + return ret; +} + +int main(int argc, char **argv) +{ + int op, ret; + + while ((op = getopt(argc, argv, "s:b:c:C:S:t:p:")) != -1) { + switch (op) { + case 's': + dst_addr = optarg; + break; + case 'b': + src_addr = optarg; + break; + case 'c': + connections = atoi(optarg); + break; + case 'C': + message_count = atoi(optarg); + break; + case 'S': + message_size = atoi(optarg); + break; + case 't': + set_tos = 1; + tos = (uint8_t) atoi(optarg); + break; + case 'p': + port_space = strtol(optarg, NULL, 0); + break; + default: + printf("usage: %s\n", argv[0]); + printf("\t[-s server_address]\n"); + printf("\t[-b bind_address]\n"); + printf("\t[-c connections]\n"); + printf("\t[-C message_count]\n"); + printf("\t[-S message_size]\n"); + printf("\t[-t type_of_service]\n"); + printf("\t[-p port_space - %#x for UDP (default), " + "%#x for IPOIB]\n", RDMA_PS_UDP, RDMA_PS_IPOIB); + exit(1); + } + } + + test.dst_addr = (struct sockaddr *) &test.dst_in; + test.src_addr = (struct sockaddr *) &test.src_in; + test.connects_left = connections; + + test.channel = rdma_create_event_channel(); + if (!test.channel) { + perror("failed to create event channel"); + exit(1); + } + + if (alloc_nodes()) + exit(1); + + if (dst_addr) + ret = run_client(); + else + ret = run_server(); + + printf("test complete\n"); + destroy_nodes(); + rdma_destroy_event_channel(test.channel); + + printf("return status %d\n", ret); + return ret; +} diff --git a/contrib/ofed/librdmacm/include/rdma/rdma_cma.h b/contrib/ofed/librdmacm/include/rdma/rdma_cma.h new file mode 100644 index 000000000000..534489d8f5d7 --- /dev/null +++ b/contrib/ofed/librdmacm/include/rdma/rdma_cma.h @@ -0,0 +1,580 @@ +/* + * Copyright (c) 2005 Voltaire Inc. All rights reserved. + * Copyright (c) 2005-2007 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if !defined(RDMA_CMA_H) +#define RDMA_CMA_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Upon receiving a device removal event, users must destroy the associated + * RDMA identifier and release all resources allocated with the device. + */ +enum rdma_cm_event_type { + RDMA_CM_EVENT_ADDR_RESOLVED, + RDMA_CM_EVENT_ADDR_ERROR, + RDMA_CM_EVENT_ROUTE_RESOLVED, + RDMA_CM_EVENT_ROUTE_ERROR, + RDMA_CM_EVENT_CONNECT_REQUEST, + RDMA_CM_EVENT_CONNECT_RESPONSE, + RDMA_CM_EVENT_CONNECT_ERROR, + RDMA_CM_EVENT_UNREACHABLE, + RDMA_CM_EVENT_REJECTED, + RDMA_CM_EVENT_ESTABLISHED, + RDMA_CM_EVENT_DISCONNECTED, + RDMA_CM_EVENT_DEVICE_REMOVAL, + RDMA_CM_EVENT_MULTICAST_JOIN, + RDMA_CM_EVENT_MULTICAST_ERROR, + RDMA_CM_EVENT_ADDR_CHANGE, + RDMA_CM_EVENT_TIMEWAIT_EXIT +}; + +enum rdma_port_space { + RDMA_PS_IPOIB= 0x0002, + RDMA_PS_TCP = 0x0106, + RDMA_PS_UDP = 0x0111, +}; + +/* + * Global qkey value for UDP QPs and multicast groups created via the + * RDMA CM. + */ +#define RDMA_UDP_QKEY 0x01234567 + +struct ib_addr { + union ibv_gid sgid; + union ibv_gid dgid; + uint16_t pkey; +}; + +struct rdma_addr { + struct sockaddr src_addr; + uint8_t src_pad[sizeof(struct sockaddr_storage) - + sizeof(struct sockaddr)]; + struct sockaddr dst_addr; + uint8_t dst_pad[sizeof(struct sockaddr_storage) - + sizeof(struct sockaddr)]; + union { + struct ib_addr ibaddr; + } addr; +}; + +struct rdma_route { + struct rdma_addr addr; + struct ibv_sa_path_rec *path_rec; + int num_paths; +}; + +struct rdma_event_channel { + int fd; +}; + +struct rdma_cm_id { + struct ibv_context *verbs; + struct rdma_event_channel *channel; + void *context; + struct ibv_qp *qp; + struct rdma_route route; + enum rdma_port_space ps; + uint8_t port_num; +}; + +struct rdma_conn_param { + const void *private_data; + uint8_t private_data_len; + uint8_t responder_resources; + uint8_t initiator_depth; + uint8_t flow_control; + uint8_t retry_count; /* ignored when accepting */ + uint8_t rnr_retry_count; + /* Fields below ignored if a QP is created on the rdma_cm_id. */ + uint8_t srq; + uint32_t qp_num; +}; + +struct rdma_ud_param { + const void *private_data; + uint8_t private_data_len; + struct ibv_ah_attr ah_attr; + uint32_t qp_num; + uint32_t qkey; +}; + +struct rdma_cm_event { + struct rdma_cm_id *id; + struct rdma_cm_id *listen_id; + enum rdma_cm_event_type event; + int status; + union { + struct rdma_conn_param conn; + struct rdma_ud_param ud; + } param; +}; + +/** + * rdma_create_event_channel - Open a channel used to report communication events. + * Description: + * Asynchronous events are reported to users through event channels. Each + * event channel maps to a file descriptor. + * Notes: + * All created event channels must be destroyed by calling + * rdma_destroy_event_channel. Users should call rdma_get_cm_event to + * retrieve events on an event channel. + * See also: + * rdma_get_cm_event, rdma_destroy_event_channel + */ +struct rdma_event_channel *rdma_create_event_channel(void); + +/** + * rdma_destroy_event_channel - Close an event communication channel. + * @channel: The communication channel to destroy. + * Description: + * Release all resources associated with an event channel and closes the + * associated file descriptor. + * Notes: + * All rdma_cm_id's associated with the event channel must be destroyed, + * and all returned events must be acked before calling this function. + * See also: + * rdma_create_event_channel, rdma_get_cm_event, rdma_ack_cm_event + */ +void rdma_destroy_event_channel(struct rdma_event_channel *channel); + +/** + * rdma_create_id - Allocate a communication identifier. + * @channel: The communication channel that events associated with the + * allocated rdma_cm_id will be reported on. + * @id: A reference where the allocated communication identifier will be + * returned. + * @context: User specified context associated with the rdma_cm_id. + * @ps: RDMA port space. + * Description: + * Creates an identifier that is used to track communication information. + * Notes: + * Rdma_cm_id's are conceptually equivalent to a socket for RDMA + * communication. The difference is that RDMA communication requires + * explicitly binding to a specified RDMA device before communication + * can occur, and most operations are asynchronous in nature. Communication + * events on an rdma_cm_id are reported through the associated event + * channel. Users must release the rdma_cm_id by calling rdma_destroy_id. + * See also: + * rdma_create_event_channel, rdma_destroy_id, rdma_get_devices, + * rdma_bind_addr, rdma_resolve_addr, rdma_connect, rdma_listen, + */ +int rdma_create_id(struct rdma_event_channel *channel, + struct rdma_cm_id **id, void *context, + enum rdma_port_space ps); + +/** + * rdma_destroy_id - Release a communication identifier. + * @id: The communication identifier to destroy. + * Description: + * Destroys the specified rdma_cm_id and cancels any outstanding + * asynchronous operation. + * Notes: + * Users must free any associated QP with the rdma_cm_id before + * calling this routine and ack an related events. + * See also: + * rdma_create_id, rdma_destroy_qp, rdma_ack_cm_event + */ +int rdma_destroy_id(struct rdma_cm_id *id); + +/** + * rdma_bind_addr - Bind an RDMA identifier to a source address. + * @id: RDMA identifier. + * @addr: Local address information. Wildcard values are permitted. + * Description: + * Associates a source address with an rdma_cm_id. The address may be + * wildcarded. If binding to a specific local address, the rdma_cm_id + * will also be bound to a local RDMA device. + * Notes: + * Typically, this routine is called before calling rdma_listen to bind + * to a specific port number, but it may also be called on the active side + * of a connection before calling rdma_resolve_addr to bind to a specific + * address. + * See also: + * rdma_create_id, rdma_listen, rdma_resolve_addr, rdma_create_qp + */ +int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr); + +/** + * rdma_resolve_addr - Resolve destination and optional source addresses. + * @id: RDMA identifier. + * @src_addr: Source address information. This parameter may be NULL. + * @dst_addr: Destination address information. + * @timeout_ms: Time to wait for resolution to complete. + * Description: + * Resolve destination and optional source addresses from IP addresses + * to an RDMA address. If successful, the specified rdma_cm_id will + * be bound to a local device. + * Notes: + * This call is used to map a given destination IP address to a usable RDMA + * address. If a source address is given, the rdma_cm_id is bound to that + * address, the same as if rdma_bind_addr were called. If no source + * address is given, and the rdma_cm_id has not yet been bound to a device, + * then the rdma_cm_id will be bound to a source address based on the + * local routing tables. After this call, the rdma_cm_id will be bound to + * an RDMA device. This call is typically made from the active side of a + * connection before calling rdma_resolve_route and rdma_connect. + * See also: + * rdma_create_id, rdma_resolve_route, rdma_connect, rdma_create_qp, + * rdma_get_cm_event, rdma_bind_addr + */ +int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, + struct sockaddr *dst_addr, int timeout_ms); + +/** + * rdma_resolve_route - Resolve the route information needed to establish a connection. + * @id: RDMA identifier. + * @timeout_ms: Time to wait for resolution to complete. + * Description: + * Resolves an RDMA route to the destination address in order to establish + * a connection. The destination address must have already been resolved + * by calling rdma_resolve_addr. + * Notes: + * This is called on the client side of a connection after calling + * rdma_resolve_addr, but before calling rdma_connect. + * See also: + * rdma_resolve_addr, rdma_connect, rdma_get_cm_event + */ +int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms); + +/** + * rdma_create_qp - Allocate a QP. + * @id: RDMA identifier. + * @pd: protection domain for the QP. + * @qp_init_attr: initial QP attributes. + * Description: + * Allocate a QP associated with the specified rdma_cm_id and transition it + * for sending and receiving. + * Notes: + * The rdma_cm_id must be bound to a local RDMA device before calling this + * function, and the protection domain must be for that same device. + * QPs allocated to an rdma_cm_id are automatically transitioned by the + * librdmacm through their states. After being allocated, the QP will be + * ready to handle posting of receives. If the QP is unconnected, it will + * be ready to post sends. + * See also: + * rdma_bind_addr, rdma_resolve_addr, rdma_destroy_qp, ibv_create_qp, + * ibv_modify_qp + */ +int rdma_create_qp(struct rdma_cm_id *id, struct ibv_pd *pd, + struct ibv_qp_init_attr *qp_init_attr); + +/** + * rdma_destroy_qp - Deallocate a QP. + * @id: RDMA identifier. + * Description: + * Destroy a QP allocated on the rdma_cm_id. + * Notes: + * Users must destroy any QP associated with an rdma_cm_id before + * destroying the ID. + * See also: + * rdma_create_qp, rdma_destroy_id, ibv_destroy_qp + */ +void rdma_destroy_qp(struct rdma_cm_id *id); + +/** + * rdma_connect - Initiate an active connection request. + * @id: RDMA identifier. + * @conn_param: connection parameters. + * Description: + * For a connected rdma_cm_id, this call initiates a connection request + * to a remote destination. For an unconnected rdma_cm_id, it initiates + * a lookup of the remote QP providing the datagram service. + * Notes: + * Users must have resolved a route to the destination address + * by having called rdma_resolve_route before calling this routine. + * See also: + * rdma_resolve_route, rdma_disconnect, rdma_listen, rdma_get_cm_event + */ +int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param); + +/** + * rdma_listen - Listen for incoming connection requests. + * @id: RDMA identifier. + * @backlog: backlog of incoming connection requests. + * Description: + * Initiates a listen for incoming connection requests or datagram service + * lookup. The listen will be restricted to the locally bound source + * address. + * Notes: + * Users must have bound the rdma_cm_id to a local address by calling + * rdma_bind_addr before calling this routine. If the rdma_cm_id is + * bound to a specific IP address, the listen will be restricted to that + * address and the associated RDMA device. If the rdma_cm_id is bound + * to an RDMA port number only, the listen will occur across all RDMA + * devices. + * See also: + * rdma_bind_addr, rdma_connect, rdma_accept, rdma_reject, rdma_get_cm_event + */ +int rdma_listen(struct rdma_cm_id *id, int backlog); + +/** + * rdma_accept - Called to accept a connection request. + * @id: Connection identifier associated with the request. + * @conn_param: Information needed to establish the connection. + * Description: + * Called from the listening side to accept a connection or datagram + * service lookup request. + * Notes: + * Unlike the socket accept routine, rdma_accept is not called on a + * listening rdma_cm_id. Instead, after calling rdma_listen, the user + * waits for a connection request event to occur. Connection request + * events give the user a newly created rdma_cm_id, similar to a new + * socket, but the rdma_cm_id is bound to a specific RDMA device. + * rdma_accept is called on the new rdma_cm_id. + * See also: + * rdma_listen, rdma_reject, rdma_get_cm_event + */ +int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param); + +/** + * rdma_reject - Called to reject a connection request. + * @id: Connection identifier associated with the request. + * @private_data: Optional private data to send with the reject message. + * @private_data_len: Size of the private_data to send, in bytes. + * Description: + * Called from the listening side to reject a connection or datagram + * service lookup request. + * Notes: + * After receiving a connection request event, a user may call rdma_reject + * to reject the request. If the underlying RDMA transport supports + * private data in the reject message, the specified data will be passed to + * the remote side. + * See also: + * rdma_listen, rdma_accept, rdma_get_cm_event + */ +int rdma_reject(struct rdma_cm_id *id, const void *private_data, + uint8_t private_data_len); + +/** + * rdma_notify - Notifies the librdmacm of an asynchronous event. + * @id: RDMA identifier. + * @event: Asynchronous event. + * Description: + * Used to notify the librdmacm of asynchronous events that have occurred + * on a QP associated with the rdma_cm_id. + * Notes: + * Asynchronous events that occur on a QP are reported through the user's + * device event handler. This routine is used to notify the librdmacm of + * communication events. In most cases, use of this routine is not + * necessary, however if connection establishment is done out of band + * (such as done through Infiniband), it's possible to receive data on a + * QP that is not yet considered connected. This routine forces the + * connection into an established state in this case in order to handle + * the rare situation where the connection never forms on its own. + * Events that should be reported to the CM are: IB_EVENT_COMM_EST. + * See also: + * rdma_connect, rdma_accept, rdma_listen + */ +int rdma_notify(struct rdma_cm_id *id, enum ibv_event_type event); + +/** + * rdma_disconnect - This function disconnects a connection. + * @id: RDMA identifier. + * Description: + * Disconnects a connection and transitions any associated QP to the + * error state. + * See also: + * rdma_connect, rdma_listen, rdma_accept + */ +int rdma_disconnect(struct rdma_cm_id *id); + +/** + * rdma_join_multicast - Joins a multicast group. + * @id: Communication identifier associated with the request. + * @addr: Multicast address identifying the group to join. + * @context: User-defined context associated with the join request. + * Description: + * Joins a multicast group and attaches an associated QP to the group. + * Notes: + * Before joining a multicast group, the rdma_cm_id must be bound to + * an RDMA device by calling rdma_bind_addr or rdma_resolve_addr. Use of + * rdma_resolve_addr requires the local routing tables to resolve the + * multicast address to an RDMA device. The user must call + * rdma_leave_multicast to leave the multicast group and release any + * multicast resources. The context is returned to the user through + * the private_data field in the rdma_cm_event. + * See also: + * rdma_leave_multicast, rdma_bind_addr, rdma_resolve_addr, rdma_create_qp + */ +int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, + void *context); + +/** + * rdma_leave_multicast - Leaves a multicast group. + * @id: Communication identifier associated with the request. + * @addr: Multicast address identifying the group to leave. + * Description: + * Leaves a multicast group and detaches an associated QP from the group. + * Notes: + * Calling this function before a group has been fully joined results in + * canceling the join operation. Users should be aware that messages + * received from the multicast group may stilled be queued for + * completion processing immediately after leaving a multicast group. + * Destroying an rdma_cm_id will automatically leave all multicast groups. + * See also: + * rdma_join_multicast, rdma_destroy_qp + */ +int rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr); + +/** + * rdma_get_cm_event - Retrieves the next pending communication event. + * @channel: Event channel to check for events. + * @event: Allocated information about the next communication event. + * Description: + * Retrieves a communication event. If no events are pending, by default, + * the call will block until an event is received. + * Notes: + * The default synchronous behavior of this routine can be changed by + * modifying the file descriptor associated with the given channel. All + * events that are reported must be acknowledged by calling rdma_ack_cm_event. + * Destruction of an rdma_cm_id will block until related events have been + * acknowledged. + * See also: + * rdma_ack_cm_event, rdma_create_event_channel, rdma_event_str + */ +int rdma_get_cm_event(struct rdma_event_channel *channel, + struct rdma_cm_event **event); + +/** + * rdma_ack_cm_event - Free a communication event. + * @event: Event to be released. + * Description: + * All events which are allocated by rdma_get_cm_event must be released, + * there should be a one-to-one correspondence between successful gets + * and acks. + * See also: + * rdma_get_cm_event, rdma_destroy_id + */ +int rdma_ack_cm_event(struct rdma_cm_event *event); + +static inline uint16_t rdma_get_src_port(struct rdma_cm_id *id) +{ + return id->route.addr.src_addr.sa_family == PF_INET6 ? + ((struct sockaddr_in6 *) &id->route.addr.src_addr)->sin6_port : + ((struct sockaddr_in *) &id->route.addr.src_addr)->sin_port; +} + +static inline uint16_t rdma_get_dst_port(struct rdma_cm_id *id) +{ + return id->route.addr.dst_addr.sa_family == PF_INET6 ? + ((struct sockaddr_in6 *) &id->route.addr.dst_addr)->sin6_port : + ((struct sockaddr_in *) &id->route.addr.dst_addr)->sin_port; +} + +static inline struct sockaddr *rdma_get_local_addr(struct rdma_cm_id *id) +{ + return &id->route.addr.src_addr; +} + +static inline struct sockaddr *rdma_get_peer_addr(struct rdma_cm_id *id) +{ + return &id->route.addr.dst_addr; +} + +/** + * rdma_get_devices - Get list of RDMA devices currently available. + * @num_devices: If non-NULL, set to the number of devices returned. + * Description: + * Return a NULL-terminated array of opened RDMA devices. Callers can use + * this routine to allocate resources on specific RDMA devices that will be + * shared across multiple rdma_cm_id's. + * Notes: + * The returned array must be released by calling rdma_free_devices. Devices + * remain opened while the librdmacm is loaded. + * See also: + * rdma_free_devices + */ +struct ibv_context **rdma_get_devices(int *num_devices); + +/** + * rdma_free_devices - Frees the list of devices returned by rdma_get_devices. + * @list: List of devices returned from rdma_get_devices. + * Description: + * Frees the device array returned by rdma_get_devices. + * See also: + * rdma_get_devices + */ +void rdma_free_devices(struct ibv_context **list); + +/** + * rdma_event_str - Returns a string representation of an rdma cm event. + * @event: Asynchronous event. + * Description: + * Returns a string representation of an asynchronous event. + * See also: + * rdma_get_cm_event + */ +const char *rdma_event_str(enum rdma_cm_event_type event); + +/* Option levels */ +enum { + RDMA_OPTION_ID = 0 +}; + +/* Option details */ +enum { + RDMA_OPTION_ID_TOS = 0 /* uint8_t: RFC 2474 */ +}; + +/** + * rdma_set_option - Set options for an rdma_cm_id. + * @id: Communication identifier to set option for. + * @level: Protocol level of the option to set. + * @optname: Name of the option to set. + * @optval: Reference to the option data. + * @optlen: The size of the %optval buffer. + */ +int rdma_set_option(struct rdma_cm_id *id, int level, int optname, + void *optval, size_t optlen); + +/** + * rdma_migrate_id - Move an rdma_cm_id to a new event channel. + * @id: Communication identifier to migrate. + * @channel: New event channel for rdma_cm_id events. + */ +int rdma_migrate_id(struct rdma_cm_id *id, struct rdma_event_channel *channel); + +#ifdef __cplusplus +} +#endif + +#endif /* RDMA_CMA_H */ diff --git a/contrib/ofed/librdmacm/include/rdma/rdma_cma_abi.h b/contrib/ofed/librdmacm/include/rdma/rdma_cma_abi.h new file mode 100644 index 000000000000..1a3a9c2e7cd7 --- /dev/null +++ b/contrib/ofed/librdmacm/include/rdma/rdma_cma_abi.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef RDMA_CMA_ABI_H +#define RDMA_CMA_ABI_H + +#include +#include + +/* + * This file must be kept in sync with the kernel's version of rdma_user_cm.h + */ + +#define RDMA_USER_CM_MIN_ABI_VERSION 3 +#define RDMA_USER_CM_MAX_ABI_VERSION 4 + +#define RDMA_MAX_PRIVATE_DATA 256 + +enum { + UCMA_CMD_CREATE_ID, + UCMA_CMD_DESTROY_ID, + UCMA_CMD_BIND_ADDR, + UCMA_CMD_RESOLVE_ADDR, + UCMA_CMD_RESOLVE_ROUTE, + UCMA_CMD_QUERY_ROUTE, + UCMA_CMD_CONNECT, + UCMA_CMD_LISTEN, + UCMA_CMD_ACCEPT, + UCMA_CMD_REJECT, + UCMA_CMD_DISCONNECT, + UCMA_CMD_INIT_QP_ATTR, + UCMA_CMD_GET_EVENT, + UCMA_CMD_GET_OPTION, + UCMA_CMD_SET_OPTION, + UCMA_CMD_NOTIFY, + UCMA_CMD_JOIN_MCAST, + UCMA_CMD_LEAVE_MCAST, + UCMA_CMD_MIGRATE_ID +}; + +struct ucma_abi_cmd_hdr { + __u32 cmd; + __u16 in; + __u16 out; +}; + +struct ucma_abi_create_id { + __u64 uid; + __u64 response; + __u16 ps; + __u8 reserved[6]; +}; + +struct ucma_abi_create_id_resp { + __u32 id; +}; + +struct ucma_abi_destroy_id { + __u64 response; + __u32 id; + __u32 reserved; +}; + +struct ucma_abi_destroy_id_resp { + __u32 events_reported; +}; + +struct ucma_abi_bind_addr { + __u64 response; + struct sockaddr_in6 addr; + __u32 id; +}; + +struct ucma_abi_resolve_addr { + struct sockaddr_in6 src_addr; + struct sockaddr_in6 dst_addr; + __u32 id; + __u32 timeout_ms; +}; + +struct ucma_abi_resolve_route { + __u32 id; + __u32 timeout_ms; +}; + +struct ucma_abi_query_route { + __u64 response; + __u32 id; + __u32 reserved; +}; + +struct ucma_abi_query_route_resp { + __u64 node_guid; + struct ibv_kern_path_rec ib_route[2]; + struct sockaddr_in6 src_addr; + struct sockaddr_in6 dst_addr; + __u32 num_paths; + __u8 port_num; + __u8 reserved[3]; +}; + +struct ucma_abi_conn_param { + __u32 qp_num; + __u32 reserved; + __u8 private_data[RDMA_MAX_PRIVATE_DATA]; + __u8 private_data_len; + __u8 srq; + __u8 responder_resources; + __u8 initiator_depth; + __u8 flow_control; + __u8 retry_count; + __u8 rnr_retry_count; + __u8 valid; +}; + +struct ucma_abi_ud_param { + __u32 qp_num; + __u32 qkey; + struct ibv_kern_ah_attr ah_attr; + __u8 private_data[RDMA_MAX_PRIVATE_DATA]; + __u8 private_data_len; + __u8 reserved[7]; + __u8 reserved2[4]; /* Round to 8-byte boundary to support 32/64 */ +}; + +struct ucma_abi_connect { + struct ucma_abi_conn_param conn_param; + __u32 id; + __u32 reserved; +}; + +struct ucma_abi_listen { + __u32 id; + __u32 backlog; +}; + +struct ucma_abi_accept { + __u64 uid; + struct ucma_abi_conn_param conn_param; + __u32 id; + __u32 reserved; +}; + +struct ucma_abi_reject { + __u32 id; + __u8 private_data_len; + __u8 reserved[3]; + __u8 private_data[RDMA_MAX_PRIVATE_DATA]; +}; + +struct ucma_abi_disconnect { + __u32 id; +}; + +struct ucma_abi_init_qp_attr { + __u64 response; + __u32 id; + __u32 qp_state; +}; + +struct ucma_abi_notify { + __u32 id; + __u32 event; +}; + +struct ucma_abi_join_mcast { + __u64 response; /* ucma_abi_create_id_resp */ + __u64 uid; + struct sockaddr_in6 addr; + __u32 id; +}; + +struct ucma_abi_get_event { + __u64 response; +}; + +struct ucma_abi_event_resp { + __u64 uid; + __u32 id; + __u32 event; + __u32 status; + union { + struct ucma_abi_conn_param conn; + struct ucma_abi_ud_param ud; + } param; +}; + +struct ucma_abi_set_option { + __u64 optval; + __u32 id; + __u32 level; + __u32 optname; + __u32 optlen; +}; + +struct ucma_abi_migrate_id { + __u64 response; + __u32 id; + __u32 fd; +}; + +struct ucma_abi_migrate_resp { + __u32 events_reported; +}; + +#endif /* RDMA_CMA_ABI_H */ diff --git a/contrib/ofed/librdmacm/librdmacm.spec b/contrib/ofed/librdmacm/librdmacm.spec new file mode 100644 index 000000000000..2405d9a6a7b0 --- /dev/null +++ b/contrib/ofed/librdmacm/librdmacm.spec @@ -0,0 +1,75 @@ +%define ver 1.0.11 + +Name: librdmacm +Version: 1.0.11 +Release: 1%{?dist} +Summary: Userspace RDMA Connection Manager + +Group: System Environment/Libraries +License: GPLv2 or BSD +Url: http://www.openfabrics.org/ +Source: http://www.openfabrics.org/downloads/rdmacm/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +BuildRequires: libibverbs-devel >= 1.1-1 + +%description +librdmacm provides a userspace RDMA Communication Managment API. + +%package devel +Summary: Development files for the librdmacm library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} %{_includedir}/infiniband/verbs.h + +%description devel +Development files for the librdmacm library. + +%package utils +Summary: Examples for the librdmacm library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} + +%description utils +Example test programs for the librdmacm library. + +%prep +%setup -q -n %{name}-%{ver} + +%build +%configure +make %{?_smp_mflags} + +%install +rm -rf $RPM_BUILD_ROOT +%makeinstall +# remove unpackaged files from the buildroot +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig + +%files +%defattr(-,root,root,-) +%{_libdir}/librdmacm*.so.* +%doc AUTHORS COPYING README + +%files devel +%defattr(-,root,root) +%{_libdir}/lib*.so +%{_libdir}/*.a +%{_includedir}/* +%{_mandir}/man3/* +%{_mandir}/man7/* + +%files utils +%defattr(-,root,root,-) +%{_bindir}/* +%{_mandir}/man1/* + +%changelog + +* Fri Feb 15 2008 Roland Dreier - 1.0.6-1 +- Initial Fedora spec file diff --git a/contrib/ofed/librdmacm/librdmacm.spec.in b/contrib/ofed/librdmacm/librdmacm.spec.in new file mode 100644 index 000000000000..85c7118cf353 --- /dev/null +++ b/contrib/ofed/librdmacm/librdmacm.spec.in @@ -0,0 +1,75 @@ +%define ver @VERSION@ + +Name: librdmacm +Version: 1.0.11 +Release: 1%{?dist} +Summary: Userspace RDMA Connection Manager + +Group: System Environment/Libraries +License: GPLv2 or BSD +Url: http://www.openfabrics.org/ +Source: http://www.openfabrics.org/downloads/rdmacm/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +BuildRequires: libibverbs-devel >= 1.1-1 + +%description +librdmacm provides a userspace RDMA Communication Managment API. + +%package devel +Summary: Development files for the librdmacm library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} %{_includedir}/infiniband/verbs.h + +%description devel +Development files for the librdmacm library. + +%package utils +Summary: Examples for the librdmacm library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} + +%description utils +Example test programs for the librdmacm library. + +%prep +%setup -q -n %{name}-%{ver} + +%build +%configure +make %{?_smp_mflags} + +%install +rm -rf $RPM_BUILD_ROOT +%makeinstall +# remove unpackaged files from the buildroot +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig + +%files +%defattr(-,root,root,-) +%{_libdir}/librdmacm*.so.* +%doc AUTHORS COPYING README + +%files devel +%defattr(-,root,root) +%{_libdir}/lib*.so +%{_libdir}/*.a +%{_includedir}/* +%{_mandir}/man3/* +%{_mandir}/man7/* + +%files utils +%defattr(-,root,root,-) +%{_bindir}/* +%{_mandir}/man1/* + +%changelog + +* Fri Feb 15 2008 Roland Dreier - 1.0.6-1 +- Initial Fedora spec file diff --git a/contrib/ofed/librdmacm/man/mckey.1 b/contrib/ofed/librdmacm/man/mckey.1 new file mode 100644 index 000000000000..441881919dd2 --- /dev/null +++ b/contrib/ofed/librdmacm/man/mckey.1 @@ -0,0 +1,59 @@ +.TH "MCKEY" 1 "2007-05-15" "librdmacm" "librdmacm" librdmacm +.SH NAME +mckey \- RDMA CM multicast setup and simple data transfer test. +.SH SYNOPSIS +.sp +.nf +\fImckey\fR -m multicast_address [-s] [-b bind_address] [-c connections] + [-C message_count] [-S message_size] [-p port_space] +\fImckey\fR -m multicast_address -s [-b bind_address] [-c connections] + [-C message_count] [-S message_size] [-p port_space] +\fImckey\fR -M unmapped_multicast_address -b bind_address [-s] [-c connections] + [-C message_count] [-S message_size] [-p port_space] +.fi +.SH "DESCRIPTION" +Establishes a set of RDMA multicast communication paths between nodes +using the librdmacm, optionally transfers datagrams to receiving nodes, +then tears down the communication. +.SH "OPTIONS" +.TP +\-m multicast_address +IP multicast address to join. +.TP +\-M unmapped_multicast_address +RDMA transport specific multicast address to join. +.TP +\-s +Send datagrams to the multicast group. +.TP +\-b bind_address +The local network address to bind to. +.TP +\-c connections +The number of QPs to join the multicast group. (default 1) +.TP +\-C message_count +The number of messages to transfer over each connection. (default 10) +.TP +\-S message_size +The size of each message transferred, in bytes. This value must be smaller +than the MTU of the underlying RDMA transport, or an error will occur. +(default 100) +.TP +\-p port_space +The port space of the datagram communication. May be either the RDMA +UDP (0x0111) or IPoIB (0x0002) port space. (default RDMA_PS_UDP) +.SH "NOTES" +Basic usage is to start mckey -m multicast_address on a server system, +then run mckey -m multicast_address -s on a client system. +.P +Unique Infiniband SA assigned multicast GIDs can be retrived by +invoking mckey with a zero MGID or IP address. (Example, -M 0 or +-m 0.0.0.0). The assigned address will be displayed to allow +mckey clients to join the created group. +.P +Because this test maps RDMA resources to userspace, users must ensure +that they have available system resources and permissions. See the +libibverbs README file for additional details. +.SH "SEE ALSO" +rdma_cm(7), ucmatose(1), udaddy(1), rping(1) diff --git a/contrib/ofed/librdmacm/man/rdma_accept.3 b/contrib/ofed/librdmacm/man/rdma_accept.3 new file mode 100644 index 000000000000..bdf90bd884cc --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_accept.3 @@ -0,0 +1,85 @@ +.TH "RDMA_ACCEPT" 3 "2007-10-31" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_accept \- Called to accept a connection request. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_accept +.BI "(struct rdma_cm_id *" id "," +.BI "struct rdma_conn_param *" conn_param ");" +.SH ARGUMENTS +.IP "id" 12 +Connection identifier associated with the request. +.IP "conn_param" 12 +Information needed to establish the connection. See CONNECTION PROPERTIES +below for details. +.SH "DESCRIPTION" +Called from the listening side to accept a connection or datagram +service lookup request. +.SH "NOTES" +Unlike the socket accept routine, rdma_accept is not called on a +listening rdma_cm_id. Instead, after calling rdma_listen, the user +waits for an RDMA_CM_EVENT_CONNECT_REQUEST event to occur. Connection request +events give the user a newly created rdma_cm_id, similar to a new +socket, but the rdma_cm_id is bound to a specific RDMA device. +rdma_accept is called on the new rdma_cm_id. +.SH "CONNECTION PROPERTIES" +The following properties are used to configure the communication and specified +by the conn_param parameter when accepting a connection or datagram +communication request. Users should use the rdma_conn_param values reported +in the connection request event to determine appropriate values for these +fields when accepting. Users may reference the rdma_conn_param structure in +the connection event directly, or can reference their own structure. If the +rdma_conn_param structure from an event is referenced, the event must not be +acked until after this call returns. +.IP private_data +References a user-controlled data buffer. The contents of the buffer are +copied and transparently passed to the remote side as part of the +communication request. May be NULL if private_data is not required. +.IP private_data_len +Specifies the size of the user-controlled data buffer. Note that the actual +amount of data transferred to the remote side is transport dependent and may +be larger than that requested. +.IP responder_resources +The maximum number of outstanding RDMA read and atomic operations that the +local side will accept from the remote side. Applies only to RDMA_PS_TCP. +This value must be less than or equal to the local RDMA device attribute +max_qp_rd_atom and the responder_resources value reported in the connect +request event. +.IP initiator_depth +The maximum number of outstanding RDMA read and atomic operations that the +local side will have to the remote side. Applies only to RDMA_PS_TCP. +This value must be less than or equal to the local RDMA device attribute +max_qp_init_rd_atom and the initiator_depth value reported in the connect +request event. +.IP flow_control +Specifies if hardware flow control is available. This value is exchanged +with the remote peer and is not used to configure the QP. Applies only to +RDMA_PS_TCP. +.IP retry_count +This value is ignored. +.IP rnr_retry_count +The maximum number of times that a send operation from the remote peer +should be retried on a connection after receiving a receiver not ready (RNR) +error. RNR errors are generated when a send request arrives before a buffer +has been posted to receive the incoming data. Applies only to RDMA_PS_TCP. +.IP srq +Specifies if the QP associated with the connection is using a shared receive +queue. This field is ignored by the library if a QP has been created on the +rdma_cm_id. Applies only to RDMA_PS_TCP. +.IP qp_num +Specifies the QP number associated with the connection. This field is ignored +by the library if a QP has been created on the rdma_cm_id. +.SH "INFINIBAND SPECIFIC" +In addition to the connection properties defined above, InfiniBand QPs are +configured with minimum RNR NAK timer and local ACK timeout values. The +minimum RNR NAK timer value is set to 0, for a delay of 655 ms. +The local ACK timeout is calculated based on the packet lifetime and local +HCA ACK delay. The packet lifetime is determined by the InfiniBand Subnet +Administrator and is part of the route (path record) information obtained +by the active side of the connection. The HCA ACK delay is a property of +the locally used HCA. +.P +The RNR retry count is a 3-bit value. +.SH "SEE ALSO" +rdma_listen(3), rdma_reject(3), rdma_get_cm_event(3) diff --git a/contrib/ofed/librdmacm/man/rdma_ack_cm_event.3 b/contrib/ofed/librdmacm/man/rdma_ack_cm_event.3 new file mode 100644 index 000000000000..3c243579d770 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_ack_cm_event.3 @@ -0,0 +1,18 @@ +.TH "RDMA_ACK_CM_EVENT" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_ack_cm_event \- Free a communication event. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_ack_cm_event +.BI "(struct rdma_cm_event *" event ");" +.SH ARGUMENTS +.IP "event" 12 +Event to be released. +.SH "DESCRIPTION" +All events which are allocated by rdma_get_cm_event must be released, +there should be a one-to-one correspondence between successful gets +and acks. This call frees the event structure and any memory that it +references. +.SH "SEE ALSO" +rdma_get_cm_event(3), rdma_destroy_id(3) diff --git a/contrib/ofed/librdmacm/man/rdma_bind_addr.3 b/contrib/ofed/librdmacm/man/rdma_bind_addr.3 new file mode 100644 index 000000000000..06f30ce7ac3d --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_bind_addr.3 @@ -0,0 +1,29 @@ +.TH "RDMA_BIND_ADDR" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_bind_addr \- Bind an RDMA identifier to a source address. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_bind_addr +.BI "(struct rdma_cm_id *" id "," +.BI "struct sockaddr *" addr ");" +.SH ARGUMENTS +.IP "id" 12 +RDMA identifier. +.IP "addr" 12 +Local address information. Wildcard values are permitted. +.SH "DESCRIPTION" +Associates a source address with an rdma_cm_id. The address may be +wildcarded. If binding to a specific local address, the rdma_cm_id +will also be bound to a local RDMA device. +.SH "NOTES" +Typically, this routine is called before calling rdma_listen to bind +to a specific port number, but it may also be called on the active side +of a connection before calling rdma_resolve_addr to bind to a specific +address. +.P +If used to bind to port 0, the rdma_cm will select an available port, +which can be retrieved with rdma_get_src_port(3). +.SH "SEE ALSO" +rdma_create_id(3), rdma_listen(3), rdma_resolve_addr(3), rdma_create_qp(3), +rdma_get_local_addr(3), rdma_get_src_port(3) diff --git a/contrib/ofed/librdmacm/man/rdma_cm.7 b/contrib/ofed/librdmacm/man/rdma_cm.7 new file mode 100644 index 000000000000..fd0495925e46 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_cm.7 @@ -0,0 +1,132 @@ +.TH "RDMA_CM" 7 "2008-01-02" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_cm \- RDMA communication manager. +.SH SYNOPSIS +.B "#include " +.SH "DESCRIPTION" +Used to establish communication over RDMA transports. +.SH "NOTES" +The RDMA CM is a communication manager used to setup reliable, connected +and unreliable datagram data transfers. It provides an RDMA transport +neutral interface for establishing connections. The API is based on sockets, +but adapted for queue pair (QP) based semantics: communication must be +over a specific RDMA device, and data transfers are message based. +.P +The RDMA CM only provides the communication management (connection setup / +teardown) portion of an RDMA API. It works in conjunction with the verbs +API defined by the libibverbs library. The libibverbs library provides the +interfaces needed to send and receive data. +.SH "CLIENT OPERATION" +This section provides a general overview of the basic operation for the active, +or client, side of communication. A general connection flow would be: +.IP rdma_create_event_channel +create channel to receive events +.IP rdma_create_id +allocate an rdma_cm_id, this is conceptually similar to a socket +.IP rdma_resolve_addr +obtain a local RDMA device to reach the remote address +.IP rdma_get_cm_event +wait for RDMA_CM_EVENT_ADDR_RESOLVED event +.IP rdma_ack_cm_event +ack event +.IP rdma_create_qp +allocate a QP for the communication +.IP rdma_resolve_route +determine the route to the remote address +.IP rdma_get_cm_event +wait for RDMA_CM_EVENT_ROUTE_RESOLVED event +.IP rdma_ack_cm_event +ack event +.IP rdma_connect +connect to the remote server +.IP rdma_get_cm_event +wait for RDMA_CM_EVENT_ESTABLISHED event +.IP rdma_ack_cm_event +ack event +.P +Perform data transfers over connection +.IP rdma_disconnect +tear-down connection +.IP rdma_get_cm_event +wait for RDMA_CM_EVENT_DISCONNECTED event +.IP rdma_ack_cm_event +ack event +.IP rdma_destroy_qp +destroy the QP +.IP rdma_destroy_id +release the rdma_cm_id +.IP rdma_destroy_event_channel +release the event channel +.P +An almost identical process is used to setup unreliable datagram (UD) +communication between nodes. No actual connection is formed between QPs +however, so disconnection is not needed. +.P +Although this example shows the client initiating the disconnect, either side +of a connection may initiate the disconnect. +.SH "SERVER OPERATION" +This section provides a general overview of the basic operation for the passive, +or server, side of communication. A general connection flow would be: +.IP rdma_create_event_channel +create channel to receive events +.IP rdma_create_id +allocate an rdma_cm_id, this is conceptually similar to a socket +.IP rdma_bind_addr +set the local port number to listen on +.IP rdma_listen +begin listening for connection requests +.IP rdma_get_cm_event +wait for RDMA_CM_EVENT_CONNECT_REQUEST event with a new rdma_cm_id +.IP rdma_create_qp +allocate a QP for the communication on the new rdma_cm_id +.IP rdma_accept +accept the connection request +.IP rdma_ack_cm_event +ack event +.IP rdma_get_cm_event +wait for RDMA_CM_EVENT_ESTABLISHED event +.IP rdma_ack_cm_event +ack event +.P +Perform data transfers over connection +.IP rdma_get_cm_event +wait for RDMA_CM_EVENT_DISCONNECTED event +.IP rdma_ack_cm_event +ack event +.IP rdma_disconnect +tear-down connection +.IP rdma_destroy_qp +destroy the QP +.IP rdma_destroy_id +release the connected rdma_cm_id +.IP rdma_destroy_id +release the listening rdma_cm_id +.IP rdma_destroy_event_channel +release the event channel +.SH "RETURN CODES" +.IP "= 0" +success +.IP "= -1" +error - see errno for more details +.P +Librdmacm functions return 0 to indicate success, and a -1 return value +to indicate failure. If a function operates asynchronously, a return value of 0 +means that the operation was successfully started. The operation could still +complete in error; users should check the status of the related event. If the +return value is -1, then errno will contain additional information +regarding the reason for the failure. +.P +Prior versions of the library would return -errno and not set errno for some cases +related to ENOMEM, ENODEV, ENODATA, EINVAL, and EADDRNOTAVAIL codes. Applications +that want to check these codes and have compatability with prior library versions +must manually set errno to the negative of the return code if it is < -1. +.SH "SEE ALSO" +rdma_create_event_channel(3), rdma_get_cm_event(3), rdma_create_id(3), +rdma_resolve_addr(3), rdma_bind_addr(3), rdma_create_qp(3), +rdma_resolve_route(3), rdma_connect(3), rdma_listen(3), rdma_accept(3), +rdma_reject(3), rdma_join_multicast(3), rdma_leave_multicast(3), rdma_notify(3), +rdma_ack_cm_event(3), rdma_disconnect(3), rdma_destroy_qp(3), rdma_destroy_id(3), +rdma_destroy_event_channel(3), rdma_get_devices(3), rdma_free_devices(3), +rdma_get_peer_addr(3), rdma_get_local_addr(3), +rdma_get_dst_port(3), rdma_get_src_port(3), rdma_set_option(3) +ucmatose(1), udaddy(1), mckey(1), rping(1) diff --git a/contrib/ofed/librdmacm/man/rdma_connect.3 b/contrib/ofed/librdmacm/man/rdma_connect.3 new file mode 100644 index 000000000000..8dab9ee42222 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_connect.3 @@ -0,0 +1,83 @@ +.TH "RDMA_CONNECT" 3 "2007-10-31" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_connect \- Initiate an active connection request. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_connect +.BI "(struct rdma_cm_id *" id "," +.BI "struct rdma_conn_param *" conn_param ");" +.SH ARGUMENTS +.IP "id" 12 +RDMA identifier. +.IP "conn_param" 12 +connection parameters. See CONNECTION PROPERTIES below for details. +.SH "DESCRIPTION" +For an rdma_cm_id of type RDMA_PS_TCP, this call initiates a connection request +to a remote destination. For an rdma_cm_id of type RDMA_PS_UDP, it initiates +a lookup of the remote QP providing the datagram service. +.SH "NOTES" +Users must have resolved a route to the destination address +by having called rdma_resolve_route before calling this routine. +.SH "CONNECTION PROPERTIES" +The following properties are used to configure the communication and specified +by the conn_param parameter when connecting or establishing datagram +communication. +.IP private_data +References a user-controlled data buffer. The contents of the buffer are +copied and transparently passed to the remote side as part of the +communication request. May be NULL if private_data is not required. +.IP private_data_len +Specifies the size of the user-controlled data buffer. Note that the actual +amount of data transferred to the remote side is transport dependent and may +be larger than that requested. +.IP responder_resources +The maximum number of outstanding RDMA read and atomic operations that the +local side will accept from the remote side. Applies only to RDMA_PS_TCP. +This value must be less than or equal to the local RDMA device attribute +max_qp_rd_atom and remote RDMA device attribute max_qp_init_rd_atom. The +remote endpoint can adjust this value when accepting the connection. +.IP initiator_depth +The maximum number of outstanding RDMA read and atomic operations that the +local side will have to the remote side. Applies only to RDMA_PS_TCP. +This value must be less than or equal to the local RDMA device attribute +max_qp_init_rd_atom and remote RDMA device attribute max_qp_rd_atom. The +remote endpoint can adjust this value when accepting the connection. +.IP flow_control +Specifies if hardware flow control is available. This value is exchanged +with the remote peer and is not used to configure the QP. Applies only to +RDMA_PS_TCP. +.IP retry_count +The maximum number of times that a data transfer operation should be retried +on the connection when an error occurs. This setting controls the number of +times to retry send, RDMA, and atomic operations when timeouts occur. +Applies only to RDMA_PS_TCP. +.IP rnr_retry_count +The maximum number of times that a send operation from the remote peer +should be retried on a connection after receiving a receiver not ready (RNR) +error. RNR errors are generated when a send request arrives before a buffer +has been posted to receive the incoming data. Applies only to RDMA_PS_TCP. +.IP srq +Specifies if the QP associated with the connection is using a shared receive +queue. This field is ignored by the library if a QP has been created on the +rdma_cm_id. Applies only to RDMA_PS_TCP. +.IP qp_num +Specifies the QP number associated with the connection. This field is ignored +by the library if a QP has been created on the rdma_cm_id. Applies only to +RDMA_PS_TCP. +.SH "INFINIBAND SPECIFIC" +In addition to the connection properties defined above, InfiniBand QPs are +configured with minimum RNR NAK timer and local ACK timeout values. The +minimum RNR NAK timer value is set to 0, for a delay of 655 ms. +The local ACK timeout is calculated based on the packet lifetime and local +HCA ACK delay. The packet lifetime is determined by the InfiniBand Subnet +Administrator and is part of the resolved route (path record) information. +The HCA ACK delay is a property of the locally used HCA. +.P +Retry count and RNR retry count values are 3-bit values. +.SH "IWARP SPECIFIC" +Connections established over iWarp RDMA devices currently require that the +active side of the connection send the first message. +.SH "SEE ALSO" +rdma_cm(7), rdma_create_id(3), rdma_resolve_route(3), rdma_disconnect(3), +rdma_listen(3), rdma_get_cm_event(3) diff --git a/contrib/ofed/librdmacm/man/rdma_create_event_channel.3 b/contrib/ofed/librdmacm/man/rdma_create_event_channel.3 new file mode 100644 index 000000000000..67db26885b87 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_create_event_channel.3 @@ -0,0 +1,28 @@ +.TH "RDMA_CREATE_EVENT_CHANNEL" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_create_event_channel \- Open a channel used to report communication events. +.SH SYNOPSIS +.B "#include " +.P +.B "struct rdma_event_channel *" rdma_create_event_channel +.BI "(" void ");" +.SH ARGUMENTS +.IP "void" 12 +no arguments +.SH "DESCRIPTION" +Asynchronous events are reported to users through event channels. +.SH "NOTES" +Event channels are used to direct all events on an rdma_cm_id. For many +clients, a single event channel may be sufficient, however, when managing +a large number of connections or cm_id's, users may find it useful to direct +events for different cm_id's to different channels for processing. +.P +All created event channels must be destroyed by calling +rdma_destroy_event_channel. Users should call rdma_get_cm_event to +retrieve events on an event channel. +.P +Each event channel is mapped to a file descriptor. The associated file +descriptor can be used and manipulated like any other fd to change its +behavior. Users may make the fd non-blocking, poll or select the fd, etc. +.SH "SEE ALSO" +rdma_cm(7), rdma_get_cm_event(3), rdma_destroy_event_channel(3) diff --git a/contrib/ofed/librdmacm/man/rdma_create_id.3 b/contrib/ofed/librdmacm/man/rdma_create_id.3 new file mode 100644 index 000000000000..eb29f3c7a736 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_create_id.3 @@ -0,0 +1,44 @@ +.TH "RDMA_CREATE_ID" 3 "2007-08-06" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_create_id \- Allocate a communication identifier. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_create_id +.BI "(struct rdma_event_channel *" channel "," +.BI "struct rdma_cm_id **" id "," +.BI "void *" context "," +.BI "enum rdma_port_space " ps ");" +.SH ARGUMENTS +.IP "channel" 12 +The communication channel that events associated with the +allocated rdma_cm_id will be reported on. +.IP "id" 12 +A reference where the allocated communication identifier will be +returned. +.IP "context" 12 +User specified context associated with the rdma_cm_id. +.IP "ps" 12 +RDMA port space. +.SH "DESCRIPTION" +Creates an identifier that is used to track communication information. +.SH "NOTES" +Rdma_cm_id's are conceptually equivalent to a socket for RDMA +communication. The difference is that RDMA communication requires +explicitly binding to a specified RDMA device before communication +can occur, and most operations are asynchronous in nature. Communication +events on an rdma_cm_id are reported through the associated event +channel. Users must release the rdma_cm_id by calling rdma_destroy_id. +.SH "PORT SPACE" +Details of the services provided by the different port spaces are outlined +below. +.IP RDMA_PS_TCP +Provides reliable, connection-oriented QP communication. Unlike TCP, the RDMA +port space provides message, not stream, based communication. +.IP RDMA_PS_UDP +Provides unreliable, connectionless QP communication. Supports both datagram +and multicast communication. +.SH "SEE ALSO" +rdma_cm(7), rdma_create_event_channel(3), rdma_destroy_id(3), rdma_get_devices(3), +rdma_bind_addr(3), rdma_resolve_addr(3), rdma_connect(3), rdma_listen(3), +rdma_set_option(3) diff --git a/contrib/ofed/librdmacm/man/rdma_create_qp.3 b/contrib/ofed/librdmacm/man/rdma_create_qp.3 new file mode 100644 index 000000000000..09314991c388 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_create_qp.3 @@ -0,0 +1,30 @@ +.TH "RDMA_CREATE_QP" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_create_qp \- Allocate a QP. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_create_qp +.BI "(struct rdma_cm_id *" id "," +.BI "struct ibv_pd *" pd "," +.BI "struct ibv_qp_init_attr *" qp_init_attr ");" +.SH ARGUMENTS +.IP "id" 12 +RDMA identifier. +.IP "pd" 12 +protection domain for the QP. +.IP "qp_init_attr" 12 +initial QP attributes. +.SH "DESCRIPTION" +Allocate a QP associated with the specified rdma_cm_id and transition it +for sending and receiving. +.SH "NOTES" +The rdma_cm_id must be bound to a local RDMA device before calling this +function, and the protection domain must be for that same device. +QPs allocated to an rdma_cm_id are automatically transitioned by the +librdmacm through their states. After being allocated, the QP will be +ready to handle posting of receives. If the QP is unconnected, it will +be ready to post sends. +.SH "SEE ALSO" +rdma_bind_addr(3), rdma_resolve_addr(3), rdma_destroy_qp(3), ibv_create_qp(3), +ibv_modify_qp(3) diff --git a/contrib/ofed/librdmacm/man/rdma_destroy_event_channel.3 b/contrib/ofed/librdmacm/man/rdma_destroy_event_channel.3 new file mode 100644 index 000000000000..ed4636e371bb --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_destroy_event_channel.3 @@ -0,0 +1,19 @@ +.TH "RDMA_DESTROY_EVENT_CHANNEL" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_destroy_event_channel \- Close an event communication channel. +.SH SYNOPSIS +.B "#include " +.P +.B "void" rdma_destroy_event_channel +.BI "(struct rdma_event_channel *" channel ");" +.SH ARGUMENTS +.IP "channel" 12 +The communication channel to destroy. +.SH "DESCRIPTION" +Release all resources associated with an event channel and closes the +associated file descriptor. +.SH "NOTES" +All rdma_cm_id's associated with the event channel must be destroyed, +and all returned events must be acked before calling this function. +.SH "SEE ALSO" +rdma_create_event_channel(3), rdma_get_cm_event(3), rdma_ack_cm_event(3) diff --git a/contrib/ofed/librdmacm/man/rdma_destroy_id.3 b/contrib/ofed/librdmacm/man/rdma_destroy_id.3 new file mode 100644 index 000000000000..77e8151ddd83 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_destroy_id.3 @@ -0,0 +1,19 @@ +.TH "RDMA_DESTROY_ID" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_destroy_id \- Release a communication identifier. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_destroy_id +.BI "(struct rdma_cm_id *" id ");" +.SH ARGUMENTS +.IP "id" 12 +The communication identifier to destroy. +.SH "DESCRIPTION" +Destroys the specified rdma_cm_id and cancels any outstanding +asynchronous operation. +.SH "NOTES" +Users must free any associated QP with the rdma_cm_id before +calling this routine and ack an related events. +.SH "SEE ALSO" +rdma_create_id(3), rdma_destroy_qp(3), rdma_ack_cm_event(3) diff --git a/contrib/ofed/librdmacm/man/rdma_destroy_qp.3 b/contrib/ofed/librdmacm/man/rdma_destroy_qp.3 new file mode 100644 index 000000000000..bb1360eb5140 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_destroy_qp.3 @@ -0,0 +1,18 @@ +.TH "RDMA_DESTROY_QP" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_destroy_qp \- Deallocate a QP. +.SH SYNOPSIS +.B "#include " +.P +.B "void" rdma_destroy_qp +.BI "(struct rdma_cm_id *" id ");" +.SH ARGUMENTS +.IP "id" 12 +RDMA identifier. +.SH "DESCRIPTION" +Destroy a QP allocated on the rdma_cm_id. +.SH "NOTES" +Users must destroy any QP associated with an rdma_cm_id before +destroying the ID. +.SH "SEE ALSO" +rdma_create_qp(3), rdma_destroy_id(3), ibv_destroy_qp(3) diff --git a/contrib/ofed/librdmacm/man/rdma_disconnect.3 b/contrib/ofed/librdmacm/man/rdma_disconnect.3 new file mode 100644 index 000000000000..8b2a03500d39 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_disconnect.3 @@ -0,0 +1,19 @@ +.TH "RDMA_DISCONNECT" 3 "2008-01-02" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_disconnect \- This function disconnects a connection. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_disconnect +.BI "(struct rdma_cm_id *" id ");" +.SH ARGUMENTS +.IP "id" 12 +RDMA identifier. +.SH "DESCRIPTION" +Disconnects a connection and transitions any associated QP to the error state, +which will flush any posted work requests to the completion queue. This +routine may be called by both the client and server side of a connection. +After successfully disconnecting, an RDMA_CM_EVENT_DISCONNECTED event will be +generated on both sides of the connection. +.SH "SEE ALSO" +rdma_connect(3), rdma_listen(3), rdma_accept(3), rdma_get_cm_event(3) diff --git a/contrib/ofed/librdmacm/man/rdma_event_str.3 b/contrib/ofed/librdmacm/man/rdma_event_str.3 new file mode 100644 index 000000000000..612698322b6a --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_event_str.3 @@ -0,0 +1,15 @@ +.TH "RDMA_EVENT_STR" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_event_str \- Returns a string representation of an rdma cm event. +.SH SYNOPSIS +.B "#include " +.P +.B "char *" rdma_event_str +.BI "("enum rdma_cm_event_type " event ");" +.SH ARGUMENTS +.IP "event" 12 +Asynchronous event. +.SH "DESCRIPTION" +Returns a string representation of an asynchronous event. +.SH "SEE ALSO" +rdma_get_cm_event(3) diff --git a/contrib/ofed/librdmacm/man/rdma_free_devices.3 b/contrib/ofed/librdmacm/man/rdma_free_devices.3 new file mode 100644 index 000000000000..1ed4cb3205b4 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_free_devices.3 @@ -0,0 +1,15 @@ +.TH "RDMA_FREE_DEVICES" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_free_devices \- Frees the list of devices returned by rdma_get_devices. +.SH SYNOPSIS +.B "#include " +.P +.B "void" rdma_free_devices +.BI "(struct ibv_context **" list ");" +.SH ARGUMENTS +.IP "list" 12 +List of devices returned from rdma_get_devices. +.SH "DESCRIPTION" +Frees the device array returned by rdma_get_devices. +.SH "SEE ALSO" +rdma_get_devices(3) diff --git a/contrib/ofed/librdmacm/man/rdma_get_cm_event.3 b/contrib/ofed/librdmacm/man/rdma_get_cm_event.3 new file mode 100644 index 000000000000..79bf606c5daf --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_get_cm_event.3 @@ -0,0 +1,156 @@ +.TH "RDMA_GET_CM_EVENT" 3 "2007-10-31" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_get_cm_event \- Retrieves the next pending communication event. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_get_cm_event +.BI "(struct rdma_event_channel *" channel "," +.BI "struct rdma_cm_event **" event ");" +.SH ARGUMENTS +.IP "channel" 12 +Event channel to check for events. +.IP "event" 12 +Allocated information about the next communication event. +.SH "DESCRIPTION" +Retrieves a communication event. If no events are pending, by default, +the call will block until an event is received. +.SH "NOTES" +The default synchronous behavior of this routine can be changed by +modifying the file descriptor associated with the given channel. All +events that are reported must be acknowledged by calling rdma_ack_cm_event. +Destruction of an rdma_cm_id will block until related events have been +acknowledged. +.SH "EVENT DATA" +Communication event details are returned in the rdma_cm_event structure. +This structure is allocated by the rdma_cm and released by the +rdma_ack_cm_event routine. Details of the rdma_cm_event structure are +given below. +.IP "id" 12 +The rdma_cm identifier associated with the event. If the event type is +RDMA_CM_EVENT_CONNECT_REQUEST, then this references a new id for that +communication. +.IP "listen_id" 12 +For RDMA_CM_EVENT_CONNECT_REQUEST event types, this references the +corresponding listening request identifier. +.IP "event" 12 +Specifies the type of communication event which occurred. See EVENT TYPES +below. +.IP "status" 12 +Returns any asynchronous error information associated with an event. The +status is zero unless the corresponding operation failed. +.IP "param" 12 +Provides additional details based on the type of event. Users should +select the conn or ud subfields based on the rdma_port_space of the +rdma_cm_id associated with the event. See UD EVENT DATA and CONN EVENT +DATA below. +.SH "UD EVENT DATA" +Event parameters related to unreliable datagram (UD) services: RDMA_PS_UDP and +RDMA_PS_IPOIB. The UD event data is valid for RDMA_CM_EVENT_ESTABLISHED and +RDMA_CM_EVENT_MULTICAST_JOIN events, unless stated otherwise. +.IP "private_data" 12 +References any user-specified data associated with RDMA_CM_EVENT_CONNECT_REQUEST +or RDMA_CM_EVENT_ESTABLISHED events. The data referenced by this field matches +that specified by the remote side when calling rdma_connect or rdma_accept. +This field is NULL if the event does not include private data. The buffer +referenced by this pointer is deallocated when calling rdma_ack_cm_event. +.IP "private_data_len" 12 +The size of the private data buffer. Users should note that the size of +the private data buffer may be larger than the amount of private data +sent by the remote side. Any additional space in the buffer will be +zeroed out. +.IP "ah_attr" 12 +Address information needed to send data to the remote endpoint(s). +Users should use this structure when allocating their address handle. +.IP "qp_num" 12 +QP number of the remote endpoint or multicast group. +.IP "qkey" 12 +QKey needed to send data to the remote endpoint(s). +.SH "CONN EVENT DATA" +Event parameters related to connected QP services: RDMA_PS_TCP. The +connection related event data is valid for RDMA_CM_EVENT_CONNECT_REQUEST +and RDMA_CM_EVENT_ESTABLISHED events, unless stated otherwise. +.IP "private_data" 12 +References any user-specified data associated with the event. The data +referenced by this field matches that specified by the remote side when +calling rdma_connect or rdma_accept. This field is NULL if the event +does not include private data. The buffer referenced by this pointer is +deallocated when calling rdma_ack_cm_event. +.IP "private_data_len" 12 +The size of the private data buffer. Users should note that the size of +the private data buffer may be larger than the amount of private data +sent by the remote side. Any additional space in the buffer will be +zeroed out. +.IP "responder_resources" 12 +The number of responder resources requested of the recipient. +This field matches the initiator depth specified by the remote node when +calling rdma_connect and rdma_accept. +.IP "initiator_depth" 12 +The maximum number of outstanding RDMA read/atomic operations +that the recipient may have outstanding. This field matches the responder +resources specified by the remote node when calling rdma_connect and +rdma_accept. +.IP "flow_control" 12 +Indicates if hardware level flow control is provided by the sender. +.IP "retry_count" 12 +For RDMA_CM_EVENT_CONNECT_REQUEST events only, indicates the number of times +that the recipient should retry send operations. +.IP "rnr_retry_count" 12 +The number of times that the recipient should retry receiver not ready (RNR) +NACK errors. +.IP "srq" 12 +Specifies if the sender is using a shared-receive queue. +.IP "qp_num" 12 +Indicates the remote QP number for the connection. +.SH "EVENT TYPES" +The following types of communication events may be reported. +.IP RDMA_CM_EVENT_ADDR_RESOLVED +Address resolution (rdma_resolve_addr) completed successfully. +.IP RDMA_CM_EVENT_ADDR_ERROR +Address resolution (rdma_resolve_addr) failed. +.IP RDMA_CM_EVENT_ROUTE_RESOLVED +Route resolution (rdma_resolve_route) completed successfully. +.IP RDMA_CM_EVENT_ROUTE_ERROR +Route resolution (rdma_resolve_route) failed. +.IP RDMA_CM_EVENT_CONNECT_REQUEST +Generated on the passive side to notify the user of a new connection request. +.IP RDMA_CM_EVENT_CONNECT_RESPONSE +Generated on the active side to notify the user of a successful response +to a connection request. It is only generated on rdma_cm_id's that do not +have a QP associated with them. +.IP RDMA_CM_EVENT_CONNECT_ERROR +Indicates that an error has occurred trying to establish or a connection. +May be generated on the active or passive side of a connection. +.IP RDMA_CM_EVENT_UNREACHABLE +Generated on the active side to notify the user that the remote server is +not reachable or unable to respond to a connection request. +.IP RDMA_CM_EVENT_REJECTED +Indicates that a connection request or response was rejected by the remote +end point. +.IP RDMA_CM_EVENT_ESTABLISHED +Indicates that a connection has been established with the remote end point. +.IP RDMA_CM_EVENT_DISCONNECTED +The connection has been disconnected. +.IP RDMA_CM_EVENT_DEVICE_REMOVAL +The local RDMA device associated with the rdma_cm_id has been removed. +Upon receiving this event, the user must destroy the related rdma_cm_id. +.IP RDMA_CM_EVENT_MULTICAST_JOIN +The multicast join operation (rdma_join_multicast) completed successfully. +.IP RDMA_CM_EVENT_MULTICAST_ERROR +An error either occurred joining a multicast group, or, if the group had +already been joined, on an existing group. The specified multicast group is +no longer accessible and should be rejoined, if desired. +.IP RDMA_CM_EVENT_ADDR_CHANGE +The network device associated with this ID through address resolution changed +its HW address, eg following of bonding failover. This event can serve as a +hint for applications who want the links used for their RDMA sessions to +align with the network stack. +.IP RDMA_CM_EVENT_TIMEWAIT_EXIT +The QP associated with a connection has exited its timewait state and is now +ready to be re-used. After a QP has been disconnected, it is maintained in +a timewait state to allow any in flight packets to exit the network. After +the timewait state has completed, the rdma_cm will report this event. +.SH "SEE ALSO" +rdma_ack_cm_event(3), rdma_create_event_channel(3), rdma_resolve_addr(3), +rdma_resolve_route(3), rdma_connect(3), rdma_listen(3), rdma_join_multicast(3), +rdma_destroy_id(3), rdma_event_str(3) diff --git a/contrib/ofed/librdmacm/man/rdma_get_devices.3 b/contrib/ofed/librdmacm/man/rdma_get_devices.3 new file mode 100644 index 000000000000..05dcee2ed81a --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_get_devices.3 @@ -0,0 +1,20 @@ +.TH "RDMA_GET_DEVICES" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_get_devices \- Get a list of RDMA devices currently available. +.SH SYNOPSIS +.B "#include " +.P +.B "struct ibv_context **" rdma_get_devices +.BI "(int *" num_devices ");" +.SH ARGUMENTS +.IP "num_devices" 12 +If non-NULL, set to the number of devices returned. +.SH "DESCRIPTION" +Return a NULL-terminated array of opened RDMA devices. Callers can use +this routine to allocate resources on specific RDMA devices that will be +shared across multiple rdma_cm_id's. +.SH "NOTES" +The returned array must be released by calling rdma_free_devices. Devices +remain opened while the librdmacm is loaded. +.SH "SEE ALSO" +rdma_free_devices(3) diff --git a/contrib/ofed/librdmacm/man/rdma_get_dst_port.3 b/contrib/ofed/librdmacm/man/rdma_get_dst_port.3 new file mode 100644 index 000000000000..92932e95ebd4 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_get_dst_port.3 @@ -0,0 +1,17 @@ +.TH "RDMA_GET_DST_PORT" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_get_dst_port \- Returns the remote port number of a bound rdma_cm_id. +.SH SYNOPSIS +.B "#include " +.P +.B "uint16_t" rdma_get_dst_port +.BI "(struct rdma_cm_id *" id ");" +.SH ARGUMENTS +.IP "id" 12 +RDMA identifier. +.SH "DESCRIPTION" +Returns the remote port number for an rdma_cm_id that has been bound to +a remote address. +.SH "SEE ALSO" +rdma_connect(3), rdma_accept(3), rdma_get_cm_event(3), rdma_get_src_port(3), +rdma_get_local_addr(3), rdma_get_peer_addr(3) diff --git a/contrib/ofed/librdmacm/man/rdma_get_local_addr.3 b/contrib/ofed/librdmacm/man/rdma_get_local_addr.3 new file mode 100644 index 000000000000..80856270f440 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_get_local_addr.3 @@ -0,0 +1,17 @@ +.TH "RDMA_GET_LOCAL_ADDR" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_get_local_addr \- Returns the local IP address of a bound rdma_cm_id. +.SH SYNOPSIS +.B "#include " +.P +.B "struct sockaddr *" rdma_get_local_addr +.BI "(struct rdma_cm_id *" id ");" +.SH ARGUMENTS +.IP "id" 12 +RDMA identifier. +.SH "DESCRIPTION" +Returns the local IP address for an rdma_cm_id that has been bound to +a local device. +.SH "SEE ALSO" +rdma_bind_addr(3), rdma_resolve_addr(3), rdma_get_src_port(3), +rdma_get_dst_port(3), rdma_get_peer_addr(3) diff --git a/contrib/ofed/librdmacm/man/rdma_get_peer_addr.3 b/contrib/ofed/librdmacm/man/rdma_get_peer_addr.3 new file mode 100644 index 000000000000..880e9c576748 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_get_peer_addr.3 @@ -0,0 +1,16 @@ +.TH "RDMA_GET_PEER_ADDR" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_get_peer_addr \- Returns the remote IP address of a bound rdma_cm_id. +.SH SYNOPSIS +.B "#include " +.P +.B "struct sockaddr *" rdma_get_peer_addr +.BI "(struct rdma_cm_id *" id ");" +.SH ARGUMENTS +.IP "id" 12 +RDMA identifier. +.SH "DESCRIPTION" +Returns the remote IP address associated with an rdma_cm_id. +.SH "SEE ALSO" +rdma_resolve_addr(3), rdma_get_src_port(3), rdma_get_dst_port(3), +rdma_get_local_addr(3) diff --git a/contrib/ofed/librdmacm/man/rdma_get_src_port.3 b/contrib/ofed/librdmacm/man/rdma_get_src_port.3 new file mode 100644 index 000000000000..0a2f44585fa6 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_get_src_port.3 @@ -0,0 +1,17 @@ +.TH "RDMA_GET_SRC_PORT" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_get_src_port \- Returns the local port number of a bound rdma_cm_id. +.SH SYNOPSIS +.B "#include " +.P +.B "uint16_t" rdma_get_src_port +.BI "(struct rdma_cm_id *" id ");" +.SH ARGUMENTS +.IP "id" 12 +RDMA identifier. +.SH "DESCRIPTION" +Returns the local port number for an rdma_cm_id that has been bound to +a local address. +.SH "SEE ALSO" +rdma_bind_addr(3), rdma_resolve_addr(3), rdma_get_dst_port(3), +rdma_get_local_addr(3), rdma_get_peer_addr(3) diff --git a/contrib/ofed/librdmacm/man/rdma_join_multicast.3 b/contrib/ofed/librdmacm/man/rdma_join_multicast.3 new file mode 100644 index 000000000000..2df57a03b9de --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_join_multicast.3 @@ -0,0 +1,32 @@ +.TH "RDMA_JOIN_MULTICAST" 3 "2008-01-02" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_join_multicast \- Joins a multicast group. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_join_multicast +.BI "(struct rdma_cm_id *" id "," +.BI "struct sockaddr *" addr "," +.BI "void *" context ");" +.SH ARGUMENTS +.IP "id" 12 +Communication identifier associated with the request. +.IP "addr" 12 +Multicast address identifying the group to join. +.IP "context" 12 +User-defined context associated with the join request. +.SH "DESCRIPTION" +Joins a multicast group and attaches an associated QP to the group. +.SH "NOTES" +Before joining a multicast group, the rdma_cm_id must be bound to +an RDMA device by calling rdma_bind_addr or rdma_resolve_addr. Use of +rdma_resolve_addr requires the local routing tables to resolve the +multicast address to an RDMA device, unless a specific source address +is provided. The user must call rdma_leave_multicast to leave the +multicast group and release any multicast resources. After the join +operation completes, any associated QP is automatically attached to the +multicast group, and the join context is returned to the user through +the private_data field in the rdma_cm_event. +.SH "SEE ALSO" +rdma_leave_multicast(3), rdma_bind_addr(3), rdma_resolve_addr(3), rdma_create_qp(3), +rdma_get_cm_event(3) diff --git a/contrib/ofed/librdmacm/man/rdma_leave_multicast.3 b/contrib/ofed/librdmacm/man/rdma_leave_multicast.3 new file mode 100644 index 000000000000..e4262e826e92 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_leave_multicast.3 @@ -0,0 +1,24 @@ +.TH "RDMA_LEAVE_MULTICAST" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_leave_multicast \- Leaves a multicast group. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_leave_multicast +.BI "(struct rdma_cm_id *" id "," +.BI "struct sockaddr *" addr ");" +.SH ARGUMENTS +.IP "id" 12 +Communication identifier associated with the request. +.IP "addr" 12 +Multicast address identifying the group to leave. +.SH "DESCRIPTION" +Leaves a multicast group and detaches an associated QP from the group. +.SH "NOTES" +Calling this function before a group has been fully joined results in +canceling the join operation. Users should be aware that messages +received from the multicast group may stilled be queued for +completion processing immediately after leaving a multicast group. +Destroying an rdma_cm_id will automatically leave all multicast groups. +.SH "SEE ALSO" +rdma_join_multicast(3), rdma_destroy_qp(3) diff --git a/contrib/ofed/librdmacm/man/rdma_listen.3 b/contrib/ofed/librdmacm/man/rdma_listen.3 new file mode 100644 index 000000000000..426618480d50 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_listen.3 @@ -0,0 +1,28 @@ +.TH "RDMA_LISTEN" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_listen \- Listen for incoming connection requests. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_listen +.BI "(struct rdma_cm_id *" id "," +.BI "int " backlog ");" +.SH ARGUMENTS +.IP "id" 12 +RDMA identifier. +.IP "backlog" 12 +backlog of incoming connection requests. +.SH "DESCRIPTION" +Initiates a listen for incoming connection requests or datagram service +lookup. The listen will be restricted to the locally bound source +address. +.SH "NOTES" +Users must have bound the rdma_cm_id to a local address by calling +rdma_bind_addr before calling this routine. If the rdma_cm_id is +bound to a specific IP address, the listen will be restricted to that +address and the associated RDMA device. If the rdma_cm_id is bound +to an RDMA port number only, the listen will occur across all RDMA +devices. +.SH "SEE ALSO" +rdma_cm(7), rdma_bind_addr(3), rdma_connect(3), rdma_accept(3), rdma_reject(3), +rdma_get_cm_event(3) diff --git a/contrib/ofed/librdmacm/man/rdma_migrate_id.3 b/contrib/ofed/librdmacm/man/rdma_migrate_id.3 new file mode 100644 index 000000000000..ffbad45a2cca --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_migrate_id.3 @@ -0,0 +1,27 @@ +.TH "RDMA_MIGRATE_ID" 3 "2007-11-13" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_migrate_id \- Move a communication identifer to a different event channel. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_migrate_id +.BI "(struct rdma_cm_id *" id "," +.BI "struct rdma_event_channel *" channel ");" +.SH ARGUMENTS +.IP "id" 12 +An existing communication identifier to migrate. +.IP "channel" 12 +The communication channel that events associated with the +allocated rdma_cm_id will be reported on. +.SH "DESCRIPTION" +Migrates a communication identifier to a different event channel. +.SH "NOTES" +This routine migrates a communication identifier to the specified event +channel and moves any pending events associated with the rdma_cm_id +to the new channel. Users should not poll for events on the +rdma_cm_id's current event channel or invoke other routines on the +rdma_cm_id while migrating between channels. This call will block while +there are any unacknowledged events on the current event channel. +.SH "SEE ALSO" +rdma_cm(7), rdma_create_event_channel(3), rdma_create_id(3), +rdma_get_cm_event(3) diff --git a/contrib/ofed/librdmacm/man/rdma_notify.3 b/contrib/ofed/librdmacm/man/rdma_notify.3 new file mode 100644 index 000000000000..7114ac42346e --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_notify.3 @@ -0,0 +1,29 @@ +.TH "RDMA_NOTIFY" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_notify \- Notifies the librdmacm of an asynchronous event. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_notify +.BI "(struct rdma_cm_id *" id "," +.BI "enum ibv_event_type " event ");" +.SH ARGUMENTS +.IP "id" 12 +RDMA identifier. +.IP "event" 12 +Asynchronous event. +.SH "DESCRIPTION" +Used to notify the librdmacm of asynchronous events that have occurred +on a QP associated with the rdma_cm_id. +.SH "NOTES" +Asynchronous events that occur on a QP are reported through the user's +device event handler. This routine is used to notify the librdmacm of +communication events. In most cases, use of this routine is not +necessary, however if connection establishment is done out of band +(such as done through Infiniband), it's possible to receive data on a +QP that is not yet considered connected. This routine forces the +connection into an established state in this case in order to handle +the rare situation where the connection never forms on its own. +Events that should be reported to the CM are: IB_EVENT_COMM_EST. +.SH "SEE ALSO" +rdma_connect(3), rdma_accept(3), rdma_listen(3) diff --git a/contrib/ofed/librdmacm/man/rdma_reject.3 b/contrib/ofed/librdmacm/man/rdma_reject.3 new file mode 100644 index 000000000000..dc3216018c40 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_reject.3 @@ -0,0 +1,29 @@ +.TH "RDMA_REJECT" 3 "2007-05-15" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_reject \- Called to reject a connection request. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_reject +.BI "(struct rdma_cm_id *" id "," +.BI "const void *" private_data "," +.BI "uint8_t " private_data_len ");" +.SH ARGUMENTS +.IP "id" 12 +Connection identifier associated with the request. +.IP "private_data" 12 +Optional private data to send with the reject message. +.IP "private_data_len" 12 +Specifies the size of the user-controlled data buffer. Note that the actual +amount of data transferred to the remote side is transport dependent and may +be larger than that requested. +.SH "DESCRIPTION" +Called from the listening side to reject a connection or datagram +service lookup request. +.SH "NOTES" +After receiving a connection request event, a user may call rdma_reject +to reject the request. If the underlying RDMA transport supports +private data in the reject message, the specified data will be passed to +the remote side. +.SH "SEE ALSO" +rdma_listen(3), rdma_accept(3), rdma_get_cm_event(3) diff --git a/contrib/ofed/librdmacm/man/rdma_resolve_addr.3 b/contrib/ofed/librdmacm/man/rdma_resolve_addr.3 new file mode 100644 index 000000000000..e612606bfeb5 --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_resolve_addr.3 @@ -0,0 +1,43 @@ +.TH "RDMA_RESOLVE_ADDR" 3 "2007-10-31" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_resolve_addr \- Resolve destination and optional source addresses. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_resolve_addr +.BI "(struct rdma_cm_id *" id "," +.BI "struct sockaddr *" src_addr "," +.BI "struct sockaddr *" dst_addr "," +.BI "int " timeout_ms ");" +.SH ARGUMENTS +.IP "id" 12 +RDMA identifier. +.IP "src_addr" 12 +Source address information. This parameter may be NULL. +.IP "dst_addr" 12 +Destination address information. +.IP "timeout_ms" 12 +Time to wait for resolution to complete. +.SH "DESCRIPTION" +Resolve destination and optional source addresses from IP addresses +to an RDMA address. If successful, the specified rdma_cm_id will +be bound to a local device. +.SH "NOTES" +This call is used to map a given destination IP address to a usable RDMA +address. The IP to RDMA address mapping is done using the local routing +tables, or via ARP. +If a source address is given, the rdma_cm_id is bound to that +address, the same as if rdma_bind_addr were called. If no source +address is given, and the rdma_cm_id has not yet been bound to a device, +then the rdma_cm_id will be bound to a source address based on the +local routing tables. After this call, the rdma_cm_id will be bound to +an RDMA device. This call is typically made from the active side of a +connection before calling rdma_resolve_route and rdma_connect. +.SH "INFINIBAND SPECIFIC" +This call maps the destination and, if given, source IP addresses to GIDs. +In order to perform the mapping, IPoIB must be running on both the local +and remote nodes. +.SH "SEE ALSO" +rdma_create_id(3), rdma_resolve_route(3), rdma_connect(3), rdma_create_qp(3), +rdma_get_cm_event(3), rdma_bind_addr(3), rdma_get_src_port(3), +rdma_get_dst_port(3), rdma_get_local_addr(3), rdma_get_peer_addr(3) diff --git a/contrib/ofed/librdmacm/man/rdma_resolve_route.3 b/contrib/ofed/librdmacm/man/rdma_resolve_route.3 new file mode 100644 index 000000000000..ac1b3bccf5ec --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_resolve_route.3 @@ -0,0 +1,25 @@ +.TH "RDMA_RESOLVE_ROUTE" 3 "2007-10-31" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_resolve_route \- Resolve the route information needed to establish a connection. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_resolve_route +.BI "(struct rdma_cm_id *" id "," +.BI "int " timeout_ms ");" +.SH ARGUMENTS +.IP "id" 12 +RDMA identifier. +.IP "timeout_ms" 12 +Time to wait for resolution to complete. +.SH "DESCRIPTION" +Resolves an RDMA route to the destination address in order to establish +a connection. The destination address must have already been resolved +by calling rdma_resolve_addr. +.SH "NOTES" +This is called on the client side of a connection after calling +rdma_resolve_addr, but before calling rdma_connect. +.SH "INFINIBAND SPECIFIC" +This call obtains a path record that is used by the connection. +.SH "SEE ALSO" +rdma_resolve_addr(3), rdma_connect(3), rdma_get_cm_event(3) diff --git a/contrib/ofed/librdmacm/man/rdma_set_option.3 b/contrib/ofed/librdmacm/man/rdma_set_option.3 new file mode 100644 index 000000000000..ffa516cc194a --- /dev/null +++ b/contrib/ofed/librdmacm/man/rdma_set_option.3 @@ -0,0 +1,30 @@ +.TH "RDMA_SET_OPTION" 3 "2007-08-06" "librdmacm" "Librdmacm Programmer's Manual" librdmacm +.SH NAME +rdma_set_option \- Set communication options for an rdma_cm_id. +.SH SYNOPSIS +.B "#include " +.P +.B "int" rdma_set_option +.BI "(struct rdma_cm_id *" id "," +.BI "int " level "," +.BI "int " optname "," +.BI "void *" optval "," +.BI "size_t " optlen ");" +.SH ARGUMENTS +.IP "id" 12 +RDMA identifier. +.IP "level" 12 +Protocol level of the option to set. +.IP "optname" 12 +Name of the option, relative to the level, to set. +.IP "optval" 12 +Reference to the option data. The data is dependent on the level and optname. +.IP "optlen" 12 +The size of the %optval buffer. +.SH "DESCRIPTION" +Sets communication options for an rdma_cm_id. This call is used to override +the default system settings. +.SH "NOTES" +Option details may be found in the relevent header files. +.SH "SEE ALSO" +rdma_create_id(3) diff --git a/contrib/ofed/librdmacm/man/rping.1 b/contrib/ofed/librdmacm/man/rping.1 new file mode 100644 index 000000000000..a2b7b6be604b --- /dev/null +++ b/contrib/ofed/librdmacm/man/rping.1 @@ -0,0 +1,54 @@ +.TH "RPING" 1 "2007-05-15" "librdmacm" "librdmacm" librdmacm +.SH NAME +rping \- RDMA CM connection and RDMA ping-pong test. +.SH SYNOPSIS +.sp +.nf +\fIrping\fR -s [-v] [-V] [-d] [-P] [-a address] [-p port] + [-C message_count] [-S message_size] +\fIrping\fR -c [-v] [-V] [-d] -a address [-p port] + [-C message_count] [-S message_size] +.fi +.SH "DESCRIPTION" +Establishes a reliable RDMA connection between two nodes using the +librdmacm, optionally performs RDMA transfers between the nodes, +then disconnects. +.SH "OPTIONS" +.TP +\-s +Run as the server. +.TP +\-c +Run as the client. +.TP +\-a address +On the server, specifies the network address to bind the connection to. +On the client, specifies the server address to connect to. +.TP +\-p +Port number for listening server. +.TP +\-v +Display ping data. +.TP +\-V +Validate ping data. +.TP +\-d +Display debug information. +.TP +\-C message_count +The number of messages to transfer over each connection. (default infinite) +.TP +\-S message_size +The size of each message transferred, in bytes. (default 100) +.TP +\-P +Run the server in persistent mode. This allows multiple rping clients +to connect to a single server instance. The server will run until killed. +.SH "NOTES" +Because this test maps RDMA resources to userspace, users must ensure +that they have available system resources and permissions. See the +libibverbs README file for additional details. +.SH "SEE ALSO" +rdma_cm(7), ucmatose(1), udaddy(1), mckey(1) diff --git a/contrib/ofed/librdmacm/man/ucmatose.1 b/contrib/ofed/librdmacm/man/ucmatose.1 new file mode 100644 index 000000000000..73477ea6dcf7 --- /dev/null +++ b/contrib/ofed/librdmacm/man/ucmatose.1 @@ -0,0 +1,50 @@ +.TH "UCMATOSE" 1 "2007-05-15" "librdmacm" "librdmacm" librdmacm +.SH NAME +ucmatose \- RDMA CM connection and simple ping-pong test. +.SH SYNOPSIS +.sp +.nf +\fIucmatose\fR [-s server_address] [-b bind_address] [-c connections] + [-C message_count] [-S message_size] +\fIucmatose\fR -s server_address [-b bind_address] [-c connections] + [-C message_count] [-S message_size] [-t tos] +.fi +.SH "DESCRIPTION" +Establishes a set of reliable RDMA connections between two nodes using the +librdmacm, optionally transfers data between the nodes, then disconnects. +.SH "OPTIONS" +.TP +\-s server_address +The network name or IP address of the server system listening for +connections. The used name or address must route over an RDMA device. +This option must be specified by the client. +.TP +\-b bind_address +The local network address to bind to. +.TP +\-c connections +The number of connections to establish between the client and server. +(default 1) +.TP +\-C message_count +The number of messages to transfer over each connection. (default 10) +.TP +\-S message_size +The size of each message transferred, in bytes. (default 100) +.TP +\-t tos +Indicates the type of service used for the communication. Type of service +is implementation dependent based on subnet configuration. +.TP +\-m +Tests event channel migration. Migrates all communication identifiers to +a different event channel for disconnect events. +.SH "NOTES" +Basic usage is to start ucmatose on a server system, then run +ucmatose -s server_name on a client system. +.P +Because this test maps RDMA resources to userspace, users must ensure +that they have available system resources and permissions. See the +libibverbs README file for additional details. +.SH "SEE ALSO" +rdma_cm(7), udaddy(1), mckey(1), rping(1) diff --git a/contrib/ofed/librdmacm/man/udaddy.1 b/contrib/ofed/librdmacm/man/udaddy.1 new file mode 100644 index 000000000000..2f56b465b211 --- /dev/null +++ b/contrib/ofed/librdmacm/man/udaddy.1 @@ -0,0 +1,54 @@ +.TH "UDADDY" 1 "2007-05-15" "librdmacm" "librdmacm" librdmacm +.SH NAME +udaddy \- RDMA CM datagram setup and simple ping-pong test. +.SH SYNOPSIS +.sp +.nf +\fIudaddy\fR [-s server_address] [-b bind_address] [-c connections] + [-C message_count] [-S message_size] [-p port_space] +\fIudaddy\fR -s server_address [-b bind_address] [-c connections] + [-C message_count] [-S message_size] [-t tos] [-p port_space] +.fi +.SH "DESCRIPTION" +Establishes a set of unreliable RDMA datagram communication paths between two +nodes using the librdmacm, optionally transfers datagrams between the nodes, +then tears down the communication. +.SH "OPTIONS" +.TP +\-s server_address +The network name or IP address of the server system listening for +communication. The used name or address must route over an RDMA device. +This option must be specified by the client. +.TP +\-b bind_address +The local network address to bind to. +.TP +\-c connections +The number of communication paths to establish between the client and server. +The test uses unreliable datagram communication, so no actual connections are +formed. (default 1) +.TP +\-C message_count +The number of messages to transfer over each connection. (default 10) +.TP +\-S message_size +The size of each message transferred, in bytes. This value must be smaller +than the MTU of the underlying RDMA transport, or an error will occur. +(default 100) +.TP +\-t tos +Indicates the type of service used for the communication. Type of service +is implementation dependent based on subnet configuration. +.TP +\-p port_space +The port space of the datagram communication. May be either the RDMA +UDP (0x0111) or IPoIB (0x0002) port space. (default RDMA_PS_UDP) +.SH "NOTES" +Basic usage is to start udaddy on a server system, then run +udaddy -s server_name on a client system. +.P +Because this test maps RDMA resources to userspace, users must ensure +that they have available system resources and permissions. See the +libibverbs README file for additional details. +.SH "SEE ALSO" +rdma_cm(7), ucmatose(1), mckey(1), rping(1) diff --git a/contrib/ofed/librdmacm/src/cma.c b/contrib/ofed/librdmacm/src/cma.c new file mode 100644 index 000000000000..bcffa778e2d2 --- /dev/null +++ b/contrib/ofed/librdmacm/src/cma.c @@ -0,0 +1,1518 @@ +/* + * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: cm.c 3453 2005-09-15 21:43:21Z sean.hefty $ + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef INCLUDE_VALGRIND +# include +# ifndef VALGRIND_MAKE_MEM_DEFINED +# warning "Valgrind requested, but VALGRIND_MAKE_MEM_DEFINED undefined" +# endif +#endif + +#ifndef VALGRIND_MAKE_MEM_DEFINED +# define VALGRIND_MAKE_MEM_DEFINED(addr,len) +#endif + +#define PFX "librdmacm: " + +#if __BYTE_ORDER == __LITTLE_ENDIAN +static inline uint64_t htonll(uint64_t x) { return bswap_64(x); } +static inline uint64_t ntohll(uint64_t x) { return bswap_64(x); } +#else +static inline uint64_t htonll(uint64_t x) { return x; } +static inline uint64_t ntohll(uint64_t x) { return x; } +#endif + +static inline int ERR(int err) +{ + errno = err; + return -1; +} + +#define CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, type, size) \ +do { \ + struct ucma_abi_cmd_hdr *hdr; \ + \ + size = sizeof(*hdr) + sizeof(*cmd); \ + msg = alloca(size); \ + if (!msg) \ + return ERR(ENOMEM); \ + hdr = msg; \ + cmd = msg + sizeof(*hdr); \ + hdr->cmd = type; \ + hdr->in = sizeof(*cmd); \ + hdr->out = sizeof(*resp); \ + memset(cmd, 0, sizeof(*cmd)); \ + resp = alloca(sizeof(*resp)); \ + if (!resp) \ + return ERR(ENOMEM); \ + cmd->response = (uintptr_t)resp;\ +} while (0) + +#define CMA_CREATE_MSG_CMD(msg, cmd, type, size) \ +do { \ + struct ucma_abi_cmd_hdr *hdr; \ + \ + size = sizeof(*hdr) + sizeof(*cmd); \ + msg = alloca(size); \ + if (!msg) \ + return ERR(ENOMEM); \ + hdr = msg; \ + cmd = msg + sizeof(*hdr); \ + hdr->cmd = type; \ + hdr->in = sizeof(*cmd); \ + hdr->out = 0; \ + memset(cmd, 0, sizeof(*cmd)); \ +} while (0) + +struct cma_device { + struct ibv_context *verbs; + uint64_t guid; + int port_cnt; + uint8_t max_initiator_depth; + uint8_t max_responder_resources; +}; + +struct cma_id_private { + struct rdma_cm_id id; + struct cma_device *cma_dev; + int events_completed; + int connect_error; + pthread_cond_t cond; + pthread_mutex_t mut; + uint32_t handle; + struct cma_multicast *mc_list; +}; + +struct cma_multicast { + struct cma_multicast *next; + struct cma_id_private *id_priv; + void *context; + int events_completed; + pthread_cond_t cond; + uint32_t handle; + union ibv_gid mgid; + uint16_t mlid; + struct sockaddr_storage addr; +}; + +struct cma_event { + struct rdma_cm_event event; + uint8_t private_data[RDMA_MAX_PRIVATE_DATA]; + struct cma_id_private *id_priv; + struct cma_multicast *mc; +}; + +static struct cma_device *cma_dev_array; +static int cma_dev_cnt; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +static int abi_ver = RDMA_USER_CM_MAX_ABI_VERSION; + +#define container_of(ptr, type, field) \ + ((type *) ((void *)ptr - offsetof(type, field))) + +static void ucma_cleanup(void) +{ + if (cma_dev_cnt) { + while (cma_dev_cnt) + ibv_close_device(cma_dev_array[--cma_dev_cnt].verbs); + + free(cma_dev_array); + cma_dev_cnt = 0; + } +} + +static int check_abi_version(void) +{ + char value[8]; + + if ((ibv_read_sysfs_file(ibv_get_sysfs_path(), + "class/misc/rdma_cm/abi_version", + value, sizeof value) < 0) && + (ibv_read_sysfs_file(ibv_get_sysfs_path(), + "class/infiniband_ucma/abi_version", + value, sizeof value) < 0)) { + /* + * Older version of Linux do not have class/misc. To support + * backports, assume the most recent version of the ABI. If + * we're wrong, we'll simply fail later when calling the ABI. + */ + fprintf(stderr, "librdmacm: couldn't read ABI version.\n"); + fprintf(stderr, "librdmacm: assuming: %d\n", abi_ver); + return 0; + } + + abi_ver = strtol(value, NULL, 10); + if (abi_ver < RDMA_USER_CM_MIN_ABI_VERSION || + abi_ver > RDMA_USER_CM_MAX_ABI_VERSION) { + fprintf(stderr, "librdmacm: kernel ABI version %d " + "doesn't match library version %d.\n", + abi_ver, RDMA_USER_CM_MAX_ABI_VERSION); + return -1; + } + return 0; +} + +static int ucma_init(void) +{ + struct ibv_device **dev_list = NULL; + struct cma_device *cma_dev; + struct ibv_device_attr attr; + int i, ret, dev_cnt; + + pthread_mutex_lock(&mut); + if (cma_dev_cnt) { + pthread_mutex_unlock(&mut); + return 0; + } + + ret = check_abi_version(); + if (ret) + goto err1; + + dev_list = ibv_get_device_list(&dev_cnt); + if (!dev_list) { + printf("CMA: unable to get RDMA device list\n"); + ret = ERR(ENODEV); + goto err1; + } + + cma_dev_array = malloc(sizeof *cma_dev * dev_cnt); + if (!cma_dev_array) { + ret = ERR(ENOMEM); + goto err2; + } + + for (i = 0; dev_list[i];) { + cma_dev = &cma_dev_array[i]; + + cma_dev->guid = ibv_get_device_guid(dev_list[i]); + cma_dev->verbs = ibv_open_device(dev_list[i]); + if (!cma_dev->verbs) { + printf("CMA: unable to open RDMA device\n"); + ret = ERR(ENODEV); + goto err3; + } + + i++; + ret = ibv_query_device(cma_dev->verbs, &attr); + if (ret) { + printf("CMA: unable to query RDMA device\n"); + goto err3; + } + + cma_dev->port_cnt = attr.phys_port_cnt; + cma_dev->max_initiator_depth = (uint8_t) attr.max_qp_init_rd_atom; + cma_dev->max_responder_resources = (uint8_t) attr.max_qp_rd_atom; + } + + cma_dev_cnt = dev_cnt; + pthread_mutex_unlock(&mut); + ibv_free_device_list(dev_list); + return 0; + +err3: + while (i--) + ibv_close_device(cma_dev_array[i].verbs); + free(cma_dev_array); +err2: + ibv_free_device_list(dev_list); +err1: + pthread_mutex_unlock(&mut); + return ret; +} + +struct ibv_context **rdma_get_devices(int *num_devices) +{ + struct ibv_context **devs = NULL; + int i; + + if (!cma_dev_cnt && ucma_init()) + goto out; + + devs = malloc(sizeof *devs * (cma_dev_cnt + 1)); + if (!devs) + goto out; + + for (i = 0; i < cma_dev_cnt; i++) + devs[i] = cma_dev_array[i].verbs; + devs[i] = NULL; +out: + if (num_devices) + *num_devices = devs ? cma_dev_cnt : 0; + return devs; +} + +void rdma_free_devices(struct ibv_context **list) +{ + free(list); +} + +static void __attribute__((destructor)) rdma_cma_fini(void) +{ + ucma_cleanup(); +} + +struct rdma_event_channel *rdma_create_event_channel(void) +{ + struct rdma_event_channel *channel; + + if (!cma_dev_cnt && ucma_init()) + return NULL; + + channel = malloc(sizeof *channel); + if (!channel) + return NULL; + + channel->fd = open("/dev/rdma_cm", O_RDWR); + if (channel->fd < 0) { + printf("CMA: unable to open /dev/rdma_cm\n"); + goto err; + } + return channel; +err: + free(channel); + return NULL; +} + +void rdma_destroy_event_channel(struct rdma_event_channel *channel) +{ + close(channel->fd); + free(channel); +} + +static int ucma_get_device(struct cma_id_private *id_priv, uint64_t guid) +{ + struct cma_device *cma_dev; + int i; + + for (i = 0; i < cma_dev_cnt; i++) { + cma_dev = &cma_dev_array[i]; + if (cma_dev->guid == guid) { + id_priv->cma_dev = cma_dev; + id_priv->id.verbs = cma_dev->verbs; + return 0; + } + } + + return ERR(ENODEV); +} + +static void ucma_free_id(struct cma_id_private *id_priv) +{ + pthread_cond_destroy(&id_priv->cond); + pthread_mutex_destroy(&id_priv->mut); + if (id_priv->id.route.path_rec) + free(id_priv->id.route.path_rec); + free(id_priv); +} + +static struct cma_id_private *ucma_alloc_id(struct rdma_event_channel *channel, + void *context, + enum rdma_port_space ps) +{ + struct cma_id_private *id_priv; + + id_priv = malloc(sizeof *id_priv); + if (!id_priv) + return NULL; + + memset(id_priv, 0, sizeof *id_priv); + id_priv->id.context = context; + id_priv->id.ps = ps; + id_priv->id.channel = channel; + pthread_mutex_init(&id_priv->mut, NULL); + if (pthread_cond_init(&id_priv->cond, NULL)) + goto err; + + return id_priv; + +err: ucma_free_id(id_priv); + return NULL; +} + +int rdma_create_id(struct rdma_event_channel *channel, + struct rdma_cm_id **id, void *context, + enum rdma_port_space ps) +{ + struct ucma_abi_create_id_resp *resp; + struct ucma_abi_create_id *cmd; + struct cma_id_private *id_priv; + void *msg; + int ret, size; + + ret = cma_dev_cnt ? 0 : ucma_init(); + if (ret) + return ret; + + id_priv = ucma_alloc_id(channel, context, ps); + if (!id_priv) + return ERR(ENOMEM); + + CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_CREATE_ID, size); + cmd->uid = (uintptr_t) id_priv; + cmd->ps = ps; + + ret = write(channel->fd, msg, size); + if (ret != size) + goto err; + + VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp); + + id_priv->handle = resp->id; + *id = &id_priv->id; + return 0; + +err: ucma_free_id(id_priv); + return ret; +} + +static int ucma_destroy_kern_id(int fd, uint32_t handle) +{ + struct ucma_abi_destroy_id_resp *resp; + struct ucma_abi_destroy_id *cmd; + void *msg; + int ret, size; + + CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_DESTROY_ID, size); + cmd->id = handle; + + ret = write(fd, msg, size); + if (ret != size) + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + + VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp); + + return resp->events_reported; +} + +int rdma_destroy_id(struct rdma_cm_id *id) +{ + struct cma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct cma_id_private, id); + ret = ucma_destroy_kern_id(id->channel->fd, id_priv->handle); + if (ret < 0) + return ret; + + pthread_mutex_lock(&id_priv->mut); + while (id_priv->events_completed < ret) + pthread_cond_wait(&id_priv->cond, &id_priv->mut); + pthread_mutex_unlock(&id_priv->mut); + + ucma_free_id(id_priv); + return 0; +} + +static int ucma_addrlen(struct sockaddr *addr) +{ + if (!addr) + return 0; + + switch (addr->sa_family) { + case PF_INET: + return sizeof(struct sockaddr_in); + case PF_INET6: + return sizeof(struct sockaddr_in6); + default: + return 0; + } +} + +static int ucma_query_route(struct rdma_cm_id *id) +{ + struct ucma_abi_query_route_resp *resp; + struct ucma_abi_query_route *cmd; + struct cma_id_private *id_priv; + void *msg; + int ret, size, i; + + CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_QUERY_ROUTE, size); + id_priv = container_of(id, struct cma_id_private, id); + cmd->id = id_priv->handle; + + ret = write(id->channel->fd, msg, size); + if (ret != size) + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + + VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp); + + if (resp->num_paths) { + id->route.path_rec = malloc(sizeof *id->route.path_rec * + resp->num_paths); + if (!id->route.path_rec) + return ERR(ENOMEM); + + id->route.num_paths = resp->num_paths; + for (i = 0; i < resp->num_paths; i++) + ibv_copy_path_rec_from_kern(&id->route.path_rec[i], + &resp->ib_route[i]); + } + + memcpy(id->route.addr.addr.ibaddr.sgid.raw, resp->ib_route[0].sgid, + sizeof id->route.addr.addr.ibaddr.sgid); + memcpy(id->route.addr.addr.ibaddr.dgid.raw, resp->ib_route[0].dgid, + sizeof id->route.addr.addr.ibaddr.dgid); + id->route.addr.addr.ibaddr.pkey = resp->ib_route[0].pkey; + memcpy(&id->route.addr.src_addr, &resp->src_addr, + sizeof resp->src_addr); + memcpy(&id->route.addr.dst_addr, &resp->dst_addr, + sizeof resp->dst_addr); + + if (!id_priv->cma_dev && resp->node_guid) { + ret = ucma_get_device(id_priv, resp->node_guid); + if (ret) + return ret; + id_priv->id.port_num = resp->port_num; + } + + return 0; +} + +int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) +{ + struct ucma_abi_bind_addr *cmd; + struct cma_id_private *id_priv; + void *msg; + int ret, size, addrlen; + + addrlen = ucma_addrlen(addr); + if (!addrlen) + return ERR(EINVAL); + + CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_BIND_ADDR, size); + id_priv = container_of(id, struct cma_id_private, id); + cmd->id = id_priv->handle; + memcpy(&cmd->addr, addr, addrlen); + + ret = write(id->channel->fd, msg, size); + if (ret != size) + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + + return ucma_query_route(id); +} + +int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, + struct sockaddr *dst_addr, int timeout_ms) +{ + struct ucma_abi_resolve_addr *cmd; + struct cma_id_private *id_priv; + void *msg; + int ret, size, daddrlen; + + daddrlen = ucma_addrlen(dst_addr); + if (!daddrlen) + return ERR(EINVAL); + + CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_RESOLVE_ADDR, size); + id_priv = container_of(id, struct cma_id_private, id); + cmd->id = id_priv->handle; + if (src_addr) + memcpy(&cmd->src_addr, src_addr, ucma_addrlen(src_addr)); + memcpy(&cmd->dst_addr, dst_addr, daddrlen); + cmd->timeout_ms = timeout_ms; + + ret = write(id->channel->fd, msg, size); + if (ret != size) + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + + memcpy(&id->route.addr.dst_addr, dst_addr, daddrlen); + return 0; +} + +int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) +{ + struct ucma_abi_resolve_route *cmd; + struct cma_id_private *id_priv; + void *msg; + int ret, size; + + CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_RESOLVE_ROUTE, size); + id_priv = container_of(id, struct cma_id_private, id); + cmd->id = id_priv->handle; + cmd->timeout_ms = timeout_ms; + + ret = write(id->channel->fd, msg, size); + if (ret != size) + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +static int ucma_is_ud_ps(enum rdma_port_space ps) +{ + return (ps == RDMA_PS_UDP || ps == RDMA_PS_IPOIB); +} + +static int rdma_init_qp_attr(struct rdma_cm_id *id, struct ibv_qp_attr *qp_attr, + int *qp_attr_mask) +{ + struct ucma_abi_init_qp_attr *cmd; + struct ibv_kern_qp_attr *resp; + struct cma_id_private *id_priv; + void *msg; + int ret, size; + + CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_INIT_QP_ATTR, size); + id_priv = container_of(id, struct cma_id_private, id); + cmd->id = id_priv->handle; + cmd->qp_state = qp_attr->qp_state; + + ret = write(id->channel->fd, msg, size); + if (ret != size) + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + + VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp); + + ibv_copy_qp_attr_from_kern(qp_attr, resp); + *qp_attr_mask = resp->qp_attr_mask; + return 0; +} + +static int ucma_modify_qp_rtr(struct rdma_cm_id *id, + struct rdma_conn_param *conn_param) +{ + struct ibv_qp_attr qp_attr; + int qp_attr_mask, ret; + + if (!id->qp) + return ERR(EINVAL); + + /* Need to update QP attributes from default values. */ + qp_attr.qp_state = IBV_QPS_INIT; + ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask); + if (ret) + return ret; + + ret = ibv_modify_qp(id->qp, &qp_attr, qp_attr_mask); + if (ret) + return ret; + + qp_attr.qp_state = IBV_QPS_RTR; + ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask); + if (ret) + return ret; + + if (conn_param) + qp_attr.max_dest_rd_atomic = conn_param->responder_resources; + return ibv_modify_qp(id->qp, &qp_attr, qp_attr_mask); +} + +static int ucma_modify_qp_rts(struct rdma_cm_id *id) +{ + struct ibv_qp_attr qp_attr; + int qp_attr_mask, ret; + + qp_attr.qp_state = IBV_QPS_RTS; + ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask); + if (ret) + return ret; + + return ibv_modify_qp(id->qp, &qp_attr, qp_attr_mask); +} + +static int ucma_modify_qp_sqd(struct rdma_cm_id *id) +{ + struct ibv_qp_attr qp_attr; + + if (!id->qp) + return 0; + + qp_attr.qp_state = IBV_QPS_SQD; + return ibv_modify_qp(id->qp, &qp_attr, IBV_QP_STATE); +} + +static int ucma_modify_qp_err(struct rdma_cm_id *id) +{ + struct ibv_qp_attr qp_attr; + + if (!id->qp) + return 0; + + qp_attr.qp_state = IBV_QPS_ERR; + return ibv_modify_qp(id->qp, &qp_attr, IBV_QP_STATE); +} + +static int ucma_find_pkey(struct cma_device *cma_dev, uint8_t port_num, + uint16_t pkey, uint16_t *pkey_index) +{ + int ret, i; + uint16_t chk_pkey; + + for (i = 0, ret = 0; !ret; i++) { + ret = ibv_query_pkey(cma_dev->verbs, port_num, i, &chk_pkey); + if (!ret && pkey == chk_pkey) { + *pkey_index = (uint16_t) i; + return 0; + } + } + return ERR(EINVAL); +} + +static int ucma_init_conn_qp3(struct cma_id_private *id_priv, struct ibv_qp *qp) +{ + struct ibv_qp_attr qp_attr; + int ret; + + ret = ucma_find_pkey(id_priv->cma_dev, id_priv->id.port_num, + id_priv->id.route.addr.addr.ibaddr.pkey, + &qp_attr.pkey_index); + if (ret) + return ret; + + qp_attr.port_num = id_priv->id.port_num; + qp_attr.qp_state = IBV_QPS_INIT; + qp_attr.qp_access_flags = 0; + + return ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE | IBV_QP_ACCESS_FLAGS | + IBV_QP_PKEY_INDEX | IBV_QP_PORT); +} + +static int ucma_init_conn_qp(struct cma_id_private *id_priv, struct ibv_qp *qp) +{ + struct ibv_qp_attr qp_attr; + int qp_attr_mask, ret; + + if (abi_ver == 3) + return ucma_init_conn_qp3(id_priv, qp); + + qp_attr.qp_state = IBV_QPS_INIT; + ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); + if (ret) + return ret; + + return ibv_modify_qp(qp, &qp_attr, qp_attr_mask); +} + +static int ucma_init_ud_qp3(struct cma_id_private *id_priv, struct ibv_qp *qp) +{ + struct ibv_qp_attr qp_attr; + int ret; + + ret = ucma_find_pkey(id_priv->cma_dev, id_priv->id.port_num, + id_priv->id.route.addr.addr.ibaddr.pkey, + &qp_attr.pkey_index); + if (ret) + return ret; + + qp_attr.port_num = id_priv->id.port_num; + qp_attr.qp_state = IBV_QPS_INIT; + qp_attr.qkey = RDMA_UDP_QKEY; + + ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE | IBV_QP_QKEY | + IBV_QP_PKEY_INDEX | IBV_QP_PORT); + if (ret) + return ret; + + qp_attr.qp_state = IBV_QPS_RTR; + ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE); + if (ret) + return ret; + + qp_attr.qp_state = IBV_QPS_RTS; + qp_attr.sq_psn = 0; + return ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE | IBV_QP_SQ_PSN); +} + +static int ucma_init_ud_qp(struct cma_id_private *id_priv, struct ibv_qp *qp) +{ + struct ibv_qp_attr qp_attr; + int qp_attr_mask, ret; + + if (abi_ver == 3) + return ucma_init_ud_qp3(id_priv, qp); + + qp_attr.qp_state = IBV_QPS_INIT; + ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); + if (ret) + return ret; + + ret = ibv_modify_qp(qp, &qp_attr, qp_attr_mask); + if (ret) + return ret; + + qp_attr.qp_state = IBV_QPS_RTR; + ret = ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE); + if (ret) + return ret; + + qp_attr.qp_state = IBV_QPS_RTS; + qp_attr.sq_psn = 0; + return ibv_modify_qp(qp, &qp_attr, IBV_QP_STATE | IBV_QP_SQ_PSN); +} + +int rdma_create_qp(struct rdma_cm_id *id, struct ibv_pd *pd, + struct ibv_qp_init_attr *qp_init_attr) +{ + struct cma_id_private *id_priv; + struct ibv_qp *qp; + int ret; + + id_priv = container_of(id, struct cma_id_private, id); + if (id->verbs != pd->context) + return ERR(EINVAL); + + qp = ibv_create_qp(pd, qp_init_attr); + if (!qp) + return ERR(ENOMEM); + + if (ucma_is_ud_ps(id->ps)) + ret = ucma_init_ud_qp(id_priv, qp); + else + ret = ucma_init_conn_qp(id_priv, qp); + if (ret) + goto err; + + id->qp = qp; + return 0; +err: + ibv_destroy_qp(qp); + return ret; +} + +void rdma_destroy_qp(struct rdma_cm_id *id) +{ + ibv_destroy_qp(id->qp); +} + +static int ucma_valid_param(struct cma_id_private *id_priv, + struct rdma_conn_param *conn_param) +{ + if (id_priv->id.ps != RDMA_PS_TCP) + return 0; + + if ((conn_param->responder_resources > + id_priv->cma_dev->max_responder_resources) || + (conn_param->initiator_depth > + id_priv->cma_dev->max_initiator_depth)) + return ERR(EINVAL); + + return 0; +} + +static void ucma_copy_conn_param_to_kern(struct ucma_abi_conn_param *dst, + struct rdma_conn_param *src, + uint32_t qp_num, uint8_t srq) +{ + dst->qp_num = qp_num; + dst->srq = srq; + dst->responder_resources = src->responder_resources; + dst->initiator_depth = src->initiator_depth; + dst->flow_control = src->flow_control; + dst->retry_count = src->retry_count; + dst->rnr_retry_count = src->rnr_retry_count; + dst->valid = 1; + + if (src->private_data && src->private_data_len) { + memcpy(dst->private_data, src->private_data, + src->private_data_len); + dst->private_data_len = src->private_data_len; + } +} + +int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) +{ + struct ucma_abi_connect *cmd; + struct cma_id_private *id_priv; + void *msg; + int ret, size; + + id_priv = container_of(id, struct cma_id_private, id); + ret = ucma_valid_param(id_priv, conn_param); + if (ret) + return ret; + + CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_CONNECT, size); + cmd->id = id_priv->handle; + if (id->qp) + ucma_copy_conn_param_to_kern(&cmd->conn_param, conn_param, + id->qp->qp_num, + (id->qp->srq != NULL)); + else + ucma_copy_conn_param_to_kern(&cmd->conn_param, conn_param, + conn_param->qp_num, + conn_param->srq); + + ret = write(id->channel->fd, msg, size); + if (ret != size) + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +int rdma_listen(struct rdma_cm_id *id, int backlog) +{ + struct ucma_abi_listen *cmd; + struct cma_id_private *id_priv; + void *msg; + int ret, size; + + CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_LISTEN, size); + id_priv = container_of(id, struct cma_id_private, id); + cmd->id = id_priv->handle; + cmd->backlog = backlog; + + ret = write(id->channel->fd, msg, size); + if (ret != size) + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + + return ucma_query_route(id); +} + +int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) +{ + struct ucma_abi_accept *cmd; + struct cma_id_private *id_priv; + void *msg; + int ret, size; + + id_priv = container_of(id, struct cma_id_private, id); + ret = ucma_valid_param(id_priv, conn_param); + if (ret) + return ret; + + if (!ucma_is_ud_ps(id->ps)) { + ret = ucma_modify_qp_rtr(id, conn_param); + if (ret) + return ret; + } + + CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_ACCEPT, size); + cmd->id = id_priv->handle; + cmd->uid = (uintptr_t) id_priv; + if (id->qp) + ucma_copy_conn_param_to_kern(&cmd->conn_param, conn_param, + id->qp->qp_num, + (id->qp->srq != NULL)); + else + ucma_copy_conn_param_to_kern(&cmd->conn_param, conn_param, + conn_param->qp_num, + conn_param->srq); + + ret = write(id->channel->fd, msg, size); + if (ret != size) { + ucma_modify_qp_err(id); + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + } + + return 0; +} + +int rdma_reject(struct rdma_cm_id *id, const void *private_data, + uint8_t private_data_len) +{ + struct ucma_abi_reject *cmd; + struct cma_id_private *id_priv; + void *msg; + int ret, size; + + CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_REJECT, size); + + id_priv = container_of(id, struct cma_id_private, id); + cmd->id = id_priv->handle; + if (private_data && private_data_len) { + memcpy(cmd->private_data, private_data, private_data_len); + cmd->private_data_len = private_data_len; + } else + cmd->private_data_len = 0; + + ret = write(id->channel->fd, msg, size); + if (ret != size) + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +int rdma_notify(struct rdma_cm_id *id, enum ibv_event_type event) +{ + struct ucma_abi_notify *cmd; + struct cma_id_private *id_priv; + void *msg; + int ret, size; + + CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_NOTIFY, size); + + id_priv = container_of(id, struct cma_id_private, id); + cmd->id = id_priv->handle; + cmd->event = event; + ret = write(id->channel->fd, msg, size); + if (ret != size) + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +int rdma_disconnect(struct rdma_cm_id *id) +{ + struct ucma_abi_disconnect *cmd; + struct cma_id_private *id_priv; + void *msg; + int ret, size; + + switch (id->verbs->device->transport_type) { + case IBV_TRANSPORT_IB: + ret = ucma_modify_qp_err(id); + break; + case IBV_TRANSPORT_IWARP: + ret = ucma_modify_qp_sqd(id); + break; + default: + ret = ERR(EINVAL); + } + if (ret) + return ret; + + CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_DISCONNECT, size); + id_priv = container_of(id, struct cma_id_private, id); + cmd->id = id_priv->handle; + + ret = write(id->channel->fd, msg, size); + if (ret != size) + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, + void *context) +{ + struct ucma_abi_join_mcast *cmd; + struct ucma_abi_create_id_resp *resp; + struct cma_id_private *id_priv; + struct cma_multicast *mc, **pos; + void *msg; + int ret, size, addrlen; + + id_priv = container_of(id, struct cma_id_private, id); + addrlen = ucma_addrlen(addr); + if (!addrlen) + return ERR(EINVAL); + + mc = malloc(sizeof *mc); + if (!mc) + return ERR(ENOMEM); + + memset(mc, 0, sizeof *mc); + mc->context = context; + mc->id_priv = id_priv; + memcpy(&mc->addr, addr, addrlen); + if (pthread_cond_init(&mc->cond, NULL)) { + ret = -1; + goto err1; + } + + pthread_mutex_lock(&id_priv->mut); + mc->next = id_priv->mc_list; + id_priv->mc_list = mc; + pthread_mutex_unlock(&id_priv->mut); + + CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_JOIN_MCAST, size); + cmd->id = id_priv->handle; + memcpy(&cmd->addr, addr, addrlen); + cmd->uid = (uintptr_t) mc; + + ret = write(id->channel->fd, msg, size); + if (ret != size) { + ret = (ret >= 0) ? ERR(ECONNREFUSED) : -1; + goto err2; + } + + VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp); + + mc->handle = resp->id; + return 0; +err2: + pthread_mutex_lock(&id_priv->mut); + for (pos = &id_priv->mc_list; *pos != mc; pos = &(*pos)->next) + ; + *pos = mc->next; + pthread_mutex_unlock(&id_priv->mut); +err1: + free(mc); + return ret; +} + +int rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) +{ + struct ucma_abi_destroy_id *cmd; + struct ucma_abi_destroy_id_resp *resp; + struct cma_id_private *id_priv; + struct cma_multicast *mc, **pos; + void *msg; + int ret, size, addrlen; + + addrlen = ucma_addrlen(addr); + if (!addrlen) + return ERR(EINVAL); + + id_priv = container_of(id, struct cma_id_private, id); + pthread_mutex_lock(&id_priv->mut); + for (pos = &id_priv->mc_list; *pos; pos = &(*pos)->next) + if (!memcmp(&(*pos)->addr, addr, addrlen)) + break; + + mc = *pos; + if (*pos) + *pos = mc->next; + pthread_mutex_unlock(&id_priv->mut); + if (!mc) + return ERR(EADDRNOTAVAIL); + + if (id->qp) + ibv_detach_mcast(id->qp, &mc->mgid, mc->mlid); + + CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_LEAVE_MCAST, size); + cmd->id = mc->handle; + + ret = write(id->channel->fd, msg, size); + if (ret != size) { + ret = (ret >= 0) ? ERR(ECONNREFUSED) : -1; + goto free; + } + + VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp); + + pthread_mutex_lock(&id_priv->mut); + while (mc->events_completed < resp->events_reported) + pthread_cond_wait(&mc->cond, &id_priv->mut); + pthread_mutex_unlock(&id_priv->mut); + + ret = 0; +free: + free(mc); + return ret; +} + +static void ucma_complete_event(struct cma_id_private *id_priv) +{ + pthread_mutex_lock(&id_priv->mut); + id_priv->events_completed++; + pthread_cond_signal(&id_priv->cond); + pthread_mutex_unlock(&id_priv->mut); +} + +static void ucma_complete_mc_event(struct cma_multicast *mc) +{ + pthread_mutex_lock(&mc->id_priv->mut); + mc->events_completed++; + pthread_cond_signal(&mc->cond); + mc->id_priv->events_completed++; + pthread_cond_signal(&mc->id_priv->cond); + pthread_mutex_unlock(&mc->id_priv->mut); +} + +int rdma_ack_cm_event(struct rdma_cm_event *event) +{ + struct cma_event *evt; + + if (!event) + return ERR(EINVAL); + + evt = container_of(event, struct cma_event, event); + + if (evt->mc) + ucma_complete_mc_event(evt->mc); + else + ucma_complete_event(evt->id_priv); + free(evt); + return 0; +} + +static int ucma_process_conn_req(struct cma_event *evt, + uint32_t handle) +{ + struct cma_id_private *id_priv; + int ret; + + id_priv = ucma_alloc_id(evt->id_priv->id.channel, + evt->id_priv->id.context, evt->id_priv->id.ps); + if (!id_priv) { + ucma_destroy_kern_id(evt->id_priv->id.channel->fd, handle); + ret = ERR(ENOMEM); + goto err; + } + + evt->event.listen_id = &evt->id_priv->id; + evt->event.id = &id_priv->id; + id_priv->handle = handle; + + ret = ucma_query_route(&id_priv->id); + if (ret) { + rdma_destroy_id(&id_priv->id); + goto err; + } + + return 0; +err: + ucma_complete_event(evt->id_priv); + return ret; +} + +static int ucma_process_conn_resp(struct cma_id_private *id_priv) +{ + struct ucma_abi_accept *cmd; + void *msg; + int ret, size; + + ret = ucma_modify_qp_rtr(&id_priv->id, NULL); + if (ret) + goto err; + + ret = ucma_modify_qp_rts(&id_priv->id); + if (ret) + goto err; + + CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_ACCEPT, size); + cmd->id = id_priv->handle; + + ret = write(id_priv->id.channel->fd, msg, size); + if (ret != size) { + ret = (ret >= 0) ? ERR(ECONNREFUSED) : -1; + goto err; + } + + return 0; +err: + ucma_modify_qp_err(&id_priv->id); + return ret; +} + +static int ucma_process_establish(struct rdma_cm_id *id) +{ + int ret; + + ret = ucma_modify_qp_rts(id); + if (ret) + ucma_modify_qp_err(id); + + return ret; +} + +static int ucma_process_join(struct cma_event *evt) +{ + evt->mc->mgid = evt->event.param.ud.ah_attr.grh.dgid; + evt->mc->mlid = evt->event.param.ud.ah_attr.dlid; + + if (!evt->id_priv->id.qp) + return 0; + + return ibv_attach_mcast(evt->id_priv->id.qp, &evt->mc->mgid, + evt->mc->mlid); +} + +static void ucma_copy_conn_event(struct cma_event *event, + struct ucma_abi_conn_param *src) +{ + struct rdma_conn_param *dst = &event->event.param.conn; + + dst->private_data_len = src->private_data_len; + if (src->private_data_len) { + dst->private_data = &event->private_data; + memcpy(&event->private_data, src->private_data, + src->private_data_len); + } + + dst->responder_resources = src->responder_resources; + dst->initiator_depth = src->initiator_depth; + dst->flow_control = src->flow_control; + dst->retry_count = src->retry_count; + dst->rnr_retry_count = src->rnr_retry_count; + dst->srq = src->srq; + dst->qp_num = src->qp_num; +} + +static void ucma_copy_ud_event(struct cma_event *event, + struct ucma_abi_ud_param *src) +{ + struct rdma_ud_param *dst = &event->event.param.ud; + + dst->private_data_len = src->private_data_len; + if (src->private_data_len) { + dst->private_data = &event->private_data; + memcpy(&event->private_data, src->private_data, + src->private_data_len); + } + + ibv_copy_ah_attr_from_kern(&dst->ah_attr, &src->ah_attr); + dst->qp_num = src->qp_num; + dst->qkey = src->qkey; +} + +int rdma_get_cm_event(struct rdma_event_channel *channel, + struct rdma_cm_event **event) +{ + struct ucma_abi_event_resp *resp; + struct ucma_abi_get_event *cmd; + struct cma_event *evt; + void *msg; + int ret, size; + + ret = cma_dev_cnt ? 0 : ucma_init(); + if (ret) + return ret; + + if (!event) + return ERR(EINVAL); + + evt = malloc(sizeof *evt); + if (!evt) + return ERR(ENOMEM); + +retry: + memset(evt, 0, sizeof *evt); + CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_GET_EVENT, size); + ret = write(channel->fd, msg, size); + if (ret != size) { + free(evt); + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + } + + VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp); + + evt->event.event = resp->event; + evt->id_priv = (void *) (uintptr_t) resp->uid; + evt->event.id = &evt->id_priv->id; + evt->event.status = resp->status; + + switch (resp->event) { + case RDMA_CM_EVENT_ADDR_RESOLVED: + evt->event.status = ucma_query_route(&evt->id_priv->id); + if (evt->event.status) + evt->event.event = RDMA_CM_EVENT_ADDR_ERROR; + break; + case RDMA_CM_EVENT_ROUTE_RESOLVED: + evt->event.status = ucma_query_route(&evt->id_priv->id); + if (evt->event.status) + evt->event.event = RDMA_CM_EVENT_ROUTE_ERROR; + break; + case RDMA_CM_EVENT_CONNECT_REQUEST: + evt->id_priv = (void *) (uintptr_t) resp->uid; + if (ucma_is_ud_ps(evt->id_priv->id.ps)) + ucma_copy_ud_event(evt, &resp->param.ud); + else + ucma_copy_conn_event(evt, &resp->param.conn); + + ret = ucma_process_conn_req(evt, resp->id); + if (ret) + goto retry; + break; + case RDMA_CM_EVENT_CONNECT_RESPONSE: + ucma_copy_conn_event(evt, &resp->param.conn); + evt->event.status = ucma_process_conn_resp(evt->id_priv); + if (!evt->event.status) + evt->event.event = RDMA_CM_EVENT_ESTABLISHED; + else { + evt->event.event = RDMA_CM_EVENT_CONNECT_ERROR; + evt->id_priv->connect_error = 1; + } + break; + case RDMA_CM_EVENT_ESTABLISHED: + if (ucma_is_ud_ps(evt->id_priv->id.ps)) { + ucma_copy_ud_event(evt, &resp->param.ud); + break; + } + + ucma_copy_conn_event(evt, &resp->param.conn); + evt->event.status = ucma_process_establish(&evt->id_priv->id); + if (evt->event.status) { + evt->event.event = RDMA_CM_EVENT_CONNECT_ERROR; + evt->id_priv->connect_error = 1; + } + break; + case RDMA_CM_EVENT_REJECTED: + if (evt->id_priv->connect_error) { + ucma_complete_event(evt->id_priv); + goto retry; + } + ucma_copy_conn_event(evt, &resp->param.conn); + ucma_modify_qp_err(evt->event.id); + break; + case RDMA_CM_EVENT_DISCONNECTED: + if (evt->id_priv->connect_error) { + ucma_complete_event(evt->id_priv); + goto retry; + } + ucma_copy_conn_event(evt, &resp->param.conn); + break; + case RDMA_CM_EVENT_MULTICAST_JOIN: + evt->mc = (void *) (uintptr_t) resp->uid; + evt->id_priv = evt->mc->id_priv; + evt->event.id = &evt->id_priv->id; + ucma_copy_ud_event(evt, &resp->param.ud); + evt->event.param.ud.private_data = evt->mc->context; + evt->event.status = ucma_process_join(evt); + if (evt->event.status) + evt->event.event = RDMA_CM_EVENT_MULTICAST_ERROR; + break; + case RDMA_CM_EVENT_MULTICAST_ERROR: + evt->mc = (void *) (uintptr_t) resp->uid; + evt->id_priv = evt->mc->id_priv; + evt->event.id = &evt->id_priv->id; + evt->event.param.ud.private_data = evt->mc->context; + break; + default: + evt->id_priv = (void *) (uintptr_t) resp->uid; + evt->event.id = &evt->id_priv->id; + evt->event.status = resp->status; + if (ucma_is_ud_ps(evt->id_priv->id.ps)) + ucma_copy_ud_event(evt, &resp->param.ud); + else + ucma_copy_conn_event(evt, &resp->param.conn); + break; + } + + *event = &evt->event; + return 0; +} + +const char *rdma_event_str(enum rdma_cm_event_type event) +{ + switch (event) { + case RDMA_CM_EVENT_ADDR_RESOLVED: + return "RDMA_CM_EVENT_ADDR_RESOLVED"; + case RDMA_CM_EVENT_ADDR_ERROR: + return "RDMA_CM_EVENT_ADDR_ERROR"; + case RDMA_CM_EVENT_ROUTE_RESOLVED: + return "RDMA_CM_EVENT_ROUTE_RESOLVED"; + case RDMA_CM_EVENT_ROUTE_ERROR: + return "RDMA_CM_EVENT_ROUTE_ERROR"; + case RDMA_CM_EVENT_CONNECT_REQUEST: + return "RDMA_CM_EVENT_CONNECT_REQUEST"; + case RDMA_CM_EVENT_CONNECT_RESPONSE: + return "RDMA_CM_EVENT_CONNECT_RESPONSE"; + case RDMA_CM_EVENT_CONNECT_ERROR: + return "RDMA_CM_EVENT_CONNECT_ERROR"; + case RDMA_CM_EVENT_UNREACHABLE: + return "RDMA_CM_EVENT_UNREACHABLE"; + case RDMA_CM_EVENT_REJECTED: + return "RDMA_CM_EVENT_REJECTED"; + case RDMA_CM_EVENT_ESTABLISHED: + return "RDMA_CM_EVENT_ESTABLISHED"; + case RDMA_CM_EVENT_DISCONNECTED: + return "RDMA_CM_EVENT_DISCONNECTED"; + case RDMA_CM_EVENT_DEVICE_REMOVAL: + return "RDMA_CM_EVENT_DEVICE_REMOVAL"; + case RDMA_CM_EVENT_MULTICAST_JOIN: + return "RDMA_CM_EVENT_MULTICAST_JOIN"; + case RDMA_CM_EVENT_MULTICAST_ERROR: + return "RDMA_CM_EVENT_MULTICAST_ERROR"; + case RDMA_CM_EVENT_ADDR_CHANGE: + return "RDMA_CM_EVENT_ADDR_CHANGE"; + case RDMA_CM_EVENT_TIMEWAIT_EXIT: + return "RDMA_CM_EVENT_TIMEWAIT_EXIT"; + default: + return "UNKNOWN EVENT"; + } +} + +int rdma_set_option(struct rdma_cm_id *id, int level, int optname, + void *optval, size_t optlen) +{ + struct ucma_abi_set_option *cmd; + struct cma_id_private *id_priv; + void *msg; + int ret, size; + + CMA_CREATE_MSG_CMD(msg, cmd, UCMA_CMD_SET_OPTION, size); + id_priv = container_of(id, struct cma_id_private, id); + cmd->id = id_priv->handle; + cmd->optval = (uintptr_t) optval; + cmd->level = level; + cmd->optname = optname; + cmd->optlen = optlen; + + ret = write(id->channel->fd, msg, size); + if (ret != size) + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + + return 0; +} + +int rdma_migrate_id(struct rdma_cm_id *id, struct rdma_event_channel *channel) +{ + struct ucma_abi_migrate_resp *resp; + struct ucma_abi_migrate_id *cmd; + struct cma_id_private *id_priv; + void *msg; + int ret, size; + + id_priv = container_of(id, struct cma_id_private, id); + CMA_CREATE_MSG_CMD_RESP(msg, cmd, resp, UCMA_CMD_MIGRATE_ID, size); + cmd->id = id_priv->handle; + cmd->fd = id->channel->fd; + + ret = write(channel->fd, msg, size); + if (ret != size) + return (ret >= 0) ? ERR(ECONNREFUSED) : -1; + + VALGRIND_MAKE_MEM_DEFINED(resp, sizeof *resp); + + /* + * Eventually if we want to support migrating channels while events are + * being processed on the current channel, we need to block here while + * there are any outstanding events on the current channel for this id + * to prevent the user from processing events for this id on the old + * channel after this call returns. + */ + pthread_mutex_lock(&id_priv->mut); + id->channel = channel; + while (id_priv->events_completed < resp->events_reported) + pthread_cond_wait(&id_priv->cond, &id_priv->mut); + pthread_mutex_unlock(&id_priv->mut); + + return 0; +} diff --git a/contrib/ofed/librdmacm/src/librdmacm.map b/contrib/ofed/librdmacm/src/librdmacm.map new file mode 100644 index 000000000000..cb94efe17971 --- /dev/null +++ b/contrib/ofed/librdmacm/src/librdmacm.map @@ -0,0 +1,32 @@ +RDMACM_1.0 { + global: + rdma_create_event_channel; + rdma_destroy_event_channel; + rdma_create_id; + rdma_destroy_id; + rdma_bind_addr; + rdma_resolve_addr; + rdma_resolve_route; + rdma_create_qp; + rdma_destroy_qp; + rdma_connect; + rdma_listen; + rdma_accept; + rdma_reject; + rdma_notify; + rdma_disconnect; + rdma_get_cm_event; + rdma_ack_cm_event; + rdma_get_src_port; + rdma_get_dst_port; + rdma_join_multicast; + rdma_leave_multicast; + rdma_get_devices; + rdma_free_devices; + rdma_event_str; + rdma_set_option; + rdma_get_local_addr; + rdma_get_peer_addr; + rdma_migrate_id; + local: *; +}; diff --git a/contrib/ofed/libsdp/COPYING b/contrib/ofed/libsdp/COPYING new file mode 100644 index 000000000000..fac7531bd835 --- /dev/null +++ b/contrib/ofed/libsdp/COPYING @@ -0,0 +1,36 @@ +This software is available to you under a choice of one of two +licenses. You may choose to be licensed under the terms of the GNU +General Public License (GPL) Version 2, available at +, or the OpenIB.org BSD +license, included below. + +Copyright (c) 2004 Topspin Communications. All rights reserved. +Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + + +OpenIB.org BSD license: + +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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/contrib/ofed/libsdp/ChangeLog b/contrib/ofed/libsdp/ChangeLog new file mode 100644 index 000000000000..d38dc69cc78e --- /dev/null +++ b/contrib/ofed/libsdp/ChangeLog @@ -0,0 +1,96 @@ +2010-12-26 18:14:02 +0200 Amir Vadai + * 9c2ad15 libsdp: full ipv6 support + +2010-11-29 11:43:51 +0200 Amir Vadai + * 0a3d5c3 libsdp: BUG2130 - libsdp.so is not installed + version + 1.1.106 +2010-11-08 14:41:27 +0200 Amir Vadai + * 7a1880f libsdp: updated version to 1.1.105 + +2010-11-08 14:31:13 +0200 Amir Vadai + * c6efc06 libsdp: fix security issues with log file + +2010-11-02 15:28:06 +0200 Amir Vadai + * 09343d1 libsdp: fix bad permissions + +2010-10-28 13:46:39 +0200 root + * 46d845d libsdp: fixed indentation + +2010-10-04 11:49:46 +0200 Amir Vadai + * 59b6a36 libsdp: updated version to 1.1.104 + +2010-10-04 11:22:23 +0200 Amir Vadai + * 21b63e0 libsdp: fix libsdp.so permissions + +2010-10-04 11:20:49 +0200 Amir Vadai + * 3180e25 libsdp: fix "make dist" + +2010-09-13 10:31:52 +0200 Amir Vadai + * df744a5 libsdp: updated version to 1.1.103 + +2010-09-13 10:45:40 +0200 Amir Vadai + * e3ce469 libsdp: don't make libsdp depend on sdp_socket.h from ib-kernel + +2010-08-03 15:35:11 +0300 Amir Vadai + * c5ff8e2 libsdp: updated version to 1.1.102 + +2010-08-03 15:33:57 +0300 Amir Vadai + * 82fe3f9 libsdp: search openib headers according to 'prefix' + +2010-04-11 11:38:47 +0300 Amir Vadai + * 76060c5 libsdp: changed version to 1.1.101 + +2010-04-08 09:33:29 +0300 Eldad Zinger + * 8bf57aa libsdp: added differentiation between bind failures of sdp. + +2010-03-23 10:13:45 +0200 Eldad Zinger + * 93706ed sdp: BUG1984 - fix for bad memory access. + +2010-04-08 15:40:55 +0300 Amir Vadai + * dadef4b libsdp: add path to openib include's + +2010-02-18 11:04:29 +0200 Amir Vadai + * 920ea31 libsdp: changed version to 1.1.100 + +2010-02-18 11:02:20 +0200 Amir Vadai + * 0fe8a11 libsdp: updated changelog from git + script to get change log + +2010-02-18 10:49:42 +0200 Amir Vadai + * a298098 libsdp: Fix memory leak. free libsdp_fd_attributes + +2010-02-18 10:49:00 +0200 Amir Vadai + * cf4ceab libsdp: make libsdp.so have gid bit on + +2008-11-26 13:44:26 +0200 Amir Vadai + * b1eaecb libsdp: Enable building libsdp on Solaris + +2008-11-23 Amir Vadai + * BUG1405 - conflict when running an application that use yacc. + +2008-12-08 18:29:09 +0200 Yossi Etigin + * dcfca98 libsdp: BUG1256 - Add epoll support + +2008-11-23 16:09:21 +0200 Amir Vadai + * 02404fb libsdp: BUG1405 - conflict when running an application that use yacc. + +2008-09-02 15:13:22 +0300 Yossi Etigin <[yossi.openib@gmail.com]> + * 64adc0e libsdp: enable fallback to TCP for nonblocking sockets + +2008-08-21 10:52:19 +0300 Yossi Etigin <[yossi.openib@gmail.com]> + * cee8053 libsdp: write fcntl argument in debug prints + +2008-07-21 22:01:21 +0300 Amir Vadai + * 81d6ec3 removed not unnecessary use of va_copy. + +2008-06-12 14:13:07 +0300 Amir Vadai + * 90f25b7 Fixed compilation error on Fedora Release 9 + +2006-05-29 Eitan Zahavi + + * Support IPv4 embedded in IPv6 addresses. Since SDP currently does + not support IPv6 we need to convert to IPv4 and back on queries. + + * port.c - cleanup abnd re-written for clearer flow. Added verbose + messages. + + * Major re-write of the parser to support new syntax and using BNF diff --git a/contrib/ofed/libsdp/Makefile.am b/contrib/ofed/libsdp/Makefile.am new file mode 100644 index 000000000000..13c5680991f4 --- /dev/null +++ b/contrib/ofed/libsdp/Makefile.am @@ -0,0 +1,23 @@ +SUBDIRS = src + +EXTRA_DIST = libsdp.spec.in libsdp.conf + +dist-hook: libsdp.spec + cp libsdp.spec $(distdir) + +install-data-hook: + if test -e $(DESTDIR)$(sysconfdir)/libsdp.conf; then \ + diff -q $(srcdir)/libsdp.conf $(DESTDIR)$(sysconfdir)/libsdp.conf 1> /dev/null; \ + if test $$? == 1; then \ + t=$(shell date +'%Y%m%d%H%M%S'); \ + cp -p $(srcdir)/libsdp.conf \ + $(DESTDIR)$(sysconfdir)/libsdp.conf.$$t; \ + echo "NOTE: existing libsdp.conf was not updated."; \ + echo " libsdp.conf installed as ibsdp.conf.$$t instead."; \ + fi; \ + else \ + if test ! -d $(DESTDIR)$(sysconfdir); then \ + mkdir -p $(DESTDIR)$(sysconfdir); \ + fi; \ + cp -p $(srcdir)/libsdp.conf $(DESTDIR)$(sysconfdir)/libsdp.conf; \ + fi diff --git a/contrib/ofed/libsdp/NEWS b/contrib/ofed/libsdp/NEWS new file mode 100644 index 000000000000..1fb082be75d6 --- /dev/null +++ b/contrib/ofed/libsdp/NEWS @@ -0,0 +1,4 @@ +0.9.0 - Initial release. +1.0.0 - Following RFC for enhanced configuration semantics, strong parsing, + major cleanup, verbosity logging and thread safe code + \ No newline at end of file diff --git a/contrib/ofed/libsdp/README b/contrib/ofed/libsdp/README new file mode 100644 index 000000000000..6499bbca0509 --- /dev/null +++ b/contrib/ofed/libsdp/README @@ -0,0 +1,68 @@ +LIBSDP - A User Level Socket Switch for Seemless Migration to SDP +----------------------------------------------------------------- + +OVERVIEW: +--------- +libsdp is a LD_PRELOAD-able library that can be used to migrate existing +applications use InfiniBand Sockets Direct Protocol (SDP) instead of +TCP sockets, transparently and without recompilations. To setup libsdp +please follow the instructions below. + +SETUP: +------ +libsdp.so isn't setup automatically. it can be used in one of 2 ways: +1) LD_PRELOAD environment variable. Setting this to the name of the + library you want to use will cause it to be preloaded. +2) Adding the name of the library into /etc/ld.so.preload. This will + cause the library to be preloaded for every executable that is linked + with libc. + +The library should be installed in a directory in which the dynamic loader +searches for shared libraries (as specified by LD_LIBRARY_PATH, +/etc/ld.so.conf, etc). Alternatively, you can specify the full path to the +library that you want to use in LD_PRELOAD or /etc/ld.so.preload as described +above. + +The last option cant be used if you have multiple library versions +(e.g. 64/32 bit) and want the linker to select between them automatically. +The best way to handle such case is to use LD_LIBRARY_PATH to point to both the +lib (the 32 bit version) and lib64 directories and LD_RELOAD the libsdp.so. +This way the correct 32/64bit libsdp.so will be selected. +For example running ssh over SDP with OFED distribution from bash this can be written: +LD_LIBRARY_PATH=/usr/local/ofed/lib64:/usr/local/ofed/lib LD_PRELOAD=libsdp.so ssh + +CONFIGURATION: +-------------- +libsdp supports two modes of configuration: +* simple operation where it converts all calls to socket(2) with a family + of AF_INET(6) and a type of SOCK_STREAM into family of AF_INET_SDP. +* selective mode where it uses a configuration file to select which sockets + will be using SDP and which will not. + +For real world applications where communication with X, authentication, +DNS and other servers connected through TCP is required the selective mode +is required. + +Simple mode will be selected in one of the following conditions: +* the environment variable SIMPLE_LIBSDP to a non-empty value +* no configuration file is defined or is un-readble +* the configuration file does not include any address family rule + +For information on how to configure libsdp, see libsdp.conf, which is installed +in $(sysconfdir) (usually /usr/local/etc or /etc). The user can further control +the file to be used for configuration by setting the environment variable: +LIBSDP_CONFIG_FILE + +LIMITATIONS: +------------ +1. Applications statically linked with libc will not allow dynamic pre-loading + to port these applications to use SDP one needs to replace specific socket + calls (within the application) with AF_INET_SDP and recompile. +2. If for some reason the dynamic linker fail to pre-load libc before the + libsdp.so is initialized or it does not support RTDL_NEXT, libsdp will + fail to find the libc socket API. To overcome this situation a simple + implementation of hijacking "socket" call is provided in libsdp_sys. + This partial implementation does not support any configuration and is + limited to i386 architecture. +3. Non-blocking connect in "both" mode defaults to SDP. Specific rules might be + needed for applications to operate properly. diff --git a/contrib/ofed/libsdp/autogen.sh b/contrib/ofed/libsdp/autogen.sh new file mode 100755 index 000000000000..fd47839cae8c --- /dev/null +++ b/contrib/ofed/libsdp/autogen.sh @@ -0,0 +1,8 @@ +#! /bin/sh + +set -x +aclocal -I config +libtoolize --force --copy +autoheader +automake --foreign --add-missing --copy +autoconf diff --git a/contrib/ofed/libsdp/changelog_from_git.sh b/contrib/ofed/libsdp/changelog_from_git.sh new file mode 100755 index 000000000000..e3d86b21531d --- /dev/null +++ b/contrib/ofed/libsdp/changelog_from_git.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +git log --pretty=format:"%ai %an <%ae>%n * %h %s%n" diff --git a/contrib/ofed/libsdp/config/libsdp_indent b/contrib/ofed/libsdp/config/libsdp_indent new file mode 100755 index 000000000000..6bae67dc91ac --- /dev/null +++ b/contrib/ofed/libsdp/config/libsdp_indent @@ -0,0 +1,71 @@ +#!/bin/bash +# +# Copyright (c) 2006 Mellanox Technologies LTD. All rights reserved. +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# $Id: osm_indent 4707 2006-01-03 16:18:08Z halr $ +# +######################################################################### +# +# Abstract: +# Indent script for enforcing source code formatting. +# +# This is the indent format used for libsdp: +# +# -bad Blank line after declarations +# -bap Blank line after Procedures +# -nbbb NO Blank line before block comments +# -nbbo NO Break after Boolean operator +# -bl Break after if line +# -bli0 Indent for braces is 0 +# -bls Break after struct declarations +# -cbi0 Case break indent 0 +# -ci3 Continue indent 3 spaces +# -cli0 Case label indent 0 spaces +# -ncs No space after cast operator +# -hnl Honor existing newlines on long lines +# -i3 Substitute indent with 3 spaces +# -npcs No space after procedure calls +# -prs Space after parenthesis +# -nsai No space after if keyword - removed +# -nsaw No space after while keyword - removed +# -sc Put * at left of comments in a block comment style +# -nsob Don't swallow unnecessary blank lines +# -ts3 Tab size is 3 +# -psl Type of procedure return in a separate line +# -bfda Function declaration arguments in a separate line. +# -ut No tabs as we allow spaces +# -br Put braces on line with if, etc +# -ce Cuddle else and preceeding } +# +######################################################################### + +eval indent -bad -bap -nbbb -nbbo -bl -bli0 -bls -cbi0 -ci3 -cli0 -ncs \ + -hnl -i3 -npcs -prs -sc -nsob -ts3 -psl -bfda -ut -br -ce $* diff --git a/contrib/ofed/libsdp/configure.in b/contrib/ofed/libsdp/configure.in new file mode 100644 index 000000000000..b1f34a4f1993 --- /dev/null +++ b/contrib/ofed/libsdp/configure.in @@ -0,0 +1,59 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + + +AC_PREREQ(2.57) +AC_INIT(libsdp, 1.1.108, openib-general@openib.org) +AC_CONFIG_SRCDIR([src/port.c]) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(libsdp, 1.1.108) + +AC_CANONICAL_HOST +AM_MAINTAINER_MODE + +AC_DISABLE_STATIC +AC_PROG_LIBTOOL + +# Checks for programs. +AC_PROG_CC +AM_PROG_LEX +AC_PROG_YACC + +# Checks for libraries. + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([arpa/inet.h netinet/in.h stdlib.h string.h sys/socket.h syslog.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +# Checks for library functions. +AC_REPLACE_FNMATCH +AC_PROG_GCC_TRADITIONAL +AC_FUNC_MALLOC +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([dup2 memset socket strcasecmp strchr strdup strpbrk strrchr strtoul]) + +# check OS +case "${host}" in +i[[3456]]86-*-linux*) AC_DEFINE(LINUX_BUILD, 1, [OS is linux]) ac_cv_linux_build="yes" ;; +sparc*-sun-solaris*) AC_DEFINE(SOLARIS_BUILD, 1, [OS is sparc solaris]) ac_cv_solaris_build="yes";; +esac + +AM_CONDITIONAL(LINUX_BUILD, test "$ac_cv_linux_build" = "yes") +AM_CONDITIONAL(SOLARIS_BUILD, test "$ac_cv_solaris_build" = "yes") + +# Check if we should build libsdp_sys +AC_CACHE_CHECK(whether to build i386-specific libsdp_sys, ac_cv_libsdp_sys, + AC_TRY_COMPILE(,[ + #if !i386 + #error Not i386 + #endif + ], ac_cv_libsdp_sys="yes", ac_cv_libsdp_sys="no")) + +AM_CONDITIONAL(WANT_LIBSDP_SYS, test "$ac_cv_libsdp_sys" = "yes") + +AC_CONFIG_FILES([Makefile src/Makefile libsdp.spec]) +AC_OUTPUT diff --git a/contrib/ofed/libsdp/libsdp.conf b/contrib/ofed/libsdp/libsdp.conf new file mode 100644 index 000000000000..65f1f837fac7 --- /dev/null +++ b/contrib/ofed/libsdp/libsdp.conf @@ -0,0 +1,139 @@ +# libsdp.conf - configuration file for libsdp +# +# $Id$ +# +# Comments are starts with # and cause the entire line after it to be ignored. +# Any beginning whitespace is skipped. Any line that is empty is also skipped. +# +# There are 2 main types of statements supported by this configuration file: +# - "use" - which defines the address family to be used for the sockets that +# match the line +# - "log" - for setting logging related configuration. As the log settings +# takes immidiate effect we define these at the beggining of the file. +# +############################################################################## +# DEAFUALT SETTINGS: +# Please do not forget to comment if you want to change these. +# (the rest of this file explains the syntax and give examples) +# +# Get errors printed into the files /tmp/libsdp.log./log +# or /var/log/ for root +log min-level 9 destination file libsdp.log +# +# By default we let all servers and client try SDP first. +# to exclude SDP add "use tcp" rules before these defaults. +use both server * *:* +use both client * *:* +# +# +############################################################################## +# +# LOG CONFIGURATION: +# ------------------ +# The log directive allows the user to specify which and where debug and error +# messages get sent. The log statement format is: +# log [destination stderr|syslog|file ] [min-level <1-9>] +# +# destination - defines the destination of the log messages: +# stderr - messages will be forwarded to the stderr +# syslog - messages sent to the syslog service +# file - messages will be written to the file /var/log/ for root. +# for regular user, if full path is requsted ./log +# or /tmp/./log if no path is requested +# Due to security reasons, must not be: +# 1. a soft link +# 2. owned by other user. +# 3. Other permissions except User permissions. +# +# min-level - defines the verbosity of the log: +# 9 - only errors are printed +# 8 - warnings +# 7 - connect and listen summary (useful for tracking SDP usage) +# 4 - positive match summary (useful for config file debug) +# 3 - negative match summary (useful for config file debug) +# 2 - function calls and return values +# 1 - debug messages +# +# Examples: +# +# Get SDP usage per connect and listen into stderr +# log min-level 7 destination stderr +# +# Send errors only into syslog +# log min-level 9 destination syslog +# +############################################################################## +# +# SOCKET ADDRESS FAMILY CONTROL: +# ------------------------------ +# The socket control statements allows the user to specify when libsdp will +# replace AF_INET/SOCK_STREAM sockets with AF_SDP/SOCK_STREAM +# sockets. Each control statement specifies a matching rule that all its +# subexpressions must evaluate as true (logical and) to apply. +# +# The statements that control which type of sockets to open are made +# of the following: +# use : +# +# can be one of: +# "sdp" - for specifying when an SDP should be used +# "tcp" - for specifying when SDP socket should not be matched +# "both" - for specifying when both SDP and AF_INET sockets should be used. +# +# Note: that "both" semantics is different between "server" and "client" roles: +# For a "server" is means that the server will be listening on both sdp and tcp +# For a "client" the connect will prefer using sdp but will silently +# fall back to tcp if the sdp connection failed. +# +# can be one of: +# "server" or "listen" - for defining the listening port address family +# "client" or "connect" - for defining the connected port address family +# +# field: +# Defines the program name (not including the path) the rule applies to. +# Wildcards with same semantics as "ls" are supported (* and ?). +# So db2* would match on any program with a name starting with db2. +# t?cp would match on ttcp, etc. +# If not provided (default) the statement matches all programs. +# +# means: +# Either the local address the server is bind to or the remote server +# address the client connects to. Syntax for address matching is: +# [/]|* +# IPv4 address = [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+ each sub number < 255 +# prefix_length = [0-9]+ and with value <= 32. A prefix_length of 24 +# matches the subnet mask 255.255.255.0 . A prefix_length of 32 +# requires matching of the exact IP. +# +# is: +# start-port[-end-port] where port numbers are >0 and < 65536 +# +# Rules are evaluated in order of definition. So the first match wins. +# If no match is made libsdp will default to "both". +# +# Examples: +# +# Use SDP by clients connecting to machines that belongs to subnet 192.168.1.* +# family role program address:port[-range] +# use sdp connect * 192.168.1.0/24:* +# +# Use SDP by ttcp when it connects to port 5001 of any machine +# family role program address:port[-range] +# use sdp listen ttcp *:5001 +# +# Use TCP for any program with name starting with ttcp* serving ports 22 to 25 +# family role program address:port[-range] +# use tcp server ttcp* *:22-25 +# +# Listen on both TCP and SDP by any server that listen on port 8080 +# family role program address:port[-range] +# use both server * *:8080 +# +# Connect ssh through SDP and fallback to TCP to hosts on 11.4.8.* port 22 +# family role program address:port[-range] +# use both connect * 11.4.8.0/24:22 +# +# NOTE: If all "use" rules are commented SDP will take "simple SDP" +# mode and use SDP for all connections +# +############################################################################## diff --git a/contrib/ofed/libsdp/libsdp.spec.in b/contrib/ofed/libsdp/libsdp.spec.in new file mode 100644 index 000000000000..c7ba35a8e700 --- /dev/null +++ b/contrib/ofed/libsdp/libsdp.spec.in @@ -0,0 +1,55 @@ + +Summary: LD_PRELOAD-able library for using SDP +Name: libsdp +Version: @VERSION@ +Release: 1%{?dist} +License: GPL/BSD +Group: System Environment/Libraries +BuildRoot: %{_tmppath}/%{name}-%{version}-root +Source: http://www.openfabrics.org/downloads/%{name}-%{version}.tar.gz +Url: http://www.openfabrics.org/ + +%description +libsdp can be LD_PRELOAD-ed to have a sockets application use +InfiniBand Sockets Direct Protocol (SDP) instead of TCP, transparently +and without recompiling the application. + +%package devel +Summary: Development files for the libsdp +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +Development files of libsdp that may be linked directly to an +application, which may be useful for debugging. + +%prep +%setup -q + +%build +%configure +make + +%install +make DESTDIR=${RPM_BUILD_ROOT} install +# remove unpackaged files from the buildroot +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(6644,root,root) +%{_libdir}/libsdp*.so* +%defattr(0644,root,root) +%config(noreplace) %{_sysconfdir}/libsdp.conf +%config(noreplace) %{_includedir}/linux/sdp_inet.h +%doc README NEWS ChangeLog COPYING + +%files devel +%defattr(6644,root,root,-) +%{_libdir}/libsdp*.so + +%changelog +* Sun Jul 22 2007 Vladimir Sokolovsky +- Initial packaging diff --git a/contrib/ofed/libsdp/src/Makefile.am b/contrib/ofed/libsdp/src/Makefile.am new file mode 100644 index 000000000000..f6907b2769cd --- /dev/null +++ b/contrib/ofed/libsdp/src/Makefile.am @@ -0,0 +1,29 @@ +lib_LTLIBRARIES = libsdp.la $(LIB_SDP_SYS) +if WANT_LIBSDP_SYS +LIB_SDP_SYS = libsdp_sys.la +endif + +AM_CFLAGS = -Wall -DSYSCONFDIR=\"$(sysconfdir)\" + +libsdp_la_SOURCES = log.c match.c port.c config_parser.c config_scanner.c +libsdp_la_LDFLAGS = -version-info 1 -ldl -lc +if SOLARIS_BUILD +libsdp_la_LDFLAGS += -lsocket +endif +libsdp_sys_la_SOURCES = socket.c +libsdp_sys_la_LDFLAGS = -version-info 1 + +EXTRA_DIST = libsdp.h linux/sdp_inet.h config_parser.h + +config_parser.c: @MAINTAINER_MODE_TRUE@ $(srcdir)/config_parser.y + $(YACC) -y -plibsdp_yy -d $(srcdir)/config_parser.y + mv y.tab.c config_parser.c + mv y.tab.h config_parser.h + cp -f config_parser.c config_parser.h $(srcdir)/ + +config_scanner.c: @MAINTAINER_MODE_TRUE@ $(srcdir)/config_scanner.l + $(LEX) -Plibsdp_yy $(srcdir)/config_scanner.l + mv lex.libsdp_yy.c config_scanner.c + cp -f config_scanner.c $(srcdir)/config_scanner.c + +nobase_include_HEADERS = linux/sdp_inet.h diff --git a/contrib/ofed/libsdp/src/config_parser.c b/contrib/ofed/libsdp/src/config_parser.c new file mode 100644 index 000000000000..87968fcd63fb --- /dev/null +++ b/contrib/ofed/libsdp/src/config_parser.c @@ -0,0 +1,1890 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.3" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* Substitute the variable and function names. */ +#define yyparse libsdp_yyparse +#define yylex libsdp_yylex +#define yyerror libsdp_yyerror +#define yylval libsdp_yylval +#define yychar libsdp_yychar +#define yydebug libsdp_yydebug +#define yynerrs libsdp_yynerrs + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + USE = 258, + CLIENT = 259, + SERVER = 260, + TCP = 261, + SDP = 262, + BOTH = 263, + INT = 264, + LOG = 265, + DEST = 266, + STDERR = 267, + SYSLOG = 268, + FILENAME = 269, + NAME = 270, + LEVEL = 271, + LINE = 272 + }; +#endif +/* Tokens. */ +#define USE 258 +#define CLIENT 259 +#define SERVER 260 +#define TCP 261 +#define SDP 262 +#define BOTH 263 +#define INT 264 +#define LOG 265 +#define DEST 266 +#define STDERR 267 +#define SYSLOG 268 +#define FILENAME 269 +#define NAME 270 +#define LEVEL 271 +#define LINE 272 + + + + +/* Copy the first part of user declarations. */ +#line 39 "./config_parser.y" + + +/* header section */ +#include +#include +#include +#include "libsdp.h" +#include +#include +#include + +#define YYERROR_VERBOSE 1 + +extern int yyerror(char *msg); +extern int yylex(void); +static int parse_err = 0; + +struct use_family_rule *__sdp_clients_family_rules_head = NULL; +struct use_family_rule *__sdp_clients_family_rules_tail = NULL; +struct use_family_rule *__sdp_servers_family_rules_head = NULL; +struct use_family_rule *__sdp_servers_family_rules_tail = NULL; + +/* some globals to store intermidiate parser state */ +static struct use_family_rule __sdp_rule; +static int current_role = 0; + +int __sdp_config_empty( + void + ) +{ + return ( (__sdp_clients_family_rules_head == NULL) && + (__sdp_servers_family_rules_head == NULL) ); +} + +/* define the address by 4 integers */ +static void __sdp_set_ipv4_addr(short a0, short a1, short a2, short a3) +{ + char buf[16]; + sprintf(buf,"%d.%d.%d.%d", a0, a1, a2, a3); + if (!inet_aton(buf, &( __sdp_rule.ipv4 ))) + { + parse_err = 1; + yyerror("provided address is not legal"); + } +} + +static void __sdp_set_prog_name_expr(char *prog_name_expr) +{ + __sdp_rule.prog_name_expr = strdup(prog_name_expr); + if (!__sdp_rule.prog_name_expr) { + yyerror("fail to allocate program name expression"); + } +} + +static char *__sdp_get_role_str(int role) +{ + if (role == 1) return("server"); + if (role == 2) return("client"); + return("unknown role"); +} + +extern int __sdp_min_level; + +/* dump the current state in readable format */ +static void __sdp_dump_config_state() { + char buf[1024]; + sprintf(buf, "CONFIG: use %s %s %s", + __sdp_get_family_str(__sdp_rule.target_family), + __sdp_get_role_str( current_role ), + __sdp_rule.prog_name_expr); + if (__sdp_rule.match_by_addr) { + if ( __sdp_rule.prefixlen != 32 ) + sprintf(buf+strlen(buf), " %s/%d", + inet_ntoa( __sdp_rule.ipv4 ), __sdp_rule.prefixlen); + else + sprintf(buf+strlen(buf), " %s", inet_ntoa( __sdp_rule.ipv4 )); + } else { + sprintf(buf+strlen(buf), " *"); + } + if (__sdp_rule.match_by_port) { + sprintf(buf+strlen(buf), ":%d",__sdp_rule.sport); + if (__sdp_rule.eport > __sdp_rule.sport) + sprintf(buf+strlen(buf), "-%d",__sdp_rule.eport); + } + else + sprintf(buf+strlen(buf), ":*"); + sprintf(buf+strlen(buf), "\n"); + __sdp_log(1, buf); +} + +/* use the above state for making a new rule */ +static void __sdp_add_rule() { + struct use_family_rule **p_tail, **p_head, *rule; + + if (__sdp_min_level <= 1) __sdp_dump_config_state(); + if ( current_role == 1 ) { + p_tail = &__sdp_servers_family_rules_tail; + p_head = &__sdp_servers_family_rules_head; + } else if ( current_role == 2 ) { + p_tail = &__sdp_clients_family_rules_tail; + p_head = &__sdp_clients_family_rules_head; + } else { + yyerror("ignoring unknown role"); + parse_err = 1; + return; + } + + rule = (struct use_family_rule *)malloc(sizeof(*rule)); + if (!rule) { + yyerror("fail to allocate new rule"); + parse_err = 1; + return; + } + + memset(rule, 0, sizeof(*rule)); + *rule = __sdp_rule; + rule->prev = *p_tail; + if (!(*p_head)) { + *p_head = rule; + } else { + (*p_tail)->next = rule; + } /* if */ + *p_tail = rule; +} + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 1 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 1 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 167 "./config_parser.y" +{ + int ival; + char *sval; +} +/* Line 193 of yacc.c. */ +#line 270 "y.tab.c" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ +#line 192 "./config_parser.y" + + long __sdp_config_line_num; + + +/* Line 216 of yacc.c. */ +#line 286 "y.tab.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int i) +#else +static int +YYID (i) + int i; +#endif +{ + return i; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 7 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 36 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 23 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 17 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 33 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 53 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 272 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 19, 2, 2, 22, 21, 20, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 18, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 5, 8, 9, 11, 14, 15, 18, + 20, 22, 26, 27, 30, 33, 36, 39, 43, 46, + 55, 57, 59, 61, 63, 65, 67, 69, 71, 75, + 77, 85, 87, 91 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 26, 0, -1, 17, -1, 24, 17, -1, -1, 24, + -1, 25, 27, -1, -1, 27, 28, -1, 29, -1, + 33, -1, 10, 30, 24, -1, -1, 30, 31, -1, + 30, 32, -1, 11, 12, -1, 11, 13, -1, 11, + 14, 15, -1, 16, 9, -1, 3, 34, 35, 36, + 37, 18, 39, 24, -1, 6, -1, 7, -1, 8, + -1, 5, -1, 4, -1, 15, -1, 19, -1, 38, + -1, 38, 20, 9, -1, 19, -1, 9, 21, 9, + 21, 9, 21, 9, -1, 9, -1, 9, 22, 9, + -1, 19, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 198, 198, 199, 201, 202, 205, 208, 209, 213, + 214, 218, 221, 222, 223, 227, 228, 229, 233, 237, + 241, 242, 243, 247, 248, 252, 253, 257, 258, 259, + 263, 267, 268, 269 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "\"use\"", "\"client or connect\"", + "\"server or listen\"", "\"tcp\"", "\"sdp\"", "\"both\"", + "\"integer value\"", "\"log statement\"", "\"destination\"", + "\"stderr\"", "\"syslog\"", "\"file\"", "\"a name\"", "\"min-level\"", + "\"new line\"", "':'", "'*'", "'/'", "'.'", "'-'", "$accept", "NL", + "ONL", "config", "statements", "statement", "log_statement", "log_opts", + "log_dest", "verbosity", "socket_statement", "family", "role", "program", + "address", "ipv4", "ports", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 58, 42, + 47, 46, 45 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 23, 24, 24, 25, 25, 26, 27, 27, 28, + 28, 29, 30, 30, 30, 31, 31, 31, 32, 33, + 34, 34, 34, 35, 35, 36, 36, 37, 37, 37, + 38, 39, 39, 39 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 2, 0, 1, 2, 0, 2, 1, + 1, 3, 0, 2, 2, 2, 2, 3, 2, 8, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, + 7, 1, 3, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 4, 2, 5, 7, 0, 3, 6, 1, 0, 12, + 8, 9, 10, 20, 21, 22, 0, 0, 24, 23, + 0, 0, 0, 11, 13, 14, 25, 26, 0, 15, + 16, 0, 18, 0, 29, 0, 27, 17, 0, 0, + 0, 0, 31, 33, 0, 28, 0, 0, 19, 0, + 32, 0, 30 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 2, 3, 4, 6, 10, 11, 17, 24, 25, + 12, 16, 20, 28, 35, 36, 44 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -18 +static const yytype_int8 yypact[] = +{ + -13, -18, 4, -18, 22, -18, 0, -18, 9, -18, + -18, -18, -18, -18, -18, -18, 2, -3, -18, -18, + -10, 6, 14, 4, -18, -18, -18, -18, -8, -18, + -18, 10, -18, 3, -18, 8, 11, -18, 19, -7, + 20, 12, 13, -18, -13, -18, 21, 23, 4, 15, + -18, 25, -18 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -18, -17, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 23, 33, 42, 8, 1, 26, 18, 19, 21, 27, + 9, 34, 43, 22, 1, 13, 14, 15, 29, 30, + 31, 5, 7, 32, 38, 37, 39, 48, 41, 45, + 49, 40, 50, 46, 52, 47, 51 +}; + +static const yytype_uint8 yycheck[] = +{ + 17, 9, 9, 3, 17, 15, 4, 5, 11, 19, + 10, 19, 19, 16, 17, 6, 7, 8, 12, 13, + 14, 17, 0, 9, 21, 15, 18, 44, 9, 9, + 9, 20, 9, 21, 9, 22, 21 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 17, 24, 25, 26, 17, 27, 0, 3, 10, + 28, 29, 33, 6, 7, 8, 34, 30, 4, 5, + 35, 11, 16, 24, 31, 32, 15, 19, 36, 12, + 13, 14, 9, 9, 19, 37, 38, 15, 21, 18, + 20, 9, 9, 19, 39, 9, 21, 22, 24, 9, + 9, 21, 9 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +#else +static void +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + fprintf (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + fprintf (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + int yystate; + int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + look-ahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to look-ahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a look-ahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 15: +#line 227 "./config_parser.y" + { __sdp_log_set_log_stderr(); } + break; + + case 16: +#line 228 "./config_parser.y" + { __sdp_log_set_log_syslog(); } + break; + + case 17: +#line 229 "./config_parser.y" + { __sdp_log_set_log_file((yyvsp[(3) - (3)].sval)); } + break; + + case 18: +#line 233 "./config_parser.y" + { __sdp_log_set_min_level((yyvsp[(2) - (2)].ival)); } + break; + + case 19: +#line 237 "./config_parser.y" + { __sdp_add_rule(); } + break; + + case 20: +#line 241 "./config_parser.y" + { __sdp_rule.target_family = USE_TCP; } + break; + + case 21: +#line 242 "./config_parser.y" + { __sdp_rule.target_family = USE_SDP; } + break; + + case 22: +#line 243 "./config_parser.y" + { __sdp_rule.target_family = USE_BOTH; } + break; + + case 23: +#line 247 "./config_parser.y" + { current_role = 1; } + break; + + case 24: +#line 248 "./config_parser.y" + { current_role = 2; } + break; + + case 25: +#line 252 "./config_parser.y" + { __sdp_set_prog_name_expr((yyvsp[(1) - (1)].sval)); } + break; + + case 26: +#line 253 "./config_parser.y" + { __sdp_set_prog_name_expr("*"); } + break; + + case 27: +#line 257 "./config_parser.y" + { __sdp_rule.match_by_addr = 1; __sdp_rule.prefixlen = 32; } + break; + + case 28: +#line 258 "./config_parser.y" + { __sdp_rule.match_by_addr = 1; __sdp_rule.prefixlen = (yyvsp[(3) - (3)].ival); } + break; + + case 29: +#line 259 "./config_parser.y" + { __sdp_rule.match_by_addr = 0; __sdp_rule.prefixlen = 32; } + break; + + case 30: +#line 263 "./config_parser.y" + { __sdp_set_ipv4_addr((yyvsp[(1) - (7)].ival),(yyvsp[(3) - (7)].ival),(yyvsp[(5) - (7)].ival),(yyvsp[(7) - (7)].ival)); } + break; + + case 31: +#line 267 "./config_parser.y" + { __sdp_rule.match_by_port = 1; __sdp_rule.sport= (yyvsp[(1) - (1)].ival); __sdp_rule.eport= (yyvsp[(1) - (1)].ival); } + break; + + case 32: +#line 268 "./config_parser.y" + { __sdp_rule.match_by_port = 1; __sdp_rule.sport= (yyvsp[(1) - (3)].ival); __sdp_rule.eport= (yyvsp[(3) - (3)].ival); } + break; + + case 33: +#line 269 "./config_parser.y" + { __sdp_rule.match_by_port = 0; __sdp_rule.sport= 0 ; __sdp_rule.eport= 0; } + break; + + +/* Line 1267 of yacc.c. */ +#line 1614 "y.tab.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + +#line 272 "./config_parser.y" + + +int yyerror(char *msg) +{ + /* replace the $undefined and $end if exists */ + char *orig_msg = (char*)malloc(strlen(msg)+25); + char *final_msg = (char*)malloc(strlen(msg)+25); + + strcpy(orig_msg, msg); + + char *word = strtok(orig_msg, " "); + final_msg[0] = '\0'; + while (word != NULL) { + if (!strncmp(word, "$undefined", 10)) { + strcat(final_msg, "unrecognized-token "); + } else if (!strncmp(word, "$end",4)) { + strcat(final_msg, "end-of-file "); + } else { + strcat(final_msg, word); + strcat(final_msg, " "); + } + word = strtok(NULL, " "); + } + + __sdp_log(9, "Error (line:%ld) : %s\n", __sdp_config_line_num, final_msg); + parse_err = 1; + + free(orig_msg); + free(final_msg); + return 1; +} + +#include +#include + +/* parse apollo route dump file */ +int __sdp_parse_config (const char *fileName) { + extern FILE * libsdp_yyin; + + /* open the file */ + if (access(fileName, R_OK)) { + printf("libsdp Error: No access to open File:%s %s\n", + fileName, strerror(errno)); + return(1); + } + + libsdp_yyin = fopen(fileName,"r"); + if (!libsdp_yyin) { + printf("libsdp Error: Fail to open File:%s\n", fileName); + return(1); + } + parse_err = 0; + __sdp_config_line_num = 1; + + /* parse it */ + yyparse(); + + fclose(libsdp_yyin); + return(parse_err); +} + + + diff --git a/contrib/ofed/libsdp/src/config_parser.h b/contrib/ofed/libsdp/src/config_parser.h new file mode 100644 index 000000000000..fd193f358fb9 --- /dev/null +++ b/contrib/ofed/libsdp/src/config_parser.h @@ -0,0 +1,95 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + USE = 258, + CLIENT = 259, + SERVER = 260, + TCP = 261, + SDP = 262, + BOTH = 263, + INT = 264, + LOG = 265, + DEST = 266, + STDERR = 267, + SYSLOG = 268, + FILENAME = 269, + NAME = 270, + LEVEL = 271, + LINE = 272 + }; +#endif +/* Tokens. */ +#define USE 258 +#define CLIENT 259 +#define SERVER 260 +#define TCP 261 +#define SDP 262 +#define BOTH 263 +#define INT 264 +#define LOG 265 +#define DEST 266 +#define STDERR 267 +#define SYSLOG 268 +#define FILENAME 269 +#define NAME 270 +#define LEVEL 271 +#define LINE 272 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 167 "./config_parser.y" +{ + int ival; + char *sval; +} +/* Line 1529 of yacc.c. */ +#line 88 "y.tab.h" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + +extern YYSTYPE libsdp_yylval; + diff --git a/contrib/ofed/libsdp/src/config_scanner.c b/contrib/ofed/libsdp/src/config_scanner.c new file mode 100644 index 000000000000..661b58430fc7 --- /dev/null +++ b/contrib/ofed/libsdp/src/config_scanner.c @@ -0,0 +1,1885 @@ +#define yy_create_buffer libsdp_yy_create_buffer +#define yy_delete_buffer libsdp_yy_delete_buffer +#define yy_scan_buffer libsdp_yy_scan_buffer +#define yy_scan_string libsdp_yy_scan_string +#define yy_scan_bytes libsdp_yy_scan_bytes +#define yy_flex_debug libsdp_yy_flex_debug +#define yy_init_buffer libsdp_yy_init_buffer +#define yy_flush_buffer libsdp_yy_flush_buffer +#define yy_load_buffer_state libsdp_yy_load_buffer_state +#define yy_switch_to_buffer libsdp_yy_switch_to_buffer +#define yyin libsdp_yyin +#define yyleng libsdp_yyleng +#define yylex libsdp_yylex +#define yyout libsdp_yyout +#define yyrestart libsdp_yyrestart +#define yytext libsdp_yytext +#define yywrap libsdp_yywrap + +/* A lexical scanner generated by flex*/ + +/* Scanner skeleton version: + * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include +#include + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include +#include +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* Some routines like yy_flex_realloc() are emitted as static but are + not called by all lexers. This generates warnings in some compilers, + notably GCC. Arrange to suppress these. */ +#ifdef __GNUC__ +#define YY_MAY_BE_UNUSED __attribute__((unused)) +#else +#define YY_MAY_BE_UNUSED +#endif + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )) YY_MAY_BE_UNUSED; +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 20 +#define YY_END_OF_BUFFER 21 +static yyconst short int yy_accept[171] = + { 0, + 0, 0, 0, 0, 21, 19, 18, 16, 17, 2, + 2, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 18, 1, 15, 15, 2, 2, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 1, 18, 17, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 18, 1, 1, 15, 15, 2, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 1, 0, 0, 0, 0, 0, 0, + 3, 0, 11, 0, 0, 0, 10, 9, 1, 15, + 15, 15, 15, 15, 15, 3, 15, 11, 15, 15, + + 15, 10, 9, 12, 0, 0, 0, 8, 0, 0, + 0, 0, 0, 12, 15, 15, 15, 8, 15, 15, + 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, + 0, 15, 15, 15, 15, 15, 15, 15, 15, 13, + 0, 0, 14, 0, 6, 7, 13, 15, 15, 14, + 15, 6, 7, 0, 0, 15, 15, 0, 0, 15, + 15, 0, 5, 15, 5, 0, 15, 4, 4, 0 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 4, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 5, 1, 1, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 8, 9, 10, 11, + + 12, 13, 14, 15, 16, 1, 1, 17, 18, 19, + 20, 21, 1, 22, 23, 24, 25, 26, 1, 1, + 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[28] = + { 0, + 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1 + } ; + +static yyconst short int yy_base[177] = + { 0, + 0, 26, 30, 56, 214, 215, 211, 215, 0, 215, + 55, 192, 46, 199, 194, 48, 193, 58, 198, 184, + 63, 0, 0, 204, 0, 65, 185, 56, 192, 187, + 58, 186, 68, 191, 177, 197, 196, 0, 77, 173, + 180, 176, 171, 176, 169, 177, 171, 168, 166, 176, + 163, 164, 172, 73, 0, 0, 0, 181, 80, 158, + 165, 161, 156, 161, 154, 162, 156, 153, 151, 161, + 148, 149, 157, 166, 152, 154, 146, 140, 151, 138, + 215, 156, 215, 134, 147, 141, 215, 215, 0, 142, + 144, 136, 130, 141, 128, 0, 146, 0, 124, 137, + + 131, 0, 0, 215, 128, 134, 129, 215, 132, 126, + 130, 119, 120, 0, 120, 126, 121, 0, 124, 118, + 122, 111, 112, 107, 120, 110, 109, 115, 104, 103, + 110, 99, 112, 102, 101, 107, 96, 95, 102, 215, + 91, 106, 215, 87, 215, 215, 0, 88, 103, 0, + 84, 0, 0, 85, 96, 83, 94, 78, 76, 75, + 73, 69, 215, 68, 0, 62, 40, 215, 0, 215, + 95, 97, 28, 99, 101, 103 + } ; + +static yyconst short int yy_def[177] = + { 0, + 170, 1, 170, 3, 170, 170, 170, 170, 171, 170, + 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 172, 173, 174, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 175, 170, 171, 170, 170, + 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 170, 170, 170, 176, 172, 173, 174, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 175, 170, 170, 170, 170, 170, 170, + 170, 170, 170, 170, 170, 170, 170, 170, 176, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + + 173, 173, 173, 170, 170, 170, 170, 170, 170, 170, + 170, 170, 170, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 170, 170, 170, 170, 170, 170, 170, + 170, 173, 173, 173, 173, 173, 173, 173, 173, 170, + 170, 170, 170, 170, 170, 170, 173, 173, 173, 173, + 173, 173, 173, 170, 170, 173, 173, 170, 170, 173, + 173, 170, 170, 173, 173, 170, 173, 170, 173, 0, + 170, 170, 170, 170, 170, 170 + } ; + +static yyconst short int yy_nxt[243] = + { 0, + 6, 7, 8, 9, 6, 10, 11, 6, 12, 13, + 14, 6, 15, 6, 6, 6, 16, 17, 6, 6, + 6, 6, 18, 19, 20, 6, 6, 21, 57, 22, + 23, 7, 8, 24, 23, 25, 26, 23, 27, 28, + 29, 23, 30, 23, 23, 23, 31, 32, 23, 23, + 23, 23, 33, 34, 35, 23, 23, 21, 169, 36, + 39, 39, 41, 45, 54, 42, 55, 46, 48, 49, + 59, 59, 61, 65, 54, 62, 55, 66, 68, 69, + 168, 50, 39, 39, 51, 59, 59, 167, 166, 165, + 164, 70, 163, 162, 71, 38, 38, 56, 56, 58, + + 58, 74, 74, 89, 89, 161, 160, 159, 158, 157, + 156, 147, 155, 154, 140, 153, 152, 150, 151, 150, + 149, 148, 147, 146, 145, 143, 144, 143, 142, 141, + 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, + 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, + 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, + 110, 109, 108, 107, 106, 105, 104, 56, 103, 102, + 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, + 91, 90, 38, 88, 87, 86, 85, 84, 83, 82, + 81, 80, 79, 78, 77, 76, 75, 37, 56, 73, + + 72, 67, 64, 63, 60, 38, 53, 52, 47, 44, + 43, 40, 37, 170, 5, 170, 170, 170, 170, 170, + 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 170 + } ; + +static yyconst short int yy_chk[243] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, 173, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 4, 167, 4, + 11, 11, 13, 16, 21, 13, 21, 16, 18, 18, + 26, 26, 28, 31, 54, 28, 54, 31, 33, 33, + 166, 18, 39, 39, 18, 59, 59, 164, 162, 161, + 160, 33, 159, 158, 33, 171, 171, 172, 172, 174, + + 174, 175, 175, 176, 176, 157, 156, 155, 154, 151, + 149, 148, 144, 142, 141, 139, 138, 137, 136, 135, + 134, 133, 132, 131, 130, 129, 128, 127, 126, 125, + 124, 123, 122, 121, 120, 119, 117, 116, 115, 113, + 112, 111, 110, 109, 107, 106, 105, 101, 100, 99, + 97, 95, 94, 93, 92, 91, 90, 86, 85, 84, + 82, 80, 79, 78, 77, 76, 75, 74, 73, 72, + 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, + 61, 60, 58, 53, 52, 51, 50, 49, 48, 47, + 46, 45, 44, 43, 42, 41, 40, 37, 36, 35, + + 34, 32, 30, 29, 27, 24, 20, 19, 17, 15, + 14, 12, 7, 5, 170, 170, 170, 170, 170, 170, + 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 170 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "./config_scanner.l" +#define INITIAL 0 +/* + * Copyright (c) 2006 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id: ibnl_scanner.ll,v 1.4 2005/02/23 21:08:37 eitan Exp $ + */ +#line 36 "./config_scanner.l" + +/* #define DEBUG 1 */ + +#define yyparse libsdp_yyparse +#define yylex libsdp_yylex +#define yyerror libsdp_yyerror +#define yylval libsdp_yylval +#define yychar libsdp_yychar +#define yydebug libsdp_yydebug +#define yynerrs libsdp_yynerrs + +#define yywrap libsdp_yywrap + +#include +#include +#include "config_parser.h" +extern long __sdp_config_line_num; +#define CANNAME 1 + +#line 550 "lex.libsdp_yy.c" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + if ( yyleng > 0 ) \ + yy_current_buffer->yy_at_bol = \ + (yytext[yyleng - 1] == '\n'); \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp = NULL, *yy_bp = NULL; + register int yy_act; + +#line 55 "./config_scanner.l" + + +#line 707 "lex.libsdp_yy.c" + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; + yy_current_state += YY_AT_BOL(); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 171 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 215 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 57 "./config_scanner.l" +{} + YY_BREAK +case 2: +YY_RULE_SETUP +#line 59 "./config_scanner.l" +{ + yylval.ival = atoi(yytext); +#ifdef DEBUG + printf("INT:%d\n",yylval.ival); +#endif + return INT; +} + YY_BREAK +case 3: +YY_RULE_SETUP +#line 67 "./config_scanner.l" +{ + yylval.ival = LOG; +#ifdef DEBUG + printf("LOG\n"); +#endif + return LOG; +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 75 "./config_scanner.l" +{ + yylval.ival = DEST; +#ifdef DEBUG + printf("DEST\n"); +#endif + return DEST; +} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 83 "./config_scanner.l" +{ + yylval.ival = LEVEL; +#ifdef DEBUG + printf("LEVEL\n"); +#endif + return LEVEL; +} + YY_BREAK +case 6: +YY_RULE_SETUP +#line 91 "./config_scanner.l" +{ + yylval.ival = STDERR; +#ifdef DEBUG + printf("STDERR\n"); +#endif + return STDERR; +} + YY_BREAK +case 7: +YY_RULE_SETUP +#line 99 "./config_scanner.l" +{ + yylval.ival = SYSLOG; +#ifdef DEBUG + printf("SYSLOG\n"); +#endif + return SYSLOG; +} + YY_BREAK +case 8: +YY_RULE_SETUP +#line 107 "./config_scanner.l" +{ + yylval.ival = FILENAME; +#ifdef DEBUG + printf("FILENAME\n"); +#endif + BEGIN(CANNAME); + return FILENAME; +} + YY_BREAK +case 9: +YY_RULE_SETUP +#line 116 "./config_scanner.l" +{ + yylval.ival = USE; +#ifdef DEBUG + printf("USE\n"); +#endif + return USE; +} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 124 "./config_scanner.l" +{ + yylval.ival = TCP; +#ifdef DEBUG + printf("TCP\n"); +#endif + return TCP; +} + YY_BREAK +case 11: +YY_RULE_SETUP +#line 132 "./config_scanner.l" +{ + yylval.ival = SDP; +#ifdef DEBUG + printf("SDP\n"); +#endif + return SDP; +} + YY_BREAK +case 12: +YY_RULE_SETUP +#line 140 "./config_scanner.l" +{ + yylval.ival = BOTH; +#ifdef DEBUG + printf("BOTH\n"); +#endif + return BOTH; +} + YY_BREAK +case 13: +YY_RULE_SETUP +#line 148 "./config_scanner.l" +{ + yylval.ival = CLIENT; +#ifdef DEBUG + printf("CLIENT\n"); +#endif + BEGIN(CANNAME); + return CLIENT; +} + YY_BREAK +case 14: +YY_RULE_SETUP +#line 157 "./config_scanner.l" +{ + yylval.ival = SERVER; +#ifdef DEBUG + printf("SERVER\n"); +#endif + BEGIN(CANNAME); + return SERVER; +} + YY_BREAK +case 15: +YY_RULE_SETUP +#line 166 "./config_scanner.l" +{ + yylval.sval = (char *)malloc(strlen(yytext) + 1); + strcpy(yylval.sval, yytext); +#ifdef DEBUG + printf("NAME:%s\n",yylval.sval); +#endif + BEGIN(0); + return (NAME); +} + YY_BREAK +case 16: +YY_RULE_SETUP +#line 176 "./config_scanner.l" +{ + __sdp_config_line_num++; +#ifdef DEBUG + printf("LINE\n"); +#endif + yylval.ival = LINE; + return(LINE); +} + YY_BREAK +case 17: +YY_RULE_SETUP +#line 185 "./config_scanner.l" +{ + __sdp_config_line_num++; +} + YY_BREAK +case 18: +YY_RULE_SETUP +#line 189 "./config_scanner.l" +{} + YY_BREAK +case 19: +YY_RULE_SETUP +#line 191 "./config_scanner.l" +{ +#ifdef DEBUG + printf("CHAR:%c\n",yytext[0]); +#endif + return(yytext[0]); +} + YY_BREAK +case 20: +YY_RULE_SETUP +#line 198 "./config_scanner.l" +ECHO; + YY_BREAK +#line 994 "lex.libsdp_yy.c" +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(CANNAME): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + yy_current_state += YY_AT_BOL(); + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 171 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + register char *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 171 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 170); + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + yy_current_buffer->yy_at_bol = (c == '\n'); + + return c; + } +#endif /* YY_NO_INPUT */ + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 198 "./config_scanner.l" + + +int yywrap () +{ + return (1); +} + diff --git a/contrib/ofed/libsdp/src/libsdp.h b/contrib/ofed/libsdp/src/libsdp.h new file mode 100644 index 000000000000..0402d55a6002 --- /dev/null +++ b/contrib/ofed/libsdp/src/libsdp.h @@ -0,0 +1,131 @@ +/* + This software is available to you under a choice of one of two + licenses. You may choose to be licensed under the terms of the GNU + General Public License (GPL) Version 2, available at + , or the OpenIB.org BSD + license, available in the LICENSE.TXT file accompanying this + software. These details are also available at + . + + 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. + + Copyright (c) 2004 Topspin Communications. All rights reserved. + Copyright (c) 2005-2006 Mellanox Technologies Ltd. All rights reserved. + + $Id$ +*/ + +#include + +/* + * SDP specific includes + */ +#include "linux/sdp_inet.h" + +/* --------------------------------------------------------------------- */ +/* library static and global variables */ +/* --------------------------------------------------------------------- */ + +/* max string length to store any IPv4/IPv6 address */ +#define MAX_ADDR_STR_LEN 49 + +typedef enum +{ + USE_TCP = 1, + USE_SDP, + USE_BOTH, +} use_family_t; + +/* some state to string functions */ +static inline char * +__sdp_get_family_str( + use_family_t family ) +{ + switch ( family ) { + case USE_TCP: + return "tcp"; + break; + case USE_SDP: + return "sdp"; + break; + case USE_BOTH: + return "both"; + break; + } + return ( "unknown-family" ); +} + +/* data structure for holding address family mapoping rules */ +/* note we filter non relevant programs during parsing ... */ +struct use_family_rule +{ + struct use_family_rule *prev, *next; + int match_by_addr; /* if 0 ignore address match */ + struct in_addr ipv4; /* IPv4 address for mapping */ + unsigned char prefixlen; /* length of CIDR prefix (ie /24) */ + int match_by_port; /* if 0 ignore port match */ + unsigned short sport, eport; /* start port - end port, inclusive */ + use_family_t target_family; /* if match - use this family */ + char *prog_name_expr; /* expression for program name */ +}; + +extern struct use_family_rule *__sdp_clients_family_rules_head; +extern struct use_family_rule *__sdp_clients_family_rules_tail; +extern struct use_family_rule *__sdp_servers_family_rules_head; +extern struct use_family_rule *__sdp_servers_family_rules_tail; + +#define SDP_NETMASK(n) ((n == 0) ? 0 : ~((1UL<<(32 - n)) - 1)) + +/* match.c */ +use_family_t __sdp_match_connect( + const struct sockaddr *sin, + const socklen_t addrlen ); + +use_family_t __sdp_match_listen( + const struct sockaddr *sin, + const socklen_t addrlen ); + +/* config.c */ +int __sdp_config_empty( + void ); + +int __sdp_parse_config( + const char *config_file ); + +use_family_t __sdp_match_by_program( + ); + +/* log.c */ +void __sdp_log( + int level, + char *format, + ... ); + +int __sdp_log_get_level( + void ); + +void __sdp_log_set_min_level( + int level ); + +int __sdp_log_set_log_stderr( + void ); + +int __sdp_log_set_log_syslog( + void ); + +int __sdp_log_set_log_file( + char *filename ); + +/* port.c */ +int __sdp_sockaddr_to_sdp( + const struct sockaddr *addr_in, + socklen_t addrlen, + struct sockaddr_in *addr_out, + int *was_ipv6 ); diff --git a/contrib/ofed/libsdp/src/linux/sdp_inet.h b/contrib/ofed/libsdp/src/linux/sdp_inet.h new file mode 100644 index 000000000000..fde347f073d6 --- /dev/null +++ b/contrib/ofed/libsdp/src/linux/sdp_inet.h @@ -0,0 +1,52 @@ +/* + This software is available to you under a choice of one of two + licenses. You may choose to be licensed under the terms of the GNU + General Public License (GPL) Version 2, available at + , or the OpenIB.org BSD + license, available in the LICENSE.TXT file accompanying this + software. These details are also available at + . + + 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. + + Copyright (c) 2004 Topspin Communications. All rights reserved. + + $Id$ +*/ + +#ifndef _SDP_INET_H +#define _SDP_INET_H + +/* + * constants shared between user and kernel space. + */ + +#ifndef SOLARIS_BUILD +#define AF_INET_SDP 27 /* SDP socket protocol family */ +#define AF_INET6_SDP 28 /* SDP socket protocol family */ +#else +#define AF_INET_SDP 31 /* This is an invalid family on native solaris + * and will only work using QuickTransit */ +//TODO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx +#define AF_INET6_SDP 32 /* SDP socket protocol family */ +#endif + +#define AF_INET_STR "AF_INET_SDP" /* SDP enabled environment variable */ +#define AF_INET6_STR "AF_INET6_SDP" /* SDP enabled environment variable */ + +#ifndef SDP_ZCOPY_THRESH +#define SDP_ZCOPY_THRESH 80 +#endif + +#ifndef SDP_LAST_BIND_ERR +#define SDP_LAST_BIND_ERR 81 +#endif + +#endif /* _SDP_INET_H */ diff --git a/contrib/ofed/libsdp/src/log.c b/contrib/ofed/libsdp/src/log.c new file mode 100644 index 000000000000..c98ee461e53f --- /dev/null +++ b/contrib/ofed/libsdp/src/log.c @@ -0,0 +1,236 @@ +/* + This software is available to you under a choice of one of two + licenses. You may choose to be licensed under the terms of the GNU + General Public License (GPL) Version 2, available at + , or the OpenIB.org BSD + license, available in the LICENSE.TXT file accompanying this + software. These details are also available at + . + + 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. + + Copyright (c) 2004 Topspin Communications. All rights reserved. + Copyright (c) 2006 Mellanox Technologies Ltd. All rights reserved. + + $Id$ +*/ + +/* + * system includes + */ +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * SDP specific includes + */ +#include "libsdp.h" + +extern char *program_invocation_short_name; + +typedef enum +{ + SDP_LOG_FILE, + SDP_LOG_SYSLOG, +} __sdp_log_type_t; + +/* --------------------------------------------------------------------- */ +/* library static and global variables */ +/* --------------------------------------------------------------------- */ +int __sdp_min_level = 9; +static __sdp_log_type_t __sdp_log_type = SDP_LOG_FILE; +static FILE *__sdp_log_file = NULL; + +void +__sdp_log( + int level, + char *format, + ... ) +{ + va_list ap; + char extra_format[512]; + time_t timeval; + char timestr[32]; + + if ( level < __sdp_min_level ) { + return; + } + + va_start( ap, format ); + switch ( __sdp_log_type ) { + case SDP_LOG_SYSLOG: + sprintf( extra_format, "%s[%d] libsdp %s ", + program_invocation_short_name, getpid( ), format ); + vsyslog( LOG_USER | LOG_NOTICE, extra_format, ap ); + break; + case SDP_LOG_FILE: + timeval = time(NULL); +#ifdef SOLARIS_BUILD + ctime_r(&timeval, timestr, sizeof timestr); +#else + ctime_r(&timeval, timestr); +#endif + timestr[strlen(timestr)-1] = '\0'; + sprintf( extra_format, "%s %s[%d] libsdp %s ", + timestr, program_invocation_short_name, + getpid( ), format ); + if ( __sdp_log_file == NULL ) { + vfprintf( stderr, extra_format, ap ); +#if 0 /* might slow everything too much? */ + ( void )fflush( stderr ); +#endif + } else { + vfprintf( __sdp_log_file, extra_format, ap ); +#if 0 /* might slow everything too much? */ + ( void )fflush( __sdp_log_file ); +#endif + } + break; + } + va_end( ap ); +} + +int +__sdp_log_get_level( + void ) +{ + return ( __sdp_min_level ); +} + +void +__sdp_log_set_min_level( + int level ) +{ + __sdp_min_level = level; +} + +static void +__sdp_log_set_log_type( + __sdp_log_type_t type ) +{ + if ( __sdp_log_file != NULL ) { + fclose( __sdp_log_file ); + __sdp_log_file = NULL; + } + + __sdp_log_type = type; +} + +int +__sdp_log_set_log_stderr( + void ) +{ + __sdp_log_set_log_type( SDP_LOG_FILE ); + /* NULL means stderr */ + + return 1; +} + +int +__sdp_log_set_log_syslog( + void ) +{ + __sdp_log_set_log_type( SDP_LOG_SYSLOG ); + + return 1; +} + +int +__sdp_log_set_log_file( + char *filename ) +{ + FILE *f; + uid_t uid; + struct stat lstat_res; + int status; + + char *p, tfilename[PATH_MAX + 1]; + + /* Strip off any paths from the filename */ + p = strrchr( filename, '/' ); + + /* + base on the active user ID we either use /var/log for root or + append the uid to the name + */ + uid = geteuid(); + if (uid == 0) { + if ( p ) + filename = p + 1; + snprintf( tfilename, sizeof(tfilename), "/var/log/%s", filename ); + } else { + char tdir[PATH_MAX + 1]; + /* + for regular user, allow log file to be placed in a user + requested path. If no path is requested the log file is + placed in /tmp/ + */ + if ( p ) + snprintf(tdir, sizeof(tdir), "%s.%d", filename, uid ); + else + snprintf(tdir, sizeof(tdir ), "/tmp/%s.%d", filename, uid ); + + if (mkdir(tdir, 0700)) { + struct stat stat; + + if (errno != EEXIST) { + __sdp_log( 9, "Couldn't create directory '%s' for logging (%m)\n", tdir ); + return 0; + } + + if (lstat(tdir, &stat)) { + __sdp_log(9, "Couldn't lstat directory %s\n", tdir); + return 0; + } + + if (!S_ISDIR(stat.st_mode) || stat.st_uid != uid || + (stat.st_mode & ~(S_IFMT | S_IRWXU))) { + __sdp_log( 9, "Cowardly refusing to log into directory:'%s'. " + "Make sure it is not: (1) link, (2) other uid, (3) bad permissions." + "thus is a security issue.\n", tdir ); + return 0; + } + } + + snprintf(tfilename, sizeof(tfilename), "%s/log", tdir); + printf("dir: %s file: %s\n", tdir, tfilename); + } + + /* double check the file is not a link */ + status = lstat(tfilename, &lstat_res); + if ( (status == 0) && S_ISLNK(lstat_res.st_mode) ) { + __sdp_log( 9, "Cowardly refusing to log into:'%s'. " + "It is a link - thus is a security issue.\n", tfilename ); + return 0; + } + + f = fopen( tfilename, "a" ); + if ( !f ) { + __sdp_log( 9, "Couldn't open '%s' for logging (%m)\n", tfilename ); + return 0; + } + + __sdp_log_set_log_type( SDP_LOG_FILE ); + __sdp_log_file = f; + + return 1; +} diff --git a/contrib/ofed/libsdp/src/match.c b/contrib/ofed/libsdp/src/match.c new file mode 100644 index 000000000000..fe981b2e6f05 --- /dev/null +++ b/contrib/ofed/libsdp/src/match.c @@ -0,0 +1,296 @@ +/* + This software is available to you under a choice of one of two + licenses. You may choose to be licensed under the terms of the GNU + General Public License (GPL) Version 2, available at + , or the OpenIB.org BSD + license, available in the LICENSE.TXT file accompanying this + software. These details are also available at + . + + 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. + + Copyright (c) 2004 Topspin Communications. All rights reserved. + Copyright (c) 2005-2006 Mellanox Technologies Ltd. All rights reserved. + + $Id$ +*/ + +/* + * system includes + */ +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * SDP specific includes + */ +#include "libsdp.h" + +/* --------------------------------------------------------------------- */ +/* library static and global variables */ +/* --------------------------------------------------------------------- */ +extern char *program_invocation_name, *program_invocation_short_name; + +static void +get_rule_str( + struct use_family_rule *rule, + char *buf, + size_t len ) +{ + char addr_buf[MAX_ADDR_STR_LEN]; + char ports_buf[16]; + char *target = __sdp_get_family_str( rule->target_family ); + char *prog = rule->prog_name_expr; + + /* TODO: handle IPv6 in rule */ + if ( rule->match_by_addr ) { + if ( rule->prefixlen != 32 ) + sprintf( addr_buf, "%s/%d", inet_ntoa( rule->ipv4 ), + rule->prefixlen ); + else + sprintf( addr_buf, "%s", inet_ntoa( rule->ipv4 ) ); + } else { + strcpy( addr_buf, "*" ); + } + + if ( rule->match_by_port ) + if ( rule->eport > rule->sport ) + sprintf( ports_buf, "%d", rule->sport ); + else + sprintf( ports_buf, "%d-%d", rule->sport, rule->eport ); + else + sprintf( ports_buf, "*" ); + + snprintf( buf, len, "use %s %s %s:%s", target, prog, addr_buf, ports_buf ); +} + +/* return 0 if the addresses match */ +static inline int +match_ipv4_addr( + struct use_family_rule *rule, + const struct sockaddr_in *sin ) +{ + return ( rule->ipv4.s_addr != + ( sin->sin_addr. + s_addr & htonl( SDP_NETMASK( rule->prefixlen ) ) ) ); +} + +static int +match_ip_addr_and_port( + struct use_family_rule *rule, + const struct sockaddr *addr_in, + const socklen_t addrlen ) +{ + const struct sockaddr_in *sin = ( const struct sockaddr_in * )addr_in; + const struct sockaddr_in6 *sin6 = ( const struct sockaddr_in6 * )addr_in; + struct sockaddr_in tmp_sin; + unsigned short port; + int match = 1; + char addr_buf[MAX_ADDR_STR_LEN]; + const char *addr_str; + char rule_str[512]; + + if ( __sdp_log_get_level( ) <= 3 ) { + if ( sin6->sin6_family == AF_INET6 ) { + addr_str = + inet_ntop( AF_INET6, ( void * )&( sin6->sin6_addr ), addr_buf, + MAX_ADDR_STR_LEN ); + port = ntohs( sin6->sin6_port ); + } else { + addr_str = + inet_ntop( AF_INET, ( void * )&( sin->sin_addr ), addr_buf, + MAX_ADDR_STR_LEN ); + port = ntohs( sin->sin_port ); + } + if ( addr_str == NULL ) + addr_str = "INVALID_ADDR"; + + get_rule_str( rule, rule_str, sizeof( rule_str ) ); + + __sdp_log( 3, "MATCH: matching %s:%d to %s => \n", addr_str, port, + rule_str ); + } + + /* We currently only support IPv4 and IPv4 embedded in IPv6 */ + if ( rule->match_by_port ) { + if ( sin6->sin6_family == AF_INET6 ) + port = ntohs( sin6->sin6_port ); + else + port = ntohs( sin->sin_port ); + + if ( ( port < rule->sport ) || ( port > rule->eport ) ) { + __sdp_log( 3, "NEGATIVE by port range\n" ); + match = 0; + } + } + + if ( match && rule->match_by_addr ) { + if ( __sdp_sockaddr_to_sdp( addr_in, addrlen, &tmp_sin, NULL ) || + match_ipv4_addr( rule, &tmp_sin ) ) { + __sdp_log( 3, "NEGATIVE by address\n" ); + match = 0; + } + } + + if ( match ) + __sdp_log( 3, "POSITIVE\n" ); + + return match; +} + +/* return 1 on match */ +static int +match_program_name( + struct use_family_rule *rule ) +{ + return !fnmatch( rule->prog_name_expr, program_invocation_short_name, 0 ); +} + +static use_family_t +get_family_by_first_matching_rule( + const struct sockaddr *sin, + const socklen_t addrlen, + struct use_family_rule *rules ) +{ + struct use_family_rule *rule; + + for ( rule = rules; rule != NULL; rule = rule->next ) { + /* skip if not our program */ + if ( !match_program_name( rule ) ) + continue; + + /* first rule wins */ + if ( match_ip_addr_and_port( rule, sin, addrlen ) ) + return ( rule->target_family ); + } + + return ( USE_BOTH ); +} + +/* return the result of the first matching rule found */ +use_family_t +__sdp_match_listen( + const struct sockaddr * sin, + const socklen_t addrlen ) +{ + use_family_t target_family; + + /* if we do not have any rules we use sdp */ + if ( __sdp_config_empty( ) ) + target_family = USE_SDP; + else + target_family = + get_family_by_first_matching_rule( sin, addrlen, + __sdp_servers_family_rules_head ); + + __sdp_log( 4, "MATCH LISTEN: => %s\n", + __sdp_get_family_str( target_family ) ); + + return ( target_family ); +} + +use_family_t +__sdp_match_connect( + const struct sockaddr * sin, + const socklen_t addrlen ) +{ + use_family_t target_family; + + /* if we do not have any rules we use sdp */ + if ( __sdp_config_empty( ) ) + target_family = USE_SDP; + else + target_family = + get_family_by_first_matching_rule( sin, addrlen, + __sdp_clients_family_rules_head ); + + __sdp_log( 4, "MATCH CONNECT: => %s\n", + __sdp_get_family_str( target_family ) ); + + return ( target_family ); +} + +/* given a set of rules see if there is a global match for current program */ +static use_family_t +match_by_all_rules_program( + struct use_family_rule *rules ) +{ + int any_sdp = 0; + int any_tcp = 0; + use_family_t target_family = USE_BOTH; + struct use_family_rule *rule; + + for ( rule = rules; ( rule != NULL ) && ( target_family == USE_BOTH ); + rule = rule->next ) { + /* skip if not our program */ + if ( !match_program_name( rule ) ) + continue; + + /* + * to declare a dont care we either have a dont care address and port + * or the previous non global rules use the same target family as the + * global rule + */ + if ( rule->match_by_addr || rule->match_by_port ) { + /* not a glocal match rule - just track the target family */ + if ( rule->target_family == USE_SDP ) + any_sdp++; + else if ( rule->target_family == USE_TCP ) + any_tcp++; + } else { + /* a global match so we can declare a match by program */ + if ( ( rule->target_family == USE_SDP ) && ( any_tcp == 0 ) ) + target_family = USE_SDP; + else if ( ( rule->target_family == USE_TCP ) && ( any_sdp == 0 ) ) + target_family = USE_TCP; + } + } + return ( target_family ); +} + +/* return tcp or sdp if the port and role are dont cares */ +use_family_t +__sdp_match_by_program( + ) +{ + use_family_t server_target_family; + use_family_t client_target_family; + use_family_t target_family = USE_BOTH; + + if ( __sdp_config_empty( ) ) { + target_family = USE_SDP; + } else { + /* need to try both server and client rules */ + server_target_family = + match_by_all_rules_program( __sdp_servers_family_rules_head ); + client_target_family = + match_by_all_rules_program( __sdp_clients_family_rules_head ); + + /* only if both agree */ + if ( server_target_family == client_target_family ) + target_family = server_target_family; + } + + __sdp_log( 4, "MATCH PROGRAM: => %s\n", + __sdp_get_family_str( target_family ) ); + + return ( target_family ); +} diff --git a/contrib/ofed/libsdp/src/port.c b/contrib/ofed/libsdp/src/port.c new file mode 100644 index 000000000000..26bcf7cf30e3 --- /dev/null +++ b/contrib/ofed/libsdp/src/port.c @@ -0,0 +1,2629 @@ +/* + This software is available to you under a choice of one of two + licenses. You may choose to be licensed under the terms of the GNU + General Public License (GPL) Version 2, available at + , or the OpenIB.org BSD + license, available in the LICENSE.TXT file accompanying this + software. These details are also available at + . + + 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. + + Copyright (c) 2004 Topspin Communications. All rights reserved. + Copyright (c) 2005-2006 Mellanox Technologies Ltd. All rights reserved. + + $Id$ +*/ + +/* + * system includes + */ +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef SOLARIS_BUILD +/* Our prototypes for ioctl, get*name and accept do not strictly + match the headers - we use the following lines to move the header + versions 'out of the way' temporarily. */ +#define ioctl __real_ioctl +#define getsockname __real_getsockname +#define getpeername __real_getpeername +#define accept __real_accept +#define FASYNC 0 +#include +#endif +#include +#include +#include +#include +#include +#define __USE_GNU +#define _GNU_SOURCE /* define RTLD_NEXT */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __linux__ +#include +#endif + +#ifdef SOLARIS_BUILD +/* We're done protecting ourselves from the header prototypes */ +#undef ioctl +#undef getsockname +#undef getpeername +#undef accept +#endif + +/* + * SDP specific includes + */ +#include "libsdp.h" + +/* We can not use sizeof(sockaddr_in6) as the extra scope_id field is not a must have */ +#define IPV6_ADDR_IN_MIN_LEN 24 + +/* setsockopt() level and optname declarations */ +#define SOL_SDP 1025 +#define SDP_UNBIND 259 /* Unbind socket */ + +/* Solaris has two entry socket creation functions */ +#define SOCKET_SEMANTIC_DEFAULT 0 +#define SOCKET_SEMANTIC_XNET 1 + +/* HACK: filter ioctl errors for FIONREAD */ +#define FIONREAD 0x541B + +void __attribute__ ((constructor)) __sdp_init(void); +void __attribute__ ((destructor)) __sdp_fini(void); + +/* --------------------------------------------------------------------- */ +/* library type definitions. */ +/* --------------------------------------------------------------------- */ + +typedef int (*ioctl_func_t) (int fd, + int request, + void *arg0, + void *arg1, + void *arg2, + void *arg3, + void *arg4, void *arg5, void *arg6, void *arg7); + +typedef int (*fcntl_func_t) (int fd, int cmd, ...); + +typedef int (*socket_func_t) (int domain, int type, int protocol); + +typedef int (*setsockopt_func_t) (int s, + int level, + int optname, + const void *optval, socklen_t optlen); + +typedef int (*connect_func_t) (int sockfd, + const struct sockaddr * serv_addr, + socklen_t addrlen); + +typedef int (*listen_func_t) (int s, int backlog); + +typedef int (*bind_func_t) (int sockfd, + const struct sockaddr * my_addr, socklen_t addrlen); + +typedef int (*close_func_t) (int fd); + +typedef int (*dup_func_t) (int fd); + +typedef int (*dup2_func_t) (int oldfd, int newfd); + +typedef int (*getsockname_func_t) (int fd, + struct sockaddr * name, socklen_t * namelen); + +typedef int (*getpeername_func_t) (int fd, + struct sockaddr * name, socklen_t * namelen); + +typedef int (*accept_func_t) (int fd, + struct sockaddr * addr, socklen_t * addrlen); + +typedef int (*select_func_t) (int n, + fd_set * readfds, + fd_set * writefds, + fd_set * exceptfds, struct timeval * timeout); + +typedef int (*pselect_func_t) (int n, + fd_set * readfds, + fd_set * writefds, + fd_set * exceptfds, + const struct timespec * timeout, + const sigset_t * sigmask); + +typedef int (*poll_func_t) (struct pollfd * ufds, + unsigned long int nfds, int timeout); + +#ifdef __linux__ +typedef int (*epoll_create_func_t) (int size); + +typedef int (*epoll_ctl_func_t) (int epfd, + int op, int fd, struct epoll_event * event); + +typedef int (*epoll_wait_func_t) (int epfd, + struct epoll_event * events, + int maxevents, int timeout); + +typedef int (*epoll_pwait_func_t) (int epfd, + struct epoll_event * events, + int maxevents, + int timeout, const sigset_t * sigmask); +#endif + + +struct socket_lib_funcs { + ioctl_func_t ioctl; + fcntl_func_t fcntl; + socket_func_t socket; + setsockopt_func_t setsockopt; + connect_func_t connect; + listen_func_t listen; + bind_func_t bind; + close_func_t close; + dup_func_t dup; + dup2_func_t dup2; + getpeername_func_t getpeername; + getsockname_func_t getsockname; + accept_func_t accept; + select_func_t select; + pselect_func_t pselect; + poll_func_t poll; +#ifdef __linux__ + epoll_create_func_t epoll_create; + epoll_ctl_func_t epoll_ctl; + epoll_wait_func_t epoll_wait; + epoll_pwait_func_t epoll_pwait; +#endif +}; /* socket_lib_funcs */ + +#ifdef SOLARIS_BUILD +/* Solaris has another interface to socket functions prefixed with __xnet_ */ +struct socket_lib_xnet_funcs { + socket_func_t socket; + connect_func_t connect; + listen_func_t listen; + bind_func_t bind; +}; +#endif + +static int simple_sdp_library; +static int max_file_descriptors; +static int dev_null_fd; +volatile static int init_status = 0; /* 0: idle, 1:during, 2:ready */ + +/* --------------------------------------------------------------------- */ +/* library static and global variables */ +/* --------------------------------------------------------------------- */ + +/* glibc provides these symbols - for Solaris builds we fake them + * until _init is called, at which point we quiz libdl.. */ +#ifdef SOLARIS_BUILD +char *program_invocation_name = "[progname]", *program_invocation_short_name = + "[short_progname]"; +#else +extern char *program_invocation_name, *program_invocation_short_name; +#endif + +#ifdef RTLD_NEXT +static void *__libc_dl_handle = RTLD_NEXT; +#else +static void *__libc_dl_handle; +#endif + +/* extra fd attributes we need for our algorithms */ +struct sdp_extra_fd_attributes { + int shadow_fd; /* file descriptor of shadow sdp socket */ + short last_accept_was_tcp; /* used by accept to alternate tcp and sdp */ + short is_sdp; /* 1 if the fd represents an sdp socket */ +}; /* sdp_extra_fd_attributes */ + +/* stores the extra attributes struct by fd */ +static struct sdp_extra_fd_attributes *libsdp_fd_attributes; + +static struct socket_lib_funcs _socket_funcs = { + .socket = NULL, + /* Automatically sets all other elements to NULL */ +}; /* _socket_funcs */ + +#ifdef SOLARIS_BUILD +static struct socket_lib_xnet_funcs _socket_xnet_funcs = { + .socket = NULL, + /* Automatically sets all other elements to NULL */ +}; +#endif + +/* --------------------------------------------------------------------- */ +/* Prototypes */ +/* --------------------------------------------------------------------- */ +void __sdp_init(void); + +/* --------------------------------------------------------------------- */ +/* */ +/* local static functions. */ +/* */ +/* --------------------------------------------------------------------- */ + +/* ========================================================================= */ +/*..init_extra_attribute -- initialize the set of extra attributes for a fd */ +static void init_extra_attribute(int fd) +{ + if ((0 <= fd) && (max_file_descriptors > fd)) { + libsdp_fd_attributes[fd].shadow_fd = -1; + libsdp_fd_attributes[fd].is_sdp = 0; + libsdp_fd_attributes[fd].last_accept_was_tcp = -1; + } +} + +static inline int is_valid_fd(int fd) +{ + return (0 <= fd) && (fd < max_file_descriptors); +} + +/* ========================================================================= */ +/*..get_shadow_fd_by_fd -- given an fd return its shadow fd if exists */ +static inline int get_shadow_fd_by_fd(int fd) +{ + if (is_valid_fd(fd)) + return libsdp_fd_attributes[fd].shadow_fd; + else + return -1; +} + +/* ========================================================================= */ +/*..set_shadow_for_fd -- */ +static inline void set_shadow_for_fd(int fd, int shadow_fd) +{ + if (is_valid_fd(fd)) + libsdp_fd_attributes[fd].shadow_fd = shadow_fd; +} + +/* ========================================================================= */ +/*..set_is_sdp_socket -- */ +static inline void set_is_sdp_socket(int fd, short is_sdp) +{ + if (is_valid_fd(fd)) + libsdp_fd_attributes[fd].is_sdp = is_sdp; +} + +/* ========================================================================= */ +/*..get_is_sdp_socket -- given an fd return 1 if it is an SDP socket */ +static inline int get_is_sdp_socket(int fd) +{ + if (is_valid_fd(fd)) + return libsdp_fd_attributes[fd].is_sdp; + else + return 0; +} + +/* ========================================================================= */ +/*..last_accept_was_tcp -- given an fd return 1 if last accept was tcp */ +static inline int last_accept_was_tcp(int fd) +{ + if (is_valid_fd(fd)) + return libsdp_fd_attributes[fd].last_accept_was_tcp; + else + return 0; +} + +/* ========================================================================= */ +/*..set_last_accept -- given an fd set last accept was tcp */ +static inline void set_last_accept(int fd, int was_tcp) +{ + if (is_valid_fd(fd)) + libsdp_fd_attributes[fd].last_accept_was_tcp = was_tcp; +} + +/* ========================================================================= */ +/*..cleanup_shadow -- an error occured on an SDP socket, cleanup */ +static int cleanup_shadow(int fd) +{ + int shadow_fd = get_shadow_fd_by_fd(fd); + + if (shadow_fd == -1) + return 0; + libsdp_fd_attributes[fd].shadow_fd = -1; + libsdp_fd_attributes[fd].last_accept_was_tcp = 0; + return (_socket_funcs.close(shadow_fd)); +} /* cleanup_shadow */ + +/* ========================================================================= */ +/*..replace_fd_with_its_shadow -- perform all required for such promotion */ +static int replace_fd_with_its_shadow(int fd) +{ + int shadow_fd = libsdp_fd_attributes[fd].shadow_fd; + + if (shadow_fd == -1) { + __sdp_log(9, "Error replace_fd_with_its_shadow: no shadow for fd:%d\n", + fd); + return EINVAL; + } + + /* copy the attributes of the shadow before we clean them up */ + libsdp_fd_attributes[fd] = libsdp_fd_attributes[shadow_fd]; + libsdp_fd_attributes[fd].shadow_fd = -1; + if (_socket_funcs.dup2(shadow_fd, fd) < 0) { + init_extra_attribute(fd); + _socket_funcs.close(shadow_fd); + return EINVAL; + } + _socket_funcs.close(shadow_fd); + return 0; +} + +static sa_family_t get_sdp_domain(int domain) +{ + if (AF_INET_SDP == domain || AF_INET6_SDP == domain) + return domain; + + if (AF_INET == domain) + return AF_INET_SDP; + else if (AF_INET6 == domain) + return AF_INET6_SDP; + + __sdp_log(9, "Error %s: unknown TCP domain: %d\n", __func__, domain); + + return -1; +} + +static int get_sock_domain(int sd) +{ + struct sockaddr_storage tmp_sin; + socklen_t tmp_sinlen = sizeof(tmp_sin); + + if (_socket_funcs.getsockname(sd, (struct sockaddr *) &tmp_sin, &tmp_sinlen) < 0) { + __sdp_log(9, "Error %s: getsockname return <%d> for socket\n", __func__, errno); + return -1; + } + + return ((struct sockaddr *)&tmp_sin)->sa_family; +} + +/* ========================================================================= */ +/*..is_filtered_unsuported_sockopt -- return 1 if to filter sockopt failure */ +static inline int is_filtered_unsuported_sockopt(int level, int optname) +{ + /* + * TODO: until we know exactly which unsupported opts are really + * a don't care we always pass the error + */ + return 0; +#if 0 + /* these are the SOL_TCP OPTS we should consider filterring */ + TCP_NODELAY 1 /* Don't delay send to coalesce packets */ + TCP_MAXSEG 2 /* Set maximum segment size */ + TCP_CORK 3 /* Control sending of partial frames */ + TCP_KEEPIDLE 4 /* Start keeplives after this period */ + TCP_KEEPINTVL 5 /* Interval between keepalives */ + TCP_KEEPCNT 6 /* Number of keepalives before death */ + TCP_SYNCNT 7 /* Number of SYN retransmits */ + TCP_LINGER2 8 /* Life time of orphaned FIN-WAIT-2 state */ + TCP_DEFER_ACCEPT 9 /* Wake up listener only when data arrive */ + TCP_WINDOW_CLAMP 10 /* Bound advertised window */ + TCP_INFO 11 /* Information about this connection. */ + TCP_QUICKACK 12 /* Bock/reenable quick ACKs. */ +#endif +} + +/* ========================================================================= */ +/*..is_invalid_addr -- return 1 if given pointer is not valid */ +/* NOTE: invalidation of the size is going to happen during actual call */ +static inline int is_invalid_addr(const void *p) +{ + /* HACK: on some systems we can not write to check for pointer validity */ + size_t ret = fcntl(dev_null_fd, F_GETLK, p); + + ret = (errno == EFAULT); + errno = 0; + return ret; +} + +/* ========================================================================= */ +/*..get_addr_str -- fill in the given buffer with addr str or return 1 */ +static int get_addr_str(const struct sockaddr *addr, char *buf, size_t len) +{ + const struct sockaddr_in *sin = (struct sockaddr_in *) addr; + const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; + char const *conv_res; + + if (sin->sin_family == AF_INET) { + conv_res = inet_ntop(AF_INET, (void *) &(sin->sin_addr), buf, len); + } else if (sin6->sin6_family == AF_INET6) { + conv_res = inet_ntop(AF_INET6, (void *) &sin6->sin6_addr, buf, len); + } else { + strncpy(buf, "unknown address family", len); + conv_res = (char *) 1; + } + return conv_res == NULL; +} + +/* --------------------------------------------------------------------- */ +/* */ +/* Socket library function overrides. */ +/* */ +/* --------------------------------------------------------------------- */ + +/* ========================================================================= */ +/*..ioctl -- replacement ioctl call. */ +int +ioctl(int fd, + int request, + void *arg0, + void *arg1, + void *arg2, void *arg3, void *arg4, void *arg5, void *arg6, void *arg7) +{ + int shadow_fd; + int sret = 0; + int ret = 0; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.ioctl) { + __sdp_log(9, "Error ioctl: no implementation for ioctl found\n"); + return -1; + } + + shadow_fd = get_shadow_fd_by_fd(fd); + + __sdp_log(2, "IOCTL: <%s:%d:%d> request <%d>\n", + program_invocation_short_name, fd, shadow_fd, request); + + ret = _socket_funcs.ioctl(fd, request, + arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + + /* HACK: avoid failing on FIONREAD error as SDP does not support it at the moment */ + if ((ret < 0) && get_is_sdp_socket(fd) && (request == FIONREAD)) { + __sdp_log(8, "Warning ioctl: " + "Ignoring FIONREAD error for SDP socket.\n"); + ret = 0; + } + + /* if shadow and no error on tcp */ + if ((ret >= 0) && (-1 != shadow_fd)) { + sret = _socket_funcs.ioctl(shadow_fd, request, + arg0, arg1, arg2, arg3, arg4, arg5, arg6, + arg7); + /* HACK: avoid failing on FIONREAD error as SDP does not support it at the moment */ + if ((sret < 0) && (request == FIONREAD)) { + __sdp_log(8, "Warning ioctl: " + "Ignoring FIONREAD error for shadow SDP socket.\n"); + sret = 0; + } + + if (sret < 0) { + __sdp_log(9, "Error ioctl: " + "<%d> calling ioctl for SDP socket, closing it.\n", + errno); + cleanup_shadow(fd); + } + } + + __sdp_log(2, "IOCTL: <%s:%d:%d> result <%d:%d>\n", + program_invocation_short_name, fd, shadow_fd, ret, sret); + + return ret; +} /* ioctl */ + +/* ========================================================================= */ +/*..fcntl -- replacement fcntl call. */ +int fcntl(int fd, int cmd, ...) +{ + int shadow_fd; + int sret = 0; + int ret = 0; + + void *arg; + va_list ap; + + va_start(ap, cmd); + arg = va_arg(ap, void *); + va_end(ap); + + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.fcntl) { + __sdp_log(9, "Error fcntl: no implementation for fcntl found\n"); + return -1; + } + + shadow_fd = get_shadow_fd_by_fd(fd); + + __sdp_log(2, "FCNTL: <%s:%d:%d> command <%d> argument <%p>\n", + program_invocation_short_name, fd, shadow_fd, cmd, arg); + + ret = _socket_funcs.fcntl(fd, cmd, arg); + if ((ret >= 0) && (-1 != shadow_fd)) { + sret = _socket_funcs.fcntl(shadow_fd, cmd, arg); + if (sret < 0) { + __sdp_log(9, "Error fcntl:" + " <%d> calling fcntl(%d, %d, %p) for SDP socket. Closing it.\n", + shadow_fd, cmd, arg, errno); + cleanup_shadow(fd); + } + } + + __sdp_log(2, "FCNTL: <%s:%d:%d> result <%d:%d>\n", + program_invocation_short_name, fd, shadow_fd, ret, sret); + + return ret; +} /* fcntl */ + +/* ========================================================================= */ +/*..setsockopt -- replacement setsockopt call. */ +int +setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) +{ + int shadow_fd; + int sret = 0; + int ret = 0; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.setsockopt) { + __sdp_log(9, "Error setsockopt:" + " no implementation for setsockopt found\n"); + return -1; + } + + shadow_fd = get_shadow_fd_by_fd(fd); + + __sdp_log(2, "SETSOCKOPT: <%s:%d:%d> level <%d> name <%d>\n", + program_invocation_short_name, fd, shadow_fd, level, optname); + + if (level == SOL_SOCKET && optname == SO_KEEPALIVE && get_is_sdp_socket(fd)) { + level = AF_INET_SDP; + __sdp_log(2, "SETSOCKOPT: <%s:%d:%d> substitute level %d\n", + program_invocation_short_name, fd, shadow_fd, level); + } + + ret = _socket_funcs.setsockopt(fd, level, optname, optval, optlen); + if ((ret >= 0) && (shadow_fd != -1)) { + if (level == SOL_SOCKET && optname == SO_KEEPALIVE && + get_is_sdp_socket(shadow_fd)) { + level = AF_INET_SDP; + __sdp_log(2, "SETSOCKOPT: <%s:%d:%d> substitute level %d\n", + program_invocation_short_name, fd, shadow_fd, level); + } + + sret = _socket_funcs.setsockopt(shadow_fd, level, optname, optval, optlen); + if (sret < 0) { + __sdp_log(8, "Warning sockopts:" + " ignoring error on shadow SDP socket fd:<%d>\n", fd); + /* + * HACK: we should allow some errors as some sock opts are unsupported + * __sdp_log(9, "Error %d calling setsockopt for SDP socket, closing\n", errno); + * cleanup_shadow(fd); + */ + } + } + + /* Due to SDP limited implmentation of sockopts we ignore some errors */ + if ((ret < 0) && get_is_sdp_socket(fd) && + is_filtered_unsuported_sockopt(level, optname)) { + __sdp_log(8, "Warning sockopts: " + "ignoring error on non implemented sockopt on SDP socket" + " fd:<%d> level:<%d> opt:<%d>\n", fd, level, optval); + ret = 0; + } + + __sdp_log(2, "SETSOCKOPT: <%s:%d:%d> result <%d:%d>\n", + program_invocation_short_name, fd, shadow_fd, ret, sret); + + return ret; +} /* setsockopt */ + +/* ========================================================================= */ +/*..socket -- replacement socket call. */ + +static inline int __create_socket_semantic(int domain, + int type, + int protocol, int semantics) +{ + return +#ifdef SOLARIS_BUILD + (semantics == SOCKET_SEMANTIC_XNET) ? + _socket_xnet_funcs.socket(domain, type, protocol) : +#endif + _socket_funcs.socket(domain, type, protocol); +} + +/* Contains the main logic for creating shadow SDP sockets */ +static int __create_socket(int domain, int type, int protocol, int semantics) +{ + int s = -1; + int shadow_fd = -1; + use_family_t family_by_prog; + int sdp_domain; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.socket) { + __sdp_log(9, "Error socket: no implementation for socket found\n"); + return -1; + } + + __sdp_log(2, "SOCKET: <%s> domain <%d> type <%d> protocol <%d>\n", + program_invocation_short_name, domain, type, protocol); + + sdp_domain = get_sdp_domain(domain); + if (sdp_domain < 0) { + errno = EAFNOSUPPORT; + s = -1; + goto done; + } + + /* check to see if we can skip the shadow */ + if ((AF_INET == domain || AF_INET6 == domain) && (SOCK_STREAM == type)) + if (simple_sdp_library) + family_by_prog = USE_SDP; + else + family_by_prog = __sdp_match_by_program(); + else if (AF_INET_SDP == domain || AF_INET6_SDP == domain) + family_by_prog = USE_SDP; + else + family_by_prog = USE_TCP; + + if (family_by_prog == USE_TCP) { + __sdp_log(1, "SOCKET: making TCP only socket (no shadow)\n"); + s = __create_socket_semantic(domain, type, protocol, semantics); + init_extra_attribute(s); + set_is_sdp_socket(s, 0); + goto done; + } + + if (family_by_prog == USE_SDP) { + /* HACK: convert the protocol if IPPROTO_IP */ + if (protocol == 0) + protocol = IPPROTO_TCP; + + __sdp_log(1, "SOCKET: making SDP socket type:%d proto:%d\n", + type, protocol); + s = __create_socket_semantic(sdp_domain, type, protocol, semantics); + init_extra_attribute(s); + set_is_sdp_socket(s, 1); + goto done; + } + + /* HACK: if we fail creating the TCP socket should we abort ? */ + __sdp_log(1, "SOCKET: making TCP socket\n"); + s = __create_socket_semantic(domain, type, protocol, semantics); + init_extra_attribute(s); + set_is_sdp_socket(s, 0); + if (is_valid_fd(s)) { + if (((AF_INET == domain) || (AF_INET6 == domain)) && + (SOCK_STREAM == type)) { + + if (protocol == 0) + protocol = IPPROTO_TCP; + __sdp_log(1, "SOCKET: making SDP shadow socket type:%d proto:%d\n", + type, protocol); + shadow_fd = + __create_socket_semantic(sdp_domain, type, protocol, + semantics); + if (is_valid_fd(shadow_fd)) { + init_extra_attribute(shadow_fd); + if (libsdp_fd_attributes[s].shadow_fd != -1) { + __sdp_log(8, "Warning socket: " + "overriding existing shadow fd:%d for fd:%d\n", + libsdp_fd_attributes[s].shadow_fd, s); + } + set_is_sdp_socket(shadow_fd, 1); + set_shadow_for_fd(s, shadow_fd); + } else { + __sdp_log(9, + "Error socket: <%d> calling socket for SDP socket\n", + errno); + /* fail if we did not make the SDP socket */ + __sdp_log(1, "SOCKET: closing TCP socket:<%d>\n", s); + _socket_funcs.close(s); + s = -1; + } + } + } else { + __sdp_log(9, "Error socket: " + "ignoring SDP socket since TCP fd:%d out of range\n", s); + } + +done: + __sdp_log(2, "SOCKET: <%s:%d:%d>\n", + program_invocation_short_name, s, shadow_fd); + + return s; +} /* socket */ + +int socket(int domain, int type, int protocol) +{ + return __create_socket(domain, type, protocol, SOCKET_SEMANTIC_DEFAULT); +} + +#ifdef SOLARIS_BUILD +int __xnet_socket(int domain, int type, int protocol) +{ + return __create_socket(domain, type, protocol, SOCKET_SEMANTIC_XNET); +} +#endif + +/* ========================================================================= */ +/*..get_fd_addr_port_num - obtain the port the fd is attached to */ +static int get_fd_addr_port_num(int sd) +{ + struct sockaddr_storage addr; + int ret; + const struct sockaddr_in *sin; + socklen_t addrlen = sizeof(addr); + + ret = _socket_funcs.getsockname(sd, (struct sockaddr *) &addr, &addrlen); + + if (ret) { + __sdp_log(9, "Error: in get_fd_addr_port_num - Failed to get getsockname\n"); + return -1; + } + + /* port num is in same location for IPv4 and IPv6 */ + sin = (const struct sockaddr_in *) &addr; + return ntohs(sin->sin_port); +} + +/* ========================================================================= */ +/*..set_addr_port_num - sets the port in the given address */ +static int set_addr_port_num(const struct sockaddr *addr, int port) +{ + struct sockaddr_in *sin = (struct sockaddr_in *) addr; + + /* port num is in same location for IPv4 and IPv6 */ + sin->sin_port = htons(port); + return 0; +} + +/* ========================================================================= */ +/* perform a bind with the given socket semantics */ +static inline int +__bind_semantics(int fd, + const struct sockaddr *my_addr, + socklen_t addrlen, int semantics) +{ + return +#ifdef SOLARIS_BUILD + (semantics == SOCKET_SEMANTIC_XNET) ? + _socket_xnet_funcs.bind(fd, my_addr, addrlen) : +#endif + _socket_funcs.bind(fd, my_addr, addrlen); +} + +/* ========================================================================= */ +/*..find_free_port - find same free port on both TCP and SDP */ +#define MAX_BIND_ANY_PORT_TRIES 20000 +static int +find_free_port(const struct sockaddr *sin_addr, + const socklen_t addrlen, + int orig_sd, + int *sdp_sd, int *tcp_sd, int semantics) +{ + static int tcp_turn = 1; + int tmp_turn = tcp_turn; + int num_of_loops = 0; + int port = -1; + int tmp_sd[2]; + unsigned int yes = 1; + int ret; + int domain, sdp_domain; + + __sdp_log(2, "find_free_port: starting search for common free port\n"); + + /* need to obtain the address family from the fd */ + domain = get_sock_domain(orig_sd); + if (domain == -1) { + errno = EFAULT; + goto done; + } + + sdp_domain = get_sdp_domain(domain); + if (sdp_domain < 0) { + errno = EFAULT; + goto done; + } + + do { + __sdp_log(1, "find_free_port: taking loop (%d)\n", ++num_of_loops); + + __sdp_log(1, "find_free_port: creating the two sockets\n"); + tmp_sd[0] = _socket_funcs.socket(sdp_domain, SOCK_STREAM, IPPROTO_TCP); + if (tmp_sd[0] < 0) { + __sdp_log(8, "Warning find_free_port: creating first socket failed\n"); + goto done; + } + + _socket_funcs.setsockopt(tmp_sd[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + + tmp_sd[1] = _socket_funcs.socket(domain, SOCK_STREAM, IPPROTO_TCP); + if (tmp_sd[1] < 0) { + __sdp_log(8, "Warning find_free_port: creating second socket failed\n"); + _socket_funcs.close(tmp_sd[0]); + goto done; + } + + _socket_funcs.setsockopt(tmp_sd[1], SOL_SOCKET, SO_REUSEADDR, &yes, + sizeof(yes)); + + __sdp_log(1, "find_free_port: binding first %s socket\n", + tmp_turn ? "tcp" : "sdp"); + ret = __bind_semantics(tmp_sd[tmp_turn], sin_addr, addrlen, semantics); + if (ret < 0) { + __sdp_log(8, + "Warning find_free_port: binding first socket failed:%s\n", + strerror(errno)); + _socket_funcs.close(tmp_sd[0]); + _socket_funcs.close(tmp_sd[1]); + goto done; + } + + __sdp_log(1, "find_free_port: listening on first socket\n"); + ret = _socket_funcs.listen(tmp_sd[tmp_turn], 5); + if (ret < 0) { + __sdp_log(8, "Warning find_free_port: listening on first socket failed:%s\n", + strerror(errno)); + _socket_funcs.close(tmp_sd[0]); + _socket_funcs.close(tmp_sd[1]); + goto done; + } + + port = get_fd_addr_port_num(tmp_sd[tmp_turn]); + if (port < 0) { + __sdp_log(8, "Warning find_free_port: first socket port:%d < 0\n", + port); + _socket_funcs.close(tmp_sd[0]); + _socket_funcs.close(tmp_sd[1]); + goto done; + } + __sdp_log(1, "find_free_port: first socket port:%u\n", port); + + set_addr_port_num(sin_addr, port); + + __sdp_log(1, "find_free_port: binding second socket\n"); + ret = __bind_semantics(tmp_sd[1 - tmp_turn], sin_addr, addrlen, semantics); + if (ret < 0) { + /* bind() for sdp socket failed. It is acceptable only + * if the IP is not part of IB network. */ + + if (errno != EADDRINUSE) { + __sdp_log(8, "Warning find_free_port: " + "binding second socket failed with %s\n", + strerror(errno)); + goto close_and_mark; + } else { + int err; +#ifdef __linux__ + socklen_t len = sizeof(int); + + ret = getsockopt(tmp_sd[1 - tmp_turn], SOL_TCP, + SDP_LAST_BIND_ERR, &err, &len); + if (-1 == ret) { + __sdp_log(9, "Error %s:getsockopt: %s\n", + __func__, strerror(errno)); + goto close_and_mark; + } +#else + err = -errno; +#endif + if (-ENOENT == err || -EADDRINUSE != err) { + /* bind() failed due to either: + * 1. IP is ETH, not IB, so can't bind() to sdp socket. + * 2. real error. + * Continue only with TCP */ + goto close_and_mark; + } + __sdp_log(1, "find_free_port: %s port %u was busy\n", + 1 - tmp_turn ? "tcp" : "sdp", + ntohs(((const struct sockaddr_in *)sin_addr)->sin_port)); + } + + /* close the sockets - we will need new ones ... */ + __sdp_log(1, + "find_free_port: closing the two sockets before next loop\n"); + _socket_funcs.close(tmp_sd[0]); + _socket_funcs.close(tmp_sd[1]); + + port = -1; + /* we always start with tcp so we keep the original setting for now */ + /* tmp_turn = 1 - tmp_turn; */ + } + + } while ((port < 0) && (num_of_loops < MAX_BIND_ANY_PORT_TRIES)); + +setfds: + tcp_turn = tmp_turn; + *sdp_sd = tmp_sd[0]; + *tcp_sd = tmp_sd[1]; + +done: + __sdp_log(2, "find_free_port: return port:<%d>\n", port); + return port; + +close_and_mark: + _socket_funcs.close(tmp_sd[0]); + tmp_sd[0] = -1; /* mark with error */ + goto setfds; + +} + +/* ========================================================================= */ +/*..check_legal_bind - check if given address is okay for both TCP and SDP */ +static int +check_legal_bind(const struct sockaddr *sin_addr, + const socklen_t addrlen, + int orig_sd, + int *sdp_sd, int *tcp_sd, int semantics) +{ + unsigned int yes = 1; + int ret = -1; + int sret = -1; + int domain, sdp_domain; + + /* need to obtain the address family from the fd */ + domain = get_sock_domain(orig_sd); + if (domain == -1) { + errno = EFAULT; + ret = -1; + goto done; + } + + sdp_domain = get_sdp_domain(domain); + if (sdp_domain < 0) { + errno = EFAULT; + goto done; + } + + __sdp_log(2, "check_legal_bind: binding two temporary sockets\n"); + *sdp_sd = _socket_funcs.socket(sdp_domain, SOCK_STREAM, IPPROTO_TCP); + if (*sdp_sd < 0) { + __sdp_log(9, "Error check_legal_bind: " "creating SDP socket failed\n"); + goto done; + } + + __sdp_log(2, "check_legal_bind: reusing <%d> \n", *sdp_sd); + sret = + _socket_funcs.setsockopt(*sdp_sd, SOL_SOCKET, SO_REUSEADDR, &yes, + sizeof(yes)); + if (sret < 0) { + __sdp_log(9, "Error bind: Could not setsockopt sdp_sd\n"); + } + + *tcp_sd = _socket_funcs.socket(domain, SOCK_STREAM, IPPROTO_TCP); + if (*tcp_sd < 0) { + __sdp_log(9, "Error check_legal_bind: " + "creating second socket failed:%s\n", strerror(errno)); + _socket_funcs.close(*sdp_sd); + goto done; + } + + __sdp_log(2, "check_legal_bind: reusing <%d> \n", *tcp_sd); + sret = + _socket_funcs.setsockopt(*tcp_sd, SOL_SOCKET, SO_REUSEADDR, &yes, + sizeof(yes)); + if (sret < 0) { + __sdp_log(9, "Error bind: Could not setsockopt tcp_sd\n"); + } + + __sdp_log(1, "check_legal_bind: binding SDP socket\n"); + ret = __bind_semantics(*sdp_sd, sin_addr, addrlen, semantics); + if (ret < 0) { + /* bind() for sdp socket failed. It is acceptable only if + * the IP is not part of IB network. */ + int err; + socklen_t len = sizeof(int); + + if (EADDRINUSE != errno) + goto done; +#ifdef __linux__ + if (-1 == getsockopt(*sdp_sd, SOL_TCP, SDP_LAST_BIND_ERR, &err, &len)) { + __sdp_log(9, "Error check_legal_bind:getsockopt: %s\n", + strerror(errno)); + goto done; + } +#else + err = -errno; +#endif + if (-ENOENT != err) { + /* bind() failed due to real error. Can't continue */ + __sdp_log(9, "Error check_legal_bind: " + "binding SDP socket failed:%s\n", strerror(errno)); + _socket_funcs.close(*sdp_sd); + _socket_funcs.close(*tcp_sd); + + /* TCP and SDP without library return EINVAL */ + if (errno == EADDRINUSE) + errno = EINVAL; + + goto done; + } + /* IP is ETH, not IB, so can't bind() to sdp socket */ + /* Continue only with TCP */ + _socket_funcs.close(*sdp_sd); + *sdp_sd = -1; + } + + __sdp_log(1, "check_legal_bind: binding TCP socket\n"); + ret = __bind_semantics(*tcp_sd, sin_addr, addrlen, semantics); + if (ret < 0) { + __sdp_log(9, "Error check_legal_bind: " + "binding TCP socket failed:%s\n", strerror(errno)); + if (-1 != *sdp_sd) + _socket_funcs.close(*sdp_sd); + _socket_funcs.close(*tcp_sd); + goto done; + } + ret = 0; + __sdp_log(2, "check_legal_bind: result:<%d>\n", ret); +done: + return ret; +} + +/* ========================================================================= */ +/*..close_and_bind - close an open fd and bind another one immediately */ +static int +close_and_bind(int old_sd, + int new_sd, + const struct sockaddr *addr, socklen_t addrlen, int semantics) +{ + int ret; + + __sdp_log(2, "close_and_bind: closing <%d> binding <%d>\n", old_sd, new_sd); + ret = _socket_funcs.close(old_sd); + if (ret < 0) { + __sdp_log(9, "Error bind: Could not close old_sd\n"); + goto done; + } + + ret = __bind_semantics(new_sd, addr, addrlen, semantics); + if (ret < 0) + __sdp_log(9, "Error bind: Could not bind new_sd\n"); + +done: + __sdp_log(2, "close_and_bind: returning <%d>\n", ret); + return ret; +} + +/* ========================================================================= */ +/*..bind -- replacement bind call. */ +/* + As we do not know the role of this socket yet so we cannot choose AF. + We need to be able to handle shadow too. + SDP sockets (may be shadow or not) must be using converted address + + Since there is no way to "rebind" a socket we have to avoid "false" bind: + 1. When the given address for the bind includes a port we need to + guarantee the port is free on both address families. We do that + by creating temporary sockets and biding them first. Then we close and + re-use the address on the real sockets. + 2. When ANY_PORT is requested we need to make sure the port we obtain from + the first address family is also free on the second one. We use temporary + sockets for that task too. We loop several times to find such common + available socket +*/ +static int +__perform_bind(int fd, + const struct sockaddr *addr, socklen_t addrlen, int semantics) +{ + int shadow_fd; + struct sockaddr_in *sin_addr = (struct sockaddr_in *) addr; + int ret, sret = -1; + char buf[MAX_ADDR_STR_LEN]; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.bind) { + __sdp_log(9, "Error bind: no implementation for bind found\n"); + return -1; + } + + shadow_fd = get_shadow_fd_by_fd(fd); + + if ((addr == NULL) || is_invalid_addr(addr)) { + errno = EFAULT; + __sdp_log(9, "Error bind: illegal address provided\n"); + return -1; + } + + if (get_addr_str(addr, buf, MAX_ADDR_STR_LEN)) { + __sdp_log(9, "Error bind: provided illegal address: %s\n", + strerror(errno)); + return -1; + } + + __sdp_log(2, "BIND: <%s:%d:%d> type <%d> IP <%s> port <%d>\n", + program_invocation_short_name, fd, shadow_fd, + sin_addr->sin_family, buf, ntohs(sin_addr->sin_port)); + + if (get_is_sdp_socket(fd)) { + __sdp_log(1, "BIND: binding SDP socket:<%d>\n", fd); + ret = __bind_semantics(fd, addr, addrlen, semantics); + goto done; + } else if (shadow_fd != -1) { + /* has shadow */ + /* we need to validate the given address or find a common port + * so we use the following tmp address and sockets */ + struct sockaddr_storage tmp_addr; + int sdp_sd = -1, tcp_sd = -1, port; + + memcpy(&tmp_addr, addr, addrlen); + ret = 0; + if (ntohs(sin_addr->sin_port) == 0) { + /* When we get ANY_PORT we need to make sure that both TCP + * and SDP sockets will use the same port */ + + port = find_free_port(addr, addrlen, fd, &sdp_sd, &tcp_sd, semantics); + if (port < 0) { + ret = -1; + __sdp_log(9, "BIND: Failed to find common free port\n"); + /* We cannot bind both tcp and sdp on the same port, we will close + * the sdp and continue with tcp only */ + goto done; + } else { + /* copy the port to the tmp address */ + set_addr_port_num((struct sockaddr *) &tmp_addr, port); + } + } else { + /* have a shadow but requested specific port - check that we + * can actually bind the two addresses and then reuse */ + ret = check_legal_bind(addr, addrlen, fd, &sdp_sd, &tcp_sd, semantics); + if (ret < 0) { + __sdp_log(9, "Error bind: " + "Provided address can not bind on the two sockets\n"); + } + } + + /* if we fail to find a common port or given address can not be used + * we return error */ + if (ret < 0) { + /* Temporary sockets already closed by check_legal_bind or + * find_free_port */ + errno = EADDRINUSE; + goto done; + } + + /* close temporary sockets and reuse their address */ + /* HACK: close_and_bind might race with other applications. */ + /* When the race occur we return EADDRINUSE */ + ret = close_and_bind(tcp_sd, fd, (struct sockaddr *) &tmp_addr, + addrlen, semantics); + if (ret < 0) { + __sdp_log(9, "Error bind: " "Could not close_and_bind TCP side\n"); + if (-1 != sdp_sd) + _socket_funcs.close(sdp_sd); + goto done; + } + + if (-1 != sdp_sd) { + ret = close_and_bind(sdp_sd, shadow_fd, (struct sockaddr *) &tmp_addr, + addrlen, semantics); + + if (ret < 0) { + __sdp_log(9, + "Error bind: " "Could not close_and_bind sdp side\n"); + goto done; + } + } + goto done; + } + + /* we can only get here on single TCP socket */ + __sdp_log(1, "BIND: binding TCP socket:<%d>\n", fd); + ret = __bind_semantics(fd, addr, addrlen, semantics); + +done: + __sdp_log(2, "BIND: <%s:%d:%d> result <%d:%d>\n", + program_invocation_short_name, fd, shadow_fd, ret, sret); + + return ret; +} /* bind */ + + +int bind(int fd, const struct sockaddr *my_addr, socklen_t addrlen) +{ + return __perform_bind(fd, my_addr, addrlen, SOCKET_SEMANTIC_DEFAULT); +} + +#ifdef SOLARIS_BUILD +int __xnet_bind(int fd, const struct sockaddr *my_addr, socklen_t addrlen) +{ + return __perform_bind(fd, my_addr, addrlen, SOCKET_SEMANTIC_XNET); +} +#endif + + +/* ========================================================================= */ +/*..connect -- replacement connect call. */ +/* + Given the connect address we can take out AF decision + if target AF == both it means SDP and fall back to TCP + if any connect worked we are fine +*/ +static inline int +__connect_semantics(int fd, + const struct sockaddr *serv_addr, + socklen_t addrlen, int semantics) +{ + return +#ifdef SOLARIS_BUILD + (semantics == SOCKET_SEMANTIC_XNET) ? + _socket_xnet_funcs.connect(fd, serv_addr, addrlen) : +#endif + _socket_funcs.connect(fd, serv_addr, addrlen); +} + +static int +__perform_connect(int fd, const struct sockaddr *serv_addr, + socklen_t addrlen, int semantics) +{ + struct sockaddr_in *serv_sin = (struct sockaddr_in *) serv_addr; + char buf[MAX_ADDR_STR_LEN]; + int shadow_fd; + int ret = -1, dup_ret; + use_family_t target_family; + int fopts; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.connect) { + __sdp_log(9, "Error connect: no implementation for connect found\n"); + return -1; + } + + shadow_fd = get_shadow_fd_by_fd(fd); + + if ((serv_addr == NULL) || is_invalid_addr(serv_addr)) { + errno = EFAULT; + __sdp_log(9, "Error connect: illegal address provided\n"); + return -1; + } + + if (get_addr_str(serv_addr, buf, MAX_ADDR_STR_LEN)) { + __sdp_log(9, "Error connect: provided illegal address: %s\n", + strerror(errno)); + return EADDRNOTAVAIL; + } + + __sdp_log(2, "CONNECT: <%s:%d:%d> domain <%d> IP <%s> port <%d>\n", + program_invocation_short_name, fd, shadow_fd, + serv_sin->sin_family, buf, ntohs(serv_sin->sin_port)); + + + /* obtain the target address family */ + target_family = __sdp_match_connect(serv_addr, addrlen); + + /* if we do not have a shadow - just do the work */ + if (shadow_fd == -1) { + __sdp_log(1, "CONNECT: connectingthrough %s\n", + get_is_sdp_socket(fd) ? "SDP" : "TCP"); + ret = __connect_semantics(fd, serv_addr, addrlen, semantics); + if ((ret == 0) || (errno == EINPROGRESS)) { + __sdp_log(7, "CONNECT: connected SDP fd:%d to:%s port %d\n", + fd, buf, ntohs(serv_sin->sin_port)); + } + goto done; + } + + if ((target_family == USE_SDP) || (target_family == USE_BOTH)) { + /* NOTE: the entire if sequence is negative logic */ + __sdp_log(1, "CONNECT: connecting SDP fd:%d\n", shadow_fd); + + /* make the socket blocking on shadow SDP */ + fopts = _socket_funcs.fcntl(shadow_fd, F_GETFL); + if ((target_family == USE_BOTH) && (fopts & O_NONBLOCK)) { + __sdp_log(1, + "CONNECT: shadow_fd <%d> will be blocking during connect\n", + shadow_fd); + _socket_funcs.fcntl(shadow_fd, F_SETFL, fopts & (~O_NONBLOCK)); + } + + ret = __connect_semantics(shadow_fd, serv_addr, addrlen, semantics); + if ((ret < 0) && (errno != EINPROGRESS)) { + __sdp_log(9, "Error connect: " + "failed for SDP fd:%d with error:%m\n", shadow_fd); + } else { + __sdp_log(7, "CONNECT: connected SDP fd:%d to:%s port %d\n", + fd, buf, ntohs(serv_sin->sin_port)); + } + + /* restore socket options */ + _socket_funcs.fcntl(shadow_fd, F_SETFL, fopts); + + /* if target is SDP or we succeeded we need to dup SDP fd into TCP fd */ + if ((target_family == USE_SDP) || (ret >= 0)) { + dup_ret = replace_fd_with_its_shadow(fd); + if (dup_ret < 0) { + __sdp_log(9, "Error connect: " + "failed to dup2 shadow into orig fd:%d\n", fd); + ret = dup_ret; + } else { + /* we can skip the TCP option if we are done */ + __sdp_log(1, "CONNECT: " + "matched SDP fd:%d so shadow dup into TCP\n", fd); + goto done; + } + } + } + + if ((target_family == USE_TCP) || (target_family == USE_BOTH)) { + __sdp_log(1, "CONNECT: connecting TCP fd:%d\n", fd); + ret = __connect_semantics(fd, serv_addr, addrlen, semantics); + if ((ret < 0) && (errno != EINPROGRESS)) + __sdp_log(9, "Error connect: for TCP fd:%d failed with error:%m\n", + fd); + else + __sdp_log(7, "CONNECT: connected TCP fd:%d to:%s port %d\n", + fd, buf, ntohs(serv_sin->sin_port)); + + if ((target_family == USE_TCP) || (ret >= 0) || (errno == EINPROGRESS)) { + if (cleanup_shadow(fd) < 0) + __sdp_log(9, + "Error connect: failed to cleanup shadow for fd:%d\n", + fd); + } + } + +done: + __sdp_log(2, "CONNECT: <%s:%d:%d> result <%d>\n", + program_invocation_short_name, fd, shadow_fd, ret); + + return ret; +} /* connect */ + +int connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen) +{ + return __perform_connect(fd, serv_addr, addrlen, SOCKET_SEMANTIC_DEFAULT); +} + +#if defined( SOLARIS_BUILD ) +int __xnet_connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen) +{ + return __perform_connect(fd, serv_addr, addrlen, SOCKET_SEMANTIC_XNET); +} +#endif + +/* ========================================================================= */ +/*..listen -- replacement listen call. */ +/* + Now we know our role (passive/server) and our address so we can get AF. + If both we should try listening on both +*/ + +static inline int __listen_semantics(int fd, int backlog, int semantics) +{ + return +#ifdef SOLARIS_BUILD + (semantics == SOCKET_SEMANTIC_XNET) ? + _socket_xnet_funcs.listen(fd, backlog) : +#endif + _socket_funcs.listen(fd, backlog); +} + +static int __perform_listen(int fd, int backlog, int semantics) +{ + use_family_t target_family; + int shadow_fd; + int ret = 0, sret = 0; + struct sockaddr_storage tmp_sin; + socklen_t tmp_sinlen = sizeof(tmp_sin); + struct sockaddr_in *sin4 = (struct sockaddr_in *) &tmp_sin; + char buf[MAX_ADDR_STR_LEN]; + int actual_port; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.listen) { + __sdp_log(9, "Error listen: no implementation for listen found\n"); + return -1; + } + + shadow_fd = get_shadow_fd_by_fd(fd); + __sdp_log(2, "LISTEN: <%s:%d:%d>\n", + program_invocation_short_name, fd, shadow_fd); + + /* if there is no shadow - simply call listen */ + if (shadow_fd == -1) { + __sdp_log(1, "LISTEN: calling listen on fd:%d\n", fd); + ret = __listen_semantics(fd, backlog, semantics); + goto done; + } + + /* we need to obtain the address from the fd */ + if (_socket_funcs.getsockname(fd, (struct sockaddr *) &tmp_sin, &tmp_sinlen) + < 0) { + __sdp_log(9, "Error listen: getsockname return <%d> for TCP socket\n", + errno); + errno = EADDRNOTAVAIL; + sret = -1; + goto done; + } + + if (get_addr_str((struct sockaddr *) &tmp_sin, buf, MAX_ADDR_STR_LEN)) { + __sdp_log(9, "Error listen: provided illegal address: %s\n", + strerror(errno)); + } + + __sdp_log(2, "LISTEN: <%s:%d:%d> domain <%d> IP <%s> port <%d>\n", + program_invocation_short_name, fd, shadow_fd, + sin4->sin_family, buf, ntohs(sin4->sin_port)); + + target_family = + __sdp_match_listen((struct sockaddr *) &tmp_sin, sizeof(tmp_sin)); + + /* + * in case of an implicit bind and "USE_BOTH" rule we need to first bind the + * two sockets to the same port number + */ + actual_port = ntohs(sin4->sin_port); + + /* do we need to implicit bind both */ + if ((actual_port == 0) && (target_family == USE_BOTH)) { + int sdp_sd = -1, tcp_sd = -1; + + actual_port = find_free_port((struct sockaddr *) &tmp_sin, tmp_sinlen, + fd, &sdp_sd, &tcp_sd, semantics); + if (actual_port < 0) { + ret = -1; + __sdp_log(8, "LISTEN: Failed to find common free port. Only TCP will be used.\n"); + target_family = USE_TCP; + } else { + /* copy the port to the tmp address */ + set_addr_port_num((struct sockaddr *) sin4, actual_port); + + __sdp_log(2, "LISTEN: BOTH on IP <%s> port <%d>\n", + buf, actual_port); + /* perform the bind */ + ret = close_and_bind(tcp_sd, fd, (struct sockaddr *) sin4, + tmp_sinlen, semantics); + if (ret < 0) { + __sdp_log(9, "Error listen: " + "Could not close_and_bind TCP side\n"); + } + + ret = close_and_bind(sdp_sd, shadow_fd, (struct sockaddr *) sin4, + tmp_sinlen, semantics); + if (ret < 0) { + __sdp_log(9, "Error listen: " + "Could not close_and_bind SDP side\n"); + } + } + } + + if ((target_family == USE_TCP) || (target_family == USE_BOTH)) { + __sdp_log(1, "LISTEN: calling listen on TCP fd:%d\n", fd); + ret = __listen_semantics(fd, backlog, semantics); + if (ret < 0) { + __sdp_log(9, "Error listen: failed with code <%d> on TCP fd:<%d>\n", + errno, fd); + } else { + __sdp_log(7, "LISTEN: fd:%d listening on TCP bound to:%s port:%d\n", + fd, buf, actual_port); + } + } + + if ((target_family == USE_SDP) || (target_family == USE_BOTH)) { + __sdp_log(1, "LISTEN: calling listen on SDP fd:<%d>\n", shadow_fd); + sret = __listen_semantics(shadow_fd, backlog, semantics); + if (sret < 0) { + __sdp_log(9, "Error listen: failed with code <%d> SDP fd:<%d>\n", + errno, shadow_fd); + } else { + __sdp_log(7, "LISTEN: fd:%d listening on SDP bound to:%s port:%d\n", + fd, buf, actual_port); + } + } + + /* cleanup the un-needed shadow if TCP and did not fail */ + if ((target_family == USE_TCP) && (ret >= 0)) { + __sdp_log(1, "LISTEN: cleaning up shadow SDP\n"); + if (cleanup_shadow(fd) < 0) + __sdp_log(9, "Error listen: failed to cleanup shadow for fd:%d\n", + fd); + } + + /* cleanup the TCP socket and replace with SDP */ + if ((target_family == USE_SDP) && (sret >= 0)) { + __sdp_log(1, "LISTEN: cleaning TCP socket and dup2 SDP into it\n"); + if (0 > (sret = replace_fd_with_its_shadow(fd))) + __sdp_log(9, "Error listen: " + "failed to dup2 shadow into orig fd:%d\n", fd); + } + +done: + __sdp_log(2, "LISTEN: <%s:%d:%d> result <%d>\n", + program_invocation_short_name, fd, shadow_fd, ret); + /* its a success only if both are ok */ + if (ret < 0) + return (ret); + if (sret < 0) + return (sret); + return 0; +} /* listen */ + +int listen(int fd, int backlog) +{ + return __perform_listen(fd, backlog, SOCKET_SEMANTIC_DEFAULT); +} + +#ifdef SOLARIS_BUILD +int __xnet_listen(int fd, int backlog) +{ + return __perform_listen(fd, backlog, SOCKET_SEMANTIC_XNET); +} +#endif + +/* ========================================================================= */ +/*..close -- replacement close call. */ +int close(int fd) +{ + int shadow_fd; + int ret; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.close) { + __sdp_log(9, "Error close: no implementation for close found\n"); + return -1; + } + + shadow_fd = get_shadow_fd_by_fd(fd); + + __sdp_log(2, "CLOSE: <%s:%d:%d>\n", + program_invocation_short_name, fd, shadow_fd); + + if (shadow_fd != -1) { + __sdp_log(1, "CLOSE: closing shadow fd:<%d>\n", shadow_fd); + if (cleanup_shadow(fd) < 0) + __sdp_log(9, "Error close: failed to cleanup shadow for fd:%d\n", + fd); + } + + init_extra_attribute(fd); + ret = _socket_funcs.close(fd); + __sdp_log(2, "CLOSE: <%s:%d:%d> result <%d>\n", + program_invocation_short_name, fd, shadow_fd, ret); + return ret; +} /* close */ + +/* ========================================================================= */ +/*..dup -- replacement dup call. */ +/* we duplicate the fd and its shadow if exists - ok if the main worked */ +int dup(int fd) +{ + int newfd, new_shadow_fd = -1; + int shadow_fd; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.dup) { + __sdp_log(9, "Error dup: no implementation for dup found\n"); + return -1; + } + + shadow_fd = get_shadow_fd_by_fd(fd); + + __sdp_log(2, "DUP: <%s:%d:%d>\n", + program_invocation_short_name, fd, shadow_fd); + + __sdp_log(1, "DUP: duplication fd:<%d>\n", fd); + newfd = _socket_funcs.dup(fd); + + if (newfd == fd) + return (fd); + + if (!is_valid_fd(newfd)) { + __sdp_log(9, "Error dup: new fd <%d> out of range.\n", newfd); + } else { + /* copy attributes from old fd */ + libsdp_fd_attributes[newfd] = libsdp_fd_attributes[fd]; + libsdp_fd_attributes[newfd].shadow_fd = -1; + + if (shadow_fd != -1) { + __sdp_log(1, "DUP: duplication shadow fd:<%d>\n", shadow_fd); + new_shadow_fd = _socket_funcs.dup(shadow_fd); + if ((new_shadow_fd > max_file_descriptors) || (new_shadow_fd < 0)) { + __sdp_log(9, "Error dup: new shadow fd <%d> out of range.\n", + new_shadow_fd); + } else { + libsdp_fd_attributes[new_shadow_fd] = + libsdp_fd_attributes[shadow_fd]; + libsdp_fd_attributes[newfd].shadow_fd = new_shadow_fd; + } + } /* shadow exists */ + } + + __sdp_log(2, "DUP: <%s:%d:%d> return <%d:%d>\n", + program_invocation_short_name, fd, shadow_fd, newfd, + new_shadow_fd); + + return newfd; +} /* dup */ + +/* ========================================================================= */ +/*..dup2 -- replacement dup2 call. */ +/* since only the main new fd is given we only move the shadow if exists */ +int dup2(int fd, int newfd) +{ + int shadow_fd; + int shadow_newfd; + int new_shadow_fd = -1; + int ret = 0; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.dup2) { + __sdp_log(9, "Error dup2: no implementation for dup2 found\n"); + return -1; + } + + shadow_fd = get_shadow_fd_by_fd(fd); + shadow_newfd = get_shadow_fd_by_fd(newfd); + + __sdp_log(2, "DUP2: <%s:%d:%d>\n", + program_invocation_short_name, fd, shadow_fd); + + if (newfd == fd) { + __sdp_log(1, "DUP2: skip duplicating fd:<%d> into:<%d>\n", fd, newfd); + goto done; + } + + /* dup2 closes the target file desc if it is a valid fd */ + if (shadow_newfd != -1) { + __sdp_log(1, "DUP2: closing newfd:<%d> shadow:<%d>\n", newfd, + shadow_newfd); + ret = _socket_funcs.close(shadow_newfd); + if (ret != 0) { + __sdp_log(9, + "DUP2: fail to close newfd:<%d> shadow:<%d> with: %d %s\n", + newfd, shadow_newfd, ret, strerror(errno)); + } + } + + __sdp_log(1, "DUP2: duplicating fd:<%d> into:<%d>\n", fd, newfd); + newfd = _socket_funcs.dup2(fd, newfd); + if ((newfd > max_file_descriptors) || (newfd < 0)) { + __sdp_log(9, "Error dup2: new fd <%d> out of range.\n", newfd); + } else { + /* copy attributes from old fd */ + libsdp_fd_attributes[fd].shadow_fd = -1; + libsdp_fd_attributes[newfd] = libsdp_fd_attributes[fd]; + + /* if it had a shadow create a new shadow */ + if (shadow_fd != -1) { + __sdp_log(1, "DUP2: duplication shadow fd:<%d>\n", shadow_fd); + new_shadow_fd = _socket_funcs.dup(shadow_fd); + if ((new_shadow_fd > max_file_descriptors) || (new_shadow_fd < 0)) { + __sdp_log(9, "Error dup2: new shadow fd <%d> out of range.\n", + new_shadow_fd); + } else { + libsdp_fd_attributes[new_shadow_fd] = + libsdp_fd_attributes[shadow_fd]; + libsdp_fd_attributes[newfd].shadow_fd = new_shadow_fd; + } + } /* newfd is ok */ + } + +done: + __sdp_log(2, "DUP2: <%s:%d:%d> return <%d:%d>\n", + program_invocation_short_name, fd, shadow_fd, newfd, + new_shadow_fd); + + return newfd; +} /* dup */ + +/* ========================================================================= */ +/*..getsockname -- replacement getsocknanme call. */ +int getsockname(int fd, struct sockaddr *name, socklen_t * namelen) +{ + int ret = 0; + char buf[MAX_ADDR_STR_LEN]; + + if (init_status == 0) + __sdp_init(); + + /* + * ensure the SDP protocol family is not exposed to the user, since + * this is meant to be a transparency layer. + */ + if (NULL == _socket_funcs.getsockname) { + __sdp_log(9, + "Error getsockname: no implementation for getsockname found\n"); + return -1; + } + + /* double check provided pointers */ + if ((name == NULL) || is_invalid_addr(name)) { + errno = EFAULT; + __sdp_log(9, "Error getsockname: illegal address provided\n"); + return -1; + } + + if ((namelen != NULL) && is_invalid_addr(namelen)) { + errno = EFAULT; + __sdp_log(9, "Error getsockname: illegal address length pointer provided\n"); + return -1; + } + + __sdp_log(2, "GETSOCKNAME <%s:%d>\n", program_invocation_short_name, fd); + + ret = _socket_funcs.getsockname(fd, name, namelen); + + if (__sdp_log_get_level() <= 1) { + if (get_addr_str(name, buf, MAX_ADDR_STR_LEN)) { + __sdp_log(1, "GETSOCKNAME: " "address is illegal\n"); + } else { + __sdp_log(1, "GETSOCKNAME: address is:%s port:%d\n", buf, + ntohs(((struct sockaddr_in *) name)->sin_port)); + } + } + __sdp_log(2, "GETSOCKNAME <%s:%d> result <%d>\n", + program_invocation_short_name, fd, ret); + + return ret; +} /* getsockname */ + +/* ========================================================================= */ +/*..getpeername -- replacement getpeername call. */ +int getpeername(int fd, struct sockaddr *name, socklen_t * namelen) +{ + int ret = 0; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.getpeername) { + __sdp_log(9, "Error getpeername: " + "no implementation for getpeername found\n"); + return -1; + } + + /* double check provided pointers */ + if ((name == NULL) || is_invalid_addr(name)) { + errno = EFAULT; + __sdp_log(9, "Error getsockname: illegal address provided\n"); + return -1; + } + + if ((namelen != NULL) && is_invalid_addr(namelen)) { + errno = EFAULT; + __sdp_log(9, + "Error getsockname: illegal address length pointer provided\n"); + return -1; + } + + __sdp_log(2, "GETPEERNAME <%s:%d>\n", program_invocation_short_name, fd); + + ret = _socket_funcs.getpeername(fd, name, namelen); + + __sdp_log(2, "GETPEERNAME <%s:%d> result <%d:%d> family=%d s_addr=%d\n", + program_invocation_short_name, fd, ret, + (!(0 > ret) ? 0 : -1), name->sa_family, + ((struct sockaddr_in *) name)->sin_addr.s_addr); + + return ret; +} /* getpeername */ + + + +/* ========================================================================= */ +/*..accept -- replacement accept call. */ +/* + If we have a shadow we need to decide which socket we want to accept on + so we select first and then give priority based on previous selection +*/ +int accept(int fd, struct sockaddr *addr, socklen_t * addrlen) +{ + int shadow_fd; + int ret = 0; + fd_set fds; + socklen_t saved_addrlen = 0; + int fopts; + char buf[MAX_ADDR_STR_LEN]; + + if (init_status == 0) + __sdp_init(); + + shadow_fd = get_shadow_fd_by_fd(fd); + + /* + * ensure the SDP protocol family is not exposed to the user, since + * this is meant to be a transparency layer. + */ + if (NULL == _socket_funcs.accept) { + __sdp_log(9, "Error accept: no implementation for accept found\n"); + return -1; + } + + /* double check provided pointers */ + if ((addr != NULL) && is_invalid_addr(addr)) { + errno = EINVAL; + __sdp_log(9, "Error accept: illegal address provided\n"); + return -1; + } + + if ((addrlen != NULL) && is_invalid_addr(addrlen)) { + errno = EINVAL; + __sdp_log(9, "Error accept: illegal address length pointer provided\n"); + return -1; + } + + if (addr && addrlen) + saved_addrlen = *addrlen; + + __sdp_log(2, "ACCEPT: <%s:%d>\n", program_invocation_short_name, fd); + + if (shadow_fd == -1) { + fopts = _socket_funcs.fcntl(fd, F_GETFL); + __sdp_log(1, "ACCEPT: fd <%d> opts are <0x%x>\n", fd, fopts); + + __sdp_log(7, "ACCEPT: accepting on single fd:<%d>\n", fd); + ret = _socket_funcs.accept(fd, addr, addrlen); + if (ret < 0) { + if (!(fopts & O_NONBLOCK && errno == EWOULDBLOCK)) + __sdp_log(9, "Error accept: accept returned :<%d> %s\n", + ret, strerror(errno)); + } else { + set_is_sdp_socket(ret, get_is_sdp_socket(fd)); + } + } else { + + fopts = _socket_funcs.fcntl(shadow_fd, F_GETFL); + __sdp_log(1, "ACCEPT: shadow_fd <%d> opts are <0x%x>\n", + shadow_fd, fopts); + + /* we need different behavior for NONBLOCK or signal IO and BLOCK */ + if ((fopts > 0) && (fopts & (O_NONBLOCK | FASYNC))) { + __sdp_log(1, "ACCEPT: accepting (nonblock) on SDP fd:<%d>\n", shadow_fd); + + ret = _socket_funcs.accept(shadow_fd, addr, addrlen); + if (ret >= 0) { + set_is_sdp_socket(ret, 1); + + __sdp_log(7, "ACCEPT: accepted (nonblock) SDP fd:<%d>\n", + shadow_fd); + } else { + __sdp_log(1, "ACCEPT: accept on SDP fd:<%d> return:%d errno:%d\n", + shadow_fd, ret, errno); + + __sdp_log(1, "ACCEPT: accepting (nonblock) on TCP fd:<%d>\n", fd); + ret = _socket_funcs.accept(fd, addr, addrlen); + if (ret >= 0) { + __sdp_log(7, "ACCEPT: accepted (nonblock) TCP fd:<%d>\n", + shadow_fd); + } else { + __sdp_log(1, "ACCEPT: accept on TCP fd:<%d> " + "return:%d errno:%d\n", fd, ret, errno); + } + } + } else { + __sdp_log(1, "ACCEPT: selecting both fd:<%d> and shadow:<%d>\n", + fd, shadow_fd); + FD_ZERO(&fds); + FD_SET(fd, &fds); + FD_SET(shadow_fd, &fds); + ret = + _socket_funcs.select(1 + ((fd > shadow_fd) ? fd : shadow_fd), + &fds, NULL, NULL, NULL); + if (ret >= 0) { + if (last_accept_was_tcp(fd) == 0) { + if (FD_ISSET(fd, &fds)) { + set_last_accept(fd, 1); + __sdp_log(7, "ACCEPT: accepting on TCP fd:<%d>\n", fd); + ret = _socket_funcs.accept(fd, addr, addrlen); + } else { + __sdp_log(7, "ACCEPT: accepting on SDP fd:<%d>\n", + shadow_fd); + ret = _socket_funcs.accept(shadow_fd, addr, addrlen); + if (ret >= 0) + set_is_sdp_socket(ret, 1); + } + } else { + if (FD_ISSET(shadow_fd, &fds)) { + set_last_accept(fd, 1); + __sdp_log(7, "ACCEPT: accepting on SDP fd:<%d>\n", + shadow_fd); + ret = _socket_funcs.accept(shadow_fd, addr, addrlen); + if (ret >= 0) + set_is_sdp_socket(ret, 1); + } else { + __sdp_log(7, "ACCEPT: accepting on TCP fd:<%d>\n", fd); + ret = _socket_funcs.accept(fd, addr, addrlen); + } + } + } else { + if (errno != EINTR) { + __sdp_log(9, + "Error accept: select returned :<%d> (%d) %s\n", + ret, errno, strerror(errno)); + } else { + __sdp_log(1, "ACCEPT: select returned :<%d> (%d) %s\n", + ret, errno, strerror(errno)); + } + } + } /* blocking mode */ + } /* shadow fd */ + + if ((__sdp_log_get_level() <= 1) && (ret >= 0) && addr && addrlen) { + get_addr_str(addr, buf, *addrlen); + __sdp_log(1, "ACCEPT: accepted from:%s port:%d into fd:%d\n", + buf, ntohs(((struct sockaddr_in *) addr)->sin_port), ret); + } + __sdp_log(2, "ACCEPT: <%s:%d> return <%d>\n", + program_invocation_short_name, fd, ret); + + return ret; +} /* accept */ + +/* ========================================================================= */ +/*..select -- replacement socket call. */ +/* + if we have shadow we must select on it too - which requires a hack back + and forth +*/ +int +select(int n, + fd_set * readfds, + fd_set * writefds, fd_set * exceptfds, struct timeval *timeout) +{ + int shadow_fd; + int ret; + int current; + int maxi = 0; + fd_set new_fds; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.select) { + __sdp_log(9, "Error select: no implementation for select found\n"); + return -1; + } + + __sdp_log(2, "SELECT: <%s:%d>\n", program_invocation_short_name, n); + + /* if we do not read - nothing to do */ + if (readfds == NULL) { + ret = _socket_funcs.select(n, readfds, writefds, exceptfds, timeout); + goto done; + } + + FD_ZERO(&new_fds); + if (n > 0) { + maxi = n - 1; + } + + /* add shadow bits */ + for (current = 0; current < n; current++) { + if (FD_ISSET(current, readfds)) { + FD_SET(current, &new_fds); + if (current > maxi) { + maxi = current; + } + shadow_fd = get_shadow_fd_by_fd(current); + if (shadow_fd != -1) { + __sdp_log(1, + "SELECT: adding fd:<%d> shadow_fd:<%d> to readfs\n", + current, shadow_fd); + FD_SET(shadow_fd, &new_fds); + if (shadow_fd > maxi) { + maxi = shadow_fd; + } + } + } + } + + __sdp_log(1, "SELECT: invoking select n=<%d>\n", 1 + maxi); + ret = _socket_funcs.select(1 + maxi, + &new_fds, writefds, exceptfds, timeout); + + /* remove the count and bits of the shadows */ + if (ret >= 0) { + for (current = 0; current < n; current++) { + shadow_fd = get_shadow_fd_by_fd(current); + if (shadow_fd == -1) { + if (FD_ISSET(current, readfds) && + FD_ISSET(current, &new_fds) == 0) { + FD_CLR(current, readfds); + } + } else { + if (FD_ISSET(current, readfds) && FD_ISSET(current, &new_fds) + && FD_ISSET(shadow_fd, &new_fds)) { + ret -= 1; + } + if (FD_ISSET(current, readfds) && + FD_ISSET(current, &new_fds) == 0 && + FD_ISSET(shadow_fd, &new_fds) == 0) { + FD_CLR(current, readfds); + } + } + } + } + +done: + + __sdp_log(2, "SELECT: <%s:%d> return <%d>\n", + program_invocation_short_name, n, ret); + return ret; +} /* select */ + +/* ========================================================================= */ +/*..pselect -- replacement socket call. */ +/* + if we have shadow we must pselect on it too - which requires a hack back + and forth +*/ +int +pselect(int n, + fd_set * readfds, + fd_set * writefds, + fd_set * exceptfds, + const struct timespec *timeout, const sigset_t * sigmask) +{ + int shadow_fd; + int ret; + int current; + int maxi = 0; + fd_set new_fds; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.pselect) { + __sdp_log(9, "Error pselect: no implementation for pselect found\n"); + return -1; + } + + __sdp_log(2, "PSELECT: <%s:%d>\n", program_invocation_short_name, n); + + /* if we do not read - nothing to do */ + if (readfds == NULL) { + ret = + _socket_funcs.pselect(n, readfds, writefds, exceptfds, timeout, + sigmask); + goto done; + } + + FD_ZERO(&new_fds); + if (n > 0) { + maxi = n - 1; + } + + /* add shadow bits */ + for (current = 0; current < n; current++) { + if (FD_ISSET(current, readfds)) { + FD_SET(current, &new_fds); + if (current > maxi) { + maxi = current; + } + shadow_fd = get_shadow_fd_by_fd(current); + if (shadow_fd != -1) { + __sdp_log(1, + "PSELECT: adding fd:<%d> shadow_fd:<%d> to readfs\n", + current, shadow_fd); + FD_SET(shadow_fd, &new_fds); + if (shadow_fd > maxi) { + maxi = shadow_fd; + } + } + } + } + + __sdp_log(1, "PSELECT: invoking pselect n=<%d>\n", 1 + maxi); + ret = _socket_funcs.pselect(1 + maxi, + &new_fds, writefds, exceptfds, + timeout, sigmask); + + /* remove the count and bits of the shadows */ + if (ret >= 0) { + for (current = 0; current < n; current++) { + shadow_fd = get_shadow_fd_by_fd(current); + if (shadow_fd == -1) { + if (FD_ISSET(current, readfds) && + FD_ISSET(current, &new_fds) == 0) { + FD_CLR(current, readfds); + } + } else { + if (FD_ISSET(current, readfds) && FD_ISSET(current, &new_fds) + && FD_ISSET(shadow_fd, &new_fds)) { + ret -= 1; + } + if (FD_ISSET(current, readfds) && + FD_ISSET(current, &new_fds) == 0 && + FD_ISSET(shadow_fd, &new_fds) == 0) { + FD_CLR(current, readfds); + } + } + } + } + +done: + + __sdp_log(2, "PSELECT: <%s:%d> return <%d>\n", + program_invocation_short_name, n, ret); + return ret; +} /* pselect */ + +/* ========================================================================= */ +/*..poll -- replacement socket call. */ +/* + if we have shadow we must poll on it too - which requires a hack back + and forth +*/ +int poll(struct pollfd *ufds, nfds_t nfds, int timeout) +{ + int ret; + int shadow_fd; + int current; + int extra = 0; + struct pollfd *poll_fds = NULL; + struct pollfd *poll_fd_ptr = NULL; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.poll) { + __sdp_log(9, "Error poll: no implementation for poll found\n"); + return -1; + } + + __sdp_log(2, "POLL: <%s:%d>\n", program_invocation_short_name, nfds); + + /* if we do not have any file desc - nothing to do */ + if (ufds == NULL) { + ret = _socket_funcs.poll(ufds, nfds, timeout); + goto done; + } + + /* scan for how many extra fds are required */ + for (current = 0; current < nfds; current++) { + shadow_fd = get_shadow_fd_by_fd(ufds[current].fd); + if (shadow_fd != -1) + extra++; + } + + if (!extra) { + poll_fds = ufds; + } else { + poll_fds = + (struct pollfd *) malloc((nfds + extra) * sizeof(struct pollfd)); + if (!poll_fds) { + __sdp_log(9, + "Error poll: malloc of extended pollfd array failed\n"); + ret = -1; + errno = ENOMEM; + goto done; + } + poll_fd_ptr = poll_fds; + for (current = 0; current < nfds; current++) { + *poll_fd_ptr = ufds[current]; + poll_fd_ptr++; + shadow_fd = get_shadow_fd_by_fd(ufds[current].fd); + if (shadow_fd != -1) { + __sdp_log(1, "POLL: adding fd:<%d> shadow_fd:<%d> to readfs\n", + current, shadow_fd); + *poll_fd_ptr = ufds[current]; + poll_fd_ptr->fd = shadow_fd; + poll_fd_ptr++; + } + } + } + + __sdp_log(1, "POLL: invoking poll nfds=<%d>\n", nfds + extra); + ret = _socket_funcs.poll(poll_fds, nfds + extra, timeout); + + /* refactor into original list if any events */ + if ((ret > 0) && extra) { + poll_fd_ptr = poll_fds; + for (current = 0; current < nfds; current++) { + shadow_fd = get_shadow_fd_by_fd(ufds[current].fd); + if (shadow_fd == -1) { + ufds[current] = *poll_fd_ptr; + } else { + ufds[current] = *poll_fd_ptr; + poll_fd_ptr++; + if (poll_fd_ptr->revents) { + if (ufds[current].revents) + ret--; + ufds[current].revents |= poll_fd_ptr->revents; + } + } + poll_fd_ptr++; + } + } + + if (extra) + free(poll_fds); +done: + + __sdp_log(2, "POLL: <%s:%d> return <%d>\n", + program_invocation_short_name, nfds, ret); + return ret; +} /* poll */ + +#ifdef __linux__ +/* ========================================================================= */ +/*..epoll_create -- replacement socket call. */ +/* + Need to make the size twice as large for shadow fds +*/ +int epoll_create(int size) +{ + int epfd; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.epoll_create) { + __sdp_log(9, + "Error epoll_create: no implementation for epoll_create found\n"); + return -1; + } + + __sdp_log(2, "EPOLL_CREATE: <%s:%d>\n", program_invocation_short_name, + size); + + epfd = _socket_funcs.epoll_create(size * 2); + + __sdp_log(2, "EPOLL_CREATE: <%s:%d> return %d\n", + program_invocation_short_name, size, epfd); + return epfd; +} /* epoll_create */ + +/* ========================================================================= */ +/*..epoll_ctl -- replacement socket call. */ +/* + Need to add/delete/modify shadow fds as well +*/ +int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) +{ + int ret, shadow_fd, ret2; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.epoll_ctl) { + __sdp_log(9, + "Error epoll_ctl: no implementation for epoll_ctl found\n"); + return -1; + } + + __sdp_log(2, "EPOLL_CTL: <%s:%d> op <%d:%d>\n", + program_invocation_short_name, epfd, op, fd); + + ret = _socket_funcs.epoll_ctl(epfd, op, fd, event); + + shadow_fd = get_shadow_fd_by_fd(fd); + if (shadow_fd != -1) { + ret2 = _socket_funcs.epoll_ctl(epfd, op, shadow_fd, event); + if (ret2 < 0) { + __sdp_log(9, "Error epoll_ctl <%s:%d:%d>", + program_invocation_short_name, fd, shadow_fd); + return ret2; + } + } + + __sdp_log(2, "EPOLL_CTL: <%s:%d> return <%d>\n", + program_invocation_short_name, epfd, ret); + return ret; +} /* epoll_ctl */ + +/* ========================================================================= */ +/*..epoll_wait -- replacement socket call. */ +/* + We don't care who generated the event because all we get is user-context + values. +*/ +int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) +{ + int ret; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.epoll_wait) { + __sdp_log(9, + "Error epoll_wait: no implementation for epoll_wait found\n"); + return -1; + } + + __sdp_log(2, "EPOLL_WAIT: <%s:%d>\n", program_invocation_short_name, epfd); + + ret = _socket_funcs.epoll_wait(epfd, events, maxevents, timeout); + + __sdp_log(2, "EPOLL_WAIT: <%s:%d> return <%d>\n", + program_invocation_short_name, epfd, ret); + return ret; +} /* epoll_wait */ + +/* ========================================================================= */ +/*..epoll_pwait -- replacement socket call. */ +/* + We don't care who generated the event because all we get is user-context + values. +*/ +int +epoll_pwait(int epfd, + struct epoll_event *events, + int maxevents, int timeout, const sigset_t * sigmask) +{ + int ret; + + if (init_status == 0) + __sdp_init(); + + if (NULL == _socket_funcs.epoll_pwait) { + __sdp_log(9, + "Error epoll_pwait: no implementation for epoll_pwait found\n"); + return -1; + } + + __sdp_log(2, "EPOLL_PWAIT: <%s:%d>\n", program_invocation_short_name, epfd); + + ret = _socket_funcs.epoll_pwait(epfd, events, maxevents, timeout, sigmask); + + __sdp_log(2, "EPOLL_PWAIT: <%s:%d> return <%d>\n", + program_invocation_short_name, epfd, ret); + return ret; +} /* epoll_pwait */ +#endif + +/* ========================================================================= */ + +/* --------------------------------------------------------------------- */ +/* */ +/* Library load/unload initialization/cleanup */ +/* */ +/* --------------------------------------------------------------------- */ +/* ========================================================================= */ +/*..__sdp_init -- intialize the library */ +void __sdp_init(void) +{ + char *config_file, *error_str; + int fd; + struct rlimit nofiles_limit; + + /* HACK: races might apply here: can we assume init is happening + only within one thread ? */ + if (init_status != 0) + return; + init_status = 1; + + dev_null_fd = open("/dev/null", O_WRONLY); + + /* figure out the max number of file descriptors */ + if (getrlimit(RLIMIT_NOFILE, &nofiles_limit)) + max_file_descriptors = 1024; + else + max_file_descriptors = nofiles_limit.rlim_cur; + + /* allocate and initialize the shadow sdp sockets array */ + libsdp_fd_attributes = + (struct sdp_extra_fd_attributes *) calloc(max_file_descriptors, + sizeof(struct + sdp_extra_fd_attributes)); + for (fd = 0; fd < max_file_descriptors; fd++) + init_extra_attribute(fd); + +#ifndef RTLD_NEXT + /* + * open libc for original socket call. + * Solaris relies on RTLD next - since the socket calls are + * actually in libsocket rather than libc. + */ + __libc_dl_handle = dlopen("/lib64/libc.so.6", RTLD_LAZY); + if (NULL == __libc_dl_handle) { + __libc_dl_handle = dlopen("/lib/libc.so.6", RTLD_LAZY); + if (NULL == __libc_dl_handle) { + fprintf(stderr, "%s\n", dlerror()); + return; + } + } +#endif + + /* + * Get the original functions + */ + _socket_funcs.ioctl = dlsym(__libc_dl_handle, "ioctl"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.fcntl = dlsym(__libc_dl_handle, "fcntl"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.socket = dlsym(__libc_dl_handle, "socket"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.setsockopt = dlsym(__libc_dl_handle, "setsockopt"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.connect = dlsym(__libc_dl_handle, "connect"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.listen = dlsym(__libc_dl_handle, "listen"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.bind = dlsym(__libc_dl_handle, "bind"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.close = dlsym(__libc_dl_handle, "close"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.dup = dlsym(__libc_dl_handle, "dup"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.dup2 = dlsym(__libc_dl_handle, "dup2"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.getpeername = dlsym(__libc_dl_handle, "getpeername"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.getsockname = dlsym(__libc_dl_handle, "getsockname"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.accept = dlsym(__libc_dl_handle, "accept"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.select = dlsym(__libc_dl_handle, "select"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.pselect = dlsym(__libc_dl_handle, "pselect"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.poll = dlsym(__libc_dl_handle, "poll"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + +#ifdef __linux__ + _socket_funcs.epoll_create = dlsym(__libc_dl_handle, "epoll_create"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.epoll_ctl = dlsym(__libc_dl_handle, "epoll_ctl"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.epoll_wait = dlsym(__libc_dl_handle, "epoll_wait"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_funcs.epoll_pwait = dlsym(__libc_dl_handle, "epoll_pwait"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } +#endif +#ifdef SOLARIS_BUILD + _socket_xnet_funcs.socket = dlsym(__libc_dl_handle, "__xnet_socket"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_xnet_funcs.connect = dlsym(__libc_dl_handle, "__xnet_connect"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_xnet_funcs.listen = dlsym(__libc_dl_handle, "__xnet_listen"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + _socket_xnet_funcs.bind = dlsym(__libc_dl_handle, "__xnet_bind"); + if (NULL != (error_str = dlerror())) { + fprintf(stderr, "%s\n", error_str); + } + + /* Determine program name by asking libdl */ + Dl_argsinfo args_info; + if (NULL != dlinfo(RTLD_SELF, RTLD_DI_ARGSINFO, &args_info)) { + fprintf(stderr, "args_info: %s\n", dlerror()); + } else { + program_invocation_name = args_info.dla_argv[0]; + program_invocation_short_name = basename(args_info.dla_argv[0]); + } +#endif + + if (getenv("SIMPLE_LIBSDP") != NULL) { + simple_sdp_library = 1; + } + + if (getenv("ALWAYS_USE_SDP") != NULL) { + simple_sdp_library = 1; + } +#define LIBSDP_DEFAULT_CONFIG_FILE SYSCONFDIR "/libsdp.conf" + if (!simple_sdp_library) { + config_file = getenv("LIBSDP_CONFIG_FILE"); + if (!config_file) + config_file = LIBSDP_DEFAULT_CONFIG_FILE; + + if (__sdp_parse_config(config_file)) { + fprintf(stderr, + "libsdp Error: failed to parse config file:%s. Using defaults.\n", + config_file); + } + } + + __sdp_log(1, "Max file descriptors:%d\n", max_file_descriptors); + init_status = 2; + +} /* __sdp_init */ + +/* ========================================================================= */ +/*..__sdp_fini -- when the library is unloaded this is called */ +void __sdp_fini(void) +{ + struct use_family_rule *rule; + for (rule = __sdp_clients_family_rules_head; rule != NULL; + rule = rule->next) + free(rule->prog_name_expr); + for (rule = __sdp_servers_family_rules_head; rule != NULL; + rule = rule->next) + free(rule->prog_name_expr); + + free(libsdp_fd_attributes); + +#ifndef RTLD_NEXT + dlclose(__libc_dl_handle); +#endif +} /* _fini */ diff --git a/contrib/ofed/libsdp/src/socket.c b/contrib/ofed/libsdp/src/socket.c new file mode 100644 index 000000000000..d40265b17845 --- /dev/null +++ b/contrib/ofed/libsdp/src/socket.c @@ -0,0 +1,167 @@ +/* + This software is available to you under a choice of one of two + licenses. You may choose to be licensed under the terms of the GNU + General Public License (GPL) Version 2, available at + , or the OpenIB.org BSD + license, available in the LICENSE.TXT file accompanying this + software. These details are also available at + . + + 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. + + Copyright (c) 2004 Topspin Communications. All rights reserved. + Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + + $Id$ +*/ + +/* + * system includes + */ +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +/* + For non-i386 systems, we pass socket() through to library code using + dlsym() instead of trying to make the system call directly. This + may cause problems if this library is LD_PRELOADed before the real C + library is available. Eventually we may want to add the same type + of system call assembly code as i386 has for IA64 and AMD64, but for + now.... +*/ +#ifndef i386 +#define _GNU_SOURCE /* Get RTLD_NEXT */ +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +/* + * SDP specific includes + */ +#include "linux/sdp_inet.h" + +#if 0 +#define _SDP_VERBOSE_PRELOAD +#endif + +#define SOCKOP_socket 1 +#define SOCKOP_bind 2 +#define SOCKOP_connect 3 +#define SOCKOP_listen 4 +#define SOCKOP_accept 5 +#define SOCKOP_getsockname 6 +#define SOCKOP_getpeername 7 +#define SOCKOP_socketpair 8 +#define SOCKOP_send 9 +#define SOCKOP_recv 10 +#define SOCKOP_sendto 11 +#define SOCKOP_recvfrom 12 +#define SOCKOP_shutdown 13 +#define SOCKOP_setsockopt 14 +#define SOCKOP_getsockopt 15 +#define SOCKOP_sendmsg 16 +#define SOCKOP_recvmsg 17 + +extern char * program_invocation_name; +extern char * program_invocation_short_name; +extern char ** const environ; + +/* ========================================================================= */ +/*..socket -- replacment socket call. */ +int socket +( + int domain, + int type, + int protocol +) +{ +#ifdef i386 + long __ret; + void *__scratch; + int call[3]; +#endif + char *test; + char *inet; + char **tenviron; + +#ifdef _SDP_VERBOSE_PRELOAD + FILE *fd; +#endif + /* + * check for magic enviroment variable + */ + if ((AF_INET == domain || AF_INET6 == domain) && + SOCK_STREAM == type) { + + if (environ) { + tenviron = environ; + for (test = *tenviron; NULL != test; test = *++tenviron) { + + inet = AF_INET_STR; + + while (*inet == *test && '\0' != *inet) { + + inet++; + test++; + } /* while */ + + if ('\0' == *inet && '=' == *test) { + + domain = AF_INET_SDP; + break; + } /* if */ + } /* for */ + } /* if */ + } /* if */ + +#ifdef _SDP_VERBOSE_PRELOAD + fd = fopen("/tmp/libsdp.log.txt", "a+"); + + fprintf(fd, "SOCKET: <%s> domain <%d> type <%d> protocol <%d>\n", + program_invocation_short_name, domain, type, protocol); + + fclose(fd); +#endif + +#ifdef i386 + /* Make the socket() system call directly, as described above */ + call[0] = domain; + call[1] = type; + call[2] = protocol; + + __asm__ __volatile__("movl %%ebx, %1\n" /* save %ebx */ + "movl %3, %%ebx\n" /* put sockopt in %ebx as arg */ + "int $0x80\n" /* do syscall */ + "movl %1, %%ebx\n" /* restore %ebx */ + : "=a" (__ret), "=r" (__scratch) + : "0" (__NR_socketcall), + "g" (SOCKOP_socket), + "c" (call)); + return __ret; +#else /* i386 */ + /* Use the standard library socket() to pass through the call */ + { + static int (*orig_socket)(int, int, int); + + if (!orig_socket) { + orig_socket = dlsym(RTLD_NEXT, "socket"); + } + + return orig_socket(domain, type, protocol); + } +#endif /* i386 */ +} /* socket */ diff --git a/contrib/ofed/management/AUTHORS b/contrib/ofed/management/AUTHORS new file mode 100644 index 000000000000..d09c13fe2781 --- /dev/null +++ b/contrib/ofed/management/AUTHORS @@ -0,0 +1,3 @@ +Shahar Frank +Hal Rosenstock +Sasha Khapyorsky diff --git a/contrib/ofed/management/COPYING b/contrib/ofed/management/COPYING new file mode 100644 index 000000000000..1b1ca1d2fb84 --- /dev/null +++ b/contrib/ofed/management/COPYING @@ -0,0 +1,384 @@ +This software with the exception of OpenSM is available to you +under a choice of one of two licenses. You may chose to be +licensed under the terms of the the OpenIB.org BSD license or +the GNU General Public License (GPL) Version 2, both included +below. + +OpenSM is licensed under either GNU General Public License (GPL) +Version 2, or Intel BSD + Patent license. See OpenSM for the +specific language for the latter licensing terms. + + +Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + +================================================================== + + OpenIB.org BSD license + +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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +================================================================== + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/ofed/management/ChangeLog b/contrib/ofed/management/ChangeLog new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ofed/management/INSTALL b/contrib/ofed/management/INSTALL new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ofed/management/Makefile b/contrib/ofed/management/Makefile new file mode 100644 index 000000000000..863c3aa163c3 --- /dev/null +++ b/contrib/ofed/management/Makefile @@ -0,0 +1,21 @@ + +SUBDIRS:= libibcommon libibumad libibmad opensm infiniband-diags + +all: + +config: + $(foreach dir, $(SUBDIRS), \ + if [ ! -z "$(force)" -o ! -x $(dir)/configure ] ; then \ + ( cd $(dir) && ./autogen.sh && ./configure $(CONFIG_OPTS) ) \ + || exit 1 ; \ + elif [ ! -e $(dir)/Makefile ] ; then \ + ( cd $(dir) && ./configure $(CONFIG_OPTS) ) \ + || exit 1 ; \ + fi ; ) + +automake: force=1 +automake: config + +all install: config +all install clean: + $(foreach dir, $(SUBDIRS), $(MAKE) -C $(dir) $@ && ) echo $@ done diff --git a/contrib/ofed/management/NEWS b/contrib/ofed/management/NEWS new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/ofed/management/README b/contrib/ofed/management/README new file mode 100644 index 000000000000..c6efd9fa46b9 --- /dev/null +++ b/contrib/ofed/management/README @@ -0,0 +1,132 @@ +This README is for OpenSM and the InfiniBand diagnostic utilities +in this directory (management). + +The master source repository is +git://git.openfabrics.org/~sashak/management.git and can be cloned by: + + git clone git://git.openfabrics.org/~sashak/management.git + + +Packages +-------- +libibcommon - common stuff +libibumad - interface to ib_umad module (user_mad) library +libibmad - generic MAD handling library +opensm - OpenSM +infiniband-diags - various diagnostic tools + + +Building +-------- +To make this unpack tarballs and in directories libibcommon, libibumad, +libibmad, opensm, infiniband-diags (in that order) run: + + ./configure && make && make install + +(If you are building the cloned repository run also ./autogen.sh first) + +Typically the autogen and configure steps only need be done the first +time unless configure.in or Makefile.am changes in the directories. + +Libraries are installed by default at /usr/local/lib and binaries at +/usr/local/sbin. + + +Running +------- +After compiling and installing, you can run opensm by invoking + + /usr/local/sbin/opensm + +opensm must be run as root. Run 'opensm --help' to see the options. + +Note also that you must have udev mount /dev/infiniband or do it manually. +See .../src/linux-kernel/docs/user_mad.txt. Also, ib_umad module must be +loaded. + +opensm will run on the first existing port on the first IB device (HCA). +You can override that by using "-g ". +Verify that the first port is active. This assumes the port is plugged +into another IB device. + +In case of problems, run the opensm with -V and send the log file +(/var/log/opensm.log). + +IMPORTANT: +Don't forget to modprobe ib_umad and make sure udev is configured before +using any of the userspace programs. + + +OpenSM Limitations: +1. Retry mechanism in SM is primitive and needs enhancing to deal with +ports which are active but don't respond to SM MADs. +2. Async events are not yet supported (by OpenSM). The only one supported +is local LID change (and this is handled in the mthca driver). Future +versions of OpenSM may need to act on more local events. + + +Tuning OpenSM for Large Clusters +-------------------------------- +Currently OpenSM is compiled with debug and no optimization. This +should be changed to at least -O2 (and perhaps -O4) but I would start +with -O2. This results in a 2x speedup for some code paths. + +OpenSM supports a pipelining mode for SMPs. The default is 4 +outstanding SMPs. -maxsmps <#> indicates the number of outstanding SMPs +allowed and should speed up the initialization. Useful values of this +are 16 and 32. + +Beyond this, there may be some issue with a link which is causing +timeout and retries to kick in. The OpenSM log should have some messages +in there indicating this. + + +Other utilities (infiniband diagnostics) +--------------------------------------- +ibstat - show host adapters status +ibstatus - similar to ibstat but implemented as a script +ibnetdiscover - scan topology +ibaddr - shows the lid range and default GID of the target (default is + the local port) +ibroute - display unicast and multicast forwarding tables of switches +ibtracert - display unicast or multicast route from source to destination +ibping - ping/pong between IB nodes (currently using vendor MADs) +ibsysstat - obtain basic information for node (hostname, cpus, memory, + utilization) which may be remote +sminfo - query the SMInfo attribute on a node +smpdump - simple solicited SMP query tool. Output is hex dump + (unless requested otherwise, e.g. using -s) +smpquery - formatted SMP query tool +perfquery - dump (and optionally clear) the performance (including error) + counters of the destination port +ibcheckport - perform some basic tests on the specified port +ibchecknode - perform some basic tests on the specified node +ibcheckerrs - check if the error counters of the port/node have passed + some predefined thresholds +ibchecknet - perform port/node/errors check on the subnet. ibnetdiscover + output can be used as in input topology +ibswitches - scan the net or use existing net topology file and list all + switches +ibhosts - scan the net or use existing net topology file and list all hosts +ibnodes - scan the net or use existing net topology file and list all nodes +ibportstate - get the logical and physical port state of an IB port or + disable or enable the port (only on a switch) +ibcheckwidth - perform port width check on the subnet. Used to find ports + with 1x link width. +ibcheckportwidth - perform 1x port width check on specified port +ibcheckstate - perform port state (and physical port state) check on + the subnet. Used to find ports not in LinkUp physical port state + and not Active port state +ibcheckportstate - perform port state (and physical port state) check on + specified port +ibcheckerrors - perform error check on subnet. Used to find ports with + error counters (PMA PortCounters) beyond the indicated thresholds +ibclearerrors - clear all error counters on subnet +ibclearcounters - clear all port counters on subnet +ibdiscover.pl - takes output of ibnetdiscover and a map file and produces + a topology file (local node GUID and port connected to remote + node GUID and port) +saquery - issue some SA queries + +Note that the above list is not up to date and the infiniband-diags +subdirectory should be checked for the latest tools. diff --git a/contrib/ofed/management/doc/diagtools-proposal.txt b/contrib/ofed/management/doc/diagtools-proposal.txt new file mode 100644 index 000000000000..f0f15cb2e43e --- /dev/null +++ b/contrib/ofed/management/doc/diagtools-proposal.txt @@ -0,0 +1,169 @@ +Diagnostic Tools +11/29/04 + +user space applications (also library support) +two categories: host and network + +Host Oriented Diagnostic Tools + +1. ibstatus + +Description: +ibstatus displays basic information obtained from the local IB driver. +-v enables verbose mode. Normal output includes LID, SMLID, port state, +link width active, and port physical state. Verbose includes all sysfs +supported parameters for that interface and port. + +Syntax: +ibstatus [-v] [-I mthca0] [-p port] + +Dependencies: +sysfs support in mthca + +2. ibroute + +Description: +ibroute uses SMPs to display the forwarding tables (unicast +(LinearForwardingTable or LFT) or multicast (MulticastForwardingTable or MFT)) +for the specified LID. + +Syntax: +ibroute [-multi] [-m mkey] [-pa path] [-I mthca0] [-p port] LID + +Dependencies: +user MAD access, SMA + +3. ibtracert + +Description: +ibtracert uses SMPs to trace the path from a source GID/LID to a +destination GID/LID. The source GID/LID must be local to the node. +Each hop along the path is displayed until the destination is reached or +a hop does not respond. By using -mg and/or -ml options, multicast path +tracing can be performed between source and destination nodes. + +Syntax: +ibtracert [-m mkey] [-pa path] [-sg SGID] [-sl SLID] [-dg DGID] [-dl DLID] \ + [-mg MGID] [-ml MLID] [-I mthca0] [-p port] + +Dependencies: +user MAD access, SMA + +4. smpquery + +Description: +smpquery allows a basic subset of standard SMP queries including the following: +local information (LID, GID, etc.), node information (from NodeDescription, +NodeInfo, and possibly SwitchInfo if node is a switch), port information +(port address and state), and port parameters (SLtoVLMappingTable, +VLArbitrationTable, HOQLife, ...). + +Syntax: +smpquery [-m mkey] [-l LID] [-pa path] [-I mthca0] [-p port] \ + [-l] [-n] [-pi] [-pp] + +Dependencies: +User MAD access + +5. smpdump + +Description: +smpdump is a general purpose SMP utility which gets SM attributes from a +specified SMA. The result is dumped as hex (-x) or string (-s), with hex +as the default. + +Syntax: +smpdump [-m mkey] [-l LID] [-p path] [-I mthca0] [-p port] \ + [-a attributeID] [-am attributeModifier] [-s] [-x] + +Dependencies: +User MAD access, MAD snooping support + +6. perfquery + +Description: +perfquery uses PerfMgt GMPs to obtain the PortCounters (basic performance +and error counters) from the PMA at the node specified. -r resets these +counters after obtaining them. + +Syntax: +perfquery [-I mthca0] [-p port] [-r] [-g GID] LID + +Dependencies: +User MAD access, PMA + +7. ibping + +Description: +ibping uses UD transport to validate connectivity between IB nodes. +It is run as client/server (daemon). -v option uses vendor MADs rather than +normal UD transport. + +Syntax: +ibping [-d] [-v] [-c count] [-i interval] [-s packetsize] \ + [-I mthca0] [-p port] [-q qkey] [-g DGID] [-qp dqp] [-dl DLID] + +-d: run as daemon (server) + +Dependencies: +user MAD access + + +Network Oriented Diagnostics + +8. ibnetdiscover + +Description: +ibnetdiscover performs IB subnet discovery and outputs a human readable +topology file. GUIDs, node types, and port numbers are displayed +as well as port LIDs and NodeDescriptions. All nodes (and links) are displayed +(full topology). + +Syntax: +ibnetdiscover [-I mthca0] [-p port] [-o topology-filename] + +Dependencies: +user MAD access + +Future versions of this file will be annotated with additional information +including system guid, system type, internal to physical mapping, and physical +location information (blade or ASIC number, etc.). + +9. ibhosts + +Description: +ibhosts either walks the IB subnet topology or uses an already saved topology +file and extracts the HCA nodes. + +Syntax: +ibhosts [-I mthca0] [-p port] [-i topology-filename] [-o ibhosts-filename] + +Dependencies: +user MAD access, ibnetdiscover + +10. ibswitches + +Description: +ibswitches either walks the IB subnet topology or uses an already saved +topology file and extracts the IB switches. + +Syntax: +ibswitches [-I mthca0] [-p port] \ + [-i topology-filename] [-o ibswitches-filename] + +Dependencies: +user MAD access, ibnetdiscover + +11. ibnetverify + +Description: +ibnetverify uses a full topology file that was created by ibnetdiscover, +scans the network to see if the current topology matches or not displaying +any discrepancies, and validates the connectivity and reports errors +(from port counters). + +Syntax: +ibnetverify -f filename [-I mthca0] [-p port] + +Dependencies: +user MAD access, ibnetdiscover diff --git a/contrib/ofed/management/doc/diagtools.txt b/contrib/ofed/management/doc/diagtools.txt new file mode 100644 index 000000000000..8ef2590a90a1 --- /dev/null +++ b/contrib/ofed/management/doc/diagtools.txt @@ -0,0 +1,565 @@ +Diagnostic Tools +shaharf@voltaire.com, halr@voltaire.com + +General: + +Model of operation: All utilities use direct MAD access to perform their +operations. Operations that require QP 0 mads only, may use direct routed +mads, and therefore may work even in unconfigured subnets. Almost all +utilities can operate without accessing the SM, unless GUID to lid translation +is required. + +Dependencies: Most utilities depend on libibmad and libibumad. + All utilities depend on the ib_umad kernel module. + +Multiple port/Multiple CA support: when no IB device or port is specified + (see the "local umad parameters" below), the libibumad library + selects the port to use by the following criteria: + 1. the first port that is ACTIVE. + 2. if not found, the first port that is UP (physical link up). + + If a port and/or CA name is specified, the libibumad library + attempts to fulfill the user request, and will fail if it is not + possible. + For example: + ibaddr # use the 'best port' + ibaddr -C mthca1 # pick the best port from mthca1 only. + ibaddr -P 2 # use the second (active/up) port from the + first available IB device. + ibaddr -C mthca0 -P 2 # use the specified port only. + +Common options & flags: + Most diagnostics take the following flags. The exact list of supported + flags per utility can be found in the usage message and can be shown + using util_name -h syntax. + + # Debugging flags + -d raise the IB debugging level. May be used + several times (-ddd or -d -d -d). + -e show umad send receive errors (timeouts and others) + -h show the usage message + -v increase the application verbosity level. + May be used several times (-vv or -v -v -v) + -V show the internal version info. + + # Addressing flags + -D use directed path address arguments. The path + is a comma separated list of out ports. + Examples: + "0" # self port + "0,1,2,1,4" # out via port 1, then 2, ... + -G use GUID address arguments. In most cases, it is the Port GUID. + Examples: + "0x08f1040023" + -s use 'smlid' as the target lid for SA queries. + + # Local umad parameters: + -C use the specified ca_name. + -P use the specified ca_port. + -t override the default timeout for the solicited mads. + +CLI notation: all utilities use the POSIX style notation, + meaning that all options (flags) must precede all arguments + (parameters). + + +Utilities descriptions: + +1. ibstatus + +Description: +ibstatus is a script which displays basic information obtained from the local +IB driver. Output includes LID, SMLID, port state, link width active, and port +physical state. + +Syntax: +ibstatus [-h] [devname[:port]]... + +Examples: + ibstatus # display status of all IB ports + ibstatus mthca1 # status of mthca1 ports + ibstatus mthca1:1 mthca0:2 # show status of specified ports + +See also: + ibstat + +2. ibstat + +Description: +Similar to the ibstatus utility but implemented as a binary and not a script. +It has options to list CAs and/or ports. + +Syntax: +ibstat [-d(ebug) -l(ist_of_cas) -p(ort_list) -s(hort)] [portnum] + +Examples: + ibstat # display status of all IB ports + ibstat mthca1 # status of mthca1 ports + ibstat mthca1 2 # show status of specified ports + ibstat -p mthca0 # list the port guids of mthca0 + ibstat -l # list all CA names + +See also: + ibstatus + +3. ibroute + +Description: +ibroute uses SMPs to display the forwarding tables (unicast +(LinearForwardingTable or LFT) or multicast (MulticastForwardingTable or MFT)) +for the specified switch LID and the optional lid (mlid) range. +The default range is all valid entries in the range 1...FDBTop. + +Syntax: +ibroute [options] [ []]] + +Non standard flags: + -a show all lids in range, even invalid entries. + -n do not try to resolve destinations. + -M show multicast forwarding tables. In this case the range + parameters are specifying mlid range. + +Examples: + ibroute 2 # dump all valid entries of switch lid 2 + ibroute 2 15 # dump entries in the range 15...FDBTop. + ibroute -a 2 10 20 # dump all entries in the range 10..20 + ibroute -n 2 # simple format + ibroute -M 2 # show multicast tables + +See also: + ibtracert + +4. ibtracert + +Description: +ibtracert uses SMPs to trace the path from a source GID/LID to a +destination GID/LID. Each hop along the path is displayed until the destination +is reached or a hop does not respond. By using the -m option, multicast path +tracing can be performed between source and destination nodes. + +Syntax: +ibtracert [options] + +Non standard flags: + -n simple format; don't show additional information. + -m show the multicast trace of the specified mlid. + +Examples: + ibtracert 2 23 # show trace between lid 2 and 23 + ibtracert -m 0xc000 3 5 # show multicast trace between lid 3 and 5 + for mcast lid 0xc000. + +5. smpquery + +Description: +smpquery allows a basic subset of standard SMP queries including the following: +node info, node description, switch info, port info. Fields are displayed in +human readable format. + +Syntax: +smpquery [options] [op_params] + +Current supported operations and their parameters: + nodeinfo + nodedesc + portinfo [] # default port is zero + switchinfo + pkeys [] + sl2vl [] + vlarb [] + +Examples: + smpquery nodeinfo 2 # show nodeinfo for lid 2 + smpquery portinfo 2 5 # show portinfo for lid 2 port 5 + +6. smpdump + +Description: +smpdump is a general purpose SMP utility which gets SM attributes from a +specified SMA. The result is dumped in hex by default. + +Syntax: +smpdump [options] [mod] + +Non standard flags: + -s show output as string + +Examples: + smpdump -D 0,1,2 0x15 2 # port info, port 2 + smpdump 3 0x15 2 # port info, lid 3 port 2 + +7. ibaddr + +Description: +ibaddr can be used to show the lid and GID addresses of the specified port, +or the local port by default. +Note: this utility can be used as simple address resolver. + +Syntax: +ibaddr [options] [] + +Examples: + ibaddr # show local address + ibaddr 2 # show address of the specified port lid + ibaddr -G 0x8f1040023 # show address of the specified port guid + +8. sminfo + +Description: +sminfo issue and dumps the output of a sminfo query in human readable format. +The target SM is the one listed in the local port info, or the SM specified +by the optional SM lid or by the SM direct routed path. +Note: using sminfo for any purposes other then simple query may be very +dangerous, and may result in a malfunction of the target SM. + +Syntax: +sminfo [options] [sminfo_modifier] + +Non standard flags: + -s # use the specified state in sminfo mad + -p # use the specified priority in sminfo mad + -a # use the specified activity in sminfo mad + +Examples: + sminfo # show sminfo of SM listed in local portinfo + sminfo 2 # query SM on port lid 2 + +9. perfquery + +Description: +perfquery uses PerfMgt GMPs to obtain the PortCounters (basic performance +and error counters) from the PMA at the node specified. Optionally +show aggregated counters for all ports of node. Also, optionally, reset +after read, or only reset counters. + +Syntax: +perfquery [options] [ [[port] [reset_mask]]] + +Non standard flags: + -a show aggregated counters for all ports of the destination lid. + -r reset counters after read. + -R only reset counters. + +Examples: + perfquery # read local port's performance counters + perfquery 32 1 # read performance counters from lid 32, port 1 + perfquery -a 32 # read node aggregated performance counters + perfquery -r 32 1 # read performance counters and reset + perfquery -R 32 1 # reset performance counters of port 1 only + perfquery -R -a 32 # reset performance counters of all ports + perfquery -R 32 2 0xf000 # reset only non-error counters of port 2 + +10. ibping + +Description: +ibping uses vendor mads to validate connectivity between IB nodes. +On exit, (IP) ping like output is show. ibping is run as client/server. +Default is to run as client. Note also that a default ping server is +implemented within the kernel. + +Syntax: +ibping [options] + +Non standard flags: + -c stop after count packets + -f flood destination: send packets back to back w/o delay + -o use specified OUI number to multiplex vendor mads + -S start in server mode (do not return) + +11. ibnetdiscover + +Description: +ibnetdiscover performs IB subnet discovery and outputs a human readable +topology file. GUIDs, node types, and port numbers are displayed +as well as port LIDs and NodeDescriptions. All nodes (and links) are displayed +(full topology). Optionally this utility can be used to list the current +connected nodes. The output is printed to the standard output unless a +topology file is specified. + +Syntax: +ibnetdiscover [options] [] + +Non standard flags: + -l List of connected nodes + -H List of connected HCAs + -S List of connected switches + -g Grouping + +12. ibhosts + +Description: +ibhosts either walks the IB subnet topology or uses an already saved topology +file and extracts the CA nodes. + +Syntax: +ibhosts [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format + +13. ibswitches + +Description: +ibswitches either walks the IB subnet topology or uses an already saved +topology file and extracts the IB switches. + +Syntax: +ibswitches [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format + +14. ibchecknet + +Description: +ibchecknet uses a full topology file that was created by ibnetdiscover, +scans the network to validate the connectivity and reports errors +(from port counters). + +Syntax: +ibchecknet [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format, ibchecknode, ibcheckport, ibcheckerrs + +15. ibcheckport + +Description: +Check connectivity and do some simple sanity checks for the specified port. +Port address is lid unless -G option is used to specify a GUID address. + +Syntax: +ibcheckport [-h] [-G] + +Example: + ibcheckport 2 3 # check lid 2 port 3 + +Dependencies: +smpquery, smpquery output format, ibaddr + +16. ibchecknode + +Description: +Check connectivity and do some simple sanity checks for the specified node. +Port address is lid unless -G option is used to specify a GUID address. + +Syntax: +ibchecknode [-h] [-G] + +Example: + ibchecknode 2 # check node via lid 2 + +Dependencies: +smpquery, smpquery output format, ibaddr + +Usage: + +17. ibcheckerrs + +Description: +Check specified port (or node) and report errors that surpassed their predefined +threshold. Port address is lid unless -G option is used to specify a GUID +address. The predefined thresholds can be dumped using the -s option, and a +user defined threshold_file (using the same format as the dump) can be +specified using the -t option. + +Syntax: +ibcheckerrs [-h] [-G] [-t ] [-s(how_thresholds)] [] + +Examples: + ibcheckerrs 2 # check aggregated node counter for lid 2 + ibcheckerrs 2 4 # check port counters for lid 2 port 4 + ibcheckerrs -t xxx 2 # check node using xxx threshold file + +Dependencies: +perfquery, perfquery output format, ibaddr + +18. ibportstate + +Description: +ibportstate allows the port state and port physical state of an IB port +to be queried or a switch port to be disabled or enabled. + +Syntax: +ibportstate [-d(ebug) -e(rr_show) -v(erbose) -D(irect) -G(uid) -s smlid +-V(ersion) -C ca_name -P ca_port -t timeout_ms] + [] + supported ops: enable, disable, query + +Examples: + ibportstate 3 1 disable # by lid + ibportstate -G 0x2C9000100D051 1 enable # by guid + ibportstate -D 0 1 # by direct route + +19. ibcheckwidth + +Description: +ibcheckwidth uses a full topology file that was created by ibnetdiscover, +scans the network to validate the active link widths and reports any 1x +links. + +Syntax: +ibcheckwidth [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format, ibchecknode, ibcheckportwidth + +20. ibcheckportwidth + +Description: +Check connectivity and check the specified port for 1x link width. +Port address is lid unless -G option is used to specify a GUID address. + +Syntax: +ibcheckportwidth [-h] [-G] + +Example: + ibcheckportwidth 2 3 # check lid 2 port 3 + +Dependencies: +smpquery, smpquery output format, ibaddr + +21. ibcheckstate + +Description: +ibcheckstate uses a full topology file that was created by ibnetdiscover, +scans the network to validate the port state and port physical state, +and reports any ports which have a port state other than Active or +a port physical state other than LinkUp. + +Syntax: +ibcheckstate [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format, ibchecknode, ibcheckportstate + +22. ibcheckportstate + +Description: +Check connectivity and check the specified port for proper port state +(Active) and port physical state (LinkUp). +Port address is lid unless -G option is used to specify a GUID address. + +yntax: +ibcheckportstate [-h] [-G] + +Example: + ibcheckportstate 2 3 # check lid 2 port 3 + +Dependencies: +smpquery, smpquery output format, ibaddr + +23. ibcheckerrors + +ibcheckerrors uses a full topology file that was created by ibnetdiscover, +scans the network to validate the connectivity and reports errors +(from port counters). + +Syntax: +ibnetcheckerrors [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format, ibchecknode, ibcheckport, ibcheckerrs + +24. ibdiscover.pl + +ibdiscover.pl uses a topology file create by ibnetdiscover and a discover.map +file which the network administrator creates which indicates the nodes +to be expected and a ibdiscover.topo file which is the expected connectivity +and produces a new connectivity file (discover.topo.new) and outputs +the changes to stdout. The network administrator can choose to replace +the "old" topo file with the new one or certain changes in. + +The syntax of the ibdiscover.map file is: +|port|"Text for node"| +e.g. +8f10400410015|8|"ISR 6000"|# SW-6IB4 Voltaire port 0 lid 5 +8f10403960558|2|"HCA 1"|# MT23108 InfiniHost Mellanox Technologies + +The syntax of the old and new topo files (ibdiscover.topo and +ibdiscover.topo.new) are: +||| +e.g. +10|5442ba00003080|1|8f10400410015 + +These topo files are produced by the ibdiscover.pl tool. + +Syntax: +ibnetdiscover | ibdiscover.pl + +Dependencies: +ibnetdiscover, ibnetdiscover format + +25. ibnodes + +Description: +ibnodes either walks the IB subnet topology or uses an already saved topology +file and extracts the IB nodes (CAs and switches). + +Syntax: +ibnodes [] + +Dependencies: +ibnetdiscover, ibnetdiscover format + +26. ibclearerrors + +Description: +ibclearerrors clears the PMA error counters in PortCounters by either walking +the IB subnet topology or using an already saved topology file. + +Syntax: +ibclearerrors [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format, perfquery + +27. ibclearcounters + +Description: +ibclearcounters clears the PMA port counters by either walking +the IB subnet topology or using an already saved topology file. + +Syntax: +ibclearcounters [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format, perfquery + +28. saquery + +Description: +Issue some SA queries. + +Syntax: +Usage: saquery [-h -d -P -N -L -G -s -g][] + Queries node records by default + -d enable debugging + -P get PathRecord info + -N get NodeRecord info + -L Return just the Lid of the name specified + -G Return just the Guid of the name specified + -s Return the PortInfoRecords with isSM capability mask bit on + -g get multicast group info + +Dependencies: +OpenSM libvendor, OpenSM libopensm, libibumad + +29. ibsysstat + +Description: +ibsysstat uses vendor mads to validate connectivity between IB nodes +and obtain other information about the IB node. ibsysstat is run as +client/server. Default is to run as client. + +Syntax: +ibsysstat [options] [] + +Non standard flags: + Current supported operations: + ping - verify connectivity to server (default) + host - obtain host information from server + cpu - obtain cpu information from server + -o use specified OUI number to multiplex vendor mads + -S start in server mode (do not return) + diff --git a/contrib/ofed/management/doc/ibtracer.txt b/contrib/ofed/management/doc/ibtracer.txt new file mode 100644 index 000000000000..c86000c5253c --- /dev/null +++ b/contrib/ofed/management/doc/ibtracer.txt @@ -0,0 +1,106 @@ +ibtracer +1/11/05 + +Description: +ibtracer is used to build a source route into a UD packet and validate the +path taken to a destination. It is based on a client/server architecture and +relies on a special ibtracer IB agent in each node along the way. It can +deal with switches which do not currently run this agent but validation for +that part of the path is impossible. + +Syntax: +ibtracer [-I mthca0] [-p port] [-r <# retries>] [-t ] \ + [-l LID] [-g DGID] [-v] + +Architecture: +IBA 1.2 defines a new set of vendor specific MADs which include OUI. OpenIB +will use one of these classes (0x30) to implement ibtracer (and the vendor +MAD option of ibping). + +Note that these are general service MADs and rely on the network being up. +If the network is not up, then DR SMPs must be used. There are a number of +separate SMP tools for this. + +The OpenIB vendor specific MAD agent will support the following attributes: +ClassPortInfo (0x0001) and SourceRoute (0x0010). There may be an additional +attribute (TBD) to support ibping but this can be done out of the same agent. + +Only the VendorGet method needs to be supported by this agent. No traps +are currently defined for this class. + +Although from the ibtracer client perspective, these vendor MADs are sent +on outgoing ports, it is the server (agent) which needs to validate the +incoming port. As a result of this, it is the expected incoming port +at the next hop which needs to be added to the SourceRoute attribute. +SourceRoute requests (Gets) and responses (GetResps) are exchanged +directly between the source node where the ibtracer command is initiated +and each hop along the way to the destination until the destination is +reached. As the hops to the destination are walked, the incoming ports are +added to the SourceRoute attribute and checked when the packet is received +by that hop that it did arrive on that port. If it did not arrive on that +port, an error is indicated in the status field (status 7). In either case, +the port it did arrive on is put in the SourceRoute attribute in the GetResp. + +One of DLID or DGID must be specified in the ibtracer invocation. +If DGID is specified, a PathRecord request is made to the SA +to obtain the DLID. Other than that, no SM or SA is involved with +ibtracer although the SM is needed to set up the forwarding tables. + +Once the DLID is obtained from either the command invoication or the SA, +a DR SMP packet is sent to the next hop to obtain the PortInfo attribute +to obtain the base LID for the next hop. A VendorGet(ClassPortInfo) is +then attempted to see if this management class is supported on that node. +If it is (a VendorGetResp is received), a VendorGet(SourceRoute) +to the next hop LID is attempted after updating the source route attribute +with the local port number from the returned PortInfo attribute. Upon +receipt of the VendorGet(SourceRoute), the receiving agent validates the +port number it is received on with the port number in the SourceRoute +attribute. It indicates failure when they do not match and in either case +the port is was received on is put back into the VendorGetResp(SourceRoute). + +If the next hop does not support this management class, this is indicated +(if -v is enabled) and the algorithm proceeds with the next hop. The +algorithm is terminated when the next hop LID is the DLID (factoring in +the LMC). + +Note that rather than doing much of this with DR SMPs directly, +these could be SA requests (using PortInfoRecords and LinkRecords, +or TraceRecords). Investigation would need to be done to validate +whether these SA attributes are supported by the various SMs +(although OpenSM is most important in terms of OpenIB). TraceRecords +are optional and are not believed to be currently supported. It can +be done with just PortInfoRecords and LinkRecords. + +Since vendor MADs are UD, there is a retransmission strategy (timeout/retry) +which have defaults but are settable on the command line. + +-v option displays entire path. Note that the incoming (rather than outgoing) +ports are displayed. Without -v specified, just success or failure is +displayed. + +Reversible paths are used for the responses. Note that the path from A to +B might not be the same from B to A so ibtracer needs to be initiated at +both ends if this is of interest. + +This tool cannot currently be used for multicast tracing. There are a +couple of reasons for this. Base switch port 0 does not support +multicast and it is not a requirement of enhanced switch port 0 +to support this so there would be more hop skipping. Also, the attribute +format would need to be enhanced for this as well as the client needing +to handle multiple responses to a single request. + + +SourceRoute attribute format + +Actual Incoming Port Number (valid on response) - 1 byte +Current Hop Count - 1 byte +Vector of Incoming Port Numbers (0-63) - 64 bytes + + +Outstanding Questions + +Should SL be supported rather than assume SL 0 ? + +Should GRH be supported (and tied to GID specification in command invocation) ? + +Is multicast tracing important ? diff --git a/contrib/ofed/management/doc/libibmad.txt b/contrib/ofed/management/doc/libibmad.txt new file mode 100644 index 000000000000..42a61d49f7c5 --- /dev/null +++ b/contrib/ofed/management/doc/libibmad.txt @@ -0,0 +1,687 @@ +libibmad: + +Overview: libibmad provides the following functionalities: + * common declarations: IB structures, fields, and enumerations + * general IB mad interface encapsulation (init port, registration, + etc.) + * IB mads marshaling and de-marshaling + * Reliable mad RPC mechanisms (solicited mads) + * Server side mad io functions (send, receive) + * General SMP support + * General SA (queries) support + * Port performance class support + * IB addresses resolution (path record queries) + * Fields parsing and dump functions + * Debugging support + +Model of operation: libibmad is designed to easy the implementation of MAD + client and server tools and applications. Mad clients (i.e. application + that do not reply to requests) should use the mad RPC mechanism. Mad + servers should use the send/receive mechanisms. Applications are + assumed to be single threaded, but some multiple threading support + is provided. Most IO mechanisms may be blocking. Currently no + explicit asynchronous support is implemented. + +Marshaling/De-marshaling model: libibmad handles two types of data - opaque + network data images and native host ordered fields. libibmad do + not define C structures to access MAD fields. Instead, it defines + a field structure for every separate field and implements a set + of conversion functions from the native types to the opaque + network image and back. The advantage of this approach is + that the marshaling/de-marshaling problems are transparent to most + of the application code resulting a clean, machine independent + code. Furthermore, even the marshaling/de-marshaling code itself + is extremely straight-forward due that fact that the library + automatically knows what marshaling/de-marshaling method it has + to apply to each field. The disadvantage of this approach is that + the marshaling/de-marshaling implementation itself is somehow less + efficient then manually crafted manipulations, but this seem a fair + tradeoff comparing to the simplicity and cleanness factors. + +Field dump functions: a side benefit of the marshaling/de-marshaling model + (see above), is that the library is aware to the size and the type + of each field and therefore is able to print out a human readable + representation of the field value. + + +Library objects: + +ib_field_t: IB field structure + +ib_dr_path_t: direct routed address structure + +ib_portid_t: (endpoint) address structure + +ib_attr_t: mad attribute and modifier + +ib_rpc_t: encapsulate information required for the RPC mechanism + +ib_rmpp_hdr_t: RMPP information structure (currently not supported) + +ib_sa_call_t: SA request structure + +ib_vendor_call_t: vendor specific mad structure + + +Mad RPC functions: + +madrpc_init: + +Synopsis: + void madrpc_init(char *dev_name, int dev_port, + int *mgmt_classes, int num_classes); + +Description: library main initialization function. Open the user mad port +specified by 'dev_name' and 'dev_port', and registers the application as mad +client for the 'num_classes' management classes specified in 'mgmt_classes' +array. This function must be called before any other call to the library. +Initialization errors cause this function to panic. + +madrpc: + +Synopsis: + void * madrpc(ib_rpc_t *rpc, ib_portid_t *dport, + void *payload, void *rcvdata); + +Description: Perform RPC to the destination port specified by 'dport' using +'rpc' parameters. If 'payload' in non-null, copy the payload buffer to the +outgoing packet, while if the 'rcvdata' is non-null, copy the received packet +payload to the 'rcvdata' buffer. Both buffer must be big enough to contain the +maximal mad data payload length. If in doubt, use 256 bytes sized buffers. +Return rcvdata pointer on success, and null on errors. + +madrpc_rmpp: + +Synopsis: + void * madrpc_rmpp(ib_rpc_t *rpc, ib_portid_t *dport, + ib_rmpp_hdr_t *rmpp, void *data); + +Description: Same as madrpc but supports also RMPP mads. + +Bugs: + RMPP is not supported yet. + +madrpc_portid: + +Synopsis: + int madrpc_portid(void); + +Description: return the portid the library uses. See libibumad:portid for +details. + +See also: + libibumad:umad_open_port + +madrpc_set_retries: + +Synopsis: + int madrpc_set_retries(int retries); + +Description: Change the maximal number of retries attempted by the library +before it times out to 'retries'. Non-positive values are ignored. Return +the current retries count. + +madrpc_set_timeout: + +Synopsis: + int madrpc_set_timeout(int timeout); + +Description: Change the default timeout value used for solicited mads to +'timeout' milliseconds. Return 0 on success, -1 on errors. Note that the +'timeout' value is used per retry, meaning the total timeout value is acctualy +'timeout' * max_retries (see madrpc_set_retries()). + +madrpc_save_mad: + +Synopsis: + void madrpc_save_mad(void *madbuf, int len); + +Description: Save the next replied mad image in 'madbuf', copying maximux 'len' +bytes. In fact, this function snoop a single incoming mad. To snoop several +packets, this function has to be called repeatedly after each RPC operation. + +Bugs: + Not applicable to mad_receive + +madrpc_lock: + +Synopsis: + void madrpc_lock(void); + +Description: Locks the mad RPC mechanism until madrpc_unlock() is called. Calls +to this function while the RPC mechanism is already locked cause the calling +process to be blocked until madrpc_unlock(). This function should be used +only by multiple-threaded applications. + +See also: + madrpc_unlock + +madrpc_unlock: + +Synopsis: + void madrpc_unlock(void); + +Description: Unlock the mad RPC mechanism. See madrpc_lock() for details. + +madrpc_show_errors: + +Synopsis: + void madrpc_show_errors(int set); + +Description: If 'set' is non-null, print out warning messages on some error +events: retries, timeouts, replies with error status, etc. Zero 'set' value +causes the library to be quiet. + +ib_mad_dump_fn: + +Synopsis: + typedef void (ib_mad_dump_fn)(char *buf, int bufsz, + void *val, int valsz); + +Description: Dump the value given in 'val' that have 'valsz' size (in bytes), +to the specified 'buf' buffer and limit the output to 'bufsz' bytes. The +output is expected to be human readable. + + +Management classes' registration functions: + +Synopsis: + int mad_register_client(int mgmt); + +Description: Register the application as a client of the specified +'mgmt'. Return a non-negative agentid on success and -1 on errors. +Note that madrpc_init provides more efficient method to register to several +classes. + +See also: + madrpc_init + +mad_register_server: + +Synopsis: + int mad_register_server(int mgmt, uint32 method_mask[4], + uint32 class_oui); + +Description: Register the appication as the default responder of the class +methods specified by 'mngt' and 'method_mask' bitmap. Vendor classes in +range 2 require also non-zero 'class_oui'. Return a non-negative agentid on +success and -1 on errors. + +mad_class_agent: + +Synopsis: + int mad_class_agent(int mgmt); + +Description: Map the given 'mgmt' class to agentid of the agent handling +this class. Return non-negative agentid or -1 if the specified class is +not registered. + +Synopsis: + int mad_agent_class(int agent); + +Description: Map the given 'agent' id to the management class registered +for it. Return positive class value on success, 0 if no management class +is registered for this agentid, or -1 if the agent id is invalid. + +MAD client functions: + +ib_vendor_call: + +Synopsis: + uint8 *ib_vendor_call(void *data, ib_portid_t *dport, + ib_vendor_call_t *call); + +Description: Perform vendor specific RPC specified by 'call' to the destination +port specified by 'dport'. The buffer pointed by 'data' is used as payload +for the outgoing packet, and the received packet payload is copied back +to the 'data' buffer. The 'data' buffer must be big enough to contain the +replied data. Note that if the 'call' method is not get/set/trap, then a +simple send operation is performed and the function returns immediately. +Return the 'data' pointer on success, or null on errors. + +mad_is_vendor_range1: + +Synopsis: + int mad_is_vendor_range1(int mgmt); + +Description: return non-zero value if 'mgmt' is in the vendor specific range +1, and zero otherwise. + +mad_is_vendor_range2: + +Synopsis: + int mad_is_vendor_range2(int mgmt); + +Description: return non-zero value if 'mgmt' is in the vendor specific range +2, and zero otherwise. + +smp_query: + +Synopsis: + uint8 * smp_query(void *buf, ib_portid_t *dport, + uint attrid, uint mod, uint timeout); + +Description: Perform the SMP query (get) RPC specified by 'attrid' and 'mod' +to the destination port 'dport'. The data in 'buf' is used as the outgoing +SMP payload, and the replied packet's data is copied back to 'buf'. The +buffer pointed by 'buf' should be big enough to contain the reply - i.e. at +least 64 bytes. If timeout is non-zero then it is used as the query's +timeout. Otherwise the default timeout value is used. + +See also: + madrpc_set_timeout + +smp_set: + +Synopsis: + uint8 * smp_set(void *buf, ib_portid_t *dport, + uint attrid, uint mod, uint timeout); + +Description: Same as smp_query() but a set method is used instead of get. +Note that SMP sets may lead to many (desired or less desired) results. +Specifically it may cause the destination port to malfunction, confuse the +current master SM, and lead to non-functioning network. Do not use this +function unless you really know what you are doing. + +See also: + smp_set + +Bugs: + very dangerous. Shouldn't be allowed to non-privileged applications + +Synopsis: + uint8 * safe_smp_query(void *rcvbuf, ib_portid_t *portid, + uint attrid, uint mod, uint timeout) + +Description: Thread-safe version of smp_query(). + +See also: + smp_query + +safe_smp_set: + +Synopsis: + uint8 * safe_smp_set(void *rcvbuf, ib_portid_t *portid, + uint attrid, uint mod, uint timeout) + +Description: Thread-safe version of smp_set(). + +See also: + smp_set + +sa_call: + +Synopsis: + uint8 * sa_call(void *data, ib_portid_t *dport, + ib_sa_call_t *sa, uint timeout); + +Description: Perform SA RPC specified by 'sa' to the specified port +'dport'. The 'data' buffer is used as the outgoing mad payload, and the +returned packet's payload is copied back to the 'data' buffer. The buffer +must be big enough to contain the response. If timeout is non-zero then it +is used as the query's timeout. Otherwise the default timeout value is used. +Return 'data' pointer on success, and null on errors. + +See also: + smp_query, smp_set_timeout + +Bugs: + RMPP support is missing, not all methods are supported + +ib_path_query: + +Synopsis: + int ib_path_query(ib_gid_t srcgid, ib_gid_t destgid, + ib_portid_t *sm_id, void *buf); + +Description: Perform a simple path record get query using the 'srcgid' and the +'destgid' arguments. The query is targeted to the SM specified by 'sm_id'. +Copy the query's result to the buffer 'buf' and returns the destination +LID. If the query fails return -1. + + +Synopsis: + uint8 * safe_sa_call(void *rcvbuf, ib_portid_t *portid, + ib_sa_call_t *sa, uint timeout); + +Description: Thread-safe version of sa_call(). + +See also + sa_call + +port_performance_query: + +Synopsis: + uint8 *port_performance_query(void *rcvbuf, ib_portid_t *dport, + int portnum, uint timeout); + +Description: Perform a port counters get query to the destination port(s) +specified by 'dport' and portnum. Use portnum of 0xff to get the aggregated +counters of the entire node. The query result is copied to the 'rcvbuf' that +must be big enough to contain the response. If timeout is non-zero then it +is used as the query's timeout. Otherwise the default timeout value is used. +Return 'rcvbuf' pointer on success, and null on errors. + +port_performance_reset: + +Synopsis: + uint8 *port_performance_reset(void *rcvbuf, ib_portid_t *dest, + int portnum, uint mask, uint timeout); + +Description: Perform a port counters set operation to clear the counters of the +destination port(s) specified by 'dport' and 'portnum'. the 'mask' bit-field +is used to specify which counters are cleared. Use 'portnum' of 0xff to clear +the aggregated counters of the entire node. The operation result is copied +to the 'rcvbuf' that must be big enough to contain the response. If timeout +is non-zero then it is used as the query's timeout. Otherwise the default +timeout value is used. Return 'rcvbuf' pointer on success, and null on errors. + +Mad server functions: + +mad_send: + +Synopsis: + int mad_send(ib_rpc_t *rpc, ib_portid_t *dport, + ib_rmpp_hdr_t *rmpp, void *data); + +Description: Send a single mad to the destination port specified by +'dport'. The mad is build using 'rpc' and rmpp arguments and the payload +'data'. Note that this function operates similarly to send part of madrpc +and madrpc_rmpp returns immediately after the send without retrying or +waiting for the response (if any). Note that if solicited mads are send +using this function, it is the caller responsibility to handle retries and +timeouts. Return zero on success, -1 on errors. + +See also: + madrpc, madrpc_rmpp + +mad_receive: + +Synopsis: + void * mad_receive(void *umad, int timeout_ms); + +Description: Wait 'timeout_ms' milliseconds for a packet to be received. Once +a packet is received, it is copied to the specified 'umad' buffer allocated +by mad_alloc() or to a internally allocated umad buffer if 'umad' is null. In +any case it is the caller responsibility to free the received packet using +mad_free(). Negative 'timeout_ms' value makes the function to block until +a packet is received. Zero 'timeout_ms' guarantees non blocking read, +i.e. either the function returns immediately with new received packet, +or it will return with error. Return a pointer to the received umad buffer +or null in case of errors. + +mad_respond: + +Synopsis: + int mad_respond(void *umad, ib_portid_t *portid, uint32 rstatus); + +Description: Respond to the request mad specified by 'umad'. Send the +response mad to the port specified by 'portid' or the original caller of +'umad' if 'portid' is null. The status 'rstatus' is used to fill the mad +status field. The following outgoing fields are set by the function using the +original 'umad' fields: mgt_class, method, attribute_id, attribute_modifier, +SA attribute offset, vendor class OUI, mad transaction id (only the relevant +fields are set). Return zero on success, -1 on errors. + +mad_alloc: + +Synopsis: + void * mad_alloc(void); + +Description: Allocate a user mad buffer. This buffer should be de-allocated +using mad_free(). The mad buffer (umad) should be used be used as opaque. +Return a pointer to the buffer, or null if the allocation fails. + +See also: + mad_free + +Synopsis: + void mad_free(void *umad); + +Description: Free a umad buffer previously allocated by mad_alloc + +See also: + mad_alloc + +Address resolving functions: + +ib_resolve_smlid: + +Synopsis: + int ib_resolve_smlid(ib_portid_t *sm_id, int timeout); + +Description: Resolve the current SM address (LID) and copy it to +'sm_id'. Internally this function queries the local port for the smlid +field. 'timeout' is used similarly to madrpc(). Return zero on success, +-1 on errors. + +ib_resolve_guid: + +Synopsis: + int ib_resolve_guid(ib_portid_t *portid, uint64_t *guid, + ib_portid_t *sm_id, int timeout); + +Description: Resolve the given 'guid' to find the port lid and set 'portid' +accordingly. The resolving process is done by sending a path record query +to the SM using the specified address 'sm_id'. If the 'sm_id' is null, the +SM address is resolved using ib_resove_smlid(). 'timeout' is used similary +to madrpc(). Return zero on success, -1 on errors. + +See also: + ib_resolve_smlid, ib_path_query, madrpc + +ib_resolve_portid_str: + +Synopsis: + int ib_resolve_portid_str(ib_portid_t *portid, char *addr_str, + int dest_type, ib_portid_t *sm_id); + +Description: Resolve the port address specified by the string 'addr_str' +and the type 'dest_type' and set 'portid' accordingly. If the dest_type +is IB_DEST_GUID, then a path record query is sent to the SM specified by +'sm_id' or to the SM address found by ib_resolve_smlid() if sm_id is null. The +following string formats are supported: + Type String + IB_DEST_LID: (Decimal/Hex) integer (see strtoul for details) + IB_DEST_DRPATH out-ports vector "p1,p2,p3" (e.g. "0,1,6,5,20,1") + IB_DEST_GUID: 64 bit integer (see strtoll for details) +Return zero on success, -1 on errors. + +See also: + str2drpath, ib_resolve_smlid, ib_resolve_guid + +ib_resolve_self: + +Synopsis: + int ib_resolve_self(ib_portid_t *portid, int *portnum, + ib_gid_t *gid); + +Description: Resolve the local port address and set 'portid', 'portnum' and +'gid' accordingly. The resolve process is done by issuing a NodeInfo and +PortInfo to the local port. Return zero on success, -1 on errors. + +Port ID helper functions: + +portid2str: + +Synopsis: + char * portid2str(ib_portid_t *portid); + +Description: Return a string representation of the specified 'portid'. + +Bugs: + uses a static string buffer and therefore not thread safe. + +portid2portnum: + +Synopsis: + int portid2portnum(ib_portid_t *portid); + +Description: Return the port number of the destination port specified by +the direct routed address 'portid'. Return -1 if the portid is not directed +route address, and 0 if it is local port address (vector [0]). + +str2drpath: + +Synopsis: + int str2drpath(ib_dr_path_t *path, char *routepath, + int drslid, int drdlid); + +Description: Parse the 'routepath' string, and use the given 'drslid' and +'drdlid' set the given 'path'. Return path count or -1 on invalid string. + +ib_portid_set: + +Synopsis: + int ib_portid_set(ib_portid_t *portid, int lid, int qp, int qkey); + +Description: Set the given 'portid' fields using the 'lid', 'qp' and 'qkey' +arguments. + +Mad fields manipulation functions: + +mad_get_field: + +Synopsis: + uint32 mad_get_field(void *buf, int base_offset, int field); + +Description: Return the value of 'field' from the mad buffer specified by +'buf' and the offset 'base_offset' within. The result is in host order. + +See also: + ib_mad_f fields array, model of operation + +mad_set_field: + +Synopsis: + void mad_set_field(void *buf, int base_offs, int field, uint32 val); + +Description: Set the value of 'field' in the mad buffer specified by 'buf' +and the offset 'base_offset' within, using host ordered 'val'. + +See also: + ib_mad_f fields array, model of operation + +mad_get_field64: + +Synopsis: + uint64 mad_get_field64(void *buf, int base_offs, int field); + +Description: Same as mad_get_field, but for 64 bit fields. + +mad_set_field64: + +Synopsis: + void mad_set_field64(void *buf, int base_offs, + int field, uint64 val); + +Description: Same as mad_set_field, but for 64 bit fields. + +mad_set_array: + +Synopsis: + void mad_set_array(void *buf, int base_offs, int field, void *val); + +Description: Same as mad_get_field, but for opaque byte arrays. + +mad_get_array: + +Synopsis: + void mad_get_array(void *buf, int base_offs, int field, void *val); + +Description: Same as mad_set_field, but for opaque byte arrays. + +mad_decode_field: + +Synopsis: + void mad_decode_field(uint8 *buf, int field, void *val); + +Description: Decode 'field' within the mad buffer specified by 'buf' and +return it in 'val'. The result is in host order. Note that the buffer pointer +by 'val' must be big enough to contain the value. + +See also: + ib_mad_f fields array, model of operation + +mad_encode_field: + +Synopsis: + void mad_encode_field(uint8 *buf, int field, void *val); + +Description: Encode the 'field' within the mad buffer specified by 'buf' +using the host ordered value 'val'. + +See also: + ib_mad_f fields array, model of operation + +mad_encode: + +Synopsis: + void * mad_encode(void *buf, ib_rpc_t *rpc, + ib_dr_path_t *drpath, void *data); +Description: Encode an outgoing mad headers in 'buf' using the given 'rpc', +the optional direct routed address 'drpath', and the optional payload +'data'. Return a pointer to the first byte after the mad image, or null +on errors. + +mad_trid: + +Synopsis: + uint64 mad_trid(void); + +Description: Set the given 'portid' fields using the 'lid', 'qp' and 'qkey' + +mad_build_pkt: + +Synopsis: + int mad_build_pkt(void *umad, ib_rpc_t *rpc, ib_portid_t *dport, + ib_rmpp_hdr_t *rmpp, void *data); + +Description: Encode a mad in the buffer 'umad' given the structures 'rpc', +'dport', the optional 'rmpp' structure and the payload 'data'. Return +number of encode bytes or a negative number if failed. + +Dump functions: + +mad_print_field: + +Synopsis: + int mad_print_field(int field, char *name, void *val); + +Description: Print a human readable format of the 'field' given the value +'val' to the standard output. If 'name' is non-null, it is printed as the +field name. Otherwise the default field name is used. Return the number of +printed bytes. + +See also: + ib_mad_f fields array, model of operation + +mad_dump_field: + +Synopsis: + char * mad_dump_field(int field, char *buf, int bufsz, void *val); + +Description: Print a human readable format of the 'field' given the value +'val' to the given buffer 'buf'. The default field name is used. No more than +'bufsz' bytes are printed. Return the number of printed bytes. + +mad_dump_val: + +Synopsis: + char * mad_dump_val(int field, char *buf, int bufsz, void *val); + +Description: Same as mad_print_field, but only the field value is printed. + +Debugging support: + +ibdebug: + +Synopsis: + extern int ibdebug; + +Description: Control the library debugging level. The following levels +are supported: + 0 - no debugging + 1 - print debugging information + 2 - as level 1 but also xdump the umad IO + diff --git a/contrib/ofed/management/doc/libibumad.txt b/contrib/ofed/management/doc/libibumad.txt new file mode 100644 index 000000000000..76809f7c1b69 --- /dev/null +++ b/contrib/ofed/management/doc/libibumad.txt @@ -0,0 +1,392 @@ +libibumad: + +Overview: libibumad provides the following functionality: + * Provide information about the IB devices installed. This includes + list of IB devices names, list of port, device and port + attributes. + * Basic user mode mad functions: open/close port, + register/unregister, send/receive/poll mad, etc. + * Umad packet helper functions. + * debugging support. + + +Library objects: + +umad_ca: encapsulate an IB device. Identified by CA_NAME. + +umad_port: encapsulate an IB port within an IB device. Identified by CA_NAME + and port number. + +ib_umad_addr: IB destination address structure. + +portid (int): opened port handle. + +agentid (int): mad multiplexing agent handle. + + +Module management functions: + +umad_init: + +Synopsis: + int umad_init(void) + +Description: library main initialization function. Must be called before any +other call to the library. Return zero on success, -1 if the infiniband mad +class can't be opened, or the abi version doesn't match. + +umad_done: + +Synopsis: + int umad_done(void) + +Description: library main destruction function. library should not be called after calling this function. Return zero on success, -1 on errors. + + +IB devices and ports information functions: + +umad_get_cas_names: + +Synopsis: + int umad_get_cas_names(char cas[][UMAD_CA_NAME_LEN], int max); + +Description: Fill 'cas' array with up to 'max' local ib devices (CAs) names. +The return value is the number of entries actually filled, or -1 on errors. + +umad_get_ca_portguids: + +Synopsis: + int umad_get_ca_portguids(char *ca_name, uint64_t *portguids, + int max); + +Description: Fill 'portguids' array with up to 'max' port GUIDs belonging the +specified IB device 'ca_name', or to the default ib device if 'ca_name' is null. +The return value is the number of entries actually filled, or -1 on errors. + +umad_get_ca: + +Synopsis: + int umad_get_ca(char *ca_name, umad_ca_t *ca); + +Description: Fill 'ca' structure with the ib device attributes specified by +'ca_name', or with the default ib device attributes if 'ca_name' is null. +Return zero on success, -1 on error. +Note that the library allocates memory for some of the 'ca' fields, and +therefore umad_release_ca() should be used to free these fields before the +'ca' structure can be de-allocated. + +See also: + umad_release_ca + +umad_release_ca: + +Synopsis: + int umad_release_ca(umad_ca_t *ca); + +Description: de-allocated any fields within 'ca' that were allocated by +umad_get_ca(). Return zero on success, -1 on error. + +See also: + umad_get_ca + +umad_get_port: + +Synopsis: + int umad_get_port(char *ca_name, int portnum, umad_port_t *port); + +Description: Fill the 'port' structure with the specified ib port attributes +specified by 'ca_name' and 'portnum', or the default port if 'ca_name' is null +and 'portnum' is zero. If only one of the 'ca_name' and 'portnum' are specified, +the other is used as a filter. For example, passing a null ca_name and 2 for the +portnum means - get a port from any of the local ib devices, as long as it is +the second port. Return zero on success, -1 on error. +Note that the library may use some reference scheme to support port caching +therefore umad_release_port() should be called before the 'port' structure can +be deallocated. + +See also: + umad_release_port + +umad_release_port: + +Synopsis: + int umad_release_port(umad_port_t *port); + +Description: Notify the library that the 'port' that was filled by +umad_get_port() is not required anymore. Return zero on success, -1 on error. + +See also: + umad_get_port + + +Port oriented functions: + +umad_open_port: + +Synopsis: + int umad_open_port(char *ca_name, int portnum); + +Description: Open the port specified by 'ca_name' and 'portnum' for umad IO. +The port is selected by the library if not all parameters are provided (see +umad_get_port() for details). Return non-negative portid handle (int) or +negative value on errors. + +Errors: + -ENODEV ib device can't be resolved + -EINVAL port is not valid (bad 'portnum' or no umad device) + -EIO umad device for this port can't be opened + +See also: + umad_get_port + +umad_close_port: + +Synopsis: + int umad_close_port(int portid); + +Description: Close the port specified by the handle 'portid'. Return 0 on +success and -EINVAL if the portid is not a handle to a valid (open) port. + +See also: + umad_open_port + +Register/unregister functions: + +umad_register: + +Synopsis: + int umad_register(int portid, int mgmt_class, + int mgmt_version, uint32_t method_mask[4]); + +Description: Register to the specified management class and version in the port +specified by the 'portid' handle. If 'method_mask' array is provided, the caller +is registered as a replier (server) for the methods having their coresponding +bit on in the 'method_mask'. If 'method_mask' is null, the caller is registered +as a mad client, meaning that it can only receive replies on mads it sent +(solicited mads). +Return non-negative agent id number on success, and a negative value on errors. + +Errors: + -EINVAL invalid port handle + -EPERM registration failed + +umad_register_oui: + +Synopsis: + int umad_register_oui(int portid, int mgmt_class, uint8_t +rmpp_version, + uint8 oui[3], uint32 method_mask[4]); + +Description: Register to the specified vendor class range 2, the specified +oui, and whether rmpp is being used. Otherwise operate similarly to +umad_register(). + +Errors: + -EINVAL invalid port handle or class is not in the vendor class 2 range + -EPERM registration failed + +umad_unregister: + +Synopsis: + int umad_unregister(int portid, int agentid); + +Description: Unregister the specified 'agentid' previously registered using +umad_register() or umad_register_oui(). Returns 0 on success and negative +value on errors. + +Errors: + -EINVAL invalid port handle or agentid + * (kernel error codes) + + +Port IO functions: + +umad_send: + +Synopsis: + int umad_send(int portid, int agentid, void *umad, + int timeout_ms, int retries); + +Description: Send the specified 'umad' buffer from the port specified by +'portid' and using the agent specified by 'agentid'. 'timeout_ms' controls +solicited mads behavior as follows: zero value means not solicited. Positive +value makes the kernel indicate timeout if the reply is not received within the +specified value, and return the original buffer in the read channel with +the status field set (non zero). Negative 'timeout_ms' value makes the kernel +wait forever for the reply. Returns 0 on success and negative value on errors. + +Errors: + -EINVAL invalid port handle or agentid + -EIO send operation failed + +umad_recv: + +Synopsis: + int umad_recv(int portid, void *umad, int timeout_ms); + +Description: Wait up to 'timeout_ms' for a packet to be received from the +port specified by 'portid'. The packet is copied to the 'umad' buffer. +Negative 'timeout_ms' value makes the function block until a packet +is received. Zero 'timeout_ms' indicates a non blocking read. +Return non negative receiving agentid on success and negative value on errors. + +Errors: + -EINVAL invalid port handle or agentid + -EIO receive operation failed + -EWOULDBLOCK non blocking read can't be fulfilled + +umad_poll: + +Synopsis: + int umad_poll(int portid, int timeout_ms); + +Description: Wait up to 'timeout_ms' for a packet to be received from the +port specified by 'portid'. Once a packet is ready to be read the function +returns 0 after that the packet can be read using umad_recv(). Otherwise +-ETIMEDOUT is returned. Note that successfully polling a port does not guarantee +that the following umad_recv will be non blocking when several threads are using +the same port. Instead, use timeout_ms parameter of zero to umad_recv to ensure +a non-blocking read. + +Errors: + -EINVAL invalid port handle or agentid + -ETIMEDOUT poll operation timed out + -EIO poll operation failed + +umad_get_fd: + +Synopsis: + int umad_get_fd(int portid) + +Description: Return umad fd for port specified by 'portid'. Returns fd +for port or -EINVAL if portid is invalid. + +Errors: + -EINVAL invalid port handle + + +umad helper functions: + +umad_get_mad: + +Synopsis: + void * umad_get_mad(void *umad); + +Description: Return a pointer to the mad image within the 'umad' buffer. + +umad_size: + +Synopsis: + size_t umad_size(void); + +Description: Return the size of umad buffer (in bytes). + +umad_status: + +Synopsis: + int umad_status(void *umad); + +Description: Return the internal 'umad' status field. After a packet is +received, a non zero status means the packet had a send-timeout +indication. Otherwise, it is a valid packet. + +umad_get_mad_addr: + +Synopsis: + ib_mad_addr_t *umad_get_mad_addr(void *umad); + +Description: Return a pointer to the ib_mad_addr struct within 'umad' buffer. + +umad_set_grh_net: + +Synopsis: + int umad_set_grh_net(void *umad, void *grh); + +Description: set the GRH fields within the 'umad' buffer. The given 'grh' +fields are expected to be in network order. Returns 0 on success, -1 on errors. + +BUGS: + not implemented. + +umad_set_grh: + +Synopsis: + int umad_set_grh(void *umad, void *grh); + +Description: set the GRH fields within the 'umad' buffer. The given 'grh' +fields are expected to be in host order. Returns 0 on success, -1 on errors. + +umad_set_addr_net: + +Synopsis: + int umad_set_addr_net(void *umad, int dlid, int dqp, + int sl, int qkey); + +Description: Set the mad address fields within the 'umad' buffer using +the given network ordered fields. Return 0 on success, -1 on errors. + +umad_set_addr: + +Synopsis: + int umad_set_addr(void *umad, int dlid, int dqp, int sl, int qkey); + +Description: Set the mad address fields within the 'umad' buffer using +the given host ordered fields. Return 0 on success, -1 on errors. + +umad_set_pkey: + +Synopsis: + int umad_set_pkey(void *umad, int pkey_index); + +Description: Set the pkey within the 'umad' buffer. Return 0 on success, +-1 on errors. + +BUGS: + not implemented. + +umad_alloc: + +Synopsis: + void *umad_alloc(int num); + +Description: Allocate memory for 'num' umad buffers array. Return null if +out of memory. + +umad_free: + +Synopsis: + void umad_free(void *umad); + +Description: Deallocate memory previously allocated with uamd_alloc(). + +See also: + umad_alloc + + +Debugging support functions: + +umad_debug: + +Synopsis: + int umad_debug(int level); + +Description: Set the library internal debugging level to 'level'. The following +debugging levels are supported: 0 - no debugging (the default), +1 - basic debugging information, 2 - verbose debugging. Negative values are +ignored. Returns the new level. Note that the current debugging level can +be queried by passing negative values. + +umad_addr_dump: + +Synopsis: + void umad_addr_dump(ib_mad_addr_t *addr); + +Description: Dump the given 'addr' structure to the stderr. + +umad_dump: + +Synopsis: + void umad_dump(void *umad); + +Description: Dump the given 'umad' buffer to the stderr. + diff --git a/contrib/ofed/management/gen_chlog.sh b/contrib/ofed/management/gen_chlog.sh new file mode 100755 index 000000000000..bd1dbd80b835 --- /dev/null +++ b/contrib/ofed/management/gen_chlog.sh @@ -0,0 +1,74 @@ +#!/bin/sh + +usage() +{ + echo "Usage: $0 [--spec] " + exit 2 +} + +test -z "$1" && usage + +if [ "$1" = "--spec" ] ; then + spec_format=1 + shift + test -z "$1" && usage +fi + +TARGET=$1 + +GIT_DIR=`git rev-parse --git-dir 2>/dev/null` + +test -z "$GIT_DIR" && usage + + +export GIT_DIR +export GIT_PAGER="" +export PAGER="" + + +mkchlog() +{ + target=$1 + format=$2 + + prev_tag="" + + for tag in `git tag -l ${target}-'*'` ; do + obj=`git cat-file tag $tag | awk '/^object /{print $2}'` + base=`git merge-base $obj HEAD` + if [ -z "$base" -o "$base" != $obj ] ; then + continue + fi + all_vers="$prev_tag$tag $all_vers" + prev_tag=$tag.. + done + + if [ -z "$prev_tag" ] ; then + all_vers=HEAD + else + all_vers="${prev_tag}HEAD $all_vers" + fi + + for ver in $all_vers ; do + log_out=`git log $ver -- $target` + if [ -z "$log_out" ] ; then + continue + fi + ver_name=`echo $ver | sed -e 's/^.*\.\.//'` + echo "" + echo "** Version: $ver_name" + echo "" + git log --no-merges "${format}" $ver -- $target + prev_t=$tag.. + done +} + + +if [ -z "$spec_format" ] ; then + mkchlog $TARGET --pretty=format:"%ad %an%n%H%n%n* %s%n" \ + | sed -e 's/^\* /\t* /' +else + echo "%changelog" + mkchlog $TARGET --pretty=format:"- %ad %an: %s" + echo "" +fi diff --git a/contrib/ofed/management/gen_ver.sh b/contrib/ofed/management/gen_ver.sh new file mode 100755 index 000000000000..93882d456663 --- /dev/null +++ b/contrib/ofed/management/gen_ver.sh @@ -0,0 +1,38 @@ +#!/bin/sh +# +# This generates a version string which includes recent version as +# specified in correspondent sub project's configure.in file, plus +# git revision abbreviation in the case if sub-project HEAD is different +# from recent tag, plus "-dirty" suffix if local uncommitted changes are +# in the sub project tree. +# + +usage() +{ + echo "Usage: $0 " + exit 2 +} + +test -z "$1" && usage + +package=$1 + +cd `dirname $0` + +conf_file=$package/configure.in +version=`cat $conf_file | sed -ne '/AC_INIT.*'$package'.*/s/^AC_INIT.*'$package', \(.*\),.*$/\1/p'` + +git diff --quiet $package-$version..HEAD -- $package > /dev/null 2>&1 +if [ $? -eq 1 ] ; then + abbr=`git rev-parse --short --verify HEAD 2>/dev/null` + if [ ! -z "$abbr" ] ; then + version="${version}_${abbr}" + fi +fi + +git diff-index --quiet HEAD -- $package > /dev/null 2>&1 +if [ $? -eq 1 ] ; then + version="${version}_dirty" +fi + +echo $version diff --git a/contrib/ofed/management/infiniband-diags/COPYING b/contrib/ofed/management/infiniband-diags/COPYING new file mode 100644 index 000000000000..a0177289d0d6 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/COPYING @@ -0,0 +1,384 @@ +This software with the exception of OpenSM is available to you +under a choice of one of two licenses. You may chose to be +licensed under the terms of the the OpenIB.org BSD license or +the GNU General Public License (GPL) Version 2, both included +below. + +OpenSM is licensed under either GNU General Public License (GPL) +Version 2, or Intel BSD + Patent license. See OpenSM for the +specific language for the latter licensing terms. + + +Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + +================================================================== + + OpenIB.org BSD license + +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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +================================================================== + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/ofed/management/infiniband-diags/ChangeLog b/contrib/ofed/management/infiniband-diags/ChangeLog new file mode 100644 index 000000000000..6add52adf790 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/ChangeLog @@ -0,0 +1,470 @@ +2007-08-09 Ira Weiny + + * scripts/set_mthca_nodedesc.sh: change to set_nodedesc.sh + * scripts/set_mthca_nodedesc.sh: attempt to set nodedesc on all + HCA's found in sysfs + +2007-07-10 Hal Rosenstock + + * 1.3.1 release of infiniband-diags + +2007-06-20 Hal Rosenstock + + * src/ibaddr.c, src/ibping.c, src/ibportstate.c, + src/ibsysstat.c, src/perfquery.c, src/sminfo.c, + src/smpquery.c, src/vendstat.c, Makefile.am: + Use diag common code ib_error routine + +2007-06-18 Hal Rosenstock + + * man/ibaddr.8: Improve description + +2007-06-04 Hal Rosenstock + + * include/ibnetdiscover.h, src/ibnetdiscover.c, + man/ibnetdiscover.8: Add link width and speed to topology + file output + +2007-06-02 Hal Rosenstock + + * man/ibnetdiscover.8: Add topology file format section + +2007-06-01 Hal Rosenstock + + * man/ibnetdiscover.8: Add grouping information + + * include/ibnetdiscover.h, src/ibnetdiscover.c: Fix + list by nodetype operations + + * src/ibnetdiscover.c, man/ibnetdiscover.8: Add support + for -R(outer_list) + + * Makefile.am: Add ibidsverify + + * scripts/ibidsverify.pl, man/ibidsverify.8: Add script + and man page for ibidsverify + +2007-05-31 Hal Rosenstock + + * man/ibprintca.8, man/ibprintswitch.8, man/ibprintrt.8: + Add description of list capability + + * Makefile.am, configure.in: Add ibdatacounters + + * scripts/ibdatacounters.in, man/ibdatacounters.8: Add + script and man page for subnet wide data counters + + * configure.in: Change IBSCRIPTPATH from bindir to sbindir + +2007-05-30 Hal Rosenstock + + * Makefile.am, configure.in: Add ibrouters and ibprintrt.pl + + * scripts/ibrouters.in, scripts/ibprintrt.pl, + man/ibrouters.8, man/ibprintrt.8: Add scripts and man pages + for display of IB routers + + * scripts/ibqueryerrors.pl: Add GUID to output line for ports + + * scripts/ibcheckerrs.in, scripts/ibcheckport.in, + scripts/ibcheckportstate.in, scripts/ibcheckportwidth.in, + scripts/ibdatacounts.in: Add lid and port into verbose output + + * scripts/ibcheckerrs.in, scripts/ibcheckport.in, + scripts/ibdatacounts.in: Change portnum to port in output + + * Makefile.am, configure.in: Add ibdatacounts + + * scripts/ibdatacounts.in, man/ibdatacounts.8: Add script + to display only data counters and associated man page + +2007-05-26 Hal Rosenstock + + * scripts/IBswcountlimits.pm: Fix node description parsing + for switches + + * scripts/iblinkinfo.pl: Add peer port link width and speed + validation + +2007-05-25 Hal Rosenstock + + * scripts/IBswcountlimits.pm: Add support for routers + + * scripts/iblinkinfo.pl: Display remote LID with peer port info + + * scripts/IBswcountlimits.pm: Add support for rem_lid in + get_link_ends subroutine + + * src/ibportstate.c: Handle peer ports at 1x that + should be wider and 2.5 Gbps that should be faster + + * src/ibportstate.c: Add LinkSpeed/Width related components + to output + +2007-05-24 Hal Rosenstock + + * scripts/ibprintca.pl: Add support for routers + +2007-05-23 Hal Rosenstock + + * scripts/ibcheckerrors.in, scripts/ibchecknet.in, + scripts/ibcheckstate.in, scripts/ibcheckwidth.in, + scripts/ibclearcounters.in, scripts/ibclearerrors.in, + scripts/ibfindnodesusing.in, scripts/IBswcountlimits.pm: + Add support for routers + +2007-05-09 Hal Rosenstock + + * src/grouping.c: Eliminate conditional compilation + based on WORDSIZE + +2007-05-08 Hal Rosenstock + + * src/ibnetdiscover.c: Bumped build version + + * include/grouping.h, src/grouping.c: Added support + for ISR2012 and ISR2004 + +2007-04-27 Ira K. Weiny + + * scripts/IBswcountlimits.pm, scripts/ibfindnodesusing.pl, + scripts/ibprintca.pl, scripts/ibprintswitch.pl, + scripts/ibqueryerrors.pl, scripts/ibswportwatch.pl: + Remove all uses of "/tmp" from perl diags + +2007-04-14 Albert L. Chu + + * src/saquery.c, man/saquery.8: Add switch map support + (for -O and -U options) + + * man/ibtracert.8: Improve man page formatting + +2007-04-04 Hal Rosenstock + + * src/saquery.c, man/saquery.8: Add support for isSMdisabled + into -s query + +2007-04-02 Albert L. Chu + + * src/saquery.c, man/saquery.8: Add get name queries (-O and -U) + + * src/saquery.c: Add name input checks + +2007-03-29 Hal Rosenstock + + * man/perfquery.8: Add note on Data components being octets + divided by 4 rather than just octets + + * scripts/IBswcountlimits.pm, scripts/ibcheckerrs.in: Changed + due to libibmad change (Xmt/RcvBytes now being Xmt/RcvData) + +2007-03-29 Hal Rosenstock + + * 1.3.0 release of openib-diags + +2007-03-21 Albert L. Chu + + * scripts/IBswcountlimits.pm: Add some extra debug information + +2007-03-21 Hal Rosenstock + + * src/ibtracert.c: Send normal output to stdout rather than stderr + + * src/ibdiag_common.c: Don't truncate NodeDescriptions with + ctl characters + +2007=03-20 Hal Rosenstock + + * src/ibnetdiscover.c: Chassis 0 is not a chassis + Caused Cisco SFS7000 to be reported as a chassis + +2007-03-15 Hal Rosenstock + + * src/smpquery.c: Modified guid_info to not use port number + and not query unneeded SM attributes; also added guid to + operations supported in help + + * man/smpquery.8: Add guid to list of supported operations + +2007-03-14 Dotan Barak + + * src/smpquery.c: Add support to query the GUIDInfo + table + +2007-03-12 Ira K. Weiny + + * configure.in, diags.spec.in, ibdiag_common.c: + Allow user to specify a default switch map file + +2007-03-09 Hal Rosenstock + + * 1.2.5 release of openib-diags + +2007-03-09 Albert L. Chu + + * configure.in, scripts/ibcheck*, scripts/ibclear*, + scripts/ibhosts, scripts/ibnodes, scripts/ibswitches: + autoconf support for default pathname in scripts + +2007-03-05 Sasha Khapyorsky + + * include/ibdiag_common.h, src/ibdiag_common.c, + src/saquery.c: Clean gcc-4.1 warnings + +2007-03-03 Hal Rosenstock + + * 1.2.4 release of openib-diags + +2007-03-02 Ira K. Weiny + + * diags.spec.in: Include set_mthca_nodedesc.sh and dump_lfts.sh + in the rpm + + * Makefile.am, configure.in, diags.spec.in: Fix rpmbuild from make dist + +2007-03-01 Hal Rosenstock + + * 1.2.3 release of openib-diags + + * src/saquery.c: Fixed timeout handling + Also, changed default timeout to 1000 msec + +2007-02-27 Hal Rosenstock + + * 1.2.2 release of openib-diags + + * scripts/ibswitches, scripts/ibhosts: Removed extra quotes + around display of NodeDescription + +2007-02-15 Hal Rosenstock + + * 1.2.1 release of openib-diags + + * src/vendstat.c, man/vendstat.8: Initial release + + * Makefile.am: Updated for vendstat + +2007-02-12 Hal Rosenstock + + * 1.2.0 release of openib-diags + +2007-02-02 Ira Weiny + + * scripts/ibcheckerrors, scripts/ibcheckerrs: Added + brief option + * man/ibcheckerrors.8, man/ibcheckerrs.8: Updated + man pages for brief option + +2007-02-02 Hal Rosenstock + + * src/ibportstate.c, src/sminfo.c, src/smpquery.c: + Update build version tags + +2007-02-01 Hal Rosenstock + + * src/saquery.c: Add build version option + +2007-02-01 Hal Rosenstock + + * scripts/ibcheckerrors, scripts/ibcheckerrs, + scripts/ibchecknet, scripts/ibchecknode, scripts/ibcheckport, + scripts/ibcheckportstate, scripts/ibcheckportwidth, + scripts/ibcheckstate, scripts/ibcheckwidth, + scripts/ibclearcounters, scripts/ibclearerrors: Added -N | + -nocolor to usage displays + + * man/ibcheckerrors.8, man/ibcheckerrs.8, + man/ibchecknet.8, man/ibchecknode.8, man/ibcheckport.8, + man/ibcheckportstate.8, man/ibcheckportwidth.8, + man/ibcheckstate.8, man/ibcheckwidth.8, + man/ibclearcounters.8, man/ibclearerrors.8: Updated + man pages for nocolor option + +2007-02-01 Ira Weiny + + * scripts/ibcheckportwidth, scripts/ibcheckportstate, + scripts/ibcheckport, scripts/ibcheckerrs: Fix -nocolor + and -G options + + * scripts/ibchecknode: Fix -G option + + * scripts/ibchecknet: Fix error return status + + * scripts/ibcheckerrors: Add exit code + + * scripts/ibcheckerrs: Add nodename to output + + * scripts/ibqueryerrors.pl: Reduce the "common" errors + supressed by -c option; Fix -d option; Remove the use + of tmp files + + * scripts/ibfindnodeusing.pl: Remove use of tmpfile + for ibroute data + + * scripts/ibswportwatch.pl, scripts/IBswcountlimits.pm: + Add data rate option + + * scripts/IBswcountlimits.pm: Fix undefined subroutine error + in iblinkinfo.pl + +2007-01-31 Ira Weiny + + * src/ibtracert.c, man/ibtracert.8, + src/ibnetdiscover.c, man/ibnetdiscover.8: Add switch-map option + + * src/saquery.c: Clean up node descriptions before printing + +2007-01-31 Hal Rosenstock + + * src/saquery.c, man/saquery.8: Clarifications for + --src-to-dst option + + * src/saquery.c: Fix minor memory leak with --src-to-dst option + +2007-01-29 Hal Rosenstock + + * src/ibnetdiscover.c: Add non Voltaire chassis listing back + into dump_topology + +2007-01-29 Ira Weiny + + * src/ibnetdiscover.c: Add peer NodeDescription and LID to output + Also, for grouping, order Spind and Line Nodes (for Voltaire + chassis) + +2007-01-28 Ira Weiny + + * include/grouping.h, src/grouping.c: Change group_nodes API + signature to return point to ChassisList rather than void + +2007-01-27 Ira Weiny + + * src/ibtracert.c, src/ibroute.c: Add clean_nodedesc function + + * src/saquery.c, man/saquery.8: Add additional semantics to -m option + +2007-01-26 Hal Rosenstock + + * src/ibnetdiscover.c: Cosmetic change to some router strings + +2007-01-24 Sasha Khapyorsky + + * src/ibnetdiscover.c: Minor clean_nodedesc simplification + +2007-01-18 Hal Rosenstock + + * src/perfquery.c: Minor code reorder + +2007-01-17 Ira Weiny + + * scripts/iblinkinfo.pl: Add better error handling + + * src/saquery.c: Add timeout option to command line + +2007-01-16 Hal Rosenstock + + * man/perfquery.8: Removed unneeded DR description in common options + +2007-01-13 Hal Rosenstock + + * scripts/dump_mfts.sh, man/dump_mfts.8: Add dump_mfts similar + to dump_lfts + +2007-01-12 Hal Rosenstock + + * man/dump_lfts.8: Minor changes based on existence of dump_mfts + +2007-01-04 Hal Rosenstock + + * scripts/iblinkspeed.pl, man/iblinkspeed.8: Removed as no + longer needed + +2007-01-03 Sasha Khapyorsky + + * src/ibnetdiscover.c: Discover improvements + (memory leaks, ports moving, etc.) + +2007-01-02 Ira Weiny + + * scripts/iblinkinfo.pl: Convert iblinkspeed.pl into + iblinkinfo.pl and add additional capabilities + +2006-12-28 Hal Rosenstock + + * src/ibtracert.c: Add 0x in front of GUID printing + +2006-12-28 Sasha Khapyorsky + + * src/ibnetdiscover.c: Fix loopback handling + + * src/ibnetdiscover.c, src/ibroute.c, + src/ibtracert.c, src/sminfo.c: + Eliminate __WORDSIZE ifdefs for printing + +2006-12-07 Hal Rosenstock + + * src/saquery.c, man/saquery.8: Add support for + querying ServiceRecords + +2006-11-21 Hal Rosenstock + + * src/perfquery.c: Add support for PerfMgt ClassPortInfo: + CapabilityMask IsExtendedWidthSupported IBA 1.2 erratum + +2006-11-20 Sasha Khapyorsky + + * src/ibnetdiscover.c, src/ibtracert.c: Fix various + uses of printf() style functions + +2006-10-20 Hal Rosenstock + + * man/ibportstate.8, man/smpquery.8: Updated man + pages for DrSLID support. + + * src/ibportstate.c: For query operations, add peer + port checking of link width and speed active. + + * src/smpquery.c: Add support for DrSLID. + +2006-10-19 Sasha Khapyorsky + + * src/ibroute.c: Fix double calculated block value. + +2006-10-16 Hal Rosenstock + + * src/ibnetdiscover.c, src/ibtracert.c: IB router support. + +2006-10-09 Ira Weiny + + * man/iblinkspeed.8, man/ibqueryerrors.8, + man/ibswportwatch.8, man/ibprintswitch.8, + man/ibprintca.8, man/ibfindnodesusing.8: + Add man pages for new diag scripts. + + * scripts/iblinkspeed.pl, scripts/ibqueryerrors.pl, + scripts/ibswportwatch.pl, scripts/ibprintswitch.pl, + scripts/ibprintca.pl, scripts/ibfindnodesusing.pl: + Add some new diag scripts. + + * src/saquery.c: Add additional options for + NodeDescriptions of CAs only, Unique LID of name specified, + SA's ClassPortInfo, and PathRecord by src/dest name. + +2006-10-03 Hal Rosenstock + + * man/ibportstate.8: Update ibportstate man page for + speed operations. + + * src/ibportstate.c: Support changing LinkSpeedEnabled + on any IB port. + + * man/ibportstate.8: Update ibportstate man page for + port reset, enable, and disable operations. + + * src/ibportstate.c: Support explicit port reset in + addition to disable and enable. + +2006-09-28 Dotan Barak + + * src/saquery.c: Fix compile warning. + diff --git a/contrib/ofed/management/infiniband-diags/Makefile.am b/contrib/ofed/management/infiniband-diags/Makefile.am new file mode 100644 index 000000000000..c22ba5eb2f4d --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/Makefile.am @@ -0,0 +1,125 @@ + +INCLUDES = -I$(top_builddir)/include/ -I$(srcdir)/include -I$(includedir) -I$(includedir)/infiniband + +if DEBUG +DBGFLAGS = -ggdb -D_DEBUG_ +else +DBGFLAGS = +endif + +sbin_PROGRAMS = src/ibaddr src/ibnetdiscover src/ibping src/ibportstate \ + src/ibroute src/ibstat src/ibsysstat src/ibtracert \ + src/perfquery src/sminfo src/smpdump src/smpquery \ + src/saquery src/vendstat + +if ENABLE_TEST_UTILS +sbin_PROGRAMS += src/ibsendtrap src/mcm_rereg_test +endif + +sbin_SCRIPTS = scripts/ibcheckerrs scripts/ibchecknet scripts/ibchecknode \ + scripts/ibcheckport scripts/ibhosts scripts/ibstatus \ + scripts/ibswitches scripts/ibnodes scripts/ibrouters \ + scripts/ibcheckwidth scripts/ibcheckportwidth \ + scripts/ibcheckstate scripts/ibcheckportstate \ + scripts/ibcheckerrors scripts/ibclearerrors \ + scripts/ibclearcounters scripts/ibdatacounts \ + scripts/ibdatacounters scripts/ibdiscover.pl \ + scripts/dump_lfts.sh scripts/dump_mfts.sh \ + scripts/set_nodedesc.sh \ + scripts/ibqueryerrors.pl scripts/ibswportwatch.pl \ + scripts/iblinkinfo.pl scripts/ibprintswitch.pl \ + scripts/ibprintca.pl scripts/ibprintrt.pl \ + scripts/ibfindnodesusing.pl scripts/ibidsverify.pl \ + scripts/check_lft_balance.pl + +src_ibaddr_SOURCES = src/ibaddr.c src/ibdiag_common.c +src_ibaddr_CFLAGS = -Wall $(DBGFLAGS) + +src_ibnetdiscover_SOURCES = src/ibnetdiscover.c src/grouping.c src/ibdiag_common.c +src_ibnetdiscover_CFLAGS = -Wall $(DBGFLAGS) +src_ibnetdiscover_LDFLAGS = -Wl,--rpath -Wl,$(libdir) + +src_ibping_SOURCES = src/ibping.c src/ibdiag_common.c +src_ibping_CFLAGS = -Wall $(DBGFLAGS) + +src_ibportstate_SOURCES = src/ibportstate.c src/ibdiag_common.c +src_ibportstate_CFLAGS = -Wall $(DBGFLAGS) + +src_ibroute_SOURCES = src/ibroute.c src/ibdiag_common.c +src_ibroute_CFLAGS = -Wall $(DBGFLAGS) + +src_ibstat_SOURCES = src/ibstat.c +src_ibstat_CFLAGS = -Wall $(DBGFLAGS) + +src_ibsysstat_SOURCES = src/ibsysstat.c src/ibdiag_common.c +src_ibsysstat_CFLAGS = -Wall $(DBGFLAGS) + +src_ibtracert_SOURCES = src/ibtracert.c src/ibdiag_common.c +src_ibtracert_CFLAGS = -Wall $(DBGFLAGS) +src_ibtracert_LDFLAGS = -Wl,--rpath -Wl,$(libdir) + +src_perfquery_SOURCES = src/perfquery.c src/ibdiag_common.c +src_perfquery_CFLAGS = -Wall $(DBGFLAGS) + +src_sminfo_SOURCES = src/sminfo.c src/ibdiag_common.c +src_sminfo_CFLAGS = -Wall $(DBGFLAGS) + +src_smpdump_SOURCES = src/smpdump.c +src_smpdump_CFLAGS = -Wall $(DBGFLAGS) + +src_smpquery_SOURCES = src/smpquery.c src/ibdiag_common.c +src_smpquery_CFLAGS = -Wall $(DBGFLAGS) +src_smpquery_LDFLAGS = -Wl,--rpath -Wl,$(libdir) + +src_saquery_SOURCES = src/saquery.c src/ibdiag_common.c +src_saquery_CFLAGS = -Wall -DOSM_VENDOR_INTF_OPENIB -DVENDOR_RMPP_SUPPORT -DDUAL_SIDED_RMPP $(DBGFLAGS) +src_saquery_LDFLAGS = -Wl,--rpath -Wl,$(libdir) + +src_ibsendtrap_SOURCES = src/ibsendtrap.c src/ibdiag_common.c +src_ibsendtrap_CFLAGS = -Wall $(DBGFLAGS) +src_ibsendtrap_LDFLAGS = -Wl,--rpath -Wl,$(libdir) + +src_vendstat_SOURCES = src/vendstat.c src/ibdiag_common.c +src_vendstat_CFLAGS = -Wall $(DBGFLAGS) + +src_mcm_rereg_test_SOURCES = src/mcm_rereg_test.c +src_mcm_rereg_test_CFLAGS = -Wall $(DBGFLAGS) + +man_MANS = man/ibaddr.8 man/ibcheckerrors.8 man/ibcheckerrs.8 \ + man/ibchecknet.8 man/ibchecknode.8 man/ibcheckport.8 \ + man/ibcheckportstate.8 man/ibcheckportwidth.8 man/ibcheckstate.8 \ + man/ibcheckwidth.8 man/ibclearcounters.8 man/ibclearerrors.8 \ + man/ibhosts.8 man/ibnetdiscover.8 man/ibnodes.8 man/ibping.8 \ + man/ibportstate.8 man/ibroute.8 man/ibstat.8 man/ibstatus.8 \ + man/ibswitches.8 man/ibtracert.8 man/perfquery.8 man/sminfo.8 \ + man/smpdump.8 man/smpquery.8 man/saquery.8 man/vendstat.8 \ + man/dump_lfts.8 man/dump_mfts.8 man/ibdiscover.8 man/ibsysstat.8 \ + man/iblinkinfo.8 man/ibqueryerrors.8 man/ibswportwatch.8 \ + man/ibprintswitch.8 man/ibprintca.8 man/ibfindnodesusing.8 \ + man/ibdatacounts.8 man/ibdatacounters.8 \ + man/ibrouters.8 man/ibprintrt.8 man/ibidsverify.8 \ + man/check_lft_balance.8 + +BUILT_SOURCES = ibdiag_version +ibdiag_version: + if [ -x $(top_srcdir)/../gen_ver.sh ] ; then \ + ver_file=$(top_builddir)/include/ibdiag_version.h ; \ + ibdiag_ver=`cat $$ver_file | sed -ne '/#define IBDIAG_VERSION /s/^.*\"\(.*\)\"$$/\1/p'` ; \ + ver=`$(top_srcdir)/../gen_ver.sh $(PACKAGE)` ; \ + if [ $$ver != $$ibdiag_ver ] ; then \ + cat $$ver_file | sed -e '/#define IBDIAG_VERSION /s/\".*\"/\"'$$ver'\"/' > tmp_new_version ; \ + cat tmp_new_version > $$ver_file && rm -f tmp_new_version ; \ + fi ; \ + fi + +EXTRA_DIST = scripts include infiniband-diags.spec.in infiniband-diags.spec \ + $(man_MANS) autogen.sh + +dist-hook: + if [ -x $(top_srcdir)/../gen_chlog.sh ] ; then \ + $(top_srcdir)/../gen_chlog.sh $(PACKAGE) > $(distdir)/ChangeLog ; \ + fi + +# install this to a default location. +install-data-hook: + $(top_srcdir)/config/install-sh -c -m 444 $(top_srcdir)/scripts/IBswcountlimits.pm $(DESTDIR)/$(PERL_INSTALLDIR)/IBswcountlimits.pm diff --git a/contrib/ofed/management/infiniband-diags/README b/contrib/ofed/management/infiniband-diags/README new file mode 100644 index 000000000000..c251726f1896 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/README @@ -0,0 +1,564 @@ +Diagnostic Tools +shaharf@voltaire.com, halr@voltaire.com + +General: + +Model of operation: All utilities use direct MAD access to perform their +operations. Operations that require QP 0 mads only, may use direct routed +mads, and therefore may work even in unconfigured subnets. Almost all +utilities can operate without accessing the SM, unless GUID to lid translation +is required. + +Dependencies: Most utilities depend on libibmad and libibumad. + All utilities depend on the ib_umad kernel module. + +Multiple port/Multiple CA support: when no IB device or port is specified + (see the "local umad parameters" below), the libibumad library + selects the port to use by the following criteria: + 1. the first port that is ACTIVE. + 2. if not found, the first port that is UP (physical link up). + + If a port and/or CA name is specified, the libibumad library + attempts to fulfill the user request, and will fail if it is not + possible. + For example: + ibaddr # use the 'best port' + ibaddr -C mthca1 # pick the best port from mthca1 only. + ibaddr -P 2 # use the second (active/up) port from the + first available IB device. + ibaddr -C mthca0 -P 2 # use the specified port only. + +Common options & flags: + Most diagnostics take the following flags. The exact list of supported + flags per utility can be found in the usage message and can be shown + using util_name -h syntax. + + # Debugging flags + -d raise the IB debugging level. May be used + several times (-ddd or -d -d -d). + -e show umad send receive errors (timeouts and others) + -h show the usage message + -v increase the application verbosity level. + May be used several times (-vv or -v -v -v) + -V show the internal version info. + + # Addressing flags + -D use directed path address arguments. The path + is a comma separated list of out ports. + Examples: + "0" # self port + "0,1,2,1,4" # out via port 1, then 2, ... + -G use GUID address arguments. In most cases, it is the Port GUID. + Examples: + "0x08f1040023" + -s use 'smlid' as the target lid for SA queries. + + # Local umad parameters: + -C use the specified ca_name. + -P use the specified ca_port. + -t override the default timeout for the solicited mads. + +CLI notation: all utilities use the POSIX style notation, + meaning that all options (flags) must precede all arguments + (parameters). + + +Utilities descriptions: + +1. ibstatus + +Description: +ibstatus is a script which displays basic information obtained from the local +IB driver. Output includes LID, SMLID, port state, link width active, and port +physical state. + +Syntax: +ibstatus [-h] [devname[:port]]... + +Examples: + ibstatus # display status of all IB ports + ibstatus mthca1 # status of mthca1 ports + ibstatus mthca1:1 mthca0:2 # show status of specified ports + +See also: + ibstat + +2. ibstat + +Description: +Similar to the ibstatus utility but implemented as a binary and not a script. +It has options to list CAs and/or ports. + +Syntax: +ibstat [-d(ebug) -l(ist_of_cas) -p(ort_list) -s(hort)] [portnum] + +Examples: + ibstat # display status of all IB ports + ibstat mthca1 # status of mthca1 ports + ibstat mthca1 2 # show status of specified ports + ibstat -p mthca0 # list the port guids of mthca0 + ibstat -l # list all CA names + +See also: + ibstatus + +3. ibroute + +Description: +ibroute uses SMPs to display the forwarding tables (unicast +(LinearForwardingTable or LFT) or multicast (MulticastForwardingTable or MFT)) +for the specified switch LID and the optional lid (mlid) range. +The default range is all valid entries in the range 1...FDBTop. + +Syntax: +ibroute [options] [ []]] + +Non standard flags: + -a show all lids in range, even invalid entries. + -n do not try to resolve destinations. + -M show multicast forwarding tables. In this case the range + parameters are specifying mlid range. + +Examples: + ibroute 2 # dump all valid entries of switch lid 2 + ibroute 2 15 # dump entries in the range 15...FDBTop. + ibroute -a 2 10 20 # dump all entries in the range 10..20 + ibroute -n 2 # simple format + ibroute -M 2 # show multicast tables + +See also: + ibtracert + +4. ibtracert + +Description: +ibtracert uses SMPs to trace the path from a source GID/LID to a +destination GID/LID. Each hop along the path is displayed until the destination +is reached or a hop does not respond. By using the -m option, multicast path +tracing can be performed between source and destination nodes. + +Syntax: +ibtracert [options] + +Non standard flags: + -n simple format; don't show additional information. + -m show the multicast trace of the specified mlid. + +Examples: + ibtracert 2 23 # show trace between lid 2 and 23 + ibtracert -m 0xc000 3 5 # show multicast trace between lid 3 and 5 + for mcast lid 0xc000. + +5. smpquery + +Description: +smpquery allows a basic subset of standard SMP queries including the following: +node info, node description, switch info, port info. Fields are displayed in +human readable format. + +Syntax: +smpquery [options] [op_params] + +Current supported operations and their parameters: + nodeinfo + nodedesc + portinfo [] # default port is zero + switchinfo + pkeys [] + sl2vl [] + vlarb [] + +Examples: + smpquery nodeinfo 2 # show nodeinfo for lid 2 + smpquery portinfo 2 5 # show portinfo for lid 2 port 5 + +6. smpdump + +Description: +smpdump is a general purpose SMP utility which gets SM attributes from a +specified SMA. The result is dumped in hex by default. + +Syntax: +smpdump [options] [mod] + +Non standard flags: + -s show output as string + +Examples: + smpdump -D 0,1,2 0x15 2 # port info, port 2 + smpdump 3 0x15 2 # port info, lid 3 port 2 + +7. ibaddr + +Description: +ibaddr can be used to show the lid and GID addresses of the specified port, +or the local port by default. +Note: this utility can be used as simple address resolver. + +Syntax: +ibaddr [options] [] + +Examples: + ibaddr # show local address + ibaddr 2 # show address of the specified port lid + ibaddr -G 0x8f1040023 # show address of the specified port guid + +8. sminfo + +Description: +sminfo issue and dumps the output of a sminfo query in human readable format. +The target SM is the one listed in the local port info, or the SM specified +by the optional SM lid or by the SM direct routed path. +Note: using sminfo for any purposes other then simple query may be very +dangerous, and may result in a malfunction of the target SM. + +Syntax: +sminfo [options] [sminfo_modifier] + +Non standard flags: + -s # use the specified state in sminfo mad + -p # use the specified priority in sminfo mad + -a # use the specified activity in sminfo mad + +Examples: + sminfo # show sminfo of SM listed in local portinfo + sminfo 2 # query SM on port lid 2 + +9. perfquery + +Description: +perfquery uses PerfMgt GMPs to obtain the PortCounters (basic performance +and error counters) from the PMA at the node specified. Optionally reset all +or + +Syntax: +perfquery [options] [ [[port] [reset_mask]]] + +Non standard flags: + -a show aggregated counters for all ports of the destination lid. + -r reset counters after read. + -R only reset counters. + +Examples: + perfquery # read local port's performance counters + perfquery 32 1 # read performance counters from lid 32, port 1 + perfquery -a 32 # read node aggregated performance counters + perfquery -r 32 1 # read performance counters and reset + perfquery -R 32 1 # reset performance counters of port 1 only + perfquery -R -a 32 # reset performance counters of all ports + perfquery -R 32 2 0xf000 # reset only non-error counters of port 2 + +10. ibping + +Description: +ibping uses vendor mads to validate connectivity between IB nodes. +On exit, (IP) ping like output is show. ibping is run as client/server. +Default is to run as client. Note also that a default ping server is +implemented within the kernel. + +Syntax: +ibping [options] + +Non standard flags: + -c stop after count packets + -f flood destination: send packets back to back w/o delay + -o use specified OUI number to multiplex vendor mads + -S start in server mode (do not return) + +11. ibnetdiscover + +Description: +ibnetdiscover performs IB subnet discovery and outputs a human readable +topology file. GUIDs, node types, and port numbers are displayed +as well as port LIDs and NodeDescriptions. All nodes (and links) are displayed +(full topology). Optionally this utility can be used to list the current +connected nodes. The output is printed to the standard output unless a +topology file is specified. + +Syntax: +ibnetdiscover [options] [] + +Non standard flags: + -l List of connected nodes + -H List of connected HCAs + -S List of connected switches + -g Grouping + +12. ibhosts + +Description: +ibhosts either walks the IB subnet topology or uses an already saved topology +file and extracts the CA nodes. + +Syntax: +ibhosts [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format + +13. ibswitches + +Description: +ibswitches either walks the IB subnet topology or uses an already saved +topology file and extracts the IB switches. + +Syntax: +ibswitches [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format + +14. ibchecknet + +Description: +ibchecknet uses a full topology file that was created by ibnetdiscover, +scans the network to validate the connectivity and reports errors +(from port counters). + +Syntax: +ibchecknet [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format, ibchecknode, ibcheckport, ibcheckerrs + +15. ibcheckport + +Description: +Check connectivity and do some simple sanity checks for the specified port. +Port address is lid unless -G option is used to specify a GUID address. + +Syntax: +ibcheckport [-h] [-G] + +Example: + ibcheckport 2 3 # check lid 2 port 3 + +Dependencies: +smpquery, smpquery output format, ibaddr + +16. ibchecknode + +Description: +Check connectivity and do some simple sanity checks for the specified node. +Port address is lid unless -G option is used to specify a GUID address. + +Syntax: +ibchecknode [-h] [-G] + +Example: + ibchecknode 2 # check node via lid 2 + +Dependencies: +smpquery, smpquery output format, ibaddr + +Usage: + +17. ibcheckerrs + +Description: +Check specified port (or node) and report errors that surpassed their predefined +threshold. Port address is lid unless -G option is used to specify a GUID +address. The predefined thresholds can be dumped using the -s option, and a +user defined threshold_file (using the same format as the dump) can be +specified using the -t option. + +Syntax: +ibcheckerrs [-h] [-G] [-t ] [-s(how_thresholds)] [] + +Examples: + ibcheckerrs 2 # check aggregated node counter for lid 2 + ibcheckerrs 2 4 # check port counters for lid 2 port 4 + ibcheckerrs -t xxx 2 # check node using xxx threshold file + +Dependencies: +perfquery, perfquery output format, ibaddr + +18. ibportstate + +Description: +ibportstate allows the port state and port physical state of an IB port +to be queried or a switch port to be disabled or enabled. + +Syntax: +ibportstate [-d(ebug) -e(rr_show) -v(erbose) -D(irect) -G(uid) -s smlid +-V(ersion) -C ca_name -P ca_port -t timeout_ms] + [] + supported ops: enable, disable, query + +Examples: + ibportstate 3 1 disable # by lid + ibportstate -G 0x2C9000100D051 1 enable # by guid + ibportstate -D 0 1 # by direct route + +19. ibcheckwidth + +Description: +ibcheckwidth uses a full topology file that was created by ibnetdiscover, +scans the network to validate the active link widths and reports any 1x +links. + +Syntax: +ibcheckwidth [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format, ibchecknode, ibcheckportwidth + +20. ibcheckportwidth + +Description: +Check connectivity and check the specified port for 1x link width. +Port address is lid unless -G option is used to specify a GUID address. + +Syntax: +ibcheckportwidth [-h] [-G] + +Example: + ibcheckportwidth 2 3 # check lid 2 port 3 + +Dependencies: +smpquery, smpquery output format, ibaddr + +21. ibcheckstate + +Description: +ibcheckstate uses a full topology file that was created by ibnetdiscover, +scans the network to validate the port state and port physical state, +and reports any ports which have a port state other than Active or +a port physical state other than LinkUp. + +Syntax: +ibcheckstate [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format, ibchecknode, ibcheckportstate + +22. ibcheckportstate + +Description: +Check connectivity and check the specified port for proper port state +(Active) and port physical state (LinkUp). +Port address is lid unless -G option is used to specify a GUID address. + +yntax: +ibcheckportstate [-h] [-G] + +Example: + ibcheckportstate 2 3 # check lid 2 port 3 + +Dependencies: +smpquery, smpquery output format, ibaddr + +23. ibcheckerrors + +ibcheckerrors uses a full topology file that was created by ibnetdiscover, +scans the network to validate the connectivity and reports errors +(from port counters). + +Syntax: +ibnetcheckerrors [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format, ibchecknode, ibcheckport, ibcheckerrs + +24. ibdiscover.pl + +ibdiscover.pl uses a topology file create by ibnetdiscover and a discover.map +file which the network administrator creates which indicates the nodes +to be expected and a ibdiscover.topo file which is the expected connectivity +and produces a new connectivity file (discover.topo.new) and outputs +the changes to stdout. The network administrator can choose to replace +the "old" topo file with the new one or certain changes in. + +The syntax of the ibdiscover.map file is: +|port|"Text for node"| +e.g. +8f10400410015|8|"ISR 6000"|# SW-6IB4 Voltaire port 0 lid 5 +8f10403960558|2|"HCA 1"|# MT23108 InfiniHost Mellanox Technologies + +The syntax of the old and new topo files (ibdiscover.topo and +ibdiscover.topo.new) are: +||| +e.g. +10|5442ba00003080|1|8f10400410015 + +These topo files are produced by the ibdiscover.pl tool. + +Syntax: +ibnetdiscover | ibdiscover.pl + +Dependencies: +ibnetdiscover, ibnetdiscover format + +25. ibnodes + +Description: +ibnodes either walks the IB subnet topology or uses an already saved topology +file and extracts the IB nodes (CAs and switches). + +Syntax: +ibnodes [] + +Dependencies: +ibnetdiscover, ibnetdiscover format + +26. ibclearerrors + +Description: +ibclearerrors clears the PMA error counters in PortCounters by either walking +the IB subnet topology or using an already saved topology file. + +Syntax: +ibclearerrors [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format, perfquery + +27. ibclearcounters + +Description: +ibclearcounters clears the PMA port counters by either walking +the IB subnet topology or using an already saved topology file. + +Syntax: +ibclearcounters [-h] [] + +Dependencies: +ibnetdiscover, ibnetdiscover format, perfquery + +28. saquery + +Description: +Issue some SA queries. + +Syntax: +Usage: saquery [-h -d -P -N -L -G -s -g][] + Queries node records by default + -d enable debugging + -P get PathRecord info + -N get NodeRecord info + -L Return just the Lid of the name specified + -G Return just the Guid of the name specified + -s Return the PortInfoRecords with isSM capability mask bit on + -g get multicast group info + +Dependencies: +OpenSM libvendor, OpenSM libopensm, libibumad + +29. ibsysstat + +Description: +ibsysstat uses vendor mads to validate connectivity between IB nodes +and obtain other information about the IB node. ibsysstat is run as +client/server. Default is to run as client. + +Syntax: +ibsysstat [options] [] + +Non standard flags: + Current supported operations: + ping - verify connectivity to server (default) + host - obtain host information from server + cpu - obtain cpu information from server + -o use specified OUI number to multiplex vendor mads + -S start in server mode (do not return) + diff --git a/contrib/ofed/management/infiniband-diags/autogen.sh b/contrib/ofed/management/infiniband-diags/autogen.sh new file mode 100755 index 000000000000..4827884ba1f1 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/autogen.sh @@ -0,0 +1,11 @@ +#! /bin/sh + +# create config dir if not exist +test -d config || mkdir config + +set -x +aclocal -I config +libtoolize --force --copy +autoheader +automake --foreign --add-missing --copy +autoconf diff --git a/contrib/ofed/management/infiniband-diags/configure.in b/contrib/ofed/management/infiniband-diags/configure.in new file mode 100644 index 000000000000..d8524f4682fd --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/configure.in @@ -0,0 +1,170 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(infiniband-diags, 1.5.0, general@lists.openfabrics.org) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE + +AC_SUBST(RELEASE, ${RELEASE:-unknown}) +AC_SUBST(TARBALL, ${TARBALL:-${PACKAGE}-${VERSION}.tar.gz}) + +AC_ARG_ENABLE(libcheck, [ --disable-libcheck do not test for presence of ib libraries], +[ if test x$enableval = xno ; then + disable_libcheck=yes + fi +]) + +dnl support debug mode +AC_ARG_ENABLE(debug, +[ --enable-debug Turn on debug mode], +[case "${enableval}" in + yes) debug=true ;; + no) debug=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;; +esac],[debug=false]) +AM_CONDITIONAL(DEBUG, test x$debug = xtrue) + +dnl Checks for programs +AC_PROG_CC +AC_PROG_LIBTOOL + +if test "$disable_libcheck" != "yes" +then +dnl Checks for libraries +AC_CHECK_LIB(ibcommon, sys_read_string, [], + AC_MSG_ERROR([sys_read_string() not found. diags require libibcommon.])) +AC_CHECK_LIB(ibumad, umad_init, [], + AC_MSG_ERROR([umad_init() not found. diags require libibumad.])) +AC_CHECK_LIB(ibmad, mad_dump_int, [], + AC_MSG_ERROR([mad_dump_int() not found. diags require libibmad.])) +AC_CHECK_LIB(ibmad, port_performance_ext_query, [], + AC_MSG_ERROR([port_performance_ext_query() not found. diags require more recent libibmad.])) +AC_CHECK_LIB(osmcomp, cl_thread_init, [], + AC_MSG_ERROR([cl_thread_init() not found. diags require libosmcomp.])) +AC_CHECK_LIB(osmvendor, osmv_query_sa, [], + AC_MSG_ERROR([osmv_query_sa() not found. diags require libosmvendor.]), [-lopensm]) +AC_CHECK_LIB(opensm, osm_log_init_v2, [], + AC_MSG_ERROR([osm_log_init_v2() not found. diags require libopensm.])) +fi + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([stdlib.h string.h unistd.h fcntl.h inttypes.h netinet/in.h sys/ioctl.h syslog.h]) +if test "$disable_libcheck" != "yes" +then +AC_CHECK_HEADER(infiniband/common.h, [], + AC_MSG_ERROR([ not found. diags require libibcommon.]) +) +AC_CHECK_HEADER(infiniband/umad.h, [], + AC_MSG_ERROR([ not found. diags require libibumad.]) +) +AC_CHECK_HEADER(infiniband/mad.h, [], + AC_MSG_ERROR([ not found. diags require libibmad.]) +) +fi + +dnl Checks for library functions +AC_FUNC_ERROR_AT_LINE +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([strchr strrchr strtol strtoul memset]) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST + +dnl Check if we should include test utilities +AC_MSG_CHECKING(for --enable-test-utils) +AC_ARG_ENABLE(test-utils, +[ --enable-test-utils build additional test utilities], +[case "${enableval}" in + yes) tutils=yes ;; + no) tutils=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-test-utils) ;; +esac],[tutils=no]) +AM_CONDITIONAL(ENABLE_TEST_UTILS, test x$tutils = xyes) +AC_MSG_RESULT(${tutils=no}) + +dnl Check for perl and perl install location +AC_MSG_CHECKING(for --with-perl-path ) +AC_ARG_WITH(perl-path, + AC_HELP_STRING([--with-perl-path=path], + [define perl location]), + [ case "$withval" in + no) + ;; + *) + withperlpath=yes + PERL=$withval + ;; + esac ] +) +AC_MSG_RESULT(${withperlpath=no}) +AC_SUBST(PERL) + +if test $withperlpath = "no" +then + AC_PATH_PROG([PERL], [perl]) +fi +AC_SUBST(PERL) + +AC_MSG_CHECKING(for --with-perl-installdir ) +AC_ARG_WITH(perl-installdir, + AC_HELP_STRING([--with-perl-installdir=path], + [define perl install path]), + [ case "$withval" in + no) + ;; + *) + withperlinstalldir=yes + PERL_INSTALLDIR=$withval + ;; + esac ] +) +AC_MSG_RESULT(${withperlinstalldir=no}) +AC_SUBST(PERL_INSTALLDIR) + +if test $withperlinstalldir = "no" +then + PERL_INSTALLDIR=`$PERL -e 'use Config; $T=$Config{installsitearch}; print $T;'` +fi +AC_SUBST(PERL_INSTALLDIR) + +AC_CACHE_CHECK(whether ld accepts --version-script, ac_cv_version_script, + if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then + ac_cv_version_script=yes + else + ac_cv_version_script=no + fi) + +AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$ac_cv_version_script" = "yes") + +dnl Make appropriate substitution for IB script path +dnl Must expand nested unquoting +IBSCRIPTPATH_TMP1="`eval echo ${sbindir}`" +IBSCRIPTPATH_TMP2="`echo $IBSCRIPTPATH_TMP1 | sed 's/^NONE/$ac_default_prefix/'`" +IBSCRIPTPATH="`eval echo $IBSCRIPTPATH_TMP2`" +AC_SUBST(IBSCRIPTPATH) + +AC_CONFIG_FILES([\ + Makefile \ + infiniband-diags.spec \ + include/ibdiag_version.h \ + scripts/ibcheckerrors \ + scripts/ibcheckerrs \ + scripts/ibchecknet \ + scripts/ibchecknode \ + scripts/ibcheckport \ + scripts/ibcheckportstate \ + scripts/ibcheckportwidth \ + scripts/ibcheckstate \ + scripts/ibcheckwidth \ + scripts/ibclearcounters \ + scripts/ibclearerrors \ + scripts/ibdatacounts \ + scripts/ibdatacounters \ + scripts/ibhosts \ + scripts/ibnodes \ + scripts/ibswitches \ + scripts/ibrouters +]) +AC_OUTPUT diff --git a/contrib/ofed/management/infiniband-diags/include/grouping.h b/contrib/ofed/management/infiniband-diags/include/grouping.h new file mode 100644 index 000000000000..e54efef83a85 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/include/grouping.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _GROUPING_H_ +#define _GROUPING_H_ + +/*========================================================*/ +/* FABRIC SCANNER SPECIFIC DATA */ +/*========================================================*/ + +#define SPINES_MAX_NUM 12 +#define LINES_MAX_NUM 36 + +typedef struct ChassisList ChassisList; +typedef struct AllChassisList AllChassisList; + +struct ChassisList { + ChassisList *next; + uint64_t chassisguid; + int chassisnum; + int chassistype; + int nodecount; /* used for grouping by SystemImageGUID */ + Node *spinenode[SPINES_MAX_NUM + 1]; + Node *linenode[LINES_MAX_NUM + 1]; +}; + +struct AllChassisList { + ChassisList *first; + ChassisList *current; + ChassisList *last; +}; + +/*========================================================*/ +/* CHASSIS RECOGNITION SPECIFIC DATA */ +/*========================================================*/ + +/* Device IDs */ +#define VTR_DEVID_IB_FC_ROUTER 0x5a00 +#define VTR_DEVID_IB_IP_ROUTER 0x5a01 +#define VTR_DEVID_ISR9600_SPINE 0x5a02 +#define VTR_DEVID_ISR9600_LEAF 0x5a03 +#define VTR_DEVID_HCA1 0x5a04 +#define VTR_DEVID_HCA2 0x5a44 +#define VTR_DEVID_HCA3 0x6278 +#define VTR_DEVID_SW_6IB4 0x5a05 +#define VTR_DEVID_ISR9024 0x5a06 +#define VTR_DEVID_ISR9288 0x5a07 +#define VTR_DEVID_SLB24 0x5a09 +#define VTR_DEVID_SFB12 0x5a08 +#define VTR_DEVID_SFB4 0x5a0b +#define VTR_DEVID_ISR9024_12 0x5a0c +#define VTR_DEVID_SLB8 0x5a0d +#define VTR_DEVID_RLX_SWITCH_BLADE 0x5a20 +#define VTR_DEVID_ISR9024_DDR 0x5a31 +#define VTR_DEVID_SFB12_DDR 0x5a32 +#define VTR_DEVID_SFB4_DDR 0x5a33 +#define VTR_DEVID_SLB24_DDR 0x5a34 +#define VTR_DEVID_SFB2012 0x5a37 +#define VTR_DEVID_SLB2024 0x5a38 +#define VTR_DEVID_ISR2012 0x5a39 +#define VTR_DEVID_SFB2004 0x5a40 +#define VTR_DEVID_ISR2004 0x5a41 +#define VTR_DEVID_SRB2004 0x5a42 + +enum ChassisType { UNRESOLVED_CT, ISR9288_CT, ISR9096_CT, ISR2012_CT, ISR2004_CT }; +enum ChassisSlot { UNRESOLVED_CS, LINE_CS, SPINE_CS, SRBD_CS }; + +/*========================================================*/ +/* External interface */ +/*========================================================*/ + +ChassisList *group_nodes(); +char *portmapstring(Port *port); +char *get_chassis_type(unsigned char chassistype); +char *get_chassis_slot(unsigned char chassisslot); +uint64_t get_chassis_guid(unsigned char chassisnum); + +int is_xsigo_guid(uint64_t guid); +int is_xsigo_tca(uint64_t guid); +int is_xsigo_hca(uint64_t guid); + +#endif /* _GROUPING_H_ */ diff --git a/contrib/ofed/management/infiniband-diags/include/ibdiag_common.h b/contrib/ofed/management/infiniband-diags/include/ibdiag_common.h new file mode 100644 index 000000000000..39e09d70909c --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/include/ibdiag_common.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2006-2007 The Regents of the University of California. + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _IBDIAG_COMMON_H_ +#define _IBDIAG_COMMON_H_ + +#include +#include + +extern char *argv0; +extern int ibdebug; + +/*========================================================*/ +/* External interface */ +/*========================================================*/ + +#undef DEBUG +#define DEBUG if (ibdebug || verbose) IBWARN +#define VERBOSE if (ibdebug || verbose > 1) IBWARN +#define IBERROR(fmt, args...) iberror(__FUNCTION__, fmt, ## args) + +void iberror(const char *fn, char *msg, ...); + +#include + +static inline const char* get_build_version(void) +{ + return "BUILD VERSION: " IBDIAG_VERSION " Build date: " __DATE__ " " __TIME__ ; +} + +#endif /* _IBDIAG_COMMON_H_ */ diff --git a/contrib/ofed/management/infiniband-diags/include/ibdiag_version.h b/contrib/ofed/management/infiniband-diags/include/ibdiag_version.h new file mode 100644 index 000000000000..da9ed51096e9 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/include/ibdiag_version.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _IBDIAG_VERSION_H_ +#define _IBDIAG_VERSION_H_ + +#define IBDIAG_VERSION "1.4.4" + +#endif /* _IBDIAG_VERSION_H_ */ diff --git a/contrib/ofed/management/infiniband-diags/include/ibdiag_version.h.in b/contrib/ofed/management/infiniband-diags/include/ibdiag_version.h.in new file mode 100644 index 000000000000..62430c57d9a8 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/include/ibdiag_version.h.in @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _IBDIAG_VERSION_H_ +#define _IBDIAG_VERSION_H_ + +#define IBDIAG_VERSION "@VERSION@" + +#endif /* _IBDIAG_VERSION_H_ */ diff --git a/contrib/ofed/management/infiniband-diags/include/ibnetdiscover.h b/contrib/ofed/management/infiniband-diags/include/ibnetdiscover.h new file mode 100644 index 000000000000..0226615537aa --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/include/ibnetdiscover.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _IBNETDISCOVER_H_ +#define _IBNETDISCOVER_H_ + +#define MAXHOPS 63 + +#define CA_NODE 1 +#define SWITCH_NODE 2 +#define ROUTER_NODE 3 + +#define LIST_CA_NODE (1 << CA_NODE) +#define LIST_SWITCH_NODE (1 << SWITCH_NODE) +#define LIST_ROUTER_NODE (1 << ROUTER_NODE) + +/* Vendor IDs (for chassis based systems) */ +#define VTR_VENDOR_ID 0x8f1 /* Voltaire */ +#define TS_VENDOR_ID 0x5ad /* Cisco */ +#define SS_VENDOR_ID 0x66a /* InfiniCon */ +#define XS_VENDOR_ID 0x1397 /* Xsigo */ + + +typedef struct Port Port; +typedef struct Node Node; +typedef struct ChassisRecord ChassisRecord; + +struct ChassisRecord { + ChassisRecord *next; + + unsigned char chassisnum; + unsigned char anafanum; + unsigned char slotnum; + unsigned char chassistype; + unsigned char chassisslot; +}; + +struct Port { + Port *next; + uint64_t portguid; + int portnum; + int lid; + int lmc; + int state; + int physstate; + int linkwidth; + int linkspeed; + + Node *node; + Port *remoteport; /* null if SMA */ +}; + +struct Node { + Node *htnext; + Node *dnext; + Port *ports; + ib_portid_t path; + int type; + int dist; + int numports; + int localport; + int smalid; + int smalmc; + int smaenhsp0; + uint32_t devid; + uint32_t vendid; + uint64_t sysimgguid; + uint64_t nodeguid; + uint64_t portguid; + char nodedesc[64]; + uint8_t nodeinfo[64]; + + ChassisRecord *chrecord; +}; + +#endif /* _IBNETDISCOVER_H_ */ diff --git a/contrib/ofed/management/infiniband-diags/infiniband-diags.spec.in b/contrib/ofed/management/infiniband-diags/infiniband-diags.spec.in new file mode 100644 index 000000000000..9c8c0c4c83f7 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/infiniband-diags.spec.in @@ -0,0 +1,194 @@ + +%define RELEASE @RELEASE@ +%define rel %{?CUSTOM_RELEASE} %{!?CUSTOM_RELEASE:%RELEASE} + +Summary: OpenFabrics Alliance InfiniBand Diagnostic Tools +Name: infiniband-diags +Version: @VERSION@ +Release: %rel%{?dist} +License: GPLv2 or BSD +Group: System Environment/Libraries +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +Source: http://www.openfabrics.org/downloads/management/@TARBALL@ +Url: http://openfabrics.org/ +BuildRequires: libibmad-devel, opensm-devel, libibcommon-devel, libibumad-devel +Provides: perl(IBswcountlimits) +Obsoletes: openib-diags + +%description +This package provides IB diagnostic programs and scripts needed to +diagnose an IB subnet. + +%prep +%setup -q + +%if %{?_with_node_name_map:1}%{!?_with_node_name_map:0} +%define _enable_node_name_map --with-node-name-map%{?_with_node_name_map} +%endif + +%build +%configure %{?_enable_node_name_map} +make + +%install +rm -rf $RPM_BUILD_ROOT +make DESTDIR=${RPM_BUILD_ROOT} install +# remove unpackaged files from the buildroot +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%{_sbindir}/ibdiscover.pl +%{_sbindir}/ib* +%{_sbindir}/perfquery +%{_sbindir}/saquery +%{_sbindir}/vendstat +%{_sbindir}/dump_mfts.sh +%{_sbindir}/dump_lfts.sh +%{_sbindir}/check_lft_balance.pl +%{_sbindir}/set_nodedesc.sh +%{_sbindir}/sm* +%define _perldir %(perl -e 'use Config; $T=$Config{installsitearch}; $T=~/(.*)\\/site_perl.*/; print $1;') +%{_perldir}/* +%{_mandir}/man8/* +%doc README COPYING ChangeLog + +%changelog +* Mon Mar 03 2008 Albert Chu - 1.3.5 +- Add check_lft_balance script. + +* Wed Oct 31 2007 Ira Weiny - 1.3.2 +- Change switch-map option to node-name-map + +* Thu Aug 9 2007 Ira Weiny - 1.3.1 +- Change set_mthca_nodedesc.sh to set_nodedesc.sh + +* Tue Jul 10 2007 Hal Rosenstock - 1.3.1 +- Add link width and speed to topology file output in ibnetdiscover +- Add support for -R(outer_list) in ibnetdiscover +- Add script and man page for ibidsverify +- Moved diags from bin to sbin +- Add scripts and man pages for display on IB routers +- Add GUID to output line for ports in ibqueryerrors.pl +- Add ibdatacounts and ibdatacounters scripts and man pages +- Add peer port link width and speed validation in iblinkinfo.pl +- Display remote LID with peer port info in IBswcountlimits.pm +- Handle peer ports at 1x that should be wider and 2.5 Gbps + links that should be faster in ibportstate +- Add LinkSpeed/Width components to output of ibportstate +- Add support for IB routers +- Add grouping support for ISR2012 and ISR2004 in ibnetdiscover +- Remove all uses of "/tmp" from perl scripts +- Add switch map support for saquery -O and -U options +- Add support for saquery -s (isSMdisabled) +- Add name input checks to saquery (-O and -U) + +* Thu Mar 29 2007 Hal Rosenstock - 1.3.0 +- Add some extra debug information to IBswcountlimits.pm +- Send normal output to stdout in ibtracert +- Don't truncate NodeDescriptions containing ctl characters in ibdiag_common +- Fix ibnetdiscover grouping for Cisco SFS7000 +- Add support to query the GUIDInfo table in smpquery +- Allow user to specify a default switch map file + +* Fri Mar 9 2007 Hal Rosenstock - 1.2.5 +- Find perl modules in perl sitearch directory +- Fix non standard prefix install for diag scripts +- Clean gcc-4.1 warnings in saquery and ibdiag_common + +* Fri Mar 2 2007 Hal Rosenstock - 1.2.4 +- OpenFabrics 1.2.4 release +- Fix diag rpmbuild from make dist +- Include set_mthca_nodedesc.sh and dump_lfts.sh in the rpm + +* Thu Mar 1 2007 Hal Rosenstock - 1.2.3 +- OpenFabrics 1.2.3 release +- Fixed saquery timeout handling + +* Tue Feb 27 2007 Hal Rosenstock - 1.2.2 +- OpenFabrics 1.2.2 release +- Minor changes to ibswitches and ibhosts output + +* Thu Feb 14 2007 Hal Rosenstock - 1.2.1 +- OpenFabrics 1.2.1 release +- Initial release of vendstat tool + +* Fri Feb 2 2007 Hal Rosenstock - 1.2.0 +- OpenFabrics 1.2.0 release +- Added brief option to ibcheckerrors and ibcheckerrs +- Updated man pages +- Added build version to saquery and updated build version tags of other tools +- Added -N | nocolor to usage display of scripts +- Fixed -nocolor and -G options on scripts +- Fixed error return status in ibchecknet +- Added exit code to ibcheckerrors +- Added nodename to output of ibcheckerrs +- ibqueryerrors.pl fixes and improvements +- Removed use of tmpfile for ibroute data in ibfindnodeusing.pl +- Fixed undefined subroutine error in iblinkinfo.pl +- Added switch-map option to ibtracert and ibnetdiscover +- Cleaned up node descriptions before printing in saquery +- Clarified --src-to-dst option in saquery +- Added peer NodeDescription and LID to output of inbetdiscover +- For grouping, ordered Spine and Line Nodes (for Voltaire chassis) in ibnetdiscover +- Cleaned up node descriptions before printing in ibtracert and ibroute +- Added additional sematics to -m option of saquery +- Added dump_mfts.sh similar to dump_lfts.sh +- ibnetdiscover improvements (memory leaks, ports moving, etc.) +- Converted iblinkspeed.pl into iblinkinfo.pl and added additional capabilities +- Added 0x in front of GUID printing of ibtracert +- Fixed loopback handling in ibnetdiscover +- Added support for querying Service Records to saquery +- Added support for PerfMgt IsExtendedWidthSupported IBA 1.2 erratum in perfquery +- For query operations, added peer port checking of linkwidth and speed + active in ibportstate +- Added support for DrSLID in smpquery +- Added IB router support to ibnetdiscover and ibtracert +- Added additional options to saquery +- Added support to change LinkSpeedEnabled in ibportstate + +* Fri Sep 22 2006 Hal Rosenstock - 1.1.0 +- OpenFabrics 1.1 release + +* Wed Sep 13 2006 Hal Rosenstock - 1.1.0-rc5 +- OpenFabrics 1.1-rc5 release + +* Wed Sep 6 2006 Hal Rosenstock - 1.1.0-rc4 +- OpenFabrics 1.1-rc4 release + +* Wed Aug 23 2006 Hal Rosenstock - 1.1.0-rc3 +- OpenFabrics 1.1-rc3 release + +* Mon Aug 14 2006 Hal Rosenstock - 1.1.0-rc2 +- OpenFabrics 1.1-rc2 release +- Added ibsysstat man page + +* Wed Jul 26 2006 Hal Rosenstock - 1.1.0-rc1 +- OpenFabrics 1.1-rc1 release +- Added man pages +- Made diag command/script options more consistent +- saquery tool added +- dump_lft.sh script added +- Renamed discover.pl to ibdiscover.pl + +* Sun Jun 10 2006 Hal Rosenstock - 1.0-1 +- OpenFabrics 1.0 release + +* Tue May 30 2006 Hal Rosenstock - 1.0.0-rc6 +- Maintenance release + +* Fri May 12 2006 Hal Rosenstock - 1.0.0-rc5 +- Maintenance release + +* Thu Apr 27 2006 Hal Rosenstock - 1.0.0-rc4 +- Maintenance release +- Note rc3 skipped to sync with OFED + +* Mon Apr 10 2006 Hal Rosenstock - 1.0.0-rc2 +- Maintenance release + +* Mon Feb 27 2006 Hal Rosenstock - 1.0.0-rc1 +- Initial spec file and release diff --git a/contrib/ofed/management/infiniband-diags/man/check_lft_balance.8 b/contrib/ofed/management/infiniband-diags/man/check_lft_balance.8 new file mode 100644 index 000000000000..3eeca0ddf075 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/check_lft_balance.8 @@ -0,0 +1,42 @@ +.TH CHECK_LFT_BALANCE.SH 8 "March 1, 2008" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +check_lft_balance.sh \- check InfiniBand unicast forwarding tables balance + +.SH SYNOPSIS +.B check_lft_balance.sh +[-hRv] + + +.SH DESCRIPTION +.PP +check_lft_balance.sh is a script which checks for balancing in Infiniband +unicast forwarding tables. It analyzes the output of +.BR dump_lfts(8) +and +.BR iblinkinfo(8). + +.SH OPTIONS + +.PP +.TP +\fB\-h\fR +show help +.TP +\fB\-R\fR +Recalculate dump_lfts information, ie do not use the cached +information. This option is slower but should be used if the diag tools have +not been used for some time or if there are other reasons to believe that +the fabric has changed. +.TP +\fB\-v\fR +verbose output + +.SH SEE ALSO +.BR dump_lfts(8), +.BR iblinkinfo(8) + +.SH AUTHORS +.TP +Albert Chu +.RI < chu11@llnl.gov > diff --git a/contrib/ofed/management/infiniband-diags/man/dump_lfts.8 b/contrib/ofed/management/infiniband-diags/man/dump_lfts.8 new file mode 100644 index 000000000000..4498260c63b3 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/dump_lfts.8 @@ -0,0 +1,50 @@ +.TH DUMP_LFTS.SH 8 "May 21, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +dump_lfts.sh \- dump InfiniBand unicast forwarding tables + +.SH SYNOPSIS +.B dump_lfts.sh +[\-h] [\-D] [\-C ca_name] [\-P ca_port] [\-t(imeout) timeout_ms] [>/path/to/dump-file] + + +.SH DESCRIPTION +.PP +dump_lfts.sh is a script which dumps the InfiniBand unciast forwarding +tables (MFTs) in the switch nodes in the subnet. + +The dump file format is compatible with loading into OpenSM using +the -R file -U /path/to/dump-file syntax. + +.SH OPTIONS + +.PP +.TP +\fB\-D\fR +dump forwarding tables using direct routed rather than LID routed SMPs +.TP +\fB\-h\fR +show help +.TP +\fB\-C\fR +use the specified ca_name. +.TP +\fB\-P\fR +use the specified ca_port. +.TP +\fB\-t\fR +override the default timeout for the solicited mads. + +.SH SEE ALSO +.BR dump_mfts(8), +.BR ibroute(8), +.BR ibswitches(8), +.BR opensm(8) + +.SH AUTHORS +.TP +Sasha Khapyorsky +.RI < sashak@voltaire.com > +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/dump_mfts.8 b/contrib/ofed/management/infiniband-diags/man/dump_mfts.8 new file mode 100644 index 000000000000..885301e92b9f --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/dump_mfts.8 @@ -0,0 +1,45 @@ +.TH DUMP_MFTS.SH 8 "May 21, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +dump_lfts.sh \- dump InfiniBand multicast forwarding tables + +.SH SYNOPSIS +.B dump_mfts.sh +[\-h] [\-D] [\-C ca_name] [\-P ca_port] [\-t(imeout) timeout_ms] +[>/path/to/file] + +.SH DESCRIPTION +.PP +dump_mfts.sh is a script which dumps the InfiniBand multicast +forwarding tables (MFTs) in the switch nodes in the subnet. + +.SH OPTIONS + +.PP +.TP +\fB\-D\fR +dump forwarding tables using direct routed rather than LID routed SMPs +.TP +\fB\-h\fR +show help +.TP +\fB\-C\fR +use the specified ca_name. +.TP +\fB\-P\fR +use the specified ca_port. +.TP +\fB\-t\fR +override the default timeout for the solicited mads. + + +.SH SEE ALSO +.BR dump_lfts(8), +.BR ibroute(8), +.BR ibswitches(8), +.BR opensm(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibaddr.8 b/contrib/ofed/management/infiniband-diags/man/ibaddr.8 new file mode 100644 index 000000000000..622c6f99e91e --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibaddr.8 @@ -0,0 +1,109 @@ +.TH IBADDR 8 "June 18, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibaddr \- query InfiniBand address(es) + +.SH SYNOPSIS +.B ibaddr +[\-d(ebug)] [\-D(irect)] [\-G(uid)] [\-l(id_show)] [\-g(id_show)] [\-C ca_name] [\-P ca_port] [\-t(imeout) timeout_ms] [\-V(ersion)] [\-h(elp)] [] + +.SH DESCRIPTION +.PP +Display the lid (and range) as well as the GID address of the +port specified (by DR path, lid, or GUID) or the local port by default. +.PP +Note: this utility can be used as simple address resolver. + +.SH OPTIONS + +.PP +.TP +\fB\-G\fR, \fB\-\-Guid\fR +show lid range and gid for GUID address +.TP +\fB\-l\fR, \fB\-\-lid_show\fR +show lid range only +.TP +\fB\-L\fR, \fB\-\-Lid_show\fR +show lid range (in decimal) only +.TP +\fB\-g\fR, \fB\-\-gid_show\fR +show gid address only + +.SH COMMON OPTIONS + +Most OpenIB diagnostics take the following common flags. The exact list of +supported flags per utility can be found in the usage message and can be shown +using the util_name -h syntax. + +# Debugging flags +.PP +\-d raise the IB debugging level. + May be used several times (-ddd or -d -d -d). +.PP +\-e show send and receive errors (timeouts and others) +.PP +\-h show the usage message +.PP +\-v increase the application verbosity level. + May be used several times (-vv or -v -v -v) +.PP +\-V show the version info. + +# Addressing flags +.PP +\-D use directed path address arguments. The path + is a comma separated list of out ports. + Examples: + "0" # self port + "0,1,2,1,4" # out via port 1, then 2, ... +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-s use 'smlid' as the target lid for SM/SA queries. + +# Other common flags: +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +Multiple CA/Multiple Port Support + +When no IB device or port is specified, the port to use is selected +by the following criteria: +.PP +1. the first port that is ACTIVE. +.PP +2. if not found, the first port that is UP (physical link up). + +If a port and/or CA name is specified, the user request is +attempted to be fulfilled, and will fail if it is not possible. + +.SH EXAMPLES + +.PP +ibaddr # local port\'s address +.PP +ibaddr 32 # show lid range and gid of lid 32 +.PP +ibaddr -G 0x8f1040023 # same but using guid address +.PP +ibaddr -l 32 # show lid range only +.PP +ibaddr -L 32 # show decimal lid range only +.PP +ibaddr -g 32 # show gid address only + +.SH SEE ALSO +.BR ibroute (8), +.BR ibtracert (8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibcheckerrors.8 b/contrib/ofed/management/infiniband-diags/man/ibcheckerrors.8 new file mode 100644 index 000000000000..7c2467f875bb --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibcheckerrors.8 @@ -0,0 +1,41 @@ +.TH IBCHECKERRORS 8 "May 21, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibcheckerrors \- validate IB subnet and report errors + +.SH SYNOPSIS +.B ibcheckerrors +[\-h] [\-b] [\-v] [\-N | \-nocolor] [ | \-C ca_name +\-P ca_port \-t(imeout) timeout_ms] + +.SH DESCRIPTION +.PP +ibcheckerrors is a script which uses a full topology file that was created by +ibnetdiscover, scans the network to validate the connectivity and reports +errors (from port counters). + +.SH OPTIONS +.PP +\-v increase the verbosity level +.PP +\-b brief mode. Reduce the output to show only if errors are present, + not what they are. +.PP +\-N | \-nocolor use mono rather than color mode +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH SEE ALSO +.BR ibnetdiscover(8), +.BR ibchecknode(8), +.BR ibcheckport(8), +.BR ibcheckerrs(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibcheckerrs.8 b/contrib/ofed/management/infiniband-diags/man/ibcheckerrs.8 new file mode 100644 index 000000000000..f8aa8488f9e8 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibcheckerrs.8 @@ -0,0 +1,59 @@ +.TH IBCHECKERRS 8 "May 30, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibcheckerrs \- validate IB port (or node) and report errors in counters above threshold + +.SH SYNOPSIS +.B ibcheckerrs +[\-h] [\-b] [\-v] [\-G] [\-T ] [\-s(how_thresholds)] +[\-N | \-nocolor] [\-C ca_name] [\-P ca_port] [\-t(imeout) timeout_ms] + + + +.SH DESCRIPTION +.PP +Check specified port (or node) and report errors that surpassed their predefined +threshold. Port address is lid unless -G option is used to specify a GUID +address. The predefined thresholds can be dumped using the -s option, and a +user defined threshold_file (using the same format as the dump) can be +specified using the -t option. + +.SH OPTIONS +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-s show predefined thresholds +.PP +\-T use specified threshold file +.PP +\-v increase the verbosity level +.PP +\-b brief mode. Reduce the output to show only if errors are + present, not what they are. +.PP +\-N | \-nocolor use mono rather than color mode +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH EXAMPLE +.PP +ibcheckerrs 2 # check aggregated node counter for lid 2 +.PP +ibcheckerrs 2 4 # check port counters for lid 2 port 4 +.PP +ibcheckerrs -T xxx 2 # check node using xxx threshold file + +.SH SEE ALSO +.BR perfquery(8), +.BR ibaddr(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibchecknet.8 b/contrib/ofed/management/infiniband-diags/man/ibchecknet.8 new file mode 100644 index 000000000000..f90782387096 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibchecknet.8 @@ -0,0 +1,36 @@ +.TH IBCHECKNET 8 "May 21, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibchecknet \- validate IB subnet and report errors + +.SH SYNOPSIS +.B ibchecknet +[\-h] [\-N | \-nocolor] [ | \-C ca_name \-P ca_port +\-t(imeout) timeout_ms] + +.SH DESCRIPTION +.PP +ibchecknet is a script which uses a full topology file that was created +by ibnetdiscover, and scans the network to validate the connectivity and +reports errors (from port counters). + +.SH OPTIONS +.PP +\-N | \-nocolor use mono rather than color mode +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH SEE ALSO +.BR ibnetdiscover(8), +.BR ibchecknode(8), +.BR ibcheckport(8), +.BR ibcheckerrs(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibchecknode.8 b/contrib/ofed/management/infiniband-diags/man/ibchecknode.8 new file mode 100644 index 000000000000..3d65d8a45b0d --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibchecknode.8 @@ -0,0 +1,43 @@ +.TH IBCHECKNODE 8 "May 21, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibchecknode \- validate IB node and report errors + +.SH SYNOPSIS +.B ibchecknode +[\-h] [\-v] [\-N | \-nocolor] [\-G] [\-C ca_name] [\-P ca_port] +[\-t(imeout) timeout_ms] + +.SH DESCRIPTION +.PP +Check connectivity and do some simple sanity checks for the specified node. +Port address is a lid unless -G option is used to specify a GUID address. + +.SH OPTIONS +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-v increase the verbosity level +.PP +\-N | \-nocolor use mono rather than color mode +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH EXAMPLE +.PP +ibchecknode 2 # check node via lid 2 + +.SH SEE ALSO +.BR smpquery(8), +.BR ibaddr(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibcheckport.8 b/contrib/ofed/management/infiniband-diags/man/ibcheckport.8 new file mode 100644 index 000000000000..f01095b576ec --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibcheckport.8 @@ -0,0 +1,43 @@ +.TH IBCHECKPORT 8 "May 21, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibcheckport \- validate IB port and report errors + +.SH SYNOPSIS +.B ibcheckport +[\-h] [\-v] [\-N | \-nocolor] [\-G] [\-C ca_name] [\-P ca_port] +[\-t(imeout) timeout_ms] + +.SH DESCRIPTION +.PP +Check connectivity and do some simple sanity checks for the specified port. +Port address is a lid unless -G option is used to specify a GUID address. + +.SH OPTIONS +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-v increase the verbosity level +.PP +\-N | \-nocolor use mono rather than color mode +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH EXAMPLE +.PP +ibcheckport 2 3 # check lid 2 port 3 + +.SH SEE ALSO +.BR smpquery(8), +.BR ibaddr(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibcheckportstate.8 b/contrib/ofed/management/infiniband-diags/man/ibcheckportstate.8 new file mode 100644 index 000000000000..8d7f38b3d79d --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibcheckportstate.8 @@ -0,0 +1,44 @@ +.TH IBCHECKPORTSTATE 8 "May 21, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibcheckportstate \- validate IB port for LinkUp and not Active state + +.SH SYNOPSIS +.B ibcheckportstate +[\-h] [\-v] [\-N | \-nocolor] [\-G] [\-C ca_name] [\-P ca_port] +[\-t(imeout) timeout_ms] + +.SH DESCRIPTION +.PP +Check connectivity and check the specified port for proper port state +(Active) and port physical state (LinkUp). +Port address is a lid unless -G option is used to specify a GUID address. + +.SH OPTIONS +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-v increase the verbosity level +.PP +\-N | \-nocolor use mono rather than color mode +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH EXAMPLE +.PP +ibcheckportstate 2 3 # check lid 2 port 3 + +.SH SEE ALSO +.BR smpquery(8), +.BR ibaddr(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibcheckportwidth.8 b/contrib/ofed/management/infiniband-diags/man/ibcheckportwidth.8 new file mode 100644 index 000000000000..85c06fc04501 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibcheckportwidth.8 @@ -0,0 +1,43 @@ +.TH IBCHECKPORTWIDTH 8 "May 21, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibcheckportwidth \- validate IB port for 1x link width + +.SH SYNOPSIS +.B ibcheckport +[\-h] [\-v] [\-N | \-nocolor] [\-G] [\-C ca_name] [\-P ca_port] +[\-t(imeout) timeout_ms] + +.SH DESCRIPTION +.PP +Check connectivity and check the specified port for 1x link width. +Port address is a lid unless -G option is used to specify a GUID address. + +.SH OPTIONS +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-v increase the verbosity level +.PP +\-N | \-nocolor use mono rather than color mode +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH EXAMPLE +.PP +ibcheckportwidth 2 3 # check lid 2 port 3 + +.SH SEE ALSO +.BR smpquery(8), +.BR ibaddr(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibcheckstate.8 b/contrib/ofed/management/infiniband-diags/man/ibcheckstate.8 new file mode 100644 index 000000000000..89daeb88e625 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibcheckstate.8 @@ -0,0 +1,36 @@ +.TH IBCHECKSTATE 8 "May 21, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibcheckstate \- find ports in IB subnet which are link up but not active + +.SH SYNOPSIS +.B ibcheckstate +[\-h] [\-v] [\-N | \-nocolor] [ | \-C ca_name \-P ca_port +\-t(imeout) timeout_ms] + +.SH DESCRIPTION +.PP +ibcheckstat is a script which uses a full topology file that was created by +ibnetdiscover, scans the network to validate the port state and port physical +state, and reports any ports which have a port state other than Active or +a port physical state other than LinkUp. + +.SH OPTIONS +.PP +\-N | \-nocolor use mono rather than color mode +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH SEE ALSO +.BR ibnetdiscover(8), +.BR ibchecknode(8), +.BR ibcheckportstate(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibcheckwidth.8 b/contrib/ofed/management/infiniband-diags/man/ibcheckwidth.8 new file mode 100644 index 000000000000..1414fb2cb68d --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibcheckwidth.8 @@ -0,0 +1,36 @@ +.TH IBCHECKWIDTH 8 "May 21, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibcheckwidth \- find 1x links in IB subnet + +.SH SYNOPSIS +.B ibcheckwidth +[\-h] [\-v] [\-N | \-nocolor] [ | \-C ca_name +\-P ca_port \-t(imeout) timeout_ms] + + +.SH DESCRIPTION +.PP +ibcheckwidth is a script which uses a full topology file that was created by +ibnetdiscover, scans the network to validate the active link widths and +reports any 1x links. + +.SH OPTIONS +.PP +\-N | \-nocolor use mono rather than color mode +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH SEE ALSO +.BR ibnetdiscover(8), +.BR ibchecknode(8), +.BR ibcheckportwidth(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibclearcounters.8 b/contrib/ofed/management/infiniband-diags/man/ibclearcounters.8 new file mode 100644 index 000000000000..1fca7bd9809f --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibclearcounters.8 @@ -0,0 +1,30 @@ +.TH IBCLEARCOUNTERS 8 "May 21, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibclearcounters \- clear port counters in IB subnet + +.SH SYNOPSIS +.B ibclearcounters +[\-h] [ | \-C ca_name \-P ca_port \-t(imeout) timeout_ms] + +.SH DESCRIPTION +.PP +ibclearcounters is a script that clears the PMA port counters by either walking +the IB subnet topology or using an already saved topology file. + +.SH OPTIONS +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH SEE ALSO +.BR ibnetdiscover(8), +.BR perfquery(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibclearerrors.8 b/contrib/ofed/management/infiniband-diags/man/ibclearerrors.8 new file mode 100644 index 000000000000..7692c64917e8 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibclearerrors.8 @@ -0,0 +1,34 @@ +.TH IBCLEARERRORS 8 "May 21, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibclearerrors \- clear error counters in IB subnet + +.SH SYNOPSIS +.B ibclearerrors +[\-h] [\-N | \-nocolor] [ | \-C ca_name \-P ca_port +\-t(imeout) timeout_ms] + +.SH DESCRIPTION +.PP +ibclearerrors is a script which clears the PMA error counters in PortCounters +by either walking the IB subnet topology or using an already saved topology +file. + +.SH OPTIONS +.PP +\-N | \-nocolor use mono rather than color mode +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH SEE ALSO +.BR ibnetdiscover(8), +.BR perfquery(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibdatacounters.8 b/contrib/ofed/management/infiniband-diags/man/ibdatacounters.8 new file mode 100644 index 000000000000..60fec8f90bc0 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibdatacounters.8 @@ -0,0 +1,38 @@ +.TH IBDATACOUNTERS 8 "May 31, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibdatacounters \- query IB subnet for data counters + +.SH SYNOPSIS +.B ibdatacounters +[\-h] [\-b] [\-v] [\-N | \-nocolor] [ | \-C ca_name \-P ca_port \-t(imeout) timeout_ms] + +.SH DESCRIPTION +.PP +ibdatacounters is a script which uses a full topology file that was created by +ibnetdiscover, scans the network to validate the connectivity and reports +the data counters (from port counters). + +.SH OPTIONS +.PP +\-v increase the verbosity level +.PP +\-b brief mode. Reduce the output to show only if errors are present, + not what they are. +.PP +\-N | \-nocolor use mono rather than color mode +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH SEE ALSO +.BR ibnetdiscover(8), +.BR ibdatacounts(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibdatacounts.8 b/contrib/ofed/management/infiniband-diags/man/ibdatacounts.8 new file mode 100644 index 000000000000..d1b31e3fa385 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibdatacounts.8 @@ -0,0 +1,48 @@ +.TH IBDATACOUNTS 8 "May 30, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibdatacounts \- get IB port data counters + +.SH SYNOPSIS +.B ibdatacounts +[\-h] [\-b] [\-v] [\-G] [\-N | \-nocolor] [\-C ca_name] [\-P ca_port] +[\-t(imeout) timeout_ms] [] + +.SH DESCRIPTION +.PP +Obtain PMA data counters from specified port (or node). +Port address is lid unless -G option is used to specify a GUID +address. + +.SH OPTIONS +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-v increase the verbosity level +.PP +\-b brief mode +.PP +\-N | \-nocolor use mono rather than color mode +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH EXAMPLE +.PP +ibdatacounts 2 # show data counters for lid 2 +.PP +ibdatacounts 2 4 # show data counters for lid 2 port 4 + +.SH SEE ALSO +.BR perfquery(8), +.BR ibaddr(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibdiscover.8 b/contrib/ofed/management/infiniband-diags/man/ibdiscover.8 new file mode 100644 index 000000000000..5e1e019191d7 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibdiscover.8 @@ -0,0 +1,50 @@ +.TH IBDISCOVER.PL 8 "September 21, 2006" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibdiscover.pl \- annotate and compare InfiniBand topology + +.SH SYNOPSIS +.B ibdiscover.pl + +.SH DESCRIPTION +.PP +ibdiscover.pl uses a topology file create by ibnetdiscover and a discover.map +file which the network administrator creates which indicates the nodes +to be expected and a ibdiscover.topo file which is the expected connectivity +and produces a new connectivity file (discover.topo.new) and outputs +the changes to stdout. The network administrator can choose to replace +the "old" topo file with the new one or certain changes in. + +The syntax of the ibdiscover.map file is: + +|port|"Text for node"| + +e.g. + +8f10400410015|8|"ISR 6000"|# SW-6IB4 Voltaire port 0 lid 5 + +8f10403960558|2|"HCA 1"|# MT23108 InfiniHost Mellanox Technologies + +The syntax of the old and new topo files (ibdiscover.topo and +ibdiscover.topo.new) are: + +||| + +e.g. + +10|5442ba00003080|1|8f10400410015 + +These topo files are produced by the ibdiscover.pl tool. + +.SH USAGE + +.PP +ibnetdiscover | ibdiscover.pl + +.SH SEE ALSO +.BR ibnetdiscover(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibfindnodesusing.8 b/contrib/ofed/management/infiniband-diags/man/ibfindnodesusing.8 new file mode 100644 index 000000000000..d5e3e68aaef6 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibfindnodesusing.8 @@ -0,0 +1,30 @@ +.TH IBFINDNODESUSING 8 "May 22, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibfindnodesusing.pl \- find a list of end nodes which are routed through the specified switch and port + +.SH SYNOPSIS +.B ibfindnodesusing.pl +[-R] + +.SH DESCRIPTION +.PP +ibfindnodesusing.pl uses ibroute and detects the current nodes which are routed +through both directions of the link specified. The link is specified by one +switch port end; the script finds the remote end automatically. + + +.SH OPTIONS + +.PP +.TP +\fB\-R\fR +Recalculate the ibnetdiscover information, ie do not use the cached +information. This option is slower but should be used if the diag tools have +not been used for some time or if there are other reasons to believe that +the fabric has changed. + +.SH AUTHOR +.TP +Ira Weiny +.RI < weiny2@llnl.gov > diff --git a/contrib/ofed/management/infiniband-diags/man/ibhosts.8 b/contrib/ofed/management/infiniband-diags/man/ibhosts.8 new file mode 100644 index 000000000000..db3c8ce8951b --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibhosts.8 @@ -0,0 +1,31 @@ +.TH IBHOSTS 8 "July 25, 2006" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibhosts \- show InfiniBand host nodes in topology + +.SH SYNOPSIS +.B ibhosts +[\-h] [ | \-C ca_name \-P ca_port \-t(imeout) timeout_ms] + +.SH DESCRIPTION +.PP +ibhosts is a script which either walks the IB subnet topology or uses an +already saved topology file and extracts the CA nodes. + +.SH OPTIONS +.PP +\-h show the usage message +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH SEE ALSO +.BR ibnetdiscover(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibidsverify.8 b/contrib/ofed/management/infiniband-diags/man/ibidsverify.8 new file mode 100644 index 000000000000..f42fd44f20df --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibidsverify.8 @@ -0,0 +1,36 @@ +.TH IBIDSVERIFY 8 "June 1, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibidsverify.pl \- validate IB identifiers in subnet and report errors + +.SH SYNOPSIS +.B ibidsverify.pl +[\-h] [\-R] + +.SH DESCRIPTION +.PP +ibidsverify.pl is a perl script which uses a full topology file that was created +by ibnetdiscover, scans the network to validate the LIDs and GUIDs in the +subnet. The validation consists of checking that there are no zero or duplicate +identifiers. + +Finally, ibidsverify.pl will also reuse the cached ibnetdiscover output from +some of the other diag tools which makes it a bit faster than running +ibnetdiscover from scratch. + +.SH OPTIONS +.PP +.TP +\fB\-R\fR +Recalculate the ibnetdiscover information, ie do not use the cached +information. This option is slower but should be used if the diag tools have +not been used for some time or if there are other reasons to believe the +fabric has changed. + +.SH SEE ALSO +.BR ibnetdiscover(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/iblinkinfo.8 b/contrib/ofed/management/infiniband-diags/man/iblinkinfo.8 new file mode 100644 index 000000000000..ebb03945c064 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/iblinkinfo.8 @@ -0,0 +1,52 @@ +.TH IBLINKINFO 8 "Jan 24, 2008" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +iblinkinfo.pl \- report link info for all links in the fabric + +.SH SYNOPSIS +.B iblinkinfo.pl + [-Rhcdl -C -P -v -S -D ] + +.SH DESCRIPTION +.PP +iblinkinfo.pl reports the link info for each port of each switch active in the +IB fabric. + +.SH OPTIONS + +.PP +.TP +\fB\-R\fR +Recalculate the ibnetdiscover information, ie do not use the cached +information. This option is slower but should be used if the diag tools have +not been used for some time or if there are other reasons to believe the +fabric has changed. +.TP +\fB\-S \fR +Output only the switch specified by (hex format) +.TP +\fB\-D \fR +Output only the switch specified by the direct route path. +.TP +\fB\-l\fR +Print all information for each link on one line. Default is to print a header +with the switch information and then a list for each port (useful for grep\'ing output). +.TP +\fB\-d\fR +Print only switches which have a port in the "Down" state. +.TP +\fB\-v \fR +Verify additional switch settings (,,) +.TP +\fB\-c\fR +Print port capabilities (enabled and supported values) +.TP +\fB\-C \fR use the specified ca_name for the search. +.TP +\fB\-P \fR use the specified ca_port for the search. + + +.SH AUTHOR +.TP +Ira Weiny +.RI < weiny2@llnl.gov > diff --git a/contrib/ofed/management/infiniband-diags/man/ibnetdiscover.8 b/contrib/ofed/management/infiniband-diags/man/ibnetdiscover.8 new file mode 100644 index 000000000000..958efa999a22 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibnetdiscover.8 @@ -0,0 +1,233 @@ +.TH IBNETDISCOVER 8 "January 3, 2008" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibnetdiscover \- discover InfiniBand topology + +.SH SYNOPSIS +.B ibnetdiscover +[\-d(ebug)] [\-e(rr_show)] [\-v(erbose)] [\-s(how)] [\-l(ist)] [\-g(rouping)] [\-H(ca_list)] [\-S(witch_list)] [\-R(outer_list)] [\-C ca_name] [\-P ca_port] [\-t(imeout) timeout_ms] [\-V(ersion)] [\--node-name-map ] [\-p(orts)] [\-h(elp)] [] + +.SH DESCRIPTION +.PP +ibnetdiscover performs IB subnet discovery and outputs a human readable +topology file. GUIDs, node types, and port numbers are displayed +as well as port LIDs and NodeDescriptions. All nodes (and links) are displayed +(full topology). Optionally, this utility can be used to list the current +connected nodes by nodetype. The output is printed to standard output +unless a topology file is specified. + +.SH OPTIONS + +.PP +.TP +\fB\-l\fR, \fB\-\-list\fR +List of connected nodes +.TP +\fB\-g\fR, \fB\-\-grouping\fR +Show grouping. Grouping correlates IB nodes by different vendor specific +schemes. It may also show the switch external ports correspondence. +.TP +\fB\-H\fR, \fB\-\-Hca_list\fR +List of connected CAs +.TP +\fB\-S\fR, \fB\-\-Switch_list\fR +List of connected switches +.TP +\fB\-R\fR, \fB\-\-Router_list\fR +List of connected routers +.TP +\fB\-s\fR, \fB\-\-show\fR +Show more information +.TP +\fB\-\-node\-name\-map\fR +Specify a node name map. The node name map file maps GUIDs to more user friendly +names. See file format below. +.TP +\fB\-p\fR, \fB\-\-ports\fR +Obtain a ports report which is a +list of connected ports with relevant information (like LID, portnum, +GUID, width, speed, and NodeDescription). + +.SH COMMON OPTIONS + +Most OpenIB diagnostics take the following common flags. The exact list of +supported flags per utility can be found in the usage message and can be shown +using the util_name -h syntax. + +# Debugging flags +.PP +\-d raise the IB debugging level. + May be used several times (-ddd or -d -d -d). +.PP +\-e show send and receive errors (timeouts and others) +.PP +\-h show the usage message +.PP +\-v increase the application verbosity level. + May be used several times (-vv or -v -v -v) +.PP +\-V show the version info. + +# Other common flags: +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +Multiple CA/Multiple Port Support + +When no IB device or port is specified, the port to use is selected +by the following criteria: +.PP +1. the first port that is ACTIVE. +.PP +2. if not found, the first port that is UP (physical link up). + +If a port and/or CA name is specified, the user request is +attempted to be fulfilled, and will fail if it is not possible. + +.SH TOPOLOGY FILE FORMAT +The topology file format is human readable and largely intuitive. +Most identifiers are given textual names like vendor ID (vendid), device ID +(device ID), GUIDs of various types (sysimgguid, caguid, switchguid, etc.). +PortGUIDs are shown in parentheses (). For switches, this is shown on the +switchguid line. For CA and router ports, it is shown on the connectivity lines. The IB node is identified followed by the number of ports and a quoted +the node GUID. On the right of this line is a comment (#) followed by the +NodeDescription in quotes. If the node is a switch, this line also contains +whether switch port 0 is base or enhanced, and the LID and LMC of port 0. +Subsequent lines pertaining to this node show the connectivity. On the +left is the port number of the current node. On the right is the peer node +(node at other end of link). It is identified in quotes with nodetype +followed by - followed by NodeGUID with the port number in square brackets. +Further on the right is a comment (#). What follows the comment is +dependent on the node type. If it it a switch node, it is followed by +the NodeDescription in quotes and the LID of the peer node. If it is a +CA or router node, it is followed by the local LID and LMC and then +followed by the NodeDescription in quotes and the LID of the peer node. +The active link width and speed are then appended to the end of this +output line. + +An example of this is: +.nf +# +# Topology file: generated on Tue Jun 5 14:15:10 2007 +# +# Max of 3 hops discovered +# Initiated from node 0008f10403960558 port 0008f10403960559 + +Non-Chassis Nodes + +vendid=0x8f1 +devid=0x5a06 +sysimgguid=0x5442ba00003000 +switchguid=0x5442ba00003080(5442ba00003080) +Switch 24 "S-005442ba00003080" # "ISR9024 Voltaire" base port 0 lid 6 lmc 0 +[22] "H-0008f10403961354"[1](8f10403961355) # "MT23108 InfiniHost Mellanox Technologies" lid 4 4xSDR +[10] "S-0008f10400410015"[1] # "SW-6IB4 Voltaire" lid 3 4xSDR +[8] "H-0008f10403960558"[2](8f1040396055a) # "MT23108 InfiniHost Mellanox Technologies" lid 14 4xSDR +[6] "S-0008f10400410015"[3] # "SW-6IB4 Voltaire" lid 3 4xSDR +[12] "H-0008f10403960558"[1](8f10403960559) # "MT23108 InfiniHost Mellanox Technologies" lid 10 4xSDR + +vendid=0x8f1 +devid=0x5a05 +switchguid=0x8f10400410015(8f10400410015) +Switch 8 "S-0008f10400410015" # "SW-6IB4 Voltaire" base port 0 lid 3 lmc 0 +[6] "H-0008f10403960984"[1](8f10403960985) # "MT23108 InfiniHost Mellanox Technologies" lid 16 4xSDR +[4] "H-005442b100004900"[1](5442b100004901) # "MT23108 InfiniHost Mellanox Technologies" lid 12 4xSDR +[1] "S-005442ba00003080"[10] # "ISR9024 Voltaire" lid 6 1xSDR +[3] "S-005442ba00003080"[6] # "ISR9024 Voltaire" lid 6 4xSDR + +vendid=0x2c9 +devid=0x5a44 +caguid=0x8f10403960984 +Ca 2 "H-0008f10403960984" # "MT23108 InfiniHost Mellanox Technologies" +[1](8f10403960985) "S-0008f10400410015"[6] # lid 16 lmc 1 "SW-6IB4 Voltaire" lid 3 4xSDR + +vendid=0x2c9 +devid=0x5a44 +caguid=0x5442b100004900 +Ca 2 "H-005442b100004900" # "MT23108 InfiniHost Mellanox Technologies" +[1](5442b100004901) "S-0008f10400410015"[4] # lid 12 lmc 1 "SW-6IB4 Voltaire" lid 3 4xSDR + +vendid=0x2c9 +devid=0x5a44 +caguid=0x8f10403961354 +Ca 2 "H-0008f10403961354" # "MT23108 InfiniHost Mellanox Technologies" +[1](8f10403961355) "S-005442ba00003080"[22] # lid 4 lmc 1 "ISR9024 Voltaire" lid 6 4xSDR + +vendid=0x2c9 +devid=0x5a44 +caguid=0x8f10403960558 +Ca 2 "H-0008f10403960558" # "MT23108 InfiniHost Mellanox Technologies" +[2](8f1040396055a) "S-005442ba00003080"[8] # lid 14 lmc 1 "ISR9024 Voltaire" lid 6 4xSDR +[1](8f10403960559) "S-005442ba00003080"[12] # lid 10 lmc 1 "ISR9024 Voltaire" lid 6 1xSDR +.fi + +When grouping is used, IB nodes are organized into chasses which are +numbered. Nodes which cannot be determined to be in a chassis are +displayed as "Non-Chassis Nodes". External ports are also shown on the +connectivity lines. + + +.SH NODE NAME MAP FILE FORMAT +The node name map is used to specify user friendly names for nodes in the +output. GUIDs are used to perform the lookup. + +.TP +\fBGenerically:\fR + +# comment +.br + "" + +.TP +\fBExample:\fR + +# IB1 +.br +# Line cards +.br +0x0008f104003f125c "IB1 (Rack 11 slot 1 ) ISR9288/ISR9096 Voltaire sLB-24D" +.br +0x0008f104003f125d "IB1 (Rack 11 slot 1 ) ISR9288/ISR9096 Voltaire sLB-24D" +.br +0x0008f104003f10d2 "IB1 (Rack 11 slot 2 ) ISR9288/ISR9096 Voltaire sLB-24D" +.br +0x0008f104003f10d3 "IB1 (Rack 11 slot 2 ) ISR9288/ISR9096 Voltaire sLB-24D" +.br +0x0008f104003f10bf "IB1 (Rack 11 slot 12 ) ISR9288/ISR9096 Voltaire sLB-24D" +.br +.br +# Spines +.br +0x0008f10400400e2d "IB1 (Rack 11 spine 1 ) ISR9288 Voltaire sFB-12D" +.br +0x0008f10400400e2e "IB1 (Rack 11 spine 1 ) ISR9288 Voltaire sFB-12D" +.br +0x0008f10400400e2f "IB1 (Rack 11 spine 1 ) ISR9288 Voltaire sFB-12D" +.br +0x0008f10400400e31 "IB1 (Rack 11 spine 2 ) ISR9288 Voltaire sFB-12D" +.br +0x0008f10400400e32 "IB1 (Rack 11 spine 2 ) ISR9288 Voltaire sFB-12D" +.br +.br +# GUID Node Name +.br +0x0008f10400411a08 "SW1 (Rack 3) ISR9024 Voltaire 9024D" +.br +0x0008f10400411a28 "SW2 (Rack 3) ISR9024 Voltaire 9024D" +.br +0x0008f10400411a34 "SW3 (Rack 3) ISR9024 Voltaire 9024D" +.br +0x0008f104004119d0 "SW4 (Rack 3) ISR9024 Voltaire 9024D" +.br + +.SH AUTHORS +.TP +Hal Rosenstock +.RI < halr@voltaire.com > +.TP +Ira Weiny +.RI < weiny2@llnl.gov > diff --git a/contrib/ofed/management/infiniband-diags/man/ibnodes.8 b/contrib/ofed/management/infiniband-diags/man/ibnodes.8 new file mode 100644 index 000000000000..901665d86d0d --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibnodes.8 @@ -0,0 +1,31 @@ +.TH IBNODES 8 "July 25, 2006" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibnodes \- show InfiniBand nodes in topology + +.SH SYNOPSIS +.B ibnodes +[\-h] [ | \-C ca_name \-P ca_port \-t(imeout) timeout_ms] + +.SH DESCRIPTION +.PP +ibnodes is a script which either walks the IB subnet topology or uses an +already saved topology file and extracts the IB nodes (CAs and switches). + +.SH OPTIONS +.PP +\-h show the usage message +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. +.SH SEE ALSO + +.BR ibnetdiscover(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibping.8 b/contrib/ofed/management/infiniband-diags/man/ibping.8 new file mode 100644 index 000000000000..c25fc8dd542b --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibping.8 @@ -0,0 +1,84 @@ +.TH IBPING 8 "August 11, 2006" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibping \- ping an InfiniBand address + +.SH SYNOPSIS +.B ibping +[\-d(ebug)] [\-e(rr_show)] [\-v(erbose)] [\-G(uid)] [\-C ca_name] [\-P ca_port] [\-s smlid] [\-t(imeout) timeout_ms] [\-V(ersion)] [\-c ping_count] [\-f(lood)] [\-o oui] [\-S(erver)] [\-h(elp)] + +.SH DESCRIPTION +.PP +ibping uses vendor mads to validate connectivity between IB nodes. +On exit, (IP) ping like output is show. ibping is run as client/server. +Default is to run as client. Note also that a default ping server is +implemented within the kernel. + +.SH OPTIONS + +.PP +.TP +\fB\-c\fR +stop after count packets +.TP +\fB\-f\fR, \fB\-\-flood\fR +flood destination: send packets back to back without delay +.TP +\fB\-o\fR, \fB\-\-oui\fR +use specified OUI number to multiplex vendor mads +.TP +\fB\-S\fR, \fB\-\-Server\fR +start in server mode (do not return) + +.SH COMMON OPTIONS + +Most OpenIB diagnostics take the following common flags. The exact list of +supported flags per utility can be found in the usage message and can be shown +using the util_name -h syntax. + +# Debugging flags +.PP +\-d raise the IB debugging level. + May be used several times (-ddd or -d -d -d). +.PP +\-e show send and receive errors (timeouts and others) +.PP +\-h show the usage message +.PP +\-v increase the application verbosity level. + May be used several times (-vv or -v -v -v) +.PP +\-V show the version info. + +# Addressing flags +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-s use 'smlid' as the target lid for SM/SA queries. + +# Other common flags: +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +Multiple CA/Multiple Port Support + +When no IB device or port is specified, the port to use is selected +by the following criteria: +.PP +1. the first port that is ACTIVE. +.PP +2. if not found, the first port that is UP (physical link up). + +If a port and/or CA name is specified, the user request is +attempted to be fulfilled, and will fail if it is not possible. + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibportstate.8 b/contrib/ofed/management/infiniband-diags/man/ibportstate.8 new file mode 100644 index 000000000000..0306f29f5286 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibportstate.8 @@ -0,0 +1,113 @@ +.TH IBPORTSTATE 8 "October 19, 2006" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibportstate \- handle port (physical) state and link speed of an InfiniBand port + +.SH SYNOPSIS +.B ibportstate +[\-d(ebug)] [\-e(rr_show)] [\-v(erbose)] [\-D(irect)] [\-G(uid)] [\-s smlid] [\-V(ersion)] [\-C ca_name] [\-P ca_port] [\-t(imeout) timeout_ms] [\-h(elp)] [] + +.SH DESCRIPTION +.PP +ibportstate allows the port state and port physical state of an IB port +to be queried (in addition to link width and speed being validated +relative to the peer port when the port queried is a switch port), +or a switch port to be disabled, enabled, or reset. It +also allows the link speed enabled on any IB port to be adjusted. + +.SH OPTIONS + +.PP +.TP +op +Port operations allowed + supported ops: enable, disable, reset, speed, query + Default is query +.PP + ops enable, disable, and reset are only allowed on switch ports + (An error is indicated if attempted on CA or router ports) + speed op is allowed on any port + speed values are legal values for PortInfo:LinkSpeedEnabled + (An error is indicated if PortInfo:LinkSpeedSupported does not support + this setting) + (NOTE: Speed changes are not effected until the port goes through + link renegotiation) + query also validates port characteristics (link width and speed) + based on the peer port. This checking is done when the port + queried is a switch port as it relies on combined routing + (an initial LID route with directed routing to the peer) which + can only be done on a switch. This peer port validation feature + of query op requires LID routing to be functioning in the subnet. + + +.SH COMMON OPTIONS + +Most OpenIB diagnostics take the following common flags. The exact list of +supported flags per utility can be found in the usage message and can be shown +using the util_name -h syntax. + +# Debugging flags +.PP +\-d raise the IB debugging level. + May be used several times (-ddd or -d -d -d). +.PP +\-e show send and receive errors (timeouts and others) +.PP +\-h show the usage message +.PP +\-v increase the application verbosity level. + May be used several times (-vv or -v -v -v) +.PP +\-V show the version info. + +# Addressing flags +.PP +\-D use directed path address arguments. The path + is a comma separated list of out ports. + Examples: + "0" # self port + "0,1,2,1,4" # out via port 1, then 2, ... +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-s use 'smlid' as the target lid for SM/SA queries. + +# Other common flags: +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +Multiple CA/Multiple Port Support + +When no IB device or port is specified, the port to use is selected +by the following criteria: +.PP +1. the first port that is ACTIVE. +.PP +2. if not found, the first port that is UP (physical link up). + +If a port and/or CA name is specified, the user request is +attempted to be fulfilled, and will fail if it is not possible. + +.SH EXAMPLES + +.PP +ibportstate 3 1 disable # by lid +.PP +ibportstate -G 0x2C9000100D051 1 enable # by guid +.PP +ibportstate -D 0 1 # (query) by direct route +.PP +ibportstate 3 1 reset # by lid +.PP +ibportstate 3 1 speed 1 # by lid + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibprintca.8 b/contrib/ofed/management/infiniband-diags/man/ibprintca.8 new file mode 100644 index 000000000000..ae304f785d46 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibprintca.8 @@ -0,0 +1,44 @@ +.TH IBPRINTCA 8 "May 31, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibprintca.pl \- print either the ca specified or the list of cas from the ibnetdiscover output + +.SH SYNOPSIS +.B ibprintca.pl +[-R -l -C -P ] [] + +.SH DESCRIPTION +.PP +Faster than greping/viewing with an editor the output of ibnetdiscover, +ibprintca.pl will parse out and print either the CA information for the +specified CA or a list of all the CAs in the subnet. + +Finally, ibprintca.pl will also reuse the cached ibnetdiscover output from +some of the other diag tools which makes it a bit faster than running +ibnetdiscover from scratch. + + +.SH OPTIONS + +.PP +.TP +\fB\-l\fR +List the CAs (simply a wrapper for ibhosts). +.TP +\fB\-R\fR +Recalculate the ibnetdiscover information, ie do not use the cached +information. This option is slower but should be used if the diag tools have +not been used for some time or if there are other reasons to believe that +the fabric has changed. +.TP +\fB\-C \fR use the specified ca_name for the search. +.TP +\fB\-P \fR use the specified ca_port for the search. + +.SH AUTHORS +.TP +Ira Weiny +.RI < weiny2@llnl.gov > +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibprintrt.8 b/contrib/ofed/management/infiniband-diags/man/ibprintrt.8 new file mode 100644 index 000000000000..4929586c0c44 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibprintrt.8 @@ -0,0 +1,42 @@ +.TH IBPRINTRT 8 "May 31, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibprintrt.pl \- print either only the router specified or a list of routers from the ibnetdiscover output + +.SH SYNOPSIS +.B ibprintrt.pl +[-R -l -C -P ] [] + +.SH DESCRIPTION +.PP +Faster than greping/viewing with an editor the output of ibnetdiscover, +ibprintrt.pl will parse out and print either the router information for the +specified IB router or a list of all IB routers in the subnet. + +Finally, ibprintrt.pl will also reuse the cached ibnetdiscover output from +some of the other diag tools which makes it a bit faster than running +ibnetdiscover from scratch. + + +.SH OPTIONS + +.PP +.TP +\fB\-l\fR +List the Rts (simply a wrapper for ibrouters). +.TP +\fB\-R\fR +Recalculate the ibnetdiscover information, ie do not use the cached +information. This option is slower but should be used if the diag tools have +not been used for some time or if there are other reasons to believe that +the fabric has changed. +.TP +\fB\-C \fR use the specified ca_name for the search. +.TP +\fB\-P \fR use the specified ca_port for the search. + + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibprintswitch.8 b/contrib/ofed/management/infiniband-diags/man/ibprintswitch.8 new file mode 100644 index 000000000000..11e0a8789122 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibprintswitch.8 @@ -0,0 +1,47 @@ +.TH IBPRINTSWITCH 8 "May 31, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibprintswitch.pl \- print either the switch specified or a list of switches from the ibnetdiscover output + +.SH SYNOPSIS +.B ibprintswitch.pl +[-R -l -C -P ] [] + +.SH DESCRIPTION +.PP +Faster than greping/viewing with an editor the output of ibnetdiscover, +ibprintswitch.pl will parse out and print either the switch information for the +switch specified or a list of all the switches found in the subnet. +In addition, it will crudely parse on the node description +information and if found report all the information for an entire chasis if the +description information is consistent. + +Finally, ibprintswitch.pl will also reuse the cached ibnetdiscover output from +some of the other diag tools which makes it a bit faster than running +ibnetdiscover from scratch. + +.SH OPTIONS + +.PP +.TP +\fB\-l\fR +List the switches (simply a wrapper for ibswitches). +.TP +\fB\-R\fR +Recalculate the ibnetdiscover information, ie do not use the cached +information. This option is slower but should be used if the diag tools have +not been used for some time or if there are other reasons to believe that +the fabric has changed. +.TP +\fB\-C \fR use the specified ca_name for the search. +.TP +\fB\-P \fR use the specified ca_port for the search. + + +.SH AUTHORS +.TP +Ira Weiny +.RI < weiny2@llnl.gov > +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibqueryerrors.8 b/contrib/ofed/management/infiniband-diags/man/ibqueryerrors.8 new file mode 100644 index 000000000000..5c7eb179f67c --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibqueryerrors.8 @@ -0,0 +1,63 @@ +.TH IBQUERYERRORS 8 "Jan 24, 2008" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibqueryerrors.pl \- query and report non-zero IB port counters + +.SH SYNOPSIS +.B ibqueryerrors.pl +[-a -c -r -R -C -P -s -S -D -d] + +.SH DESCRIPTION +.PP +ibqueryerrors.pl reports the port counters of switches. This is similar to +ibcheckerrors with the additional ability to filter out selected errors, +include the optional transmit and receive data counters, report actions to +remedy a non-zero count, and report full link information for the link +reported. + +.SH OPTIONS + +.PP +.TP +\fB\-a\fR +Report an action to take. Some of the counters are not errors in and of +themselves. This reports some more information on what the counters mean and +what actions can/should be taken if they are non-zero. +.TP +\fB\-c\fR +Suppress some of the common "side effect" counters. These counters usually do +not indicate an error condition and can be usually be safely ignored. +.TP +\fB\-r\fR +Report the port information. This includes LID, port, external port (if +applicable), link speed setting, remote GUID, remote port, remote external port +(if applicable), and remote node description information. +.TP +\fB\-R\fR +Recalculate the ibnetdiscover information, ie do not use the cached +information. This option is slower but should be used if the diag tools have +not been used for some time or if there are other reasons to believe that +the fabric has changed. +.TP +\fB\-s \fR +Suppress the errors listed in the comma separated list provided. +.TP +\fB\-S \fR +Report results only for the switch specified. (hex format) +.TP +\fB\-D \fR +Report results only for the switch specified by the direct route path. +.TP +\fB\-d\fR +Include the optional transmit and receive data counters. +.TP +\fB\-C \fR use the specified ca_name for the search. +.TP +\fB\-P \fR use the specified ca_port for the search. + + +.SH AUTHOR +.TP +Ira Weiny +.RI < weiny2@llnl.gov > + diff --git a/contrib/ofed/management/infiniband-diags/man/ibroute.8 b/contrib/ofed/management/infiniband-diags/man/ibroute.8 new file mode 100644 index 000000000000..9f28477c0224 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibroute.8 @@ -0,0 +1,119 @@ +.TH IBROUTE 8 "July 25, 2006" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibroute \- query InfiniBand switch forwarding tables + +.SH SYNOPSIS +.B ibroute +[\-d(ebug)] [-a(ll)] [-n(o_dests)] [-v(erbose)] [\-D(irect)] [\-G(uid)] [-M(ulticast)] [-s smlid] [\-C ca_name] [\-P ca_port] [\-t(imeout) timeout_ms] [\-V(ersion)] [\-h(elp)] [ [ []]] + +.SH DESCRIPTION +.PP +ibroute uses SMPs to display the forwarding tables (unicast +(LinearForwardingTable or LFT) or multicast (MulticastForwardingTable or MFT)) +for the specified switch LID and the optional lid (mlid) range. +The default range is all valid entries in the range 1...FDBTop. + +.SH OPTIONS + +.PP +.TP +\fB\-a\fR, \fB\-\-all\fR +show all lids in range, even invalid entries +.TP +\fB\-n\fR, \fB\-\-no_dests\fR +do not try to resolve destinations +.TP +\fB\-M\fR, \fB\-\-Multicast\fR +show multicast forwarding tables +In this case, the range parameters are specifying the mlid range. + +.SH COMMON OPTIONS + +Most OpenIB diagnostics take the following common flags. The exact list of +supported flags per utility can be found in the usage message and can be shown +using the util_name -h syntax. + +# Debugging flags +.PP +\-d raise the IB debugging level. + May be used several times (-ddd or -d -d -d). +.PP +\-e show send and receive errors (timeouts and others) +.PP +\-h show the usage message +.PP +\-v increase the application verbosity level. + May be used several times (-vv or -v -v -v) +.PP +\-V show the version info. + +# Addressing flags +.PP +\-D use directed path address arguments. The path + is a comma separated list of out ports. + Examples: + "0" # self port + "0,1,2,1,4" # out via port 1, then 2, ... +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-s use 'smlid' as the target lid for SM/SA queries. + +# Other common flags: +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +Multiple CA/Multiple Port Support + +When no IB device or port is specified, the port to use is selected +by the following criteria: +.PP +1. the first port that is ACTIVE. +.PP +2. if not found, the first port that is UP (physical link up). + +If a port and/or CA name is specified, the user request is +attempted to be fulfilled, and will fail if it is not possible. + +.SH EXAMPLES + +.PP +Unicast examples +.PP +ibroute 4 # dump all lids with valid out ports of switch with lid 4 +.PP +ibroute -a 4 # same, but dump all lids, even with invalid out ports +.PP +ibroute -n 4 # simple dump format - no destination resolution +.PP +ibroute 4 10 # dump lids starting from 10 (up to FDBTop) +.PP +ibroute 4 0x10 0x20 # dump lid range +.PP +ibroute -G 0x08f1040023 # resolve switch by GUID +.PP +ibroute -D 0,1 # resolve switch by direct path + +.PP +Multicast examples +.PP +ibroute -M 4 # dump all non empty mlids of switch with lid 4 +.PP +ibroute -M 4 0xc010 0xc020 # same, but with range +.PP +ibroute -M -n 4 # simple dump format + +.SH SEE ALSO +.BR ibtracert (8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibrouters.8 b/contrib/ofed/management/infiniband-diags/man/ibrouters.8 new file mode 100644 index 000000000000..9c3ef681cf28 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibrouters.8 @@ -0,0 +1,31 @@ +.TH IBROUTERS 8 "May 30, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibrouters \- show InfiniBand router nodes in topology + +.SH SYNOPSIS +.B ibrouters +[\-h] [ | \-C ca_name \-P ca_port \-t(imeout) timeout_ms] + +.SH DESCRIPTION +.PP +ibrouters is a script which either walks the IB subnet topology or uses an +already saved topology file and extracts the Rt nodes. + +.SH OPTIONS +.PP +\-h show the usage message +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH SEE ALSO +.BR ibnetdiscover(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibstat.8 b/contrib/ofed/management/infiniband-diags/man/ibstat.8 new file mode 100644 index 000000000000..b607d83c3df1 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibstat.8 @@ -0,0 +1,110 @@ +.TH IBSTAT 8 "July 25, 2006" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibstat \- query basic status of InfiniBand device(s) + +.SH SYNOPSIS +.B ibstat +[\-d(ebug)] [\-l(ist_of_cas)] [\-s(hort)] [\-p(ort_list)] [\-V(ersion)] [\-h] [portnum] + +.SH DESCRIPTION +.PP +ibstat is a binary which displays basic information obtained from the local +IB driver. Output includes LID, SMLID, port state, link width active, and port +physical state. + +It is similar to the ibstatus utility but implemented as a binary rather +than a script. It has options to list CAs and/or ports and displays more +information than ibstatus. + +.SH OPTIONS + +.PP +.TP +\fB\-l\fR, \fB\-\-list_of_cas\fR +list all IB devices +.TP +\fB\-s\fR, \fB\-\-short\fR +short output +.TP +\fB\-p\fR, \fB\-\-port_list\fR +show port list +.TP +ca_name +InfiniBand device name +.TP +portnum +port number of InfiniBand device + +.SH COMMON OPTIONS + +Most OpenIB diagnostics take the following common flags. The exact list of +supported flags per utility can be found in the usage message and can be shown +using the util_name -h syntax. + +# Debugging flags +.PP +\-d raise the IB debugging level. + May be used several times (-ddd or -d -d -d). +.PP +\-e show send and receive errors (timeouts and others) +.PP +\-h show the usage message +.PP +\-v increase the application verbosity level. + May be used several times (-vv or -v -v -v) +.PP +\-V show the version info. + +# Addressing flags +.PP +\-D use directed path address arguments. The path + is a comma separated list of out ports. + Examples: + "0" # self port + "0,1,2,1,4" # out via port 1, then 2, ... +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-s use 'smlid' as the target lid for SM/SA queries. + +# Other common flags: +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +Multiple CA/Multiple Port Support + +When no IB device or port is specified, the port to use is selected +by the following criteria: +.PP +1. the first port that is ACTIVE. +.PP +2. if not found, the first port that is UP (physical link up). + +If a port and/or CA name is specified, the user request is +attempted to be fulfilled, and will fail if it is not possible. + +.SH EXAMPLES + +.PP +ibstat # display status of all ports on all IB devices +.PP +ibstat -l # list all IB devices +.PP +ibstat -p # show port guids +.PP +ibstat mthca0 2 # show status of port 2 of 'mthca0' + +.SH SEE ALSO +.BR ibstatus (8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibstatus.8 b/contrib/ofed/management/infiniband-diags/man/ibstatus.8 new file mode 100644 index 000000000000..c4b38313d740 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibstatus.8 @@ -0,0 +1,41 @@ +.TH IBSTATUS 8 "July 25, 2006" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibstatus \- query basic status of InfiniBand device(s) + +.SH SYNOPSIS +.B ibstatus +[\-h] [devname[:port]]... + +.SH DESCRIPTION +.PP +ibstatus is a script which displays basic information obtained from the local +IB driver. Output includes LID, SMLID, port state, link width active, and port +physical state. + +.SH OPTIONS + +.PP +.TP +devname +InfiniBand device name +.TP +portnum +port number of InfiniBand device + +.SH EXAMPLES + +.PP +ibstatus # display status of all IB ports +.PP +ibstatus mthca1 # status of mthca1 ports +.PP +ibstatus mthca1:1 mthca0:2 # show status of specified ports + +.SH SEE ALSO +.BR ibstat (8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibswitches.8 b/contrib/ofed/management/infiniband-diags/man/ibswitches.8 new file mode 100644 index 000000000000..3bd99047e705 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibswitches.8 @@ -0,0 +1,31 @@ +.TH IBSWITCHES 8 "July 25, 2006" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibswitches\- show InfiniBand switch nodes in topology + +.SH SYNOPSIS +.B ibswitches +[\-h] [ | \-C ca_name \-P ca_port \-t(imeout) timeout_ms] + +.SH DESCRIPTION +.PP +ibswitches is a script which either walks the IB subnet topology or uses an +already saved topology file and extracts the switch nodes. + +.SH OPTIONS +.PP +\-h show the usage message +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +.SH SEE ALSO +.BR ibnetdiscover(8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibswportwatch.8 b/contrib/ofed/management/infiniband-diags/man/ibswportwatch.8 new file mode 100644 index 000000000000..72501ab7ad26 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibswportwatch.8 @@ -0,0 +1,35 @@ +.TH IBSWPORTWATCH 8 "September 27, 2006" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibswportwatch.pl \- poll the counters on the specified switch/port and report rate +of change information. + +.SH SYNOPSIS +.B ibswportwatch.pl +[-p -v -n -G] + +.SH DESCRIPTION +.PP +ibswportwatch.pl polls the port counters of the specified port and calculates rate +of change information. + +.SH OPTIONS + +.PP +.TP +\fB\-p \fR +Specify a pause time (polling interval) other than the default. +.TP +\fB\-v\fR +Be verbose. +.TP +\fB\-n \fR +Run for a set number of poll intervals and stop. (Default == -1 == forever) +.TP +\fB\-G\fR +The address provided is a GUID rather than LID. + +.SH AUTHOR +.TP +Ira Weiny +.RI < weiny2@llnl.gov > diff --git a/contrib/ofed/management/infiniband-diags/man/ibsysstat.8 b/contrib/ofed/management/infiniband-diags/man/ibsysstat.8 new file mode 100644 index 000000000000..2f2c69f36275 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibsysstat.8 @@ -0,0 +1,83 @@ +.TH IBSYSSTAT 8 "August 11, 2006" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibsysstat \- system status on an InfiniBand address + +.SH SYNOPSIS +.B ibsysstat +[\-d(ebug)] [\-e(rr_show)] [\-v(erbose)] [\-G(uid)] [\-C ca_name] [\-P ca_port] [\-s smlid] [\-t(imeout) timeout_ms] [\-V(ersion)] [\-o oui] [\-S(erver)] [\-h(elp)] [] + +.SH DESCRIPTION +.PP +ibsysstat uses vendor mads to validate connectivity between IB nodes +and obtain other information about the IB node. ibsysstat is run as +client/server. Default is to run as client. + +.SH OPTIONS + +.PP +.TP +Current supported operations: + ping \- verify connectivity to server (default) + host \- obtain host information from server + cpu \- obtain cpu information from server +.TP +\fB\-o\fR, \fB\-\-oui\fR +use specified OUI number to multiplex vendor mads +.TP +\fB\-S\fR, \fB\-\-Server\fR +start in server mode (do not return) + + +.SH COMMON OPTIONS + +Most OpenIB diagnostics take the following common flags. The exact list of +supported flags per utility can be found in the usage message and can be shown +using the util_name -h syntax. + +# Debugging flags +.PP +\-d raise the IB debugging level. + May be used several times (-ddd or -d -d -d). +.PP +\-e show send and receive errors (timeouts and others) +.PP +\-h show the usage message +.PP +\-v increase the application verbosity level. + May be used several times (-vv or -v -v -v) +.PP +\-V show the version info. + +# Addressing flags +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-s use 'smlid' as the target lid for SM/SA queries. + +# Other common flags: +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +Multiple CA/Multiple Port Support + +When no IB device or port is specified, the port to use is selected +by the following criteria: +.PP +1. the first port that is ACTIVE. +.PP +2. if not found, the first port that is UP (physical link up). + +If a port and/or CA name is specified, the user request is +attempted to be fulfilled, and will fail if it is not possible. + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/ibtracert.8 b/contrib/ofed/management/infiniband-diags/man/ibtracert.8 new file mode 100644 index 000000000000..1b48572b0f5d --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/ibtracert.8 @@ -0,0 +1,112 @@ +.TH IBTRACERT 8 "April 14, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +ibtracert\- trace InfiniBand path + +.SH SYNOPSIS +.B ibtracert +[\-d(ebug)] [-v(erbose)] [\-D(irect)] [\-G(uids)] [-n(o_info)] [-m mlid] [-s +smlid] [\-C ca_name] [\-P ca_port] [\-t(imeout) timeout_ms] [\-V(ersion)] +[\-\-node\-name\-\-map ] [\-h(elp)] [ [ []]] + +.SH DESCRIPTION +.PP +ibtracert uses SMPs to trace the path from a source GID/LID to a +destination GID/LID. Each hop along the path is displayed until the destination +is reached or a hop does not respond. By using the -m option, multicast path +tracing can be performed between source and destination nodes. + +.SH OPTIONS + +.PP +.TP +\fB\-n\fR, \fB\-\-no_info\fR +simple format; don't show additional information +.TP +\fB\-m\fR +show the multicast trace of the specified mlid +.TP +\fB\-\-node\-name\-map\fR +Specify a node name map. The node name map file maps GUIDs to more user friendly +names. See +.B ibnetdiscover(8) +for node name map file format. + +.SH COMMON OPTIONS + +Most OpenIB diagnostics take the following common flags. The exact list of +supported flags per utility can be found in the usage message and can be shown +using the util_name -h syntax. + +# Debugging flags +.PP +\-d raise the IB debugging level. + May be used several times (-ddd or -d -d -d). +.PP +\-h show the usage message +.PP +\-v increase the application verbosity level. + May be used several times (-vv or -v -v -v) +.PP +\-V show the version info. + +# Addressing flags +.PP +\-D use directed path address arguments. The path + is a comma separated list of out ports. + Examples: + "0" # self port + "0,1,2,1,4" # out via port 1, then 2, ... +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-s use 'smlid' as the target lid for SM/SA queries. + +# Other common flags: +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +Multiple CA/Multiple Port Support + +When no IB device or port is specified, the port to use is selected +by the following criteria: +.PP +1. the first port that is ACTIVE. +.PP +2. if not found, the first port that is UP (physical link up). + +If a port and/or CA name is specified, the user request is +attempted to be fulfilled, and will fail if it is not possible. + +.SH EXAMPLES + +.PP +Unicast examples +.PP +ibtracert 4 16 # show path between lids 4 and 16 +.PP +ibtracert -n 4 16 # same, but using simple output format +.PP +ibtracert -G 0x8f1040396522d 0x002c9000100d051 # use guid addresses + +.PP +Multicast example +.PP +ibtracert -m 0xc000 4 16 # show multicast path of mlid 0xc000 between lids 4 and 16 + +.SH SEE ALSO +.BR ibroute (8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > +.TP +Ira Weiny +.RI < weiny2@llnl.gov > diff --git a/contrib/ofed/management/infiniband-diags/man/perfquery.8 b/contrib/ofed/management/infiniband-diags/man/perfquery.8 new file mode 100644 index 000000000000..716d6ff05eb9 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/perfquery.8 @@ -0,0 +1,124 @@ +.TH PERFQUERY 8 "March 29, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +perfquery \- query InfiniBand port counters + +.SH SYNOPSIS +.B perfquery +[\-d(ebug)] [\-G(uid)] [-e(xtended)] [-a(ll_ports)] [-l(oop_ports)] [-r(eset_after_read)] [-R(eset_only)] [\-C ca_name] [\-P ca_port] [\-t(imeout) timeout_ms] [\-V(ersion)] [\-h(elp)] [ [[port] [reset_mask]]] + +.SH DESCRIPTION +.PP +perfquery uses PerfMgt GMPs to obtain the PortCounters (basic performance +and error counters) or PortExtendedCounters from the PMA at the node/port +specified. Optionally shows aggregated counters for all ports of node. +Also, optionally, reset after read, or only reset counters. + +Note: In both PortCounters and PortCountersExtended, components +that represent Data (e.g. PortXmitData and PortRcvData) indicate octets +divided by 4 rather than just octets. + +Note: Inputting a port of 255 indicates an operation be performed on all ports. + +.SH OPTIONS + +.PP +.TP +\fB\-e\fR, \fB\-\-extended\fR +show extended port counters rather than (basic) port counters. +Note that extended port counters attribute is optional. +.TP +\fB\-a\fR, \fB\-\-all_ports\fR +show aggregated counters for all ports of the destination lid +or reset all counters for all ports. If the destination lid +does not support the AllPortSelect flag, all ports will be +iterated through to emulate AllPortSelect behavior. +.TP +\fB\-l\fR, \fB\-\-loop_ports\fR +If all ports are selected by the user (either through the +\fB\-a\fR option or port 255) iterate through each port +rather than doing than aggregate operation. +.TP +\fB\-r\fR, \fB\-\-reset_after_read\fR +reset counters after read +.TP +\fB\-R\fR, \fB\-\-Reset_only\fR +only reset counters + +.SH COMMON OPTIONS + +Most OpenIB diagnostics take the following common flags. The exact list of +supported flags per utility can be found in the usage message and can be shown +using the util_name -h syntax. + +# Debugging flags +.PP +\-d raise the IB debugging level. + May be used several times (-ddd or -d -d -d). +.PP +\-e show send and receive errors (timeouts and others) +.PP +\-h show the usage message +.PP +\-v increase the application verbosity level. + May be used several times (-vv or -v -v -v) +.PP +\-V show the version info. + +# Addressing flags +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-s use 'smlid' as the target lid for SM/SA queries. + +# Other common flags: +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +Multiple CA/Multiple Port Support + +When no IB device or port is specified, the port to use is selected +by the following criteria: +.PP +1. the first port that is ACTIVE. +.PP +2. if not found, the first port that is UP (physical link up). + +If a port and/or CA name is specified, the user request is +attempted to be fulfilled, and will fail if it is not possible. + +.SH EXAMPLES + +.PP +perfquery # read local port performance counters +.PP +perfquery 32 1 # read performance counters from lid 32, port 1 +.PP +perfquery -e 32 1 # read extended performance counters from lid 32, port 1 +.PP +perfquery -a 32 # read perf counters from lid 32, all ports +.PP +perfquery -r 32 1 # read performance counters and reset +.PP +perfquery -e -r 32 1 # read extended performance counters and reset +.PP +perfquery -R 0x20 1 # reset performance counters of port 1 only +.PP +perfquery -e -R 0x20 1 # reset extended performance counters of port 1 only +.PP +perfquery -R -a 32 # reset performance counters of all ports +.PP +perfquery -R 32 2 0x0fff # reset only error counters of port 2 +.PP +perfquery -R 32 2 0xf000 # reset only non-error counters of port 2 + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/saquery.8 b/contrib/ofed/management/infiniband-diags/man/saquery.8 new file mode 100644 index 000000000000..82a5fed94e86 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/saquery.8 @@ -0,0 +1,132 @@ +.TH SAQUERY 8 "October 19, 2008" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +saquery \- query InfiniBand subnet administration attributes + +.SH SYNOPSIS +.B saquery +[\-h] [\-d] [\-p] [\-N] [\-\-list | \-D] [\-S] [\-I] [\-L] [\-l] [\-G] [\-O] +[\-U] [\-c] [\-s] [\-g] [\-m] [\-x] +[\-C ca_name] [\-P ca_port] [\-\-smkey val] [\-t(imeout) ] +[\-\-src\-to\-dst ] +[\-\-sgid\-to\-dgid ] +[\-\-node\-name\-map ] +[ | | ] + +.SH DESCRIPTION +.PP +saquery issues the selected SA query. Node records are queried by default. + +.SH OPTIONS + +.PP +.TP +\fB\-p\fR +get PathRecord info +.TP +\fB\-N\fR +get NodeRecord info +.TP +\fB\-\-list | \-D\fR +get NodeDescriptions of CAs only +.TP +\fB\-S\fR +get ServiceRecord info +.TP +\fB\-I\fR +get InformInfoRecord (subscription) info +.TP +\fB\-L\fR +return the Lids of the name specified +.TP +\fB\-l\fR +return the unique Lid of the name specified +.TP +\fB\-G\fR +return the Guids of the name specified +.TP +\fB\-O\fR +return the name for the Lid specified +.TP +\fB\-U\fR +return the name for the Guid specified +.TP +\fB\-c\fR +get the SA's class port info +.TP +\fB\-s\fR +return the PortInfoRecords with isSM or isSMdisabled capability mask bit on +.TP +\fB\-g\fR +get multicast group info +.TP +\fB\-m\fR +get multicast member info. If a group is specified, limit the output to the +group specified and print one line containing only the GUID and node +description for each entry. Example: saquery -m 0xc000 +.TP +\fB\-x\fR +get LinkRecord info +.TP +\fB\-\-src-to-dst\fR +get a PathRecord for +where src and dst are either node names or LIDs +.TP +.B \-\-sgid\-to\-dgid +get a PathRecord for +.I sgid +to +.I dgid +where both GIDs are in an IPv6 format acceptable to +.BR inet_pton (3). +.TP +\fB\-C\fR +use the specified ca_name. +.TP +\fB\-P\fR +use the specified ca_port. +.TP +\fB\-\-smkey\fR +use SM_Key value for the query. Will be used only with "trusted" queries. +If non-numeric value (like 'x') is specified then saquery will prompt for +a value. +.TP +\fB\-t\fR, \fB\-timeout\fR +Specify SA query response timeout in milliseconds. +Default is 100 milliseconds. You may want to use +this option if IB_TIMEOUT is indicated. +.TP +\fB\-\-node\-name\-map\fR +Specify a node name map. The node name map file maps GUIDs to more user friendly +names. See +.B ibnetdiscover(8) +for node name map file format. Only used with the \fB\-O\fR and \fB\-U\fR options. +.TP +Supported query names (and aliases): + ClassPortInfo (CPI) + NodeRecord (NR) + PortInfoRecord (PIR) [[lid]/[port]] + SL2VLTableRecord (SL2VL) [[lid]/[in_port]/[out_port]] + PKeyTableRecord (PKTR) [[lid]/[port]/[block]] + VLArbitrationTableRecord (VLAR) [[lid]/[port]/[block]] + InformInfoRecord (IIR) + LinkRecord (LR) [[from_lid]/[from_port]] [[to_lid]/[to_port]] + ServiceRecord (SR) + PathRecord (PR) + MCMemberRecord (MCMR) + LFTRecord (LFTR) [[lid]/[block]] + MFTRecord (MFTR) [[mlid]/[position]/[block]] +.TP +\fB\-d\fR +enable debugging +.TP +\fB\-h\fR +show help + +.SH AUTHORS +.TP +Ira Weiny +.RI < weiny2@llnl.gov > +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/sminfo.8 b/contrib/ofed/management/infiniband-diags/man/sminfo.8 new file mode 100644 index 000000000000..6c57362d01de --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/sminfo.8 @@ -0,0 +1,105 @@ +.TH SMINFO 8 "July 25, 2006" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +sminfo \- query InfiniBand SMInfo attribute + +.SH SYNOPSIS +.B sminfo +[\-d(ebug)] [\-e(rr_show)] -s state -p prio -a activity [\-D(irect)] [\-G(uid)] [\-C ca_name] [\-P ca_port] [\-t(imeout) timeout_ms] [\-V(ersion)] [\-h(elp)] sm_lid | sm_dr_path [modifier] + +.SH DESCRIPTION +.PP +Optionally set and display the output of a sminfo query in human readable +format. The target SM is the one listed in the local port info, or the SM +specified by the optional SM lid or by the SM direct routed path. +.PP +Note: using sminfo for any purposes other then simple query may be very +dangerous, and may result in a malfunction of the target SM. + +.SH OPTIONS + +.PP +.TP +\fB\-s\fR +set SM state + 0 - not active + 1 - discovering + 2 - standby + 3 - master +.TP +\fB\-p\fR +set priority (0-15) +.TP +\fB\-a\fR +set activity count + +.SH COMMON OPTIONS + +Most OpenIB diagnostics take the following common flags. The exact list of +supported flags per utility can be found in the usage message and can be shown +using the util_name -h syntax. + +# Debugging flags +.PP +\-d raise the IB debugging level. + May be used several times (-ddd or -d -d -d). +.PP +\-e show send and receive errors (timeouts and others) +.PP +\-h show the usage message +.PP +\-v increase the application verbosity level. + May be used several times (-vv or -v -v -v) +.PP +\-V show the version info. + +# Addressing flags +.PP +\-D use directed path address arguments. The path + is a comma separated list of out ports. + Examples: + "0" # self port + "0,1,2,1,4" # out via port 1, then 2, ... +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-s use 'smlid' as the target lid for SM/SA queries. + +# Other common flags: +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +Multiple CA/Multiple Port Support + +When no IB device or port is specified, the port to use is selected +by the following criteria: +.PP +1. the first port that is ACTIVE. +.PP +2. if not found, the first port that is UP (physical link up). + +If a port and/or CA name is specified, the user request is +attempted to be fulfilled, and will fail if it is not possible. + +.SH EXAMPLES + +.PP +sminfo # local port\'s sminfo +.PP +sminfo 32 # show sminfo of lid 32 +.PP +sminfo -G 0x8f1040023 # same but using guid address + +.SH SEE ALSO +.BR smpdump (8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/smpdump.8 b/contrib/ofed/management/infiniband-diags/man/smpdump.8 new file mode 100644 index 000000000000..2a0875394e5a --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/smpdump.8 @@ -0,0 +1,98 @@ +.TH SMPDUMP 8 "July 25, 2006" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +smpdump \- dump InfiniBand subnet management attributes + +.SH SYNOPSIS +.B smpdump +[\-s(ring)] [\-D(irect)] [\-C ca_name] [\-P ca_port] [\-t(imeout) timeout_ms] [\-V(ersion)] [\-h(elp)] [mod] + +.SH DESCRIPTION +.PP +smpdump is a general purpose SMP utility which gets SM attributes from a +specified SMA. The result is dumped in hex by default. + +.SH OPTIONS + +.TP +attr +IBA attribute ID for SM attribute +.TP +mod +IBA modifier for SM attribute + +.SH COMMON OPTIONS + +Most OpenIB diagnostics take the following common flags. The exact list of +supported flags per utility can be found in the usage message and can be shown +using the util_name -h syntax. + +# Debugging flags +.PP +\-d raise the IB debugging level. + May be used several times (-ddd or -d -d -d). +.PP +\-e show send and receive errors (timeouts and others) +.PP +\-h show the usage message +.PP +\-v increase the application verbosity level. + May be used several times (-vv or -v -v -v) +.PP +\-V show the version info. + +# Addressing flags +.PP +\-D use directed path address arguments. The path + is a comma separated list of out ports. + Examples: + "0" # self port + "0,1,2,1,4" # out via port 1, then 2, ... +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-s use 'smlid' as the target lid for SM/SA queries. + +# Other common flags: +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +Multiple CA/Multiple Port Support + +When no IB device or port is specified, the port to use is selected +by the following criteria: +.PP +1. the first port that is ACTIVE. +.PP +2. if not found, the first port that is UP (physical link up). + +If a port and/or CA name is specified, the user request is +attempted to be fulfilled, and will fail if it is not possible. + +.SH EXAMPLES + +Direct Routed Examples +.PP +smpdump -D 0,1,2,3,5 16 # NODE DESC +.PP +smpdump -D 0,1,2 0x15 2 # PORT INFO, port 2 + +LID Routed Examples +.PP +smpdump 3 0x15 2 # PORT INFO, lid 3 port 2 +.PP +smpdump 0xa0 0x11 # NODE INFO, lid 0xa0 + +.SH SEE ALSO +.BR smpquery (8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/smpquery.8 b/contrib/ofed/management/infiniband-diags/man/smpquery.8 new file mode 100644 index 000000000000..5b719c463465 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/smpquery.8 @@ -0,0 +1,113 @@ +.TH SMPQUERY 8 "March 14, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +smpquery \- query InfiniBand subnet management attributes + +.SH SYNOPSIS +.B smpquery +[\-d(ebug)] [\-e(rr_show)] [\-v(erbose)] [\-D(irect)] [\-G(uid)] [\-C ca_name] [\-P ca_port] [\-t(imeout) timeout_ms] [--node-name-map node-name-map] [\-V(ersion)] [\-h(elp)] [op params] + +.SH DESCRIPTION +.PP +smpquery allows a basic subset of standard SMP queries including the following: +node info, node description, switch info, port info. Fields are displayed in +human readable format. + +.SH OPTIONS + +.PP +.TP +Current supported operations and their parameters: + nodeinfo + nodedesc + portinfo [] # default port is zero + switchinfo + pkeys [] + sl2vl [] + vlarb [] + guids + +.TP +\fB\-\-node\-name\-map\fR +Specify a node name map. The node name map file maps GUIDs to more user friendly +names. See +.B ibnetdiscover(8) +for node name map file format. + +.SH COMMON OPTIONS + +Most OpenIB diagnostics take the following common flags. The exact list of +supported flags per utility can be found in the usage message and can be shown +using the util_name -h syntax. + +# Debugging flags +.PP +\-d raise the IB debugging level. + May be used several times (-ddd or -d -d -d). +.PP +\-e show send and receive errors (timeouts and others) +.PP +\-h show the usage message +.PP +\-v increase the application verbosity level. + May be used several times (-vv or -v -v -v) +.PP +\-V show the version info. + +# Addressing flags +.PP +\-D use directed path address arguments. The path + is a comma separated list of out ports. + Examples: + "0" # self port + "0,1,2,1,4" # out via port 1, then 2, ... +.PP +\-c use combined route address arguments. The + address is a combination of a LID and a direct route path. + The LID specified is the DLID and the local LID is used + as the DrSLID. +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-s use 'smlid' as the target lid for SM/SA queries. + +# Other common flags: +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +Multiple CA/Multiple Port Support + +When no IB device or port is specified, the port to use is selected +by the following criteria: +.PP +1. the first port that is ACTIVE. +.PP +2. if not found, the first port that is UP (physical link up). + +If a port and/or CA name is specified, the user request is +attempted to be fulfilled, and will fail if it is not possible. + +.SH EXAMPLES + +.PP +smpquery portinfo 3 1 # portinfo by lid, with port modifier +.PP +smpquery -G switchinfo 0x2C9000100D051 1 # switchinfo by guid +.PP +smpquery -D nodeinfo 0 # nodeinfo by direct route +.PP +smpquery -c nodeinfo 6 0,12 # nodeinfo by combined route + +.SH SEE ALSO +.BR smpdump (8) + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/man/vendstat.8 b/contrib/ofed/management/infiniband-diags/man/vendstat.8 new file mode 100644 index 000000000000..e32650a13146 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/man/vendstat.8 @@ -0,0 +1,84 @@ +.TH VENDSTAT 8 "February 15, 2007" "OpenIB" "OpenIB Diagnostics" + +.SH NAME +vendstat \- query InfiniBand vendor specific functions + +.SH SYNOPSIS +.B vendstat +[\-d(ebug)] [\-G(uid)] [\-N] [\-w] [\-C ca_name] [\-P ca_port] [\-t(imeout) timeout_ms] [\-V(ersion)] [\-h(elp)] + +.SH DESCRIPTION +.PP +vendstat uses vendor specific MADs to access beyond the IB spec +vendor specific functionality. Currently, there is support only for +Mellanox InfiniSwitch-III (IS3). + +.SH OPTIONS + +.PP +.TP +\fB\-N\fR +show IS3 general information. +.TP +\fB\-w\fR +show IS3 port xmit wait counters. + +.SH COMMON OPTIONS + +Most OpenIB diagnostics take the following common flags. The exact list of +supported flags per utility can be found in the usage message and can be shown +using the util_name -h syntax. + +# Debugging flags +.PP +\-d raise the IB debugging level. + May be used several times (-ddd or -d -d -d). +.PP +\-e show send and receive errors (timeouts and others) +.PP +\-h show the usage message +.PP +\-v increase the application verbosity level. + May be used several times (-vv or -v -v -v) +.PP +\-V show the version info. + +# Addressing flags +.PP +\-G use GUID address argument. In most cases, it is the Port GUID. + Example: + "0x08f1040023" +.PP +\-s use 'smlid' as the target lid for SM/SA queries. + +# Other common flags: +.PP +\-C use the specified ca_name. +.PP +\-P use the specified ca_port. +.PP +\-t override the default timeout for the solicited mads. + +Multiple CA/Multiple Port Support + +When no IB device or port is specified, the port to use is selected +by the following criteria: +.PP +1. the first port that is ACTIVE. +.PP +2. if not found, the first port that is UP (physical link up). + +If a port and/or CA name is specified, the user request is +attempted to be fulfilled, and will fail if it is not possible. + +.SH EXAMPLES + +.PP +vendstat -N 6 # read IS3 general information +.PP +vendstat -w 6 # read IS3 port xmit wait counters + +.SH AUTHOR +.TP +Hal Rosenstock +.RI < halr@voltaire.com > diff --git a/contrib/ofed/management/infiniband-diags/perltidy.sh b/contrib/ofed/management/infiniband-diags/perltidy.sh new file mode 100755 index 000000000000..bc5f0def9c83 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/perltidy.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# +# Copyright (c) 2006 The Regents of the University of California. +# +# Produced at Lawrence Livermore National Laboratory. +# Written by Ira Weiny . +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +tidy_cmd="perltidy -pt=2 -sbt=2 -bt=2 -nsfs -b -t -nola -ce -sbl -nbbc" + +argv0=`basename $0` +scripts_dir=`dirname $0`/scripts + +if [ "$1" == "-h" ]; then + echo "$argv0 [-h]" + echo " Run perltidy on all perl scripts and modules in the scripts directory" + exit 1 +fi + +cd $scripts_dir + +for file in *.pl ; do + echo "tidy : $scripts_dir/$file" + $tidy_cmd $file +done + +for file in *.pm ; do + echo "tidy : $scripts_dir/$file" + $tidy_cmd $file +done + +exit 0 diff --git a/contrib/ofed/management/infiniband-diags/scripts/IBswcountlimits.pm b/contrib/ofed/management/infiniband-diags/scripts/IBswcountlimits.pm new file mode 100755 index 000000000000..6623b8b60775 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/IBswcountlimits.pm @@ -0,0 +1,501 @@ +#!/usr/bin/perl +# +# Copyright (c) 2006 The Regents of the University of California. +# Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. +# +# Produced at Lawrence Livermore National Laboratory. +# Written by Ira Weiny . +# Erez Strauss from Voltaire for help in the get_link_ends code. +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +use strict; + +%IBswcountlimits::cur_counts = (); +%IBswcountlimits::new_counts = (); +@IBswcountlimits::suppress_errors = (); +$IBswcountlimits::link_ends = undef; +$IBswcountlimits::pause_time = 10; +$IBswcountlimits::cache_dir = "/var/cache/infiniband-diags"; + +# all the PerfMgt counters +@IBswcountlimits::counters = ( + "SymbolErrors", "LinkRecovers", + "LinkDowned", "RcvErrors", + "RcvRemotePhysErrors", "RcvSwRelayErrors", + "XmtDiscards", "XmtConstraintErrors", + "RcvConstraintErrors", "LinkIntegrityErrors", + "ExcBufOverrunErrors", "VL15Dropped", + "XmtData", "RcvData", + "XmtPkts", "RcvPkts" +); + +# non-critical counters +%IBswcountlimits::error_counters = ( + "SymbolErrors", +"No action is required except if counter is increasing along with LinkRecovers", + "LinkRecovers", +"If this is increasing along with SymbolErrors this may indicate a bad link, run ibswportwatch.pl on this port", + "LinkDowned", + "Number of times the port has gone down (Usually for valid reasons)", + "RcvErrors", +"This is a bad link, if the link is internal to a 288 try setting SDR, otherwise check the cable", + "RcvRemotePhysErrors", + "This indicates a problem ELSEWHERE in the fabric.", + "XmtDiscards", +"This is a symptom of congestion and may require tweaking either HOQ or switch lifetime values", + "XmtConstraintErrors", + "This is a result of bad partitioning, check partition configuration.", + "RcvConstraintErrors", + "This is a result of bad partitioning, check partition configuration.", + "LinkIntegrityErrors", + "May indicate a bad link, run ibswportwatch.pl on this port", + "ExcBufOverrunErrors", +"This is a flow control state machine error and can be caused by packets with physical errors", + "VL15Dropped", + "check with ibswportwatch.pl, if increasing in SMALL increments, OK", + "RcvSwRelayErrors", + "This counter can increase due to a valid network event" +); + +sub check_counters +{ + my $print_action = $_[0]; + my $actions = undef; + + COUNTER: foreach my $cnt (keys %IBswcountlimits::error_counters) { + if ($IBswcountlimits::cur_counts{$cnt} > 0) { + foreach my $sup_cnt (@IBswcountlimits::suppress_errors) { + if ("$cnt" eq $sup_cnt) { next COUNTER; } + } + print " [$cnt == $IBswcountlimits::cur_counts{$cnt}]"; + if ("$print_action" eq "yes") { + $actions = join " ", + ( + $actions, + " $cnt: $IBswcountlimits::error_counters{$cnt}\n" + ); + } + } + } + + if ($actions) { + print "\n Actions:\n$actions"; + } +} + +# Data counters +%IBswcountlimits::data_counters = ( + "XmtData", +"Total number of data octets, divided by 4, transmitted on all VLs from the port", + "RcvData", +"Total number of data octets, divided by 4, received on all VLs to the port", + "XmtPkts", +"Total number of packets, excluding link packets, transmitted on all VLs from the port", + "RcvPkts", +"Total number of packets, excluding link packets, received on all VLs to the port" +); + +sub check_data_counters +{ + my $print_action = $_[0]; + my $actions = undef; + + COUNTER: foreach my $cnt (keys %IBswcountlimits::data_counters) { + print " [$cnt == $IBswcountlimits::cur_counts{$cnt}]"; + if ("$print_action" eq "yes") { + $actions = join " ", + ( + $actions, + " $cnt: $IBswcountlimits::data_counters{$cnt}\n" + ); + } + } + if ($actions) { + print "\n Descriptions:\n$actions"; + } +} + +sub print_data_rates +{ + COUNTER: foreach my $cnt (keys %IBswcountlimits::data_counters) { + my $cnt_per_second = calculate_rate( + $IBswcountlimits::cur_counts{$cnt}, + $IBswcountlimits::new_counts{$cnt} + ); + print " $cnt_per_second $cnt/second\n"; + } +} + +# ========================================================================= +# Rate dependent counters +# calculate the count/sec +# calculate_rate old_count new_count +sub calculate_rate +{ + my $rate = 0; + my $old_val = $_[0]; + my $new_val = $_[1]; + my $rate = ($new_val - $old_val) / $IBswcountlimits::pause_time; + return ($rate); +} +%IBswcountlimits::rate_dep_thresholds = ( + "SymbolErrors", 10, "LinkRecovers", 10, + "RcvErrors", 10, "LinkIntegrityErrors", 10, + "XmtDiscards", 10 +); + +sub check_counter_rates +{ + foreach my $rate_count (keys %IBswcountlimits::rate_dep_thresholds) { + my $rate = calculate_rate( + $IBswcountlimits::cur_counts{$rate_count}, + $IBswcountlimits::new_counts{$rate_count} + ); + if ($rate > $IBswcountlimits::rate_dep_thresholds{$rate_count}) { + print "Detected excessive rate for $rate_count ($rate cnts/sec)\n"; + } elsif ($rate > 0) { + print "Detected rate for $rate_count ($rate cnts/sec)\n"; + } + } +} + +# ========================================================================= +# +sub clear_counters +{ + # clear the counters + foreach my $count (@IBswcountlimits::counters) { + $IBswcountlimits::cur_counts{$count} = 0; + } +} + +# ========================================================================= +# +sub any_counts +{ + my $total = 0; + my $count = 0; + foreach $count (keys %IBswcountlimits::critical) { + $total = $total + $IBswcountlimits::cur_counts{$count}; + } + COUNTER: foreach $count (keys %IBswcountlimits::error_counters) { + foreach my $sup_cnt (@IBswcountlimits::suppress_errors) { + if ("$count" eq $sup_cnt) { next COUNTER; } + } + $total = $total + $IBswcountlimits::cur_counts{$count}; + } + return ($total); +} + +# ========================================================================= +# +sub ensure_cache_dir +{ + if (!(-d "$IBswcountlimits::cache_dir") && + !mkdir($IBswcountlimits::cache_dir, 0700)) { + die "cannot create $IBswcountlimits::cache_dir: $!\n"; + } +} + +# ========================================================================= +# get_cache_file(ca_name, ca_port) +# +sub get_cache_file +{ + my $ca_name = $_[0]; + my $ca_port = $_[1]; + ensure_cache_dir; + return ( + "$IBswcountlimits::cache_dir/ibnetdiscover-$ca_name-$ca_port.topology"); +} + +# ========================================================================= +# get_ca_name_port_param_string(ca_name, ca_port) +# +sub get_ca_name_port_param_string +{ + my $ca_name = $_[0]; + my $ca_port = $_[1]; + + if ("$ca_name" ne "") { $ca_name = "-C $ca_name"; } + if ("$ca_port" ne "") { $ca_port = "-P $ca_port"; } + + return ("$ca_name $ca_port"); +} + +# ========================================================================= +# generate_ibnetdiscover_topology(ca_name, ca_port) +# +sub generate_ibnetdiscover_topology +{ + my $ca_name = $_[0]; + my $ca_port = $_[1]; + my $cache_file = get_cache_file($ca_name, $ca_port); + my $extra_params = get_ca_name_port_param_string($ca_name, $ca_port); + + if (`ibnetdiscover -g $extra_params > $cache_file`) { + die "Execution of ibnetdiscover failed: $!\n"; + } +} + +# ========================================================================= +# get_link_ends(regenerate_map, ca_name, ca_port) +# +sub get_link_ends +{ + my $regenerate_map = $_[0]; + my $ca_name = $_[1]; + my $ca_port = $_[2]; + + my $cache_file = get_cache_file($ca_name, $ca_port); + + if ($regenerate_map || !(-f "$cache_file")) { + generate_ibnetdiscover_topology($ca_name, $ca_port); + } + open IBNET_TOPO, "<$cache_file" + or die "Failed to open ibnet topology: $!\n"; + my $in_switch = "no"; + my $desc = ""; + my $guid = ""; + my $loc_sw_lid = ""; + + my $loc_port = ""; + my $line = ""; + + while ($line = ) { + if ($line =~ /^Switch.*\"S-(.*)\"\s+#.*\"(.*)\".* lid (\d+).*/) { + $guid = $1; + $desc = $2; + $loc_sw_lid = $3; + $in_switch = "yes"; + } + if ($in_switch eq "yes") { + my $rec = undef; + if ($line =~ +/^\[(\d+)\]\s+\"[HSR]-(.+)\"\[(\d+)\](\(.+\))?\s+#.*\"(.*)\"\.* lid (\d+).*/ + ) + { + $loc_port = $1; + my $rem_guid = $2; + my $rem_port = $3; + my $rem_port_guid = $4; + my $rem_desc = $5; + my $rem_lid = $6; + $rec = { + loc_guid => "0x$guid", + loc_port => $loc_port, + loc_ext_port => "", + loc_desc => $desc, + loc_sw_lid => $loc_sw_lid, + rem_guid => "0x$rem_guid", + rem_lid => $rem_lid, + rem_port => $rem_port, + rem_ext_port => "", + rem_desc => $rem_desc, + rem_port_guid => $rem_port_guid + }; + } + if ($line =~ +/^\[(\d+)\]\[ext (\d+)\]\s+\"[HSR]-(.+)\"\[(\d+)\](\(.+\))?\s+#.*\"(.*)\"\.* lid (\d+).*/ + ) + { + $loc_port = $1; + my $loc_ext_port = $2; + my $rem_guid = $3; + my $rem_port = $4; + my $rem_port_guid = $5; + my $rem_desc = $6; + my $rem_lid = $7; + $rec = { + loc_guid => "0x$guid", + loc_port => $loc_port, + loc_ext_port => $loc_ext_port, + loc_desc => $desc, + loc_sw_lid => $loc_sw_lid, + rem_guid => "0x$rem_guid", + rem_lid => $rem_lid, + rem_port => $rem_port, + rem_ext_port => "", + rem_desc => $rem_desc, + rem_port_guid => $rem_port_guid + }; + } + if ($line =~ +/^\[(\d+)\]\s+\"[HSR]-(.+)\"\[(\d+)\]\[ext (\d+)\](\(.+\))?\s+#.*\"(.*)\"\.* lid (\d+).*/ + ) + { + $loc_port = $1; + my $rem_guid = $2; + my $rem_port = $3; + my $rem_ext_port = $4; + my $rem_port_guid = $5; + my $rem_desc = $6; + my $rem_lid = $7; + $rec = { + loc_guid => "0x$guid", + loc_port => $loc_port, + loc_ext_port => "", + loc_desc => $desc, + loc_sw_lid => $loc_sw_lid, + rem_guid => "0x$rem_guid", + rem_lid => $rem_lid, + rem_port => $rem_port, + rem_ext_port => $rem_ext_port, + rem_desc => $rem_desc, + rem_port_guid => $rem_port_guid + }; + } + if ($line =~ +/^\[(\d+)\]\[ext (\d+)\]\s+\"[HSR]-(.+)\"\[(\d+)\]\[ext (\d+)\](\(.+\))?\s+#.*\"(.*)\"\.* lid (\d+).*/ + ) + { + $loc_port = $1; + my $loc_ext_port = $2; + my $rem_guid = $3; + my $rem_port = $4; + my $rem_ext_port = $5; + my $rem_port_guid = $6; + my $rem_desc = $7; + my $rem_lid = $8; + $rec = { + loc_guid => "0x$guid", + loc_port => $loc_port, + loc_ext_port => $loc_ext_port, + loc_desc => $desc, + loc_sw_lid => $loc_sw_lid, + rem_guid => "0x$rem_guid", + rem_lid => $rem_lid, + rem_port => $rem_port, + rem_ext_port => $rem_ext_port, + rem_desc => $rem_desc, + rem_port_guid => $rem_port_guid + }; + } + if ($rec) { + $rec->{rem_port_guid} =~ s/\((.*)\)/$1/; + $IBswcountlimits::link_ends{"0x$guid"}{$loc_port} = $rec; + } + } + + if ($line =~ /^Ca.*/ || $line =~ /^Rt.*/) { $in_switch = "no"; } + } + close IBNET_TOPO; +} + +# ========================================================================= +# get_num_ports(switch_guid, ca_name, ca_port) +# +sub get_num_ports +{ + my $guid = $_[0]; + my $ca_name = $_[1]; + my $ca_port = $_[2]; + my $num_ports = 0; + my $extra_params = get_ca_name_port_param_string($ca_name, $ca_port); + + my $data = `smpquery $extra_params -G nodeinfo $guid` || + die "'smpquery $extra_params -G nodeinfo $guid' faild\n"; + my @lines = split("\n", $data); + my $pkt_lifetime = ""; + foreach my $line (@lines) { + if ($line =~ /^NumPorts:\.+(.*)/) { $num_ports = $1; } + } + return ($num_ports); +} + +# ========================================================================= +# format_guid(guid) +# The diags store the guids as strings. This converts the guid supplied +# to the correct string format. +# eg: 0x0008f10400411f56 == 0x8f10400411f56 +# +sub format_guid +{ + my $guid = $_[0]; + my $guid_str = ""; + + $guid =~ tr/[A-F]/[a-f]/; + if ($guid =~ /0x(.*)/) { + $guid_str = sprintf("0x%016s", $1); + } else { + $guid_str = sprintf("0x%016s", $guid); + } + return ($guid_str); +} + +# ========================================================================= +# convert_dr_to_guid(direct_route) +# +sub convert_dr_to_guid +{ + my $guid = undef; + + my $data = `smpquery nodeinfo -D $_[0]` || + die "'mpquery nodeinfo -D $_[0]' failed\n"; + my @lines = split("\n", $data); + foreach my $line (@lines) { + if ($line =~ /^PortGuid:\.+(.*)/) { $guid = $1; } + } + return format_guid($guid); +} + +# ========================================================================= +# get_node_type(guid_or_direct_route) +# +sub get_node_type +{ + my $type = undef; + my $query_arg = "smpquery nodeinfo "; + if ($_[0] =~ /x/) { + # assume arg is a guid if contains an x + $query_arg .= "-G " . $_[0]; + } else { + # assume arg is a direct path + $query_arg .= "-D " . $_[0]; + } + + my $data = `$query_arg` || + die "'$query_arg' failed\n"; + my @lines = split("\n", $data); + foreach my $line (@lines) { + if ($line =~ /^NodeType:\.+(.*)/) { $type = $1; } + } + return $type; +} + +# ========================================================================= +# is_switch(guid_or_direct_route) +# +sub is_switch +{ + my $node_type = &get_node_type($_[0]); + return ($node_type =~ /Switch/); +} diff --git a/contrib/ofed/management/infiniband-diags/scripts/check_lft_balance.pl b/contrib/ofed/management/infiniband-diags/scripts/check_lft_balance.pl new file mode 100755 index 000000000000..cd4950f83938 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/check_lft_balance.pl @@ -0,0 +1,321 @@ +#!/usr/bin/perl +# +# Copyright (C) 2001-2003 The Regents of the University of California. +# Copyright (c) 2006 The Regents of the University of California. +# Copyright (c) 2007-2008 Voltaire, Inc. All rights reserved. +# +# Produced at Lawrence Livermore National Laboratory. +# Written by Ira Weiny +# Jim Garlick +# Albert Chu +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +use strict; + +use Getopt::Std; +use IBswcountlimits; + +my $regenerate_cache = 0; +my $verbose = 0; + +my $switch_lid = undef; +my $switch_guid = undef; +my $switch_name = undef; +my %switch_port_count = (); +my @switch_maybe_directly_connected_hosts = (); +my $host = undef; +my @host_ports = (); + +my @lft_lines = (); +my $lft_line; + +my $lids_per_port; +my $lids_per_port_calculated; + +my $iblinkinfo_regenerate = 0; + +my $cache_file; + +sub usage +{ + my $prog = `basename $0`; + + chomp($prog); + print "Usage: $prog [-R -v]\n"; + print " -R recalculate all cached information\n"; + print " -v verbose output\n"; + exit 2; +} + +sub is_port_up +{ + my $iblinkinfo_output = $_[0]; + my $port = $_[1]; + my $decport; + my @lines; + my $line; + + $port =~ /0+(.+)/; + $decport = $1; + + # Add a space if necessary + if ($decport >= 1 && $decport <= 9) { + $decport = " $decport"; + } + + @lines = split("\n", $iblinkinfo_output); + foreach $line (@lines) { + if ($line =~ /$decport\[..\] ==/) { + if ($line =~ /Down/) { + return 0; + } + } + } + return 1; +} + +sub is_directly_connected +{ + my $iblinkinfo_output = $_[0]; + my $port = $_[1]; + my $decport; + my $str; + my $rv = 0; + my $host_tmp; + my @lines; + my $line; + + if (($switch_port_count{$port} != $lids_per_port) + || !(@switch_maybe_directly_connected_hosts)) + { + return $rv; + } + + $port =~ /0+(.+)/; + $decport = $1; + + # Add a space if necessary + if ($decport >= 1 && $decport <= 9) { + $decport = " $decport"; + } + + @lines = split("\n", $iblinkinfo_output); + foreach $line (@lines) { + if ($line =~ /$decport\[..\] ==/) { + $str = $line; + } + } + + if ($str =~ "Active") { + $str =~ +/[\d]+[\s]+[\d]+\[.+\] \=\=.+\=\=>[\s]+[\d]+[\s]+[\d]+\[.+\] \"(.+)\".+/; + for $host_tmp (@switch_maybe_directly_connected_hosts) { + if ($1 == $host_tmp) { + $rv = 1; + last; + } + } + } + + return $rv; +} + +sub output_switch_port_usage +{ + my $min_usage = 999999; + my $max_usage = 0; + my @ports = ( + "001", "002", "003", "004", "005", "006", "007", "008", + "009", "010", "011", "012", "013", "014", "015", "016", + "017", "018", "019", "020", "021", "022", "023", "024" + ); + my @output_ports = (); + my $port; + my $iblinkinfo_output; + my $ret; + + # Run command once to reduce number of calls to iblinkinfo.pl + if ($regenerate_cache && !$iblinkinfo_regenerate) { + $iblinkinfo_output = `iblinkinfo.pl -R -S $switch_guid`; + $iblinkinfo_regenerate++; + } + else { + $iblinkinfo_output = `iblinkinfo.pl -S $switch_guid`; + } + + for $port (@ports) { + if (!defined($switch_port_count{$port})) { + $switch_port_count{$port} = 0; + } + + if ($switch_port_count{$port} == 0) { + # If port is down, don't use it in this calculation + $ret = is_port_up($iblinkinfo_output, $port); + if ($ret == 0) { + next; + } + } + + # If port is directly connected to a node, don't use + # it in this calculation. + if (is_directly_connected($iblinkinfo_output, $port) == 1) { + next; + } + + # Save off ports that should be output later + push(@output_ports, $port); + + if ($switch_port_count{$port} < $min_usage) { + $min_usage = $switch_port_count{$port}; + } + if ($switch_port_count{$port} > $max_usage) { + $max_usage = $switch_port_count{$port}; + } + } + + if ($verbose || ($max_usage > ($min_usage + 1))) { + if ($max_usage > ($min_usage + 1)) { + print "Unbalanced Switch Port Usage: "; + print "$switch_name, $switch_guid, $switch_lid\n"; + } else { + print + "Switch Port Usage: $switch_name, $switch_guid, $switch_lid\n"; + } + for $port (@output_ports) { + print "Port $port: $switch_port_count{$port}\n"; + } + } +} + +sub process_host_ports +{ + my $test_port; + my $tmp; + my $flag = 0; + + if (@host_ports == $lids_per_port) { + # Are all the host ports identical? + $test_port = $host_ports[0]; + for $tmp (@host_ports) { + if ($tmp != $test_port) { + $flag = 1; + last; + } + } + # If all host ports are identical, maybe its directly + # connected to a host. + if ($flag == 0) { + push(@switch_maybe_directly_connected_hosts, $host); + } + } +} + +if (!getopts("hRv")) { + usage(); +} + +if (defined($main::opt_h)) { + usage(); +} + +if (defined($main::opt_R)) { + $regenerate_cache = 1; +} + +if (defined($main::opt_v)) { + $verbose = 1; +} + +$cache_file = "$IBswcountlimits::cache_dir/dump_lfts.out"; +if ($regenerate_cache || !(-f $cache_file)) { + `dump_lfts.sh > $cache_file`; + if ($? != 0) { + die "Execution of dump_lfts.sh failed with errors\n"; + } +} + +if (!open(FH, "< $cache_file")) { + print STDERR ("Couldn't open cache file: $cache_file: $!\n"); +} + +@lft_lines = ; + +foreach $lft_line (@lft_lines) { + chomp($lft_line); + if ($lft_line =~ /Unicast/) { + $lft_line =~ /Unicast lids .+ of switch Lid (.+) guid (.+) \((.+)\)/; + if (@host_ports) { + process_host_ports(); + } + if (defined($switch_name)) { + output_switch_port_usage(); + } + $switch_lid = $1; + $switch_guid = $2; + $switch_name = $3; + @switch_maybe_directly_connected_hosts = (); + %switch_port_count = (); + @host_ports = (); + $lids_per_port = 0; + $lids_per_port_calculated = 0; + } elsif ($lft_line =~ /Channel/ || $lft_line =~ /Router/) { + $lft_line =~ /.+ (.+) : \(.+ portguid .+: '(.+)'\)/; + $host = $2; + $switch_port_count{$1}++; + if (@host_ports) { + process_host_ports(); + } + @host_ports = ($1); + + if ($lids_per_port == 0) { + $lids_per_port++; + } else { + $lids_per_port_calculated++; + } + } elsif ($lft_line =~ /path/) { + $lft_line =~ /.+ (.+) : \(path #. out of .: portguid .+\)/; + $switch_port_count{$1}++; + if ($lids_per_port_calculated == 0) { + $lids_per_port++; + } + push(@host_ports, $1); + } else { + if ($lids_per_port) { + $lids_per_port_calculated++; + } + next; + } +} + +if (@host_ports) { + process_host_ports(); +} +output_switch_port_usage(); diff --git a/contrib/ofed/management/infiniband-diags/scripts/dump_lfts.sh b/contrib/ofed/management/infiniband-diags/scripts/dump_lfts.sh new file mode 100755 index 000000000000..ebca7050ad43 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/dump_lfts.sh @@ -0,0 +1,72 @@ +#!/bin/sh +# +# This simple script will collect outputs of ibroute for all switches +# on the subnet and drop it on stdout. It can be used for LFTs dump +# generation. +# + +usage () +{ + echo Usage: `basename $0` "[-h] [-D] [-C ca_name]" \ + "[-P ca_port] [-t(imeout) timeout_ms]" + exit 2 +} + +dump_by_lid () +{ +for sw_lid in `ibswitches $ca_info \ + | sed -ne 's/^.* lid \([0-9a-f]*\) .*$/\1/p'` ; do + ibroute $ca_info $sw_lid +done +} + +dump_by_dr_path () +{ +for sw_dr in `ibnetdiscover $ca_info -v \ + | sed -ne '/^DR path .* switch /s/^DR path \([,|0-9]\+\) ->.*{\([0-9|a-f]\+\)}.*$/\2 \1/p' \ + | sort -u \ + | awk 'BEGIN {guid=0;} {if ($1 != guid) { guid=$1; print $2; }}'` ; do + ibroute $ca_info -D ${sw_dr} +done +} + +use_d="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -D) + use_d="-D" + ;; + -h) + usage + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + usage + ;; + esac + shift +done + +if [ "$use_d" = "-D" ] ; then + dump_by_dr_path +else + dump_by_lid +fi + +exit diff --git a/contrib/ofed/management/infiniband-diags/scripts/dump_mfts.sh b/contrib/ofed/management/infiniband-diags/scripts/dump_mfts.sh new file mode 100755 index 000000000000..39fc5fb92bd3 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/dump_mfts.sh @@ -0,0 +1,72 @@ +#!/bin/sh +# +# This simple script will collect outputs of ibroute for all switches +# on the subnet and drop it on stdout. It can be used for MFTs dump +# generation. +# + +usage () +{ + echo Usage: `basename $0` "[-h] [-D] [-C ca_name]" \ + "[-P ca_port] [-t(imeout) timeout_ms]" + exit 2 +} + +dump_by_lid () +{ +for sw_lid in `ibswitches $ca_info \ + | sed -ne 's/^.* lid \([0-9a-f]*\) .*$/\1/p'` ; do + ibroute $ca_info -M $sw_lid +done +} + +dump_by_dr_path () +{ +for sw_dr in `ibnetdiscover $ca_info -v \ + | sed -ne '/^DR path .* switch /s/^DR path \[\(.*\)\].*$/\1/p' \ + | sed -e 's/\]\[/,/g' \ + | sort -u` ; do + ibroute $ca_info -M -D ${sw_dr} +done +} + +use_d="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -D) + use_d="-D" + ;; + -h) + usage + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + usage + ;; + esac + shift +done + +if [ "$use_d" = "-D" ] ; then + dump_by_dr_path +else + dump_by_lid +fi + +exit diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibcheckerrors.in b/contrib/ofed/management/infiniband-diags/scripts/ibcheckerrors.in new file mode 100644 index 000000000000..a45bd63d7cc5 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibcheckerrors.in @@ -0,0 +1,133 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [-b] [-v] [-N | -nocolor]"\ + "[ | -C ca_name -P ca_port -t(imeout) timeout_ms]" + exit -1 +} + +function user_abort() { + echo "Aborted" + exit 1 +} + +trap user_abort SIGINT + +gflags="" +verbose="" +brief="" +v=0 +ntype="" +nodeguid="" +topofile="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -h) + usage + ;; + -N|-nocolor) + gflags=-N + ;; + -v) + verbose=-v + brief="" + v=1 + ;; + -b) + brief=-b + verbose="" + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + if [ "$topofile" ]; then + usage + fi + topofile="$1" + ;; + esac + shift +done + +if [ "$topofile" ]; then + netcmd="cat $topofile" +else + netcmd="$IBPATH/ibnetdiscover $ca_info" +fi + +text="`eval $netcmd`" +rv=$? +echo "$text" | awk ' +BEGIN { + ne=0 +} +function check_node(lid, port) +{ + if (system("'$IBPATH'/ibchecknode '"$ca_info"' '$gflags' '$verbose' " lid)) { + ne++ + print "\n# " ntype ": nodeguid 0x" nodeguid " failed" + return 1; + } + if (system("'$IBPATH'/ibcheckerrs '"$ca_info"' '$gflags' '$verbose' '$brief' " lid " " port)) + return 2; + return 0; +} + +/^Ca/ || /^Switch/ || /^Rt/ { + nnodes++ + ntype=$1; nodeguid=substr($3, 4, 16); ports=$2 + if ('$v') + print "\n# Checking " ntype ": nodeguid 0x" nodeguid + + err = 0; + if (ntype != "Switch") + next + + lid = substr($0, index($0, "port 0 lid ") + 11) + lid = substr(lid, 1, index(lid, " ") - 1) + err = check_node(lid, 255) + } +/^\[/ { + nports++ + port = $1 + sub("\\(.*\\)", "", port) + gsub("[\\[\\]]", "", port) + if (ntype != "Switch") { + lid = substr($0, index($0, " lid ") + 5) + lid = substr(lid, 1, index(lid, " ") - 1) + if (check_node(lid, port) == 2) + pcnterr++; + } else if (err && + system("'$IBPATH'/ibcheckerrs '"$ca_info"' '$gflags' '$verbose' '$brief' " lid " " port)) + pcnterr++; +} + +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} + +END { + printf "\n## Summary: %d nodes checked, %d bad nodes found\n", nnodes, ne + printf "## %d ports checked, %d ports have errors beyond threshold\n", nports, pcnterr + exit (ne + pcnterr) +} +' +exit $rv diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibcheckerrs.in b/contrib/ofed/management/infiniband-diags/scripts/ibcheckerrs.in new file mode 100644 index 000000000000..305379a027ae --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibcheckerrs.in @@ -0,0 +1,223 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [-b] [-v] [-G] [-T ]" \ + "[-s(how_thresholds)] [-N \| -nocolor] [-C ca_name] [-P ca_port]" \ + "[-t(imeout) timeout_ms] []" + exit -1 +} + +function green() { + if [ "$bw" = "yes" ]; then + if [ "$verbose" = "yes" ]; then + echo $1 + fi + return + fi + if [ "$verbose" = "yes" ]; then + echo -e "\\033[1;032m" $1 "\\033[0;39m" + fi +} + +function red() { + if [ "$bw" = "yes" ]; then + echo $1 + return + fi + echo -e "\\033[1;031m" $1 "\\033[0;39m" +} + +function show_thresholds() { + echo "SymbolErrors=$SymbolErrors" + echo "LinkRecovers=$LinkRecovers" + echo "LinkDowned=$LinkDowned" + echo "RcvErrors=$RcvErrors" + echo "RcvRemotePhysErrors=$RcvRemotePhysErrors" + echo "RcvSwRelayErrors=$RcvSwRelayErrors" + echo "XmtDiscards=$XmtDiscards" + echo "XmtConstraintErrors=$XmtConstraintErrors" + echo "RcvConstraintErrors=$RcvConstraintErrors" + echo "LinkIntegrityErrors=$LinkIntegrityErrors" + echo "ExcBufOverrunErrors=$ExcBufOverrunErrors" + echo "VL15Dropped=$VL15Dropped" +} + +function get_thresholds() { + . $1 +} + +# Default thresholds +SymbolErrors=10 +LinkRecovers=10 +LinkDowned=10 +RcvErrors=10 +RcvRemotePhysErrors=100 +RcvSwRelayErrors=100 +XmtDiscards=100 +XmtConstraintErrors=100 +RcvConstraintErrors=100 +LinkIntegrityErrors=10 +ExcBufOverrunErrors=10 +VL15Dropped=100 + +guid_addr="" +bw="" +verbose="" +brief="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -G) + guid_addr=yes + ;; + -nocolor|-N) + bw=yes + ;; + -v) + verbose=yes + brief="" + ;; + -b) + brief=yes + verbose="" + ;; + -T) + if ! [ -r $2 ]; then + echo "Can't use threshold file '$2'" + usage + fi + get_thresholds $2 + shift + ;; + -s) + show_thresholds + exit 0 + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + break + ;; + esac + shift +done + +#default is all ports +portnum=255 + +if [ $# -lt 1 ]; then + usage +fi + +if [ "$2" ]; then + portnum=$2 +fi + +if [ "$portnum" = "255" ]; then + portname="all" +else + portname=$2 +fi + +if [ "$guid_addr" ]; then + if ! lid=`$IBPATH/ibaddr $ca_info -G -L $1 | awk '/failed/{exit -1} {print $3}'`; then + echo -n "guid $1 address resolution: " + red "FAILED" + exit -1 + fi + guid=$1 +else + lid=$1 + if ! temp=`$IBPATH/ibaddr $ca_info -L $1 | awk '/failed/{exit -1} {print $1}'`; then + echo -n "lid $1 address resolution: " + red "FAILED" + exit -1 + fi +fi + +nodename=`$IBPATH/smpquery $ca_info nodedesc $lid | sed -e "s/^Node Description:\.*\(.*\)/\1/"` + +text="`eval $IBPATH/perfquery $ca_info $lid $portnum`" +rv=$? +if echo "$text" | awk -v mono=$bw -v brief=$brief -F '[.:]*' ' +function blue(s) +{ + if (brief == "yes") { + return + } + if (mono) + printf s + else if (!quiet) { + printf "\033[1;034m" s + printf "\033[0;39m" + } +} + +BEGIN { + th["SymbolErrors"] = '$SymbolErrors' + th["LinkRecovers"] = '$LinkRecovers' + th["LinkDowned"] = '$LinkDowned' + th["RcvErrors"] = '$RcvErrors' + th["RcvRemotePhysErrors"] = '$RcvRemotePhysErrors' + th["RcvSwRelayErrors"] = '$RcvSwRelayErrors' + th["XmtDiscards"] = '$XmtDiscards' + th["XmtConstraintErrors"] = '$XmtConstraintErrors' + th["RcvConstraintErrors"] = '$RcvConstraintErrors' + th["LinkIntegrityErrors"] = '$LinkIntegrityErrors' + th["ExcBufOverrunErrors"] = '$ExcBufOverrunErrors' + th["VL15Dropped"] = '$VL15Dropped' +} + +/^CounterSelect/ {next} + +/AllPortSelect/ {next} + +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} + +/^PortSelect/ { if ($2 != '$portnum') {err = err "error: lid '$lid' port " $2 " does not match query ('$portnum')\n"; exit -1}} + +$1 ~ "(Xmt|Rcv)(Pkts|Data)" { next } + + { if (th[$1] > 0 && $2 >= th[$1]) + warn = warn "#warn: counter " $1 " = " $2 " \t(threshold " th[$1] ") lid '$lid' port '$portnum'\n" + } +END { + if (err != "") { + blue(err) + exit -1 + } + if (warn != "") { + blue(warn) + exit -1 + } + exit 0 +}' 2>&1 && test $rv -eq 0 ; then + if [ "$verbose" = "yes" ]; then + echo -n "Error check on lid $lid ($nodename) port $portname: " + green OK + fi + exit 0 +else + echo -n "Error check on lid $lid ($nodename) port $portname: " + red FAILED + exit -1 +fi diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibchecknet.in b/contrib/ofed/management/infiniband-diags/scripts/ibchecknet.in new file mode 100644 index 000000000000..644783532243 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibchecknet.in @@ -0,0 +1,140 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [-v] [-N | -nocolor]" \ + "[ | -C ca_name -P ca_port -t(imeout) timeout_ms]" + exit -1 +} + +function user_abort() { + echo "Aborted" + exit 1 +} + +trap user_abort SIGINT + +gflags="" +verbose="" +v=0 +oldlid="" +topofile="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -h) + usage + ;; + -N|-nocolor) + gflags=-N + ;; + -v) + verbose=-v + v=0 + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + if [ "$topofile" ]; then + usage + fi + topofile="$1" + ;; + esac + shift +done + +if [ "$topofile" ]; then + netcmd="cat $topofile" +else + netcmd="$IBPATH/ibnetdiscover $ca_info" +fi + +text="`eval $netcmd`" +rv=$? +echo "$text" | awk ' +BEGIN { + ne=0 + pe=0 +} +function check_node(lid, port) +{ + if (system("'$IBPATH'/ibchecknode '"$ca_info"' '$gflags' '$verbose' " lid)) { + ne++ + print "\n# " ntype ": nodeguid 0x" nodeguid " failed" + return 1; + } + if (system("'$IBPATH'/ibcheckerrs '"$ca_info"' '$gflags' '$verbose' '$brief' " lid " " port)) + return 2; + return 0; +} + +/^Ca/ || /^Switch/ || /^Rt/ { + nnodes++ + ntype=$1; nodeguid=substr($3, 4, 16); ports=$2 + if ('$v' || ntype != "Switch") + print "\n# Checking " ntype ": nodeguid 0x" nodeguid + + err = 0; + if (ntype != "Switch") + next + + lid = substr($0, index($0, "port 0 lid ") + 11) + lid = substr(lid, 1, index(lid, " ") - 1) + err = check_node(lid, 255) + } +/^\[/ { + nports++ + port = $1 + sub("\\(.*\\)", "", port) + gsub("[\\[\\]]", "", port) + if (ntype != "Switch") { + lid = substr($0, index($0, " lid ") + 5) + lid = substr(lid, 1, index(lid, " ") - 1) + if (check_node(lid, port) == 2) + pcnterr++; + } else if (err && + system("'$IBPATH'/ibcheckerrs '"$ca_info"' '$gflags' '$verbose' '$brief' " lid " " port)) + pcnterr++; + if (system("'$IBPATH'/ibcheckport'"$ca_info"' '$gflags' '$verbose' " lid " " port)) { + if (!'$v' && oldlid != lid) { + print "# Checked " ntype ": nodeguid 0x" nodeguid " with failure" + oldlid = lid + } + pe++; + } +} + +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} + +END { + printf "\n## Summary: %d nodes checked, %d bad nodes found\n", nnodes, ne + printf "## %d ports checked, %d bad ports found\n", nports, pe + printf "## %d ports have errors beyond threshold\n", pcnterr + exit (ne + pe + pcnterr) +} +' +av=$? +if [ $av -ne 0 ] ; then + exit $av +else + exit $rv +fi diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibchecknode.in b/contrib/ofed/management/infiniband-diags/scripts/ibchecknode.in new file mode 100644 index 000000000000..5eea7b58b4e7 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibchecknode.in @@ -0,0 +1,100 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [-v] [-N | -nocolor] [-G]" \ + "[-C ca_name] [-P ca_port] [-t(imeout) timeout_ms] " + exit -1 +} + +function green() { + if [ "$bw" = "yes" ]; then + if [ "$verbose" = "yes" ]; then + echo $1 + fi + return + fi + if [ "$verbose" = "yes" ]; then + echo -e "\\033[1;032m" $1 "\\033[0;39m" + fi +} + +function red() { + if [ "$bw" = "yes" ]; then + echo $1 + return + fi + echo -e "\\033[1;031m" $1 "\\033[0;39m" +} + +guid_addr="" +bw="" +verbose="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -G) + guid_addr=yes + ;; + -nocolor|-N) + bw=yes + ;; + -v) + verbose=yes + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + break + ;; + esac + shift +done + +if [ -z "$1" ]; then + usage +fi + +if [ "$guid_addr" ]; then + if ! lid=`$IBPATH/ibaddr $ca_info -G -L $1 | awk '/failed/{exit -1} {print $3}'`; then + echo -n "guid $1 address resolution: " + red "FAILED" + exit -1 + fi +else + lid=$1 + if ! temp=`$IBPATH/ibaddr $ca_info -L $1 | awk '/failed/{exit -1} {print $1}'`; then + echo -n "lid $1 address resolution: " + red "FAILED" + exit -1 + fi +fi + +## For now, check node only checks if node info is replied + +if $IBPATH/smpquery $ca_info nodeinfo $lid > /dev/null 2>&1 ; then + if [ "$verbose" = "yes" ]; then + echo -n "Node check lid $lid: " + green OK + fi + exit 0 +else + echo -n "Node check lid $lid: " + red FAILED + exit -1 +fi diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibcheckport.in b/contrib/ofed/management/infiniband-diags/scripts/ibcheckport.in new file mode 100644 index 000000000000..fa5e81ece024 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibcheckport.in @@ -0,0 +1,144 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [-v] [-N | -nocolor] [-G]" \ + "[-C ca_name] [-P ca_port] [-t(imeout) timeout_ms] " + exit -1 +} + +function green() { + if [ "$bw" = "yes" ]; then + if [ "$verbose" = "yes" ]; then + echo $1 + fi + return + fi + if [ "$verbose" = "yes" ]; then + echo -e "\\033[1;032m" $1 "\\033[0;39m" + fi +} + +function red() { + if [ "$bw" = "yes" ]; then + echo $1 + return + fi + echo -e "\\033[1;031m" $1 "\\033[0;39m" +} + +guid_addr="" +bw="" +verbose="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -G) + guid_addr=yes + ;; + -nocolor|-N) + bw=yes + ;; + -v) + verbose=yes + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + break + ;; + esac + shift +done + +if [ $# -lt 2 ]; then + usage +fi + +portnum=$2 + +if [ "$guid_addr" ]; then + if ! lid=`$IBPATH/ibaddr $ca_info -G -L $1 | awk '/failed/{exit -1} {print $3}'`; then + echo -n "guid $1 address resolution: " + red "FAILED" + exit -1 + fi + guid=$1 +else + lid=$1 + if ! temp=`$IBPATH/ibaddr $ca_info -L $1 | awk '/failed/{exit -1} {print $1}'`; then + echo -n "lid $1 address resolution: " + red "FAILED" + exit -1 + fi +fi + + +text="`eval $IBPATH/smpquery $ca_info portinfo $lid $portnum`" +rv=$? +if echo "$text" | awk -v mono=$bw -F '[.:]*' ' +function blue(s) +{ + if (mono) + printf s + else if (!quiet) { + printf "\033[1;034m" s + printf "\033[0;39m" + } +} + +# Checks + +/^PhysLinkState/{ if ($2 != "LinkUp") {err = err "#error: Physical link state is " $2 " lid '$lid' port '$portnum'\n"; exit -1}} + +/^LinkState/{ if ($2 != "Active") warn = warn "#warn: Logical link state is " $2 " lid '$lid' port '$portnum'\n"} + +/^LinkWidthActive/{ if ($2 == "1X") warn = warn "#warn: Link configured as 1X lid '$lid' port '$portnum'\n"} + +/^Lid/{ if ($2 == "0") warn = warn "#warn: Lid is not configured lid '$lid' port '$portnum'\n"} + +/^SMLid/{ if ($2 == "0") warn = warn "#warn: SM Lid is not configured\n"} + +#/^LocalPort/ { if ($2 != '$portnum') {err = err "#error: port " $2 " does not match query ('$portnum')\n"; exit -1}} + +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} + +END { + if (err != "") { + blue(err) + exit -1 + } + if (warn != "") { + blue(warn) + exit -1 + } + exit 0 +}' 2>&1 && test $rv -eq 0 ; then + if [ "$verbose" = "yes" ]; then + echo -n "Port check lid $lid port $portnum: " + green "OK" + fi + exit 0 +else + echo -n "Port check lid $lid port $portnum: " + red "FAILED" + exit -1 +fi diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibcheckportstate.in b/contrib/ofed/management/infiniband-diags/scripts/ibcheckportstate.in new file mode 100644 index 000000000000..dc4fb1408cd2 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibcheckportstate.in @@ -0,0 +1,136 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [-v] [-N | -nocolor] [-G]" \ + "[-C ca_name] [-P ca_port] [-t(imeout) timeout_ms] " + exit -1 +} + +function green() { + if [ "$bw" = "yes" ]; then + if [ "$verbose" = "yes" ]; then + echo $1 + fi + return + fi + if [ "$verbose" = "yes" ]; then + echo -e "\\033[1;032m" $1 "\\033[0;39m" + fi +} + +function red() { + if [ "$bw" = "yes" ]; then + echo $1 + return + fi + echo -e "\\033[1;031m" $1 "\\033[0;39m" +} + +guid_addr="" +bw="" +verbose="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -G) + guid_addr=yes + ;; + -nocolor|-N) + bw=yes + ;; + -v) + verbose=yes + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + break + ;; + esac + shift +done + +if [ $# -lt 2 ]; then + usage +fi + +portnum=$2 + +if [ "$guid_addr" ]; then + if ! lid=`$IBPATH/ibaddr $ca_info -G -L $1 | awk '/failed/{exit -1} {print $3}'`; then + echo -n "guid $1 address resolution: " + red "FAILED" + exit -1 + fi + guid=$1 +else + lid=$1 + if ! temp=`$IBPATH/ibaddr $ca_info -L $1 | awk '/failed/{exit -1} {print $1}'`; then + echo -n "lid $1 address resolution: " + red "FAILED" + exit -1 + fi +fi + + +text="`eval $IBPATH/smpquery $ca_info portinfo $lid $portnum`" +rv=$? +if echo "$text" | awk -v mono=$bw -F '[.:]*' ' +function blue(s) +{ + if (mono) + printf s + else if (!quiet) { + printf "\033[1;034m" s + printf "\033[0;39m" + } +} + +# Only check PortPhysicalState and PortState + +/^PhysLinkState/{ if ($2 != "LinkUp") {err = err "#error: Physical link state is " $2 " lid '$lid' port '$portnum'\n"; exit -1}} + +/^LinkState/{ if ($2 != "Active") warn = warn "#warn: Logical link state is " $2 " lid '$lid' port '$portnum'\n"} + +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} + +END { + if (err != "") { + blue(err) + exit -1 + } + if (warn != "") { + blue(warn) + exit -1 + } + exit 0 +}' 2>&1 && test $rv -eq 0 ; then + if [ "$verbose" = "yes" ]; then + echo -n "Port check lid $lid port $portnum: " + green "OK" + fi + exit 0 +else + echo -n "Port check lid $lid port $portnum: " + red "FAILED" + exit -1 +fi diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibcheckportwidth.in b/contrib/ofed/management/infiniband-diags/scripts/ibcheckportwidth.in new file mode 100644 index 000000000000..32c5c5e68999 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibcheckportwidth.in @@ -0,0 +1,134 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [-v] [-N | -nocolor] [-G]" \ + "[-C ca_name] [-P ca_port] [-t(imeout) timeout_ms] " + exit -1 +} + +function green() { + if [ "$bw" = "yes" ]; then + if [ "$verbose" = "yes" ]; then + echo $1 + fi + return + fi + if [ "$verbose" = "yes" ]; then + echo -e "\\033[1;032m" $1 "\\033[0;39m" + fi +} + +function red() { + if [ "$bw" = "yes" ]; then + echo $1 + return + fi + echo -e "\\033[1;031m" $1 "\\033[0;39m" +} + +guid_addr="" +bw="" +verbose="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -G) + guid_addr=yes + ;; + -nocolor|-N) + bw=yes + ;; + -v) + verbose=yes + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + break + ;; + esac + shift +done + +if [ $# -lt 2 ]; then + usage +fi + +portnum=$2 + +if [ "$guid_addr" ]; then + if ! lid=`$IBPATH/ibaddr $ca_info -G -L $1 | awk '/failed/{exit -1} {print $3}'`; then + echo -n "guid $1 address resolution: " + red "FAILED" + exit -1 + fi + guid=$1 +else + lid=$1 + if ! temp=`$IBPATH/ibaddr $ca_info -L $1 | awk '/failed/{exit -1} {print $1}'`; then + echo -n "lid $1 address resolution: " + red "FAILED" + exit -1 + fi +fi + + +text="`eval $IBPATH/smpquery $ca_info portinfo $lid $portnum`" +rv=$? +if echo "$text" | awk -v mono=$bw -F '[.:]*' ' +function blue(s) +{ + if (mono) + printf s + else if (!quiet) { + printf "\033[1;034m" s + printf "\033[0;39m" + } +} + +# Only check LinkWidthActive if LinkWidthSupported is not 1X +/^LinkWidthSupported/{ if ($2 != "1X") { next } } +/^LinkWidthActive/{ if ($2 == "1X") warn = warn "#warn: Link configured as 1X lid '$lid' port '$portnum'\n"} + +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} + +END { + if (err != "") { + blue(err) + exit -1 + } + if (warn != "") { + blue(warn) + exit -1 + } + exit 0 +}' 2>&1 && test $rv -eq 0 ; then + if [ "$verbose" = "yes" ]; then + echo -n "Port check lid $lid port $portnum: " + green "OK" + fi + exit 0 +else + echo -n "Port check lid $lid port $portnum: " + red "FAILED" + exit -1 +fi diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibcheckstate.in b/contrib/ofed/management/infiniband-diags/scripts/ibcheckstate.in new file mode 100644 index 000000000000..63551d563524 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibcheckstate.in @@ -0,0 +1,135 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [-v] [-N | -nocolor]" \ + "[ | -C ca_name -P ca_port -t(imeout) timeout_ms]" + exit -1 +} + +function user_abort() { + echo "Aborted" + exit 1 +} + +trap user_abort SIGINT + +gflags="" +verbose="" +v=0 +ntype="" +nodeguid="" +oldlid="" +topofile="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -h) + usage + ;; + -N|-nocolor) + gflags=-N + ;; + -v) + verbose=-v + v=1 + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + if [ "$topofile" ]; then + usage + fi + topofile="$1" + ;; + esac + shift +done + +if [ "$topofile" ]; then + netcmd="cat $topofile" +else + netcmd="$IBPATH/ibnetdiscover $ca_info" +fi + +text="`eval $netcmd`" +rv=$? +echo "$text" | awk ' +BEGIN { + ne=0 + pe=0 +} +function check_node(lid) +{ + nodechecked=1 + if (system("'$IBPATH'/ibchecknode'"$ca_info"' '$gflags' '$verbose' " lid)) { + ne++ + badnode=1 + return + } +} + +/^Ca/ || /^Switch/ || /^Rt/ { + nnodes++ + ntype=$1; nodeguid=substr($3, 4, 16); ports=$2 + if ('$v') + print "\n# Checking " ntype ": nodeguid 0x" nodeguid + + nodechecked=0 + badnode=0 + if (ntype != "Switch") + next + + lid = substr($0, index($0, "port 0 lid ") + 11) + lid = substr(lid, 1, index(lid, " ") - 1) + check_node(lid) + } +/^\[/ { + nports++ + port = $1 + if (!nodechecked) { + lid = substr($0, index($0, " lid ") + 5) + lid = substr(lid, 1, index(lid, " ") - 1) + check_node(lid) + } + if (badnode) { + print "\n# " ntype ": nodeguid 0x" nodeguid " failed" + next + } + sub("\\(.*\\)", "", port) + gsub("[\\[\\]]", "", port) + if (system("'$IBPATH'/ibcheckportstate'"$ca_info"' '$gflags' '$verbose' " lid " " port)) { + if (!'$v' && oldlid != lid) { + print "# Checked " ntype ": nodeguid 0x" nodeguid " with failure" + oldlid = lid + } + pe++; + } +} + +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} + +END { + printf "\n## Summary: %d nodes checked, %d bad nodes found\n", nnodes, ne + printf "## %d ports checked, %d ports with bad state found\n", nports, pe +} +' +exit $rv diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibcheckwidth.in b/contrib/ofed/management/infiniband-diags/scripts/ibcheckwidth.in new file mode 100644 index 000000000000..6b723c54d3a7 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibcheckwidth.in @@ -0,0 +1,135 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [-v] [-N | -nocolor]" \ + "[ \| -C ca_name -P ca_port -t(imeout) timeout_ms]" + exit -1 +} + +function user_abort() { + echo "Aborted" + exit 1 +} + +trap user_abort SIGINT + +gflags="" +verbose="" +v=0 +ntype="" +nodeguid="" +oldlid="" +topofile="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -h) + usage + ;; + -N|-nocolor) + gflags=-N + ;; + -v) + verbose="-v" + v=1 + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + if [ "$topofile" ]; then + usage + fi + topofile="$1" + ;; + esac + shift +done + +if [ "$topofile" ]; then + netcmd="cat $topofile" +else + netcmd="$IBPATH/ibnetdiscover $ca_info" +fi + +text="`eval $netcmd`" +rv=$? +echo "$text" | awk ' +BEGIN { + ne=0 + pe=0 +} +function check_node(lid) +{ + nodechecked=1 + if (system("'$IBPATH'/ibchecknode'"$ca_info"' '$gflags' '$verbose' " lid)) { + ne++ + badnode=1 + return + } +} + +/^Ca/ || /^Switch/ || /^Rt/ { + nnodes++ + ntype=$1; nodeguid=substr($3, 4, 16); ports=$2 + if ('$v') + print "\n# Checking " ntype ": nodeguid 0x" nodeguid + + nodechecked=0 + badnode=0 + if (ntype != "Switch") + next + + lid = substr($0, index($0, "port 0 lid ") + 11) + lid = substr(lid, 1, index(lid, " ") - 1) + check_node(lid) + } +/^\[/ { + nports++ + port = $1 + if (!nodechecked) { + lid = substr($0, index($0, " lid ") + 5) + lid = substr(lid, 1, index(lid, " ") - 1) + check_node(lid) + } + if (badnode) { + print "\n# " ntype ": nodeguid 0x" nodeguid " failed" + next + } + sub("\\(.*\\)", "", port) + gsub("[\\[\\]]", "", port) + if (system("'$IBPATH'/ibcheckportwidth'"$ca_info"' '$gflags' '$verbose' " lid " " port)) { + if (!'$v' && oldlid != lid) { + print "# Checked " ntype ": nodeguid 0x" nodeguid " with failure" + oldlid = lid + } + pe++; + } +} + +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} + +END { + printf "\n## Summary: %d nodes checked, %d bad nodes found\n", nnodes, ne + printf "## %d ports checked, %d ports with 1x width in error found\n", nports, pe +} +' +exit $rv diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibclearcounters.in b/contrib/ofed/management/infiniband-diags/scripts/ibclearcounters.in new file mode 100644 index 000000000000..86a5528b74c4 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibclearcounters.in @@ -0,0 +1,107 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [" \ + "| -C ca_name -P ca_port -t(imeout) timeout_ms]" + exit -1 +} + +function user_abort() { + echo "Aborted" + exit 1 +} + +trap user_abort SIGINT + +gflags="" +verbose="" +v=0 +topofile="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -h) + usage + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + if [ "$topofile" ]; then + usage + fi + topofile="$1" + ;; + esac + shift +done + +if [ "$topofile" ]; then + netcmd="cat $topofile" +else + netcmd="$IBPATH/ibnetdiscover $ca_info" +fi + +text="`eval $netcmd`" +rv=$? +echo "$text" | awk ' + +function clear_counters(lid) +{ + if (system("'$IBPATH'/perfquery'"$ca_info"' '$gflags' -R -a " lid)) + nodeerr++ +} + +function clear_port_counters(lid, port) +{ + if (system("'$IBPATH'/perfquery'"$ca_info"' '$gflags' -R " lid " " port)) + nodeerr++ +} + +/^Ca/ || /^Switch/ || /^Rt/ { + nnodes++ + ntype=$1; nodeguid=substr($3, 4, 16); ports=$2 + if (ntype != "Switch") + next + + lid = substr($0, index($0, "port 0 lid ") + 11) + lid = substr(lid, 1, index(lid, " ") - 1) + clear_counters(lid) + } + +/^\[/ { + port = $1 + sub("\\(.*\\)", "", port) + gsub("[\\[\\]]", "", port) + if (ntype != "Switch") { + lid = substr($0, index($0, " lid ") + 5) + lid = substr(lid, 1, index(lid, " ") - 1) + clear_port_counters(lid, port) + } + } + +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} + +END { + printf "\n## Summary: %d nodes cleared %d errors\n", nnodes, nodeerr +} +' +exit $rv diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibclearerrors.in b/contrib/ofed/management/infiniband-diags/scripts/ibclearerrors.in new file mode 100644 index 000000000000..3dfb96bbf4da --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibclearerrors.in @@ -0,0 +1,111 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [-N | -nocolor] [" \ + "| -C ca_name -P ca_port -t(imeout) timeout_ms]" + exit -1 +} + +function user_abort() { + echo "Aborted" + exit 1 +} + +trap user_abort SIGINT + +gflags="" +verbose="" +v=0 +oldlid="" +topofile="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -h) + usage + ;; + -N|-nocolor) + gflags=-N + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + if [ "$topofile" ]; then + usage + fi + topofile="$1" + ;; + esac + shift +done + +if [ "$topofile" ]; then + netcmd="cat $topofile" +else + netcmd="$IBPATH/ibnetdiscover $ca_info" +fi + +text="`eval $netcmd`" +rv=$? +echo "$text" | awk ' + +function clear_all_errors(lid, port) +{ + if (system("'$IBPATH'/perfquery'"$ca_info"' '$gflags' -R -a " lid " " port " 0x0fff")) + nodeerr++ +} + +function clear_errors(lid, port) +{ + if (system("'$IBPATH'/perfquery'"$ca_info"' '$gflags' -R " lid " " port " 0x0fff")) + nodeerr++ +} + +/^Ca/ || /^Switch/ || /^Rt/ { + nnodes++ + ntype=$1; nodeguid=substr($3, 4, 16); ports=$2 + if (ntype != "Switch") + next + + lid = substr($0, index($0, "port 0 lid ") + 11) + lid = substr(lid, 1, index(lid, " ") - 1) + clear_all_errors(lid, 255) + } + +/^\[/ { + port = $1 + sub("\\(.*\\)", "", port) + gsub("[\\[\\]]", "", port) + if (ntype != "Switch") { + lid = substr($0, index($0, " lid ") + 5) + lid = substr(lid, 1, index(lid, " ") - 1) + clear_errors(lid, port) + } + } + +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} + +END { + printf "\n## Summary: %d nodes cleared %d errors\n", nnodes, nodeerr +} +' +exit $rv diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibdatacounters.in b/contrib/ofed/management/infiniband-diags/scripts/ibdatacounters.in new file mode 100644 index 000000000000..59674067978f --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibdatacounters.in @@ -0,0 +1,129 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [-b] [-v] [-N | -nocolor]" \ + "[ \| -C ca_name -P ca_port -t(imeout) timeout_ms]" + exit -1 +} + +function user_abort() { + echo "Aborted" + exit 1 +} + +trap user_abort SIGINT + +gflags="" +verbose="" +brief="" +v=0 +ntype="" +nodeguid="" +topofile="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -h) + usage + ;; + -N|-nocolor) + gflags=-N + ;; + -v) + verbose=-v + brief="" + v=1 + ;; + -b) + brief=-b + verbose="" + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + if [ "$topofile" ]; then + usage + fi + topofile="$1" + ;; + esac + shift +done + +if [ "$topofile" ]; then + netcmd="cat $topofile" +else + netcmd="$IBPATH/ibnetdiscover $ca_info" +fi + +text="`eval $netcmd`" +rv=$? +echo "$text" | awk ' +BEGIN { + ne=0 +} +function check_node(lid, port) +{ + if (system("'$IBPATH'/ibchecknode '"$ca_info"' '$gflags' '$verbose' " lid)) { + ne++ + print "\n# " ntype ": nodeguid 0x" nodeguid " failed" + return 1; + } + return system("'$IBPATH'/ibcheckerrs '"$ca_info"' '$gflags' '$verbose' '$brief' " lid " " port); +} + +/^Ca/ || /^Switch/ || /^Rt/ { + nnodes++ + ntype=$1; nodeguid=substr($3, 4, 16); ports=$2 + if ('$v') + print "\n# Checking " ntype ": nodeguid 0x" nodeguid + + err = 0; + if (ntype != "Switch") + next + + lid = substr($0, index($0, "port 0 lid ") + 11) + lid = substr(lid, 1, index(lid, " ") - 1) + err = check_node(lid, 255) + } +/^\[/ { + nports++ + port = $1 + sub("\\(.*\\)", "", port) + gsub("[\\[\\]]", "", port) + if (ntype != "Switch") { + lid = substr($0, index($0, " lid ") + 5) + lid = substr(lid, 1, index(lid, " ") - 1) + check_node(lid, port) + } else if (err) + system("'$IBPATH'/ibdatacounts '"$ca_info"' '$gflags' '$verbose' '$brief' " lid " " port); +} + +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} + +END { + printf "\n## Summary: %d nodes checked, %d bad nodes found\n", nnodes, ne + printf "## %d ports checked\n", nports + exit (ne ) +} +' +exit $rv diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibdatacounts.in b/contrib/ofed/management/infiniband-diags/scripts/ibdatacounts.in new file mode 100644 index 000000000000..3dbc56a2f6e8 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibdatacounts.in @@ -0,0 +1,164 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [-b] [-v] [-G] [-N | -nocolor]" \ + "[-C ca_name] [-P ca_port] [-t(imeout) timeout_ms] " \ + "[]" + exit -1 +} + +function green() { + if [ "$bw" = "yes" ]; then + if [ "$verbose" = "yes" ]; then + echo $1 + fi + return + fi + if [ "$verbose" = "yes" ]; then + echo -e "\\033[1;032m" $1 "\\033[0;39m" + fi +} + +function red() { + if [ "$bw" = "yes" ]; then + echo $1 + return + fi + echo -e "\\033[1;031m" $1 "\\033[0;39m" +} + +guid_addr="" +bw="" +verbose="" +brief="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -G) + guid_addr=yes + ;; + -nocolor|-N) + bw=yes + ;; + -v) + verbose=yes + brief="" + ;; + -b) + brief=yes + verbose="" + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + break + ;; + esac + shift +done + +#default is all ports +portnum=255 + +if [ $# -lt 1 ]; then + usage +fi + +if [ "$2" ]; then + portnum=$2 +fi + +if [ "$portnum" = "255" ]; then + portname="all" +else + portname=$2 +fi + +if [ "$guid_addr" ]; then + if ! lid=`$IBPATH/ibaddr $ca_info -G -L $1 | awk '/failed/{exit -1} {print $3}'`; then + echo -n "guid $1 address resolution: " + red "FAILED" + exit -1 + fi + guid=$1 +else + lid=$1 + if ! temp=`$IBPATH/ibaddr $ca_info -L $1 | awk '/failed/{exit -1} {print $1}'`; then + echo -n "lid $1 address resolution: " + red "FAILED" + exit -1 + fi +fi + +nodename=`smpquery $ca_info nodedesc $lid | sed -e "s/^Node Description:\.*\(.*\)/\1/"` + +text="`eval $IBPATH/perfquery $ca_info $lid $portnum`" +rv=$? +if echo "$text" | awk -v mono=$bw -v brief=$brief -F '[.:]*' ' +function blue(s) +{ + if (brief == "yes") { + return + } + if (mono) + printf s + else if (!quiet) { + printf "\033[1;034m" s + printf "\033[0;39m" + } +} + +# Only display Xmit/Rcv Pkts/Data + +/^# Port counters/ {print} + +/^CounterSelect/ {next} + +/AllPortSelect/ {next} + +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} + +/^PortSelect/ { if ($2 != '$portnum') {err = err "error: lid '$lid' port " $2 " does not match query ('$portnum')\n"; exit -1}} + +$1 ~ "(Xmt|Rcv)(Pkts|Data)" { print $1 ":........................." $2 } + +END { + if (err != "") { + blue(err) + exit -1 + } + if (warn != "") { + blue(warn) + exit -1 + } + exit 0 +}' 2>&1 && test $rv -eq 0 ; then + if [ "$verbose" = "yes" ]; then + echo -n "Error on lid $lid ($nodename) port $portname: " + green OK + fi + exit 0 +else + echo -n "Error on lid $lid ($nodename) port $portname: " + red FAILED + exit -1 +fi diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibdiscover.map b/contrib/ofed/management/infiniband-diags/scripts/ibdiscover.map new file mode 100644 index 000000000000..58c69da5f6bd --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibdiscover.map @@ -0,0 +1,6 @@ +8f10400410015|8|"ISR 6000"|# SW-6IB4 Voltaire port 0 lid 5 +5442ba00003080|24|"ISR 9024"|# ISR9024 Voltaire port 0 lid 2 +8f10403960558|2|"HCA 1"|# MT23108 InfiniHost Mellanox Technologies +5442b100004900|2|"HCA 2"|# MT23108 InfiniHost Mellanox Technologies +8f10403961354|2|"HCA 3"|# MT23108 InfiniHost Mellanox Technologies +8f10403960984|2|"HCA 4"|# MT23108 InfiniHost Mellanox Technologies diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibdiscover.pl b/contrib/ofed/management/infiniband-diags/scripts/ibdiscover.pl new file mode 100755 index 000000000000..86069195d32a --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibdiscover.pl @@ -0,0 +1,86 @@ +#!/usr/bin/perl + +# +# Read mapfile +# +open(MAP, "< ibdiscover.map"); + +while () { + ($pre, $port, $desc) = split /\|/; + $val{$pre} = $desc; + # print "Ack1 - $pre - $port - $desc\n"; +} +close(MAP); + +# +# Read old topo map in +# +open(TOPO, "< ibdiscover.topo"); +$topomap = 0; + +while () { + $topomap = 1; + ($localPort, $localGuid, $remotePort, $remoteGuid) = split /\|/; + chomp $remoteGuid; + $var = sprintf("%s|%2s|%2s|%s", $localGuid, $localPort, $remotePort, + $remoteGuid); + $topo{$var} = 1; + # ${$pre} = $desc; + # print "Ack1 - $pre - $port - $desc\n"; +} +close(TOPO); + +# +# Read stdin and output enhanced output +# +# Search and replace =0x???? with value +# Search and replace -000???? with value + +open(TOPO2, " >ibdiscover.topo.new"); +while () { + ($a, $b, $local, $d) = /([sh])([\s\S]*)=0x([a-f\d]*)([\s\S]*)/; + if ($local ne "") { + printf( + "\n%s GUID: %s %s\n", + ($a eq "s" ? "Switch" : "Host"), + $local, $val{$local} + ); + chomp $local; + $localGuid = $local; + } else { + ($localPort, $type, $remoteGuid, $remotePort) = + /([\s\S]*)"([SH])\-000([a-f\d]*)"([\s\S]*)\n/; + ($localPort) = $localPort =~ /\[(\d*)]/; + ($remotePort) = $remotePort =~ /\[(\d*)]/; + if ($remoteGuid ne "" && $localPort ne "") { + printf(TOPO2 "%d|%s|%d|%s\n", + $localPort, $localGuid, $remotePort, $remoteGuid); + $var = sprintf("%s|%2s|%2s|%s", + $localGuid, $localPort, $remotePort, $remoteGuid); + $topo{$var} += 1; + printf( + "Local: %2s Remote: %2s %7s GUID: %s Location: %s\n", + $localPort, + $remotePort, + ($type eq "H" ? "Host" : "Switch"), + $remoteGuid, + ($val{$remoteGuid} ne "" ? $val{$remoteGuid} : $remoteGuid) + ); + } + } +} +close(STDIN); +close(TOPO2); + +printf("\nDelta change in topo (change between successive runs)\n\n"); + +foreach $el (keys %topo) { + if ($topo{$el} < 2 || $topomap == 0) { + ($lg, $lp, $rp, $rg) = split(/\|/, $el); + printf( +"Link change: Local/Remote Port %2d/%2d Local/Remote GUID: %s/%s\n", + $lp, $rp, $lg, $rg); + printf("\tLocations: Local/Remote\n\t\t%s\n\t\t%s\n\n", + $val{$lg}, $val{$rg}); + } +} diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibfindnodesusing.pl b/contrib/ofed/management/infiniband-diags/scripts/ibfindnodesusing.pl new file mode 100755 index 000000000000..a2102c74006d --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibfindnodesusing.pl @@ -0,0 +1,231 @@ +#!/usr/bin/perl +# +# Copyright (C) 2001-2003 The Regents of the University of California. +# Copyright (c) 2006 The Regents of the University of California. +# Copyright (c) 2007-2008 Voltaire, Inc. All rights reserved. +# +# Produced at Lawrence Livermore National Laboratory. +# Written by Ira Weiny +# Jim Garlick +# Albert Chu +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +use strict; + +use Getopt::Std; +use IBswcountlimits; +my $ca_name = ""; +my $ca_port = ""; + +# ========================================================================= +# +sub get_hosts_routed +{ + my $sw_guid = $_[0]; + my $sw_port = $_[1]; + my @hosts = undef; + my $extra_params = get_ca_name_port_param_string($ca_name, $ca_port); + + if ($sw_guid eq "") { return (@hosts); } + + my $data = `ibroute $extra_params -G $sw_guid`; + my @lines = split("\n", $data); + foreach my $line (@lines) { + if ($line =~ /\w+\s+(\d+)\s+:\s+\(Channel Adapter.*:\s+'(.*)'\)/) { + if ($1 == $sw_port) { + push @hosts, $2; + } + } + } + + return (@hosts); +} + +# ========================================================================= +# +sub usage_and_exit +{ + my $prog = $_[0]; + print +"Usage: $prog [-R -C -P ] \n"; + print " find a list of nodes which are routed through switch:port\n"; + print " -R Recalculate ibnetdiscover information\n"; + print " -C use selected Channel Adaptor name for queries\n"; + print " -P use selected channel adaptor port for queries\n"; + exit 2; +} + +my $argv0 = `basename $0`; +my $regenerate_map = undef; +chomp $argv0; +if (!getopts("hRC:P:")) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_h) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_R) { $regenerate_map = $Getopt::Std::opt_R; } +if (defined $Getopt::Std::opt_C) { $ca_name = $Getopt::Std::opt_C; } +if (defined $Getopt::Std::opt_P) { $ca_port = $Getopt::Std::opt_P; } + +my $target_switch = format_guid($ARGV[0]); +my $target_port = $ARGV[1]; + +get_link_ends($regenerate_map, $ca_name, $ca_port); + +if ($target_switch eq "" || $target_port eq "") { + usage_and_exit $argv0; +} + +# sortn: +# +# sort a group of alphanumeric strings by the last group of digits on +# those strings, if such exists (good for numerically suffixed host lists) +# +sub sortn +{ + map { $$_[0] } + sort { ($$a[1] || 0) <=> ($$b[1] || 0) } map { [$_, /(\d*)$/] } @_; +} + +# comp2(): +# +# takes a list of names and returns a hash of arrays, indexed by name prefix, +# each containing a list of numerical ranges describing the initial list. +# +# e.g.: %hash = comp2(lx01,lx02,lx03,lx05,dev0,dev1,dev21) +# will return: +# $hash{"lx"} = ["01-03", "05"] +# $hash{"dev"} = ["0-1", "21"] +# +sub comp2 +{ + my (%i) = (); + my (%s) = (); + + # turn off warnings here to avoid perl complaints about + # uninitialized values for members of %i and %s + local ($^W) = 0; + push( + @{ + $s{$$_[0]}[ + ( + $s{$$_[0]}[$i{$$_[0]}][$#{$s{$$_[0]}[$i{$$_[0]}]}] == + ($$_[1] - 1) + ) ? $i{$$_[0]} : ++$i{$$_[0]} + ] + }, + ($$_[1]) + ) for map { [/(.*?)(\d*)$/] } sortn(@_); + + for my $key (keys %s) { + @{$s{$key}} = + map { $#$_ > 0 ? "$$_[0]-$$_[$#$_]" : @{$_} } @{$s{$key}}; + } + + return %s; +} + +sub compress_hostlist +{ + my %rng = comp2(@_); + my @list = (); + + local $" = ","; + + foreach my $k (keys %rng) { + @{$rng{$k}} = map { "$k$_" } @{$rng{$k}}; + } + @list = map { @{$rng{$_}} } sort keys %rng; + return "@list"; +} + +# ========================================================================= +# +sub main +{ + my $found_switch = undef; + my $cache_file = get_cache_file($ca_name, $ca_port); + open IBNET_TOPO, "<$cache_file" or die "Failed to open ibnet topology\n"; + my $in_switch = "no"; + my $switch_guid = ""; + my $desc = undef; + my %ports = undef; + while (my $line = ) { + + if ($line =~ /^Switch.*\"S-(.*)\"\s+# (.*) port.*/) { + $switch_guid = $1; + $desc = $2; + if ("0x$switch_guid" eq $target_switch + || $desc =~ /.*$target_switch\s+.*/) + { + $found_switch = "yes"; + goto FOUND; + } + } + if ($line =~ /^Ca.*/ || $line =~ /^Rt.*/) { $in_switch = "no"; } + + if ($line =~ /^\[(\d+)\].*/ && $in_switch eq "yes") { + $ports{$1} = $line; + } + + } + + FOUND: + close IBNET_TOPO; + if (!$found_switch) { + print "Switch \"$target_switch\" not found\n"; + print " Try running with the \"-R\" or \"-P\" option.\n"; + exit 1; + } + + $switch_guid = "0x$switch_guid"; + + my $hr = $IBswcountlimits::link_ends{$switch_guid}{$target_port}; + my $rem_sw_guid = $hr->{rem_guid}; + my $rem_sw_port = $hr->{rem_port}; + my $rem_sw_desc = $hr->{rem_desc}; + + my @hosts = undef; + @hosts = get_hosts_routed($switch_guid, $target_port); + + my $hosts = compress_hostlist(@hosts); + @hosts = split ",", $hosts; + print +"$switch_guid $target_port ($desc) ==>> $rem_sw_guid $rem_sw_port ($rem_sw_desc)\n"; + print "@hosts\n\n"; + + @hosts = get_hosts_routed($rem_sw_guid, $rem_sw_port); + + $hosts = compress_hostlist(@hosts); + @hosts = split ",", $hosts; + print +"$switch_guid $target_port ($desc) <<== $rem_sw_guid $rem_sw_port ($rem_sw_desc)\n"; + print "@hosts\n"; +} +main + diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibhosts.in b/contrib/ofed/management/infiniband-diags/scripts/ibhosts.in new file mode 100644 index 000000000000..baba1051056c --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibhosts.in @@ -0,0 +1,60 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [ | -C ca_name" \ + "-P ca_port -t(imeout) timeout_ms]" + exit -1 +} + +topofile="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -h) + usage + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + if [ "$topofile" ]; then + usage + fi + topofile="$1" + ;; + esac + shift +done + +if [ "$topofile" ]; then + netcmd="cat $topofile" +else + netcmd="$IBPATH/ibnetdiscover $ca_info" +fi + +text="`eval $netcmd`" +rv=$? +echo "$text" | awk ' +/^Ca/ {print $1 "\t: 0x" substr($3, 4, 16) " ports " $2 " "\ + substr($0, match($0, "#[ \t]*")+RLENGTH)} +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} +' +exit $rv diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibidsverify.pl b/contrib/ofed/management/infiniband-diags/scripts/ibidsverify.pl new file mode 100755 index 000000000000..0d017ba94ebb --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibidsverify.pl @@ -0,0 +1,254 @@ +#!/usr/bin/perl +# +# Copyright (c) 2007-2008 Voltaire, Inc. All rights reserved. +# Copyright (c) 2006 The Regents of the University of California. +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +use strict; + +use Getopt::Std; +use IBswcountlimits; + +sub usage_and_exit +{ + my $prog = $_[0]; + print "Usage: $prog [-Rh]\n"; + print +" Validate LIDs and GUIDs (check for zero and duplicates) in the local subnet\n"; + print " -h This help message\n"; + print +" -R Recalculate ibnetdiscover information (Default is to reuse ibnetdiscover output)\n"; + exit 2; +} + +my $argv0 = `basename $0`; +my $regenerate_map = undef; + +chomp $argv0; +if (!getopts("hR")) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_h) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_R) { $regenerate_map = $Getopt::Std::opt_R; } + +sub validate_non_zero_lid +{ + my ($lid) = shift(@_); + my ($nodeguid) = shift(@_); + my ($nodetype) = shift(@_); + + if ($lid eq 0) { + print "LID 0 found for $nodetype NodeGUID $nodeguid\n"; + return 1; + } + return 0; +} + +sub validate_non_zero_guid +{ + my ($lid) = shift(@_); + my ($guid) = shift(@_); + my ($nodetype) = shift(@_); + + if ($guid eq 0x0) { + print "$nodetype GUID 0x0 found with LID $lid\n"; + return 1; + } + return 0; +} + +$insert_lid::lids = undef; +$insert_nodeguid::nodeguids = undef; +$insert_portguid::portguids = undef; + +sub insert_lid +{ + my ($lid) = shift(@_); + my ($nodeguid) = shift(@_); + my ($nodetype) = shift(@_); + my $rec = undef; + my $status = ""; + + $status = validate_non_zero_lid($lid, $nodeguid, $nodetype); + if ($status eq 0) { + if (defined($insert_lid::lids{$lid})) { + print +"LID $lid already defined for NodeGUID $insert_lid::lids{$lid}->{nodeguid}\n"; + } else { + $rec = {lid => $lid, nodeguid => $nodeguid}; + $insert_lid::lids{$lid} = $rec; + } + } +} + +sub insert_nodeguid +{ + my ($lid) = shift(@_); + my ($nodeguid) = shift(@_); + my ($nodetype) = shift(@_); + my $rec = undef; + my $status = ""; + + $status = validate_non_zero_guid($lid, $nodeguid, $nodetype); + if ($status eq 0) { + if (defined($insert_nodeguid::nodeguids{$nodeguid})) { + print +"NodeGUID $nodeguid already defined for LID $insert_nodeguid::nodeguids{$nodeguid}->{lid}\n"; + } else { + $rec = {lid => $lid, nodeguid => $nodeguid}; + $insert_nodeguid::nodeguids{$nodeguid} = $rec; + } + } +} + +sub validate_portguid +{ + my ($portguid) = shift(@_); + my ($firstport) = shift(@_); + + if (defined($insert_nodeguid::nodeguids{$portguid}) + && ($firstport ne "yes")) + { + print "PortGUID $portguid is invalid duplicate of a NodeGUID\n"; + } +} + +sub insert_portguid +{ + my ($lid) = shift(@_); + my ($portguid) = shift(@_); + my ($nodetype) = shift(@_); + my ($firstport) = shift(@_); + my $rec = undef; + my $status = ""; + + $status = validate_non_zero_guid($lid, $portguid, $nodetype); + if ($status eq 0) { + if (defined($insert_portguid::portguids{$portguid})) { + print +"PortGUID $portguid already defined for LID $insert_portguid::portguids{$portguid}->{lid}\n"; + } else { + $rec = {lid => $lid, portguid => $portguid}; + $insert_portguid::portguids{$portguid} = $rec; + validate_portguid($portguid, $firstport); + } + } +} + +sub main +{ + if ($regenerate_map + || !(-f "$IBswcountlimits::cache_dir/ibnetdiscover.topology")) + { + generate_ibnetdiscover_topology; + } + + open IBNET_TOPO, "<$IBswcountlimits::cache_dir/ibnetdiscover.topology" + or die "Failed to open ibnet topology: $!\n"; + + my $nodetype = ""; + my $nodeguid = ""; + my $portguid = ""; + my $lid = ""; + my $line = ""; + my $firstport = ""; + + while ($line = ) { + + if ($line =~ /^caguid=(.*)/ || $line =~ /^rtguid=(.*)/) { + $nodeguid = $1; + $nodetype = ""; + } + + if ($line =~ /^switchguid=(.*)/) { + $nodeguid = $1; + $portguid = ""; + $nodetype = ""; + } + if ($line =~ /^switchguid=(.*)\((.*)\)/) { + $nodeguid = $1; + $portguid = "0x" . $2; + } + + if ($line =~ /^Switch.*\"S-(.*)\"\s+# (.*) port.* lid (\d+) .*/) { + $nodetype = "switch"; + $firstport = "yes"; + $lid = $3; + insert_lid($lid, $nodeguid, $nodetype); + insert_nodeguid($lid, $nodeguid, $nodetype); + if ($portguid ne "") { + insert_portguid($lid, $portguid, $nodetype, $firstport); + } + } + if ($line =~ /^Ca.*/) { + $nodetype = "ca"; + $firstport = "yes"; + } + if ($line =~ /^Rt.*/) { + $nodetype = "router"; + $firstport = "yes"; + } + + if ($nodetype eq "ca" || $nodetype eq "router") { + if ($line =~ /"S-(.*)\# lid (\d+) .*/) { + $lid = $2; + insert_lid($lid, $nodeguid, $nodetype); + if ($firstport eq "yes") { + insert_nodeguid($lid, $nodeguid, $nodetype); + $firstport = "no"; + } + } + if ($line =~ /^.*"H-(.*)\# lid (\d+) .*/) { + $lid = $2; + insert_lid($lid, $nodeguid, $nodetype); + if ($firstport eq "yes") { + insert_nodeguid($lid, $nodeguid, $nodetype); + $firstport = "no"; + } + } + if ($line =~ /^.*"R-(.*)\# lid (\d+) .*/) { + $lid = $2; + insert_lid($lid, $nodeguid, $nodetype); + if ($firstport eq "yes") { + insert_nodeguid($lid, $nodeguid, $nodetype); + $firstport = "no"; + } + } + if ($line =~ /^\[(\d+)\]\((.*)\)/) { + $portguid = "0x" . $2; + insert_portguid($lid, $portguid, $nodetype, $firstport); + } + } + + } + + close IBNET_TOPO; +} +main; + diff --git a/contrib/ofed/management/infiniband-diags/scripts/iblinkinfo.pl b/contrib/ofed/management/infiniband-diags/scripts/iblinkinfo.pl new file mode 100755 index 000000000000..b6b27ce9013c --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/iblinkinfo.pl @@ -0,0 +1,327 @@ +#!/usr/bin/perl +# +# Copyright (c) 2006 The Regents of the University of California. +# Copyright (c) 2007-2008 Voltaire, Inc. All rights reserved. +# +# Produced at Lawrence Livermore National Laboratory. +# Written by Ira Weiny . +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +use strict; + +use Getopt::Std; +use IBswcountlimits; + +sub usage_and_exit +{ + my $prog = $_[0]; + print +"Usage: $prog [-Rhclp -S -D -C -P ]\n"; + print +" Report link speed and connection for each port of each switch which is active\n"; + print " -h This help message\n"; + print +" -R Recalculate ibnetdiscover information (Default is to reuse ibnetdiscover output)\n"; + print +" -D output only the switch specified by direct route path\n"; + print " -S output only the switch specified by (hex format)\n"; + print " -d print only down links\n"; + print + " -l (line mode) print all information for each link on each line\n"; + print +" -p print additional switch settings (PktLifeTime,HoqLife,VLStallCount)\n"; + print " -c print port capabilities (enabled/supported values)\n"; + print " -C use selected Channel Adaptor name for queries\n"; + print " -P use selected channel adaptor port for queries\n"; + print " -g print port guids instead of node guids\n"; + exit 2; +} + +my $argv0 = `basename $0`; +my $regenerate_map = undef; +my $single_switch = undef; +my $direct_route = undef; +my $line_mode = undef; +my $print_add_switch = undef; +my $print_extended_cap = undef; +my $only_down_links = undef; +my $ca_name = ""; +my $ca_port = ""; +my $print_port_guids = undef; +my $switch_found = "no"; +chomp $argv0; + +if (!getopts("hcpldRS:D:C:P:g")) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_h) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_D) { $direct_route = $Getopt::Std::opt_D; } +if (defined $Getopt::Std::opt_R) { $regenerate_map = $Getopt::Std::opt_R; } +if (defined $Getopt::Std::opt_S) { + $single_switch = format_guid($Getopt::Std::opt_S); +} +if (defined $Getopt::Std::opt_d) { $only_down_links = $Getopt::Std::opt_d; } +if (defined $Getopt::Std::opt_l) { $line_mode = $Getopt::Std::opt_l; } +if (defined $Getopt::Std::opt_p) { $print_add_switch = $Getopt::Std::opt_p; } +if (defined $Getopt::Std::opt_c) { $print_extended_cap = $Getopt::Std::opt_c; } +if (defined $Getopt::Std::opt_C) { $ca_name = $Getopt::Std::opt_C; } +if (defined $Getopt::Std::opt_P) { $ca_port = $Getopt::Std::opt_P; } +if (defined $Getopt::Std::opt_g) { $print_port_guids = $Getopt::Std::opt_g; } + +my $extra_smpquery_params = get_ca_name_port_param_string($ca_name, $ca_port); + +sub main +{ + get_link_ends($regenerate_map, $ca_name, $ca_port); + if (defined($direct_route)) { + # convert DR to guid, then use original single_switch option + $single_switch = convert_dr_to_guid($direct_route); + if (!defined($single_switch) || !is_switch($single_switch)) { + printf("The direct route (%s) does not map to a switch.\n", + $direct_route); + return; + } + } + foreach my $switch (sort (keys(%IBswcountlimits::link_ends))) { + if ($single_switch && $switch ne $single_switch) { + next; + } else { + $switch_found = "yes"; + } + my $switch_prompt = "no"; + my $num_ports = get_num_ports($switch, $ca_name, $ca_port); + if ($num_ports == 0) { + printf("ERROR: switch $switch has 0 ports???\n"); + } + my @output_lines = undef; + my $pkt_lifetime = ""; + my $pkt_life_prompt = ""; + my $port_timeouts = ""; + my $print_switch = "yes"; + if ($only_down_links) { $print_switch = "no"; } + if ($print_add_switch) { + my $data = `smpquery $extra_smpquery_params -G switchinfo $switch`; + if ($data eq "") { + printf("ERROR: failed to get switchinfo for $switch\n"); + } + my @lines = split("\n", $data); + foreach my $line (@lines) { + if ($line =~ /^LifeTime:\.+(.*)/) { $pkt_lifetime = $1; } + } + $pkt_life_prompt = sprintf(" (LT: %2s)", $pkt_lifetime); + } + foreach my $port (1 .. $num_ports) { + my $hr = $IBswcountlimits::link_ends{$switch}{$port}; + if ($switch_prompt eq "no" && !$line_mode) { + my $switch_name = ""; + my $tmp_port = $port; + while ($switch_name eq "" && $tmp_port <= $num_ports) { + # the first port is down find switch name with up port + my $hr = $IBswcountlimits::link_ends{$switch}{$tmp_port}; + $switch_name = $hr->{loc_desc}; + $tmp_port++; + } + if ($switch_name eq "") { + printf( + "WARNING: Switch Name not found for $switch\n"); + } + push( + @output_lines, + sprintf( + "Switch %18s %s%s:\n", + $switch, $switch_name, $pkt_life_prompt + ) + ); + $switch_prompt = "yes"; + } + my $data = + `smpquery $extra_smpquery_params -G portinfo $switch $port`; + if ($data eq "") { + printf( + "ERROR: failed to get portinfo for $switch port $port\n"); + } + my @lines = split("\n", $data); + my $speed = ""; + my $speed_sup = ""; + my $speed_enable = ""; + my $width = ""; + my $width_sup = ""; + my $width_enable = ""; + my $state = ""; + my $hoq_life = ""; + my $vl_stall = ""; + my $phy_link_state = ""; + + foreach my $line (@lines) { + if ($line =~ /^LinkSpeedActive:\.+(.*)/) { $speed = $1; } + if ($line =~ /^LinkSpeedEnabled:\.+(.*)/) { + $speed_enable = $1; + } + if ($line =~ /^LinkSpeedSupported:\.+(.*)/) { $speed_sup = $1; } + if ($line =~ /^LinkWidthActive:\.+(.*)/) { $width = $1; } + if ($line =~ /^LinkWidthEnabled:\.+(.*)/) { + $width_enable = $1; + } + if ($line =~ /^LinkWidthSupported:\.+(.*)/) { $width_sup = $1; } + if ($line =~ /^LinkState:\.+(.*)/) { $state = $1; } + if ($line =~ /^HoqLife:\.+(.*)/) { $hoq_life = $1; } + if ($line =~ /^VLStallCount:\.+(.*)/) { $vl_stall = $1; } + if ($line =~ /^PhysLinkState:\.+(.*)/) { $phy_link_state = $1; } + } + my $rem_port = $hr->{rem_port}; + my $rem_lid = $hr->{rem_lid}; + my $rem_speed_sup = ""; + my $rem_speed_enable = ""; + my $rem_width_sup = ""; + my $rem_width_enable = ""; + if ($rem_lid ne "" && $rem_port ne "") { + $data = + `smpquery $extra_smpquery_params portinfo $rem_lid $rem_port`; + if ($data eq "") { + printf( + "ERROR: failed to get portinfo for $switch port $port\n" + ); + } + my @lines = split("\n", $data); + foreach my $line (@lines) { + if ($line =~ /^LinkSpeedEnabled:\.+(.*)/) { + $rem_speed_enable = $1; + } + if ($line =~ /^LinkSpeedSupported:\.+(.*)/) { + $rem_speed_sup = $1; + } + if ($line =~ /^LinkWidthEnabled:\.+(.*)/) { + $rem_width_enable = $1; + } + if ($line =~ /^LinkWidthSupported:\.+(.*)/) { + $rem_width_sup = $1; + } + } + } + my $capabilities = ""; + if ($print_extended_cap) { + $capabilities = sprintf("(%3s %s %6s / %8s [%s/%s][%s/%s])", + $width, $speed, $state, $phy_link_state, $width_enable, + $width_sup, $speed_enable, $speed_sup); + } else { + $capabilities = sprintf("(%3s %s %6s / %8s)", + $width, $speed, $state, $phy_link_state); + } + if ($print_add_switch) { + $port_timeouts = + sprintf(" (HOQ:%s VL_Stall:%s)", $hoq_life, $vl_stall); + } + if (!$only_down_links || ($only_down_links && $state eq "Down")) { + my $width_msg = ""; + my $speed_msg = ""; + if ($rem_width_enable ne "" && $rem_width_sup ne "") { + if ( $width_enable =~ /12X/ + && $rem_width_enable =~ /12X/ + && $width !~ /12X/) + { + $width_msg = "Could be 12X"; + } else { + if ( $width_enable =~ /8X/ + && $rem_width_enable =~ /8X/ + && $width !~ /8X/) + { + $width_msg = "Could be 8X"; + } else { + if ( $width_enable =~ /4X/ + && $rem_width_enable =~ /4X/ + && $width !~ /4X/) + { + $width_msg = "Could be 4X"; + } + } + } + } + if ($rem_speed_enable ne "" && $rem_speed_sup ne "") { + if ( $speed_enable =~ /10\.0/ + && $rem_speed_enable =~ /10\.0/ + && $speed !~ /10\.0/) + { + $speed_msg = "Could be 10.0 Gbps"; + } else { + if ( $speed_enable =~ /5\.0/ + && $rem_speed_enable =~ /5\.0/ + && $speed !~ /5\.0/) + { + $speed_msg = "Could be 5.0 Gbps"; + } + } + } + + if ($line_mode) { + my $line_begin = sprintf("%18s \"%30s\"%s", + $switch, $hr->{loc_desc}, $pkt_life_prompt); + my $ext_guid = sprintf("%18s", $hr->{rem_guid}); + if ($print_port_guids && $hr->{rem_port_guid} ne "") { + $ext_guid = sprintf("0x%016s", $hr->{rem_port_guid}); + } + push( + @output_lines, + sprintf( +"%s %6s %4s[%2s] ==%s%s==> %18s %6s %4s[%2s] \"%s\" ( %s %s)\n", + $line_begin, $hr->{loc_sw_lid}, + $port, $hr->{loc_ext_port}, + $capabilities, $port_timeouts, + $ext_guid, $hr->{rem_lid}, + $hr->{rem_port}, $hr->{rem_ext_port}, + $hr->{rem_desc}, $width_msg, + $speed_msg + ) + ); + } else { + push( + @output_lines, + sprintf( +" %6s %4s[%2s] ==%s%s==> %6s %4s[%2s] \"%s\" ( %s %s)\n", + $hr->{loc_sw_lid}, $port, + $hr->{loc_ext_port}, $capabilities, + $port_timeouts, $hr->{rem_lid}, + $hr->{rem_port}, $hr->{rem_ext_port}, + $hr->{rem_desc}, $width_msg, + $speed_msg + ) + ); + } + $print_switch = "yes"; + } + } + if ($print_switch eq "yes") { + foreach my $line (@output_lines) { print $line; } + } + } + if ($single_switch && $switch_found ne "yes") { + printf("Switch \"%s\" not found.\n", $single_switch); + } +} +main; + diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibnodes.in b/contrib/ofed/management/infiniband-diags/scripts/ibnodes.in new file mode 100644 index 000000000000..5871da835220 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibnodes.in @@ -0,0 +1,5 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +$IBPATH/ibhosts $@; $IBPATH/ibswitches $@ diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibprintca.pl b/contrib/ofed/management/infiniband-diags/scripts/ibprintca.pl new file mode 100755 index 000000000000..3cac9b4b7742 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibprintca.pl @@ -0,0 +1,136 @@ +#!/usr/bin/perl +# +# Copyright (c) 2006 The Regents of the University of California. +# Copyright (c) 2007-2008 Voltaire, Inc. All rights reserved. +# +# Produced at Lawrence Livermore National Laboratory. +# Written by Ira Weiny . +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +use strict; + +use Getopt::Std; +use IBswcountlimits; + +# ========================================================================= +# +sub usage_and_exit +{ + my $prog = $_[0]; + print "Usage: $prog [-R -l] [-G | ]\n"; + print " print only the ca specified from the ibnetdiscover output\n"; + print " -R Recalculate ibnetdiscover information\n"; + print " -l list cas\n"; + print " -C use selected channel adaptor name for queries\n"; + print " -P use selected channel adaptor port for queries\n"; + print " -G node is specified with GUID\n"; + exit 2; +} + +my $argv0 = `basename $0`; +my $regenerate_map = undef; +my $list_hcas = undef; +my $ca_name = ""; +my $ca_port = ""; +my $name_is_guid = "no"; +chomp $argv0; +if (!getopts("hRlC:P:G")) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_h) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_R) { $regenerate_map = $Getopt::Std::opt_R; } +if (defined $Getopt::Std::opt_l) { $list_hcas = $Getopt::Std::opt_l; } +if (defined $Getopt::Std::opt_C) { $ca_name = $Getopt::Std::opt_C; } +if (defined $Getopt::Std::opt_P) { $ca_port = $Getopt::Std::opt_P; } +if (defined $Getopt::Std::opt_G) { $name_is_guid = "yes"; } + +my $target_hca = $ARGV[0]; + +if ($name_is_guid eq "yes") { + $target_hca = format_guid($target_hca); +} + +my $cache_file = get_cache_file($ca_name, $ca_port); + +if ($regenerate_map || !(-f "$cache_file")) { + generate_ibnetdiscover_topology($ca_name, $ca_port); +} + +if ($list_hcas) { + system("ibhosts $cache_file"); + exit 1; +} + +if ($target_hca eq "") { + usage_and_exit $argv0; +} + +# ========================================================================= +# +sub main +{ + my $found_hca = 0; + open IBNET_TOPO, "<$cache_file" or die "Failed to open ibnet topology\n"; + my $in_hca = "no"; + my %ports = undef; + while (my $line = ) { + if ($line =~ /^Ca.*\"H-(.*)\"\s+# (.*)/) { + my $guid = $1; + my $desc = $2; + if ($in_hca eq "yes") { + $in_hca = "no"; + foreach my $port (sort { $a <=> $b } (keys %ports)) { + print $ports{$port}; + } + } + if ("0x$guid" eq $target_hca || $desc =~ /[\s\"]$target_hca[\s\"]/) { + print $line; + $in_hca = "yes"; + $found_hca++; + } + } + if ($line =~ /^Switch.*/ || $line =~ /^Rt.*/) { $in_hca = "no"; } + + if ($line =~ /^\[(\d+)\].*/ && $in_hca eq "yes") { + $ports{$1} = $line; + } + + } + if ($found_hca == 0) { + die "\"$target_hca\" not found\n" . + " Try running with the \"-R\" option.\n" . + " If still not found the node is probably down.\n"; + } + if ($found_hca > 1) { + print "\nWARNING: Found $found_hca CA's with the name \"$target_hca\"\n"; + } + close IBNET_TOPO; +} +main + diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibprintrt.pl b/contrib/ofed/management/infiniband-diags/scripts/ibprintrt.pl new file mode 100755 index 000000000000..48c20f854d27 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibprintrt.pl @@ -0,0 +1,136 @@ +#!/usr/bin/perl +# +# Copyright (c) 2006 The Regents of the University of California. +# Copyright (c) 2007-2008 Voltaire, Inc. All rights reserved. +# +# Produced at Lawrence Livermore National Laboratory. +# Written by Ira Weiny . +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +use strict; + +use Getopt::Std; +use IBswcountlimits; + +# ========================================================================= +# +sub usage_and_exit +{ + my $prog = $_[0]; + print "Usage: $prog [-R -l] [-G | ]\n"; + print " print only the rt specified from the ibnetdiscover output\n"; + print " -R Recalculate ibnetdiscover information\n"; + print " -l list rts\n"; + print " -C use selected channel adaptor name for queries\n"; + print " -P use selected channel adaptor port for queries\n"; + print " -G node is specified with GUID\n"; + exit 2; +} + +my $argv0 = `basename $0`; +my $regenerate_map = undef; +my $list_rts = undef; +my $ca_name = ""; +my $ca_port = ""; +my $name_is_guid = "no"; +chomp $argv0; +if (!getopts("hRlC:P:G")) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_h) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_R) { $regenerate_map = $Getopt::Std::opt_R; } +if (defined $Getopt::Std::opt_l) { $list_rts = $Getopt::Std::opt_l; } +if (defined $Getopt::Std::opt_C) { $ca_name = $Getopt::Std::opt_C; } +if (defined $Getopt::Std::opt_P) { $ca_port = $Getopt::Std::opt_P; } +if (defined $Getopt::Std::opt_G) { $name_is_guid = "yes"; } + +my $target_rt = $ARGV[0]; + +if ($name_is_guid eq "yes") { + $target_rt = format_guid($target_rt); +} + +my $cache_file = get_cache_file($ca_name, $ca_port); + +if ($regenerate_map || !(-f "$cache_file")) { + generate_ibnetdiscover_topology($ca_name, $ca_port); +} + +if ($list_rts) { + system("ibrouters $cache_file"); + exit 1; +} + +if ($target_rt eq "") { + usage_and_exit $argv0; +} + +# ========================================================================= +# +sub main +{ + my $found_rt = 0; + open IBNET_TOPO, "<$cache_file" or die "Failed to open ibnet topology\n"; + my $in_rt = "no"; + my %ports = undef; + while (my $line = ) { + if ($line =~ /^Rt.*\"R-(.*)\"\s+# (.*)/) { + my $guid = $1; + my $desc = $2; + if ($in_rt eq "yes") { + $in_rt = "no"; + foreach my $port (sort { $a <=> $b } (keys %ports)) { + print $ports{$port}; + } + } + if ("0x$guid" eq $target_rt || $desc =~ /[\s\"]$target_rt[\s\"]/) { + print $line; + $in_rt = "yes"; + $found_rt++; + } + } + if ($line =~ /^Switch.*/ || $line =~ /^Ca.*/) { $in_rt = "no"; } + + if ($line =~ /^\[(\d+)\].*/ && $in_rt eq "yes") { + $ports{$1} = $line; + } + + } + if ($found_rt == 0) { + die "\"$target_rt\" not found\n" . + " Try running with the \"-R\" option.\n" . + " If still not found the node is probably down.\n"; + } + if ($found_rt > 1) { + print "\nWARNING: Found $found_rt Router's with the name \"$target_rt\"\n"; + } + close IBNET_TOPO; +} +main + diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibprintswitch.pl b/contrib/ofed/management/infiniband-diags/scripts/ibprintswitch.pl new file mode 100755 index 000000000000..f20bd4bb9eb4 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibprintswitch.pl @@ -0,0 +1,135 @@ +#!/usr/bin/perl +# +# Copyright (c) 2008 Voltaire, Inc. All rights reserved. +# Copyright (c) 2006 The Regents of the University of California. +# +# Produced at Lawrence Livermore National Laboratory. +# Written by Ira Weiny . +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +use strict; + +use Getopt::Std; +use IBswcountlimits; + +# ========================================================================= +# +sub usage_and_exit +{ + my $prog = $_[0]; + print "Usage: $prog [-R -l] [-G | ]\n"; + print " print only the switch specified from the ibnetdiscover output\n"; + print " -R Recalculate ibnetdiscover information\n"; + print " -l list switches\n"; + print " -C use selected channel adaptor name for queries\n"; + print " -P use selected channel adaptor port for queries\n"; + print " -G node is specified with GUID\n"; + exit 2; +} + +my $argv0 = `basename $0`; +my $regenerate_map = undef; +my $list_switches = undef; +my $ca_name = ""; +my $ca_port = ""; +my $name_is_guid = "no"; +chomp $argv0; +if (!getopts("hRlC:P:G")) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_h) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_R) { $regenerate_map = $Getopt::Std::opt_R; } +if (defined $Getopt::Std::opt_l) { $list_switches = $Getopt::Std::opt_l; } +if (defined $Getopt::Std::opt_C) { $ca_name = $Getopt::Std::opt_C; } +if (defined $Getopt::Std::opt_P) { $ca_port = $Getopt::Std::opt_P; } +if (defined $Getopt::Std::opt_G) { $name_is_guid = "yes"; } + +my $target_switch = $ARGV[0]; + +if ($name_is_guid eq "yes") { + $target_switch = format_guid($target_switch); +} + +my $cache_file = get_cache_file($ca_name, $ca_port); + +if ($regenerate_map || !(-f "$cache_file")) { + generate_ibnetdiscover_topology($ca_name, $ca_port); +} + +if ($list_switches) { + system("ibswitches $cache_file"); + exit 1; +} + +if ($target_switch eq "") { + usage_and_exit $argv0; +} + +# ========================================================================= +# +sub main +{ + my $found_switch = 0; + open IBNET_TOPO, "<$cache_file" or die "Failed to open ibnet topology\n"; + my $in_switch = "no"; + my %ports = undef; + while (my $line = ) { + if ($line =~ /^Switch.*\"S-(.*)\"\s+# (.*) port.*/) { + my $guid = $1; + my $desc = $2; + if ($in_switch eq "yes") { + $in_switch = "no"; + foreach my $port (sort { $a <=> $b } (keys %ports)) { + print $ports{$port}; + } + } + if ("0x$guid" eq $target_switch || $desc =~ /[\s\"]$target_switch[\s\"]/) { + print $line; + $in_switch = "yes"; + $found_switch++; + } + } + if ($line =~ /^Ca.*/) { $in_switch = "no"; } + + if ($line =~ /^\[(\d+)\].*/ && $in_switch eq "yes") { + $ports{$1} = $line; + } + + } + if ($found_switch == 0) { + die "Switch \"$target_switch\" not found\n" . + " Try running with the \"-R\" option.\n"; + } + if ($found_switch > 1) { + print "\nWARNING: Found $found_switch switches with the name \"$target_switch\"\n"; + } + close IBNET_TOPO; +} +main + diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibqueryerrors.pl b/contrib/ofed/management/infiniband-diags/scripts/ibqueryerrors.pl new file mode 100755 index 000000000000..99adac753400 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibqueryerrors.pl @@ -0,0 +1,230 @@ +#!/usr/bin/perl +# +# Copyright (c) 2008 Voltaire, Inc. All rights reserved. +# Copyright (c) 2006 The Regents of the University of California. +# +# Produced at Lawrence Livermore National Laboratory. +# Written by Ira Weiny . +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +use strict; + +use Getopt::Std; +use IBswcountlimits; + +my $print_action = "no"; +my $report_port_info = undef; +my $single_switch = undef; +my $include_data_counters = undef; +my $cache_file = ""; +my $switch_found = "no"; + +# ========================================================================= +# +sub report_counts +{ + my $addr = $_[0]; + my $port = $_[1]; + my $ca_name = $_[2]; + my $ca_port = $_[3]; + my $extra_params = get_ca_name_port_param_string($ca_name, $ca_port); + + if (any_counts()) { + print(" GUID $addr port $port:"); + check_counters($print_action); + if ($include_data_counters) { + check_data_counters($print_action); + } + print("\n"); + + if ($report_port_info) { + my $lid = ""; + my $speed = ""; + my $width = ""; + my $data = `smpquery $extra_params -G portinfo $addr $port`; + my @lines = split("\n", $data); + foreach my $line (@lines) { + if ($line =~ /^# Port info: Lid (\w+) port.*/) { $lid = $1; } + if ($line =~ /^LinkSpeedActive:\.+(.*)/) { $speed = $1; } + if ($line =~ /^LinkWidthActive:\.+(.*)/) { $width = $1; } + } + my $hr = $IBswcountlimits::link_ends{"$addr"}{$port}; + if ($hr) { + printf( +" Link info: %6s %4s[%2s] ==(%3s %s)==> %18s %4s[%2s] \"%s\"\n", + $lid, $port, + $hr->{loc_ext_port}, $width, + $speed, $hr->{rem_guid}, + $hr->{rem_port}, $hr->{rem_ext_port}, + $hr->{rem_desc} + ); + } else { + printf( +" Link info: %6s %4s[ ] ==(%3s %s)==> (Disconnected)\n", + $lid, $port, $width, $speed); + } + } + } +} + +# ========================================================================= +# use perfquery to get the counters. +sub get_counts +{ + my $addr = $_[0]; + my $port = $_[1]; + my $ca_name = $_[2]; + my $ca_port = $_[3]; + my $extra_params = get_ca_name_port_param_string($ca_name, $ca_port); + + my $data = `perfquery $extra_params -G $addr $port` || + die "'perfquery $extra_params -G $addr $port' FAILED.\n"; + my @lines = split("\n", $data); + foreach my $line (@lines) { + foreach my $count (@IBswcountlimits::counters) { + if ($line =~ /^$count:\.+(\d+)/) { + $IBswcountlimits::cur_counts{$count} = $1; + } + } + } +} + +# ========================================================================= +# +my %switches = (); + +sub get_switches +{ + my $data = `ibswitches $cache_file` || + die "'ibswitches $cache_file' failed.\n"; + my @lines = split("\n", $data); + foreach my $line (@lines) { + if ($line =~ /^Switch\s+:\s+(\w+)\s+ports\s+(\d+)\s+.*/) { + $switches{$1} = $2; + } + } +} + +# ========================================================================= +# +sub usage_and_exit +{ + my $prog = $_[0]; + print +"Usage: $prog [-a -c -r -R -s -S -D -d -C -P ]\n"; + print " Report counters on all switches in subnet\n"; + print " -a Report an action to take\n"; + print " -c suppress some of the common counters\n"; + print " -r report port configuration information\n"; + print " -R Recalculate ibnetdiscover information\n"; + print " -s suppress errors listed\n"; + print +" -D output only the switch specified by direct route path\n"; + print " -S query only (hex format)\n"; + print " -d include the data counters in the output\n"; + print " -C use selected Channel Adaptor name for queries\n"; + print " -P use selected channel adaptor port for queries\n"; + exit 2; +} + +my $argv0 = `basename $0`; +my $regenerate_map = undef; +my $single_switch = undef; +my $direct_route = undef; +my $ca_name = ""; +my $ca_port = ""; + +chomp $argv0; +if (!getopts("has:crRS:D:dC:P:")) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_h) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_a) { $print_action = "yes"; } +if (defined $Getopt::Std::opt_s) { + @IBswcountlimits::suppress_errors = split(",", $Getopt::Std::opt_s); +} +if (defined $Getopt::Std::opt_c) { + @IBswcountlimits::suppress_errors = split(",", "RcvSwRelayErrors"); +} +if (defined $Getopt::Std::opt_r) { $report_port_info = $Getopt::Std::opt_r; } +if (defined $Getopt::Std::opt_R) { $regenerate_map = $Getopt::Std::opt_R; } +if (defined $Getopt::Std::opt_D) { $direct_route = $Getopt::Std::opt_D; } +if (defined $Getopt::Std::opt_S) { + $single_switch = format_guid($Getopt::Std::opt_S); +} +if (defined $Getopt::Std::opt_d) { + $include_data_counters = $Getopt::Std::opt_d; +} +if (defined $Getopt::Std::opt_C) { $ca_name = $Getopt::Std::opt_C; } +if (defined $Getopt::Std::opt_P) { $ca_port = $Getopt::Std::opt_P; } + +$cache_file = get_cache_file($ca_name, $ca_port); + +sub main +{ + if (@IBswcountlimits::suppress_errors) { + my $msg = join(",", @IBswcountlimits::suppress_errors); + print "Suppressing: $msg\n"; + } + get_link_ends($regenerate_map, $ca_name, $ca_port); + get_switches; + if (defined($direct_route)) { + # convert DR to guid, then use original single_switch option + $single_switch = convert_dr_to_guid($direct_route); + if (!defined($single_switch) || !is_switch($single_switch)) { + printf("The direct route (%s) does not map to a switch.\n", + $direct_route); + return; + } + } + foreach my $sw_addr (keys %switches) { + if ($single_switch && $sw_addr ne "$single_switch") { + next; + } else { + $switch_found = "yes"; + } + + my $switch_prompt = "no"; + foreach my $sw_port (1 .. $switches{$sw_addr}) { + clear_counters; + get_counts($sw_addr, $sw_port, $ca_name, $ca_port); + if (any_counts() && $switch_prompt eq "no") { + my $hr = $IBswcountlimits::link_ends{"$sw_addr"}{$sw_port}; + printf("Errors for %18s \"%s\"\n", $sw_addr, $hr->{loc_desc}); + $switch_prompt = "yes"; + } + report_counts($sw_addr, $sw_port); + } + } + if ($single_switch && $switch_found ne "yes") { + printf("Switch \"%s\" not found.\n", $single_switch); + } +} +main; + diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibrouters.in b/contrib/ofed/management/infiniband-diags/scripts/ibrouters.in new file mode 100644 index 000000000000..6404acaa85eb --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibrouters.in @@ -0,0 +1,60 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [ | -C ca_name" \ + "-P ca_port -t(imeout) timeout_ms]" + exit -1 +} + +topofile="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -h) + usage + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + if [ "$topofile" ]; then + usage + fi + topofile="$1" + ;; + esac + shift +done + +if [ "$topofile" ]; then + netcmd="cat $topofile" +else + netcmd="$IBPATH/ibnetdiscover $ca_info" +fi + +text="`eval $netcmd`" +rv=$? +echo "$text" | awk ' +/^Rt/ {print $1 "\t: 0x" substr($3, 4, 16) " ports " $2 " "\ + substr($0, match($0, "#[ \t]*")+RLENGTH)} +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} +' +exit $rv diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibstatus b/contrib/ofed/management/infiniband-diags/scripts/ibstatus new file mode 100755 index 000000000000..87fbb0c10d9a --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibstatus @@ -0,0 +1,77 @@ +#!/bin/sh + +# Usage ibstatus [devname[:port]] + +infiniband_base="/sys/class/infiniband" +def_ibdev="mthca0" + +usage() { + prog=`basename $0` + echo "Usage: " $prog " [-h] [devname[:portnum]]" + echo " -h: this help screen" + echo " Examples:" + echo " $prog mthca1 # shows status of all ports of 'mthca1'" + echo " $prog mthca0:2 # shows status port number 2 of 'mthca0'" + echo " $prog # default: shows status of all '$def_ibdev' ports" + exit -1 +} + +fatal() { + echo "Fatal error: " $* + exit -1 +} + + +port_status() { + port_dir="$infiniband_base/$1/ports/$2" + echo "Infiniband device '$1' port $2 status:" + echo " default gid: " `[ -r $port_dir/gids/0 ] && cat $port_dir/gids/0 || echo unknown` + echo " base lid: " `[ -r $port_dir/lid ] && cat $port_dir/lid || echo unknown` + echo " sm lid: " `[ -r $port_dir/sm_lid ] && cat $port_dir/sm_lid || echo unknown` + echo " state: " `[ -r $port_dir/state ] && cat $port_dir/state || echo unknown` + echo " phys state: " `[ -r $port_dir/phys_state ] && cat $port_dir/phys_state || echo unknown` + echo " rate: " `[ -r $port_dir/rate ] && cat $port_dir/rate || echo unknown` + echo +} + +ib_status() { + ports_dir="$infiniband_base/$1/ports" + + if ! [ -d "$ports_dir" ]; then + fatal "device '$1': sys files not found ($ports_dir)" + fi + + if [ "$2" = "+" ]; then + ports=`(cd "$infiniband_base/$1/ports" 2>/dev/null || fatal No devices; echo *)` + else + ports=$2 + fi + + for i in $ports; do + port_status $1 $i + done +} + +if [ "$1" = "-h" ]; then + usage +fi + +if [ -z "$1" ]; then + cd $infiniband_base 2>/dev/null || fatal No devices + for dev in *; do + ib_status $dev "+"; + done + exit 0 +fi + +while [ "$1" ]; do + dev=`echo $1 | sed 's/:.*$//'` + port=`echo $1 | sed 's/^.*://'` + + if [ "$port" = "$dev" ]; then + port="+" + fi + + ib_status $dev $port + shift +done diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibswitches.in b/contrib/ofed/management/infiniband-diags/scripts/ibswitches.in new file mode 100644 index 000000000000..163620a0d096 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibswitches.in @@ -0,0 +1,79 @@ +#!/bin/sh + +IBPATH=${IBPATH:-@IBSCRIPTPATH@} + +function usage() { + echo Usage: `basename $0` "[-h] [ | -C ca_name" \ + "-P ca_port -t(imeout) timeout_ms]" + exit -1 +} + +topofile="" +ca_info="" + +while [ "$1" ]; do + case $1 in + -h) + usage + ;; + -P | -C | -t | -timeout) + case $2 in + -*) + usage + ;; + esac + if [ x$2 = x ] ; then + usage + fi + ca_info="$ca_info $1 $2" + shift + ;; + -*) + usage + ;; + *) + if [ "$topofile" ]; then + usage + fi + topofile="$1" + ;; + esac + shift +done + +if [ "$topofile" ]; then + netcmd="cat $topofile" +else + netcmd="$IBPATH/ibnetdiscover $ca_info" +fi + +text="`eval $netcmd`" +rv=$? +echo "$text" | awk ' +/^Switch/ { + l=$0 + desc=substr(l, match(l, "#[ \t]*")+RLENGTH) + pi=match(desc, "port 0.*") + pinfo=substr(desc, pi) + desc=substr(desc, 1, pi-2) + type="base" + ti=match(desc, type) + if (ti==0) { + type="enhanced" + ti=match(desc, type) + if (ti!=0) + desc=substr(desc, 1, ti-2) + } else + desc=substr(desc, 1, ti-2) + if (ti==0) + print $1 "\t: 0x" substr($3, 4, 16) " ports " $2 " "\ + desc " " pinfo + else + print $1 "\t: 0x" substr($3, 4, 16) " ports " $2 " "\ + desc " " type " " pinfo} +/^ib/ {print $0; next} +/ibpanic:/ {print $0} +/ibwarn:/ {print $0} +/iberror:/ {print $0} +' +exit $rv diff --git a/contrib/ofed/management/infiniband-diags/scripts/ibswportwatch.pl b/contrib/ofed/management/infiniband-diags/scripts/ibswportwatch.pl new file mode 100755 index 000000000000..a2880aac2bb6 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/ibswportwatch.pl @@ -0,0 +1,174 @@ +#!/usr/bin/perl +# +# Copyright (c) 2008 Voltaire, Inc. All rights reserved. +# Copyright (c) 2006 The Regents of the University of California. +# +# Produced at Lawrence Livermore National Laboratory. +# Written by Ira Weiny . +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +use strict; + +use Getopt::Std; +use IBswcountlimits; + +my $sw_addr = ""; +my $sw_port = ""; +my $verbose = undef; + +# ========================================================================= +# +sub print_verbose +{ + if ($verbose) { + print $_[0]; + } +} + +# ========================================================================= +# +sub print_all_counts +{ + if (!$verbose) { return; } + + print " Counter\t\t\tNew ==> Old\n"; + foreach my $cnt (@IBswcountlimits::counters) { + print +" $cnt\t\t\t$IBswcountlimits::new_counts{$cnt} ==> $IBswcountlimits::cur_counts{$cnt}\n"; + } +} + +# ========================================================================= +# +sub usage_and_exit +{ + my $prog = $_[0]; + print + "Usage: $prog [-p -b -v -n -G] \n"; + print " Attempt to diagnose a problem on a port\n"; + print +" Run this on a link while a job is running which utilizes that link.\n"; + print +" -p define the ammount of time between counter polls (default $IBswcountlimits::pause_time)\n"; + print " -v Be verbose\n"; + print " -n run n cycles then exit (default -1 == forever)\n"; + print " -G Address provided is a GUID\n"; + print " -b report bytes/second packets/second\n"; + exit 2; +} + +# ========================================================================= +# +sub clear_counters +{ + # clear the counters + foreach my $count (@IBswcountlimits::counters) { + $IBswcountlimits::cur_counts{$count} = 0; + $IBswcountlimits::new_counts{$count} = 0; + } +} + +# ========================================================================= +# +sub mv_counts +{ + foreach my $count (@IBswcountlimits::counters) { + $IBswcountlimits::cur_counts{$count} = + $IBswcountlimits::new_counts{$count}; + } +} + +# ========================================================================= +# use perfquery to get the counters. +my $GUID = ""; + +sub get_new_counts +{ + my $addr = $_[0]; + my $port = $_[1]; + mv_counts; + ensure_cache_dir; + if ( + system( +"perfquery $GUID $addr $port > $IBswcountlimits::cache_dir/perfquery.out" + ) + ) + { + die "perfquery failed : \"perfquery $GUID $addr $port\"\n"; + } + open PERF_QUERY, "<$IBswcountlimits::cache_dir/perfquery.out" + or die "cannot read '$IBswcountlimits::cache_dir/perfquery.out': $!\n"; + while (my $line = ) { + foreach my $count (@IBswcountlimits::counters) { + if ($line =~ /^$count:\.+(\d+)/) { + $IBswcountlimits::new_counts{$count} = $1; + } + } + } + close PERF_QUERY; +} + +my $cycle = -1; # forever + +my $bytes_per_second = undef; +my $argv0 = `basename $0`; +chomp $argv0; +if (!getopts("hbvp:n:G")) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_h) { usage_and_exit $argv0; } +if (defined $Getopt::Std::opt_p) { + $IBswcountlimits::pause_time = $Getopt::Std::opt_p; +} +if (defined $Getopt::Std::opt_v) { $verbose = $Getopt::Std::opt_v; } +if (defined $Getopt::Std::opt_n) { $cycle = $Getopt::Std::opt_n; } +if (defined $Getopt::Std::opt_G) { $GUID = "-G"; } +if (defined $Getopt::Std::opt_b) { $bytes_per_second = $Getopt::Std::opt_b; } + +my $sw_addr = $ARGV[0]; +my $sw_port = $ARGV[1]; + +sub main +{ + clear_counters; + get_new_counts($sw_addr, $sw_port); + while ($cycle != 0) { + print "Checking counts...\n"; + sleep($IBswcountlimits::pause_time); + get_new_counts($sw_addr, $sw_port); + check_counter_rates; + if ($bytes_per_second) { + print_data_rates; + } + print_all_counts; + if ($cycle != -1) { $cycle = $cycle - 1; } + } +} +main; + diff --git a/contrib/ofed/management/infiniband-diags/scripts/set_nodedesc.sh b/contrib/ofed/management/infiniband-diags/scripts/set_nodedesc.sh new file mode 100755 index 000000000000..855ced70a5d3 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/scripts/set_nodedesc.sh @@ -0,0 +1,57 @@ +#!/bin/sh + +if [ -f /etc/sysconfig/network ]; then +. /etc/sysconfig/network +fi + +ib_sysfs="/sys/class/infiniband" +newname="$HOSTNAME" + + +function usage +{ + echo "Usage: `basename $0` [-hv] []" + echo " set the node_desc field of all hca's found in \"$ib_sysfs\"" + echo " -h this help" + echo " -v view all node descriptors" + echo " [] set name to name specified." + echo " Default is to use the hostname: \"$HOSTNAME\"" + exit 2 +} + +function viewall +{ + for hca in `ls $ib_sysfs`; do + if [ -f $ib_sysfs/$hca/node_desc ]; then + echo -n "$hca: " + cat $ib_sysfs/$hca/node_desc + else + logger -s "Failed to set node_desc for : $hca" + fi + done + exit 0 +} + +while getopts "hv" flag +do + case $flag in + "h") usage;; + "v") viewall;; + esac +done + +shift $(($OPTIND - 1)) + +if [ "$1" != "" ]; then + newname="$1" +fi + +for hca in `ls $ib_sysfs`; do + if [ -f $ib_sysfs/$hca/node_desc ]; then + echo -n "$newname" >> $ib_sysfs/$hca/node_desc + else + logger -s "Failed to set node_desc for : $hca" + fi +done + +exit 0 diff --git a/contrib/ofed/management/infiniband-diags/src/grouping.c b/contrib/ofed/management/infiniband-diags/src/grouping.c new file mode 100644 index 000000000000..f1a996fe68ed --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/grouping.c @@ -0,0 +1,787 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/*========================================================*/ +/* FABRIC SCANNER SPECIFIC DATA */ +/*========================================================*/ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include + +#include "ibnetdiscover.h" +#include "grouping.h" + +#define OUT_BUFFER_SIZE 16 + + +extern Node *nodesdist[MAXHOPS+1]; /* last is CA list */ +extern Node *mynode; +extern Port *myport; +extern int maxhops_discovered; + +AllChassisList mylist; + +char *ChassisTypeStr[5] = { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004" }; +char *ChassisSlotStr[4] = { "", "Line", "Spine", "SRBD" }; + + +char *get_chassis_type(unsigned char chassistype) +{ + if (chassistype == UNRESOLVED_CT || chassistype > ISR2004_CT) + return NULL; + return ChassisTypeStr[chassistype]; +} + +char *get_chassis_slot(unsigned char chassisslot) +{ + if (chassisslot == UNRESOLVED_CS || chassisslot > SRBD_CS) + return NULL; + return ChassisSlotStr[chassisslot]; +} + +static struct ChassisList *find_chassisnum(unsigned char chassisnum) +{ + ChassisList *current; + + for (current = mylist.first; current; current = current->next) { + if (current->chassisnum == chassisnum) + return current; + } + + return NULL; +} + +static uint64_t topspin_chassisguid(uint64_t guid) +{ + /* Byte 3 in system image GUID is chassis type, and */ + /* Byte 4 is location ID (slot) so just mask off byte 4 */ + return guid & 0xffffffff00ffffffULL; +} + +int is_xsigo_guid(uint64_t guid) +{ + if ((guid & 0xffffff0000000000ULL) == 0x0013970000000000ULL) + return 1; + else + return 0; +} + +static int is_xsigo_leafone(uint64_t guid) +{ + if ((guid & 0xffffffffff000000ULL) == 0x0013970102000000ULL) + return 1; + else + return 0; +} + +int is_xsigo_hca(uint64_t guid) +{ + /* NodeType 2 is HCA */ + if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL) + return 1; + else + return 0; +} + +int is_xsigo_tca(uint64_t guid) +{ + /* NodeType 3 is TCA */ + if ((guid & 0xffffffff00000000ULL) == 0x0013970300000000ULL) + return 1; + else + return 0; +} + +static int is_xsigo_ca(uint64_t guid) +{ + if (is_xsigo_hca(guid) || is_xsigo_tca(guid)) + return 1; + else + return 0; +} + +static int is_xsigo_switch(uint64_t guid) +{ + if ((guid & 0xffffffff00000000ULL) == 0x0013970100000000ULL) + return 1; + else + return 0; +} + +static uint64_t xsigo_chassisguid(Node *node) +{ + if (!is_xsigo_ca(node->sysimgguid)) { + /* Byte 3 is NodeType and byte 4 is PortType */ + /* If NodeType is 1 (switch), PortType is masked */ + if (is_xsigo_switch(node->sysimgguid)) + return node->sysimgguid & 0xffffffff00ffffffULL; + else + return node->sysimgguid; + } else { + /* Is there a peer port ? */ + if (!node->ports->remoteport) + return node->sysimgguid; + + /* If peer port is Leaf 1, use its chassis GUID */ + if (is_xsigo_leafone(node->ports->remoteport->node->sysimgguid)) + return node->ports->remoteport->node->sysimgguid & + 0xffffffff00ffffffULL; + else + return node->sysimgguid; + } +} + +static uint64_t get_chassisguid(Node *node) +{ + if (node->vendid == TS_VENDOR_ID || node->vendid == SS_VENDOR_ID) + return topspin_chassisguid(node->sysimgguid); + else if (node->vendid == XS_VENDOR_ID || is_xsigo_guid(node->sysimgguid)) + return xsigo_chassisguid(node); + else + return node->sysimgguid; +} + +static struct ChassisList *find_chassisguid(Node *node) +{ + ChassisList *current; + uint64_t chguid; + + chguid = get_chassisguid(node); + for (current = mylist.first; current; current = current->next) { + if (current->chassisguid == chguid) + return current; + } + + return NULL; +} + +uint64_t get_chassis_guid(unsigned char chassisnum) +{ + ChassisList *chassis; + + chassis = find_chassisnum(chassisnum); + if (chassis) + return chassis->chassisguid; + else + return 0; +} + +static int is_router(Node *node) +{ + return (node->devid == VTR_DEVID_IB_FC_ROUTER || + node->devid == VTR_DEVID_IB_IP_ROUTER); +} + +static int is_spine_9096(Node *node) +{ + return (node->devid == VTR_DEVID_SFB4 || + node->devid == VTR_DEVID_SFB4_DDR); +} + +static int is_spine_9288(Node *node) +{ + return (node->devid == VTR_DEVID_SFB12 || + node->devid == VTR_DEVID_SFB12_DDR); +} + +static int is_spine_2004(Node *node) +{ + return (node->devid == VTR_DEVID_SFB2004); +} + +static int is_spine_2012(Node *node) +{ + return (node->devid == VTR_DEVID_SFB2012); +} + +static int is_spine(Node *node) +{ + return (is_spine_9096(node) || is_spine_9288(node) || + is_spine_2004(node) || is_spine_2012(node)); +} + +static int is_line_24(Node *node) +{ + return (node->devid == VTR_DEVID_SLB24 || + node->devid == VTR_DEVID_SLB24_DDR || + node->devid == VTR_DEVID_SRB2004); +} + +static int is_line_8(Node *node) +{ + return (node->devid == VTR_DEVID_SLB8); +} + +static int is_line_2024(Node *node) +{ + return (node->devid == VTR_DEVID_SLB2024); +} + +static int is_line(Node *node) +{ + return (is_line_24(node) || is_line_8(node) || is_line_2024(node)); +} + +int is_chassis_switch(Node *node) +{ + return (is_spine(node) || is_line(node)); +} + +/* these structs help find Line (Anafa) slot number while using spine portnum */ +int line_slot_2_sfb4[25] = { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4 }; +int anafa_line_slot_2_sfb4[25] = { 0, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2 }; +int line_slot_2_sfb12[25] = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10, 10, 11, 11, 12, 12 }; +int anafa_line_slot_2_sfb12[25] = { 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 }; + +/* IPR FCR modules connectivity while using sFB4 port as reference */ +int ipr_slot_2_sfb4_port[25] = { 0, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1 }; + +/* these structs help find Spine (Anafa) slot number while using spine portnum */ +int spine12_slot_2_slb[25] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +int anafa_spine12_slot_2_slb[25]= { 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +int spine4_slot_2_slb[25] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +int anafa_spine4_slot_2_slb[25] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +/* reference { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; */ + +static void get_sfb_slot(Node *node, Port *lineport) +{ + ChassisRecord *ch = node->chrecord; + + ch->chassisslot = SPINE_CS; + if (is_spine_9096(node)) { + ch->chassistype = ISR9096_CT; + ch->slotnum = spine4_slot_2_slb[lineport->portnum]; + ch->anafanum = anafa_spine4_slot_2_slb[lineport->portnum]; + } else if (is_spine_9288(node)) { + ch->chassistype = ISR9288_CT; + ch->slotnum = spine12_slot_2_slb[lineport->portnum]; + ch->anafanum = anafa_spine12_slot_2_slb[lineport->portnum]; + } else if (is_spine_2012(node)) { + ch->chassistype = ISR2012_CT; + ch->slotnum = spine12_slot_2_slb[lineport->portnum]; + ch->anafanum = anafa_spine12_slot_2_slb[lineport->portnum]; + } else if (is_spine_2004(node)) { + ch->chassistype = ISR2004_CT; + ch->slotnum = spine4_slot_2_slb[lineport->portnum]; + ch->anafanum = anafa_spine4_slot_2_slb[lineport->portnum]; + } else { + IBPANIC("Unexpected node found: guid 0x%016" PRIx64, node->nodeguid); + } +} + +static void get_router_slot(Node *node, Port *spineport) +{ + ChassisRecord *ch = node->chrecord; + int guessnum = 0; + + if (!ch) { + if (!(node->chrecord = calloc(1, sizeof(ChassisRecord)))) + IBPANIC("out of mem"); + ch = node->chrecord; + } + + ch->chassisslot = SRBD_CS; + if (is_spine_9096(spineport->node)) { + ch->chassistype = ISR9096_CT; + ch->slotnum = line_slot_2_sfb4[spineport->portnum]; + ch->anafanum = ipr_slot_2_sfb4_port[spineport->portnum]; + } else if (is_spine_9288(spineport->node)) { + ch->chassistype = ISR9288_CT; + ch->slotnum = line_slot_2_sfb12[spineport->portnum]; + /* this is a smart guess based on nodeguids order on sFB-12 module */ + guessnum = spineport->node->nodeguid % 4; + /* module 1 <--> remote anafa 3 */ + /* module 2 <--> remote anafa 2 */ + /* module 3 <--> remote anafa 1 */ + ch->anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2)); + } else if (is_spine_2012(spineport->node)) { + ch->chassistype = ISR2012_CT; + ch->slotnum = line_slot_2_sfb12[spineport->portnum]; + /* this is a smart guess based on nodeguids order on sFB-12 module */ + guessnum = spineport->node->nodeguid % 4; + // module 1 <--> remote anafa 3 + // module 2 <--> remote anafa 2 + // module 3 <--> remote anafa 1 + ch->anafanum = (guessnum == 3? 1 : (guessnum == 1 ? 3 : 2)); + } else if (is_spine_2004(spineport->node)) { + ch->chassistype = ISR2004_CT; + ch->slotnum = line_slot_2_sfb4[spineport->portnum]; + ch->anafanum = ipr_slot_2_sfb4_port[spineport->portnum]; + } else { + IBPANIC("Unexpected node found: guid 0x%016" PRIx64, spineport->node->nodeguid); + } +} + +static void get_slb_slot(ChassisRecord *ch, Port *spineport) +{ + ch->chassisslot = LINE_CS; + if (is_spine_9096(spineport->node)) { + ch->chassistype = ISR9096_CT; + ch->slotnum = line_slot_2_sfb4[spineport->portnum]; + ch->anafanum = anafa_line_slot_2_sfb4[spineport->portnum]; + } else if (is_spine_9288(spineport->node)) { + ch->chassistype = ISR9288_CT; + ch->slotnum = line_slot_2_sfb12[spineport->portnum]; + ch->anafanum = anafa_line_slot_2_sfb12[spineport->portnum]; + } else if (is_spine_2012(spineport->node)) { + ch->chassistype = ISR2012_CT; + ch->slotnum = line_slot_2_sfb12[spineport->portnum]; + ch->anafanum = anafa_line_slot_2_sfb12[spineport->portnum]; + } else if (is_spine_2004(spineport->node)) { + ch->chassistype = ISR2004_CT; + ch->slotnum = line_slot_2_sfb4[spineport->portnum]; + ch->anafanum = anafa_line_slot_2_sfb4[spineport->portnum]; + } else { + IBPANIC("Unexpected node found: guid 0x%016" PRIx64, spineport->node->nodeguid); + } +} + +/* + This function called for every Voltaire node in fabric + It could be optimized so, but time overhead is very small + and its only diag.util +*/ +static void fill_chassis_record(Node *node) +{ + Port *port; + Node *remnode = 0; + ChassisRecord *ch = 0; + + if (node->chrecord) /* somehow this node has already been passed */ + return; + + if (!(node->chrecord = calloc(1, sizeof(ChassisRecord)))) + IBPANIC("out of mem"); + + ch = node->chrecord; + + /* node is router only in case of using unique lid */ + /* (which is lid of chassis router port) */ + /* in such case node->ports is actually a requested port... */ + if (is_router(node) && is_spine(node->ports->remoteport->node)) + get_router_slot(node, node->ports->remoteport); + else if (is_spine(node)) { + for (port = node->ports; port; port = port->next) { + if (!port->remoteport) + continue; + remnode = port->remoteport->node; + if (remnode->type != SWITCH_NODE) { + if (!remnode->chrecord) + get_router_slot(remnode, port); + continue; + } + if (!ch->chassistype) + /* we assume here that remoteport belongs to line */ + get_sfb_slot(node, port->remoteport); + + /* we could break here, but need to find if more routers connected */ + } + + } else if (is_line(node)) { + for (port = node->ports; port; port = port->next) { + if (port->portnum > 12) + continue; + if (!port->remoteport) + continue; + /* we assume here that remoteport belongs to spine */ + get_slb_slot(ch, port->remoteport); + break; + } + } + + return; +} + +static int get_line_index(Node *node) +{ + int retval = 3 * (node->chrecord->slotnum - 1) + node->chrecord->anafanum; + + if (retval > LINES_MAX_NUM || retval < 1) + IBPANIC("Internal error"); + return retval; +} + +static int get_spine_index(Node *node) +{ + int retval; + + if (is_spine_9288(node) || is_spine_2012(node)) + retval = 3 * (node->chrecord->slotnum - 1) + node->chrecord->anafanum; + else + retval = node->chrecord->slotnum; + + if (retval > SPINES_MAX_NUM || retval < 1) + IBPANIC("Internal error"); + return retval; +} + +static void insert_line_router(Node *node, ChassisList *chassislist) +{ + int i = get_line_index(node); + + if (chassislist->linenode[i]) + return; /* already filled slot */ + + chassislist->linenode[i] = node; + node->chrecord->chassisnum = chassislist->chassisnum; +} + +static void insert_spine(Node *node, ChassisList *chassislist) +{ + int i = get_spine_index(node); + + if (chassislist->spinenode[i]) + return; /* already filled slot */ + + chassislist->spinenode[i] = node; + node->chrecord->chassisnum = chassislist->chassisnum; +} + +static void pass_on_lines_catch_spines(ChassisList *chassislist) +{ + Node *node, *remnode; + Port *port; + int i; + + for (i = 1; i <= LINES_MAX_NUM; i++) { + node = chassislist->linenode[i]; + + if (!(node && is_line(node))) + continue; /* empty slot or router */ + + for (port = node->ports; port; port = port->next) { + if (port->portnum > 12) + continue; + + if (!port->remoteport) + continue; + remnode = port->remoteport->node; + + if (!remnode->chrecord) + continue; /* some error - spine not initialized ? FIXME */ + insert_spine(remnode, chassislist); + } + } +} + +static void pass_on_spines_catch_lines(ChassisList *chassislist) +{ + Node *node, *remnode; + Port *port; + int i; + + for (i = 1; i <= SPINES_MAX_NUM; i++) { + node = chassislist->spinenode[i]; + if (!node) + continue; /* empty slot */ + for (port = node->ports; port; port = port->next) { + if (!port->remoteport) + continue; + remnode = port->remoteport->node; + + if (!remnode->chrecord) + continue; /* some error - line/router not initialized ? FIXME */ + insert_line_router(remnode, chassislist); + } + } +} + +/* + Stupid interpolation algorithm... + But nothing to do - have to be compliant with VoltaireSM/NMS +*/ +static void pass_on_spines_interpolate_chguid(ChassisList *chassislist) +{ + Node *node; + int i; + + for (i = 1; i <= SPINES_MAX_NUM; i++) { + node = chassislist->spinenode[i]; + if (!node) + continue; /* skip the empty slots */ + + /* take first guid minus one to be consistent with SM */ + chassislist->chassisguid = node->nodeguid - 1; + break; + } +} + +/* + This function fills chassislist structure with all nodes + in that chassis + chassislist structure = structure of one standalone chassis +*/ +static void build_chassis(Node *node, ChassisList *chassislist) +{ + Node *remnode = 0; + Port *port = 0; + + /* we get here with node = chassis_spine */ + chassislist->chassistype = node->chrecord->chassistype; + insert_spine(node, chassislist); + + /* loop: pass on all ports of node */ + for (port = node->ports; port; port = port->next) { + if (!port->remoteport) + continue; + remnode = port->remoteport->node; + + if (!remnode->chrecord) + continue; /* some error - line or router not initialized ? FIXME */ + + insert_line_router(remnode, chassislist); + } + + pass_on_lines_catch_spines(chassislist); + /* this pass needed for to catch routers, since routers connected only */ + /* to spines in slot 1 or 4 and we could miss them first time */ + pass_on_spines_catch_lines(chassislist); + + /* additional 2 passes needed for to overcome a problem of pure "in-chassis" */ + /* connectivity - extra pass to ensure that all related chips/modules */ + /* inserted into the chassislist */ + pass_on_lines_catch_spines(chassislist); + pass_on_spines_catch_lines(chassislist); + pass_on_spines_interpolate_chguid(chassislist); +} + +/*========================================================*/ +/* INTERNAL TO EXTERNAL PORT MAPPING */ +/*========================================================*/ + +/* +Description : On ISR9288/9096 external ports indexing + is not matching the internal ( anafa ) port + indexes. Use this MAP to translate the data you get from + the OpenIB diagnostics (smpquery, ibroute, ibtracert, etc.) + + +Module : sLB-24 + anafa 1 anafa 2 +ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24 +int port | 22 23 24 18 17 16 | 22 23 24 18 17 16 +ext port | 1 2 3 4 5 6 | 7 8 9 10 11 12 +int port | 19 20 21 15 14 13 | 19 20 21 15 14 13 +------------------------------------------------ + +Module : sLB-8 + anafa 1 anafa 2 +ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24 +int port | 24 23 22 18 17 16 | 24 23 22 18 17 16 +ext port | 1 2 3 4 5 6 | 7 8 9 10 11 12 +int port | 21 20 19 15 14 13 | 21 20 19 15 14 13 + +-----------> + anafa 1 anafa 2 +ext port | - - 5 - - 6 | - - 7 - - 8 +int port | 24 23 22 18 17 16 | 24 23 22 18 17 16 +ext port | - - 1 - - 2 | - - 3 - - 4 +int port | 21 20 19 15 14 13 | 21 20 19 15 14 13 +------------------------------------------------ + +Module : sLB-2024 + +ext port | 13 14 15 16 17 18 19 20 21 22 23 24 +A1 int port| 13 14 15 16 17 18 19 20 21 22 23 24 +ext port | 1 2 3 4 5 6 7 8 9 10 11 12 +A2 int port| 13 14 15 16 17 18 19 20 21 22 23 24 +--------------------------------------------------- + +*/ + +int int2ext_map_slb24[2][25] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, 4, 18, 17, 16, 1, 2, 3, 13, 14, 15 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 11, 10, 24, 23, 22, 7, 8, 9, 19, 20, 21 } + }; +int int2ext_map_slb8[2][25] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 6, 6, 6, 1, 1, 1, 5, 5, 5 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 8, 8, 8, 3, 3, 3, 7, 7, 7 } + }; +int int2ext_map_slb2024[2][25] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 } + }; +/* reference { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; */ + +/* + This function relevant only for line modules/chips + Returns string with external port index +*/ +char *portmapstring(Port *port) +{ + static char mapping[OUT_BUFFER_SIZE]; + ChassisRecord *ch = port->node->chrecord; + int portnum = port->portnum; + int chipnum = 0; + int pindex = 0; + Node *node = port->node; + + if (!ch || !is_line(node) || (portnum < 13 || portnum > 24)) + return NULL; + + if (ch->anafanum < 1 || ch->anafanum > 2) + return NULL; + + memset(mapping, 0, sizeof(mapping)); + + chipnum = ch->anafanum - 1; + + if (is_line_24(node)) + pindex = int2ext_map_slb24[chipnum][portnum]; + else if (is_line_2024(node)) + pindex = int2ext_map_slb2024[chipnum][portnum]; + else + pindex = int2ext_map_slb8[chipnum][portnum]; + + sprintf(mapping, "[ext %d]", pindex); + + return mapping; +} + +static void add_chassislist() +{ + if (!(mylist.current = calloc(1, sizeof(ChassisList)))) + IBPANIC("out of mem"); + + if (mylist.first == NULL) { + mylist.first = mylist.current; + mylist.last = mylist.current; + } else { + mylist.last->next = mylist.current; + mylist.current->next = NULL; + mylist.last = mylist.current; + } +} + +/* + Main grouping function + Algorithm: + 1. pass on every Voltaire node + 2. catch spine chip for every Voltaire node + 2.1 build/interpolate chassis around this chip + 2.2 go to 1. + 3. pass on non Voltaire nodes (SystemImageGUID based grouping) + 4. now group non Voltaire nodes by SystemImageGUID +*/ +ChassisList *group_nodes() +{ + Node *node; + int dist; + int chassisnum = 0; + struct ChassisList *chassis; + + mylist.first = NULL; + mylist.current = NULL; + mylist.last = NULL; + + /* first pass on switches and build for every Voltaire node */ + /* an appropriate chassis record (slotnum and position) */ + /* according to internal connectivity */ + /* not very efficient but clear code so... */ + for (dist = 0; dist <= maxhops_discovered; dist++) { + for (node = nodesdist[dist]; node; node = node->dnext) { + if (node->vendid == VTR_VENDOR_ID) + fill_chassis_record(node); + } + } + + /* separate every Voltaire chassis from each other and build linked list of them */ + /* algorithm: catch spine and find all surrounding nodes */ + for (dist = 0; dist <= maxhops_discovered; dist++) { + for (node = nodesdist[dist]; node; node = node->dnext) { + if (node->vendid != VTR_VENDOR_ID) + continue; + if (!node->chrecord || node->chrecord->chassisnum || !is_spine(node)) + continue; + add_chassislist(); + mylist.current->chassisnum = ++chassisnum; + build_chassis(node, mylist.current); + } + } + + /* now make pass on nodes for chassis which are not Voltaire */ + /* grouped by common SystemImageGUID */ + for (dist = 0; dist <= maxhops_discovered; dist++) { + for (node = nodesdist[dist]; node; node = node->dnext) { + if (node->vendid == VTR_VENDOR_ID) + continue; + if (node->sysimgguid) { + chassis = find_chassisguid(node); + if (chassis) + chassis->nodecount++; + else { + /* Possible new chassis */ + add_chassislist(); + mylist.current->chassisguid = get_chassisguid(node); + mylist.current->nodecount = 1; + } + } + } + } + + /* now, make another pass to see which nodes are part of chassis */ + /* (defined as chassis->nodecount > 1) */ + for (dist = 0; dist <= MAXHOPS; ) { + for (node = nodesdist[dist]; node; node = node->dnext) { + if (node->vendid == VTR_VENDOR_ID) + continue; + if (node->sysimgguid) { + chassis = find_chassisguid(node); + if (chassis && chassis->nodecount > 1) { + if (!chassis->chassisnum) + chassis->chassisnum = ++chassisnum; + if (!node->chrecord) { + if (!(node->chrecord = calloc(1, sizeof(ChassisRecord)))) + IBPANIC("out of mem"); + node->chrecord->chassisnum = chassis->chassisnum; + } + } + } + } + if (dist == maxhops_discovered) + dist = MAXHOPS; /* skip to CAs */ + else + dist++; + } + + return (mylist.first); +} diff --git a/contrib/ofed/management/infiniband-diags/src/ibaddr.c b/contrib/ofed/management/infiniband-diags/src/ibaddr.c new file mode 100644 index 000000000000..0e2f9ac2d29b --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/ibaddr.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "ibdiag_common.h" + +char *argv0 = "ibaddr"; + +static int +ib_resolve_addr(ib_portid_t *portid, int portnum, int show_lid, int show_gid) +{ + char gid_str[INET6_ADDRSTRLEN]; + uint8_t portinfo[64]; + uint8_t nodeinfo[64]; + uint64_t guid, prefix; + ibmad_gid_t gid; + int lmc; + + if (!smp_query(nodeinfo, portid, IB_ATTR_NODE_INFO, 0, 0)) + return -1; + + if (!smp_query(portinfo, portid, IB_ATTR_PORT_INFO, portnum, 0)) + return -1; + + mad_decode_field(portinfo, IB_PORT_LID_F, &portid->lid); + mad_decode_field(portinfo, IB_PORT_GID_PREFIX_F, &prefix); + mad_decode_field(portinfo, IB_PORT_LMC_F, &lmc); + mad_decode_field(nodeinfo, IB_NODE_PORT_GUID_F, &guid); + + mad_encode_field(gid, IB_GID_PREFIX_F, &prefix); + mad_encode_field(gid, IB_GID_GUID_F, &guid); + + if (show_gid) { + printf("GID %s ", inet_ntop(AF_INET6, gid, gid_str, + sizeof gid_str)); + } + + if (show_lid > 0) + printf("LID start 0x%x end 0x%x", portid->lid, portid->lid + (1 << lmc) - 1); + else if (show_lid < 0) + printf("LID start %d end %d", portid->lid, portid->lid + (1 << lmc) - 1); + printf("\n"); + return 0; +} + +static void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -D(irect) -G(uid) -l(id_show) -g(id_show) -s(m_port) sm_lid -C ca_name -P ca_port " + "-t(imeout) timeout_ms -V(ersion) -h(elp)] []\n", + basename); + fprintf(stderr, "\tExamples:\n"); + fprintf(stderr, "\t\t%s\t\t\t# local port's address\n", basename); + fprintf(stderr, "\t\t%s 32\t\t# show lid range and gid of lid 32\n", basename); + fprintf(stderr, "\t\t%s -G 0x8f1040023\t# same but using guid address\n", basename); + fprintf(stderr, "\t\t%s -l 32\t\t# show lid range only\n", basename); + fprintf(stderr, "\t\t%s -L 32\t\t# show decimal lid range only\n", basename); + fprintf(stderr, "\t\t%s -g 32\t\t# show gid address only\n", basename); + exit(-1); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + ib_portid_t portid = {0}; + extern int ibdebug; + int dest_type = IB_DEST_LID; + int timeout = 0; /* use default */ + int show_lid = 0, show_gid = 0; + int port = 0; + char *ca = 0; + int ca_port = 0; + + static char const str_opts[] = "C:P:t:s:dDGglLVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "Direct", 0, 0, 'D'}, + { "Guid", 0, 0, 'G'}, + { "gid_show", 0, 0, 'g'}, + { "lid_show", 0, 0, 'l'}, + { "Lid_show", 0, 0, 'L'}, + { "timeout", 1, 0, 't'}, + { "sm_port", 1, 0, 's'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'd': + ibdebug++; + break; + case 'D': + dest_type = IB_DEST_DRPATH; + break; + case 'g': + show_gid++; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 'l': + show_lid++; + break; + case 'L': + show_lid = -100; + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc > 1) + port = strtoul(argv[1], 0, 0); + + if (!show_lid && !show_gid) + show_lid = show_gid = 1; + + madrpc_init(ca, ca_port, mgmt_classes, 3); + + if (argc) { + if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + } else { + if (ib_resolve_self(&portid, &port, 0) < 0) + IBERROR("can't resolve self port %s", argv[0]); + } + + if (ib_resolve_addr(&portid, port, show_lid, show_gid) < 0) + IBERROR("can't resolve requested address"); + exit(0); +} diff --git a/contrib/ofed/management/infiniband-diags/src/ibdiag_common.c b/contrib/ofed/management/infiniband-diags/src/ibdiag_common.c new file mode 100644 index 000000000000..90e2cec3b212 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/ibdiag_common.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2006-2007 The Regents of the University of California. + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/** + * Define common functions which can be included in the various C based diags. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ibdiag_common.h" + +int ibdebug; + +void +iberror(const char *fn, char *msg, ...) +{ + char buf[512], *s; + va_list va; + int n; + + va_start(va, msg); + n = vsprintf(buf, msg, va); + va_end(va); + buf[n] = 0; + + if ((s = strrchr(argv0, '/'))) + argv0 = s + 1; + + if (ibdebug) + printf("%s: iberror: [pid %d] %s: failed: %s\n", argv0, getpid(), fn, buf); + else + printf("%s: iberror: failed: %s\n", argv0, buf); + + exit(-1); +} + diff --git a/contrib/ofed/management/infiniband-diags/src/ibnetdiscover.c b/contrib/ofed/management/infiniband-diags/src/ibnetdiscover.c new file mode 100644 index 000000000000..2cfaa8ae55ef --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/ibnetdiscover.c @@ -0,0 +1,1051 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ibnetdiscover.h" +#include "grouping.h" +#include "ibdiag_common.h" + +static char *node_type_str[] = { + "???", + "ca", + "switch", + "router", + "iwarp rnic" +}; + +static char *linkwidth_str[] = { + "??", + "1x", + "4x", + "??", + "8x", + "??", + "??", + "??", + "12x" +}; + +static char *linkspeed_str[] = { + "???", + "SDR", + "DDR", + "???", + "QDR" +}; + +static int timeout = 2000; /* ms */ +static int dumplevel = 0; +static int verbose; +static FILE *f; + +char *argv0 = "ibnetdiscover"; + +static char *node_name_map_file = NULL; +static nn_map_t *node_name_map = NULL; + +Node *nodesdist[MAXHOPS+1]; /* last is Ca list */ +Node *mynode; +int maxhops_discovered = 0; + +struct ChassisList *chassis = NULL; + +static char * +get_linkwidth_str(int linkwidth) +{ + if (linkwidth > 8) + return linkwidth_str[0]; + else + return linkwidth_str[linkwidth]; +} + +static char * +get_linkspeed_str(int linkspeed) +{ + if (linkspeed > 4) + return linkspeed_str[0]; + else + return linkspeed_str[linkspeed]; +} + +static inline const char* +node_type_str2(Node *node) +{ + switch(node->type) { + case SWITCH_NODE: return "SW"; + case CA_NODE: return "CA"; + case ROUTER_NODE: return "RT"; + } + return "??"; +} + +void +decode_port_info(void *pi, Port *port) +{ + mad_decode_field(pi, IB_PORT_LID_F, &port->lid); + mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc); + mad_decode_field(pi, IB_PORT_STATE_F, &port->state); + mad_decode_field(pi, IB_PORT_PHYS_STATE_F, &port->physstate); + mad_decode_field(pi, IB_PORT_LINK_WIDTH_ACTIVE_F, &port->linkwidth); + mad_decode_field(pi, IB_PORT_LINK_SPEED_ACTIVE_F, &port->linkspeed); +} + + +int +get_port(Port *port, int portnum, ib_portid_t *portid) +{ + char portinfo[64]; + void *pi = portinfo; + + port->portnum = portnum; + + if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout)) + return -1; + decode_port_info(pi, port); + + DEBUG("portid %s portnum %d: lid %d state %d physstate %d %s %s", + portid2str(portid), portnum, port->lid, port->state, port->physstate, get_linkwidth_str(port->linkwidth), get_linkspeed_str(port->linkspeed)); + return 1; +} +/* + * Returns 0 if non switch node is found, 1 if switch is found, -1 if error. + */ +int +get_node(Node *node, Port *port, ib_portid_t *portid) +{ + char portinfo[64]; + char switchinfo[64]; + void *pi = portinfo, *ni = node->nodeinfo, *nd = node->nodedesc; + void *si = switchinfo; + + if (!smp_query(ni, portid, IB_ATTR_NODE_INFO, 0, timeout)) + return -1; + + mad_decode_field(ni, IB_NODE_GUID_F, &node->nodeguid); + mad_decode_field(ni, IB_NODE_TYPE_F, &node->type); + mad_decode_field(ni, IB_NODE_NPORTS_F, &node->numports); + mad_decode_field(ni, IB_NODE_DEVID_F, &node->devid); + mad_decode_field(ni, IB_NODE_VENDORID_F, &node->vendid); + mad_decode_field(ni, IB_NODE_SYSTEM_GUID_F, &node->sysimgguid); + mad_decode_field(ni, IB_NODE_PORT_GUID_F, &node->portguid); + mad_decode_field(ni, IB_NODE_LOCAL_PORT_F, &node->localport); + port->portnum = node->localport; + port->portguid = node->portguid; + + if (!smp_query(nd, portid, IB_ATTR_NODE_DESC, 0, timeout)) + return -1; + + if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, 0, timeout)) + return -1; + decode_port_info(pi, port); + + if (node->type != SWITCH_NODE) + return 0; + + node->smalid = port->lid; + node->smalmc = port->lmc; + + /* after we have the sma information find out the real PortInfo for this port */ + if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, node->localport, timeout)) + return -1; + decode_port_info(pi, port); + + if (!smp_query(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout)) + node->smaenhsp0 = 0; /* assume base SP0 */ + else + mad_decode_field(si, IB_SW_ENHANCED_PORT0_F, &node->smaenhsp0); + + DEBUG("portid %s: got switch node %" PRIx64 " '%s'", + portid2str(portid), node->nodeguid, node->nodedesc); + return 1; +} + +static int +extend_dpath(ib_dr_path_t *path, int nextport) +{ + if (path->cnt+2 >= sizeof(path->p)) + return -1; + ++path->cnt; + if (path->cnt > maxhops_discovered) + maxhops_discovered = path->cnt; + path->p[path->cnt] = nextport; + return path->cnt; +} + +static void +dump_endnode(ib_portid_t *path, char *prompt, Node *node, Port *port) +{ + if (!dumplevel) + return; + + fprintf(f, "%s -> %s %s {%016" PRIx64 "} portnum %d lid %d-%d\"%s\"\n", + portid2str(path), prompt, + (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), + node->nodeguid, node->type == SWITCH_NODE ? 0 : port->portnum, + port->lid, port->lid + (1 << port->lmc) - 1, + clean_nodedesc(node->nodedesc)); +} + +#define HASHGUID(guid) ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103))) +#define HTSZ 137 + +static Node *nodestbl[HTSZ]; + +static Node * +find_node(Node *new) +{ + int hash = HASHGUID(new->nodeguid) % HTSZ; + Node *node; + + for (node = nodestbl[hash]; node; node = node->htnext) + if (node->nodeguid == new->nodeguid) + return node; + + return NULL; +} + +static Node * +create_node(Node *temp, ib_portid_t *path, int dist) +{ + Node *node; + int hash = HASHGUID(temp->nodeguid) % HTSZ; + + node = malloc(sizeof(*node)); + if (!node) + return NULL; + + memcpy(node, temp, sizeof(*node)); + node->dist = dist; + node->path = *path; + + node->htnext = nodestbl[hash]; + nodestbl[hash] = node; + + if (node->type != SWITCH_NODE) + dist = MAXHOPS; /* special Ca list */ + + node->dnext = nodesdist[dist]; + nodesdist[dist] = node; + + return node; +} + +static Port * +find_port(Node *node, Port *port) +{ + Port *old; + + for (old = node->ports; old; old = old->next) + if (old->portnum == port->portnum) + return old; + + return NULL; +} + +static Port * +create_port(Node *node, Port *temp) +{ + Port *port; + + port = malloc(sizeof(*port)); + if (!port) + return NULL; + + memcpy(port, temp, sizeof(*port)); + port->node = node; + port->next = node->ports; + node->ports = port; + + return port; +} + +static void +link_ports(Node *node, Port *port, Node *remotenode, Port *remoteport) +{ + DEBUG("linking: 0x%" PRIx64 " %p->%p:%u and 0x%" PRIx64 " %p->%p:%u", + node->nodeguid, node, port, port->portnum, + remotenode->nodeguid, remotenode, remoteport, remoteport->portnum); + if (port->remoteport) + port->remoteport->remoteport = NULL; + if (remoteport->remoteport) + remoteport->remoteport->remoteport = NULL; + port->remoteport = remoteport; + remoteport->remoteport = port; +} + +static int +handle_port(Node *node, Port *port, ib_portid_t *path, int portnum, int dist) +{ + Node node_buf; + Port port_buf; + Node *remotenode, *oldnode; + Port *remoteport, *oldport; + + memset(&node_buf, 0, sizeof(node_buf)); + memset(&port_buf, 0, sizeof(port_buf)); + + DEBUG("handle node %p port %p:%d dist %d", node, port, portnum, dist); + if (port->physstate != 5) /* LinkUp */ + return -1; + + if (extend_dpath(&path->drpath, portnum) < 0) + return -1; + + if (get_node(&node_buf, &port_buf, path) < 0) { + IBWARN("NodeInfo on %s failed, skipping port", + portid2str(path)); + path->drpath.cnt--; /* restore path */ + return -1; + } + + oldnode = find_node(&node_buf); + if (oldnode) + remotenode = oldnode; + else if (!(remotenode = create_node(&node_buf, path, dist + 1))) + IBERROR("no memory"); + + oldport = find_port(remotenode, &port_buf); + if (oldport) { + remoteport = oldport; + if (node != remotenode || port != remoteport) + IBWARN("port moving..."); + } else if (!(remoteport = create_port(remotenode, &port_buf))) + IBERROR("no memory"); + + dump_endnode(path, oldnode ? "known remote" : "new remote", + remotenode, remoteport); + + link_ports(node, port, remotenode, remoteport); + + path->drpath.cnt--; /* restore path */ + return 0; +} + +/* + * Return 1 if found, 0 if not, -1 on errors. + */ +static int +discover(ib_portid_t *from) +{ + Node node_buf; + Port port_buf; + Node *node; + Port *port; + int i; + int dist = 0; + ib_portid_t *path; + + DEBUG("from %s", portid2str(from)); + + memset(&node_buf, 0, sizeof(node_buf)); + memset(&port_buf, 0, sizeof(port_buf)); + + if (get_node(&node_buf, &port_buf, from) < 0) { + IBWARN("can't reach node %s", portid2str(from)); + return -1; + } + + node = create_node(&node_buf, from, 0); + if (!node) + IBERROR("out of memory"); + + mynode = node; + + port = create_port(node, &port_buf); + if (!port) + IBERROR("out of memory"); + + if (node->type != SWITCH_NODE && + handle_port(node, port, from, node->localport, 0) < 0) + return 0; + + for (dist = 0; dist < MAXHOPS; dist++) { + + for (node = nodesdist[dist]; node; node = node->dnext) { + + path = &node->path; + + DEBUG("dist %d node %p", dist, node); + dump_endnode(path, "processing", node, port); + + for (i = 1; i <= node->numports; i++) { + if (i == node->localport) + continue; + + if (get_port(&port_buf, i, path) < 0) { + IBWARN("can't reach node %s port %d", portid2str(path), i); + continue; + } + + port = find_port(node, &port_buf); + if (port) + continue; + + port = create_port(node, &port_buf); + if (!port) + IBERROR("out of memory"); + + /* If switch, set port GUID to node GUID */ + if (node->type == SWITCH_NODE) + port->portguid = node->portguid; + + handle_port(node, port, path, i, dist); + } + } + } + + return 0; +} + +char * +node_name(Node *node) +{ + static char buf[256]; + + switch(node->type) { + case SWITCH_NODE: + sprintf(buf, "\"%s", "S"); + break; + case CA_NODE: + sprintf(buf, "\"%s", "H"); + break; + case ROUTER_NODE: + sprintf(buf, "\"%s", "R"); + break; + default: + sprintf(buf, "\"%s", "?"); + break; + } + sprintf(buf+2, "-%016" PRIx64 "\"", node->nodeguid); + + return buf; +} + +void +list_node(Node *node) +{ + char *node_type; + char *nodename = remap_node_name(node_name_map, node->nodeguid, + node->nodedesc); + + switch(node->type) { + case SWITCH_NODE: + node_type = "Switch"; + break; + case CA_NODE: + node_type = "Ca"; + break; + case ROUTER_NODE: + node_type = "Router"; + break; + default: + node_type = "???"; + break; + } + fprintf(f, "%s\t : 0x%016" PRIx64 " ports %d devid 0x%x vendid 0x%x \"%s\"\n", + node_type, + node->nodeguid, node->numports, node->devid, node->vendid, + nodename); + + free(nodename); +} + +void +out_ids(Node *node, int group, char *chname) +{ + fprintf(f, "\nvendid=0x%x\ndevid=0x%x\n", node->vendid, node->devid); + if (node->sysimgguid) + fprintf(f, "sysimgguid=0x%" PRIx64, node->sysimgguid); + if (group + && node->chrecord && node->chrecord->chassisnum) { + fprintf(f, "\t\t# Chassis %d", node->chrecord->chassisnum); + if (chname) + fprintf(f, " (%s)", chname); + if (is_xsigo_tca(node->nodeguid) && node->ports->remoteport) + fprintf(f, " slot %d", node->ports->remoteport->portnum); + } + fprintf(f, "\n"); +} + +uint64_t +out_chassis(int chassisnum) +{ + uint64_t guid; + + fprintf(f, "\nChassis %d", chassisnum); + guid = get_chassis_guid(chassisnum); + if (guid) + fprintf(f, " (guid 0x%" PRIx64 ")", guid); + fprintf(f, "\n"); + return guid; +} + +void +out_switch(Node *node, int group, char *chname) +{ + char *str; + char *nodename = NULL; + + out_ids(node, group, chname); + fprintf(f, "switchguid=0x%" PRIx64, node->nodeguid); + fprintf(f, "(%" PRIx64 ")", node->portguid); + /* Currently, only if Voltaire chassis */ + if (group + && node->chrecord && node->chrecord->chassisnum + && node->vendid == VTR_VENDOR_ID) { + str = get_chassis_type(node->chrecord->chassistype); + if (str) + fprintf(f, "%s ", str); + str = get_chassis_slot(node->chrecord->chassisslot); + if (str) + fprintf(f, "%s ", str); + fprintf(f, "%d Chip %d", node->chrecord->slotnum, node->chrecord->anafanum); + } + + nodename = remap_node_name(node_name_map, node->nodeguid, + node->nodedesc); + + fprintf(f, "\nSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d\n", + node->numports, node_name(node), + nodename, + node->smaenhsp0 ? "enhanced" : "base", + node->smalid, node->smalmc); + + free(nodename); +} + +void +out_ca(Node *node, int group, char *chname) +{ + char *node_type; + char *node_type2; + char *nodename = remap_node_name(node_name_map, node->nodeguid, + node->nodedesc); + + out_ids(node, group, chname); + switch(node->type) { + case CA_NODE: + node_type = "ca"; + node_type2 = "Ca"; + break; + case ROUTER_NODE: + node_type = "rt"; + node_type2 = "Rt"; + break; + default: + node_type = "???"; + node_type2 = "???"; + break; + } + + fprintf(f, "%sguid=0x%" PRIx64 "\n", node_type, node->nodeguid); + fprintf(f, "%s\t%d %s\t\t# \"%s\"", + node_type2, node->numports, node_name(node), + nodename); + if (group && is_xsigo_hca(node->nodeguid)) + fprintf(f, " (scp)"); + fprintf(f, "\n"); + + free(nodename); +} + +static char * +out_ext_port(Port *port, int group) +{ + char *str = NULL; + + /* Currently, only if Voltaire chassis */ + if (group + && port->node->chrecord && port->node->vendid == VTR_VENDOR_ID) + str = portmapstring(port); + + return (str); +} + +void +out_switch_port(Port *port, int group) +{ + char *ext_port_str = NULL; + char *rem_nodename = NULL; + + DEBUG("port %p:%d remoteport %p", port, port->portnum, port->remoteport); + fprintf(f, "[%d]", port->portnum); + + ext_port_str = out_ext_port(port, group); + if (ext_port_str) + fprintf(f, "%s", ext_port_str); + + rem_nodename = remap_node_name(node_name_map, + port->remoteport->node->nodeguid, + port->remoteport->node->nodedesc); + + ext_port_str = out_ext_port(port->remoteport, group); + fprintf(f, "\t%s[%d]%s", + node_name(port->remoteport->node), + port->remoteport->portnum, + ext_port_str ? ext_port_str : ""); + if (port->remoteport->node->type != SWITCH_NODE) + fprintf(f, "(%" PRIx64 ") ", port->remoteport->portguid); + fprintf(f, "\t\t# \"%s\" lid %d %s%s", + rem_nodename, + port->remoteport->node->type == SWITCH_NODE ? port->remoteport->node->smalid : port->remoteport->lid, + get_linkwidth_str(port->linkwidth), + get_linkspeed_str(port->linkspeed)); + + if (is_xsigo_tca(port->remoteport->portguid)) + fprintf(f, " slot %d", port->portnum); + else if (is_xsigo_hca(port->remoteport->portguid)) + fprintf(f, " (scp)"); + fprintf(f, "\n"); + + free(rem_nodename); +} + +void +out_ca_port(Port *port, int group) +{ + char *str = NULL; + char *rem_nodename = NULL; + + fprintf(f, "[%d]", port->portnum); + if (port->node->type != SWITCH_NODE) + fprintf(f, "(%" PRIx64 ") ", port->portguid); + fprintf(f, "\t%s[%d]", + node_name(port->remoteport->node), + port->remoteport->portnum); + str = out_ext_port(port->remoteport, group); + if (str) + fprintf(f, "%s", str); + if (port->remoteport->node->type != SWITCH_NODE) + fprintf(f, " (%" PRIx64 ") ", port->remoteport->portguid); + + rem_nodename = remap_node_name(node_name_map, + port->remoteport->node->nodeguid, + port->remoteport->node->nodedesc); + + fprintf(f, "\t\t# lid %d lmc %d \"%s\" lid %d %s%s\n", + port->lid, port->lmc, rem_nodename, + port->remoteport->node->type == SWITCH_NODE ? port->remoteport->node->smalid : port->remoteport->lid, + get_linkwidth_str(port->linkwidth), + get_linkspeed_str(port->linkspeed)); + + free(rem_nodename); +} + +int +dump_topology(int listtype, int group) +{ + Node *node; + Port *port; + int i = 0, dist = 0; + time_t t = time(0); + uint64_t chguid; + char *chname = NULL; + + if (!listtype) { + fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t)); + fprintf(f, "# Max of %d hops discovered\n", maxhops_discovered); + fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n", mynode->nodeguid, mynode->portguid); + } + + /* Make pass on switches */ + if (group && !listtype) { + ChassisList *ch = NULL; + + /* Chassis based switches first */ + for (ch = chassis; ch; ch = ch->next) { + int n = 0; + + if (!ch->chassisnum) + continue; + chguid = out_chassis(ch->chassisnum); + if (chname) + free(chname); + chname = NULL; + if (is_xsigo_guid(chguid)) { + for (node = nodesdist[MAXHOPS]; node; node = node->dnext) { + if (!node->chrecord || + !node->chrecord->chassisnum) + continue; + + if (node->chrecord->chassisnum != ch->chassisnum) + continue; + + if (is_xsigo_hca(node->nodeguid)) { + chname = remap_node_name(node_name_map, + node->nodeguid, + node->nodedesc); + fprintf(f, "Hostname: %s\n", chname); + } + } + } + + fprintf(f, "\n# Spine Nodes"); + for (n = 1; n <= (SPINES_MAX_NUM+1); n++) { + if (ch->spinenode[n]) { + out_switch(ch->spinenode[n], group, chname); + for (port = ch->spinenode[n]->ports; port; port = port->next, i++) + if (port->remoteport) + out_switch_port(port, group); + } + } + fprintf(f, "\n# Line Nodes"); + for (n = 1; n <= (LINES_MAX_NUM+1); n++) { + if (ch->linenode[n]) { + out_switch(ch->linenode[n], group, chname); + for (port = ch->linenode[n]->ports; port; port = port->next, i++) + if (port->remoteport) + out_switch_port(port, group); + } + } + + fprintf(f, "\n# Chassis Switches"); + for (dist = 0; dist <= maxhops_discovered; dist++) { + + for (node = nodesdist[dist]; node; node = node->dnext) { + + /* Non Voltaire chassis */ + if (node->vendid == VTR_VENDOR_ID) + continue; + if (!node->chrecord || + !node->chrecord->chassisnum) + continue; + + if (node->chrecord->chassisnum != ch->chassisnum) + continue; + + out_switch(node, group, chname); + for (port = node->ports; port; port = port->next, i++) + if (port->remoteport) + out_switch_port(port, group); + + } + + } + + fprintf(f, "\n# Chassis CAs"); + for (node = nodesdist[MAXHOPS]; node; node = node->dnext) { + if (!node->chrecord || + !node->chrecord->chassisnum) + continue; + + if (node->chrecord->chassisnum != ch->chassisnum) + continue; + + out_ca(node, group, chname); + for (port = node->ports; port; port = port->next, i++) + if (port->remoteport) + out_ca_port(port, group); + + } + + } + + } else { + for (dist = 0; dist <= maxhops_discovered; dist++) { + + for (node = nodesdist[dist]; node; node = node->dnext) { + + DEBUG("SWITCH: dist %d node %p", dist, node); + if (!listtype) + out_switch(node, group, chname); + else { + if (listtype & LIST_SWITCH_NODE) + list_node(node); + continue; + } + + for (port = node->ports; port; port = port->next, i++) + if (port->remoteport) + out_switch_port(port, group); + } + } + } + + if (chname) + free(chname); + chname = NULL; + if (group && !listtype) { + + fprintf(f, "\nNon-Chassis Nodes\n"); + + for (dist = 0; dist <= maxhops_discovered; dist++) { + + for (node = nodesdist[dist]; node; node = node->dnext) { + + DEBUG("SWITCH: dist %d node %p", dist, node); + /* Now, skip chassis based switches */ + if (node->chrecord && + node->chrecord->chassisnum) + continue; + out_switch(node, group, chname); + + for (port = node->ports; port; port = port->next, i++) + if (port->remoteport) + out_switch_port(port, group); + } + + } + + } + + /* Make pass on CAs */ + for (node = nodesdist[MAXHOPS]; node; node = node->dnext) { + + DEBUG("CA: dist %d node %p", dist, node); + if (!listtype) { + /* Now, skip chassis based CAs */ + if (group && node->chrecord && + node->chrecord->chassisnum) + continue; + out_ca(node, group, chname); + } else { + if (((listtype & LIST_CA_NODE) && (node->type == CA_NODE)) || + ((listtype & LIST_ROUTER_NODE) && (node->type == ROUTER_NODE))) + list_node(node); + continue; + } + + for (port = node->ports; port; port = port->next, i++) + if (port->remoteport) + out_ca_port(port, group); + } + + if (chname) + free(chname); + + return i; +} + +void dump_ports_report () +{ + int b, n = 0, p; + Node *node; + Port *port; + + // If switch and LID == 0, search of other switch ports with + // valid LID and assign it to all ports of that switch + for (b = 0; b <= MAXHOPS; b++) + for (node = nodesdist[b]; node; node = node->dnext) + if (node->type == SWITCH_NODE) { + int swlid = 0; + for (p = 0, port = node->ports; + p < node->numports && port && !swlid; + port = port->next) + if (port->lid != 0) + swlid = port->lid; + for (p = 0, port = node->ports; + p < node->numports && port; + port = port->next) + port->lid = swlid; + } + + for (b = 0; b <= MAXHOPS; b++) + for (node = nodesdist[b]; node; node = node->dnext) { + for (p = 0, port = node->ports; + p < node->numports && port; + p++, port = port->next) { + fprintf(stdout, + "%2s %5d %2d 0x%016" PRIx64 " %s %s", + node_type_str2(port->node), port->lid, + port->portnum, + port->portguid, + get_linkwidth_str(port->linkwidth), + get_linkspeed_str(port->linkspeed)); + if (port->remoteport) + fprintf(stdout, + " - %2s %5d %2d 0x%016" PRIx64 + " ( '%s' - '%s' )\n", + node_type_str2(port->remoteport->node), + port->remoteport->lid, + port->remoteport->portnum, + port->remoteport->portguid, + port->node->nodedesc, + port->remoteport->node->nodedesc); + else + fprintf(stdout, "%36s'%s'\n", "", + port->node->nodedesc); + } + n++; + } +} + +void +usage(void) +{ + fprintf(stderr, "Usage: %s [-d(ebug)] -e(rr_show) -v(erbose) -s(how) -l(ist) -g(rouping) -H(ca_list) -S(witch_list) -R(outer_list) -V(ersion) -C ca_name -P ca_port " + "-t(imeout) timeout_ms --node-name-map node-name-map] -p(orts) []\n", + argv0); + fprintf(stderr, " --node-name-map specify a node name map file\n"); + exit(-1); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[2] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS}; + ib_portid_t my_portid = {0}; + int udebug = 0, list = 0; + char *ca = 0; + int ca_port = 0; + int group = 0; + int ports_report = 0; + + static char const str_opts[] = "C:P:t:devslgHSRpVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "err_show", 0, 0, 'e'}, + { "verbose", 0, 0, 'v'}, + { "show", 0, 0, 's'}, + { "list", 0, 0, 'l'}, + { "grouping", 0, 0, 'g'}, + { "Hca_list", 0, 0, 'H'}, + { "Switch_list", 0, 0, 'S'}, + { "Router_list", 0, 0, 'R'}, + { "timeout", 1, 0, 't'}, + { "node-name-map", 1, 0, 1}, + { "ports", 0, 0, 'p'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + f = stdout; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 1: + node_name_map_file = strdup(optarg); + break; + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + break; + case 'v': + verbose++; + dumplevel++; + break; + case 's': + dumplevel = 1; + break; + case 'e': + madrpc_show_errors(1); + break; + case 'l': + list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE; + break; + case 'g': + group = 1; + break; + case 'S': + list = LIST_SWITCH_NODE; + break; + case 'H': + list = LIST_CA_NODE; + break; + case 'R': + list = LIST_ROUTER_NODE; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + case 'p': + ports_report = 1; + break; + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc && !(f = fopen(argv[0], "w"))) + IBERROR("can't open file %s for writing", argv[0]); + + madrpc_init(ca, ca_port, mgmt_classes, 2); + node_name_map = open_node_name_map(node_name_map_file); + + if (discover(&my_portid) < 0) + IBERROR("discover"); + + if (group) + chassis = group_nodes(); + + if (ports_report) + dump_ports_report(); + else + dump_topology(list, group); + + close_node_name_map(node_name_map); + exit(0); +} diff --git a/contrib/ofed/management/infiniband-diags/src/ibping.c b/contrib/ofed/management/infiniband-diags/src/ibping.c new file mode 100644 index 000000000000..4fd2dcb8fdcc --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/ibping.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +#undef DEBUG +#define DEBUG if (verbose) IBWARN + +static int dest_type = IB_DEST_LID; +static int verbose; +static char host_and_domain[IB_VENDOR_RANGE2_DATA_SIZE]; +static char last_host[IB_VENDOR_RANGE2_DATA_SIZE]; + +char *argv0 = "ibping"; + +static void +get_host_and_domain(char *data, int sz) +{ + char *s = data; + int n; + + if (gethostname(s, sz) < 0) + snprintf(s, sz, "?hostname?"); + + s[sz-1] = 0; + if ((n = strlen(s)) >= sz) + return; + s[n] = '.'; + s += n + 1; + sz -= n + 1; + + if (getdomainname(s, sz) < 0) + snprintf(s, sz, "?domainname?"); + if (strlen(s) == 0) + s[-1] = 0; /* no domain */ +} + +static char * +ibping_serv(void) +{ + void *umad; + void *mad; + char *data; + + DEBUG("starting to serve..."); + + while ((umad = mad_receive(0, -1))) { + + mad = umad_get_mad(umad); + data = (char *)mad + IB_VENDOR_RANGE2_DATA_OFFS; + + memcpy(data, host_and_domain, IB_VENDOR_RANGE2_DATA_SIZE); + + DEBUG("Pong: %s", data); + + if (mad_respond(umad, 0, 0) < 0) + DEBUG("respond failed"); + + mad_free(umad); + } + + DEBUG("server out"); + return 0; +} + +static uint64_t +ibping(ib_portid_t *portid, int quiet) +{ + char data[IB_VENDOR_RANGE2_DATA_SIZE] = {0}; + ib_vendor_call_t call; + uint64_t start, rtt; + + DEBUG("Ping.."); + + start = getcurrenttime(); + + call.method = IB_MAD_METHOD_GET; + call.mgmt_class = IB_VENDOR_OPENIB_PING_CLASS; + call.attrid = 0; + call.mod = 0; + call.oui = IB_OPENIB_OUI; + call.timeout = 0; + memset(&call.rmpp, 0, sizeof call.rmpp); + + if (!ib_vendor_call(data, portid, &call)) + return ~0llu; + + rtt = getcurrenttime() - start; + + if (!last_host[0]) + memcpy(last_host, data, sizeof last_host); + + if (!quiet) + printf("Pong from %s (%s): time %" PRIu64 ".%03" PRIu64 " ms\n", + data, portid2str(portid), rtt/1000, rtt%1000); + + return rtt; +} + +static void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port " + "-t(imeout) timeout_ms -c ping_count -f(lood) -o oui -S(erver)] \n", + basename); + exit(-1); +} + +static uint64_t minrtt = ~0ull, maxrtt, total_rtt; +static uint64_t start, total_time, replied, lost, ntrans; +static ib_portid_t portid = {0}; + +void +report(int sig) +{ + total_time = getcurrenttime() - start; + + DEBUG("out due signal %d", sig); + + printf("\n--- %s (%s) ibping statistics ---\n", last_host, portid2str(&portid)); + printf("%" PRIu64 " packets transmitted, %" PRIu64 " received, %" PRIu64 "%% packet loss, time %" PRIu64 " ms\n", + ntrans, replied, + (lost != 0) ? lost * 100 / ntrans : 0, total_time / 1000); + printf("rtt min/avg/max = %" PRIu64 ".%03" PRIu64 "/%" PRIu64 ".%03" PRIu64 "/%" PRIu64 ".%03" PRIu64 " ms\n", + minrtt == ~0ull ? 0 : minrtt/1000, + minrtt == ~0ull ? 0 : minrtt%1000, + replied ? total_rtt/replied/1000 : 0, + replied ? (total_rtt/replied)%1000 : 0, + maxrtt/1000, maxrtt%1000); + + exit(0); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + int ping_class = IB_VENDOR_OPENIB_PING_CLASS; + ib_portid_t *sm_id = 0, sm_portid = {0}; + int timeout = 0, udebug = 0, server = 0, flood = 0; + int oui = IB_OPENIB_OUI; + uint64_t rtt; + unsigned count = ~0; + extern int ibdebug; + char *err; + char *ca = 0; + int ca_port = 0; + + static char const str_opts[] = "C:P:t:s:c:o:devGfSVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "err_show", 0, 0, 'e'}, + { "verbose", 0, 0, 'v'}, + { "Guid", 0, 0, 'G'}, + { "s", 1, 0, 's'}, + { "timeout", 1, 0, 't'}, + { "c", 1, 0, 'c'}, + { "flood", 0, 0, 'f'}, + { "o", 1, 0, 'o'}, + { "Server", 0, 0, 'S'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'c': + count = strtoul(optarg, 0, 0); + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'e': + madrpc_show_errors(1); + break; + case 'f': + flood++; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 'o': + oui = strtoul(optarg, 0, 0); + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 'S': + server++; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'v': + verbose++; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (!argc && !server) + usage(); + + madrpc_init(ca, ca_port, mgmt_classes, 3); + + if (server) { + if (mad_register_server(ping_class, 0, 0, oui) < 0) + IBERROR("can't serve class %d on this port", ping_class); + + get_host_and_domain(host_and_domain, sizeof host_and_domain); + + if ((err = ibping_serv())) + IBERROR("ibping to %s: %s", portid2str(&portid), err); + exit(0); + } + + if (mad_register_client(ping_class, 0) < 0) + IBERROR("can't register ping class %d on this port", ping_class); + + if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + + signal(SIGINT, report); + signal(SIGTERM, report); + + start = getcurrenttime(); + + while (count-- > 0) { + ntrans++; + if ((rtt = ibping(&portid, flood)) == ~0ull) { + DEBUG("ibping to %s failed", portid2str(&portid)); + lost++; + } else { + if (rtt < minrtt) + minrtt = rtt; + if (rtt > maxrtt) + maxrtt = rtt; + total_rtt += rtt; + replied++; + } + + if (!flood) + sleep(1); + } + + report(0); + + exit(-1); +} diff --git a/contrib/ofed/management/infiniband-diags/src/ibportstate.c b/contrib/ofed/management/infiniband-diags/src/ibportstate.c new file mode 100644 index 000000000000..36453bbebba8 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/ibportstate.c @@ -0,0 +1,448 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +#undef DEBUG +#define DEBUG if (verbose>1) IBWARN + +static int dest_type = IB_DEST_LID; +static int verbose; + +char *argv0 = "ibportstate"; + +/*******************************************/ + +static int +get_node_info(ib_portid_t *dest, uint8_t *data) +{ + int node_type; + + if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) + return -1; + + node_type = mad_get_field(data, 0, IB_NODE_TYPE_F); + if (node_type == IB_NODE_SWITCH) /* Switch NodeType ? */ + return 0; + else + return 1; +} + +static int +get_port_info(ib_portid_t *dest, uint8_t *data, int portnum, int port_op) +{ + char buf[2048]; + char val[64]; + + if (!smp_query(data, dest, IB_ATTR_PORT_INFO, portnum, 0)) + return -1; + + if (port_op != 4) { + mad_dump_portstates(buf, sizeof buf, data, sizeof data); + mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, val); + mad_dump_field(IB_PORT_LINK_WIDTH_SUPPORTED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, val); + mad_dump_field(IB_PORT_LINK_WIDTH_ENABLED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, val); + mad_dump_field(IB_PORT_LINK_WIDTH_ACTIVE_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_SUPPORTED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_ACTIVE_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + } else { + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf, sizeof buf, val); + sprintf(buf+strlen(buf), "%s", "\n"); + } + + printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf); + return 0; +} + +static int +set_port_info(ib_portid_t *dest, uint8_t *data, int portnum, int port_op) +{ + char buf[2048]; + char val[64]; + + if (!smp_set(data, dest, IB_ATTR_PORT_INFO, portnum, 0)) + return -1; + + if (port_op != 4) + mad_dump_portstates(buf, sizeof buf, data, sizeof data); + else { + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf, sizeof buf, val); + sprintf(buf+strlen(buf), "%s", "\n"); + } + + printf("\nAfter PortInfo set:\n"); + printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf); + return 0; +} + +static int +get_link_width(int lwe, int lws) +{ + if (lwe == 255) + return lws; + else + return lwe; +} + +static int +get_link_speed(int lse, int lss) +{ + if (lse == 15) + return lss; + else + return lse; +} + +static void +validate_width(int width, int peerwidth, int lwa) +{ + if ((width & 0x8) && (peerwidth & 0x8)) { + if (lwa != 8) + IBWARN("Peer ports operating at active width %d rather than 8 (12x)", lwa); + } else { + if ((width & 0x4) && (peerwidth & 0x4)) { + if (lwa != 4) + IBWARN("Peer ports operating at active width %d rather than 4 (8x)", lwa); + } else { + if ((width & 0x2) && (peerwidth & 0x2)) { + if (lwa != 2) + IBWARN("Peer ports operating at active width %d rather than 2 (4x)", lwa); + } else { + if ((width & 0x1) && (peerwidth & 0x1)) { + if (lwa != 1) + IBWARN("Peer ports operating at active width %d rather than 1 (1x)", lwa); + } + } + } + } +} + +static void +validate_speed(int speed, int peerspeed, int lsa) +{ + if ((speed & 0x4) && (peerspeed & 0x4)) { + if (lsa != 4) + IBWARN("Peer ports operating at active speed %d rather than 4 (10.0 Gbps)", lsa); + } else { + if ((speed & 0x2) && (peerspeed & 0x2)) { + if (lsa != 2) + IBWARN("Peer ports operating at active speed %d rather than 2 (5.0 Gbps)", lsa); + } else { + if ((speed & 0x1) && (peerspeed & 0x1)) { + if (lsa != 1) + IBWARN("Peer ports operating at active speed %d rather than 1 (2.5 Gbps)", lsa); + } + } + } +} + +void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -D(irect) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port " + "-t(imeout) timeout_ms] []\n", + basename); + fprintf(stderr, "\tsupported ops: enable, disable, reset, speed, query\n"); + fprintf(stderr, "\n\texamples:\n"); + fprintf(stderr, "\t\t%s 3 1 disable\t\t\t# by lid\n", basename); + fprintf(stderr, "\t\t%s -G 0x2C9000100D051 1 enable\t# by guid\n", basename); + fprintf(stderr, "\t\t%s -D 0 1\t\t\t# (query) by direct route\n", basename); + fprintf(stderr, "\t\t%s 3 1 reset\t\t\t# by lid\n", basename); + fprintf(stderr, "\t\t%s 3 1 speed 1\t\t\t# by lid\n", basename); + exit(-1); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + ib_portid_t portid = {0}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + extern int ibdebug; + int err; + int timeout = 0, udebug = 0; + char *ca = 0; + int ca_port = 0; + int port_op = 0; /* default to query */ + int speed = 15; + int is_switch = 1; + int state, physstate, lwe, lws, lwa, lse, lss, lsa; + int peerlocalportnum, peerlwe, peerlws, peerlwa, peerlse, peerlss, peerlsa; + int width, peerwidth, peerspeed; + uint8_t data[IB_SMP_DATA_SIZE]; + ib_portid_t peerportid = {0}; + int portnum = 0; + ib_portid_t selfportid = {0}; + int selfport = 0; + + static char const str_opts[] = "C:P:t:s:devDGVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "err_show", 0, 0, 'e'}, + { "verbose", 0, 0, 'v'}, + { "Direct", 0, 0, 'D'}, + { "Guid", 0, 0, 'G'}, + { "timeout", 1, 0, 't'}, + { "s", 1, 0, 's'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'e': + madrpc_show_errors(1); + break; + case 'D': + dest_type = IB_DEST_DRPATH; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'v': + verbose++; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc < 2) + usage(); + + madrpc_init(ca, ca_port, mgmt_classes, 3); + + if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + + /* First, make sure it is a switch port if it is a "set" */ + if (argc >= 3) { + if (!strcmp(argv[2], "enable")) + port_op = 1; + else if (!strcmp(argv[2], "disable")) + port_op = 2; + else if (!strcmp(argv[2], "reset")) + port_op = 3; + else if (!strcmp(argv[2], "speed")) { + if (argc < 4) + IBERROR("speed requires an additional parameter"); + port_op = 4; + /* Parse speed value */ + speed = strtoul(argv[3], 0, 0); + if (speed > 15) + IBERROR("invalid speed value %d", speed); + } + } + + err = get_node_info(&portid, data); + if (err < 0) + IBERROR("smp query nodeinfo failed"); + if (err) { /* not switch */ + if (port_op == 0) /* query op */ + is_switch = 0; + else if (port_op != 4) /* other than speed op */ + IBERROR("smp query nodeinfo: Node type not switch"); + } + + if (argc-1 > 0) + portnum = strtol(argv[1], 0, 0); + + if (port_op) + printf("Initial PortInfo:\n"); + else + printf("PortInfo:\n"); + err = get_port_info(&portid, data, portnum, port_op); + if (err < 0) + IBERROR("smp query portinfo failed"); + + /* Only if one of the "set" options is chosen */ + if (port_op) { + if (port_op == 1) /* Enable port */ + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 2); /* Polling */ + else if ((port_op == 2) || (port_op == 3)) { /* Disable port */ + mad_set_field(data, 0, IB_PORT_STATE_F, 1); /* Down */ + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 3); /* Disabled */ + } else if (port_op == 4) { /* Set speed */ + mad_set_field(data, 0, IB_PORT_LINK_SPEED_ENABLED_F, speed); + mad_set_field(data, 0, IB_PORT_STATE_F, 0); + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 0); + } + + err = set_port_info(&portid, data, portnum, port_op); + if (err < 0) + IBERROR("smp set portinfo failed"); + + if (port_op == 3) { /* Reset port - so also enable */ + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 2); /* Polling */ + err = set_port_info(&portid, data, portnum, port_op); + if (err < 0) + IBERROR("smp set portinfo failed"); + } + } else { /* query op */ + /* only compare peer port if switch port */ + if (is_switch) { + /* First, exclude SP0 */ + if (portnum) { + /* Now, make sure PortState is Active */ + /* Or is PortPhysicalState LinkUp sufficient ? */ + mad_decode_field(data, IB_PORT_STATE_F, &state); + mad_decode_field(data, IB_PORT_PHYS_STATE_F, &physstate); + if (state == 4) { /* Active */ + mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, &lwe ); + mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, &lws); + mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, &lwa); + mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, &lss); + mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, &lsa); + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, &lse); + + /* Setup portid for peer port */ + memcpy(&peerportid, &portid, sizeof(peerportid)); + peerportid.drpath.cnt = 1; + peerportid.drpath.p[1] = portnum; + + /* Set DrSLID to local lid */ + if (ib_resolve_self(&selfportid, &selfport, 0) < 0) + IBERROR("could not resolve self"); + peerportid.drpath.drslid = selfportid.lid; + peerportid.drpath.drdlid = 0xffff; + + /* Get peer port NodeInfo to obtain peer port number */ + err = get_node_info(&peerportid, data); + if (err < 0) + IBERROR("smp query nodeinfo failed"); + + mad_decode_field(data, IB_NODE_LOCAL_PORT_F, &peerlocalportnum); + + printf("Peer PortInfo:\n"); + /* Get peer port characteristics */ + err = get_port_info(&peerportid, data, peerlocalportnum, port_op); + if (err < 0) + IBERROR("smp query peer portinfofailed"); + + mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, &peerlwe ); + mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, &peerlws); + mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, &peerlwa); + mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, &peerlss); + mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, &peerlsa); + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, &peerlse); + + /* Now validate peer port characteristics */ + /* Examine Link Width */ + width = get_link_width(lwe, lws); + peerwidth = get_link_width(peerlwe, peerlws); + validate_width(width, peerwidth, lwa); + + /* Examine Link Speed */ + speed = get_link_speed(lse, lss); + peerspeed = get_link_speed(peerlse, peerlss); + validate_speed(speed, peerspeed, lsa); + } + } + } + } + + exit(0); +} diff --git a/contrib/ofed/management/infiniband-diags/src/ibroute.c b/contrib/ofed/management/infiniband-diags/src/ibroute.c new file mode 100644 index 000000000000..f2ee170cedc0 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/ibroute.c @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ibdiag_common.h" + +static int dest_type = IB_DEST_LID; +static int brief; +static int verbose; +static int dump_all; + +char *argv0 = "ibroute"; + +/*******************************************/ + +char * +check_switch(ib_portid_t *portid, int *nports, uint64_t *guid, + uint8_t *sw, char *nd) +{ + uint8_t ni[IB_SMP_DATA_SIZE] = {0}; + int type; + + DEBUG("checking node type"); + if (!smp_query(ni, portid, IB_ATTR_NODE_INFO, 0, 0)) { + xdump(stderr, "nodeinfo\n", ni, sizeof ni); + return "node info failed: valid addr?"; + } + + if (!smp_query(nd, portid, IB_ATTR_NODE_DESC, 0, 0)) + return "node desc failed"; + + mad_decode_field(ni, IB_NODE_TYPE_F, &type); + if (type != IB_NODE_SWITCH) + return "not a switch"; + + DEBUG("Gathering information about switch"); + mad_decode_field(ni, IB_NODE_NPORTS_F, nports); + mad_decode_field(ni, IB_NODE_GUID_F, guid); + + if (!smp_query(sw, portid, IB_ATTR_SWITCH_INFO, 0, 0)) + return "switch info failed: is a switch node?"; + + return 0; +} + +#define IB_MLIDS_IN_BLOCK (IB_SMP_DATA_SIZE/2) + +int +dump_mlid(char *str, int strlen, int mlid, int nports, + uint16_t mft[16][IB_MLIDS_IN_BLOCK]) +{ + uint16_t mask; + int i, chunk, bit; + int nonzero = 0; + + if (brief) { + int n = 0, chunks = ALIGN(nports + 1, 16) / 16; + for (i = 0; i < chunks; i++) { + mask = ntohs(mft[i][mlid%IB_MLIDS_IN_BLOCK]); + if (mask) + nonzero++; + n += snprintf(str + n, strlen - n, "%04hx", mask); + if (n >= strlen) { + n = strlen; + break; + } + } + if (!nonzero && !dump_all) { + str[0] = 0; + return 0; + } + return n; + } + for (i = 0; i <= nports; i++) { + chunk = i / 16; + bit = i % 16; + + mask = ntohs(mft[chunk][mlid%IB_MLIDS_IN_BLOCK]); + if (mask) + nonzero++; + str[i*2] = (mask & (1 << bit)) ? 'x' : ' '; + str[i*2+1] = ' '; + } + if (!nonzero && !dump_all) { + str[0] = 0; + return 0; + } + str[i*2] = 0; + return i * 2; +} + +uint16_t mft[16][IB_MLIDS_IN_BLOCK]; + +char * +dump_multicast_tables(ib_portid_t *portid, int startlid, int endlid) +{ + char nd[IB_SMP_DATA_SIZE] = {0}; + uint8_t sw[IB_SMP_DATA_SIZE] = {0}; + char str[512]; + char *s; + uint64_t nodeguid; + uint32_t mod; + int block, i, j, e, nports, cap, chunks; + int n = 0, startblock, lastblock; + + if ((s = check_switch(portid, &nports, &nodeguid, sw, nd))) + return s; + + mad_decode_field(sw, IB_SW_MCAST_FDB_CAP_F, &cap); + + if (!endlid || endlid > IB_MIN_MCAST_LID + cap - 1) + endlid = IB_MIN_MCAST_LID + cap - 1; + + if (!startlid) + startlid = IB_MIN_MCAST_LID; + + if (startlid < IB_MIN_MCAST_LID) { + IBWARN("illegal start mlid %x, set to %x", startlid, IB_MIN_MCAST_LID); + startlid = IB_MIN_MCAST_LID; + } + + if (endlid > IB_MAX_MCAST_LID) { + IBWARN("illegal end mlid %x, truncate to %x", endlid, IB_MAX_MCAST_LID); + endlid = IB_MAX_MCAST_LID; + } + + printf("Multicast mlids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 " (%s):\n", + startlid, endlid, portid2str(portid), nodeguid, clean_nodedesc(nd)); + + if (brief) + printf(" MLid Port Mask\n"); + else { + if (nports > 9) { + for (i = 0, s = str; i <= nports; i++) { + *s++ = (i%10) ? ' ' : '0' + i/10; + *s++ = ' '; + } + *s = 0; + printf(" %s\n", str); + } + for (i = 0, s = str; i <= nports; i++) + s += sprintf(s, "%d ", i%10); + printf(" Ports: %s\n", str); + printf(" MLid\n"); + } + if (verbose) + printf("Switch muticast mlids capability is 0x%d\n", cap); + + chunks = ALIGN(nports + 1, 16) / 16; + + startblock = startlid / IB_MLIDS_IN_BLOCK; + lastblock = endlid / IB_MLIDS_IN_BLOCK; + for (block = startblock; block <= lastblock; block++) { + for (j = 0; j < chunks; j++) { + mod = (block - IB_MIN_MCAST_LID/IB_MLIDS_IN_BLOCK) | (j << 28); + + DEBUG("reading block %x chunk %d mod %x", block, j, mod); + if (!smp_query(mft + j, portid, IB_ATTR_MULTICASTFORWTBL, mod, 0)) + return "multicast forwarding table get failed"; + } + + i = block * IB_MLIDS_IN_BLOCK; + e = i + IB_MLIDS_IN_BLOCK; + if (i < startlid) + i = startlid; + if (e > endlid + 1) + e = endlid + 1; + + for (; i < e; i++) { + if (dump_mlid(str, sizeof str, i, nports, mft) == 0) + continue; + printf("0x%04x %s\n", i, str); + n++; + } + } + + printf("%d %smlids dumped \n", n, dump_all ? "" : "valid "); + return 0; +} + +int +dump_lid(char *str, int strlen, int lid, int valid) +{ + char nd[IB_SMP_DATA_SIZE] = {0}; + uint8_t ni[IB_SMP_DATA_SIZE] = {0}; + uint8_t pi[IB_SMP_DATA_SIZE] = {0}; + ib_portid_t lidport = {0}; + static int last_port_lid, base_port_lid; + char ntype[50], sguid[30], desc[64]; + static uint64_t portguid; + int baselid, lmc, type; + + if (brief) { + str[0] = 0; + return 0; + } + + if (lid <= last_port_lid) { + if (!valid) + return snprintf(str, strlen, ": (path #%d - illegal port)", + lid - base_port_lid); + else if (!portguid) + return snprintf(str, strlen, + ": (path #%d out of %d)", + lid - base_port_lid + 1, + last_port_lid - base_port_lid + 1); + else { + return snprintf(str, strlen, + ": (path #%d out of %d: portguid %s)", + lid - base_port_lid + 1, + last_port_lid - base_port_lid + 1, + mad_dump_val(IB_NODE_PORT_GUID_F, sguid, sizeof sguid, &portguid)); + } + } + + if (!valid) + return snprintf(str, strlen, ": (illegal port)"); + + portguid = 0; + lidport.lid = lid; + + if (!smp_query(nd, &lidport, IB_ATTR_NODE_DESC, 0, 100) || + !smp_query(pi, &lidport, IB_ATTR_PORT_INFO, 0, 100) || + !smp_query(ni, &lidport, IB_ATTR_NODE_INFO, 0, 100)) + return snprintf(str, strlen, ": (unknown node and type)"); + + mad_decode_field(ni, IB_NODE_PORT_GUID_F, &portguid); + mad_decode_field(ni, IB_NODE_TYPE_F, &type); + + mad_decode_field(pi, IB_PORT_LID_F, &baselid); + mad_decode_field(pi, IB_PORT_LMC_F, &lmc); + + if (lmc > 0) { + base_port_lid = baselid; + last_port_lid = baselid + (1 << lmc) - 1; + } + + return snprintf(str, strlen, ": (%s portguid %s: %s)", + mad_dump_val(IB_NODE_TYPE_F, ntype, sizeof ntype, &type), + mad_dump_val(IB_NODE_PORT_GUID_F, sguid, sizeof sguid, &portguid), + mad_dump_val(IB_NODE_DESC_F, desc, sizeof desc, clean_nodedesc(nd))); +} + +char * +dump_unicast_tables(ib_portid_t *portid, int startlid, int endlid) +{ + char lft[IB_SMP_DATA_SIZE]; + char nd[IB_SMP_DATA_SIZE]; + uint8_t sw[IB_SMP_DATA_SIZE]; + char str[200], *s; + uint64_t nodeguid; + int block, i, e, nports, top; + int n = 0, startblock, endblock; + + if ((s = check_switch(portid, &nports, &nodeguid, sw, nd))) + return s; + + mad_decode_field(sw, IB_SW_LINEAR_FDB_TOP_F, &top); + + if (!endlid || endlid > top) + endlid = top; + + if (endlid > IB_MAX_UCAST_LID) { + IBWARN("ilegal lft top %d, truncate to %d", endlid, IB_MAX_UCAST_LID); + endlid = IB_MAX_UCAST_LID; + } + + printf("Unicast lids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 " (%s):\n", + startlid, endlid, portid2str(portid), nodeguid, clean_nodedesc(nd)); + + DEBUG("Switch top is 0x%x\n", top); + + printf(" Lid Out Destination\n"); + printf(" Port Info \n"); + startblock = startlid / IB_SMP_DATA_SIZE; + endblock = ALIGN(endlid, IB_SMP_DATA_SIZE) / IB_SMP_DATA_SIZE; + for (block = startblock; block <= endblock; block++) { + DEBUG("reading block %d", block); + if (!smp_query(lft, portid, IB_ATTR_LINEARFORWTBL, block, 0)) + return "linear forwarding table get failed"; + i = block * IB_SMP_DATA_SIZE; + e = i + IB_SMP_DATA_SIZE; + if (i < startlid) + i = startlid; + if (e > endlid + 1) + e = endlid + 1; + + for (;i < e; i++) { + unsigned outport = lft[i % IB_SMP_DATA_SIZE]; + unsigned valid = (outport <= nports); + + if (!valid && !dump_all) + continue; + dump_lid(str, sizeof str, i, valid); + printf("0x%04x %03u %s\n", i, outport & 0xff, str); + n++; + } + } + + printf("%d %slids dumped \n", n, dump_all ? "" : "valid "); + return 0; +} + +void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug)] -a(ll) -n(o_dests) -v(erbose) -D(irect) -G(uid) -M(ulticast) -s smlid -V(ersion) -C ca_name -P ca_port " + "-t(imeout) timeout_ms] [ [ []]]\n", + basename); + fprintf(stderr, "\n\tUnicast examples:\n"); + fprintf(stderr, "\t\t%s 4\t# dump all lids with valid out ports of switch with lid 4\n", basename); + fprintf(stderr, "\t\t%s -a 4\t# same, but dump all lids, even with invalid out ports\n", basename); + fprintf(stderr, "\t\t%s -n 4\t# simple dump format - no destination resolving\n", basename); + fprintf(stderr, "\t\t%s 4 10\t# dump lids starting from 10\n", basename); + fprintf(stderr, "\t\t%s 4 0x10 0x20\t# dump lid range\n", basename); + fprintf(stderr, "\t\t%s -G 0x08f1040023\t# resolve switch by GUID\n", basename); + fprintf(stderr, "\t\t%s -D 0,1\t# resolve switch by direct path\n", basename); + + fprintf(stderr, "\n\tMulticast examples:\n"); + fprintf(stderr, "\t\t%s -M 4\t# dump all non empty mlids of switch with lid 4\n", basename); + fprintf(stderr, "\t\t%s -M 4 0xc010 0xc020\t# same, but with range\n", basename); + fprintf(stderr, "\t\t%s -M -n 4\t# simple dump format\n", basename); + exit(-1); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + ib_portid_t portid = {0}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + int timeout; + int multicast = 0, startlid = 0, endlid = 0; + char *err; + char *ca = 0; + int ca_port = 0; + + static char const str_opts[] = "C:P:t:s:danvDGMVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "all", 0, 0, 'a'}, + { "no_dests", 0, 0, 'n'}, + { "verbose", 0, 0, 'v'}, + { "Direct", 0, 0, 'D'}, + { "Guid", 0, 0, 'G'}, + { "Multicast", 0, 0, 'M'}, + { "timeout", 1, 0, 't'}, + { "s", 1, 0, 's'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'a': + dump_all++; + break; + case 'd': + ibdebug++; + break; + case 'D': + dest_type = IB_DEST_DRPATH; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 'M': + multicast++; + break; + case 'n': + brief++; + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'v': + madrpc_show_errors(1); + verbose++; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (!argc) + usage(); + + if (argc > 1) + startlid = strtoul(argv[1], 0, 0); + if (argc > 2) + endlid = strtoul(argv[2], 0, 0); + + madrpc_init(ca, ca_port, mgmt_classes, 3); + + if (!argc) { + if (ib_resolve_self(&portid, 0, 0) < 0) + IBERROR("can't resolve self addr"); + } else { + if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[1]); + } + + if (multicast) + err = dump_multicast_tables(&portid, startlid, endlid); + else + err = dump_unicast_tables(&portid, startlid, endlid); + + if (err) + IBERROR("dump tables: %s", err); + + exit(0); +} diff --git a/contrib/ofed/management/infiniband-diags/src/ibsendtrap.c b/contrib/ofed/management/infiniband-diags/src/ibsendtrap.c new file mode 100644 index 000000000000..66620de62e2b --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/ibsendtrap.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2008 Lawrence Livermore National Security + * + * Produced at Lawrence Livermore National Laboratory. + * Written by Ira Weiny . + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include +#include +#include + +#define _GNU_SOURCE +#include + +#include +#include + +#include "ibdiag_common.h" + +char *argv0 = ""; + +static int send_144_node_desc_update(void) +{ + ib_portid_t sm_port; + ib_portid_t selfportid; + int selfport; + ib_rpc_t trap_rpc; + ib_mad_notice_attr_t notice; + + if (ib_resolve_self(&selfportid, &selfport, NULL)) + IBERROR("can't resolve self"); + + if (ib_resolve_smlid(&sm_port, 0)) + IBERROR("can't resolve SM destination port"); + + memset(&trap_rpc, 0, sizeof(trap_rpc)); + trap_rpc.mgtclass = IB_SMI_CLASS; + trap_rpc.method = IB_MAD_METHOD_TRAP; + trap_rpc.trid = mad_trid(); + trap_rpc.attr.id = NOTICE; + trap_rpc.datasz = IB_SMP_DATA_SIZE; + trap_rpc.dataoffs = IB_SMP_DATA_OFFS; + + memset(¬ice, 0, sizeof(notice)); + notice.generic_type = 0x80 | IB_NOTICE_TYPE_INFO; + notice.g_or_v.generic.prod_type_lsb = cl_hton16(IB_NODE_TYPE_CA); + notice.g_or_v.generic.trap_num = cl_hton16(144); + notice.issuer_lid = cl_hton16(selfportid.lid); + notice.data_details.ntc_144.lid = cl_hton16(selfportid.lid); + notice.data_details.ntc_144.local_changes = + TRAP_144_MASK_OTHER_LOCAL_CHANGES; + notice.data_details.ntc_144.change_flgs = + TRAP_144_MASK_NODE_DESCRIPTION_CHANGE; + + return (mad_send(&trap_rpc, &sm_port, NULL, ¬ice)); +} + +typedef struct _trap_def { + char *trap_name; + int (*send_func) (void); +} trap_def_t; + +trap_def_t traps[2] = { + {"node_desc_change", send_144_node_desc_update}, + {NULL, NULL} +}; + +static void usage(void) +{ + int i; + + fprintf(stderr, "Usage: %s [-hV]" + " [-C ] [-P ] []\n", argv0); + fprintf(stderr, " -V print version\n"); + fprintf(stderr, " can be one of the following\n"); + for (i = 0; traps[i].trap_name; i++) { + fprintf(stderr, " %s\n", traps[i].trap_name); + } + fprintf(stderr, " default behavior is to send \"%s\"\n", + traps[0].trap_name); + + exit(-1); +} + +int send_trap(char *trap_name) +{ + int i; + + for (i = 0; traps[i].trap_name; i++) { + if (strcmp(traps[i].trap_name, trap_name) == 0) { + return (traps[i].send_func()); + } + } + usage(); + exit(1); +} + +int main(int argc, char **argv) +{ + int mgmt_classes[2] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS }; + int ch = 0; + char *trap_name = NULL; + char *ca = NULL; + int ca_port = 0; + + static char const str_opts[] = "hVP:C:"; + static const struct option long_opts[] = { + {"Version", 0, 0, 'V'}, + {"P", 1, 0, 'P'}, + {"C", 1, 0, 'C'}, + {"help", 0, 0, 'h'}, + {} + }; + + argv0 = argv[0]; + + while ((ch = getopt_long(argc, argv, str_opts, long_opts, NULL)) != -1) { + switch (ch) { + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version()); + exit(-1); + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, NULL, 0); + break; + case 'h': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (!argv[0]) { + trap_name = traps[0].trap_name; + } else { + trap_name = argv[0]; + } + + madrpc_show_errors(1); + madrpc_init(ca, ca_port, mgmt_classes, 2); + + return (send_trap(trap_name)); +} diff --git a/contrib/ofed/management/infiniband-diags/src/ibstat.c b/contrib/ofed/management/infiniband-diags/src/ibstat.c new file mode 100644 index 000000000000..600a6570a088 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/ibstat.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#define _GNU_SOURCE + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +static int debug; + +char *argv0 = "ibstat"; + +static char *node_type_str[] = { + "???", + "CA", + "Switch", + "Router", + "iWARP RNIC" +}; + +static void +ca_dump(umad_ca_t *ca) +{ + if (!ca->node_type) + return; + printf("%s '%s'\n", ((uint)ca->node_type <= IB_NODE_MAX ? node_type_str[ca->node_type] : "???"), ca->ca_name); + printf("\t%s type: %s\n", ((uint)ca->node_type <= IB_NODE_MAX ? node_type_str[ca->node_type] : "???"),ca->ca_type); + printf("\tNumber of ports: %d\n", ca->numports); + printf("\tFirmware version: %s\n", ca->fw_ver); + printf("\tHardware version: %s\n", ca->hw_ver); + printf("\tNode GUID: 0x%016llx\n", (long long unsigned)ntohll(ca->node_guid)); + printf("\tSystem image GUID: 0x%016llx\n", (long long unsigned)ntohll(ca->system_guid)); +} + +static char *port_state_str[] = { + "???", + "Down", + "Initializing", + "Armed", + "Active" +}; + +static char *port_phy_state_str[] = { + "No state change", + "Sleep", + "Polling", + "Disabled", + "PortConfigurationTraining", + "LinkUp", + "LinkErrorRecovery", + "PhyTest" +}; + +static int +port_dump(umad_port_t *port, int alone) +{ + char *pre = ""; + char *hdrpre = ""; + + if (!port) + return -1; + + if (!alone) { + pre = " "; + hdrpre = " "; + } + + printf("%sPort %d:\n", hdrpre, port->portnum); + printf("%sState: %s\n", pre, (uint)port->state <= 4 ? port_state_str[port->state] : "???"); + printf("%sPhysical state: %s\n", pre, (uint)port->state <= 7 ? port_phy_state_str[port->phys_state] : "???"); + printf("%sRate: %d\n", pre, port->rate); + printf("%sBase lid: %d\n", pre, port->base_lid); + printf("%sLMC: %d\n", pre, port->lmc); + printf("%sSM lid: %d\n", pre, port->sm_lid); + printf("%sCapability mask: 0x%08x\n", pre, (unsigned)ntohl(port->capmask)); + printf("%sPort GUID: 0x%016llx\n", pre, (long long unsigned)ntohll(port->port_guid)); + return 0; +} + +static int +ca_stat(char *ca_name, int portnum, int no_ports) +{ + umad_ca_t ca; + int r; + + if ((r = umad_get_ca(ca_name, &ca)) < 0) + return r; + + if (!ca.node_type) + return 0; + + if (!no_ports && portnum >= 0) { + if (portnum > ca.numports || !ca.ports[portnum]) { + IBWARN("%s: '%s' has no port number %d - max (%d)", + ((uint)ca.node_type <= IB_NODE_MAX ? node_type_str[ca.node_type] : "???"), + ca_name, portnum, ca.numports); + return -1; + } + printf("%s: '%s'\n", ((uint)ca.node_type <= IB_NODE_MAX ? node_type_str[ca.node_type] : "???"), ca.ca_name); + port_dump(ca.ports[portnum], 1); + return 0; + } + + /* print ca header */ + ca_dump(&ca); + + if (no_ports) + return 0; + + for (portnum = 0; portnum <= ca.numports; portnum++) + port_dump(ca.ports[portnum], 0); + + return 0; +} + +static int +ports_list(char names[][UMAD_CA_NAME_LEN], int n) +{ + uint64_t guids[64]; + int found, ports, i; + + for (i = 0, found = 0; i < n && found < 64; i++) { + if ((ports = umad_get_ca_portguids(names[i], guids + found, 64 - found)) < 0) + return -1; + found += ports; + } + + for (i = 0; i < found; i++) + if (guids[i]) + printf("0x%016llx\n", (long long unsigned)ntohll(guids[i])); + return found; +} + +void +usage(void) +{ + fprintf(stderr, "Usage: %s [-d(ebug) -l(ist_of_cas) -s(hort) -p(ort_list) -V(ersion)] [portnum]\n", argv0); + fprintf(stderr, "\tExamples:\n"); + fprintf(stderr, "\t\t%s -l # list all IB devices\n", argv0); + fprintf(stderr, "\t\t%s mthca0 2 # stat port 2 of 'mthca0'\n", argv0); + exit(-1); +} + +int +main(int argc, char *argv[]) +{ + char names[UMAD_MAX_DEVICES][UMAD_CA_NAME_LEN]; + int dev_port = -1; + int list_only = 0, short_format = 0, list_ports = 0; + int n, i; + + static char const str_opts[] = "dlspVhu"; + static const struct option long_opts[] = { + { "debug", 0, 0, 'd'}, + { "list_of_cas", 0, 0, 'l'}, + { "short", 0, 0, 's'}, + { "port_list", 0, 0, 'p'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'd': + debug++; + break; + case 'l': + list_only++; + break; + case 's': + short_format++; + break; + case 'p': + list_ports++; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc > 1) + dev_port = strtol(argv[1], 0, 0); + + if (umad_init() < 0) + IBPANIC("can't init UMAD library"); + + if ((n = umad_get_cas_names(names, UMAD_MAX_DEVICES)) < 0) + IBPANIC("can't list IB device names"); + + if (argc) { + for (i = 0; i < n; i++) + if (!strncmp(names[i], argv[0], sizeof names[i])) + break; + if (i >= n) + IBPANIC("'%s' IB device can't be found", argv[0]); + + strncpy(names[i], argv[0], sizeof names[i]); + n = 1; + } + + if (list_ports) { + if (ports_list(names, n) < 0) + IBPANIC("can't list ports"); + return 0; + } + + if (!list_only && argc) { + if (ca_stat(argv[0], dev_port, short_format) < 0) + IBPANIC("stat of IB device '%s' failed", argv[0]); + return 0; + } + + for (i = 0; i < n; i++) { + if (list_only) + printf("%s\n", names[i]); + else + if (ca_stat(names[i], -1, short_format) < 0) + IBPANIC("stat of IB device '%s' failed", names[i]); + } + + return 0; +} diff --git a/contrib/ofed/management/infiniband-diags/src/ibsysstat.c b/contrib/ofed/management/infiniband-diags/src/ibsysstat.c new file mode 100644 index 000000000000..e3d0b9f0e761 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/ibsysstat.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +#undef DEBUG +#define DEBUG if (verbose) IBWARN + +static int dest_type = IB_DEST_LID; +static int verbose; + +#define MAX_CPUS 8 + +enum ib_sysstat_attr_t { + IB_PING_ATTR = 0x10, + IB_HOSTINFO_ATTR = 0x11, + IB_CPUINFO_ATTR = 0x12, +}; + +typedef struct cpu_info { + char *model; + char *mhz; +} cpu_info; + +static cpu_info cpus[MAX_CPUS]; +static int host_ncpu; + +char *argv0 = "ibsysstat"; + +static void +mk_reply(int attr, void *data, int sz) +{ + char *s = data; + int n, i; + + switch (attr) { + case IB_PING_ATTR: + break; /* nothing to do here, just reply */ + case IB_HOSTINFO_ATTR: + if (gethostname(s, sz) < 0) + snprintf(s, sz, "?hostname?"); + s[sz-1] = 0; + if ((n = strlen(s)) >= sz) + break; + s[n] = '.'; + s += n+1; + sz -= n+1; + if (getdomainname(s, sz) < 0) + snprintf(s, sz, "?domainname?"); + if (strlen(s) == 0) + s[-1] = 0; /* no domain */ + break; + case IB_CPUINFO_ATTR: + for (i = 0; i < host_ncpu && sz > 0; i++) { + n = snprintf(s, sz, "cpu %d: model %s MHZ %s\n", + i, cpus[i].model, cpus[i].mhz); + if (n >= sz) { + IBWARN("cpuinfo truncated"); + break; + } + sz -= n; + s += n; + } + break; + default: + DEBUG("unknown attr %d", attr); + } +} + +static char * +ibsystat_serv(void) +{ + void *umad; + void *mad; + int attr, mod; + + DEBUG("starting to serve..."); + + while ((umad = mad_receive(0, -1))) { + + mad = umad_get_mad(umad); + + attr = mad_get_field(mad, 0, IB_MAD_ATTRID_F); + mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F); + + DEBUG("got packet: attr 0x%x mod 0x%x", attr, mod); + + mk_reply(attr, (char *)mad + IB_VENDOR_RANGE2_DATA_OFFS, IB_VENDOR_RANGE2_DATA_SIZE); + + if (mad_respond(umad, 0, 0) < 0) + DEBUG("respond failed"); + + mad_free(umad); + } + + DEBUG("server out"); + return 0; +} + +static int +match_attr(char *str) +{ + if (!strcmp(str, "ping")) + return IB_PING_ATTR; + if (!strcmp(str, "host")) + return IB_HOSTINFO_ATTR; + if (!strcmp(str, "cpu")) + return IB_CPUINFO_ATTR; + return -1; +} + +static char * +ibsystat(ib_portid_t *portid, int attr) +{ + char data[IB_VENDOR_RANGE2_DATA_SIZE] = {0}; + ib_vendor_call_t call; + + DEBUG("Sysstat ping.."); + + call.method = IB_MAD_METHOD_GET; + call.mgmt_class = IB_VENDOR_OPENIB_SYSSTAT_CLASS; + call.attrid = attr; + call.mod = 0; + call.oui = IB_OPENIB_OUI; + call.timeout = 0; + memset(&call.rmpp, 0, sizeof call.rmpp); + + if (!ib_vendor_call(data, portid, &call)) + return "vendor call failed"; + + DEBUG("Got sysstat pong.."); + if (attr != IB_PING_ATTR) + puts(data); + else + printf("sysstat ping succeeded\n"); + return 0; +} + +int +build_cpuinfo(void) +{ + char line[1024] = {0}, *s, *e; + FILE *f; + int ncpu = 0; + + if (!(f = fopen("/proc/cpuinfo", "r"))) { + IBWARN("couldn't open /proc/cpuinfo"); + return 0; + } + + while (fgets(line, sizeof(line) - 1, f)) { + if (!strncmp(line, "processor\t", 10)) { + ncpu++; + if (ncpu > MAX_CPUS) + return MAX_CPUS; + continue; + } + + if (!ncpu || !(s = strchr(line, ':'))) + continue; + + if ((e = strchr(s, '\n'))) + *e = 0; + if (!strncmp(line, "model name\t", 11)) + cpus[ncpu-1].model = strdup(s+1); + else if (!strncmp(line, "cpu MHz\t", 8)) + cpus[ncpu-1].mhz = strdup(s+1); + } + + fclose(f); + + DEBUG("ncpu %d", ncpu); + + return ncpu; +} + +static void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port " + "-t(imeout) timeout_ms -o oui -S(erver)] []\n", + basename); + exit(-1); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + int sysstat_class = IB_VENDOR_OPENIB_SYSSTAT_CLASS; + ib_portid_t portid = {0}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + int timeout = 0, udebug = 0, server = 0; + int oui = IB_OPENIB_OUI, attr = IB_PING_ATTR; + extern int ibdebug; + char *err; + char *ca = 0; + int ca_port = 0; + + static char const str_opts[] = "C:P:t:s:o:devGSVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "err_show", 0, 0, 'e'}, + { "verbose", 0, 0, 'v'}, + { "Guid", 0, 0, 'G'}, + { "timeout", 1, 0, 't'}, + { "s", 1, 0, 's'}, + { "o", 1, 0, 'o'}, + { "Server", 0, 0, 'S'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'e': + madrpc_show_errors(1); + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 'o': + oui = strtoul(optarg, 0, 0); + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 'S': + server++; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'v': + verbose++; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (!argc && !server) + usage(); + + if (argc > 1 && (attr = match_attr(argv[1])) < 0) + usage(); + + madrpc_init(ca, ca_port, mgmt_classes, 3); + + if (server) { + if (mad_register_server(sysstat_class, 0, 0, oui) < 0) + IBERROR("can't serve class %d", sysstat_class); + + host_ncpu = build_cpuinfo(); + + if ((err = ibsystat_serv())) + IBERROR("ibssystat to %s: %s", portid2str(&portid), err); + exit(0); + } + + if (mad_register_client(sysstat_class, 0) < 0) + IBERROR("can't register to sysstat class %d", sysstat_class); + + if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + + if ((err = ibsystat(&portid, attr))) + IBERROR("ibsystat to %s: %s", portid2str(&portid), err); + + exit(0); +} diff --git a/contrib/ofed/management/infiniband-diags/src/ibtracert.c b/contrib/ofed/management/infiniband-diags/src/ibtracert.c new file mode 100644 index 000000000000..bde0ea795326 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/ibtracert.c @@ -0,0 +1,865 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ibdiag_common.h" + +#define MAXHOPS 63 + +static char *node_type_str[] = { + "???", + "ca", + "switch", + "router", + "iwarp rnic" +}; + +static int timeout = 0; /* ms */ +static int verbose; +static int force; +static FILE *f; + +char *argv0 = "ibtracert"; + +static char *node_name_map_file = NULL; +static nn_map_t *node_name_map = NULL; + +typedef struct Port Port; +typedef struct Switch Switch; +typedef struct Node Node; + +struct Port { + Port *next; + Port *remoteport; + uint64_t portguid; + int portnum; + int lid; + int lmc; + int state; + int physstate; + char portinfo[64]; +}; + +struct Switch { + int linearcap; + int mccap; + int linearFDBtop; + int fdb_base; + int8_t fdb[64]; + char switchinfo[64]; +}; + +struct Node { + Node *htnext; + Node *dnext; + Port *ports; + ib_portid_t path; + int type; + int dist; + int numports; + int upport; + Node *upnode; + uint64_t nodeguid; /* also portguid */ + char nodedesc[64]; + char nodeinfo[64]; +}; + +Node *nodesdist[MAXHOPS]; +uint64_t target_portguid; + +static int +get_node(Node *node, Port *port, ib_portid_t *portid) +{ + void *pi = port->portinfo, *ni = node->nodeinfo, *nd = node->nodedesc; + char *s, *e; + + if (!smp_query(ni, portid, IB_ATTR_NODE_INFO, 0, timeout)) + return -1; + + if (!smp_query(nd, portid, IB_ATTR_NODE_DESC, 0, timeout)) + return -1; + + for (s = nd, e = s + 64; s < e; s++) { + if (!*s) + break; + if (!isprint(*s)) + *s = ' '; + } + + if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, 0, timeout)) + return -1; + + mad_decode_field(ni, IB_NODE_GUID_F, &node->nodeguid); + mad_decode_field(ni, IB_NODE_TYPE_F, &node->type); + mad_decode_field(ni, IB_NODE_NPORTS_F, &node->numports); + + mad_decode_field(ni, IB_NODE_PORT_GUID_F, &port->portguid); + mad_decode_field(ni, IB_NODE_LOCAL_PORT_F, &port->portnum); + mad_decode_field(pi, IB_PORT_LID_F, &port->lid); + mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc); + mad_decode_field(pi, IB_PORT_STATE_F, &port->state); + + DEBUG("portid %s: got node %" PRIx64 " '%s'", portid2str(portid), node->nodeguid, node->nodedesc); + return 0; +} + +static int +switch_lookup(Switch *sw, ib_portid_t *portid, int lid) +{ + void *si = sw->switchinfo, *fdb = sw->fdb; + + if (!smp_query(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout)) + return -1; + + mad_decode_field(si, IB_SW_LINEAR_FDB_CAP_F, &sw->linearcap); + mad_decode_field(si, IB_SW_LINEAR_FDB_TOP_F, &sw->linearFDBtop); + + if (lid > sw->linearcap && lid > sw->linearFDBtop) + return -1; + + if (!smp_query(fdb, portid, IB_ATTR_LINEARFORWTBL, lid / 64, timeout)) + return -1; + + DEBUG("portid %s: forward lid %d to port %d", + portid2str(portid), lid, sw->fdb[lid % 64]); + return sw->fdb[lid % 64]; +} + +static int +sameport(Port *a, Port *b) +{ + return a->portguid == b->portguid || (force && a->lid == b->lid); +} + +static int +extend_dpath(ib_dr_path_t *path, int nextport) +{ + if (path->cnt+2 >= sizeof(path->p)) + return -1; + ++path->cnt; + path->p[path->cnt] = nextport; + return path->cnt; +} + +static void +dump_endnode(int dump, char *prompt, Node *node, Port *port) +{ + char *nodename = NULL; + + if (!dump) + return; + if (dump == 1) { + fprintf(f, "%s {0x%016" PRIx64 "}[%d]\n", + prompt, node->nodeguid, + node->type == IB_NODE_SWITCH ? 0 : port->portnum); + return; + } + + nodename = remap_node_name(node_name_map, node->nodeguid, node->nodedesc); + + fprintf(f, "%s %s {0x%016" PRIx64 "} portnum %d lid %u-%u \"%s\"\n", + prompt, + (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), + node->nodeguid, node->type == IB_NODE_SWITCH ? 0 : port->portnum, + port->lid, port->lid + (1 << port->lmc) - 1, + nodename); + + free(nodename); +} + +static void +dump_route(int dump, Node *node, int outport, Port *port) +{ + char *nodename = NULL; + + if (!dump && !verbose) + return; + + nodename = remap_node_name(node_name_map, node->nodeguid, node->nodedesc); + + if (dump == 1) + fprintf(f, "[%d] -> {0x%016" PRIx64 "}[%d]\n", + outport, port->portguid, port->portnum); + else + fprintf(f, "[%d] -> %s port {0x%016" PRIx64 "}[%d] lid %u-%u \"%s\"\n", + outport, + (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), + port->portguid, port->portnum, + port->lid, port->lid + (1 << port->lmc) - 1, + nodename); + + free(nodename); +} + +static int +find_route(ib_portid_t *from, ib_portid_t *to, int dump) +{ + Node *node, fromnode, tonode, nextnode; + Port *port, fromport, toport, nextport; + Switch sw; + int maxhops = MAXHOPS; + int portnum, outport; + + DEBUG("from %s", portid2str(from)); + + if (get_node(&fromnode, &fromport, from) < 0 || + get_node(&tonode, &toport, to) < 0) { + IBWARN("can't reach to/from ports"); + if (!force) + return -1; + if (to->lid > 0) + toport.lid = to->lid; + IBWARN("Force: look for lid %d", to->lid); + } + + node = &fromnode; + port = &fromport; + portnum = port->portnum; + + dump_endnode(dump, "From", node, port); + + while (maxhops--) { + if (port->state != 4) + goto badport; + + if (sameport(port, &toport)) + break; /* found */ + + outport = portnum; + if (node->type == IB_NODE_SWITCH) { + DEBUG("switch node"); + if ((outport = switch_lookup(&sw, from, to->lid)) < 0 || + outport > node->numports) + goto badtbl; + + if (extend_dpath(&from->drpath, outport) < 0) + goto badpath; + + if (get_node(&nextnode, &nextport, from) < 0) { + IBWARN("can't reach port at %s", portid2str(from)); + return -1; + } + if (outport == 0) { + if (!sameport(&nextport, &toport)) + goto badtbl; + else + break; /* found SMA port */ + } + } else if ((node->type == IB_NODE_CA) || + (node->type == IB_NODE_ROUTER)) { + int ca_src = 0; + + DEBUG("ca or router node"); + if (!sameport(port, &fromport)) { + IBWARN("can't continue: reached CA or router port %" PRIx64 ", lid %d", + port->portguid, port->lid); + return -1; + } + /* we are at CA or router "from" - go one hop back to (hopefully) a switch */ + if (from->drpath.cnt > 0) { + DEBUG("ca or router node - return back 1 hop"); + from->drpath.cnt--; + } else { + ca_src = 1; + if (portnum && extend_dpath(&from->drpath, portnum) < 0) + goto badpath; + } + if (get_node(&nextnode, &nextport, from) < 0) { + IBWARN("can't reach port at %s", portid2str(from)); + return -1; + } + /* fix port num to be seen from the CA or router side */ + if (!ca_src) + nextport.portnum = from->drpath.p[from->drpath.cnt+1]; + } + port = &nextport; + if (port->state != 4) + goto badoutport; + node = &nextnode; + portnum = port->portnum; + dump_route(dump, node, outport, port); + } + + if (maxhops <= 0) { + IBWARN("no route found after %d hops", MAXHOPS); + return -1; + } + dump_endnode(dump, "To", node, port); + return 0; + +badport: + IBWARN("Bad port state found: node \"%s\" port %d state %d", + clean_nodedesc(node->nodedesc), portnum, port->state); + return -1; +badoutport: + IBWARN("Bad out port state found: node \"%s\" outport %d state %d", + clean_nodedesc(node->nodedesc), outport, port->state); + return -1; +badtbl: + IBWARN("Bad forwarding table entry found at: node \"%s\" lid entry %d is %d (top %d)", + clean_nodedesc(node->nodedesc), to->lid, outport, sw.linearFDBtop); + return -1; +badpath: + IBWARN("Direct path too long!"); + return -1; +} + + +/************************** + * MC span part + */ + +#define HASHGUID(guid) ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103))) +#define HTSZ 137 + +static int +insert_node(Node *new) +{ + static Node *nodestbl[HTSZ]; + int hash = HASHGUID(new->nodeguid) % HTSZ; + Node *node ; + + for (node = nodestbl[hash]; node; node = node->htnext) + if (node->nodeguid == new->nodeguid) { + DEBUG("node %" PRIx64 " already exists", new->nodeguid); + return -1; + } + + new->htnext = nodestbl[hash]; + nodestbl[hash] = new; + + return 0; +} + +static int +get_port(Port *port, int portnum, ib_portid_t *portid) +{ + char portinfo[64]; + void *pi = portinfo; + + port->portnum = portnum; + + if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout)) + return -1; + + mad_decode_field(pi, IB_PORT_LID_F, &port->lid); + mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc); + mad_decode_field(pi, IB_PORT_STATE_F, &port->state); + mad_decode_field(pi, IB_PORT_PHYS_STATE_F, &port->physstate); + + VERBOSE("portid %s portnum %d: lid %d state %d physstate %d", + portid2str(portid), portnum, port->lid, port->state, port->physstate); + return 1; +} + +static void +link_port(Port *port, Node *node) +{ + port->next = node->ports; + node->ports = port; +} + +static int +new_node(Node *node, Port *port, ib_portid_t *path, int dist) +{ + if (port->portguid == target_portguid) { + node->dist = -1; /* tag as target */ + link_port(port, node); + dump_endnode(verbose, "found target", node, port); + return 1; /* found; */ + } + + /* BFS search start with my self */ + if (insert_node(node) < 0) + return -1; /* known switch */ + + VERBOSE("insert dist %d node %p port %d lid %d", dist, node, port->portnum, port->lid); + + link_port(port, node); + + node->dist = dist; + node->path = *path; + node->dnext = nodesdist[dist]; + nodesdist[dist] = node; + + return 0; +} + +static int +switch_mclookup(Node *node, ib_portid_t *portid, int mlid, char *map) +{ + Switch sw; + char mdb[64]; + void *si = sw.switchinfo; + uint16_t *msets = (uint16_t *)mdb; + int maxsets, block, i, set; + + memset(map, 0, 256); + + if (!smp_query(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout)) + return -1; + + mlid -= 0xc000; + + mad_decode_field(si, IB_SW_MCAST_FDB_CAP_F, &sw.mccap); + + if (mlid > sw.mccap) + return -1; + + block = mlid / 32; + maxsets = (node->numports + 15) / 16; /* round up */ + + for (set = 0; set < maxsets; set++) { + if (!smp_query(mdb, portid, IB_ATTR_MULTICASTFORWTBL, + block | (set << 28), timeout)) + return -1; + + for (i = 0; i < 16; i++, map++) { + uint16_t mask = ntohs(msets[mlid % 32]); + if (mask & (1 << i)) + *map = 1; + else + continue; + VERBOSE("Switch guid 0x%" PRIx64 ": mlid 0x%x is forwarded to port %d", + node->nodeguid, mlid + 0xc000, i + set * 16); + } + } + + return 0; +} + +/* + * Return 1 if found, 0 if not, -1 on errors. + */ +static Node * +find_mcpath(ib_portid_t *from, int mlid) +{ + Node *node, *remotenode; + Port *port, *remoteport; + char map[256]; + int r, i; + int dist = 0, leafport = 0; + ib_portid_t *path; + + DEBUG("from %s", portid2str(from)); + + if (!(node = calloc(1, sizeof(Node)))) + IBERROR("out of memory"); + + if (!(port = calloc(1, sizeof(Port)))) + IBERROR("out of memory"); + + if (get_node(node, port, from) < 0) { + IBWARN("can't reach node %s", portid2str(from)); + return 0; + } + + node->upnode = 0; /* root */ + if ((r = new_node(node, port, from, 0)) > 0) { + if (node->type != IB_NODE_SWITCH) { + IBWARN("ibtracert from CA to CA is unsupported"); + return 0; /* ibtracert from host to itself is unsupported */ + } + + if (switch_mclookup(node, from, mlid, map) < 0 || + !map[0]) + return 0; + return node; + } + + for (dist = 0; dist < MAXHOPS; dist++) { + + for (node = nodesdist[dist]; node; node = node->dnext) { + + path = &node->path; + + VERBOSE("dist %d node %p", dist, node); + dump_endnode(verbose, "processing", node, node->ports); + + memset(map, 0, sizeof(map)); + + if (node->type != IB_NODE_SWITCH) { + if (dist) + continue; + leafport = path->drpath.p[path->drpath.cnt]; + map[port->portnum] = 1; + node->upport = 0; /* starting here */ + DEBUG("Starting from CA 0x%" PRIx64 " lid %d port %d (leafport %d)", + node->nodeguid, port->lid, port->portnum, leafport); + } else { /* switch */ + + /* if starting from a leaf port fix up port (up port) */ + if (dist == 1 && leafport) + node->upport = leafport; + + if (switch_mclookup(node, path, mlid, map) < 0) { + IBWARN("skipping bad Switch 0x%" PRIx64 "", + node->nodeguid); + continue; + } + } + + for (i = 1; i <= node->numports; i++) { + if (!map[i] || i == node->upport) + continue; + + if (dist == 0 && leafport) { + if (from->drpath.cnt > 0) + path->drpath.cnt--; + } else { + if (!(port = calloc(1, sizeof(Port)))) + IBERROR("out of memory"); + + if (get_port(port, i, path) < 0) { + IBWARN("can't reach node %s port %d", portid2str(path), i); + return 0; + } + + if (port->physstate != 5) { /* LinkUP */ + free(port); + continue; + } + +#if 0 + link_port(port, node); +#endif + + if (extend_dpath(&path->drpath, i) < 0) + return 0; + } + + if (!(remotenode = calloc(1, sizeof(Node)))) + IBERROR("out of memory"); + + if (!(remoteport = calloc(1, sizeof(Port)))) + IBERROR("out of memory"); + + if (get_node(remotenode, remoteport, path) < 0) { + IBWARN("NodeInfo on %s port %d failed, skipping port", + portid2str(path), i); + path->drpath.cnt--; /* restore path */ + free(remotenode); + free(remoteport); + continue; + } + + remotenode->upnode = node; + remotenode->upport = remoteport->portnum; + remoteport->remoteport = port; + + if ((r = new_node(remotenode, remoteport, path, dist+1)) > 0) + return remotenode; + + if (r == 0) + dump_endnode(verbose, "new remote", + remotenode, remoteport); + else if (remotenode->type == IB_NODE_SWITCH) + dump_endnode(2, "ERR: circle discovered at", + remotenode, remoteport); + + path->drpath.cnt--; /* restore path */ + } + } + } + + return 0; /* not found */ +} + +static uint64_t +find_target_portguid(ib_portid_t *to) +{ + Node tonode; + Port toport; + + if (get_node(&tonode, &toport, to) < 0) { + IBWARN("can't find to port\n"); + return -1; + } + + return toport.portguid; +} + +static void +dump_mcpath(Node *node, int dumplevel) +{ + char *nodename = NULL; + + if (node->upnode) + dump_mcpath(node->upnode, dumplevel); + + nodename = remap_node_name(node_name_map, node->nodeguid, node->nodedesc); + + if (!node->dist) { + printf("From %s 0x%" PRIx64 " port %d lid %u-%u \"%s\"\n", + (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), + node->nodeguid, node->ports->portnum, node->ports->lid, + node->ports->lid + (1 << node->ports->lmc) - 1, + nodename); + goto free_name; + } + + if (node->dist) { + if (dumplevel == 1) + printf("[%d] -> %s {0x%016" PRIx64 "}[%d]\n", + node->ports->remoteport->portnum, + (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), + node->nodeguid, node->upport); + else + printf("[%d] -> %s 0x%" PRIx64 "[%d] lid %u \"%s\"\n", + node->ports->remoteport->portnum, + (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), + node->nodeguid, node->upport, + node->ports->lid, nodename); + } + + if (node->dist < 0) + /* target node */ + printf("To %s 0x%" PRIx64 " port %d lid %u-%u \"%s\"\n", + (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), + node->nodeguid, node->ports->portnum, node->ports->lid, + node->ports->lid + (1 << node->ports->lmc) - 1, + nodename); + +free_name: + free(nodename); +} + +static int resolve_lid(ib_portid_t *portid, const void *srcport) +{ + uint8_t portinfo[64]; + uint16_t lid; + + if (!smp_query_via(portinfo, portid, IB_ATTR_PORT_INFO, 0, 0, srcport)) + return -1; + mad_decode_field(portinfo, IB_PORT_LID_F, &lid); + + ib_portid_set(portid, lid, 0, 0); + + return 0; +} + +static void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -v(erbose) -D(irect) -G(uids) -n(o_info) -C ca_name -P ca_port " + "-s smlid -t(imeout) timeout_ms -m mlid --node-name-map node-name-map ] \n", + basename); + fprintf(stderr, "\n\tUnicast examples:\n"); + fprintf(stderr, "\t\t%s 4 16\t\t\t# show path between lids 4 and 16\n", basename); + fprintf(stderr, "\t\t%s -n 4 16\t\t# same, but using simple output format\n", basename); + fprintf(stderr, "\t\t%s -G 0x8f1040396522d 0x002c9000100d051\t# use guid addresses\n", basename); + + fprintf(stderr, "\n\tMulticast example:\n"); + fprintf(stderr, "\t\t%s -m 0xc000 4 16\t# show multicast path of mlid 0xc000 between lids 4 and 16\n", basename); + exit(-1); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + ib_portid_t my_portid = {0}; + ib_portid_t src_portid = {0}; + ib_portid_t dest_portid = {0}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + int dumplevel = 2, dest_type = IB_DEST_LID, multicast = 0, mlid = 0; + Node *endnode; + int udebug = 0; + char *ca = 0; + int ca_port = 0; + + static char const str_opts[] = "C:P:t:s:m:dvfDGnVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "verbose", 0, 0, 'v'}, + { "force", 0, 0, 'f'}, + { "Direct", 0, 0, 'D'}, + { "Guids", 0, 0, 'G'}, + { "no_info", 0, 0, 'n'}, + { "timeout", 1, 0, 't'}, + { "s", 1, 0, 's'}, + { "m", 1, 0, 'm'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { "node-name-map", 1, 0, 1}, + { } + }; + + argv0 = argv[0]; + + f = stdout; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 1: + node_name_map_file = strdup(optarg); + break; + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'D': + dest_type = IB_DEST_DRPATH; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 'm': + multicast++; + mlid = strtoul(optarg, 0, 0); + break; + case 'f': + force++; + break; + case 'n': + dumplevel = 1; + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'v': + madrpc_show_errors(1); + verbose++; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc < 2) + usage(); + + madrpc_init(ca, ca_port, mgmt_classes, 3); + node_name_map = open_node_name_map(node_name_map_file); + + if (ib_resolve_portid_str(&src_portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve source port %s", argv[0]); + + if (ib_resolve_portid_str(&dest_portid, argv[1], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[1]); + + if (dest_type == IB_DEST_DRPATH) { + if (resolve_lid(&src_portid, NULL) < 0) + IBERROR("cannot resolve lid for port \'%s\'", + portid2str(&src_portid)); + if (resolve_lid(&dest_portid, NULL) < 0) + IBERROR("cannot resolve lid for port \'%s\'", + portid2str(&dest_portid)); + } + + if (dest_portid.lid == 0 || src_portid.lid == 0) { + IBWARN("bad src/dest lid"); + usage(); + } + + if (dest_type != IB_DEST_DRPATH) { + /* first find a direct path to the src port */ + if (find_route(&my_portid, &src_portid, 0) < 0) + IBERROR("can't find a route to the src port"); + + src_portid = my_portid; + } + + if (!multicast) { + if (find_route(&src_portid, &dest_portid, dumplevel) < 0) + IBERROR("can't find a route from src to dest"); + exit(0); + } else { + if (mlid < 0xc000) + IBWARN("invalid MLID; must be 0xc000 or larger"); + } + + if (!(target_portguid = find_target_portguid(&dest_portid))) + IBERROR("can't reach target lid %d", dest_portid.lid); + + if (!(endnode = find_mcpath(&src_portid, mlid))) + IBERROR("can't find a multicast route from src to dest"); + + /* dump multicast path */ + dump_mcpath(endnode, dumplevel); + + close_node_name_map(node_name_map); + exit(0); +} diff --git a/contrib/ofed/management/infiniband-diags/src/mcm_rereg_test.c b/contrib/ofed/management/infiniband-diags/src/mcm_rereg_test.c new file mode 100644 index 000000000000..9285b95aabb3 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/mcm_rereg_test.c @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2006 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include +#include +#include + +#include +#include + +#define info(fmt, arg...) fprintf(stderr, "INFO: " fmt, ##arg ) +#define err(fmt, arg...) fprintf(stderr, "ERR: " fmt, ##arg ) +#ifdef NOISY_DEBUG +#define dbg(fmt, arg...) fprintf(stderr, "DBG: " fmt, ##arg ) +#else +#define dbg(fmt, arg...) +#endif + +#define TMO 100 + +/* Multicast Member Record Component Masks */ +#define IB_MCR_COMPMASK_MGID (1ULL<<0) +#define IB_MCR_COMPMASK_PORT_GID (1ULL<<1) +#define IB_MCR_COMPMASK_QKEY (1ULL<<2) +#define IB_MCR_COMPMASK_MLID (1ULL<<3) +#define IB_MCR_COMPMASK_MTU_SEL (1ULL<<4) +#define IB_MCR_COMPMASK_MTU (1ULL<<5) +#define IB_MCR_COMPMASK_TCLASS (1ULL<<6) +#define IB_MCR_COMPMASK_PKEY (1ULL<<7) +#define IB_MCR_COMPMASK_RATE_SEL (1ULL<<8) +#define IB_MCR_COMPMASK_RATE (1ULL<<9) +#define IB_MCR_COMPMASK_LIFE_SEL (1ULL<<10) +#define IB_MCR_COMPMASK_LIFE (1ULL<<11) +#define IB_MCR_COMPMASK_SL (1ULL<<12) +#define IB_MCR_COMPMASK_FLOW (1ULL<<13) +#define IB_MCR_COMPMASK_HOP (1ULL<<14) +#define IB_MCR_COMPMASK_SCOPE (1ULL<<15) +#define IB_MCR_COMPMASK_JOIN_STATE (1ULL<<16) +#define IB_MCR_COMPMASK_PROXY (1ULL<<17) + +static ibmad_gid_t mgid_ipoib = { + 0xff, 0x12, 0x40, 0x1b, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff +}; + +uint64_t build_mcm_rec(uint8_t *data, ibmad_gid_t mgid, ibmad_gid_t port_gid) +{ + memset(data, 0, IB_SA_DATA_SIZE); + mad_set_array(data, 0, IB_SA_MCM_MGID_F, mgid); + mad_set_array(data, 0, IB_SA_MCM_PORTGID_F, port_gid); + mad_set_field(data, 0, IB_SA_MCM_JOIN_STATE_F, 1); + + return IB_MCR_COMPMASK_MGID|IB_MCR_COMPMASK_PORT_GID| + IB_MCR_COMPMASK_JOIN_STATE; +} + +static void build_mcm_rec_umad(void *umad, ib_portid_t *dport, int method, + uint64_t comp_mask, uint8_t *data) +{ + ib_rpc_t rpc; + + memset(&rpc, 0, sizeof(rpc)); + rpc.mgtclass = IB_SA_CLASS; + rpc.method = method; + rpc.attr.id = IB_SA_ATTR_MCRECORD; + rpc.attr.mod = 0; // ??? + rpc.mask = comp_mask; + rpc.datasz = IB_SA_DATA_SIZE; + rpc.dataoffs = IB_SA_DATA_OFFS; + + mad_build_pkt(umad, &rpc, dport, NULL, data); +} + +static int rereg_send(int port, int agent, ib_portid_t *dport, + uint8_t *umad, int len, int method, ibmad_gid_t port_gid) +{ + uint8_t data[IB_SA_DATA_SIZE]; + uint64_t comp_mask; + + comp_mask = build_mcm_rec(data, mgid_ipoib, port_gid); + + build_mcm_rec_umad(umad, dport, method, comp_mask, data); + if(umad_send(port, agent, umad, len, TMO, 0) < 0) { + err("umad_send leave failed: %s\n", strerror(errno)); + return -1; + } + dbg("umad_send %d: tid = 0x%016" PRIx64 "\n", method, + mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F)); + + return 0; +} + +static int rereg_port_gid(int port, int agent, ib_portid_t *dport, + uint8_t *umad, int len, ibmad_gid_t port_gid) +{ + uint8_t data[IB_SA_DATA_SIZE]; + uint64_t comp_mask; + + comp_mask = build_mcm_rec(data, mgid_ipoib, port_gid); + + build_mcm_rec_umad(umad, dport, IB_MAD_METHOD_DELETE, + comp_mask, data); + if(umad_send(port, agent, umad, len, TMO, 0) < 0) { + err("umad_send leave failed: %s\n", strerror(errno)); + return -1; + } + dbg("umad_send leave: tid = 0x%016" PRIx64 "\n", + mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F)); + + build_mcm_rec_umad(umad, dport, IB_MAD_METHOD_SET, + comp_mask, data); + if(umad_send(port, agent, umad, len, TMO, 0) < 0) { + err("umad_send join failed: %s\n", strerror(errno)); + return -1; + } + dbg("umad_send join: tid = 0x%016" PRIx64 "\n", + mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F)); + + return 0; +} + +struct guid_trid { + ibmad_gid_t gid; + uint64_t guid; + uint64_t trid; +}; + +static int rereg_send_all(int port, int agent, ib_portid_t *dport, + struct guid_trid *list, unsigned cnt) +{ + uint8_t *umad; + int len = umad_size() + 256; + int i, ret; + + info("rereg_send_all... cnt = %u\n", cnt); + + umad = calloc(1, len); + if (!umad) { + err("cannot alloc mem for umad: %s\n", strerror(errno)); + return -1; + } + + for (i = 0; i < cnt; i++) { + ret = rereg_port_gid(port, agent, dport, umad, len, list[i].gid); + if (ret < 0) { + err("rereg_send_all: rereg_port_gid 0x%016" PRIx64 + " failed\n", list[i].guid); + continue; + } + list[i].trid = mad_get_field64(umad_get_mad(umad), 0, + IB_MAD_TRID_F); + } + + info("rereg_send_all: sent %u requests\n", cnt*2); + + free(umad); + + return 0; +} + +#if 0 +static int rereg_mcm_rec_send(int port, int agent, ib_portid_t *dport, int cnt) +{ + ib_portid_t portid; + ibmad_gid_t port_gid; + uint8_t *umad; + int len, ret = 0; + + ib_resolve_self(&portid, NULL, &port_gid); + + len = umad_size() + 256; + umad = calloc(1, len); + if (!umad) { + err("cannot alloc mem for umad: %s\n", strerror(errno)); + return -1; + } + + while(cnt--) { + if (!rereg_port_gid(port, agent, dport, umad, len, port_gid)) + ret += 2; + } + + free(umad); + + return ret; +} +#endif + +static int rereg_recv(int port, int agent, ib_portid_t *dport, + uint8_t *umad, int length, int tmo) +{ + int ret, retry = 0; + int len = length; + + while((ret = umad_recv(port, umad, &len, tmo)) < 0 && + errno == ETIMEDOUT) { + if (retry++ > 3) + return 0; + } + if (ret < 0) { + err("umad_recv %d failed: %s\n", ret, strerror(errno)); + return -1; + } + dbg("umad_recv (retries %d), tid = 0x%016" PRIx64 ": len = %d, status = %d\n", + retry, + mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F), + len, umad_status(umad)); + + return 1; +} + +static int rereg_recv_all(int port, int agent, ib_portid_t *dport, + struct guid_trid *list, unsigned cnt) +{ + uint8_t *umad, *mad; + int len = umad_size() + 256; + uint64_t trid; + unsigned n, method, status; + int i; + + info("rereg_recv_all...\n"); + + umad = calloc(1, len); + if (!umad) { + err("cannot alloc mem for umad: %s\n", strerror(errno)); + return -1; + } + + n = 0; + while (rereg_recv(port, agent, dport, umad, len, TMO) > 0) { + dbg("rereg_recv_all: done %d\n", n); + n++; + mad = umad_get_mad(umad); + + method = mad_get_field(mad, 0, IB_MAD_METHOD_F); + status = mad_get_field(mad, 0, IB_MAD_STATUS_F); + + if (status) + dbg("MAD status %x, method %x\n", status, method); + + if (status && + (method&0x7f) == (IB_MAD_METHOD_GET_RESPONSE&0x7f)) { + trid = mad_get_field64(mad, 0, IB_MAD_TRID_F); + for (i = 0; i < cnt; i++) + if (trid == list[i].trid) + break; + if (i == cnt) { + err("cannot find trid 0x%016" PRIx64 "\n", + trid); + continue; + } + info("guid 0x%016" PRIx64 ": method = %x status = %x. Resending\n", + ntohll(list[i].guid), method, status); + rereg_port_gid(port, agent, dport, umad, len, + list[i].gid); + list[i].trid = mad_get_field64(umad_get_mad(umad), 0, + IB_MAD_TRID_F); + } + } + + info("rereg_recv_all: got %u responses\n", n); + + free(umad); + return 0; +} + +static int rereg_query_all(int port, int agent, ib_portid_t *dport, + struct guid_trid *list, unsigned cnt) +{ + uint8_t *umad, *mad; + int len = umad_size() + 256; + unsigned method, status; + int i, ret; + + info("rereg_query_all...\n"); + + umad = calloc(1, len); + if (!umad) { + err("cannot alloc mem for umad: %s\n", strerror(errno)); + return -1; + } + + for ( i = 0; i < cnt; i++ ) { + ret = rereg_send(port, agent, dport, umad, len, + IB_MAD_METHOD_GET, list[i].gid); + if (ret < 0) { + err("query_all: rereg_send failed.\n"); + continue; + } + + ret = rereg_recv(port, agent, dport, umad, len, TMO); + if (ret < 0) { + err("query_all: rereg_recv failed.\n"); + continue; + } + + mad = umad_get_mad(umad); + + method = mad_get_field(mad, 0, IB_MAD_METHOD_F); + status = mad_get_field(mad, 0, IB_MAD_STATUS_F); + + if (status) + info("guid 0x%016" PRIx64 ": status %x, method %x\n", + ntohll(list[i].guid), status, method); + } + + info("rereg_query_all: %u queried.\n", cnt); + + free(umad); + return 0; +} + +#if 0 +static int rereg_mcm_rec_recv(int port, int agent, int cnt) +{ + uint8_t *umad, *mad; + int len = umad_size() + 256; + int i; + + umad = calloc(1, len); + if (!umad) { + err("cannot alloc mem for umad: %s\n", strerror(errno)); + return -1; + } + + for ( i = 0; i < cnt; i++ ) { + int retry; + retry = 0; + while (umad_recv(port, umad, &len, TMO) < 0 && + errno == ETIMEDOUT) + if (retry++ > 3) { + err("umad_recv %d failed: %s\n", + i, strerror(errno)); + free(umad); + return -1; + } + dbg("umad_recv %d (retries %d), tid = 0x%016" PRIx64 ": len = %d, status = %d\n", + i, retry, + mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F), + len, umad_status(umad)); + mad = umad_get_mad(umad); + } + + free(umad); + return 0; +} +#endif + +#define MAX_CLIENTS 50 + +static int rereg_and_test_port(char *guid_file, int port, int agent, ib_portid_t *dport, int timeout) +{ + char line[256]; + FILE *f; + ibmad_gid_t port_gid; + uint64_t prefix = htonll(0xfe80000000000000llu); + uint64_t guid = htonll(0x0002c90200223825llu); + struct guid_trid *list; + int i = 0; + + list = calloc(MAX_CLIENTS, sizeof(*list)); + if (!list) { + err("cannot alloc mem for guid/trid list: %s\n", strerror(errno)); + return -1; + } + + f = fopen(guid_file, "r"); + if (!f) { + err("cannot open %s: %s\n", guid_file, strerror(errno)); + return -1; + } + + while (fgets(line, sizeof(line), f)) { + guid = strtoull(line, NULL, 0); + guid = htonll(guid); + memcpy(&port_gid[0], &prefix, 8); + memcpy(&port_gid[8], &guid, 8); + + list[i].guid = guid; + memcpy(list[i].gid, port_gid, sizeof(list[i].gid)); + list[i].trid = 0; + if (++i >= MAX_CLIENTS) + break; + } + fclose(f); + + rereg_send_all(port, agent, dport, list, i); + rereg_recv_all(port, agent, dport, list, i); + + rereg_query_all(port, agent, dport, list, i); + + free(list); + return 0; +} + +int main(int argc, char **argv) +{ + char *guid_file = "port_guids.list"; + int mgmt_classes[2] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS}; + ib_portid_t dport_id; + int port, agent; + uint8_t *umad, *mad; + int len; + + if (argc > 1) + guid_file = argv[1]; + + madrpc_init(NULL, 0, mgmt_classes, 2); + +#if 1 + ib_resolve_smlid(&dport_id, TMO); +#else + memset(&dport_id, 0, sizeof(dport_id)); + dport_id.lid = 1; +#endif + dport_id.qp = 1; + if (!dport_id.qkey) + dport_id.qkey = IB_DEFAULT_QP1_QKEY; + + + len = umad_size() + 256; + umad = calloc(1, len); + if (!umad) { + err("cannot alloc mem for umad: %s\n", strerror(errno)); + return -1; + } + +#if 1 + port = madrpc_portid(); +#else + ret = umad_init(); + + port = umad_open_port(NULL, 0); + if (port < 0) { + err("umad_open_port failed: %s\n", strerror(errno)); + return port; + } +#endif + + agent = umad_register(port, IB_SA_CLASS, 2, 0, NULL); + +#if 0 + int cnt; + cnt = rereg_mcm_rec_send(port, agent, &dport_id, cnt); + + rereg_recv_all(port, agent, &dport_id); +#else + rereg_and_test_port(guid_file, port, agent, &dport_id, TMO); +#endif + mad = umad_get_mad(umad); + + free(umad); + umad_unregister(port, agent); + umad_close_port(port); + umad_done(); + + return 0; +} diff --git a/contrib/ofed/management/infiniband-diags/src/perfquery.c b/contrib/ofed/management/infiniband-diags/src/perfquery.c new file mode 100644 index 000000000000..7a53e9256e49 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/perfquery.c @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +struct perf_count { + uint32_t portselect; + uint32_t counterselect; + uint32_t symbolerrors; + uint32_t linkrecovers; + uint32_t linkdowned; + uint32_t rcverrors; + uint32_t rcvremotephyerrors; + uint32_t rcvswrelayerrors; + uint32_t xmtdiscards; + uint32_t xmtconstrainterrors; + uint32_t rcvconstrainterrors; + uint32_t linkintegrityerrors; + uint32_t excbufoverrunerrors; + uint32_t vl15dropped; + uint32_t xmtdata; + uint32_t rcvdata; + uint32_t xmtpkts; + uint32_t rcvpkts; +}; + +struct perf_count_ext { + uint32_t portselect; + uint32_t counterselect; + uint64_t portxmitdata; + uint64_t portrcvdata; + uint64_t portxmitpkts; + uint64_t portrcvpkts; + uint64_t portunicastxmitpkts; + uint64_t portunicastrcvpkts; + uint64_t portmulticastxmitpkits; + uint64_t portmulticastrcvpkts; +}; + +static uint8_t pc[1024]; + +struct perf_count perf_count = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +struct perf_count_ext perf_count_ext = {0,0,0,0,0,0,0,0,0,0}; + +char *argv0 = "perfquery"; + +#define ALL_PORTS 0xFF + +static void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -G(uid) -a(ll_ports) -l(oop_ports) -r(eset_after_read) -C ca_name -P ca_port " + "-R(eset_only) -t(imeout) timeout_ms -V(ersion) -h(elp)] [ [[port] [reset_mask]]]\n", + basename); + fprintf(stderr, "\tExamples:\n"); + fprintf(stderr, "\t\t%s\t\t# read local port's performance counters\n", basename); + fprintf(stderr, "\t\t%s 32 1\t\t# read performance counters from lid 32, port 1\n", basename); + fprintf(stderr, "\t\t%s -e 32 1\t# read extended performance counters from lid 32, port 1\n", basename); + fprintf(stderr, "\t\t%s -a 32\t\t# read performance counters from lid 32, all ports\n", basename); + fprintf(stderr, "\t\t%s -r 32 1\t# read performance counters and reset\n", basename); + fprintf(stderr, "\t\t%s -e -r 32 1\t# read extended performance counters and reset\n", basename); + fprintf(stderr, "\t\t%s -R 0x20 1\t# reset performance counters of port 1 only\n", basename); + fprintf(stderr, "\t\t%s -e -R 0x20 1\t# reset extended performance counters of port 1 only\n", basename); + fprintf(stderr, "\t\t%s -R -a 32\t# reset performance counters of all ports\n", basename); + fprintf(stderr, "\t\t%s -R 32 2 0x0fff\t# reset only error counters of port 2\n", basename); + fprintf(stderr, "\t\t%s -R 32 2 0xf000\t# reset only non-error counters of port 2\n", basename); + exit(-1); +} + +/* Notes: IB semantics is to cap counters if count has exceeded limits. + * Therefore we must check for overflows and cap the counters if necessary. + * + * mad_decode_field and mad_encode_field assume 32 bit integers passed in + * for fields < 32 bits in length. + */ + +static void aggregate_4bit(uint32_t *dest, uint32_t val) +{ + if ((((*dest) + val) < (*dest)) + || ((*dest) + val) > 0xf) + (*dest) = 0xf; + else + (*dest) = (*dest) + val; +} + +static void aggregate_8bit(uint32_t *dest, uint32_t val) +{ + if ((((*dest) + val) < (*dest)) + || ((*dest) + val) > 0xff) + (*dest) = 0xff; + else + (*dest) = (*dest) + val; +} + +static void aggregate_16bit(uint32_t *dest, uint32_t val) +{ + if ((((*dest) + val) < (*dest)) + || ((*dest) + val) > 0xffff) + (*dest) = 0xffff; + else + (*dest) = (*dest) + val; +} + +static void aggregate_32bit(uint32_t *dest, uint32_t val) +{ + if (((*dest) + val) < (*dest)) + (*dest) = 0xffffffff; + else + (*dest) = (*dest) + val; +} + +static void aggregate_64bit(uint64_t *dest, uint64_t val) +{ + if (((*dest) + val) < (*dest)) + (*dest) = 0xffffffffffffffffULL; + else + (*dest) = (*dest) + val; +} + +static void aggregate_perfcounters(void) +{ + uint32_t val; + + mad_decode_field(pc, IB_PC_PORT_SELECT_F, &val); + perf_count.portselect = val; + mad_decode_field(pc, IB_PC_COUNTER_SELECT_F, &val); + perf_count.counterselect = val; + mad_decode_field(pc, IB_PC_ERR_SYM_F, &val); + aggregate_16bit(&perf_count.symbolerrors, val); + mad_decode_field(pc, IB_PC_LINK_RECOVERS_F, &val); + aggregate_8bit(&perf_count.linkrecovers, val); + mad_decode_field(pc, IB_PC_LINK_DOWNED_F, &val); + aggregate_8bit(&perf_count.linkdowned, val); + mad_decode_field(pc, IB_PC_ERR_RCV_F, &val); + aggregate_16bit(&perf_count.rcverrors, val); + mad_decode_field(pc, IB_PC_ERR_PHYSRCV_F, &val); + aggregate_16bit(&perf_count.rcvremotephyerrors, val); + mad_decode_field(pc, IB_PC_ERR_SWITCH_REL_F, &val); + aggregate_16bit(&perf_count.rcvswrelayerrors, val); + mad_decode_field(pc, IB_PC_XMT_DISCARDS_F, &val); + aggregate_16bit(&perf_count.xmtdiscards, val); + mad_decode_field(pc, IB_PC_ERR_XMTCONSTR_F, &val); + aggregate_8bit(&perf_count.xmtconstrainterrors, val); + mad_decode_field(pc, IB_PC_ERR_RCVCONSTR_F, &val); + aggregate_8bit(&perf_count.rcvconstrainterrors, val); + mad_decode_field(pc, IB_PC_ERR_LOCALINTEG_F, &val); + aggregate_4bit(&perf_count.linkintegrityerrors, val); + mad_decode_field(pc, IB_PC_ERR_EXCESS_OVR_F, &val); + aggregate_4bit(&perf_count.excbufoverrunerrors, val); + mad_decode_field(pc, IB_PC_VL15_DROPPED_F, &val); + aggregate_16bit(&perf_count.vl15dropped, val); + mad_decode_field(pc, IB_PC_XMT_BYTES_F, &val); + aggregate_32bit(&perf_count.xmtdata, val); + mad_decode_field(pc, IB_PC_RCV_BYTES_F, &val); + aggregate_32bit(&perf_count.rcvdata, val); + mad_decode_field(pc, IB_PC_XMT_PKTS_F, &val); + aggregate_32bit(&perf_count.xmtpkts, val); + mad_decode_field(pc, IB_PC_RCV_PKTS_F, &val); + aggregate_32bit(&perf_count.rcvpkts, val); +} + +static void output_aggregate_perfcounters(ib_portid_t *portid) +{ + char buf[1024]; + uint32_t val = ALL_PORTS; + + /* set port_select to 255 to emulate AllPortSelect */ + mad_encode_field(pc, IB_PC_PORT_SELECT_F, &val); + mad_encode_field(pc, IB_PC_COUNTER_SELECT_F, &perf_count.counterselect); + mad_encode_field(pc, IB_PC_ERR_SYM_F, &perf_count.symbolerrors); + mad_encode_field(pc, IB_PC_LINK_RECOVERS_F, &perf_count.linkrecovers); + mad_encode_field(pc, IB_PC_LINK_DOWNED_F, &perf_count.linkdowned); + mad_encode_field(pc, IB_PC_ERR_RCV_F, &perf_count.rcverrors); + mad_encode_field(pc, IB_PC_ERR_PHYSRCV_F, &perf_count.rcvremotephyerrors); + mad_encode_field(pc, IB_PC_ERR_SWITCH_REL_F, &perf_count.rcvswrelayerrors); + mad_encode_field(pc, IB_PC_XMT_DISCARDS_F, &perf_count.xmtdiscards); + mad_encode_field(pc, IB_PC_ERR_XMTCONSTR_F, &perf_count.xmtconstrainterrors); + mad_encode_field(pc, IB_PC_ERR_RCVCONSTR_F, &perf_count.rcvconstrainterrors); + mad_encode_field(pc, IB_PC_ERR_LOCALINTEG_F, &perf_count.linkintegrityerrors); + mad_encode_field(pc, IB_PC_ERR_EXCESS_OVR_F, &perf_count.excbufoverrunerrors); + mad_encode_field(pc, IB_PC_VL15_DROPPED_F, &perf_count.vl15dropped); + mad_encode_field(pc, IB_PC_XMT_BYTES_F, &perf_count.xmtdata); + mad_encode_field(pc, IB_PC_RCV_BYTES_F, &perf_count.rcvdata); + mad_encode_field(pc, IB_PC_XMT_PKTS_F, &perf_count.xmtpkts); + mad_encode_field(pc, IB_PC_RCV_PKTS_F, &perf_count.rcvpkts); + + mad_dump_perfcounters(buf, sizeof buf, pc, sizeof pc); + + printf("# Port counters: %s port %d\n%s", portid2str(portid), ALL_PORTS, buf); +} + +static void aggregate_perfcounters_ext(void) +{ + uint32_t val; + uint64_t val64; + + mad_decode_field(pc, IB_PC_EXT_PORT_SELECT_F, &val); + perf_count_ext.portselect = val; + mad_decode_field(pc, IB_PC_EXT_COUNTER_SELECT_F, &val); + perf_count_ext.counterselect = val; + mad_decode_field(pc, IB_PC_EXT_XMT_BYTES_F, &val64); + aggregate_64bit(&perf_count_ext.portxmitdata, val64); + mad_decode_field(pc, IB_PC_EXT_RCV_BYTES_F, &val64); + aggregate_64bit(&perf_count_ext.portrcvdata, val64); + mad_decode_field(pc, IB_PC_EXT_XMT_PKTS_F, &val64); + aggregate_64bit(&perf_count_ext.portxmitpkts, val64); + mad_decode_field(pc, IB_PC_EXT_RCV_PKTS_F, &val64); + aggregate_64bit(&perf_count_ext.portrcvpkts, val64); + mad_decode_field(pc, IB_PC_EXT_XMT_UPKTS_F, &val64); + aggregate_64bit(&perf_count_ext.portunicastxmitpkts, val64); + mad_decode_field(pc, IB_PC_EXT_RCV_UPKTS_F, &val64); + aggregate_64bit(&perf_count_ext.portunicastrcvpkts, val64); + mad_decode_field(pc, IB_PC_EXT_XMT_MPKTS_F, &val64); + aggregate_64bit(&perf_count_ext.portmulticastxmitpkits, val64); + mad_decode_field(pc, IB_PC_EXT_RCV_MPKTS_F, &val64); + aggregate_64bit(&perf_count_ext.portmulticastrcvpkts, val64); +} + +static void output_aggregate_perfcounters_ext(ib_portid_t *portid) +{ + char buf[1024]; + uint32_t val = ALL_PORTS; + + /* set port_select to 255 to emulate AllPortSelect */ + mad_encode_field(pc, IB_PC_EXT_PORT_SELECT_F, &val); + mad_encode_field(pc, IB_PC_EXT_COUNTER_SELECT_F, &perf_count_ext.counterselect); + mad_encode_field(pc, IB_PC_EXT_XMT_BYTES_F, &perf_count_ext.portxmitdata); + mad_encode_field(pc, IB_PC_EXT_RCV_BYTES_F, &perf_count_ext.portrcvdata); + mad_encode_field(pc, IB_PC_EXT_XMT_PKTS_F, &perf_count_ext.portxmitpkts); + mad_encode_field(pc, IB_PC_EXT_RCV_PKTS_F, &perf_count_ext.portrcvpkts); + mad_encode_field(pc, IB_PC_EXT_XMT_UPKTS_F, &perf_count_ext.portunicastxmitpkts); + mad_encode_field(pc, IB_PC_EXT_RCV_UPKTS_F, &perf_count_ext.portunicastrcvpkts); + mad_encode_field(pc, IB_PC_EXT_XMT_MPKTS_F, &perf_count_ext.portmulticastxmitpkits); + mad_encode_field(pc, IB_PC_EXT_RCV_MPKTS_F, &perf_count_ext.portmulticastrcvpkts); + + mad_dump_perfcounters_ext(buf, sizeof buf, pc, sizeof pc); + + printf("# Port counters: %s port %d\n%s", portid2str(portid), ALL_PORTS, buf); +} + +static void dump_perfcounters(int extended, int timeout, uint16_t cap_mask, ib_portid_t *portid, + int port, int aggregate) +{ + char buf[1024]; + + if (extended != 1) { + if (!port_performance_query(pc, portid, port, timeout)) + IBERROR("perfquery"); + if (aggregate) + aggregate_perfcounters(); + else + mad_dump_perfcounters(buf, sizeof buf, pc, sizeof pc); + } else { + if (!(cap_mask & 0x200)) /* 1.2 errata: bit 9 is extended counter support */ + IBWARN("PerfMgt ClassPortInfo 0x%x extended counters not indicated\n", cap_mask); + + if (!port_performance_ext_query(pc, portid, port, timeout)) + IBERROR("perfextquery"); + if (aggregate) + aggregate_perfcounters_ext(); + else + mad_dump_perfcounters_ext(buf, sizeof buf, pc, sizeof pc); + } + + if (!aggregate) + printf("# Port counters: %s port %d\n%s", portid2str(portid), port, buf); +} + +static void reset_counters(int extended, int timeout, int mask, ib_portid_t *portid, int port) +{ + if (extended != 1) { + if (!port_performance_reset(pc, portid, port, mask, timeout)) + IBERROR("perf reset"); + } else { + if (!port_performance_ext_reset(pc, portid, port, mask, timeout)) + IBERROR("perf ext reset"); + } +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[4] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS, IB_PERFORMANCE_CLASS}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + ib_portid_t portid = {0}; + extern int ibdebug; + int dest_type = IB_DEST_LID; + int timeout = 0; /* use default */ + int mask = 0xffff, all_ports = 0; + int reset = 0, reset_only = 0; + int port = 0; + int udebug = 0; + char *ca = 0; + int ca_port = 0; + int extended = 0; + uint16_t cap_mask; + int all_ports_loop = 0; + int loop_ports = 0; + int node_type, num_ports = 0; + uint8_t data[IB_SMP_DATA_SIZE]; + int start_port = 1; + int enhancedport0; + int i; + + static char const str_opts[] = "C:P:s:t:dGealrRVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "Guid", 0, 0, 'G'}, + { "extended", 0, 0, 'e'}, + { "all_ports", 0, 0, 'a'}, + { "loop_ports", 0, 0, 'l'}, + { "reset_after_read", 0, 0, 'r'}, + { "Reset_only", 0, 0, 'R'}, + { "sm_portid", 1, 0, 's'}, + { "timeout", 1, 0, 't'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'e': + extended = 1; + break; + case 'a': + all_ports++; + port = ALL_PORTS; + break; + case 'l': + loop_ports++; + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 'r': + reset++; + break; + case 'R': + reset_only++; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc > 1) + port = strtoul(argv[1], 0, 0); + if (argc > 2) + mask = strtoul(argv[2], 0, 0); + + madrpc_init(ca, ca_port, mgmt_classes, 4); + + if (argc) { + if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + } else { + if (ib_resolve_self(&portid, &port, 0) < 0) + IBERROR("can't resolve self port %s", argv[0]); + } + + /* PerfMgt ClassPortInfo is a required attribute */ + if (!perf_classportinfo_query(pc, &portid, port, timeout)) + IBERROR("classportinfo query"); + /* ClassPortInfo should be supported as part of libibmad */ + memcpy(&cap_mask, pc+2, sizeof(cap_mask)); /* CapabilityMask */ + cap_mask = ntohs(cap_mask); + if (!(cap_mask & 0x100)) { /* bit 8 is AllPortSelect */ + if (!all_ports && port == ALL_PORTS) + IBERROR("AllPortSelect not supported"); + if (all_ports) + all_ports_loop = 1; + } + + if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) { + if (smp_query(data, &portid, IB_ATTR_NODE_INFO, 0, 0) < 0) + IBERROR("smp query nodeinfo failed"); + node_type = mad_get_field(data, 0, IB_NODE_TYPE_F); + mad_decode_field(data, IB_NODE_NPORTS_F, &num_ports); + if (!num_ports) + IBERROR("smp query nodeinfo: num ports invalid"); + + if (node_type == IB_NODE_SWITCH) { + if (smp_query(data, &portid, IB_ATTR_SWITCH_INFO, 0, 0) < 0) + IBERROR("smp query nodeinfo failed"); + enhancedport0 = mad_get_field(data, 0, IB_SW_ENHANCED_PORT0_F); + if (enhancedport0) + start_port = 0; + } + if (all_ports_loop && !loop_ports) + IBWARN("Emulating AllPortSelect by iterating through all ports"); + } + + if (reset_only) + goto do_reset; + + if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) { + for (i = start_port; i <= num_ports; i++) + dump_perfcounters(extended, timeout, cap_mask, &portid, i, + (all_ports_loop && !loop_ports)); + if (all_ports_loop && !loop_ports) { + if (extended != 1) + output_aggregate_perfcounters(&portid); + else + output_aggregate_perfcounters_ext(&portid); + } + } + else + dump_perfcounters(extended, timeout, cap_mask, &portid, port, 0); + + if (!reset) + exit(0); + +do_reset: + + if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) { + for (i = start_port; i <= num_ports; i++) + reset_counters(extended, timeout, mask, &portid, i); + } + else + reset_counters(extended, timeout, mask, &portid, port); + + exit(0); +} diff --git a/contrib/ofed/management/infiniband-diags/src/saquery.c b/contrib/ofed/management/infiniband-diags/src/saquery.c new file mode 100644 index 000000000000..97663d1d538f --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/saquery.c @@ -0,0 +1,1891 @@ +/* + * Copyright (c) 2006,2007 The Regents of the University of California. + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * Produced at Lawrence Livermore National Laboratory. + * Written by Ira Weiny . + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define _GNU_SOURCE +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ibdiag_common.h" + +struct query_cmd { + const char *name, *alias; + ib_net16_t query_type; + const char *usage; + int (*handler) (const struct query_cmd * q, osm_bind_handle_t h, + int argc, char *argv[]); +}; + +char *argv0 = "saquery"; + +static char *node_name_map_file = NULL; +static nn_map_t *node_name_map = NULL; +static ib_net64_t smkey = OSM_DEFAULT_SA_KEY; + +/** + * Declare some globals because I don't want this to be too complex. + */ +#define MAX_PORTS (8) +#define DEFAULT_SA_TIMEOUT_MS (1000) +osmv_query_res_t result; +osm_log_t log_osm; +osm_mad_pool_t mad_pool; +osm_vendor_t *vendor = NULL; +int osm_debug = 0; +uint32_t sa_timeout_ms = DEFAULT_SA_TIMEOUT_MS; +char *sa_hca_name = NULL; +uint32_t sa_port_num = 0; + +enum { + ALL, + LID_ONLY, + UNIQUE_LID_ONLY, + GUID_ONLY, + ALL_DESC, + NAME_OF_LID, + NAME_OF_GUID, +} node_print_desc = ALL; + +char *requested_name = NULL; +ib_net16_t requested_lid = 0; +int requested_lid_flag = 0; +ib_net64_t requested_guid = 0; +int requested_guid_flag = 0; + +static void format_buf(char *in, char *out, unsigned size) +{ + unsigned i; + + for (i = 0; i < size - 3 && *in; i++) { + *out++ = *in; + if (*in++ == '\n' && *in) { + *out++ = '\t'; + *out++ = '\t'; + } + } + *out = '\0'; +} + +/** + * Call back for the various record requests. + */ +static void query_res_cb(osmv_query_res_t * res) +{ + result = *res; +} + +static void print_node_desc(ib_node_record_t * node_record) +{ + ib_node_info_t *p_ni = &(node_record->node_info); + ib_node_desc_t *p_nd = &(node_record->node_desc); + + if (p_ni->node_type == IB_NODE_TYPE_CA) { + printf("%6d \"%s\"\n", + cl_ntoh16(node_record->lid), + clean_nodedesc((char *)p_nd->description)); + } +} + +static void print_node_record(ib_node_record_t * node_record) +{ + ib_node_info_t *p_ni = NULL; + ib_node_desc_t *p_nd = NULL; + char *name; + + p_ni = &(node_record->node_info); + p_nd = &(node_record->node_desc); + + switch (node_print_desc) { + case LID_ONLY: + case UNIQUE_LID_ONLY: + printf("%d\n", cl_ntoh16(node_record->lid)); + return; + case GUID_ONLY: + printf("0x%016" PRIx64 "\n", cl_ntoh64(p_ni->port_guid)); + return; + case NAME_OF_LID: + case NAME_OF_GUID: + name = remap_node_name(node_name_map, + cl_ntoh64(p_ni->node_guid), + (char *)p_nd->description); + printf("%s\n", name); + free(name); + return; + case ALL: + default: + break; + } + + printf("NodeRecord dump:\n" + "\t\tlid.....................0x%X\n" + "\t\treserved................0x%X\n" + "\t\tbase_version............0x%X\n" + "\t\tclass_version...........0x%X\n" + "\t\tnode_type...............%s\n" + "\t\tnum_ports...............0x%X\n" + "\t\tsys_guid................0x%016" PRIx64 "\n" + "\t\tnode_guid...............0x%016" PRIx64 "\n" + "\t\tport_guid...............0x%016" PRIx64 "\n" + "\t\tpartition_cap...........0x%X\n" + "\t\tdevice_id...............0x%X\n" + "\t\trevision................0x%X\n" + "\t\tport_num................0x%X\n" + "\t\tvendor_id...............0x%X\n" + "\t\tNodeDescription.........%s\n" + "", + cl_ntoh16(node_record->lid), + cl_ntoh16(node_record->resv), + p_ni->base_version, + p_ni->class_version, + ib_get_node_type_str(p_ni->node_type), + p_ni->num_ports, + cl_ntoh64(p_ni->sys_guid), + cl_ntoh64(p_ni->node_guid), + cl_ntoh64(p_ni->port_guid), + cl_ntoh16(p_ni->partition_cap), + cl_ntoh16(p_ni->device_id), + cl_ntoh32(p_ni->revision), + ib_node_info_get_local_port_num(p_ni), + cl_ntoh32(ib_node_info_get_vendor_id(p_ni)), + clean_nodedesc((char *)node_record->node_desc.description) + ); +} + +static void dump_path_record(void *data) +{ + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + ib_path_rec_t *p_pr = data; + printf("PathRecord dump:\n" + "\t\tservice_id..............0x%016" PRIx64 "\n" + "\t\tdgid....................%s\n" + "\t\tsgid....................%s\n" + "\t\tdlid....................0x%X\n" + "\t\tslid....................0x%X\n" + "\t\thop_flow_raw............0x%X\n" + "\t\ttclass..................0x%X\n" + "\t\tnum_path_revers.........0x%X\n" + "\t\tpkey....................0x%X\n" + "\t\tqos_class...............0x%X\n" + "\t\tsl......................0x%X\n" + "\t\tmtu.....................0x%X\n" + "\t\trate....................0x%X\n" + "\t\tpkt_life................0x%X\n" + "\t\tpreference..............0x%X\n" + "\t\tresv2...................0x%X\n" + "\t\tresv3...................0x%X\n" + "", + cl_ntoh64(p_pr->service_id), + inet_ntop(AF_INET6, p_pr->dgid.raw, gid_str, sizeof gid_str), + inet_ntop(AF_INET6, p_pr->sgid.raw, gid_str2, sizeof gid_str2), + cl_ntoh16(p_pr->dlid), + cl_ntoh16(p_pr->slid), + cl_ntoh32(p_pr->hop_flow_raw), + p_pr->tclass, + p_pr->num_path, + cl_ntoh16(p_pr->pkey), + ib_path_rec_qos_class(p_pr), + ib_path_rec_sl(p_pr), + p_pr->mtu, + p_pr->rate, + p_pr->pkt_life, + p_pr->preference, + *(uint32_t *) & p_pr->resv2, *((uint16_t *) & p_pr->resv2 + 2) + ); +} + +static void dump_class_port_info(void *data) +{ + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + ib_class_port_info_t *class_port_info = data; + + printf("SA ClassPortInfo:\n" + "\t\tBase version.............%d\n" + "\t\tClass version............%d\n" + "\t\tCapability mask..........0x%04X\n" + "\t\tCapability mask 2........0x%08X\n" + "\t\tResponse time value......0x%02X\n" + "\t\tRedirect GID.............%s\n" + "\t\tRedirect TC/SL/FL........0x%08X\n" + "\t\tRedirect LID.............0x%04X\n" + "\t\tRedirect PKey............0x%04X\n" + "\t\tRedirect QP..............0x%08X\n" + "\t\tRedirect QKey............0x%08X\n" + "\t\tTrap GID.................%s\n" + "\t\tTrap TC/SL/FL............0x%08X\n" + "\t\tTrap LID.................0x%04X\n" + "\t\tTrap PKey................0x%04X\n" + "\t\tTrap HL/QP...............0x%08X\n" + "\t\tTrap QKey................0x%08X\n" + "", + class_port_info->base_ver, + class_port_info->class_ver, + cl_ntoh16(class_port_info->cap_mask), + ib_class_cap_mask2(class_port_info), + ib_class_resp_time_val(class_port_info), + inet_ntop(AF_INET6, &(class_port_info->redir_gid), gid_str, + sizeof gid_str), + cl_ntoh32(class_port_info->redir_tc_sl_fl), + cl_ntoh16(class_port_info->redir_lid), + cl_ntoh16(class_port_info->redir_pkey), + cl_ntoh32(class_port_info->redir_qp), + cl_ntoh32(class_port_info->redir_qkey), + inet_ntop(AF_INET6, &(class_port_info->trap_gid), gid_str2, + sizeof gid_str2), + cl_ntoh32(class_port_info->trap_tc_sl_fl), + cl_ntoh16(class_port_info->trap_lid), + cl_ntoh16(class_port_info->trap_pkey), + cl_ntoh32(class_port_info->trap_hop_qp), + cl_ntoh32(class_port_info->trap_qkey) + ); +} + +static void dump_portinfo_record(void *data) +{ + ib_portinfo_record_t *p_pir = data; + const ib_port_info_t *const p_pi = &p_pir->port_info; + + printf("PortInfoRecord dump:\n" + "\t\tEndPortLid..............0x%X\n" + "\t\tPortNum.................0x%X\n" + "\t\tbase_lid................0x%X\n" + "\t\tmaster_sm_base_lid......0x%X\n" + "\t\tcapability_mask.........0x%X\n" + "", + cl_ntoh16(p_pir->lid), + p_pir->port_num, + cl_ntoh16(p_pi->base_lid), + cl_ntoh16(p_pi->master_sm_base_lid), + cl_ntoh32(p_pi->capability_mask) + ); +} + +static void dump_one_portinfo_record(void *data) +{ + char buf[2048], buf2[4096]; + ib_portinfo_record_t *pir = data; + ib_port_info_t *pi = &pir->port_info; + + mad_dump_portinfo(buf, sizeof(buf), pi, sizeof(*pi)); + + format_buf(buf, buf2, sizeof(buf2)); + + printf("PortInfoRecord dump:\n" + "\tRID:\n" + "\t\tEndPortLid..............%u\n" + "\t\tPortNum.................0x%x\n" + "\t\tReserved................0x%x\n" + "\tPortInfo dump:\n\t\t%s", + cl_ntoh16(pir->lid), pir->port_num, pir->resv, buf2); +} + +static void dump_multicast_group_record(void *data) +{ + char gid_str[INET6_ADDRSTRLEN]; + ib_member_rec_t *p_mcmr = data; + uint8_t sl; + ib_member_get_sl_flow_hop(p_mcmr->sl_flow_hop, &sl, NULL, NULL); + printf("MCMemberRecord group dump:\n" + "\t\tMGID....................%s\n" + "\t\tMlid....................0x%X\n" + "\t\tMtu.....................0x%X\n" + "\t\tpkey....................0x%X\n" + "\t\tRate....................0x%X\n" + "\t\tSL......................0x%X\n" + "", + inet_ntop(AF_INET6, p_mcmr->mgid.raw, gid_str, sizeof gid_str), + cl_ntoh16(p_mcmr->mlid), + p_mcmr->mtu, cl_ntoh16(p_mcmr->pkey), p_mcmr->rate, sl); +} + +static void dump_multicast_member_record(void *data) +{ + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + ib_member_rec_t *p_mcmr = data; + uint16_t mlid = cl_ntoh16(p_mcmr->mlid); + int i = 0; + char *node_name = ""; + + /* go through the node records searching for a port guid which matches + * this port gid interface id. + * This gives us a node name to print, if available. + */ + for (i = 0; i < result.result_cnt; i++) { + ib_node_record_t *nr = + osmv_get_query_node_rec(result.p_result_madw, i); + if (nr->node_info.port_guid == + p_mcmr->port_gid.unicast.interface_id) { + node_name = + clean_nodedesc((char *)nr->node_desc.description); + break; + } + } + + if (requested_name) { + if (strtol(requested_name, NULL, 0) == mlid) { + printf("\t\tPortGid.................%s (%s)\n", + inet_ntop(AF_INET6, p_mcmr->port_gid.raw, + gid_str, sizeof gid_str), node_name); + } + } else { + printf("MCMemberRecord member dump:\n" + "\t\tMGID....................%s\n" + "\t\tMlid....................0x%X\n" + "\t\tPortGid.................%s\n" + "\t\tScopeState..............0x%X\n" + "\t\tProxyJoin...............0x%X\n" + "\t\tNodeDescription.........%s\n" + "", + inet_ntop(AF_INET6, p_mcmr->mgid.raw, gid_str, + sizeof gid_str), + cl_ntoh16(p_mcmr->mlid), + inet_ntop(AF_INET6, p_mcmr->port_gid.raw, + gid_str2, sizeof gid_str2), + p_mcmr->scope_state, p_mcmr->proxy_join, node_name); + } +} + +static void dump_service_record(void *data) +{ + char gid_str[INET6_ADDRSTRLEN]; + char buf_service_key[35]; + char buf_service_name[65]; + ib_service_record_t *p_sr = data; + + sprintf(buf_service_key, + "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + p_sr->service_key[0], p_sr->service_key[1], + p_sr->service_key[2], p_sr->service_key[3], + p_sr->service_key[4], p_sr->service_key[5], + p_sr->service_key[6], p_sr->service_key[7], + p_sr->service_key[8], p_sr->service_key[9], + p_sr->service_key[10], p_sr->service_key[11], + p_sr->service_key[12], p_sr->service_key[13], + p_sr->service_key[14], p_sr->service_key[15]); + strncpy(buf_service_name, (char *)p_sr->service_name, 64); + buf_service_name[64] = '\0'; + + printf("ServiceRecord dump:\n" + "\t\tServiceID...............0x%016" PRIx64 "\n" + "\t\tServiceGID..............%s\n" + "\t\tServiceP_Key............0x%X\n" + "\t\tServiceLease............0x%X\n" + "\t\tServiceKey..............%s\n" + "\t\tServiceName.............%s\n" + "\t\tServiceData8.1..........0x%X\n" + "\t\tServiceData8.2..........0x%X\n" + "\t\tServiceData8.3..........0x%X\n" + "\t\tServiceData8.4..........0x%X\n" + "\t\tServiceData8.5..........0x%X\n" + "\t\tServiceData8.6..........0x%X\n" + "\t\tServiceData8.7..........0x%X\n" + "\t\tServiceData8.8..........0x%X\n" + "\t\tServiceData8.9..........0x%X\n" + "\t\tServiceData8.10.........0x%X\n" + "\t\tServiceData8.11.........0x%X\n" + "\t\tServiceData8.12.........0x%X\n" + "\t\tServiceData8.13.........0x%X\n" + "\t\tServiceData8.14.........0x%X\n" + "\t\tServiceData8.15.........0x%X\n" + "\t\tServiceData8.16.........0x%X\n" + "\t\tServiceData16.1.........0x%X\n" + "\t\tServiceData16.2.........0x%X\n" + "\t\tServiceData16.3.........0x%X\n" + "\t\tServiceData16.4.........0x%X\n" + "\t\tServiceData16.5.........0x%X\n" + "\t\tServiceData16.6.........0x%X\n" + "\t\tServiceData16.7.........0x%X\n" + "\t\tServiceData16.8.........0x%X\n" + "\t\tServiceData32.1.........0x%X\n" + "\t\tServiceData32.2.........0x%X\n" + "\t\tServiceData32.3.........0x%X\n" + "\t\tServiceData32.4.........0x%X\n" + "\t\tServiceData64.1.........0x%016" PRIx64 "\n" + "\t\tServiceData64.2.........0x%016" PRIx64 "\n" + "", + cl_ntoh64(p_sr->service_id), + inet_ntop(AF_INET6, p_sr->service_gid.raw, gid_str, + sizeof gid_str), + cl_ntoh16(p_sr->service_pkey), + cl_ntoh32(p_sr->service_lease), + buf_service_key, + buf_service_name, + p_sr->service_data8[0], p_sr->service_data8[1], + p_sr->service_data8[2], p_sr->service_data8[3], + p_sr->service_data8[4], p_sr->service_data8[5], + p_sr->service_data8[6], p_sr->service_data8[7], + p_sr->service_data8[8], p_sr->service_data8[9], + p_sr->service_data8[10], p_sr->service_data8[11], + p_sr->service_data8[12], p_sr->service_data8[13], + p_sr->service_data8[14], p_sr->service_data8[15], + cl_ntoh16(p_sr->service_data16[0]), + cl_ntoh16(p_sr->service_data16[1]), + cl_ntoh16(p_sr->service_data16[2]), + cl_ntoh16(p_sr->service_data16[3]), + cl_ntoh16(p_sr->service_data16[4]), + cl_ntoh16(p_sr->service_data16[5]), + cl_ntoh16(p_sr->service_data16[6]), + cl_ntoh16(p_sr->service_data16[7]), + cl_ntoh32(p_sr->service_data32[0]), + cl_ntoh32(p_sr->service_data32[1]), + cl_ntoh32(p_sr->service_data32[2]), + cl_ntoh32(p_sr->service_data32[3]), + cl_ntoh64(p_sr->service_data64[0]), + cl_ntoh64(p_sr->service_data64[1]) + ); +} + +static void dump_inform_info_record(void *data) +{ + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + ib_inform_info_record_t *p_iir = data; + uint32_t qpn; + uint8_t resp_time_val; + + ib_inform_info_get_qpn_resp_time(p_iir->inform_info.g_or_v.generic. + qpn_resp_time_val, &qpn, + &resp_time_val); + + if (p_iir->inform_info.is_generic) { + printf("InformInfoRecord dump:\n" + "\t\tRID\n" + "\t\tSubscriberGID...........%s\n" + "\t\tSubscriberEnum..........0x%X\n" + "\t\tInformInfo dump:\n" + "\t\tgid.....................%s\n" + "\t\tlid_range_begin.........0x%X\n" + "\t\tlid_range_end...........0x%X\n" + "\t\tis_generic..............0x%X\n" + "\t\tsubscribe...............0x%X\n" + "\t\ttrap_type...............0x%X\n" + "\t\ttrap_num................%u\n" + "\t\tqpn.....................0x%06X\n" + "\t\tresp_time_val...........0x%X\n" + "\t\tnode_type...............0x%06X\n" + "", + inet_ntop(AF_INET6, p_iir->subscriber_gid.raw, gid_str, + sizeof gid_str), + cl_ntoh16(p_iir->subscriber_enum), + inet_ntop(AF_INET6, p_iir->inform_info.gid.raw, gid_str2, + sizeof gid_str2), + cl_ntoh16(p_iir->inform_info.lid_range_begin), + cl_ntoh16(p_iir->inform_info.lid_range_end), + p_iir->inform_info.is_generic, + p_iir->inform_info.subscribe, + cl_ntoh16(p_iir->inform_info.trap_type), + cl_ntoh16(p_iir->inform_info.g_or_v.generic.trap_num), + cl_ntoh32(qpn), + resp_time_val, + cl_ntoh32(ib_inform_info_get_prod_type + (&p_iir->inform_info)) + ); + } else { + printf("InformInfoRecord dump:\n" + "\t\tRID\n" + "\t\tSubscriberGID...........%s\n" + "\t\tSubscriberEnum..........0x%X\n" + "\t\tInformInfo dump:\n" + "\t\tgid.....................%s\n" + "\t\tlid_range_begin.........0x%X\n" + "\t\tlid_range_end...........0x%X\n" + "\t\tis_generic..............0x%X\n" + "\t\tsubscribe...............0x%X\n" + "\t\ttrap_type...............0x%X\n" + "\t\tdev_id..................0x%X\n" + "\t\tqpn.....................0x%06X\n" + "\t\tresp_time_val...........0x%X\n" + "\t\tvendor_id...............0x%06X\n" + "", + inet_ntop(AF_INET6, p_iir->subscriber_gid.raw, gid_str, + sizeof gid_str), + cl_ntoh16(p_iir->subscriber_enum), + inet_ntop(AF_INET6, p_iir->inform_info.gid.raw, + gid_str2, sizeof gid_str2), + cl_ntoh16(p_iir->inform_info.lid_range_begin), + cl_ntoh16(p_iir->inform_info.lid_range_end), + p_iir->inform_info.is_generic, + p_iir->inform_info.subscribe, + cl_ntoh16(p_iir->inform_info.trap_type), + cl_ntoh16(p_iir->inform_info.g_or_v.vend.dev_id), + cl_ntoh32(qpn), + resp_time_val, + cl_ntoh32(ib_inform_info_get_prod_type + (&p_iir->inform_info)) + ); + } +} + +static void dump_one_link_record(void *data) +{ + ib_link_record_t *lr = data; + printf("LinkRecord dump:\n" + "\t\tFromLID....................%u\n" + "\t\tFromPort...................%u\n" + "\t\tToPort.....................%u\n" + "\t\tToLID......................%u\n", + cl_ntoh16(lr->from_lid), lr->from_port_num, + lr->to_port_num, cl_ntoh16(lr->to_lid)); +} + +static void dump_one_slvl_record(void *data) +{ + ib_slvl_table_record_t *slvl = data; + ib_slvl_table_t *t = &slvl->slvl_tbl; + printf("SL2VLTableRecord dump:\n" + "\t\tLID........................%u\n" + "\t\tInPort.....................%u\n" + "\t\tOutPort....................%u\n" + "\t\tSL: 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|\n" + "\t\tVL:%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u" + "|%2u|%2u|%2u|\n", + cl_ntoh16(slvl->lid), slvl->in_port_num, slvl->out_port_num, + ib_slvl_table_get(t, 0), ib_slvl_table_get(t, 1), + ib_slvl_table_get(t, 2), ib_slvl_table_get(t, 3), + ib_slvl_table_get(t, 4), ib_slvl_table_get(t, 5), + ib_slvl_table_get(t, 6), ib_slvl_table_get(t, 7), + ib_slvl_table_get(t, 8), ib_slvl_table_get(t, 9), + ib_slvl_table_get(t, 10), ib_slvl_table_get(t, 11), + ib_slvl_table_get(t, 12), ib_slvl_table_get(t, 13), + ib_slvl_table_get(t, 14), ib_slvl_table_get(t, 15)); +} + +static void dump_one_vlarb_record(void *data) +{ + ib_vl_arb_table_record_t *vlarb = data; + ib_vl_arb_element_t *e = vlarb->vl_arb_tbl.vl_entry; + int i; + printf("VLArbTableRecord dump:\n" + "\t\tLID........................%u\n" + "\t\tPort.......................%u\n" + "\t\tBlock......................%u\n", + cl_ntoh16(vlarb->lid), vlarb->port_num, vlarb->block_num); + for (i = 0; i < 32; i += 16) { + printf("\t\tVL :%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|" + "%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|", + e[i + 0].vl, e[i + 1].vl, e[i + 2].vl, e[i + 3].vl, + e[i + 4].vl, e[i + 5].vl, e[i + 6].vl, e[i + 7].vl, + e[i + 8].vl, e[i + 9].vl, e[i + 10].vl, e[i + 11].vl, + e[i + 12].vl, e[i + 13].vl, e[i + 14].vl, e[i + 15].vl); + printf("\n\t\tWeight:%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|" + "%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|", + e[i + 0].weight, e[i + 1].weight, e[i + 2].weight, + e[i + 3].weight, e[i + 4].weight, e[i + 5].weight, + e[i + 6].weight, e[i + 7].weight, e[i + 8].weight, + e[i + 9].weight, e[i + 10].weight, e[i + 11].weight, + e[i + 12].weight, e[i + 13].weight, e[i + 14].weight, + e[i + 15].weight); + printf("\n"); + } +} + +static void dump_one_pkey_tbl_record(void *data) +{ + ib_pkey_table_record_t *pktr = data; + ib_net16_t *p = pktr->pkey_tbl.pkey_entry; + int i; + printf("PKeyTableRecord dump:\n" + "\t\tLID........................%u\n" + "\t\tPort.......................%u\n" + "\t\tBlock......................%u\n" + "\t\tPKey Table:\n", + cl_ntoh16(pktr->lid), pktr->port_num, pktr->block_num); + for (i = 0; i < 32; i += 8) + printf("\t\t0x%04x 0x%04x 0x%04x 0x%04x" + " 0x%04x 0x%04x 0x%04x 0x%04x\n", + cl_ntoh16(p[i + 0]), cl_ntoh16(p[i + 1]), + cl_ntoh16(p[i + 2]), cl_ntoh16(p[i + 3]), + cl_ntoh16(p[i + 4]), cl_ntoh16(p[i + 5]), + cl_ntoh16(p[i + 6]), cl_ntoh16(p[i + 7])); + printf("\n"); +} + +static void dump_one_lft_record(void *data) +{ + ib_lft_record_t *lftr = data; + unsigned block = cl_ntoh16(lftr->block_num); + int i; + printf("LFT Record dump:\n" + "\t\tLID........................%u\n" + "\t\tBlock......................%u\n" + "\t\tLFT:\n\t\tLID\tPort Number\n", cl_ntoh16(lftr->lid), block); + for (i = 0; i < 64; i++) + printf("\t\t%u\t%u\n", block * 64 + i, lftr->lft[i]); + printf("\n"); +} + +static void dump_one_mft_record(void *data) +{ + ib_mft_record_t *mftr = data; + unsigned position = cl_ntoh16(mftr->position_block_num) >> 12; + unsigned block = cl_ntoh16(mftr->position_block_num) & + IB_MCAST_BLOCK_ID_MASK_HO; + int i; + printf("MFT Record dump:\n" + "\t\tLID........................%u\n" + "\t\tPosition...................%u\n" + "\t\tBlock......................%u\n" + "\t\tMFT:\n\t\tMLID\tPort Mask\n", + cl_ntoh16(mftr->lid), position, block); + for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++) + printf("\t\t0x%x\t0x%x\n", + IB_LID_MCAST_START_HO + block * 64 + i, + cl_ntoh16(mftr->mft[i])); + printf("\n"); +} +static void dump_results(osmv_query_res_t * r, void (*dump_func) (void *)) +{ + int i; + for (i = 0; i < r->result_cnt; i++) { + void *data = osmv_get_query_result(r->p_result_madw, i); + dump_func(data); + } +} + +static void return_mad(void) +{ + /* + * Return the IB query MAD to the pool as necessary. + */ + if (result.p_result_madw != NULL) { + osm_mad_pool_put(&mad_pool, result.p_result_madw); + result.p_result_madw = NULL; + } +} + +/** + * Get any record(s) + */ +static ib_api_status_t +get_any_records(osm_bind_handle_t h, + ib_net16_t attr_id, ib_net32_t attr_mod, ib_net64_t comp_mask, + void *attr, ib_net16_t attr_offset, ib_net64_t sm_key) +{ + ib_api_status_t status; + osmv_query_req_t req; + osmv_user_query_t user; + + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + + user.attr_id = attr_id; + user.attr_offset = attr_offset; + user.attr_mod = attr_mod; + user.comp_mask = comp_mask; + user.p_attr = attr; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = sa_timeout_ms; + req.retry_cnt = 1; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = NULL; + req.pfn_query_cb = query_res_cb; + req.p_query_input = &user; + req.sm_key = sm_key; + + if ((status = osmv_query_sa(h, &req)) != IB_SUCCESS) { + fprintf(stderr, "Query SA failed: %s\n", + ib_get_err_str(status)); + return status; + } + + if (result.status != IB_SUCCESS) { + fprintf(stderr, "Query result returned: %s\n", + ib_get_err_str(result.status)); + return result.status; + } + + return status; +} + +/** + * Get all the records available for requested query type. + */ +static ib_api_status_t +get_all_records(osm_bind_handle_t h, + ib_net16_t query_id, ib_net16_t attr_offset, int trusted) +{ + return get_any_records(h, query_id, 0, 0, NULL, attr_offset, + trusted ? smkey : 0); +} + +/** + * return the lid from the node descriptor (name) supplied + */ +static ib_api_status_t +get_lid_from_name(osm_bind_handle_t h, const char *name, ib_net16_t * lid) +{ + int i = 0; + ib_node_record_t *node_record = NULL; + ib_node_info_t *p_ni = NULL; + ib_net16_t attr_offset = ib_get_attr_offset(sizeof(*node_record)); + ib_api_status_t status; + + status = get_all_records(h, IB_MAD_ATTR_NODE_RECORD, attr_offset, 0); + if (status != IB_SUCCESS) + return (status); + + for (i = 0; i < result.result_cnt; i++) { + node_record = osmv_get_query_node_rec(result.p_result_madw, i); + p_ni = &(node_record->node_info); + if (name + && strncmp(name, (char *)node_record->node_desc.description, + sizeof(node_record->node_desc.description)) == + 0) { + *lid = cl_ntoh16(node_record->lid); + break; + } + } + return_mad(); + return (status); +} + +static ib_net16_t get_lid(osm_bind_handle_t h, const char *name) +{ + ib_net16_t rc_lid = 0; + + if (!name) + return (0); + if (isalpha(name[0])) + assert(get_lid_from_name(h, name, &rc_lid) == IB_SUCCESS); + else + rc_lid = atoi(name); + if (rc_lid == 0) + fprintf(stderr, "Failed to find lid for \"%s\"\n", name); + return (rc_lid); +} + +static int parse_lid_and_ports(osm_bind_handle_t h, + char *str, int *lid, int *port1, int *port2) +{ + char *p, *e; + + if (port1) + *port1 = -1; + if (port2) + *port2 = -1; + + p = strchr(str, '/'); + if (p) + *p = '\0'; + if (lid) + *lid = get_lid(h, str); + + if (!p) + return 0; + str = p + 1; + p = strchr(str, '/'); + if (p) + *p = '\0'; + if (port1) { + *port1 = strtoul(str, &e, 0); + if (e == str) + *port1 = -1; + } + + if (!p) + return 0; + str = p + 1; + if (port2) { + *port2 = strtoul(str, &e, 0); + if (e == str) + *port2 = -1; + } + + return 0; +} + +/* + * Get the portinfo records available with IsSM or IsSMdisabled CapabilityMask bit on. + */ +static ib_api_status_t +get_issm_records(osm_bind_handle_t h, ib_net32_t capability_mask) +{ + ib_portinfo_record_t attr; + + memset(&attr, 0, sizeof(attr)); + attr.port_info.capability_mask = capability_mask; + + return get_any_records(h, IB_MAD_ATTR_PORTINFO_RECORD, + cl_hton32(1 << 31), IB_PIR_COMPMASK_CAPMASK, + &attr, + ib_get_attr_offset(sizeof(ib_portinfo_record_t)), + 0); +} + +static ib_api_status_t print_node_records(osm_bind_handle_t h) +{ + int i = 0; + ib_node_record_t *node_record = NULL; + ib_net16_t attr_offset = ib_get_attr_offset(sizeof(*node_record)); + ib_api_status_t status; + + status = get_all_records(h, IB_MAD_ATTR_NODE_RECORD, attr_offset, 0); + if (status != IB_SUCCESS) + return (status); + + if (node_print_desc == ALL_DESC) { + printf(" LID \"name\"\n"); + printf("================\n"); + } + for (i = 0; i < result.result_cnt; i++) { + node_record = osmv_get_query_node_rec(result.p_result_madw, i); + if (node_print_desc == ALL_DESC) { + print_node_desc(node_record); + } else if (node_print_desc == NAME_OF_LID) { + if (requested_lid == cl_ntoh16(node_record->lid)) { + print_node_record(node_record); + } + } else if (node_print_desc == NAME_OF_GUID) { + ib_node_info_t *p_ni = &(node_record->node_info); + + if (requested_guid == cl_ntoh64(p_ni->port_guid)) { + print_node_record(node_record); + } + } else { + if (!requested_name || + (strncmp(requested_name, + (char *)node_record->node_desc.description, + sizeof(node_record->node_desc. + description)) == 0)) { + print_node_record(node_record); + if (node_print_desc == UNIQUE_LID_ONLY) { + return_mad(); + exit(0); + } + } + } + } + return_mad(); + return (status); +} + +static ib_api_status_t +get_print_path_rec_lid(osm_bind_handle_t h, + ib_net16_t src_lid, ib_net16_t dst_lid) +{ + osmv_query_req_t req; + osmv_lid_pair_t lid_pair; + ib_api_status_t status; + + lid_pair.src_lid = cl_hton16(src_lid); + lid_pair.dest_lid = cl_hton16(dst_lid); + + memset(&req, 0, sizeof(req)); + + req.query_type = OSMV_QUERY_PATH_REC_BY_LIDS; + req.timeout_ms = sa_timeout_ms; + req.retry_cnt = 1; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = NULL; + req.pfn_query_cb = query_res_cb; + req.p_query_input = (void *)&lid_pair; + req.sm_key = 0; + + if ((status = osmv_query_sa(h, &req)) != IB_SUCCESS) { + fprintf(stderr, "ERROR: Query SA failed: %s\n", + ib_get_err_str(status)); + return (status); + } + if (result.status != IB_SUCCESS) { + fprintf(stderr, "ERROR: Query result returned: %s\n", + ib_get_err_str(result.status)); + return (result.status); + } + status = result.status; + dump_results(&result, dump_path_record); + return_mad(); + return (status); +} + +static ib_api_status_t +get_print_path_rec_gid(osm_bind_handle_t h, + const ib_gid_t * src_gid, const ib_gid_t * dst_gid) +{ + osmv_query_req_t req; + osmv_gid_pair_t gid_pair; + ib_api_status_t status; + + gid_pair.src_gid = *src_gid; + gid_pair.dest_gid = *dst_gid; + + memset(&req, 0, sizeof(req)); + + req.query_type = OSMV_QUERY_PATH_REC_BY_GIDS; + req.timeout_ms = sa_timeout_ms; + req.retry_cnt = 1; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = NULL; + req.pfn_query_cb = query_res_cb; + req.p_query_input = (void *)&gid_pair; + req.sm_key = 0; + + if ((status = osmv_query_sa(h, &req)) != IB_SUCCESS) { + fprintf(stderr, "ERROR: Query SA failed: %s\n", + ib_get_err_str(status)); + return (status); + } + if (result.status != IB_SUCCESS) { + fprintf(stderr, "ERROR: Query result returned: %s\n", + ib_get_err_str(result.status)); + return (result.status); + } + status = result.status; + dump_results(&result, dump_path_record); + return_mad(); + return (status); +} + +static ib_api_status_t get_print_class_port_info(osm_bind_handle_t h) +{ + osmv_query_req_t req; + ib_api_status_t status; + + memset(&req, 0, sizeof(req)); + + req.query_type = OSMV_QUERY_CLASS_PORT_INFO; + req.timeout_ms = sa_timeout_ms; + req.retry_cnt = 1; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = NULL; + req.pfn_query_cb = query_res_cb; + req.p_query_input = NULL; + req.sm_key = 0; + + if ((status = osmv_query_sa(h, &req)) != IB_SUCCESS) { + fprintf(stderr, "ERROR: Query SA failed: %s\n", + ib_get_err_str(status)); + return (status); + } + if (result.status != IB_SUCCESS) { + fprintf(stderr, "ERROR: Query result returned: %s\n", + ib_get_err_str(result.status)); + return (result.status); + } + status = result.status; + dump_results(&result, dump_class_port_info); + return_mad(); + return (status); +} + +static int query_path_records(const struct query_cmd *q, + osm_bind_handle_t h, int argc, char *argv[]) +{ + ib_net16_t attr_offset = ib_get_attr_offset(sizeof(ib_path_rec_t)); + ib_api_status_t status; + + status = get_all_records(h, IB_MAD_ATTR_PATH_RECORD, attr_offset, 0); + if (status != IB_SUCCESS) + return (status); + + dump_results(&result, dump_path_record); + return_mad(); + return (status); +} + +static ib_api_status_t print_issm_records(osm_bind_handle_t h) +{ + ib_api_status_t status; + + /* First, get IsSM records */ + status = get_issm_records(h, IB_PORT_CAP_IS_SM); + if (status != IB_SUCCESS) + return (status); + + printf("IsSM ports\n"); + dump_results(&result, dump_portinfo_record); + return_mad(); + + /* Now, get IsSMdisabled records */ + status = get_issm_records(h, IB_PORT_CAP_SM_DISAB); + if (status != IB_SUCCESS) + return (status); + + printf("\nIsSMdisabled ports\n"); + dump_results(&result, dump_portinfo_record); + return_mad(); + + return (status); +} + +static ib_api_status_t print_multicast_member_records(osm_bind_handle_t h) +{ + osmv_query_res_t mc_group_result; + ib_api_status_t status; + + status = get_all_records(h, IB_MAD_ATTR_MCMEMBER_RECORD, + ib_get_attr_offset(sizeof(ib_member_rec_t)), + 1); + if (status != IB_SUCCESS) + return (status); + + mc_group_result = result; + + status = get_all_records(h, IB_MAD_ATTR_NODE_RECORD, + ib_get_attr_offset(sizeof(ib_node_record_t)), + 0); + if (status != IB_SUCCESS) + goto return_mc; + + dump_results(&mc_group_result, dump_multicast_member_record); + return_mad(); + +return_mc: + /* return_mad for the mc_group_result */ + if (mc_group_result.p_result_madw != NULL) { + osm_mad_pool_put(&mad_pool, mc_group_result.p_result_madw); + mc_group_result.p_result_madw = NULL; + } + + return (status); +} + +static ib_api_status_t print_multicast_group_records(osm_bind_handle_t h) +{ + ib_api_status_t status; + + status = get_all_records(h, IB_MAD_ATTR_MCMEMBER_RECORD, + ib_get_attr_offset(sizeof(ib_member_rec_t)), + 0); + if (status != IB_SUCCESS) + return (status); + + dump_results(&result, dump_multicast_group_record); + return_mad(); + return (status); +} + +static int query_class_port_info(const struct query_cmd *q, + osm_bind_handle_t h, int argc, char *argv[]) +{ + return get_print_class_port_info(h); +} + +static int query_node_records(const struct query_cmd *q, + osm_bind_handle_t h, int argc, char *argv[]) +{ + return print_node_records(h); +} + +static int query_portinfo_records(const struct query_cmd *q, + osm_bind_handle_t h, int argc, char *argv[]) +{ + ib_portinfo_record_t pir; + ib_net64_t comp_mask = 0; + int lid = 0, port = -1; + ib_api_status_t status; + + if (argc > 0) + parse_lid_and_ports(h, argv[0], &lid, &port, NULL); + + memset(&pir, 0, sizeof(pir)); + + if (lid > 0) { + pir.lid = cl_hton16(lid); + comp_mask |= IB_PIR_COMPMASK_LID; + } + if (port >= 0) { + pir.port_num = cl_hton16(port); + comp_mask |= IB_PIR_COMPMASK_PORTNUM; + } + + status = get_any_records(h, IB_MAD_ATTR_PORTINFO_RECORD, 0, + comp_mask, &pir, + ib_get_attr_offset(sizeof(pir)), 0); + + if (status != IB_SUCCESS) + return status; + + dump_results(&result, dump_one_portinfo_record); + return_mad(); + + return 0; +} + +static int query_mcmember_records(const struct query_cmd *q, + osm_bind_handle_t h, int argc, char *argv[]) +{ + return print_multicast_member_records(h); +} + +static int query_service_records(const struct query_cmd *q, + osm_bind_handle_t h, int argc, char *argv[]) +{ + ib_net16_t attr_offset = + ib_get_attr_offset(sizeof(ib_service_record_t)); + ib_api_status_t status; + + status = get_all_records(h, IB_MAD_ATTR_SERVICE_RECORD, attr_offset, 0); + if (status != IB_SUCCESS) + return (status); + + dump_results(&result, dump_service_record); + return_mad(); + return (status); +} + +static int query_informinfo_records(const struct query_cmd *q, + osm_bind_handle_t h, int argc, char *argv[]) +{ + ib_net16_t attr_offset = + ib_get_attr_offset(sizeof(ib_inform_info_record_t)); + ib_api_status_t status; + + status = + get_all_records(h, IB_MAD_ATTR_INFORM_INFO_RECORD, attr_offset, 0); + if (status != IB_SUCCESS) + return (status); + + dump_results(&result, dump_inform_info_record); + return_mad(); + return (status); +} + +static int query_link_records(const struct query_cmd *q, + osm_bind_handle_t h, int argc, char *argv[]) +{ + ib_link_record_t lr; + ib_net64_t comp_mask = 0; + int from_lid = 0, to_lid = 0, from_port = -1, to_port = -1; + ib_api_status_t status; + + if (argc > 0) + parse_lid_and_ports(h, argv[0], &from_lid, &from_port, NULL); + + if (argc > 1) + parse_lid_and_ports(h, argv[1], &to_lid, &to_port, NULL); + + memset(&lr, 0, sizeof(lr)); + + if (from_lid > 0) { + lr.from_lid = cl_hton16(from_lid); + comp_mask |= IB_LR_COMPMASK_FROM_LID; + } + if (from_port >= 0) { + lr.from_port_num = from_port; + comp_mask |= IB_LR_COMPMASK_FROM_PORT; + } + if (to_lid > 0) { + lr.to_lid = cl_hton16(to_lid); + comp_mask |= IB_LR_COMPMASK_TO_LID; + } + if (to_port >= 0) { + lr.to_port_num = to_port; + comp_mask |= IB_LR_COMPMASK_TO_PORT; + } + + status = get_any_records(h, IB_MAD_ATTR_LINK_RECORD, 0, + comp_mask, &lr, + ib_get_attr_offset(sizeof(lr)), 0); + if (status != IB_SUCCESS) + return status; + + dump_results(&result, dump_one_link_record); + return_mad(); + return status; +} + +static int query_sl2vl_records(const struct query_cmd *q, + osm_bind_handle_t h, int argc, char *argv[]) +{ + ib_slvl_table_record_t slvl; + ib_net64_t comp_mask = 0; + int lid = 0, in_port = -1, out_port = -1; + ib_api_status_t status; + + if (argc > 0) + parse_lid_and_ports(h, argv[0], &lid, &in_port, &out_port); + + memset(&slvl, 0, sizeof(slvl)); + + if (lid > 0) { + slvl.lid = cl_hton16(lid); + comp_mask |= IB_SLVL_COMPMASK_LID; + } + if (in_port >= 0) { + slvl.in_port_num = in_port; + comp_mask |= IB_SLVL_COMPMASK_IN_PORT; + } + if (out_port >= 0) { + slvl.out_port_num = out_port; + comp_mask |= IB_SLVL_COMPMASK_OUT_PORT; + } + + status = get_any_records(h, IB_MAD_ATTR_SLVL_RECORD, 0, + comp_mask, &slvl, + ib_get_attr_offset(sizeof(slvl)), 0); + if (status != IB_SUCCESS) + return status; + + dump_results(&result, dump_one_slvl_record); + return_mad(); + return status; +} + +static int query_vlarb_records(const struct query_cmd *q, + osm_bind_handle_t h, int argc, char *argv[]) +{ + ib_vl_arb_table_record_t vlarb; + ib_net64_t comp_mask = 0; + int lid = 0, port = -1, block = -1; + ib_api_status_t status; + + if (argc > 0) + parse_lid_and_ports(h, argv[0], &lid, &port, &block); + + memset(&vlarb, 0, sizeof(vlarb)); + + if (lid > 0) { + vlarb.lid = cl_hton16(lid); + comp_mask |= IB_VLA_COMPMASK_LID; + } + if (port >= 0) { + vlarb.port_num = port; + comp_mask |= IB_VLA_COMPMASK_OUT_PORT; + } + if (block >= 0) { + vlarb.block_num = block; + comp_mask |= IB_VLA_COMPMASK_BLOCK; + } + + status = get_any_records(h, IB_MAD_ATTR_VLARB_RECORD, 0, + comp_mask, &vlarb, + ib_get_attr_offset(sizeof(vlarb)), 0); + if (status != IB_SUCCESS) + return status; + + dump_results(&result, dump_one_vlarb_record); + return_mad(); + return status; +} + +static int query_pkey_tbl_records(const struct query_cmd *q, + osm_bind_handle_t h, int argc, char *argv[]) +{ + ib_pkey_table_record_t pktr; + ib_net64_t comp_mask = 0; + int lid = 0, port = -1, block = -1; + ib_api_status_t status; + + if (argc > 0) + parse_lid_and_ports(h, argv[0], &lid, &port, &block); + + memset(&pktr, 0, sizeof(pktr)); + + if (lid > 0) { + pktr.lid = cl_hton16(lid); + comp_mask |= IB_PKEY_COMPMASK_LID; + } + if (port >= 0) { + pktr.port_num = port; + comp_mask |= IB_PKEY_COMPMASK_PORT; + } + if (block >= 0) { + pktr.block_num = block; + comp_mask |= IB_PKEY_COMPMASK_BLOCK; + } + + status = get_any_records(h, IB_MAD_ATTR_PKEY_TBL_RECORD, 0, + comp_mask, &pktr, + ib_get_attr_offset(sizeof(pktr)), smkey); + if (status != IB_SUCCESS) + return status; + + dump_results(&result, dump_one_pkey_tbl_record); + return_mad(); + return status; +} + +static int query_lft_records(const struct query_cmd *q, + osm_bind_handle_t h, int argc, char *argv[]) +{ + ib_lft_record_t lftr; + ib_net64_t comp_mask = 0; + int lid = 0, block = -1; + ib_api_status_t status; + + if (argc > 0) + parse_lid_and_ports(h, argv[0], &lid, &block, NULL); + + memset(&lftr, 0, sizeof(lftr)); + + if (lid > 0) { + lftr.lid = cl_hton16(lid); + comp_mask |= IB_LFTR_COMPMASK_LID; + } + if (block >= 0) { + lftr.block_num = cl_hton16(block); + comp_mask |= IB_LFTR_COMPMASK_BLOCK; + } + + status = get_any_records(h, IB_MAD_ATTR_LFT_RECORD, 0, + comp_mask, &lftr, + ib_get_attr_offset(sizeof(lftr)), 0); + if (status != IB_SUCCESS) + return status; + + dump_results(&result, dump_one_lft_record); + return_mad(); + return status; +} + +static int query_mft_records(const struct query_cmd *q, + osm_bind_handle_t h, int argc, char *argv[]) +{ + ib_mft_record_t mftr; + ib_net64_t comp_mask = 0; + int lid = 0, block = -1, position = -1; + ib_api_status_t status; + + if (argc > 0) + parse_lid_and_ports(h, argv[0], &lid, &position, &block); + + memset(&mftr, 0, sizeof(mftr)); + + if (lid > 0) { + mftr.lid = cl_hton16(lid); + comp_mask |= IB_MFTR_COMPMASK_LID; + } + if (position >= 0) { + mftr.position_block_num = cl_hton16(position << 12); + comp_mask |= IB_MFTR_COMPMASK_POSITION; + } + if (block >= 0) { + mftr.position_block_num |= + cl_hton16(block & IB_MCAST_BLOCK_ID_MASK_HO); + comp_mask |= IB_MFTR_COMPMASK_BLOCK; + } + + status = get_any_records(h, IB_MAD_ATTR_MFT_RECORD, 0, + comp_mask, &mftr, + ib_get_attr_offset(sizeof(mftr)), 0); + if (status != IB_SUCCESS) + return status; + + dump_results(&result, dump_one_mft_record); + return_mad(); + return status; +} + +static osm_bind_handle_t get_bind_handle(void) +{ + uint32_t i = 0; + uint64_t port_guid = (uint64_t) - 1; + osm_bind_handle_t h; + ib_api_status_t status; + ib_port_attr_t attr_array[MAX_PORTS]; + uint32_t num_ports = MAX_PORTS; + uint32_t ca_name_index = 0; + + complib_init(); + + osm_log_construct(&log_osm); + if ((status = osm_log_init_v2(&log_osm, TRUE, 0x0001, NULL, + 0, TRUE)) != IB_SUCCESS) { + fprintf(stderr, "Failed to init osm_log: %s\n", + ib_get_err_str(status)); + exit(-1); + } + osm_log_set_level(&log_osm, OSM_LOG_NONE); + if (osm_debug) + osm_log_set_level(&log_osm, OSM_LOG_DEFAULT_LEVEL); + + vendor = osm_vendor_new(&log_osm, sa_timeout_ms); + osm_mad_pool_construct(&mad_pool); + if ((status = osm_mad_pool_init(&mad_pool)) != IB_SUCCESS) { + fprintf(stderr, "Failed to init mad pool: %s\n", + ib_get_err_str(status)); + exit(-1); + } + + if ((status = + osm_vendor_get_all_port_attr(vendor, attr_array, + &num_ports)) != IB_SUCCESS) { + fprintf(stderr, "Failed to get port attributes: %s\n", + ib_get_err_str(status)); + exit(-1); + } + + for (i = 0; i < num_ports; i++) { + if (i > 1 && cl_ntoh64(attr_array[i].port_guid) + != (cl_ntoh64(attr_array[i - 1].port_guid) + 1)) + ca_name_index++; + if (sa_port_num && sa_port_num != attr_array[i].port_num) + continue; + if (sa_hca_name + && strcmp(sa_hca_name, + vendor->ca_names[ca_name_index]) != 0) + continue; + if (attr_array[i].link_state == IB_LINK_ACTIVE) { + port_guid = attr_array[i].port_guid; + break; + } + } + + if (port_guid == (uint64_t) - 1) { + fprintf(stderr, + "Failed to find active port, check port status with \"ibstat\"\n"); + exit(-1); + } + + h = osmv_bind_sa(vendor, &mad_pool, port_guid); + + if (h == OSM_BIND_INVALID_HANDLE) { + fprintf(stderr, "Failed to bind to SA\n"); + exit(-1); + } + return h; +} + +static void clean_up(void) +{ + osm_mad_pool_destroy(&mad_pool); + osm_vendor_delete(&vendor); +} + +static const struct query_cmd query_cmds[] = { + {"ClassPortInfo", "CPI", IB_MAD_ATTR_CLASS_PORT_INFO, + NULL, query_class_port_info}, + {"NodeRecord", "NR", IB_MAD_ATTR_NODE_RECORD, + NULL, query_node_records}, + {"PortInfoRecord", "PIR", IB_MAD_ATTR_PORTINFO_RECORD, + "[[lid]/[port]]", query_portinfo_records}, + {"SL2VLTableRecord", "SL2VL", IB_MAD_ATTR_SLVL_RECORD, + "[[lid]/[in_port]/[out_port]]", query_sl2vl_records}, + {"PKeyTableRecord", "PKTR", IB_MAD_ATTR_PKEY_TBL_RECORD, + "[[lid]/[port]/[block]]", query_pkey_tbl_records}, + {"VLArbitrationTableRecord", "VLAR", IB_MAD_ATTR_VLARB_RECORD, + "[[lid]/[port]/[block]]", query_vlarb_records}, + {"InformInfoRecord", "IIR", IB_MAD_ATTR_INFORM_INFO_RECORD, + NULL, query_informinfo_records}, + {"LinkRecord", "LR", IB_MAD_ATTR_LINK_RECORD, + "[[from_lid]/[from_port]] [[to_lid]/[to_port]]", query_link_records}, + {"ServiceRecord", "SR", IB_MAD_ATTR_SERVICE_RECORD, + NULL, query_service_records}, + {"PathRecord", "PR", IB_MAD_ATTR_PATH_RECORD, + NULL, query_path_records}, + {"MCMemberRecord", "MCMR", IB_MAD_ATTR_MCMEMBER_RECORD, + NULL, query_mcmember_records}, + {"LFTRecord", "LFTR", IB_MAD_ATTR_LFT_RECORD, + "[[lid]/[block]]", query_lft_records}, + {"MFTRecord", "MFTR", IB_MAD_ATTR_MFT_RECORD, + "[[mlid]/[position]/[block]]", query_mft_records}, + {0} +}; + +static const struct query_cmd *find_query(const char *name) +{ + const struct query_cmd *q; + unsigned len = strlen(name); + + for (q = query_cmds; q->name; q++) + if (!strncasecmp(name, q->name, len) || + (q->alias && !strncasecmp(name, q->alias, len))) + return q; + + return NULL; +} + +static const struct query_cmd *find_query_by_type(ib_net16_t type) +{ + const struct query_cmd *q; + + for (q = query_cmds; q->name; q++) + if (q->query_type == type) + return q; + + return NULL; +} + +static void usage(void) +{ + const struct query_cmd *q; + + fprintf(stderr, "Usage: %s [-h -d -p -N] [--list | -D] [-S -I -L -l -G" + " -O -U -c -s -g -m --src-to-dst --sgid-to-dgid " + "-C -P -t(imeout) ] [query-name] [ | | ]\n", + argv0); + fprintf(stderr, " Queries node records by default\n"); + fprintf(stderr, " -d enable debugging\n"); + fprintf(stderr, " -p get PathRecord info\n"); + fprintf(stderr, " -N get NodeRecord info\n"); + fprintf(stderr, " --list | -D the node desc of the CA's\n"); + fprintf(stderr, " -S get ServiceRecord info\n"); + fprintf(stderr, " -I get InformInfoRecord (subscription) info\n"); + fprintf(stderr, " -L return the Lids of the name specified\n"); + fprintf(stderr, " -l return the unique Lid of the name specified\n"); + fprintf(stderr, " -G return the Guids of the name specified\n"); + fprintf(stderr, " -O return name for the Lid specified\n"); + fprintf(stderr, " -U return name for the Guid specified\n"); + fprintf(stderr, " -c get the SA's class port info\n"); + fprintf(stderr, " -s return the PortInfoRecords with isSM or " + "isSMdisabled capability mask bit on\n"); + fprintf(stderr, " -g get multicast group info\n"); + fprintf(stderr, " -m get multicast member info\n"); + fprintf(stderr, " (if multicast group specified, list member GIDs" + " only for group specified\n"); + fprintf(stderr, " specified, for example 'saquery -m 0xC000')\n"); + fprintf(stderr, " -x get LinkRecord info\n"); + fprintf(stderr, " --src-to-dst get a PathRecord for \n" + " where src and dst are either node " + "names or LIDs\n"); + fprintf(stderr, " --sgid-to-dgid get a PathRecord for \n" + " where sgid and dgid are addresses in " + "IPv6 format\n"); + fprintf(stderr, " -C specify the SA query HCA\n"); + fprintf(stderr, " -P specify the SA query port\n"); + fprintf(stderr, " --smkey specify SM_Key value for the query." + " If non-numeric value \n" + " (like 'x') is specified then " + "saquery will prompt for a value\n"); + fprintf(stderr, " -t | --timeout specify the SA query " + "response timeout (default %u msec)\n", DEFAULT_SA_TIMEOUT_MS); + fprintf(stderr, + " --node-name-map specify a node name map\n"); + fprintf(stderr, "\n Supported query names (and aliases):\n"); + for (q = query_cmds; q->name; q++) + fprintf(stderr, " %s (%s) %s\n", q->name, + q->alias ? q->alias : "", q->usage ? q->usage : ""); + fprintf(stderr, "\n"); + + exit(-1); +} + +enum saquery_command { + SAQUERY_CMD_QUERY, + SAQUERY_CMD_NODE_RECORD, + SAQUERY_CMD_PATH_RECORD, + SAQUERY_CMD_CLASS_PORT_INFO, + SAQUERY_CMD_ISSM, + SAQUERY_CMD_MCGROUPS, + SAQUERY_CMD_MCMEMBERS, +}; + +int main(int argc, char **argv) +{ + int ch = 0; + osm_bind_handle_t h; + enum saquery_command command = SAQUERY_CMD_QUERY; + const struct query_cmd *q = NULL; + char *src = NULL, *dst = NULL; + char *sgid = NULL, *dgid = NULL; + ib_net16_t query_type = 0; + ib_net16_t src_lid, dst_lid; + ib_api_status_t status; + + static char const str_opts[] = "pVNDLlGOUcSIsgmxdhP:C:t:"; + static const struct option long_opts[] = { + {"p", 0, 0, 'p'}, + {"Version", 0, 0, 'V'}, + {"N", 0, 0, 'N'}, + {"L", 0, 0, 'L'}, + {"l", 0, 0, 'l'}, + {"G", 0, 0, 'G'}, + {"O", 0, 0, 'O'}, + {"U", 0, 0, 'U'}, + {"s", 0, 0, 's'}, + {"g", 0, 0, 'g'}, + {"m", 0, 0, 'm'}, + {"x", 0, 0, 'x'}, + {"d", 0, 0, 'd'}, + {"c", 0, 0, 'c'}, + {"S", 0, 0, 'S'}, + {"I", 0, 0, 'I'}, + {"P", 1, 0, 'P'}, + {"C", 1, 0, 'C'}, + {"help", 0, 0, 'h'}, + {"list", 0, 0, 'D'}, + {"src-to-dst", 1, 0, 1}, + {"sgid-to-dgid", 1, 0, 2}, + {"timeout", 1, 0, 't'}, + {"node-name-map", 1, 0, 3}, + {"smkey", 1, 0, 4}, + {} + }; + + argv0 = argv[0]; + + while ((ch = getopt_long(argc, argv, str_opts, long_opts, NULL)) != -1) { + switch (ch) { + case 1: + { + char *opt = strdup(optarg); + char *ch = strchr(opt, ':'); + if (!ch) { + fprintf(stderr, + "ERROR: --src-to-dst :\n"); + usage(); + } + *ch++ = '\0'; + if (*opt) + src = strdup(opt); + if (*ch) + dst = strdup(ch); + free(opt); + command = SAQUERY_CMD_PATH_RECORD; + break; + } + case 2: + { + char *opt = strdup(optarg); + char *tok1 = strtok(opt, "-"); + char *tok2 = strtok(NULL, "\0"); + + if (tok1 && tok2) { + sgid = strdup(tok1); + dgid = strdup(tok2); + } else { + fprintf(stderr, + "ERROR: --sgid-to-dgid -\n"); + usage(); + } + free(opt); + command = SAQUERY_CMD_PATH_RECORD; + break; + } + case 3: + node_name_map_file = strdup(optarg); + break; + case 4: + if (!isxdigit(*optarg) && + !(optarg = getpass("SM_Key: "))) { + fprintf(stderr, "cannot get SM_Key\n"); + usage(); + } + smkey = cl_hton64(strtoull(optarg, NULL, 0)); + break; + case 'p': + command = SAQUERY_CMD_PATH_RECORD; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version()); + exit(-1); + case 'D': + node_print_desc = ALL_DESC; + break; + case 'c': + command = SAQUERY_CMD_CLASS_PORT_INFO; + break; + case 'S': + query_type = IB_MAD_ATTR_SERVICE_RECORD; + break; + case 'I': + query_type = IB_MAD_ATTR_INFORM_INFO_RECORD; + break; + case 'N': + command = SAQUERY_CMD_NODE_RECORD; + break; + case 'L': + node_print_desc = LID_ONLY; + break; + case 'l': + node_print_desc = UNIQUE_LID_ONLY; + break; + case 'G': + node_print_desc = GUID_ONLY; + break; + case 'O': + node_print_desc = NAME_OF_LID; + break; + case 'U': + node_print_desc = NAME_OF_GUID; + break; + case 's': + command = SAQUERY_CMD_ISSM; + break; + case 'g': + command = SAQUERY_CMD_MCGROUPS; + break; + case 'm': + command = SAQUERY_CMD_MCMEMBERS; + break; + case 'x': + query_type = IB_MAD_ATTR_LINK_RECORD; + break; + case 'd': + osm_debug = 1; + break; + case 'C': + sa_hca_name = optarg; + break; + case 'P': + sa_port_num = strtoul(optarg, NULL, 0); + break; + case 't': + sa_timeout_ms = strtoul(optarg, NULL, 0); + break; + case 'h': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (!query_type) { + if (!argc || !(q = find_query(argv[0]))) + query_type = IB_MAD_ATTR_NODE_RECORD; + else { + query_type = q->query_type; + argc--; + argv++; + } + } + + if (argc) { + if (node_print_desc == NAME_OF_LID) { + requested_lid = (ib_net16_t) strtoul(argv[0], NULL, 0); + requested_lid_flag++; + } else if (node_print_desc == NAME_OF_GUID) { + requested_guid = (ib_net64_t) strtoul(argv[0], NULL, 0); + requested_guid_flag++; + } else { + requested_name = argv[0]; + } + } + + if ((node_print_desc == LID_ONLY || + node_print_desc == UNIQUE_LID_ONLY || + node_print_desc == GUID_ONLY) && !requested_name) { + fprintf(stderr, "ERROR: name not specified\n"); + usage(); + } + + if (node_print_desc == NAME_OF_LID && !requested_lid_flag) { + fprintf(stderr, "ERROR: lid not specified\n"); + usage(); + } + + if (node_print_desc == NAME_OF_GUID && !requested_guid_flag) { + fprintf(stderr, "ERROR: guid not specified\n"); + usage(); + } + + /* Note: lid cannot be 0; see infiniband spec 4.1.3 */ + if (node_print_desc == NAME_OF_LID && !requested_lid) { + fprintf(stderr, "ERROR: lid invalid\n"); + usage(); + } + + h = get_bind_handle(); + node_name_map = open_node_name_map(node_name_map_file); + + switch (command) { + case SAQUERY_CMD_NODE_RECORD: + status = print_node_records(h); + break; + case SAQUERY_CMD_PATH_RECORD: + if (src && dst) { + src_lid = get_lid(h, src); + dst_lid = get_lid(h, dst); + printf("Path record for %s -> %s\n", src, dst); + if (src_lid == 0 || dst_lid == 0) { + status = IB_UNKNOWN_ERROR; + } else { + status = + get_print_path_rec_lid(h, src_lid, dst_lid); + } + } else if (sgid && dgid) { + struct in6_addr src_addr, dst_addr; + + if (inet_pton(AF_INET6, sgid, &src_addr) <= 0) { + fprintf(stderr, "invalid src gid: %s\n", sgid); + exit(-1); + } + if (inet_pton(AF_INET6, dgid, &dst_addr) <= 0) { + fprintf(stderr, "invalid dst gid: %s\n", dgid); + exit(-1); + } + status = get_print_path_rec_gid(h, + (ib_gid_t *) & src_addr.s6_addr, + (ib_gid_t *) & dst_addr.s6_addr); + } else { + status = query_path_records(q, h, 0, NULL); + } + break; + case SAQUERY_CMD_CLASS_PORT_INFO: + status = get_print_class_port_info(h); + break; + case SAQUERY_CMD_ISSM: + status = print_issm_records(h); + break; + case SAQUERY_CMD_MCGROUPS: + status = print_multicast_group_records(h); + break; + case SAQUERY_CMD_MCMEMBERS: + status = print_multicast_member_records(h); + break; + default: + if ((!q && !(q = find_query_by_type(query_type))) + || !q->handler) { + fprintf(stderr, "Unknown query type %d\n", + ntohs(query_type)); + status = IB_UNKNOWN_ERROR; + } else + status = q->handler(q, h, argc, argv); + break; + } + + if (src) + free(src); + if (dst) + free(dst); + clean_up(); + close_node_name_map(node_name_map); + return (status); +} diff --git a/contrib/ofed/management/infiniband-diags/src/sminfo.c b/contrib/ofed/management/infiniband-diags/src/sminfo.c new file mode 100644 index 000000000000..c8110577414d --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/sminfo.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +static uint8_t sminfo[1024]; + +char *argv0 = "sminfo"; + +static void +usage(void) +{ + fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -s state -p prio -a activity -D(irect) -G(uid) -V(ersion) -C ca_name -P ca_port " + "-t(imeout) timeout_ms] [modifier]\n", + argv0); + exit(-1); +} + +int strdata, xdata=1, bindata; +enum { + SMINFO_NOTACT, + SMINFO_DISCOVER, + SMINFO_STANDBY, + SMINFO_MASTER, + + SMINFO_STATE_LAST, +}; + +char *statestr[] = { + [SMINFO_NOTACT] "SMINFO_NOTACT", + [SMINFO_DISCOVER] "SMINFO_DISCOVER", + [SMINFO_STANDBY] "SMINFO_STANDBY", + [SMINFO_MASTER] "SMINFO_MASTER", +}; + +#define STATESTR(s) (((unsigned)(s)) < SMINFO_STATE_LAST ? statestr[s] : "???") + +int +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + int mod = 0; + ib_portid_t portid = {0}; + int timeout = 0; /* use default */ + uint8_t *p; + unsigned act = 0; + int prio = 0, state = SMINFO_STANDBY; + uint64_t guid = 0, key = 0; + extern int ibdebug; + int dest_type = IB_DEST_LID; + int udebug = 0; + char *ca = 0; + int ca_port = 0; + + static char const str_opts[] = "C:P:t:s:p:a:deDGVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "err_show", 0, 0, 'e'}, + { "s", 1, 0, 's'}, + { "p", 1, 0, 'p'}, + { "a", 1, 0, 'a'}, + { "Direct", 0, 0, 'D'}, + { "Guid", 0, 0, 'G'}, + { "Version", 0, 0, 'V'}, + { "timeout", 1, 0, 't'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'e': + madrpc_show_errors(1); + break; + case 'D': + dest_type = IB_DEST_DRPATH; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'a': + act = strtoul(optarg, 0, 0); + break; + case 's': + state = strtoul(optarg, 0, 0); + break; + case 'p': + prio = strtoul(optarg, 0, 0); + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc > 1) + mod = atoi(argv[1]); + + madrpc_init(ca, ca_port, mgmt_classes, 3); + + if (argc) { + if (ib_resolve_portid_str(&portid, argv[0], dest_type, 0) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + } else { + if (ib_resolve_smlid(&portid, timeout) < 0) + IBERROR("can't resolve sm port %s", argv[0]); + } + + mad_encode_field(sminfo, IB_SMINFO_GUID_F, &guid); + mad_encode_field(sminfo, IB_SMINFO_ACT_F, &act); + mad_encode_field(sminfo, IB_SMINFO_KEY_F, &key); + mad_encode_field(sminfo, IB_SMINFO_PRIO_F, &prio); + mad_encode_field(sminfo, IB_SMINFO_STATE_F, &state); + + if (mod) { + if (!(p = smp_set(sminfo, &portid, IB_ATTR_SMINFO, mod, timeout))) + IBERROR("query"); + } else + if (!(p = smp_query(sminfo, &portid, IB_ATTR_SMINFO, 0, timeout))) + IBERROR("query"); + + mad_decode_field(sminfo, IB_SMINFO_GUID_F, &guid); + mad_decode_field(sminfo, IB_SMINFO_ACT_F, &act); + mad_decode_field(sminfo, IB_SMINFO_KEY_F, &key); + mad_decode_field(sminfo, IB_SMINFO_PRIO_F, &prio); + mad_decode_field(sminfo, IB_SMINFO_STATE_F, &state); + + printf("sminfo: sm lid %d sm guid 0x%" PRIx64 ", activity count %u priority %d state %d %s\n", + portid.lid, guid, act, prio, state, STATESTR(state)); + + exit(0); +} diff --git a/contrib/ofed/management/infiniband-diags/src/smpdump.c b/contrib/ofed/management/infiniband-diags/src/smpdump.c new file mode 100644 index 000000000000..de2ee8db8c26 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/smpdump.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#define _GNU_SOURCE + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +static const uint8_t CLASS_SUBN_DIRECTED_ROUTE = 0x81; +static const uint8_t CLASS_SUBN_LID_ROUTE = 0x1; + +#define ATTR_NODE_DESC ((uint16_t)(htons(0x10))) +#define ATTR_NODE_INFO ((uint16_t)(htons(0x11))) +#define ATTR_PORT_INFO ((uint16_t)(htons(0x15))) + +static int mad_agent; +static int drmad_tid = 0x123; + +static int debug, verbose; + +char *argv0 = "smpdump"; + +typedef struct { + char path[64]; + int hop_cnt; +} DRPath; + +struct drsmp { + uint8_t base_version; + uint8_t mgmt_class; + uint8_t class_version; + uint8_t method; + uint16_t status; + uint8_t hop_ptr; + uint8_t hop_cnt; + uint64_t tid; + uint16_t attr_id; + uint16_t resv; + uint32_t attr_mod; + uint64_t mkey; + uint16_t dr_slid; + uint16_t dr_dlid; + uint8_t reserved[28]; + uint8_t data[64]; + uint8_t initial_path[64]; + uint8_t return_path[64]; +}; + +void +drsmp_get_init(void *umad, DRPath *path, int attr, int mod) +{ + struct drsmp *smp = (struct drsmp *)(umad_get_mad(umad)); + + memset(smp, 0, sizeof (*smp)); + + smp->base_version = 1; + smp->mgmt_class = CLASS_SUBN_DIRECTED_ROUTE; + smp->class_version = 1; + + smp->method = 1; + smp->attr_id = (uint16_t)htons((uint16_t)attr); + smp->attr_mod = htonl(mod); + smp->tid = htonll(drmad_tid++); + smp->dr_slid = 0xffff; + smp->dr_dlid = 0xffff; + + umad_set_addr(umad, 0xffff, 0, 0, 0); + + if (path) + memcpy(smp->initial_path, path->path, path->hop_cnt+1); + + smp->hop_cnt = path->hop_cnt; +} + +void +smp_get_init(void *umad, int lid, int attr, int mod) +{ + struct drsmp *smp = (struct drsmp *)(umad_get_mad(umad)); + + memset(smp, 0, sizeof (*smp)); + + smp->base_version = 1; + smp->mgmt_class = CLASS_SUBN_LID_ROUTE; + smp->class_version = 1; + + smp->method = 1; + smp->attr_id = (uint16_t)htons((uint16_t)attr); + smp->attr_mod = htonl(mod); + smp->tid = htonll(drmad_tid++); + + umad_set_addr(umad, lid, 0, 0xffff, 0); +} + +void +drsmp_set_init(void *umad, DRPath *path, int attr, int mod, void *data) +{ + struct drsmp *smp = (struct drsmp *)(umad_get_mad(umad)); + + memset(smp, 0, sizeof (*smp)); + + smp->method = 2; /* SET */ + smp->attr_id = (uint16_t)htons((uint16_t)attr); + smp->attr_mod = htonl(mod); + smp->tid = htonll(drmad_tid++); + smp->dr_slid = 0xffff; + smp->dr_dlid = 0xffff; + + umad_set_addr(umad, 0xffff, 0, 0, 0); + + if (path) + memcpy(smp->initial_path, path->path, path->hop_cnt+1); + + if (data) + memcpy(smp->data, data, sizeof smp->data); + + smp->hop_cnt = path->hop_cnt; +} + +char * +drmad_status_str(struct drsmp *drsmp) +{ + switch (drsmp->status) { + case 0: + return "success"; + case ETIMEDOUT: + return "timeout"; + } + return "unknown error"; +} + +int +str2DRPath(char *str, DRPath *path) +{ + char *s; + + path->hop_cnt = -1; + + DEBUG("DR str: %s", str); + while (str && *str) { + if ((s = strchr(str, ','))) + *s = 0; + path->path[++path->hop_cnt] = atoi(str); + if (!s) + break; + str = s+1; + } + +#if 0 + if (path->path[0] != 0 || + (path->hop_cnt > 0 && dev_port && path->path[1] != dev_port)) { + DEBUG("hop 0 != 0 or hop 1 != dev_port"); + return -1; + } +#endif + + return path->hop_cnt; +} + +void +usage(void) +{ + fprintf(stderr, "Usage: %s [-s(ring) -D(irect) -V(ersion) -C ca_name -P ca_port -t(imeout) timeout_ms] [mod]\n", argv0); + fprintf(stderr, "\tDR examples:\n"); + fprintf(stderr, "\t\t%s -D 0,1,2,3,5 16 # NODE DESC\n", argv0); + fprintf(stderr, "\t\t%s -D 0,1,2 0x15 2 # PORT INFO, port 2\n", argv0); + fprintf(stderr, "\n\tLID routed examples:\n"); + fprintf(stderr, "\t\t%s 3 0x15 2 # PORT INFO, lid 3 port 2\n", argv0); + fprintf(stderr, "\t\t%s 0xa0 0x11 # NODE INFO, lid 0xa0\n", argv0); + fprintf(stderr, "\n"); + exit(-1); +} + +int +main(int argc, char *argv[]) +{ + int dump_char = 0, timeout_ms = 1000; + int dev_port = 0, mgmt_class = CLASS_SUBN_LID_ROUTE, dlid = 0; + char *dev_name = 0; + void *umad; + struct drsmp *smp; + int i, portid, mod = 0, attr; + DRPath path; + uint8_t *desc; + int length; + + static char const str_opts[] = "C:P:t:dsDVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "sring", 0, 0, 's'}, + { "Direct", 0, 0, 'D'}, + { "timeout", 1, 0, 't'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 's': + dump_char++; + break; + case 'd': + debug++; + if (debug > 1) + umad_debug(debug-1); + break; + case 'D': + mgmt_class = CLASS_SUBN_DIRECTED_ROUTE; + break; + case 'C': + dev_name = optarg; + break; + case 'P': + dev_port = atoi(optarg); + break; + case 't': + timeout_ms = strtoul(optarg, 0, 0); + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc < 2) + usage(); + + if (mgmt_class == CLASS_SUBN_DIRECTED_ROUTE && + str2DRPath(strdup(argv[0]), &path) < 0) + IBPANIC("bad path str '%s'", argv[0]); + + if (mgmt_class == CLASS_SUBN_LID_ROUTE) + dlid = strtoul(argv[0], 0, 0); + + attr = strtoul(argv[1], 0, 0); + if (argc > 2) + mod = strtoul(argv[2], 0, 0); + + if (umad_init() < 0) + IBPANIC("can't init UMAD library"); + + if ((portid = umad_open_port(dev_name, dev_port)) < 0) + IBPANIC("can't open UMAD port (%s:%d)", dev_name, dev_port); + + if ((mad_agent = umad_register(portid, mgmt_class, 1, 0, 0)) < 0) + IBPANIC("Couldn't register agent for SMPs"); + + if (!(umad = umad_alloc(1, umad_size() + IB_MAD_SIZE))) + IBPANIC("can't alloc MAD"); + + smp = umad_get_mad(umad); + + if (mgmt_class == CLASS_SUBN_DIRECTED_ROUTE) + drsmp_get_init(umad, &path, attr, mod); + else + smp_get_init(umad, dlid, attr, mod); + + if (debug > 1) + xdump(stderr, "before send:\n", smp, 256); + + length = IB_MAD_SIZE; + if (umad_send(portid, mad_agent, umad, length, timeout_ms, 0) < 0) + IBPANIC("send failed"); + + if (umad_recv(portid, umad, &length, -1) != mad_agent) + IBPANIC("recv error: %s", drmad_status_str(smp)); + + if (!dump_char) { + xdump(stdout, 0, smp->data, 64); + if (smp->status) + fprintf(stdout, "SMP status: 0x%x\n", ntohs(smp->status)); + return 0; + } + + desc = smp->data; + for (i = 0; i < 64; ++i) { + if (!desc[i]) + break; + putchar(desc[i]); + } + putchar('\n'); + if (smp->status) + fprintf(stdout, "SMP status: 0x%x\n", ntohs(smp->status)); + return 0; +} diff --git a/contrib/ofed/management/infiniband-diags/src/smpquery.c b/contrib/ofed/management/infiniband-diags/src/smpquery.c new file mode 100644 index 000000000000..ed8ec83c9a06 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/smpquery.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define __STDC_FORMAT_MACROS +#include + +#include +#include +#include +#include + +#include "ibdiag_common.h" + +#undef DEBUG +#define DEBUG if (verbose>1) IBWARN + +static int dest_type = IB_DEST_LID; +static int verbose; + +typedef char *(op_fn_t)(ib_portid_t *dest, char **argv, int argc); + +typedef struct match_rec { + char *name; + op_fn_t *fn; + unsigned opt_portnum; +} match_rec_t; + +static op_fn_t node_desc, node_info, port_info, switch_info, pkey_table, + sl2vl_table, vlarb_table, guid_info; + +static const match_rec_t match_tbl[] = { + { "nodeinfo", node_info }, + { "nodedesc", node_desc }, + { "portinfo", port_info, 1 }, + { "switchinfo", switch_info }, + { "pkeys", pkey_table, 1 }, + { "sl2vl", sl2vl_table, 1 }, + { "vlarb", vlarb_table, 1 }, + { "guids", guid_info }, + {0} +}; + +char *argv0 = "smpquery"; +static char *node_name_map_file = NULL; +static nn_map_t *node_name_map = NULL; + +/*******************************************/ +static char * +node_desc(ib_portid_t *dest, char **argv, int argc) +{ + int node_type, l; + uint64_t node_guid; + char nd[IB_SMP_DATA_SIZE]; + uint8_t data[IB_SMP_DATA_SIZE]; + char dots[128]; + char *nodename = NULL; + + if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) + return "node info query failed"; + + mad_decode_field(data, IB_NODE_TYPE_F, &node_type); + mad_decode_field(data, IB_NODE_GUID_F, &node_guid); + + if (!smp_query(nd, dest, IB_ATTR_NODE_DESC, 0, 0)) + return "node desc query failed"; + + nodename = remap_node_name(node_name_map, node_guid, nd); + + l = strlen(nodename); + if (l < 32) { + memset(dots, '.', 32 - l); + dots[32 - l] = '\0'; + } else { + dots[0] = '.'; + dots[1] = '\0'; + } + + printf("Node Description:%s%s\n", dots, nodename); + free(nodename); + return 0; +} + +static char * +node_info(ib_portid_t *dest, char **argv, int argc) +{ + char buf[2048]; + char data[IB_SMP_DATA_SIZE]; + + if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) + return "node info query failed"; + + mad_dump_nodeinfo(buf, sizeof buf, data, sizeof data); + + printf("# Node info: %s\n%s", portid2str(dest), buf); + return 0; +} + +static char * +port_info(ib_portid_t *dest, char **argv, int argc) +{ + char buf[2048]; + char data[IB_SMP_DATA_SIZE]; + int portnum = 0; + + if (argc > 0) + portnum = strtol(argv[0], 0, 0); + + if (!smp_query(data, dest, IB_ATTR_PORT_INFO, portnum, 0)) + return "port info query failed"; + + mad_dump_portinfo(buf, sizeof buf, data, sizeof data); + + printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf); + return 0; +} + +static char * +switch_info(ib_portid_t *dest, char **argv, int argc) +{ + char buf[2048]; + char data[IB_SMP_DATA_SIZE]; + + if (!smp_query(data, dest, IB_ATTR_SWITCH_INFO, 0, 0)) + return "switch info query failed"; + + mad_dump_switchinfo(buf, sizeof buf, data, sizeof data); + + printf("# Switch info: %s\n%s", portid2str(dest), buf); + return 0; +} + +static char * +pkey_table(ib_portid_t *dest, char **argv, int argc) +{ + uint8_t data[IB_SMP_DATA_SIZE]; + uint32_t i, j, k; + uint16_t *p; + unsigned mod; + int n, t, phy_ports; + int portnum = 0; + + if (argc > 0) + portnum = strtol(argv[0], 0, 0); + + /* Get the partition capacity */ + if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) + return "node info query failed"; + + mad_decode_field(data, IB_NODE_TYPE_F, &t); + mad_decode_field(data, IB_NODE_NPORTS_F, &phy_ports); + if (portnum > phy_ports) + return "invalid port number"; + + if ((t == IB_NODE_SWITCH) && (portnum != 0)) { + if (!smp_query(data, dest, IB_ATTR_SWITCH_INFO, 0, 0)) + return "switch info failed"; + mad_decode_field(data, IB_SW_PARTITION_ENFORCE_CAP_F, &n); + } else + mad_decode_field(data, IB_NODE_PARTITION_CAP_F, &n); + + for (i = 0; i < (n + 31) / 32; i++) { + mod = i | (portnum << 16); + if (!smp_query(data, dest, IB_ATTR_PKEY_TBL, mod, 0)) + return "pkey table query failed"; + if (i + 1 == (n + 31) / 32) + k = ((n + 7 - i * 32) / 8) * 8; + else + k = 32; + p = (uint16_t *) data; + for (j = 0; j < k; j += 8, p += 8) { + printf("%4u: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", + (i * 32) + j, + ntohs(p[0]), ntohs(p[1]), + ntohs(p[2]), ntohs(p[3]), + ntohs(p[4]), ntohs(p[5]), + ntohs(p[6]), ntohs(p[7])); + } + } + printf("%d pkeys capacity for this port\n", n); + + return 0; +} + +static char *sl2vl_dump_table_entry(ib_portid_t *dest, int in, int out) +{ + char buf[2048]; + char data[IB_SMP_DATA_SIZE]; + int portnum = (in << 8) | out; + + if (!smp_query(data, dest, IB_ATTR_SLVL_TABLE, portnum, 0)) + return "slvl query failed"; + + mad_dump_sltovl(buf, sizeof buf, data, sizeof data); + printf("ports: in %2d, out %2d: ", in, out); + printf("%s", buf); + return 0; +} + +static char * +sl2vl_table(ib_portid_t *dest, char **argv, int argc) +{ + uint8_t data[IB_SMP_DATA_SIZE]; + int type, num_ports, portnum = 0; + int i; + char *ret; + + if (argc > 0) + portnum = strtol(argv[0], 0, 0); + + if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) + return "node info query failed"; + + mad_decode_field(data, IB_NODE_TYPE_F, &type); + mad_decode_field(data, IB_NODE_NPORTS_F, &num_ports); + if (portnum > num_ports) + return "invalid port number"; + + printf("# SL2VL table: %s\n", portid2str(dest)); + printf("# SL: |"); + for (i = 0 ; i < 16 ; i++) + printf("%2d|", i); + printf("\n"); + + if (type != IB_NODE_SWITCH) + return sl2vl_dump_table_entry(dest, 0, 0); + + for (i = 0 ; i <= num_ports ; i++) { + ret = sl2vl_dump_table_entry(dest, i, portnum); + if (ret) + return ret; + } + return 0; +} + +static char *vlarb_dump_table_entry(ib_portid_t *dest, int portnum, int offset, unsigned cap) +{ + char buf[2048]; + char data[IB_SMP_DATA_SIZE]; + + if (!smp_query(data, dest, IB_ATTR_VL_ARBITRATION, + (offset << 16) | portnum, 0)) + return "vl arb query failed"; + mad_dump_vlarbitration(buf, sizeof(buf), data, cap * 2); + printf("%s", buf); + return 0; +} + +static char *vlarb_dump_table(ib_portid_t *dest, int portnum, + char *name, int offset, int cap) +{ + char *ret; + + printf("# %s priority VL Arbitration Table:", name); + ret = vlarb_dump_table_entry(dest, portnum, offset, + cap < 32 ? cap : 32); + if (!ret && cap > 32) + ret = vlarb_dump_table_entry(dest, portnum, offset + 1, + cap - 32); + return ret; +} + +static char * +vlarb_table(ib_portid_t *dest, char **argv, int argc) +{ + uint8_t data[IB_SMP_DATA_SIZE]; + int portnum = 0; + int type, enhsp0, lowcap, highcap; + char *ret = 0; + + if (argc > 0) + portnum = strtol(argv[0], 0, 0); + + /* port number of 0 could mean SP0 or port MAD arrives on */ + if (portnum == 0) { + if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) + return "node info query failed"; + + mad_decode_field(data, IB_NODE_TYPE_F, &type); + if (type == IB_NODE_SWITCH) { + if (!smp_query(data, dest, IB_ATTR_SWITCH_INFO, 0, 0)) + return "switch info query failed"; + mad_decode_field(data, IB_SW_ENHANCED_PORT0_F, &enhsp0); + if (!enhsp0) { + printf("# No VLArbitration tables (BSP0): %s port %d\n", + portid2str(dest), 0); + return 0; + } + } + } + + if (!smp_query(data, dest, IB_ATTR_PORT_INFO, portnum, 0)) + return "port info query failed"; + + mad_decode_field(data, IB_PORT_VL_ARBITRATION_LOW_CAP_F, &lowcap); + mad_decode_field(data, IB_PORT_VL_ARBITRATION_HIGH_CAP_F,&highcap); + + printf("# VLArbitration tables: %s port %d LowCap %d HighCap %d\n", + portid2str(dest), portnum, lowcap, highcap); + + if (lowcap > 0) + ret = vlarb_dump_table(dest, portnum, "Low", 1, lowcap); + + if (!ret && highcap > 0) + ret = vlarb_dump_table(dest, portnum, "High", 3, highcap); + + return ret; +} + +static char * +guid_info(ib_portid_t *dest, char **argv, int argc) +{ + uint8_t data[IB_SMP_DATA_SIZE]; + uint32_t i, j, k; + uint64_t *p; + unsigned mod; + int n; + + /* Get the guid capacity */ + if (!smp_query(data, dest, IB_ATTR_PORT_INFO, 0, 0)) + return "port info failed"; + mad_decode_field(data, IB_PORT_GUID_CAP_F, &n); + + for (i = 0; i < (n + 7) / 8; i++) { + mod = i; + if (!smp_query(data, dest, IB_ATTR_GUID_INFO, mod, 0)) + return "guid info query failed"; + if (i + 1 == (n + 7) / 8) + k = ((n + 1 - i * 8) / 2) * 2; + else + k = 8; + p = (uint64_t *) data; + for (j = 0; j < k; j += 2, p += 2) { + printf("%4u: 0x%016"PRIx64" 0x%016"PRIx64"\n", + (i * 8) + j, + ntohll(p[0]), ntohll(p[1])); + } + } + printf("%d guids capacity for this port\n", n); + + return 0; +} + +static op_fn_t * +match_op(char *name) +{ + const match_rec_t *r; + for (r = match_tbl; r->name; r++) + if (!strcmp(r->name, name)) + return r->fn; + return 0; +} + +static void +usage(void) +{ + char *basename; + const match_rec_t *r; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -D(irect) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port " + "-t(imeout) timeout_ms --node-name-map node-name-map] [op params]\n", + basename); + fprintf(stderr, "\tsupported ops:\n"); + for (r = match_tbl ; r->name ; r++) { + fprintf(stderr, "\t\t%s %s\n", r->name, + r->opt_portnum ? " []" : ""); + } + fprintf(stderr, "\n\texamples:\n"); + fprintf(stderr, "\t\t%s portinfo 3 1\t\t\t\t# portinfo by lid, with port modifier\n", basename); + fprintf(stderr, "\t\t%s -G switchinfo 0x2C9000100D051 1\t# switchinfo by guid\n", basename); + fprintf(stderr, "\t\t%s -D nodeinfo 0\t\t\t\t# nodeinfo by direct route\n", basename); + fprintf(stderr, "\t\t%s -c nodeinfo 6 0,12\t\t\t# nodeinfo by combined route\n", basename); + exit(-1); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + ib_portid_t portid = {0}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + extern int ibdebug; + int timeout = 0, udebug = 0; + char *ca = 0; + int ca_port = 0; + char *err; + op_fn_t *fn; + + static char const str_opts[] = "C:P:t:s:devDcGVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "err_show", 0, 0, 'e'}, + { "verbose", 0, 0, 'v'}, + { "Direct", 0, 0, 'D'}, + { "combined", 0, 0, 'c'}, + { "Guid", 0, 0, 'G'}, + { "smlid", 1, 0, 's'}, + { "timeout", 1, 0, 't'}, + { "node-name-map", 1, 0, 1}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 1: + node_name_map_file = strdup(optarg); + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'e': + madrpc_show_errors(1); + break; + case 'D': + dest_type = IB_DEST_DRPATH; + break; + case 'c': + dest_type = IB_DEST_DRSLID; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'v': + verbose++; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc < 2) + usage(); + + if (!(fn = match_op(argv[0]))) + IBERROR("operation '%s' not supported", argv[0]); + + madrpc_init(ca, ca_port, mgmt_classes, 3); + node_name_map = open_node_name_map(node_name_map_file); + + if (dest_type != IB_DEST_DRSLID) { + if (ib_resolve_portid_str(&portid, argv[1], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[1]); + if ((err = fn(&portid, argv+2, argc-2))) + IBERROR("operation %s: %s", argv[0], err); + } else { + char concat[64]; + + memset(concat, 0, 64); + snprintf(concat, sizeof(concat), "%s %s", argv[1], argv[2]); + if (ib_resolve_portid_str(&portid, concat, dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", concat); + if ((err = fn(&portid, argv+3, argc-3))) + IBERROR("operation %s: %s", argv[0], err); + } + close_node_name_map(node_name_map); + exit(0); +} diff --git a/contrib/ofed/management/infiniband-diags/src/vendstat.c b/contrib/ofed/management/infiniband-diags/src/vendstat.c new file mode 100644 index 000000000000..067498614ad6 --- /dev/null +++ b/contrib/ofed/management/infiniband-diags/src/vendstat.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +#define IS3_DEVICE_ID 47396 + +#define IB_MLX_VENDOR_CLASS 10 +/* Vendor specific Attribute IDs */ +#define IB_MLX_IS3_GENERAL_INFO 0x17 +#define IB_MLX_IS3_CONFIG_SPACE_ACCESS 0x50 +/* Config space addresses */ +#define IB_MLX_IS3_PORT_XMIT_WAIT 0x10013C + +char *argv0 = "vendstat"; + +typedef struct { + uint16_t hw_revision; + uint16_t device_id; + uint8_t reserved[24]; + uint32_t uptime; +} is3_hw_info_t; + +typedef struct { + uint8_t resv1; + uint8_t major; + uint8_t minor; + uint8_t sub_minor; + uint32_t build_id; + uint8_t month; + uint8_t day; + uint16_t year; + uint16_t resv2; + uint16_t hour; + uint8_t psid[16]; + uint32_t ini_file_version; +} is3_fw_info_t; + +typedef struct { + uint8_t resv1; + uint8_t major; + uint8_t minor; + uint8_t sub_minor; + uint8_t resv2[28]; +} is3_sw_info_t; + +typedef struct { + uint8_t reserved[8]; + is3_hw_info_t hw_info; + is3_fw_info_t fw_info; + is3_sw_info_t sw_info; +} is3_general_info_t; + +typedef struct { + uint32_t address; + uint32_t data; + uint32_t mask; +} is3_record_t; + +typedef struct { + uint8_t reserved[8]; + is3_record_t record[18]; +} is3_config_space_t; + +static void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -N -w -G(uid) -C ca_name -P ca_port " + "-t(imeout) timeout_ms -V(ersion) -h(elp)] \n", + basename); + fprintf(stderr, "\tExamples:\n"); + fprintf(stderr, "\t\t%s -N 6\t\t# read IS3 general information\n", basename); + fprintf(stderr, "\t\t%s -w 6\t\t# read IS3 port xmit wait counters\n", basename); + exit(-1); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[4] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS, IB_MLX_VENDOR_CLASS}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + ib_portid_t portid = {0}; + extern int ibdebug; + int dest_type = IB_DEST_LID; + int timeout = 0; /* use default */ + int port = 0; + char buf[1024]; + int udebug = 0; + char *ca = 0; + int ca_port = 0; + ib_vendor_call_t call; + is3_general_info_t *gi; + is3_config_space_t *cs; + int general_info = 0; + int xmit_wait = 0; + int i; + + static char const str_opts[] = "C:P:s:t:dNwGVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "N", 1, 0, 'N'}, + { "w", 1, 0, 'w'}, + { "debug", 0, 0, 'd'}, + { "Guid", 0, 0, 'G'}, + { "sm_portid", 1, 0, 's'}, + { "timeout", 1, 0, 't'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'N': + general_info = 1; + break; + case 'w': + xmit_wait = 1; + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc > 1) + port = strtoul(argv[1], 0, 0); + + madrpc_init(ca, ca_port, mgmt_classes, 4); + + if (argc) { + if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + } else { + if (ib_resolve_self(&portid, &port, 0) < 0) + IBERROR("can't resolve self port %s", argv[0]); + } + + /* Only General Info and Port Xmit Wait Counters */ + /* queries are currently supported */ + if (!general_info && !xmit_wait) + IBERROR("at least one of -N and -w must be specified"); + + /* These are Mellanox specific vendor MADs */ + /* but vendors change the VendorId so how know for sure ? */ + /* Would need a list of these and it might not be complete */ + /* so for right now, punt on this */ + + memset(&call, 0, sizeof(call)); + call.mgmt_class = IB_MLX_VENDOR_CLASS; + call.method = IB_MAD_METHOD_GET; + call.timeout = timeout; + + memset(&buf, 0, sizeof(buf)); + /* vendor ClassPortInfo is required attribute if class supported */ + call.attrid = CLASS_PORT_INFO; + if (!ib_vendor_call(&buf, &portid, &call)) + IBERROR("classportinfo query"); + + memset(&buf, 0, sizeof(buf)); + call.attrid = IB_MLX_IS3_GENERAL_INFO; + if (!ib_vendor_call(&buf, &portid, &call)) + IBERROR("vendstat"); + gi = (is3_general_info_t *)&buf; + + if (general_info) { + /* dump IS3 general info here */ + printf("hw_dev_rev: 0x%04x\n", ntohs(gi->hw_info.hw_revision)); + printf("hw_dev_id: 0x%04x\n", ntohs(gi->hw_info.device_id)); + printf("hw_uptime: 0x%08x\n", ntohl(gi->hw_info.uptime)); + printf("fw_version: %02d.%02d.%02d\n", + gi->fw_info.major, gi->fw_info.minor, gi->fw_info.sub_minor); + printf("fw_build_id: 0x%04x\n", ntohl(gi->fw_info.build_id)); + printf("fw_date: %02d/%02d/%04x\n", + gi->fw_info.month, gi->fw_info.day, ntohs(gi->fw_info.year)); + printf("fw_psid: '%s'\n", gi->fw_info.psid); + printf("fw_ini_ver: %d\n", ntohl(gi->fw_info.ini_file_version)); + printf("sw_version: %02d.%02d.%02d\n", + gi->sw_info.major, gi->sw_info.minor, gi->sw_info.sub_minor); + } + + if (xmit_wait) { + if (ntohs(gi->hw_info.device_id) != IS3_DEVICE_ID) + IBERROR("Unsupported device ID 0x%x", ntohs(gi->hw_info.device_id)); + + memset(&buf, 0, sizeof(buf)); + call.attrid = IB_MLX_IS3_CONFIG_SPACE_ACCESS; + /* Limit of 18 accesses per MAD ? */ + call.mod = 2 << 22 | 16 << 16; /* 16 records */ + /* Set record addresses for each port */ + cs = (is3_config_space_t *)&buf; + for (i = 0; i < 16; i++) + cs->record[i].address = htonl(IB_MLX_IS3_PORT_XMIT_WAIT + ((i + 1) << 12)); + if (!ib_vendor_call(&buf, &portid, &call)) + IBERROR("vendstat"); + + for (i = 0; i < 16; i++) + if (cs->record[i].data) /* PortXmitWait is 32 bit counter */ + printf("Port %d: PortXmitWait 0x%x\n", i + 4, ntohl(cs->record[i].data)); /* port 4 is first port */ + + /* Last 8 ports is another query */ + memset(&buf, 0, sizeof(buf)); + call.attrid = IB_MLX_IS3_CONFIG_SPACE_ACCESS; + call.mod = 2 << 22 | 8 << 16; /* 8 records */ + /* Set record addresses for each port */ + cs = (is3_config_space_t *)&buf; + for (i = 0; i < 8; i++) + cs->record[i].address = htonl(IB_MLX_IS3_PORT_XMIT_WAIT + ((i + 17) << 12)); + if (!ib_vendor_call(&buf, &portid, &call)) + IBERROR("vendstat"); + + for (i = 0; i < 8; i++) + if (cs->record[i].data) /* PortXmitWait is 32 bit counter */ + printf("Port %d: PortXmitWait 0x%x\n", + i < 4 ? i + 21 : i - 3, + ntohl(cs->record[i].data)); + } + + exit(0); +} diff --git a/contrib/ofed/management/libibcommon/AUTHORS b/contrib/ofed/management/libibcommon/AUTHORS new file mode 100644 index 000000000000..d09c13fe2781 --- /dev/null +++ b/contrib/ofed/management/libibcommon/AUTHORS @@ -0,0 +1,3 @@ +Shahar Frank +Hal Rosenstock +Sasha Khapyorsky diff --git a/contrib/ofed/management/libibcommon/COPYING b/contrib/ofed/management/libibcommon/COPYING new file mode 100644 index 000000000000..1b1ca1d2fb84 --- /dev/null +++ b/contrib/ofed/management/libibcommon/COPYING @@ -0,0 +1,384 @@ +This software with the exception of OpenSM is available to you +under a choice of one of two licenses. You may chose to be +licensed under the terms of the the OpenIB.org BSD license or +the GNU General Public License (GPL) Version 2, both included +below. + +OpenSM is licensed under either GNU General Public License (GPL) +Version 2, or Intel BSD + Patent license. See OpenSM for the +specific language for the latter licensing terms. + + +Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + +================================================================== + + OpenIB.org BSD license + +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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +================================================================== + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/ofed/management/libibcommon/ChangeLog b/contrib/ofed/management/libibcommon/ChangeLog new file mode 100644 index 000000000000..0fdeaa9a5158 --- /dev/null +++ b/contrib/ofed/management/libibcommon/ChangeLog @@ -0,0 +1,21 @@ +2007-06-29 Hal Rosenstock + + * Release version 1.0.4 + +2007-06-26 Hal Rosenstock + + * src/sysfs.c: Change uint to unsigned for strict ANSI + +2007-06-26 Michael S. Tsirkin + + * include/infiniband/common.h: Change uint to unsigned + for strict ANSI + +2007-01-25 Hal Rosenstock + + * Release version 1.0.2. + +2006-11-20 Sasha Khapyorsky + + * include/infiniband/common.h: Enable strict format/args + checking for printf() style functions diff --git a/contrib/ofed/management/libibcommon/Makefile.am b/contrib/ofed/management/libibcommon/Makefile.am new file mode 100644 index 000000000000..75889f48de19 --- /dev/null +++ b/contrib/ofed/management/libibcommon/Makefile.am @@ -0,0 +1,32 @@ + +SUBDIRS = . + +INCLUDES = -I$(srcdir)/include/infiniband + +lib_LTLIBRARIES = libibcommon.la + +libibcommon_la_CFLAGS = -Wall + +if HAVE_LD_VERSION_SCRIPT +libibcommon_version_script = -Wl,--version-script=$(srcdir)/src/libibcommon.map +else +libibcommon_version_script = +endif + +libibcommon_la_SOURCES = src/stack.c src/sysfs.c src/util.c src/time.c src/hash.c +libibcommon_la_LDFLAGS = -version-info $(ibcommon_api_version) \ + -export-dynamic $(libibcommon_version_script) +libibcommon_la_DEPENDENCIES = $(srcdir)/src/libibcommon.map + +libibcommonincludedir = $(includedir)/infiniband + +libibcommoninclude_HEADERS = $(srcdir)/include/infiniband/common.h + +EXTRA_DIST = $(srcdir)/include/infiniband/common.h \ + libibcommon.spec.in libibcommon.spec \ + $(srcdir)/src/libibcommon.map libibcommon.ver autogen.sh + +dist-hook: + if [ -x $(top_srcdir)/../gen_chlog.sh ] ; then \ + $(top_srcdir)/../gen_chlog.sh $(PACKAGE) > $(distdir)/ChangeLog ; \ + fi diff --git a/contrib/ofed/management/libibcommon/autogen.sh b/contrib/ofed/management/libibcommon/autogen.sh new file mode 100755 index 000000000000..4827884ba1f1 --- /dev/null +++ b/contrib/ofed/management/libibcommon/autogen.sh @@ -0,0 +1,11 @@ +#! /bin/sh + +# create config dir if not exist +test -d config || mkdir config + +set -x +aclocal -I config +libtoolize --force --copy +autoheader +automake --foreign --add-missing --copy +autoconf diff --git a/contrib/ofed/management/libibcommon/configure.in b/contrib/ofed/management/libibcommon/configure.in new file mode 100644 index 000000000000..0f2fc3326f78 --- /dev/null +++ b/contrib/ofed/management/libibcommon/configure.in @@ -0,0 +1,52 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(libibcommon, 1.2.0, general@lists.openfabrics.org) +AC_CONFIG_SRCDIR([src/stack.c]) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE + +AC_SUBST(RELEASE, ${RELEASE:-unknown}) +AC_SUBST(TARBALL, ${TARBALL:-${PACKAGE}-${VERSION}.tar.gz}) + +dnl the library version info is available in the file: libibcommon.ver +ibcommon_api_version=`grep LIBVERSION $srcdir/libibcommon.ver | sed 's/LIBVERSION=//'` +if test -z $ibcommon_api_version; then + ibcommon_api_version=1:0:0 +fi +AC_SUBST(ibcommon_api_version) + +dnl Checks for programs +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AM_PROG_LIBTOOL + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([fcntl.h inttypes.h netinet/in.h stdint.h stdlib.h string.h sys/ioctl.h syslog.h unistd.h]) + +dnl Checks for library functions +AC_TYPE_SIGNAL +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([strrchr strtoul strtoull]) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_STRUCT_TM + +AC_CACHE_CHECK(whether ld accepts --version-script, ac_cv_version_script, + if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then + ac_cv_version_script=yes + else + ac_cv_version_script=no + fi) + +AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$ac_cv_version_script" = "yes") + +AC_CONFIG_FILES([Makefile libibcommon.spec]) +AC_OUTPUT diff --git a/contrib/ofed/management/libibcommon/include/infiniband/common.h b/contrib/ofed/management/libibcommon/include/infiniband/common.h new file mode 100644 index 000000000000..e955593edb6e --- /dev/null +++ b/contrib/ofed/management/libibcommon/include/infiniband/common.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#ifndef ntohll +static inline uint64_t ntohll(uint64_t x) { + return bswap_64(x); +} +#endif +#ifndef htonll +static inline uint64_t htonll(uint64_t x) { + return bswap_64(x); +} +#endif +#elif __BYTE_ORDER == __BIG_ENDIAN +#ifndef ntohll +static inline uint64_t ntohll(uint64_t x) { + return x; +} +#endif +#ifndef htonll +static inline uint64_t htonll(uint64_t x) { + return x; +} +#endif +#endif /* __BYTE_ORDER == __BIG_ENDIAN */ + +/***************************** + * COMMON MACHINE INDEPENDENT + */ + +/* Misc. macros: */ +/** align value \a l to \a size (ceil) */ +#ifndef ALIGN +#define ALIGN(l, size) (((l) + ((size) - 1)) / (size) * (size)) + +/** align value \a l to \a sizeof 32 bit int (ceil) */ +#define ALIGN32(l) (ALIGN((l), sizeof(uint32))) +#endif + +/** printf style debugging MACRO, conmmon header includes name of function */ +#define IBWARN(fmt, args...) ibwarn(__FUNCTION__, fmt, ## args) + +/** printf style debugging MACRO, conmmon header includes name of function */ +#define LOG(fmt, args...) logmsg(__FUNCTION__, fmt, ## args) + +/** printf style abort MACRO, common header includes name of function */ +#define IBPANIC(fmt, args...) ibpanic(__FUNCTION__, fmt, ## args) + +/** abort program if expression \a x is \b false */ +#define SANITY(x) if (common.sanity && !(x))\ + ibpanic(__FUNCTION__,\ + "sanity check <%s> failed: line %d",\ + (x), __LINE__) + +/** avoid unused compilation warning */ +#ifndef USED +#define USED(x) while(0) {void *v = &(x); printf("%p", v);} +#endif + +/** define index macro for string array generated by enumstr.awk */ +#define ENUM_STR_DEF(enumname, last, val) (((unsigned)(val) < last) ? enumname ## _str[val] : "???") +#define ENUM_STR_ARRAY(name) char * name ## _str[] + +#ifdef __GNUC__ +#define IBCOMMON_STRICT_FORMAT __attribute__((format(printf, 2, 3))) +#else +#define IBCOMMON_STRICT_FORMAT +#endif + +/* util.c: debugging and tracing */ +void ibwarn(const char * const fn, char *msg, ...) IBCOMMON_STRICT_FORMAT; +void ibpanic(const char * const fn, char *msg, ...) IBCOMMON_STRICT_FORMAT; +void logmsg(const char *const fn, char *msg, ...) IBCOMMON_STRICT_FORMAT; + +void xdump(FILE *file, char *msg, void *p, int size); + +/* sysfs.c: /sys utilities */ +int sys_read_string(char *dir_name, char *file_name, char *str, int max_len); +int sys_read_guid(char *dir_name, char *file_name, uint64_t *net_guid); +int sys_read_gid(char *dir_name, char *file_name, uint8_t *gid); +int sys_read_uint64(char *dir_name, char *file_name, uint64_t *u); +int sys_read_uint(char *dir_name, char *file_name, unsigned *u); +int sys_scandir(const char *dirname, struct dirent ***namelist, + int (*select)(const struct dirent *), + int (*compar)(const struct dirent **, const struct dirent **)); + +/* stack.c */ +void stack_dump(void); +void enable_stack_dump(int loop); + +/* time.c */ +uint64_t getcurrenttime(void); + +/* hash.c */ +uint32_t fhash(uint8_t *k, int length, uint32_t initval); + +END_C_DECLS + +#endif /* __COMMON_H__ */ diff --git a/contrib/ofed/management/libibcommon/libibcommon.spec.in b/contrib/ofed/management/libibcommon/libibcommon.spec.in new file mode 100644 index 000000000000..bd328b0fc14c --- /dev/null +++ b/contrib/ofed/management/libibcommon/libibcommon.spec.in @@ -0,0 +1,72 @@ + +%define RELEASE @RELEASE@ +%define rel %{?CUSTOM_RELEASE} %{!?CUSTOM_RELEASE:%RELEASE} + +Summary: OpenFabrics Alliance InfiniBand management common library +Name: libibcommon +Version: @VERSION@ +Release: %rel%{?dist} +License: GPLv2 or BSD +Group: System Environment/Libraries +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +Source: http://www.openfabrics.org/downloads/management/@TARBALL@ +Url: http://openfabrics.org/ +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig +BuildRequires: libtool + +%description +libibcommon provides common utility functions for the OFA diagnostic and +management tools. + +%package devel +Summary: Development files for the libibcommon library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description devel +Development files for the libibcommon library. + +%package static +Summary: Static library files for the libibcommon library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} + +%description static +Static library files for the libibcommon library. + +%prep +%setup -q + +%build +%configure +make %{?_smp_mflags} + +%install +make DESTDIR=${RPM_BUILD_ROOT} install +# remove unpackaged files from the buildroot +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig +%post devel -p /sbin/ldconfig +%postun devel -p /sbin/ldconfig + +%files +%defattr(-,root,root) +%{_libdir}/libibcommon*.so.* +%doc AUTHORS COPYING ChangeLog + +%files devel +%defattr(-,root,root) +%{_libdir}/libibcommon.so +%{_includedir}/infiniband/*.h + +%files static +%defattr(-,root,root) +%{_libdir}/libibcommon.a diff --git a/contrib/ofed/management/libibcommon/libibcommon.ver b/contrib/ofed/management/libibcommon/libibcommon.ver new file mode 100644 index 000000000000..7b88f1b615c9 --- /dev/null +++ b/contrib/ofed/management/libibcommon/libibcommon.ver @@ -0,0 +1,9 @@ +# In this file we track the current API version +# of the IB common interface (and libraries) +# The version is built of the following +# tree numbers: +# API_REV:RUNNING_REV:AGE +# API_REV - advance on any added API +# RUNNING_REV - advance any change to the vendor files +# AGE - number of backward versions the API still supports +LIBVERSION=1:0:0 diff --git a/contrib/ofed/management/libibcommon/src/hash.c b/contrib/ofed/management/libibcommon/src/hash.c new file mode 100644 index 000000000000..05fbff245d2a --- /dev/null +++ b/contrib/ofed/management/libibcommon/src/hash.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2005 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this + * code any way you wish, private, educational, or commercial. It's free. + * + * See http://burtleburtle.net/bob/hash/evahash.html + * Use for hash table lookup, or anything where one collision in 2^^32 is + * acceptable. Do NOT use for cryptographic purposes. + */ + +#include + +#define hashsize(n) ((uint32)1<<(n)) +#define hashmask(n) (hashsize(n)-1) + + +/* +-------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. +For every delta with one or two bits set, and the deltas of all three + high bits or all three low bits, whether the original value of a,b,c + is almost all zero or is uniformly distributed, +* If mix() is run forward or backward, at least 32 bits in a,b,c + have at least 1/4 probability of changing. +* If mix() is run forward, every bit of c will change between 1/3 and + 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) +mix() was built out of 36 single-cycle latency instructions in a + structure that could supported 2x parallelism, like so: + a -= b; + a -= c; x = (c>>13); + b -= c; a ^= x; + b -= a; x = (a<<8); + c -= a; b ^= x; + c -= b; x = (b>>13); + ... + Unfortunately, superscalar Pentiums and Sparcs can't take advantage + of that parallelism. They've also turned some of those single-cycle + latency instructions into multi-cycle latency instructions. Still, + this is the fastest good hash I could find. There were about 2^^68 + to choose from. I only looked at a billion or so. +-------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<<8); \ + c -= a; c -= b; c ^= (b>>13); \ + a -= b; a -= c; a ^= (c>>12); \ + b -= c; b -= a; b ^= (a<<16); \ + c -= a; c -= b; c ^= (b>>5); \ + a -= b; a -= c; a ^= (c>>3); \ + b -= c; b -= a; b ^= (a<<10); \ + c -= a; c -= b; c ^= (b>>15); \ +} + +/* +-------------------------------------------------------------------- +fhash() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + len : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Every 1-bit and 2-bit delta achieves avalanche. +About 6*len+35 instructions. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8 **)k, do it like this: + for (i=0, h=0; i= 12) { + a += (k[0] + ((uint32_t)k[1]<<8) + + ((uint32_t)k[2]<<16) + ((uint32_t)k[3]<<24)); + b += (k[4] + ((uint32_t)k[5]<<8) + ((uint32_t)k[6]<<16) + + ((uint32_t)k[7]<<24)); + c += (k[8] + ((uint32_t)k[9]<<8) + ((uint32_t)k[10]<<16) + + ((uint32_t)k[11]<<24)); + mix(a, b, c); + k += 12; len -= 12; + } + + /* handle the last 11 bytes */ + c += length; + switch (len) { /* all the case statements fall through */ + case 11: c += ((uint32_t)k[10]<<24); + case 10: c += ((uint32_t)k[9]<<16); + case 9 : c += ((uint32_t)k[8]<<8); + /* the first byte of c is reserved for the length */ + case 8 : b += ((uint32_t)k[7]<<24); + case 7 : b += ((uint32_t)k[6]<<16); + case 6 : b += ((uint32_t)k[5]<<8); + case 5 : b += k[4]; + case 4 : a += ((uint32_t)k[3]<<24); + case 3 : a += ((uint32_t)k[2]<<16); + case 2 : a += ((uint32_t)k[1]<<8); + case 1 : a += k[0]; + /* case 0: nothing left to add */ + } + + mix(a, b, c); + + return c; +} diff --git a/contrib/ofed/management/libibcommon/src/libibcommon.map b/contrib/ofed/management/libibcommon/src/libibcommon.map new file mode 100644 index 000000000000..58291584387c --- /dev/null +++ b/contrib/ofed/management/libibcommon/src/libibcommon.map @@ -0,0 +1,18 @@ +IBCOMMON_1.0 { + global: + enable_stack_dump; + stack_dump; + sys_read_gid; + sys_read_guid; + sys_read_string; + sys_read_uint; + sys_read_uint64; + sys_scandir; + getcurrenttime; + fhash; + logmsg; + ibpanic; + ibwarn; + xdump; + local: *; +}; diff --git a/contrib/ofed/management/libibcommon/src/stack.c b/contrib/ofed/management/libibcommon/src/stack.c new file mode 100644 index 000000000000..a51edaebf44f --- /dev/null +++ b/contrib/ofed/management/libibcommon/src/stack.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2004,2005 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#define _GNU_SOURCE + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +static int loop_on_panic; + +void +stack_dump(void) +{ + if (!__builtin_frame_address(1)) + return + syslog(LOG_ALERT, "#1 %p\n", __builtin_return_address(1)); + + if (!__builtin_frame_address(2)) + return + syslog(LOG_ALERT, "#2 %p\n", __builtin_return_address(2)); + + if (!__builtin_frame_address(3)) + return + syslog(LOG_ALERT, "#3 %p\n", __builtin_return_address(3)); + + if (!__builtin_frame_address(4)) + return + syslog(LOG_ALERT, "#4 %p\n", __builtin_return_address(4)); + + if (!__builtin_frame_address(5)) + return + syslog(LOG_ALERT, "#5 %p\n", __builtin_return_address(5)); + + if (!__builtin_frame_address(6)) + return + syslog(LOG_ALERT, "#6 %p\n", __builtin_return_address(6)); + + if (!__builtin_frame_address(7)) + return + syslog(LOG_ALERT, "#7 %p\n", __builtin_return_address(7)); + + if (!__builtin_frame_address(8)) + return + syslog(LOG_ALERT, "#8 %p\n", __builtin_return_address(8)); + + if (!__builtin_frame_address(9)) + return + syslog(LOG_ALERT, "#9 %p\n", __builtin_return_address(9)); + + if (!__builtin_frame_address(10)) + return + syslog(LOG_ALERT, "#10 %p\n", __builtin_return_address(10)); + + if (!__builtin_frame_address(11)) + return + syslog(LOG_ALERT, "#11 %p\n", __builtin_return_address(11)); + + if (!__builtin_frame_address(12)) + return + syslog(LOG_ALERT, "#12 %p\n", __builtin_return_address(12)); + + if (!__builtin_frame_address(13)) + return + syslog(LOG_ALERT, "#13 %p\n", __builtin_return_address(13)); + + if (!__builtin_frame_address(14)) + return + syslog(LOG_ALERT, "#14 %p\n", __builtin_return_address(14)); + + if (!__builtin_frame_address(15)) + return + syslog(LOG_ALERT, "#15 %p\n", __builtin_return_address(15)); + + if (!__builtin_frame_address(16)) + return + syslog(LOG_ALERT, "#16 %p\n", __builtin_return_address(16)); + + if (!__builtin_frame_address(17)) + return + syslog(LOG_ALERT, "#17 %p\n", __builtin_return_address(17)); + + if (!__builtin_frame_address(18)) + return + syslog(LOG_ALERT, "#18 %p\n", __builtin_return_address(18)); +} + +static void +handler(int x) +{ + static int in; + time_t tm; + + if (!in) { + in++; + + syslog(LOG_ALERT, "*** exception handler: died with signal %d", x); + stack_dump(); + + fflush(NULL); + + tm = time(0); + fprintf(stderr, "%s *** exception handler: died with signal %d pid %d\n", + ctime(&tm), x, getpid()); + + fflush(NULL); + } + + if (loop_on_panic) { + fprintf(stderr, "exception handler: entering tight loop ... pid %d\n",getpid()); + for (; ; ) + ; + } + + signal(x, SIG_DFL); +} + +void +enable_stack_dump(int loop) +{ + loop_on_panic = loop; + signal(SIGILL, handler); + signal(SIGBUS, handler); + signal(SIGSEGV, handler); + signal(SIGABRT, handler); +} diff --git a/contrib/ofed/management/libibcommon/src/sysfs.c b/contrib/ofed/management/libibcommon/src/sysfs.c new file mode 100644 index 000000000000..dfa722f2b590 --- /dev/null +++ b/contrib/ofed/management/libibcommon/src/sysfs.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#define _GNU_SOURCE + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "common.h" + +static int +ret_code(void) +{ + int e = errno; + + if (e > 0) + return -e; + return e; +} + +int +sys_read_string(char *dir_name, char *file_name, char *str, int max_len) +{ + char path[256], *s; + size_t len; + + snprintf(path, sizeof(path), "%s/%s", dir_name, file_name); + + for (s = &path[0]; *s != '\0'; s++) + if (*s == '/') + *s = '.'; + + len = max_len; + if (sysctlbyname(&path[1], str, &len, NULL, 0) == -1) + return ret_code(); + + str[(len < max_len) ? len : max_len - 1] = 0; + + if ((s = strrchr(str, '\n'))) + *s = 0; + + return 0; +} + +int +sys_read_guid(char *dir_name, char *file_name, uint64_t *net_guid) +{ + char buf[32], *str, *s; + uint64_t guid; + int r, i; + + if ((r = sys_read_string(dir_name, file_name, buf, sizeof(buf))) < 0) + return r; + + guid = 0; + + for (s = buf, i = 0 ; i < 4; i++) { + if (!(str = strsep(&s, ": \t\n"))) + return -EINVAL; + guid = (guid << 16) | (strtoul(str, 0, 16) & 0xffff); + } + + *net_guid = htonll(guid); + + return 0; +} + +int +sys_read_gid(char *dir_name, char *file_name, uint8_t *gid) +{ + char buf[64], *str, *s; + uint16_t *ugid = (uint16_t *)gid; + int r, i; + + if ((r = sys_read_string(dir_name, file_name, buf, sizeof(buf))) < 0) + return r; + + for (s = buf, i = 0 ; i < 8; i++) { + if (!(str = strsep(&s, ": \t\n"))) + return -EINVAL; + ugid[i] = htons(strtoul(str, 0, 16) & 0xffff); + } + + return 0; +} + +int +sys_read_uint64(char *dir_name, char *file_name, uint64_t *u) +{ + char buf[32]; + int r; + + if ((r = sys_read_string(dir_name, file_name, buf, sizeof(buf))) < 0) + return r; + + *u = strtoull(buf, 0, 0); + + return 0; +} + +int +sys_read_uint(char *dir_name, char *file_name, unsigned *u) +{ + char buf[32]; + int r; + + if ((r = sys_read_string(dir_name, file_name, buf, sizeof(buf))) < 0) + return r; + + *u = strtoul(buf, 0, 0); + + return 0; +} + +#define DIRECTSIZ(namlen) \ + (((uintptr_t)&((struct dirent *)0)->d_name + \ + ((namlen)+1)*sizeof(((struct dirent *)0)->d_name[0]) + 3) & ~3) + +int +sys_scandir(const char *dirname, struct dirent ***namelist, + int (*select)(const struct dirent *), + int (*compar)(const struct dirent **, const struct dirent **)) +{ + struct dirent **names; + struct dirent **names2; + struct dirent *dp; + char name[1024]; + int lsname[22]; + int chname[22]; + int name2[22]; + int oid[22]; + char *s; + size_t n1, n2; + size_t len, oidlen, namlen; + int cnt, max; + int err; + int i; + + *namelist = NULL; + /* Skip the leading / */ + strncpy(name, &dirname[1], sizeof(name)); + for (s = &name[0]; *s != '\0'; s++) + if (*s == '/') + *s = '.'; + /* + * Resolve the path. + */ + len = sizeof(oid) / sizeof(int); + namlen = strlen(name) + 1; + if (sysctlnametomib(name, oid, &len) != 0) + return (-errno); + lsname[0] = 0; /* Root */ + lsname[1] = 2; /* Get next */ + memcpy(lsname+2, oid, len * sizeof(int)); + n1 = 2 + len; + oidlen = len; + /* + * Setup the return list of dirents. + */ + cnt = 0; + max = 64; + names = malloc(max * sizeof(void *)); + if (names == NULL) + return (-ENOMEM); + + for (;;) { + n2 = sizeof(name2); + if (sysctl(lsname, n1, name2, &n2, 0, 0) < 0) { + if (errno == ENOENT) + break; + goto errout; + } + n2 /= sizeof(int); + if (n2 < oidlen) + break; + for (i = 0; i < oidlen; i++) + if (name2[i] != oid[i]) + goto out; + chname[0] = 0; /* root */ + chname[1] = 1; /* oid name */ + memcpy(chname + 2, name2, n2 * sizeof(int)); + memcpy(lsname + 2, name2, n2 * sizeof(int)); + n1 = 2 + n2; + /* + * scandir() is not supposed to go deeper than the requested + * directory but sysctl also doesn't return a node for + * 'subdirectories' so we have to find a file in the subdir + * and then truncate the name to report it. + */ + if (n2 > oidlen + 1) { + /* Skip to the next name after this one. */ + n1 = 2 + oidlen + 1; + lsname[n1 - 1]++; + } + len = sizeof(name); + if (sysctl(chname, n2 + 2, name, &len, 0, 0) < 0) + goto errout; + if (len <= 0 || len < namlen) + goto out; + s = name + namlen; + /* Just keep the first level name. */ + if (strchr(s, '.')) + *strchr(s, '.') = '\0'; + len = strlen(s) + 1; + dp = malloc(DIRECTSIZ(len)); + dp->d_reclen = DIRECTSIZ(len); + dp->d_namlen = len; + memcpy(&dp->d_name, s, len); + if (select && !select(dp)) { + free(dp); + continue; + } + if (cnt == max) { + max *= 2; + names2 = realloc(names, max * sizeof(void *)); + if (names2 == NULL) { + errno = ENOMEM; + free(dp); + goto errout; + } + names = names2; + } + names[cnt++] = dp; + } +out: + if (cnt && compar) + qsort(names, cnt, sizeof(struct dirent *), + (int (*)(const void *, const void *))compar); + + *namelist = names; + + return (cnt); + +errout: + err = errno; + for (i = 0; i < cnt; i++) + free(names[i]); + free(names); + return (-err); +} diff --git a/contrib/ofed/management/libibcommon/src/time.c b/contrib/ofed/management/libibcommon/src/time.c new file mode 100644 index 000000000000..7354d6a59ed6 --- /dev/null +++ b/contrib/ofed/management/libibcommon/src/time.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2004,2005 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include + +/** + * getcurrenttime: Returns micro seconds elapsed from epoch. + */ +uint64_t +getcurrenttime(void) +{ + struct timeval tv; + + gettimeofday(&tv, 0); + return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec; +} diff --git a/contrib/ofed/management/libibcommon/src/util.c b/contrib/ofed/management/libibcommon/src/util.c new file mode 100644 index 000000000000..4b91644bcbff --- /dev/null +++ b/contrib/ofed/management/libibcommon/src/util.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#define _GNU_SOURCE + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +void +ibwarn(const char * const fn, char *msg, ...) +{ + char buf[512]; + va_list va; + int n; + + va_start(va, msg); + n = vsnprintf(buf, sizeof(buf), msg, va); + va_end(va); + + printf("ibwarn: [%d] %s: %s\n", getpid(), fn, buf); +} + +void +ibpanic(const char * const fn, char *msg, ...) +{ + char buf[512]; + va_list va; + int n; + + va_start(va, msg); + n = vsnprintf(buf, sizeof(buf), msg, va); + va_end(va); + + printf("ibpanic: [%d] %s: %s: (%m)\n", getpid(), fn, buf); + syslog(LOG_ALERT, "ibpanic: [%d] %s: %s: (%m)\n", getpid(), fn, buf); + + exit(-1); +} + +void +logmsg(const char * const fn, char *msg, ...) +{ + char buf[512]; + va_list va; + int n; + + va_start(va, msg); + n = vsnprintf(buf, sizeof(buf), msg, va); + va_end(va); + + syslog(LOG_ALERT, "[%d] %s: %s: (%m)\n", getpid(), fn, buf); +} + +void +xdump(FILE *file, char *msg, void *p, int size) +{ +#define HEX(x) ((x) < 10 ? '0' + (x) : 'a' + ((x) -10)) + uint8_t *cp = p; + int i; + + if (msg) + fputs(msg, file); + + for (i = 0; i < size;) { + fputc(HEX(*cp >> 4), file); + fputc(HEX(*cp & 0xf), file); + if (++i >= size) + break; + fputc(HEX(cp[1] >> 4), file); + fputc(HEX(cp[1] & 0xf), file); + if ((++i) % 16) + fputc(' ', file); + else + fputc('\n', file); + cp += 2; + } + if (i % 16) { + fputc('\n', file); + } +} diff --git a/contrib/ofed/management/libibmad/AUTHORS b/contrib/ofed/management/libibmad/AUTHORS new file mode 100644 index 000000000000..d09c13fe2781 --- /dev/null +++ b/contrib/ofed/management/libibmad/AUTHORS @@ -0,0 +1,3 @@ +Shahar Frank +Hal Rosenstock +Sasha Khapyorsky diff --git a/contrib/ofed/management/libibmad/COPYING b/contrib/ofed/management/libibmad/COPYING new file mode 100644 index 000000000000..1b1ca1d2fb84 --- /dev/null +++ b/contrib/ofed/management/libibmad/COPYING @@ -0,0 +1,384 @@ +This software with the exception of OpenSM is available to you +under a choice of one of two licenses. You may chose to be +licensed under the terms of the the OpenIB.org BSD license or +the GNU General Public License (GPL) Version 2, both included +below. + +OpenSM is licensed under either GNU General Public License (GPL) +Version 2, or Intel BSD + Patent license. See OpenSM for the +specific language for the latter licensing terms. + + +Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + +================================================================== + + OpenIB.org BSD license + +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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +================================================================== + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/ofed/management/libibmad/ChangeLog b/contrib/ofed/management/libibmad/ChangeLog new file mode 100644 index 000000000000..0c4c337ee34e --- /dev/null +++ b/contrib/ofed/management/libibmad/ChangeLog @@ -0,0 +1,88 @@ +2008-06-15 Max Matveev + * Add extra entry points for most functions to allow explicit + selection of HCA for MAD rpc. + * Constify MAD port pointer for mad_rpc, mad_rpc_rmpp, and sa_rpc_call + +2007-07-10 Hal Rosenstock + + * Release version 1.1.1. + +2007-06-26 Hal Rosenstock + + * src/dump.c, src/fields.c, src/gs.c, src/rpc.c, src/sa.c, + src/smp.c: Change uint to unsigned for strict ANSI + +2007-06-26 Michael S. Tsirkin + + * include/infiniband/mad.h: Change uint to unsigned + for strict ANSI + +2007-06-18 Hal Rosenstock + + * include/infiniband/mad.h, src/fields.c: Change IB_PORT_MTRU_CAP_F + to IB_PORT_MTU_CAP_F + +2007-06-05 Sasha Khapyorsky + + * include/infiniband/mad.h, src/fields.c: Add Notice DataDetails + fields for DataDetails, and trap 144 LID and CapabilityMask + +2007-05-21 Hal Rosenstock + + * src/fields.c: Changed PortMulticastPkts to PortMulticastRcvPkts + +2007-03-29 Hal Rosenstock + + * src/fields.c: Changed Xmt/RcvBytes to Xmt/RcvData + +2007-03-29 Hal Rosenstock + + * Release version 1.1.0. + +2007-03-22 Hal Rosenstock + + * src/mad.c: Implement GRH support in mad_build_pkt + + * include/infiniband/mad.h: In ib_portid_set, ensure + grh_present is 0 + + * src/portid.c: In portid2str, fix endian of dispay of GID + +2007-03-14 Hal Rosenstock + + * include/infiniband/mad.h, src/fields.c: Add encode/decode + support for GUID0 in SM GUIDInfo attribute + +2007-03-14 Dotan Barak + + * include/infiniband/mad.h: Add GUIDInfo as SM attribute ID + +2007-02-08 Ira Weiny + + * src/portid.c: Change DR path output to be comma separated + decimal values like OpenSM + +2007-01-25 Hal Rosenstock + + * Release version 1.0.2. + +2006-12-11 Hal Rosenstock + + * src/(sa serv smp vendor).c: Change some debug parameters + to hex from decimal + +2006-11-20 Sasha Khapyorsky + + * src/rpc.c: Fix various uses of printf() style functions + +2006-10-20 Hal Rosenstock + + * include/infiniband/mad.h, src/resolve.c (ib_resolve_portid_str), + src/smp.c (smp_set), src/mad.c (mad_build_pkt), + src/portid.c (portid2str): Add and handle IB_DEST_DRSLID. + +2006-10-09 Hal Rosenstock + + * src/resolve.c (ib_resolve_portid_str): Use strtoull rather than + strtoll for IB_DEST_GUID + diff --git a/contrib/ofed/management/libibmad/Makefile.am b/contrib/ofed/management/libibmad/Makefile.am new file mode 100644 index 000000000000..beae1a478d6e --- /dev/null +++ b/contrib/ofed/management/libibmad/Makefile.am @@ -0,0 +1,34 @@ + +SUBDIRS = . + +INCLUDES = -I$(srcdir)/include/infiniband -I$(includedir) + +lib_LTLIBRARIES = libibmad.la + +libibmad_la_CFLAGS = -Wall + +if HAVE_LD_VERSION_SCRIPT +libibmad_version_script = -Wl,--version-script=$(srcdir)/src/libibmad.map +else +libibmad_version_script = +endif + +libibmad_la_SOURCES = src/dump.c src/fields.c src/mad.c src/portid.c \ + src/resolve.c src/rpc.c src/sa.c src/smp.c src/gs.c \ + src/serv.c src/register.c src/vendor.c + +libibmad_la_LDFLAGS = -version-info $(ibmad_api_version) \ + -export-dynamic $(libibmad_version_script) +libibmad_la_DEPENDENCIES = $(srcdir)/src/libibmad.map + +libibmadincludedir = $(includedir)/infiniband + +libibmadinclude_HEADERS = $(srcdir)/include/infiniband/mad.h + +EXTRA_DIST = $(srcdir)/include/infiniband/mad.h libibmad.spec.in libibmad.spec \ + $(srcdir)/src/libibmad.map libibmad.ver autogen.sh + +dist-hook: + if [ -x $(top_srcdir)/../gen_chlog.sh ] ; then \ + $(top_srcdir)/../gen_chlog.sh $(PACKAGE) > $(distdir)/ChangeLog ; \ + fi diff --git a/contrib/ofed/management/libibmad/autogen.sh b/contrib/ofed/management/libibmad/autogen.sh new file mode 100755 index 000000000000..4827884ba1f1 --- /dev/null +++ b/contrib/ofed/management/libibmad/autogen.sh @@ -0,0 +1,11 @@ +#! /bin/sh + +# create config dir if not exist +test -d config || mkdir config + +set -x +aclocal -I config +libtoolize --force --copy +autoheader +automake --foreign --add-missing --copy +autoconf diff --git a/contrib/ofed/management/libibmad/configure.in b/contrib/ofed/management/libibmad/configure.in new file mode 100644 index 000000000000..3d8e73d16162 --- /dev/null +++ b/contrib/ofed/management/libibmad/configure.in @@ -0,0 +1,70 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(libibmad, 1.3.0, general@lists.openfabrics.org) +AC_CONFIG_SRCDIR([src/sa.c]) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE + +AC_SUBST(RELEASE, ${RELEASE:-unknown}) +AC_SUBST(TARBALL, ${TARBALL:-${PACKAGE}-${VERSION}.tar.gz}) + +dnl the library version info is available in the file: libibmad.ver +ibmad_api_version=`grep LIBVERSION $srcdir/libibmad.ver | sed 's/LIBVERSION=//'` +if test -z $ibmad_api_version; then + ibmad_api_version=1:0:0 +fi +AC_SUBST(ibmad_api_version) + +AC_ARG_ENABLE(libcheck, [ --disable-libcheck do not test for presence of ib libraries], +[ if test x$enableval = xno ; then + disable_libcheck=yes + fi +]) + +AM_PROG_LIBTOOL + +dnl Checks for programs +AC_PROG_CC + +dnl Checks for libraries +if test "$disable_libcheck" != "yes" +then +AC_CHECK_LIB(ibcommon, sys_read_string, [], + AC_MSG_ERROR([sys_read_string() not found. libibmad requires libibcommon.])) +AC_CHECK_LIB(ibumad, umad_init, [], + AC_MSG_ERROR([umad_init() not found. libibmad requires libibumad.])) +fi + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([netinet/in.h stdlib.h string.h sys/time.h unistd.h]) +if test "$disable_libcheck" != "yes" +then +AC_CHECK_HEADER(infiniband/common.h, [], + AC_MSG_ERROR([ not found. libibmad requires libibcommon.]) +) +AC_CHECK_HEADER(infiniband/umad.h, [], + AC_MSG_ERROR([ not found. libibmad requires libibumad.]) +) +fi + +dnl Checks for library functions +AC_CHECK_FUNCS([memset strrchr strtol]) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE + +AC_CACHE_CHECK(whether ld accepts --version-script, ac_cv_version_script, + if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then + ac_cv_version_script=yes + else + ac_cv_version_script=no + fi) + +AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$ac_cv_version_script" = "yes") + +AC_CONFIG_FILES([Makefile libibmad.spec]) +AC_OUTPUT diff --git a/contrib/ofed/management/libibmad/include/infiniband/mad.h b/contrib/ofed/management/libibmad/include/infiniband/mad.h new file mode 100644 index 000000000000..c2ad148f6744 --- /dev/null +++ b/contrib/ofed/management/libibmad/include/infiniband/mad.h @@ -0,0 +1,905 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#ifndef _MAD_H_ +#define _MAD_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +#define IB_SUBNET_PATH_HOPS_MAX 64 +#define IB_DEFAULT_SUBN_PREFIX 0xfe80000000000000llu +#define IB_DEFAULT_QP1_QKEY 0x80010000 + +#define IB_MAD_SIZE 256 + +#define IB_SMP_DATA_OFFS 64 +#define IB_SMP_DATA_SIZE 64 + +#define IB_VENDOR_RANGE1_DATA_OFFS 24 +#define IB_VENDOR_RANGE1_DATA_SIZE (IB_MAD_SIZE - IB_VENDOR_RANGE1_DATA_OFFS) + +#define IB_VENDOR_RANGE2_DATA_OFFS 40 +#define IB_VENDOR_RANGE2_DATA_SIZE (IB_MAD_SIZE - IB_VENDOR_RANGE2_DATA_OFFS) + +#define IB_SA_DATA_SIZE 200 +#define IB_SA_DATA_OFFS 56 + +#define IB_PC_DATA_OFFS 64 +#define IB_PC_DATA_SZ (IB_MAD_SIZE - IB_PC_DATA_OFFS) + +#define IB_SA_MCM_RECSZ 53 +#define IB_SA_PR_RECSZ 64 + +enum MAD_CLASSES { + IB_SMI_CLASS = 0x1, + IB_SMI_DIRECT_CLASS = 0x81, + IB_SA_CLASS = 0x3, + IB_PERFORMANCE_CLASS = 0x4, + IB_BOARD_MGMT_CLASS = 0x5, + IB_DEVICE_MGMT_CLASS = 0x6, + IB_CM_CLASS = 0x7, + IB_SNMP_CLASS = 0x8, + IB_VENDOR_RANGE1_START_CLASS = 0x9, + IB_VENDOR_RANGE1_END_CLASS = 0x0f, + IB_CC_CLASS = 0x21, + IB_VENDOR_RANGE2_START_CLASS = 0x30, + IB_VENDOR_RANGE2_END_CLASS = 0x4f, +}; + +enum MAD_METHODS { + IB_MAD_METHOD_GET = 0x1, + IB_MAD_METHOD_SET = 0x2, + IB_MAD_METHOD_GET_RESPONSE = 0x81, + + IB_MAD_METHOD_SEND = 0x3, + IB_MAD_METHOD_TRAP = 0x5, + IB_MAD_METHOD_TRAP_REPRESS = 0x7, + + IB_MAD_METHOD_REPORT = 0x6, + IB_MAD_METHOD_REPORT_RESPONSE = 0x86, + IB_MAD_METHOD_GET_TABLE = 0x12, + IB_MAD_METHOD_GET_TABLE_RESPONSE = 0x92, + IB_MAD_METHOD_GET_TRACE_TABLE = 0x13, + IB_MAD_METHOD_GET_TRACE_TABLE_RESPONSE = 0x93, + IB_MAD_METHOD_GETMULTI = 0x14, + IB_MAD_METHOD_GETMULTI_RESPONSE = 0x94, + IB_MAD_METHOD_DELETE = 0x15, + IB_MAD_METHOD_DELETE_RESPONSE = 0x95, + + IB_MAD_RESPONSE = 0x80, +}; + +enum MAD_ATTR_ID { + CLASS_PORT_INFO = 0x1, + NOTICE = 0x2, + INFORM_INFO = 0x3, +}; + +enum SMI_ATTR_ID { + IB_ATTR_NODE_DESC = 0x10, + IB_ATTR_NODE_INFO = 0x11, + IB_ATTR_SWITCH_INFO = 0x12, + IB_ATTR_GUID_INFO = 0x14, + IB_ATTR_PORT_INFO = 0x15, + IB_ATTR_PKEY_TBL = 0x16, + IB_ATTR_SLVL_TABLE = 0x17, + IB_ATTR_VL_ARBITRATION = 0x18, + IB_ATTR_LINEARFORWTBL = 0x19, + IB_ATTR_MULTICASTFORWTBL = 0x1b, + IB_ATTR_SMINFO = 0x20, + + IB_ATTR_LAST +}; + +enum SA_ATTR_ID { + IB_SA_ATTR_NOTICE = 0x02, + IB_SA_ATTR_INFORMINFO = 0x03, + IB_SA_ATTR_PORTINFORECORD = 0x12, + IB_SA_ATTR_LINKRECORD = 0x20, + IB_SA_ATTR_SERVICERECORD = 0x31, + IB_SA_ATTR_PATHRECORD = 0x35, + IB_SA_ATTR_MCRECORD = 0x38, + IB_SA_ATTR_MULTIPATH = 0x3a, + + IB_SA_ATTR_LAST +}; + +enum GSI_ATTR_ID { + IB_GSI_PORT_SAMPLES_CONTROL = 0x10, + IB_GSI_PORT_SAMPLES_RESULT = 0x11, + IB_GSI_PORT_COUNTERS = 0x12, + IB_GSI_PORT_COUNTERS_EXT = 0x1D, + + IB_GSI_ATTR_LAST +}; + +#define IB_VENDOR_OPENIB_PING_CLASS (IB_VENDOR_RANGE2_START_CLASS + 2) +#define IB_VENDOR_OPENIB_SYSSTAT_CLASS (IB_VENDOR_RANGE2_START_CLASS + 3) +#define IB_OPENIB_OUI (0x001405) + +typedef uint8_t ibmad_gid_t[16]; +#ifdef USE_DEPRECATED_IB_GID_T +typedef ibmad_gid_t ib_gid_t __attribute__((deprecated)); +#endif + +typedef struct { + int cnt; + uint8_t p[IB_SUBNET_PATH_HOPS_MAX]; + uint16_t drslid; + uint16_t drdlid; +} ib_dr_path_t; + +typedef struct { + unsigned id; + unsigned mod; +} ib_attr_t; + +typedef struct { + int mgtclass; + int method; + ib_attr_t attr; + uint32_t rstatus; /* return status */ + int dataoffs; + int datasz; + uint64_t mkey; + uint64_t trid; /* used for out mad if nonzero, return real val */ + uint64_t mask; /* for sa mads */ + unsigned recsz; /* for sa mads (attribute offset) */ + int timeout; + uint32_t oui; /* for vendor range 2 mads */ +} ib_rpc_t; + +typedef struct portid { + int lid; /* lid or 0 if directed route */ + ib_dr_path_t drpath; + int grh_present; /* flag */ + ibmad_gid_t gid; + uint32_t qp; + uint32_t qkey; + uint8_t sl; + unsigned pkey_idx; +} ib_portid_t; + +typedef void (ib_mad_dump_fn)(char *buf, int bufsz, void *val, int valsz); + +#define IB_FIELD_NAME_LEN 32 + +typedef struct ib_field { + int bitoffs; + int bitlen; + char name[IB_FIELD_NAME_LEN]; + ib_mad_dump_fn *def_dump_fn; +} ib_field_t; + +enum MAD_FIELDS { + IB_NO_FIELD, + + IB_GID_PREFIX_F, + IB_GID_GUID_F, + + /* first MAD word (0-3 bytes) */ + IB_MAD_METHOD_F, + IB_MAD_RESPONSE_F, + IB_MAD_CLASSVER_F, + IB_MAD_MGMTCLASS_F, + IB_MAD_BASEVER_F, + + /* second MAD word (4-7 bytes) */ + IB_MAD_STATUS_F, + + /* DRSMP only */ + IB_DRSMP_HOPCNT_F, + IB_DRSMP_HOPPTR_F, + IB_DRSMP_STATUS_F, + IB_DRSMP_DIRECTION_F, + + /* words 3,4,5,6 (8-23 bytes) */ + IB_MAD_TRID_F, + IB_MAD_ATTRID_F, + IB_MAD_ATTRMOD_F, + + /* word 7,8 (24-31 bytes) */ + IB_MAD_MKEY_F, + + /* word 9 (32-37 bytes) */ + IB_DRSMP_DRSLID_F, + IB_DRSMP_DRDLID_F, + + /* word 10,11 (36-43 bytes) */ + IB_SA_MKEY_F, + + /* word 12 (44-47 bytes) */ + IB_SA_ATTROFFS_F, + + /* word 13,14 (48-55 bytes) */ + IB_SA_COMPMASK_F, + + /* word 13,14 (56-255 bytes) */ + IB_SA_DATA_F, + + /* bytes 64 - 127 */ + IB_SM_DATA_F, + + /* bytes 64 - 256 */ + IB_GS_DATA_F, + + /* bytes 128 - 191 */ + IB_DRSMP_PATH_F, + + /* bytes 192 - 255 */ + IB_DRSMP_RPATH_F, + + /* + * PortInfo fields: + */ + IB_PORT_FIRST_F, + IB_PORT_MKEY_F = IB_PORT_FIRST_F, + IB_PORT_GID_PREFIX_F, + IB_PORT_LID_F, + IB_PORT_SMLID_F, + IB_PORT_CAPMASK_F, + IB_PORT_DIAG_F, + IB_PORT_MKEY_LEASE_F, + IB_PORT_LOCAL_PORT_F, + IB_PORT_LINK_WIDTH_ENABLED_F, + IB_PORT_LINK_WIDTH_SUPPORTED_F, + IB_PORT_LINK_WIDTH_ACTIVE_F, + IB_PORT_LINK_SPEED_SUPPORTED_F, + IB_PORT_STATE_F, + IB_PORT_PHYS_STATE_F, + IB_PORT_LINK_DOWN_DEF_F, + IB_PORT_MKEY_PROT_BITS_F, + IB_PORT_LMC_F, + IB_PORT_LINK_SPEED_ACTIVE_F, + IB_PORT_LINK_SPEED_ENABLED_F, + IB_PORT_NEIGHBOR_MTU_F, + IB_PORT_SMSL_F, + IB_PORT_VL_CAP_F, + IB_PORT_INIT_TYPE_F, + IB_PORT_VL_HIGH_LIMIT_F, + IB_PORT_VL_ARBITRATION_HIGH_CAP_F, + IB_PORT_VL_ARBITRATION_LOW_CAP_F, + IB_PORT_INIT_TYPE_REPLY_F, + IB_PORT_MTU_CAP_F, + IB_PORT_VL_STALL_COUNT_F, + IB_PORT_HOQ_LIFE_F, + IB_PORT_OPER_VLS_F, + IB_PORT_PART_EN_INB_F, + IB_PORT_PART_EN_OUTB_F, + IB_PORT_FILTER_RAW_INB_F, + IB_PORT_FILTER_RAW_OUTB_F, + IB_PORT_MKEY_VIOL_F, + IB_PORT_PKEY_VIOL_F, + IB_PORT_QKEY_VIOL_F, + IB_PORT_GUID_CAP_F, + IB_PORT_CLIENT_REREG_F, + IB_PORT_SUBN_TIMEOUT_F, + IB_PORT_RESP_TIME_VAL_F, + IB_PORT_LOCAL_PHYS_ERR_F, + IB_PORT_OVERRUN_ERR_F, + IB_PORT_MAX_CREDIT_HINT_F, + IB_PORT_LINK_ROUND_TRIP_F, + IB_PORT_LAST_F, + + /* + * NodeInfo fields: + */ + IB_NODE_FIRST_F, + IB_NODE_BASE_VERS_F = IB_NODE_FIRST_F, + IB_NODE_CLASS_VERS_F, + IB_NODE_TYPE_F, + IB_NODE_NPORTS_F, + IB_NODE_SYSTEM_GUID_F, + IB_NODE_GUID_F, + IB_NODE_PORT_GUID_F, + IB_NODE_PARTITION_CAP_F, + IB_NODE_DEVID_F, + IB_NODE_REVISION_F, + IB_NODE_LOCAL_PORT_F, + IB_NODE_VENDORID_F, + IB_NODE_LAST_F, + + /* + * SwitchInfo fields: + */ + IB_SW_FIRST_F, + IB_SW_LINEAR_FDB_CAP_F = IB_SW_FIRST_F, + IB_SW_RANDOM_FDB_CAP_F, + IB_SW_MCAST_FDB_CAP_F, + IB_SW_LINEAR_FDB_TOP_F, + IB_SW_DEF_PORT_F, + IB_SW_DEF_MCAST_PRIM_F, + IB_SW_DEF_MCAST_NOT_PRIM_F, + IB_SW_LIFE_TIME_F, + IB_SW_STATE_CHANGE_F, + IB_SW_LIDS_PER_PORT_F, + IB_SW_PARTITION_ENFORCE_CAP_F, + IB_SW_PARTITION_ENF_INB_F, + IB_SW_PARTITION_ENF_OUTB_F, + IB_SW_FILTER_RAW_INB_F, + IB_SW_FILTER_RAW_OUTB_F, + IB_SW_ENHANCED_PORT0_F, + IB_SW_LAST_F, + + /* + * SwitchLinearForwardingTable fields: + */ + IB_LINEAR_FORW_TBL_F, + + /* + * SwitchMulticastForwardingTable fields: + */ + IB_MULTICAST_FORW_TBL_F, + + /* + * NodeDescription fields: + */ + IB_NODE_DESC_F, + + /* + * Notice/Trap fields + */ + IB_NOTICE_IS_GENERIC_F, + IB_NOTICE_TYPE_F, + IB_NOTICE_PRODUCER_F, + IB_NOTICE_TRAP_NUMBER_F, + IB_NOTICE_ISSUER_LID_F, + IB_NOTICE_TOGGLE_F, + IB_NOTICE_COUNT_F, + IB_NOTICE_DATA_DETAILS_F, + IB_NOTICE_DATA_LID_F, + IB_NOTICE_DATA_144_LID_F, + IB_NOTICE_DATA_144_CAPMASK_F, + + /* + * GS Performance + */ + IB_PC_FIRST_F, + IB_PC_PORT_SELECT_F = IB_PC_FIRST_F, + IB_PC_COUNTER_SELECT_F, + IB_PC_ERR_SYM_F, + IB_PC_LINK_RECOVERS_F, + IB_PC_LINK_DOWNED_F, + IB_PC_ERR_RCV_F, + IB_PC_ERR_PHYSRCV_F, + IB_PC_ERR_SWITCH_REL_F, + IB_PC_XMT_DISCARDS_F, + IB_PC_ERR_XMTCONSTR_F, + IB_PC_ERR_RCVCONSTR_F, + IB_PC_ERR_LOCALINTEG_F, + IB_PC_ERR_EXCESS_OVR_F, + IB_PC_VL15_DROPPED_F, + IB_PC_XMT_BYTES_F, + IB_PC_RCV_BYTES_F, + IB_PC_XMT_PKTS_F, + IB_PC_RCV_PKTS_F, + IB_PC_LAST_F, + + /* + * SMInfo + */ + IB_SMINFO_GUID_F, + IB_SMINFO_KEY_F, + IB_SMINFO_ACT_F, + IB_SMINFO_PRIO_F, + IB_SMINFO_STATE_F, + + /* + * SA RMPP + */ + IB_SA_RMPP_VERS_F, + IB_SA_RMPP_TYPE_F, + IB_SA_RMPP_RESP_F, + IB_SA_RMPP_FLAGS_F, + IB_SA_RMPP_STATUS_F, + + /* data1 */ + IB_SA_RMPP_D1_F, + IB_SA_RMPP_SEGNUM_F, + /* data2 */ + IB_SA_RMPP_D2_F, + IB_SA_RMPP_LEN_F, /* DATA: Payload len */ + IB_SA_RMPP_NEWWIN_F, /* ACK: new window last */ + + /* + * SA Multi Path rec + */ + IB_SA_MP_NPATH_F, + IB_SA_MP_NSRC_F, + IB_SA_MP_NDEST_F, + IB_SA_MP_GID0_F, + + /* + * SA Path rec + */ + IB_SA_PR_DGID_F, + IB_SA_PR_SGID_F, + IB_SA_PR_DLID_F, + IB_SA_PR_SLID_F, + IB_SA_PR_NPATH_F, + + /* + * MC Member rec + */ + IB_SA_MCM_MGID_F, + IB_SA_MCM_PORTGID_F, + IB_SA_MCM_QKEY_F, + IB_SA_MCM_MLID_F, + IB_SA_MCM_SL_F, + IB_SA_MCM_MTU_F, + IB_SA_MCM_RATE_F, + IB_SA_MCM_TCLASS_F, + IB_SA_MCM_PKEY_F, + IB_SA_MCM_FLOW_LABEL_F, + IB_SA_MCM_JOIN_STATE_F, + IB_SA_MCM_PROXY_JOIN_F, + + /* + * Service record + */ + IB_SA_SR_ID_F, + IB_SA_SR_GID_F, + IB_SA_SR_PKEY_F, + IB_SA_SR_LEASE_F, + IB_SA_SR_KEY_F, + IB_SA_SR_NAME_F, + IB_SA_SR_DATA_F, + + /* + * ATS SM record - within SA_SR_DATA + */ + IB_ATS_SM_NODE_ADDR_F, + IB_ATS_SM_MAGIC_KEY_F, + IB_ATS_SM_NODE_TYPE_F, + IB_ATS_SM_NODE_NAME_F, + + /* + * SLTOVL MAPPING TABLE + */ + IB_SLTOVL_MAPPING_TABLE_F, + + /* + * VL ARBITRATION TABLE + */ + IB_VL_ARBITRATION_TABLE_F, + + /* + * IB vendor class range 2 + */ + IB_VEND2_OUI_F, + IB_VEND2_DATA_F, + + /* + * PortCountersExtended + */ + IB_PC_EXT_FIRST_F, + IB_PC_EXT_PORT_SELECT_F = IB_PC_EXT_FIRST_F, + IB_PC_EXT_COUNTER_SELECT_F, + IB_PC_EXT_XMT_BYTES_F, + IB_PC_EXT_RCV_BYTES_F, + IB_PC_EXT_XMT_PKTS_F, + IB_PC_EXT_RCV_PKTS_F, + IB_PC_EXT_XMT_UPKTS_F, + IB_PC_EXT_RCV_UPKTS_F, + IB_PC_EXT_XMT_MPKTS_F, + IB_PC_EXT_RCV_MPKTS_F, + IB_PC_EXT_LAST_F, + + /* + * GUIDInfo fields + */ + IB_GUID_GUID0_F, + + IB_FIELD_LAST_ /* must be last */ +}; + +/* + * SA RMPP section + */ +enum RMPP_TYPE_ENUM { + IB_RMPP_TYPE_NONE, + IB_RMPP_TYPE_DATA, + IB_RMPP_TYPE_ACK, + IB_RMPP_TYPE_STOP, + IB_RMPP_TYPE_ABORT, +}; + +enum RMPP_FLAGS_ENUM { + IB_RMPP_FLAG_ACTIVE = 1 << 0, + IB_RMPP_FLAG_FIRST = 1 << 1, + IB_RMPP_FLAG_LAST = 1 << 2, +}; + +typedef struct { + int type; + int flags; + int status; + union { + uint32_t u; + uint32_t segnum; + } d1; + union { + uint32_t u; + uint32_t len; + uint32_t newwin; + } d2; +} ib_rmpp_hdr_t; + +enum SA_SIZES_ENUM { + SA_HEADER_SZ = 20, +}; + +typedef struct ib_sa_call { + unsigned attrid; + unsigned mod; + uint64_t mask; + unsigned method; + + uint64_t trid; /* used for out mad if nonzero, return real val */ + unsigned recsz; /* return field */ + ib_rmpp_hdr_t rmpp; +} ib_sa_call_t; + +typedef struct ib_vendor_call { + unsigned method; + unsigned mgmt_class; + unsigned attrid; + unsigned mod; + uint32_t oui; + unsigned timeout; + ib_rmpp_hdr_t rmpp; +} ib_vendor_call_t; + +#define IB_MIN_UCAST_LID 1 +#define IB_MAX_UCAST_LID (0xc000-1) +#define IB_MIN_MCAST_LID 0xc000 +#define IB_MAX_MCAST_LID (0xffff-1) + +#define IB_LID_VALID(lid) ((lid) >= IB_MIN_UCAST_LID && lid <= IB_MAX_UCAST_LID) +#define IB_MLID_VALID(lid) ((lid) >= IB_MIN_MCAST_LID && lid <= IB_MAX_MCAST_LID) + +#define MAD_DEF_RETRIES 3 +#define MAD_DEF_TIMEOUT_MS 1000 + +enum { + IB_DEST_LID, + IB_DEST_DRPATH, + IB_DEST_GUID, + IB_DEST_DRSLID, +}; + +enum { + IB_NODE_CA = 1, + IB_NODE_SWITCH, + IB_NODE_ROUTER, + NODE_RNIC, + + IB_NODE_MAX = NODE_RNIC +}; + +/******************************************************************************/ + +/* portid.c */ +char * portid2str(ib_portid_t *portid); +int portid2portnum(ib_portid_t *portid); +int str2drpath(ib_dr_path_t *path, char *routepath, int drslid, int drdlid); +char * drpath2str(ib_dr_path_t *path, char *dstr, size_t dstr_size); + +static inline int +ib_portid_set(ib_portid_t *portid, int lid, int qp, int qkey) +{ + portid->lid = lid; + portid->qp = qp; + portid->qkey = qkey; + portid->grh_present = 0; + + return 0; +} + +/* fields.c */ +extern ib_field_t ib_mad_f[]; + +void _set_field(void *buf, int base_offs, ib_field_t *f, uint32_t val); +uint32_t _get_field(void *buf, int base_offs, ib_field_t *f); +void _set_array(void *buf, int base_offs, ib_field_t *f, void *val); +void _get_array(void *buf, int base_offs, ib_field_t *f, void *val); +void _set_field64(void *buf, int base_offs, ib_field_t *f, uint64_t val); +uint64_t _get_field64(void *buf, int base_offs, ib_field_t *f); + +/* mad.c */ +static inline uint32_t +mad_get_field(void *buf, int base_offs, int field) +{ + return _get_field(buf, base_offs, ib_mad_f + field); +} + +static inline void +mad_set_field(void *buf, int base_offs, int field, uint32_t val) +{ + _set_field(buf, base_offs, ib_mad_f + field, val); +} + +/* field must be byte aligned */ +static inline uint64_t +mad_get_field64(void *buf, int base_offs, int field) +{ + return _get_field64(buf, base_offs, ib_mad_f + field); +} + +static inline void +mad_set_field64(void *buf, int base_offs, int field, uint64_t val) +{ + _set_field64(buf, base_offs, ib_mad_f + field, val); +} + +static inline void +mad_set_array(void *buf, int base_offs, int field, void *val) +{ + _set_array(buf, base_offs, ib_mad_f + field, val); +} + +static inline void +mad_get_array(void *buf, int base_offs, int field, void *val) +{ + _get_array(buf, base_offs, ib_mad_f + field, val); +} + +void mad_decode_field(uint8_t *buf, int field, void *val); +void mad_encode_field(uint8_t *buf, int field, void *val); +void * mad_encode(void *buf, ib_rpc_t *rpc, ib_dr_path_t *drpath, void *data); +uint64_t mad_trid(void); +int mad_build_pkt(void *umad, ib_rpc_t *rpc, ib_portid_t *dport, ib_rmpp_hdr_t *rmpp, void *data); + +/* register.c */ +int mad_register_port_client(int port_id, int mgmt, uint8_t rmpp_version); +int mad_register_client(int mgmt, uint8_t rmpp_version); +int mad_register_server(int mgmt, uint8_t rmpp_version, + long method_mask[16/sizeof(long)], + uint32_t class_oui); +int mad_class_agent(int mgmt); +int mad_agent_class(int agent); + +/* serv.c */ +int mad_send(ib_rpc_t *rpc, ib_portid_t *dport, ib_rmpp_hdr_t *rmpp, + void *data); +void * mad_receive(void *umad, int timeout); +int mad_respond(void *umad, ib_portid_t *portid, uint32_t rstatus); +void * mad_alloc(void); +void mad_free(void *umad); + +/* vendor.c */ +uint8_t *ib_vendor_call(void *data, ib_portid_t *portid, + ib_vendor_call_t *call); + +static inline int +mad_is_vendor_range1(int mgmt) +{ + return mgmt >= 0x9 && mgmt <= 0xf; +} + +static inline int +mad_is_vendor_range2(int mgmt) +{ + return mgmt >= 0x30 && mgmt <= 0x4f; +} + +/* rpc.c */ +int madrpc_portid(void); +int madrpc_set_retries(int retries); +int madrpc_set_timeout(int timeout); +void * madrpc(ib_rpc_t *rpc, ib_portid_t *dport, void *payload, void *rcvdata); +void * madrpc_rmpp(ib_rpc_t *rpc, ib_portid_t *dport, ib_rmpp_hdr_t *rmpp, + void *data); +void madrpc_init(char *dev_name, int dev_port, int *mgmt_classes, + int num_classes); +void madrpc_save_mad(void *madbuf, int len); +void madrpc_lock(void); +void madrpc_unlock(void); +void madrpc_show_errors(int set); + +void * mad_rpc_open_port(char *dev_name, int dev_port, int *mgmt_classes, + int num_classes); +void mad_rpc_close_port(void *ibmad_port); +void * mad_rpc(const void *ibmad_port, ib_rpc_t *rpc, ib_portid_t *dport, + void *payload, void *rcvdata); +void * mad_rpc_rmpp(const void *ibmad_port, ib_rpc_t *rpc, ib_portid_t *dport, + ib_rmpp_hdr_t *rmpp, void *data); + +/* smp.c */ +uint8_t * smp_query(void *buf, ib_portid_t *id, unsigned attrid, unsigned mod, + unsigned timeout); +uint8_t * smp_set(void *buf, ib_portid_t *id, unsigned attrid, unsigned mod, + unsigned timeout); +uint8_t * smp_query_via(void *buf, ib_portid_t *id, unsigned attrid, + unsigned mod, unsigned timeout, const void *srcport); +uint8_t * smp_set_via(void *buf, ib_portid_t *id, unsigned attrid, unsigned mod, + unsigned timeout, const void *srcport); + +inline static uint8_t * +safe_smp_query(void *rcvbuf, ib_portid_t *portid, unsigned attrid, unsigned mod, + unsigned timeout) +{ + uint8_t *p; + + madrpc_lock(); + p = smp_query(rcvbuf, portid, attrid, mod, timeout); + madrpc_unlock(); + + return p; +} + +inline static uint8_t * +safe_smp_set(void *rcvbuf, ib_portid_t *portid, unsigned attrid, unsigned mod, + unsigned timeout) +{ + uint8_t *p; + + madrpc_lock(); + p = smp_set(rcvbuf, portid, attrid, mod, timeout); + madrpc_unlock(); + + return p; +} + +/* sa.c */ +uint8_t * sa_call(void *rcvbuf, ib_portid_t *portid, ib_sa_call_t *sa, + unsigned timeout); +uint8_t * sa_rpc_call(const void *ibmad_port, void *rcvbuf, ib_portid_t *portid, + ib_sa_call_t *sa, unsigned timeout); +int ib_path_query(ibmad_gid_t srcgid, ibmad_gid_t destgid, ib_portid_t *sm_id, + void *buf); /* returns lid */ +int ib_path_query_via(const void *srcport, ibmad_gid_t srcgid, + ibmad_gid_t destgid, ib_portid_t *sm_id, void *buf); + +inline static uint8_t * +safe_sa_call(void *rcvbuf, ib_portid_t *portid, ib_sa_call_t *sa, + unsigned timeout) +{ + uint8_t *p; + + madrpc_lock(); + p = sa_call(rcvbuf, portid, sa, timeout); + madrpc_unlock(); + + return p; +} + +/* resolve.c */ +int ib_resolve_smlid(ib_portid_t *sm_id, int timeout); +int ib_resolve_guid(ib_portid_t *portid, uint64_t *guid, + ib_portid_t *sm_id, int timeout); +int ib_resolve_portid_str(ib_portid_t *portid, char *addr_str, + int dest_type, ib_portid_t *sm_id); +int ib_resolve_self(ib_portid_t *portid, int *portnum, ibmad_gid_t *gid); + +int ib_resolve_smlid_via(ib_portid_t *sm_id, int timeout, + const void *srcport); +int ib_resolve_guid_via(ib_portid_t *portid, uint64_t *guid, + ib_portid_t *sm_id, int timeout, + const void *srcport); +int ib_resolve_portid_str_via(ib_portid_t *portid, char *addr_str, + int dest_type, ib_portid_t *sm_id, + const void *srcport); +int ib_resolve_self_via(ib_portid_t *portid, int *portnum, ibmad_gid_t *gid, + const void *srcport); + +/* gs.c */ +uint8_t *perf_classportinfo_query(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout); +uint8_t *port_performance_query(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout); +uint8_t *port_performance_reset(void *rcvbuf, ib_portid_t *dest, int port, + unsigned mask, unsigned timeout); +uint8_t *port_performance_ext_query(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout); +uint8_t *port_performance_ext_reset(void *rcvbuf, ib_portid_t *dest, int port, + unsigned mask, unsigned timeout); +uint8_t *port_samples_control_query(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout); +uint8_t *port_samples_result_query(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout); + +uint8_t *perf_classportinfo_query_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout, const void *srcport); +uint8_t *port_performance_query_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout, const void *srcport); +uint8_t *port_performance_reset_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned mask, unsigned timeout, const void *srcport); +uint8_t *port_performance_ext_query_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout, const void *srcport); +uint8_t *port_performance_ext_reset_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned mask, unsigned timeout, const void *srcport); +uint8_t *port_samples_control_query_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout, const void *srcport); +uint8_t *port_samples_result_query_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout, const void *srcport); +/* dump.c */ +ib_mad_dump_fn + mad_dump_int, mad_dump_uint, mad_dump_hex, mad_dump_rhex, + mad_dump_bitfield, mad_dump_array, mad_dump_string, + mad_dump_linkwidth, mad_dump_linkwidthsup, mad_dump_linkwidthen, + mad_dump_linkdowndefstate, + mad_dump_linkspeed, mad_dump_linkspeedsup, mad_dump_linkspeeden, + mad_dump_portstate, mad_dump_portstates, + mad_dump_physportstate, mad_dump_portcapmask, + mad_dump_mtu, mad_dump_vlcap, mad_dump_opervls, + mad_dump_node_type, + mad_dump_sltovl, mad_dump_vlarbitration, + mad_dump_nodedesc, mad_dump_nodeinfo, mad_dump_portinfo, mad_dump_switchinfo, + mad_dump_perfcounters, mad_dump_perfcounters_ext; + +int _mad_dump(ib_mad_dump_fn *fn, char *name, void *val, int valsz); +char * _mad_dump_field(ib_field_t *f, char *name, char *buf, int bufsz, + void *val); +int _mad_print_field(ib_field_t *f, char *name, void *val, int valsz); +char * _mad_dump_val(ib_field_t *f, char *buf, int bufsz, void *val); + +static inline int +mad_print_field(int field, char *name, void *val) +{ + if (field <= IB_NO_FIELD || field >= IB_FIELD_LAST_) + return -1; + return _mad_print_field(ib_mad_f + field, name, val, 0); +} + +static inline char * +mad_dump_field(int field, char *buf, int bufsz, void *val) +{ + if (field <= IB_NO_FIELD || field >= IB_FIELD_LAST_) + return 0; + return _mad_dump_field(ib_mad_f + field, 0, buf, bufsz, val); +} + +static inline char * +mad_dump_val(int field, char *buf, int bufsz, void *val) +{ + if (field <= IB_NO_FIELD || field >= IB_FIELD_LAST_) + return 0; + return _mad_dump_val(ib_mad_f + field, buf, bufsz, val); +} + +extern int ibdebug; + +END_C_DECLS + +#endif /* _MAD_H_ */ diff --git a/contrib/ofed/management/libibmad/libibmad.spec.in b/contrib/ofed/management/libibmad/libibmad.spec.in new file mode 100644 index 000000000000..5fd10f6b2de2 --- /dev/null +++ b/contrib/ofed/management/libibmad/libibmad.spec.in @@ -0,0 +1,73 @@ + +%define RELEASE @RELEASE@ +%define rel %{?CUSTOM_RELEASE} %{!?CUSTOM_RELEASE:%RELEASE} + +Summary: OpenFabrics Alliance InfiniBand MAD library +Name: libibmad +Version: @VERSION@ +Release: %rel%{?dist} +License: GPLv2 or BSD +Group: System Environment/Libraries +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +Source: http://www.openfabrics.org/downloads/management/@TARBALL@ +Url: http://openfabrics.org/ +BuildRequires: libibumad-devel, libtool +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description +libibmad provides low layer IB functions for use by the IB diagnostic +and management programs. These include MAD, SA, SMP, and other basic +IB functions. + +%package devel +Summary: Development files for the libibmad library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} libibumad-devel +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description devel +Development files for the libibmad library. + +%package static +Summary: Static version of the libibmad library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} + +%description static +Static version of the libibmad library + +%prep +%setup -q + +%build +%configure +make %{?_smp_mflags} + +%install +make DESTDIR=${RPM_BUILD_ROOT} install +# remove unpackaged files from the buildroot +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig +%post devel -p /sbin/ldconfig +%postun devel -p /sbin/ldconfig + +%files +%defattr(-,root,root) +%{_libdir}/libibmad*.so.* +%doc AUTHORS COPYING ChangeLog + +%files devel +%defattr(-,root,root) +%{_libdir}/libibmad.so +%{_includedir}/infiniband/*.h + +%files static +%defattr(-,root,root) +%{_libdir}/libibmad.a diff --git a/contrib/ofed/management/libibmad/libibmad.ver b/contrib/ofed/management/libibmad/libibmad.ver new file mode 100644 index 000000000000..51f2b71e126d --- /dev/null +++ b/contrib/ofed/management/libibmad/libibmad.ver @@ -0,0 +1,9 @@ +# In this file we track the current API version +# of the IB mad interface (and libraries) +# The version is built of the following +# tree numbers: +# API_REV:RUNNING_REV:AGE +# API_REV - advance on any added API +# RUNNING_REV - advance any change to the vendor files +# AGE - number of backward versions the API still supports +LIBVERSION=4:0:3 diff --git a/contrib/ofed/management/libibmad/src/dump.c b/contrib/ofed/management/libibmad/src/dump.c new file mode 100644 index 000000000000..052127f8c2c6 --- /dev/null +++ b/contrib/ofed/management/libibmad/src/dump.c @@ -0,0 +1,782 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +void +mad_dump_int(char *buf, int bufsz, void *val, int valsz) +{ + switch (valsz) { + case 1: + snprintf(buf, bufsz, "%d", *(uint8_t *)val); + break; + case 2: + snprintf(buf, bufsz, "%d", *(uint16_t *)val); + break; + case 3: + case 4: + snprintf(buf, bufsz, "%d", *(uint32_t *)val); + break; + case 5: + case 6: + case 7: + case 8: + snprintf(buf, bufsz, "%" PRIu64, *(uint64_t *)val); + break; + default: + IBWARN("bad int sz %d", valsz); + buf[0] = 0; + } +} + +void +mad_dump_uint(char *buf, int bufsz, void *val, int valsz) +{ + switch (valsz) { + case 1: + snprintf(buf, bufsz, "%u", *(uint8_t *)val); + break; + case 2: + snprintf(buf, bufsz, "%u", *(uint16_t *)val); + break; + case 3: + case 4: + snprintf(buf, bufsz, "%u", *(uint32_t *)val); + break; + case 5: + case 6: + case 7: + case 8: + snprintf(buf, bufsz, "%" PRIu64, *(uint64_t *)val); + break; + default: + IBWARN("bad int sz %u", valsz); + buf[0] = 0; + } +} + +void +mad_dump_hex(char *buf, int bufsz, void *val, int valsz) +{ + switch (valsz) { + case 1: + snprintf(buf, bufsz, "0x%02x", *(uint8_t *)val); + break; + case 2: + snprintf(buf, bufsz, "0x%04x", *(uint16_t *)val); + break; + case 3: + snprintf(buf, bufsz, "0x%06x", *(uint32_t *)val & 0xffffff); + break; + case 4: + snprintf(buf, bufsz, "0x%08x", *(uint32_t *)val); + break; + case 5: + snprintf(buf, bufsz, "0x%010" PRIx64, *(uint64_t *)val & (uint64_t) 0xffffffffffllu); + break; + case 6: + snprintf(buf, bufsz, "0x%012" PRIx64, *(uint64_t *)val & (uint64_t) 0xffffffffffffllu); + break; + case 7: + snprintf(buf, bufsz, "0x%014" PRIx64, *(uint64_t *)val & (uint64_t) 0xffffffffffffffllu); + break; + case 8: + snprintf(buf, bufsz, "0x%016" PRIx64, *(uint64_t *)val); + break; + default: + IBWARN("bad int sz %d", valsz); + buf[0] = 0; + } +} + +void +mad_dump_rhex(char *buf, int bufsz, void *val, int valsz) +{ + switch (valsz) { + case 1: + snprintf(buf, bufsz, "%02x", *(uint8_t *)val); + break; + case 2: + snprintf(buf, bufsz, "%04x", *(uint16_t *)val); + break; + case 3: + snprintf(buf, bufsz, "%06x", *(uint32_t *)val & 0xffffff); + break; + case 4: + snprintf(buf, bufsz, "%08x", *(uint32_t *)val); + break; + case 5: + snprintf(buf, bufsz, "%010" PRIx64, *(uint64_t *)val & (uint64_t) 0xffffffffffllu); + break; + case 6: + snprintf(buf, bufsz, "%012" PRIx64, *(uint64_t *)val & (uint64_t) 0xffffffffffffllu); + break; + case 7: + snprintf(buf, bufsz, "%014" PRIx64, *(uint64_t *)val & (uint64_t) 0xffffffffffffffllu); + break; + case 8: + snprintf(buf, bufsz, "%016" PRIx64, *(uint64_t *)val); + break; + default: + IBWARN("bad int sz %d", valsz); + buf[0] = 0; + } +} + +void +mad_dump_linkwidth(char *buf, int bufsz, void *val, int valsz) +{ + int width = *(int *)val; + + switch (width) { + case 1: + snprintf(buf, bufsz, "1X"); + break; + case 2: + snprintf(buf, bufsz, "4X"); + break; + case 4: + snprintf(buf, bufsz, "8X"); + break; + case 8: + snprintf(buf, bufsz, "12X"); + break; + default: + IBWARN("bad width %d", width); + buf[0] = 0; + } +} + +static void +dump_linkwidth(char *buf, int bufsz, int width) +{ + int n = 0; + + if (width & 0x1) + n += snprintf(buf + n, bufsz - n, "1X or "); + if (n < bufsz && (width & 0x2)) + n += snprintf(buf + n, bufsz - n, "4X or "); + if (n < bufsz && (width & 0x4)) + n += snprintf(buf + n, bufsz - n, "8X or "); + if (n < bufsz && (width & 0x8)) + n += snprintf(buf + n, bufsz - n, "12X or "); + + if (n >= bufsz) + return; + else if (width == 0 || (width >> 4)) + snprintf(buf + n, bufsz - n, "undefined (%d)", width); + else if (bufsz > 3) + buf[n-4] = '\0'; +} + +void +mad_dump_linkwidthsup(char *buf, int bufsz, void *val, int valsz) +{ + int width = *(int *)val; + + dump_linkwidth(buf, bufsz, width); + + switch(width) { + case 1: + case 3: + case 7: + case 11: + case 15: + break; + + default: + if (!(width >> 4)) + snprintf(buf + strlen(buf), bufsz - strlen(buf), + " (IBA extension)"); + break; + } +} + +void +mad_dump_linkwidthen(char *buf, int bufsz, void *val, int valsz) +{ + int width = *(int *)val; + + dump_linkwidth(buf, bufsz, width); +} + +void +mad_dump_linkspeed(char *buf, int bufsz, void *val, int valsz) +{ + int speed = *(int *)val; + + switch (speed) { + case 1: + snprintf(buf, bufsz, "2.5 Gbps"); + break; + case 2: + snprintf(buf, bufsz, "5.0 Gbps"); + break; + case 4: + snprintf(buf, bufsz, "10.0 Gbps"); + break; + default: + snprintf(buf, bufsz, "undefined (%d)", speed); + break; + } +} + +static void +dump_linkspeed(char *buf, int bufsz, int speed) +{ + int n = 0; + + if (speed & 0x1) + n += snprintf(buf + n, bufsz - n, "2.5 Gbps or "); + if (n < bufsz && (speed & 0x2)) + n += snprintf(buf + n, bufsz - n, "5.0 Gbps or "); + if (n < bufsz && (speed & 0x4)) + n += snprintf(buf + n, bufsz - n, "10.0 Gbps or "); + + if (n >= bufsz) + return; + else if (speed == 0 || (speed >> 3)) { + n += snprintf(buf + n, bufsz - n, "undefined (%d)", speed); + if (n >= bufsz) + return; + } else if (bufsz > 3) { + buf[n-4] = '\0'; + n -= 4; + } + + switch (speed) { + case 1: + case 3: + case 5: + case 7: + break; + default: + if (!(speed >> 3)) + snprintf(buf + n, bufsz - n, " (IBA extension)"); + break; + } +} + +void +mad_dump_linkspeedsup(char *buf, int bufsz, void *val, int valsz) +{ + int speed = *(int *)val; + + dump_linkspeed(buf, bufsz, speed); +} + +void +mad_dump_linkspeeden(char *buf, int bufsz, void *val, int valsz) +{ + int speed = *(int *)val; + + dump_linkspeed(buf, bufsz, speed); +} + +void +mad_dump_portstate(char *buf, int bufsz, void *val, int valsz) +{ + int state = *(int *)val; + + switch (state) { + case 0: + snprintf(buf, bufsz, "NoChange"); + break; + case 1: + snprintf(buf, bufsz, "Down"); + break; + case 2: + snprintf(buf, bufsz, "Initialize"); + break; + case 3: + snprintf(buf, bufsz, "Armed"); + break; + case 4: + snprintf(buf, bufsz, "Active"); + break; + default: + snprintf(buf, bufsz, "?(%d)", state); + } +} + +void +mad_dump_linkdowndefstate(char *buf, int bufsz, void *val, int valsz) +{ + int state = *(int *)val; + + switch(state) { + case 0: + snprintf(buf, bufsz, "NoChange"); + break; + case 1: + snprintf(buf, bufsz, "Sleep"); + break; + case 2: + snprintf(buf, bufsz, "Polling"); + break; + default: + snprintf(buf, bufsz, "?(%d)", state); + break; + } +} + +void +mad_dump_physportstate(char *buf, int bufsz, void *val, int valsz) +{ + int state = *(int *)val; + + switch (state) { + case 0: + snprintf(buf, bufsz, "NoChange"); + break; + case 1: + snprintf(buf, bufsz, "Sleep"); + break; + case 2: + snprintf(buf, bufsz, "Polling"); + break; + case 3: + snprintf(buf, bufsz, "Disabled"); + break; + case 4: + snprintf(buf, bufsz, "PortConfigurationTraining"); + break; + case 5: + snprintf(buf, bufsz, "LinkUp"); + break; + case 6: + snprintf(buf, bufsz, "LinkErrorRecovery"); + break; + case 7: + snprintf(buf, bufsz, "PhyTest"); + break; + default: + snprintf(buf, bufsz, "?(%d)", state); + } +} + +void +mad_dump_mtu(char *buf, int bufsz, void *val, int valsz) +{ + int mtu = *(int *)val; + + switch (mtu) { + case 1: + snprintf(buf, bufsz, "256"); + break; + case 2: + snprintf(buf, bufsz, "512"); + break; + case 3: + snprintf(buf, bufsz, "1024"); + break; + case 4: + snprintf(buf, bufsz, "2048"); + break; + case 5: + snprintf(buf, bufsz, "4096"); + break; + default: + snprintf(buf, bufsz, "?(%d)", mtu); + buf[0] = 0; + } +} + +void +mad_dump_vlcap(char *buf, int bufsz, void *val, int valsz) +{ + int vlcap = *(int *)val; + + switch (vlcap) { + case 1: + snprintf(buf, bufsz, "VL0"); + break; + case 2: + snprintf(buf, bufsz, "VL0-1"); + break; + case 3: + snprintf(buf, bufsz, "VL0-3"); + break; + case 4: + snprintf(buf, bufsz, "VL0-7"); + break; + case 5: + snprintf(buf, bufsz, "VL0-14"); + break; + default: + snprintf(buf, bufsz, "?(%d)", vlcap); + } +} + +void +mad_dump_opervls(char *buf, int bufsz, void *val, int valsz) +{ + int opervls = *(int *)val; + + switch (opervls) { + case 0: + snprintf(buf, bufsz, "No change"); + break; + case 1: + snprintf(buf, bufsz, "VL0"); + break; + case 2: + snprintf(buf, bufsz, "VL0-1"); + break; + case 3: + snprintf(buf, bufsz, "VL0-3"); + break; + case 4: + snprintf(buf, bufsz, "VL0-7"); + break; + case 5: + snprintf(buf, bufsz, "VL0-14"); + break; + default: + snprintf(buf, bufsz, "?(%d)", opervls); + } +} + +void +mad_dump_portcapmask(char *buf, int bufsz, void *val, int valsz) +{ + unsigned mask = *(unsigned *)val; + char *s = buf; + + s += sprintf(s, "0x%x\n", mask); + if (mask & (1 << 1)) + s += sprintf(s, "\t\t\t\tIsSM\n"); + if (mask & (1 << 2)) + s += sprintf(s, "\t\t\t\tIsNoticeSupported\n"); + if (mask & (1 << 3)) + s += sprintf(s, "\t\t\t\tIsTrapSupported\n"); + if (mask & (1 << 5)) + s += sprintf(s, "\t\t\t\tIsAutomaticMigrationSupported\n"); + if (mask & (1 << 6)) + s += sprintf(s, "\t\t\t\tIsSLMappingSupported\n"); + if (mask & (1 << 7)) + s += sprintf(s, "\t\t\t\tIsMKeyNVRAM\n"); + if (mask & (1 << 8)) + s += sprintf(s, "\t\t\t\tIsPKeyNVRAM\n"); + if (mask & (1 << 9)) + s += sprintf(s, "\t\t\t\tIsLedInfoSupported\n"); + if (mask & (1 << 10)) + s += sprintf(s, "\t\t\t\tIsSMdisabled\n"); + if (mask & (1 << 11)) + s += sprintf(s, "\t\t\t\tIsSystemImageGUIDsupported\n"); + if (mask & (1 << 12)) + s += sprintf(s, "\t\t\t\tIsPkeySwitchExternalPortTrapSupported\n"); + if (mask & (1 << 16)) + s += sprintf(s, "\t\t\t\tIsCommunicatonManagementSupported\n"); + if (mask & (1 << 17)) + s += sprintf(s, "\t\t\t\tIsSNMPTunnelingSupported\n"); + if (mask & (1 << 18)) + s += sprintf(s, "\t\t\t\tIsReinitSupported\n"); + if (mask & (1 << 19)) + s += sprintf(s, "\t\t\t\tIsDeviceManagementSupported\n"); + if (mask & (1 << 20)) + s += sprintf(s, "\t\t\t\tIsVendorClassSupported\n"); + if (mask & (1 << 21)) + s += sprintf(s, "\t\t\t\tIsDRNoticeSupported\n"); + if (mask & (1 << 22)) + s += sprintf(s, "\t\t\t\tIsCapabilityMaskNoticeSupported\n"); + if (mask & (1 << 23)) + s += sprintf(s, "\t\t\t\tIsBootManagementSupported\n"); + if (mask & (1 << 24)) + s += sprintf(s, "\t\t\t\tIsLinkRoundTripLatencySupported\n"); + if (mask & (1 << 25)) + s += sprintf(s, "\t\t\t\tIsClientRegistrationSupported\n"); + if (mask & (1 << 26)) + s += sprintf(s, "\t\t\t\tIsOtherLocalChangesNoticeSupported\n"); + if (mask & (1 << 27)) + s += sprintf(s, "\t\t\t\tIsLinkSpeedWidthPairsTableSupported\n"); + + if (s != buf) + *(--s) = 0; +} + +void +mad_dump_bitfield(char *buf, int bufsz, void *val, int valsz) +{ + snprintf(buf, bufsz, "0x%x", *(uint32_t *)val); +} + +void +mad_dump_array(char *buf, int bufsz, void *val, int valsz) +{ + uint8_t *p = val, *e; + char *s = buf; + + if (bufsz < valsz*2) + valsz = bufsz/2; + + for (p = val, e = p + valsz; p < e; p++, s += 2) + sprintf(s, "%02x", *p); +} + +void +mad_dump_string(char *buf, int bufsz, void *val, int valsz) +{ + if (bufsz < valsz) + valsz = bufsz; + + snprintf(buf, valsz, "'%s'", (char *)val); +} + +void +mad_dump_node_type(char *buf, int bufsz, void *val, int valsz) +{ + int nodetype = *(int*)val; + + switch (nodetype) { + case 1: + snprintf(buf, bufsz, "Channel Adapter"); + break; + case 2: + snprintf(buf, bufsz, "Switch"); + break; + case 3: + snprintf(buf, bufsz, "Router"); + break; + default: + snprintf(buf, bufsz, "?(%d)?", nodetype); + break; + } +} + +#define IB_MAX_NUM_VLS 16 +#define IB_MAX_NUM_VLS_TO_U8 ((IB_MAX_NUM_VLS)/2) + +typedef struct _ib_slvl_table { + uint8_t vl_by_sl_num[IB_MAX_NUM_VLS_TO_U8]; +} ib_slvl_table_t; + +static inline void +ib_slvl_get_i(ib_slvl_table_t *tbl, int i, uint8_t *vl) +{ + *vl = (tbl->vl_by_sl_num[i >> 1] >> ((!(i&1)) << 2)) & 0xf; +} + +#define IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK 32 + +typedef struct _ib_vl_arb_table { + struct { + uint8_t res_vl; + uint8_t weight; + } vl_entry[IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK]; +} __attribute__((packed)) ib_vl_arb_table_t; + +static inline void +ib_vl_arb_get_vl(uint8_t res_vl, uint8_t *const vl ) +{ + *vl = res_vl & 0x0F; +} + +void +mad_dump_sltovl(char *buf, int bufsz, void *val, int valsz) +{ + ib_slvl_table_t* p_slvl_tbl = val; + uint8_t vl; + int i, n = 0; + n = snprintf(buf, bufsz, "|"); + for (i = 0; i < 16; i++) { + ib_slvl_get_i(p_slvl_tbl, i, &vl); + n += snprintf(buf + n, bufsz - n, "%2u|", vl); + if (n >= bufsz) + break; + } + snprintf(buf + n, bufsz - n, "\n"); +} + +void +mad_dump_vlarbitration(char *buf, int bufsz, void *val, int num) +{ + ib_vl_arb_table_t* p_vla_tbl = val; + unsigned i, n; + uint8_t vl; + + num /= sizeof(p_vla_tbl->vl_entry[0]); + + n = snprintf(buf, bufsz, "\nVL : |"); + if (n >= bufsz) + return; + for (i = 0; i < num; i++) { + ib_vl_arb_get_vl(p_vla_tbl->vl_entry[i].res_vl, &vl); + n += snprintf(buf + n, bufsz - n, "0x%-2X|", vl); + if (n >= bufsz) + return; + } + + n += snprintf(buf + n, bufsz - n, "\nWEIGHT: |"); + if (n >= bufsz) + return; + for (i = 0; i < num; i++) { + n += snprintf(buf + n, bufsz - n, "0x%-2X|", + p_vla_tbl->vl_entry[i].weight); + if (n >= bufsz) + return; + } + + snprintf(buf + n, bufsz - n, "\n"); +} + +static int +_dump_fields(char *buf, int bufsz, void *data, int start, int end) +{ + char val[64]; + char *s = buf; + int n, field; + + for (field = start; field < end && bufsz > 0; field++) { + mad_decode_field(data, field, val); + if (!mad_dump_field(field, s, bufsz, val)) + return -1; + n = strlen(s); + s += n; + *s++ = '\n'; + *s = 0; + n++; + bufsz -= n; + } + + return s - buf; +} + +void +mad_dump_nodedesc(char *buf, int bufsz, void *val, int valsz) +{ + strncpy(buf, val, bufsz); + + if (valsz < bufsz) + buf[valsz] = 0; +} + +void +mad_dump_nodeinfo(char *buf, int bufsz, void *val, int valsz) +{ + _dump_fields(buf, bufsz, val, IB_NODE_FIRST_F, IB_NODE_LAST_F); +} + +void +mad_dump_portinfo(char *buf, int bufsz, void *val, int valsz) +{ + _dump_fields(buf, bufsz, val, IB_PORT_FIRST_F, IB_PORT_LAST_F); +} + +void +mad_dump_portstates(char *buf, int bufsz, void *val, int valsz) +{ + _dump_fields(buf, bufsz, val, IB_PORT_STATE_F, IB_PORT_LINK_DOWN_DEF_F); +} + +void +mad_dump_switchinfo(char *buf, int bufsz, void *val, int valsz) +{ + _dump_fields(buf, bufsz, val, IB_SW_FIRST_F, IB_SW_LAST_F); +} + +void +mad_dump_perfcounters(char *buf, int bufsz, void *val, int valsz) +{ + _dump_fields(buf, bufsz, val, IB_PC_FIRST_F, IB_PC_LAST_F); +} + +void +mad_dump_perfcounters_ext(char *buf, int bufsz, void *val, int valsz) +{ + _dump_fields(buf, bufsz, val, IB_PC_EXT_FIRST_F, IB_PC_EXT_LAST_F); +} + +/************************/ + +char * +_mad_dump_val(ib_field_t *f, char *buf, int bufsz, void *val) +{ + f->def_dump_fn(buf, bufsz, val, ALIGN(f->bitlen, 8) / 8); + buf[bufsz - 1] = 0; + + return buf; +} + +char * +_mad_dump_field(ib_field_t *f, char *name, char *buf, int bufsz, void *val) +{ + char dots[128]; + int l, n; + + if (bufsz <= 32) + return 0; /* buf too small */ + + if (!name) + name = f->name; + + l = strlen(name); + if (l < 32) { + memset(dots, '.', 32 - l); + dots[32 - l] = 0; + } + + n = snprintf(buf, bufsz, "%s:%s", name, dots); + _mad_dump_val(f, buf + n, bufsz - n, val); + buf[bufsz - 1] = 0; + + return buf; +} + +int +_mad_dump(ib_mad_dump_fn *fn, char *name, void *val, int valsz) +{ + ib_field_t f = { .def_dump_fn = fn, .bitlen = valsz * 8}; + char buf[512]; + + return printf("%s\n", _mad_dump_field(&f, name, buf, sizeof buf, val)); +} + +int +_mad_print_field(ib_field_t *f, char *name, void *val, int valsz) +{ + return _mad_dump(f->def_dump_fn, name ? name : f->name, val, valsz ? valsz : ALIGN(f->bitlen, 8) / 8); +} diff --git a/contrib/ofed/management/libibmad/src/fields.c b/contrib/ofed/management/libibmad/src/fields.c new file mode 100644 index 000000000000..6942e853cf84 --- /dev/null +++ b/contrib/ofed/management/libibmad/src/fields.c @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include +#include + +/* + * BITSOFFS and BE_OFFS are required due the fact that the bit offsets are inconsistently + * encoded in the IB spec - IB headers are encoded such that the bit offsets + * are in big endian convention (BE_OFFS), while the SMI/GSI queries data fields bit + * offsets are specified using real bit offset (?!) + * The following macros normalize everything to big endian offsets. + */ +#define BITSOFFS(o, w) (((o) & ~31) | ((32 - ((o) & 31) - (w)))), (w) +#define BE_OFFS(o, w) (o), (w) +#define BE_TO_BITSOFFS(o, w) (((o) & ~31) | ((32 - ((o) & 31) - (w)))) + +ib_field_t ib_mad_f [] = { + [0] {0, 0}, /* IB_NO_FIELD - reserved as invalid */ + + [IB_GID_PREFIX_F] {0, 64, "GidPrefix", mad_dump_rhex}, + [IB_GID_GUID_F] {64, 64, "GidGuid", mad_dump_rhex}, + + /* + * MAD: common MAD fields (IB spec 13.4.2) + * SMP: Subnet Management packets - lid routed (IB spec 14.2.1.1) + * DSMP: Subnet Management packets - direct route (IB spec 14.2.1.2) + * SA: Subnet Administration packets (IB spec 15.2.1.1) + */ + + /* first MAD word (0-3 bytes) */ + [IB_MAD_METHOD_F] {BE_OFFS(0, 7), "MadMethod", mad_dump_hex}, /* TODO: add dumper */ + [IB_MAD_RESPONSE_F] {BE_OFFS(7, 1), "MadIsResponse", mad_dump_uint}, /* TODO: add dumper */ + [IB_MAD_CLASSVER_F] {BE_OFFS(8, 8), "MadClassVersion", mad_dump_uint}, + [IB_MAD_MGMTCLASS_F] {BE_OFFS(16, 8), "MadMgmtClass", mad_dump_uint}, /* TODO: add dumper */ + [IB_MAD_BASEVER_F] {BE_OFFS(24, 8), "MadBaseVersion", mad_dump_uint}, + + /* second MAD word (4-7 bytes) */ + [IB_MAD_STATUS_F] {BE_OFFS(48, 16), "MadStatus", mad_dump_hex}, /* TODO: add dumper */ + + /* DR SMP only */ + [IB_DRSMP_HOPCNT_F] {BE_OFFS(32, 8), "DrSmpHopCnt", mad_dump_uint}, + [IB_DRSMP_HOPPTR_F] {BE_OFFS(40, 8), "DrSmpHopPtr", mad_dump_uint}, + [IB_DRSMP_STATUS_F] {BE_OFFS(48, 15), "DrSmpStatus", mad_dump_hex}, /* TODO: add dumper */ + [IB_DRSMP_DIRECTION_F] {BE_OFFS(63, 1), "DrSmpDirection", mad_dump_uint}, /* TODO: add dumper */ + + /* words 3,4,5,6 (8-23 bytes) */ + [IB_MAD_TRID_F] {64, 64, "MadTRID", mad_dump_hex}, + [IB_MAD_ATTRID_F] {BE_OFFS(144, 16), "MadAttr", mad_dump_hex}, /* TODO: add dumper */ + [IB_MAD_ATTRMOD_F] {160, 32, "MadModifier", mad_dump_hex}, /* TODO: add dumper */ + + /* word 7,8 (24-31 bytes) */ + [IB_MAD_MKEY_F] {196, 64, "MadMkey", mad_dump_hex}, + + /* word 9 (32-37 bytes) */ + [IB_DRSMP_DRDLID_F] {BE_OFFS(256, 16), "DrSmpDLID", mad_dump_hex}, + [IB_DRSMP_DRSLID_F] {BE_OFFS(272, 16), "DrSmpSLID", mad_dump_hex}, + + /* word 12 (44-47 bytes) */ + [IB_SA_ATTROFFS_F] {BE_OFFS(46*8, 16), "SaAttrOffs", mad_dump_uint}, + + /* word 13,14 (48-55 bytes) */ + [IB_SA_COMPMASK_F] {48*8, 64, "SaCompMask", mad_dump_hex}, + + /* word 13,14 (56-255 bytes) */ + [IB_SA_DATA_F] {56*8, (256-56)*8, "SaData", mad_dump_hex}, + + [IB_DRSMP_PATH_F] {1024, 512, "DrSmpPath", mad_dump_hex}, + [IB_DRSMP_RPATH_F] {1536, 512, "DrSmpRetPath", mad_dump_hex}, + + [IB_GS_DATA_F] {64*8, (256-64) * 8, "GsData", mad_dump_hex}, + + /* + * PortInfo fields: + */ + [IB_PORT_MKEY_F] {0, 64, "Mkey", mad_dump_hex}, + [IB_PORT_GID_PREFIX_F] {64, 64, "GidPrefix", mad_dump_hex}, + [IB_PORT_LID_F] {BITSOFFS(128, 16), "Lid", mad_dump_hex}, + [IB_PORT_SMLID_F] {BITSOFFS(144, 16), "SMLid", mad_dump_hex}, + [IB_PORT_CAPMASK_F] {160, 32, "CapMask", mad_dump_portcapmask}, + [IB_PORT_DIAG_F] {BITSOFFS(192, 16), "DiagCode", mad_dump_hex}, + [IB_PORT_MKEY_LEASE_F] {BITSOFFS(208, 16), "MkeyLeasePeriod", mad_dump_uint}, + [IB_PORT_LOCAL_PORT_F] {BITSOFFS(224, 8), "LocalPort", mad_dump_uint}, + [IB_PORT_LINK_WIDTH_ENABLED_F] {BITSOFFS(232, 8), "LinkWidthEnabled", mad_dump_linkwidthen}, + [IB_PORT_LINK_WIDTH_SUPPORTED_F] {BITSOFFS(240, 8), "LinkWidthSupported", mad_dump_linkwidthsup}, + [IB_PORT_LINK_WIDTH_ACTIVE_F] {BITSOFFS(248, 8), "LinkWidthActive", mad_dump_linkwidth}, + [IB_PORT_LINK_SPEED_SUPPORTED_F] {BITSOFFS(256, 4), "LinkSpeedSupported", mad_dump_linkspeedsup}, + [IB_PORT_STATE_F] {BITSOFFS(260, 4), "LinkState", mad_dump_portstate}, + [IB_PORT_PHYS_STATE_F] {BITSOFFS(264, 4), "PhysLinkState", mad_dump_physportstate}, + [IB_PORT_LINK_DOWN_DEF_F] {BITSOFFS(268, 4), "LinkDownDefState", mad_dump_linkdowndefstate}, + [IB_PORT_MKEY_PROT_BITS_F] {BITSOFFS(272, 2), "ProtectBits", mad_dump_uint}, + [IB_PORT_LMC_F] {BITSOFFS(277, 3), "LMC", mad_dump_uint}, + [IB_PORT_LINK_SPEED_ACTIVE_F] {BITSOFFS(280, 4), "LinkSpeedActive", mad_dump_linkspeed}, + [IB_PORT_LINK_SPEED_ENABLED_F] {BITSOFFS(284, 4), "LinkSpeedEnabled", mad_dump_linkspeeden}, + [IB_PORT_NEIGHBOR_MTU_F] {BITSOFFS(288, 4), "NeighborMTU", mad_dump_mtu}, + [IB_PORT_SMSL_F] {BITSOFFS(292, 4), "SMSL", mad_dump_uint}, + [IB_PORT_VL_CAP_F] {BITSOFFS(296, 4), "VLCap", mad_dump_vlcap}, + [IB_PORT_INIT_TYPE_F] {BITSOFFS(300, 4), "InitType", mad_dump_hex}, + [IB_PORT_VL_HIGH_LIMIT_F] {BITSOFFS(304, 8), "VLHighLimit", mad_dump_uint}, + [IB_PORT_VL_ARBITRATION_HIGH_CAP_F] {BITSOFFS(312, 8), "VLArbHighCap", mad_dump_uint}, + [IB_PORT_VL_ARBITRATION_LOW_CAP_F] {BITSOFFS(320, 8), "VLArbLowCap", mad_dump_uint}, + + [IB_PORT_INIT_TYPE_REPLY_F] {BITSOFFS(328, 4), "InitReply", mad_dump_hex}, + [IB_PORT_MTU_CAP_F] {BITSOFFS(332, 4), "MtuCap", mad_dump_mtu}, + [IB_PORT_VL_STALL_COUNT_F] {BITSOFFS(336, 3), "VLStallCount", mad_dump_uint}, + [IB_PORT_HOQ_LIFE_F] {BITSOFFS(339, 5), "HoqLife", mad_dump_uint}, + [IB_PORT_OPER_VLS_F] {BITSOFFS(344, 4), "OperVLs", mad_dump_opervls}, + [IB_PORT_PART_EN_INB_F] {BITSOFFS(348, 1), "PartEnforceInb", mad_dump_uint}, + [IB_PORT_PART_EN_OUTB_F] {BITSOFFS(349, 1), "PartEnforceOutb", mad_dump_uint}, + [IB_PORT_FILTER_RAW_INB_F] {BITSOFFS(350, 1), "FilterRawInb", mad_dump_uint}, + [IB_PORT_FILTER_RAW_OUTB_F] {BITSOFFS(351, 1), "FilterRawOutb", mad_dump_uint}, + [IB_PORT_MKEY_VIOL_F] {BITSOFFS(352, 16), "MkeyViolations", mad_dump_uint}, + [IB_PORT_PKEY_VIOL_F] {BITSOFFS(368, 16), "PkeyViolations", mad_dump_uint}, + [IB_PORT_QKEY_VIOL_F] {BITSOFFS(384, 16), "QkeyViolations", mad_dump_uint}, + [IB_PORT_GUID_CAP_F] {BITSOFFS(400, 8), "GuidCap", mad_dump_uint}, + [IB_PORT_CLIENT_REREG_F] {BITSOFFS(408, 1), "ClientReregister", mad_dump_uint}, + [IB_PORT_SUBN_TIMEOUT_F] {BITSOFFS(411, 5), "SubnetTimeout", mad_dump_uint}, + [IB_PORT_RESP_TIME_VAL_F] {BITSOFFS(419, 5), "RespTimeVal", mad_dump_uint}, + [IB_PORT_LOCAL_PHYS_ERR_F] {BITSOFFS(424, 4), "LocalPhysErr", mad_dump_uint}, + [IB_PORT_OVERRUN_ERR_F] {BITSOFFS(428, 4), "OverrunErr", mad_dump_uint}, + [IB_PORT_MAX_CREDIT_HINT_F] {BITSOFFS(432, 16), "MaxCreditHint", mad_dump_uint}, + [IB_PORT_LINK_ROUND_TRIP_F] {BITSOFFS(456, 24), "RoundTrip", mad_dump_uint}, + + /* + * NodeInfo fields: + */ + [IB_NODE_BASE_VERS_F] {BITSOFFS(0,8), "BaseVers", mad_dump_uint}, + [IB_NODE_CLASS_VERS_F] {BITSOFFS(8,8), "ClassVers", mad_dump_uint}, + [IB_NODE_TYPE_F] {BITSOFFS(16,8), "NodeType", mad_dump_node_type}, + [IB_NODE_NPORTS_F] {BITSOFFS(24,8), "NumPorts", mad_dump_uint}, + [IB_NODE_SYSTEM_GUID_F] {32, 64, "SystemGuid", mad_dump_hex}, + [IB_NODE_GUID_F] {96, 64, "Guid", mad_dump_hex}, + [IB_NODE_PORT_GUID_F] {160, 64, "PortGuid", mad_dump_hex}, + [IB_NODE_PARTITION_CAP_F] {BITSOFFS(224,16), "PartCap", mad_dump_uint}, + [IB_NODE_DEVID_F] {BITSOFFS(240,16), "DevId", mad_dump_hex}, + [IB_NODE_REVISION_F] {256, 32, "Revision", mad_dump_hex}, + [IB_NODE_LOCAL_PORT_F] {BITSOFFS(288,8), "LocalPort", mad_dump_uint}, + [IB_NODE_VENDORID_F] {BITSOFFS(296,24), "VendorId", mad_dump_hex}, + + /* + * SwitchInfo fields: + */ + [IB_SW_LINEAR_FDB_CAP_F] {BITSOFFS(0, 16), "LinearFdbCap", mad_dump_uint}, + [IB_SW_RANDOM_FDB_CAP_F] {BITSOFFS(16, 16), "RandomFdbCap", mad_dump_uint}, + [IB_SW_MCAST_FDB_CAP_F] {BITSOFFS(32, 16), "McastFdbCap", mad_dump_uint}, + [IB_SW_LINEAR_FDB_TOP_F] {BITSOFFS(48, 16), "LinearFdbTop", mad_dump_uint}, + [IB_SW_DEF_PORT_F] {BITSOFFS(64, 8), "DefPort", mad_dump_uint}, + [IB_SW_DEF_MCAST_PRIM_F] {BITSOFFS(72, 8), "DefMcastPrimPort", mad_dump_uint}, + [IB_SW_DEF_MCAST_NOT_PRIM_F] {BITSOFFS(80, 8), "DefMcastNotPrimPort", mad_dump_uint}, + [IB_SW_LIFE_TIME_F] {BITSOFFS(88, 5), "LifeTime", mad_dump_uint}, + [IB_SW_STATE_CHANGE_F] {BITSOFFS(93, 1), "StateChange", mad_dump_uint}, + [IB_SW_LIDS_PER_PORT_F] {BITSOFFS(96,16), "LidsPerPort", mad_dump_uint}, + [IB_SW_PARTITION_ENFORCE_CAP_F] {BITSOFFS(112, 16), "PartEnforceCap", mad_dump_uint}, + [IB_SW_PARTITION_ENF_INB_F] {BITSOFFS(128, 1), "InboundPartEnf", mad_dump_uint}, + [IB_SW_PARTITION_ENF_OUTB_F] {BITSOFFS(129, 1), "OutboundPartEnf", mad_dump_uint}, + [IB_SW_FILTER_RAW_INB_F] {BITSOFFS(130, 1), "FilterRawInbound", mad_dump_uint}, + [IB_SW_FILTER_RAW_OUTB_F] {BITSOFFS(131, 1), "FilterRawOutbound", mad_dump_uint}, + [IB_SW_ENHANCED_PORT0_F] {BITSOFFS(132, 1), "EnhancedPort0", mad_dump_uint}, + + /* + * SwitchLinearForwardingTable fields: + */ + [IB_LINEAR_FORW_TBL_F] {0, 512, "LinearForwTbl", mad_dump_array}, + + /* + * SwitchMulticastForwardingTable fields: + */ + [IB_MULTICAST_FORW_TBL_F] {0, 512, "MulticastForwTbl", mad_dump_array}, + + /* + * Notice/Trap fields + */ + [IB_NOTICE_IS_GENERIC_F] {BITSOFFS(0, 1), "NoticeIsGeneric", mad_dump_uint}, + [IB_NOTICE_TYPE_F] {BITSOFFS(1, 7), "NoticeType", mad_dump_uint}, + [IB_NOTICE_PRODUCER_F] {BITSOFFS(8, 24), "NoticeProducerType", mad_dump_node_type}, + [IB_NOTICE_TRAP_NUMBER_F] {BITSOFFS(32, 16), "NoticeTrapNumber", mad_dump_uint}, + [IB_NOTICE_ISSUER_LID_F] {BITSOFFS(48, 16), "NoticeIssuerLID", mad_dump_uint}, + [IB_NOTICE_TOGGLE_F] {BITSOFFS(64, 1), "NoticeToggle", mad_dump_uint}, + [IB_NOTICE_COUNT_F] {BITSOFFS(65, 15), "NoticeCount", mad_dump_uint}, + [IB_NOTICE_DATA_DETAILS_F] {80, 432, "NoticeDataDetails", mad_dump_array}, + [IB_NOTICE_DATA_LID_F] {BITSOFFS(80, 16), "NoticeDataLID", mad_dump_uint}, + [IB_NOTICE_DATA_144_LID_F] {BITSOFFS(96, 16), "NoticeDataTrap144LID", mad_dump_uint}, + [IB_NOTICE_DATA_144_CAPMASK_F] {BITSOFFS(128, 32), "NoticeDataTrap144CapMask", mad_dump_uint}, + + /* + * NodeDescription fields: + */ + [IB_NODE_DESC_F] {0, 64*8, "NodeDesc", mad_dump_string}, + + /* + * Port counters + */ + [IB_PC_PORT_SELECT_F] {BITSOFFS(8, 8), "PortSelect", mad_dump_uint}, + [IB_PC_COUNTER_SELECT_F] {BITSOFFS(16, 16), "CounterSelect", mad_dump_hex}, + [IB_PC_ERR_SYM_F] {BITSOFFS(32, 16), "SymbolErrors", mad_dump_uint}, + [IB_PC_LINK_RECOVERS_F] {BITSOFFS(48, 8), "LinkRecovers", mad_dump_uint}, + [IB_PC_LINK_DOWNED_F] {BITSOFFS(56, 8), "LinkDowned", mad_dump_uint}, + [IB_PC_ERR_RCV_F] {BITSOFFS(64, 16), "RcvErrors", mad_dump_uint}, + [IB_PC_ERR_PHYSRCV_F] {BITSOFFS(80, 16), "RcvRemotePhysErrors", mad_dump_uint}, + [IB_PC_ERR_SWITCH_REL_F] {BITSOFFS(96, 16), "RcvSwRelayErrors", mad_dump_uint}, + [IB_PC_XMT_DISCARDS_F] {BITSOFFS(112, 16), "XmtDiscards", mad_dump_uint}, + [IB_PC_ERR_XMTCONSTR_F] {BITSOFFS(128, 8), "XmtConstraintErrors", mad_dump_uint}, + [IB_PC_ERR_RCVCONSTR_F] {BITSOFFS(136, 8), "RcvConstraintErrors", mad_dump_uint}, + [IB_PC_ERR_LOCALINTEG_F] {BITSOFFS(152, 4), "LinkIntegrityErrors", mad_dump_uint}, + [IB_PC_ERR_EXCESS_OVR_F] {BITSOFFS(156, 4), "ExcBufOverrunErrors", mad_dump_uint}, + [IB_PC_VL15_DROPPED_F] {BITSOFFS(176, 16), "VL15Dropped", mad_dump_uint}, + [IB_PC_XMT_BYTES_F] {192, 32, "XmtData", mad_dump_uint}, + [IB_PC_RCV_BYTES_F] {224, 32, "RcvData", mad_dump_uint}, + [IB_PC_XMT_PKTS_F] {256, 32, "XmtPkts", mad_dump_uint}, + [IB_PC_RCV_PKTS_F] {288, 32, "RcvPkts", mad_dump_uint}, + + /* + * SMInfo + */ + [IB_SMINFO_GUID_F] {0, 64, "SmInfoGuid", mad_dump_hex}, + [IB_SMINFO_KEY_F] {64, 64, "SmInfoKey", mad_dump_hex}, + [IB_SMINFO_ACT_F] {128, 32, "SmActivity", mad_dump_uint}, + [IB_SMINFO_PRIO_F] {BITSOFFS(160, 4), "SmPriority", mad_dump_uint}, + [IB_SMINFO_STATE_F] {BITSOFFS(164, 4), "SmState", mad_dump_uint}, + + /* + * SA RMPP + */ + [IB_SA_RMPP_VERS_F] {BE_OFFS(24*8+24, 8), "RmppVers", mad_dump_uint}, + [IB_SA_RMPP_TYPE_F] {BE_OFFS(24*8+16, 8), "RmppType", mad_dump_uint}, + [IB_SA_RMPP_RESP_F] {BE_OFFS(24*8+11, 5), "RmppResp", mad_dump_uint}, + [IB_SA_RMPP_FLAGS_F] {BE_OFFS(24*8+8, 3), "RmppFlags", mad_dump_hex}, + [IB_SA_RMPP_STATUS_F] {BE_OFFS(24*8+0, 8), "RmppStatus", mad_dump_hex}, + + /* data1 */ + [IB_SA_RMPP_D1_F] {28*8, 32, "RmppData1", mad_dump_hex}, + [IB_SA_RMPP_SEGNUM_F] {28*8, 32, "RmppSegNum", mad_dump_uint}, + /* data2 */ + [IB_SA_RMPP_D2_F] {32*8, 32, "RmppData2", mad_dump_hex}, + [IB_SA_RMPP_LEN_F] {32*8, 32, "RmppPayload", mad_dump_uint}, + [IB_SA_RMPP_NEWWIN_F] {32*8, 32, "RmppNewWin", mad_dump_uint}, + + /* + * SA Path rec + */ + [IB_SA_PR_DGID_F] {64, 128, "PathRecDGid", mad_dump_array}, + [IB_SA_PR_SGID_F] {192, 128, "PathRecSGid", mad_dump_array}, + [IB_SA_PR_DLID_F] {BITSOFFS(320,16), "PathRecDLid", mad_dump_hex}, + [IB_SA_PR_SLID_F] {BITSOFFS(336,16), "PathRecSLid", mad_dump_hex}, + [IB_SA_PR_NPATH_F] {BITSOFFS(393,7), "PathRecNumPath", mad_dump_uint}, + + /* + * SA Get Multi Path + */ + [IB_SA_MP_NPATH_F] {BITSOFFS(41,7), "MultiPathNumPath", mad_dump_uint}, + [IB_SA_MP_NSRC_F] {BITSOFFS(120,8), "MultiPathNumSrc", mad_dump_uint}, + [IB_SA_MP_NDEST_F] {BITSOFFS(128,8), "MultiPathNumDest", mad_dump_uint}, + [IB_SA_MP_GID0_F] {192, 128, "MultiPathGid", mad_dump_array}, + + /* + * MC Member rec + */ + [IB_SA_MCM_MGID_F] {0, 128, "McastMemMGid", mad_dump_array}, + [IB_SA_MCM_PORTGID_F] {128, 128, "McastMemPortGid", mad_dump_array}, + [IB_SA_MCM_QKEY_F] {256, 32, "McastMemQkey", mad_dump_hex}, + [IB_SA_MCM_MLID_F] {BITSOFFS(288, 16), "McastMemMLid", mad_dump_hex}, + [IB_SA_MCM_MTU_F] {BITSOFFS(306, 6), "McastMemMTU", mad_dump_uint}, + [IB_SA_MCM_TCLASS_F] {BITSOFFS(312, 8), "McastMemTClass", mad_dump_uint}, + [IB_SA_MCM_PKEY_F] {BITSOFFS(320, 16), "McastMemPkey", mad_dump_uint}, + [IB_SA_MCM_RATE_F] {BITSOFFS(338, 6), "McastMemRate", mad_dump_uint}, + [IB_SA_MCM_SL_F] {BITSOFFS(352, 4), "McastMemSL", mad_dump_uint}, + [IB_SA_MCM_FLOW_LABEL_F] {BITSOFFS(356, 20), "McastMemFlowLbl", mad_dump_uint}, + [IB_SA_MCM_JOIN_STATE_F] {BITSOFFS(388, 4), "McastMemJoinState", mad_dump_uint}, + [IB_SA_MCM_PROXY_JOIN_F] {BITSOFFS(392, 1), "McastMemProxyJoin", mad_dump_uint}, + + /* + * Service record + */ + [IB_SA_SR_ID_F] {0, 64, "ServRecID", mad_dump_hex}, + [IB_SA_SR_GID_F] {64, 128, "ServRecGid", mad_dump_array}, + [IB_SA_SR_PKEY_F] {BITSOFFS(192, 16), "ServRecPkey", mad_dump_hex}, + [IB_SA_SR_LEASE_F] {224, 32, "ServRecLease", mad_dump_hex}, + [IB_SA_SR_KEY_F] {256, 128, "ServRecKey", mad_dump_hex}, + [IB_SA_SR_NAME_F] {384, 512, "ServRecName", mad_dump_string}, + [IB_SA_SR_DATA_F] {896, 512, "ServRecData", mad_dump_array}, /* ATS for example */ + + /* + * ATS SM record - within SA_SR_DATA + */ + [IB_ATS_SM_NODE_ADDR_F] {12*8, 32, "ATSNodeAddr", mad_dump_hex}, + [IB_ATS_SM_MAGIC_KEY_F] {BITSOFFS(16*8, 16), "ATSMagicKey", mad_dump_hex}, + [IB_ATS_SM_NODE_TYPE_F] {BITSOFFS(18*8, 16), "ATSNodeType", mad_dump_hex}, + [IB_ATS_SM_NODE_NAME_F] {32*8, 32*8, "ATSNodeName", mad_dump_string}, + + /* + * SLTOVL MAPPING TABLE + */ + [IB_SLTOVL_MAPPING_TABLE_F] {0, 64, "SLToVLMap", mad_dump_hex}, + + /* + * VL ARBITRATION TABLE + */ + [IB_VL_ARBITRATION_TABLE_F] {0, 512, "VLArbTbl", mad_dump_array}, + + /* + * IB vendor classes range 2 + */ + [IB_VEND2_OUI_F] {BE_OFFS(36*8, 24), "OUI", mad_dump_array}, + [IB_VEND2_DATA_F] {40*8, (256-40)*8, "Vendor2Data", mad_dump_array}, + + /* + * Extended port counters + */ + [IB_PC_EXT_PORT_SELECT_F] {BITSOFFS(8, 8), "PortSelect", mad_dump_uint}, + [IB_PC_EXT_COUNTER_SELECT_F] {BITSOFFS(16, 16), "CounterSelect", mad_dump_hex}, + [IB_PC_EXT_XMT_BYTES_F] {64, 64, "PortXmitData", mad_dump_uint}, + [IB_PC_EXT_RCV_BYTES_F] {128, 64, "PortRcvData", mad_dump_uint}, + [IB_PC_EXT_XMT_PKTS_F] {192, 64, "PortXmitPkts", mad_dump_uint}, + [IB_PC_EXT_RCV_PKTS_F] {256, 64, "PortRcvPkts", mad_dump_uint}, + [IB_PC_EXT_XMT_UPKTS_F] {320, 64, "PortUnicastXmitPkts", mad_dump_uint}, + [IB_PC_EXT_RCV_UPKTS_F] {384, 64, "PortUnicastRcvPkts", mad_dump_uint}, + [IB_PC_EXT_XMT_MPKTS_F] {448, 64, "PortMulticastXmitPkts", mad_dump_uint}, + [IB_PC_EXT_RCV_MPKTS_F] {512, 64, "PortMulticastRcvPkts", mad_dump_uint}, + + /* + * GUIDInfo fields + */ + [IB_GUID_GUID0_F] {0, 64, "GUID0", mad_dump_hex}, + +}; + +void +_set_field64(void *buf, int base_offs, ib_field_t *f, uint64_t val) +{ + uint64_t nval; + + nval = htonll(val); + memcpy((char *)buf + base_offs + f->bitoffs / 8, &nval, sizeof(uint64_t)); +} + +uint64_t +_get_field64(void *buf, int base_offs, ib_field_t *f) +{ + uint64_t val; + memcpy(&val, ((char *)buf + base_offs + f->bitoffs / 8), sizeof(uint64_t)); + return ntohll(val); +} + +void +_set_field(void *buf, int base_offs, ib_field_t *f, uint32_t val) +{ + int prebits = (8 - (f->bitoffs & 7)) & 7; + int postbits = (f->bitoffs + f->bitlen) & 7; + int bytelen = f->bitlen / 8; + unsigned idx = base_offs + f->bitoffs / 8; + char *p = (char *)buf; + + if (!bytelen && (f->bitoffs & 7) + f->bitlen < 8) { + p[3^idx] &= ~((((1 << f->bitlen) - 1)) << (f->bitoffs & 7)); + p[3^idx] |= (val & ((1 << f->bitlen) - 1)) << (f->bitoffs & 7); + return; + } + + if (prebits) { /* val lsb in byte msb */ + p[3^idx] &= (1 << (8 - prebits)) - 1; + p[3^idx++] |= (val & ((1 << prebits) - 1)) << (8 - prebits); + val >>= prebits; + } + + /* BIG endian byte order */ + for (; bytelen--; val >>= 8) + p[3^idx++] = val & 0xff; + + if (postbits) { /* val msb in byte lsb */ + p[3^idx] &= ~((1 << postbits) - 1); + p[3^idx] |= val; + } +} + +uint32_t +_get_field(void *buf, int base_offs, ib_field_t *f) +{ + int prebits = (8 - (f->bitoffs & 7)) & 7; + int postbits = (f->bitoffs + f->bitlen) & 7; + int bytelen = f->bitlen / 8; + unsigned idx = base_offs + f->bitoffs / 8; + uint8_t *p = (uint8_t *)buf; + uint32_t val = 0, v = 0, i; + + if (!bytelen && (f->bitoffs & 7) + f->bitlen < 8) + return (p[3^idx] >> (f->bitoffs & 7)) & ((1 << f->bitlen) - 1); + + if (prebits) /* val lsb from byte msb */ + v = p[3^idx++] >> (8 - prebits); + + if (postbits) { /* val msb from byte lsb */ + i = base_offs + (f->bitoffs + f->bitlen) / 8; + val = (p[3^i] & ((1 << postbits) - 1)); + } + + /* BIG endian byte order */ + for (idx += bytelen - 1; bytelen--; idx--) + val = (val << 8) | p[3^idx]; + + return (val << prebits) | v; +} + +/* field must be byte aligned */ +void +_set_array(void *buf, int base_offs, ib_field_t *f, void *val) +{ + int bitoffs = f->bitoffs; + + if (f->bitlen < 32) + bitoffs = BE_TO_BITSOFFS(bitoffs, f->bitlen); + + memcpy((uint8_t *)buf + base_offs + bitoffs / 8, val, f->bitlen / 8); +} + +void +_get_array(void *buf, int base_offs, ib_field_t *f, void *val) +{ + int bitoffs = f->bitoffs; + + if (f->bitlen < 32) + bitoffs = BE_TO_BITSOFFS(bitoffs, f->bitlen); + + memcpy(val, (uint8_t *)buf + base_offs + bitoffs / 8, f->bitlen / 8); +} diff --git a/contrib/ofed/management/libibmad/src/gs.c b/contrib/ofed/management/libibmad/src/gs.c new file mode 100644 index 000000000000..89c927ebb997 --- /dev/null +++ b/contrib/ofed/management/libibmad/src/gs.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include "mad.h" + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN + +static uint8_t * +pma_query_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout, unsigned id, const void *srcport) +{ + ib_rpc_t rpc = {0}; + int lid = dest->lid; + + DEBUG("lid %d port %d", lid, port); + + if (lid == -1) { + IBWARN("only lid routed is supported"); + return 0; + } + + rpc.mgtclass = IB_PERFORMANCE_CLASS; + rpc.method = IB_MAD_METHOD_GET; + rpc.attr.id = id; + + /* Same for attribute IDs */ + mad_set_field(rcvbuf, 0, IB_PC_PORT_SELECT_F, port); + rpc.attr.mod = 0; + rpc.timeout = timeout; + rpc.datasz = IB_PC_DATA_SZ; + rpc.dataoffs = IB_PC_DATA_OFFS; + + dest->qp = 1; + if (!dest->qkey) + dest->qkey = IB_DEFAULT_QP1_QKEY; + + if (srcport) { + return mad_rpc(srcport, &rpc, dest, rcvbuf, rcvbuf); + } else { + return madrpc(&rpc, dest, rcvbuf, rcvbuf); + } +} + +uint8_t * +pma_query(void *rcvbuf, ib_portid_t *dest, int port, unsigned timeout, unsigned id) +{ + return pma_query_via(rcvbuf, dest, port, timeout, id, NULL); +} + +uint8_t * +perf_classportinfo_query_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout, const void *srcport) +{ + return pma_query_via(rcvbuf, dest, port, timeout, CLASS_PORT_INFO, + srcport); +} + +uint8_t * +perf_classportinfo_query(void *rcvbuf, ib_portid_t *dest, int port, unsigned timeout) +{ + return pma_query(rcvbuf, dest, port, timeout, CLASS_PORT_INFO); +} + +uint8_t * +port_performance_query_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout, const void *srcport) +{ + return pma_query_via(rcvbuf, dest, port, timeout, + IB_GSI_PORT_COUNTERS, srcport); +} + +uint8_t * +port_performance_query(void *rcvbuf, ib_portid_t *dest, int port, unsigned timeout) +{ + return pma_query(rcvbuf, dest, port, timeout, IB_GSI_PORT_COUNTERS); +} + +static uint8_t * +performance_reset_via(void *rcvbuf, ib_portid_t *dest, int port, unsigned mask, + unsigned timeout, unsigned id, const void *srcport) +{ + ib_rpc_t rpc = {0}; + int lid = dest->lid; + + DEBUG("lid %d port %d mask 0x%x", lid, port, mask); + + if (lid == -1) { + IBWARN("only lid routed is supported"); + return 0; + } + + if (!mask) + mask = ~0; + + rpc.mgtclass = IB_PERFORMANCE_CLASS; + rpc.method = IB_MAD_METHOD_SET; + rpc.attr.id = id; + + memset(rcvbuf, 0, IB_MAD_SIZE); + + /* Same for attribute IDs */ + mad_set_field(rcvbuf, 0, IB_PC_PORT_SELECT_F, port); + mad_set_field(rcvbuf, 0, IB_PC_COUNTER_SELECT_F, mask); + rpc.attr.mod = 0; + rpc.timeout = timeout; + rpc.datasz = IB_PC_DATA_SZ; + rpc.dataoffs = IB_PC_DATA_OFFS; + dest->qp = 1; + if (!dest->qkey) + dest->qkey = IB_DEFAULT_QP1_QKEY; + + if (srcport) { + return mad_rpc(srcport, &rpc, dest, rcvbuf, rcvbuf); + } else { + return madrpc(&rpc, dest, rcvbuf, rcvbuf); + } +} + +static uint8_t * +performance_reset(void *rcvbuf, ib_portid_t *dest, int port, unsigned mask, + unsigned timeout, unsigned id) +{ + return performance_reset_via(rcvbuf, dest, port, mask, timeout, + id, NULL); +} + +uint8_t * +port_performance_reset_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned mask, unsigned timeout, const void *srcport) +{ + return performance_reset_via(rcvbuf, dest, port, mask, timeout, + IB_GSI_PORT_COUNTERS, srcport); +} + +uint8_t * +port_performance_reset(void *rcvbuf, ib_portid_t *dest, int port, unsigned mask, + unsigned timeout) +{ + return performance_reset(rcvbuf, dest, port, mask, timeout, IB_GSI_PORT_COUNTERS); +} + +uint8_t * +port_performance_ext_query_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout, const void *srcport) +{ + return pma_query_via(rcvbuf, dest, port, timeout, + IB_GSI_PORT_COUNTERS_EXT, srcport); +} + +uint8_t * +port_performance_ext_query(void *rcvbuf, ib_portid_t *dest, int port, unsigned timeout) +{ + return pma_query(rcvbuf, dest, port, timeout, IB_GSI_PORT_COUNTERS_EXT); +} + +uint8_t * +port_performance_ext_reset_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned mask, unsigned timeout, + const void *srcport) +{ + return performance_reset_via(rcvbuf, dest, port, mask, timeout, + IB_GSI_PORT_COUNTERS_EXT, srcport); +} + +uint8_t * +port_performance_ext_reset(void *rcvbuf, ib_portid_t *dest, int port, unsigned mask, + unsigned timeout) +{ + return performance_reset(rcvbuf, dest, port, mask, timeout, IB_GSI_PORT_COUNTERS_EXT); +} + +uint8_t * +port_samples_control_query_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout, const void *srcport) +{ + return pma_query_via(rcvbuf, dest, port, timeout, + IB_GSI_PORT_SAMPLES_CONTROL, srcport); +} + +uint8_t * +port_samples_control_query(void *rcvbuf, ib_portid_t *dest, int port, unsigned timeout) +{ + return pma_query(rcvbuf, dest, port, timeout, IB_GSI_PORT_SAMPLES_CONTROL); +} + +uint8_t * +port_samples_result_query_via(void *rcvbuf, ib_portid_t *dest, int port, + unsigned timeout, const void *srcport) +{ + return pma_query_via(rcvbuf, dest, port, timeout, + IB_GSI_PORT_SAMPLES_RESULT, srcport); +} + +uint8_t * +port_samples_result_query(void *rcvbuf, ib_portid_t *dest, int port, unsigned timeout) +{ + return pma_query(rcvbuf, dest, port, timeout, IB_GSI_PORT_SAMPLES_RESULT); +} diff --git a/contrib/ofed/management/libibmad/src/libibmad.map b/contrib/ofed/management/libibmad/src/libibmad.map new file mode 100644 index 000000000000..f26d28d4a7a6 --- /dev/null +++ b/contrib/ofed/management/libibmad/src/libibmad.map @@ -0,0 +1,110 @@ +IBMAD_1.3 { + global: + _mad_dump; + _mad_dump_field; + _mad_dump_val; + _mad_print_field; + mad_dump_array; + mad_dump_bitfield; + mad_dump_hex; + mad_dump_int; + mad_dump_linkdowndefstate; + mad_dump_linkspeed; + mad_dump_linkspeeden; + mad_dump_linkspeedsup; + mad_dump_linkwidth; + mad_dump_linkwidthen; + mad_dump_linkwidthsup; + mad_dump_mtu; + mad_dump_node_type; + mad_dump_nodedesc; + mad_dump_nodeinfo; + mad_dump_opervls; + mad_dump_perfcounters; + mad_dump_perfcounters_ext; + mad_dump_physportstate; + mad_dump_portcapmask; + mad_dump_portinfo; + mad_dump_portstates; + mad_dump_portstate; + mad_dump_rhex; + mad_dump_sltovl; + mad_dump_string; + mad_dump_switchinfo; + mad_dump_uint; + mad_dump_vlarbitration; + mad_dump_vlcap; + _get_array; + _get_field; + _get_field64; + _set_array; + _set_field; + _set_field64; + ib_mad_f; + perf_classportinfo_query; + port_performance_query; + port_performance_reset; + port_performance_ext_query; + port_performance_ext_reset; + port_samples_control_query; + port_samples_result_query; + mad_build_pkt; + mad_decode_field; + mad_encode; + mad_encode_field; + mad_trid; + portid2portnum; + portid2str; + str2drpath; + drpath2str; + mad_agent_class; + mad_class_agent; + mad_register_client; + mad_register_server; + ib_resolve_guid; + ib_resolve_portid_str; + ib_resolve_self; + ib_resolve_smlid; + ibdebug; + mad_rpc_open_port; + mad_rpc_close_port; + mad_rpc; + mad_rpc_rmpp; + madrpc; + madrpc_def_timeout; + madrpc_init; + madrpc_lock; + madrpc_portid; + madrpc_rmpp; + madrpc_save_mad; + madrpc_set_retries; + madrpc_set_timeout; + madrpc_show_errors; + madrpc_unlock; + ib_path_query; + sa_call; + sa_rpc_call; + mad_alloc; + mad_free; + mad_receive; + mad_respond; + mad_send; + smp_query; + smp_set; + ib_vendor_call; + smp_query_via; + smp_set_via; + ib_path_query_via; + ib_resolve_smlid_via; + ib_resolve_guid_via; + ib_resolve_portid_str_via; + ib_resolve_self_via; + perf_classportinfo_query_via; + port_performance_query_via; + port_performance_reset_via; + port_performance_ext_query_via; + port_performance_ext_reset_via; + port_samples_control_query_via; + port_samples_result_query_via; + local: *; +}; diff --git a/contrib/ofed/management/libibmad/src/mad.c b/contrib/ofed/management/libibmad/src/mad.c new file mode 100644 index 000000000000..1367ecd5c453 --- /dev/null +++ b/contrib/ofed/management/libibmad/src/mad.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN + +void +mad_decode_field(uint8_t *buf, int field, void *val) +{ + ib_field_t *f = ib_mad_f + field; + + if (!field) { + *(int *)val = *(int *)buf; + return; + } + if (f->bitlen <= 32) { + *(uint32_t *)val = _get_field(buf, 0, f); + return; + } + if (f->bitlen == 64) { + *(uint64_t *)val = _get_field64(buf, 0, f); + return; + } + _get_array(buf, 0, f, val); +} + +void +mad_encode_field(uint8_t *buf, int field, void *val) +{ + ib_field_t *f = ib_mad_f + field; + + if (!field) { + *(int *)buf = *(int *)val; + return; + } + if (f->bitlen <= 32) { + _set_field(buf, 0, f, *(uint32_t *)val); + return; + } + if (f->bitlen == 64) { + _set_field64(buf, 0, f, *(uint64_t *)val); + return; + } + _set_array(buf, 0, f, val); +} + +uint64_t +mad_trid(void) +{ + static uint64_t base; + static uint64_t trid; + uint64_t next; + + if (!base) { + srandom(time(0)*getpid()); + base = random(); + trid = random(); + } + next = ++trid | (base << 32); + return next; +} + +void * +mad_encode(void *buf, ib_rpc_t *rpc, ib_dr_path_t *drpath, void *data) +{ + int is_resp = rpc->method & IB_MAD_RESPONSE; + + /* first word */ + mad_set_field(buf, 0, IB_MAD_METHOD_F, rpc->method); + mad_set_field(buf, 0, IB_MAD_RESPONSE_F, is_resp ? 1 : 0); + mad_set_field(buf, 0, IB_MAD_CLASSVER_F, rpc->mgtclass == IB_SA_CLASS ? 2 : 1); + mad_set_field(buf, 0, IB_MAD_MGMTCLASS_F, rpc->mgtclass); + mad_set_field(buf, 0, IB_MAD_BASEVER_F, 1); + + /* second word */ + if (rpc->mgtclass == IB_SMI_DIRECT_CLASS) { + if (!drpath) { + IBWARN("encoding dr mad without drpath (null)"); + return 0; + } + mad_set_field(buf, 0, IB_DRSMP_HOPCNT_F, drpath->cnt); + mad_set_field(buf, 0, IB_DRSMP_HOPPTR_F, is_resp ? drpath->cnt + 1 : 0x0); + mad_set_field(buf, 0, IB_DRSMP_STATUS_F, rpc->rstatus); + mad_set_field(buf, 0, IB_DRSMP_DIRECTION_F, is_resp ? 1 : 0); /* out */ + } else + mad_set_field(buf, 0, IB_MAD_STATUS_F, rpc->rstatus); + + /* words 3,4,5,6 */ + if (!rpc->trid) + rpc->trid = mad_trid(); + + mad_set_field64(buf, 0, IB_MAD_TRID_F, rpc->trid); + mad_set_field(buf, 0, IB_MAD_ATTRID_F, rpc->attr.id); + mad_set_field(buf, 0, IB_MAD_ATTRMOD_F, rpc->attr.mod); + + /* words 7,8 */ + mad_set_field(buf, 0, IB_MAD_MKEY_F, rpc->mkey >> 32); + mad_set_field(buf, 4, IB_MAD_MKEY_F, rpc->mkey & 0xffffffff); + + if (rpc->mgtclass == IB_SMI_DIRECT_CLASS) { + /* word 9 */ + mad_set_field(buf, 0, IB_DRSMP_DRDLID_F, drpath->drdlid ? drpath->drdlid : 0xffff); + mad_set_field(buf, 0, IB_DRSMP_DRSLID_F, drpath->drslid ? drpath->drslid : 0xffff); + + /* bytes 128 - 256 - by default should be zero due to memset*/ + if (is_resp) + mad_set_array(buf, 0, IB_DRSMP_RPATH_F, drpath->p); + else + mad_set_array(buf, 0, IB_DRSMP_PATH_F, drpath->p); + } + + if (rpc->mgtclass == IB_SA_CLASS) + mad_set_field64(buf, 0, IB_SA_COMPMASK_F, rpc->mask); + + if (data) + memcpy((char *)buf + rpc->dataoffs, data, rpc->datasz); + + /* vendor mads range 2 */ + if (mad_is_vendor_range2(rpc->mgtclass)) + mad_set_field(buf, 0, IB_VEND2_OUI_F, rpc->oui); + + return (uint8_t *)buf + IB_MAD_SIZE; +} + +int +mad_build_pkt(void *umad, ib_rpc_t *rpc, ib_portid_t *dport, + ib_rmpp_hdr_t *rmpp, void *data) +{ + uint8_t *p, *mad; + int lid_routed = rpc->mgtclass != IB_SMI_DIRECT_CLASS; + int is_smi = (rpc->mgtclass == IB_SMI_CLASS || + rpc->mgtclass == IB_SMI_DIRECT_CLASS); + struct ib_mad_addr addr; + + if (!is_smi) + umad_set_addr(umad, dport->lid, dport->qp, dport->sl, dport->qkey); + else if (lid_routed) + umad_set_addr(umad, dport->lid, dport->qp, 0, 0); + else if ((dport->drpath.drslid != 0xffff) && (dport->lid > 0)) + umad_set_addr(umad, dport->lid, 0, 0, 0); + else + umad_set_addr(umad, 0xffff, 0, 0, 0); + + if (dport->grh_present && !is_smi) { + addr.grh_present = 1; + memcpy(addr.gid, dport->gid, 16); + addr.hop_limit = 0xff; + addr.traffic_class = 0; + addr.flow_label = 0; + umad_set_grh(umad, &addr); + } else + umad_set_grh(umad, 0); + umad_set_pkey(umad, is_smi ? 0 : dport->pkey_idx); + + mad = umad_get_mad(umad); + p = mad_encode(mad, rpc, lid_routed ? 0 : &dport->drpath, data); + + if (!is_smi && rmpp) { + mad_set_field(mad, 0, IB_SA_RMPP_VERS_F, 1); + mad_set_field(mad, 0, IB_SA_RMPP_TYPE_F, rmpp->type); + mad_set_field(mad, 0, IB_SA_RMPP_RESP_F, 0x3f); + mad_set_field(mad, 0, IB_SA_RMPP_FLAGS_F, rmpp->flags); + mad_set_field(mad, 0, IB_SA_RMPP_STATUS_F, rmpp->status); + mad_set_field(mad, 0, IB_SA_RMPP_D1_F, rmpp->d1.u); + mad_set_field(mad, 0, IB_SA_RMPP_D2_F, rmpp->d2.u); + } + + return p - mad; +} diff --git a/contrib/ofed/management/libibmad/src/portid.c b/contrib/ofed/management/libibmad/src/portid.c new file mode 100644 index 000000000000..24a555b13043 --- /dev/null +++ b/contrib/ofed/management/libibmad/src/portid.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN + +int +portid2portnum(ib_portid_t *portid) +{ + if (portid->lid > 0) + return -1; + + if (portid->drpath.cnt == 0) + return 0; + + return portid->drpath.p[(portid->drpath.cnt-1)]; +} + +char * +portid2str(ib_portid_t *portid) +{ + static char buf[1024] = "local"; + int n = 0; + + if (portid->lid > 0) { + n += sprintf(buf + n, "Lid %d", portid->lid); + if (portid->grh_present) { + char gid[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; + if (inet_ntop(AF_INET6, portid->gid, gid, sizeof(gid))) + n += sprintf(buf + n, " Gid %s", gid); + } + if (portid->drpath.cnt) + n += sprintf(buf + n, " "); + else + return buf; + } + n += sprintf(buf + n, "DR path "); + drpath2str(&(portid->drpath), buf + n, sizeof(buf) - n); + + return buf; +} + +int +str2drpath(ib_dr_path_t *path, char *routepath, int drslid, int drdlid) +{ + char *s, *str = routepath; + + path->cnt = -1; + + DEBUG("DR str: %s", routepath); + while (str && *str) { + if ((s = strchr(str, ','))) + *s = 0; + path->p[++path->cnt] = atoi(str); + if (!s) + break; + str = s+1; + } + + path->drdlid = drdlid ? drdlid : 0xffff; + path->drslid = drslid ? drslid : 0xffff; + + return path->cnt; +} + +char * +drpath2str(ib_dr_path_t *path, char *dstr, size_t dstr_size) +{ + int i = 0; + int rc = snprintf(dstr, dstr_size, "slid %d; dlid %d; %d", + path->drslid, path->drdlid, path->p[0]); + if (rc >= dstr_size) + return dstr; + for (i = 1; i <= path->cnt; i++) { + rc += snprintf(dstr+rc, dstr_size-rc, ",%d", path->p[i]); + if (rc >= dstr_size) + break; + } + return (dstr); +} diff --git a/contrib/ofed/management/libibmad/src/register.c b/contrib/ofed/management/libibmad/src/register.c new file mode 100644 index 000000000000..a33acd8e88e0 --- /dev/null +++ b/contrib/ofed/management/libibmad/src/register.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2004,2005 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "mad.h" + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN + +#define MAX_CLASS 256 +#define MAX_AGENTS 256 + +static int class_agent[MAX_CLASS]; +static int agent_class[MAX_AGENTS]; + +static int +register_agent(int agent, int mclass) +{ + static int initialized; + + if (!initialized) { + initialized++; + memset(class_agent, 0xff, sizeof class_agent); + memset(agent_class, 0xff, sizeof agent_class); + } + + if (mclass < 0 || mclass >= MAX_CLASS || + agent < 0 || agent >= MAX_AGENTS) { + DEBUG("bad mgmt class %d or agent %d", mclass, agent); + return -1; + } + + class_agent[mclass] = agent; + agent_class[agent] = mclass; + + return 0; +} + +static int +mgmt_class_vers(int mgmt_class) +{ + if ((mgmt_class >= IB_VENDOR_RANGE1_START_CLASS && + mgmt_class <= IB_VENDOR_RANGE1_END_CLASS) || + (mgmt_class >= IB_VENDOR_RANGE2_START_CLASS && + mgmt_class <= IB_VENDOR_RANGE2_END_CLASS)) + return 1; + + switch(mgmt_class) { + case IB_SMI_CLASS: + case IB_SMI_DIRECT_CLASS: + return 1; + case IB_SA_CLASS: + return 2; + case IB_PERFORMANCE_CLASS: + return 1; + case IB_DEVICE_MGMT_CLASS: + return 1; + case IB_CC_CLASS: + return 2; + } + + return 0; +} + +int +mad_class_agent(int mgmt) +{ + if (mgmt < 1 || mgmt > MAX_CLASS) + return -1; + return class_agent[mgmt]; +} + +int +mad_agent_class(int agent) +{ + if (agent < 1 || agent > MAX_AGENTS) + return -1; + return agent_class[agent]; +} + +int +mad_register_port_client(int port_id, int mgmt, uint8_t rmpp_version) +{ + int vers, agent; + + if ((vers = mgmt_class_vers(mgmt)) <= 0) { + DEBUG("Unknown class %d mgmt_class", mgmt); + return -1; + } + if ((agent = umad_register(port_id, mgmt, + vers, rmpp_version, 0)) < 0) { + DEBUG("Can't register agent for class %d", mgmt); + return -1; + } + + if (mgmt < 0 || mgmt >= MAX_CLASS || agent >= MAX_AGENTS) { + DEBUG("bad mgmt class %d or agent %d", mgmt, agent); + return -1; + } + + return agent; +} + +int +mad_register_client(int mgmt, uint8_t rmpp_version) +{ + int agent; + + agent = mad_register_port_client(madrpc_portid(), mgmt, rmpp_version); + if (agent < 0) + return agent; + + return register_agent(agent, mgmt); +} + +int +mad_register_server(int mgmt, uint8_t rmpp_version, + long method_mask[], uint32_t class_oui) +{ + long class_method_mask[16/sizeof(long)]; + uint8_t oui[3]; + int agent, vers, mad_portid; + + if (method_mask) + memcpy(class_method_mask, method_mask, sizeof class_method_mask); + else + memset(class_method_mask, 0xff, sizeof(class_method_mask)); + + if ((mad_portid = madrpc_portid()) < 0) + return -1; + + if (class_agent[mgmt] >= 0) { + DEBUG("Class 0x%x already registered", mgmt); + return -1; + } + if ((vers = mgmt_class_vers(mgmt)) <= 0) { + DEBUG("Unknown class 0x%x mgmt_class", mgmt); + return -1; + } + if (mgmt >= IB_VENDOR_RANGE2_START_CLASS && + mgmt <= IB_VENDOR_RANGE2_END_CLASS) { + oui[0] = (class_oui >> 16) & 0xff; + oui[1] = (class_oui >> 8) & 0xff; + oui[2] = class_oui & 0xff; + if ((agent = umad_register_oui(mad_portid, mgmt, rmpp_version, + oui, class_method_mask)) < 0) { + DEBUG("Can't register agent for class %d", mgmt); + return -1; + } + } else if ((agent = umad_register(mad_portid, mgmt, vers, rmpp_version, + class_method_mask)) < 0) { + DEBUG("Can't register agent for class %d", mgmt); + return -1; + } + + if (register_agent(agent, mgmt) < 0) + return -1; + + return agent; +} diff --git a/contrib/ofed/management/libibmad/src/resolve.c b/contrib/ofed/management/libibmad/src/resolve.c new file mode 100644 index 000000000000..25062f65f0be --- /dev/null +++ b/contrib/ofed/management/libibmad/src/resolve.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2004-2006 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN + +int +ib_resolve_smlid_via(ib_portid_t *sm_id, int timeout, const void *srcport) +{ + ib_portid_t self = {0}; + uint8_t portinfo[64]; + int lid; + + memset(sm_id, 0, sizeof(*sm_id)); + + if (!smp_query_via(portinfo, &self, IB_ATTR_PORT_INFO, + 0, 0, srcport)) + return -1; + + mad_decode_field(portinfo, IB_PORT_SMLID_F, &lid); + + return ib_portid_set(sm_id, lid, 0, 0); +} + +int +ib_resolve_smlid(ib_portid_t *sm_id, int timeout) +{ + return ib_resolve_smlid_via(sm_id, timeout, NULL); +} + +int +ib_resolve_guid_via(ib_portid_t *portid, uint64_t *guid, ib_portid_t *sm_id, int timeout, const void *srcport) +{ + ib_portid_t sm_portid; + char buf[IB_SA_DATA_SIZE] = {0}; + + if (!sm_id) { + sm_id = &sm_portid; + if (ib_resolve_smlid_via(sm_id, timeout, srcport) < 0) + return -1; + } + if (*(uint64_t*)&portid->gid == 0) + mad_set_field64(portid->gid, 0, IB_GID_PREFIX_F, IB_DEFAULT_SUBN_PREFIX); + if (guid) + mad_set_field64(portid->gid, 0, IB_GID_GUID_F, *guid); + + if ((portid->lid = ib_path_query_via(srcport, portid->gid, portid->gid, sm_id, buf)) < 0) + return -1; + + return 0; +} + +int +ib_resolve_portid_str_via(ib_portid_t *portid, char *addr_str, int dest_type, ib_portid_t *sm_id, const void *srcport) +{ + uint64_t guid; + int lid; + char *routepath; + ib_portid_t selfportid = {0}; + int selfport = 0; + + switch (dest_type) { + case IB_DEST_LID: + lid = strtol(addr_str, 0, 0); + if (!IB_LID_VALID(lid)) + return -1; + return ib_portid_set(portid, lid, 0, 0); + + case IB_DEST_DRPATH: + if (str2drpath(&portid->drpath, addr_str, 0, 0) < 0) + return -1; + return 0; + + case IB_DEST_GUID: + if (!(guid = strtoull(addr_str, 0, 0))) + return -1; + + /* keep guid in portid? */ + return ib_resolve_guid_via(portid, &guid, sm_id, 0, srcport); + + case IB_DEST_DRSLID: + lid = strtol(addr_str, &routepath, 0); + routepath++; + if (!IB_LID_VALID(lid)) + return -1; + ib_portid_set(portid, lid, 0, 0); + + /* handle DR parsing and set DrSLID to local lid */ + if (ib_resolve_self_via(&selfportid, &selfport, 0, srcport) < 0) + return -1; + if (str2drpath(&portid->drpath, routepath, selfportid.lid, 0) < 0) + return -1; + return 0; + + default: + IBWARN("bad dest_type %d", dest_type); + } + + return -1; +} + +int +ib_resolve_portid_str(ib_portid_t *portid, char *addr_str, int dest_type, ib_portid_t *sm_id) +{ + return ib_resolve_portid_str_via(portid, addr_str, dest_type, + sm_id, NULL); +} + +int +ib_resolve_self_via(ib_portid_t *portid, int *portnum, ibmad_gid_t *gid, + const void *srcport) +{ + ib_portid_t self = {0}; + uint8_t portinfo[64]; + uint8_t nodeinfo[64]; + uint64_t guid, prefix; + + if (!smp_query_via(nodeinfo, &self, IB_ATTR_NODE_INFO, 0, 0, srcport)) + return -1; + + if (!smp_query_via(portinfo, &self, IB_ATTR_PORT_INFO, 0, 0, srcport)) + return -1; + + mad_decode_field(portinfo, IB_PORT_LID_F, &portid->lid); + mad_decode_field(portinfo, IB_PORT_GID_PREFIX_F, &prefix); + mad_decode_field(nodeinfo, IB_NODE_PORT_GUID_F, &guid); + + if (portnum) + mad_decode_field(nodeinfo, IB_NODE_LOCAL_PORT_F, portnum); + if (gid) { + mad_encode_field(*gid, IB_GID_PREFIX_F, &prefix); + mad_encode_field(*gid, IB_GID_GUID_F, &guid); + } + return 0; +} + +int +ib_resolve_self(ib_portid_t *portid, int *portnum, ibmad_gid_t *gid) +{ + return ib_resolve_self_via (portid, portnum, gid, NULL); +} diff --git a/contrib/ofed/management/libibmad/src/rpc.c b/contrib/ofed/management/libibmad/src/rpc.c new file mode 100644 index 000000000000..f27c5af87770 --- /dev/null +++ b/contrib/ofed/management/libibmad/src/rpc.c @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2004-2006 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "mad.h" + +#define MAX_CLASS 256 + +struct ibmad_port { + int port_id; /* file descriptor returned by umad_open() */ + int class_agents[MAX_CLASS]; /* class2agent mapper */ +}; + +int ibdebug; + +static int mad_portid = -1; +static int iberrs; + +static int madrpc_retries = MAD_DEF_RETRIES; +static int def_madrpc_timeout = MAD_DEF_TIMEOUT_MS; +static void *save_mad; +static int save_mad_len = 256; + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN +#define ERRS if (iberrs || ibdebug) IBWARN + +#define MAD_TID(mad) (*((uint64_t *)((char *)(mad) + 8))) + +void +madrpc_show_errors(int set) +{ + iberrs = set; +} + +void +madrpc_save_mad(void *madbuf, int len) +{ + save_mad = madbuf; + save_mad_len = len; +} + +int +madrpc_set_retries(int retries) +{ + if (retries > 0) + madrpc_retries = retries; + return madrpc_retries; +} + +int +madrpc_set_timeout(int timeout) +{ + def_madrpc_timeout = timeout; + return 0; +} + +int +madrpc_def_timeout(void) +{ + return def_madrpc_timeout; +} + +int +madrpc_portid(void) +{ + return mad_portid; +} + +static int +_do_madrpc(int port_id, void *sndbuf, void *rcvbuf, int agentid, int len, + int timeout) +{ + uint32_t trid; /* only low 32 bits */ + int retries; + int length, status; + + if (!timeout) + timeout = def_madrpc_timeout; + + if (ibdebug > 1) { + IBWARN(">>> sending: len %d pktsz %zu", len, umad_size() + len); + xdump(stderr, "send buf\n", sndbuf, umad_size() + len); + } + + if (save_mad) { + memcpy(save_mad, umad_get_mad(sndbuf), + save_mad_len < len ? save_mad_len : len); + save_mad = 0; + } + + trid = mad_get_field64(umad_get_mad(sndbuf), 0, IB_MAD_TRID_F); + + for (retries = 0; retries < madrpc_retries; retries++) { + if (retries) { + ERRS("retry %d (timeout %d ms)", retries, timeout); + } + + length = len; + if (umad_send(port_id, agentid, sndbuf, length, timeout, 0) < 0) { + IBWARN("send failed; %s", strerror(errno)); + return -1; + } + + /* Use same timeout on receive side just in case */ + /* send packet is lost somewhere. */ + do { + if (umad_recv(port_id, rcvbuf, &length, timeout) < 0) { + IBWARN("recv failed: %s", strerror(errno)); + return -1; + } + + if (ibdebug > 1) { + IBWARN("rcv buf:"); + xdump(stderr, "rcv buf\n", umad_get_mad(rcvbuf), IB_MAD_SIZE); + } + } while ((uint32_t)mad_get_field64(umad_get_mad(rcvbuf), 0, IB_MAD_TRID_F) != trid); + + status = umad_status(rcvbuf); + if (!status) + return length; /* done */ + if (status == ENOMEM) + return length; + } + + ERRS("timeout after %d retries, %d ms", retries, timeout * retries); + return -1; +} + +void * +mad_rpc(const void *port_id, ib_rpc_t *rpc, ib_portid_t *dport, void *payload, + void *rcvdata) +{ + const struct ibmad_port *p = port_id; + int status, len; + uint8_t sndbuf[1024], rcvbuf[1024], *mad; + + len = 0; + memset(sndbuf, 0, umad_size() + IB_MAD_SIZE); + + if ((len = mad_build_pkt(sndbuf, rpc, dport, 0, payload)) < 0) + return 0; + + if ((len = _do_madrpc(p->port_id, sndbuf, rcvbuf, + p->class_agents[rpc->mgtclass], + len, rpc->timeout)) < 0) { + IBWARN("_do_madrpc failed; dport (%s)", portid2str(dport)); + return 0; + } + + mad = umad_get_mad(rcvbuf); + + if ((status = mad_get_field(mad, 0, IB_DRSMP_STATUS_F)) != 0) { + ERRS("MAD completed with error status 0x%x; dport (%s)", + status, portid2str(dport)); + return 0; + } + + if (ibdebug) { + IBWARN("data offs %d sz %d", rpc->dataoffs, rpc->datasz); + xdump(stderr, "mad data\n", mad + rpc->dataoffs, rpc->datasz); + } + + if (rcvdata) + memcpy(rcvdata, mad + rpc->dataoffs, rpc->datasz); + + return rcvdata; +} + +void * +mad_rpc_rmpp(const void *port_id, ib_rpc_t *rpc, ib_portid_t *dport, + ib_rmpp_hdr_t *rmpp, void *data) +{ + const struct ibmad_port *p = port_id; + int status, len; + uint8_t sndbuf[1024], rcvbuf[1024], *mad; + + memset(sndbuf, 0, umad_size() + IB_MAD_SIZE); + + DEBUG("rmpp %p data %p", rmpp, data); + + if ((len = mad_build_pkt(sndbuf, rpc, dport, rmpp, data)) < 0) + return 0; + + if ((len = _do_madrpc(p->port_id, sndbuf, rcvbuf, + p->class_agents[rpc->mgtclass], + len, rpc->timeout)) < 0) { + IBWARN("_do_madrpc failed; dport (%s)", portid2str(dport)); + return 0; + } + + mad = umad_get_mad(rcvbuf); + + if ((status = mad_get_field(mad, 0, IB_MAD_STATUS_F)) != 0) { + ERRS("MAD completed with error status 0x%x; dport (%s)", + status, portid2str(dport)); + return 0; + } + + if (ibdebug) { + IBWARN("data offs %d sz %d", rpc->dataoffs, rpc->datasz); + xdump(stderr, "rmpp mad data\n", mad + rpc->dataoffs, + rpc->datasz); + } + + if (rmpp) { + rmpp->flags = mad_get_field(mad, 0, IB_SA_RMPP_FLAGS_F); + if ((rmpp->flags & 0x3) && + mad_get_field(mad, 0, IB_SA_RMPP_VERS_F) != 1) { + IBWARN("bad rmpp version"); + return 0; + } + rmpp->type = mad_get_field(mad, 0, IB_SA_RMPP_TYPE_F); + rmpp->status = mad_get_field(mad, 0, IB_SA_RMPP_STATUS_F); + DEBUG("rmpp type %d status %d", rmpp->type, rmpp->status); + rmpp->d1.u = mad_get_field(mad, 0, IB_SA_RMPP_D1_F); + rmpp->d2.u = mad_get_field(mad, 0, IB_SA_RMPP_D2_F); + } + + if (data) + memcpy(data, mad + rpc->dataoffs, rpc->datasz); + + rpc->recsz = mad_get_field(mad, 0, IB_SA_ATTROFFS_F); + + return data; +} + +void * +madrpc(ib_rpc_t *rpc, ib_portid_t *dport, void *payload, void *rcvdata) +{ + struct ibmad_port port; + + port.port_id = mad_portid; + port.class_agents[rpc->mgtclass] = mad_class_agent(rpc->mgtclass); + return mad_rpc(&port, rpc, dport, payload, rcvdata); +} + +void * +madrpc_rmpp(ib_rpc_t *rpc, ib_portid_t *dport, ib_rmpp_hdr_t *rmpp, void *data) +{ + struct ibmad_port port; + + port.port_id = mad_portid; + port.class_agents[rpc->mgtclass] = mad_class_agent(rpc->mgtclass); + return mad_rpc_rmpp(&port, rpc, dport, rmpp, data); +} + +static pthread_mutex_t rpclock = PTHREAD_MUTEX_INITIALIZER; + +void +madrpc_lock(void) +{ + pthread_mutex_lock(&rpclock); +} + +void +madrpc_unlock(void) +{ + pthread_mutex_unlock(&rpclock); +} + +void +madrpc_init(char *dev_name, int dev_port, int *mgmt_classes, int num_classes) +{ + if (umad_init() < 0) + IBPANIC("can't init UMAD library"); + + if ((mad_portid = umad_open_port(dev_name, dev_port)) < 0) + IBPANIC("can't open UMAD port (%s:%d)", dev_name, dev_port); + + if (num_classes >= MAX_CLASS) + IBPANIC("too many classes %d requested", num_classes); + + while (num_classes--) { + int rmpp_version = 0; + int mgmt = *mgmt_classes++; + + if (mgmt == IB_SA_CLASS) + rmpp_version = 1; + if (mad_register_client(mgmt, rmpp_version) < 0) + IBPANIC("client_register for mgmt class %d failed", mgmt); + } +} + +void * +mad_rpc_open_port(char *dev_name, int dev_port, + int *mgmt_classes, int num_classes) +{ + struct ibmad_port *p; + int port_id; + + if (num_classes >= MAX_CLASS) { + IBWARN("too many classes %d requested", num_classes); + errno = EINVAL; + return NULL; + } + + if (umad_init() < 0) { + IBWARN("can't init UMAD library"); + errno = ENODEV; + return NULL; + } + + p = malloc(sizeof(*p)); + if (!p) { + errno = ENOMEM; + return NULL; + } + memset(p, 0, sizeof(*p)); + + if ((port_id = umad_open_port(dev_name, dev_port)) < 0) { + IBWARN("can't open UMAD port (%s:%d)", dev_name, dev_port); + if (!errno) + errno = EIO; + free(p); + return NULL; + } + + while (num_classes--) { + int rmpp_version = 0; + int mgmt = *mgmt_classes++; + int agent; + + if (mgmt == IB_SA_CLASS) + rmpp_version = 1; + if (mgmt < 0 || mgmt >= MAX_CLASS || + (agent = mad_register_port_client(port_id, mgmt, + rmpp_version)) < 0) { + IBWARN("client_register for mgmt %d failed", mgmt); + if(!errno) + errno = EINVAL; + umad_close_port(port_id); + free(p); + return NULL; + } + p->class_agents[mgmt] = agent; + } + + p->port_id = port_id; + return p; +} + +void +mad_rpc_close_port(void *port_id) +{ + struct ibmad_port *p = port_id; + + umad_close_port(p->port_id); + free(p); +} + +uint8_t * +sa_call(void *rcvbuf, ib_portid_t *portid, ib_sa_call_t *sa, unsigned timeout) +{ + struct ibmad_port port; + + port.port_id = mad_portid; + port.class_agents[IB_SA_CLASS] = mad_class_agent(IB_SA_CLASS); + return sa_rpc_call(&port, rcvbuf, portid, sa, timeout); +} diff --git a/contrib/ofed/management/libibmad/src/sa.c b/contrib/ofed/management/libibmad/src/sa.c new file mode 100644 index 000000000000..2e092ec10794 --- /dev/null +++ b/contrib/ofed/management/libibmad/src/sa.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN + +uint8_t * +sa_rpc_call(const void *ibmad_port, void *rcvbuf, ib_portid_t *portid, + ib_sa_call_t *sa, unsigned timeout) +{ + ib_rpc_t rpc = {0}; + uint8_t *p; + + DEBUG("attr 0x%x mod 0x%x route %s", sa->attrid, sa->mod, + portid2str(portid)); + + if (portid->lid <= 0) { + IBWARN("only lid routes are supported"); + return 0; + } + + rpc.mgtclass = IB_SA_CLASS; + rpc.method = sa->method; + rpc.attr.id = sa->attrid; + rpc.attr.mod = sa->mod; + rpc.mask = sa->mask; + rpc.timeout = timeout; + rpc.datasz = IB_SA_DATA_SIZE; + rpc.dataoffs = IB_SA_DATA_OFFS; + rpc.trid = sa->trid; + + portid->qp = 1; + if (!portid->qkey) + portid->qkey = IB_DEFAULT_QP1_QKEY; + + p = mad_rpc_rmpp(ibmad_port, &rpc, portid, 0/*&sa->rmpp*/, rcvbuf); /* TODO: RMPP */ + + sa->recsz = rpc.recsz; + + return p; +} + +/* PathRecord */ +#define IB_PR_COMPMASK_DGID (1ull<<2) +#define IB_PR_COMPMASK_SGID (1ull<<3) +#define IB_PR_COMPMASK_DLID (1ull<<4) +#define IB_PR_COMPMASK_SLID (1ull<<5) +#define IB_PR_COMPMASK_RAWTRAFIC (1ull<<6) +#define IB_PR_COMPMASK_RESV0 (1ull<<7) +#define IB_PR_COMPMASK_FLOWLABEL (1ull<<8) +#define IB_PR_COMPMASK_HOPLIMIT (1ull<<9) +#define IB_PR_COMPMASK_TCLASS (1ull<<10) +#define IB_PR_COMPMASK_REVERSIBLE (1ull<<11) +#define IB_PR_COMPMASK_NUMBPATH (1ull<<12) +#define IB_PR_COMPMASK_PKEY (1ull<<13) +#define IB_PR_COMPMASK_RESV1 (1ull<<14) +#define IB_PR_COMPMASK_SL (1ull<<15) +#define IB_PR_COMPMASK_MTUSELEC (1ull<<16) +#define IB_PR_COMPMASK_MTU (1ull<<17) +#define IB_PR_COMPMASK_RATESELEC (1ull<<18) +#define IB_PR_COMPMASK_RATE (1ull<<19) +#define IB_PR_COMPMASK_PKTLIFETIMESELEC (1ull<<20) +#define IB_PR_COMPMASK_PKTLIFETIME (1ull<<21) +#define IB_PR_COMPMASK_PREFERENCE (1ull<<22) + +#define IB_PR_DEF_MASK (IB_PR_COMPMASK_DGID |\ + IB_PR_COMPMASK_SGID |\ + IB_PR_COMPMASK_NUMBPATH) + +int +ib_path_query_via(const void *srcport, ibmad_gid_t srcgid, ibmad_gid_t destgid, ib_portid_t *sm_id, void *buf) +{ + int npath; + ib_sa_call_t sa = {0}; + uint8_t *p; + int dlid; + + npath = 1; /* only MAD_METHOD_GET is supported */ + memset(&sa, 0, sizeof sa); + sa.method = IB_MAD_METHOD_GET; + sa.attrid = IB_SA_ATTR_PATHRECORD; + sa.mask = IB_PR_DEF_MASK; + sa.trid = mad_trid(); + + memset(buf, 0, IB_SA_PR_RECSZ); + + mad_encode_field(buf, IB_SA_PR_NPATH_F, &npath); + mad_encode_field(buf, IB_SA_PR_DGID_F, destgid); + mad_encode_field(buf, IB_SA_PR_SGID_F, srcgid); + + if (srcport) { + p = sa_rpc_call (srcport, buf, sm_id, &sa, 0); + } else { + p = safe_sa_call(buf, sm_id, &sa, 0); + } + if (!p) { + IBWARN("sa call path_query failed"); + return -1; + } + + mad_decode_field(p, IB_SA_PR_DLID_F, &dlid); + return dlid; +} +int +ib_path_query(ibmad_gid_t srcgid, ibmad_gid_t destgid, ib_portid_t *sm_id, void *buf) +{ + return ib_path_query_via (NULL, srcgid, destgid, sm_id, buf); +} diff --git a/contrib/ofed/management/libibmad/src/serv.c b/contrib/ofed/management/libibmad/src/serv.c new file mode 100644 index 000000000000..9b20cb666110 --- /dev/null +++ b/contrib/ofed/management/libibmad/src/serv.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2004,2005 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN + +int +mad_send(ib_rpc_t *rpc, ib_portid_t *dport, ib_rmpp_hdr_t *rmpp, void *data) +{ + uint8_t pktbuf[1024]; + void *umad = pktbuf; + + memset(pktbuf, 0, umad_size()); + + DEBUG("rmpp %p data %p", rmpp, data); + + if (mad_build_pkt(umad, rpc, dport, rmpp, data) < 0) + return 0; + + if (ibdebug) { + IBWARN("data offs %d sz %d", rpc->dataoffs, rpc->datasz); + xdump(stderr, "mad send data\n", + (char *)umad_get_mad(umad) + rpc->dataoffs, rpc->datasz); + } + + if (umad_send(madrpc_portid(), mad_class_agent(rpc->mgtclass), + umad, IB_MAD_SIZE, rpc->timeout, 0) < 0) { + IBWARN("send failed; %m"); + return -1; + } + + return 0; +} + +int +mad_respond(void *umad, ib_portid_t *portid, uint32_t rstatus) +{ + uint8_t *mad = umad_get_mad(umad); + ib_mad_addr_t *mad_addr; + ib_rpc_t rpc = {0}; + ib_portid_t rport; + int is_smi; + + if (!portid) { + if (!(mad_addr = umad_get_mad_addr(umad))) + return -1; + + memset(&rport, 0, sizeof(rport)); + + rport.lid = ntohs(mad_addr->lid); + rport.qp = ntohl(mad_addr->qpn); + rport.qkey = ntohl(mad_addr->qkey); + rport.sl = mad_addr->sl; + + portid = &rport; + } + + DEBUG("dest %s", portid2str(portid)); + + rpc.mgtclass = mad_get_field(mad, 0, IB_MAD_MGMTCLASS_F); + + rpc.method = mad_get_field(mad, 0, IB_MAD_METHOD_F); + if (rpc.method == IB_MAD_METHOD_SET) + rpc.method = IB_MAD_METHOD_GET; + if (rpc.method != IB_MAD_METHOD_SEND) + rpc.method |= IB_MAD_RESPONSE; + + rpc.attr.id = mad_get_field(mad, 0, IB_MAD_ATTRID_F); + rpc.attr.mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F); + if (rpc.mgtclass == IB_SA_CLASS) + rpc.recsz = mad_get_field(mad, 0, IB_SA_ATTROFFS_F); + if (mad_is_vendor_range2(rpc.mgtclass)) + rpc.oui = mad_get_field(mad, 0, IB_VEND2_OUI_F); + + rpc.trid = mad_get_field64(mad, 0, IB_MAD_TRID_F); + + /* cleared by default: timeout, datasz, dataoffs, mkey, mask */ + + is_smi = rpc.mgtclass == IB_SMI_CLASS || + rpc.mgtclass == IB_SMI_DIRECT_CLASS; + + if (is_smi) + portid->qp = 0; + else if (!portid->qp) + portid->qp = 1; + + if (!portid->qkey && portid->qp == 1) + portid->qkey = IB_DEFAULT_QP1_QKEY; + + DEBUG("qp 0x%x class 0x%x method %d attr 0x%x mod 0x%x datasz %d off %d qkey %x", + portid->qp, rpc.mgtclass, rpc.method, rpc.attr.id, rpc.attr.mod, + rpc.datasz, rpc.dataoffs, portid->qkey); + + if (mad_build_pkt(umad, &rpc, portid, 0, 0) < 0) + return -1; + + if (ibdebug > 1) + xdump(stderr, "mad respond pkt\n", mad, IB_MAD_SIZE); + + if (umad_send(madrpc_portid(), mad_class_agent(rpc.mgtclass), umad, + IB_MAD_SIZE, rpc.timeout, 0) < 0) { + DEBUG("send failed; %m"); + return -1; + } + + return 0; +} + +void * +mad_receive(void *umad, int timeout) +{ + void *mad = umad ? umad : umad_alloc(1, umad_size() + IB_MAD_SIZE); + int agent; + int length = IB_MAD_SIZE; + + if ((agent = umad_recv(madrpc_portid(), mad, + &length, timeout)) < 0) { + if (!umad) + umad_free(mad); + DEBUG("recv failed: %m"); + return 0; + } + + return mad; +} + +void * +mad_alloc(void) +{ + return umad_alloc(1, umad_size() + IB_MAD_SIZE); +} + +void +mad_free(void *umad) +{ + umad_free(umad); +} diff --git a/contrib/ofed/management/libibmad/src/smp.c b/contrib/ofed/management/libibmad/src/smp.c new file mode 100644 index 000000000000..2c2bde2dfb14 --- /dev/null +++ b/contrib/ofed/management/libibmad/src/smp.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN + +uint8_t * +smp_set_via(void *data, ib_portid_t *portid, unsigned attrid, unsigned mod, unsigned timeout, const void *srcport) +{ + ib_rpc_t rpc = {0}; + + DEBUG("attr 0x%x mod 0x%x route %s", attrid, mod, portid2str(portid)); + if ((portid->lid <= 0) || + (portid->drpath.drslid == 0xffff) || + (portid->drpath.drdlid == 0xffff)) + rpc.mgtclass = IB_SMI_DIRECT_CLASS; /* direct SMI */ + else + rpc.mgtclass = IB_SMI_CLASS; /* Lid routed SMI */ + + rpc.method = IB_MAD_METHOD_SET; + rpc.attr.id = attrid; + rpc.attr.mod = mod; + rpc.timeout = timeout; + rpc.datasz = IB_SMP_DATA_SIZE; + rpc.dataoffs = IB_SMP_DATA_OFFS; + + portid->sl = 0; + portid->qp = 0; + + if (srcport) { + return mad_rpc(srcport, &rpc, portid, data, data); + } else { + return madrpc(&rpc, portid, data, data); + } +} + +uint8_t * +smp_set(void *data, ib_portid_t *portid, unsigned attrid, unsigned mod, unsigned timeout) +{ + return smp_set_via(data, portid, attrid, mod, timeout, NULL); +} + +uint8_t * +smp_query_via(void *rcvbuf, ib_portid_t *portid, unsigned attrid, unsigned mod, + unsigned timeout, const void *srcport) +{ + ib_rpc_t rpc = {0}; + + DEBUG("attr 0x%x mod 0x%x route %s", attrid, mod, portid2str(portid)); + rpc.method = IB_MAD_METHOD_GET; + rpc.attr.id = attrid; + rpc.attr.mod = mod; + rpc.timeout = timeout; + rpc.datasz = IB_SMP_DATA_SIZE; + rpc.dataoffs = IB_SMP_DATA_OFFS; + + if ((portid->lid <= 0) || + (portid->drpath.drslid == 0xffff) || + (portid->drpath.drdlid == 0xffff)) + rpc.mgtclass = IB_SMI_DIRECT_CLASS; /* direct SMI */ + else + rpc.mgtclass = IB_SMI_CLASS; /* Lid routed SMI */ + + portid->sl = 0; + portid->qp = 0; + + if (srcport) { + return mad_rpc(srcport, &rpc, portid, 0, rcvbuf); + } else { + return madrpc(&rpc, portid, 0, rcvbuf); + } +} + +uint8_t * +smp_query(void *rcvbuf, ib_portid_t *portid, unsigned attrid, unsigned mod, + unsigned timeout) +{ + return smp_query_via(rcvbuf, portid, attrid, mod, timeout, NULL); +} diff --git a/contrib/ofed/management/libibmad/src/vendor.c b/contrib/ofed/management/libibmad/src/vendor.c new file mode 100644 index 000000000000..468e2d3496e1 --- /dev/null +++ b/contrib/ofed/management/libibmad/src/vendor.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2004,2005 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#undef DEBUG +#define DEBUG if (ibdebug) IBWARN + +static inline int +response_expected(int method) +{ + return method == IB_MAD_METHOD_GET || + method == IB_MAD_METHOD_SET || + method == IB_MAD_METHOD_TRAP; +} + +uint8_t * +ib_vendor_call(void *data, ib_portid_t *portid, ib_vendor_call_t *call) +{ + ib_rpc_t rpc = {0}; + int range1 = 0, resp_expected; + + DEBUG("route %s data %p", portid2str(portid), data); + if (portid->lid <= 0) + return 0; /* no direct SMI */ + + if (!(range1 = mad_is_vendor_range1(call->mgmt_class)) && + !(mad_is_vendor_range2(call->mgmt_class))) + return 0; + + resp_expected = response_expected(call->method); + + rpc.mgtclass = call->mgmt_class; + + rpc.method = call->method; + rpc.attr.id = call->attrid; + rpc.attr.mod = call->mod; + rpc.timeout = resp_expected ? call->timeout : 0; + rpc.datasz = range1 ? IB_VENDOR_RANGE1_DATA_SIZE : IB_VENDOR_RANGE2_DATA_SIZE; + rpc.dataoffs = range1 ? IB_VENDOR_RANGE1_DATA_OFFS : IB_VENDOR_RANGE2_DATA_OFFS; + + if (!range1) + rpc.oui = call->oui; + + DEBUG("class 0x%x method 0x%x attr 0x%x mod 0x%x datasz %d off %d res_ex %d", + rpc.mgtclass, rpc.method, rpc.attr.id, rpc.attr.mod, + rpc.datasz, rpc.dataoffs, resp_expected); + + portid->qp = 1; + if (!portid->qkey) + portid->qkey = IB_DEFAULT_QP1_QKEY; + + if (resp_expected) + return madrpc_rmpp(&rpc, portid, 0, data); /* FIXME: no RMPP for now */ + + return mad_send(&rpc, portid, 0, data) < 0 ? 0 : data; /* FIXME: no RMPP for now */ +} diff --git a/contrib/ofed/management/libibumad/AUTHORS b/contrib/ofed/management/libibumad/AUTHORS new file mode 100644 index 000000000000..d09c13fe2781 --- /dev/null +++ b/contrib/ofed/management/libibumad/AUTHORS @@ -0,0 +1,3 @@ +Shahar Frank +Hal Rosenstock +Sasha Khapyorsky diff --git a/contrib/ofed/management/libibumad/COPYING b/contrib/ofed/management/libibumad/COPYING new file mode 100644 index 000000000000..1b1ca1d2fb84 --- /dev/null +++ b/contrib/ofed/management/libibumad/COPYING @@ -0,0 +1,384 @@ +This software with the exception of OpenSM is available to you +under a choice of one of two licenses. You may chose to be +licensed under the terms of the the OpenIB.org BSD license or +the GNU General Public License (GPL) Version 2, both included +below. + +OpenSM is licensed under either GNU General Public License (GPL) +Version 2, or Intel BSD + Patent license. See OpenSM for the +specific language for the latter licensing terms. + + +Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + +================================================================== + + OpenIB.org BSD license + +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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +================================================================== + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/ofed/management/libibumad/ChangeLog b/contrib/ofed/management/libibumad/ChangeLog new file mode 100644 index 000000000000..f394ef8c89a9 --- /dev/null +++ b/contrib/ofed/management/libibumad/ChangeLog @@ -0,0 +1,94 @@ +2007-07-10 Hal Rosenstock + + * Release version 1.1.2 + + * Makefile.am: Add man/umad_set_pkey.3 into install + + * man/umad_set_pkey.3: Clarify that umad_set_pkey takes + pkey_index rather than pkey + +2007-07-10 Sean Hefty + + * include/infiniband/umad.h: Clarify that umad_set_pkey() + takes a pkey index, and not the pkey itself + +2007-06-26 Hal Rosenstock + + * src/umad.c: Change uint to unsigned for strict ANSI + +2007-06-26 Michael S. Tsirkin + + * include/infiniband/umad.h: Change uint to unsigned + for strict ANSI + +2007-05-24 Hal Rosenstock + + * man/umad_set_grh.3, man/umad_set_grh_net.3: Some more + changes based on comments from Dotan Barak + +2007-05-23 Ira K. Weiny + + * libibumad.spec.in: Add man pages + +2007-05-21 Hal Rosenstock + + * man/umad_set_addr.3, man/umad_set_addr_net.3, + man/umad_set_grh.3, man/umad_set_grh_net.3: + Add "SEE ALSO" section + + * man: More changes based on additional comments from Dotan Barak + +2007-05-17 Hal Rosenstock + + * Makefile.am: No longer install man/umad_set_pkey.3 + + * man: Man page updates based on comments from Dotan Barak + +2007-05-11 Hal Rosenstock + + * Release version 1.1.1. + + * Makefile.am: Added man pages support + + * man: Add initial version of libibumad man pages + +2007-04-24 Roland Dreier + + * src/umad.c: In umad_open_port, fix declaration of + return value from dev_to_umad_id + +2007-04-24 Hal Rosenstock + + * src/umad,c: In get_ca, handle drivers which do not + support SYS_CA_HW_VERS or SYS_CA_TYPE + +2007-03-29 Hal Rosenstock + + * Release version 1.1.0. + +2007-03-22 Hal Rosenstock + + * src/umad.c: Implement GRH support in umad_set_grh + +2007-03-11 Dotan Barak + + * src/umad.c: In umad_get_ca_portguids, add release_ca call + in error flow to prevent resource leak + +2007-01-25 Hal Rosenstock + + * Release version 1.0.2. + +2006-11-20 Sasha Khapyorsky + + * src/umad.c: Fix various uses of printf() style functions + +2006-10-31 Sasha Khapyorsky + + * src/umad.c (umad_set_addr_net): Fix endian used in + TRACE macro + +2006-09-28 Sasha Khapyorsky + + * src/umad.c (umad_open_port): Show open()'s errno string + diff --git a/contrib/ofed/management/libibumad/Makefile.am b/contrib/ofed/management/libibumad/Makefile.am new file mode 100644 index 000000000000..1e3e6fdc8f28 --- /dev/null +++ b/contrib/ofed/management/libibumad/Makefile.am @@ -0,0 +1,56 @@ + +SUBDIRS = . + +INCLUDES = -I$(srcdir)/include/infiniband -I$(includedir) + +man_MANS = man/umad_debug.3 man/umad_get_ca.3 \ + man/umad_get_ca_portguids.3 man/umad_get_cas_names.3 \ + man/umad_get_mad.3 man/umad_get_port.3 man/umad_init.3 \ + man/umad_open_port.3 man/umad_close_port.3 man/umad_size.3 \ + man/umad_status.3 man/umad_alloc.3 man/umad_free.3 \ + man/umad_dump.3 man/umad_addr_dump.3 man/umad_get_fd.3 \ + man/umad_get_mad.3 man/umad_get_mad_addr.3 \ + man/umad_set_grh_net.3 man/umad_set_grh.3 \ + man/umad_set_addr_net.3 man/umad_set_addr.3 man/umad_set_pkey.3 \ + man/umad_get_pkey.3 \ + man/umad_register.3 man/umad_register_oui.3 man/umad_unregister.3 \ + man/umad_send.3 man/umad_recv.3 man/umad_poll.3 \ + man/umad_get_issm_path.3 + +lib_LTLIBRARIES = libibumad.la + +libibumad_la_CFLAGS = -Wall + +if HAVE_LD_VERSION_SCRIPT +libibumad_version_script = -Wl,--version-script=$(srcdir)/src/libibumad.map +else +libibumad_version_script = +endif + +libibumad_la_SOURCES = src/umad.c +libibumad_la_LDFLAGS = -version-info $(ibumad_api_version) \ + -export-dynamic $(libibumad_version_script) +libibumad_la_DEPENDENCIES = $(srcdir)/src/libibumad.map + +libibumadincludedir = $(includedir)/infiniband + +libibumadinclude_HEADERS = $(srcdir)/include/infiniband/umad.h + +EXTRA_DIST = $(srcdir)/include/infiniband/umad.h \ + libibumad.spec.in libibumad.spec \ + $(srcdir)/src/libibumad.map libibumad.ver \ + $(man_MANS) autogen.sh + +dist-hook: + if [ -x $(top_srcdir)/../gen_chlog.sh ] ; then \ + $(top_srcdir)/../gen_chlog.sh $(PACKAGE) > $(distdir)/ChangeLog ; \ + fi + +install-data-hook: + cd $(DESTDIR)$(mandir)/man3 && \ + $(RM) umad_done.3 && \ + $(RM) umad_release_ca.3 && \ + $(RM) umad_release_port.3 && \ + $(LN_S) umad_init.3 umad_done.3 && \ + $(LN_S) umad_get_ca.3 umad_release_ca.3 && \ + $(LN_S) umad_get_port.3 umad_release_port.3 diff --git a/contrib/ofed/management/libibumad/autogen.sh b/contrib/ofed/management/libibumad/autogen.sh new file mode 100755 index 000000000000..4827884ba1f1 --- /dev/null +++ b/contrib/ofed/management/libibumad/autogen.sh @@ -0,0 +1,11 @@ +#! /bin/sh + +# create config dir if not exist +test -d config || mkdir config + +set -x +aclocal -I config +libtoolize --force --copy +autoheader +automake --foreign --add-missing --copy +autoconf diff --git a/contrib/ofed/management/libibumad/configure.in b/contrib/ofed/management/libibumad/configure.in new file mode 100644 index 000000000000..ad3afcddf0d4 --- /dev/null +++ b/contrib/ofed/management/libibumad/configure.in @@ -0,0 +1,90 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(libibumad, 1.3.0, general@lists.openfabrics.org) +AC_CONFIG_SRCDIR([src/umad.c]) +AC_CONFIG_AUX_DIR(config) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE + +AC_SUBST(RELEASE, ${RELEASE:-unknown}) +AC_SUBST(TARBALL, ${TARBALL:-${PACKAGE}-${VERSION}.tar.gz}) + +dnl the library version info is available in the file: libibumad.ver +ibumad_api_version=`grep LIBVERSION $srcdir/libibumad.ver | sed 's/LIBVERSION=//'` +if test -z $ibumad_api_version; then + ibumad_api_version=1:0:0 +fi +AC_SUBST(ibumad_api_version) + +AC_ARG_ENABLE(libcheck, [ --disable-libcheck do not test for presence of ib libraries], +[ if test x$enableval = xno ; then + disable_libcheck=yes + fi +]) + +AC_ARG_WITH([valgrind], + AC_HELP_STRING([--with-valgrind], + [Enable Valgrind annotations (small runtime overhead, default NO)])) +if test x$with_valgrind = x || test x$with_valgrind = xno; then + want_valgrind=no + AC_DEFINE([NVALGRIND], 1, [Define to 1 to disable Valgrind annotations.]) +else + want_valgrind=yes + if test -d $with_valgrind; then + CPPFLAGS="$CPPFLAGS -I$with_valgrind/include" + fi +fi + +dnl Checks for programs +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AM_PROG_LIBTOOL + +if test "$disable_libcheck" != "yes" +then +dnl Checks for libraries +AC_CHECK_LIB(ibcommon, sys_read_string, [], + AC_MSG_ERROR([sys_read_string() not found. libibumad requires libibcommon.])) +fi + +dnl Checks for header files. +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_CHECK_HEADERS([fcntl.h netinet/in.h stdlib.h string.h sys/ioctl.h unistd.h]) +if test "$disable_libcheck" != "yes" +then +AC_CHECK_HEADER(infiniband/common.h, [], + AC_MSG_ERROR([ not found. libibumad requires libibcommon.]) +) +fi + +dnl Checks for library functions +AC_PROG_GCC_TRADITIONAL +AC_FUNC_MALLOC +AC_CHECK_FUNCS([memset]) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_INLINE + +AC_CHECK_HEADER(valgrind/memcheck.h, + [AC_DEFINE(HAVE_VALGRIND_MEMCHECK_H, 1, + [Define to 1 if you have the header file.])], + [if test $want_valgrind = yes; then + AC_MSG_ERROR([Valgrind memcheck support requested, but not found.]) + fi]) + +AC_CACHE_CHECK(whether ld accepts --version-script, ac_cv_version_script, + if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then + ac_cv_version_script=yes + else + ac_cv_version_script=no + fi) + +AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$ac_cv_version_script" = "yes") + +AC_CONFIG_FILES([Makefile libibumad.spec]) +AC_OUTPUT diff --git a/contrib/ofed/management/libibumad/include/infiniband/umad.h b/contrib/ofed/management/libibumad/include/infiniband/umad.h new file mode 100644 index 000000000000..cc5bef5424b7 --- /dev/null +++ b/contrib/ofed/management/libibumad/include/infiniband/umad.h @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#ifndef _UMAD_H +#define _UMAD_H + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +#define UMAD_MAX_DEVICES 20 +#define UMAD_ANY_PORT 0 + +typedef struct ib_mad_addr { + uint32_t qpn; + uint32_t qkey; + uint16_t lid; + uint8_t sl; + uint8_t path_bits; + uint8_t grh_present; + uint8_t gid_index; + uint8_t hop_limit; + uint8_t traffic_class; + uint8_t gid[16]; + uint32_t flow_label; + uint16_t pkey_index; + uint8_t reserved[6]; +} ib_mad_addr_t; + +typedef struct ib_user_mad { + uint32_t agent_id; + uint32_t status; + uint32_t timeout_ms; + uint32_t retries; + uint32_t length; + ib_mad_addr_t addr; + uint8_t data[0]; +} ib_user_mad_t; + +#define IB_UMAD_ABI_VERSION 5 +#define IB_UMAD_ABI_DIR "/sys/class/infiniband_mad" +#define IB_UMAD_ABI_FILE "abi_version" + +#define IB_IOCTL_MAGIC 0x1b + +#define IB_USER_MAD_REGISTER_AGENT _IO(IB_IOCTL_MAGIC, 1) +#define IB_USER_MAD_UNREGISTER_AGENT _IO(IB_IOCTL_MAGIC, 2) +#define IB_USER_MAD_ENABLE_PKEY _IO(IB_IOCTL_MAGIC, 3) + +#define UMAD_CA_NAME_LEN 20 +#define UMAD_CA_MAX_PORTS 10 /* 0 - 9 */ +#define UMAD_CA_MAX_AGENTS 32 + +#define SYS_INFINIBAND "/sys/class/infiniband" + +#define SYS_INFINIBAND_MAD "/sys/class/infiniband_mad" +#define SYS_IB_MAD_PORT "port" +#define SYS_IB_MAD_DEV "ibdev" + +#define UMAD_MAX_PORTS 64 + +#define UMAD_DEV_DIR "/dev" + +#define SYS_CA_PORTS_DIR "ports" + +#define SYS_NODE_TYPE "node_type" +#define SYS_CA_FW_VERS "fw_ver" +#define SYS_CA_HW_VERS "hw_rev" +#define SYS_CA_TYPE "hca_type" +#define SYS_CA_NODE_GUID "node_guid" +#define SYS_CA_SYS_GUID "sys_image_guid" + +#define SYS_PORT_LMC "lid_mask_count" +#define SYS_PORT_SMLID "sm_lid" +#define SYS_PORT_SMSL "sm_sl" +#define SYS_PORT_LID "lid" +#define SYS_PORT_STATE "state" +#define SYS_PORT_PHY_STATE "phys_state" +#define SYS_PORT_CAPMASK "cap_mask" +#define SYS_PORT_RATE "rate" +#define SYS_PORT_GUID "port_guid" +#define SYS_PORT_GID "gids/0" + +typedef struct umad_port { + char ca_name[UMAD_CA_NAME_LEN]; + int portnum; + unsigned base_lid; + unsigned lmc; + unsigned sm_lid; + unsigned sm_sl; + unsigned state; + unsigned phys_state; + unsigned rate; + uint64_t capmask; + uint64_t gid_prefix; + uint64_t port_guid; + unsigned pkeys_size; + uint16_t *pkeys; +} umad_port_t; + +typedef struct umad_ca { + char ca_name[UMAD_CA_NAME_LEN]; + unsigned node_type; + int numports; + char fw_ver[20]; + char ca_type[40]; + char hw_ver[20]; + uint64_t node_guid; + uint64_t system_guid; + umad_port_t *ports[UMAD_CA_MAX_PORTS]; +} umad_ca_t; + +int umad_init(void); +int umad_done(void); + +int umad_get_cas_names(char cas[][UMAD_CA_NAME_LEN], int max); +int umad_get_ca_portguids(char *ca_name, uint64_t *portguids, int max); + +int umad_get_ca(char *ca_name, umad_ca_t *ca); +int umad_release_ca(umad_ca_t *ca); +int umad_get_port(char *ca_name, int portnum, umad_port_t *port); +int umad_release_port(umad_port_t *port); + +int umad_get_issm_path(char *ca_name, int portnum, char path[], int max); + +int umad_open_port(char *ca_name, int portnum); +int umad_close_port(int portid); + +void * umad_get_mad(void *umad); +size_t umad_size(void); +int umad_status(void *umad); + +ib_mad_addr_t *umad_get_mad_addr(void *umad); +int umad_set_grh_net(void *umad, void *mad_addr); +int umad_set_grh(void *umad, void *mad_addr); +int umad_set_addr_net(void *umad, int dlid, int dqp, int sl, int qkey); +int umad_set_addr(void *umad, int dlid, int dqp, int sl, int qkey); +int umad_set_pkey(void *umad, int pkey_index); +int umad_get_pkey(void *umad); + +int umad_send(int portid, int agentid, void *umad, int length, + int timeout_ms, int retries); +int umad_recv(int portid, void *umad, int *length, int timeout_ms); +int umad_poll(int portid, int timeout_ms); +int umad_get_fd(int portid); + +int umad_register(int portid, int mgmt_class, int mgmt_version, + uint8_t rmpp_version, long method_mask[16/sizeof(long)]); +int umad_register_oui(int portid, int mgmt_class, uint8_t rmpp_version, + uint8_t oui[3], long method_mask[16/sizeof(long)]); +int umad_unregister(int portid, int agentid); + +int umad_debug(int level); +void umad_addr_dump(ib_mad_addr_t *addr); +void umad_dump(void *umad); + +#include + +static inline void * +umad_alloc(int num, size_t size) /* alloc array of umad buffers */ +{ + return calloc(num, size); +} + +static inline void +umad_free(void *umad) +{ + free(umad); +} + +END_C_DECLS + +#endif /* _UMAD_H */ diff --git a/contrib/ofed/management/libibumad/libibumad.spec.in b/contrib/ofed/management/libibumad/libibumad.spec.in new file mode 100644 index 000000000000..1b11d180967d --- /dev/null +++ b/contrib/ofed/management/libibumad/libibumad.spec.in @@ -0,0 +1,74 @@ + +%define RELEASE @RELEASE@ +%define rel %{?CUSTOM_RELEASE} %{!?CUSTOM_RELEASE:%RELEASE} + +Summary: OpenFabrics Alliance InfiniBand umad (user MAD) library +Name: libibumad +Version: @VERSION@ +Release: %rel%{?dist} +License: GPLv2 or BSD +Group: System Environment/Libraries +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +Source: http://www.openfabrics.org/downloads/management/@TARBALL@ +Url: http://openfabrics.org +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig +BuildRequires: libibcommon-devel, libtool + +%description +libibumad provides the user MAD library functions which sit on top of +the user MAD modules in the kernel. These are used by the IB diagnostic +and management tools, including OpenSM. + +%package devel +Summary: Development files for the libibumad library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} libibcommon-devel +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description devel +Development files for the libibumad library. + +%package static +Summary: Static version of the libibumad library +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} + +%description static +Static version of the libibumad library. + +%prep +%setup -q + +%build +%configure +make %{?_smp_mflags} + +%install +make DESTDIR=${RPM_BUILD_ROOT} install +# remove unpackaged files from the buildroot +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig +%postun -p /sbin/ldconfig +%post devel -p /sbin/ldconfig +%postun devel -p /sbin/ldconfig + +%files +%defattr(-,root,root) +%{_libdir}/libibumad*.so.* +%{_mandir}/man3/* +%doc AUTHORS COPYING ChangeLog + +%files devel +%defattr(-,root,root) +%{_libdir}/libibumad.so +%{_includedir}/infiniband/*.h + +%files static +%defattr(-,root,root) +%{_libdir}/libibumad.a diff --git a/contrib/ofed/management/libibumad/libibumad.ver b/contrib/ofed/management/libibumad/libibumad.ver new file mode 100644 index 000000000000..21cf1ed51f3b --- /dev/null +++ b/contrib/ofed/management/libibumad/libibumad.ver @@ -0,0 +1,9 @@ +# In this file we track the current API version +# of the IB umad interface (and libraries) +# The version is built of the following +# tree numbers: +# API_REV:RUNNING_REV:AGE +# API_REV - advance on any added API +# RUNNING_REV - advance any change to the vendor files +# AGE - number of backward versions the API still supports +LIBVERSION=1:3:0 diff --git a/contrib/ofed/management/libibumad/man/umad_addr_dump.3 b/contrib/ofed/management/libibumad/man/umad_addr_dump.3 new file mode 100644 index 000000000000..7f09214925e4 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_addr_dump.3 @@ -0,0 +1,45 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_ADDR_DUMP 3 "May 21, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_addr_dump \- dump addr structure to stderr +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "void umad_addr_dump(ib_mad_addr_t " "*addr"); +.fi +.SH "DESCRIPTION" +.B umad_addr_dump() +dumps the given +.I addr\fR +to stderr. +The argument +.I addr +is an +.I ib_mad_addr_t +struct, as specified in . +.PP +.nf +typedef struct ib_mad_addr { +.in +8 +uint32_t qpn; +uint32_t qkey; +uint16_t lid; +uint8_t sl; +uint8_t path_bits; +uint8_t grh_present; +uint8_t gid_index; +uint8_t hop_limit; +uint8_t traffic_class; +uint8_t gid[16]; +uint32_t flow_label; +.in -8 +} ib_mad_addr_t; +.fi +.SH "RETURN VALUE" +.B umad_addr_dump() +returns no value. +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_alloc.3 b/contrib/ofed/management/libibumad/man/umad_alloc.3 new file mode 100644 index 000000000000..5c65f3ece42b --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_alloc.3 @@ -0,0 +1,33 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_ALLOC 3 "May 21, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_alloc \- allocate memory for umad buffers +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "void * umad_alloc(int " "num" ", size_t " "size"); +.fi +.SH "DESCRIPTION" +.B umad_alloc() +allocates memory for an array of +.I num\fR +umad buffers of +.I size +bytes\fR. +Note that +.I size\fR +should include the +.B umad_size() +plus the length (MAD_BLOCK_SIZE for normal MADs or the length returned from +.B umad_recv() +for RMPP MADs). +.SH "RETURN VALUE" +.B umad_alloc() +returns NULL if out of memory. +.SH "SEE ALSO" +.BR umad_free (3) +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_close_port.3 b/contrib/ofed/management/libibumad/man/umad_close_port.3 new file mode 100644 index 000000000000..2c56d906b9b4 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_close_port.3 @@ -0,0 +1,26 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_OPEN_PORT 3 "May 11, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_close_port \- close InfiniBand device port for umad access +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_close_port(int " "portid" ); +.fi +.SH "DESCRIPTION" +.B umad_close_port() +closes the port specified by the handle +.I portid\fR. +.SH "RETURN VALUE" +.B umad_close_port() +returns 0 on success, and a negative value on error. +-EINVAL is returned if the +.I portid\fR +is not a handle to a valid (open) port. +.SH "SEE ALSO" +.BR umad_open_port (3) +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_debug.3 b/contrib/ofed/management/libibumad/man/umad_debug.3 new file mode 100644 index 000000000000..b7da2b01f0e5 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_debug.3 @@ -0,0 +1,29 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_DEBUG 3 "May 21, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_debug \- set debug level +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_debug(int " "level" ); +.fi +.SH "DESCRIPTION" +.B umad_debug() +sets the umad library internal debug level to +.I level\fR. +The following +debug levels are supported: 0 - no debug (the default), +1 - basic debug information, 2 - verbose debug information. Negative values are +ignored in terms of set. Note that the current debug level can +be queried by passing a negative value as +.I level\fR. +.SH "RETURN VALUE" +.B umad_debug() +returns the actual debug level. +.SH "AUTHORS" +.TP +Hal Rosenstock +.TP +Dotan Barak diff --git a/contrib/ofed/management/libibumad/man/umad_dump.3 b/contrib/ofed/management/libibumad/man/umad_dump.3 new file mode 100644 index 000000000000..101a2e0c4997 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_dump.3 @@ -0,0 +1,22 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_DUMP 3 "May 17, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_dump \- dump umad buffer to stderr +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "void umad_dump(void " "*umad"); +.fi +.SH "DESCRIPTION" +.B umad_dump() +dumps the given +.I umad\fR +buffer to stderr. +.SH "RETURN VALUE" +.B umad_dump() +returns no value. +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_free.3 b/contrib/ofed/management/libibumad/man/umad_free.3 new file mode 100644 index 000000000000..ac397942ea76 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_free.3 @@ -0,0 +1,23 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_FREE 3 "May 17, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_free \- frees memory of umad buffers +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "void umad_free(void " "*umad"); +.fi +.SH "DESCRIPTION" +.B umad_free() +frees memory previously allocated with +.B umad_alloc()\fR. +.SH "RETURN VALUE" +.B umad_free() +returns no value. +.SH "SEE ALSO" +.BR umad_alloc (3) +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_get_ca.3 b/contrib/ofed/management/libibumad/man/umad_get_ca.3 new file mode 100644 index 000000000000..2f5fd1a71420 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_get_ca.3 @@ -0,0 +1,65 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_GET_CA 3 "May 21, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_get_ca, umad_release_ca \- get and release InfiniBand device port attributes +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_get_ca(char " "*ca_name" ", umad_ca_t " "*ca" ); +.nl +.BI "int umad_release_ca(umad_ca_t " "*ca" ); +.fi +.SH "DESCRIPTION" +.B umad_get_ca() +gets the attributes of the InfiniBand device +.I ca_name\fR. +It fills +the +.I ca +structure with the device attributes specified by +the +.I ca_name +or with the default device attributes if +.I ca_name +is NULL. +.B umad_release_ca() +should be called before the +.I ca +structure is deallocated. +The argument +.I ca +is an +.I umad_ca_t +struct, as specified in . +.PP +.nf +typedef struct umad_ca { +.in +8 +char ca_name[UMAD_CA_NAME_LEN]; /* Name of the device */ +uint node_type; /* Type of the device */ +int numports; /* Number of physical ports */ +char fw_ver[20]; /* FW version */ +char ca_type[40]; /* CA type (e.g. MT23108, etc.) */ +char hw_ver[20]; /* Hardware version */ +uint64_t node_guid; /* Node GUID */ +uint64_t system_guid; /* System image GUID */ +umad_port_t *ports[UMAD_CA_MAX_PORTS]; /* Array of device port properties */ +.in -8 +} umad_ca_t; +.fi +.PP +.B umad_release_ca() +releases the resources that were allocated in the function +.B umad_get_ca()\fR. +.SH "RETURN VALUE" +.B umad_get_ca() +and +.B umad_release_ca() +return 0 on success, and a negative value on error. +.SH "AUTHORS" +.TP +Hal Rosenstock +.TP +Dotan Barak diff --git a/contrib/ofed/management/libibumad/man/umad_get_ca_portguids.3 b/contrib/ofed/management/libibumad/man/umad_get_ca_portguids.3 new file mode 100644 index 000000000000..351264910589 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_get_ca_portguids.3 @@ -0,0 +1,39 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_GET_CA_PORTGUIDS 3 "May 11, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_get_ca_portguids \- get the InfiniBand device ports GUIDs +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_get_ca_portguids(char " "*ca_name" ", uint64_t " "*portguids" ", int " "max" ); +.fi +.SH "DESCRIPTION" +.B umad_get_ca_portguids() +fills the +.I portguids\fR +array with up to +.I max +port GUIDs belonging the specified IB device +.I ca_name +, or to the default IB device if +.I ca_name +is NULL. +The argument +.I portguids +is an array of +.I max +uint64_t entries. +.SH "RETURN VALUE" +On success, +.B umad_get_ca_portguids() +returns a non-negative value equal to the number of port GUIDs actually filled. +On failure, a negative value is returned. +.SH "SEE ALSO" +.BR umad_get_cas_names (3) +.SH "AUTHORS" +.TP +Hal Rosenstock +.TP +Dotan Barak diff --git a/contrib/ofed/management/libibumad/man/umad_get_cas_names.3 b/contrib/ofed/management/libibumad/man/umad_get_cas_names.3 new file mode 100644 index 000000000000..85e76f815ace --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_get_cas_names.3 @@ -0,0 +1,37 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_GET_CAS_NAMES 3 "May 21, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_get_cas_names \- get list of available InfiniBand device names +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_get_cas_names(char " "cas[][UMAD_CA_NAME_LEN]" ", int " "max" ); +.fi +.SH "DESCRIPTION" +.B umad_get_cas_names() +fills the +.I cas +array with up to +.I max +local IB devices (CAs) names. +The argument +.I cas +is a character array with +.I max +entries, each with +.B UMAD_CA_NAME_LEN +characters. +.SH "RETURN VALUE" +.B umad_get_cas_names() +returns a non-negative value equal to the number of entries filled, +or \-1 on errors. +.SH "SEE ALSO" +.BR umad_get_ca_portguids (3), +.BR umad_open_port (3) +.SH "AUTHORS" +.TP +Hal Rosenstock +.TP +Dotan Barak diff --git a/contrib/ofed/management/libibumad/man/umad_get_fd.3 b/contrib/ofed/management/libibumad/man/umad_get_fd.3 new file mode 100644 index 000000000000..49aa83976cee --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_get_fd.3 @@ -0,0 +1,25 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_GET_FD 3 "May 17, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_get_fd \- get the umad fd for the requested port +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_get_fd(int " "portid" ); +.fi +.SH "DESCRIPTION" +.B umad_get_fd() +returns the umad fd for the port specified by +.I portid\fR. +.SH "RETURN VALUE" +.B umad_get_fd() +returns the fd for the +.I portid\fR +requested or -EINVAL if +.I portid\fR +is invalid. +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_get_issm_path.3 b/contrib/ofed/management/libibumad/man/umad_get_issm_path.3 new file mode 100644 index 000000000000..ac538c935769 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_get_issm_path.3 @@ -0,0 +1,38 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_GET_ISSM_PATH 3 "Oct 18, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_get_issm_path \- get path of issm device +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_get_issm_path(char " "*ca_name" ", int " "portnum", char *path, int max); +.fi +.SH "DESCRIPTION" +.B umad_get_issm_path() +resolves path to issm device (which used for setting/clearing PortInfo:CapMask IsSM bit) for +.I portnum +of the IB device +.I ca_name +, it stores resolved path in +.I path +array which cannot exceed +.I max +bytes in length (including NULL terminator). +.fi +Opening issm device sets PortInfo:CapMask IsSM bit and closing clears it. +.fi +.SH "RETURN VALUE" +.B umad_open_port() +returns 0 on success and a negative value on error as follows: + -ENODEV IB device can\'t be resolved + -EINVAL port is not valid (bad +.I portnum\fR +or no umad device) +.SH "SEE ALSO" +.BR umad_open_port (3), +.BR umad_get_port (3) +.SH "AUTHOR" +.TP +Sasha Khapyorsky diff --git a/contrib/ofed/management/libibumad/man/umad_get_mad.3 b/contrib/ofed/management/libibumad/man/umad_get_mad.3 new file mode 100644 index 000000000000..78c59ac74331 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_get_mad.3 @@ -0,0 +1,24 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_GET_MAD 3 "May 21, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_get_mad \- get the MAD pointer of a umad buffer +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "void * umad_get_mad(void " "*umad"); +.fi +.SH "DESCRIPTION" +.B umad_get_mad() +returns a pointer to the MAD contained within the +.I umad\fR +buffer. +.SH "RETURN VALUE" +.B umad_get_mad() +returns a pointer to the MAD contained within the supplied +.I umad\fR +buffer. +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_get_mad_addr.3 b/contrib/ofed/management/libibumad/man/umad_get_mad_addr.3 new file mode 100644 index 000000000000..5da86c247546 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_get_mad_addr.3 @@ -0,0 +1,42 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_GET_MAD_ADDR 3 "May 21, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_get_mad_addr \- get the address of the ib_mad_addr from a umad buffer +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "ib_mad_addr_t * umad_get_mad_addr(void " "*umad"); +.fi +.SH "DESCRIPTION" +.B umad_get_mad_addr() +returns a pointer to the ib_mad_addr struct within the specified +.I umad\fR +buffer. +.SH "RETURN VALUE" +The return value +is a pointer to an +.I ib_mad_addr_t +struct, as specified in . +.PP +.nf +typedef struct ib_mad_addr { +.in +8 +uint32_t qpn; +uint32_t qkey; +uint16_t lid; +uint8_t sl; +uint8_t path_bits; +uint8_t grh_present; +uint8_t gid_index; +uint8_t hop_limit; +uint8_t traffic_class; +uint8_t gid[16]; +uint32_t flow_label; +.in -8 +} ib_mad_addr_t; +.fi +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_get_pkey.3 b/contrib/ofed/management/libibumad/man/umad_get_pkey.3 new file mode 100644 index 000000000000..a03c0a6adffb --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_get_pkey.3 @@ -0,0 +1,23 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_GET_PKEY 3 "Jan 15, 2008" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_get_pkey \- get pkey index from umad buffer +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_get_pkey(void " "*umad"); +.fi +.SH "DESCRIPTION" +.B umad_get_pkey() +gets the pkey index from the specified +.I umad\fR +buffer. +.SH "RETURN VALUE" +.B umad_get_pkey() +returns value of pkey index (or zero if pkey index is not supported by +user_mad interface). +.SH "AUTHOR" +.TP +Sasha Khapyorsky diff --git a/contrib/ofed/management/libibumad/man/umad_get_port.3 b/contrib/ofed/management/libibumad/man/umad_get_port.3 new file mode 100644 index 000000000000..863afa7f8286 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_get_port.3 @@ -0,0 +1,82 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_GET_PORT 3 "May 21, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_get_port, umad_release_port \- open and close an InfiniBand port +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_get_port(char " "*ca_name" ", int " "portnum" ", umad_port_t " "*port" ); +.nl +.BI "int umad_release_port(umad_port_t " "*port" ); +.fi +.SH "DESCRIPTION" +.B umad_get_port() +fills the +.I port +structure with the IB port attributes specified by +.I ca_name +and +.I portnum +, or the default port if +.I ca_name +is NULL and +.I portnum +is zero. If only one of +.I ca_name +and +.I portnum +are specified, the other is used as a filter. +For example, passing a NULL +.I ca_name +and 2 for the +.I portnum +means get a port from any of the local IB devices, as long as it is +the second port. +Note that the library may use some reference scheme to support port caching +therefore +.B umad_release_port() +should be called before the +.I port +structure can be deallocated. +The argument +.I port +is an +.B umad_port_t +struct, as specified in . +.PP +.nf +typedef struct umad_port { +.in +8 +char ca_name[UMAD_CA_NAME_LEN]; /* Name of the device */ +int portnum; /* Physical port number */ +uint base_lid; /* Base port LID */ +uint lmc; /* LMC of LID */ +uint sm_lid; /* SM LID */ +uint sm_sl; /* SM service level */ +uint state; /* Logical port state */ +uint phys_state; /* Physical port state */ +uint rate; /* Port link bit rate */ +uint64_t capmask; /* Port capabilities */ +uint64_t gid_prefix; /* Gid prefix of this port */ +uint64_t port_guid; /* GUID of this port */ +.in -8 +} umad_port_t; +.fi +.PP +.B umad_release_port() +releases the resources that were allocated by the +.B umad_get_port() +function for the specified IB +.I port\fR. +.SH "RETURN VALUE" +.B umad_get_port() +and +.B umad_release_port() +return 0 on success, and a negative value on error. +.SH "AUTHORS" +.TP +Hal Rosenstock +.TP +Dotan Barak diff --git a/contrib/ofed/management/libibumad/man/umad_init.3 b/contrib/ofed/management/libibumad/man/umad_init.3 new file mode 100644 index 000000000000..a8108773c09f --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_init.3 @@ -0,0 +1,39 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_INIT 3 "May 21, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_init, umad_done \- perform library initialization and finalization +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_init(void); +.nl +.BI "int umad_done(void); +.fi +.SH "DESCRIPTION" +.B umad_init() +initializes the umad library for use. Must be called before any +other call to this library. +.PP +.B umad_done() +finalizes the use of the umad library. +.SH "RETURN VALUE" +.B umad_init() +and +.B umad_done() +return 0 on success, and \-1 on error. +Error is returned from +.B umad_init() +if infiniband umad +can\'t be opened, or the abi version doesn\'t match. +There are no errors currently returned by +.B umad_done(). +.SH "NOTES" +If an error occurs during the library initialization, no further use of the +umad library should be attempted. +.SH "AUTHORS" +.TP +Hal Rosenstock +.TP +Dotan Barak diff --git a/contrib/ofed/management/libibumad/man/umad_open_port.3 b/contrib/ofed/management/libibumad/man/umad_open_port.3 new file mode 100644 index 000000000000..53f2946ea814 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_open_port.3 @@ -0,0 +1,37 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_OPEN_PORT 3 "May 21, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_open_port \- open InfiniBand device port for umad access +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_open_port(char " "*ca_name" ", int " "portnum" ); +.fi +.SH "DESCRIPTION" +.B umad_open_port() +opens the port +.I portnum +of the IB device +.I ca_name +for umad access. The port is selected by the library if not all parameters +are provided (see +.B umad_get_port() +for details). +.fi +.SH "RETURN VALUE" +.B umad_open_port() +returns 0 or an unique positive value of umad device descriptor on success, and a negative value on error as follows: + -ENODEV IB device can\'t be resolved + -EINVAL port is not valid (bad +.I portnum\fR +or no umad device) + -EIO umad device for this port can\'t be opened +.SH "SEE ALSO" +.BR umad_close_port (3), +.BR umad_get_cas_names (3), +.BR umad_get_port (3) +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_poll.3 b/contrib/ofed/management/libibumad/man/umad_poll.3 new file mode 100644 index 000000000000..93f9425c5f0d --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_poll.3 @@ -0,0 +1,40 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_POLL 3 "October 23, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_poll \- poll umad +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_poll(int " "portid" ", int " "timeout_ms"); +.fi +.SH "DESCRIPTION" +.B umad_poll() +waits up to +.I timeout_ms\fR +milliseconds for a packet to be received from the port specified by +.I portid\fR. +Once a packet is ready to be read, the function +returns 0. After that the packet can be read using +.B umad_recv(). +Otherwise, \-ETIMEDOUT is returned. Note that successfully polling a port +does not guarantee that the subsequent +.B umad_recv() +will be non blocking when several threads are using +the same port. Instead, use a +.I timeout_ms\fR +parameter of zero to +.B umad_recv() +to ensure a non-blocking read. +.SH "RETURN VALUE" +.B umad_poll() +returns 0 on success, and a negative value on error as follows: + -EINVAL invalid port handle or agentid + -ETIMEDOUT poll operation timed out + -EIO poll operation failed +.SH "SEE ALSO" +.BR umad_recv (3) +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_recv.3 b/contrib/ofed/management/libibumad/man/umad_recv.3 new file mode 100644 index 000000000000..e1b2985619e7 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_recv.3 @@ -0,0 +1,40 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_RECV 3 "May 11, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_recv \- receive umad +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_recv(int " "portid" ", void " "*umad" ", int " "*length" ", int " "timeout_ms"); +.fi +.SH "DESCRIPTION" +.B umad_recv() +waits up to +.I timeout_ms\fR +milliseconds for a packet to be received from the port specified by +.I portid\fR. +The packet is copied to the +.I umad\fR +buffer if there is sufficient room and the received +.I length\fR is indicated. +If the buffer is not large enough, the size of the umad +buffer needed is returned in +.I length\fR. +A negative +.I timeout_ms\fR +makes the function block until a packet is received. A +.I timeout_ms\fR +parameter of zero indicates a non blocking read. +.SH "RETURN VALUE" +.B umad_recv() +returns non negative receiving agentid on success, and a negative value on error as follows: + -EINVAL invalid port handle or agentid + -EIO receive operation failed + -EWOULDBLOCK non blocking read can't be fulfilled +.SH "SEE ALSO" +.BR umad_poll (3) +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_register.3 b/contrib/ofed/management/libibumad/man/umad_register.3 new file mode 100644 index 000000000000..7f11b515af9b --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_register.3 @@ -0,0 +1,36 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_REGISTER 3 "May 11, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_register \- register the specified management class and version for port +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_register(int " "portid" ", int " "mgmt_class" ", int " "mgmt_version" " , uint8_t " "rmpp_version" ", uint32_t " "method_mask[4]"); +.fi +.SH "DESCRIPTION" +.B umad_register() +registers the specified management class, management version, +and whether RMPP is being used for the port specified by the +.I portid\fR +parameter. If +.I method_mask\fR +array is provided, the caller is registered as a replier (server) for the +methods having their corresponding bit on in the +.I method_mask\fR. +If +.I method_mask\fR +is NULL, the caller is registered as a MAD client, meaning that it can +only receive replies on MADs that it sent (solicited MADs). +.SH "RETURN VALUE" +.B umad_register() +returns non-negative agent id number on success, and a negative value on error as follows: + -EINVAL invalid port handle + -EPERM registration failed +.SH "SEE ALSO" +.BR umad_register_oui(3), +.BR umad_unregister (3) +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_register_oui.3 b/contrib/ofed/management/libibumad/man/umad_register_oui.3 new file mode 100644 index 000000000000..4e8171c5cbaa --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_register_oui.3 @@ -0,0 +1,37 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_REGISTER_OUI 3 "May 17, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_register_oui \- register the specified class in vendor range 2 for port +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_register_oui(int " "portid" ", int " "mgmt_class" ", uint8_t " "rmpp_version" ", uint8_t " "oui[3]" ", uint32_t " "method_mask[4]"); +.fi +.SH "DESCRIPTION" +.B umad_register_oui() +registers the specified class in vendor range 2, the specified +.I oui\fR, +and whether RMPP is being used for the port specified by the +.I portid\fR +handle. If +.I method_mask\fR +array is provided, the caller is registered as a replier (server) for the +methods having their corresponding bit on in the +.I method_mask\fR. +If +.I method_mask\fR +is NULL, the caller is registered as a MAD client, meaning that it can +only receive replies on MADs that it sent (solicited MADs). +.SH "RETURN VALUE" +.B umad_register() +returns non-negative agent id number on success, and a negative value on error as follows: + -EINVAL invalid port handle or class is not in the vendor class 2 range + -EPERM registration failed +.SH "SEE ALSO" +.BR umad_register (3), +.BR umad_unregister (3) +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_send.3 b/contrib/ofed/management/libibumad/man/umad_send.3 new file mode 100644 index 000000000000..2d84f574654c --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_send.3 @@ -0,0 +1,37 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_SEND 3 "May 11, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_send \- send umad +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_send(int " "portid" ", int " "agentid" ", void " "*umad" ", int " "timeout_ms" ", int " "retries"); +.fi +.SH "DESCRIPTION" +.B umad_send() +sends the specified +.I umad\fR +buffer from the port specified by +.I portid\fR, +and using the agent specified by +.I agentid\fR. +.I timeout_ms\fR +controls the solicited MADs behavior as follows: +zero value means not solicited. Positive value makes kernel indicate timeout +in milliseconds. If reply is not received within the specified value, the +original buffer is returned in the read channel with the status field set (to +non zero). Negative +.I timeout_ms\fR +makes kernel wait forever for the reply. +.I retries\fR +indicates the number of times the MAD will be retried before giving up. +.SH "RETURN VALUE" +.B umad_send() +returns 0 on success, and a negative value on error as follows: + -EINVAL invalid port handle or agentid + -EIO send operation failed +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_set_addr.3 b/contrib/ofed/management/libibumad/man/umad_set_addr.3 new file mode 100644 index 000000000000..82f81908e0b5 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_set_addr.3 @@ -0,0 +1,33 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_SET_ADDR 3 "May 17, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_set_addr \- set MAD address fields within umad buffer using host ordering +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_set_addr(void " "*umad" ", int " "dlid" ", int " "dqp" ", int " "sl" ", int " "qkey"); +.fi +.SH "DESCRIPTION" +.B umad_set_addr() +sets the MAD address fields within the specified +.I umad\fR +buffer using the provided host ordered fields. +.I dlid\fR +is the destination LID. +.I dqp\fR +is the destination QP (queue pair). +.I sl\fR +is the SL (service level). +.I qkey\fR +is the Q_Key (queue key). +.SH "RETURN VALUE" +.B umad_set_addr() +returns 0 on success, and a negative value on errors. Currently, there +are no errors indicated. +.SH "SEE ALSO" +.BR umad_set_addr_net (3) +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_set_addr_net.3 b/contrib/ofed/management/libibumad/man/umad_set_addr_net.3 new file mode 100644 index 000000000000..1f409c2a1540 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_set_addr_net.3 @@ -0,0 +1,33 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_SET_ADDR_NET 3 "May 21, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_set_addr_net \- set MAD address fields within umad buffer using network ordering +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_set_addr_net(void " "*umad" ", int " "dlid" ", int " "dqp" ", int " "sl" ", int " "qkey"); +.fi +.SH "DESCRIPTION" +.B umad_set_addr_net() +sets the MAD address fields within the specified +.I umad\fR +buffer using the provided network ordered fields. +.I dlid\fR +is the destination LID. +.I dqp\fR +is the destination QP (queue pair). +.I sl\fR +is the SL (service level). +.I qkey\fR +is the Q_Key (queue key). +.SH "RETURN VALUE" +.B umad_set_addr_net() +returns 0 on success, and a negative value on errors. Currently, there +are no errors indicated. +.SH "SEE ALSO" +.BR umad_set_addr (3) +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_set_grh.3 b/contrib/ofed/management/libibumad/man/umad_set_grh.3 new file mode 100644 index 000000000000..17fe73b74bae --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_set_grh.3 @@ -0,0 +1,75 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_SET_GRH 3 "May 24, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_set_grh \- set GRH fields within umad buffer using host ordering +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_set_grh(void " "*umad" ", void " "*mad_addr"); +.fi +.SH "DESCRIPTION" +.B umad_set_grh() +sets the GRH fields (grh_present, gid, hop_limit, traffic_class, flow_label) +within the specified +.I umad\fR +buffer based on the +.I mad_addr\fR +supplied. The provided +.I mad_addr\fR +fields are expected to be in host order. +If the +.I mad_addr\fR +pointer supplied is NULL, no GRH is set. +The argument +.I mad_addr +is a pointer to an +.I ib_mad_addr_t +struct, as specified in +.I . +The argument +.I umad +is a pointer to an +.I ib_user_mad_t +struct, as specified in +.I . +.PP +.nf +typedef struct ib_mad_addr { +.in +8 +uint32_t qpn; +uint32_t qkey; +uint16_t lid; +uint8_t sl; +uint8_t path_bits; +uint8_t grh_present; +uint8_t gid_index; +uint8_t hop_limit; +uint8_t traffic_class; +uint8_t gid[16]; +uint32_t flow_label; +.in -8 +} ib_mad_addr_t; +.PP +typedef struct ib_user_mad { +.in +8 +uint32_t agent_id; +uint32_t status; +uint32_t timeout_ms; +uint32_t retries; +uint32_t length; +ib_mad_addr_t addr; +uint8_t data[0]; +.in -8 +} ib_user_mad_t; +.fi +.SH "RETURN VALUE" +.B umad_set_grh() +returns 0 on success, and a negative value on errors. Currently, there +are no errors indicated. +.SH "SEE ALSO" +.BR umad_set_grh_net (3) +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_set_grh_net.3 b/contrib/ofed/management/libibumad/man/umad_set_grh_net.3 new file mode 100644 index 000000000000..8425b3fbbc75 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_set_grh_net.3 @@ -0,0 +1,76 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_SET_GRH_NET 3 "May 24, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_set_grh_net \- set GRH fields within umad buffer using network ordering +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_set_grh_net(void " "*umad" ", void " "*mad_addr"); +.fi +.SH "DESCRIPTION" +.B umad_set_grh_net() +sets the GRH fields (grh_present, gid, hop_limit, traffic_class, flow_label) +within the specified +.I umad\fR +buffer based on the +.I mad_addr\fR +supplied. The provided +.I mad_addr\fR +fields are expected to be in network order. +If the +.I mad_addr\fR +pointer supplied is NULL, no GRH is set. +The argument +.I mad_addr +is a pointer to an +.I ib_mad_addr_t +struct, as specified in . +The argument +.I umad +is a pointer to an +.I ib_user_mad_t +struct, as specified in +.I . +.PP +.nf +typedef struct ib_mad_addr { +.in +8 +uint32_t qpn; +uint32_t qkey; +uint16_t lid; +uint8_t sl; +uint8_t path_bits; +uint8_t grh_present; +uint8_t gid_index; +uint8_t hop_limit; +uint8_t traffic_class; +uint8_t gid[16]; +uint32_t flow_label; +.in -8 +} ib_mad_addr_t; +.PP +typedef struct ib_user_mad { +.in +8 +uint32_t agent_id; +uint32_t status; +uint32_t timeout_ms; +uint32_t retries; +uint32_t length; +ib_mad_addr_t addr; +uint8_t data[0]; +.in -8 +} ib_user_mad_t; +.fi +.SH "RETURN VALUE" +.B umad_set_grh_net() +returns 0 on success, and a negative value on errors. Currently, there +are no errors indicated. +.SH "KNOWN BUGS" +Not implemented. +.SH "SEE ALSO" +.BR umad_set_grh (3) +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_set_pkey.3 b/contrib/ofed/management/libibumad/man/umad_set_pkey.3 new file mode 100644 index 000000000000..d6b86064247d --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_set_pkey.3 @@ -0,0 +1,22 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_SET_PKEY 3 "June 20, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_set_pkey \- set pkey index within umad buffer +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_set_pkey(void " "*umad" ", int " "pkey_index"); +.fi +.SH "DESCRIPTION" +.B umad_set_pkey() +sets the pkey index within the specified +.I umad\fR +buffer. +.SH "RETURN VALUE" +.B umad_set_pkey() +returns 0 on success, and a negative value on an error. +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_size.3 b/contrib/ofed/management/libibumad/man/umad_size.3 new file mode 100644 index 000000000000..db861ef21536 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_size.3 @@ -0,0 +1,20 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_SIZE 3 "May 21, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_size \- get the size of umad buffer +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "size_t umad_size(void); +.fi +.SH "DESCRIPTION" +.B umad_size() +returns the size of umad buffer (in bytes). +.SH "RETURN VALUE" +.B umad_size() +returns the size of umad buffer (in bytes). +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_status.3 b/contrib/ofed/management/libibumad/man/umad_status.3 new file mode 100644 index 000000000000..3978b84d04b2 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_status.3 @@ -0,0 +1,26 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_STATUS 3 "May 17, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_status \- get the status of a umad buffer +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_status(void " "*umad" ); +.fi +.SH "DESCRIPTION" +.B umad_status() +get the internal +.I umad\fR +status field. +.SH "RETURN VALUE" +After a packet is received, +.B umad_status() +returns 0 on a successful receive, or a non zero status. +ETIMEDOUT means that the packet had +a send-timeout indication. In this case, the transaction ID will be +set to the TID of the original request. +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/man/umad_unregister.3 b/contrib/ofed/management/libibumad/man/umad_unregister.3 new file mode 100644 index 000000000000..472afec6e779 --- /dev/null +++ b/contrib/ofed/management/libibumad/man/umad_unregister.3 @@ -0,0 +1,30 @@ +.\" -*- nroff -*- +.\" +.TH UMAD_UNREGISTER 3 "May 21, 2007" "OpenIB" "OpenIB Programmer\'s Manual" +.SH "NAME" +umad_unregister \- unregister umad agent +.SH "SYNOPSIS" +.nf +.B #include +.sp +.BI "int umad_unregister(int " "portid" ", int " "agentid"); +.fi +.SH "DESCRIPTION" +.B umad_unregister() +unregisters the specified +.I agentid\fR +previously registered using +.B umad_register() +or +.B umad_register_oui()\fR. +.SH "RETURN VALUE" +.B umad_unregister() +returns 0 on success and negative value on error as follows: + -EINVAL invalid port handle or agentid + * (kernel error codes) +.SH "SEE ALSO" +.BR umad_register (3), +.BR umad_register_oui (3) +.SH "AUTHOR" +.TP +Hal Rosenstock diff --git a/contrib/ofed/management/libibumad/src/libibumad.map b/contrib/ofed/management/libibumad/src/libibumad.map new file mode 100644 index 000000000000..0154b7fe7ef7 --- /dev/null +++ b/contrib/ofed/management/libibumad/src/libibumad.map @@ -0,0 +1,34 @@ +IBUMAD_1.0 { + global: + umad_init; + umad_done; + umad_get_cas_names; + umad_get_ca_portguids; + umad_open_port; + umad_get_ca; + umad_release_ca; + umad_get_port; + umad_release_port; + umad_close_port; + umad_get_mad; + umad_get_issm_path; + umad_size; + umad_set_grh; + umad_set_pkey; + umad_get_pkey; + umad_set_addr; + umad_set_addr_net; + umad_send; + umad_recv; + umad_poll; + umad_get_fd; + umad_register; + umad_register_oui; + umad_unregister; + umad_status; + umad_get_mad_addr; + umad_debug; + umad_addr_dump; + umad_dump; + local: *; +}; diff --git a/contrib/ofed/management/libibumad/src/umad.c b/contrib/ofed/management/libibumad/src/umad.c new file mode 100644 index 000000000000..00fcff67fb07 --- /dev/null +++ b/contrib/ofed/management/libibumad/src/umad.c @@ -0,0 +1,1036 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "umad.h" + +#define IB_OPENIB_OUI (0x001405) + +#ifdef HAVE_VALGRIND_MEMCHECK_H + +# include + +# ifndef VALGRIND_MAKE_MEM_DEFINED +# warning "Valgrind support requested, but VALGRIND_MAKE_MEM_DEFINED not available" +# endif + +#endif /* HAVE_VALGRIND_MEMCHECK_H */ + +#ifndef VALGRIND_MAKE_MEM_DEFINED +# define VALGRIND_MAKE_MEM_DEFINED(addr,len) +#endif + +typedef struct ib_user_mad_reg_req { + uint32_t id; + uint32_t method_mask[4]; + uint8_t qpn; + uint8_t mgmt_class; + uint8_t mgmt_class_version; + uint8_t oui[3]; + uint8_t rmpp_version; +} ib_user_mad_reg_req_t; + +#define TRACE if (umaddebug) IBWARN +#define DEBUG if (umaddebug) IBWARN + +int umaddebug = 0; + +#define UMAD_DEV_FILE_SZ 256 + +static char *def_ca_name = "mthca0"; +static int def_ca_port = 1; + +static unsigned abi_version; +static unsigned new_user_mad_api; + +/************************************* + * Port + */ +static int +find_cached_ca(char *ca_name, umad_ca_t *ca) +{ + return 0; /* caching not implemented yet */ +} + +static int +put_ca(umad_ca_t *ca) +{ + return 0; /* caching not implemented yet */ +} + +static int +release_port(umad_port_t *port) +{ + free(port->pkeys); + port->pkeys = NULL; + port->pkeys_size = 0; + return 0; +} + +static int check_for_digit_name(const struct dirent *dent) +{ + const char *p = dent->d_name; + while (*p && isdigit(*p)) + p++; + return *p ? 0 : 1; +} + +static int +get_port(char *ca_name, char *dir, int portnum, umad_port_t *port) +{ + char port_dir[256]; + uint8_t gid[16]; + struct dirent **namelist = NULL; + int i, len, ret = 0; + + strncpy(port->ca_name, ca_name, sizeof port->ca_name - 1); + port->portnum = portnum; + port->pkeys = NULL; + + len = snprintf(port_dir, sizeof(port_dir), "%s/%d", dir, portnum); + if (len < 0 || len > sizeof(port_dir)) + goto clean; + + if (sys_read_uint(port_dir, SYS_PORT_LMC, &port->lmc) < 0) + goto clean; + if (sys_read_uint(port_dir, SYS_PORT_SMLID, &port->sm_lid) < 0) + goto clean; + if (sys_read_uint(port_dir, SYS_PORT_SMSL, &port->sm_sl) < 0) + goto clean; + if (sys_read_uint(port_dir, SYS_PORT_LID, &port->base_lid) < 0) + goto clean; + if (sys_read_uint(port_dir, SYS_PORT_STATE, &port->state) < 0) + goto clean; + if (sys_read_uint(port_dir, SYS_PORT_PHY_STATE, &port->phys_state) < 0) + goto clean; + if (sys_read_uint(port_dir, SYS_PORT_RATE, &port->rate) < 0) + goto clean; + if (sys_read_uint64(port_dir, SYS_PORT_CAPMASK, &port->capmask) < 0) + goto clean; + + port->capmask = htonl(port->capmask); + + if (sys_read_gid(port_dir, SYS_PORT_GID, gid) < 0) + goto clean; + + memcpy(&port->gid_prefix, gid, sizeof port->gid_prefix); + memcpy(&port->port_guid, gid + 8, sizeof port->port_guid); + + snprintf(port_dir + len, sizeof(port_dir) - len, "/pkeys"); + ret = sys_scandir(port_dir, &namelist, check_for_digit_name, NULL); + if (ret <= 0) { + IBWARN("no pkeys found for %s:%u (at dir %s)...", + port->ca_name, port->portnum, port_dir); + goto clean; + } + port->pkeys = calloc(ret, sizeof(port->pkeys[0])); + if (!port->pkeys) { + IBWARN("get_port: calloc failed: %s", strerror(errno)); + goto clean; + } + for (i = 0; i < ret ; i++) { + unsigned idx, val; + idx = strtoul(namelist[i]->d_name, NULL, 0); + sys_read_uint(port_dir, namelist[i]->d_name, &val); + port->pkeys[idx] = val; + free(namelist[i]); + } + port->pkeys_size = ret; + free(namelist); + namelist = NULL; + port_dir[len] = '\0'; + + /* FIXME: handle gids */ + + return 0; + +clean: + if (namelist) { + for (i = 0; i < ret ; i++) + free(namelist[i]); + free(namelist); + } + if (port->pkeys) + free(port->pkeys); + return -EIO; +} + +static int +release_ca(umad_ca_t *ca) +{ + int i; + + for (i = 0; i <= ca->numports; i++) { + if (!ca->ports[i]) + continue; + release_port(ca->ports[i]); + free(ca->ports[i]); + ca->ports[i] = 0; + } + return 0; +} + +/* + * if *port > 0, check ca[port] state. Otherwise set *port to + * the first port that is active, and if such is not found, to + * the first port that is link up and if none are linkup, then + * the first port that is not disabled. Otherwise return -1. + */ +static int +resolve_ca_port(char *ca_name, int *port) +{ + umad_ca_t ca; + int active = -1, up = -1; + int i; + + TRACE("checking ca '%s'", ca_name); + + if (umad_get_ca(ca_name, &ca) < 0) + return -1; + + if (ca.node_type == 2) { + *port = 0; /* switch sma port 0 */ + return 1; + } + + if (*port > 0) { /* check only the port the user wants */ + if (*port > ca.numports) + return -1; + if (!ca.ports[*port]) + return -1; + if (ca.ports[*port]->state == 4) + return 1; + if (ca.ports[*port]->phys_state != 3) + return 0; + return -1; + } + + for (i = 0; i <= ca.numports; i++) { + DEBUG("checking port %d", i); + if (!ca.ports[i]) + continue; + if (up < 0 && ca.ports[i]->phys_state == 5) + up = *port = i; + if (ca.ports[i]->state == 4) { + active = *port = i; + DEBUG("found active port %d", i); + break; + } + } + + if (active == -1 && up == -1) { /* no active or linkup port found */ + for (i = 0; i <= ca.numports; i++) { + DEBUG("checking port %d", i); + if (!ca.ports[i]) + continue; + if (ca.ports[i]->phys_state != 3) { + up = *port = i; + break; + } + } + } + + release_ca(&ca); + + if (active >= 0) + return 1; + if (up >= 0) + return 0; + return -1; +} + +static char * +resolve_ca_name(char *ca_name, int *best_port) +{ + static char names[UMAD_MAX_DEVICES][UMAD_CA_NAME_LEN]; + int phys_found = -1, port_found = 0, port, port_type; + int caidx, n; + + if (ca_name && (!best_port || *best_port)) + return ca_name; + + if (ca_name) { + if (resolve_ca_port(ca_name, best_port) < 0) + return 0; + return ca_name; + } + + /* Get the list of CA names */ + if ((n = umad_get_cas_names((void *)names, 20)) < 0) + return 0; + + /* Find the first existing CA with an active port */ + for (caidx = 0; caidx < n; caidx++) { + TRACE("checking ca '%s'", names[caidx]); + + port = best_port ? *best_port : 0; + if ((port_type = resolve_ca_port(names[caidx], &port)) < 0) + continue; + + DEBUG("found ca %s with port %d type %d", + names[caidx], port, port_type); + + if (port_type > 0) { + if (best_port) + *best_port = port; + DEBUG("found ca %s with active port %d", + names[caidx], port); + return (char *)(names + caidx); + } + + if (phys_found == -1) { + phys_found = caidx; + port_found = port; + } + } + + DEBUG("phys found %d on %s port %d", + phys_found, phys_found >=0 ? names[phys_found] : 0, port_found); + if (phys_found >= 0) { + if (best_port) + *best_port = port_found; + return names[phys_found]; + } + + if (best_port) + *best_port = def_ca_port; + return def_ca_name; +} + +static int +get_ca(char *ca_name, umad_ca_t *ca) +{ +#ifdef __linux__ + DIR *dir; +#endif + char dir_name[256]; + struct dirent **namelist; + int r, i, ret; + int portnum; + + strncpy(ca->ca_name, ca_name, sizeof ca->ca_name); + + snprintf(dir_name, sizeof(dir_name), "%s/%s", SYS_INFINIBAND, + ca->ca_name); + + if ((r = sys_read_uint(dir_name, SYS_NODE_TYPE, &ca->node_type)) < 0) + return r; + if (sys_read_string(dir_name, SYS_CA_FW_VERS, ca->fw_ver, + sizeof ca->fw_ver) < 0) + ca->fw_ver[0] = '\0'; + if (sys_read_string(dir_name, SYS_CA_HW_VERS, ca->hw_ver, + sizeof ca->hw_ver) < 0) + ca->hw_ver[0] = '\0'; + if ((r = sys_read_string(dir_name, SYS_CA_TYPE, ca->ca_type, + sizeof ca->ca_type)) < 0) + ca->ca_type[0] = '\0'; + if ((r = sys_read_guid(dir_name, SYS_CA_NODE_GUID, &ca->node_guid)) < 0) + return r; + if ((r = sys_read_guid(dir_name, SYS_CA_SYS_GUID, &ca->system_guid)) < 0) + return r; + + snprintf(dir_name, sizeof(dir_name), "%s/%s/%s", + SYS_INFINIBAND, ca->ca_name, SYS_CA_PORTS_DIR); + +#ifdef __linux__ + if (!(dir = opendir(dir_name))) + return -ENOENT; +#endif + + if ((r = sys_scandir(dir_name, &namelist, 0, alphasort)) < 0) { + ret = errno < 0 ? errno : -EIO; + goto error; + } + + ret = 0; + ca->numports = 0; + memset(ca->ports, 0, sizeof ca->ports); + for (i = 0; i < r; i++) { + portnum = 0; + if (!strcmp(".", namelist[i]->d_name) || + !strcmp("..", namelist[i]->d_name)) + continue; + if (strcmp("0", namelist[i]->d_name) && + ((portnum = atoi(namelist[i]->d_name)) <= 0 || + portnum >= UMAD_CA_MAX_PORTS)) { + ret = -EIO; + goto clean; + } + if (!(ca->ports[portnum] = calloc(1, sizeof(*ca->ports[portnum])))) { + ret = -ENOMEM; + goto clean; + } + if (get_port(ca_name, dir_name, portnum, ca->ports[portnum]) < 0) { + free(ca->ports[portnum]); + ca->ports[portnum] = NULL; + ret = -EIO; + goto clean; + } + if (ca->numports < portnum) + ca->numports = portnum; + } + + for (i = 0; i < r; i++) + free(namelist[i]); + free(namelist); + +#ifdef __linux__ + closedir(dir); +#endif + put_ca(ca); + return 0; + +clean: + for (i = 0; i < r; i++) + free(namelist[i]); + free(namelist); +error: +#ifdef __linux__ + closedir(dir); +#endif + release_ca(ca); + + return ret; +} + +static int +umad_id_to_dev(int umad_id, char *dev, unsigned *port) +{ + char path[256]; + int r; + + snprintf(path, sizeof(path), SYS_INFINIBAND_MAD "/umad%d", umad_id); + + if ((r = sys_read_string(path, SYS_IB_MAD_DEV, dev, UMAD_CA_NAME_LEN)) < 0) + return r; + + if ((r = sys_read_uint(path, SYS_IB_MAD_PORT, port)) < 0) + return r; + + return 0; +} + +static int +dev_to_umad_id(char *dev, unsigned port) +{ + char umad_dev[UMAD_CA_NAME_LEN]; + unsigned umad_port; + int id; + + for (id = 0; id < UMAD_MAX_PORTS; id++) { + if (umad_id_to_dev(id, umad_dev, &umad_port) < 0) + continue; + if (strncmp(dev, umad_dev, UMAD_CA_NAME_LEN)) + continue; + if (port != umad_port) + continue; + + DEBUG("mapped %s %d to %d", dev, port, id); + return id; + } + + return -1; /* not found */ +} + +/******************************* + * Public interface + */ + +int +umad_init(void) +{ + TRACE("umad_init"); + if (sys_read_uint(IB_UMAD_ABI_DIR, IB_UMAD_ABI_FILE, &abi_version) < 0) { + IBWARN("can't read ABI version from %s/%s (%m): is ib_umad module loaded?", + IB_UMAD_ABI_DIR, IB_UMAD_ABI_FILE); + return -1; + } + if (abi_version < IB_UMAD_ABI_VERSION) { + IBWARN("wrong ABI version: %s/%s is %d but library minimal ABI is %d", + IB_UMAD_ABI_DIR, IB_UMAD_ABI_FILE, abi_version, IB_UMAD_ABI_VERSION); + return -1; + } + return 0; +} + +int +umad_done(void) +{ + TRACE("umad_done"); + /* FIXME - verify that all ports are closed */ + return 0; +} + +static unsigned is_ib_type(char *ca_name) +{ + char dir_name[256]; + unsigned type; + + snprintf(dir_name, sizeof(dir_name), "%s/%s", SYS_INFINIBAND, ca_name); + + if (sys_read_uint(dir_name, SYS_NODE_TYPE, &type) < 0) + return 0; + + return type >= 1 && type <= 3 ? 1 : 0; +} + +int +umad_get_cas_names(char cas[][UMAD_CA_NAME_LEN], int max) +{ + struct dirent **namelist; + int n, i, j = 0; + + TRACE("max %d", max); + + n = sys_scandir(SYS_INFINIBAND, &namelist, NULL, alphasort); + if (n > 0) { + for (i = 0; i < n; i++) { + if (strcmp(namelist[i]->d_name, ".") && + strcmp(namelist[i]->d_name, "..")) { + if (j < max && is_ib_type(namelist[i]->d_name)) + strncpy(cas[j++], namelist[i]->d_name, + UMAD_CA_NAME_LEN); + } + free(namelist[i]); + } + DEBUG("return %d cas", j); + } else { + /* Is this still needed ? */ + strncpy((char *)cas, def_ca_name, UMAD_CA_NAME_LEN); + DEBUG("return 1 ca"); + j = 1; + } + if (n >= 0) + free(namelist); + return j; +} + +int +umad_get_ca_portguids(char *ca_name, uint64_t *portguids, int max) +{ + umad_ca_t ca; + int ports = 0, i; + + TRACE("ca name %s max port guids %d", ca_name, max); + if (!(ca_name = resolve_ca_name(ca_name, 0))) + return -ENODEV; + + if (umad_get_ca(ca_name, &ca) < 0) + return -1; + + if (portguids) { + if (ca.numports + 1 > max) { + release_ca(&ca); + return -ENOMEM; + } + + for (i = 0; i <= ca.numports; i++) + portguids[ports++] = ca.ports[i] ? ca.ports[i]->port_guid : 0; + } + + release_ca(&ca); + DEBUG("%s: %d ports", ca_name, ports); + + return ports; +} + +int +umad_get_issm_path(char *ca_name, int portnum, char path[], int max) +{ + int umad_id; + + TRACE("ca %s port %d", ca_name, portnum); + + if (!(ca_name = resolve_ca_name(ca_name, &portnum))) + return -ENODEV; + + if ((umad_id = dev_to_umad_id(ca_name, portnum)) < 0) + return -EINVAL; + + snprintf(path, max, "%s/issm%u", UMAD_DEV_DIR , umad_id); + + return 0; +} + +int +umad_open_port(char *ca_name, int portnum) +{ + char dev_file[UMAD_DEV_FILE_SZ]; + int umad_id, fd; + + TRACE("ca %s port %d", ca_name, portnum); + + if (!(ca_name = resolve_ca_name(ca_name, &portnum))) + return -ENODEV; + + DEBUG("opening %s port %d", ca_name, portnum); + + if ((umad_id = dev_to_umad_id(ca_name, portnum)) < 0) + return -EINVAL; + + snprintf(dev_file, sizeof(dev_file), "%s/umad%d", + UMAD_DEV_DIR , umad_id); + + if ((fd = open(dev_file, O_RDWR|O_NONBLOCK)) < 0) { + DEBUG("open %s failed: %s", dev_file, strerror(errno)); + return -EIO; + } + + if (abi_version > 5 || !ioctl(fd, IB_USER_MAD_ENABLE_PKEY, NULL)) + new_user_mad_api = 1; + else + new_user_mad_api = 0; + + DEBUG("opened %s fd %d portid %d", dev_file, fd, umad_id); + return fd; +} + +int +umad_get_ca(char *ca_name, umad_ca_t *ca) +{ + int r; + + TRACE("ca_name %s", ca_name); + if (!(ca_name = resolve_ca_name(ca_name, 0))) + return -ENODEV; + + if (find_cached_ca(ca_name, ca) > 0) + return 0; + + if ((r = get_ca(ca_name, ca)) < 0) + return r; + + DEBUG("opened %s", ca_name); + return 0; +} + +int +umad_release_ca(umad_ca_t *ca) +{ + int r; + + TRACE("ca_name %s", ca->ca_name); + if (!ca) + return -ENODEV; + + if ((r = release_ca(ca)) < 0) + return r; + + DEBUG("releasing %s", ca->ca_name); + return 0; +} + +int +umad_get_port(char *ca_name, int portnum, umad_port_t *port) +{ + char dir_name[256]; + + TRACE("ca_name %s portnum %d", ca_name, portnum); + + if (!(ca_name = resolve_ca_name(ca_name, &portnum))) + return -ENODEV; + + snprintf(dir_name, sizeof(dir_name), "%s/%s/%s", + SYS_INFINIBAND, ca_name, SYS_CA_PORTS_DIR); + + return get_port(ca_name, dir_name, portnum, port); +} + +int +umad_release_port(umad_port_t *port) +{ + int r; + + TRACE("port %s:%d", port->ca_name, port->portnum); + if (!port) + return -ENODEV; + + if ((r = release_port(port)) < 0) + return r; + + DEBUG("releasing %s:%d", port->ca_name, port->portnum); + return 0; +} + +int +umad_close_port(int fd) +{ + close(fd); + DEBUG("closed fd %d", fd); + return 0; +} + +void * +umad_get_mad(void *umad) +{ + return new_user_mad_api ? ((struct ib_user_mad *)umad)->data : + (void *)&((struct ib_user_mad *)umad)->addr.pkey_index; +} + +size_t +umad_size(void) +{ + return new_user_mad_api ? sizeof (struct ib_user_mad) : + sizeof(struct ib_user_mad) - 8; +} + +int +umad_set_grh(void *umad, void *mad_addr) +{ + struct ib_user_mad *mad = umad; + struct ib_mad_addr *addr = mad_addr; + + if (mad_addr) { + mad->addr.grh_present = 1; + memcpy(mad->addr.gid, addr->gid, 16); + mad->addr.flow_label = htonl(addr->flow_label); + mad->addr.hop_limit = addr->hop_limit; + mad->addr.traffic_class = addr->traffic_class; + } else + mad->addr.grh_present = 0; + return 0; +} + +int +umad_set_pkey(void *umad, int pkey_index) +{ + struct ib_user_mad *mad = umad; + + if (new_user_mad_api) + mad->addr.pkey_index = pkey_index; + + return 0; +} + +int +umad_get_pkey(void *umad) +{ + struct ib_user_mad *mad = umad; + + if (new_user_mad_api) + return mad->addr.pkey_index; + + return 0; +} + +int +umad_set_addr(void *umad, int dlid, int dqp, int sl, int qkey) +{ + struct ib_user_mad *mad = umad; + + TRACE("umad %p dlid %d dqp %d sl %d, qkey %x", + umad, dlid, dqp, sl, qkey); + mad->addr.qpn = htonl(dqp); + mad->addr.lid = htons(dlid); + mad->addr.qkey = htonl(qkey); + mad->addr.sl = sl; + + return 0; +} + +int +umad_set_addr_net(void *umad, int dlid, int dqp, int sl, int qkey) +{ + struct ib_user_mad *mad = umad; + + TRACE("umad %p dlid %d dqp %d sl %d qkey %x", + umad, ntohs(dlid), ntohl(dqp), sl, ntohl(qkey)); + mad->addr.qpn = dqp; + mad->addr.lid = dlid; + mad->addr.qkey = qkey; + mad->addr.sl = sl; + + return 0; +} + +int +umad_send(int fd, int agentid, void *umad, int length, + int timeout_ms, int retries) +{ + struct ib_user_mad *mad = umad; + int n; + + TRACE("fd %d agentid %d umad %p timeout %u", + fd, agentid, umad, timeout_ms); + errno = 0; + + mad->timeout_ms = timeout_ms; + mad->retries = retries; + mad->agent_id = agentid; + + if (umaddebug > 1) + umad_dump(mad); + + n = write(fd, mad, length + umad_size()); + if (n == length + umad_size()) + return 0; + + DEBUG("write returned %d != sizeof umad %zu + length %d (%m)", + n, umad_size(), length); + if (!errno) + errno = EIO; + return -EIO; +} + +static int +dev_poll(int fd, int timeout_ms) +{ + struct pollfd ufds; + int n; + + ufds.fd = fd; + ufds.events = POLLIN; + + if ((n = poll(&ufds, 1, timeout_ms)) == 1) + return 0; + + if (n == 0) + return -ETIMEDOUT; + + return -EIO; +} + +int +umad_recv(int fd, void *umad, int *length, int timeout_ms) +{ + struct ib_user_mad *mad = umad; + int n; + + errno = 0; + TRACE("fd %d umad %p timeout %u", fd, umad, timeout_ms); + + if (!umad || !length) { + errno = EINVAL; + return -EINVAL; + } + + if (timeout_ms && (n = dev_poll(fd, timeout_ms)) < 0) { + if (!errno) + errno = -n; + return n; + } + + n = read(fd, umad, umad_size() + *length); + + VALGRIND_MAKE_MEM_DEFINED(umad, umad_size() + *length); + + if ((n >= 0) && (n <= umad_size() + *length)) { + DEBUG("mad received by agent %d length %d", mad->agent_id, n); + if (n > umad_size()) + *length = n - umad_size(); + else + *length = 0; + return mad->agent_id; + } + + if (n == -EWOULDBLOCK) { + if (!errno) + errno = EWOULDBLOCK; + return n; + } + + DEBUG("read returned %zu > sizeof umad %zu + length %d (%m)", + mad->length - umad_size(), umad_size(), *length); + + *length = mad->length - umad_size(); + if (!errno) + errno = EIO; + return -errno; +} + +int +umad_poll(int fd, int timeout_ms) +{ + TRACE("fd %d timeout %u", fd, timeout_ms); + return dev_poll(fd, timeout_ms); +} + +int +umad_get_fd(int fd) +{ + TRACE("fd %d", fd); + return fd; +} + +int +umad_register_oui(int fd, int mgmt_class, uint8_t rmpp_version, + uint8_t oui[3], long method_mask[]) +{ + struct ib_user_mad_reg_req req; + + TRACE("fd %d mgmt_class %u rmpp_version %d oui 0x%x%x%x method_mask %p", + fd, mgmt_class, (int)rmpp_version, (int)oui[0], (int)oui[1], + (int)oui[2], method_mask); + + if (mgmt_class < 0x30 || mgmt_class > 0x4f) { + DEBUG("mgmt class %d not in vendor range 2", mgmt_class); + return -EINVAL; + } + + req.qpn = 1; + req.mgmt_class = mgmt_class; + req.mgmt_class_version = 1; + memcpy(req.oui, oui, sizeof req.oui); + req.rmpp_version = rmpp_version; + + if (method_mask) + memcpy(req.method_mask, method_mask, sizeof req.method_mask); + else + memset(req.method_mask, 0, sizeof req.method_mask); + + VALGRIND_MAKE_MEM_DEFINED(&req, sizeof req); + + if (!ioctl(fd, IB_USER_MAD_REGISTER_AGENT, (void *)&req)) { + DEBUG("fd %d registered to use agent %d qp %d class 0x%x oui %p", + fd, req.id, req.qpn, req.mgmt_class, oui); + return req.id; /* return agentid */ + } + + DEBUG("fd %d registering qp %d class 0x%x version %d oui %p failed: %m", + fd, req.qpn, req.mgmt_class, req.mgmt_class_version, oui); + return -EPERM; +} + +int +umad_register(int fd, int mgmt_class, int mgmt_version, + uint8_t rmpp_version, long method_mask[]) +{ + struct ib_user_mad_reg_req req; + uint32_t oui = htonl(IB_OPENIB_OUI); + int qp; + + TRACE("fd %d mgmt_class %u mgmt_version %u rmpp_version %d method_mask %p", + fd, mgmt_class, mgmt_version, rmpp_version, method_mask); + + req.qpn = qp = (mgmt_class == 0x1 || mgmt_class == 0x81) ? 0 : 1; + req.mgmt_class = mgmt_class; + req.mgmt_class_version = mgmt_version; + req.rmpp_version = rmpp_version; + + if (method_mask) + memcpy(req.method_mask, method_mask, sizeof req.method_mask); + else + memset(req.method_mask, 0, sizeof req.method_mask); + + memcpy(&req.oui, (char *)&oui + 1, sizeof req.oui); + + VALGRIND_MAKE_MEM_DEFINED(&req, sizeof req); + + if (!ioctl(fd, IB_USER_MAD_REGISTER_AGENT, (void *)&req)) { + DEBUG("fd %d registered to use agent %d qp %d", + fd, req.id, qp); + return req.id; /* return agentid */ + } + + DEBUG("fd %d registering qp %d class 0x%x version %d failed: %m", + fd, qp, mgmt_class, mgmt_version); + return -EPERM; +} + +int +umad_unregister(int fd, int agentid) +{ + TRACE("fd %d unregistering agent %d", fd, agentid); + return ioctl(fd, IB_USER_MAD_UNREGISTER_AGENT, &agentid); +} + +int +umad_status(void *umad) +{ + struct ib_user_mad *mad = umad; + + return mad->status; +} + +ib_mad_addr_t * +umad_get_mad_addr(void *umad) +{ + struct ib_user_mad *mad = umad; + + return &mad->addr; +} + +int +umad_debug(int level) +{ + if (level >= 0) + umaddebug = level; + return umaddebug; +} + +void +umad_addr_dump(ib_mad_addr_t *addr) +{ +#define HEX(x) ((x) < 10 ? '0' + (x) : 'a' + ((x) -10)) + char gid_str[64]; + int i; + + for (i = 0; i < sizeof addr->gid; i++) { + gid_str[i*2] = HEX(addr->gid[i] >> 4); + gid_str[i*2+1] = HEX(addr->gid[i] & 0xf); + } + gid_str[i*2] = 0; + IBWARN("qpn %d qkey 0x%x lid 0x%x sl %d\n" + "grh_present %d gid_index %d hop_limit %d traffic_class %d flow_label 0x%x pkey_index 0x%x\n" + "Gid 0x%s", + ntohl(addr->qpn), ntohl(addr->qkey), ntohs(addr->lid), addr->sl, + addr->grh_present, (int)addr->gid_index, (int)addr->hop_limit, + (int)addr->traffic_class, addr->flow_label, addr->pkey_index, + gid_str); +} + +void +umad_dump(void *umad) +{ + struct ib_user_mad * mad = umad; + + IBWARN("agent id %d status %x timeout %d", + mad->agent_id, mad->status, mad->timeout_ms); + umad_addr_dump(&mad->addr); +} diff --git a/contrib/ofed/management/make.dist b/contrib/ofed/management/make.dist new file mode 100755 index 000000000000..b5b587c08469 --- /dev/null +++ b/contrib/ofed/management/make.dist @@ -0,0 +1,144 @@ +#!/bin/bash + +TMPDIR=`pwd`/dist +if [ ! -d $TMPDIR ]; then mkdir $TMPDIR; fi + +usage() { +echo "$0 daily | release [ signed | ]" +echo +echo " You must specify either release or daily in order for this script" +echo "to make tarballs. If this is a daily release, the tarballs will" +echo "be named -git.tar.gz and will overwrite existing tarballs." +echo "If this is a release build, then the tarball will be named" +echo "-.tar.gz and must be a new file. In addition," +echo "the script will add a new set of symbolic tags to the git repo" +echo "that correspond to the - of each tarball." +echo +echo " If the TARGETS environment variable is not NULL, then it is taken" +echo "as the list of components in the management tree that should be" +echo "included in this release. If it's NULL, then do all the components." +echo +echo " If the script detects that the tag on any component already exists," +echo "it will abort the release and prompt you to update the version on" +echo "the already tagged component. This enforces the proper behavior of" +echo "treating any released tarball as set in stone so that in the future" +echo "you will always be able to get to any given release tarball by" +echo "checking out the git tag and know with certainty that it is the same" +echo "code as released before even if you no longer have the same tarball" +echo "around." +echo +echo " As part of this process, the script will parse the .spec.in" +echo "file and output a .spec file. Since this script isn't smart" +echo "enough to deal with other random changes that should have their own" +echo "checkin the script will refuse to run if the current repo state is not" +echo "clean." +echo +echo " NOTE: the script has no clue if you are tagging on the right branch," +echo "it will however show you the git branch output so you can confirm it" +echo "is on the right branch before proceeding with the release." +echo +echo " In addition to just tagging the git repo, whenever creating a release" +echo "there is an optional argument of either signed or a hex gpg key-id." +echo "If you do not pass an argument to release, then the tag will be a" +echo "simple git annotated tag. If you pass signed as the argument, the" +echo "git tag operation will use your default signing key to sign the tag." +echo "Or you can pass an actual gpg key id in hex format and git will sign" +echo "the tag with that key." +echo +} + +if [ -z "$1" ]; then usage; exit 1; fi + +if [ "$1" != "daily" -a "$1" != "release" ]; then usage; exit 1; fi + +if [ -z "$TARGETS" ]; then + TARGETS="libibcommon libibumad libibmad opensm infiniband-diags" +fi + +# Is the repo clean? +git diff-index --quiet HEAD -- $package > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "Git tree is dirty. Please commit or undo any changes before proceeding." + exit 4 +fi + +# make sure we are on the right branch +git branch +echo -n "Is the active branch the right one to tag this release on [y/N]? " +read answer +if [ "$answer" = y -o "$answer" = Y ]; then + echo "Proceeding..." +else + echo "Please check out the right branch and run make.dist again" + exit 0 +fi + +for target in $TARGETS; do + VERSION=`grep "AC_INIT.*$target" $target/configure.in | cut -f 2 -d ',' | sed -e 's/ //g'` + if [ "$1" = "release" ]; then + # Check versions to make sure that we can proceed + if [ -f $TMPDIR/$target-$VERSION.tar.gz ]; then + echo "Target $target-$VERSION.tar.gz already exists, please update the version on" + echo "component $target" + exit 2 + fi + if [ ! -z "`git tag -l $target-$VERSION`" ]; then + echo "A git tag already exists for $target-$VERSION. Please change the version" + echo "of $target so a tag replacement won't occur." + exit 3 + fi +# On a real release, this resets the daily release starting point, on the +# assumption that any new daily builds will have a version number that is +# incrementally higher than the last officially released tarball. + RELEASE=1 + echo $RELEASE > $TMPDIR/$target.release + + if [ ! -z "$2" ]; then + if [ $2 = "signed" ]; then + git tag -s -m "Auto tag by make.dist on release tarball creation" $target-$VERSION + else + git tag -u "$2" -m "Auto tag by make.dist on release tarball creation" $target-$VERSION + fi + elif [ $1 = "release" ]; then + git tag -a -m "Auto tag by make.dist on release tarball creation" $target-$VERSION + fi + elif [ "$1" = "daily" ]; then + DATE=`date +%Y%m%d` + git_rev=`./gen_ver.sh $target | sed -e 's/^'$VERSION'_//'` + if [ "$git_rev" = "$VERSION" ] ; then + VERSION=${VERSION}_${DATE} + else + VERSION=${VERSION}_${DATE}_${git_rev} + fi + if [ -f $TMPDIR/$target.gitrev ]; then + old_rev=`cat $TMPDIR/$target.gitrev` + fi + echo $git_rev > $TMPDIR/$target.gitrev + if [ "$old_rev" = "$git_rev" ] ; then + echo "No daily build is needed for '$target' ($git_rev)" + continue + fi + if [ -f $TMPDIR/$target.release ]; then + RELEASE=`cat $TMPDIR/$target.release` + RELEASE=`expr $RELEASE + 1` + else + RELEASE=1 + fi + echo $RELEASE > $TMPDIR/$target.release + RELEASE=0.${RELEASE} + cat $target/configure.in \ + | sed -e '/AC_INIT/s/'$target', .*,/'$target', '$VERSION',/' \ + > configure.in.new + diff $target/configure.in configure.in.new > /dev/null \ + || cat configure.in.new > $target/configure.in + fi + + TARBALL=$target-$VERSION.tar.gz + + echo "Creating $TMPDIR/$TARBALL" + ( export RELEASE=$RELEASE && export TARBALL=$TARBALL && + cd $target && ./autogen.sh && ./configure && + make dist && mv $target-$VERSION.tar.gz $TMPDIR/$TARBALL ) || + exit $? + git checkout $target/configure.in +done diff --git a/contrib/ofed/management/opensm/AUTHORS b/contrib/ofed/management/opensm/AUTHORS new file mode 100644 index 000000000000..0106a07a84c7 --- /dev/null +++ b/contrib/ofed/management/opensm/AUTHORS @@ -0,0 +1,9 @@ + +By the chronological order of involvement: +Steve King, Intel +Anil Keshavamurthy, Intel +Eitan Zahavi, Mellanox Technologies, eitan@mellanox.co.il +Yael Kalka, Mellanox Technologies, yael@mellanox.co.il +Shahar Frank, Voltaire +Hal Rosenstock, Voltaire, halr@voltaire.com +Sasha Khapyorsky, Voltaire, sashak@voltaire.com diff --git a/contrib/ofed/management/opensm/COPYING b/contrib/ofed/management/opensm/COPYING new file mode 100644 index 000000000000..07e5ab0b0465 --- /dev/null +++ b/contrib/ofed/management/opensm/COPYING @@ -0,0 +1,32 @@ + Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + + This software is available to you under a choice of one of two + licenses. You may choose to be licensed under the terms of the GNU + General Public License (GPL) Version 2, available from the file + COPYING in the main directory of this source tree, or the + OpenIB.org BSD license below: + + Redistribution and use in source and binary forms, with or + without modification, are permitted provided that the following + conditions are met: + + - Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + - Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + diff --git a/contrib/ofed/management/opensm/ChangeLog b/contrib/ofed/management/opensm/ChangeLog new file mode 100644 index 000000000000..cb67d2b0f6f2 --- /dev/null +++ b/contrib/ofed/management/opensm/ChangeLog @@ -0,0 +1,14 @@ +2005-09-12 Hal Rosenstock + + * Improved SA MCMemberRecord error messages + +2005-08-22 Yael Kalka + + * Merge of OpenSM 1.8.0 previously available only on Gen1 + +2005-08-14 Eitan Zahavi + + * Provided a top level auto tools project so there is no need to + cd into each of the sub directories and do: + ./autogen.sh && configure && make && make install + diff --git a/contrib/ofed/management/opensm/INSTALL b/contrib/ofed/management/opensm/INSTALL new file mode 100644 index 000000000000..095b1eb40635 --- /dev/null +++ b/contrib/ofed/management/opensm/INSTALL @@ -0,0 +1,231 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PREFIX', the package will +use PREFIX as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/contrib/ofed/management/opensm/Makefile.am b/contrib/ofed/management/opensm/Makefile.am new file mode 100644 index 000000000000..2287eddb7515 --- /dev/null +++ b/contrib/ofed/management/opensm/Makefile.am @@ -0,0 +1,32 @@ + +# note that order matters: make the libs first then use them +SUBDIRS = complib libvendor opensm osmtest include $(DEFAULT_EVENT_PLUGIN) +DIST_SUBDIRS = complib libvendor opensm osmtest include osmeventplugin + +ACLOCAL_AMFLAGS = -I config + +# we should provide a hint for other apps about the build mode of this project +install-exec-hook: + mkdir -p $(DESTDIR)/$(includedir) +if DEBUG + echo "define osm_build_type \"debug\"" > $(DESTDIR)/$(includedir)/infiniband/opensm/osm_build_id.h +else + echo "define osm_build_type \"free\"" > $(DESTDIR)/$(includedir)/infiniband/opensm/osm_build_id.h +endif + $(top_srcdir)/config/install-sh -m 755 -d $(DESTDIR)/$(sysconfdir)/init.d + cp $(top_builddir)/scripts/opensm.init $(DESTDIR)/$(sysconfdir)/init.d/opensmd + chmod 755 $(DESTDIR)/$(sysconfdir)/init.d/opensmd + + +man_MANS = man/opensm.8 man/osmtest.8 + +various_scripts = $(wildcard scripts/*) +docs = doc/performance-manager-HOWTO.txt doc/QoS_management_in_OpenSM.txt \ + doc/opensm_release_notes-3.2.txt + +EXTRA_DIST = autogen.sh opensm.spec $(various_scripts) $(man_MANS) $(docs) + +dist-hook: $(EXTRA_DIST) + if [ -x $(top_srcdir)/../gen_chlog.sh ] ; then \ + cd $(top_srcdir)/.. ; ./gen_chlog.sh $(PACKAGE) > $(distdir)/ChangeLog ; cd - ; \ + fi diff --git a/contrib/ofed/management/opensm/NEWS b/contrib/ofed/management/opensm/NEWS new file mode 100644 index 000000000000..888755294bbc --- /dev/null +++ b/contrib/ofed/management/opensm/NEWS @@ -0,0 +1,2 @@ + +This file will hold news about the OpenSM project. diff --git a/contrib/ofed/management/opensm/README b/contrib/ofed/management/opensm/README new file mode 100644 index 000000000000..40556ba43158 --- /dev/null +++ b/contrib/ofed/management/opensm/README @@ -0,0 +1,25 @@ +OpenSM README: +-------------- + +OpenSM provides an implementation for an InfiniBand Subnet Manager and +Administrator. Such a software entity is required to run for in order +to initialize the InfiniBand hardware (at least one per each +InfiniBand subnet). + +The full list of OpenSM features is described in the user manual +provided in the doc sub directory. + +The installation of OpenSM includes: + +sbin/ + opensm - the SM/SA executable + osmtest - a test program for the SM/SA +lib/ + libosmcomp.{a,so} - component library with generic services and containers + libopensm.{a,so} - opensm services for logs and mad buffer pool + libosmvendor.{a,so} - interface to the user mad service of the driver +include/ + iba/ib_types.h - IBA types header file + complib/ - component library includes + vendor/ - vendor library includes + opensm/ - public opensm library includes diff --git a/contrib/ofed/management/opensm/autogen.sh b/contrib/ofed/management/opensm/autogen.sh new file mode 100755 index 000000000000..fee88007397c --- /dev/null +++ b/contrib/ofed/management/opensm/autogen.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# We change dir since the later utilities assume to work in the project dir +cd ${0%*/*} + +# make sure autoconf is up-to-date +ac_ver=`autoconf --version | head -n 1 | awk '{print $NF}'` +ac_maj=`echo $ac_ver|sed 's/\..*//'` +ac_min=`echo $ac_ver|sed 's/.*\.//'` +if [[ $ac_maj -lt 2 ]]; then + echo Min autoconf version is 2.57 + exit 1 +elif [[ $ac_maj -eq 2 && $ac_min -lt 57 ]]; then + echo Min autoconf version is 2.57 + exit 1 +fi + +# make sure automake is up-to-date +am_ver=`automake --version | head -n 1 | awk '{print $NF}'` +am_maj=`echo $am_ver|sed 's/\..*//'` +am_min=`echo $am_ver|sed 's/[^\.]*\.\([^\.]*\)\.*.*/\1/'` +am_sub=`echo $am_ver|sed 's/[^\.]*\.[^\.]*\.*//'` +if [[ $am_maj -lt 1 ]]; then + echo Min automake version is 1.6.3 + exit 1 +elif [[ $am_maj -eq 1 && $am_min -lt 6 ]]; then + echo "automake version is too old:$am_maj.$am_min.$am_sub < required 1.6.3" + exit 1 +elif [[ $am_maj -eq 1 && $am_min -eq 6 && $am_sub -lt 3 ]]; then + echo "automake version is too old:$am_maj.$am_min.$am_sub < required 1.6.3" + exit 1 +fi + +# make sure libtool is up-to-date +lt_ver=`libtool --version | head -n 1 | awk '{print $4}'` +lt_maj=`echo $lt_ver|sed 's/\..*//'` +lt_min=`echo $lt_ver|sed 's/[^\.]*\.\([^\.]*\)\.*.*/\1/'` +lt_sub=`echo $lt_ver|sed 's/[^\.]*\.[^\.]*\.*//'` +if [[ $lt_maj -lt 1 ]]; then + echo Min libtool version is 1.4.2 + exit 1 +elif [[ $lt_maj -eq 1 && $lt_min -lt 4 ]]; then + echo "libtool version is too old:$lt_maj.$lt_min.$lt_sub < required 1.4.2" + exit 1 +elif [[ $lt_maj -eq 1 && $lt_min -eq 4 && $lt_sub -lt 2 ]]; then + echo "libtool version is too old:$lt_maj.$lt_min.$lt_sub < required 1.4.2" + exit 1 +fi + +# cleanup +find . \( -name Makefile.in -o -name aclocal.m4 -o -name autom4te.cache -o -name configure -o -name aclocal.m4 \) -exec \rm -rf {} \; -prune + +aclocal -I config && \ +libtoolize --force --copy && \ +autoheader && \ +automake --foreign --add-missing --copy && \ +autoconf diff --git a/contrib/ofed/management/opensm/complib/ChangeLog b/contrib/ofed/management/opensm/complib/ChangeLog new file mode 100644 index 000000000000..2b13147279ec --- /dev/null +++ b/contrib/ofed/management/opensm/complib/ChangeLog @@ -0,0 +1,96 @@ +2007-07=11 Hal Rosenstock + + * configure.in: to version 2.2.1 + +2007-06-25 Hal Rosenstock + + * cl_event_wheel.c: Fix some typos in printfs when + __CL_EVENT_WHEEL_TEST__ defined + +2007-06-20 Hal Rosenstock + + * libosmcomp.map: Add get_next map functions as global + +2007-06-20 Todd Rimmer + + * include/complib/cl_map.h, include/complib/cl_qmap.h, + include/complib/cl_fleximap.h, cl_map.c: + Add get_next functions to the various maps + + * include/complib/cl_fleximap.h: In cl_fmap_remove_all, make + sure the count field is properly maintained. + +2007-06-19 Todd Rimmer + + * include/complib/cl_qmap.h: In cl_qmap_remove_all, make + sure the count field is properly maintained. + +2007-06-19 Hal Rosenstock + + * include/complib/cl_threadpool.h: Eliminate compile warning + with cl_threadpool.c introduced by previous change + +2007-06-13 Sasha Khapyorsky + + * include/complib/cl_threadpool.h, complib/cl_threadpool.c, + complib/cl_dispatcher.c, complib/libosmcomp.map: Thread + pool rework + +2007-06-13 Hal Rosenstock + + * configure.in: Bump to version 2.2.0 + + * libosmcomp.ver, libosmcomp.map: Update version info for + previous API removals + + * include/complib/cl_memory.h, include/complib/cl_memtrack.h, + complib/cl_memory.c, complib/cl_memtrack.c, include/Makefile.am: + Remove deprecated memory allocation related routines + +2007-06-13 Yevgeny Kliteynik + + * include/complib/cl_perf.h, include/complib/cl_async_proc.h, + complib/cl_perf.c, complib/cl_async_proc.c, Makefile.am, + libosmcomp.map: Remove unused cl_perf and cl_async_proc + +2007-05-09 Hal Rosenstock + + * configure.in: Bump to version 2.1.2 + +2007-03-29 Hal Rosenstock + + * configure.in: Bump to version 2.1.1 + +2007-01-08 Sasha Khapyorsky + + * cl_log.c: SIGUSR1 fixes + +2007-01-08 Ira Weiny + + * cl_log.c: Add SIGUSR1 handling to reopen osm.log + +2006-10-31 Hal Rosenstock + + * configure.in: Bumped to version version 2.1.0 + +2006-09-05 Sasha Khapyorsky + + * cl_event_wheel.c: Changes to support new osm_log + initializer osm_log_init_v2() + +2006-08-29 Sasha Khapyorsky + + * cl_event_wheel.c: Support option to limit size of OpenSM + log file + +2006-07-20 Sasha Khapyorsky + + * cl_pool.c: Fix memory corruption in cl_qcpool_init + +2006-07-19 Hal Rosenstock + + * Makefile.am: Eliminate deprecated warnings + +2006-06-11 Hal Rosenstock + + * configure.in: Released version 1.2.1 (OFED 1.1) diff --git a/contrib/ofed/management/opensm/complib/Makefile.am b/contrib/ofed/management/opensm/complib/Makefile.am new file mode 100644 index 000000000000..6f2f203068fc --- /dev/null +++ b/contrib/ofed/management/opensm/complib/Makefile.am @@ -0,0 +1,81 @@ + +INCLUDES = -I$(srcdir)/../include + +lib_LTLIBRARIES = libosmcomp.la + +if DEBUG +DBGFLAGS = -ggdb -D_DEBUG_ +else +DBGFLAGS = -g +endif + +libosmcomp_la_CFLAGS = -Wall $(DBGFLAGS) -D_XOPEN_SOURCE=600 -D_BSD_SOURCE=1 + +if HAVE_LD_VERSION_SCRIPT + libosmcomp_version_script = -Wl,--version-script=$(srcdir)/libosmcomp.map +else + libosmcomp_version_script = +endif + +complib_api_version=$(shell grep LIBVERSION= $(srcdir)/libosmcomp.ver | sed 's/LIBVERSION=//') + +libosmcomp_la_SOURCES = cl_complib.c cl_dispatcher.c \ + cl_event.c cl_event_wheel.c \ + cl_list.c cl_log.c cl_map.c \ + cl_pool.c cl_ptr_vector.c \ + cl_spinlock.c cl_statustext.c \ + cl_thread.c cl_threadpool.c \ + cl_timer.c cl_vector.c \ + ib_statustext.c \ + cl_nodenamemap.c + +libosmcomp_la_LDFLAGS = -version-info $(complib_api_version) \ + -export-dynamic $(libosmcomp_version_script) +libosmcomp_la_DEPENDENCIES = $(srcdir)/libosmcomp.map + +libosmcompincludedir = $(includedir)/infiniband/complib + +libosmcompinclude_HEADERS = $(srcdir)/../include/complib/cl_atomic.h \ + $(srcdir)/../include/complib/cl_atomic_osd.h \ + $(srcdir)/../include/complib/cl_byteswap.h \ + $(srcdir)/../include/complib/cl_byteswap_osd.h \ + $(srcdir)/../include/complib/cl_comppool.h \ + $(srcdir)/../include/complib/cl_debug.h \ + $(srcdir)/../include/complib/cl_debug_osd.h \ + $(srcdir)/../include/complib/cl_dispatcher.h \ + $(srcdir)/../include/complib/cl_event.h \ + $(srcdir)/../include/complib/cl_event_wheel.h \ + $(srcdir)/../include/complib/cl_event_osd.h \ + $(srcdir)/../include/complib/cl_fleximap.h \ + $(srcdir)/../include/complib/cl_list.h \ + $(srcdir)/../include/complib/cl_log.h \ + $(srcdir)/../include/complib/cl_map.h \ + $(srcdir)/../include/complib/cl_math.h \ + $(srcdir)/../include/complib/cl_nodenamemap.h \ + $(srcdir)/../include/complib/cl_packoff.h \ + $(srcdir)/../include/complib/cl_packon.h \ + $(srcdir)/../include/complib/cl_passivelock.h \ + $(srcdir)/../include/complib/cl_pool.h \ + $(srcdir)/../include/complib/cl_ptr_vector.h \ + $(srcdir)/../include/complib/cl_qcomppool.h \ + $(srcdir)/../include/complib/cl_qlist.h \ + $(srcdir)/../include/complib/cl_qmap.h \ + $(srcdir)/../include/complib/cl_qpool.h \ + $(srcdir)/../include/complib/cl_spinlock.h \ + $(srcdir)/../include/complib/cl_spinlock_osd.h \ + $(srcdir)/../include/complib/cl_thread.h \ + $(srcdir)/../include/complib/cl_thread_osd.h \ + $(srcdir)/../include/complib/cl_threadpool.h \ + $(srcdir)/../include/complib/cl_timer.h \ + $(srcdir)/../include/complib/cl_timer_osd.h \ + $(srcdir)/../include/complib/cl_types.h \ + $(srcdir)/../include/complib/cl_types_osd.h \ + $(srcdir)/../include/complib/cl_threadpool.h \ + $(srcdir)/../include/complib/cl_timer.h \ + $(srcdir)/../include/complib/cl_timer_osd.h \ + $(srcdir)/../include/complib/cl_types.h \ + $(srcdir)/../include/complib/cl_types_osd.h \ + $(srcdir)/../include/complib/cl_vector.h + +# headers are distributed as part of the include dir +EXTRA_DIST = $(srcdir)/libosmcomp.map $(srcdir)/libosmcomp.ver diff --git a/contrib/ofed/management/opensm/complib/cl_complib.c b/contrib/ofed/management/opensm/complib/cl_complib.c new file mode 100644 index 000000000000..2449d9d70bfc --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_complib.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include +#include + +/* + * Prototypes + */ + +extern + cl_status_t __cl_timer_prov_create(void); + +extern +void __cl_timer_prov_destroy(void); + +cl_spinlock_t cl_atomic_spinlock; + +void complib_init(void) +{ + cl_status_t status = CL_SUCCESS; + + status = cl_spinlock_init(&cl_atomic_spinlock); + if (status != CL_SUCCESS) + goto _error; + + status = __cl_timer_prov_create(); + if (status != CL_SUCCESS) + goto _error; + return; + +_error: + cl_msg_out("__init: failed to create complib (%s)\n", + CL_STATUS_MSG(status)); + exit(1); +} + +void complib_exit(void) +{ + __cl_timer_prov_destroy(); + cl_spinlock_destroy(&cl_atomic_spinlock); +} + +boolean_t cl_is_debug(void) +{ +#if defined( _DEBUG_ ) + return TRUE; +#else + return FALSE; +#endif /* defined( _DEBUG_ ) */ +} diff --git a/contrib/ofed/management/opensm/complib/cl_dispatcher.c b/contrib/ofed/management/opensm/complib/cl_dispatcher.c new file mode 100644 index 000000000000..b0a0a768d70d --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_dispatcher.c @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of Dispatcher abstraction. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +/* give some guidance when we build our cl_pool of messages */ +#define CL_DISP_INITIAL_MSG_COUNT 256 +#define CL_DISP_MSG_GROW_SIZE 64 + +/* give some guidance when we build our cl_pool of registration elements */ +#define CL_DISP_INITIAL_REG_COUNT 16 +#define CL_DISP_REG_GROW_SIZE 16 + +/******************************************************************** + __cl_disp_worker + + Description: + This function takes messages off the FIFO and calls Processmsg() + This function executes as passive level. + + Inputs: + p_disp - Pointer to Dispatcher object + + Outputs: + None + + Returns: + None +********************************************************************/ +void __cl_disp_worker(IN void *context) +{ + cl_disp_msg_t *p_msg; + cl_dispatcher_t *p_disp = (cl_dispatcher_t *) context; + + cl_spinlock_acquire(&p_disp->lock); + + /* Process the FIFO until we drain it dry. */ + while (cl_qlist_count(&p_disp->msg_fifo)) { + /* Pop the message at the head from the FIFO. */ + p_msg = + (cl_disp_msg_t *) cl_qlist_remove_head(&p_disp->msg_fifo); + + /* we track the tim ethe last message spent in the queue */ + p_disp->last_msg_queue_time_us = + cl_get_time_stamp() - p_msg->in_time; + + /* + * Release the spinlock while the message is processed. + * The user's callback may reenter the dispatcher + * and cause the lock to be reaquired. + */ + cl_spinlock_release(&p_disp->lock); + p_msg->p_dest_reg->pfn_rcv_callback((void *)p_msg->p_dest_reg-> + context, + (void *)p_msg->p_data); + + cl_atomic_dec(&p_msg->p_dest_reg->ref_cnt); + + /* The client has seen the data. Notify the sender as appropriate. */ + if (p_msg->pfn_xmt_callback) { + p_msg->pfn_xmt_callback((void *)p_msg->context, + (void *)p_msg->p_data); + cl_atomic_dec(&p_msg->p_src_reg->ref_cnt); + } + + /* Grab the lock for the next iteration through the list. */ + cl_spinlock_acquire(&p_disp->lock); + + /* Return this message to the pool. */ + cl_qpool_put(&p_disp->msg_pool, (cl_pool_item_t *) p_msg); + } + + cl_spinlock_release(&p_disp->lock); +} + +/******************************************************************** + ********************************************************************/ +void cl_disp_construct(IN cl_dispatcher_t * const p_disp) +{ + CL_ASSERT(p_disp); + + cl_qlist_init(&p_disp->reg_list); + cl_ptr_vector_construct(&p_disp->reg_vec); + cl_qlist_init(&p_disp->msg_fifo); + cl_spinlock_construct(&p_disp->lock); + cl_qpool_construct(&p_disp->msg_pool); +} + +/******************************************************************** + ********************************************************************/ +void cl_disp_shutdown(IN cl_dispatcher_t * const p_disp) +{ + CL_ASSERT(p_disp); + + /* Stop the thread pool. */ + cl_thread_pool_destroy(&p_disp->worker_threads); + + /* Process all outstanding callbacks. */ + __cl_disp_worker(p_disp); + + /* Free all registration info. */ + while (!cl_is_qlist_empty(&p_disp->reg_list)) + free(cl_qlist_remove_head(&p_disp->reg_list)); +} + +/******************************************************************** + ********************************************************************/ +void cl_disp_destroy(IN cl_dispatcher_t * const p_disp) +{ + CL_ASSERT(p_disp); + + cl_spinlock_destroy(&p_disp->lock); + /* Destroy the message pool */ + cl_qpool_destroy(&p_disp->msg_pool); + /* Destroy the pointer vector of registrants. */ + cl_ptr_vector_destroy(&p_disp->reg_vec); +} + +/******************************************************************** + ********************************************************************/ +cl_status_t +cl_disp_init(IN cl_dispatcher_t * const p_disp, + IN const uint32_t thread_count, IN const char *const name) +{ + cl_status_t status; + + CL_ASSERT(p_disp); + + cl_disp_construct(p_disp); + + status = cl_spinlock_init(&p_disp->lock); + if (status != CL_SUCCESS) { + cl_disp_destroy(p_disp); + return (status); + } + + /* Specify no upper limit to the number of messages in the pool */ + status = cl_qpool_init(&p_disp->msg_pool, CL_DISP_INITIAL_MSG_COUNT, + 0, CL_DISP_MSG_GROW_SIZE, sizeof(cl_disp_msg_t), + NULL, NULL, NULL); + if (status != CL_SUCCESS) { + cl_disp_destroy(p_disp); + return (status); + } + + status = cl_ptr_vector_init(&p_disp->reg_vec, CL_DISP_INITIAL_REG_COUNT, + CL_DISP_REG_GROW_SIZE); + if (status != CL_SUCCESS) { + cl_disp_destroy(p_disp); + return (status); + } + + status = cl_thread_pool_init(&p_disp->worker_threads, thread_count, + __cl_disp_worker, p_disp, name); + if (status != CL_SUCCESS) + cl_disp_destroy(p_disp); + + return (status); +} + +/******************************************************************** + ********************************************************************/ +cl_disp_reg_handle_t +cl_disp_register(IN cl_dispatcher_t * const p_disp, + IN const cl_disp_msgid_t msg_id, + IN cl_pfn_msgrcv_cb_t pfn_callback OPTIONAL, + IN const void *const context OPTIONAL) +{ + cl_disp_reg_info_t *p_reg; + cl_status_t status; + + CL_ASSERT(p_disp); + + /* Check that the requested registrant ID is available. */ + cl_spinlock_acquire(&p_disp->lock); + if ((msg_id != CL_DISP_MSGID_NONE) && + (msg_id < cl_ptr_vector_get_size(&p_disp->reg_vec)) && + (cl_ptr_vector_get(&p_disp->reg_vec, msg_id))) { + cl_spinlock_release(&p_disp->lock); + return (NULL); + } + + /* Get a registration info from the pool. */ + p_reg = (cl_disp_reg_info_t *) malloc(sizeof(cl_disp_reg_info_t)); + if (!p_reg) { + cl_spinlock_release(&p_disp->lock); + return (NULL); + } else { + memset(p_reg, 0, sizeof(cl_disp_reg_info_t)); + } + + p_reg->p_disp = p_disp; + p_reg->ref_cnt = 0; + p_reg->pfn_rcv_callback = pfn_callback; + p_reg->context = context; + p_reg->msg_id = msg_id; + + /* Insert the registration in the list. */ + cl_qlist_insert_tail(&p_disp->reg_list, (cl_list_item_t *) p_reg); + + /* Set the array entry to the registrant. */ + /* The ptr_vector grow automatically as necessary. */ + if (msg_id != CL_DISP_MSGID_NONE) { + status = cl_ptr_vector_set(&p_disp->reg_vec, msg_id, p_reg); + if (status != CL_SUCCESS) { + free(p_reg); + cl_spinlock_release(&p_disp->lock); + return (NULL); + } + } + + cl_spinlock_release(&p_disp->lock); + + return (p_reg); +} + +/******************************************************************** + ********************************************************************/ +void cl_disp_unregister(IN const cl_disp_reg_handle_t handle) +{ + cl_disp_reg_info_t *p_reg; + cl_dispatcher_t *p_disp; + + if (handle == CL_DISP_INVALID_HANDLE) + return; + + p_reg = (cl_disp_reg_info_t *) handle; + p_disp = p_reg->p_disp; + CL_ASSERT(p_disp); + + cl_spinlock_acquire(&p_disp->lock); + /* + * Clear the registrant vector entry. This will cause any further + * post calls to fail. + */ + if (p_reg->msg_id != CL_DISP_MSGID_NONE) { + CL_ASSERT(p_reg->msg_id < + cl_ptr_vector_get_size(&p_disp->reg_vec)); + cl_ptr_vector_set(&p_disp->reg_vec, p_reg->msg_id, NULL); + } + cl_spinlock_release(&p_disp->lock); + + while (p_reg->ref_cnt > 0) + cl_thread_suspend(1); + + cl_spinlock_acquire(&p_disp->lock); + /* Remove the registrant from the list. */ + cl_qlist_remove_item(&p_disp->reg_list, (cl_list_item_t *) p_reg); + /* Return the registration info to the pool */ + free(p_reg); + + cl_spinlock_release(&p_disp->lock); +} + +/******************************************************************** + ********************************************************************/ +cl_status_t +cl_disp_post(IN const cl_disp_reg_handle_t handle, + IN const cl_disp_msgid_t msg_id, + IN const void *const p_data, + IN cl_pfn_msgdone_cb_t pfn_callback OPTIONAL, + IN const void *const context OPTIONAL) +{ + cl_disp_reg_info_t *p_src_reg = (cl_disp_reg_info_t *) handle; + cl_disp_reg_info_t *p_dest_reg; + cl_dispatcher_t *p_disp; + cl_disp_msg_t *p_msg; + + p_disp = handle->p_disp; + CL_ASSERT(p_disp); + CL_ASSERT(msg_id != CL_DISP_MSGID_NONE); + + cl_spinlock_acquire(&p_disp->lock); + /* Check that the recipient exists. */ + p_dest_reg = cl_ptr_vector_get(&p_disp->reg_vec, msg_id); + if (!p_dest_reg) { + cl_spinlock_release(&p_disp->lock); + return (CL_NOT_FOUND); + } + + /* Get a free message from the pool. */ + p_msg = (cl_disp_msg_t *) cl_qpool_get(&p_disp->msg_pool); + if (!p_msg) { + cl_spinlock_release(&p_disp->lock); + return (CL_INSUFFICIENT_MEMORY); + } + + /* Initialize the message */ + p_msg->p_src_reg = p_src_reg; + p_msg->p_dest_reg = p_dest_reg; + p_msg->p_data = p_data; + p_msg->pfn_xmt_callback = pfn_callback; + p_msg->context = context; + p_msg->in_time = cl_get_time_stamp(); + + /* + * Increment the sender's reference count if they request a completion + * notification. + */ + if (pfn_callback) + cl_atomic_inc(&p_src_reg->ref_cnt); + + /* Increment the recipient's reference count. */ + cl_atomic_inc(&p_dest_reg->ref_cnt); + + /* Queue the message in the FIFO. */ + cl_qlist_insert_tail(&p_disp->msg_fifo, (cl_list_item_t *) p_msg); + cl_spinlock_release(&p_disp->lock); + + /* Signal the thread pool that there is work to be done. */ + cl_thread_pool_signal(&p_disp->worker_threads); + return (CL_SUCCESS); +} + +void +cl_disp_get_queue_status(IN const cl_disp_reg_handle_t handle, + OUT uint32_t * p_num_queued_msgs, + OUT uint64_t * p_last_msg_queue_time_ms) +{ + cl_dispatcher_t *p_disp = ((cl_disp_reg_info_t *) handle)->p_disp; + + cl_spinlock_acquire(&p_disp->lock); + + if (p_last_msg_queue_time_ms) + *p_last_msg_queue_time_ms = + p_disp->last_msg_queue_time_us / 1000; + + if (p_num_queued_msgs) + *p_num_queued_msgs = cl_qlist_count(&p_disp->msg_fifo); + + cl_spinlock_release(&p_disp->lock); +} diff --git a/contrib/ofed/management/opensm/complib/cl_event.c b/contrib/ofed/management/opensm/complib/cl_event.c new file mode 100644 index 000000000000..d14b2f44bddd --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_event.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +void cl_event_construct(IN cl_event_t * p_event) +{ + CL_ASSERT(p_event); + + p_event->state = CL_UNINITIALIZED; +} + +cl_status_t +cl_event_init(IN cl_event_t * const p_event, IN const boolean_t manual_reset) +{ + CL_ASSERT(p_event); + + cl_event_construct(p_event); + + pthread_cond_init(&p_event->condvar, NULL); + pthread_mutex_init(&p_event->mutex, NULL); + p_event->signaled = FALSE; + p_event->manual_reset = manual_reset; + p_event->state = CL_INITIALIZED; + + return (CL_SUCCESS); +} + +void cl_event_destroy(IN cl_event_t * const p_event) +{ + CL_ASSERT(cl_is_state_valid(p_event->state)); + + /* Destroy only if the event was constructed */ + if (p_event->state == CL_INITIALIZED) { + pthread_cond_broadcast(&p_event->condvar); + pthread_cond_destroy(&p_event->condvar); + pthread_mutex_destroy(&p_event->mutex); + } + + p_event->state = CL_UNINITIALIZED; +} + +cl_status_t cl_event_signal(IN cl_event_t * const p_event) +{ + /* Make sure that the event was started */ + CL_ASSERT(p_event->state == CL_INITIALIZED); + + pthread_mutex_lock(&p_event->mutex); + p_event->signaled = TRUE; + /* Wake up one or all depending on whether the event is auto-resetting. */ + if (p_event->manual_reset) + pthread_cond_broadcast(&p_event->condvar); + else + pthread_cond_signal(&p_event->condvar); + + pthread_mutex_unlock(&p_event->mutex); + + return (CL_SUCCESS); +} + +cl_status_t cl_event_reset(IN cl_event_t * const p_event) +{ + /* Make sure that the event was started */ + CL_ASSERT(p_event->state == CL_INITIALIZED); + + pthread_mutex_lock(&p_event->mutex); + p_event->signaled = FALSE; + pthread_mutex_unlock(&p_event->mutex); + + return (CL_SUCCESS); +} + +cl_status_t +cl_event_wait_on(IN cl_event_t * const p_event, + IN const uint32_t wait_us, IN const boolean_t interruptible) +{ + cl_status_t status; + int wait_ret; + struct timespec timeout; + struct timeval curtime; + + /* Make sure that the event was Started */ + CL_ASSERT(p_event->state == CL_INITIALIZED); + + pthread_mutex_lock(&p_event->mutex); + + /* Return immediately if the event is signalled. */ + if (p_event->signaled) { + if (!p_event->manual_reset) + p_event->signaled = FALSE; + + pthread_mutex_unlock(&p_event->mutex); + return (CL_SUCCESS); + } + + /* If just testing the state, return CL_TIMEOUT. */ + if (wait_us == 0) { + pthread_mutex_unlock(&p_event->mutex); + return (CL_TIMEOUT); + } + + if (wait_us == EVENT_NO_TIMEOUT) { + /* Wait for condition variable to be signaled or broadcast. */ + if (pthread_cond_wait + (&p_event->condvar, &p_event->mutex)) + status = CL_NOT_DONE; + else + status = CL_SUCCESS; + } else { + /* Get the current time */ + if (gettimeofday(&curtime, NULL) == 0) { + timeout.tv_sec = curtime.tv_sec + (wait_us / 1000000); + timeout.tv_nsec = + (curtime.tv_usec + (wait_us % 1000000)) * 1000; + + wait_ret = pthread_cond_timedwait(&p_event->condvar, + &p_event->mutex, + &timeout); + if (wait_ret == 0) + status = + (p_event-> + signaled ? CL_SUCCESS : CL_NOT_DONE); + else if (wait_ret == ETIMEDOUT) + status = CL_TIMEOUT; + else + status = CL_NOT_DONE; + } else { + status = CL_ERROR; + } + } + if (!p_event->manual_reset) + p_event->signaled = FALSE; + + pthread_mutex_unlock(&p_event->mutex); + return (status); +} diff --git a/contrib/ofed/management/opensm/complib/cl_event_wheel.c b/contrib/ofed/management/opensm/complib/cl_event_wheel.c new file mode 100644 index 000000000000..ca068821cfab --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_event_wheel.c @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#define CL_DBG(fmt, arg...) + +static cl_status_t +__event_will_age_before(IN const cl_list_item_t * const p_list_item, + IN void *context) +{ + uint64_t aging_time = *((uint64_t *) context); + cl_event_wheel_reg_info_t *p_event; + + p_event = + PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, list_item); + + if (p_event->aging_time < aging_time) + return CL_SUCCESS; + else + return CL_NOT_FOUND; +} + +static void __cl_event_wheel_callback(IN void *context) +{ + cl_event_wheel_t *p_event_wheel = (cl_event_wheel_t *) context; + cl_list_item_t *p_list_item, *p_prev_event_list_item; + cl_list_item_t *p_list_next_item; + cl_event_wheel_reg_info_t *p_event; + uint64_t current_time; + uint64_t next_aging_time; + uint32_t new_timeout; + cl_status_t cl_status; + + /* might be during closing ... */ + if (p_event_wheel->closing) + return; + + current_time = cl_get_time_stamp(); + + if (NULL != p_event_wheel->p_external_lock) + + /* Take care of the order of acquiring locks to avoid the deadlock! + * The external lock goes first. + */ + cl_spinlock_acquire(p_event_wheel->p_external_lock); + + cl_spinlock_acquire(&p_event_wheel->lock); + + p_list_item = cl_qlist_head(&p_event_wheel->events_wheel); + if (p_list_item == cl_qlist_end(&p_event_wheel->events_wheel)) + /* the list is empty - nothing to do */ + goto Exit; + + /* we found such an item. get the p_event */ + p_event = + PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, list_item); + + while (p_event->aging_time <= current_time) { + /* this object has aged - invoke it's callback */ + if (p_event->pfn_aged_callback) + next_aging_time = + p_event->pfn_aged_callback(p_event->key, + p_event->num_regs, + p_event->context); + else + next_aging_time = 0; + + /* point to the next object in the wheel */ + p_list_next_item = cl_qlist_next(p_list_item); + + /* We need to retire the event if the next aging time passed */ + if (next_aging_time < current_time) { + /* remove it from the map */ + cl_qmap_remove_item(&p_event_wheel->events_map, + &(p_event->map_item)); + + /* pop p_event from the wheel */ + cl_qlist_remove_head(&p_event_wheel->events_wheel); + + /* delete the event info object - allocated by cl_event_wheel_reg */ + free(p_event); + } else { + /* update the required aging time */ + p_event->aging_time = next_aging_time; + p_event->num_regs++; + + /* do not remove from the map - but remove from the list head and + place in the correct position */ + + /* pop p_event from the wheel */ + cl_qlist_remove_head(&p_event_wheel->events_wheel); + + /* find the event that ages just before */ + p_prev_event_list_item = + cl_qlist_find_from_tail(&p_event_wheel-> + events_wheel, + __event_will_age_before, + &p_event->aging_time); + + /* insert just after */ + cl_qlist_insert_next(&p_event_wheel->events_wheel, + p_prev_event_list_item, + &p_event->list_item); + + /* as we have modified the list - restart from first item: */ + p_list_next_item = + cl_qlist_head(&p_event_wheel->events_wheel); + } + + /* advance to next event */ + p_list_item = p_list_next_item; + if (p_list_item == cl_qlist_end(&p_event_wheel->events_wheel)) + /* the list is empty - nothing to do */ + break; + + /* get the p_event */ + p_event = + PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, + list_item); + } + + /* We need to restart the timer only if the list is not empty now */ + if (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel)) { + /* get the p_event */ + p_event = + PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, + list_item); + + /* start the timer to the timeout [msec] */ + new_timeout = + (uint32_t) (((p_event->aging_time - current_time) / 1000) + + 0.5); + CL_DBG("__cl_event_wheel_callback: Restart timer in: " + "%u [msec]\n", new_timeout); + cl_status = cl_timer_start(&p_event_wheel->timer, new_timeout); + if (cl_status != CL_SUCCESS) { + CL_DBG("__cl_event_wheel_callback : ERR 6100: " + "Failed to start timer\n"); + } + } + + /* release the lock */ +Exit: + cl_spinlock_release(&p_event_wheel->lock); + if (NULL != p_event_wheel->p_external_lock) + cl_spinlock_release(p_event_wheel->p_external_lock); +} + +/* + * Construct and Initialize + */ +void cl_event_wheel_construct(IN cl_event_wheel_t * const p_event_wheel) +{ + cl_spinlock_construct(&(p_event_wheel->lock)); + cl_timer_construct(&(p_event_wheel->timer)); +} + +cl_status_t +cl_event_wheel_init(IN cl_event_wheel_t * const p_event_wheel) +{ + cl_status_t cl_status = CL_SUCCESS; + + /* initialize */ + p_event_wheel->p_external_lock = NULL; + p_event_wheel->closing = FALSE; + cl_status = cl_spinlock_init(&(p_event_wheel->lock)); + if (cl_status != CL_SUCCESS) + return cl_status; + cl_qlist_init(&p_event_wheel->events_wheel); + cl_qmap_init(&p_event_wheel->events_map); + + /* init the timer with timeout */ + cl_status = cl_timer_init(&p_event_wheel->timer, __cl_event_wheel_callback, p_event_wheel); /* cb context */ + + return cl_status; +} + +cl_status_t +cl_event_wheel_init_ex(IN cl_event_wheel_t * const p_event_wheel, + IN cl_spinlock_t * p_external_lock) +{ + cl_status_t cl_status; + + cl_status = cl_event_wheel_init(p_event_wheel); + if (CL_SUCCESS != cl_status) + return cl_status; + + p_event_wheel->p_external_lock = p_external_lock; + return cl_status; +} + +void cl_event_wheel_dump(IN cl_event_wheel_t * const p_event_wheel) +{ + cl_list_item_t *p_list_item; + cl_event_wheel_reg_info_t *p_event; + + p_list_item = cl_qlist_head(&p_event_wheel->events_wheel); + + while (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel)) { + p_event = + PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, + list_item); + CL_DBG("cl_event_wheel_dump: Found event key:<0x%" + PRIx64 ">, aging time:%" PRIu64 "\n", + p_event->key, p_event->aging_time); + p_list_item = cl_qlist_next(p_list_item); + } +} + +void cl_event_wheel_destroy(IN cl_event_wheel_t * const p_event_wheel) +{ + cl_list_item_t *p_list_item; + cl_map_item_t *p_map_item; + cl_event_wheel_reg_info_t *p_event; + + /* we need to get a lock */ + cl_spinlock_acquire(&p_event_wheel->lock); + + cl_event_wheel_dump(p_event_wheel); + + /* go over all the items in the list and remove them */ + p_list_item = cl_qlist_remove_head(&p_event_wheel->events_wheel); + while (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel)) { + p_event = + PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, + list_item); + + CL_DBG("cl_event_wheel_destroy: Found outstanding event" + " key:<0x%" PRIx64 ">\n", p_event->key); + + /* remove it from the map */ + p_map_item = &(p_event->map_item); + cl_qmap_remove_item(&p_event_wheel->events_map, p_map_item); + free(p_event); /* allocated by cl_event_wheel_reg */ + p_list_item = + cl_qlist_remove_head(&p_event_wheel->events_wheel); + } + + /* destroy the timer */ + cl_timer_destroy(&p_event_wheel->timer); + + /* destroy the lock (this should be done without releasing - we don't want + any other run to grab the lock at this point. */ + cl_spinlock_release(&p_event_wheel->lock); + cl_spinlock_destroy(&(p_event_wheel->lock)); +} + +cl_status_t +cl_event_wheel_reg(IN cl_event_wheel_t * const p_event_wheel, + IN const uint64_t key, + IN const uint64_t aging_time_usec, + IN cl_pfn_event_aged_cb_t pfn_callback, + IN void *const context) +{ + cl_event_wheel_reg_info_t *p_event; + uint64_t timeout; + uint32_t to; + cl_status_t cl_status = CL_SUCCESS; + cl_list_item_t *prev_event_list_item; + cl_map_item_t *p_map_item; + + /* Get the lock on the manager */ + cl_spinlock_acquire(&(p_event_wheel->lock)); + + cl_event_wheel_dump(p_event_wheel); + + /* Make sure such a key does not exists */ + p_map_item = cl_qmap_get(&p_event_wheel->events_map, key); + if (p_map_item != cl_qmap_end(&p_event_wheel->events_map)) { + CL_DBG("cl_event_wheel_reg: Already exists key:0x%" + PRIx64 "\n", key); + + /* already there - remove it from the list as it is getting a new time */ + p_event = + PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t, + map_item); + + /* remove the item from the qlist */ + cl_qlist_remove_item(&p_event_wheel->events_wheel, + &p_event->list_item); + /* and the qmap */ + cl_qmap_remove_item(&p_event_wheel->events_map, + &p_event->map_item); + } else { + /* make a new one */ + p_event = (cl_event_wheel_reg_info_t *) + malloc(sizeof(cl_event_wheel_reg_info_t)); + p_event->num_regs = 0; + } + + p_event->key = key; + p_event->aging_time = aging_time_usec; + p_event->pfn_aged_callback = pfn_callback; + p_event->context = context; + p_event->num_regs++; + + CL_DBG("cl_event_wheel_reg: Registering event key:0x%" PRIx64 + " aging in %u [msec]\n", p_event->key, + (uint32_t) ((p_event->aging_time - + cl_get_time_stamp()) / 1000)); + + /* If the list is empty - need to start the timer */ + if (cl_is_qlist_empty(&p_event_wheel->events_wheel)) { + /* Edward Bortnikov 03/29/2003 + * ++TBD Consider moving the timer manipulation behind the list manipulation. + */ + + /* calculate the new timeout */ + timeout = + (p_event->aging_time - cl_get_time_stamp() + 500) / 1000; + + /* stop the timer if it is running */ + + /* Edward Bortnikov 03/29/2003 + * Don't call cl_timer_stop() because it spins forever. + * cl_timer_start() will invoke cl_timer_stop() by itself. + * + * The problematic scenario is when __cl_event_wheel_callback() + * is in race condition with this code. It sets timer.in_timer_cb + * to TRUE and then blocks on p_event_wheel->lock. Following this, + * the call to cl_timer_stop() hangs. Following this, the whole system + * enters into a deadlock. + * + * cl_timer_stop(&p_event_wheel->timer); + */ + + /* The timeout for the cl_timer_start should be given as uint32_t. + if there is an overflow - warn about it. */ + to = (uint32_t) timeout; + if (timeout > (uint32_t) timeout) { + to = 0xffffffff; /* max 32 bit timer */ + CL_DBG("cl_event_wheel_reg: timeout requested is " + "too large. Using timeout: %u\n", to); + } + + /* start the timer to the timeout [msec] */ + cl_status = cl_timer_start(&p_event_wheel->timer, to); + if (cl_status != CL_SUCCESS) { + CL_DBG("cl_event_wheel_reg : ERR 6103: " + "Failed to start timer\n"); + goto Exit; + } + } + + /* insert the object to the qlist and the qmap */ + + /* BUT WE MUST INSERT IT IN A SORTED MANNER */ + prev_event_list_item = + cl_qlist_find_from_tail(&p_event_wheel->events_wheel, + __event_will_age_before, + &p_event->aging_time); + + cl_qlist_insert_next(&p_event_wheel->events_wheel, + prev_event_list_item, &p_event->list_item); + + cl_qmap_insert(&p_event_wheel->events_map, key, &(p_event->map_item)); + +Exit: + cl_spinlock_release(&p_event_wheel->lock); + + return cl_status; +} + +void +cl_event_wheel_unreg(IN cl_event_wheel_t * const p_event_wheel, IN uint64_t key) +{ + cl_event_wheel_reg_info_t *p_event; + cl_map_item_t *p_map_item; + + CL_DBG("cl_event_wheel_unreg: " "Removing key:0x%" PRIx64 "\n", key); + + cl_spinlock_acquire(&p_event_wheel->lock); + p_map_item = cl_qmap_get(&p_event_wheel->events_map, key); + if (p_map_item != cl_qmap_end(&p_event_wheel->events_map)) { + /* we found such an item. */ + p_event = + PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t, + map_item); + + /* remove the item from the qlist */ + cl_qlist_remove_item(&p_event_wheel->events_wheel, + &(p_event->list_item)); + /* remove the item from the qmap */ + cl_qmap_remove_item(&p_event_wheel->events_map, + &(p_event->map_item)); + + CL_DBG("cl_event_wheel_unreg: Removed key:0x%" PRIx64 "\n", + key); + + /* free the item */ + free(p_event); + } else { + CL_DBG("cl_event_wheel_unreg: did not find key:0x%" PRIx64 + "\n", key); + } + + cl_spinlock_release(&p_event_wheel->lock); +} + +uint32_t +cl_event_wheel_num_regs(IN cl_event_wheel_t * const p_event_wheel, + IN uint64_t key) +{ + + cl_event_wheel_reg_info_t *p_event; + cl_map_item_t *p_map_item; + uint32_t num_regs = 0; + + /* try to find the key in the map */ + CL_DBG("cl_event_wheel_num_regs: Looking for key:0x%" + PRIx64 "\n", key); + + cl_spinlock_acquire(&p_event_wheel->lock); + p_map_item = cl_qmap_get(&p_event_wheel->events_map, key); + if (p_map_item != cl_qmap_end(&p_event_wheel->events_map)) { + /* ok so we can simply return it's num_regs */ + p_event = + PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t, + map_item); + num_regs = p_event->num_regs; + } + + cl_spinlock_release(&p_event_wheel->lock); + return (num_regs); +} + +#ifdef __CL_EVENT_WHEEL_TEST__ + +/* Dump out the complete state of the event wheel */ +void __cl_event_wheel_dump(IN cl_event_wheel_t * const p_event_wheel) +{ + cl_list_item_t *p_list_item; + cl_map_item_t *p_map_item; + cl_event_wheel_reg_info_t *p_event; + + printf("************** Event Wheel Dump ***********************\n"); + printf("Event Wheel List has %u items:\n", + cl_qlist_count(&p_event_wheel->events_wheel)); + + p_list_item = cl_qlist_head(&p_event_wheel->events_wheel); + while (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel)) { + p_event = + PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, + list_item); + printf("Event key:0x%" PRIx64 " Context:%s NumRegs:%u\n", + p_event->key, (char *)p_event->context, + p_event->num_regs); + + /* next */ + p_list_item = cl_qlist_next(p_list_item); + } + + printf("Event Map has %u items:\n", + cl_qmap_count(&p_event_wheel->events_map)); + + p_map_item = cl_qmap_head(&p_event_wheel->events_map); + while (p_map_item != cl_qmap_end(&p_event_wheel->events_map)) { + p_event = + PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t, + map_item); + printf("Event key:0x%" PRIx64 " Context:%s NumRegs:%u\n", + p_event->key, (char *)p_event->context, + p_event->num_regs); + + /* next */ + p_map_item = cl_qmap_next(p_map_item); + } + +} + +/* The callback for aging event */ +/* We assume we pass a text context */ +void __test_event_aging(uint64_t key, void *context) +{ + printf("*****************************************************\n"); + printf("Aged key: 0x%" PRIx64 " Context:%s\n", key, (char *)context); +} + +int main() +{ + cl_event_wheel_t event_wheel; + /* uint64_t key; */ + + /* construct */ + cl_event_wheel_construct(&event_wheel); + + /* init */ + cl_event_wheel_init(&event_wheel); + + /* Start Playing */ + cl_event_wheel_reg(&event_wheel, 1, /* key */ + cl_get_time_stamp() + 3000000, /* 3 sec lifetime */ + __test_event_aging, /* cb */ + "The first Aging Event"); + + cl_event_wheel_reg(&event_wheel, 2, /* key */ + cl_get_time_stamp() + 3000000, /* 3 sec lifetime */ + __test_event_aging, /* cb */ + "The Second Aging Event"); + + cl_event_wheel_reg(&event_wheel, 3, /* key */ + cl_get_time_stamp() + 3500000, /* 3 sec lifetime */ + __test_event_aging, /* cb */ + "The Third Aging Event"); + + __cl_event_wheel_dump(&event_wheel); + + sleep(2); + cl_event_wheel_reg(&event_wheel, 2, /* key */ + cl_get_time_stamp() + 8000000, /* 3 sec lifetime */ + __test_event_aging, /* cb */ + "The Second Aging Event Moved"); + + __cl_event_wheel_dump(&event_wheel); + + sleep(1); + /* remove the third event */ + cl_event_wheel_unreg(&event_wheel, 3); /* key */ + + /* get the number of registrations for the keys */ + printf("Event 1 Registered: %u\n", + cl_event_wheel_num_regs(&event_wheel, 1)); + printf("Event 2 Registered: %u\n", + cl_event_wheel_num_regs(&event_wheel, 2)); + + sleep(5); + /* destroy */ + cl_event_wheel_destroy(&event_wheel); + + return (0); +} + +#endif /* __CL_EVENT_WHEEL_TEST__ */ diff --git a/contrib/ofed/management/opensm/complib/cl_list.c b/contrib/ofed/management/opensm/complib/cl_list.c new file mode 100644 index 000000000000..8129c6195efb --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_list.c @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of quick list, and list. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +#define FREE_ITEM_GROW_SIZE 10 + +/****************************************************************************** +******************************************************************************* +************** ************ +************** IMPLEMENTATION OF QUICK LIST ************ +************** ************ +******************************************************************************* +******************************************************************************/ +void +cl_qlist_insert_array_head(IN cl_qlist_t * const p_list, + IN cl_list_item_t * const p_array, + IN uint32_t item_count, IN const uint32_t item_size) +{ + cl_list_item_t *p_item; + + CL_ASSERT(p_list); + CL_ASSERT(p_list->state == CL_INITIALIZED); + CL_ASSERT(p_array); + CL_ASSERT(item_size >= sizeof(cl_list_item_t)); + CL_ASSERT(item_count); + + /* + * To add items from the array to the list in the same order as + * the elements appear in the array, we add them starting with + * the last one first. Locate the last item. + */ + p_item = (cl_list_item_t *) ((uint8_t *) p_array + + (item_size * (item_count - 1))); + + /* Continue to add all items to the list. */ + while (item_count--) { + cl_qlist_insert_head(p_list, p_item); + + /* Get the next object to add to the list. */ + p_item = (cl_list_item_t *) ((uint8_t *) p_item - item_size); + } +} + +void +cl_qlist_insert_array_tail(IN cl_qlist_t * const p_list, + IN cl_list_item_t * const p_array, + IN uint32_t item_count, IN const uint32_t item_size) +{ + cl_list_item_t *p_item; + + CL_ASSERT(p_list); + CL_ASSERT(p_list->state == CL_INITIALIZED); + CL_ASSERT(p_array); + CL_ASSERT(item_size >= sizeof(cl_list_item_t)); + CL_ASSERT(item_count); + + /* Set the first item to add to the list. */ + p_item = p_array; + + /* Continue to add all items to the list. */ + while (item_count--) { + cl_qlist_insert_tail(p_list, p_item); + + /* Get the next object to add to the list. */ + p_item = (cl_list_item_t *) ((uint8_t *) p_item + item_size); + } +} + +void +cl_qlist_insert_list_head(IN cl_qlist_t * const p_dest_list, + IN cl_qlist_t * const p_src_list) +{ +#if defined( _DEBUG_ ) + cl_list_item_t *p_item; +#endif + + CL_ASSERT(p_dest_list); + CL_ASSERT(p_src_list); + CL_ASSERT(p_dest_list->state == CL_INITIALIZED); + CL_ASSERT(p_src_list->state == CL_INITIALIZED); + + /* + * Is the src list empty? + * We must have this check here for code below to work. + */ + if (cl_is_qlist_empty(p_src_list)) + return; + +#if defined( _DEBUG_ ) + /* Check that all items in the source list belong there. */ + p_item = cl_qlist_head(p_src_list); + while (p_item != cl_qlist_end(p_src_list)) { + /* All list items in the source list must point to it. */ + CL_ASSERT(p_item->p_list == p_src_list); + /* Point them all to the destination list. */ + p_item->p_list = p_dest_list; + p_item = cl_qlist_next(p_item); + } +#endif + + /* Chain the destination list to the tail of the source list. */ + cl_qlist_tail(p_src_list)->p_next = cl_qlist_head(p_dest_list); + cl_qlist_head(p_dest_list)->p_prev = cl_qlist_tail(p_src_list); + + /* + * Update the head of the destination list to the head of + * the source list. + */ + p_dest_list->end.p_next = cl_qlist_head(p_src_list); + cl_qlist_head(p_src_list)->p_prev = &p_dest_list->end; + + /* + * Update the count of the destination to reflect the source items having + * been added. + */ + p_dest_list->count += p_src_list->count; + + /* Update source list to reflect being empty. */ + __cl_qlist_reset(p_src_list); +} + +void +cl_qlist_insert_list_tail(IN cl_qlist_t * const p_dest_list, + IN cl_qlist_t * const p_src_list) +{ +#if defined( _DEBUG_ ) + cl_list_item_t *p_item; +#endif + + CL_ASSERT(p_dest_list); + CL_ASSERT(p_src_list); + CL_ASSERT(p_dest_list->state == CL_INITIALIZED); + CL_ASSERT(p_src_list->state == CL_INITIALIZED); + + /* + * Is the src list empty? + * We must have this check here for code below to work. + */ + if (cl_is_qlist_empty(p_src_list)) + return; + +#if defined( _DEBUG_ ) + /* Check that all items in the source list belong there. */ + p_item = cl_qlist_head(p_src_list); + while (p_item != cl_qlist_end(p_src_list)) { + /* All list items in the source list must point to it. */ + CL_ASSERT(p_item->p_list == p_src_list); + /* Point them all to the destination list. */ + p_item->p_list = p_dest_list; + p_item = cl_qlist_next(p_item); + } +#endif + + /* Chain the source list to the tail of the destination list. */ + cl_qlist_tail(p_dest_list)->p_next = cl_qlist_head(p_src_list); + cl_qlist_head(p_src_list)->p_prev = cl_qlist_tail(p_dest_list); + + /* + * Update the tail of the destination list to the tail of + * the source list. + */ + p_dest_list->end.p_prev = cl_qlist_tail(p_src_list); + cl_qlist_tail(p_src_list)->p_next = &p_dest_list->end; + + /* + * Update the count of the destination to reflect the source items having + * been added. + */ + p_dest_list->count += p_src_list->count; + + /* Update source list to reflect being empty. */ + __cl_qlist_reset(p_src_list); +} + +boolean_t +cl_is_item_in_qlist(IN const cl_qlist_t * const p_list, + IN const cl_list_item_t * const p_list_item) +{ + const cl_list_item_t *p_temp; + + CL_ASSERT(p_list); + CL_ASSERT(p_list_item); + CL_ASSERT(p_list->state == CL_INITIALIZED); + + /* Traverse looking for a match */ + p_temp = cl_qlist_head(p_list); + while (p_temp != cl_qlist_end(p_list)) { + if (p_temp == p_list_item) { + CL_ASSERT(p_list_item->p_list == p_list); + return (TRUE); + } + + p_temp = cl_qlist_next(p_temp); + } + + return (FALSE); +} + +cl_list_item_t *cl_qlist_find_next(IN const cl_qlist_t * const p_list, + IN const cl_list_item_t * const p_list_item, + IN cl_pfn_qlist_find_t pfn_func, + IN const void *const context) +{ + cl_list_item_t *p_found_item; + + CL_ASSERT(p_list); + CL_ASSERT(p_list->state == CL_INITIALIZED); + CL_ASSERT(p_list_item); + CL_ASSERT(p_list_item->p_list == p_list); + CL_ASSERT(pfn_func); + + p_found_item = cl_qlist_next(p_list_item); + + /* The user provided a compare function */ + while (p_found_item != cl_qlist_end(p_list)) { + CL_ASSERT(p_found_item->p_list == p_list); + + if (pfn_func(p_found_item, (void *)context) == CL_SUCCESS) + break; + + p_found_item = cl_qlist_next(p_found_item); + } + + /* No match */ + return (p_found_item); +} + +cl_list_item_t *cl_qlist_find_prev(IN const cl_qlist_t * const p_list, + IN const cl_list_item_t * const p_list_item, + IN cl_pfn_qlist_find_t pfn_func, + IN const void *const context) +{ + cl_list_item_t *p_found_item; + + CL_ASSERT(p_list); + CL_ASSERT(p_list->state == CL_INITIALIZED); + CL_ASSERT(p_list_item); + CL_ASSERT(p_list_item->p_list == p_list); + CL_ASSERT(pfn_func); + + p_found_item = cl_qlist_prev(p_list_item); + + /* The user provided a compare function */ + while (p_found_item != cl_qlist_end(p_list)) { + CL_ASSERT(p_found_item->p_list == p_list); + + if (pfn_func(p_found_item, (void *)context) == CL_SUCCESS) + break; + + p_found_item = cl_qlist_prev(p_found_item); + } + + /* No match */ + return (p_found_item); +} + +void +cl_qlist_apply_func(IN const cl_qlist_t * const p_list, + IN cl_pfn_qlist_apply_t pfn_func, + IN const void *const context) +{ + cl_list_item_t *p_list_item; + + /* Note that context can have any arbitrary value. */ + CL_ASSERT(p_list); + CL_ASSERT(p_list->state == CL_INITIALIZED); + CL_ASSERT(pfn_func); + + p_list_item = cl_qlist_head(p_list); + while (p_list_item != cl_qlist_end(p_list)) { + pfn_func(p_list_item, (void *)context); + p_list_item = cl_qlist_next(p_list_item); + } +} + +void +cl_qlist_move_items(IN cl_qlist_t * const p_src_list, + IN cl_qlist_t * const p_dest_list, + IN cl_pfn_qlist_find_t pfn_func, + IN const void *const context) +{ + cl_list_item_t *p_current_item, *p_next; + + CL_ASSERT(p_src_list); + CL_ASSERT(p_dest_list); + CL_ASSERT(p_src_list->state == CL_INITIALIZED); + CL_ASSERT(p_dest_list->state == CL_INITIALIZED); + CL_ASSERT(pfn_func); + + p_current_item = cl_qlist_head(p_src_list); + + while (p_current_item != cl_qlist_end(p_src_list)) { + /* Before we do anything, get a pointer to the next item. */ + p_next = cl_qlist_next(p_current_item); + + if (pfn_func(p_current_item, (void *)context) == CL_SUCCESS) { + /* Move the item from one list to the other. */ + cl_qlist_remove_item(p_src_list, p_current_item); + cl_qlist_insert_tail(p_dest_list, p_current_item); + } + p_current_item = p_next; + } +} + +/****************************************************************************** +******************************************************************************* +************** ************ +************** IMPLEMENTATION OF LIST ************ +************** ************ +******************************************************************************* +******************************************************************************/ +void cl_list_construct(IN cl_list_t * const p_list) +{ + CL_ASSERT(p_list); + + cl_qpool_construct(&p_list->list_item_pool); +} + +cl_status_t cl_list_init(IN cl_list_t * const p_list, IN const size_t min_items) +{ + uint32_t grow_size; + + CL_ASSERT(p_list); + cl_qlist_init(&p_list->list); + + /* + * We will grow by min_items/8 items at a time, with a minimum of + * FREE_ITEM_GROW_SIZE. + */ + grow_size = (uint32_t) min_items >> 3; + if (grow_size < FREE_ITEM_GROW_SIZE) + grow_size = FREE_ITEM_GROW_SIZE; + + /* Initialize the pool of list items. */ + return (cl_qpool_init(&p_list->list_item_pool, min_items, 0, grow_size, + sizeof(cl_pool_obj_t), NULL, NULL, NULL)); +} + +void cl_list_destroy(IN cl_list_t * const p_list) +{ + CL_ASSERT(p_list); + + cl_qpool_destroy(&p_list->list_item_pool); +} + +static cl_status_t +cl_list_find_cb(IN const cl_list_item_t * const p_list_item, + IN void *const context) +{ + CL_ASSERT(p_list_item); + + if (cl_list_obj(p_list_item) == context) + return (CL_SUCCESS); + + return (CL_NOT_FOUND); +} + +cl_status_t +cl_list_remove_object(IN cl_list_t * const p_list, + IN const void *const p_object) +{ + cl_list_item_t *p_list_item; + + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + + /* find the item in question */ + p_list_item = + cl_qlist_find_from_head(&p_list->list, cl_list_find_cb, p_object); + if (p_list_item != cl_qlist_end(&p_list->list)) { + /* remove this item */ + cl_qlist_remove_item(&p_list->list, p_list_item); + cl_qpool_put(&p_list->list_item_pool, + (cl_pool_item_t *) p_list_item); + return (CL_SUCCESS); + } + return (CL_NOT_FOUND); +} + +boolean_t +cl_is_object_in_list(IN const cl_list_t * const p_list, + IN const void *const p_object) +{ + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + + return (cl_qlist_find_from_head + (&p_list->list, cl_list_find_cb, p_object) + != cl_qlist_end(&p_list->list)); +} + +cl_status_t +cl_list_insert_array_head(IN cl_list_t * const p_list, + IN const void *const p_array, + IN uint32_t item_count, IN const uint32_t item_size) +{ + cl_status_t status; + void *p_object; + + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + CL_ASSERT(p_array); + CL_ASSERT(item_size); + CL_ASSERT(item_count); + + /* + * To add items from the array to the list in the same order as + * the elements appear in the array, we add them starting with + * the last one first. Locate the last item. + */ + p_object = ((uint8_t *) p_array + (item_size * (item_count - 1))); + + /* Continue to add all items to the list. */ + while (item_count--) { + status = cl_list_insert_head(p_list, p_object); + if (status != CL_SUCCESS) { + /* Remove all items that have been inserted. */ + while (item_count++ < item_count) + cl_list_remove_head(p_list); + return (status); + } + + /* Get the next object to add to the list. */ + p_object = ((uint8_t *) p_object - item_size); + } + + return (CL_SUCCESS); +} + +cl_status_t +cl_list_insert_array_tail(IN cl_list_t * const p_list, + IN const void *const p_array, + IN uint32_t item_count, IN const uint32_t item_size) +{ + cl_status_t status; + void *p_object; + + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + CL_ASSERT(p_array); + CL_ASSERT(item_size); + CL_ASSERT(item_count); + + /* Set the first item to add to the list. */ + p_object = (void *)p_array; + + /* Continue to add all items to the list. */ + while (item_count--) { + status = cl_list_insert_tail(p_list, p_object); + if (status != CL_SUCCESS) { + /* Remove all items that have been inserted. */ + while (item_count++ < item_count) + cl_list_remove_tail(p_list); + return (status); + } + + /* Get the next object to add to the list. */ + p_object = ((uint8_t *) p_object + item_size); + } + + return (CL_SUCCESS); +} + +cl_list_iterator_t +cl_list_find_from_head(IN const cl_list_t * const p_list, + IN cl_pfn_list_find_t pfn_func, + IN const void *const context) +{ + cl_status_t status; + cl_list_iterator_t itor; + + /* Note that context can have any arbitrary value. */ + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + CL_ASSERT(pfn_func); + + itor = cl_list_head(p_list); + + while (itor != cl_list_end(p_list)) { + status = pfn_func(cl_list_obj(itor), (void *)context); + if (status == CL_SUCCESS) + break; + + itor = cl_list_next(itor); + } + + /* no match */ + return (itor); +} + +cl_list_iterator_t +cl_list_find_from_tail(IN const cl_list_t * const p_list, + IN cl_pfn_list_find_t pfn_func, + IN const void *const context) +{ + cl_status_t status; + cl_list_iterator_t itor; + + /* Note that context can have any arbitrary value. */ + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + CL_ASSERT(pfn_func); + + itor = cl_list_tail(p_list); + + while (itor != cl_list_end(p_list)) { + status = pfn_func(cl_list_obj(itor), (void *)context); + if (status == CL_SUCCESS) + break; + + itor = cl_list_prev(itor); + } + + /* no match */ + return (itor); +} + +void +cl_list_apply_func(IN const cl_list_t * const p_list, + IN cl_pfn_list_apply_t pfn_func, + IN const void *const context) +{ + cl_list_iterator_t itor; + + /* Note that context can have any arbitrary value. */ + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + CL_ASSERT(pfn_func); + + itor = cl_list_head(p_list); + + while (itor != cl_list_end(p_list)) { + pfn_func(cl_list_obj(itor), (void *)context); + + itor = cl_list_next(itor); + } +} diff --git a/contrib/ofed/management/opensm/complib/cl_log.c b/contrib/ofed/management/opensm/complib/cl_log.c new file mode 100644 index 000000000000..a2a13727e941 --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_log.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifdef __WIN__ +#pragma warning(disable : 4996) +#endif + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/* Maximum number of bytes that can be logged. */ +#define CL_MAX_LOG_DATA (256) + +/* + * Size of the character buffer to allow logging the above + * number of bytes. A space is added after every DWORD, and + * a new line is added after 8 DWORDS (for a line length less than 80). + */ +#define CL_LOG_DATA_SIZE (CL_MAX_LOG_DATA + (CL_MAX_LOG_DATA/4)) + +void +cl_log_event(IN const char *const name, + IN const cl_log_type_t type, + IN const char *const message, + IN const void *const p_data OPTIONAL, IN const uint32_t data_len) +{ + int priority, i; + char data[CL_LOG_DATA_SIZE]; + char *p_buf; + uint8_t *p_int_data = (uint8_t *) p_data; + + CL_ASSERT(name); + CL_ASSERT(message); + + openlog(name, LOG_NDELAY | LOG_PID, LOG_USER); + switch (type) { + case CL_LOG_ERROR: + priority = LOG_ERR; + break; + + case CL_LOG_WARN: + priority = LOG_WARNING; + break; + + case CL_LOG_INFO: + default: + priority = LOG_INFO; + break; + } + + if (p_data) { + CL_ASSERT(data_len); + if (data_len < CL_MAX_LOG_DATA) { + p_buf = data; + /* Format the data into ASCII. */ + for (i = 0; i < data_len; i++) { + sprintf(p_buf, "%02x", *p_int_data++); + p_buf += 2; + + /* Add line break after 8 DWORDS. */ + if (i % 32) { + sprintf(p_buf++, "\n"); + continue; + } + + /* Add a space between DWORDS. */ + if (i % 4) + sprintf(p_buf++, " "); + } + syslog(priority, "%s data:\n%s\n", message, p_buf); + } else { + /* The data portion is too large to log. */ + cl_msg_out + ("cl_log() - WARNING: data too large to log.\n"); + syslog(priority, "%s\n", message); + } + } else { + syslog(priority, "%s\n", message); + } + closelog(); +} diff --git a/contrib/ofed/management/opensm/complib/cl_map.c b/contrib/ofed/management/opensm/complib/cl_map.c new file mode 100644 index 000000000000..c0e44beac857 --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_map.c @@ -0,0 +1,1636 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of quick map, a binary tree where the caller always + * provides all necessary storage. + * + */ + +/***************************************************************************** +* +* Map +* +* Map is an associative array. By providing a key, the caller can retrieve +* an object from the map. All objects in the map have an associated key, +* as specified by the caller when the object was inserted into the map. +* In addition to random access, the caller can traverse the map much like +* a linked list, either forwards from the first object or backwards from +* the last object. The objects in the map are always traversed in +* order since the nodes are stored sorted. +* +* This implementation of Map uses a red black tree verified against +* Cormen-Leiserson-Rivest text, McGraw-Hill Edition, fourteenth +* printing, 1994. +* +*****************************************************************************/ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +/****************************************************************************** +******************************************************************************* +************** ************ +************** IMPLEMENTATION OF QUICK MAP ************ +************** ************ +******************************************************************************* +******************************************************************************/ + +/* + * Get the root. + */ +static inline cl_map_item_t *__cl_map_root(IN const cl_qmap_t * const p_map) +{ + CL_ASSERT(p_map); + return (p_map->root.p_left); +} + +/* + * Returns whether a given item is on the left of its parent. + */ +static boolean_t __cl_map_is_left_child(IN const cl_map_item_t * const p_item) +{ + CL_ASSERT(p_item); + CL_ASSERT(p_item->p_up); + CL_ASSERT(p_item->p_up != p_item); + + return (p_item->p_up->p_left == p_item); +} + +/* + * Retrieve the pointer to the parent's pointer to an item. + */ +static cl_map_item_t **__cl_map_get_parent_ptr_to_item(IN cl_map_item_t * + const p_item) +{ + CL_ASSERT(p_item); + CL_ASSERT(p_item->p_up); + CL_ASSERT(p_item->p_up != p_item); + + if (__cl_map_is_left_child(p_item)) + return (&p_item->p_up->p_left); + + CL_ASSERT(p_item->p_up->p_right == p_item); + return (&p_item->p_up->p_right); +} + +/* + * Rotate a node to the left. This rotation affects the least number of links + * between nodes and brings the level of C up by one while increasing the depth + * of A one. Note that the links to/from W, X, Y, and Z are not affected. + * + * R R + * | | + * A C + * / \ / \ + * W C A Z + * / \ / \ + * B Z W B + * / \ / \ + * X Y X Y + */ +static void +__cl_map_rot_left(IN cl_qmap_t * const p_map, IN cl_map_item_t * const p_item) +{ + cl_map_item_t **pp_root; + + CL_ASSERT(p_map); + CL_ASSERT(p_item); + CL_ASSERT(p_item->p_right != &p_map->nil); + + pp_root = __cl_map_get_parent_ptr_to_item(p_item); + + /* Point R to C instead of A. */ + *pp_root = p_item->p_right; + /* Set C's parent to R. */ + (*pp_root)->p_up = p_item->p_up; + + /* Set A's right to B */ + p_item->p_right = (*pp_root)->p_left; + /* + * Set B's parent to A. We trap for B being NIL since the + * caller may depend on NIL not changing. + */ + if ((*pp_root)->p_left != &p_map->nil) + (*pp_root)->p_left->p_up = p_item; + + /* Set C's left to A. */ + (*pp_root)->p_left = p_item; + /* Set A's parent to C. */ + p_item->p_up = *pp_root; +} + +/* + * Rotate a node to the right. This rotation affects the least number of links + * between nodes and brings the level of A up by one while increasing the depth + * of C one. Note that the links to/from W, X, Y, and Z are not affected. + * + * R R + * | | + * C A + * / \ / \ + * A Z W C + * / \ / \ + * W B B Z + * / \ / \ + * X Y X Y + */ +static void +__cl_map_rot_right(IN cl_qmap_t * const p_map, IN cl_map_item_t * const p_item) +{ + cl_map_item_t **pp_root; + + CL_ASSERT(p_map); + CL_ASSERT(p_item); + CL_ASSERT(p_item->p_left != &p_map->nil); + + /* Point R to A instead of C. */ + pp_root = __cl_map_get_parent_ptr_to_item(p_item); + (*pp_root) = p_item->p_left; + /* Set A's parent to R. */ + (*pp_root)->p_up = p_item->p_up; + + /* Set C's left to B */ + p_item->p_left = (*pp_root)->p_right; + /* + * Set B's parent to C. We trap for B being NIL since the + * caller may depend on NIL not changing. + */ + if ((*pp_root)->p_right != &p_map->nil) + (*pp_root)->p_right->p_up = p_item; + + /* Set A's right to C. */ + (*pp_root)->p_right = p_item; + /* Set C's parent to A. */ + p_item->p_up = *pp_root; +} + +void cl_qmap_init(IN cl_qmap_t * const p_map) +{ + CL_ASSERT(p_map); + + memset(p_map, 0, sizeof(cl_qmap_t)); + + /* special setup for the root node */ + p_map->root.p_up = &p_map->root; + p_map->root.p_left = &p_map->nil; + p_map->root.p_right = &p_map->nil; + p_map->root.color = CL_MAP_BLACK; + + /* Setup the node used as terminator for all leaves. */ + p_map->nil.p_up = &p_map->nil; + p_map->nil.p_left = &p_map->nil; + p_map->nil.p_right = &p_map->nil; + p_map->nil.color = CL_MAP_BLACK; + + p_map->state = CL_INITIALIZED; + + cl_qmap_remove_all(p_map); +} + +cl_map_item_t *cl_qmap_get(IN const cl_qmap_t * const p_map, + IN const uint64_t key) +{ + cl_map_item_t *p_item; + + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + + p_item = __cl_map_root(p_map); + + while (p_item != &p_map->nil) { + if (key == p_item->key) + break; /* just right */ + + if (key < p_item->key) + p_item = p_item->p_left; /* too small */ + else + p_item = p_item->p_right; /* too big */ + } + + return (p_item); +} + +cl_map_item_t *cl_qmap_get_next(IN const cl_qmap_t * const p_map, + IN const uint64_t key) +{ + cl_map_item_t *p_item; + cl_map_item_t *p_item_found; + + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + + p_item = __cl_map_root(p_map); + p_item_found = (cl_map_item_t *) & p_map->nil; + + while (p_item != &p_map->nil) { + if (key < p_item->key) { + p_item_found = p_item; + p_item = p_item->p_left; + } else { + p_item = p_item->p_right; + } + } + + return (p_item_found); +} + +void +cl_qmap_apply_func(IN const cl_qmap_t * const p_map, + IN cl_pfn_qmap_apply_t pfn_func, + IN const void *const context) +{ + cl_map_item_t *p_map_item; + + /* Note that context can have any arbitrary value. */ + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + CL_ASSERT(pfn_func); + + p_map_item = cl_qmap_head(p_map); + while (p_map_item != cl_qmap_end(p_map)) { + pfn_func(p_map_item, (void *)context); + p_map_item = cl_qmap_next(p_map_item); + } +} + +/* + * Balance a tree starting at a given item back to the root. + */ +static void +__cl_map_ins_bal(IN cl_qmap_t * const p_map, IN cl_map_item_t * p_item) +{ + cl_map_item_t *p_grand_uncle; + + CL_ASSERT(p_map); + CL_ASSERT(p_item); + CL_ASSERT(p_item != &p_map->root); + + while (p_item->p_up->color == CL_MAP_RED) { + if (__cl_map_is_left_child(p_item->p_up)) { + p_grand_uncle = p_item->p_up->p_up->p_right; + CL_ASSERT(p_grand_uncle); + if (p_grand_uncle->color == CL_MAP_RED) { + p_grand_uncle->color = CL_MAP_BLACK; + p_item->p_up->color = CL_MAP_BLACK; + p_item->p_up->p_up->color = CL_MAP_RED; + p_item = p_item->p_up->p_up; + continue; + } + + if (!__cl_map_is_left_child(p_item)) { + p_item = p_item->p_up; + __cl_map_rot_left(p_map, p_item); + } + p_item->p_up->color = CL_MAP_BLACK; + p_item->p_up->p_up->color = CL_MAP_RED; + __cl_map_rot_right(p_map, p_item->p_up->p_up); + } else { + p_grand_uncle = p_item->p_up->p_up->p_left; + CL_ASSERT(p_grand_uncle); + if (p_grand_uncle->color == CL_MAP_RED) { + p_grand_uncle->color = CL_MAP_BLACK; + p_item->p_up->color = CL_MAP_BLACK; + p_item->p_up->p_up->color = CL_MAP_RED; + p_item = p_item->p_up->p_up; + continue; + } + + if (__cl_map_is_left_child(p_item)) { + p_item = p_item->p_up; + __cl_map_rot_right(p_map, p_item); + } + p_item->p_up->color = CL_MAP_BLACK; + p_item->p_up->p_up->color = CL_MAP_RED; + __cl_map_rot_left(p_map, p_item->p_up->p_up); + } + } +} + +cl_map_item_t *cl_qmap_insert(IN cl_qmap_t * const p_map, + IN const uint64_t key, + IN cl_map_item_t * const p_item) +{ + cl_map_item_t *p_insert_at, *p_comp_item; + + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + CL_ASSERT(p_item); + CL_ASSERT(p_map->root.p_up == &p_map->root); + CL_ASSERT(p_map->root.color != CL_MAP_RED); + CL_ASSERT(p_map->nil.color != CL_MAP_RED); + + p_item->p_left = &p_map->nil; + p_item->p_right = &p_map->nil; + p_item->key = key; + p_item->color = CL_MAP_RED; + + /* Find the insertion location. */ + p_insert_at = &p_map->root; + p_comp_item = __cl_map_root(p_map); + + while (p_comp_item != &p_map->nil) { + p_insert_at = p_comp_item; + + if (key == p_insert_at->key) + return (p_insert_at); + + /* Traverse the tree until the correct insertion point is found. */ + if (key < p_insert_at->key) + p_comp_item = p_insert_at->p_left; + else + p_comp_item = p_insert_at->p_right; + } + + CL_ASSERT(p_insert_at != &p_map->nil); + CL_ASSERT(p_comp_item == &p_map->nil); + /* Insert the item. */ + if (p_insert_at == &p_map->root) { + p_insert_at->p_left = p_item; + /* + * Primitive insert places the new item in front of + * the existing item. + */ + __cl_primitive_insert(&p_map->nil.pool_item.list_item, + &p_item->pool_item.list_item); + } else if (key < p_insert_at->key) { + p_insert_at->p_left = p_item; + /* + * Primitive insert places the new item in front of + * the existing item. + */ + __cl_primitive_insert(&p_insert_at->pool_item.list_item, + &p_item->pool_item.list_item); + } else { + p_insert_at->p_right = p_item; + /* + * Primitive insert places the new item in front of + * the existing item. + */ + __cl_primitive_insert(p_insert_at->pool_item.list_item.p_next, + &p_item->pool_item.list_item); + } + /* Increase the count. */ + p_map->count++; + + p_item->p_up = p_insert_at; + + /* + * We have added depth to this section of the tree. + * Rebalance as necessary as we retrace our path through the tree + * and update colors. + */ + __cl_map_ins_bal(p_map, p_item); + + __cl_map_root(p_map)->color = CL_MAP_BLACK; + + /* + * Note that it is not necessary to re-color the nil node black because all + * red color assignments are made via the p_up pointer, and nil is never + * set as the value of a p_up pointer. + */ + +#ifdef _DEBUG_ + /* Set the pointer to the map in the map item for consistency checking. */ + p_item->p_map = p_map; +#endif + + return (p_item); +} + +static void +__cl_map_del_bal(IN cl_qmap_t * const p_map, IN cl_map_item_t * p_item) +{ + cl_map_item_t *p_uncle; + + while ((p_item->color != CL_MAP_RED) && (p_item->p_up != &p_map->root)) { + if (__cl_map_is_left_child(p_item)) { + p_uncle = p_item->p_up->p_right; + + if (p_uncle->color == CL_MAP_RED) { + p_uncle->color = CL_MAP_BLACK; + p_item->p_up->color = CL_MAP_RED; + __cl_map_rot_left(p_map, p_item->p_up); + p_uncle = p_item->p_up->p_right; + } + + if (p_uncle->p_right->color != CL_MAP_RED) { + if (p_uncle->p_left->color != CL_MAP_RED) { + p_uncle->color = CL_MAP_RED; + p_item = p_item->p_up; + continue; + } + + p_uncle->p_left->color = CL_MAP_BLACK; + p_uncle->color = CL_MAP_RED; + __cl_map_rot_right(p_map, p_uncle); + p_uncle = p_item->p_up->p_right; + } + p_uncle->color = p_item->p_up->color; + p_item->p_up->color = CL_MAP_BLACK; + p_uncle->p_right->color = CL_MAP_BLACK; + __cl_map_rot_left(p_map, p_item->p_up); + break; + } else { + p_uncle = p_item->p_up->p_left; + + if (p_uncle->color == CL_MAP_RED) { + p_uncle->color = CL_MAP_BLACK; + p_item->p_up->color = CL_MAP_RED; + __cl_map_rot_right(p_map, p_item->p_up); + p_uncle = p_item->p_up->p_left; + } + + if (p_uncle->p_left->color != CL_MAP_RED) { + if (p_uncle->p_right->color != CL_MAP_RED) { + p_uncle->color = CL_MAP_RED; + p_item = p_item->p_up; + continue; + } + + p_uncle->p_right->color = CL_MAP_BLACK; + p_uncle->color = CL_MAP_RED; + __cl_map_rot_left(p_map, p_uncle); + p_uncle = p_item->p_up->p_left; + } + p_uncle->color = p_item->p_up->color; + p_item->p_up->color = CL_MAP_BLACK; + p_uncle->p_left->color = CL_MAP_BLACK; + __cl_map_rot_right(p_map, p_item->p_up); + break; + } + } + p_item->color = CL_MAP_BLACK; +} + +void +cl_qmap_remove_item(IN cl_qmap_t * const p_map, IN cl_map_item_t * const p_item) +{ + cl_map_item_t *p_child, *p_del_item; + + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + CL_ASSERT(p_item); + + if (p_item == cl_qmap_end(p_map)) + return; + + /* must be checked after comparing to cl_qmap_end, since + the end is not a valid item. */ + CL_ASSERT(p_item->p_map == p_map); + + if ((p_item->p_right == &p_map->nil) || (p_item->p_left == &p_map->nil)) { + /* The item being removed has children on at most on side. */ + p_del_item = p_item; + } else { + /* + * The item being removed has children on both side. + * We select the item that will replace it. After removing + * the substitute item and rebalancing, the tree will have the + * correct topology. Exchanging the substitute for the item + * will finalize the removal. + */ + p_del_item = cl_qmap_next(p_item); + CL_ASSERT(p_del_item != &p_map->nil); + } + + /* Remove the item from the list. */ + __cl_primitive_remove(&p_item->pool_item.list_item); + /* Decrement the item count. */ + p_map->count--; + + /* Get the pointer to the new root's child, if any. */ + if (p_del_item->p_left != &p_map->nil) + p_child = p_del_item->p_left; + else + p_child = p_del_item->p_right; + + /* + * This assignment may modify the parent pointer of the nil node. + * This is inconsequential. + */ + p_child->p_up = p_del_item->p_up; + (*__cl_map_get_parent_ptr_to_item(p_del_item)) = p_child; + + if (p_del_item->color != CL_MAP_RED) + __cl_map_del_bal(p_map, p_child); + + /* + * Note that the splicing done below does not need to occur before + * the tree is balanced, since the actual topology changes are made by the + * preceding code. The topology is preserved by the color assignment made + * below (reader should be reminded that p_del_item == p_item in some cases). + */ + if (p_del_item != p_item) { + /* + * Finalize the removal of the specified item by exchanging it with + * the substitute which we removed above. + */ + p_del_item->p_up = p_item->p_up; + p_del_item->p_left = p_item->p_left; + p_del_item->p_right = p_item->p_right; + (*__cl_map_get_parent_ptr_to_item(p_item)) = p_del_item; + p_item->p_right->p_up = p_del_item; + p_item->p_left->p_up = p_del_item; + p_del_item->color = p_item->color; + } + + CL_ASSERT(p_map->nil.color != CL_MAP_RED); + +#ifdef _DEBUG_ + /* Clear the pointer to the map since the item has been removed. */ + p_item->p_map = NULL; +#endif +} + +cl_map_item_t *cl_qmap_remove(IN cl_qmap_t * const p_map, IN const uint64_t key) +{ + cl_map_item_t *p_item; + + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + + /* Seek the node with the specified key */ + p_item = cl_qmap_get(p_map, key); + + cl_qmap_remove_item(p_map, p_item); + + return (p_item); +} + +void +cl_qmap_merge(OUT cl_qmap_t * const p_dest_map, + IN OUT cl_qmap_t * const p_src_map) +{ + cl_map_item_t *p_item, *p_item2, *p_next; + + CL_ASSERT(p_dest_map); + CL_ASSERT(p_src_map); + + p_item = cl_qmap_head(p_src_map); + + while (p_item != cl_qmap_end(p_src_map)) { + p_next = cl_qmap_next(p_item); + + /* Remove the item from its current map. */ + cl_qmap_remove_item(p_src_map, p_item); + /* Insert the item into the destination map. */ + p_item2 = + cl_qmap_insert(p_dest_map, cl_qmap_key(p_item), p_item); + /* Check that the item was successfully inserted. */ + if (p_item2 != p_item) { + /* Put the item in back in the source map. */ + p_item2 = + cl_qmap_insert(p_src_map, cl_qmap_key(p_item), + p_item); + CL_ASSERT(p_item2 == p_item); + } + p_item = p_next; + } +} + +static void +__cl_qmap_delta_move(IN OUT cl_qmap_t * const p_dest, + IN OUT cl_qmap_t * const p_src, + IN OUT cl_map_item_t ** const pp_item) +{ + cl_map_item_t *p_temp, *p_next; + + /* + * Get the next item so that we can ensure that pp_item points to + * a valid item upon return from the function. + */ + p_next = cl_qmap_next(*pp_item); + /* Move the old item from its current map the the old map. */ + cl_qmap_remove_item(p_src, *pp_item); + p_temp = cl_qmap_insert(p_dest, cl_qmap_key(*pp_item), *pp_item); + /* We should never have duplicates. */ + CL_ASSERT(p_temp == *pp_item); + /* Point pp_item to a valid item in the source map. */ + (*pp_item) = p_next; +} + +void +cl_qmap_delta(IN OUT cl_qmap_t * const p_map1, + IN OUT cl_qmap_t * const p_map2, + OUT cl_qmap_t * const p_new, OUT cl_qmap_t * const p_old) +{ + cl_map_item_t *p_item1, *p_item2; + uint64_t key1, key2; + + CL_ASSERT(p_map1); + CL_ASSERT(p_map2); + CL_ASSERT(p_new); + CL_ASSERT(p_old); + CL_ASSERT(cl_is_qmap_empty(p_new)); + CL_ASSERT(cl_is_qmap_empty(p_old)); + + p_item1 = cl_qmap_head(p_map1); + p_item2 = cl_qmap_head(p_map2); + + while (p_item1 != cl_qmap_end(p_map1) && p_item2 != cl_qmap_end(p_map2)) { + key1 = cl_qmap_key(p_item1); + key2 = cl_qmap_key(p_item2); + if (key1 < key2) { + /* We found an old item. */ + __cl_qmap_delta_move(p_old, p_map1, &p_item1); + } else if (key1 > key2) { + /* We found a new item. */ + __cl_qmap_delta_move(p_new, p_map2, &p_item2); + } else { + /* Move both forward since they have the same key. */ + p_item1 = cl_qmap_next(p_item1); + p_item2 = cl_qmap_next(p_item2); + } + } + + /* Process the remainder if the end of either source map was reached. */ + while (p_item2 != cl_qmap_end(p_map2)) + __cl_qmap_delta_move(p_new, p_map2, &p_item2); + + while (p_item1 != cl_qmap_end(p_map1)) + __cl_qmap_delta_move(p_old, p_map1, &p_item1); +} + +/****************************************************************************** +******************************************************************************* +************** ************ +************** IMPLEMENTATION OF MAP ************ +************** ************ +******************************************************************************* +******************************************************************************/ + +#define MAP_GROW_SIZE 32 + +void cl_map_construct(IN cl_map_t * const p_map) +{ + CL_ASSERT(p_map); + + cl_qpool_construct(&p_map->pool); +} + +cl_status_t cl_map_init(IN cl_map_t * const p_map, IN const uint32_t min_items) +{ + uint32_t grow_size; + + CL_ASSERT(p_map); + + cl_qmap_init(&p_map->qmap); + + /* + * We will grow by min_items/8 items at a time, with a minimum of + * MAP_GROW_SIZE. + */ + grow_size = min_items >> 3; + if (grow_size < MAP_GROW_SIZE) + grow_size = MAP_GROW_SIZE; + + return (cl_qpool_init(&p_map->pool, min_items, 0, grow_size, + sizeof(cl_map_obj_t), NULL, NULL, NULL)); +} + +void cl_map_destroy(IN cl_map_t * const p_map) +{ + CL_ASSERT(p_map); + + cl_qpool_destroy(&p_map->pool); +} + +void *cl_map_insert(IN cl_map_t * const p_map, + IN const uint64_t key, IN const void *const p_object) +{ + cl_map_obj_t *p_map_obj, *p_obj_at_key; + + CL_ASSERT(p_map); + + p_map_obj = (cl_map_obj_t *) cl_qpool_get(&p_map->pool); + + if (!p_map_obj) + return (NULL); + + cl_qmap_set_obj(p_map_obj, p_object); + + p_obj_at_key = + (cl_map_obj_t *) cl_qmap_insert(&p_map->qmap, key, + &p_map_obj->item); + + /* Return the item to the pool if insertion failed. */ + if (p_obj_at_key != p_map_obj) + cl_qpool_put(&p_map->pool, &p_map_obj->item.pool_item); + + return (cl_qmap_obj(p_obj_at_key)); +} + +void *cl_map_get(IN const cl_map_t * const p_map, IN const uint64_t key) +{ + cl_map_item_t *p_item; + + CL_ASSERT(p_map); + + p_item = cl_qmap_get(&p_map->qmap, key); + + if (p_item == cl_qmap_end(&p_map->qmap)) + return (NULL); + + return (cl_qmap_obj(PARENT_STRUCT(p_item, cl_map_obj_t, item))); +} + +void *cl_map_get_next(IN const cl_map_t * const p_map, IN const uint64_t key) +{ + cl_map_item_t *p_item; + + CL_ASSERT(p_map); + + p_item = cl_qmap_get_next(&p_map->qmap, key); + + if (p_item == cl_qmap_end(&p_map->qmap)) + return (NULL); + + return (cl_qmap_obj(PARENT_STRUCT(p_item, cl_map_obj_t, item))); +} + +void +cl_map_remove_item(IN cl_map_t * const p_map, IN const cl_map_iterator_t itor) +{ + CL_ASSERT(itor->p_map == &p_map->qmap); + + if (itor == cl_map_end(p_map)) + return; + + cl_qmap_remove_item(&p_map->qmap, (cl_map_item_t *) itor); + cl_qpool_put(&p_map->pool, &((cl_map_item_t *) itor)->pool_item); +} + +void *cl_map_remove(IN cl_map_t * const p_map, IN const uint64_t key) +{ + cl_map_item_t *p_item; + void *p_obj; + + CL_ASSERT(p_map); + + p_item = cl_qmap_remove(&p_map->qmap, key); + + if (p_item == cl_qmap_end(&p_map->qmap)) + return (NULL); + + p_obj = cl_qmap_obj((cl_map_obj_t *) p_item); + cl_qpool_put(&p_map->pool, &p_item->pool_item); + + return (p_obj); +} + +void cl_map_remove_all(IN cl_map_t * const p_map) +{ + cl_map_item_t *p_item; + + CL_ASSERT(p_map); + + /* Return all map items to the pool. */ + while (!cl_is_qmap_empty(&p_map->qmap)) { + p_item = cl_qmap_head(&p_map->qmap); + cl_qmap_remove_item(&p_map->qmap, p_item); + cl_qpool_put(&p_map->pool, &p_item->pool_item); + + if (!cl_is_qmap_empty(&p_map->qmap)) { + p_item = cl_qmap_tail(&p_map->qmap); + cl_qmap_remove_item(&p_map->qmap, p_item); + cl_qpool_put(&p_map->pool, &p_item->pool_item); + } + } +} + +cl_status_t +cl_map_merge(OUT cl_map_t * const p_dest_map, IN OUT cl_map_t * const p_src_map) +{ + cl_status_t status = CL_SUCCESS; + cl_map_iterator_t itor, next; + uint64_t key; + void *p_obj, *p_obj2; + + CL_ASSERT(p_dest_map); + CL_ASSERT(p_src_map); + + itor = cl_map_head(p_src_map); + while (itor != cl_map_end(p_src_map)) { + next = cl_map_next(itor); + + p_obj = cl_map_obj(itor); + key = cl_map_key(itor); + + cl_map_remove_item(p_src_map, itor); + + /* Insert the object into the destination map. */ + p_obj2 = cl_map_insert(p_dest_map, key, p_obj); + /* Trap for failure. */ + if (p_obj != p_obj2) { + if (!p_obj2) + status = CL_INSUFFICIENT_MEMORY; + /* Put the object back in the source map. This must succeed. */ + p_obj2 = cl_map_insert(p_src_map, key, p_obj); + CL_ASSERT(p_obj == p_obj2); + /* If the failure was due to insufficient memory, return. */ + if (status != CL_SUCCESS) + return (status); + } + itor = next; + } + + return (CL_SUCCESS); +} + +static void +__cl_map_revert(IN OUT cl_map_t * const p_map1, + IN OUT cl_map_t * const p_map2, + IN OUT cl_map_t * const p_new, IN OUT cl_map_t * const p_old) +{ + cl_status_t status; + + /* Restore the initial state. */ + status = cl_map_merge(p_map1, p_old); + CL_ASSERT(status == CL_SUCCESS); + status = cl_map_merge(p_map2, p_new); + CL_ASSERT(status == CL_SUCCESS); +} + +static cl_status_t +__cl_map_delta_move(OUT cl_map_t * const p_dest, + IN OUT cl_map_t * const p_src, + IN OUT cl_map_iterator_t * const p_itor) +{ + cl_map_iterator_t next; + void *p_obj, *p_obj2; + uint64_t key; + + /* Get a valid iterator so we can continue the loop. */ + next = cl_map_next(*p_itor); + /* Get the pointer to the object for insertion. */ + p_obj = cl_map_obj(*p_itor); + /* Get the key for the object. */ + key = cl_map_key(*p_itor); + /* Move the object. */ + cl_map_remove_item(p_src, *p_itor); + p_obj2 = cl_map_insert(p_dest, key, p_obj); + /* Check for failure. We should never get a duplicate. */ + if (!p_obj2) { + p_obj2 = cl_map_insert(p_src, key, p_obj); + CL_ASSERT(p_obj2 == p_obj); + return (CL_INSUFFICIENT_MEMORY); + } + + /* We should never get a duplicate */ + CL_ASSERT(p_obj == p_obj2); + /* Update the iterator so that it is valid. */ + (*p_itor) = next; + + return (CL_SUCCESS); +} + +cl_status_t +cl_map_delta(IN OUT cl_map_t * const p_map1, + IN OUT cl_map_t * const p_map2, + OUT cl_map_t * const p_new, OUT cl_map_t * const p_old) +{ + cl_map_iterator_t itor1, itor2; + uint64_t key1, key2; + cl_status_t status; + + CL_ASSERT(p_map1); + CL_ASSERT(p_map2); + CL_ASSERT(p_new); + CL_ASSERT(p_old); + CL_ASSERT(cl_is_map_empty(p_new)); + CL_ASSERT(cl_is_map_empty(p_old)); + + itor1 = cl_map_head(p_map1); + itor2 = cl_map_head(p_map2); + + /* + * Note that the check is for the end, since duplicate items will remain + * in their respective maps. + */ + while (itor1 != cl_map_end(p_map1) && itor2 != cl_map_end(p_map2)) { + key1 = cl_map_key(itor1); + key2 = cl_map_key(itor2); + if (key1 < key2) { + status = __cl_map_delta_move(p_old, p_map1, &itor1); + /* Check for failure. */ + if (status != CL_SUCCESS) { + /* Restore the initial state. */ + __cl_map_revert(p_map1, p_map2, p_new, p_old); + /* Return the failure status. */ + return (status); + } + } else if (key1 > key2) { + status = __cl_map_delta_move(p_new, p_map2, &itor2); + if (status != CL_SUCCESS) { + /* Restore the initial state. */ + __cl_map_revert(p_map1, p_map2, p_new, p_old); + /* Return the failure status. */ + return (status); + } + } else { + /* Move both forward since they have the same key. */ + itor1 = cl_map_next(itor1); + itor2 = cl_map_next(itor2); + } + } + + /* Process the remainder if either source map is empty. */ + while (itor2 != cl_map_end(p_map2)) { + status = __cl_map_delta_move(p_new, p_map2, &itor2); + if (status != CL_SUCCESS) { + /* Restore the initial state. */ + __cl_map_revert(p_map1, p_map2, p_new, p_old); + /* Return the failure status. */ + return (status); + } + } + + while (itor1 != cl_map_end(p_map1)) { + status = __cl_map_delta_move(p_old, p_map1, &itor1); + if (status != CL_SUCCESS) { + /* Restore the initial state. */ + __cl_map_revert(p_map1, p_map2, p_new, p_old); + /* Return the failure status. */ + return (status); + } + } + + return (CL_SUCCESS); +} + +/****************************************************************************** +******************************************************************************* +************** ************ +************** IMPLEMENTATION OF FLEXI MAP ************ +************** ************ +******************************************************************************* +******************************************************************************/ + +/* + * Get the root. + */ +static inline cl_fmap_item_t *__cl_fmap_root(IN const cl_fmap_t * const p_map) +{ + CL_ASSERT(p_map); + return (p_map->root.p_left); +} + +/* + * Returns whether a given item is on the left of its parent. + */ +static boolean_t __cl_fmap_is_left_child(IN const cl_fmap_item_t * const p_item) +{ + CL_ASSERT(p_item); + CL_ASSERT(p_item->p_up); + CL_ASSERT(p_item->p_up != p_item); + + return (p_item->p_up->p_left == p_item); +} + +/* + * Retrieve the pointer to the parent's pointer to an item. + */ +static cl_fmap_item_t **__cl_fmap_get_parent_ptr_to_item(IN cl_fmap_item_t * + const p_item) +{ + CL_ASSERT(p_item); + CL_ASSERT(p_item->p_up); + CL_ASSERT(p_item->p_up != p_item); + + if (__cl_fmap_is_left_child(p_item)) + return (&p_item->p_up->p_left); + + CL_ASSERT(p_item->p_up->p_right == p_item); + return (&p_item->p_up->p_right); +} + +/* + * Rotate a node to the left. This rotation affects the least number of links + * between nodes and brings the level of C up by one while increasing the depth + * of A one. Note that the links to/from W, X, Y, and Z are not affected. + * + * R R + * | | + * A C + * / \ / \ + * W C A Z + * / \ / \ + * B Z W B + * / \ / \ + * X Y X Y + */ +static void +__cl_fmap_rot_left(IN cl_fmap_t * const p_map, IN cl_fmap_item_t * const p_item) +{ + cl_fmap_item_t **pp_root; + + CL_ASSERT(p_map); + CL_ASSERT(p_item); + CL_ASSERT(p_item->p_right != &p_map->nil); + + pp_root = __cl_fmap_get_parent_ptr_to_item(p_item); + + /* Point R to C instead of A. */ + *pp_root = p_item->p_right; + /* Set C's parent to R. */ + (*pp_root)->p_up = p_item->p_up; + + /* Set A's right to B */ + p_item->p_right = (*pp_root)->p_left; + /* + * Set B's parent to A. We trap for B being NIL since the + * caller may depend on NIL not changing. + */ + if ((*pp_root)->p_left != &p_map->nil) + (*pp_root)->p_left->p_up = p_item; + + /* Set C's left to A. */ + (*pp_root)->p_left = p_item; + /* Set A's parent to C. */ + p_item->p_up = *pp_root; +} + +/* + * Rotate a node to the right. This rotation affects the least number of links + * between nodes and brings the level of A up by one while increasing the depth + * of C one. Note that the links to/from W, X, Y, and Z are not affected. + * + * R R + * | | + * C A + * / \ / \ + * A Z W C + * / \ / \ + * W B B Z + * / \ / \ + * X Y X Y + */ +static void +__cl_fmap_rot_right(IN cl_fmap_t * const p_map, + IN cl_fmap_item_t * const p_item) +{ + cl_fmap_item_t **pp_root; + + CL_ASSERT(p_map); + CL_ASSERT(p_item); + CL_ASSERT(p_item->p_left != &p_map->nil); + + /* Point R to A instead of C. */ + pp_root = __cl_fmap_get_parent_ptr_to_item(p_item); + (*pp_root) = p_item->p_left; + /* Set A's parent to R. */ + (*pp_root)->p_up = p_item->p_up; + + /* Set C's left to B */ + p_item->p_left = (*pp_root)->p_right; + /* + * Set B's parent to C. We trap for B being NIL since the + * caller may depend on NIL not changing. + */ + if ((*pp_root)->p_right != &p_map->nil) + (*pp_root)->p_right->p_up = p_item; + + /* Set A's right to C. */ + (*pp_root)->p_right = p_item; + /* Set C's parent to A. */ + p_item->p_up = *pp_root; +} + +void cl_fmap_init(IN cl_fmap_t * const p_map, IN cl_pfn_fmap_cmp_t pfn_compare) +{ + CL_ASSERT(p_map); + CL_ASSERT(pfn_compare); + + memset(p_map, 0, sizeof(cl_fmap_t)); + + /* special setup for the root node */ + p_map->root.p_up = &p_map->root; + p_map->root.p_left = &p_map->nil; + p_map->root.p_right = &p_map->nil; + p_map->root.color = CL_MAP_BLACK; + + /* Setup the node used as terminator for all leaves. */ + p_map->nil.p_up = &p_map->nil; + p_map->nil.p_left = &p_map->nil; + p_map->nil.p_right = &p_map->nil; + p_map->nil.color = CL_MAP_BLACK; + + /* Store the compare function pointer. */ + p_map->pfn_compare = pfn_compare; + + p_map->state = CL_INITIALIZED; + + cl_fmap_remove_all(p_map); +} + +cl_fmap_item_t *cl_fmap_get(IN const cl_fmap_t * const p_map, + IN const void *const p_key) +{ + cl_fmap_item_t *p_item; + intn_t cmp; + + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + + p_item = __cl_fmap_root(p_map); + + while (p_item != &p_map->nil) { + cmp = p_map->pfn_compare(p_key, p_item->p_key); + + if (!cmp) + break; /* just right */ + + if (cmp < 0) + p_item = p_item->p_left; /* too small */ + else + p_item = p_item->p_right; /* too big */ + } + + return (p_item); +} + +cl_fmap_item_t *cl_fmap_get_next(IN const cl_fmap_t * const p_map, + IN const void *const p_key) +{ + cl_fmap_item_t *p_item; + cl_fmap_item_t *p_item_found; + intn_t cmp; + + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + + p_item = __cl_fmap_root(p_map); + p_item_found = (cl_fmap_item_t *) & p_map->nil; + + while (p_item != &p_map->nil) { + cmp = p_map->pfn_compare(p_key, p_item->p_key); + + if (cmp < 0) { + p_item_found = p_item; + p_item = p_item->p_left; /* too small */ + } else { + p_item = p_item->p_right; /* too big or match */ + } + } + + return (p_item_found); +} + +void +cl_fmap_apply_func(IN const cl_fmap_t * const p_map, + IN cl_pfn_fmap_apply_t pfn_func, + IN const void *const context) +{ + cl_fmap_item_t *p_fmap_item; + + /* Note that context can have any arbitrary value. */ + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + CL_ASSERT(pfn_func); + + p_fmap_item = cl_fmap_head(p_map); + while (p_fmap_item != cl_fmap_end(p_map)) { + pfn_func(p_fmap_item, (void *)context); + p_fmap_item = cl_fmap_next(p_fmap_item); + } +} + +/* + * Balance a tree starting at a given item back to the root. + */ +static void +__cl_fmap_ins_bal(IN cl_fmap_t * const p_map, IN cl_fmap_item_t * p_item) +{ + cl_fmap_item_t *p_grand_uncle; + + CL_ASSERT(p_map); + CL_ASSERT(p_item); + CL_ASSERT(p_item != &p_map->root); + + while (p_item->p_up->color == CL_MAP_RED) { + if (__cl_fmap_is_left_child(p_item->p_up)) { + p_grand_uncle = p_item->p_up->p_up->p_right; + CL_ASSERT(p_grand_uncle); + if (p_grand_uncle->color == CL_MAP_RED) { + p_grand_uncle->color = CL_MAP_BLACK; + p_item->p_up->color = CL_MAP_BLACK; + p_item->p_up->p_up->color = CL_MAP_RED; + p_item = p_item->p_up->p_up; + continue; + } + + if (!__cl_fmap_is_left_child(p_item)) { + p_item = p_item->p_up; + __cl_fmap_rot_left(p_map, p_item); + } + p_item->p_up->color = CL_MAP_BLACK; + p_item->p_up->p_up->color = CL_MAP_RED; + __cl_fmap_rot_right(p_map, p_item->p_up->p_up); + } else { + p_grand_uncle = p_item->p_up->p_up->p_left; + CL_ASSERT(p_grand_uncle); + if (p_grand_uncle->color == CL_MAP_RED) { + p_grand_uncle->color = CL_MAP_BLACK; + p_item->p_up->color = CL_MAP_BLACK; + p_item->p_up->p_up->color = CL_MAP_RED; + p_item = p_item->p_up->p_up; + continue; + } + + if (__cl_fmap_is_left_child(p_item)) { + p_item = p_item->p_up; + __cl_fmap_rot_right(p_map, p_item); + } + p_item->p_up->color = CL_MAP_BLACK; + p_item->p_up->p_up->color = CL_MAP_RED; + __cl_fmap_rot_left(p_map, p_item->p_up->p_up); + } + } +} + +cl_fmap_item_t *cl_fmap_insert(IN cl_fmap_t * const p_map, + IN const void *const p_key, + IN cl_fmap_item_t * const p_item) +{ + cl_fmap_item_t *p_insert_at, *p_comp_item; + intn_t cmp = 0; + + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + CL_ASSERT(p_item); + CL_ASSERT(p_map->root.p_up == &p_map->root); + CL_ASSERT(p_map->root.color != CL_MAP_RED); + CL_ASSERT(p_map->nil.color != CL_MAP_RED); + + p_item->p_left = &p_map->nil; + p_item->p_right = &p_map->nil; + p_item->p_key = p_key; + p_item->color = CL_MAP_RED; + + /* Find the insertion location. */ + p_insert_at = &p_map->root; + p_comp_item = __cl_fmap_root(p_map); + + while (p_comp_item != &p_map->nil) { + p_insert_at = p_comp_item; + + cmp = p_map->pfn_compare(p_key, p_insert_at->p_key); + + if (!cmp) + return (p_insert_at); + + /* Traverse the tree until the correct insertion point is found. */ + if (cmp < 0) + p_comp_item = p_insert_at->p_left; + else + p_comp_item = p_insert_at->p_right; + } + + CL_ASSERT(p_insert_at != &p_map->nil); + CL_ASSERT(p_comp_item == &p_map->nil); + /* Insert the item. */ + if (p_insert_at == &p_map->root) { + p_insert_at->p_left = p_item; + /* + * Primitive insert places the new item in front of + * the existing item. + */ + __cl_primitive_insert(&p_map->nil.pool_item.list_item, + &p_item->pool_item.list_item); + } else if (cmp < 0) { + p_insert_at->p_left = p_item; + /* + * Primitive insert places the new item in front of + * the existing item. + */ + __cl_primitive_insert(&p_insert_at->pool_item.list_item, + &p_item->pool_item.list_item); + } else { + p_insert_at->p_right = p_item; + /* + * Primitive insert places the new item in front of + * the existing item. + */ + __cl_primitive_insert(p_insert_at->pool_item.list_item.p_next, + &p_item->pool_item.list_item); + } + /* Increase the count. */ + p_map->count++; + + p_item->p_up = p_insert_at; + + /* + * We have added depth to this section of the tree. + * Rebalance as necessary as we retrace our path through the tree + * and update colors. + */ + __cl_fmap_ins_bal(p_map, p_item); + + __cl_fmap_root(p_map)->color = CL_MAP_BLACK; + + /* + * Note that it is not necessary to re-color the nil node black because all + * red color assignments are made via the p_up pointer, and nil is never + * set as the value of a p_up pointer. + */ + +#ifdef _DEBUG_ + /* Set the pointer to the map in the map item for consistency checking. */ + p_item->p_map = p_map; +#endif + + return (p_item); +} + +static void +__cl_fmap_del_bal(IN cl_fmap_t * const p_map, IN cl_fmap_item_t * p_item) +{ + cl_fmap_item_t *p_uncle; + + while ((p_item->color != CL_MAP_RED) && (p_item->p_up != &p_map->root)) { + if (__cl_fmap_is_left_child(p_item)) { + p_uncle = p_item->p_up->p_right; + + if (p_uncle->color == CL_MAP_RED) { + p_uncle->color = CL_MAP_BLACK; + p_item->p_up->color = CL_MAP_RED; + __cl_fmap_rot_left(p_map, p_item->p_up); + p_uncle = p_item->p_up->p_right; + } + + if (p_uncle->p_right->color != CL_MAP_RED) { + if (p_uncle->p_left->color != CL_MAP_RED) { + p_uncle->color = CL_MAP_RED; + p_item = p_item->p_up; + continue; + } + + p_uncle->p_left->color = CL_MAP_BLACK; + p_uncle->color = CL_MAP_RED; + __cl_fmap_rot_right(p_map, p_uncle); + p_uncle = p_item->p_up->p_right; + } + p_uncle->color = p_item->p_up->color; + p_item->p_up->color = CL_MAP_BLACK; + p_uncle->p_right->color = CL_MAP_BLACK; + __cl_fmap_rot_left(p_map, p_item->p_up); + break; + } else { + p_uncle = p_item->p_up->p_left; + + if (p_uncle->color == CL_MAP_RED) { + p_uncle->color = CL_MAP_BLACK; + p_item->p_up->color = CL_MAP_RED; + __cl_fmap_rot_right(p_map, p_item->p_up); + p_uncle = p_item->p_up->p_left; + } + + if (p_uncle->p_left->color != CL_MAP_RED) { + if (p_uncle->p_right->color != CL_MAP_RED) { + p_uncle->color = CL_MAP_RED; + p_item = p_item->p_up; + continue; + } + + p_uncle->p_right->color = CL_MAP_BLACK; + p_uncle->color = CL_MAP_RED; + __cl_fmap_rot_left(p_map, p_uncle); + p_uncle = p_item->p_up->p_left; + } + p_uncle->color = p_item->p_up->color; + p_item->p_up->color = CL_MAP_BLACK; + p_uncle->p_left->color = CL_MAP_BLACK; + __cl_fmap_rot_right(p_map, p_item->p_up); + break; + } + } + p_item->color = CL_MAP_BLACK; +} + +void +cl_fmap_remove_item(IN cl_fmap_t * const p_map, + IN cl_fmap_item_t * const p_item) +{ + cl_fmap_item_t *p_child, *p_del_item; + + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + CL_ASSERT(p_item); + CL_ASSERT(p_item->p_map == p_map); + + if (p_item == cl_fmap_end(p_map)) + return; + + if ((p_item->p_right == &p_map->nil) || (p_item->p_left == &p_map->nil)) { + /* The item being removed has children on at most on side. */ + p_del_item = p_item; + } else { + /* + * The item being removed has children on both side. + * We select the item that will replace it. After removing + * the substitute item and rebalancing, the tree will have the + * correct topology. Exchanging the substitute for the item + * will finalize the removal. + */ + p_del_item = cl_fmap_next(p_item); + CL_ASSERT(p_del_item != &p_map->nil); + } + + /* Remove the item from the list. */ + __cl_primitive_remove(&p_item->pool_item.list_item); + /* Decrement the item count. */ + p_map->count--; + + /* Get the pointer to the new root's child, if any. */ + if (p_del_item->p_left != &p_map->nil) + p_child = p_del_item->p_left; + else + p_child = p_del_item->p_right; + + /* + * This assignment may modify the parent pointer of the nil node. + * This is inconsequential. + */ + p_child->p_up = p_del_item->p_up; + (*__cl_fmap_get_parent_ptr_to_item(p_del_item)) = p_child; + + if (p_del_item->color != CL_MAP_RED) + __cl_fmap_del_bal(p_map, p_child); + + /* + * Note that the splicing done below does not need to occur before + * the tree is balanced, since the actual topology changes are made by the + * preceding code. The topology is preserved by the color assignment made + * below (reader should be reminded that p_del_item == p_item in some cases). + */ + if (p_del_item != p_item) { + /* + * Finalize the removal of the specified item by exchanging it with + * the substitute which we removed above. + */ + p_del_item->p_up = p_item->p_up; + p_del_item->p_left = p_item->p_left; + p_del_item->p_right = p_item->p_right; + (*__cl_fmap_get_parent_ptr_to_item(p_item)) = p_del_item; + p_item->p_right->p_up = p_del_item; + p_item->p_left->p_up = p_del_item; + p_del_item->color = p_item->color; + } + + CL_ASSERT(p_map->nil.color != CL_MAP_RED); + +#ifdef _DEBUG_ + /* Clear the pointer to the map since the item has been removed. */ + p_item->p_map = NULL; +#endif +} + +cl_fmap_item_t *cl_fmap_remove(IN cl_fmap_t * const p_map, + IN const void *const p_key) +{ + cl_fmap_item_t *p_item; + + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + + /* Seek the node with the specified key */ + p_item = cl_fmap_get(p_map, p_key); + + cl_fmap_remove_item(p_map, p_item); + + return (p_item); +} + +void +cl_fmap_merge(OUT cl_fmap_t * const p_dest_map, + IN OUT cl_fmap_t * const p_src_map) +{ + cl_fmap_item_t *p_item, *p_item2, *p_next; + + CL_ASSERT(p_dest_map); + CL_ASSERT(p_src_map); + + p_item = cl_fmap_head(p_src_map); + + while (p_item != cl_fmap_end(p_src_map)) { + p_next = cl_fmap_next(p_item); + + /* Remove the item from its current map. */ + cl_fmap_remove_item(p_src_map, p_item); + /* Insert the item into the destination map. */ + p_item2 = + cl_fmap_insert(p_dest_map, cl_fmap_key(p_item), p_item); + /* Check that the item was successfully inserted. */ + if (p_item2 != p_item) { + /* Put the item in back in the source map. */ + p_item2 = + cl_fmap_insert(p_src_map, cl_fmap_key(p_item), + p_item); + CL_ASSERT(p_item2 == p_item); + } + p_item = p_next; + } +} + +static void +__cl_fmap_delta_move(IN OUT cl_fmap_t * const p_dest, + IN OUT cl_fmap_t * const p_src, + IN OUT cl_fmap_item_t ** const pp_item) +{ + cl_fmap_item_t *p_temp, *p_next; + + /* + * Get the next item so that we can ensure that pp_item points to + * a valid item upon return from the function. + */ + p_next = cl_fmap_next(*pp_item); + /* Move the old item from its current map the the old map. */ + cl_fmap_remove_item(p_src, *pp_item); + p_temp = cl_fmap_insert(p_dest, cl_fmap_key(*pp_item), *pp_item); + /* We should never have duplicates. */ + CL_ASSERT(p_temp == *pp_item); + /* Point pp_item to a valid item in the source map. */ + (*pp_item) = p_next; +} + +void +cl_fmap_delta(IN OUT cl_fmap_t * const p_map1, + IN OUT cl_fmap_t * const p_map2, + OUT cl_fmap_t * const p_new, OUT cl_fmap_t * const p_old) +{ + cl_fmap_item_t *p_item1, *p_item2; + intn_t cmp; + + CL_ASSERT(p_map1); + CL_ASSERT(p_map2); + CL_ASSERT(p_new); + CL_ASSERT(p_old); + CL_ASSERT(cl_is_fmap_empty(p_new)); + CL_ASSERT(cl_is_fmap_empty(p_old)); + + p_item1 = cl_fmap_head(p_map1); + p_item2 = cl_fmap_head(p_map2); + + while (p_item1 != cl_fmap_end(p_map1) && p_item2 != cl_fmap_end(p_map2)) { + cmp = p_map1->pfn_compare(cl_fmap_key(p_item1), + cl_fmap_key(p_item2)); + if (cmp < 0) { + /* We found an old item. */ + __cl_fmap_delta_move(p_old, p_map1, &p_item1); + } else if (cmp > 0) { + /* We found a new item. */ + __cl_fmap_delta_move(p_new, p_map2, &p_item2); + } else { + /* Move both forward since they have the same key. */ + p_item1 = cl_fmap_next(p_item1); + p_item2 = cl_fmap_next(p_item2); + } + } + + /* Process the remainder if the end of either source map was reached. */ + while (p_item2 != cl_fmap_end(p_map2)) + __cl_fmap_delta_move(p_new, p_map2, &p_item2); + + while (p_item1 != cl_fmap_end(p_map1)) + __cl_fmap_delta_move(p_old, p_map1, &p_item1); +} diff --git a/contrib/ofed/management/opensm/complib/cl_nodenamemap.c b/contrib/ofed/management/opensm/complib/cl_nodenamemap.c new file mode 100644 index 000000000000..4c6e8a426764 --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_nodenamemap.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2007 Lawrence Livermore National Lab + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +static int map_name(void *cxt, uint64_t guid, char *p) +{ + cl_qmap_t *map = cxt; + name_map_item_t *item; + + p = strtok(p, "\"#"); + if (!p) + return 0; + + item = malloc(sizeof(*item)); + if (!item) + return -1; + item->guid = guid; + item->name = strdup(p); + cl_qmap_insert(map, item->guid, (cl_map_item_t *)item); + return 0; +} + +nn_map_t * +open_node_name_map(char *node_name_map) +{ + nn_map_t *map; + + if (!node_name_map) { +#ifdef HAVE_DEFAULT_NODENAME_MAP + struct stat buf; + node_name_map = HAVE_DEFAULT_NODENAME_MAP; + if (stat(node_name_map, &buf)) + return NULL; +#else + return NULL; +#endif /* HAVE_DEFAULT_NODENAME_MAP */ + } + + map = malloc(sizeof(*map)); + if (!map) + return NULL; + cl_qmap_init(map); + + if (parse_node_map(node_name_map, map_name, map)) { + fprintf(stderr, + "WARNING failed to open node name map \"%s\" (%s)\n", + node_name_map, strerror(errno)); + close_node_name_map(map); + return NULL; + } + + return map; +} + +void +close_node_name_map(nn_map_t *map) +{ + name_map_item_t *item = NULL; + + if (!map) + return; + + item = (name_map_item_t *)cl_qmap_head(map); + while (item != (name_map_item_t *)cl_qmap_end(map)) { + item = (name_map_item_t *)cl_qmap_remove(map, item->guid); + free(item->name); + free(item); + item = (name_map_item_t *)cl_qmap_head(map); + } + free(map); +} + +char * +remap_node_name(nn_map_t *map, uint64_t target_guid, char *nodedesc) +{ + char *rc = NULL; + name_map_item_t *item = NULL; + + if (!map) + goto done; + + item = (name_map_item_t *)cl_qmap_get(map, target_guid); + if (item != (name_map_item_t *)cl_qmap_end(map)) + rc = strdup(item->name); + +done: + if (rc == NULL) + rc = strdup(clean_nodedesc(nodedesc)); + return (rc); +} + +char * +clean_nodedesc(char *nodedesc) +{ + int i = 0; + + nodedesc[63] = '\0'; + while (nodedesc[i]) { + if (!isprint(nodedesc[i])) + nodedesc[i] = ' '; + i++; + } + + return (nodedesc); +} + +int parse_node_map(const char *file_name, + int (*create)(void *, uint64_t, char *), void *cxt) +{ + char line[256]; + FILE *f; + + if (!(f = fopen(file_name, "r"))) + return -1; + + while (fgets(line, sizeof(line), f)) { + uint64_t guid; + char *p, *e; + + p = line; + while (isspace(*p)) + p++; + if (*p == '\0' || *p == '\n' || *p == '#') + continue; + + guid = strtoull(p, &e, 0); + if (e == p || (!isspace(*e) && *e != '#' && *e != '\0')) { + fclose(f); + return -1; + } + + p = e; + while (isspace(*p)) + p++; + + e = strpbrk(p, "\n"); + if (e) + *e = '\0'; + + if (create(cxt, guid, p)) { + fclose(f); + return -1; + } + } + + fclose(f); + return 0; +} diff --git a/contrib/ofed/management/opensm/complib/cl_pool.c b/contrib/ofed/management/opensm/complib/cl_pool.c new file mode 100644 index 000000000000..07903043c6e7 --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_pool.c @@ -0,0 +1,671 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of the grow pools. The grow pools manage a pool of objects. + * The pools can grow to meet demand, limited only by system memory. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * IMPLEMENTATION OF QUICK COMPOSITE POOL + */ +void cl_qcpool_construct(IN cl_qcpool_t * const p_pool) +{ + CL_ASSERT(p_pool); + + memset(p_pool, 0, sizeof(cl_qcpool_t)); + + p_pool->state = CL_UNINITIALIZED; +} + +cl_status_t +cl_qcpool_init(IN cl_qcpool_t * const p_pool, + IN const size_t min_size, + IN const size_t max_size, + IN const size_t grow_size, + IN const size_t * const component_sizes, + IN const uint32_t num_components, + IN cl_pfn_qcpool_init_t pfn_initializer OPTIONAL, + IN cl_pfn_qcpool_dtor_t pfn_destructor OPTIONAL, + IN const void *const context) +{ + cl_status_t status; + uint32_t i; + + CL_ASSERT(p_pool); + /* Must have a minimum of 1 component. */ + CL_ASSERT(num_components); + /* A component size array is required. */ + CL_ASSERT(component_sizes); + /* + * If no initializer is provided, the first component must be large + * enough to hold a pool item. + */ + CL_ASSERT(pfn_initializer || + (component_sizes[0] >= sizeof(cl_pool_item_t))); + + cl_qcpool_construct(p_pool); + + if (num_components > 1 && !pfn_initializer) + return (CL_INVALID_SETTING); + + if (max_size && max_size < min_size) + return (CL_INVALID_SETTING); + + /* + * Allocate the array of component sizes and component pointers all + * in one allocation. + */ + p_pool->component_sizes = (size_t *) malloc((sizeof(size_t) + + sizeof(void *)) * + num_components); + + if (!p_pool->component_sizes) + return (CL_INSUFFICIENT_MEMORY); + else + memset(p_pool->component_sizes, 0, + (sizeof(size_t) + sizeof(void *)) * num_components); + + /* Calculate the pointer to the array of pointers, used for callbacks. */ + p_pool->p_components = + (void **)(p_pool->component_sizes + num_components); + + /* Copy the user's sizes into our array for future use. */ + memcpy(p_pool->component_sizes, component_sizes, + sizeof(component_sizes[0]) * num_components); + + /* Store the number of components per object. */ + p_pool->num_components = num_components; + + /* Round up and store the size of the components. */ + for (i = 0; i < num_components; i++) { + /* + * We roundup each component size so that all components + * are aligned on a natural boundary. + */ + p_pool->component_sizes[i] = + ROUNDUP(p_pool->component_sizes[i], sizeof(uintn_t)); + } + + p_pool->max_objects = max_size ? max_size : ~(size_t) 0; + p_pool->grow_size = grow_size; + + /* Store callback function pointers. */ + p_pool->pfn_init = pfn_initializer; /* may be NULL */ + p_pool->pfn_dtor = pfn_destructor; /* may be NULL */ + p_pool->context = context; + + cl_qlist_init(&p_pool->alloc_list); + + cl_qlist_init(&p_pool->free_list); + + /* + * We are now initialized. We change the initialized flag before + * growing since the grow function asserts that we are initialized. + */ + p_pool->state = CL_INITIALIZED; + + /* Allocate the minimum number of objects as requested. */ + if (!min_size) + return (CL_SUCCESS); + + status = cl_qcpool_grow(p_pool, min_size); + /* Trap for error and cleanup if necessary. */ + if (status != CL_SUCCESS) + cl_qcpool_destroy(p_pool); + + return (status); +} + +void cl_qcpool_destroy(IN cl_qcpool_t * const p_pool) +{ + /* CL_ASSERT that a non-NULL pointer was provided. */ + CL_ASSERT(p_pool); + /* CL_ASSERT that we are in a valid state (not uninitialized memory). */ + CL_ASSERT(cl_is_state_valid(p_pool->state)); + + if (p_pool->state == CL_INITIALIZED) { + /* + * Assert if the user hasn't put everything back in the pool + * before destroying it + * if they haven't, then most likely they are still using memory + * that will be freed, and the destructor will not be called! + */ +#ifdef _DEBUG_ + /* but we do not want "free" version to assert on this one */ + CL_ASSERT(cl_qcpool_count(p_pool) == p_pool->num_objects); +#endif + /* call the user's destructor for each object in the pool */ + if (p_pool->pfn_dtor) { + while (!cl_is_qlist_empty(&p_pool->free_list)) { + p_pool->pfn_dtor((cl_pool_item_t *) + cl_qlist_remove_head(&p_pool-> + free_list), + (void *)p_pool->context); + } + } else { + cl_qlist_remove_all(&p_pool->free_list); + } + + /* Free all allocated memory blocks. */ + while (!cl_is_qlist_empty(&p_pool->alloc_list)) + free(cl_qlist_remove_head(&p_pool->alloc_list)); + + if (p_pool->component_sizes) { + free(p_pool->component_sizes); + p_pool->component_sizes = NULL; + } + } + + p_pool->state = CL_UNINITIALIZED; +} + +cl_status_t cl_qcpool_grow(IN cl_qcpool_t * const p_pool, IN size_t obj_count) +{ + cl_status_t status = CL_SUCCESS; + uint8_t *p_objects; + cl_pool_item_t *p_pool_item; + uint32_t i; + size_t obj_size; + + CL_ASSERT(p_pool); + CL_ASSERT(p_pool->state == CL_INITIALIZED); + CL_ASSERT(obj_count); + + /* Validate that growth is possible. */ + if (p_pool->num_objects == p_pool->max_objects) + return (CL_INSUFFICIENT_MEMORY); + + /* Cap the growth to the desired maximum. */ + if (obj_count > (p_pool->max_objects - p_pool->num_objects)) + obj_count = p_pool->max_objects - p_pool->num_objects; + + /* Calculate the size of an object. */ + obj_size = 0; + for (i = 0; i < p_pool->num_components; i++) + obj_size += p_pool->component_sizes[i]; + + /* Allocate the buffer for the new objects. */ + p_objects = (uint8_t *) + malloc(sizeof(cl_list_item_t) + (obj_size * obj_count)); + + /* Make sure the allocation succeeded. */ + if (!p_objects) + return (CL_INSUFFICIENT_MEMORY); + else + memset(p_objects, 0, + sizeof(cl_list_item_t) + (obj_size * obj_count)); + + /* Insert the allocation in our list. */ + cl_qlist_insert_tail(&p_pool->alloc_list, (cl_list_item_t *) p_objects); + p_objects += sizeof(cl_list_item_t); + + /* initialize the new elements and add them to the free list */ + while (obj_count--) { + /* Setup the array of components for the current object. */ + p_pool->p_components[0] = p_objects; + for (i = 1; i < p_pool->num_components; i++) { + /* Calculate the pointer to the next component. */ + p_pool->p_components[i] = + (uint8_t *) p_pool->p_components[i - 1] + + p_pool->component_sizes[i - 1]; + } + + /* + * call the user's initializer + * this can fail! + */ + if (p_pool->pfn_init) { + p_pool_item = NULL; + status = p_pool->pfn_init(p_pool->p_components, + p_pool->num_components, + (void *)p_pool->context, + &p_pool_item); + if (status != CL_SUCCESS) { + /* + * User initialization failed + * we may have only grown the pool by some partial amount + * Invoke the destructor for the object that failed + * initialization. + */ + if (p_pool->pfn_dtor) + p_pool->pfn_dtor(p_pool_item, + (void *)p_pool-> + context); + + /* Return the user's status. */ + return (status); + } + CL_ASSERT(p_pool_item); + } else { + /* + * If no initializer is provided, assume that the pool item + * is stored at the beginning of the first component. + */ + p_pool_item = + (cl_pool_item_t *) p_pool->p_components[0]; + } + +#ifdef _DEBUG_ + /* + * Set the pool item's pool pointer to this pool so that we can + * check that items get returned to the correct pool. + */ + p_pool_item->p_pool = p_pool; +#endif + + /* Insert the new item in the free list, traping for failure. */ + cl_qlist_insert_head(&p_pool->free_list, + &p_pool_item->list_item); + + p_pool->num_objects++; + + /* move the pointer to the next item */ + p_objects += obj_size; + } + + return (status); +} + +cl_pool_item_t *cl_qcpool_get(IN cl_qcpool_t * const p_pool) +{ + cl_list_item_t *p_list_item; + + CL_ASSERT(p_pool); + CL_ASSERT(p_pool->state == CL_INITIALIZED); + + if (cl_is_qlist_empty(&p_pool->free_list)) { + /* + * No object is available. + * Return NULL if the user does not want automatic growth. + */ + if (!p_pool->grow_size) + return (NULL); + + /* We ran out of elements. Get more */ + cl_qcpool_grow(p_pool, p_pool->grow_size); + /* + * We may not have gotten everything we wanted but we might have + * gotten something. + */ + if (cl_is_qlist_empty(&p_pool->free_list)) + return (NULL); + } + + p_list_item = cl_qlist_remove_head(&p_pool->free_list); + /* OK, at this point we have an object */ + CL_ASSERT(p_list_item != cl_qlist_end(&p_pool->free_list)); + return ((cl_pool_item_t *) p_list_item); +} + +cl_pool_item_t *cl_qcpool_get_tail(IN cl_qcpool_t * const p_pool) +{ + cl_list_item_t *p_list_item; + + CL_ASSERT(p_pool); + CL_ASSERT(p_pool->state == CL_INITIALIZED); + + if (cl_is_qlist_empty(&p_pool->free_list)) { + /* + * No object is available. + * Return NULL if the user does not want automatic growth. + */ + if (!p_pool->grow_size) + return (NULL); + + /* We ran out of elements. Get more */ + cl_qcpool_grow(p_pool, p_pool->grow_size); + /* + * We may not have gotten everything we wanted but we might have + * gotten something. + */ + if (cl_is_qlist_empty(&p_pool->free_list)) + return (NULL); + } + + p_list_item = cl_qlist_remove_tail(&p_pool->free_list); + /* OK, at this point we have an object */ + CL_ASSERT(p_list_item != cl_qlist_end(&p_pool->free_list)); + return ((cl_pool_item_t *) p_list_item); +} + +/* + * IMPLEMENTATION OF QUICK GROW POOL + */ + +/* + * Callback to translate quick composite to quick grow pool + * initializer callback. + */ +static cl_status_t +__cl_qpool_init_cb(IN void **const p_comp_array, + IN const uint32_t num_components, + IN void *const context, + OUT cl_pool_item_t ** const pp_pool_item) +{ + cl_qpool_t *p_pool = (cl_qpool_t *) context; + + CL_ASSERT(p_pool); + CL_ASSERT(p_pool->pfn_init); + CL_ASSERT(num_components == 1); + + UNUSED_PARAM(num_components); + + return (p_pool->pfn_init(p_comp_array[0], (void *)p_pool->context, + pp_pool_item)); +} + +/* + * Callback to translate quick composite to quick grow pool + * destructor callback. + */ +static void +__cl_qpool_dtor_cb(IN const cl_pool_item_t * const p_pool_item, + IN void *const context) +{ + cl_qpool_t *p_pool = (cl_qpool_t *) context; + + CL_ASSERT(p_pool); + CL_ASSERT(p_pool->pfn_dtor); + + p_pool->pfn_dtor(p_pool_item, (void *)p_pool->context); +} + +void cl_qpool_construct(IN cl_qpool_t * const p_pool) +{ + memset(p_pool, 0, sizeof(cl_qpool_t)); + + cl_qcpool_construct(&p_pool->qcpool); +} + +cl_status_t +cl_qpool_init(IN cl_qpool_t * const p_pool, + IN const size_t min_size, + IN const size_t max_size, + IN const size_t grow_size, + IN const size_t object_size, + IN cl_pfn_qpool_init_t pfn_initializer OPTIONAL, + IN cl_pfn_qpool_dtor_t pfn_destructor OPTIONAL, + IN const void *const context) +{ + cl_status_t status; + + CL_ASSERT(p_pool); + + p_pool->pfn_init = pfn_initializer; /* may be NULL */ + p_pool->pfn_dtor = pfn_destructor; /* may be NULL */ + p_pool->context = context; + + status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size, + &object_size, 1, + pfn_initializer ? __cl_qpool_init_cb : NULL, + pfn_destructor ? __cl_qpool_dtor_cb : NULL, + p_pool); + + return (status); +} + +/* + * IMPLEMENTATION OF COMPOSITE POOL + */ + +/* + * Callback to translate quick composite to compsite pool + * initializer callback. + */ +static cl_status_t +__cl_cpool_init_cb(IN void **const p_comp_array, + IN const uint32_t num_components, + IN void *const context, + OUT cl_pool_item_t ** const pp_pool_item) +{ + cl_cpool_t *p_pool = (cl_cpool_t *) context; + cl_pool_obj_t *p_pool_obj; + cl_status_t status = CL_SUCCESS; + + CL_ASSERT(p_pool); + + /* + * Set our pointer to the list item, which is stored at the beginning of + * the first component. + */ + p_pool_obj = (cl_pool_obj_t *) p_comp_array[0]; + /* Set the pool item pointer for the caller. */ + *pp_pool_item = &p_pool_obj->pool_item; + + /* Calculate the pointer to the user's first component. */ + p_comp_array[0] = ((uint8_t *) p_comp_array[0]) + sizeof(cl_pool_obj_t); + + /* + * Set the object pointer in the pool object to point to the first of the + * user's components. + */ + p_pool_obj->p_object = p_comp_array[0]; + + /* Invoke the user's constructor callback. */ + if (p_pool->pfn_init) { + status = p_pool->pfn_init(p_comp_array, num_components, + (void *)p_pool->context); + } + + return (status); +} + +/* + * Callback to translate quick composite to composite pool + * destructor callback. + */ +static void +__cl_cpool_dtor_cb(IN const cl_pool_item_t * const p_pool_item, + IN void *const context) +{ + cl_cpool_t *p_pool = (cl_cpool_t *) context; + + CL_ASSERT(p_pool); + CL_ASSERT(p_pool->pfn_dtor); + CL_ASSERT(((cl_pool_obj_t *) p_pool_item)->p_object); + + /* Invoke the user's destructor callback. */ + p_pool->pfn_dtor((void *)((cl_pool_obj_t *) p_pool_item)->p_object, + (void *)p_pool->context); +} + +void cl_cpool_construct(IN cl_cpool_t * const p_pool) +{ + CL_ASSERT(p_pool); + + memset(p_pool, 0, sizeof(cl_cpool_t)); + + cl_qcpool_construct(&p_pool->qcpool); +} + +cl_status_t +cl_cpool_init(IN cl_cpool_t * const p_pool, + IN const size_t min_size, + IN const size_t max_size, + IN const size_t grow_size, + IN size_t * const component_sizes, + IN const uint32_t num_components, + IN cl_pfn_cpool_init_t pfn_initializer OPTIONAL, + IN cl_pfn_cpool_dtor_t pfn_destructor OPTIONAL, + IN const void *const context) +{ + cl_status_t status; + + CL_ASSERT(p_pool); + CL_ASSERT(num_components); + CL_ASSERT(component_sizes); + + /* Add the size of the pool object to the first component. */ + component_sizes[0] += sizeof(cl_pool_obj_t); + + /* Store callback function pointers. */ + p_pool->pfn_init = pfn_initializer; /* may be NULL */ + p_pool->pfn_dtor = pfn_destructor; /* may be NULL */ + p_pool->context = context; + + status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size, + component_sizes, num_components, + __cl_cpool_init_cb, + pfn_destructor ? __cl_cpool_dtor_cb : NULL, + p_pool); + + /* Restore the original value of the first component. */ + component_sizes[0] -= sizeof(cl_pool_obj_t); + + return (status); +} + +/* + * IMPLEMENTATION OF GROW POOL + */ + +/* + * Callback to translate quick composite to grow pool constructor callback. + */ +static cl_status_t +__cl_pool_init_cb(IN void **const pp_obj, + IN const uint32_t count, + IN void *const context, + OUT cl_pool_item_t ** const pp_pool_item) +{ + cl_pool_t *p_pool = (cl_pool_t *) context; + cl_pool_obj_t *p_pool_obj; + cl_status_t status = CL_SUCCESS; + + CL_ASSERT(p_pool); + CL_ASSERT(pp_obj); + CL_ASSERT(count == 1); + + UNUSED_PARAM(count); + + /* + * Set our pointer to the list item, which is stored at the beginning of + * the first component. + */ + p_pool_obj = (cl_pool_obj_t *) * pp_obj; + *pp_pool_item = &p_pool_obj->pool_item; + + /* Calculate the pointer to the user's first component. */ + *pp_obj = ((uint8_t *) * pp_obj) + sizeof(cl_pool_obj_t); + + /* + * Set the object pointer in the pool item to point to the first of the + * user's components. + */ + p_pool_obj->p_object = *pp_obj; + + /* Invoke the user's constructor callback. */ + if (p_pool->pfn_init) + status = p_pool->pfn_init(*pp_obj, (void *)p_pool->context); + + return (status); +} + +/* + * Callback to translate quick composite to grow pool destructor callback. + */ +static void +__cl_pool_dtor_cb(IN const cl_pool_item_t * const p_pool_item, + IN void *const context) +{ + cl_pool_t *p_pool = (cl_pool_t *) context; + + CL_ASSERT(p_pool); + CL_ASSERT(p_pool->pfn_dtor); + CL_ASSERT(((cl_pool_obj_t *) p_pool_item)->p_object); + + /* Invoke the user's destructor callback. */ + p_pool->pfn_dtor((void *)((cl_pool_obj_t *) p_pool_item)->p_object, + (void *)p_pool->context); +} + +void cl_pool_construct(IN cl_pool_t * const p_pool) +{ + CL_ASSERT(p_pool); + + memset(p_pool, 0, sizeof(cl_pool_t)); + + cl_qcpool_construct(&p_pool->qcpool); +} + +cl_status_t +cl_pool_init(IN cl_pool_t * const p_pool, + IN const size_t min_size, + IN const size_t max_size, + IN const size_t grow_size, + IN const size_t object_size, + IN cl_pfn_pool_init_t pfn_initializer OPTIONAL, + IN cl_pfn_pool_dtor_t pfn_destructor OPTIONAL, + IN const void *const context) +{ + cl_status_t status; + size_t total_size; + + CL_ASSERT(p_pool); + + /* Add the size of the list item to the first component. */ + total_size = object_size + sizeof(cl_pool_obj_t); + + /* Store callback function pointers. */ + p_pool->pfn_init = pfn_initializer; /* may be NULL */ + p_pool->pfn_dtor = pfn_destructor; /* may be NULL */ + p_pool->context = context; + + /* + * We need an initializer in all cases for quick composite pool, since + * the user pointer must be manipulated to hide the prefixed cl_pool_obj_t. + */ + status = cl_qcpool_init(&p_pool->qcpool, min_size, max_size, grow_size, + &total_size, 1, __cl_pool_init_cb, + pfn_destructor ? __cl_pool_dtor_cb : NULL, + p_pool); + + return (status); +} diff --git a/contrib/ofed/management/opensm/complib/cl_ptr_vector.c b/contrib/ofed/management/opensm/complib/cl_ptr_vector.c new file mode 100644 index 000000000000..c34316e4503f --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_ptr_vector.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * This file contains ivector and isvector implementations. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +void cl_ptr_vector_construct(IN cl_ptr_vector_t * const p_vector) +{ + CL_ASSERT(p_vector); + + memset(p_vector, 0, sizeof(cl_ptr_vector_t)); + + p_vector->state = CL_UNINITIALIZED; +} + +cl_status_t +cl_ptr_vector_init(IN cl_ptr_vector_t * const p_vector, + IN const size_t min_size, IN const size_t grow_size) +{ + cl_status_t status = CL_SUCCESS; + + CL_ASSERT(p_vector); + + cl_ptr_vector_construct(p_vector); + + p_vector->grow_size = grow_size; + + /* + * Set the state to initialized so that the call to set_size + * doesn't assert. + */ + p_vector->state = CL_INITIALIZED; + + /* get the storage needed by the user */ + if (min_size) { + status = cl_ptr_vector_set_size(p_vector, min_size); + if (status != CL_SUCCESS) + cl_ptr_vector_destroy(p_vector); + } + + return (status); +} + +void cl_ptr_vector_destroy(IN cl_ptr_vector_t * const p_vector) +{ + CL_ASSERT(p_vector); + CL_ASSERT(cl_is_state_valid(p_vector->state)); + + /* Call the user's destructor for each element in the array. */ + if (p_vector->state == CL_INITIALIZED) { + /* Destroy the page vector. */ + if (p_vector->p_ptr_array) { + free((void *)p_vector->p_ptr_array); + p_vector->p_ptr_array = NULL; + } + } + + p_vector->state = CL_UNINITIALIZED; +} + +cl_status_t +cl_ptr_vector_at(IN const cl_ptr_vector_t * const p_vector, + IN const size_t index, OUT void **const p_element) +{ + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + + /* Range check */ + if (index >= p_vector->size) + return (CL_INVALID_PARAMETER); + + *p_element = cl_ptr_vector_get(p_vector, index); + return (CL_SUCCESS); +} + +cl_status_t +cl_ptr_vector_set(IN cl_ptr_vector_t * const p_vector, + IN const size_t index, IN const void *const element) +{ + cl_status_t status; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + + /* Determine if the vector has room for this element. */ + if (index >= p_vector->size) { + /* Resize to accomodate the given index. */ + status = cl_ptr_vector_set_size(p_vector, index + 1); + + /* Check for failure on or before the given index. */ + if ((status != CL_SUCCESS) && (p_vector->size < index)) + return (status); + } + + /* At this point, the array is guaranteed to be big enough */ + p_vector->p_ptr_array[index] = element; + + return (CL_SUCCESS); +} + +void *cl_ptr_vector_remove(IN cl_ptr_vector_t * const p_vector, + IN const size_t index) +{ + size_t src; + const void *element; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + CL_ASSERT(p_vector->size > index); + + /* Store a copy of the element to return. */ + element = p_vector->p_ptr_array[index]; + /* Shift all items above the removed item down. */ + if (index < --p_vector->size) { + for (src = index; src < p_vector->size; src++) + p_vector->p_ptr_array[src] = + p_vector->p_ptr_array[src + 1]; + } + /* Clear the entry for the element just outside of the new upper bound. */ + p_vector->p_ptr_array[p_vector->size] = NULL; + + return ((void *)element); +} + +cl_status_t +cl_ptr_vector_set_capacity(IN cl_ptr_vector_t * const p_vector, + IN const size_t new_capacity) +{ + void *p_new_ptr_array; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + + /* Do we have to do anything here? */ + if (new_capacity <= p_vector->capacity) { + /* Nope */ + return (CL_SUCCESS); + } + + /* Allocate our pointer array. */ + p_new_ptr_array = malloc(new_capacity * sizeof(void *)); + if (!p_new_ptr_array) + return (CL_INSUFFICIENT_MEMORY); + else + memset(p_new_ptr_array, 0, new_capacity * sizeof(void *)); + + if (p_vector->p_ptr_array) { + /* Copy the old pointer array into the new. */ + memcpy(p_new_ptr_array, p_vector->p_ptr_array, + p_vector->capacity * sizeof(void *)); + + /* Free the old pointer array. */ + free((void *)p_vector->p_ptr_array); + } + + /* Set the new array. */ + p_vector->p_ptr_array = p_new_ptr_array; + + /* Update the vector with the new capactity. */ + p_vector->capacity = new_capacity; + + return (CL_SUCCESS); +} + +cl_status_t +cl_ptr_vector_set_size(IN cl_ptr_vector_t * const p_vector, + IN const size_t size) +{ + cl_status_t status; + size_t new_capacity; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + + /* Check to see if the requested size is the same as the existing size. */ + if (size == p_vector->size) + return (CL_SUCCESS); + + /* Determine if the vector has room for this element. */ + if (size >= p_vector->capacity) { + if (!p_vector->grow_size) + return (CL_INSUFFICIENT_MEMORY); + + /* Calculate the new capacity, taking into account the grow size. */ + new_capacity = size; + if (size % p_vector->grow_size) { + /* Round up to nearest grow_size boundary. */ + new_capacity += p_vector->grow_size - + (size % p_vector->grow_size); + } + + status = cl_ptr_vector_set_capacity(p_vector, new_capacity); + if (status != CL_SUCCESS) + return (status); + } + + p_vector->size = size; + return (CL_SUCCESS); +} + +cl_status_t +cl_ptr_vector_set_min_size(IN cl_ptr_vector_t * const p_vector, + IN const size_t min_size) +{ + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + + if (min_size > p_vector->size) { + /* We have to resize the array */ + return (cl_ptr_vector_set_size(p_vector, min_size)); + } + + /* We didn't have to do anything */ + return (CL_SUCCESS); +} + +void +cl_ptr_vector_apply_func(IN const cl_ptr_vector_t * const p_vector, + IN cl_pfn_ptr_vec_apply_t pfn_callback, + IN const void *const context) +{ + size_t i; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + CL_ASSERT(pfn_callback); + + for (i = 0; i < p_vector->size; i++) + pfn_callback(i, (void *)p_vector->p_ptr_array[i], + (void *)context); +} + +size_t +cl_ptr_vector_find_from_start(IN const cl_ptr_vector_t * const p_vector, + IN cl_pfn_ptr_vec_find_t pfn_callback, + IN const void *const context) +{ + size_t i; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + CL_ASSERT(pfn_callback); + + for (i = 0; i < p_vector->size; i++) { + /* Invoke the callback */ + if (pfn_callback(i, (void *)p_vector->p_ptr_array[i], + (void *)context) == CL_SUCCESS) { + break; + } + } + return (i); +} + +size_t +cl_ptr_vector_find_from_end(IN const cl_ptr_vector_t * const p_vector, + IN cl_pfn_ptr_vec_find_t pfn_callback, + IN const void *const context) +{ + size_t i; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + CL_ASSERT(pfn_callback); + + i = p_vector->size; + + while (i) { + /* Invoke the callback for the current element. */ + if (pfn_callback(i, (void *)p_vector->p_ptr_array[--i], + (void *)context) == CL_SUCCESS) { + return (i); + } + } + + return (p_vector->size); +} diff --git a/contrib/ofed/management/opensm/complib/cl_spinlock.c b/contrib/ofed/management/opensm/complib/cl_spinlock.c new file mode 100644 index 000000000000..2d81696cfbb3 --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_spinlock.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +void cl_spinlock_construct(IN cl_spinlock_t * const p_spinlock) +{ + CL_ASSERT(p_spinlock); + + p_spinlock->state = CL_UNINITIALIZED; +} + +cl_status_t cl_spinlock_init(IN cl_spinlock_t * const p_spinlock) +{ + CL_ASSERT(p_spinlock); + + cl_spinlock_construct(p_spinlock); + + /* Initialize with pthread_mutexattr_t = NULL */ + if (pthread_mutex_init(&p_spinlock->mutex, NULL)) + return (CL_ERROR); + + p_spinlock->state = CL_INITIALIZED; + return (CL_SUCCESS); +} + +void cl_spinlock_destroy(IN cl_spinlock_t * const p_spinlock) +{ + CL_ASSERT(p_spinlock); + CL_ASSERT(cl_is_state_valid(p_spinlock->state)); + + if (p_spinlock->state == CL_INITIALIZED) { + p_spinlock->state = CL_UNINITIALIZED; + pthread_mutex_lock(&p_spinlock->mutex); + pthread_mutex_unlock(&p_spinlock->mutex); + pthread_mutex_destroy(&p_spinlock->mutex); + } + p_spinlock->state = CL_UNINITIALIZED; +} + +void cl_spinlock_acquire(IN cl_spinlock_t * const p_spinlock) +{ + CL_ASSERT(p_spinlock); + CL_ASSERT(p_spinlock->state == CL_INITIALIZED); + + pthread_mutex_lock(&p_spinlock->mutex); +} + +void cl_spinlock_release(IN cl_spinlock_t * const p_spinlock) +{ + CL_ASSERT(p_spinlock); + CL_ASSERT(p_spinlock->state == CL_INITIALIZED); + + pthread_mutex_unlock(&p_spinlock->mutex); +} diff --git a/contrib/ofed/management/opensm/complib/cl_statustext.c b/contrib/ofed/management/opensm/complib/cl_statustext.c new file mode 100644 index 000000000000..b02b8b84cac3 --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_statustext.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Defines string to decode cl_status_t return values. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +/* Status values above converted to text for easier printing. */ +const char *cl_status_text[] = { + "CL_SUCCESS", + "CL_ERROR", + "CL_INVALID_STATE", + "CL_INVALID_OPERATION", + "CL_INVALID_SETTING", + "CL_INVALID_PARAMETER", + "CL_INSUFFICIENT_RESOURCES", + "CL_INSUFFICIENT_MEMORY", + "CL_INVALID_PERMISSION", + "CL_COMPLETED", + "CL_NOT_DONE", + "CL_PENDING", + "CL_TIMEOUT", + "CL_CANCELED", + "CL_REJECT", + "CL_OVERRUN", + "CL_NOT_FOUND", + "CL_UNAVAILABLE", + "CL_BUSY", + "CL_DISCONNECT", + "CL_DUPLICATE" +}; diff --git a/contrib/ofed/management/opensm/complib/cl_thread.c b/contrib/ofed/management/opensm/complib/cl_thread.c new file mode 100644 index 000000000000..38a68f8ae9b3 --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_thread.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/* + * Internal function to run a new user mode thread. + * This function is always run as a result of creation a new user mode thread. + * Its main job is to synchronize the creation and running of the new thread. + */ +static void *__cl_thread_wrapper(void *arg) +{ + cl_thread_t *p_thread = (cl_thread_t *) arg; + + CL_ASSERT(p_thread); + CL_ASSERT(p_thread->pfn_callback); + + p_thread->pfn_callback((void *)p_thread->context); + + return (NULL); +} + +void cl_thread_construct(IN cl_thread_t * const p_thread) +{ + CL_ASSERT(p_thread); + + p_thread->osd.state = CL_UNINITIALIZED; +} + +cl_status_t +cl_thread_init(IN cl_thread_t * const p_thread, + IN cl_pfn_thread_callback_t pfn_callback, + IN const void *const context, IN const char *const name) +{ + int ret; + + CL_ASSERT(p_thread); + + cl_thread_construct(p_thread); + + /* Initialize the thread structure */ + p_thread->pfn_callback = pfn_callback; + p_thread->context = context; + + ret = pthread_create(&p_thread->osd.id, NULL, + __cl_thread_wrapper, (void *)p_thread); + + if (ret != 0) /* pthread_create returns a "0" for success */ + return (CL_ERROR); + + p_thread->osd.state = CL_INITIALIZED; + + return (CL_SUCCESS); +} + +void cl_thread_destroy(IN cl_thread_t * const p_thread) +{ + CL_ASSERT(p_thread); + CL_ASSERT(cl_is_state_valid(p_thread->osd.state)); + + if (p_thread->osd.state == CL_INITIALIZED) + pthread_join(p_thread->osd.id, NULL); + + p_thread->osd.state = CL_UNINITIALIZED; +} + +void cl_thread_suspend(IN const uint32_t pause_ms) +{ + /* Convert to micro seconds */ + usleep(pause_ms * 1000); +} + +void cl_thread_stall(IN const uint32_t pause_us) +{ + /* + * Not quite a busy wait, but Linux is lacking in terms of high + * resolution time stamp information in user mode. + */ + usleep(pause_us); +} + +int cl_proc_count(void) +{ + uint32_t ret; + + ret = sysconf(_SC_NPROCESSORS_ONLN); + if (!ret) + return 1; /* Workaround for PPC where get_nprocs() returns 0 */ + + return ret; +} + +boolean_t cl_is_current_thread(IN const cl_thread_t * const p_thread) +{ + pthread_t current; + + CL_ASSERT(p_thread); + CL_ASSERT(p_thread->osd.state == CL_INITIALIZED); + + current = pthread_self(); + return (pthread_equal(current, p_thread->osd.id)); +} diff --git a/contrib/ofed/management/opensm/complib/cl_threadpool.c b/contrib/ofed/management/opensm/complib/cl_threadpool.c new file mode 100644 index 000000000000..3f6c0a4fd94e --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_threadpool.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of thread pool. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +static void cleanup_mutex(void *arg) +{ + pthread_mutex_unlock(&((cl_thread_pool_t *) arg)->mutex); +} + +static void *thread_pool_routine(void *context) +{ + cl_thread_pool_t *p_thread_pool = (cl_thread_pool_t *) context; + + do { + pthread_mutex_lock(&p_thread_pool->mutex); + pthread_cleanup_push(cleanup_mutex, p_thread_pool); + while (!p_thread_pool->events) + pthread_cond_wait(&p_thread_pool->cond, + &p_thread_pool->mutex); + p_thread_pool->events--; + pthread_cleanup_pop(1); + /* The event has been signalled. Invoke the callback. */ + (*p_thread_pool->pfn_callback) (p_thread_pool->context); + } while (1); + + return NULL; +} + +cl_status_t +cl_thread_pool_init(IN cl_thread_pool_t * const p_thread_pool, + IN unsigned count, + IN void (*pfn_callback) (void *), + IN void *context, IN const char *const name) +{ + int i; + + CL_ASSERT(p_thread_pool); + CL_ASSERT(pfn_callback); + + memset(p_thread_pool, 0, sizeof(*p_thread_pool)); + + if (!count) + count = cl_proc_count(); + + pthread_mutex_init(&p_thread_pool->mutex, NULL); + pthread_cond_init(&p_thread_pool->cond, NULL); + + p_thread_pool->events = 0; + + p_thread_pool->pfn_callback = pfn_callback; + p_thread_pool->context = context; + + p_thread_pool->tid = calloc(count, sizeof(*p_thread_pool->tid)); + if (!p_thread_pool->tid) { + cl_thread_pool_destroy(p_thread_pool); + return CL_INSUFFICIENT_MEMORY; + } + + p_thread_pool->running_count = count; + + for (i = 0; i < count; i++) { + if (pthread_create(&p_thread_pool->tid[i], NULL, + thread_pool_routine, p_thread_pool) < 0) { + cl_thread_pool_destroy(p_thread_pool); + return CL_INSUFFICIENT_RESOURCES; + } + } + + return (CL_SUCCESS); +} + +void cl_thread_pool_destroy(IN cl_thread_pool_t * const p_thread_pool) +{ + int i; + + CL_ASSERT(p_thread_pool); + + for (i = 0; i < p_thread_pool->running_count; i++) + if (p_thread_pool->tid[i]) + pthread_cancel(p_thread_pool->tid[i]); + + for (i = 0; i < p_thread_pool->running_count; i++) + if (p_thread_pool->tid[i]) + pthread_join(p_thread_pool->tid[i], NULL); + + p_thread_pool->running_count = 0; + pthread_cond_destroy(&p_thread_pool->cond); + pthread_mutex_destroy(&p_thread_pool->mutex); + + p_thread_pool->events = 0; +} + +cl_status_t cl_thread_pool_signal(IN cl_thread_pool_t * const p_thread_pool) +{ + int ret; + CL_ASSERT(p_thread_pool); + pthread_mutex_lock(&p_thread_pool->mutex); + p_thread_pool->events++; + ret = pthread_cond_signal(&p_thread_pool->cond); + pthread_mutex_unlock(&p_thread_pool->mutex); + return ret; +} diff --git a/contrib/ofed/management/opensm/complib/cl_timer.c b/contrib/ofed/management/opensm/complib/cl_timer.c new file mode 100644 index 000000000000..41b669f9e066 --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_timer.c @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Abstraction of Timer create, destroy functions. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +/* Timer provider (emulates timers in user mode). */ +typedef struct _cl_timer_prov { + pthread_t thread; + pthread_mutex_t mutex; + pthread_cond_t cond; + cl_qlist_t queue; + + boolean_t exit; + +} cl_timer_prov_t; + +/* Global timer provider. */ +static cl_timer_prov_t *gp_timer_prov = NULL; + +static void *__cl_timer_prov_cb(IN void *const context); + +/* + * Creates the process global timer provider. Must be called by the shared + * object framework to solve all serialization issues. + */ +cl_status_t __cl_timer_prov_create(void) +{ + CL_ASSERT(gp_timer_prov == NULL); + + gp_timer_prov = malloc(sizeof(cl_timer_prov_t)); + if (!gp_timer_prov) + return (CL_INSUFFICIENT_MEMORY); + else + memset(gp_timer_prov, 0, sizeof(cl_timer_prov_t)); + + cl_qlist_init(&gp_timer_prov->queue); + + pthread_mutex_init(&gp_timer_prov->mutex, NULL); + pthread_cond_init(&gp_timer_prov->cond, NULL); + + if (pthread_create(&gp_timer_prov->thread, NULL, + __cl_timer_prov_cb, NULL)) { + __cl_timer_prov_destroy(); + return (CL_ERROR); + } + + return (CL_SUCCESS); +} + +void __cl_timer_prov_destroy(void) +{ + pthread_t tid; + + if (!gp_timer_prov) + return; + + tid = gp_timer_prov->thread; + pthread_mutex_lock(&gp_timer_prov->mutex); + gp_timer_prov->exit = TRUE; + pthread_cond_broadcast(&gp_timer_prov->cond); + pthread_mutex_unlock(&gp_timer_prov->mutex); + pthread_join(tid, NULL); + + /* Destroy the mutex and condition variable. */ + pthread_mutex_destroy(&gp_timer_prov->mutex); + pthread_cond_destroy(&gp_timer_prov->cond); + + /* Free the memory and reset the global pointer. */ + free(gp_timer_prov); + gp_timer_prov = NULL; +} + +/* + * This is the internal work function executed by the timer's thread. + */ +static void *__cl_timer_prov_cb(IN void *const context) +{ + int ret; + cl_timer_t *p_timer; + + pthread_mutex_lock(&gp_timer_prov->mutex); + while (!gp_timer_prov->exit) { + if (cl_is_qlist_empty(&gp_timer_prov->queue)) { + /* Wait until we exit or a timer is queued. */ + /* cond wait does: + * pthread_cond_wait atomically unlocks the mutex (as per + * pthread_unlock_mutex) and waits for the condition variable + * cond to be signaled. The thread execution is suspended and + * does not consume any CPU time until the condition variable is + * signaled. The mutex must be locked by the calling thread on + * entrance to pthread_cond_wait. Before RETURNING TO THE + * CALLING THREAD, PTHREAD_COND_WAIT RE-ACQUIRES MUTEX (as per + * pthread_lock_mutex). + */ + ret = pthread_cond_wait(&gp_timer_prov->cond, + &gp_timer_prov->mutex); + } else { + /* + * The timer elements are on the queue in expiration order. + * Get the first in the list to determine how long to wait. + */ + + p_timer = + (cl_timer_t *) cl_qlist_head(&gp_timer_prov->queue); + ret = + pthread_cond_timedwait(&gp_timer_prov->cond, + &gp_timer_prov->mutex, + &p_timer->timeout); + + /* + Sleep again on every event other than timeout and invalid + Note: EINVAL means that we got behind. This can occur when + we are very busy... + */ + if (ret != ETIMEDOUT && ret != EINVAL) + continue; + + /* + * The timer expired. Check the state in case it was cancelled + * after it expired but before we got a chance to invoke the + * callback. + */ + if (p_timer->timer_state != CL_TIMER_QUEUED) + continue; + + /* + * Mark the timer as running to synchronize with its + * cancelation since we can't hold the mutex during the + * callback. + */ + p_timer->timer_state = CL_TIMER_RUNNING; + + /* Remove the item from the timer queue. */ + cl_qlist_remove_item(&gp_timer_prov->queue, + &p_timer->list_item); + pthread_mutex_unlock(&gp_timer_prov->mutex); + /* Invoke the callback. */ + p_timer->pfn_callback((void *)p_timer->context); + + /* Acquire the mutex again. */ + pthread_mutex_lock(&gp_timer_prov->mutex); + /* + * Only set the state to idle if the timer has not been accessed + * from the callback + */ + if (p_timer->timer_state == CL_TIMER_RUNNING) + p_timer->timer_state = CL_TIMER_IDLE; + + /* + * Signal any thread trying to manipulate the timer + * that expired. + */ + pthread_cond_signal(&p_timer->cond); + } + } + gp_timer_prov->thread = 0; + pthread_mutex_unlock(&gp_timer_prov->mutex); + pthread_exit(NULL); +} + +/* Timer implementation. */ +void cl_timer_construct(IN cl_timer_t * const p_timer) +{ + memset(p_timer, 0, sizeof(cl_timer_t)); + p_timer->state = CL_UNINITIALIZED; +} + +cl_status_t +cl_timer_init(IN cl_timer_t * const p_timer, + IN cl_pfn_timer_callback_t pfn_callback, + IN const void *const context) +{ + CL_ASSERT(p_timer); + CL_ASSERT(pfn_callback); + + cl_timer_construct(p_timer); + + if (!gp_timer_prov) + return (CL_ERROR); + + /* Store timer parameters. */ + p_timer->pfn_callback = pfn_callback; + p_timer->context = context; + + /* Mark the timer as idle. */ + p_timer->timer_state = CL_TIMER_IDLE; + + /* Create the condition variable that is used when cancelling a timer. */ + pthread_cond_init(&p_timer->cond, NULL); + + p_timer->state = CL_INITIALIZED; + + return (CL_SUCCESS); +} + +void cl_timer_destroy(IN cl_timer_t * const p_timer) +{ + CL_ASSERT(p_timer); + CL_ASSERT(cl_is_state_valid(p_timer->state)); + + if (p_timer->state == CL_INITIALIZED) + cl_timer_stop(p_timer); + + p_timer->state = CL_UNINITIALIZED; + + /* is it possible we have some threads waiting on the cond now? */ + pthread_cond_broadcast(&p_timer->cond); + pthread_cond_destroy(&p_timer->cond); + +} + +/* + * Return TRUE if timeout value 1 is earlier than timeout value 2. + */ +static __inline boolean_t +__cl_timer_is_earlier(IN struct timespec *p_timeout1, + IN struct timespec *p_timeout2) +{ + return ((p_timeout1->tv_sec < p_timeout2->tv_sec) || + ((p_timeout1->tv_sec == p_timeout2->tv_sec) && + (p_timeout1->tv_nsec < p_timeout2->tv_nsec))); +} + +/* + * Search for a timer with an earlier timeout than the one provided by + * the context. Both the list item and the context are pointers to + * a cl_timer_t structure with valid timeouts. + */ +static cl_status_t +__cl_timer_find(IN const cl_list_item_t * const p_list_item, + IN void *const context) +{ + cl_timer_t *p_in_list; + cl_timer_t *p_new; + + CL_ASSERT(p_list_item); + CL_ASSERT(context); + + p_in_list = (cl_timer_t *) p_list_item; + p_new = (cl_timer_t *) context; + + CL_ASSERT(p_in_list->state == CL_INITIALIZED); + CL_ASSERT(p_new->state == CL_INITIALIZED); + + CL_ASSERT(p_in_list->timer_state == CL_TIMER_QUEUED); + + if (__cl_timer_is_earlier(&p_in_list->timeout, &p_new->timeout)) + return (CL_SUCCESS); + + return (CL_NOT_FOUND); +} + +cl_status_t +cl_timer_start(IN cl_timer_t * const p_timer, IN const uint32_t time_ms) +{ + struct timeval curtime; + cl_list_item_t *p_list_item; + uint32_t delta_time = time_ms; + + CL_ASSERT(p_timer); + CL_ASSERT(p_timer->state == CL_INITIALIZED); + + pthread_mutex_lock(&gp_timer_prov->mutex); + /* Signal the timer provider thread to wake up. */ + pthread_cond_signal(&gp_timer_prov->cond); + + /* Remove the timer from the queue if currently queued. */ + if (p_timer->timer_state == CL_TIMER_QUEUED) + cl_qlist_remove_item(&gp_timer_prov->queue, + &p_timer->list_item); + + /* Get the current time */ +#ifndef timerclear +#define timerclear(tvp) (tvp)->tv_sec = (time_t)0, (tvp)->tv_usec = 0L +#endif + timerclear(&curtime); + gettimeofday(&curtime, NULL); + + /* do not do 0 wait ! */ + /* if (delta_time < 1000.0) {delta_time = 1000;} */ + + /* Calculate the timeout. */ + p_timer->timeout.tv_sec = curtime.tv_sec + (delta_time / 1000); + p_timer->timeout.tv_nsec = + (curtime.tv_usec + ((delta_time % 1000) * 1000)) * 1000; + + /* Add the timer to the queue. */ + if (cl_is_qlist_empty(&gp_timer_prov->queue)) { + /* The timer list is empty. Add to the head. */ + cl_qlist_insert_head(&gp_timer_prov->queue, + &p_timer->list_item); + } else { + /* Find the correct insertion place in the list for the timer. */ + p_list_item = cl_qlist_find_from_tail(&gp_timer_prov->queue, + __cl_timer_find, p_timer); + + /* Insert the timer. */ + cl_qlist_insert_next(&gp_timer_prov->queue, p_list_item, + &p_timer->list_item); + } + /* Set the state. */ + p_timer->timer_state = CL_TIMER_QUEUED; + pthread_mutex_unlock(&gp_timer_prov->mutex); + + return (CL_SUCCESS); +} + +void cl_timer_stop(IN cl_timer_t * const p_timer) +{ + CL_ASSERT(p_timer); + CL_ASSERT(p_timer->state == CL_INITIALIZED); + + pthread_mutex_lock(&gp_timer_prov->mutex); + switch (p_timer->timer_state) { + case CL_TIMER_RUNNING: + /* Wait for the callback to complete. */ + pthread_cond_wait(&p_timer->cond, &gp_timer_prov->mutex); + /* Timer could have been queued while we were waiting. */ + if (p_timer->timer_state != CL_TIMER_QUEUED) + break; + + case CL_TIMER_QUEUED: + /* Change the state of the timer. */ + p_timer->timer_state = CL_TIMER_IDLE; + /* Remove the timer from the queue. */ + cl_qlist_remove_item(&gp_timer_prov->queue, + &p_timer->list_item); + /* + * Signal the timer provider thread to move onto the + * next timer in the queue. + */ + pthread_cond_signal(&gp_timer_prov->cond); + break; + + case CL_TIMER_IDLE: + break; + } + pthread_mutex_unlock(&gp_timer_prov->mutex); +} + +cl_status_t +cl_timer_trim(IN cl_timer_t * const p_timer, IN const uint32_t time_ms) +{ + struct timeval curtime; + struct timespec newtime; + cl_status_t status; + + CL_ASSERT(p_timer); + CL_ASSERT(p_timer->state == CL_INITIALIZED); + + pthread_mutex_lock(&gp_timer_prov->mutex); + + /* Get the current time */ + timerclear(&curtime); + gettimeofday(&curtime, NULL); + + /* Calculate the timeout. */ + newtime.tv_sec = curtime.tv_sec + (time_ms / 1000); + newtime.tv_nsec = (curtime.tv_usec + ((time_ms % 1000) * 1000)) * 1000; + + if (p_timer->timer_state == CL_TIMER_QUEUED) { + /* If the old time is earlier, do not trim it. Just return. */ + if (__cl_timer_is_earlier(&p_timer->timeout, &newtime)) { + pthread_mutex_unlock(&gp_timer_prov->mutex); + return (CL_SUCCESS); + } + } + + /* Reset the timer to the new timeout value. */ + + pthread_mutex_unlock(&gp_timer_prov->mutex); + status = cl_timer_start(p_timer, time_ms); + + return (status); +} + +uint64_t cl_get_time_stamp(void) +{ + uint64_t tstamp; + struct timeval tv; + + timerclear(&tv); + gettimeofday(&tv, NULL); + + /* Convert the time of day into a microsecond timestamp. */ + tstamp = ((uint64_t) tv.tv_sec * 1000000) + (uint64_t) tv.tv_usec; + + return (tstamp); +} + +uint32_t cl_get_time_stamp_sec(void) +{ + struct timeval tv; + + timerclear(&tv); + gettimeofday(&tv, NULL); + + return (tv.tv_sec); +} diff --git a/contrib/ofed/management/opensm/complib/cl_vector.c b/contrib/ofed/management/opensm/complib/cl_vector.c new file mode 100644 index 000000000000..d9bcf3440db0 --- /dev/null +++ b/contrib/ofed/management/opensm/complib/cl_vector.c @@ -0,0 +1,561 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * This file contains ivector and isvector implementations. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/* + * Define the maximum size for array pages in an cl_vector_t. + * This size is in objects, not bytes. + */ +#define SVEC_MAX_PAGE_SIZE 0x1000 + +/* + * cl_vector_copy_general + * + * Description: + * copy operator used when size of the user object doesn't fit one of the + * other optimized copy functions. + * + * Inputs: + * p_src - source for copy + * + * Outputs: + * p_dest - destination for copy + * + * Returns: + * None + * + */ +static void +cl_vector_copy_general(OUT void *const p_dest, + IN const void *const p_src, IN const size_t size) +{ + memcpy(p_dest, p_src, size); +} + +/* + * cl_vector_copy8 + * + * Description: + * copy operator used when the user structure is only 8 bits long. + * + * Inputs: + * p_src - source for copy + * + * Outputs: + * p_dest - destination for copy + * + * Returns: + * None + * + */ +static void +cl_vector_copy8(OUT void *const p_dest, + IN const void *const p_src, IN const size_t size) +{ + CL_ASSERT(size == sizeof(uint8_t)); + UNUSED_PARAM(size); + + *(uint8_t *) p_dest = *(uint8_t *) p_src; +} + +/* + * cl_vector_copy16 + * + * Description: + * copy operator used when the user structure is only 16 bits long. + * + * Inputs: + * p_src - source for copy + * + * Outputs: + * p_dest - destination for copy + * + * Returns: + * None + * + */ +void +cl_vector_copy16(OUT void *const p_dest, + IN const void *const p_src, IN const size_t size) +{ + CL_ASSERT(size == sizeof(uint16_t)); + UNUSED_PARAM(size); + + *(uint16_t *) p_dest = *(uint16_t *) p_src; +} + +/* + * cl_vector_copy32 + * + * Description: + * copy operator used when the user structure is only 32 bits long. + * + * Inputs: + * p_src - source for copy + * + * Outputs: + * p_dest - destination for copy + * + * Returns: + * None + * + */ +void +cl_vector_copy32(OUT void *const p_dest, + IN const void *const p_src, IN const size_t size) +{ + CL_ASSERT(size == sizeof(uint32_t)); + UNUSED_PARAM(size); + + *(uint32_t *) p_dest = *(uint32_t *) p_src; +} + +/* + * cl_vector_copy64 + * + * Description: + * copy operator used when the user structure is only 64 bits long. + * + * Inputs: + * p_src - source for copy + * + * Outputs: + * p_dest - destination for copy + * + * Returns: + * None + * + */ +void +cl_vector_copy64(OUT void *const p_dest, + IN const void *const p_src, IN const size_t size) +{ + CL_ASSERT(size == sizeof(uint64_t)); + UNUSED_PARAM(size); + + *(uint64_t *) p_dest = *(uint64_t *) p_src; +} + +void cl_vector_construct(IN cl_vector_t * const p_vector) +{ + CL_ASSERT(p_vector); + + memset(p_vector, 0, sizeof(cl_vector_t)); + + p_vector->state = CL_UNINITIALIZED; +} + +cl_status_t +cl_vector_init(IN cl_vector_t * const p_vector, + IN const size_t min_size, + IN const size_t grow_size, + IN const size_t element_size, + IN cl_pfn_vec_init_t pfn_init OPTIONAL, + IN cl_pfn_vec_dtor_t pfn_dtor OPTIONAL, + IN const void *const context) +{ + cl_status_t status = CL_SUCCESS; + + CL_ASSERT(p_vector); + CL_ASSERT(element_size); + + cl_vector_construct(p_vector); + + p_vector->grow_size = grow_size; + p_vector->element_size = element_size; + p_vector->pfn_init = pfn_init; + p_vector->pfn_dtor = pfn_dtor; + p_vector->context = context; + + /* + * Try to choose a smart copy operator + * someday, we could simply let the users pass one in + */ + switch (element_size) { + case sizeof(uint8_t): + p_vector->pfn_copy = cl_vector_copy8; + break; + + case sizeof(uint16_t): + p_vector->pfn_copy = cl_vector_copy16; + break; + + case sizeof(uint32_t): + p_vector->pfn_copy = cl_vector_copy32; + break; + + case sizeof(uint64_t): + p_vector->pfn_copy = cl_vector_copy64; + break; + + default: + p_vector->pfn_copy = cl_vector_copy_general; + break; + } + + /* + * Set the state to initialized so that the call to set_size + * doesn't assert. + */ + p_vector->state = CL_INITIALIZED; + + /* Initialize the allocation list */ + cl_qlist_init(&p_vector->alloc_list); + + /* get the storage needed by the user */ + if (min_size) { + status = cl_vector_set_size(p_vector, min_size); + if (status != CL_SUCCESS) + cl_vector_destroy(p_vector); + } + + return (status); +} + +void cl_vector_destroy(IN cl_vector_t * const p_vector) +{ + size_t i; + void *p_element; + + CL_ASSERT(p_vector); + CL_ASSERT(cl_is_state_valid(p_vector->state)); + + /* Call the user's destructor for each element in the array. */ + if (p_vector->state == CL_INITIALIZED) { + if (p_vector->pfn_dtor) { + for (i = 0; i < p_vector->size; i++) { + p_element = p_vector->p_ptr_array[i]; + /* Sanity check! */ + CL_ASSERT(p_element); + p_vector->pfn_dtor(p_element, + (void *)p_vector->context); + } + } + + /* Deallocate the pages */ + while (!cl_is_qlist_empty(&p_vector->alloc_list)) + free(cl_qlist_remove_head(&p_vector->alloc_list)); + + /* Destroy the page vector. */ + if (p_vector->p_ptr_array) { + free(p_vector->p_ptr_array); + p_vector->p_ptr_array = NULL; + } + } + + p_vector->state = CL_UNINITIALIZED; +} + +cl_status_t +cl_vector_at(IN const cl_vector_t * const p_vector, + IN const size_t index, OUT void *const p_element) +{ + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + + /* Range check */ + if (index >= p_vector->size) + return (CL_INVALID_PARAMETER); + + cl_vector_get(p_vector, index, p_element); + return (CL_SUCCESS); +} + +cl_status_t +cl_vector_set(IN cl_vector_t * const p_vector, + IN const size_t index, IN void *const p_element) +{ + cl_status_t status; + void *p_dest; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + CL_ASSERT(p_element); + + /* Determine if the vector has room for this element. */ + if (index >= p_vector->size) { + /* Resize to accomodate the given index. */ + status = cl_vector_set_size(p_vector, index + 1); + + /* Check for failure on or before the given index. */ + if ((status != CL_SUCCESS) && (p_vector->size < index)) + return (status); + } + + /* At this point, the array is guaranteed to be big enough */ + p_dest = cl_vector_get_ptr(p_vector, index); + /* Sanity check! */ + CL_ASSERT(p_dest); + + /* Copy the data into the array */ + p_vector->pfn_copy(p_dest, p_element, p_vector->element_size); + + return (CL_SUCCESS); +} + +cl_status_t +cl_vector_set_capacity(IN cl_vector_t * const p_vector, + IN const size_t new_capacity) +{ + size_t new_elements; + size_t alloc_size; + size_t i; + cl_list_item_t *p_buf; + void *p_new_ptr_array; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + + /* Do we have to do anything here? */ + if (new_capacity <= p_vector->capacity) { + /* Nope */ + return (CL_SUCCESS); + } + + /* Allocate our pointer array. */ + p_new_ptr_array = malloc(new_capacity * sizeof(void *)); + if (!p_new_ptr_array) + return (CL_INSUFFICIENT_MEMORY); + else + memset(p_new_ptr_array, 0, new_capacity * sizeof(void *)); + + if (p_vector->p_ptr_array) { + /* Copy the old pointer array into the new. */ + memcpy(p_new_ptr_array, p_vector->p_ptr_array, + p_vector->capacity * sizeof(void *)); + + /* Free the old pointer array. */ + free(p_vector->p_ptr_array); + } + + /* Set the new array. */ + p_vector->p_ptr_array = p_new_ptr_array; + + /* + * We have to add capacity to the array. Determine how many + * elements to add. + */ + new_elements = new_capacity - p_vector->capacity; + /* Determine the allocation size for the new array elements. */ + alloc_size = new_elements * p_vector->element_size; + + p_buf = (cl_list_item_t *) malloc(alloc_size + sizeof(cl_list_item_t)); + if (!p_buf) + return (CL_INSUFFICIENT_MEMORY); + else + memset(p_buf, 0, alloc_size + sizeof(cl_list_item_t)); + + cl_qlist_insert_tail(&p_vector->alloc_list, p_buf); + /* Advance the buffer pointer past the list item. */ + p_buf++; + + for (i = p_vector->capacity; i < new_capacity; i++) { + p_vector->p_ptr_array[i] = p_buf; + /* Move the buffer pointer to the next element. */ + p_buf = (void *)(((uint8_t *) p_buf) + p_vector->element_size); + } + + /* Update the vector with the new capactity. */ + p_vector->capacity = new_capacity; + + return (CL_SUCCESS); +} + +cl_status_t +cl_vector_set_size(IN cl_vector_t * const p_vector, IN const size_t size) +{ + cl_status_t status; + size_t new_capacity; + size_t index; + void *p_element; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + + /* Check to see if the requested size is the same as the existing size. */ + if (size == p_vector->size) + return (CL_SUCCESS); + + /* Determine if the vector has room for this element. */ + if (size >= p_vector->capacity) { + if (!p_vector->grow_size) + return (CL_INSUFFICIENT_MEMORY); + + /* Calculate the new capacity, taking into account the grow size. */ + new_capacity = size; + if (size % p_vector->grow_size) { + /* Round up to nearest grow_size boundary. */ + new_capacity += p_vector->grow_size - + (size % p_vector->grow_size); + } + + status = cl_vector_set_capacity(p_vector, new_capacity); + if (status != CL_SUCCESS) + return (status); + } + + /* Are we growing the array and need to invoke an initializer callback? */ + if (size > p_vector->size && p_vector->pfn_init) { + for (index = p_vector->size; index < size; index++) { + /* Get a pointer to this element */ + p_element = cl_vector_get_ptr(p_vector, index); + + /* Call the user's initializer and trap failures. */ + status = + p_vector->pfn_init(p_element, + (void *)p_vector->context); + if (status != CL_SUCCESS) { + /* Call the destructor for this object */ + if (p_vector->pfn_dtor) + p_vector->pfn_dtor(p_element, + (void *)p_vector-> + context); + + /* Return the failure status to the caller. */ + return (status); + } + + /* The array just grew by one element */ + p_vector->size++; + } + } else if (p_vector->pfn_dtor) { + /* The array is shrinking and there is a destructor to invoke. */ + for (index = size; index < p_vector->size; index++) { + /* compute the address of the new elements */ + p_element = cl_vector_get_ptr(p_vector, index); + /* call the user's destructor */ + p_vector->pfn_dtor(p_element, + (void *)p_vector->context); + } + } + + p_vector->size = size; + return (CL_SUCCESS); +} + +cl_status_t +cl_vector_set_min_size(IN cl_vector_t * const p_vector, + IN const size_t min_size) +{ + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + + if (min_size > p_vector->size) { + /* We have to resize the array */ + return (cl_vector_set_size(p_vector, min_size)); + } + + /* We didn't have to do anything */ + return (CL_SUCCESS); +} + +void +cl_vector_apply_func(IN const cl_vector_t * const p_vector, + IN cl_pfn_vec_apply_t pfn_callback, + IN const void *const context) +{ + size_t i; + void *p_element; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + CL_ASSERT(pfn_callback); + + for (i = 0; i < p_vector->size; i++) { + p_element = cl_vector_get_ptr(p_vector, i); + pfn_callback(i, p_element, (void *)context); + } +} + +size_t +cl_vector_find_from_start(IN const cl_vector_t * const p_vector, + IN cl_pfn_vec_find_t pfn_callback, + IN const void *const context) +{ + size_t i; + void *p_element; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + CL_ASSERT(pfn_callback); + + for (i = 0; i < p_vector->size; i++) { + p_element = cl_vector_get_ptr(p_vector, i); + /* Invoke the callback */ + if (pfn_callback(i, p_element, (void *)context) == CL_SUCCESS) + break; + } + return (i); +} + +size_t +cl_vector_find_from_end(IN const cl_vector_t * const p_vector, + IN cl_pfn_vec_find_t pfn_callback, + IN const void *const context) +{ + size_t i; + void *p_element; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + CL_ASSERT(pfn_callback); + + i = p_vector->size; + + while (i) { + /* Get a pointer to the element in the array. */ + p_element = cl_vector_get_ptr(p_vector, --i); + CL_ASSERT(p_element); + + /* Invoke the callback for the current element. */ + if (pfn_callback(i, p_element, (void *)context) == CL_SUCCESS) + return (i); + } + + return (p_vector->size); +} diff --git a/contrib/ofed/management/opensm/complib/ib_statustext.c b/contrib/ofed/management/opensm/complib/ib_statustext.c new file mode 100644 index 000000000000..52b2adc74377 --- /dev/null +++ b/contrib/ofed/management/opensm/complib/ib_statustext.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Defines string to decode ib_api_status_t return values. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +/* ib_api_status_t values above converted to text for easier printing. */ +const char *ib_error_str[] = { + "IB_SUCCESS", + "IB_INSUFFICIENT_RESOURCES", + "IB_INSUFFICIENT_MEMORY", + "IB_INVALID_PARAMETER", + "IB_INVALID_SETTING", + "IB_NOT_FOUND", + "IB_TIMEOUT", + "IB_CANCELED", + "IB_INTERRUPTED", + "IB_INVALID_PERMISSION", + "IB_UNSUPPORTED", + "IB_OVERFLOW", + "IB_MAX_MCAST_QPS_REACHED", + "IB_INVALID_QP_STATE", + "IB_INVALID_EEC_STATE", + "IB_INVALID_APM_STATE", + "IB_INVALID_PORT_STATE", + "IB_INVALID_STATE", + "IB_RESOURCE_BUSY", + "IB_INVALID_PKEY", + "IB_INVALID_LKEY", + "IB_INVALID_RKEY", + "IB_INVALID_MAX_WRS", + "IB_INVALID_MAX_SGE", + "IB_INVALID_CQ_SIZE", + "IB_INVALID_SERVICE_TYPE", + "IB_INVALID_GID", + "IB_INVALID_LID", + "IB_INVALID_GUID", + "IB_INVALID_CA_HANDLE", + "IB_INVALID_AV_HANDLE", + "IB_INVALID_CQ_HANDLE", + "IB_INVALID_EEC_HANDLE", + "IB_INVALID_QP_HANDLE", + "IB_INVALID_PD_HANDLE", + "IB_INVALID_MR_HANDLE", + "IB_INVALID_MW_HANDLE", + "IB_INVALID_RDD_HANDLE", + "IB_INVALID_MCAST_HANDLE", + "IB_INVALID_CALLBACK", + "IB_INVALID_AL_HANDLE", + "IB_INVALID_HANDLE", + "IB_ERROR", + "IB_REMOTE_ERROR", /* Infiniband Access Layer */ + "IB_VERBS_PROCESSING_DONE", + "IB_INVALID_WR_TYPE", + "IB_QP_IN_TIMEWAIT", + "IB_EE_IN_TIMEWAIT", + "IB_INVALID_PORT", + "IB_NOT_DONE", + "IB_UNKNOWN_ERROR" +}; + +/* ib_async_event_t values above converted to text for easier printing. */ +const char *ib_async_event_str[] = { + "IB_AE_SQ_ERROR", + "IB_AE_SQ_DRAINED", + "IB_AE_RQ_ERROR", + "IB_AE_CQ_ERROR", + "IB_AE_QP_FATAL", + "IB_AE_QP_COMM", + "IB_AE_QP_APM", + "IB_AE_EEC_FATAL", + "IB_AE_EEC_COMM", + "IB_AE_EEC_APM", + "IB_AE_LOCAL_FATAL", + "IB_AE_PKEY_TRAP", + "IB_AE_QKEY_TRAP", + "IB_AE_MKEY_TRAP", + "IB_AE_PORT_TRAP", + "IB_AE_SYSIMG_GUID_TRAP", + "IB_AE_BUF_OVERRUN", + "IB_AE_LINK_INTEGRITY", + "IB_AE_FLOW_CTRL_ERROR", + "IB_AE_BKEY_TRAP", + "IB_AE_QP_APM_ERROR", + "IB_AE_EEC_APM_ERROR", + "IB_AE_WQ_REQ_ERROR", + "IB_AE_WQ_ACCESS_ERROR", + "IB_AE_PORT_ACTIVE", /* ACTIVE STATE */ + "IB_AE_PORT_DOWN", /* INIT", ARMED", DOWN */ + "IB_AE_UNKNOWN" +}; + +const char *ib_wc_status_str[] = { + "IB_WCS_SUCCESS", + "IB_WCS_LOCAL_LEN_ERR", + "IB_WCS_LOCAL_OP_ERR", + "IB_WCS_LOCAL_EEC_OP_ERR", + "IB_WCS_LOCAL_PROTECTION_ERR", + "IB_WCS_WR_FLUSHED_ERR", + "IB_WCS_MEM_WINDOW_BIND_ERR", + "IB_WCS_REM_ACCESS_ERR", + "IB_WCS_REM_OP_ERR", + "IB_WCS_RNR_RETRY_ERR", + "IB_WCS_TIMEOUT_RETRY_ERR", + "IB_WCS_REM_INVALID_REQ_ERR", + "IB_WCS_REM_INVALID_RD_REQ_ERR", + "IB_WCS_INVALID_EECN", + "IB_WCS_INVALID_EEC_STATE", + "IB_WCS_UNMATCHED_RESPONSE", /* InfiniBand Access Layer */ + "IB_WCS_CANCELED", /* InfiniBand Access Layer */ + "IB_WCS_UNKNOWN" +}; diff --git a/contrib/ofed/management/opensm/complib/libosmcomp.map b/contrib/ofed/management/opensm/complib/libosmcomp.map new file mode 100644 index 000000000000..788eb2ad3db2 --- /dev/null +++ b/contrib/ofed/management/opensm/complib/libosmcomp.map @@ -0,0 +1,154 @@ +OSMCOMP_2.3 { + global: + complib_init; + complib_exit; + cl_is_debug; + cl_disp_construct; + cl_disp_init; + cl_disp_destroy; + cl_disp_register; + cl_disp_unregister; + cl_disp_post; + cl_disp_shutdown; + cl_disp_get_queue_status; + cl_event_construct; + cl_event_init; + cl_event_destroy; + cl_event_signal; + cl_event_reset; + cl_event_wait_on; + cl_event_wheel_construct; + cl_event_wheel_init; + cl_event_wheel_init_ex; + cl_event_wheel_destroy; + cl_event_wheel_dump; + cl_event_wheel_reg; + cl_event_wheel_unreg; + cl_event_wheel_num_regs; + cl_qlist_insert_array_head; + cl_qlist_insert_array_tail; + cl_qlist_insert_list_head; + cl_qlist_insert_list_tail; + cl_is_item_in_qlist; + cl_qlist_find_next; + cl_qlist_find_prev; + cl_qlist_apply_func; + cl_qlist_move_items; + cl_list_construct; + cl_list_init; + cl_list_destroy; + cl_list_remove_object; + cl_is_object_in_list; + cl_list_insert_array_head; + cl_list_insert_array_tail; + cl_list_find_from_head; + cl_list_find_from_tail; + cl_list_apply_func; + cl_log_event; + cl_qmap_init; + cl_qmap_get; + cl_qmap_get_next; + cl_qmap_apply_func; + cl_qmap_insert; + cl_qmap_remove_item; + cl_qmap_remove; + cl_qmap_merge; + cl_qmap_delta; + cl_map_construct; + cl_map_init; + cl_map_destroy; + cl_map_insert; + cl_map_get; + cl_map_get_next; + cl_map_remove_item; + cl_map_remove; + cl_map_remove_all; + cl_map_merge; + cl_map_delta; + cl_fmap_init; + cl_fmap_get; + cl_fmap_get_next; + cl_fmap_apply_func; + cl_fmap_insert; + cl_fmap_remove_item; + cl_fmap_remove; + cl_fmap_merge; + cl_fmap_delta; + cl_qcpool_construct; + cl_qcpool_init; + cl_qcpool_destroy; + cl_qcpool_grow; + cl_qcpool_get; + cl_qcpool_get_tail; + cl_qpool_construct; + cl_qpool_init; + cl_cpool_construct; + cl_cpool_init; + cl_pool_construct; + cl_pool_init; + cl_ptr_vector_construct; + cl_ptr_vector_init; + cl_ptr_vector_destroy; + cl_ptr_vector_at; + cl_ptr_vector_set; + cl_ptr_vector_remove; + cl_ptr_vector_set_capacity; + cl_ptr_vector_set_size; + cl_ptr_vector_set_min_size; + cl_ptr_vector_apply_func; + cl_ptr_vector_find_from_start; + cl_ptr_vector_find_from_end; + cl_spinlock_construct; + cl_spinlock_init; + cl_spinlock_destroy; + cl_spinlock_acquire; + cl_spinlock_release; + cl_status_text; + cl_thread_construct; + cl_thread_init; + cl_thread_destroy; + cl_thread_suspend; + cl_thread_stall; + cl_proc_count; + cl_is_current_thread; + cl_thread_pool_construct; + cl_thread_pool_init; + cl_thread_pool_destroy; + cl_thread_pool_signal; + __cl_timer_prov_create; + __cl_timer_prov_destroy; + cl_timer_construct; + cl_timer_init; + cl_timer_destroy; + cl_timer_start; + cl_timer_stop; + cl_timer_trim; + cl_get_time_stamp; + cl_get_time_stamp_sec; + cl_vector_copy_general; + cl_vector_copy16; + cl_vector_copy32; + cl_vector_copy64; + cl_vector_construct; + cl_vector_init; + cl_vector_destroy; + cl_vector_at; + cl_vector_set; + cl_vector_set_capacity; + cl_vector_set_size; + cl_vector_set_min_size; + cl_vector_apply_func; + cl_vector_find_from_start; + cl_vector_find_from_end; + cl_atomic_spinlock; + cl_atomic_dec; + ib_error_str; + ib_async_event_str; + ib_wc_status_str; + open_node_name_map; + close_node_name_map; + parse_node_map; + remap_node_name; + clean_nodedesc; + local: *; +}; diff --git a/contrib/ofed/management/opensm/complib/libosmcomp.ver b/contrib/ofed/management/opensm/complib/libosmcomp.ver new file mode 100644 index 000000000000..f076585ca04b --- /dev/null +++ b/contrib/ofed/management/opensm/complib/libosmcomp.ver @@ -0,0 +1,9 @@ +# In this file we track the current API version +# of the complib library interface +# The version is built of the following +# tree numbers: +# API_REV:RUNNING_REV:AGE +# API_REV - advance on any added API +# RUNNING_REV - advance any change to the vendor files +# AGE - number of backward versions the API still supports +LIBVERSION=2:4:0 diff --git a/contrib/ofed/management/opensm/config/osmvsel.m4 b/contrib/ofed/management/opensm/config/osmvsel.m4 new file mode 100644 index 000000000000..c7798ccba5d3 --- /dev/null +++ b/contrib/ofed/management/opensm/config/osmvsel.m4 @@ -0,0 +1,259 @@ + +dnl osmvsel.m4: an autoconf for OpenSM Vendor Selection option +dnl +dnl To use this macro, just do OPENIB_APP_OSMV_SEL. +dnl the new configure option --with-osmv will be defined. +dnl current supported values are: openib(default),sim,gen1 +dnl The following variables are defined: +dnl OSMV_LDADD - LDADD additional libs for linking the vendor lib +AC_DEFUN([OPENIB_APP_OSMV_SEL], [ +# --- BEGIN OPENIB_APP_OSMV_SEL --- + +dnl Define a way for the user to provide the osm vendor type +AC_ARG_WITH(osmv, + AC_HELP_STRING([--with-osmv=], + [define the osm vendor type to build]), +AC_MSG_NOTICE(Using OSM Vendor Type:$with_osmv), +with_osmv="openib") + +dnl Define a way for the user to provide the path to the ibumad installation +AC_ARG_WITH(umad-prefix, + AC_HELP_STRING([--with-umad-prefix=], + [define the dir used as prefix for ibumad installation]), +AC_MSG_NOTICE(Using ibumad installation prefix:$with_umad_prefix), +with_umad_prefix="") + +dnl Define a way for the user to provide the path to the ibumad includes +AC_ARG_WITH(umad-includes, + AC_HELP_STRING([--with-umad-includes=], + [define the dir where ibumad includes are installed]), +AC_MSG_NOTICE(Using ibumad includes from:$with_umad_includes), +with_umad_includes="") + +if test x$with_umad_includes = x; then + if test x$with_umad_prefix != x; then + with_umad_includes=$with_umad_prefix/include + fi +fi + +dnl Define a way for the user to provide the path to the ibumad libs +AC_ARG_WITH(umad-libs, + AC_HELP_STRING([--with-umad-libs=], + [define the dir where ibumad libs are installed]), +AC_MSG_NOTICE(Using ibumad libs from:$with_umad_libs), +with_umad_libs="") + +if test x$with_umad_libs = x; then + if test x$with_umad_prefix != x; then +dnl Should we use lib64 or lib + if test "$(uname -m)" = "x86_64" -o "$(uname -m)" = "ppc64"; then + with_umad_libs=$with_umad_prefix/lib64 + else + with_umad_libs=$with_umad_prefix/lib + fi + fi +fi + +dnl Define a way for the user to provide the path to the simulator installation +AC_ARG_WITH(sim, + AC_HELP_STRING([--with-sim=], + [define the simulator prefix for building sim vendor (default /usr)]), +AC_MSG_NOTICE(Using Simulator from:$with_sim), +with_sim="/usr") + +dnl based on the with_osmv we can try the vendor flag +if test $with_osmv = "openib"; then + AC_DEFINE(OSM_VENDOR_INTF_OPENIB, 1, [Define as 1 for OpenIB vendor]) + OSMV_INCLUDES="-I\$(srcdir)/../include -I\$(srcdir)/../../libibcommon/include -I\$(srcdir)/../../libibumad/include -I\$(includedir)" + OSMV_LDADD="-L\$(abs_srcdir)/../../libibumad/.libs -L\$(abs_srcdir)/../../libibcommon/.libs -L\$(libdir) -libumad -libcommon" + + if test "x$with_umad_libs" != "x"; then + OSMV_LDADD="-L$with_umad_libs $OSMV_LDADD" + fi + + if test "x$with_umad_includes" != "x"; then + OSMV_INCLUDES="-I$with_umad_includes $OSMV_INCLUDES" + fi + AC_DEFINE(DUAL_SIDED_RMPP, 1, [Define as 1 if you want Dual Sided RMPP Support]) +elif test $with_osmv = "sim" ; then + AC_DEFINE(OSM_VENDOR_INTF_SIM, 1, [Define as 1 for sim vendor]) + OSMV_INCLUDES="-I$with_sim/include -I\$(srcdir)/../include" + OSMV_LDADD="-L$with_sim/lib -libmscli" +elif test $with_osmv = "gen1"; then + AC_DEFINE(OSM_VENDOR_INTF_TS, 1, [Define as 1 for ts vendor]) + + if test -z $MTHOME; then + MTHOME=/usr/local/ibgd/driver/infinihost + fi + + OSMV_INCLUDES="-I$MTHOME/include -I\$(srcdir)/../include" + + dnl we need to find the TS includes somewhere... + osmv_found=0 + if test -z $TSHOME; then + osmv_dir=`uname -r|sed 's/-smp//'` + osmv_dir_smp=`uname -r` + for d in /usr/src/linux-$osmv_dir /usr/src/linux-$osmv_dir_smp /lib/modules/$osmv_dir/build /lib/modules/$osmv_dir_smp/build/; do + if test -f $d/drivers/infiniband/include/ts_ib_useraccess.h; then + OSMV_INCLUDES="$OSMV_INCLUDES -I$d/drivers/infiniband/include" + osmv_found=1 + fi + done + else + if test -f $TSHOME/ts_ib_useraccess.h; then + OSMV_INCLUDES="$OSMV_INCLUDES -I$TSHOME" + osmv_found=1 + fi + fi + if test $osmv_found = 0; then + AC_MSG_ERROR([Fail to find gen1 include files dir]) + fi + OSMV_LDADD="-L/usr/local/ibgd/driver/infinihost/lib -lvapi -lmosal -lmtl_common -lmpga" +elif test $with_osmv = "vapi"; then + AC_DEFINE(OSM_VENDOR_INTF_MTL, 1, [Define as 1 for vapi vendor]) + OSMV_INCLUDES="-I/usr/mellanox/include -I/usr/include -I\$(srcdir)/../include" + OSMV_LDADD="-L/usr/lib -L/usr/mellanox/lib -lib_mgt -lvapi -lmosal -lmtl_common -lmpga" +else + AC_MSG_ERROR([Invalid Vendor Type provided:$with_osmv should be either openib,sim,gen1]) +fi + +AM_CONDITIONAL(OSMV_VAPI, test $with_osmv = "vapi") +AM_CONDITIONAL(OSMV_GEN1, test $with_osmv = "gen1") +AM_CONDITIONAL(OSMV_SIM, test $with_osmv = "sim") +AM_CONDITIONAL(OSMV_OPENIB, test $with_osmv = "openib") +AC_DEFINE(VENDOR_RMPP_SUPPORT, 1, [Define as 1 if you want Vendor RMPP Support]) + +AC_SUBST(OSMV_LDADD) +AC_SUBST(OSMV_INCLUDES) + +# --- END OPENIB_APP_OSMV_SEL --- +]) dnl OPENIB_APP_OSMV_SEL + +dnl Check for the vendor lib dependency +AC_DEFUN([OPENIB_APP_OSMV_CHECK_LIB], [ +# --- BEGIN OPENIB_APP_OSMV_CHECK_LIB --- +if test "$disable_libcheck" != "yes"; then + + dnl based on the with_osmv we can try the vendor flag + if test $with_osmv = "openib"; then + LDADD="$LDADD $OSMV_LDADD" + AC_CHECK_LIB(ibumad, umad_init, [], + AC_MSG_ERROR([umad_init() not found. libosmvendor of type openib requires libibumad.])) + elif test $with_osmv = "sim" ; then + LDFLAGS="$LDFLAGS -L$with_sim/lib" + AC_CHECK_FILE([$with_sim/lib/libibmscli.a], [], + AC_MSG_ERROR([ibms_bind() not found. libosmvendor of type sim requires libibmscli.])) + elif test $with_osmv = "gen1"; then + LDFLAGS="$LDFLAGS -L$MTHOME/lib -L$MTHOME/lib64 -lmosal -lmtl_common -lmpga" + AC_CHECK_LIB(vapi, vipul_init, [], + AC_MSG_ERROR([vipul_init() not found. libosmvendor of type gen1 requires libvapi.])) + elif test $with_osmv != "vapi"; then + AC_MSG_ERROR([OSM Vendor Type not defined: please make sure OPENIB_APP_OSMV SEL is run before CHECK_LIB]) + fi +fi +# --- END OPENIB_APP_OSMV_CHECK_LIB --- +]) dnl OPENIB_APP_OSMV_CHECK_LIB + +dnl Check for the vendor lib dependency +AC_DEFUN([OPENIB_APP_OSMV_CHECK_HEADER], [ +# --- BEGIN OPENIB_APP_OSMV_CHECK_HEADER --- + +dnl we might be required to ignore this check +if test "$disable_libcheck" != "yes"; then + if test $with_osmv = "openib"; then + osmv_headers=infiniband/umad.h + elif test $with_osmv = "sim" ; then + osmv_headers=ibmgtsim/ibms_client_api.h + elif test $with_osmv = "gen1"; then + osmv_headers= + elif test $with_osmv = "vapi"; then + osmv_headers=vapi.h + else + AC_MSG_ERROR([OSM Vendor Type not defined: please make sure OPENIB_APP_OSMV SEL is run before CHECK_HEADER]) + fi + if test "x$osmv_headers" != "x"; then + AC_CHECK_HEADERS($osmv_headers) + fi +fi +# --- END OPENIB_APP_OSMV_CHECK_HEADER --- +]) dnl OPENIB_APP_OSMV_CHECK_HEADER + +dnl Check if they want the socket console +AC_DEFUN([OPENIB_OSM_CONSOLE_SOCKET_SEL], [ +# --- BEGIN OPENIB_OSM_CONSOLE_SOCKET_SEL --- + +dnl Console over a socket connection +AC_ARG_ENABLE(console-socket, +[ --enable-console-socket Enable a console socket, requires tcp_wrappers (default no)], +[case $enableval in + yes) console_socket=yes ;; + no) console_socket=no ;; + esac], + console_socket=no) +if test $console_socket = yes; then + AC_CHECK_LIB(wrap, request_init, [], + AC_MSG_ERROR([request_init() not found. console-socket requires libwrap.])) + AC_DEFINE(ENABLE_OSM_CONSOLE_SOCKET, + 1, + [Define as 1 if you want to enable a console on a socket connection]) +fi +# --- END OPENIB_OSM_CONSOLE_SOCKET_SEL --- +]) dnl OPENIB_OSM_CONSOLE_SOCKET_SEL + +dnl Check if they want the PerfMgr +AC_DEFUN([OPENIB_OSM_PERF_MGR_SEL], [ +# --- BEGIN OPENIB_OSM_PERF_MGR_SEL --- + +dnl enable the perf-mgr +AC_ARG_ENABLE(perf-mgr, +[ --enable-perf-mgr Enable the performance manager (default no)], + [case $enableval in + yes) perf_mgr=yes ;; + no) perf_mgr=no ;; + esac], + perf_mgr=no) +AC_ARG_ENABLE(perf-mgr-profile, +[ --enable-perf-mgr-profile Enable the performance manager profiling (default no)], + [case $enableval in + yes) perf_mgr_profile=yes ;; + no) perf_mgr_profile=no ;; + esac], + perf_mgr_profile=no) +if test $perf_mgr = yes; then + AC_DEFINE(ENABLE_OSM_PERF_MGR, + 1, + [Define as 1 if you want to enable the performance manager]) + if test $perf_mgr_profile = yes; then + AC_DEFINE(ENABLE_OSM_PERF_MGR_PROFILE, + 1, + [Define as 1 if you want to enable the performance manager profiling code]) + fi +fi +# --- END OPENIB_OSM_PERF_MGR_SEL --- +]) dnl OPENIB_OSM_PERF_MGR_SEL + + +dnl Check if they want the event plugin +AC_DEFUN([OPENIB_OSM_DEFAULT_EVENT_PLUGIN_SEL], [ +# --- BEGIN OPENIB_OSM_DEFAULT_EVENT_PLUGIN_SEL --- + +dnl enable the default-event-plugin +AC_ARG_ENABLE(default-event-plugin, +[ --enable-default-event-plugin Enable a default event plugin "osmeventplugin" (default no)], + [case $enableval in + yes) default_event_plugin=yes ;; + no) default_event_plugin=no ;; + esac], + default_event_plugin=no) +if test $default_event_plugin = yes; then + AC_DEFINE(ENABLE_OSM_DEFAULT_EVENT_PLUGIN, + 1, + [Define as 1 if you want to enable the event plugin]) + DEFAULT_EVENT_PLUGIN=osmeventplugin +else + DEFAULT_EVENT_PLUGIN= +fi +AC_SUBST([DEFAULT_EVENT_PLUGIN]) + +# --- END OPENIB_OSM_DEFAULT_EVENT_PLUGIN_SEL --- +]) dnl OPENIB_OSM_DEFAULT_EVENT_PLUGIN_SEL diff --git a/contrib/ofed/management/opensm/configure.in b/contrib/ofed/management/opensm/configure.in new file mode 100644 index 000000000000..44790311ee0d --- /dev/null +++ b/contrib/ofed/management/opensm/configure.in @@ -0,0 +1,232 @@ +dnl Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(opensm, 3.3.0, general@lists.openfabrics.org) +AC_CONFIG_SRCDIR([opensm/osm_opensm.c]) +AC_CONFIG_AUX_DIR(config) +AC_CONFIG_HEADERS(include/config.h include/opensm/osm_config.h) +AM_INIT_AUTOMAKE + +AC_SUBST(RELEASE, ${RELEASE:-unknown}) +AC_SUBST(TARBALL, ${TARBALL:-${PACKAGE}-${VERSION}.tar.gz}) + +dnl NOTE: AC_DEFINE's and AC_DEFINE_UNQUOTED's which are used in header files +dnl MUST have a corresponding entry in include/opensm/osm_config.h.in to +dnl ensure plugin compatibility. +AC_DEFINE(_OSM_CONFIG_H_, 1, mark config.h inclusion) + +dnl Defines the Language +AC_LANG_C + +dnl Required for cases make defines a MAKE=make ??? Why +AC_PROG_MAKE_SET +AC_PROG_CC +AC_PROG_LIBTOOL +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_YACC +AC_PROG_LEX + +AC_CHECK_PROGS(_YACC_,$YACC,none) +if test "$_YACC_" = "none" +then + AC_MSG_ERROR([No bison/byacc/yacc found.]) +fi + +AC_CHECK_PROGS(_LEX_,$LEX,none) +if test "$_LEX_" = "none" +then + AC_MSG_ERROR([No flex/lex found.]) +fi + +dnl Checks for libraries +AC_CHECK_LIB(pthread, pthread_mutex_init, [], + AC_MSG_ERROR([pthread_mutex_init() not found. libosmcomp requires libpthread.])) +AC_CHECK_LIB(dl, dlopen, [], + AC_MSG_ERROR([dlopen() not found. OpenSM requires libdl.])) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_HEADER_TIME +AC_STRUCT_TM +AC_C_VOLATILE + +dnl We use --version-script with ld if possible +AC_CACHE_CHECK(whether ld accepts --version-script, ac_cv_version_script, +if test -n "`$LD --help < /dev/null 2>/dev/null | grep version-script`"; then + ac_cv_version_script=yes +else + ac_cv_version_script=no +fi) +AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$ac_cv_version_script" = "yes") + +dnl Define an input config option to control debug compile +AC_ARG_ENABLE(debug, [ --enable-debug Turn on debugging], +[case "${enableval}" in + yes) debug=true ;; + no) debug=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;; +esac],debug=false) +if test x$debug = xtrue ; then + AC_DEFINE(OSM_DEBUG, 1, [ define 1 if OpenSM build is in a debug mode ]) +fi +AM_CONDITIONAL(DEBUG, test x$debug = xtrue) + +AC_ARG_ENABLE(libcheck, [ --disable-libcheck do not test for presence of ib libraries], +[if test x$enableval = xno ; then + disable_libcheck=yes +fi]) + +dnl check if they want the socket console +OPENIB_OSM_CONSOLE_SOCKET_SEL + +dnl select performance manager or not +OPENIB_OSM_PERF_MGR_SEL + +dnl resolve config dir. +conf_dir_tmp1="`eval echo ${sysconfdir} | sed 's/^NONE/$ac_default_prefix/'`" +SYS_CONFIG_DIR="`eval echo $conf_dir_tmp1`" + +dnl Check for a different subdir for the config files. +OPENSM_CONFIG_SUB_DIR=opensm +AC_MSG_CHECKING(for --with-opensm-conf-sub-dir) +AC_ARG_WITH(opensm-conf-sub-dir, + AC_HELP_STRING([--with-opensm-conf-sub-dir=dir], + [define a directory name for opensm's conf files / (default "opensm")]), + [ case "$withval" in + no) + ;; + *) + OPENSM_CONFIG_SUB_DIR=$withval + ;; + esac ] +) +dnl this needs to be configured for rpmbuilds separate from the full path +dnl "OPENSM_CONFIG_DIR" +AC_SUBST(OPENSM_CONFIG_SUB_DIR) + +OPENSM_CONFIG_DIR=$SYS_CONFIG_DIR/$OPENSM_CONFIG_SUB_DIR +AC_MSG_RESULT($OPENSM_CONFIG_DIR) +AC_DEFINE_UNQUOTED(OPENSM_CONFIG_DIR, + ["$OPENSM_CONFIG_DIR"], + [Define OpenSM config directory]) +AC_SUBST(OPENSM_CONFIG_DIR) + +dnl Check for a different default OpenSm config file +OPENSM_CONFIG_FILE=opensm.conf +AC_MSG_CHECKING(for --with-opensm-conf-file ) +AC_ARG_WITH(opensm-conf-file, + AC_HELP_STRING([--with-opensm-conf-file=file], + [define a default OpenSM config file (default opensm.conf)]), + [ case "$withval" in + no) + ;; + *) + OPENSM_CONFIG_FILE=$withval + ;; + esac ] +) +AC_MSG_RESULT(${OPENSM_CONFIG_FILE}) +AC_DEFINE_UNQUOTED(HAVE_DEFAULT_OPENSM_CONFIG_FILE, + ["$OPENSM_CONFIG_DIR/$OPENSM_CONFIG_FILE"], + [Define a default OpenSM config file]) +AC_SUBST(OPENSM_CONFIG_FILE) + +dnl Check for a different default node name map file +NODENAMEMAPFILE=ib-node-name-map +AC_MSG_CHECKING(for --with-node-name-map ) +AC_ARG_WITH(node-name-map, + AC_HELP_STRING([--with-node-name-map=file], + [define a default node name map file (default ib-node-name-map)]), + [ case "$withval" in + no) + ;; + *) + NODENAMEMAPFILE=$withval + ;; + esac ] +) +AC_MSG_RESULT($NODENAMEMAPFILE) +AC_DEFINE_UNQUOTED(HAVE_DEFAULT_NODENAME_MAP, + ["$OPENSM_CONFIG_DIR/$NODENAMEMAPFILE"], + [Define a default node name map file]) +AC_SUBST(NODENAMEMAPFILE) + +dnl Check for a different partition conf file +PARTITION_CONFIG_FILE=partitions.conf +AC_MSG_CHECKING(for --with-partitions-conf) +AC_ARG_WITH(partitions-conf, + AC_HELP_STRING([--with-partitions-conf=file], + [define a partitions config file (default partitions.conf)]), + [ case "$withval" in + no) + ;; + *) + PARTITION_CONFIG_FILE=$withval + ;; + esac ] +) +AC_MSG_RESULT($PARTITION_CONFIG_FILE) +AC_DEFINE_UNQUOTED(HAVE_DEFAULT_PARTITION_CONFIG_FILE, + ["$OPENSM_CONFIG_DIR/$PARTITION_CONFIG_FILE"], + [Define a Partition config file]) +AC_SUBST(PARTITION_CONFIG_FILE) + +dnl Check for a different QOS policy file +QOS_POLICY_FILE=qos-policy.conf +AC_MSG_CHECKING(for --with-qos-policy-conf) +AC_ARG_WITH(qos-policy-conf, + AC_HELP_STRING([--with-qos-policy-conf=file], + [define a QOS policy config file (default qos-policy.conf)]), + [ case "$withval" in + no) + ;; + *) + QOS_POLICY_FILE=$withval + ;; + esac ] +) +AC_MSG_RESULT($QOS_POLICY_FILE) +AC_DEFINE_UNQUOTED(HAVE_DEFAULT_QOS_POLICY_FILE, + ["$OPENSM_CONFIG_DIR/$QOS_POLICY_FILE"], + [Define a QOS policy config file]) +AC_SUBST(QOS_POLICY_FILE) + +dnl Check for a different prefix-routes file +PREFIX_ROUTES_FILE=prefix-routes.conf +AC_MSG_CHECKING(for --with-prefix-routes-conf) +AC_ARG_WITH(prefix-routes-conf, + AC_HELP_STRING([--with-prefix-routes-conf=file], + [define a Prefix Routes config file (default is prefix-routes.conf)]), + [ case "$withval" in + no) + ;; + *) + PREFIX_ROUTES_FILE=$withval + ;; + esac ] +) +AC_MSG_RESULT($PREFIX_ROUTES_FILE) +AC_DEFINE_UNQUOTED(HAVE_DEFAULT_PREFIX_ROUTES_FILE, + ["$OPENSM_CONFIG_DIR/$PREFIX_ROUTES_FILE"], + [Define a Prefix Routes config file]) +AC_SUBST(PREFIX_ROUTES_FILE) + +dnl select example event plugin or not +OPENIB_OSM_DEFAULT_EVENT_PLUGIN_SEL + +dnl Provide user option to select vendor +OPENIB_APP_OSMV_SEL + +dnl Checks for headers and libraries +OPENIB_APP_OSMV_CHECK_HEADER +OPENIB_APP_OSMV_CHECK_LIB + +AC_CONFIG_FILES([man/opensm.8 scripts/opensm.init scripts/redhat-opensm.init scripts/sldd.sh]) + +dnl Create the following Makefiles +AC_OUTPUT([include/opensm/osm_version.h Makefile include/Makefile complib/Makefile libvendor/Makefile opensm/Makefile osmeventplugin/Makefile osmtest/Makefile opensm.spec]) diff --git a/contrib/ofed/management/opensm/doc/OpenSM_PKey_Mgr.txt b/contrib/ofed/management/opensm/doc/OpenSM_PKey_Mgr.txt new file mode 100644 index 000000000000..31d4c835e131 --- /dev/null +++ b/contrib/ofed/management/opensm/doc/OpenSM_PKey_Mgr.txt @@ -0,0 +1,78 @@ +OpenSM Partition Management +--------------------------- + +Roadmap: +Phase 1 - provide partition management at the EndPort (HCA, Router and Switch + Port 0) level with no routing affects. +Phase 2 - routing engine should take partitions into account. + +Phase 1 functionality: + +Supported Policy: + +1. EndPort partition groups are to be defined by listing the + PortGUIDs as full and limited members. + +2. Each partition group might be assigned an explicit P_Key (only the 15 + LSB bits are valid) or the SM should assign it randomly. + +3. A flag should control the generation of IPoIB broadcast group for + that partition. Extra optional MGIDs can be provided to be setup (on + top of the IPoIB broadcast group). + +4. A global flag "Disconnect Unconfigured EndPorts": If TRUE prevents + EndPorts that are not explicitly defined as part of any partition + (thus "unconfigured") to communicate with any other EndPort. Otherwise, it + will let these EndPorts send packets to all other EndPorts. + +Functionality: + +1. The policy should be updated: + - during SM bringup + - after kill -HUP + - through SNMP (once it is supported) + +2. Partition tables will be updated on full sweep (new port/trap etc). + As a first step, the policy feasibility should be + verified. Feasibility could be limited by the EndPorts supports for + number of partitions, etc. Unrealizable policy should be reported + and extra rules ignored after providing error messages. + +3. Each EndPort will be assigned P_Keys as follows: + + a. Default partition group limited membership as defined by rule #4 below. + (only the SM port will get 0xffff). + + b. P_Keys for all partition groups it is part of as defined in + the policy. + + c. P_Key update will preserve index for the existing P_Keys on the + port. If port has limited resources that will require reuse of, + on index a message will be provided and some of the settings will be + ommitted. P_Key indexes will not change under any circumstances. + +4. Each Switch Leaf Port (a switch port that is connected to an + EndPort) should be configured according to the same rules that + apply to the EndPort connected to that switch port. + This actually enables unauthorized port isolation (with future + usage of M_Key and ProtectBits). + +5. Policy entries matching a non EndPort will be flagged as + erroneous in the log file and ignored. + +6. At the end of the P_Key setting phase, a check for successful + setting should be made. + Errors should be clearly logged and cause a new sweep. + +7. Each partition that is marked to support IPoIB should define a + broadcast MGRP. If the partition does not support IPoIB, it should + define a dummy MGRP with parameters blocking IPoIB drivers from + registering to it. + +Phase 2 functionality: + +The partition policy should be considered during the routing such that +links are associated with particular partition or a set of +partitions. Policy should be enhanced to provide hints for how to do +that (correlating to QoS too). The exact algorithm is TBD. + diff --git a/contrib/ofed/management/opensm/doc/OpenSM_RN.pdf b/contrib/ofed/management/opensm/doc/OpenSM_RN.pdf new file mode 100644 index 000000000000..700924f24c83 Binary files /dev/null and b/contrib/ofed/management/opensm/doc/OpenSM_RN.pdf differ diff --git a/contrib/ofed/management/opensm/doc/OpenSM_UM.pdf b/contrib/ofed/management/opensm/doc/OpenSM_UM.pdf new file mode 100644 index 000000000000..ae32826b8234 Binary files /dev/null and b/contrib/ofed/management/opensm/doc/OpenSM_UM.pdf differ diff --git a/contrib/ofed/management/opensm/doc/QoS_management_in_OpenSM.txt b/contrib/ofed/management/opensm/doc/QoS_management_in_OpenSM.txt new file mode 100644 index 000000000000..8c9915f4ea33 --- /dev/null +++ b/contrib/ofed/management/opensm/doc/QoS_management_in_OpenSM.txt @@ -0,0 +1,492 @@ + + QoS Management in OpenSM + +============================================================================== + Table of contents +============================================================================== + +1. Overview +2. Full QoS Policy File +3. Simplified QoS Policy Definition +4. Policy File Syntax Guidelines +5. Examples of Full Policy File +6. Simplified QoS Policy - Details and Examples +7. SL2VL Mapping and VL Arbitration + + +============================================================================== + 1. Overview +============================================================================== + +When QoS in OpenSM is enabled (-Q or --qos), OpenSM looks for QoS Policy file. +The default name of OpenSM QoS policy file is +/usr/local/etc/opensm/qos-policy.conf. The default may be changed by using -Y +or --qos_policy_file option with OpenSM. + +During fabric initialization and at every heavy sweep OpenSM parses the QoS +policy file, applies its settings to the discovered fabric elements, and +enforces the provided policy on client requests. The overall flow for such +requests is: + - The request is matched against the defined matching rules such that the + QoS Level definition is found. + - Given the QoS Level, path(s) search is performed with the given + restrictions imposed by that level. + +There are two ways to define QoS policy: + - Full policy, where the policy file syntax provides an administrator + various ways to match PathRecord/MultiPathRecord (PR/MPR) request and + enforce various QoS constraints on the requested PR/MPR + - Simplified QoS policy definition, where an administrator would be able to + match PR/MPR requests by various ULPs and applications running on top of + these ULPs. + +While the full policy syntax is very flexible, in many cases the simplified +policy definition would be sufficient. + + +============================================================================== + 2. Full QoS Policy File +============================================================================== + +QoS policy file has the following sections: + +I) Port Groups (denoted by port-groups). +This section defines zero or more port groups that can be referred later by +matching rules (see below). Port group lists ports by: + - Port GUID + - Port name, which is a combination of NodeDescription and IB port number + - PKey, which means that all the ports in the subnet that belong to + partition with a given PKey belong to this port group + - Partition name, which means that all the ports in the subnet that belong + to partition with a given name belong to this port group + - Node type, where possible node types are: CA, SWITCH, ROUTER, ALL, and + SELF (SM's port). + +II) QoS Setup (denoted by qos-setup). +This section describes how to set up SL2VL and VL Arbitration tables on +various nodes in the fabric. +However, this is not supported in OpenSM currently. +SL2VL and VLArb tables should be configured in the OpenSM options file +(default location - /usr/local/etc/opensm/opensm.conf). + +III) QoS Levels (denoted by qos-levels). +Each QoS Level defines Service Level (SL) and a few optional fields: + - MTU limit + - Rate limit + - PKey + - Packet lifetime +When path(s) search is performed, it is done with regards to restriction that +these QoS Level parameters impose. +One QoS level that is mandatory to define is a DEFAULT QoS level. It is +applied to a PR/MPR query that does not match any existing match rule. +Similar to any other QoS Level, it can also be explicitly referred by any +match rule. + +IV) QoS Matching Rules (denoted by qos-match-rules). +Each PathRecord/MultiPathRecord query that OpenSM receives is matched against +the set of matching rules. Rules are scanned in order of appearance in the QoS +policy file such as the first match takes precedence. +Each rule has a name of QoS level that will be applied to the matching query. +A default QoS level is applied to a query that did not match any rule. +Queries can be matched by: + - Source port group (whether a source port is a member of a specified group) + - Destination port group (same as above, only for destination port) + - PKey + - QoS class + - Service ID +To match a certain matching rule, PR/MPR query has to match ALL the rule's +criteria. However, not all the fields of the PR/MPR query have to appear in +the matching rule. +For instance, if the rule has a single criterion - Service ID, it will match +any query that has this Service ID, disregarding rest of the query fields. +However, if a certain query has only Service ID (which means that this is the +only bit in the PR/MPR component mask that is on), it will not match any rule +that has other matching criteria besides Service ID. + + +============================================================================== + 3. Simplified QoS Policy Definition +============================================================================== + +Simplified QoS policy definition comprises of a single section denoted by +qos-ulps. Similar to the full QoS policy, it has a list of match rules and +their QoS Level, but in this case a match rule has only one criterion - its +goal is to match a certain ULP (or a certain application on top of this ULP) +PR/MPR request, and QoS Level has only one constraint - Service Level (SL). +The simplified policy section may appear in the policy file in combine with +the full policy, or as a stand-alone policy definition. +See more details and list of match rule criteria below. + + +============================================================================== + 4. Policy File Syntax Guidelines +============================================================================== + +- Empty lines are ignored. +- Leading and trailing blanks, as well as empty lines, are ignored, so + the indentation in the example is just for better readability. +- Comments are started with the pound sign (#) and terminated by EOL. +- Any keyword should be the first non-blank in the line, unless it's a + comment. +- Keywords that denote section/subsection start have matching closing + keywords. +- Having a QoS Level named "DEFAULT" is a must - it is applied to PR/MPR + requests that didn't match any of the matching rules. +- Any section/subsection of the policy file is optional. + + +============================================================================== + 5. Examples of Full Policy File +============================================================================== + +As mentioned earlier, any section of the policy file is optional, and +the only mandatory part of the policy file is a default QoS Level. +Here's an example of the shortest policy file: + + qos-levels + qos-level + name: DEFAULT + sl: 0 + end-qos-level + end-qos-levels + +Port groups section is missing because there are no match rules, which means +that port groups are not referred anywhere, and there is no need defining +them. And since this policy file doesn't have any matching rules, PR/MPR query +won't match any rule, and OpenSM will enforce default QoS level. +Essentially, the above example is equivalent to not having QoS policy file +at all. + +The following example shows all the possible options and keywords in the +policy file and their syntax: + + # + # See the comments in the following example. + # They explain different keywords and their meaning. + # + port-groups + + port-group # using port GUIDs + name: Storage + # "use" is just a description that is used for logging + # Other than that, it is just a comment + use: SRP Targets + port-guid: 0x10000000000001, 0x10000000000005-0x1000000000FFFA + port-guid: 0x1000000000FFFF + end-port-group + + port-group + name: Virtual Servers + # The syntax of the port name is as follows: + # "node_description/Pnum". + # node_description is compared to the NodeDescription of the node, + # and "Pnum" is a port number on that node. + port-name: vs1 HCA-1/P1, vs2 HCA-1/P1 + end-port-group + + # using partitions defined in the partition policy + port-group + name: Partitions + partition: Part1 + pkey: 0x1234 + end-port-group + + # using node types: CA, ROUTER, SWITCH, SELF (for node that runs SM) + # or ALL (for all the nodes in the subnet) + port-group + name: CAs and SM + node-type: CA, SELF + end-port-group + + end-port-groups + + qos-setup + # This section of the policy file describes how to set up SL2VL and VL + # Arbitration tables on various nodes in the fabric. + # However, this is not supported in OpenSM currently - the section is + # parsed and ignored. SL2VL and VLArb tables should be configured in the + # OpenSM options file (by default - /usr/local/etc/opensm/opensm.conf). + end-qos-setup + + qos-levels + + # Having a QoS Level named "DEFAULT" is a must - it is applied to + # PR/MPR requests that didn't match any of the matching rules. + qos-level + name: DEFAULT + use: default QoS Level + sl: 0 + end-qos-level + + # the whole set: SL, MTU-Limit, Rate-Limit, PKey, Packet Lifetime + qos-level + name: WholeSet + sl: 1 + mtu-limit: 4 + rate-limit: 5 + pkey: 0x1234 + packet-life: 8 + end-qos-level + + end-qos-levels + + # Match rules are scanned in order of their apperance in the policy file. + # First matched rule takes precedence. + qos-match-rules + + # matching by single criteria: QoS class + qos-match-rule + use: by QoS class + qos-class: 7-9,11 + # Name of qos-level to apply to the matching PR/MPR + qos-level-name: WholeSet + end-qos-match-rule + + # show matching by destination group and service id + qos-match-rule + use: Storage targets + destination: Storage + service-id: 0x10000000000001, 0x10000000000008-0x10000000000FFF + qos-level-name: WholeSet + end-qos-match-rule + + qos-match-rule + source: Storage + use: match by source group only + qos-level-name: DEFAULT + end-qos-match-rule + + qos-match-rule + use: match by all parameters + qos-class: 7-9,11 + source: Virtual Servers + destination: Storage + service-id: 0x0000000000010000-0x000000000001FFFF + pkey: 0x0F00-0x0FFF + qos-level-name: WholeSet + end-qos-match-rule + + end-qos-match-rules + + +============================================================================== + 6. Simplified QoS Policy - Details and Examples +============================================================================== + +Simplified QoS policy match rules are tailored for matching ULPs (or some +application on top of a ULP) PR/MPR requests. This section has a list of +per-ULP (or per-application) match rules and the SL that should be enforced +on the matched PR/MPR query. + +Match rules include: + - Default match rule that is applied to PR/MPR query that didn't match any + of the other match rules + - SDP + - SDP application with a specific target TCP/IP port range + - SRP with a specific target IB port GUID + - RDS + - iSER + - iSER application with a specific target TCP/IP port range + - IPoIB with a default PKey + - IPoIB with a specific PKey + - any ULP/application with a specific Service ID in the PR/MPR query + - any ULP/application with a specific PKey in the PR/MPR query + - any ULP/application with a specific target IB port GUID in the PR/MPR query + +Since any section of the policy file is optional, as long as basic rules of +the file are kept (such as no referring to nonexisting port group, having +default QoS Level, etc), the simplified policy section (qos-ulps) can serve +as a complete QoS policy file. +The shortest policy file in this case would be as follows: + + qos-ulps + default : 0 #default SL + end-qos-ulps + +It is equivalent to the previous example of the shortest policy file, and it +is also equivalent to not having policy file at all. + +Below is an example of simplified QoS policy with all the possible keywords: + + qos-ulps + default : 0 # default SL + sdp, port-num 30000 : 0 # SL for application running on top + # of SDP when a destination + # TCP/IPport is 30000 + sdp, port-num 10000-20000 : 0 + sdp : 1 # default SL for any other + # application running on top of SDP + rds : 2 # SL for RDS traffic + iser, port-num 900 : 0 # SL for iSER with a specific target + # port + iser : 3 # default SL for iSER + ipoib, pkey 0x0001 : 0 # SL for IPoIB on partition with + # pkey 0x0001 + ipoib : 4 # default IPoIB partition, + # pkey=0x7FFF + any, service-id 0x6234 : 6 # match any PR/MPR query with a + # specific Service ID + any, pkey 0x0ABC : 6 # match any PR/MPR query with a + # specific PKey + srp, target-port-guid 0x1234 : 5 # SRP when SRP Target is located on + # a specified IB port GUID + any, target-port-guid 0x0ABC-0xFFFFF : 6 # match any PR/MPR query with + # a specific target port GUID + end-qos-ulps + + +Similar to the full policy definition, matching of PR/MPR queries is done in +order of appearance in the QoS policy file such as the first match takes +precedence, except for the "default" rule, which is applied only if the query +didn't match any other rule. + +All other sections of the QoS policy file take precedence over the qos-ulps +section. That is, if a policy file has both qos-match-rules and qos-ulps +sections, then any query is matched first against the rules in the +qos-match-rules section, and only if there was no match, the query is matched +against the rules in qos-ulps section. + +Note that some of these match rules may overlap, so in order to use the +simplified QoS definition effectively, it is important to understand how each +of the ULPs is matched: + +6.1 IPoIB +IPoIB query is matched by PKey. Default PKey for IPoIB partition is 0x7fff, so +the following three match rules are equivalent: + + ipoib : + ipoib, pkey 0x7fff : + any, pkey 0x7fff : + +6.2 SDP +SDP PR query is matched by Service ID. The Service-ID for SDP is +0x000000000001PPPP, where PPPP are 4 hex digits holding the remote TCP/IP Port +Number to connect to. The following two match rules are equivalent: + + sdp : + any, service-id 0x0000000000010000-0x000000000001ffff : + +6.3 RDS +Similar to SDP, RDS PR query is matched by Service ID. The Service ID for RDS +is 0x000000000106PPPP, where PPPP are 4 hex digits holding the remote TCP/IP +Port Number to connect to. Default port number for RDS is 0x48CA, which makes +a default Service-ID 0x00000000010648CA. The following two match rules are +equivalent: + + rds : + any, service-id 0x00000000010648CA : + +6.4 iSER +Similar to RDS, iSER query is matched by Service ID, where the the Service ID +is also 0x000000000106PPPP. Default port number for iSER is 0x0CBC, which makes +a default Service-ID 0x0000000001060CBC. The following two match rules are +equivalent: + + iser : + any, service-id 0x0000000001060CBC : + +6.5 SRP +Service ID for SRP varies from storage vendor to vendor, thus SRP query is +matched by the target IB port GUID. The following two match rules are +equivalent: + + srp, target-port-guid 0x1234 : + any, target-port-guid 0x1234 : + +Note that any of the above ULPs might contain target port GUID in the PR +query, so in order for these queries not to be recognized by the QoS manager +as SRP, the SRP match rule (or any match rule that refers to the target port +guid only) should be placed at the end of the qos-ulps match rules. + +6.6 MPI +SL for MPI is manually configured by MPI admin. OpenSM is not forcing any SL +on the MPI traffic, and that's why it is the only ULP that did not appear in +the qos-ulps section. + + +============================================================================== + 7. SL2VL Mapping and VL Arbitration +============================================================================== + +OpenSM cached options file has a set of QoS related configuration parameters, +that are used to configure SL2VL mapping and VL arbitration on IB ports. +These parameters are: + - Max VLs: the maximum number of VLs that will be on the subnet. + - High limit: the limit of High Priority component of VL Arbitration + table (IBA 7.6.9). + - VLArb low table: Low priority VL Arbitration table (IBA 7.6.9) template. + - VLArb high table: High priority VL Arbitration table (IBA 7.6.9) template. + - SL2VL: SL2VL Mapping table (IBA 7.6.6) template. It is a list of VLs + corresponding to SLs 0-15 (Note that VL15 used here means drop this SL). + +There are separate QoS configuration parameters sets for various target types: +CAs, routers, switch external ports, and switch's enhanced port 0. The names +of such parameters are prefixed by "qos__" string. Here is a full list +of the currently supported sets: + + qos_ca_ - QoS configuration parameters set for CAs. + qos_rtr_ - parameters set for routers. + qos_sw0_ - parameters set for switches' port 0. + qos_swe_ - parameters set for switches' external ports. + +Here's the example of typical default values for CAs and switches' external +ports (hard-coded in OpenSM initialization): + + qos_ca_max_vls 15 + qos_ca_high_limit 0 + qos_ca_vlarb_high 0:4,1:0,2:0,3:0,4:0,5:0,6:0,7:0,8:0,9:0,10:0,11:0,12:0,13:0,14:0 + qos_ca_vlarb_low 0:0,1:4,2:4,3:4,4:4,5:4,6:4,7:4,8:4,9:4,10:4,11:4,12:4,13:4,14:4 + qos_ca_sl2vl 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7 + + qos_swe_max_vls 15 + qos_swe_high_limit 0 + qos_swe_vlarb_high 0:4,1:0,2:0,3:0,4:0,5:0,6:0,7:0,8:0,9:0,10:0,11:0,12:0,13:0,14:0 + qos_swe_vlarb_low 0:0,1:4,2:4,3:4,4:4,5:4,6:4,7:4,8:4,9:4,10:4,11:4,12:4,13:4,14:4 + qos_swe_sl2vl 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7 + +VL arbitration tables (both high and low) are lists of VL/Weight pairs. +Each list entry contains a VL number (values from 0-14), and a weighting value +(values 0-255), indicating the number of 64 byte units (credits) which may be +transmitted from that VL when its turn in the arbitration occurs. A weight +of 0 indicates that this entry should be skipped. If a list entry is +programmed for VL15 or for a VL that is not supported or is not currently +configured by the port, the port may either skip that entry or send from any +supported VL for that entry. + +Note, that the same VLs may be listed multiple times in the High or Low +priority arbitration tables, and, further, it can be listed in both tables. + +The limit of high-priority VLArb table (qos__high_limit) indicates the +number of high-priority packets that can be transmitted without an opportunity +to send a low-priority packet. Specifically, the number of bytes that can be +sent is high_limit times 4K bytes. + +A high_limit value of 255 indicates that the byte limit is unbounded. +Note: if the 255 value is used, the low priority VLs may be starved. +A value of 0 indicates that only a single packet from the high-priority table +may be sent before an opportunity is given to the low-priority table. + +Keep in mind that ports usually transmit packets of size equal to MTU. +For instance, for 4KB MTU a single packet will require 64 credits, so in order +to achieve effective VL arbitration for packets of 4KB MTU, the weighting +values for each VL should be multiples of 64. + +Below is an example of SL2VL and VL Arbitration configuration on subnet: + + qos_ca_max_vls 15 + qos_ca_high_limit 6 + qos_ca_vlarb_high 0:4 + qos_ca_vlarb_low 0:0,1:64,2:128,3:192,4:0,5:64,6:64,7:64 + qos_ca_sl2vl 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7 + + qos_swe_max_vls 15 + qos_swe_high_limit 6 + qos_swe_vlarb_high 0:4 + qos_swe_vlarb_low 0:0,1:64,2:128,3:192,4:0,5:64,6:64,7:64 + qos_swe_sl2vl 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7 + +In this example, there are 8 VLs configured on subnet: VL0 to VL7. VL0 is +defined as a high priority VL, and it is limited to 6 x 4KB = 24KB in a single +transmission burst. Such configuration would suilt VL that needs low latency +and uses small MTU when transmitting packets. Rest of VLs are defined as low +priority VLs with different weights, while VL4 is effectively turned off. diff --git a/contrib/ofed/management/opensm/doc/current-routing.txt b/contrib/ofed/management/opensm/doc/current-routing.txt new file mode 100644 index 000000000000..af008bcfe2d5 --- /dev/null +++ b/contrib/ofed/management/opensm/doc/current-routing.txt @@ -0,0 +1,346 @@ +Current OpenSM Routing +7/9/07 + +OpenSM offers five routing engines: + +1. Min Hop Algorithm - based on the minimum hops to each node where the +path length is optimized. + +2. UPDN Unicast routing algorithm - also based on the minimum hops to each +node, but it is constrained to ranking rules. This algorithm should be chosen +if the subnet is not a pure Fat Tree, and deadlock may occur due to a +loop in the subnet. + +3. Fat-tree Unicast routing algorithm - this algorithm optimizes routing +of fat-trees for congestion-free "shift" communication pattern. +It should be chosen if a subnet is a symmetrical fat-tree. +Similar to UPDN routing, Fat-tree routing is credit-loop-free. + +4. LASH unicast routing algorithm - uses Infiniband virtual layers +(SL) to provide deadlock-free shortest-path routing while also +distributing the paths between layers. LASH is an alternative +deadlock-free topology-agnostic routing algorithm to the non-minimal +UPDN algorithm avoiding the use of a potentially congested root node. + +5. DOR Unicast routing algorithm - based on the Min Hop algorithm, but +avoids port equalization except for redundant links between the same +two switches. This provides deadlock free routes for hypercubes when +the fabric is cabled as a hypercube and for meshes when cabled as a +mesh (see details below). + +OpenSM provides an optional unicast routing cache (enabled by -A or +--ucast_cache options). When enabled, unicast routing cache prevents +routing recalculation (which is a heavy task in a large cluster) when +there was no topology change detected during the heavy sweep, or when +the topology change does not require new routing calculation, e.g. when +one or more CAs/RTRs/leaf switches going down, or one or more of these +nodes coming back after being down. +A very common case that is handled by the unicast routing cache is host +reboot, which otherwise would cause two full routing recalculations: one +when the host goes down, and the other when the host comes back online. + +OpenSM also supports a file method which can load routes from a table. See +modular-routing.txt for more information on this. + +The basic routing algorithm is comprised of two stages: +1. MinHop matrix calculation + How many hops are required to get from each port to each LID ? + The algorithm to fill these tables is different if you run standard +(min hop) or Up/Down. + For standard routing, a "relaxation" algorithm is used to propagate +min hop from every destination LID through neighbor switches + For Up/Down routing, a BFS from every target is used. The BFS tracks link +direction (up or down) and avoid steps that will perform up after a down +step was used. + +2. Once MinHop matrices exist, each switch is visited and for each target LID, +a decision is made as to what port should be used to get to that LID. + This step is common to standard and Up/Down routing. Each port has a +counter counting the number of target LIDs going through it. + When there are multiple alternative ports with same MinHop to a LID, +the one with less previously assigned ports is selected. + If LMC > 0, more checks are added: Within each group of LIDs assigned to +same target port, + a. use only ports which have same MinHop + b. first prefer the ones that go to different systemImageGuid (then +the previous LID of the same LMC group) + c. if none - prefer those which go through another NodeGuid + d. fall back to the number of paths method (if all go to same node). + + +Effect of Topology Changes + +OpenSM will preserve existing routing in any case where there is no change in +the fabric switches unless the -r (--reassign_lids) option is specified. + +-r +--reassign_lids + This option causes OpenSM to reassign LIDs to all + end nodes. Specifying -r on a running subnet + may disrupt subnet traffic. + Without -r, OpenSM attempts to preserve existing + LID assignments resolving multiple use of same LID. + +If a link is added or removed, OpenSM does not recalculate +the routes that do not have to change. A route has to change +if the port is no longer UP or no longer the MinHop. When routing changes +are performed, the same algorithm for balancing the routes is invoked. + +In the case of using the file based routing, any topology changes are +currently ignored The 'file' routing engine just loads the LFTs from the file +specified, with no reaction to real topology. Obviously, this will not be able +to recheck LIDs (by GUID) for disconnected nodes, and LFTs for non-existent +switches will be skipped. Multicast is not affected by 'file' routing engine +(this uses min hop tables). + + +Min Hop Algorithm +----------------- + +The Min Hop algorithm is invoked by default if no routing algorithm is +specified. It can also be invoked by specifying '-R minhop'. + +The Min Hop algorithm is divided into two stages: computation of +min-hop tables on every switch and LFT output port assignment. Link +subscription is also equalized with the ability to override based on +port GUID. The latter is supplied by: + +-i +-ignore-guids + This option provides the means to define a set of ports + (by guids) that will be ignored by the link load + equalization algorithm. + +LMC awareness routes based on (remote) system or switch basis. + + +UPDN Routing Algorithm +---------------------- + +Purpose of UPDN Algorithm + +The UPDN algorithm is designed to prevent deadlocks from occurring in loops +of the subnet. A loop-deadlock is a situation in which it is no longer +possible to send data between any two hosts connected through the loop. As +such, the UPDN routing algorithm should be used if the subnet is not a pure +Fat Tree, and one of its loops may experience a deadlock (due, for example, +to high pressure). + +The UPDN algorithm is based on the following main stages: + +1. Auto-detect root nodes - based on the CA hop length from any switch in +the subnet, a statistical histogram is built for each switch (hop num vs +number of occurrences). If the histogram reflects a specific column (higher +than others) for a certain node, then it is marked as a root node. Since +the algorithm is statistical, it may not find any root nodes. The list of +the root nodes found by this auto-detect stage is used by the ranking +process stage. + + Note 1: The user can override the node list manually. + Note 2: If this stage cannot find any root nodes, and the user did not + specify a guid list file, OpenSM defaults back to the Min Hop + routing algorithm. + +2. Ranking process - All root switch nodes (found in stage 1) are assigned +a rank of 0. Using the BFS algorithm, the rest of the switch nodes in the +subnet are ranked incrementally. This ranking aids in the process of enforcing +rules that ensure loop-free paths. + +3. Min Hop Table setting - after ranking is done, a BFS algorithm is run from +each (CA or switch) node in the subnet. During the BFS process, the FDB table +of each switch node traversed by BFS is updated, in reference to the starting +node, based on the ranking rules and guid values. + +At the end of the process, the updated FDB tables ensure loop-free paths +through the subnet. + +Note: Up/Down routing does not allow LID routing communication between +switches that are located inside spine "switch systems". +The reason is that there is no way to allow a LID route between them +that does not break the Up/Down rule. +One ramification of this is that you cannot run SM on switches other +than the leaf switches of the fabric. + + +UPDN Algorithm Usage + +Activation through OpenSM + +Use '-R updn' option (instead of old '-u') to activate the UPDN algorithm. +Use `-a ' for adding an UPDN guid file that contains the +root nodes for ranking. +If the `-a' option is not used, OpenSM uses its auto-detect root nodes +algorithm. + +Notes on the guid list file: +1. A valid guid file specifies one guid in each line. Lines with an invalid +format will be discarded. +2. The user should specify the root switch guids. However, it is also +possible to specify CA guids; OpenSM will use the guid of the switch (if +it exists) that connects the CA to the subnet as a root node. + + +To learn more about deadlock-free routing, see the article +"Deadlock Free Message Routing in Multiprocessor Interconnection Networks" +by William J Dally and Charles L Seitz (1985). + + +Fat-tree Routing Algorithm +-------------------------- + +Purpose: + +The fat-tree algorithm optimizes routing for "shift" communication pattern. +It should be chosen if a subnet is a symmetrical or almost symmetrical +fat-tree of various types. +It supports not just K-ary-N-Trees, by handling for non-constant K, +cases where not all leafs (CAs) are present, any Constant +Bisectional Ratio (CBB) ratio. As in UPDN, fat-tree also prevents +credit-loop-deadlocks. + +If the root guid file is not provided ('-a' or '--root_guid_file' options), +the topology has to be pure fat-tree that complies with the following rules: + - Tree rank should be between two and eight (inclusively) + - Switches of the same rank should have the same number + of UP-going port groups*, unless they are root switches, + in which case the shouldn't have UP-going ports at all. + - Switches of the same rank should have the same number + of DOWN-going port groups, unless they are leaf switches. + - Switches of the same rank should have the same number + of ports in each UP-going port group. + - Switches of the same rank should have the same number + of ports in each DOWN-going port group. + - All the CAs have to be at the same tree level (rank). + +If the root guid file is provided, the topology doesn't have to be pure +fat-tree, and it should only comply with the following rules: + - Tree rank should be between two and eight (inclusively) + - All the Compute Nodes** have to be at the same tree level (rank). + Note that non-compute node CAs are allowed here to be at different + tree ranks. + +* ports that are connected to the same remote switch are referenced as +'port group'. +** list of compute nodes (CNs) can be specified by '-u' or '--cn_guid_file' +OpenSM options. + +Note that although fat-tree algorithm supports trees with non-integer CBB +ratio, the routing will not be as balanced as in case of integer CBB ratio. +In addition to this, although the algorithm allows leaf switches to have any +number of CAs, the closer the tree is to be fully populated, the more effective +the "shift" communication pattern will be. +In general, even if the root list is provided, the closer the topology to a +pure and symmetrical fat-tree, the more optimal the routing will be. + +The algorithm also dumps compute node ordering file (opensm-ftree-ca-order.dump) +in the same directory where the OpenSM log resides. This ordering file provides +the CN order that may be used to create efficient communication pattern, that +will match the routing tables. + + +Usage: + +Activation through OpenSM + +Use '-R ftree' option to activate the fat-tree algorithm. + +Note: LMC > 0 is not supported by fat-tree routing. If this is +specified, the default routing algorithm is invoked instead. + + +LASH Routing Algorithm +---------------------- + +LASH is an acronym for LAyered SHortest Path Routing. It is a +deterministic shortest path routing algorithm that enables topology +agnostic deadlock-free routing within communication networks. + +When computing the routing function, LASH analyzes the network +topology for the shortest-path routes between all pairs of sources / +destinations and groups these paths into virtual layers in such a way +as to avoid deadlock. + +Note LASH analyzes routes and ensures deadlock freedom between switch +pairs. The link from HCA between and switch does not need virtual +layers as deadlock will not arise between switch and HCA. + +In more detail, the algorithm works as follows: + +1) LASH determines the shortest-path between all pairs of source / +destination switches. Note, LASH ensures the same SL is used for all +SRC/DST - DST/SRC pairs and there is no guarantee that the return +path for a given DST/SRC will be the reverse of the route SRC/DST. + +2) LASH then begins an SL assignment process where a route is assigned +to a layer (SL) if the addition of that route does not cause deadlock +within that layer. This is achieved by maintaining and analysing a +channel dependency graph for each layer. Once the potential addition +of a path could lead to deadlock, LASH opens a new layer and continues +the process. + +3) Once this stage has been completed, it is highly likely that the +first layers processed will contain more paths than the latter ones. +To better balance the use of layers, LASH moves paths from one layer +to another so that the number of paths in each layer averages out. + +Note, the implementation of LASH in opensm attempts to use as few layers +as possible. This number can be less than the number of actual layers +available. + +In general LASH is a very flexible algorithm. It can, for example, +reduce to Dimension Order Routing in certain topologies, it is topology +agnostic and fares well in the face of faults. + +It has been shown that for both regular and irregular topologies, LASH +outperforms Up/Down. The reason for this is that LASH distributes the +traffic more evenly through a network, avoiding the bottleneck issues +related to a root node and always routes shortest-path. + +The algorithm was developed by Simula Research Laboratory. + +To learn more about LASH and the flexibility behind it, the requirement +for layers, performance comparisons to other algorithms, see the +following articles: + +"Layered Routing in Irregular Networks", Lysne et al, IEEE +Transactions on Parallel and Distributed Systems, VOL.16, No12, +December 2005. + +"Routing for the ASI Fabric Manager", Solheim et al. IEEE +Communications Magazine, Vol.44, No.7, July 2006. + +"Layered Shortest Path (LASH) Routing in Irregular System Area +Networks", Skeie et al. IEEE Computer Society Communication +Architecture for Clusters 2002. + + +Use '-R lash -Q ' option to activate the LASH algorithm. + +Note: QoS support has to be turned on in order that SL/VL mappings are +used. + +Note: LMC > 0 is not supported by the LASH routing. If this is +specified, the default routing algorithm is invoked instead. + + +DOR Routing Algorithm +--------------------- + +The Dimension Order Routing algorithm is based on the Min Hop +algorithm and so uses shortest paths. Instead of spreading traffic +out across different paths with the same shortest distance, it chooses +among the available shortest paths based on an ordering of dimensions. +Each port must be consistently cabled to represent a hypercube +dimension or a mesh dimension. Paths are grown from a destination +back to a source using the lowest dimension (port) of available paths +at each step. This provides the ordering necessary to avoid deadlock. +When there are multiple links between any two switches, they still +represent only one dimension and traffic is balanced across them +unless port equalization is turned off. In the case of hypercubes, +the same port must be used throughout the fabric to represent the +hypercube dimension and match on both ends of the cable. In the case +of meshes, the dimension should consistently use the same pair of +ports, one port on one end of the cable, and the other port on the +other end, continuing along the mesh dimension. + +Use '-R dor' option to activate the DOR algorithm. diff --git a/contrib/ofed/management/opensm/doc/modular-routing.txt b/contrib/ofed/management/opensm/doc/modular-routing.txt new file mode 100644 index 000000000000..3f2174ba533e --- /dev/null +++ b/contrib/ofed/management/opensm/doc/modular-routing.txt @@ -0,0 +1,77 @@ +Modular Routine Engine + +Modular routing engine structure has been added to allow +for ease of "plugging" new routing modules. + +Currently, only unicast callbacks are supported. Multicast +can be added later. + +One of existing routing modules is up-down "updn", which may +be activated with '-R updn' option (instead of old '-u'). + +General usage is: +$ opensm -R 'module-name' + +There is also a trivial routing module which is able +to load LFT tables from a file. + +Main features: + +- this will load switch LFTs and/or LID matrices (min hops tables) +- this will load switch LFTs according to the path entries introduced in + the file +- no additional checks will be performed (such as "is port connected", etc.) +- in case when fabric LIDs were changed this will try to reconstruct LFTs + correctly if endport GUIDs are represented in the file (in order + to disable this GUIDs may be removed from the file or zeroed) + +The file format is compatible with output of 'ibroute' util and for +whole fabric may be generated with script like this: + + for sw_lid in `ibswitches | awk '{print $NF}'` ; do + ibroute $sw_lid + done > /path/to/lfts_file + +, or using DR paths: + + for sw_dr in `ibnetdiscover -v \ + | sed -ne '/^DR path .* switch /s/^DR path \[\(.*\)\].*$/\1/p' \ + | sed -e 's/\]\[/,/g' \ + | sort -u` ; do + ibroute -D ${sw_dr} + done > /path/to/lfts_file + +This script is dump_lfts.sh + +In order to activate new module use: + + opensm -R file -U /path/to/lfts_file + +If the lfts_file is not found or is in error, the default routing +algorithm is utilized. + +The ability to dump switch lid matrices (aka min hops tables) to file and +later to load these is also supported. + +The usage is similar to unicast forwarding tables loading from a lfts +file (introduced by 'file' routing engine), but new lid matrix file +name should be specified by -M or --lid_matrix_file option. For example: + + opensm -R file -M ./opensm-lid-matrix.dump + +The dump file is named 'opensm-lid-matrix.dump' and will be generated in +standard opensm dump directory (/var/log by default) when +OSM_LOG_ROUTING logging flag is set. + +When routing engine 'file' is activated, but the lfts file is not specified +or cannot be opened, the default lid matrix algorithm will be used. + +There is also a switch forwarding tables dumper which generates +a file compatible with dump_lfts.sh output. This file can be used +as input for forwarding tables loading by 'file' routing engine. +Both or one of options -U and -M can be specified together with '-R file'. + +NOTE: ibroute has been updated (for switch management ports) to support this. +Also, lmc was added to switch management ports. ibroute needs to be r7855 or +later from the trunk. + diff --git a/contrib/ofed/management/opensm/doc/opensm-coding-style.txt b/contrib/ofed/management/opensm/doc/opensm-coding-style.txt new file mode 100644 index 000000000000..379042c6a1a6 --- /dev/null +++ b/contrib/ofed/management/opensm/doc/opensm-coding-style.txt @@ -0,0 +1,34 @@ +This short (hopefully) memo is about to define the coding style +recommended for OpenSM development. + +The goal of this is to make OpenSM code base to be standard in terms of +the rest of OpenIB management software, OpenIB projects and Linux in +general. And in this way to make OpenSM more developer friendly and to +involve more open source programmers to be part of OpenSM development +process. + +The goal of this is not to provide long and boring list of coding style +paradigms, but rather to define general coding style concept and to +suggest a way for such a concept to be implemented in the existing +OpenSM code base. + +The OpenSM project is an OpenIB and Linux centric project, so we think +it is reasonable to use the coding style most popular with OpenIB +projects (linux/Documentation/CodingStyle) as the starting point rather +than reinventing one more coding style rule-set. + +Some things from there in short: tab character for indentation and space +character for alignment, K&R style braces, short local and meanful +global names, please no confused Hungary style, short functions. And of +course to be reasonable about all above. + + +Some ideas about existing OpenSM code improvements in terms of the +Coding style: + +* When writing new code, please try to follow the new Coding style. +* Coding style improvement patches are desired and accepted, but please + try to not mix coding style improvement with functional and other + changes in one patch. +* When you are going to improve coding style for existing code, please + try to do it for entire file(s). diff --git a/contrib/ofed/management/opensm/doc/opensm_release_notes-3.1.10.txt b/contrib/ofed/management/opensm/doc/opensm_release_notes-3.1.10.txt new file mode 100644 index 000000000000..2b6253d2da55 --- /dev/null +++ b/contrib/ofed/management/opensm/doc/opensm_release_notes-3.1.10.txt @@ -0,0 +1,492 @@ + OpenSM Release Notes 3.1.10 + ============================= + +Version: OpenFabrics Enterprise Distribution (OFED) 1.3 +Repo: git://git.openfabrics.org/~ofed_1_3/management.git (release) + git://git.openfabrics.org/~sashak/management.git (development) +Date: February 2008 + +1 Overview +---------- +This document describes the contents of the OpenSM OFED 1.3 release. +OpenSM is an InfiniBand compliant Subnet Manager and Administration, +and runs on top of OpenIB. The OpenSM version for this release +is openib-3.1.10 + +This document includes the following sections: +1 This Overview section (describing new features and software + dependencies) +2 Known Issues And Limitations +3 Unsupported IB compliance statements +4 Major Bug Fixes +5 Main Verification Flows +6 Qualified software stacks and devices + +1.1 Major New Features + +* QoS manager (experimental) + This QoS manager implementation is in accordance with IBA QoS Annex. + Highly configurable QoS Policy is parsed from OpenSM QoS policy file. + Valid QoS parameters will be reported in SA PathRecord and + MultiPathRecord. In addition simple QoS levels per ULPs configuration + is supported too. + +* Performance Manager + When enabled it collects a fabric port counters and able to log it or + to pass to external program via event plugin interface. It handles + counters overflow, supports LID/QP redirection and is able to work + when OpenSM is in master, standby, and inactive states. + +* Dimension Order routing (DOR) algorithm + DOR Unicast routing algorithm - based on the Min Hop algorithm, but + avoids port equalization except for redundant links between the + same two switches. This provides deadlock free routes for hypercubes + when the fabric is cabled as a hypercube and for meshes when cabled + as a mesh (see details in OpenSM man page). + +* Routing improvements + Speedup the current routing algorithms default MinHops, Up/Down and + LASH and lid matrix generation. Fat Tree routing engine is able to work + with not pure fat free topology. + +* Multiple IB routers support + OpenSM now able to keep configurable subnet prefix to router table. + SA will report path to this routers when SA PathRecord was issued with + non-local DGID. + +* Node map + This is possible to name nodes in this config file. Those names will be + used for logging and by QoS configuration. + +* PKey index support + Proper support for PKey index in GSI queries. + +* Incremental LFTs, PKey, SL2VL, and VLarbitration table updates + OpenSM will only fetch those tables in first heavy sweep and then + will maintain this internally. + +* Fast port and switch detector + When port and/or switch was externally reset and it was fast so sweep + doesn't find this device as disconnected OpenSM will detect this by + changed port states and handle accordingly. + +* Duplicated GUIDs/port moving detector + OpenSM will be able to detect port moving during a fabric discovery + and will not report duplicated GUIDs in this case. + +* Multicast rerouting speedup + Now OpenSM will calculate and setup multicast forwarding tables for + all altered multicast groups and not for each one. + +* Event plugin API + OpenSM allows to load dynamically various plugin modules. + +* Many generic improvements + +1.2 Minor New Features: + +* Daemon mode can be activated with -B option. + +* Support multiple scopes for IPoIB multicast groups in partition config. + +* Loopback connection handling + Loopback connection is not interpreted as duplicated GUID anymore. + +* Connect root nodes option for Up/Down routing engine. + When this option is specified Up/Down will create routing paths between + its root nodes. + +* Dump and log filenames changed from osm* to opensm*. + +* Support loopback console + Socket console with only local access. + +* Configurable config directory (the default value is /etc/opensm) and + configurable default values of OpenSM config filenames. + +* Add option for force SDR link speed + Add option to opensm.opts to force link speed. Currently, only forcing + to SDR link speed is supported. This option is not supported as a + command line option. + +* Better packaging + Building and RPM packaging were improved and simplified. + +* Handle "babbling" ports + When a babbling port (port which causes a frequent trap generation) is + detected, OpenSM will disable the port which should terminate the trap + storm. + +1.3 Library API Changes + + None + +1.4 Software Dependencies + +OpenSM depends on the installation of either OFED 1.3, OFED 1.2, OFED 1.1, +OFED 1.0, OpenIB gen2 (e.g. IBG2 distribution), OpenIB gen1 (e.g. IBGD +distribution), or Mellanox VAPI stacks. The qualified driver versions +are provided in Table 2, "Qualified IB Stacks". + +Also building of QoS manager policy file parser requires flex, and either +bison or byacc installed. + +1.5 Supported Devices Firmware + +The main task of OpenSM is to initialize InfiniBand devices. The +qualified devices and their corresponding firmware versions +are listed in Table 3. + +2 Known Issues And Limitations +------------------------------ + +* No Service / Key associations: + There is no way to manage Service access by Keys. + +* No SM to SM SMDB synchronization: + Puts the burden of re-registering services, multicast groups, and + inform-info on the client application (or IB access layer core). + +3 Unsupported IB Compliance Statements +-------------------------------------- +The following section lists all the IB compliance statements which +OpenSM does not support. Please refer to the IB specification for detailed +information regarding each compliance statement. + +* C14-22 (Authentication): + M_Key M_KeyProtectBits and M_KeyLeasePeriod shall be set in one + SubnSet method. As a work-around, an OpenSM option is provided for + defining the protect bits. + +* C14-67 (Authentication): + On SubnGet(SMInfo) and SubnSet(SMInfo) - if M_Key is not zero then + the SM shall generate a SubnGetResp if the M_Key matches, or + silently drop the packet if M_Key does not match. + +* C15-0.1.23.4 (Authentication): + InformInfoRecords shall always be provided with the QPN set to 0, + except for the case of a trusted request, in which case the actual + subscriber QPN shall be returned. + +* o13-17.1.2 (Event-FWD): + If no permission to forward, the subscription should be removed and + no further forwarding should occur. + +* C14-24.1.1.5 and C14-62.1.1.22 (Initialization): + GUIDInfo - SM should enable assigning Port GUIDInfo. + +* C14-44 (Initialization): + If the SM discovers that it is missing an M_Key to update CA/RT/SW, + it should notify the higher level. + +* C14-62.1.1.12 (Initialization): + PortInfo:M_Key - Set the M_Key to a node based random value. + +* C14-62.1.1.13 (Initialization): + PortInfo:P_KeyProtectBits - set according to an optional policy. + +* C14-62.1.1.24 (Initialization): + SwitchInfo:DefaultPort - should be configured for random FDB. + +* C14-62.1.1.32 (Initialization): + RandomForwardingTable should be configured. + +* o15-0.1.12 (Multicast): + If the JoinState is SendOnlyNonMember = 1 (only), then the endport + should join as sender only. + +* o15-0.1.8 (Multicast): + If a request for creating an MCG with fields that cannot be met, + return ERR_REQ_INVALID (currently ignores SL and FlowLabelTClass). + +* C15-0.1.8.6 (SA-Query): + Respond to SubnAdmGetTraceTable - this is an optional attribute. + +* C15-0.1.13 Services: + Reject ServiceRecord create, modify or delete if the given + ServiceP_Key does not match the one included in the ServiceGID port + and the port that sent the request. + +* C15-0.1.14 (Services): + Provide means to associate service name and ServiceKeys. + +4 Major Bug Fixes +----------------- + +The following is a list of bugs that were fixed. Note that other less critical +or visible bugs were also fixed. + +* osm_ucast_ftree.c: do load-leveling of non-CN routes + +* osm_ucast_ftree.c: ignore port 0 and loopbacks on switches + +* lash: fix possible segfault in osm_get_lash_sl() + +* osm_ucast_ftree.c: fixing coredump in fat-tree routing + +* osm_sa_slvl_record: fix overflow crash + +* Break multicast rerouting requests processing when heavy sweep is + scheduled. + +* updn: report fallback properly + +* Fix incorrect identification of routing engine used + +* Don't zero base LID when invalid value is received + +* lash: fix wrong allocation size + +* Fixing broken logic in 'process world' part of LinkRecord processing + +* Fix lmc_mask bit order in osm_sa_link_record.c + +* Adding missing comparison by to_lid/from_lid in LinkRecord processing + +* Broken logic when scanning subnet for PIR request + +* No interactive games in daemon mode + +* Fixing memory leak in node description + +* Fix PortInfo update issues for switch port 0 + +* Changed method_mask type in user_mad interface in accordance with + kernel ABI + +* Use umad_get_issm_path() in osm_vendor_set_sm() + +* Report message fix + +* Uninitialized variables usage fix + +* osm_ucast_ftree.c: Possible NULL ptr seg fault + +* osm_mcast_mgr.c: Possible NULL ptr seg fault + +* TrapRepress was failing for mkey != 0 + +* IB_PR_COMPMASK was used in MPR + +* Set hop limit when creating ipoib multicast groups + +* Fix outstanding mad counters tracking on the error paths. + +* Report new ports before handover mastership + +* Fix opvls and neighbormtu when remote port invalid. + +* Bug in coding trying to set vl_arb_high_limit when PortInfo.base_lid + was still zero. + +* Protect SMInfo response against port moving issue. + +5 Main Verification Flows +------------------------- + +OpenSM verification is run using the following activities: +* osmtest - a stand-alone program +* ibmgtsim (IB management simulator) based - a set of flows that + simulate clusters, inject errors and verify OpenSM capability to + respond and bring up the network correctly. +* small cluster regression testing - where the SM is used on back to + back or single switch configurations. The regression includes + multiple OpenSM dedicated tests. +* cluster testing - when we run OpenSM to setup a large cluster, perform + hand-off, reboots and reconnects, verify routing correctness and SA + responsiveness at the ULP level (IPoIB and SDP). + +5.1 osmtest + +osmtest is an automated verification tool used for OpenSM +testing. Its verification flows are described by list below. + +* Inventory File: Obtain and verify all port info, node info, link and path + records parameters. + +* Service Record: + - Register new service + - Register another service (with a lease period) + - Register another service (with service p_key set to zero) + - Get all services by name + - Delete the first service + - Delete the third service + - Added bad flows of get/delete non valid service + - Add / Get same service with different data + - Add / Get / Delete by different component mask values (services + by Name & Key / Name & Data / Name & Id / Id only ) + +* Multicast Member Record: + - Query of existing Groups (IPoIB) + - BAD Join with insufficient comp mask (o15.0.1.3) + - Create given MGID=0 (o15.0.1.4) + - Create given MGID=0xFF12A01C,FE800000,00000000,12345678 (o15.0.1.4) + - Create BAD MGID=0xFA. (o15.0.1.6) + - Create BAD MGID=0xFF12A01B w/ link-local not set (o15.0.1.6) + - New MGID with invalid join state (o15.0.1.9) + - Retry of existing MGID - See JoinState update (o15.0.1.11) + - BAD RATE when connecting to existing MGID (o15.0.1.13) + - Partial JoinState delete request - removing FullMember (o15.0.1.14) + - Full Delete of a group (o15.0.1.14) + - Verify Delete by trying to Join deleted group (o15.0.1.14) + - BAD Delete of IPoIB membership (no prev join) (o15.0.1.15) + +* GUIDInfo Record: + - All GUIDInfoRecords in subnet are obtained + +* MultiPathRecord: + - Perform some compliant and noncompliant MultiPathRecord requests + - Validation is via status in responses and IB analyzer + +* PKeyTableRecord: + - Perform some compliant and noncompliant PKeyTableRecord queries + - Validation is via status in responses and IB analyzer + +* LinearForwardingTableRecord: + - Perform some compliant and noncompliant LinearForwardingTableRecord queries + - Validation is via status in responses and IB analyzer + +* Event Forwarding: Register for trap forwarding using reports + - Send a trap and wait for report + - Unregister non-existing + +* Trap 64/65 Flow: Register to Trap 64-65, create traps (by + disconnecting/connecting ports) and wait for report, then unregister. + +* Stress Test: send PortInfoRecord queries, both single and RMPP and + check for the rate of responses as well as their validity. + + +5.2 IB Management Simulator OpenSM Test Flows: + +The simulator provides ability to simulate the SM handling of virtual +topologies that are not limited to actual lab equipment availability. +OpenSM was simulated to bring up clusters of up to 10,000 nodes. Daily +regressions use smaller (16 and 128 nodes clusters). + +The following test flows are run on the IB management simulator: + +* Stability: + Up to 12 links from the fabric are randomly selected to drop packets + at drop rates up to 90%. The SM is required to succeed in bringing the + fabric up. The resulting routing is verified to be correct as well. + +* LID Manager: + Using LMC = 2 the fabric is initialized with LIDs. Faults such as + zero LID, Duplicated LID, non-aligned (to LMC) LIDs are + randomly assigned to various nodes and other errors are randomly + output to the guid2lid cache file. The SM sweep is run 5 times and + after each iteration a complete verification is made to ensure that all + LIDs that could possibly be maintained are kept, as well as that all nodes + were assigned a legal LID range. + +* Multicast Routing: + Nodes randomly join the 0xc000 group and eventually the + resulting routing is verified for completeness and adherence to + Up/Down routing rules. + +* osmtest: + The complete osmtest flow as described in the previous table is run on + the simulated fabrics. + +* Stress Test: + This flow merges fabric, LID and stability issues with continuous + PathRecord, ServiceRecord and Multicast Join/Leave activity to + stress the SM/SA during continuous sweeps. InformInfo Set/Delete/Get + were added to the test such both existing and non existing nodes + perform them in random order. + +5.3 OpenSM Regression + +Using a back-to-back or single switch connection, the following set of +tests is run nightly on the stacks described in table 2. The included +tests are: + +* Stress Testing: Flood the SA with queries from multiple channel + adapters to check the robustness of the entire stack up to the SA. + +* Dynamic Changes: Dynamic Topology changes, through randomly + dropping SMP packets, used to test OpenSM adaptation to an unstable + network & verify DB correctness. + +* Trap Injection: This flow injects traps to the SM and verifies that it + handles them gracefully. + +* SA Query Test: This test exhaustively checks the SA responses to all + possible single component mask. To do that the test examines the + entire set of records the SA can provide, classifies them by their + field values and then selects every field (using component mask and a + value) and verifies that the response matches the expected set of records. + A random selection using multiple component mask bits is also performed. + +5.4 Cluster testing: + +Cluster testing is usually run before a distribution release. It +involves real hardware setups of 16 to 32 nodes (or more if a beta site +is available). Each test is validated by running all-to-all ping through the IB +interface. The test procedure includes: + +* Cluster bringup + +* Hand-off between 2 or 3 SM's while performing: + - Node reboots + - Switch power cycles (disconnecting the SM's) + +* Unresponsive port detection and recovery + +* osmtest from multiple nodes + +* Trap injection and recovery + + +6 Qualification +---------------- + +Table 2 - Qualified IB Stacks +============================= + +Stack | Version +-----------------------------------------|-------------------------- +OFED | 1.3 +OFED | 1.2 +OFED | 1.1 +OFED | 1.0 +OpenIB Gen2 (IBG2 distribution) | 1.0 +OpenIB Gen1 (IBGD distribution) | 1.8.0 +VAPI (Mellanox InfiniBand HCA Driver) | 3.2 and later + +Table 3 - Qualified Devices and Corresponding Firmware +====================================================== + +Mellanox +Device | FW versions +------------------------------------|------------------------------- +InfiniScale | fw-43132 5.2.000 (and later) +InfiniScale III | fw-47396 0.5.000 (and later) +InfiniHost | fw-23108 3.5.000 (and later) +InfiniHost III Lx | fw-25204 1.2.000 (and later) +InfiniHost III Ex (InfiniHost Mode) | fw-25208 4.8.200 (and later) +InfiniHost III Ex (MemFree Mode) | fw-25218 5.3.000 (and later) +ConnectX IB | fw-25408 2.3.000 (and later) + +QLogic/PathScale +Device | Note +--------|----------------------------------------------------------- +iPath | QHT6040 (PathScale InfiniPath HT-460) +iPath | QHT6140 (PathScale InfiniPath HT-465) +iPath | QLE6140 (PathScale InfiniPath PE-880) +iPath | QLE7240 +iPath | QLE7280 + +Note 1: OpenSM does not run on an IBM Galaxy (eHCA) as it does not expose +QP0 and QP1. However, it does support it as a device on the subnet. + +Note 2: QoS firmware and Mellanox devices + +HCAs: QoS supported by ConnectX. The current FW release +doesn't support QoS. QoS-enabled FW release (2_5_000) is +planned for May. If someone wishes to get QoS-enabled FW +before the official release, they should contact Mellanox FAE. + +Switches: QoS supported by InfiniScale III +Any InfiniScale III FW that is supported by OpenSM supports QoS. diff --git a/contrib/ofed/management/opensm/doc/opensm_release_notes-3.1.11.txt b/contrib/ofed/management/opensm/doc/opensm_release_notes-3.1.11.txt new file mode 100644 index 000000000000..5d8366c97805 --- /dev/null +++ b/contrib/ofed/management/opensm/doc/opensm_release_notes-3.1.11.txt @@ -0,0 +1,492 @@ + OpenSM Release Notes 3.1.11 + ============================= + +Version: OpenFabrics Enterprise Distribution (OFED) 1.3 +Repo: git://git.openfabrics.org/~ofed_1_3/management.git (release) + git://git.openfabrics.org/~sashak/management.git (development) +Date: May 2008 + +1 Overview +---------- +This document describes the contents of the OpenSM OFED 1.3 release. +OpenSM is an InfiniBand compliant Subnet Manager and Administration, +and runs on top of OpenIB. The OpenSM version for this release +is openib-3.1.11 + +This document includes the following sections: +1 This Overview section (describing new features and software + dependencies) +2 Known Issues And Limitations +3 Unsupported IB compliance statements +4 Major Bug Fixes +5 Main Verification Flows +6 Qualified software stacks and devices + +1.1 Major New Features + +* QoS manager (experimental) + This QoS manager implementation is in accordance with IBA QoS Annex. + Highly configurable QoS Policy is parsed from OpenSM QoS policy file. + Valid QoS parameters will be reported in SA PathRecord and + MultiPathRecord. In addition simple QoS levels per ULPs configuration + is supported too. + +* Performance Manager + When enabled it collects a fabric port counters and able to log it or + to pass to external program via event plugin interface. It handles + counters overflow, supports LID/QP redirection and is able to work + when OpenSM is in master, standby, and inactive states. + +* Dimension Order routing (DOR) algorithm + DOR Unicast routing algorithm - based on the Min Hop algorithm, but + avoids port equalization except for redundant links between the + same two switches. This provides deadlock free routes for hypercubes + when the fabric is cabled as a hypercube and for meshes when cabled + as a mesh (see details in OpenSM man page). + +* Routing improvements + Speedup the current routing algorithms default MinHops, Up/Down and + LASH and lid matrix generation. Fat Tree routing engine is able to work + with not pure fat free topology. + +* Multiple IB routers support + OpenSM now able to keep configurable subnet prefix to router table. + SA will report path to this routers when SA PathRecord was issued with + non-local DGID. + +* Node map + This is possible to name nodes in this config file. Those names will be + used for logging and by QoS configuration. + +* PKey index support + Proper support for PKey index in GSI queries. + +* Incremental LFTs, PKey, SL2VL, and VLarbitration table updates + OpenSM will only fetch those tables in first heavy sweep and then + will maintain this internally. + +* Fast port and switch detector + When port and/or switch was externally reset and it was fast so sweep + doesn't find this device as disconnected OpenSM will detect this by + changed port states and handle accordingly. + +* Duplicated GUIDs/port moving detector + OpenSM will be able to detect port moving during a fabric discovery + and will not report duplicated GUIDs in this case. + +* Multicast rerouting speedup + Now OpenSM will calculate and setup multicast forwarding tables for + all altered multicast groups and not for each one. + +* Event plugin API + OpenSM allows to load dynamically various plugin modules. + +* Many generic improvements + +1.2 Minor New Features: + +* Daemon mode can be activated with -B option. + +* Support multiple scopes for IPoIB multicast groups in partition config. + +* Loopback connection handling + Loopback connection is not interpreted as duplicated GUID anymore. + +* Connect root nodes option for Up/Down routing engine. + When this option is specified Up/Down will create routing paths between + its root nodes. + +* Dump and log filenames changed from osm* to opensm*. + +* Support loopback console + Socket console with only local access. + +* Configurable config directory (the default value is /etc/opensm) and + configurable default values of OpenSM config filenames. + +* Add option for force SDR link speed + Add option to opensm.opts to force link speed. Currently, only forcing + to SDR link speed is supported. This option is not supported as a + command line option. + +* Better packaging + Building and RPM packaging were improved and simplified. + +* Handle "babbling" ports + When a babbling port (port which causes a frequent trap generation) is + detected, OpenSM will disable the port which should terminate the trap + storm. + +1.3 Library API Changes + + None + +1.4 Software Dependencies + +OpenSM depends on the installation of either OFED 1.3, OFED 1.2, OFED 1.1, +OFED 1.0, OpenIB gen2 (e.g. IBG2 distribution), OpenIB gen1 (e.g. IBGD +distribution), or Mellanox VAPI stacks. The qualified driver versions +are provided in Table 2, "Qualified IB Stacks". + +Also building of QoS manager policy file parser requires flex, and either +bison or byacc installed. + +1.5 Supported Devices Firmware + +The main task of OpenSM is to initialize InfiniBand devices. The +qualified devices and their corresponding firmware versions +are listed in Table 3. + +2 Known Issues And Limitations +------------------------------ + +* No Service / Key associations: + There is no way to manage Service access by Keys. + +* No SM to SM SMDB synchronization: + Puts the burden of re-registering services, multicast groups, and + inform-info on the client application (or IB access layer core). + +3 Unsupported IB Compliance Statements +-------------------------------------- +The following section lists all the IB compliance statements which +OpenSM does not support. Please refer to the IB specification for detailed +information regarding each compliance statement. + +* C14-22 (Authentication): + M_Key M_KeyProtectBits and M_KeyLeasePeriod shall be set in one + SubnSet method. As a work-around, an OpenSM option is provided for + defining the protect bits. + +* C14-67 (Authentication): + On SubnGet(SMInfo) and SubnSet(SMInfo) - if M_Key is not zero then + the SM shall generate a SubnGetResp if the M_Key matches, or + silently drop the packet if M_Key does not match. + +* C15-0.1.23.4 (Authentication): + InformInfoRecords shall always be provided with the QPN set to 0, + except for the case of a trusted request, in which case the actual + subscriber QPN shall be returned. + +* o13-17.1.2 (Event-FWD): + If no permission to forward, the subscription should be removed and + no further forwarding should occur. + +* C14-24.1.1.5 and C14-62.1.1.22 (Initialization): + GUIDInfo - SM should enable assigning Port GUIDInfo. + +* C14-44 (Initialization): + If the SM discovers that it is missing an M_Key to update CA/RT/SW, + it should notify the higher level. + +* C14-62.1.1.12 (Initialization): + PortInfo:M_Key - Set the M_Key to a node based random value. + +* C14-62.1.1.13 (Initialization): + PortInfo:P_KeyProtectBits - set according to an optional policy. + +* C14-62.1.1.24 (Initialization): + SwitchInfo:DefaultPort - should be configured for random FDB. + +* C14-62.1.1.32 (Initialization): + RandomForwardingTable should be configured. + +* o15-0.1.12 (Multicast): + If the JoinState is SendOnlyNonMember = 1 (only), then the endport + should join as sender only. + +* o15-0.1.8 (Multicast): + If a request for creating an MCG with fields that cannot be met, + return ERR_REQ_INVALID (currently ignores SL and FlowLabelTClass). + +* C15-0.1.8.6 (SA-Query): + Respond to SubnAdmGetTraceTable - this is an optional attribute. + +* C15-0.1.13 Services: + Reject ServiceRecord create, modify or delete if the given + ServiceP_Key does not match the one included in the ServiceGID port + and the port that sent the request. + +* C15-0.1.14 (Services): + Provide means to associate service name and ServiceKeys. + +4 Major Bug Fixes +----------------- + +The following is a list of bugs that were fixed. Note that other less critical +or visible bugs were also fixed. + +* osm_ucast_ftree.c: do load-leveling of non-CN routes + +* osm_ucast_ftree.c: ignore port 0 and loopbacks on switches + +* lash: fix possible segfault in osm_get_lash_sl() + +* osm_ucast_ftree.c: fixing coredump in fat-tree routing + +* osm_sa_slvl_record: fix overflow crash + +* Break multicast rerouting requests processing when heavy sweep is + scheduled. + +* updn: report fallback properly + +* Fix incorrect identification of routing engine used + +* Don't zero base LID when invalid value is received + +* lash: fix wrong allocation size + +* Fixing broken logic in 'process world' part of LinkRecord processing + +* Fix lmc_mask bit order in osm_sa_link_record.c + +* Adding missing comparison by to_lid/from_lid in LinkRecord processing + +* Broken logic when scanning subnet for PIR request + +* No interactive games in daemon mode + +* Fixing memory leak in node description + +* Fix PortInfo update issues for switch port 0 + +* Changed method_mask type in user_mad interface in accordance with + kernel ABI + +* Use umad_get_issm_path() in osm_vendor_set_sm() + +* Report message fix + +* Uninitialized variables usage fix + +* osm_ucast_ftree.c: Possible NULL ptr seg fault + +* osm_mcast_mgr.c: Possible NULL ptr seg fault + +* TrapRepress was failing for mkey != 0 + +* IB_PR_COMPMASK was used in MPR + +* Set hop limit when creating ipoib multicast groups + +* Fix outstanding mad counters tracking on the error paths. + +* Report new ports before handover mastership + +* Fix opvls and neighbormtu when remote port invalid. + +* Bug in coding trying to set vl_arb_high_limit when PortInfo.base_lid + was still zero. + +* Protect SMInfo response against port moving issue. + +5 Main Verification Flows +------------------------- + +OpenSM verification is run using the following activities: +* osmtest - a stand-alone program +* ibmgtsim (IB management simulator) based - a set of flows that + simulate clusters, inject errors and verify OpenSM capability to + respond and bring up the network correctly. +* small cluster regression testing - where the SM is used on back to + back or single switch configurations. The regression includes + multiple OpenSM dedicated tests. +* cluster testing - when we run OpenSM to setup a large cluster, perform + hand-off, reboots and reconnects, verify routing correctness and SA + responsiveness at the ULP level (IPoIB and SDP). + +5.1 osmtest + +osmtest is an automated verification tool used for OpenSM +testing. Its verification flows are described by list below. + +* Inventory File: Obtain and verify all port info, node info, link and path + records parameters. + +* Service Record: + - Register new service + - Register another service (with a lease period) + - Register another service (with service p_key set to zero) + - Get all services by name + - Delete the first service + - Delete the third service + - Added bad flows of get/delete non valid service + - Add / Get same service with different data + - Add / Get / Delete by different component mask values (services + by Name & Key / Name & Data / Name & Id / Id only ) + +* Multicast Member Record: + - Query of existing Groups (IPoIB) + - BAD Join with insufficient comp mask (o15.0.1.3) + - Create given MGID=0 (o15.0.1.4) + - Create given MGID=0xFF12A01C,FE800000,00000000,12345678 (o15.0.1.4) + - Create BAD MGID=0xFA. (o15.0.1.6) + - Create BAD MGID=0xFF12A01B w/ link-local not set (o15.0.1.6) + - New MGID with invalid join state (o15.0.1.9) + - Retry of existing MGID - See JoinState update (o15.0.1.11) + - BAD RATE when connecting to existing MGID (o15.0.1.13) + - Partial JoinState delete request - removing FullMember (o15.0.1.14) + - Full Delete of a group (o15.0.1.14) + - Verify Delete by trying to Join deleted group (o15.0.1.14) + - BAD Delete of IPoIB membership (no prev join) (o15.0.1.15) + +* GUIDInfo Record: + - All GUIDInfoRecords in subnet are obtained + +* MultiPathRecord: + - Perform some compliant and noncompliant MultiPathRecord requests + - Validation is via status in responses and IB analyzer + +* PKeyTableRecord: + - Perform some compliant and noncompliant PKeyTableRecord queries + - Validation is via status in responses and IB analyzer + +* LinearForwardingTableRecord: + - Perform some compliant and noncompliant LinearForwardingTableRecord queries + - Validation is via status in responses and IB analyzer + +* Event Forwarding: Register for trap forwarding using reports + - Send a trap and wait for report + - Unregister non-existing + +* Trap 64/65 Flow: Register to Trap 64-65, create traps (by + disconnecting/connecting ports) and wait for report, then unregister. + +* Stress Test: send PortInfoRecord queries, both single and RMPP and + check for the rate of responses as well as their validity. + + +5.2 IB Management Simulator OpenSM Test Flows: + +The simulator provides ability to simulate the SM handling of virtual +topologies that are not limited to actual lab equipment availability. +OpenSM was simulated to bring up clusters of up to 10,000 nodes. Daily +regressions use smaller (16 and 128 nodes clusters). + +The following test flows are run on the IB management simulator: + +* Stability: + Up to 12 links from the fabric are randomly selected to drop packets + at drop rates up to 90%. The SM is required to succeed in bringing the + fabric up. The resulting routing is verified to be correct as well. + +* LID Manager: + Using LMC = 2 the fabric is initialized with LIDs. Faults such as + zero LID, Duplicated LID, non-aligned (to LMC) LIDs are + randomly assigned to various nodes and other errors are randomly + output to the guid2lid cache file. The SM sweep is run 5 times and + after each iteration a complete verification is made to ensure that all + LIDs that could possibly be maintained are kept, as well as that all nodes + were assigned a legal LID range. + +* Multicast Routing: + Nodes randomly join the 0xc000 group and eventually the + resulting routing is verified for completeness and adherence to + Up/Down routing rules. + +* osmtest: + The complete osmtest flow as described in the previous table is run on + the simulated fabrics. + +* Stress Test: + This flow merges fabric, LID and stability issues with continuous + PathRecord, ServiceRecord and Multicast Join/Leave activity to + stress the SM/SA during continuous sweeps. InformInfo Set/Delete/Get + were added to the test such both existing and non existing nodes + perform them in random order. + +5.3 OpenSM Regression + +Using a back-to-back or single switch connection, the following set of +tests is run nightly on the stacks described in table 2. The included +tests are: + +* Stress Testing: Flood the SA with queries from multiple channel + adapters to check the robustness of the entire stack up to the SA. + +* Dynamic Changes: Dynamic Topology changes, through randomly + dropping SMP packets, used to test OpenSM adaptation to an unstable + network & verify DB correctness. + +* Trap Injection: This flow injects traps to the SM and verifies that it + handles them gracefully. + +* SA Query Test: This test exhaustively checks the SA responses to all + possible single component mask. To do that the test examines the + entire set of records the SA can provide, classifies them by their + field values and then selects every field (using component mask and a + value) and verifies that the response matches the expected set of records. + A random selection using multiple component mask bits is also performed. + +5.4 Cluster testing: + +Cluster testing is usually run before a distribution release. It +involves real hardware setups of 16 to 32 nodes (or more if a beta site +is available). Each test is validated by running all-to-all ping through the IB +interface. The test procedure includes: + +* Cluster bringup + +* Hand-off between 2 or 3 SM's while performing: + - Node reboots + - Switch power cycles (disconnecting the SM's) + +* Unresponsive port detection and recovery + +* osmtest from multiple nodes + +* Trap injection and recovery + + +6 Qualification +---------------- + +Table 2 - Qualified IB Stacks +============================= + +Stack | Version +-----------------------------------------|-------------------------- +OFED | 1.3 +OFED | 1.2 +OFED | 1.1 +OFED | 1.0 +OpenIB Gen2 (IBG2 distribution) | 1.0 +OpenIB Gen1 (IBGD distribution) | 1.8.0 +VAPI (Mellanox InfiniBand HCA Driver) | 3.2 and later + +Table 3 - Qualified Devices and Corresponding Firmware +====================================================== + +Mellanox +Device | FW versions +------------------------------------|------------------------------- +InfiniScale | fw-43132 5.2.000 (and later) +InfiniScale III | fw-47396 0.5.000 (and later) +InfiniHost | fw-23108 3.5.000 (and later) +InfiniHost III Lx | fw-25204 1.2.000 (and later) +InfiniHost III Ex (InfiniHost Mode) | fw-25208 4.8.200 (and later) +InfiniHost III Ex (MemFree Mode) | fw-25218 5.3.000 (and later) +ConnectX IB | fw-25408 2.3.000 (and later) + +QLogic/PathScale +Device | Note +--------|----------------------------------------------------------- +iPath | QHT6040 (PathScale InfiniPath HT-460) +iPath | QHT6140 (PathScale InfiniPath HT-465) +iPath | QLE6140 (PathScale InfiniPath PE-880) +iPath | QLE7240 +iPath | QLE7280 + +Note 1: OpenSM does not run on an IBM Galaxy (eHCA) as it does not expose +QP0 and QP1. However, it does support it as a device on the subnet. + +Note 2: QoS firmware and Mellanox devices + +HCAs: QoS supported by ConnectX. The current FW release +doesn't support QoS. QoS-enabled FW release (2_5_000) is +planned for May. If someone wishes to get QoS-enabled FW +before the official release, they should contact Mellanox FAE. + +Switches: QoS supported by InfiniScale III +Any InfiniScale III FW that is supported by OpenSM supports QoS. diff --git a/contrib/ofed/management/opensm/doc/opensm_release_notes-3.2.txt b/contrib/ofed/management/opensm/doc/opensm_release_notes-3.2.txt new file mode 100644 index 000000000000..3356e951359e --- /dev/null +++ b/contrib/ofed/management/opensm/doc/opensm_release_notes-3.2.txt @@ -0,0 +1,618 @@ + OpenSM Release Notes 3.2 + ============================= + +Version: OpenSM 3.2.x +Repo: git://git.openfabrics.org/~sashak/management.git +Date: Dec 2008 + +1 Overview +---------- +This document describes the contents of the OpenSM 3.2 release. +OpenSM is an InfiniBand compliant Subnet Manager and Administration, +and runs on top of OpenIB. The OpenSM version for this release +is opensm-3.2.5 + +This document includes the following sections: +1 This Overview section (describing new features and software + dependencies) +2 Known Issues And Limitations +3 Unsupported IB compliance statements +4 Bug Fixes +5 Main Verification Flows +6 Qualified Software Stacks and Devices + +1.1 Major New Features + +* Cached Routing + OpenSM provides an optional unicast routing cache (enabled by '-A' or + '--ucast_cache' options). When enabled, unicast routing cache prevents + routing recalculation (which is a heavy task in a large cluster) when + there was no topology change detected during the heavy sweep, or when + the topology change does not require new routing calculation, e.g. when + one or more CAs/RTRs/leaf switches going down, or one or more of these + nodes coming back after being down. + +* Routing Chaining + Routing chaining is the ability to configure the order in which routing + algorithms are applied in opensm, i.e. '-R ftree,updn,minhop' - try + using ftree routing. If ftree fails, try updn. If updn fails, try + minhop. + +* IPv6 Solicited Node Multicast addresses consolidation + When this mode is used (enabled with --consolidate_ipv6_snm_req option) + OpenSM will map all IPv6 Solicited Node Multicast address join requests + into a single Multicast group with address ff10:601b::1:ff00:0. In this + way limited MLID space is saved. This IBA noncompliant feature is very + useful with large (~> 1024 nodes) clusters. + +* OpenSM sweep state machine rework + Huge and buggy OpenSM sweep state machine was fully rewritten in safer + and more effective synchronous manner. + +* Multi lid routing balancing for updn/minhop routing algorithms + When LMC > 0 is used OpenSM will ensure to generate routing paths via + different switches and when possible chassis. + +* Preserve base lid routes when LMC > 0 + When LMC > 0 is used OpenSM will preserve routing paths for base lids + as it would be with LMC = 0. In this way traffic on each LID level is + not affected by LMC changes. + +* Ordered routing paths balancing + This adds ability to predefine the port order in which routing paths + balancing is performed by OpenSM. Helps to improve performance + dramatically (40-50%) for applications with known communication + pattern. Activated with --guid_routing_order_file command line option. + +* Unified OpenSM configuration + Now there is "conventional" config file instead of hidden option cache + file (opensm.opts). OpenSM will find this in a default place (consult + man page for exact value) or the file name can be specified with '-F' + command line option. Also there is an option ('-c') to generate config + file template. + +* Query remote SMs during light sweep + Master OpenSM will query remote standby SMs periodically to catch its + possible state changes and react accordingly (as required by IBA spec). + +* Predefined port ids for Up/Down algorithm + This is useful as Up/Down fine tuning tool - the algorithm will use + predefined port IDs instead of GUIDs for its decision about direction. + Activated with --ids_guid_file command line option. + +* Improved plugin API version 2. + Now OpenSM will provide to plugins the access to all data structures. + This make it possible to implement powerful multi purpose plugins. All + OpenSM header files are installed now and specific configuration/build + options are exported via generated osm_config.h header file. + +* Many code improvements, optimizations and cleanups + +* Automatic daily snapshots generation. + This is is not a "feature", but simplifies the access to recent OpenSM + bits. + +1.2 Minor New Features: + +* Cleanup cl_qlock_pool memory allocator - speedup memory allocations + +* Support for configurable (via OSM_UMAD_MAX_PENDING environment variable) + size of pending MADs pool. + +* Set packet life time to subnet timeout option rather than default + +* Enforce routing paths rebalancing on switch reconnection + +* In Up/Down routing algorithm compare GUID values in host byte order + +* Add 'switchbalance' and 'lidbalance' commands for OpenSM console + +* Respond to new trap 144 node description update flag + +* Add '--connect_roots' command line options. This preserves connectivity + between root nodes in Up/Down routing algorithm + +* Setting SL in the IPoIB MCast groups in accordance with QoS policy + +* Dump auto detected root node guids in Up/Down routing algorithm + +* Unify OpenSM dumpers code + +* Unify various guid files parsers - add generic nodenamemap style parser + +* When root node guids were provided in file update the list on each + Up/Down run + +* During ./configure show values of configuration dirs and files + +* Make prefix routes config file name configurable + +* Add a Performance Manager HOWTO to the docs and the dist + +* Support separate SA and SM keys as clarified in IBA 1.2.1 + +* Remove AM_MAINTAINER_MODE in ./configure + +* Make vendor type OSM_VENDOR_INTF_OPENIB (libibumad) to be default + +* Build osm_perfmgr_db.* content only when PerfMgr is enabled. + +* Move PerfMgr event_db_dump_file to common OpenSM dump dir + +* Allow space separated strings as values in OpenSM config + +* Support for multiple event plugins + +* Add '--version' command line option + +* Add '--create-config ' command line option + +* Speedup and simplify logging code + +* Speedup multicast processing in SA DB + +* In log messages convert unicast LIDs from hex to decimal format and + GIDs from hex to IPv6 address format + +* Handle all possible ports in "ignore-guids" file + +* Add 'reroute' console command + +* Remove many install-exec-hook from Makefiles + +* Some cleanups in LASH routing algorithm code + +* In Makefiles remove -rpath and explicit -lpthread, -ldl from LDFLAGS + (move to configurator) + +* Install all OpenSM header files + +* Improve locking in SM Info receiver + +* Add new OSM_EVENT_ID_SUBNET_UP event for plugins + +* Redo lex and yacc files generation in conventional way + +* Add a missing Node Description check on light sweep. + +* Move vendor specific compilation defines from command to generated + config.h file + +* Provide useful error message when log file opening fails + +* Add generated osm_config.h file with OpenSM specific defines + +* Display port number in decimal in log messages + +* Replace osm_vendor_select.h by generated osm_config.h + +* Unify options listing in OpenSM usage message + +* LFT buffers handling simplification + +* Add 'dump_conf' console command + +* OpenSM performs sweep on SIGCONT (coming out of suspend). + +* When our SM is in Standby state and its priority is increased + (via console command), notify master SM by sending Trap 144. + +* When entering standby state (after discovery) notify master SM + with Trap 144. + +* support more PortInfo:CapabilityMask bits + +* When babbling port policy is on disable the port with the least hop + count. + +1.3 Library API Changes + + None + +1.4 Software Dependencies + +OpenSM depends on the installation of either OFED 1.x, OpenIB gen2 (e.g. +IBG2 distribution), OpenIB gen1 (e.g. IBGD distribution), or Mellanox +VAPI stacks. The qualified driver versions are provided in Table 2, +"Qualified IB Stacks". + +Also, building of QoS manager policy file parser requires flex, and either +bison or byacc installed. + +1.5 Supported Devices Firmware + +The main task of OpenSM is to initialize InfiniBand devices. The +qualified devices and their corresponding firmware versions +are listed in Table 3. + +2 Known Issues And Limitations +------------------------------ + +* No Service / Key associations: + There is no way to manage Service access by Keys. + +* No SM to SM SMDB synchronization: + Puts the burden of re-registering services, multicast groups, and + inform-info on the client application (or IB access layer core). + +3 Unsupported IB Compliance Statements +-------------------------------------- +The following section lists all the IB compliance statements which +OpenSM does not support. Please refer to the IB specification for detailed +information regarding each compliance statement. + +* C14-22 (Authentication): + M_Key M_KeyProtectBits and M_KeyLeasePeriod shall be set in one + SubnSet method. As a work-around, an OpenSM option is provided for + defining the protect bits. + +* C14-67 (Authentication): + On SubnGet(SMInfo) and SubnSet(SMInfo) - if M_Key is not zero then + the SM shall generate a SubnGetResp if the M_Key matches, or + silently drop the packet if M_Key does not match. + +* C15-0.1.23.4 (Authentication): + InformInfoRecords shall always be provided with the QPN set to 0, + except for the case of a trusted request, in which case the actual + subscriber QPN shall be returned. + +* o13-17.1.2 (Event-FWD): + If no permission to forward, the subscription should be removed and + no further forwarding should occur. + +* C14-24.1.1.5 and C14-62.1.1.22 (Initialization): + GUIDInfo - SM should enable assigning Port GUIDInfo. + +* C14-44 (Initialization): + If the SM discovers that it is missing an M_Key to update CA/RT/SW, + it should notify the higher level. + +* C14-62.1.1.12 (Initialization): + PortInfo:M_Key - Set the M_Key to a node based random value. + +* C14-62.1.1.13 (Initialization): + PortInfo:P_KeyProtectBits - set according to an optional policy. + +* C14-62.1.1.24 (Initialization): + SwitchInfo:DefaultPort - should be configured for random FDB. + +* C14-62.1.1.32 (Initialization): + RandomForwardingTable should be configured. + +* o15-0.1.12 (Multicast): + If the JoinState is SendOnlyNonMember = 1 (only), then the endport + should join as sender only. + +* o15-0.1.8 (Multicast): + If a request for creating an MCG with fields that cannot be met, + return ERR_REQ_INVALID (currently ignores SL and FlowLabelTClass). + +* C15-0.1.8.6 (SA-Query): + Respond to SubnAdmGetTraceTable - this is an optional attribute. + +* C15-0.1.13 Services: + Reject ServiceRecord create, modify or delete if the given + ServiceP_Key does not match the one included in the ServiceGID port + and the port that sent the request. + +* C15-0.1.14 (Services): + Provide means to associate service name and ServiceKeys. + +4 Bug Fixes +----------- + +4.1 Major Bug Fixes + +* Set SA attribute offset to 0 when no records are returned + +* Send trap 64 only after new ports are in ACTIVE state. + +* Fix in sending client reregistration bit + +* Fix default OpenSM SM (and SA) Key byte order + +* Fix in sending Multicast groups creation/deletion notification (Traps + 66,67) + +* Don't startup automatically on SuSE based systems + +4.2 Other Bug Fixes + +* opensm/osm_console.c: fix seg fault when running "portstatus ca" in + the console + +* opensm: fix potential core dumps where osm_node_get_physp_ptr can + return NULL + +* opensm/osm_mcast_mgr: limit spanning tree creation recursion to value + of max hops (64) + +* opensm: switch LFTs incremental update fix + +* opensm/osm_state_mgr.c: fix segmentation fault + +* opensm: eliminate some potential NULL pointer dereferences + +* opensm/osm_console.c: fix guid parsing + +* opensm: fix off by 1 issue with max_lid and max_multicat_lid_ho + +* opensm: fix potentially wrong port_guid initialization + +* opensm/configure.in: fix wrong HAVE_DEFAULT_OPENSM_CONFIG_FILE define + generation + +* opensm: fix snprintf() usage + +* opensm/osm_sa_lft_record: validate LFT block number + +* opensm/osm_sa_lft_record: pass block parameter in host byte order + +* opensm/include/Makefile.am: don't duplicate header files in EXTRA_DIST + +* opensm/osm_sa_class_port_info.c: fix over bound array access + +* osmtest/osmt_service.c: fix over bound array access + +* osmtest: fix qpn encoding in osmtest_informinfo_request() + +* opensm/osm_vendor_mlx_sa.c: handling attribute offset of 0 + +* opensm: fix segfault corner case when osm_console_init fails + +* opensm/console: close console socket on cleanup path + +* opensm/osm_ucast_lash: fix buffer overflow + +* opensm: fix broken IPv6 SNM consolidation code + +* opensm/osm_sa_lft_record.c: fix block number encoding byte order + +* opensm/osm_sa: fix memory leak in SA responder + +* opensm/osm_mcast_mgr: fix memory leak + +* opensm: fix qos config parsing bugs + +* opensm/osm_mcast_tbl.c: fix sending invalid MF block due to max mlid + overflow + +* opensm: log_max_size config parameter in MB + +* opensm/osm_ucast_lash: fix extra memory allocations + +* opensm: fix race in main OpenSM flow + +* opensm/ftree: fix GUID check against cn_guid_file + +* opensm/ftree: save FLT buffers memory allocations + +* opensm/osm_sa_link_record.c: prevent potential endless recursion + +* opensm: remove SM from sm_guid_tbl when IsSM port capability flag is + not set + +* opensm: fix QoS config bug + +* opensm: don't reassign zeroed params from config file + +* Other less critical or visible bugs were also fixed. + +5 Main Verification Flows +------------------------- + +OpenSM verification is run using the following activities: +* osmtest - a stand-alone program +* ibmgtsim (IB management simulator) based - a set of flows that + simulate clusters, inject errors and verify OpenSM capability to + respond and bring up the network correctly. +* small cluster regression testing - where the SM is used on back to + back or single switch configurations. The regression includes + multiple OpenSM dedicated tests. +* cluster testing - when we run OpenSM to setup a large cluster, perform + hand-off, reboots and reconnects, verify routing correctness and SA + responsiveness at the ULP level (IPoIB and SDP). + +5.1 osmtest + +osmtest is an automated verification tool used for OpenSM +testing. Its verification flows are described by list below. + +* Inventory File: Obtain and verify all port info, node info, link and path + records parameters. + +* Service Record: + - Register new service + - Register another service (with a lease period) + - Register another service (with service p_key set to zero) + - Get all services by name + - Delete the first service + - Delete the third service + - Added bad flows of get/delete non valid service + - Add / Get same service with different data + - Add / Get / Delete by different component mask values (services + by Name & Key / Name & Data / Name & Id / Id only ) + +* Multicast Member Record: + - Query of existing Groups (IPoIB) + - BAD Join with insufficient comp mask (o15.0.1.3) + - Create given MGID=0 (o15.0.1.4) + - Create given MGID=0xFF12A01C,FE800000,00000000,12345678 (o15.0.1.4) + - Create BAD MGID=0xFA. (o15.0.1.6) + - Create BAD MGID=0xFF12A01B w/ link-local not set (o15.0.1.6) + - New MGID with invalid join state (o15.0.1.9) + - Retry of existing MGID - See JoinState update (o15.0.1.11) + - BAD RATE when connecting to existing MGID (o15.0.1.13) + - Partial JoinState delete request - removing FullMember (o15.0.1.14) + - Full Delete of a group (o15.0.1.14) + - Verify Delete by trying to Join deleted group (o15.0.1.14) + - BAD Delete of IPoIB membership (no prev join) (o15.0.1.15) + +* GUIDInfo Record: + - All GUIDInfoRecords in subnet are obtained + +* MultiPathRecord: + - Perform some compliant and noncompliant MultiPathRecord requests + - Validation is via status in responses and IB analyzer + +* PKeyTableRecord: + - Perform some compliant and noncompliant PKeyTableRecord queries + - Validation is via status in responses and IB analyzer + +* LinearForwardingTableRecord: + - Perform some compliant and noncompliant LinearForwardingTableRecord queries + - Validation is via status in responses and IB analyzer + +* Event Forwarding: Register for trap forwarding using reports + - Send a trap and wait for report + - Unregister non-existing + +* Trap 64/65 Flow: Register to Trap 64-65, create traps (by + disconnecting/connecting ports) and wait for report, then unregister. + +* Stress Test: send PortInfoRecord queries, both single and RMPP and + check for the rate of responses as well as their validity. + + +5.2 IB Management Simulator OpenSM Test Flows: + +The simulator provides ability to simulate the SM handling of virtual +topologies that are not limited to actual lab equipment availability. +OpenSM was simulated to bring up clusters of up to 10,000 nodes. Daily +regressions use smaller (16 and 128 nodes clusters). + +The following test flows are run on the IB management simulator: + +* Stability: + Up to 12 links from the fabric are randomly selected to drop packets + at drop rates up to 90%. The SM is required to succeed in bringing the + fabric up. The resulting routing is verified to be correct as well. + +* LID Manager: + Using LMC = 2 the fabric is initialized with LIDs. Faults such as + zero LID, Duplicated LID, non-aligned (to LMC) LIDs are + randomly assigned to various nodes and other errors are randomly + output to the guid2lid cache file. The SM sweep is run 5 times and + after each iteration a complete verification is made to ensure that all + LIDs that could possibly be maintained are kept, as well as that all nodes + were assigned a legal LID range. + +* Multicast Routing: + Nodes randomly join the 0xc000 group and eventually the + resulting routing is verified for completeness and adherence to + Up/Down routing rules. + +* osmtest: + The complete osmtest flow as described in the previous table is run on + the simulated fabrics. + +* Stress Test: + This flow merges fabric, LID and stability issues with continuous + PathRecord, ServiceRecord and Multicast Join/Leave activity to + stress the SM/SA during continuous sweeps. InformInfo Set/Delete/Get + were added to the test such both existing and non existing nodes + perform them in random order. + +5.3 OpenSM Regression + +Using a back-to-back or single switch connection, the following set of +tests is run nightly on the stacks described in table 2. The included +tests are: + +* Stress Testing: Flood the SA with queries from multiple channel + adapters to check the robustness of the entire stack up to the SA. + +* Dynamic Changes: Dynamic Topology changes, through randomly + dropping SMP packets, used to test OpenSM adaptation to an unstable + network & verify DB correctness. + +* Trap Injection: This flow injects traps to the SM and verifies that it + handles them gracefully. + +* SA Query Test: This test exhaustively checks the SA responses to all + possible single component mask. To do that the test examines the + entire set of records the SA can provide, classifies them by their + field values and then selects every field (using component mask and a + value) and verifies that the response matches the expected set of records. + A random selection using multiple component mask bits is also performed. + +5.4 Cluster testing: + +Cluster testing is usually run before a distribution release. It +involves real hardware setups of 16 to 32 nodes (or more if a beta site +is available). Each test is validated by running all-to-all ping through the IB +interface. The test procedure includes: + +* Cluster bringup + +* Hand-off between 2 or 3 SM's while performing: + - Node reboots + - Switch power cycles (disconnecting the SM's) + +* Unresponsive port detection and recovery + +* osmtest from multiple nodes + +* Trap injection and recovery + + +6 Qualified Software Stacks and Devices +--------------------------------------- + +OpenSM Compatibility +-------------------- +Note that OpenSM version 3.2.1 and earlier used a value of 1 in host +byte order for the default SM_Key, so there is a compatibility issue +with these earlier versions of OpenSM when the 3.2.2 or later version +is running on a little endian machine. This affects SM handover as well +as SA queries (saquery tool in infiniband-diags). + + +Table 2 - Qualified IB Stacks +============================= + +Stack | Version +-----------------------------------------|-------------------------- +OFED | 1.4 +OFED | 1.3 +OFED | 1.2 +OFED | 1.1 +OFED | 1.0 +OpenIB Gen2 (IBG2 distribution) | 1.0 +OpenIB Gen1 (IBGD distribution) | 1.8.0 +VAPI (Mellanox InfiniBand HCA Driver) | 3.2 and later + +Table 3 - Qualified Devices and Corresponding Firmware +====================================================== + +Mellanox +Device | FW versions +------------------------------------|------------------------------- +InfiniScale | fw-43132 5.2.000 (and later) +InfiniScale III | fw-47396 0.5.000 (and later) +InfiniScale IV | fw-48436 7.1.000 (and later) +InfiniHost | fw-23108 3.5.000 (and later) +InfiniHost III Lx | fw-25204 1.2.000 (and later) +InfiniHost III Ex (InfiniHost Mode) | fw-25208 4.8.200 (and later) +InfiniHost III Ex (MemFree Mode) | fw-25218 5.3.000 (and later) +ConnectX IB | fw-25408 2.3.000 (and later) + +QLogic/PathScale +Device | Note +--------|----------------------------------------------------------- +iPath | QHT6040 (PathScale InfiniPath HT-460) +iPath | QHT6140 (PathScale InfiniPath HT-465) +iPath | QLE6140 (PathScale InfiniPath PE-880) +iPath | QLE7240 +iPath | QLE7280 + +Note 1: OpenSM does not run on an IBM Galaxy (eHCA) as it does not expose +QP0 and QP1. However, it does support it as a device on the subnet. + +Note 2: QoS firmware and Mellanox devices + +HCAs: QoS supported by ConnectX. QoS-enabled FW release is 2_5_000 and +later. + +Switches: QoS supported by InfiniScale III +Any InfiniScale III FW that is supported by OpenSM supports QoS. diff --git a/contrib/ofed/management/opensm/doc/opensm_release_notes_ibg2-2.0.1.txt b/contrib/ofed/management/opensm/doc/opensm_release_notes_ibg2-2.0.1.txt new file mode 100644 index 000000000000..ea1f6a95d906 --- /dev/null +++ b/contrib/ofed/management/opensm/doc/opensm_release_notes_ibg2-2.0.1.txt @@ -0,0 +1,456 @@ + OpenSM Release Notes + ====================== + +Release: IBG2 +Repo: https://openib.org/svn/trunk/contrib/mellanox/gen2/src/userspace/management/osm +Version: 4956 +Date: Jan 2006 + +1 Overview +---------- +This document describes the contents of the OpenSM IBG2 release. +OpenSM is an InfiniBand compliant Subnet Manager and Administrator, +and runs on top of OpenIB. + +This document includes the following sections: +1 This Overview section (describing new features and software + dependencies) +2 Known Issues And Limitations +3 Unsupported IB compliancy statements +4 Major Bug Fixes +5 Main Verification Flows +6 Qualified software stacks and devices + +1.1 New Features + +* New libs created during installation: libopensm - contains interface + to the logging and mads pool machanism. libosmcomp - contains + interface to the complib utilities. libosmvendor - contains + interface to sending/receiving MADs through the SMI or GSI over the + IBG2 driver. + +* Change building mechanism to use autotools. + +* Change directory stucturing of the OpenSM code according to libs: + osm/libvendor - for vendor specific files. osm/complib - for complib + specific files. osm/opensm - for opensm core files. osm/include + +* Semi-static LID assignment: OpenSM uses a cache file for storing all + LID assignments such that, even after a reboot, the LIDs do not + change. The static LID assignment is built on top of a new + "persistancy" layer that abstracts that actual database from its + usage. The implemented database is based on files stored under + /var/cache/osm (this location can be overriden via the environment + variable OSM_CACHE_DIR). Other implementations can use LDAP for + example. Note that a standby SM ignores its previously assigned LIDs + when it becomes the master, and the previous master LID settings are + used. + +* Irresponsive Port Handling: A port that does not respond to SM + queries will be queried upon future light or heavy sweeps, and if + then it responds, it will be setup immediately. Previously such a + port was queried only upon a heavy sweep. + +* Leaf Switch Port HOQ: A different maximal head of queue life time is + assigned to switch ports connected to HCAs such that a bad chipset + or defective hardware will not cause back presure on the fabric. + +* OSM_TMP_DIR: This is a new environment variable controlling the + directory where subnet.lst, osm.fdbs and osm.mcfdbs files are + created. The deafult is still /tmp. + +* Configuration Options cache file: OpenSM was enhanced to provide a + means to modify all its internal configuration options, including + the ones that oreviously were only available under osmsh. The new + file is located under the cache directory and is named + opensm.opts. To automatically create this file OpenSM supports a new + flag: `-c'. The file is generated with the current set of options + used by OpenSM. + +* Previously, under extreme load conditions, when OpenSM got + overloaded with SA queries during which the incoming messages queue + also grew, delays were incurred in message response-time beyond the + expected. This new version of OpenSM has been enhanced such that, + under such a case, incoming new SA queries are returned with a + RESOURCE_BUSY status (per the InfiniBand Architecture + Specification). + +* Kill -HUP: If the OpenSM process (ps -efww |grep opensm.bin) gets a + SIGHUP (sent by kill -HUP), it will start a heavy sweep as if a trap + was received or a change in topology was observed by the SM. + +1.2 Software Dependencies + +OpenSM depends on the installation of either OpenIB gen2 (e.g. IBG2 +distribution), OpenIB gen1 (r.g. IBGD distribution) or Mellanox VAPI +stacks. The qualified driver versions are provided in Table 2, +"Qualified IB Stacks". + +1.4 Supported Devices Firmware + +The main task of OpenSM is to initialize InfiniBand devices. The +qualified devices and their corresponding firmware versions +listed in Table 3. + +2 Known Issues And Limitations +------------------------------ + +* No Partition/Pkey policy support: + OpenSM does not provide means to set poartitions. + +* IB "trusted" concept is unsupported: + Queries that should be classified according to the trustworthiness of + their sources will not be handled correctly. + +* No Service / Key associations: + There is no way to manage Service access by Keys. + +* No SM to SM SMDB synchronization: + Puts the burden of re-registering services, multicast groups, and + inform-info on the client application (or IB access layer core). + +* NPTL problem under Red Hat 9.0, Red Hat AS 3.0: + There are some bugs (pthread conditional wait missing events) + with thread handling when using the dynamic Native POSIX Thread + Library (/lib/tls) of Red Hat 9.0 & Red Hat AS 3.0 OSs. To overcome + that, OpenSM installation places wrapper scripts named opensm and + osmtest in the /usr/bin directory, which preload the standard libc + and libptherad before invoking the executables. If using the osm + package, a similar workaround is possible by putting the LD_PRELOAD + setting in .tclshrc file, for example: set env (LD_PRELOAD) + "/lib/libc.so.6:/lib/libpthread.so.0" + +* InformInfo failure over IBMGT: + OpenSM might not respect a valid InformInfo unsubscribe request when + running over Mellanox's IBMGT user level MAD interface (not on + IBGD). This will be fixed in the next release. + +* No "port down" event handling: + Changing the switch port through which OpenSM connects to the IB + fabric may cause wrong operation. Please restart OpenSM whenever + such a connectivity change is made. + +3 Unsupported IB Compliancy Statements +-------------------------------------- +The following section lists all the IB compliancy statements which +OpenSM does not support. Please refer to IB specification for detailed +information on each compliancy statement. + +* C14-22 (Authentication): + M_Key M_KeyProtectBits and M_KeyLeasePeriod shall be set in one + SubnSet method. As a work-around, an OpenSM option is provided for + defining the protect bits. + +* C14-67 (Authentication): + On SubnGet(SMInfo) and SubnSet(SMInfo) - if M_Key is not zero then + the SM shall generate a SubnGetResp if the M_Key is matching or + silently drop the packet if M_Key is not matching. + +* C15-0.1.23.1 (Authentication): + PortInfoRecords shall always be provided with the M_Key component + set to 0, except in the case of a trusted request, in which case the + actual M_Key component contents shall be provided. + +* C15-0.1.23.2 (Authentication): + P_KeyTableRecords and ServiceAssociationRecords shall only be + provided in responses to trusted requests. + +* C15-0.1.23.4 (Authentication): + InformInfoRecords shall always be provided with the QPN set to + 0, except for the case of a trusted request, in which case the actual + subscriber QPN shall be returned. + +* o13-17.1.2 (Event-FWD): + If no permission to forward, the subscription should be removed and + no further forwarding should occur. + +* C14-37.1.2 (Handover): + Priority should be kept in non-volatile memory. + +* C14-38.1.1 (Handover): + Support AttributeModifier values in SubnSet(SMInfo). If the state + transition requested is invalid - return with status code 7. + +* C14-24.1.1.5 and C14-62.1.1.22 (Initialization): + GUIDInfo - SM should enable assigning Port GUIDInfo. + +* C14-44 (Initialization): + If the SM discovers that it is missing an M_Key to update CA/RT/SW, + it should notify the higher level. + +* C14-62.1.1.11 (Initialization): + PortInfo:VLHighLimit should match the configured VLArb on the port. + +* C14-62.1.1.12 (Initialization): + PortInfo:M_Key - Set the M_Key to a node based random value. + +* C14-62.1.1.13 (Initialization): + PortInfo:P_KeyProtectBits - set according to an optional policy. + +* C14-62.1.1.24 (Initialization): + SwitchInfo:DefaultPort - should be configured for random FDB. + +* C14-62.1.1.32 (Initialization): + RandomForwardingTable should be configured. + +* o15-0.1.12 (Multicast): + If the JoinState is SendOnlyNonMember = 1 (only), then the endport + should join as sender only. + +* o15-0.1.13 (Multicast): + If a Join request using unrealistic parameters is received, return + ERR_REQ_INVALID. + +* o15-0.1.8 (Multicast): + If a request for creating an MCG with fields that cannot be met, + return ERR_REQ_INVALID (currently ignoring SL and FlowLabelTclass). + +* C15-0.1.11 (SA-Query): + Query response should use only base LIDs (as the feature has not + been qualified yet). + +* C15-0.1.19 (SA-Query): + Respond to SubnGetMulti(MultiPathRec) + +* C15-0.1.8.6 (SA-Query): + Respond to SubnAdmGetTraceTable - this is an optional attribute. + +* C15-0.1.8.7 (SA-Query): + SubnAdmGetMulti SubnAdmGetMultiResp - Only in case of a MultiPath. + +* C15-X.Y.Z.W (SA-Query): + SubAdmGet/GetTable GUIDInfo - support GUIDInfo setting/retrieval. + +* C15-0.1.13 Services: + Reject ServiceRecord create, modify or delete if the given + ServiceP_Key does not match the one included in the ServiceGID port + and the port that sent the request. + +* C15-0.1.14 (Services): + Provide means to associate service name and ServiceKeys. + +4 Major Bug Fixes +----------------- + +The following list of bugs were fixed. Note that other less critical +or visible bugs were also fixed. + +* PortInfo query was not matching on several fields. These fields + were added to teh comparison function. + +* OpenSM would crash during exit flow if run with "-o" flag A fix to + the complib global timer destruction sequence solves this problem. + +* OpenSM does not complete the sweep if the driver fails to send a MAD + Counting the number of outstanding MADs the SM waits for response + for was enhanced to take this acse into acount + +* OpenSM was not compliant to the spec statement: C14.62.1.1 Table 183 + p870 l34: ".., the SM shall ensure that one of the P_KeyTable + entries in every node contains either the value 0xFFFF (the default + P_Key, full membership) or the value 0x7FFF (the default P_Key, + partial membership)." OpenSM sets the PKey table with an entry of + 0xffff in case there is no such entry or 0x7fff entries on that + port. Switch ports are ignored. + +* If the SA is queried with IB_PIR_COMPMASK_BASELID and base_lid of 0, + the SA was incorrectly returning all the ports. Fix: do not ignore base + lid of 0 as a query criteria. + +* When provided a PathRecord query with num_paths = 0 the SM should + assuem num_paths = 1. Fix: in the PathRecord query code. + +* PathRecord query returned a deleted multicast groups info. Fix: + Added a check for multicast group state to avoid such cases. + +* LinkRecord query provided wrong results. Fix: in query code. + +* PathRecord did not honor PacketLifeTime component. Fix: Added the + check for packet lifetime matching. + +* Multicast and other registration hapenning all the time on the + cluster. Fix: OpenSM was sending false "client-re-registration" + messages (in PortInfo). + +* On some heavy load cases OpenSM would consume 100% CPU time. Fix: an + endless loop in timer implementation that would happen under rare + heavy CPU load cases. + +* OpenSM hangs during LID assignment phase. Fix: Some condition that + cause that was fixed. + +* OpenSM core dump in the middle of sweep. Fix: A memory range + overflow write was found by valgrind and fix. + +* OpenSM core dump as result fo PathRecord query with no results. Fix: + A memory free on non allocated memory was fixed. + +* OpenSM sweep algorithm confused by a timing race. Fix: A significant + race conditionin the SM sweep algorithm was found and fixed. + +* OpenSM deadlock due to out of order SMINfo and NodeInfo MAD + received. Fix: A fix in lock ordering resolves this issue. + +* TrapRepress sent even if not a master. Fix: in trap receiver. + +5 Main Verification Flows +------------------------- + +OpenSM verification is run using the following activities: +* osmtest - a standalone program +* ibmgtsim (IB management simulator) based - a set of flows that + simulate clusters, inject errors and verify OpenSM capability to + respond and bring up the network correctly. +* small cluster regression testing - where the SM is used on back to + back or single switch configuration. The regression includes + multiple OpenSM dedicated tests +* cluster testing - when we run OpenSM to setup large cluster, perform + handoff, reboots and reconnects, verify routing correctness and SA + responsiveness at teh ULP level (IPoIB and SDP) + +5.1 osmtest + +OsmTest is the main automated verification tool used for OpenSM +testing. Its verification flows are described by list below. + +* Inventory File: Obtain and verify all port info, node info, and path + records parameters. + +* Service Record: + - Register new service + - Register another service (with a lease period) + - Register another service (with service p_key set to zero) + - Get all services by name + - Delete the first service + - Delete the third service. + - Added bad flows of get/delete non valid service + - Add / Get same service with different data + - Add / Get / Delete by different component mask values (services + by Name & Key / Name & Data / Name & Id / Id only ) + +* Multicast Member Record: + - Query of existing Groups (IPoIB) + - BAD Join with insufficient comp mask (o15.0.1.3) + - Create given MGID=0 (o15.0.1.4) + - Create given MGID=0xFF12A01C,FE800000,00000000,12345678 (o15.0.1.4) + - Create BAD MGID=0xFA. (o15.0.1.6) + - Create BAD MGID=0xFF12A01B w/ link-local not set (o15.0.1.6) + - New MGID with invalid join state (o15.0.1.9) + - Retry of existing MGID - See JoinState update (o15.0.1.11) + - BAD RATE when connecting to existing MGID (o15.0.1.13) + - Partial JoinState delete request - removing FullMember (o15.0.1.14) + - Full Delete of a group (o15.0.1.14) + - Verify Delete by trying to Join deleted group (o15.0.1.14) + - BAD Delete of IPoIB membership (no prev join) (o15.0.1.15) + +* Event Forwarding: Register for trap forwarding using reports + - Send a trap and wait for report + - Unregister non-existing + +* Trap 64/65 Flow: Register to Trap 64-65, create traps (by + disconnect/connect ports) and wait for report, then unregister. + +* Stress Test: send PortInfoRecord queries both single and RMPP and + check for the rate of responses as well as their validity. + +5.2 IB Management Simulator OpenSM Test Flows: + +The simulator provides ability to simulate the SM handling of virtual +topologies that are not limitted to actual lab equipment availability. +OpenSM was simulated to bring up clusters of up to 10,000 nodes. Daily +regressions use smaller (16 and 128 nodes clusters). + +The following test flows are running on the IB management simulator: + +* Stability: + Up to 12 links from the fabric are randomly selected to drop packets + at drop rates up to 90%. The SM is required to succeed bringing the + fabric up. The reulting routing is verified to be correct too. + +* LID Manager: + Using LMC = 2 the fabric is being initialized with LIDs. Faults like + zero LID, Duplicated LID, non-aligned (to LMC) LIDs are being + randomly assigned to various nodes and other errors are randomly + output to the guid2lid cache file. The SM sweep is run 5 times and + after each iteration a complete verification is made to ensure all + LIDs that could possibly be maintained are kept, as well as all nodes + were assigned a legal LID range. + +* Multicast Routing: + Nodes are randomly joining the 0xc000 group and eventually the + resulting routing is verified for completness and adherance to + Up/Down routing rules. + +* OsmTest: + The complete osmtest flow as desribed in previous table is run on + the simulated fabrics. + +5.3 OpenSM Regression + +Using a back to back or single switch connection the following set of +tests are run nightly on the stacks described in table 2. The included +tests are: + +* Stress Testing: Flood the SA with queries from multiple channel + adapters to check the robustness of the entire stack up to the SA. + +* Dynamic Changes: Dynamic Topology changes, through randomlly + droping SMP packets used to test OpenSM adaptation to unstable + network & verify DB correctness. + +* Trap Injection: This flow injects traps to the SM and verify it does + handle them gracefully. + +* SA Query Test: This test exhoustivly checks the SA responses to all + possible single component mask. To do that the test examine the + entire set of records the SA can provide, classify them by their + field values and then select every field (using component mask and a + value) and verify the response matches the expected set of records. + A random selection using multiple component mask bits is also performed. + +5.4 Cluster testing: + +Cluster testing is usually run before a distribution release. It +involves real hardware setup of 16 to 32 nodes (or more if beta site +is available). Each test is validated by running all-to-all ping through IB +interface. The test procedure includes: + +* Cluster bringup + +* Handoff between 2 or 3 SM's while performing + - Node reboots + - Switch power cycles (disconneting the SM's) + +* Irresponsive port detection and recovery + +* osmtest from multiple nodes + +* Trap injection and recovery + + +6 Qualification +---------------- + +Table 2 - Qualified IB Stacks +============================= + +Stack | Version +----------------------------------------|-------------------------- +VAPI (Mellanox Infininband HCA Driver) | 3.2 and later +OpenIB Gen1 (IBGD distribution) | 1.8.0 +OpenIB Gen2 (IBG2 distribution) | 1.0 + +Table 3 - Qualified Devices and Corresponding Firmware +====================================================== + +Device | FW versions +--------|----------------------------------------------------------- +MT43132 | InfiniScale - fw-43132 5.2.0 (and later) +MT47396 | InfiniScale III - fw-47396 0.5.0 (and later) +MT23108 | InfiniHost - fw-23108 3.3.2 +MT25204 | InfiniHost III Lx - fw-25204 1.0.1 +MT25208 | InfiniHost III Ex (InfiniHost Mode) - fw-25208 4.6.2 (and later) +MT25208 | InfiniHost III Ex (MemFree Mode) - fw-25218 5.0.1 (and later) + +Other vendors HCAs not yet verified but eHCA is known to be discovered and configured +correctly. diff --git a/contrib/ofed/management/opensm/doc/opensm_release_notes_openib-1.2.1.txt b/contrib/ofed/management/opensm/doc/opensm_release_notes_openib-1.2.1.txt new file mode 100644 index 000000000000..02caaf8d5fe5 --- /dev/null +++ b/contrib/ofed/management/opensm/doc/opensm_release_notes_openib-1.2.1.txt @@ -0,0 +1,460 @@ + OpenSM Release Notes + ====================== + +Version: OpenFabric Enterprise Distribution (OFED) 1.0 +Repo: https://openib.org/svn/gen2/branches/1.0/src/userspace/management/osm +Version: 7992 +Date: Jun 2006 + +1 Overview +---------- +This document describes the contents of the OpenSM OFED 1.0 release. +OpenSM is an InfiniBand compliant Subnet Manager and Administrator, +and runs on top of OpenIB. The OpenSM version for this release +is openib-1.2.1 + +This document includes the following sections: +1 This Overview section (describing new features and software + dependencies) +2 Known Issues And Limitations +3 Unsupported IB compliance statements +4 Major Bug Fixes +5 Main Verification Flows +6 Qualified software stacks and devices + +1.1 New Features + +* SA GuidInfoRecord support + +* Default for maxsmps changed: + Control the number of SMP sent in parallel and thus shorten the + fabric initialization time. + +* osmtest/osmt_slvl_vl_arb.c: + Output file name changed from vl_arbs.txt to qos.txt + +* Support new IBTA Errata IsPortInfoCapMaskMatchSupported: + This new capability of the SA enables matching of individual port + capability bits dramatically reducing the query size for agents like + the SRP initiator query for finding SRP targets. + +* Honor guid2lid when coming out of standby: + This change adds an option to the opensm that forces it to honor the + guid2lid file given when it comes out of Standby state. Currently, + when opensm comes out of Standby state, it ignores the guid2lid file + it read, and honors only the lids defined on the ports themselves. + +* Add guid to opensm opts + This enables the port on which to run the SM to be defined through + the configuration file as well as through the command line. + +* PPC support: + No PPC QA was performed. + +1.2 Software Dependencies + +OpenSM depends on the installation of either OFED 1.0, +OpenIB gen2 (e.g. IBG2 distribution), OpenIB gen1 (e.g. IBGD +distribution) or Mellanox VAPI stacks. The qualified driver versions +are provided in Table 2, "Qualified IB Stacks". + +1.4 Supported Devices Firmware + +The main task of OpenSM is to initialize InfiniBand devices. The +qualified devices and their corresponding firmware versions +are listed in Table 3. + +2 Known Issues And Limitations +------------------------------ + +* No Partition/Pkey policy support: + OpenSM does not provide means to set partitions. + +* No Service / Key associations: + There is no way to manage Service access by Keys. + +* No SM to SM SMDB synchronization: + Puts the burden of re-registering services, multicast groups, and + inform-info on the client application (or IB access layer core). + +* No "port down" event handling: + Changing the switch port through which OpenSM connects to the IB + fabric may cause incorrect operation. Please restart OpenSM whenever + such a connectivity change is made. + +* Changing connections during SM operation: + Under some conditions the SM can get confused by a change in + cabling (moving a cable from one switch port to the other) and + momentarily see this as having the same GUID appear connected + to two different IB ports. Under some conditions, when the SM fails to + get the corresponding change event it might mistakenly report this case + as a "duplicated GUID" case and abort. It is advisable to double-check + the syslog after each such change in connectivity and restart + OpenSM if it has exited. + +* No QoS support: + No SL2VL and VLArbitration setting is performed by the SM. + +3 Unsupported IB Compliance Statements +-------------------------------------- +The following section lists all the IB compliance statements which +OpenSM does not support. Please refer to the IB specification for detailed +information regarding each compliance statement. + +* C14-22 (Authentication): + M_Key M_KeyProtectBits and M_KeyLeasePeriod shall be set in one + SubnSet method. As a work-around, an OpenSM option is provided for + defining the protect bits. + +* C14-67 (Authentication): + On SubnGet(SMInfo) and SubnSet(SMInfo) - if M_Key is not zero then + the SM shall generate a SubnGetResp if the M_Key matches, or + silently drop the packet if M_Key does not match. + +* C15-0.1.23.4 (Authentication): + InformInfoRecords shall always be provided with the QPN set to 0, + except for the case of a trusted request, in which case the actual + subscriber QPN shall be returned. + +* o13-17.1.2 (Event-FWD): + If no permission to forward, the subscription should be removed and + no further forwarding should occur. + +* C14-37.1.2 (Handover): + Priority should be kept in non-volatile memory. + +* C14-24.1.1.5 and C14-62.1.1.22 (Initialization): + GUIDInfo - SM should enable assigning Port GUIDInfo. + +* C14-44 (Initialization): + If the SM discovers that it is missing an M_Key to update CA/RT/SW, + it should notify the higher level. + +* C14-62.1.1.11 (Initialization): + PortInfo:VLHighLimit should match the configured VLArb on the port. + +* C14-62.1.1.12 (Initialization): + PortInfo:M_Key - Set the M_Key to a node based random value. + +* C14-62.1.1.13 (Initialization): + PortInfo:P_KeyProtectBits - set according to an optional policy. + +* C14-62.1.1.24 (Initialization): + SwitchInfo:DefaultPort - should be configured for random FDB. + +* C14-62.1.1.32 (Initialization): + RandomForwardingTable should be configured. + +* o15-0.1.12 (Multicast): + If the JoinState is SendOnlyNonMember = 1 (only), then the endport + should join as sender only. + +* o15-0.1.13 (Multicast): + If a Join request using unrealistic parameters is received, return + ERR_REQ_INVALID. + +* o15-0.1.8 (Multicast): + If a request for creating an MCG with fields that cannot be met, + return ERR_REQ_INVALID (currently ignoring SL and FlowLabelTclass). + +* C15-0.1.11 (SA-Query): + Query response should use only base LIDs (as the feature has not + been qualified yet). + +* C15-0.1.19 (SA-Query): + Respond to SubnGetMulti(MultiPathRec) + +* C15-0.1.8.6 (SA-Query): + Respond to SubnAdmGetTraceTable - this is an optional attribute. + +* C15-0.1.8.7 (SA-Query): + SubnAdmGetMulti SubnAdmGetMultiResp - Only in case of a MultiPath. + +* C15-0.1.13 Services: + Reject ServiceRecord create, modify or delete if the given + ServiceP_Key does not match the one included in the ServiceGID port + and the port that sent the request. + +* C15-0.1.14 (Services): + Provide means to associate service name and ServiceKeys. + +4 Major Bug Fixes +----------------- + +The following is a list of bugs that were fixed. Note that other less critical +or visible bugs were also fixed. + +* Eliminate error on active -> active port state transition + SM may transition port from armed to active but in the meantime, due + to passing a data packet with active enable set, the port may + already have transitioned to active. Active -> active port state + transition is indicated as an error but it isn't really an error so + don't indicate error in the osm log. + +* Routing not set for the first LID in the last LFT block: + Fix: osm_switch.c: In osm_switch_get_fwd_tbl_block last block calculation + +* Corrupted guid2lid file causes OpenSM exit + Fix: exit only if exit_on_fatal option is set (the default) + +* OpenSM was causing Client-Re-Registration continuously: + The SM was storing the response PortInfo.ClientReRegstration + bit and using it during next Set(PortInfo). Fix: clear the bit on + receive. + +* Multicast Query Selectors MTU, rate, and PacketLifeTime were not exact + +* Try not to recognize port change as duplicated GUID + This fix solves the issue of a port move during heavy sweep + being recognized as a duplicated guid. Fix: If the SM sees what + seems to be a duplicated guid, but it also received an indication + for immediately forcing another heavy sweep (for example, as a + result of receiving trap 128) then it shouldn't issue a duplicated + guid error (and possibly exit), but should just ignore this and + continue. This means that only if the SM recognizes such a + duplication in a stable subnet that it'll issue the error (and + possibly exit). + +* Set PKey table on switch ports not supporting it: + OpenSM attempts to set pkey table entries on external switch ports + even if the switch declares a PartitionEnforcementCap of zero. The + consequence is ERR 4108. Fix: Observe PartitionEnforcementCap of zero. + +* Incorrect MCMemberRecord Get/GetTable in trusted mode: + This change fixes the retrieval of the MCMember records according to + Errata MGTWG3280. This fix provide means to obtain all the group + members by issuing a trusted GetTable query. + +* Trusted MCMemberRecord query was not recognized as trusted: + Trust is checked by comparing the request SM_Key field to the SM + SM_Key. The bug was in looking up the SM_Key from the response not + the request. + +* Port left in down state after setting MTU or OpVLs on its neighbor: + In case of a difference between the MTU of two ports, only the port + with the higher MTU was set to down. Its remote port was written in + the DB as in the ACTIVE state although its real status was INIT. + Because of this, the SM didn't try to move the remote port to + ACTIVE. + +* Atomic counters used throughout the code were broken: + A new implementation has been provided. + +* MC Group creation with "less than" MTU ignores the requester MTU: + When requesting to create an MC group with MTU(rate) selector 1 + (meaning less than rate specified), the MC group is created with + MTU(rate) requested - 1. This is without checking the MTU(rate) of + the port requesting the creation of the multicast group. This means + that if, for example, port with MTU=2 sends a request for MC group + creation with MTU selector=1 and MTU=5, Opensm will try to create a + MC group with MTU=4, and fail, since the port capabilities are not + realizable. Fix: creation of the MC group with MTU(rate) also takes + into account the MTU(rate) of the port requesting the creation. + +* MC Group join does not validate that the joining port's capabilities + match those of the MC. Fix: Add verification of endport physical + capability to join MC group. + +* ClientReRegistration not sent to ports discovered after first sweep: + PortInfo sent with ClientReRegistration bit turned on only during + the first sweep after becoming Master. This doesn't cover all cases + where ClientReRegistration should be turned on. Fix: turn on this + bit also on new ports it discovers (in cases of subnet merging, for + example). + +* segfault during a report on deleted multicast group: + osm_mcast_mgr.c, executing the line of code: + osm_mgrp_send_delete_notice( p_mgr->p_subn, p_mgr->p_log, p_mgrp ); + caused segmentation fault since the handle p_mgrp was already + deleted while the function was called. Fix: inserted the line above + into the protected section. + +* segfault in osm_get_gid_by_mad_addr: + The affected flows are ports and multicast joins. + +* segfault in LID manager: + Handle NULL p_rem_physp can validly be NULL when the remote SMA is + not responding (but physical link is up). + +* segfault in Up/Down routing engine + + +5 Main Verification Flows +------------------------- + +OpenSM verification is run using the following activities: +* osmtest - a stand-alone program +* ibmgtsim (IB management simulator) based - a set of flows that + simulate clusters, inject errors and verify OpenSM capability to + respond and bring up the network correctly. +* small cluster regression testing - where the SM is used on back to + back or single switch configurations. The regression includes + multiple OpenSM dedicated tests. +* cluster testing - when we run OpenSM to setup a large cluster, perform + hand-off, reboots and reconnects, verify routing correctness and SA + responsiveness at the ULP level (IPoIB and SDP). + +5.1 osmtest + +osmtest is an automated verification tool used for OpenSM +testing. Its verification flows are described by list below. + +* Inventory File: Obtain and verify all port info, node info, and path + records parameters. + +* Service Record: + - Register new service + - Register another service (with a lease period) + - Register another service (with service p_key set to zero) + - Get all services by name + - Delete the first service + - Delete the third service. + - Added bad flows of get/delete non valid service + - Add / Get same service with different data + - Add / Get / Delete by different component mask values (services + by Name & Key / Name & Data / Name & Id / Id only ) + +* Multicast Member Record: + - Query of existing Groups (IPoIB) + - BAD Join with insufficient comp mask (o15.0.1.3) + - Create given MGID=0 (o15.0.1.4) + - Create given MGID=0xFF12A01C,FE800000,00000000,12345678 (o15.0.1.4) + - Create BAD MGID=0xFA. (o15.0.1.6) + - Create BAD MGID=0xFF12A01B w/ link-local not set (o15.0.1.6) + - New MGID with invalid join state (o15.0.1.9) + - Retry of existing MGID - See JoinState update (o15.0.1.11) + - BAD RATE when connecting to existing MGID (o15.0.1.13) + - Partial JoinState delete request - removing FullMember (o15.0.1.14) + - Full Delete of a group (o15.0.1.14) + - Verify Delete by trying to Join deleted group (o15.0.1.14) + - BAD Delete of IPoIB membership (no prev join) (o15.0.1.15) + +* GUIDInfo Record: + - All GUIDInfoRecords in subnet are obtained + +* Event Forwarding: Register for trap forwarding using reports + - Send a trap and wait for report + - Unregister non-existing + +* Trap 64/65 Flow: Register to Trap 64-65, create traps (by + disconnecting/connecting ports) and wait for report, then unregister. + +* Stress Test: send PortInfoRecord queries, both single and RMPP and + check for the rate of responses as well as their validity. + + +5.2 IB Management Simulator OpenSM Test Flows: + +The simulator provides ability to simulate the SM handling of virtual +topologies that are not limited to actual lab equipment availability. +OpenSM was simulated to bring up clusters of up to 10,000 nodes. Daily +regressions use smaller (16 and 128 nodes clusters). + +The following test flows are run on the IB management simulator: + +* Stability: + Up to 12 links from the fabric are randomly selected to drop packets + at drop rates up to 90%. The SM is required to succeed in bringing the + fabric up. The resulting routing is verified to be correct, too. + +* LID Manager: + Using LMC = 2 the fabric is initialized with LIDs. Faults such as + zero LID, Duplicated LID, non-aligned (to LMC) LIDs are + randomly assigned to various nodes and other errors are randomly + output to the guid2lid cache file. The SM sweep is run 5 times and + after each iteration a complete verification is made to ensure that all + LIDs that could possibly be maintained are kept, as well as that all nodes + were assigned a legal LID range. + +* Multicast Routing: + Nodes randomly join the 0xc000 group and eventually the + resulting routing is verified for completeness and adherence to + Up/Down routing rules. + +* osmtest: + The complete osmtest flow as described in the previous table is run on + the simulated fabrics. + +* Stress Test: + This flow merges fabric, LID and stability issues with continuous + PathRecord, ServiceRecord and Multicast Join/Leave activity to + stress the SM/SA during continuous sweeps. + +5.3 OpenSM Regression + +Using a back-to-back or single switch connection, the following set of +tests is run nightly on the stacks described in table 2. The included +tests are: + +* Stress Testing: Flood the SA with queries from multiple channel + adapters to check the robustness of the entire stack up to the SA. + +* Dynamic Changes: Dynamic Topology changes, through randomly + dropping SMP packets, used to test OpenSM adaptation to an unstable + network & verify DB correctness. + +* Trap Injection: This flow injects traps to the SM and verifies that it + handles them gracefully. + +* SA Query Test: This test exhaustively checks the SA responses to all + possible single component mask. To do that the test examines the + entire set of records the SA can provide, classifies them by their + field values and then selects every field (using component mask and a + value) and verifies that the response matches the expected set of records. + A random selection using multiple component mask bits is also performed. + +5.4 Cluster testing: + +Cluster testing is usually run before a distribution release. It +involves real hardware setups of 16 to 32 nodes (or more if a beta site +is available). Each test is validated by running all-to-all ping through the IB +interface. The test procedure includes: + +* Cluster bringup + +* Hand-off between 2 or 3 SM's while performing + - Node reboots + - Switch power cycles (disconnecting the SM's) + +* Unresponsive port detection and recovery + +* osmtest from multiple nodes + +* Trap injection and recovery + + +6 Qualification +---------------- + +Table 2 - Qualified IB Stacks +============================= + +Stack | Version +-----------------------------------------|-------------------------- +OFED | 1.0 +OpenIB Gen2 (IBG2 distribution) | 1.0 +OpenIB Gen1 (IBGD distribution) | 1.8.0 +VAPI (Mellanox InfiniBand HCA Driver) | 3.2 and later + +Table 3 - Qualified Devices and Corresponding Firmware +====================================================== + +Mellanox +Device | FW versions +--------|----------------------------------------------------------- +MT43132 | InfiniScale - fw-43132 5.2.0 (and later) +MT47396 | InfiniScale III - fw-47396 0.5.0 (and later) +MT23108 | InfiniHost - fw-23108 3.3.2 +MT25204 | InfiniHost III Lx - fw-25204 1.0.1 +MT25208 | InfiniHost III Ex (InfiniHost Mode) - fw-25208 4.6.2 (and later) +MT25208 | InfiniHost III Ex (MemFree Mode) - fw-25218 5.0.1 (and later) + +QLogic/PathScale +Device | Note +--------|----------------------------------------------------------- +iPath | QHT6040 (PathScale InfiniPath HT-460) +iPath | QHT6140 (PathScale InfiniPath HT-465) +iPath | QLE6140 (PathScale InfiniPath PE-880) + +Note: OpenSM does not run on an IBM Galaxy (eHCA) as it does not expose +QP0 and QP1. However, it does support it as a device on the subnet. diff --git a/contrib/ofed/management/opensm/doc/opensm_release_notes_openib-2.0.5.txt b/contrib/ofed/management/opensm/doc/opensm_release_notes_openib-2.0.5.txt new file mode 100644 index 000000000000..51bd21c7c579 --- /dev/null +++ b/contrib/ofed/management/opensm/doc/opensm_release_notes_openib-2.0.5.txt @@ -0,0 +1,486 @@ + OpenSM Release Notes 2.0.5 + ============================ + +Version: OpenFabrics Enterprise Distribution (OFED) 1.1 +Repo: https://openib.org/svn/gen2/branches/1.1/src/userspace/management/osm +Version: 9535 (openib-2.0.5) +Date: October 2006 + +1 Overview +---------- +This document describes the contents of the OpenSM OFED 1.1 release. +OpenSM is an InfiniBand compliant Subnet Manager and Administration, +and runs on top of OpenIB. The OpenSM version for this release +is openib-2.0.5 + +This document includes the following sections: +1 This Overview section (describing new features and software + dependencies) +2 Known Issues And Limitations +3 Unsupported IB compliance statements +4 Major Bug Fixes +5 Main Verification Flows +6 Qualified software stacks and devices + +1.1 Major New Features + +* Partition manager: + The partition manager provides a means to setup multiple partitions + by providing a partition policy file. For details please read the + doc/partition-config.txt or the opensm man page. + +* Basic QoS Manager: + Provides a uniform configuration of the entire fabric with values defined + in the OpenSM options file. The options support different settings for + CAs, Switches, and Routers. Note that this is disabled by default and + using -Q enables QoS fabric setup. + +* Loading pre-routes from a file: + A new routing module enables loading pre-routes from a file. + To use this option you should use the command line options: + "-R file --U " or + "--routing_engine file --ucast_file " + For more information refer to the file doc/modular-routing.txt + or the opensm man page. + +* SA MultiPathRecord support: + The SA can now handle requests for multiple PathRecords in one query. + This includes methods SA GetMulti/GetMultiResp and dual sided RMPP. + +* PPC64 is now QAed and supported + +* Support LMC > 0 for Switch Enhanced Port 0: + Allows enhanced switch port 0 (ESP0) to have a non zero + LMC. Use the configured subnet wide LMC for this. Modifications were + necessary to the LID assignment and routing to support this. + Also, added an option to the configuration to use LMC configured for + subnet for enhanced switch port 0 or set it to 0 even if a non zero + LMC is configured for the subnet. The default is currently the + latter option. The new configuration option is: lmc_esp0 + +1.2 Minor New Features: + +* IPoIB broadcast group configuration: + It is now possible to control the IPoIB broadcast group parameters + (MTU, rate, SL) through the partitions configuration file. + +* Limiting OpenSM log file size: + By providing the command line option: "-L " or + "--log_limit " the user can limit the generated log + file size. When specified, the log file will be truncated upon reaching + this limit. + +* Favor 1K MTU for Tavor (MT23108) HCA + In cases where a PathRecord or MultiPathRecord is queried and the + requestor does not specify the MTU or does specify it in a way + that allows for MTU to be 1K and one of the path ends in a Tavor, + limit the MTU to 1K max. + +* Man pages: + Added opensm.8 and osmtest.8 + +* Leaf VL stall count control: + A new parameter (leaf_vl_stall_count) for controlling the number of + sequential packets dropped on a switch port driving a HCA/TCA/Router + that cause the port to enter the VLStalled state was added to the + options file. + +* SM Polling/Handover defaults changed + The default SMInfo polling retries was decreased from 18 to 4 + which reduces the default handover time from 3 min to 40 seconds. + +1.3 Library API Changes + +* cl_mem* APIs deprecated in complib: + These functions are now considered as deprecated and should be + replaced by direct calls to malloc, free, memset, etc. + +* osm_log_init_v2 API added in libopensm: + Supports providing the new option for log file truncation. + +1.4 Software Dependencies + +OpenSM depends on the installation of either OFED 1.1, OFED 1.0, +OpenIB gen2 (e.g. IBG2 distribution), OpenIB gen1 (e.g. IBGD +distribution), or Mellanox VAPI stacks. The qualified driver versions +are provided in Table 2, "Qualified IB Stacks". + +1.5 Supported Devices Firmware + +The main task of OpenSM is to initialize InfiniBand devices. The +qualified devices and their corresponding firmware versions +are listed in Table 3. + +2 Known Issues And Limitations +------------------------------ + +* No Service / Key associations: + There is no way to manage Service access by Keys. + +* No SM to SM SMDB synchronization: + Puts the burden of re-registering services, multicast groups, and + inform-info on the client application (or IB access layer core). + +* No "port down" event handling: + Changing the switch port through which OpenSM connects to the IB + fabric may cause incorrect operation. Please restart OpenSM whenever + such a connectivity change is made. + +* Changing connections during SM operation: + Under some conditions the SM can get confused by a change in + cabling (moving a cable from one switch port to the other) and + momentarily see this as having the same GUID appear connected + to two different IB ports. Under some conditions, when the SM fails to + get the corresponding change event it might mistakenly report this case + as a "duplicated GUID" case and abort. It is advisable to double-check + the syslog after each such change in connectivity and restart + OpenSM if it has exited. + +3 Unsupported IB Compliance Statements +-------------------------------------- +The following section lists all the IB compliance statements which +OpenSM does not support. Please refer to the IB specification for detailed +information regarding each compliance statement. + +* C14-22 (Authentication): + M_Key M_KeyProtectBits and M_KeyLeasePeriod shall be set in one + SubnSet method. As a work-around, an OpenSM option is provided for + defining the protect bits. + +* C14-67 (Authentication): + On SubnGet(SMInfo) and SubnSet(SMInfo) - if M_Key is not zero then + the SM shall generate a SubnGetResp if the M_Key matches, or + silently drop the packet if M_Key does not match. + +* C15-0.1.23.4 (Authentication): + InformInfoRecords shall always be provided with the QPN set to 0, + except for the case of a trusted request, in which case the actual + subscriber QPN shall be returned. + +* o13-17.1.2 (Event-FWD): + If no permission to forward, the subscription should be removed and + no further forwarding should occur. + +* C14-24.1.1.5 and C14-62.1.1.22 (Initialization): + GUIDInfo - SM should enable assigning Port GUIDInfo. + +* C14-44 (Initialization): + If the SM discovers that it is missing an M_Key to update CA/RT/SW, + it should notify the higher level. + +* C14-62.1.1.12 (Initialization): + PortInfo:M_Key - Set the M_Key to a node based random value. + +* C14-62.1.1.13 (Initialization): + PortInfo:P_KeyProtectBits - set according to an optional policy. + +* C14-62.1.1.24 (Initialization): + SwitchInfo:DefaultPort - should be configured for random FDB. + +* C14-62.1.1.32 (Initialization): + RandomForwardingTable should be configured. + +* o15-0.1.12 (Multicast): + If the JoinState is SendOnlyNonMember = 1 (only), then the endport + should join as sender only. + +* o15-0.1.8 (Multicast): + If a request for creating an MCG with fields that cannot be met, + return ERR_REQ_INVALID (currently ignores SL and FlowLabelTClass). + +* C15-0.1.8.6 (SA-Query): + Respond to SubnAdmGetTraceTable - this is an optional attribute. + +* C15-0.1.13 Services: + Reject ServiceRecord create, modify or delete if the given + ServiceP_Key does not match the one included in the ServiceGID port + and the port that sent the request. + +* C15-0.1.14 (Services): + Provide means to associate service name and ServiceKeys. + +4 Major Bug Fixes +----------------- + +The following is a list of bugs that were fixed. Note that other less critical +or visible bugs were also fixed. + +* "Broken" fabric (duplicated port GUIDs) handling improved + Replace assert with a real check to handle invalid physical port + in osm_node_info_rcv.c which could occur on a broken fabric + +* SA client synchronous request failed but status returned was IB_SUCCESS + even if there was no response. + There was a missing setting of the status in the synchronous case. + +* Memory leak fixes: + 1. In libvendor/osm_vendor_ibumad.c:osm_vendor_get_all_port_attr + 2. In libvendor/osm_vendor_ibumad_sa.c:__osmv_sa_mad_rcv_cb + 3. On receiving SMInfo SA request from a node that does not share a + partition, the response mad was allocated but never free'd + as it was never sent. + +* Set(InformInfo) OpenSM Deadlock: + When receiving a request with unknown LID + +* PathRecord to inconsistent multicast destination: + Fix the return error when multicast destination is not consistently + indicated. + +* Remove double calculation of reversible path + In osm_sa_path_record.c:__osm_pr_rcv_get_lid_pair_path a PathRecord + query used to double check if the path is reversible + +* Some PathRecord log messages use "net order": + Fix GUID net to host conversion in some osm_log messages + +* DR/LID routed SMPs direction bit handling: + osm_resp.c:osm_resp_make_resp_smp, set direction bit only if direct + routed class. This bug caused two issues: + 1. Get/Set responses always had direction bit set. + 2. Trap represses never had direction bit set. + The direction bit needs setting in direct routed responses and it + doesn't exist in LID routed responses. + osm_sm_mad_ctrl.c: did not detect the "direction bit" correctly. + +* OpenSM crash due to transaction lookup (interop with Cisco stack) + When a wire TID that maps to internal TID of zero (after applying + mask) was received the lookup of the transaction was successful. + The stale transaction pointed to "free'd" memory. + +* Better handling for Path/MultiPath requests for raw traffic + +* Wrong ProducerType provided in Notice Reports: + When formating an SM generated report, the ProducerType was using + CL_NTOH32 which can not be used to format a 24bit network order number. + +* OpenSM break on PPC64 + complib: Fixed memory corruption in cl_pool.c:cl_qcpool_init. This + affected big endian 64-bit architectures only. + +* Illegal Set(InformInfo) was wrongly successful in updating the SMDB + osm_sa_informinfo.c: In osm_infr_rcv_process_set_method, if sending + error, don't call osm_infr_rcv_process_set_method + +* RMPP queries of InformInfoRecord fail + ib_types.h: Pad ib_inform_info_record_t to be modulo 8 in size so + that attribute offset is calculated properly + +* Returning "invalid request" rather than "unsupported method/attribute" + In these cases, a noncompliant response was being provided. + +* Noncompliant response for SubnAdmGet(PortInfoRecord) with no match + osm_pir_rcv_process, now returns "SA no records error" for SubnAdmGet + with 0 records found + +* Noncompliant non base LID returned by some queries: + The following attributes used to return the request LID rather than + its base LID in responses: PKeyTableRecord, GUIDInfoRecord, + SLtoVLMappingTableRecord, VLArbitrationTableRecord, LinkRecord + +* Noncompliant SubnAdmGet and SubnAdmGetTable: + Mixing of error codes in case of no records or multiple records + fixed for the attributes: + LinearForwardingTableRecord, GUIDInfoRecord, + VLArbitrationTableRecord, LinkRecord, PathRecord + +* segfault in InformInfo flows + Under stress concurrent Set/Delete/Get flows. Fixed by adding + missing lock. + +* SA queries containing LID out if range did not return ERR_REQ_INVALID + +5 Main Verification Flows +------------------------- + +OpenSM verification is run using the following activities: +* osmtest - a stand-alone program +* ibmgtsim (IB management simulator) based - a set of flows that + simulate clusters, inject errors and verify OpenSM capability to + respond and bring up the network correctly. +* small cluster regression testing - where the SM is used on back to + back or single switch configurations. The regression includes + multiple OpenSM dedicated tests. +* cluster testing - when we run OpenSM to setup a large cluster, perform + hand-off, reboots and reconnects, verify routing correctness and SA + responsiveness at the ULP level (IPoIB and SDP). + +5.1 osmtest + +osmtest is an automated verification tool used for OpenSM +testing. Its verification flows are described by list below. + +* Inventory File: Obtain and verify all port info, node info, link and path + records parameters. + +* Service Record: + - Register new service + - Register another service (with a lease period) + - Register another service (with service p_key set to zero) + - Get all services by name + - Delete the first service + - Delete the third service + - Added bad flows of get/delete non valid service + - Add / Get same service with different data + - Add / Get / Delete by different component mask values (services + by Name & Key / Name & Data / Name & Id / Id only ) + +* Multicast Member Record: + - Query of existing Groups (IPoIB) + - BAD Join with insufficient comp mask (o15.0.1.3) + - Create given MGID=0 (o15.0.1.4) + - Create given MGID=0xFF12A01C,FE800000,00000000,12345678 (o15.0.1.4) + - Create BAD MGID=0xFA. (o15.0.1.6) + - Create BAD MGID=0xFF12A01B w/ link-local not set (o15.0.1.6) + - New MGID with invalid join state (o15.0.1.9) + - Retry of existing MGID - See JoinState update (o15.0.1.11) + - BAD RATE when connecting to existing MGID (o15.0.1.13) + - Partial JoinState delete request - removing FullMember (o15.0.1.14) + - Full Delete of a group (o15.0.1.14) + - Verify Delete by trying to Join deleted group (o15.0.1.14) + - BAD Delete of IPoIB membership (no prev join) (o15.0.1.15) + +* GUIDInfo Record: + - All GUIDInfoRecords in subnet are obtained + +* MultiPathRecord: + - Perform some compliant and noncompliant MultiPathRecord requests + - Validation is via status in responses and IB analyzer + +* PKeyTableRecord: + - Perform some compliant and noncompliant PKeyTableRecord queries + - Validation is via status in responses and IB analyzer + +* LinearForwardingTableRecord: + - Perform some compliant and noncompliant LinearForwardingTableRecord queries + - Validation is via status in responses and IB analyzer + +* Event Forwarding: Register for trap forwarding using reports + - Send a trap and wait for report + - Unregister non-existing + +* Trap 64/65 Flow: Register to Trap 64-65, create traps (by + disconnecting/connecting ports) and wait for report, then unregister. + +* Stress Test: send PortInfoRecord queries, both single and RMPP and + check for the rate of responses as well as their validity. + + +5.2 IB Management Simulator OpenSM Test Flows: + +The simulator provides ability to simulate the SM handling of virtual +topologies that are not limited to actual lab equipment availability. +OpenSM was simulated to bring up clusters of up to 10,000 nodes. Daily +regressions use smaller (16 and 128 nodes clusters). + +The following test flows are run on the IB management simulator: + +* Stability: + Up to 12 links from the fabric are randomly selected to drop packets + at drop rates up to 90%. The SM is required to succeed in bringing the + fabric up. The resulting routing is verified to be correct as well. + +* LID Manager: + Using LMC = 2 the fabric is initialized with LIDs. Faults such as + zero LID, Duplicated LID, non-aligned (to LMC) LIDs are + randomly assigned to various nodes and other errors are randomly + output to the guid2lid cache file. The SM sweep is run 5 times and + after each iteration a complete verification is made to ensure that all + LIDs that could possibly be maintained are kept, as well as that all nodes + were assigned a legal LID range. + +* Multicast Routing: + Nodes randomly join the 0xc000 group and eventually the + resulting routing is verified for completeness and adherence to + Up/Down routing rules. + +* osmtest: + The complete osmtest flow as described in the previous table is run on + the simulated fabrics. + +* Stress Test: + This flow merges fabric, LID and stability issues with continuous + PathRecord, ServiceRecord and Multicast Join/Leave activity to + stress the SM/SA during continuous sweeps. InformInfo Set/Delete/Get + were added to the test such both existing and non existing nodes + perform them in random order. + +5.3 OpenSM Regression + +Using a back-to-back or single switch connection, the following set of +tests is run nightly on the stacks described in table 2. The included +tests are: + +* Stress Testing: Flood the SA with queries from multiple channel + adapters to check the robustness of the entire stack up to the SA. + +* Dynamic Changes: Dynamic Topology changes, through randomly + dropping SMP packets, used to test OpenSM adaptation to an unstable + network & verify DB correctness. + +* Trap Injection: This flow injects traps to the SM and verifies that it + handles them gracefully. + +* SA Query Test: This test exhaustively checks the SA responses to all + possible single component mask. To do that the test examines the + entire set of records the SA can provide, classifies them by their + field values and then selects every field (using component mask and a + value) and verifies that the response matches the expected set of records. + A random selection using multiple component mask bits is also performed. + +5.4 Cluster testing: + +Cluster testing is usually run before a distribution release. It +involves real hardware setups of 16 to 32 nodes (or more if a beta site +is available). Each test is validated by running all-to-all ping through the IB +interface. The test procedure includes: + +* Cluster bringup + +* Hand-off between 2 or 3 SM's while performing: + - Node reboots + - Switch power cycles (disconnecting the SM's) + +* Unresponsive port detection and recovery + +* osmtest from multiple nodes + +* Trap injection and recovery + + +6 Qualification +---------------- + +Table 2 - Qualified IB Stacks +============================= + +Stack | Version +-----------------------------------------|-------------------------- +OFED | 1.1 +OFED | 1.0 +OpenIB Gen2 (IBG2 distribution) | 1.0 +OpenIB Gen1 (IBGD distribution) | 1.8.0 +VAPI (Mellanox InfiniBand HCA Driver) | 3.2 and later + +Table 3 - Qualified Devices and Corresponding Firmware +====================================================== + +Mellanox +Device | FW versions +--------|----------------------------------------------------------- +MT43132 | InfiniScale - fw-43132 5.2.0 (and later) +MT47396 | InfiniScale III - fw-47396 0.5.0 (and later) +MT23108 | InfiniHost - fw-23108 3.3.2 (and later) +MT25204 | InfiniHost III Lx - fw-25204 1.0.1i (and later) +MT25208 | InfiniHost III Ex (InfiniHost Mode) - fw-25208 4.6.2 (and later) +MT25208 | InfiniHost III Ex (MemFree Mode) - fw-25218 5.0.1 (and later) + +QLogic/PathScale +Device | Note +--------|----------------------------------------------------------- +iPath | QHT6040 (PathScale InfiniPath HT-460) +iPath | QHT6140 (PathScale InfiniPath HT-465) +iPath | QLE6140 (PathScale InfiniPath PE-880) + +Note: OpenSM does not run on an IBM Galaxy (eHCA) as it does not expose +QP0 and QP1. However, it does support it as a device on the subnet. diff --git a/contrib/ofed/management/opensm/doc/opensm_release_notes_openib-3.0.13.txt b/contrib/ofed/management/opensm/doc/opensm_release_notes_openib-3.0.13.txt new file mode 100644 index 000000000000..b48f1481b95e --- /dev/null +++ b/contrib/ofed/management/opensm/doc/opensm_release_notes_openib-3.0.13.txt @@ -0,0 +1,535 @@ + OpenSM Release Notes 3.0.13 + ============================= + +Version: OpenFabrics Enterprise Distribution (OFED) 1.2 +Repo: git://git.openfabrics.org/~ofed_1_2/management.git (release) + git://git.openfabrics.org/~halr/management.git (development) +Date: June 2007 + +1 Overview +---------- +This document describes the contents of the OpenSM OFED 1.2 release. +OpenSM is an InfiniBand compliant Subnet Manager and Administration, +and runs on top of OpenIB. The OpenSM version for this release +is openib-3.0.13 + +This document includes the following sections: +1 This Overview section (describing new features and software + dependencies) +2 Known Issues And Limitations +3 Unsupported IB compliance statements +4 Major Bug Fixes +5 Main Verification Flows +6 Qualified software stacks and devices + +1.1 Major New Features + +* Routing improvements + Two additional routing algorithms have been added in addition to + performance improvements to the existing routing algorithms. The + two new routing algorithms are FAT tree and LASH. See the + opensm man page for additional details. + +* SA Optional Record support now "virtually" complete + Includes SA InformInfo improvements and InformInfoRecord support in + addition to support for the remaining SA optional records + (MulticastForwardingTableRecord, SwitchInfoRecord). Also, SMInfoRecord + support was improved to include all SMs found. + +* SA database dump/restore + OpenSM now includes the ability to dump and restore the SA database. + This allows for all SA registrations (multicast, services, and events) + to be saved and restored later. + + In verbose mode, OpenSM will dump SA DB (existing multicast groups, + services and InformInfo) into dump file which named "opensm-sa.dump" + and located under standard OpenSM dump directory (/var/log by default). + + If option -S is specified and SA DB dump file name is provided, OpenSM + will try to restore SA database from this file. And if restore is + successful, OpenSM won't ask for client reregistration at subnet bring-up. + +* Modular routing for multicast + In conjunction was SA database dump/restore, there is the ability to + dump and load switch lid matrices (min hops tables) which are used + for multicast route calculation. + +* IB router enablement + OpenSM now supports router ports properly (in terms of PortInfo handling). + There is also some experimental support for IB routers which is enabled + via the ROUTER_EXP compile flag. This support includes SA PathRecord and + MCMemberRecord support for off subnet GIDs. + +* Socket support added to console + OpenSM console now supports remote in addition to local access. + Remote access is currently via telnet. + +1.2 Minor New Features: + +* Change output format of DR path from hex to decimal port numbers + +* Log rotation + The OpenSM log can now be rotated while OpenSM is running (without + stopping and restarting OpenSM). This is accomplished via SIGUSR1. + +* Support scope for IPoIB multicast groups in partition config + +* Dump filename changed from subnet.lst to osm-subnet.lst + Default temp directory for non Windows platforms was previously changed + from /tmp to /var/log. + +* Add option for force SDR link speed + Add option to opensm.opts to force link speed. Currently, only forcing + to SDR link speed is supported. This option is not supported as a + command line option. + +1.3 Library API Changes + + None + +1.4 Software Dependencies + +OpenSM depends on the installation of either OFED 1.2, OFED 1.1, +OFED 1.0, OpenIB gen2 (e.g. IBG2 distribution), OpenIB gen1 (e.g. IBGD +distribution), or Mellanox VAPI stacks. The qualified driver versions +are provided in Table 2, "Qualified IB Stacks". + +1.5 Supported Devices Firmware + +The main task of OpenSM is to initialize InfiniBand devices. The +qualified devices and their corresponding firmware versions +are listed in Table 3. + +2 Known Issues And Limitations +------------------------------ + +* No Service / Key associations: + There is no way to manage Service access by Keys. + +* No SM to SM SMDB synchronization: + Puts the burden of re-registering services, multicast groups, and + inform-info on the client application (or IB access layer core). + +* No "port down" event handling: + Changing the switch port through which OpenSM connects to the IB + fabric may cause incorrect operation. Please restart OpenSM whenever + such a connectivity change is made. + +* Changing connections during SM operation: + Under some conditions the SM can get confused by a change in + cabling (moving a cable from one switch port to the other) and + momentarily see this as having the same GUID appear connected + to two different IB ports. Under some conditions, when the SM fails to + get the corresponding change event it might mistakenly report this case + as a "duplicated GUID" case and abort. It is advisable to double-check + the syslog after each such change in connectivity and restart + OpenSM if it has exited. The same error ("duplicated GUID") will + also appear with a loopback plug. + +3 Unsupported IB Compliance Statements +-------------------------------------- +The following section lists all the IB compliance statements which +OpenSM does not support. Please refer to the IB specification for detailed +information regarding each compliance statement. + +* C14-22 (Authentication): + M_Key M_KeyProtectBits and M_KeyLeasePeriod shall be set in one + SubnSet method. As a work-around, an OpenSM option is provided for + defining the protect bits. + +* C14-67 (Authentication): + On SubnGet(SMInfo) and SubnSet(SMInfo) - if M_Key is not zero then + the SM shall generate a SubnGetResp if the M_Key matches, or + silently drop the packet if M_Key does not match. + +* C15-0.1.23.4 (Authentication): + InformInfoRecords shall always be provided with the QPN set to 0, + except for the case of a trusted request, in which case the actual + subscriber QPN shall be returned. + +* o13-17.1.2 (Event-FWD): + If no permission to forward, the subscription should be removed and + no further forwarding should occur. + +* C14-24.1.1.5 and C14-62.1.1.22 (Initialization): + GUIDInfo - SM should enable assigning Port GUIDInfo. + +* C14-44 (Initialization): + If the SM discovers that it is missing an M_Key to update CA/RT/SW, + it should notify the higher level. + +* C14-62.1.1.12 (Initialization): + PortInfo:M_Key - Set the M_Key to a node based random value. + +* C14-62.1.1.13 (Initialization): + PortInfo:P_KeyProtectBits - set according to an optional policy. + +* C14-62.1.1.24 (Initialization): + SwitchInfo:DefaultPort - should be configured for random FDB. + +* C14-62.1.1.32 (Initialization): + RandomForwardingTable should be configured. + +* o15-0.1.12 (Multicast): + If the JoinState is SendOnlyNonMember = 1 (only), then the endport + should join as sender only. + +* o15-0.1.8 (Multicast): + If a request for creating an MCG with fields that cannot be met, + return ERR_REQ_INVALID (currently ignores SL and FlowLabelTClass). + +* C15-0.1.8.6 (SA-Query): + Respond to SubnAdmGetTraceTable - this is an optional attribute. + +* C15-0.1.13 Services: + Reject ServiceRecord create, modify or delete if the given + ServiceP_Key does not match the one included in the ServiceGID port + and the port that sent the request. + +* C15-0.1.14 (Services): + Provide means to associate service name and ServiceKeys. + +4 Major Bug Fixes +----------------- + +The following is a list of bugs that were fixed. Note that other less critical +or visible bugs were also fixed. + +* osm_sminfo_rcv.c: Add SMInfo self query check. OpenSM can query + itself for SMInfo occassionally due to port moving during subnet + discovery process. Don't create remote SM entry in this case to + prevent deadlocks. + +* osm_ucast_updn.c: Two similar bugs in up/down routing fixed. + 8-bit integers were used as indexes when scanning subnet, which + in one case caused OpenSM to crash when ranking "path" is longer + than 256 switches, and in the other case, caused OpenSM to go into + an infinite loop when fabric has more than 256 roots. + +* osm_sm_state_mgr.c: In __osm_sm_state_mgr_send_master_sm_info_req, + handle master GUID port not found properly + +* osm_sa_multipath_record.c: In __osm_mpr_rcv_get_path_parms, return + IB_NOT_FOUND rather than IB_ERROR when can't route to LID from switch + +* osm_sa_path_record.c: In __osm_pr_rcv_get_path_parms, return IB_NOT_FOUND + rather than IB_ERROR when can't route to LID from switch + +* osm_vendor_ibumad.c: In osm_vendor_set_sm, set issmfd to + -1 on open error + +* osm_vendor_ibumad: Termination crash fix + When OpenSM is terminated umad_receiver thread still running even after + the structures are destroyed and freed, this causes to random (but easily + reproducible) crashes. The reason is that osm_vendor_delete() does not + care about thread termination. This patch adds the receiver thread + cancellation (by using pthread_cancel() and pthread_join()) and cares to + keep have all mutexes unlocked upon termination. There is also minor + termination code consolidation - osm_vendor_port_close() function. + +* osm_port_profile.h: Fix reinsertion issue in osm_port_prof_set_ignored_port + +* osm_matrix.h: Fix segfault with up/down and root nodes file + +* osm_sa_path_record.c: In osm_pr_rcv_process, fix endian of hop_limit + +* osm_vendor_ibumad.c: Close umad port in osm_vendor_delete + +* osm_sa_(multipath path)_record.c: Fix MultiPathRecord/PathRecord issues + with using MTU/rate/PktLife explicitly ignoring selectors + + OpenSM just uses the resulting path MTU/rate/pkt-life and fail the + query even though the selector might be allowing for selecting an + appropriate value. + + After this fix, the following results are obtained for a case of + path allowing maximal 2K MTU. + +In standard mode: +------------------------------------------------------------ +MTU greater than ... 256 (0x01) -> equal to ....... 2K +MTU less than ...... 256 (0x41) -> NO PATHS +MTU equal to ....... 256 (0x81) -> equal to ....... 256 +MTU largest possible 256 (0xc1) -> equal to ....... 2K +MTU greater than ... 512 (0x02) -> equal to ....... 2K +MTU less than ...... 512 (0x42) -> equal to ....... 256 +MTU equal to ....... 512 (0x82) -> equal to ....... 512 +MTU largest possible 512 (0xc2) -> equal to ....... 2K +MTU greater than ... 1K (0x03) -> equal to ....... 2K +MTU less than ...... 1K (0x43) -> equal to ....... 512 +MTU equal to ....... 1K (0x83) -> equal to ....... 1K +MTU largest possible 1K (0xc3) -> equal to ....... 2K +MTU greater than ... 2K (0x04) -> NO PATHS +MTU less than ...... 2K (0x44) -> equal to ....... 1K +MTU equal to ....... 2K (0x84) -> equal to ....... 2K +MTU largest possible 2K (0xc4) -> equal to ....... 2K +MTU greater than ... 4K (0x05) -> NO PATHS +MTU less than ...... 4K (0x45) -> equal to ....... 2K +MTU equal to ....... 4K (0x85) -> NO PATHS +MTU largest possible 4K (0xc5) -> equal to ....... 2K +============================================================ + +With enable_quirks (when one of the ends is a Tavor device): +------------------------------------------------------------ +MTU greater than ... 256 (0x01) -> equal to ....... 1K +MTU less than ...... 256 (0x41) -> NO PATHS +MTU equal to ....... 256 (0x81) -> equal to ....... 256 +MTU largest possible 256 (0xc1) -> equal to ....... 2K +MTU greater than ... 512 (0x02) -> equal to ....... 1K +MTU less than ...... 512 (0x42) -> equal to ....... 256 +MTU equal to ....... 512 (0x82) -> equal to ....... 512 +MTU largest possible 512 (0xc2) -> equal to ....... 2K +MTU greater than ... 1K (0x03) -> NO PATHS +MTU less than ...... 1K (0x43) -> equal to ....... 512 +MTU equal to ....... 1K (0x83) -> equal to ....... 1K +MTU largest possible 1K (0xc3) -> equal to ....... 2K +MTU greater than ... 2K (0x04) -> NO PATHS +MTU less than ...... 2K (0x44) -> equal to ....... 1K +MTU equal to ....... 2K (0x84) -> equal to ....... 2K +MTU largest possible 2K (0xc4) -> equal to ....... 2K +MTU greater than ... 4K (0x05) -> NO PATHS +MTU less than ...... 4K (0x45) -> equal to ....... 1K +MTU equal to ....... 4K (0x85) -> NO PATHS +MTU largest possible 4K (0xc5) -> equal to ....... 2K +============================================================ + +* osm_pkey_rcv.c: rwlock double release fix + When the port is removed from subnet, but previously requested pkey + table block is received after this - the lock will be released twice. + This leads to deadlocks later when other MAD processor will try to + acquire the same lock. + +* osm_sa_informinfo.c: Fix InformInfoRecord searches + +* Better SA MCMemberRecord leave locking + Hold locked multicast group leave request (MCMember Record) processing. + This prevents kind of race with multicast group join request where + those requests can be reordered during processing. + +* osm_sa_informinfo.c: Conformance changes for subscribe component + +* osm_sa_path_record.c: Handle LID 0 as error + +* Fix comparing InformInfo records + 1. The received InformInfo struct was modified before dumping it. + 2. The function that compares InformInfo structures was just + comparing the whole memory allocated for it, including reserved + fields. Fixed to compare more selectively. + + As for QPN, from the IB spec, table 119 InformInfo: + QPN : Ignored except when subscribe=0 (an unsubscribe + request). Queue pair to which Report()s were sent as + a result of a corresponding subscription. If no + subscription for this Report() with this QPN exists, + the request to unsubscribe performs no action and + produces GetResp() with status indicating an invalid + field value. + +* osm_trap_rcv.c: Reduce repeated trap messages so log doesn't fill + so quickly + +* osm_helper.c: Fix stack smashing detected problem in osm_dump_service_record + +* Fix permission on db files directory + When creating directory for db files (guid2lid) storing create it with + reasonable permissions (current 777 decimal = octal 01411) and don't do + it world writable. + +* Fix node_desc.description as string usages + +5 Main Verification Flows +------------------------- + +OpenSM verification is run using the following activities: +* osmtest - a stand-alone program +* ibmgtsim (IB management simulator) based - a set of flows that + simulate clusters, inject errors and verify OpenSM capability to + respond and bring up the network correctly. +* small cluster regression testing - where the SM is used on back to + back or single switch configurations. The regression includes + multiple OpenSM dedicated tests. +* cluster testing - when we run OpenSM to setup a large cluster, perform + hand-off, reboots and reconnects, verify routing correctness and SA + responsiveness at the ULP level (IPoIB and SDP). + +5.1 osmtest + +osmtest is an automated verification tool used for OpenSM +testing. Its verification flows are described by list below. + +* Inventory File: Obtain and verify all port info, node info, link and path + records parameters. + +* Service Record: + - Register new service + - Register another service (with a lease period) + - Register another service (with service p_key set to zero) + - Get all services by name + - Delete the first service + - Delete the third service + - Added bad flows of get/delete non valid service + - Add / Get same service with different data + - Add / Get / Delete by different component mask values (services + by Name & Key / Name & Data / Name & Id / Id only ) + +* Multicast Member Record: + - Query of existing Groups (IPoIB) + - BAD Join with insufficient comp mask (o15.0.1.3) + - Create given MGID=0 (o15.0.1.4) + - Create given MGID=0xFF12A01C,FE800000,00000000,12345678 (o15.0.1.4) + - Create BAD MGID=0xFA. (o15.0.1.6) + - Create BAD MGID=0xFF12A01B w/ link-local not set (o15.0.1.6) + - New MGID with invalid join state (o15.0.1.9) + - Retry of existing MGID - See JoinState update (o15.0.1.11) + - BAD RATE when connecting to existing MGID (o15.0.1.13) + - Partial JoinState delete request - removing FullMember (o15.0.1.14) + - Full Delete of a group (o15.0.1.14) + - Verify Delete by trying to Join deleted group (o15.0.1.14) + - BAD Delete of IPoIB membership (no prev join) (o15.0.1.15) + +* GUIDInfo Record: + - All GUIDInfoRecords in subnet are obtained + +* MultiPathRecord: + - Perform some compliant and noncompliant MultiPathRecord requests + - Validation is via status in responses and IB analyzer + +* PKeyTableRecord: + - Perform some compliant and noncompliant PKeyTableRecord queries + - Validation is via status in responses and IB analyzer + +* LinearForwardingTableRecord: + - Perform some compliant and noncompliant LinearForwardingTableRecord queries + - Validation is via status in responses and IB analyzer + +* Event Forwarding: Register for trap forwarding using reports + - Send a trap and wait for report + - Unregister non-existing + +* Trap 64/65 Flow: Register to Trap 64-65, create traps (by + disconnecting/connecting ports) and wait for report, then unregister. + +* Stress Test: send PortInfoRecord queries, both single and RMPP and + check for the rate of responses as well as their validity. + + +5.2 IB Management Simulator OpenSM Test Flows: + +The simulator provides ability to simulate the SM handling of virtual +topologies that are not limited to actual lab equipment availability. +OpenSM was simulated to bring up clusters of up to 10,000 nodes. Daily +regressions use smaller (16 and 128 nodes clusters). + +The following test flows are run on the IB management simulator: + +* Stability: + Up to 12 links from the fabric are randomly selected to drop packets + at drop rates up to 90%. The SM is required to succeed in bringing the + fabric up. The resulting routing is verified to be correct as well. + +* LID Manager: + Using LMC = 2 the fabric is initialized with LIDs. Faults such as + zero LID, Duplicated LID, non-aligned (to LMC) LIDs are + randomly assigned to various nodes and other errors are randomly + output to the guid2lid cache file. The SM sweep is run 5 times and + after each iteration a complete verification is made to ensure that all + LIDs that could possibly be maintained are kept, as well as that all nodes + were assigned a legal LID range. + +* Multicast Routing: + Nodes randomly join the 0xc000 group and eventually the + resulting routing is verified for completeness and adherence to + Up/Down routing rules. + +* osmtest: + The complete osmtest flow as described in the previous table is run on + the simulated fabrics. + +* Stress Test: + This flow merges fabric, LID and stability issues with continuous + PathRecord, ServiceRecord and Multicast Join/Leave activity to + stress the SM/SA during continuous sweeps. InformInfo Set/Delete/Get + were added to the test such both existing and non existing nodes + perform them in random order. + +5.3 OpenSM Regression + +Using a back-to-back or single switch connection, the following set of +tests is run nightly on the stacks described in table 2. The included +tests are: + +* Stress Testing: Flood the SA with queries from multiple channel + adapters to check the robustness of the entire stack up to the SA. + +* Dynamic Changes: Dynamic Topology changes, through randomly + dropping SMP packets, used to test OpenSM adaptation to an unstable + network & verify DB correctness. + +* Trap Injection: This flow injects traps to the SM and verifies that it + handles them gracefully. + +* SA Query Test: This test exhaustively checks the SA responses to all + possible single component mask. To do that the test examines the + entire set of records the SA can provide, classifies them by their + field values and then selects every field (using component mask and a + value) and verifies that the response matches the expected set of records. + A random selection using multiple component mask bits is also performed. + +5.4 Cluster testing: + +Cluster testing is usually run before a distribution release. It +involves real hardware setups of 16 to 32 nodes (or more if a beta site +is available). Each test is validated by running all-to-all ping through the IB +interface. The test procedure includes: + +* Cluster bringup + +* Hand-off between 2 or 3 SM's while performing: + - Node reboots + - Switch power cycles (disconnecting the SM's) + +* Unresponsive port detection and recovery + +* osmtest from multiple nodes + +* Trap injection and recovery + + +6 Qualification +---------------- + +Table 2 - Qualified IB Stacks +============================= + +Stack | Version +-----------------------------------------|-------------------------- +OFED | 1.2 +OFED | 1.1 +OFED | 1.0 +OpenIB Gen2 (IBG2 distribution) | 1.0 +OpenIB Gen1 (IBGD distribution) | 1.8.0 +VAPI (Mellanox InfiniBand HCA Driver) | 3.2 and later + +Table 3 - Qualified Devices and Corresponding Firmware +====================================================== + +Mellanox +Device | FW versions +--------|----------------------------------------------------------- +MT43132 | InfiniScale - fw-43132 5.2.0 (and later) +MT47396 | InfiniScale III - fw-47396 0.5.0 (and later) +MT23108 | InfiniHost - fw-23108 3.3.2 (and later) +MT25204 | InfiniHost III Lx - fw-25204 1.0.1i (and later) +MT25208 | InfiniHost III Ex (InfiniHost Mode) - fw-25208 4.6.2 (and later) +MT25208 | InfiniHost III Ex (MemFree Mode) - fw-25218 5.0.1 (and later) + +QLogic/PathScale +Device | Note +--------|----------------------------------------------------------- +iPath | QHT6040 (PathScale InfiniPath HT-460) +iPath | QHT6140 (PathScale InfiniPath HT-465) +iPath | QLE6140 (PathScale InfiniPath PE-880) + +Note: OpenSM does not run on an IBM Galaxy (eHCA) as it does not expose +QP0 and QP1. However, it does support it as a device on the subnet. + diff --git a/contrib/ofed/management/opensm/doc/partition-config.txt b/contrib/ofed/management/opensm/doc/partition-config.txt new file mode 100644 index 000000000000..602cc664ccf6 --- /dev/null +++ b/contrib/ofed/management/opensm/doc/partition-config.txt @@ -0,0 +1,110 @@ +OpenSM Partition configuration +=============================== + +The default name of OpenSM partitions configuration file is +'/etc/opensm/partitions.conf'. The default may be changed by +using --Pconfig (-P) option with OpenSM. + +The default partition will be created by OpenSM unconditionally even +when partition configuration file does not exist or cannot be accessed. + +The default partition has P_Key value 0x7fff. OpenSM's port will have +full membership in default partition. All other end ports will have +partial membership. + + +File Format +=========== + +Comments: +-------- + +Line content followed after '#' character is comment and ignored by +parser. + + +General file format: +------------------- + +: ; + + +Partition Definition: +-------------------- + +[PartitionName][=PKey][,flag[=value]] + +PartitionName - string, to be used with logging. When omitted + empty string will be used. +PKey - P_Key value for this partition. Only low 15 bits will + be used. When omitted will be autogenerated. +flag - used to indicate IPoIB capability of this partition. + +Currently recognized flags are: + +ipoib - indicates that this partition may be used for IPoIB, as + result IPoIB capable MC group will be created. +rate= - specifies rate for this IPoIB MC group (default is 3 (10GBps)) +mtu= - specifies MTU for this IPoIB MC group (default is 4 (2048)) +sl= - specifies SL for this IPoIB MC group (default is 0) +scope= - specifies scope for this IPoIB MC group (default is 2 (link +local)) + +Note that values for 'rate', 'mtu'. and 'scope' should be specified as defined +in the IBTA specification (for example mtu=4 for 2048). + + +PortGUIDs list: +-------------- + +[PortGUID[=full|=limited]] [,PortGUID[=full|=limited]] [,PortGUID] ... + +PortGUID - GUID of partition member EndPort. Hexadecimal numbers + should start from 0x, decimal numbers are accepted too. +full or - indicates full or limited membership for this port. When + limited omitted (or unrecognized) limited membership is assumed. + +There are two useful keywords for PortGUID definition: + +- 'ALL' means all end ports in this subnet. +- 'SELF' means subnet manager's port. + +Empty list means no ports in this partition. + + +Notes: +----- + +White spaces are permitted between delimiters ('=', ',',':',';'). + +The Line can be wrapped after ':' followed after Partition Definition and +between. + +PartitionName does not need to be unique, PKey does need to be unique. +If PKey is repeated then those partition configurations will be merged +and first PartitionName will be used (see also next note). + +It is possible to split partition configuration in more than one +definition, but then PKey should be explicitly specified (otherwise +different PKey values will be generated for those definitions). + + +Examples: +-------- + +Default=0x7fff : ALL, SELF=full ; + +NewPartition , ipoib : 0x123456=full, 0x3456789034=limi, 0x2134af2306 ; + +YetAnotherOne = 0x300 : SELF=full ; +YetAnotherOne = 0x300 : ALL=limited ; + + +Note: +---- + +The following rule is equivalent to how OpenSM used to run prior to the +partition manager: + +Default=0x7fff,ipoib:ALL=full; + diff --git a/contrib/ofed/management/opensm/doc/perf-manager-arch.txt b/contrib/ofed/management/opensm/doc/perf-manager-arch.txt new file mode 100644 index 000000000000..f908ccf18a9e --- /dev/null +++ b/contrib/ofed/management/opensm/doc/perf-manager-arch.txt @@ -0,0 +1,181 @@ +Performance Manager +2/12/07 + +This document will describe an architecture and a phased plan +for an OpenFabrics OpenIB performance manager. + +Currently, there is no open source performance manager, only +a perfquery diagnostic tool which some have scripted into a +"poor man's" performance manager. + +The primary responsibilities of the performance manager are to: +1. Monitor subnet topology +2. Based on subnet topology, monitor performance and error counters. + Also, possible counters related to congestion. +3. Perform data reduction (various calculations (rates, histograms, etc.)) + on counters obtained +4. Log performance data and indicate "interesting" related events + + +Performance Manager Components +1. Determine subnet topology + Performance manager can determine the subnet topology by subscribing + for GID in and out of service events. Upon receipt of a GID in service + event, use GID to query SA for corresponding LID by using SubnAdmGet + NodeRecord with PortGUID specified. It would utilize the LID and NumPorts + returned and add this to the monitoring list. Note that the monitoring + list can be extended to be distributed with the manager "balancing" the + assignments of new GIDs to the set of known monitors. For GID out of + service events, the GID is removed from the monitoring list. + +2. Monitoring + Counters to be monitored include performance counters (data octets and + packets both receive and transmit) and error counters. These are all in + the mandatory PortCounters attribute. Future support will include the + optional 64 bit counters, PortExtendedCounters (as this is only known + to be supported on one IB device currently). Also, one congestion + counter (PortXmitWait) will also be monitored (on switch ports) initially. + + Polling rather than sampling will be used as the monitoring technique. The + polling rate configurable from 1-65535 seconds (default TBD) + Note that with 32 bit counters, on 4x SDR links, byte counts can max out in + 16 seconds and on 4x DDR links in 8 seconds. The polling rate needs to + deal with this is accurate byte and packet rates are desired. Since IB + counters are sticky, the counters need to be reset when they get "close" + to max'ing out. This will result in some inaccuracy. When counters are + reset, the time of the reset will be tracked in the monitor and will be + queryable. Note that when the 64 bit counters are supported more generally, + the polling rate can be reduced. + + The performance manager will support parallel queries. The level of + parallelism is configurable with a default of 64 queries outstanding + at one time. + + Configuration and dynamic adjustment of any performance manager "knobs" + will be supported. + + Also, there will be a console interface to obtain performance data. + It will be able to reset counters, report on specific nodes or + node types of interest (CAs only, switches only, all, ...). The + specifics are TBD. + +3. Data Reduction + For errors, rate rather than raw value will be calculated. Error + event is only indicated when rate exceeds a threshold. + For packet and byte counters, small changes will be aggregated + and only significant changes are updated. + Aggregated histograms (per node, all nodes (this is TBD))) for each + counter will be provided. Actual counters will also be written to files. + NodeGUID will be used to identify node. File formats are TBD. One + format to be supported might be CSV. + +4. Logging + "Interesting" events determined by the performance manager will be + logged as well as the performance data itself. Significant events + will be logged to syslog. There are some interesting scalability + issues relative to logging especially for the distributed model. + + Events will be based on rates which are configured as thresholds. + There will be configurable thresholds for the error counters with + reasonable defaults. Correlation of PerfManager and SM events is + interesting but not a mandatory requirement. + + +Performance Manager Scalability +Clearly as the polling rate goes up, the number of nodes which can be +monitored from a single performance management node decreases. There is +some evidence that a single dedicated management node may not be able to +monitor the largest clusters at a rapid rate. + +There are numerous PerfManager models which can be supported: +1. Integrated as thread(s) with OpenSM (run only when SM is master) +2. Standby SM +3. Standalone PerfManager (not running with master or standby SM) +4. Distributed PerfManager (most scalable approach) + +Note that these models are in order of implementation complexity and +hence "schedule". + +The simplest model is to run the PerfManager with the master SM. This has +the least scalability but is the simplest model. Note that in this model +the topology can be obtained without the GID in and out of service events +but this is needed for any of the other models to be supported. + +The next model is to run the PerfManager with a standby SM. Standbys are not +doing much currently (polling the master) so there is much idle CPU. +The downside of this approach is that if the standby takes over as master, +the PerfManager would need to be moved (or is becomes model 1). + +A totally separate standlone PerfManager would allow for a deployment +model which eliminates the downside of model 2 (standby SM). It could +still be built in a similar manner with model 2 with unneeded functions +(SM and SA) not included. The advantage of this model is that it could +be more readily usable with a vendor specific SM (switch based or otherwise). +Vendor specific SMs usually come with a built-in performance manager and +this assumes that there would be a way to disable that performance manager. +Model 2 can act like model 3 if a disable SM feature is supported in OpenSM +(command line/console). This will take the SM to not active. + +The most scalable model is a distributed PerfManager. One approach to +distribution is a hierarchial model where there is a PerfManager at the +top level with a number of PerfMonitors which are responsible for some +portion of the subnet. + +The separation of PerfManager from OpenSM brings up the following additional +issues: +1. What communication is needed between OpenSM and the PerfManager ? +2. Integration of interesting events with OpenSM log +(Does performance manager assume OpenSM ? Does it need to work with vendor +SMs ?) + +Hierarchial distribution brings up some additional issues: +1. How is the hierarchy determined ? +2. How do the PerfManager and PerfMonitors find each other ? +3. How is the subnet divided amongst the PerfMonitors +4. Communication amongst the PerfManager and the PerfMonitors +(including communication failures) + +In terms of inter manager communication, there seem to be several +choices: +1. Use vendor specific MADs (which can be RMPP'd) and build on top of +this +2. Use RC QP communication and build on top of this +3. Use IPoIB which is much more powerful as sockets can then be utilized + +RC QP communication improves on the lower performance of the vendor +specific MAD approach but is not as powerful as the socket based approach. + +The only downside of IPoIB is that it requires multicast to be functioning. +It seems reasonable to require IPoIB across the management nodes. This +can either be a separate IPoIB subnet or a shared one with other endnodes +on the subnet. (If this communication is built on top of sockets, it +can be any IP subnet amongst the manager nodes). + +The first implementation phase will address models 1-3. Model 3 is optional +as it is similar to models 1 and 2 and may be not be needed. + +Model 4 will be addressed in a subsequent implementation phase (and a future +version of this document). Model 4 can be built on the basis of models 1 and +2 where some SM, not necessarily master, is the PerfManager and the rest are +PerfMonitors. + + +Performance Manager Partition Membership +Note that as the performance manager needs to talk via GSI to the PMAs +in all the end nodes and GSI utilizes PKey sharing, partition membership +if invoked must account for this. + +The most straightforward deployment of the performance manager is +to have it be a member of the full default partition (P_Key 0xFFFF). + + +Performance Manager Redundancy +TBD (future version of this document) + + +Congestion Management +TBD (future version of this document) + + +QoS Management +TBD (future version of this document) diff --git a/contrib/ofed/management/opensm/doc/performance-manager-HOWTO.txt b/contrib/ofed/management/opensm/doc/performance-manager-HOWTO.txt new file mode 100644 index 000000000000..0b35e5fbd3f2 --- /dev/null +++ b/contrib/ofed/management/opensm/doc/performance-manager-HOWTO.txt @@ -0,0 +1,153 @@ +OpenSM Performance manager HOWTO +================================ + +Introduction +============ + +OpenSM now includes a performance manager which collects Port counters from +the subnet and stores them internally in OpenSM. + +Some of the features of the performance manager are: + + 1) Collect port data and error counters per v1.2 spec and store in + 64bit internal counts. + 2) Automatic reset of counters when they reach approximatly 3/4 full. + (While not guarenteeing that counts will not be missed this does + keep counts incrementing as best as possible given the current + hardware limitations.) + 3) Basic warnings in the OpenSM log on "critical" errors like symbol + errors. + 4) Automatically detects "outside" resets of counters and adjusts to + continue collecting data. + 5) Can be run when OpenSM is in standby or inactive states. + +Known issues are: + + 1) Data counters will be lost on high data rate links. Sweeping the + fabric fast enough for a DDR link is not practical. + 2) Default partition support only. + + +Setup and Usage +=============== + +Using the Performance Manager consists of 3 steps: + + 1) compiling in support for the perfmgr (Optionally: the console + socket as well) + 2) enabling the perfmgr and console in opensm.conf + 3) retrieving data which has been collected. + 3a) using console to "dump data" + 3b) using a plugin module to store the data to your own + "database" + +Step 1: Compile in support for the Performance Manager +------------------------------------------------------ + +Because of the performance manager's experimental status, it is not enabled at +compile time by default. (This will hopefully soon change as more people use +it and confirm that it does not break things... ;-) The configure option is +"--enable-perf-mgr". + +At this time it is really best to enable the console socket option as well. +OpenSM can be run in an "interactive" mode. But with the console socket option +turned on one can also make a connection to a running OpenSM. The console +option is "--enable-console-socket". This option requires the use of +tcp_wrappers to ensure security. Please be aware of your configuration for +tcp_wrappers as the commands presented in the console can affect the operation +of your subnet. + +The following configure line includes turning on the performance manager as +well as the console: + + ./configure --enable-perf-mgr --enable-console-socket + + +Step 2: Enable the perfmgr and console in opensm.conf +----------------------------------------------------- + +Turning the Perfmorance Manager on is pretty easy, set the following options in +the opensm.conf config file. (Default location is +/usr/local/etc/opensm/opensm.conf) + + # Turn it all on. + perfmgr TRUE + + # sweep time in seconds + perfmgr_sweep_time_s 180 + + # Dump file to dump the events to + event_db_dump_file /var/log/opensm_port_counters.log + +Also enable the console socket and configure the port for it to listen to if +desired. + + # console [off|local|socket] + console socket + + # Telnet port for console (default 10000) + console_port 10000 + +As noted above you also need to set up tcp_wrappers to prevent unauthorized +users from connecting to the console.[*] + + [*] As an alternate you can use the loopback mode but I noticed when + writing this (OpenSM v3.1.10; OFED 1.3) that there are some bugs in + specifying the loopback mode in the opensm.conf file. Look for this to + be fixed in newer versions. + + [**] Also you could use "local" but this is only useful if you run + OpenSM in the foreground of a terminal. As OpenSM is usually started + as a daemon I left this out as an option. + +Step 3: retrieve data which has been collected +---------------------------------------------- + +Step 3a: Using console dump function +------------------------------------ + +The console command "perfmgr dump_counters" will dump counters to the file +specified in the opensm.conf file. In the example above +"/var/log/opensm_port_counters.log" + +Example output is below: + + +"SW1 wopr ISR9024D (MLX4 FW)" 0x8f10400411f56 port 1 (Since Mon May 12 13:27:14 2008) + symbol_err_cnt : 0 + link_err_recover : 0 + link_downed : 0 + rcv_err : 0 + rcv_rem_phys_err : 0 + rcv_switch_relay_err : 2 + xmit_discards : 0 + xmit_constraint_err : 0 + rcv_constraint_err : 0 + link_integrity_err : 0 + buf_overrun_err : 0 + vl15_dropped : 0 + xmit_data : 470435 + rcv_data : 405956 + xmit_pkts : 8954 + rcv_pkts : 6900 + unicast_xmit_pkts : 0 + unicast_rcv_pkts : 0 + multicast_xmit_pkts : 0 + multicast_rcv_pkts : 0 + + + +Step 3b: Using a plugin module +------------------------------ + +If you want a more automated method of retrieving the data OpenSM provides a +plugin interface to extend OpenSM. The header file is osm_event_plugin.h. +The functions you register with this interface will be called when data is +collected. You can then use that data as appropriate. + +An example plugin can be configured at compile time using the +"--enable-default-event-plugin" option on the configure line. This plugin is +very simple. It logs "events" recieved from the performance manager to a log +file. I don't recomend using this directly but rather use it as a templat to +create your own plugin. + diff --git a/contrib/ofed/management/opensm/doc/qos-config.txt b/contrib/ofed/management/opensm/doc/qos-config.txt new file mode 100644 index 000000000000..ac7312fb919d --- /dev/null +++ b/contrib/ofed/management/opensm/doc/qos-config.txt @@ -0,0 +1,44 @@ +Trivial low level QoS configuration proposition +=============================================== + +Basically there is a set of QoS related low-level configuration parameters. +All these parameter names are prefixed by "qos_" string. Here is a full +list of these parameters: + + qos_max_vls - The maximum number of VLs that will be on the subnet + qos_high_limit - The limit of High Priority component of VL Arbitration + table (IBA 7.6.9) + qos_vlarb_low - Low priority VL Arbitration table (IBA 7.6.9) template + qos_vlarb_high - High priority VL Arbitration table (IBA 7.6.9) template + Both VL arbitration templates are pairs of VL and weight + qos_sl2vl - SL2VL Mapping table (IBA 7.6.6) template. It is a list + of VLs corresponding to SLs 0-15 (Note the VL15 used + here means drop this SL) + +Typical default values (hard-coded in OpenSM initialization) are: + + qos_max_vls 15 + qos_high_limit 0 + qos_vlarb_low 0:0,1:4,2:4,3:4,4:4,5:4,6:4,7:4,8:4,9:4,10:4,11:4,12:4,13:4,14:4 + qos_vlarb_high 0:4,1:0,2:0,3:0,4:0,5:0,6:0,7:0,8:0,9:0,10:0,11:0,12:0,13:0,14:0 + qos_sl2vl 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7 + +The syntax is compatible with rest of OpenSM configuration options and +values may be stored in OpenSM config file (cached options file). + +In addition to the above, we may define separate QoS configuration +parameters sets for various target types. As targets, we currently support +CAs, routers, switch external ports, and switch's enhanced port 0. The +names of such specialized parameters are prefixed by "qos__" +string. Here is a full list of the currently supported sets: + + qos_ca_ - QoS configuration parameters set for CAs. + qos_rtr_ - parameters set for routers. + qos_sw0_ - parameters set for switches' port 0. + qos_swe_ - parameters set for switches' external ports. + +Examples: + + qos_sw0_max_vls 2 + qos_ca_sl2vl 0,1,2,3,5,5,5,12,12,0, + qos_swe_high_limit 0 diff --git a/contrib/ofed/management/opensm/doc/todo b/contrib/ofed/management/opensm/doc/todo new file mode 100644 index 000000000000..bbb969897004 --- /dev/null +++ b/contrib/ofed/management/opensm/doc/todo @@ -0,0 +1,27 @@ +# OSM List of todo, open issues, and futures: + +1 041228 - Handle local events (local lid change, port state change, etc.) +2 041228 - SM port fail over to next port upon request ? +3 050912 - Handle busy status in SA client API/implementation +4 050912 - Handle o15-0.1.13 (SA ServiceRecord) as well as updates + to osmtest for this +5 051207 - Client reregistration is indicated before SA is + ready to accept subscriptions +6 060109 - Use LID routing for light sweep to guarantee trap + delivery path to the SM. +7 061201 - Finer grained locking ? +8 061201 - Mapping multiple MGIDs on single MLID when characteristics + match (PKey, etc.) +9 070329 - Add ssh support into remote socket/console support +10 070329 - Add authentication for (at least remote) console +11 070413 - Add dynamic rate adjustment for multicast groups + + +Futures + +LID partitioning ? +Advanced failover +Management +Regression tests and automation +Additional pathing algorithms + diff --git a/contrib/ofed/management/opensm/include/Makefile.am b/contrib/ofed/management/opensm/include/Makefile.am new file mode 100644 index 000000000000..1df1abc1af6f --- /dev/null +++ b/contrib/ofed/management/opensm/include/Makefile.am @@ -0,0 +1,33 @@ + +SUBDIRS = . + +nobase_pkginclude_HEADERS = iba/ib_types.h iba/ib_cm_types.h + +EXTRA_DIST = \ + $(srcdir)/iba/ib_types.h \ + $(srcdir)/iba/ib_cm_types.h \ + $(srcdir)/vendor/osm_vendor_mlx_transport_anafa.h \ + $(srcdir)/vendor/osm_vendor_mlx.h \ + $(srcdir)/vendor/osm_vendor_mlx_sender.h \ + $(srcdir)/vendor/osm_vendor_ibumad.h \ + $(srcdir)/vendor/osm_vendor_mlx_defs.h \ + $(srcdir)/vendor/osm_vendor_mtl_transaction_mgr.h \ + $(srcdir)/vendor/osm_vendor_mlx_sar.h \ + $(srcdir)/vendor/osm_vendor_mlx_dispatcher.h \ + $(srcdir)/vendor/osm_vendor_umadt.h \ + $(srcdir)/vendor/osm_vendor_mlx_svc.h \ + $(srcdir)/vendor/osm_vendor_mlx_hca.h \ + $(srcdir)/vendor/osm_vendor_mlx_rmpp_ctx.h \ + $(srcdir)/vendor/osm_vendor_mlx_transport.h \ + $(srcdir)/vendor/osm_vendor_mlx_inout.h \ + $(srcdir)/vendor/osm_vendor_mtl_hca_guid.h \ + $(srcdir)/vendor/osm_vendor_test.h \ + $(srcdir)/vendor/osm_vendor_ts.h \ + $(srcdir)/vendor/osm_vendor_mlx_txn.h \ + $(srcdir)/vendor/osm_vendor_al.h \ + $(srcdir)/vendor/osm_vendor_mtl.h \ + $(srcdir)/vendor/osm_ts_useraccess.h \ + $(srcdir)/vendor/osm_umadt.h \ + $(srcdir)/vendor/osm_mtl_bind.h + +pkgincludedir = $(includedir)/infiniband diff --git a/contrib/ofed/management/opensm/include/complib/cl_atomic.h b/contrib/ofed/management/opensm/include/complib/cl_atomic.h new file mode 100644 index 000000000000..92620eef6c60 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_atomic.h @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of atomic manipulation functions. + */ + +#ifndef _CL_ATOMIC_H_ +#define _CL_ATOMIC_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Atomic Operations +* NAME +* Atomic Operations +* +* DESCRIPTION +* The Atomic Operations functions allow callers to operate on +* 32-bit signed integers in an atomic fashion. +*********/ +/****f* Component Library: Atomic Operations/cl_atomic_inc +* NAME +* cl_atomic_inc +* +* DESCRIPTION +* The cl_atomic_inc function atomically increments a 32-bit signed +* integer and returns the incremented value. +* +* SYNOPSIS +*/ +int32_t cl_atomic_inc(IN atomic32_t * const p_value); +/* +* PARAMETERS +* p_value +* [in] Pointer to a 32-bit integer to increment. +* +* RETURN VALUE +* Returns the incremented value pointed to by p_value. +* +* NOTES +* The provided value is incremented and its value returned in one atomic +* operation. +* +* cl_atomic_inc maintains data consistency without requiring additional +* synchronization mechanisms in multi-threaded environments. +* +* SEE ALSO +* Atomic Operations, cl_atomic_dec, cl_atomic_add, cl_atomic_sub, +* cl_atomic_xchg, cl_atomic_comp_xchg +*********/ + +/****f* Component Library: Atomic Operations/cl_atomic_dec +* NAME +* cl_atomic_dec +* +* DESCRIPTION +* The cl_atomic_dec function atomically decrements a 32-bit signed +* integer and returns the decremented value. +* +* SYNOPSIS +*/ +int32_t cl_atomic_dec(IN atomic32_t * const p_value); +/* +* PARAMETERS +* p_value +* [in] Pointer to a 32-bit integer to decrement. +* +* RETURN VALUE +* Returns the decremented value pointed to by p_value. +* +* NOTES +* The provided value is decremented and its value returned in one atomic +* operation. +* +* cl_atomic_dec maintains data consistency without requiring additional +* synchronization mechanisms in multi-threaded environments. +* +* SEE ALSO +* Atomic Operations, cl_atomic_inc, cl_atomic_add, cl_atomic_sub, +* cl_atomic_xchg, cl_atomic_comp_xchg +*********/ + +/****f* Component Library: Atomic Operations/cl_atomic_add +* NAME +* cl_atomic_add +* +* DESCRIPTION +* The cl_atomic_add function atomically adds a value to a +* 32-bit signed integer and returns the resulting value. +* +* SYNOPSIS +*/ +int32_t +cl_atomic_add(IN atomic32_t * const p_value, IN const int32_t increment); +/* +* PARAMETERS +* p_value +* [in] Pointer to a 32-bit integer that will be added to. +* +* increment +* [in] Value by which to increment the integer pointed to by p_value. +* +* RETURN VALUE +* Returns the value pointed to by p_value after the addition. +* +* NOTES +* The provided increment is added to the value and the result returned in +* one atomic operation. +* +* cl_atomic_add maintains data consistency without requiring additional +* synchronization mechanisms in multi-threaded environments. +* +* SEE ALSO +* Atomic Operations, cl_atomic_inc, cl_atomic_dec, cl_atomic_sub, +* cl_atomic_xchg, cl_atomic_comp_xchg +*********/ + +/****f* Component Library: Atomic Operations/cl_atomic_sub +* NAME +* cl_atomic_sub +* +* DESCRIPTION +* The cl_atomic_sub function atomically subtracts a value from a +* 32-bit signed integer and returns the resulting value. +* +* SYNOPSIS +*/ +int32_t +cl_atomic_sub(IN atomic32_t * const p_value, IN const int32_t decrement); +/* +* PARAMETERS +* p_value +* [in] Pointer to a 32-bit integer that will be subtracted from. +* +* decrement +* [in] Value by which to decrement the integer pointed to by p_value. +* +* RETURN VALUE +* Returns the value pointed to by p_value after the subtraction. +* +* NOTES +* The provided decrement is subtracted from the value and the result +* returned in one atomic operation. +* +* cl_atomic_sub maintains data consistency without requiring additional +* synchronization mechanisms in multi-threaded environments. +* +* SEE ALSO +* Atomic Operations, cl_atomic_inc, cl_atomic_dec, cl_atomic_add, +* cl_atomic_xchg, cl_atomic_comp_xchg +*********/ + +END_C_DECLS +#endif /* _CL_ATOMIC_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_atomic_osd.h b/contrib/ofed/management/opensm/include/complib/cl_atomic_osd.h new file mode 100644 index 000000000000..ac14f8a19848 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_atomic_osd.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation specific header files for atomic operations. + */ + +#ifndef _CL_ATOMIC_OSD_H_ +#define _CL_ATOMIC_OSD_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS extern cl_spinlock_t cl_atomic_spinlock; + +static inline int32_t cl_atomic_inc(IN atomic32_t * const p_value) +{ + int32_t new_val; + + cl_spinlock_acquire(&cl_atomic_spinlock); + new_val = *p_value + 1; + *p_value = new_val; + cl_spinlock_release(&cl_atomic_spinlock); + return (new_val); +} + +static inline int32_t cl_atomic_dec(IN atomic32_t * const p_value) +{ + int32_t new_val; + + cl_spinlock_acquire(&cl_atomic_spinlock); + new_val = *p_value - 1; + *p_value = new_val; + cl_spinlock_release(&cl_atomic_spinlock); + return (new_val); +} + +static inline int32_t +cl_atomic_add(IN atomic32_t * const p_value, IN const int32_t increment) +{ + int32_t new_val; + + cl_spinlock_acquire(&cl_atomic_spinlock); + new_val = *p_value + increment; + *p_value = new_val; + cl_spinlock_release(&cl_atomic_spinlock); + return (new_val); +} + +static inline int32_t +cl_atomic_sub(IN atomic32_t * const p_value, IN const int32_t decrement) +{ + int32_t new_val; + + cl_spinlock_acquire(&cl_atomic_spinlock); + new_val = *p_value + decrement; + *p_value = new_val; + cl_spinlock_release(&cl_atomic_spinlock); + return (new_val); +} + +END_C_DECLS +#endif /* _CL_ATOMIC_OSD_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_byteswap.h b/contrib/ofed/management/opensm/include/complib/cl_byteswap.h new file mode 100644 index 000000000000..ca144e3a396e --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_byteswap.h @@ -0,0 +1,525 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * provides byteswapping utilities. Basic functions are obtained from + * platform specific implementations from byteswap_osd.h. + */ + +#ifndef _CL_BYTESWAP_H_ +#define _CL_BYTESWAP_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Byte Swapping +* NAME +* Byte Swapping +* +* DESCRIPTION +* The byte swapping functions and macros allow swapping bytes from network +* byte order to host byte order. +* +* All data transmitted between systems should be in network byte order. +* In order to utilize such data, it must be converted to host byte order +* before use. +* +* SEE ALSO +* Functions: +* cl_ntoh16, cl_hton16, cl_ntoh32, cl_hton32, cl_ntoh64, cl_hton64, +* cl_ntoh +* +* Macros: +* CL_NTOH16, CL_HTON16, CL_NTOH32, CL_HTON32, CL_NTOH64, CL_HTON64 +*********/ +/* + * The byteswap_osd.h provides the following macros. + * __LITTLE_ENDIAN + * __BIG_ENDIAN + * __BYTE_ORDER + * + * If the platform provides byte swapping functions, byteswap_osd.h also + * provides the following macros. + * ntoh16, hton16 + * ntoh32, hton32 + * ntoh64, hton64 + */ + +#ifndef __BYTE_ORDER +#error "__BYTE_ORDER macro undefined. Missing in endian.h?" +#endif +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define CPU_LE 1 +#define CPU_BE 0 +#else +#define CPU_LE 0 +#define CPU_BE 1 +#endif +/****d* Component Library: Byte Swapping/CL_NTOH16 +* NAME +* CL_NTOH16 +* +* DESCRIPTION +* The CL_NTOH16 macro converts a 16-bit value from network byte order to +* host byte order. The CL_NTOH16 macro will cause constant values to be +* swapped by the pre-processor. For variables, CL_NTOH16 is less efficient +* than the cl_ntoh16 function. +* +* SYNOPSIS +* CL_NTOH16( val ); +* +* PARAMETERS +* val +* [in] 16-bit value to swap from network byte order to host byte order. +* +* RESULT +* Value of val converted to host byte order. +* +* NOTES +* This macro is analogous to CL_HTON16. +* +* SEE ALSO +* Byte Swapping, CL_HTON16, CL_NTOH32, CL_NTOH64, +* cl_ntoh16, cl_ntoh32, cl_ntoh64, cl_ntoh +*********/ +/****d* Component Library: Byte Swapping/CL_HTON16 +* NAME +* CL_HTON16 +* +* DESCRIPTION +* The CL_HTON16 macro converts a 16-bit value from host byte order to +* network byte order. The CL_HTON16 macro will cause constant values to be +* swapped by the pre-processor. For variables, CL_HTON16 is less efficient +* than the cl_hton16 function. +* +* SYNOPSIS +* CL_HTON16( val ); +* +* PARAMETERS +* val +* [in] 16-bit value to swap from host byte order to network byte order. +* +* RESULT +* Value of val converted to network byte order. +* +* NOTES +* This macro is analogous to CL_NTOH16. +* +* SEE ALSO +* Byte Swapping, CL_NTOH16, CL_HTON32, CL_HTON64, +* cl_hton16, cl_hton32, cl_hton64, cl_ntoh +*********/ +#if CPU_LE +#define CL_NTOH16( x ) (uint16_t)( \ + (((uint16_t)(x) & 0x00FF) << 8) | \ + (((uint16_t)(x) & 0xFF00) >> 8) ) +#else +#define CL_NTOH16( x ) (x) +#endif +#define CL_HTON16 CL_NTOH16 +/****f* Component Library: Byte Swapping/cl_ntoh16 +* NAME +* cl_ntoh16 +* +* DESCRIPTION +* The cl_ntoh16 function converts a 16-bit value from network byte order to +* host byte order. +* +* SYNOPSIS +* uint16_t +* cl_ntoh16( +* IN const uint16_t val ); +* +* PARAMETERS +* val +* [in] Value to swap from network byte order to host byte order. +* +* RETURN VALUE +* Value of val converted to host byte order. +* +* NOTES +* This function is analogous to cl_hton16. +* +* SEE ALSO +* Byte Swapping, cl_hton16, cl_ntoh32, cl_ntoh64, cl_ntoh +*********/ +/****f* Component Library: Byte Swapping/cl_hton16 +* NAME +* cl_hton16 +* +* DESCRIPTION +* The cl_hton16 function converts a 16-bit value from host byte order to +* network byte order. +* +* SYNOPSIS +* uint16_t +* cl_hton16( +* IN const uint16_t val ); +* +* PARAMETERS +* val +* [in] Value to swap from host byte order to network byte order . +* +* RETURN VALUE +* Value of val converted to network byte order. +* +* NOTES +* This function is analogous to cl_ntoh16. +* +* SEE ALSO +* Byte Swapping, cl_ntoh16, cl_hton32, cl_hton64, cl_ntoh +*********/ +#ifndef cl_ntoh16 +#define cl_ntoh16 CL_NTOH16 +#define cl_hton16 CL_HTON16 +#endif +/****d* Component Library: Byte Swapping/CL_NTOH32 +* NAME +* CL_NTOH32 +* +* DESCRIPTION +* The CL_NTOH32 macro converts a 32-bit value from network byte order to +* host byte order. The CL_NTOH32 macro will cause constant values to be +* swapped by the pre-processor. For variables, CL_NTOH32 is less efficient +* than the cl_ntoh32 function. +* +* SYNOPSIS +* CL_NTOH32( val ); +* +* PARAMETERS +* val +* [in] 32-bit value to swap from network byte order to host byte order. +* +* RESULT +* Value of val converted to host byte order. +* +* NOTES +* This macro is analogous to CL_HTON32. +* +* SEE ALSO +* Byte Swapping, CL_HTON32, CL_NTOH16, CL_NTOH64, +* cl_ntoh16, cl_ntoh32, cl_ntoh64, cl_ntoh +*********/ +/****d* Component Library: Byte Swapping/CL_HTON32 +* NAME +* CL_HTON32 +* +* DESCRIPTION +* The CL_HTON32 macro converts a 32-bit value from host byte order to +* network byte order. The CL_HTON32 macro will cause constant values to be +* swapped by the pre-processor. For variables, CL_HTON32 is less efficient +* than the cl_hton32 function. +* +* SYNOPSIS +* CL_HTON32( val ); +* +* PARAMETERS +* val +* [in] 32-bit value to swap from host byte order to network byte order. +* +* RESULT +* Value of val converted to network byte order. +* +* NOTES +* This macro is analogous to CL_NTOH32. +* +* SEE ALSO +* Byte Swapping, CL_NTOH32, CL_HTON16, CL_HTON64, +* cl_hton16, cl_hton32, cl_hton64, cl_ntoh +*********/ +#if CPU_LE +#define CL_NTOH32( x ) (uint32_t)( \ + (((uint32_t)(x) & 0x000000FF) << 24) | \ + (((uint32_t)(x) & 0x0000FF00) << 8) | \ + (((uint32_t)(x) & 0x00FF0000) >> 8) | \ + (((uint32_t)(x) & 0xFF000000) >> 24) ) +#else +#define CL_NTOH32( x ) (x) +#endif +#define CL_HTON32 CL_NTOH32 +/****f* Component Library: Byte Swapping/cl_ntoh32 +* NAME +* cl_ntoh32 +* +* DESCRIPTION +* The cl_ntoh32 function converts a 32-bit value from network byte order to +* host byte order. +* +* SYNOPSIS +* uint32_t +* cl_ntoh32( +* IN const uint32_t val ); +* +* PARAMETERS +* val +* [in] Value to swap from network byte order to host byte order. +* +* RETURN VALUE +* Value of val converted in host byte order. +* +* NOTES +* This function is analogous to cl_hton32. +* +* SEE ALSO +* Byte Swapping, cl_hton32, cl_ntoh16, cl_ntoh64, cl_ntoh +*********/ +/****f* Component Library: Byte Swapping/cl_hton32 +* NAME +* cl_hton32 +* +* DESCRIPTION +* The cl_hton32 function converts a 32-bit value from host byte order to +* network byte order. +* +* SYNOPSIS +* uint32_t +* cl_hton32( +* IN const uint32_t val ); +* +* PARAMETERS +* val +* [in] Value to swap from host byte order to network byte order . +* +* RETURN VALUE +* Value of val converted to network byte order. +* +* NOTES +* This function is analogous to cl_ntoh32. +* +* SEE ALSO +* Byte Swapping, cl_ntoh32, cl_hton16, cl_hton64, cl_ntoh +*********/ +#ifndef cl_ntoh32 +#define cl_ntoh32 CL_NTOH32 +#define cl_hton32 CL_HTON32 +#endif +/****d* Component Library: Byte Swapping/CL_NTOH64 +* NAME +* CL_NTOH64 +* +* DESCRIPTION +* The CL_NTOH64 macro converts a 64-bit value from network byte order to +* host byte order. The CL_NTOH64 macro will cause constant values to be +* swapped by the pre-processor. For variables, CL_NTOH64 is less efficient +* than the cl_ntoh64 function. +* +* SYNOPSIS +* CL_NTOH64( val ); +* +* PARAMETERS +* val +* [in] 64-bit value to swap from network byte order to host byte order. +* +* RESULT +* Value of val converted to host byte order. +* +* NOTES +* This macro is analogous to CL_HTON64. +* +* SEE ALSO +* Byte Swapping, CL_HTON64, CL_NTOH16, CL_NTOH32, +* cl_ntoh16, cl_ntoh32, cl_ntoh64, cl_ntoh +*********/ +/****d* Component Library: Byte Swapping/CL_HTON64 +* NAME +* CL_HTON64 +* +* DESCRIPTION +* The CL_HTON64 macro converts a 64-bit value from host byte order to +* network byte order. The CL_HTON64 macro will cause constant values to be +* swapped by the pre-processor. For variables, CL_HTON64 is less efficient +* than the cl_hton64 function. +* +* SYNOPSIS +* CL_HTON64( val ); +* +* PARAMETERS +* val +* [in] 64-bit value to swap from host byte order to network byte order. +* +* RESULT +* Value of val converted to network byte order. +* +* NOTES +* This macro is analogous to CL_NTOH64. +* +* SEE ALSO +* Byte Swapping, CL_NTOH64, CL_HTON16, CL_HTON32, +* cl_hton16, cl_hton32, cl_hton64, cl_ntoh +*********/ +#if CPU_LE +#define CL_NTOH64( x ) (uint64_t)( \ + (((uint64_t)(x) & 0x00000000000000FFULL) << 56) | \ + (((uint64_t)(x) & 0x000000000000FF00ULL) << 40) | \ + (((uint64_t)(x) & 0x0000000000FF0000ULL) << 24) | \ + (((uint64_t)(x) & 0x00000000FF000000ULL) << 8 ) | \ + (((uint64_t)(x) & 0x000000FF00000000ULL) >> 8 ) | \ + (((uint64_t)(x) & 0x0000FF0000000000ULL) >> 24) | \ + (((uint64_t)(x) & 0x00FF000000000000ULL) >> 40) | \ + (((uint64_t)(x) & 0xFF00000000000000ULL) >> 56) ) +#else +#define CL_NTOH64( x ) (x) +#endif +#define CL_HTON64 CL_NTOH64 +/****f* Component Library: Byte Swapping/cl_ntoh64 +* NAME +* cl_ntoh64 +* +* DESCRIPTION +* The cl_ntoh64 function converts a 64-bit value from network byte order to +* host byte order. +* +* SYNOPSIS +* uint64_t +* cl_ntoh64( +* IN const uint64_t val ); +* +* PARAMETERS +* val +* [in] Value to swap from network byte order to host byte order. +* +* RETURN VALUE +* Value of val converted in host byte order. +* +* NOTES +* This function is analogous to cl_hton64. +* +* SEE ALSO +* Byte Swapping, cl_hton64, cl_ntoh16, cl_ntoh32, cl_ntoh +*********/ +/****f* Component Library: Byte Swapping/cl_hton64 +* NAME +* cl_hton64 +* +* DESCRIPTION +* The cl_hton64 function converts a 64-bit value from host byte order to +* network byte order. +* +* SYNOPSIS +* uint64_t +* cl_hton64( +* IN const uint64_t val ); +* +* PARAMETERS +* val +* [in] Value to swap from host byte order to network byte order . +* +* RETURN VALUE +* Value of val converted to network byte order. +* +* NOTES +* This function is analogous to cl_ntoh64. +* +* SEE ALSO +* Byte Swapping, cl_ntoh64, cl_hton16, cl_hton32, cl_ntoh +*********/ +#ifndef cl_ntoh64 +#define cl_ntoh64 CL_NTOH64 +#define cl_hton64 CL_HTON64 +#endif +/****f* Component Library: Byte Swapping/cl_ntoh +* NAME +* cl_ntoh +* +* DESCRIPTION +* The cl_ntoh function converts a value from network byte order to +* host byte order. +* +* SYNOPSIS +*/ +static inline void +cl_ntoh(OUT char *const p_dest, + IN const char *const p_src, IN const uint8_t size) +{ +#if CPU_LE + uint8_t i; + char temp; + + if (p_src == p_dest) { + /* Swap in place if source and destination are the same. */ + for (i = 0; i < size / 2; i++) { + temp = p_dest[i]; + p_dest[i] = p_src[size - 1 - i]; + p_dest[size - 1 - i] = temp; + } + } else { + for (i = 0; i < size; i++) + p_dest[i] = p_src[size - 1 - i]; + } +#else + /* + * If the source and destination are not the same, copy the source to + * the destination. + */ + if (p_src != p_dest) + memcpy(p_dest, p_src, size); +#endif +} + +/* +* PARAMETERS +* p_dest +* [in] Pointer to a byte array to contain the converted value of p_src. +* +* p_src +* [in] Pointer to a byte array to be converted from network byte +* ordering. +* +* size +* [in] Number of bytes to swap.p_dest +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_ntoh can perform in place swapping if both p_src and p_dest point to +* the same buffer. +* +* SEE ALSO +* Byte Swapping, cl_ntoh16, cl_ntoh32, cl_ntoh64 +*********/ + +END_C_DECLS +#endif /* _CL_BYTESWAP_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_byteswap_osd.h b/contrib/ofed/management/opensm/include/complib/cl_byteswap_osd.h new file mode 100644 index 000000000000..72ff40e5aeb6 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_byteswap_osd.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Provides common macros for dealing with byte swapping issues. + */ + +#ifndef _CL_BYTESWAP_OSD_H_ +#define _CL_BYTESWAP_OSD_H_ + +/* + * This provides defines __LITTLE_ENDIAN, __BIG_ENDIAN and __BYTE_ORDER + */ +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define cl_ntoh16(x) bswap_16(x) +#define cl_hton16(x) bswap_16(x) +#define cl_ntoh32(x) bswap_32(x) +#define cl_hton32(x) bswap_32(x) +#define cl_ntoh64(x) (uint64_t)bswap_64(x) +#define cl_hton64(x) (uint64_t)bswap_64(x) +#else /* Big Endian */ +#define cl_ntoh16(x) (x) +#define cl_hton16(x) (x) +#define cl_ntoh32(x) (x) +#define cl_hton32(x) (x) +#define cl_ntoh64(x) (x) +#define cl_hton64(x) (x) +#endif +END_C_DECLS +#endif /* _CL_BYTESWAP_OSD_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_comppool.h b/contrib/ofed/management/opensm/include/complib/cl_comppool.h new file mode 100644 index 000000000000..503ae181638b --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_comppool.h @@ -0,0 +1,585 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of the composite pool. + * The composite pool managers a pool of composite objects. A composite object is an object + * that is made of multiple sub objects. + * The pool can grow to meet demand, limited only by system memory. + */ + +#ifndef _CL_COMP_POOL_H_ +#define _CL_COMP_POOL_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Composite Pool +* NAME +* Composite Pool +* +* DESCRIPTION +* The Composite Pool provides a self-contained and self-sustaining pool of +* user defined composite objects. +* +* A composite object is an object that is composed of one or more +* sub-objects, each of which needs to be treated separately for +* initialization. Objects can be retrieved from the pool as long as there +* is memory in the system. +* +* To aid in object oriented design, the composite pool provides the user +* the ability to specify callbacks that are invoked for each object for +* construction, initialization, and destruction. Constructor and destructor +* callback functions may not fail. +* +* A composite pool does not return memory to the system as the user returns +* objects to the pool. The only method of returning memory to the system is +* to destroy the pool. +* +* The composite pool functions operates on a cl_cpool_t structure which +* should be treated as opaque and should be manipulated only through the +* provided functions. +* +* SEE ALSO +* Structures: +* cl_cpool_t +* +* Callbacks: +* cl_pfn_cpool_init_t, cl_pfn_cpool_dtor_t +* +* Initialization/Destruction: +* cl_cpool_construct, cl_cpool_init, cl_cpool_destroy +* +* Manipulation: +* cl_cpool_get, cl_cpool_put, cl_cpool_grow +* +* Attributes: +* cl_is_cpool_inited, cl_cpool_count +*********/ +/****d* Component Library: Composite Pool/cl_pfn_cpool_init_t +* NAME +* cl_pfn_cpool_init_t +* +* DESCRIPTION +* The cl_pfn_cpool_init_t function type defines the prototype for +* functions used as initializers for objects being allocated by a +* composite pool. +* +* SYNOPSIS +*/ +typedef cl_status_t + (*cl_pfn_cpool_init_t) (IN void **const p_comp_array, + IN const uint32_t num_components, IN void *context); +/* +* PARAMETERS +* p_object +* [in] Pointer to an object to initialize. +* +* context +* [in] Context provided in a call to cl_cpool_init. +* +* RETURN VALUES +* Return CL_SUCCESS to indicates that initialization of the object +* was successful and that initialization of further objects may continue. +* +* Other cl_status_t values will be returned by cl_cpool_init +* and cl_cpool_grow. +* +* NOTES +* This function type is provided as function prototype reference for +* the function provided by the user as an optional parameter to the +* cl_cpool_init function. +* +* The initializer is invoked once per allocated object, allowing the user +* to chain components to form a composite object and perform any necessary +* initialization. Returning a status other than CL_SUCCESS aborts a grow +* operation, initiated either through cl_cpool_init or cl_cpool_grow, and +* causes the initiating function to fail. Any non-CL_SUCCESS status will +* be returned by the function that initiated the grow operation. +* +* All memory for the requested number of components is pre-allocated. +* +* When later performing a cl_cpool_get call, the return value is a pointer +* to the first component. +* +* SEE ALSO +* Composite Pool, cl_cpool_init, cl_cpool_grow +*********/ + +/****d* Component Library: Composite Pool/cl_pfn_cpool_dtor_t +* NAME +* cl_pfn_cpool_dtor_t +* +* DESCRIPTION +* The cl_pfn_cpool_dtor_t function type defines the prototype for +* functions used as destructor for objects being deallocated by a +* composite pool. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_cpool_dtor_t) (IN void *const p_object, IN void *context); +/* +* PARAMETERS +* p_object +* [in] Pointer to an object to destruct. +* +* context +* [in] Context provided in the call to cl_cpool_init. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function type is provided as function prototype reference for +* the function provided by the user as an optional parameter to the +* cl_cpool_init function. +* +* The destructor is invoked once per allocated object, allowing the user +* to perform any necessary cleanup. Users should not attempt to deallocate +* the memory for the composite object, as the composite pool manages +* object allocation and deallocation. +* +* SEE ALSO +* Composite Pool, cl_cpool_init +*********/ + +/****s* Component Library: Composite Pool/cl_cpool_t +* NAME +* cl_cpool_t +* +* DESCRIPTION +* Composite pool structure. +* +* The cl_cpool_t structure should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_cpool { + cl_qcpool_t qcpool; + cl_pfn_cpool_init_t pfn_init; + cl_pfn_cpool_dtor_t pfn_dtor; + const void *context; +} cl_cpool_t; +/* +* FIELDS +* qcpool +* Quick composite pool that manages all objects. +* +* pfn_init +* Pointer to the user's initializer callback, used by the pool +* to translate the quick composite pool's initializer callback to +* a composite pool initializer callback. +* +* pfn_dtor +* Pointer to the user's destructor callback, used by the pool +* to translate the quick composite pool's destructor callback to +* a composite pool destructor callback. +* +* context +* User's provided context for callback functions, used by the pool +* to when invoking callbacks. +* +* SEE ALSO +* Composite Pool +*********/ + +/****f* Component Library: Composite Pool/cl_cpool_construct +* NAME +* cl_cpool_construct +* +* DESCRIPTION +* The cl_cpool_construct function constructs a composite pool. +* +* SYNOPSIS +*/ +void cl_cpool_construct(IN cl_cpool_t * const p_pool); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_cpool_t structure whose state to initialize. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_pool_init, cl_cpool_destroy, cl_is_cpool_inited. +* +* Calling cl_cpool_construct is a prerequisite to calling any other +* composite pool function except cl_cpool_init. +* +* SEE ALSO +* Composite Pool, cl_cpool_init, cl_cpool_destroy, cl_is_cpool_inited +*********/ + +/****f* Component Library: Composite Pool/cl_is_cpool_inited +* NAME +* cl_is_cpool_inited +* +* DESCRIPTION +* The cl_is_cpool_inited function returns whether a composite pool was +* successfully initialized. +* +* SYNOPSIS +*/ +static inline boolean_t cl_is_cpool_inited(IN const cl_cpool_t * const p_pool) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_pool); + return (cl_is_qcpool_inited(&p_pool->qcpool)); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_cpool_t structure whose initialization state +* to check. +* +* RETURN VALUES +* TRUE if the composite pool was initialized successfully. +* +* FALSE otherwise. +* +* NOTES +* Allows checking the state of a composite pool to determine if invoking +* member functions is appropriate. +* +* SEE ALSO +* Composite Pool +*********/ + +/****f* Component Library: Composite Pool/cl_cpool_init +* NAME +* cl_cpool_init +* +* DESCRIPTION +* The cl_cpool_init function initializes a composite pool for use. +* +* SYNOPSIS +*/ +cl_status_t +cl_cpool_init(IN cl_cpool_t * const p_pool, + IN const size_t min_size, + IN const size_t max_size, + IN const size_t grow_size, + IN size_t * const component_sizes, + IN const uint32_t num_components, + IN cl_pfn_cpool_init_t pfn_initializer OPTIONAL, + IN cl_pfn_cpool_dtor_t pfn_destructor OPTIONAL, + IN const void *const context); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_cpool_t structure to initialize. +* +* min_size +* [in] Minimum number of objects that the pool should support. All +* necessary allocations to allow storing the minimum number of items +* are performed at initialization time, and all necessary callbacks +* successfully invoked. +* +* max_size +* [in] Maximum number of objects to which the pool is allowed to grow. +* A value of zero specifies no maximum. +* +* grow_size +* [in] Number of objects to allocate when incrementally growing the pool. +* A value of zero disables automatic growth. +* +* component_sizes +* [in] Pointer to the first entry in an array of sizes describing, +* in order, the sizes of the components that make up a composite object. +* +* num_components +* [in] Number of components that make up a composite object. +* +* pfn_initializer +* [in] Initialization callback to invoke for every new object when +* growing the pool. This parameter may be NULL only if the objects +* stored in the composite pool consist of only one component. +* See the cl_pfn_cpool_init function type declaration for details +* about the callback function. +* +* pfn_destructor +* [in] Destructor callback to invoke for every object before memory for +* that object is freed. This parameter is optional and may be NULL. +* See the cl_pfn_cpool_dtor function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context. +* +* RETURN VALUES +* CL_SUCCESS if the composite pool was initialized successfully. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to initialize the +* composite pool. +* +* CL_INVALID_SETTING if a NULL constructor was provided for composite objects +* consisting of more than one component. Also returns CL_INVALID_SETTING if +* the maximum size is non-zero and less than the minimum size. +* +* Other cl_status_t value returned by optional initialization callback function +* specified by the pfn_initializer parameter. +* +* NOTES +* cl_cpool_init initializes, and if necessary, grows the pool to +* the capacity desired. +* +* SEE ALSO +* Composite Pool, cl_cpool_construct, cl_cpool_destroy, +* cl_cpool_get, cl_cpool_put, cl_cpool_grow, +* cl_cpool_count, cl_pfn_cpool_ctor_t, cl_pfn_cpool_init_t, +* cl_pfn_cpool_dtor_t +*********/ + +/****f* Component Library: Composite Pool/cl_cpool_destroy +* NAME +* cl_cpool_destroy +* +* DESCRIPTION +* The cl_cpool_destroy function destroys a composite pool. +* +* SYNOPSIS +*/ +static inline void cl_cpool_destroy(IN cl_cpool_t * const p_pool) +{ + CL_ASSERT(p_pool); + + cl_qcpool_destroy(&p_pool->qcpool); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_cpool_t structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* All memory allocated for composite objects is freed. The destructor +* callback, if any, will be invoked for every allocated object. Further +* operations on the composite pool should not be attempted after +* cl_cpool_destroy is invoked. +* +* This function should only be called after a call to cl_cpool_construct. +* +* In a debug build, cl_cpool_destroy asserts that all objects are in +* the pool. +* +* SEE ALSO +* Composite Pool, cl_cpool_construct, cl_cpool_init +*********/ + +/****f* Component Library: Composite Pool/cl_cpool_count +* NAME +* cl_cpool_count +* +* DESCRIPTION +* The cl_cpool_count function returns the number of available objects +* in a composite pool. +* +* SYNOPSIS +*/ +static inline size_t cl_cpool_count(IN cl_cpool_t * const p_pool) +{ + CL_ASSERT(p_pool); + return (cl_qcpool_count(&p_pool->qcpool)); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_cpool_t structure for which the number of +* available objects is requested. +* +* RETURN VALUE +* Returns the number of objects available in the specified +* composite pool. +* +* SEE ALSO +* Composite Pool +*********/ + +/****f* Component Library: Composite Pool/cl_cpool_get +* NAME +* cl_cpool_get +* +* DESCRIPTION +* The cl_cpool_get function retrieves an object from a +* composite pool. +* +* SYNOPSIS +*/ +static inline void *cl_cpool_get(IN cl_cpool_t * const p_pool) +{ + cl_pool_obj_t *p_pool_obj; + + CL_ASSERT(p_pool); + + p_pool_obj = (cl_pool_obj_t *) cl_qcpool_get(&p_pool->qcpool); + if (!p_pool_obj) + return (NULL); + + CL_ASSERT(p_pool_obj->p_object); + return ((void *)p_pool_obj->p_object); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_cpool_t structure from which to retrieve +* an object. +* +* RETURN VALUES +* Returns a pointer to the first component of a composite object. +* +* Returns NULL if the pool is empty and can not be grown automatically. +* +* NOTES +* cl_cpool_get returns the object at the head of the pool. If the pool is +* empty, it is automatically grown to accommodate this request unless the +* grow_size parameter passed to the cl_cpool_init function was zero. +* +* SEE ALSO +* Composite Pool, cl_cpool_get_tail, cl_cpool_put, cl_cpool_grow, +* cl_cpool_count +*********/ + +/****f* Component Library: Composite Pool/cl_cpool_put +* NAME +* cl_cpool_put +* +* DESCRIPTION +* The cl_cpool_put function returns an object to a composite pool. +* +* SYNOPSIS +*/ +static inline void +cl_cpool_put(IN cl_cpool_t * const p_pool, IN void *const p_object) +{ + cl_pool_obj_t *p_pool_obj; + + CL_ASSERT(p_pool); + CL_ASSERT(p_object); + + /* Calculate the offset to the list object representing this object. */ + p_pool_obj = (cl_pool_obj_t *) + (((uint8_t *) p_object) - sizeof(cl_pool_obj_t)); + + /* good sanity check */ + CL_ASSERT(p_pool_obj->p_object == p_object); + + cl_qcpool_put(&p_pool->qcpool, &p_pool_obj->pool_item); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_cpool_t structure to which to return +* an object. +* +* p_object +* [in] Pointer to the first component of an object to return to the pool. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_cpool_put places the returned object at the head of the pool. +* +* The object specified by the p_object parameter must have been +* retrieved from the pool by a previous call to cl_cpool_get. +* +* SEE ALSO +* Composite Pool, cl_cpool_put_tail, cl_cpool_get +*********/ + +/****f* Component Library: Composite Pool/cl_cpool_grow +* NAME +* cl_cpool_grow +* +* DESCRIPTION +* The cl_cpool_grow function grows a composite pool by +* the specified number of objects. +* +* SYNOPSIS +*/ +static inline cl_status_t +cl_cpool_grow(IN cl_cpool_t * const p_pool, IN const uint32_t obj_count) +{ + CL_ASSERT(p_pool); + return (cl_qcpool_grow(&p_pool->qcpool, obj_count)); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_cpool_t structure whose capacity to grow. +* +* obj_count +* [in] Number of objects by which to grow the pool. +* +* RETURN VALUES +* CL_SUCCESS if the composite pool grew successfully. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to grow the +* composite pool. +* +* cl_status_t value returned by optional initialization callback function +* specified by the pfn_initializer parameter passed to the +* cl_cpool_init function. +* +* NOTES +* It is not necessary to call cl_cpool_grow if the pool is +* configured to grow automatically. +* +* SEE ALSO +* Composite Pool +*********/ + +END_C_DECLS +#endif /* _CL_COMP_POOL_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_debug.h b/contrib/ofed/management/opensm/include/complib/cl_debug.h new file mode 100644 index 000000000000..05e9769b0865 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_debug.h @@ -0,0 +1,594 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of functions for reporting debug output. + */ + +#ifndef _CL_DEBUG_H_ +#define _CL_DEBUG_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Debug Output +* NAME +* Debug Output +* +* DESCRIPTION +* The debug output functions and macros send debug messages to the current +* debug target. +*********/ +/****f* Component Library: Debug Output/cl_break +* NAME +* cl_break +* +* DESCRIPTION +* The cl_break function halts execution. +* +* SYNOPSIS +* void +* cl_break(); +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* In a release build, cl_break has no effect. +*********/ +/****f* Component Library: Debug Output/cl_is_debug +* NAME +* cl_is_debug +* +* DESCRIPTION +* The cl_is_debug function returns TRUE if the complib was compiled +* in debug mode, and FALSE otherwise. +* +* SYNOPSIS +*/ +boolean_t cl_is_debug(void); +/* +* PARAMETERS +* None +* +* RETURN VALUE +* TRUE if compiled in debug version. FALSE otherwise. +* +* NOTES +* +*********/ + +#if defined( _DEBUG_ ) +#ifndef cl_dbg_out +/****f* Component Library: Debug Output/cl_dbg_out +* NAME +* cl_dbg_out +* +* DESCRIPTION +* The cl_dbg_out function sends a debug message to the debug target in +* debug builds only. +* +* SYNOPSIS +*/ +void cl_dbg_out(IN const char *const debug_message, IN ...); +/* +* PARAMETERS +* debug_message +* [in] ANSI string formatted identically as for a call to the standard C +* function printf. +* +* ... +* [in] Extra parameters for string formatting, as defined for the +* standard C function printf. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* In a release build, cl_dbg_out has no effect. +* +* The formatting of the debug_message string is the same as for printf +* +* cl_dbg_out sends the debug message to the current debug target. +* +* SEE ALSO +* Debug Output, cl_msg_out +*********/ +#endif +#else +static inline void cl_dbg_out(IN const char *const debug_message, IN ...) +{ + UNUSED_PARAM(debug_message); +} +#endif /* defined( _DEBUG_ ) */ + +#ifndef cl_msg_out +/****f* Component Library: Debug Output/cl_msg_out +* NAME +* cl_msg_out +* +* DESCRIPTION +* The cl_msg_out function sends a debug message to the message log target. +* +* SYNOPSIS +*/ +void cl_msg_out(IN const char *const message, IN ...); +/* +* PARAMETERS +* message +* [in] ANSI string formatted identically as for a call to the standard C +* function printf. +* +* ... +* [in] Extra parameters for string formatting, as defined for the +* standard C function printf. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_msg_out is available in both debug and release builds. +* +* The formatting of the message string is the same as for printf +* +* cl_msg_out sends the message to the current message logging target. +* +* SEE ALSO +* Debug Output, cl_dbg_out +*********/ +#endif + +/****d* Component Library: Debug Output/Debug Levels +* NAME +* Debug Levels +* +* DESCRIPTION +* The debug output macros reserve the upper bit of the debug level to +* convey an error. +* +* SYNOPSIS +*/ +#define CL_DBG_DISABLE 0 +#define CL_DBG_ERROR 0x80000000 +#define CL_DBG_ALL 0xFFFFFFFF +/* +* VALUES +* CL_DBG_DISABLE +* Disable all debug output, including errors. +* +* CL_DBG_ERROR +* Enable error debug output. +* +* CL_DBG_ALL +* Enbale all debug output. +* +* NOTES +* Users can define custom debug levels using the lower 31 bits of their +* debug level to control non-error debug output. Error messages are +* always displayed, regardless of the lower bit definition. +* +* When specifying the debug output desired for non-error messages +* (the CHK_LVL parameter in the debug output macros), users must define +* all bits whose output they are interested in. +* +* SEE ALSO +* Debug Output, CL_PRINT, CL_ENTER, CL_EXIT, CL_TRACE, CL_TRACE_EXIT +*********/ + +#if defined(_DEBUG_) + +/****d* Component Library: Debug Output/CL_PRINT +* NAME +* CL_PRINT +* +* DESCRIPTION +* The CL_PRINT macro sends a string to the current debug target if +* the requested debug level matches the current debug level. +* +* SYNOPSIS +* CL_PRINT( DBG_LVL, CHK_LVL, STRING ); +* +* PARAMETERS +* DBG_LVL +* [in] Debug level for the string to output +* +* CHK_LVL +* [in] Current debug level against which to check DBG_LVL +* +* STRING +* [in] String to send to the current debug target. The string includes +* parentheses in order to allow additional parameters. +* +* RETURN VALUE +* This macro does not return a value. +* +* EXAMPLE +* #define MY_FUNC_DBG_LVL 1 +* +* uint32_t my_dbg_lvl = CL_DBG_ALL; +* +* void +* my_func() +* { +* CL_PRINT( MY_FUNC_DBG_LVL, my_dbg_lvl, ("Hello %s!\n", "world") ); +* } +* +* RESULT +* Hello world! +* +* NOTES +* The requested string is printed only if all bits set in DBG_LVL are also +* set in CHK_LVL unless the most significant bit is set (indicating an +* error), in which case the lower bits are ignored. CHK_LVL may have +* additional bits set. +* +* In multi-processor environments where the current processor can be +* determined, the zero-based number of the processor on which the output +* is generated is prepended to the output. +* +* SEE ALSO +* Debug Output, Debug Levels, CL_ENTER, CL_EXIT, CL_TRACE, CL_TRACE_EXIT +*********/ +#define CL_PRINT( DBG_LVL, CHK_LVL, STRING ) \ + { \ + if( DBG_LVL & CL_DBG_ERROR ) \ + cl_dbg_out STRING; \ + else if( (DBG_LVL & CHK_LVL) == DBG_LVL ) \ + cl_dbg_out STRING; \ + } + +/****d* Component Library: Debug Output/CL_ENTER +* NAME +* CL_ENTER +* +* DESCRIPTION +* The CL_ENTER macro marks the entrance into a function by sending a +* string to the current debug target if the requested debug level matches +* the current debug level. +* +* SYNOPSIS +* CL_ENTER( DBG_LVL, CHK_LVL ); +* +* PARAMETERS +* DBG_LVL +* [in] Debug level for the string to output +* +* CHK_LVL +* [in] Current debug level against which to check DBG_LVL +* +* RETURN VALUE +* This macro does not return a value. +* +* EXAMPLE +* #define __MODULE__ "my_module" +* #define MY_FUNC_DBG_LVL 1 +* +* uint32_t my_dbg_lvl = CL_DBG_ALL; +* +* void +* my_func() +* { +* CL_ENTER( MY_FUNC_DBG_LVL, my_dbg_lvl ); +* CL_EXIT( MY_FUNC_DBG_LVL, my_dbg_lvl ); +* } +* +* RESULT +* my_module:my_func() [ +* my_module:my_func() ] +* +* NOTES +* The function entrance notification is printed only if all bits set +* in DBG_LVL are also set in CHK_LVL. CHK_LVL may have additional bits set. +* +* If the __MODULE__ preprocessor keyword is defined, that keyword will be +* prepended to the function name, separated with a colon. +* +* In multi-processor environments where the current processor can be +* determined, the zero-based number of the processor on which the output +* is generated is prepended to the output. +* +* SEE ALSO +* Debug Output, Debug Levels, CL_PRINT, CL_EXIT, CL_TRACE, CL_TRACE_EXIT +*********/ +#define CL_ENTER( DBG_LVL, CHK_LVL ) \ + CL_CHK_STK; \ + CL_PRINT( DBG_LVL, CHK_LVL, _CL_DBG_ENTER ); + +/****d* Component Library: Debug Output/CL_EXIT +* NAME +* CL_EXIT +* +* DESCRIPTION +* The CL_EXIT macro marks the exit from a function by sending a string +* to the current debug target if the requested debug level matches the +* current debug level. +* +* SYNOPSIS +* CL_EXIT( DBG_LVL, CHK_LVL ); +* +* PARAMETERS +* DBG_LVL +* [in] Debug level for the string to output +* +* CHK_LVL +* [in] Current debug level against which to check DBG_LVL +* +* RETURN VALUE +* This macro does not return a value. +* +* EXAMPLE +* #define __MODULE__ "my_module" +* #define MY_FUNC_DBG_LVL 1 +* +* uint32_t my_dbg_lvl = CL_DBG_ALL; +* +* void +* my_func() +* { +* CL_ENTER( MY_FUNC_DBG_LVL, my_dbg_lvl ); +* CL_EXIT( MY_FUNC_DBG_LVL, my_dbg_lvl ); +* } +* +* RESULT +* my_module:my_func() [ +* my_module:my_func() ] +* +* NOTES +* The exit notification is printed only if all bits set in DBG_LVL are also +* set in CHK_LVL. CHK_LVL may have additional bits set. +* +* The CL_EXIT macro must only be used after the CL_ENTRY macro as it +* depends on that macro's implementation. +* +* If the __MODULE__ preprocessor keyword is defined, that keyword will be +* prepended to the function name, separated with a colon. +* +* In multi-processor environments where the current processor can be +* determined, the zero-based number of the processor on which the output +* is generated is prepended to the output. +* +* SEE ALSO +* Debug Output, Debug Levels, CL_PRINT, CL_ENTER, CL_TRACE, CL_TRACE_EXIT +*********/ +#define CL_EXIT( DBG_LVL, CHK_LVL ) \ + CL_PRINT( DBG_LVL, CHK_LVL, _CL_DBG_EXIT ); + +/****d* Component Library: Debug Output/CL_TRACE +* NAME +* CL_TRACE +* +* DESCRIPTION +* The CL_TRACE macro sends a string to the current debug target if +* the requested debug level matches the current debug level. The +* output is prepended with the function name and, depending on the +* debug level requested, an indication of the severity of the message. +* +* SYNOPSIS +* CL_TRACE( DBG_LVL, CHK_LVL, STRING ); +* +* PARAMETERS +* DBG_LVL +* [in] Debug level for the string to output +* +* CHK_LVL +* [in] Current debug level against which to check DBG_LVL +* +* STRING +* [in] String to send to the current debug target. The string includes +* parentheses in order to allow additional parameters. +* +* RETURN VALUE +* This macro does not return a value. +* +* EXAMPLE +* #define __MODULE__ "my_module" +* #define MY_FUNC_DBG_LVL 1 +* +* uint32_t my_dbg_lvl = CL_DBG_ALL; +* +* void +* my_func() +* { +* CL_ENTER( MY_FUNC_DBG_LVL, my_dbg_lvl ); +* CL_TRACE( MY_FUNC_DBG_LVL, my_dbg_lvl, ("Hello %s!\n", "world") ); +* CL_EXIT( MY_FUNC_DBG_LVL, my_dbg_lvl ); +* } +* +* RESULT +* my_module:my_func() [ +* my_module:my_func(): Hello world! +* my_module:my_func() ] +* +* NOTES +* The requested string is printed only if all bits set in DBG_LVL are also +* set in CHK_LVL. CHK_LVL may have additional bits set. +* +* The CL_TRACE macro must only be used after the CL_ENTRY macro as it +* depends on that macro's implementation. +* +* If the DBG_LVL has the upper bit set, the output will contain +* an "!ERROR!" statement between the function name and STRING. +* +* If the __MODULE__ preprocessor keyword is defined, that keyword will be +* prepended to the function name, separated with a colon. +* +* In multi-processor environments where the current processor can be +* determined, the zero-based number of the processor on which the output +* is generated is prepended to the output. +* +* SEE ALSO +* Debug Output, Debug Levels, CL_PRINT, CL_ENTER, CL_EXIT, CL_TRACE_EXIT +*********/ +#define CL_TRACE( DBG_LVL, CHK_LVL, STRING ) \ +{ \ +switch( DBG_LVL & CL_DBG_ERROR ) \ +{ \ + case CL_DBG_ERROR: \ + CL_PRINT( DBG_LVL, CHK_LVL, _CL_DBG_ERROR ); \ + break; \ + default: \ + CL_PRINT( DBG_LVL, CHK_LVL, _CL_DBG_INFO ); \ + break; \ +} \ +CL_PRINT( DBG_LVL, CHK_LVL, STRING ); \ +} + +/****d* Component Library: Debug Output/CL_TRACE_EXIT +* NAME +* CL_TRACE_EXIT +* +* DESCRIPTION +* The CL_TRACE_EXIT macro combines the functionality of the CL_TRACE and +* CL_EXIT macros, in that order. +* +* SYNOPSIS +* CL_TRACE_EXIT( DBG_LVL, CHK_LVL, STRING ); +* +* PARAMETERS +* DBG_LVL +* [in] Debug level for the string to output +* +* CHK_LVL +* [in] Current debug level against which to check DBG_LVL +* +* STRING +* [in] String to send to the current debug target. The string includes +* parentheses in order to allow additional parameters. +* +* RETURN VALUE +* This macro does not return a value. +* +* EXAMPLE +* #define __MODULE__ "my_module" +* #define MY_FUNC_DBG_LVL 1 +* +* uint32_t my_dbg_lvl = CL_DBG_ALL; +* +* void +* my_func() +* { +* CL_ENTER( MY_FUNC_DBG_LVL, my_dbg_lvl ); +* CL_TRACE_EXIT( MY_FUNC_DBG_LVL, my_dbg_lvl, ("Hello %s!\n", "world") ); +* } +* +* RESULT +* my_module:my_func() [ +* my_module:my_func(): Hello world! +* my_module:my_func() ] +* +* NOTES +* The requested string is printed only if all bits set in DBG_LVL are also +* set in CHK_LVL. CHK_LVL may have additional bits set. +* +* The CL_TRACE_EXIT macro must only be used after the CL_ENTRY macro as it +* depends on that macro's implementation. +* +* If the DBG_LVL has the upper bit set, the output will contain +* an "!ERROR!" statement between the function name and STRING. +* +* If the __MODULE__ preprocessor keyword is defined, that keyword will be +* prepended to the function name, separated with a colon. +* +* In multi-processor environments where the current processor can be +* determined, the zero-based number of the processor on which the output +* is generated is prepended to the output. +* +* SEE ALSO +* Debug Output, Debug Levels, CL_PRINT, CL_ENTER, CL_EXIT, CL_TRACE +*********/ +#define CL_TRACE_EXIT( DBG_LVL, CHK_LVL, STRING ) \ + CL_TRACE( DBG_LVL, CHK_LVL, STRING ); \ + CL_EXIT( DBG_LVL, CHK_LVL ); + +#else /* defined(_DEBUG_) */ + +/* Define as NULL macros in a free build. */ +#define CL_PRINT( DBG_LVL, CHK_LVL, STRING ); +#define CL_ENTER( DBG_LVL, CHK_LVL ); +#define CL_EXIT( DBG_LVL, CHK_LVL ); +#define CL_TRACE( DBG_LVL, CHK_LVL, STRING ); +#define CL_TRACE_EXIT( DBG_LVL, CHK_LVL, STRING ); + +#endif /* defined(_DEBUG_) */ + +/****d* Component Library: Debug Output/64-bit Print Format +* NAME +* 64-bit Print Format +* +* DESCRIPTION +* The 64-bit print keywords allow users to use 64-bit values in debug or +* console output. +* +* Different platforms define 64-bit print formats differently. The 64-bit +* print formats exposed by the component library are supported in all +* platforms. +* +* VALUES +* PRId64 +* Print a 64-bit integer in signed decimal format. +* PRIx64 +* Print a 64-bit integer in hexadecimal format. +* PRIo64 +* Print a 64-bit integer in octal format. +* PRIu64 +* Print a 64-bit integer in unsigned decimal format. +* +* EXAMPLE +* uint64 MyVal = 2; +* // Print a 64-bit integer in hexadecimal format. +* cl_dbg_out( "MyVal: 0x%" PRIx64 "\n", MyVal ); +* +* NOTES +* Standard print flags to specify padding and precision can still be used +* following the '%' sign in the string preceding the 64-bit print keyword. +* +* The above keywords are strings and make use of compilers' string +* concatenation ability. +*********/ +void complib_init(void); + +void complib_exit(void); + +END_C_DECLS +#endif /* _CL_DEBUG_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_debug_osd.h b/contrib/ofed/management/opensm/include/complib/cl_debug_osd.h new file mode 100644 index 000000000000..b61891b310ed --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_debug_osd.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Debug Macros. + */ + +#ifndef _CL_DEBUG_OSD_H_ +#define _CL_DEBUG_OSD_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#if !defined(__MODULE__) +#define __MODULE__ "" +#define __MOD_DELIMITER__ "" +#else /* !defined(__MODULE__) */ +#define __MOD_DELIMITER__ ":" +#endif /* !defined(__MODULE__) */ +/* + * Define specifiers for print functions based on the platform + */ +#ifdef __IA64__ +#define PRIdSIZE_T "ld" +#else +#define PRIdSIZE_T "d" +#endif +#include +#include +#define cl_msg_out printf +#if defined( _DEBUG_ ) +#define cl_dbg_out printf +#else +#define cl_dbg_out foo +#endif /* _DEBUG_ */ +/* + * The following macros are used internally by the CL_ENTER, CL_TRACE, + * CL_TRACE_EXIT, and CL_EXIT macros. + */ +#define _CL_DBG_ENTER \ + ("%s%s%s() [\n", __MODULE__, __MOD_DELIMITER__, __func__) +#define _CL_DBG_EXIT \ + ("%s%s%s() ]\n", __MODULE__, __MOD_DELIMITER__, __func__) +#define _CL_DBG_INFO \ + ("%s%s%s(): ", __MODULE__, __MOD_DELIMITER__, __func__) +#define _CL_DBG_ERROR \ + ("%s%s%s() !ERROR!: ", __MODULE__, __MOD_DELIMITER__, __func__) +#define CL_CHK_STK +END_C_DECLS +#endif /* _CL_DEBUG_OSD_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_dispatcher.h b/contrib/ofed/management/opensm/include/complib/cl_dispatcher.h new file mode 100644 index 000000000000..a5b4a2893048 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_dispatcher.h @@ -0,0 +1,631 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of dispatcher abstraction. + */ + +#ifndef _CL_DISPATCHER_H_ +#define _CL_DISPATCHER_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Dispatcher +* NAME +* Dispatcher +* +* DESCRIPTION +* The Dispatcher provides a facility for message routing to +* asynchronous worker threads. +* +* The Dispatcher functions operate on a cl_dispatcher_t structure +* which should be treated as opaque and should be manipulated +* only through the provided functions. +* +* SEE ALSO +* Structures: +* cl_dispatcher_t +* +* Initialization/Destruction: +* cl_disp_construct, cl_disp_init, cl_disp_shutdown, cl_disp_destroy +* +* Manipulation: +* cl_disp_post, cl_disp_reset, cl_disp_wait_on +*********/ +/****s* Component Library: Dispatcher/cl_disp_msgid_t +* NAME +* cl_disp_msgid_t +* +* DESCRIPTION +* Defines the type of dispatcher messages. +* +* SYNOPSIS +*/ +typedef uint32_t cl_disp_msgid_t; +/**********/ + +/****s* Component Library: Dispatcher/CL_DISP_MSGID_NONE +* NAME +* CL_DISP_MSGID_NONE +* +* DESCRIPTION +* Defines a message value that means "no message". +* This value is used during registration by Dispatcher clients +* that do not wish to receive messages. +* +* No Dispatcher message is allowed to have this value. +* +* SYNOPSIS +*/ +#define CL_DISP_MSGID_NONE 0xFFFFFFFF +/**********/ + +/****s* Component Library: Dispatcher/CL_DISP_INVALID_HANDLE +* NAME +* CL_DISP_INVALID_HANDLE +* +* DESCRIPTION +* Defines the value of an invalid Dispatcher registration handle. +* +* SYNOPSIS +*/ +#define CL_DISP_INVALID_HANDLE ((cl_disp_reg_handle_t)0) +/*********/ + +/****f* Component Library: Dispatcher/cl_pfn_msgrcv_cb_t +* NAME +* cl_pfn_msgrcv_cb_t +* +* DESCRIPTION +* This typedef defines the prototype for client functions invoked +* by the Dispatcher. The Dispatcher calls the corresponding +* client function when delivering a message to the client. +* +* The client function must be reentrant if the user creates a +* Dispatcher with more than one worker thread. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_msgrcv_cb_t) (IN void *context, IN void *p_data); +/* +* PARAMETERS +* context +* [in] Client specific context specified in a call to +* cl_disp_register +* +* p_data +* [in] Pointer to the client specific data payload +* of this message. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This typedef provides a function prototype reference for +* the function provided by Dispatcher clients as a parameter +* to the cl_disp_register function. +* +* SEE ALSO +* Dispatcher, cl_disp_register +*********/ + +/****f* Component Library: Dispatcher/cl_pfn_msgdone_cb_t +* NAME +* cl_pfn_msgdone_cb_t +* +* DESCRIPTION +* This typedef defines the prototype for client functions invoked +* by the Dispatcher. The Dispatcher calls the corresponding +* client function after completing delivery of a message. +* +* The client function must be reentrant if the user creates a +* Dispatcher with more than one worker thread. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_msgdone_cb_t) (IN void *context, IN void *p_data); +/* +* PARAMETERS +* context +* [in] Client specific context specified in a call to +* cl_disp_post +* +* p_data +* [in] Pointer to the client specific data payload +* of this message. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This typedef provides a function prototype reference for +* the function provided by Dispatcher clients as a parameter +* to the cl_disp_post function. +* +* SEE ALSO +* Dispatcher, cl_disp_post +*********/ + +/****s* Component Library: Dispatcher/cl_dispatcher_t +* NAME +* cl_dispatcher_t +* +* DESCRIPTION +* Dispatcher structure. +* +* The Dispatcher is thread safe. +* +* The cl_dispatcher_t structure should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_dispatcher { + cl_spinlock_t lock; + cl_ptr_vector_t reg_vec; + cl_qlist_t reg_list; + cl_thread_pool_t worker_threads; + cl_qlist_t msg_fifo; + cl_qpool_t msg_pool; + uint64_t last_msg_queue_time_us; +} cl_dispatcher_t; +/* +* FIELDS +* reg_vec +* Vector of registration info objects. Indexed by message msg_id. +* +* lock +* Spinlock to guard internal structures. +* +* msg_fifo +* FIFO of messages being processed by the Dispatcher. New +* messages are posted to the tail of the FIFO. Worker threads +* pull messages from the front. +* +* worker_threads +* Thread pool of worker threads to dispose of posted messages. +* +* msg_pool +* Pool of message objects to be processed through the FIFO. +* +* reg_count +* Count of the number of registrants. +* +* state +* Indicates the state of the object. +* +* last_msg_queue_time_us +* The time that the last message spent in the Q in usec +* +* SEE ALSO +* Dispatcher +*********/ + +/****s* Component Library: Dispatcher/cl_disp_reg_info_t +* NAME +* cl_disp_reg_info_t +* +* DESCRIPTION +* Defines the dispatcher registration object structure. +* +* The cl_disp_reg_info_t structure is for internal use by the +* Dispatcher only. +* +* SYNOPSIS +*/ +typedef struct _cl_disp_reg_info { + cl_list_item_t list_item; + cl_pfn_msgrcv_cb_t pfn_rcv_callback; + const void *context; + atomic32_t ref_cnt; + cl_disp_msgid_t msg_id; + cl_dispatcher_t *p_disp; +} cl_disp_reg_info_t; +/* +* FIELDS +* pfn_rcv_callback +* Client's message receive callback. +* +* context +* Client's context for message receive callback. +* +* rcv_thread_count +* Number of threads currently in the receive callback. +* +* msg_done_thread_count +* Number of threads currently in the message done callback. +* +* state +* State of this registration object. +* DISP_REGSTATE_INIT: initialized and inactive +* DISP_REGSTATE_ACTIVE: in active use +* DISP_REGSTATE_UNREGPEND: unregistration is pending +* +* msg_id +* Dispatcher message msg_id value for this registration object. +* +* p_disp +* Pointer to parent Dispatcher. +* +* SEE ALSO +*********/ + +/****s* Component Library: Dispatcher/cl_disp_msg_t +* NAME +* cl_disp_msg_t +* +* DESCRIPTION +* Defines the dispatcher message structure. +* +* The cl_disp_msg_t structure is for internal use by the +* Dispatcher only. +* +* SYNOPSIS +*/ +typedef struct _cl_disp_msg { + cl_pool_item_t item; + const void *p_data; + cl_disp_reg_info_t *p_src_reg; + cl_disp_reg_info_t *p_dest_reg; + cl_pfn_msgdone_cb_t pfn_xmt_callback; + uint64_t in_time; + const void *context; +} cl_disp_msg_t; +/* +* FIELDS +* item +* List & Pool linkage. Must be first element in the structure!! +* +* msg_id +* The message's numberic ID value. +* +* p_data +* Pointer to the data payload for this message. The payload +* is opaque to the Dispatcher. +* +* p_reg_info +* Pointer to the registration info of the sender. +* +* pfn_xmt_callback +* Client's message done callback. +* +* in_time +* The absolute time the message was inserted into the queue +* +* context +* Client's message done callback context. +* +* SEE ALSO +*********/ + +/****s* Component Library: Dispatcher/cl_disp_reg_info_t +* NAME +* cl_disp_reg_info_t +* +* DESCRIPTION +* Defines the Dispatcher registration handle. This handle +* should be treated as opaque by the client. +* +* SYNOPSIS +*/ +typedef const struct _cl_disp_reg_info *cl_disp_reg_handle_t; +/**********/ + +/****f* Component Library: Dispatcher/cl_disp_construct +* NAME +* cl_disp_construct +* +* DESCRIPTION +* This function constructs a Dispatcher object. +* +* SYNOPSIS +*/ +void cl_disp_construct(IN cl_dispatcher_t * const p_disp); +/* +* PARAMETERS +* p_disp +* [in] Pointer to a Dispatcher. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_disp_init and cl_disp_destroy. +* +* SEE ALSO +* Dispatcher, cl_disp_init, cl_disp_destroy +*********/ + +/****f* Component Library: Dispatcher/cl_disp_init +* NAME +* cl_disp_init +* +* DESCRIPTION +* This function initializes a Dispatcher object. +* +* SYNOPSIS +*/ +cl_status_t +cl_disp_init(IN cl_dispatcher_t * const p_disp, + IN const uint32_t thread_count, IN const char *const name); +/* +* PARAMETERS +* p_disp +* [in] Pointer to a Dispatcher. +* +* thread_count +* [in] The number of worker threads to create in this Dispatcher. +* A value of 0 causes the Dispatcher to create one worker thread +* per CPU in the system. When the Dispatcher is created with +* only one thread, the Dispatcher guarantees to deliver posted +* messages in order. When the Dispatcher is created with more +* than one thread, messages may be delivered out of order. +* +* name +* [in] Name to associate with the threads. The name may be up to 16 +* characters, including a terminating null character. All threads +* created in the Dispatcher have the same name. +* +* RETURN VALUE +* CL_SUCCESS if the operation is successful. +* +* SEE ALSO +* Dispatcher, cl_disp_destoy, cl_disp_register, cl_disp_unregister, +* cl_disp_post +*********/ + +/****f* Component Library: Dispatcher/cl_disp_shutdown +* NAME +* cl_disp_shutdown +* +* DESCRIPTION +* This function shutdown a Dispatcher object. So it unreg all messages and +* clears the fifo and waits for the threads to exit +* +* SYNOPSIS +*/ +void cl_disp_shutdown(IN cl_dispatcher_t * const p_disp); +/* +* PARAMETERS +* p_disp +* [in] Pointer to a Dispatcher. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function does not returns until all worker threads +* have exited client callback functions and been successfully +* shutdowned. +* +* SEE ALSO +* Dispatcher, cl_disp_construct, cl_disp_init +*********/ + +/****f* Component Library: Dispatcher/cl_disp_destroy +* NAME +* cl_disp_destroy +* +* DESCRIPTION +* This function destroys a Dispatcher object. +* +* SYNOPSIS +*/ +void cl_disp_destroy(IN cl_dispatcher_t * const p_disp); +/* +* PARAMETERS +* p_disp +* [in] Pointer to a Dispatcher. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Dispatcher, cl_disp_construct, cl_disp_init +*********/ + +/****f* Component Library: Dispatcher/cl_disp_register +* NAME +* cl_disp_register +* +* DESCRIPTION +* This function registers a client with a Dispatcher object. +* +* SYNOPSIS +*/ +cl_disp_reg_handle_t +cl_disp_register(IN cl_dispatcher_t * const p_disp, + IN const cl_disp_msgid_t msg_id, + IN cl_pfn_msgrcv_cb_t pfn_callback OPTIONAL, + IN const void *const context); +/* +* PARAMETERS +* p_disp +* [in] Pointer to a Dispatcher. +* +* msg_id +* [in] Numberic message ID for which the client is registering. +* If the client does not wish to receive any messages, +* (a send-only client) then the caller should set this value +* to CL_DISP_MSGID_NONE. For efficiency, numeric message msg_id +* values should start with 0 and should be contiguous, or nearly so. +* +* pfn_callback +* [in] Message receive callback. The Dispatcher calls this +* function after receiving a posted message with the +* appropriate message msg_id value. Send-only clients may specify +* NULL for this value. +* +* context +* [in] Client context value passed to the cl_pfn_msgrcv_cb_t +* function. +* +* RETURN VALUE +* On success a Dispatcher registration handle. +* CL_CL_DISP_INVALID_HANDLE otherwise. +* +* SEE ALSO +* Dispatcher, cl_disp_unregister, cl_disp_post +*********/ + +/****f* Component Library: Dispatcher/cl_disp_unregister +* NAME +* cl_disp_unregister +* +* DESCRIPTION +* This function unregisters a client from a Dispatcher. +* +* SYNOPSIS +*/ +void cl_disp_unregister(IN const cl_disp_reg_handle_t handle); +/* +* PARAMETERS +* handle +* [in] cl_disp_reg_handle_t value return by cl_disp_register. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function will not return until worker threads have exited +* the callback functions for this client. Do not invoke this +* function from a callback. +* +* SEE ALSO +* Dispatcher, cl_disp_register +*********/ + +/****f* Component Library: Dispatcher/cl_disp_post +* NAME +* cl_disp_post +* +* DESCRIPTION +* This function posts a message to a Dispatcher object. +* +* SYNOPSIS +*/ +cl_status_t +cl_disp_post(IN const cl_disp_reg_handle_t handle, + IN const cl_disp_msgid_t msg_id, + IN const void *const p_data, + IN cl_pfn_msgdone_cb_t pfn_callback OPTIONAL, + IN const void *const context); +/* +* PARAMETERS +* handle +* [in] cl_disp_reg_handle_t value return by cl_disp_register. +* +* msg_id +* [in] Numeric message msg_id value associated with this message. +* +* p_data +* [in] Data payload for this message. +* +* pfn_callback +* [in] Pointer to a cl_pfn_msgdone_cb_t function. +* The Dispatcher calls this function after the message has been +* processed by the recipient. +* The caller may pass NULL for this value, which indicates no +* message done callback is necessary. +* +* context +* [in] Client context value passed to the cl_pfn_msgdone_cb_t +* function. +* +* RETURN VALUE +* CL_SUCCESS if the message was successfully queued in the Dispatcher. +* +* NOTES +* The caller must not modify the memory pointed to by p_data until +* the Dispatcher call the pfn_callback function. +* +* SEE ALSO +* Dispatcher +*********/ + +/****f* Component Library: Dispatcher/cl_disp_get_queue_status +* NAME +* cl_disp_get_queue_status +* +* DESCRIPTION +* This function posts a message to a Dispatcher object. +* +* SYNOPSIS +*/ +void +cl_disp_get_queue_status(IN const cl_disp_reg_handle_t handle, + OUT uint32_t * p_num_queued_msgs, + OUT uint64_t * p_last_msg_queue_time_ms); +/* +* PARAMETERS +* handle +* [in] cl_disp_reg_handle_t value return by cl_disp_register. +* +* p_last_msg_queue_time_ms +* [out] pointer to a variable to hold the time the last popped up message +* spent in the queue +* +* p_num_queued_msgs +* [out] number of messages in the queue +* +* RETURN VALUE +* Thr time the last popped up message stayed in the queue, in msec +* +* NOTES +* Extarnel Locking is not required. +* +* SEE ALSO +* Dispatcher +*********/ + +END_C_DECLS +#endif /* !defined(_CL_DISPATCHER_H_) */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_event.h b/contrib/ofed/management/opensm/include/complib/cl_event.h new file mode 100644 index 000000000000..10805fb915b6 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_event.h @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of event abstraction. + */ + +#ifndef _CL_EVENT_H_ +#define _CL_EVENT_H_ + +/* Indicates that waiting on an event should never timeout */ +#define EVENT_NO_TIMEOUT 0xFFFFFFFF + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Event +* NAME +* Event +* +* DESCRIPTION +* The Event provides the ability to suspend and wakeup a thread. +* +* The event functions operates on a cl_event_t structure which should be +* treated as opaque and should be manipulated only through the provided +* functions. +* +* SEE ALSO +* Structures: +* cl_event_t +* +* Initialization/Destruction: +* cl_event_construct, cl_event_init, cl_event_destroy +* +* Manipulation: +* cl_event_signal, cl_event_reset, cl_event_wait_on +*********/ +/****f* Component Library: Event/cl_event_construct +* NAME +* cl_event_construct +* +* DESCRIPTION +* The cl_event_construct function constructs an event. +* +* SYNOPSIS +*/ +void cl_event_construct(IN cl_event_t * const p_event); +/* +* PARAMETERS +* p_event +* [in] Pointer to an cl_event_t structure to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_event_destroy without first calling cl_event_init. +* +* Calling cl_event_construct is a prerequisite to calling any other event +* function except cl_event_init. +* +* SEE ALSO +* Event, cl_event_init, cl_event_destroy +*********/ + +/****f* Component Library: Event/cl_event_init +* NAME +* cl_event_init +* +* DESCRIPTION +* The cl_event_init function initializes an event for use. +* +* SYNOPSIS +*/ +cl_status_t +cl_event_init(IN cl_event_t * const p_event, IN const boolean_t manual_reset); +/* +* PARAMETERS +* p_event +* [in] Pointer to an cl_event_t structure to initialize. +* +* manual_reset +* [in] If FALSE, indicates that the event resets itself after releasing +* a single waiter. If TRUE, the event remains in the signalled state +* until explicitly reset by a call to cl_event_reset. +* +* RETURN VALUES +* CL_SUCCESS if event initialization succeeded. +* +* CL_ERROR otherwise. +* +* NOTES +* Allows calling event manipulation functions, such as cl_event_signal, +* cl_event_reset, and cl_event_wait_on. +* +* The event is initially in a reset state. +* +* SEE ALSO +* Event, cl_event_construct, cl_event_destroy, cl_event_signal, +* cl_event_reset, cl_event_wait_on +*********/ + +/****f* Component Library: Event/cl_event_destroy +* NAME +* cl_event_destroy +* +* DESCRIPTION +* The cl_event_destroy function performs any necessary cleanup of an event. +* +* SYNOPSIS +*/ +void cl_event_destroy(IN cl_event_t * const p_event); + +/* +* PARAMETERS +* p_event +* [in] Pointer to an cl_event_t structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function should only be called after a call to cl_event_construct +* or cl_event_init. +* +* SEE ALSO +* Event, cl_event_construct, cl_event_init +*********/ + +/****f* Component Library: Event/cl_event_signal +* NAME +* cl_event_signal +* +* DESCRIPTION +* The cl_event_signal function sets an event to the signalled state and +* releases at most one waiting thread. +* +* SYNOPSIS +*/ +cl_status_t cl_event_signal(IN cl_event_t * const p_event); +/* +* PARAMETERS +* p_event +* [in] Pointer to an cl_event_t structure to set. +* +* RETURN VALUES +* CL_SUCCESS if the event was successfully signalled. +* +* CL_ERROR otherwise. +* +* NOTES +* For auto-reset events, the event is reset automatically once a wait +* operation is satisfied. +* +* Triggering the event multiple times does not guarantee that the same +* number of wait operations are satisfied. This is because events are +* either in a signalled on non-signalled state, and triggering an event +* that is already in the signalled state has no effect. +* +* SEE ALSO +* Event, cl_event_reset, cl_event_wait_on +*********/ + +/****f* Component Library: Event/cl_event_reset +* NAME +* cl_event_reset +* +* DESCRIPTION +* The cl_event_reset function sets an event to the non-signalled state. +* +* SYNOPSIS +*/ +cl_status_t cl_event_reset(IN cl_event_t * const p_event); +/* +* PARAMETERS +* p_event +* [in] Pointer to an cl_event_t structure to reset. +* +* RETURN VALUES +* CL_SUCCESS if the event was successfully reset. +* +* CL_ERROR otherwise. +* +* SEE ALSO +* Event, cl_event_signal, cl_event_wait_on +*********/ + +/****f* Component Library: Event/cl_event_wait_on +* NAME +* cl_event_wait_on +* +* DESCRIPTION +* The cl_event_wait_on function waits for the specified event to be +* triggered for a minimum amount of time. +* +* SYNOPSIS +*/ +cl_status_t +cl_event_wait_on(IN cl_event_t * const p_event, + IN const uint32_t wait_us, IN const boolean_t interruptible); +/* +* PARAMETERS +* p_event +* [in] Pointer to an cl_event_t structure on which to wait. +* +* wait_us +* [in] Number of microseconds to wait. +* +* interruptible +* [in] Indicates whether the wait operation can be interrupted +* by external signals. +* +* RETURN VALUES +* CL_SUCCESS if the wait operation succeeded in response to the event +* being set. +* +* CL_TIMEOUT if the specified time period elapses. +* +* CL_NOT_DONE if the wait was interrupted by an external signal. +* +* CL_ERROR if the wait operation failed. +* +* NOTES +* If wait_us is set to EVENT_NO_TIMEOUT, the function will wait until the +* event is triggered and never timeout. +* +* If the timeout value is zero, this function simply tests the state of +* the event. +* +* If the event is already on the signalled state at the time of the call +* to cl_event_wait_on, the call completes immediately with CL_SUCCESS. +* +* SEE ALSO +* Event, cl_event_signal, cl_event_reset +*********/ + +END_C_DECLS +#endif /* _CL_EVENT_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_event_osd.h b/contrib/ofed/management/opensm/include/complib/cl_event_osd.h new file mode 100644 index 000000000000..541ced084674 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_event_osd.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of event object. + */ + +#ifndef _CL_EVENT_OSD_H_ +#define _CL_EVENT_OSD_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#include /* usr/include */ +/* + * Linux user mode specific data structure for the event object. + * Users should not access these variables directly. + */ +typedef struct _cl_event_t { + pthread_cond_t condvar; + pthread_mutex_t mutex; + boolean_t signaled; + boolean_t manual_reset; + cl_state_t state; +} cl_event_t; + +END_C_DECLS +#endif /* _CL_EVENT_OSD_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_event_wheel.h b/contrib/ofed/management/opensm/include/complib/cl_event_wheel.h new file mode 100644 index 000000000000..ac02242eecd0 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_event_wheel.h @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of event wheel abstraction. + */ + +#ifndef _CL_EVENT_WHEEL_H_ +#define _CL_EVENT_WHEEL_H_ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Event_Wheel +* NAME +* Event_Wheel +* +* DESCRIPTION +* The Event_Wheel provides a facility for registering delayed events +* and getting called once they timeout. +* +* The Event_Wheel functions operate on a cl_event_wheel_t structure +* which should be treated as opaque and should be manipulated +* only through the provided functions. +* +* SEE ALSO +* Structures: +* cl_event_wheel_t +* +* Initialization/Destruction: +* cl_event_wheel_construct, cl_event_wheel_init, cl_event_wheel_destroy +* +* Manipulation: +* cl_event_wheel_reg, cl_event_wheel_unreg +* +*********/ +/****f* Component Library: Event_Wheel/cl_pfn_event_aged_cb_t +* NAME +* cl_pfn_event_aged_cb_t +* +* DESCRIPTION +* This typedef defines the prototype for client functions invoked +* by the Event_Wheel. The Event_Wheel calls the corresponding +* client function when the specific item has aged. +* +* SYNOPSIS +*/ +typedef uint64_t + (*cl_pfn_event_aged_cb_t) (IN uint64_t key, + IN uint32_t num_regs, IN void *context); +/* +* PARAMETERS +* key +* [in] The key used for registering the item in the call to +* cl_event_wheel_reg +* +* num_regs +* [in] The number of times this event was registered (pushed in time). +* +* context +* [in] Client specific context specified in a call to +* cl_event_wheel_reg +* +* RETURN VALUE +* This function returns the abosolute time the event should fire in [usec]. +* If lower then current time means the event should be unregistered +* immediatly. +* +* NOTES +* This typedef provides a function prototype reference for +* the function provided by Event_Wheel clients as a parameter +* to the cl_event_wheel_reg function. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_reg +*********/ + +/****s* Component Library: Event_Wheel/cl_event_wheel_t +* NAME +* cl_event_wheel_t +* +* DESCRIPTION +* Event_Wheel structure. +* +* The Event_Wheel is thread safe. +* +* The cl_event_wheel_t structure should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_event_wheel { + cl_spinlock_t lock; + cl_spinlock_t *p_external_lock; + + cl_qmap_t events_map; + boolean_t closing; + cl_qlist_t events_wheel; + cl_timer_t timer; +} cl_event_wheel_t; +/* +* FIELDS +* lock +* Spinlock to guard internal structures. +* +* p_external_lock +* Reference to external spinlock to guard internal structures +* if the event wheel is part of a larger object protected by its own lock +* +* events_map +* A Map holding all registered event items by their key. +* +* closing +* A flag indicating the event wheel is closing. This means that +* callbacks that are called when closing == TRUE should just be ignored. +* +* events_wheel +* A list of the events sorted by expiration time. +* +* timer +* The timer scheduling event time propagation. +* +* SEE ALSO +* Event_Wheel +*********/ + +/****s* Component Library: Event_Wheel/cl_event_wheel_reg_info_t +* NAME +* cl_event_wheel_reg_info_t +* +* DESCRIPTION +* Defines the event_wheel registration object structure. +* +* The cl_event_wheel_reg_info_t structure is for internal use by the +* Event_Wheel only. +* +* SYNOPSIS +*/ +typedef struct _cl_event_wheel_reg_info { + cl_map_item_t map_item; + cl_list_item_t list_item; + uint64_t key; + cl_pfn_event_aged_cb_t pfn_aged_callback; + uint64_t aging_time; + uint32_t num_regs; + void *context; + cl_event_wheel_t *p_event_wheel; +} cl_event_wheel_reg_info_t; +/* +* FIELDS +* map_item +* The map item of this event +* +* list_item +* The sorted by aging time list item +* +* key +* The key by which one can find the event +* +* pfn_aged_callback +* The clients Event-Aged callback +* +* aging_time +* The delta time [msec] for which the event should age. +* +* num_regs +* The number of times the same event (key) was registered +* +* context +* Client's context for event-aged callback. +* +* p_event_wheel +* Pointer to this event wheel object +* +* SEE ALSO +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_construct +* NAME +* cl_event_wheel_construct +* +* DESCRIPTION +* This function constructs a Event_Wheel object. +* +* SYNOPSIS +*/ +void cl_event_wheel_construct(IN cl_event_wheel_t * const p_event_wheel); +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_event_wheel_init and cl_event_wheel_destroy. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_init, cl_event_wheel_destroy +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_init +* NAME +* cl_event_wheel_init +* +* DESCRIPTION +* This function initializes a Event_Wheel object. +* +* SYNOPSIS +*/ +cl_status_t +cl_event_wheel_init(IN cl_event_wheel_t * const p_event_wheel); + +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* RETURN VALUE +* CL_SUCCESS if the operation is successful. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_destoy, cl_event_wheel_reg, cl_event_wheel_unreg +* +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_init +* NAME +* cl_event_wheel_init +* +* DESCRIPTION +* This function initializes a Event_Wheel object. +* +* SYNOPSIS +*/ +cl_status_t +cl_event_wheel_init_ex(IN cl_event_wheel_t * const p_event_wheel, + IN cl_spinlock_t * p_external_lock); + +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* p_external_lock +* [in] Reference to external spinlock to guard internal structures +* if the event wheel is part of a larger object protected by its own lock +* +* RETURN VALUE +* CL_SUCCESS if the operation is successful. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_destoy, cl_event_wheel_reg, cl_event_wheel_unreg +* +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_destroy +* NAME +* cl_event_wheel_destroy +* +* DESCRIPTION +* This function destroys a Event_Wheel object. +* +* SYNOPSIS +*/ +void cl_event_wheel_destroy(IN cl_event_wheel_t * const p_event_wheel); +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function does not returns until all client callback functions +* been successfully finished. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_construct, cl_event_wheel_init +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_dump +* NAME +* cl_event_wheel_dump +* +* DESCRIPTION +* This function dumps the details of an Event_Whell object. +* +* SYNOPSIS +*/ +void cl_event_wheel_dump(IN cl_event_wheel_t * const p_event_wheel); +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Note that this function should be called inside a lock of the event wheel! +* It doesn't aquire the lock by itself. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_construct, cl_event_wheel_init +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_reg +* NAME +* cl_event_wheel_reg +* +* DESCRIPTION +* This function registers a client with a Event_Wheel object. +* +* SYNOPSIS +*/ +cl_status_t +cl_event_wheel_reg(IN cl_event_wheel_t * const p_event_wheel, + IN const uint64_t key, + IN const uint64_t aging_time_usec, + IN cl_pfn_event_aged_cb_t pfn_callback, + IN void *const context); +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* key +* [in] The specifc Key by which events are registered. +* +* aging_time_usec +* [in] The absolute time this event should age in usec +* +* pfn_callback +* [in] Event Aging callback. The Event_Wheel calls this +* function after the time the event has registed for has come. +* +* context +* [in] Client context value passed to the cl_pfn_event_aged_cb_t +* function. +* +* RETURN VALUE +* On success a Event_Wheel CL_SUCCESS or CL_ERROR otherwise. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_unreg +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_unreg +* NAME +* cl_event_wheel_unreg +* +* DESCRIPTION +* This function unregisters a client event from a Event_Wheel. +* +* SYNOPSIS +*/ +void +cl_event_wheel_unreg(IN cl_event_wheel_t * const p_event_wheel, + IN uint64_t key); +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* key +* [in] The key used for registering the event +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* After the event has aged it is automatically removed from +* the event wheel. So it should only be invoked when the need arises +* to remove existing events before they age. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_reg +*********/ + +/****f* Component Library: Event_Wheel/cl_event_wheel_num_regs +* NAME +* cl_event_wheel_num_regs +* +* DESCRIPTION +* This function returns the number of times an event was registered. +* +* SYNOPSIS +*/ +uint32_t +cl_event_wheel_num_regs(IN cl_event_wheel_t * const p_event_wheel, + IN uint64_t key); +/* +* PARAMETERS +* p_event_wheel +* [in] Pointer to a Event_Wheel. +* +* key +* [in] The key used for registering the event +* +* RETURN VALUE +* The number of times the event was registered. +* 0 if never registered or eventually aged. +* +* SEE ALSO +* Event_Wheel, cl_event_wheel_reg, cl_event_wheel_unreg +*********/ + +END_C_DECLS +#endif /* !defined(_CL_EVENT_WHEEL_H_) */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_fleximap.h b/contrib/ofed/management/opensm/include/complib/cl_fleximap.h new file mode 100644 index 000000000000..0af87662d210 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_fleximap.h @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of flexi map, a binary tree where the caller always provides + * all necessary storage. + */ + +#ifndef _CL_FLEXIMAP_H_ +#define _CL_FLEXIMAP_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Flexi Map +* NAME +* Flexi Map +* +* DESCRIPTION +* Flexi map implements a binary tree that stores user provided cl_fmap_item_t +* structures. Each item stored in a flexi map has a unique user defined +* key (duplicates are not allowed). Flexi map provides the ability to +* efficiently search for an item given a key. Flexi map allows user +* defined keys of any size. Storage for keys and a comparison function +* are provided by users to allow flexi map to store items with arbitrary +* key values. +* +* Flexi map does not allocate any memory, and can therefore not fail +* any operations due to insufficient memory. Flexi map can thus be useful +* in minimizing the error paths in code. +* +* Flexi map is not thread safe, and users must provide serialization when +* adding and removing items from the map. +* +* The flexi map functions operate on a cl_fmap_t structure which should +* be treated as opaque and should be manipulated only through the provided +* functions. +* +* SEE ALSO +* Structures: +* cl_fmap_t, cl_fmap_item_t +* +* Callbacks: +* cl_pfn_fmap_apply_t +* +* Item Manipulation: +* cl_fmap_key +* +* Initialization: +* cl_fmap_init +* +* Iteration: +* cl_fmap_end, cl_fmap_head, cl_fmap_tail, cl_fmap_next, cl_fmap_prev +* +* Manipulation: +* cl_fmap_insert, cl_fmap_get, cl_fmap_remove_item, cl_fmap_remove, +* cl_fmap_remove_all, cl_fmap_merge, cl_fmap_delta, cl_fmap_get_next +* +* Search: +* cl_fmap_apply_func +* +* Attributes: +* cl_fmap_count, cl_is_fmap_empty, +*********/ +/****s* Component Library: Flexi Map/cl_fmap_item_t +* NAME +* cl_fmap_item_t +* +* DESCRIPTION +* The cl_fmap_item_t structure is used by maps to store objects. +* +* The cl_fmap_item_t structure should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_fmap_item { + /* Must be first to allow casting. */ + cl_pool_item_t pool_item; + struct _cl_fmap_item *p_left; + struct _cl_fmap_item *p_right; + struct _cl_fmap_item *p_up; + cl_map_color_t color; + const void *p_key; +#ifdef _DEBUG_ + struct _cl_fmap *p_map; +#endif +} cl_fmap_item_t; +/* +* FIELDS +* pool_item +* Used to store the item in a doubly linked list, allowing more +* efficient map traversal. +* +* p_left +* Pointer to the map item that is a child to the left of the node. +* +* p_right +* Pointer to the map item that is a child to the right of the node. +* +* p_up +* Pointer to the map item that is the parent of the node. +* +* p_nil +* Pointer to the map's NIL item, used as a terminator for leaves. +* The NIL sentinel is in the cl_fmap_t structure. +* +* color +* Indicates whether a node is red or black in the map. +* +* p_key +* Pointer to the value that uniquely represents a node in a map. This +* pointer is set by calling cl_fmap_insert and can be retrieved by +* calling cl_fmap_key. +* +* NOTES +* None of the fields of this structure should be manipulated by users, as +* they are crititcal to the proper operation of the map in which they +* are stored. +* +* To allow storing items in either a quick list, a quick pool, or a flexi +* map, the map implementation guarantees that the map item can be safely +* cast to a pool item used for storing an object in a quick pool, or cast +* to a list item used for storing an object in a quick list. This removes +* the need to embed a flexi map item, a list item, and a pool item in +* objects that need to be stored in a quick list, a quick pool, and a +* flexi map. +* +* SEE ALSO +* Flexi Map, cl_fmap_insert, cl_fmap_key, cl_pool_item_t, cl_list_item_t +*********/ + +/****d* Component Library: Flexi Map/cl_pfn_fmap_cmp_t +* NAME +* cl_pfn_fmap_cmp_t +* +* DESCRIPTION +* The cl_pfn_fmap_cmp_t function type defines the prototype for functions +* used to compare item keys in a flexi map. +* +* SYNOPSIS +*/ +typedef intn_t + (*cl_pfn_fmap_cmp_t) (IN const void *const p_key1, + IN const void *const p_key2); +/* +* PARAMETERS +* p_key1 +* [in] Pointer to the first of two keys to compare. +* +* p_key2 +* [in] Pointer to the second of two keys to compare. +* +* RETURN VALUE +* Returns 0 if the keys match. +* Returns less than 0 if *p_key1 is less than *p_key2. +* Returns greater than 0 if *p_key1 is greater than *p_key2. +* +* NOTES +* This function type is provided as function prototype reference for the +* function provided by users as a parameter to the cl_fmap_init function. +* +* SEE ALSO +* Flexi Map, cl_fmap_init +*********/ + +/****s* Component Library: Flexi Map/cl_fmap_t +* NAME +* cl_fmap_t +* +* DESCRIPTION +* Flexi map structure. +* +* The cl_fmap_t structure should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_fmap { + cl_fmap_item_t root; + cl_fmap_item_t nil; + cl_state_t state; + size_t count; + cl_pfn_fmap_cmp_t pfn_compare; +} cl_fmap_t; +/* +* PARAMETERS +* root +* Map item that serves as root of the map. The root is set up to +* always have itself as parent. The left pointer is set to point +* to the item at the root. +* +* nil +* Map item that serves as terminator for all leaves, as well as +* providing the list item used as quick list for storing map items +* in a list for faster traversal. +* +* state +* State of the map, used to verify that operations are permitted. +* +* count +* Number of items in the map. +* +* pfn_compare +* Pointer to a compare function to invoke to compare the keys of +* items in the map. +* +* SEE ALSO +* Flexi Map, cl_pfn_fmap_cmp_t +*********/ + +/****d* Component Library: Flexi Map/cl_pfn_fmap_apply_t +* NAME +* cl_pfn_fmap_apply_t +* +* DESCRIPTION +* The cl_pfn_fmap_apply_t function type defines the prototype for +* functions used to iterate items in a flexi map. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_fmap_apply_t) (IN cl_fmap_item_t * const p_map_item, + IN void *context); +/* +* PARAMETERS +* p_map_item +* [in] Pointer to a cl_fmap_item_t structure. +* +* context +* [in] Value passed to the callback function. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function type is provided as function prototype reference for the +* function provided by users as a parameter to the cl_fmap_apply_func +* function. +* +* SEE ALSO +* Flexi Map, cl_fmap_apply_func +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_count +* NAME +* cl_fmap_count +* +* DESCRIPTION +* The cl_fmap_count function returns the number of items stored +* in a flexi map. +* +* SYNOPSIS +*/ +static inline size_t cl_fmap_count(IN const cl_fmap_t * const p_map) +{ + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + return (p_map->count); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_fmap_t structure whose item count to return. +* +* RETURN VALUE +* Returns the number of items stored in the map. +* +* SEE ALSO +* Flexi Map, cl_is_fmap_empty +*********/ + +/****f* Component Library: Flexi Map/cl_is_fmap_empty +* NAME +* cl_is_fmap_empty +* +* DESCRIPTION +* The cl_is_fmap_empty function returns whether a flexi map is empty. +* +* SYNOPSIS +*/ +static inline boolean_t cl_is_fmap_empty(IN const cl_fmap_t * const p_map) +{ + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + + return (p_map->count == 0); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_fmap_t structure to test for emptiness. +* +* RETURN VALUES +* TRUE if the flexi map is empty. +* +* FALSE otherwise. +* +* SEE ALSO +* Flexi Map, cl_fmap_count, cl_fmap_remove_all +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_key +* NAME +* cl_fmap_key +* +* DESCRIPTION +* The cl_fmap_key function retrieves the key value of a map item. +* +* SYNOPSIS +*/ +static inline const void *cl_fmap_key(IN const cl_fmap_item_t * const p_item) +{ + CL_ASSERT(p_item); + return (p_item->p_key); +} + +/* +* PARAMETERS +* p_item +* [in] Pointer to a map item whose key value to return. +* +* RETURN VALUE +* Returns the a pointer to the key value for the specified map item. +* The key value should not be modified to insure proper flexi map operation. +* +* NOTES +* The key value is set in a call to cl_fmap_insert. +* +* SEE ALSO +* Flexi Map, cl_fmap_insert +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_init +* NAME +* cl_fmap_init +* +* DESCRIPTION +* The cl_fmap_init function initialized a flexi map for use. +* +* SYNOPSIS +*/ +void cl_fmap_init(IN cl_fmap_t * const p_map, IN cl_pfn_fmap_cmp_t pfn_compare); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_fmap_t structure to initialize. +* +* pfn_compare +* [in] Pointer to the compare function used to compare keys. +* See the cl_pfn_fmap_cmp_t function type declaration for details +* about the callback function. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* Allows calling flexi map manipulation functions. +* +* SEE ALSO +* Flexi Map, cl_fmap_insert, cl_fmap_remove +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_end +* NAME +* cl_fmap_end +* +* DESCRIPTION +* The cl_fmap_end function returns the end of a flexi map. +* +* SYNOPSIS +*/ +static inline const cl_fmap_item_t *cl_fmap_end(IN const cl_fmap_t * + const p_map) +{ + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + /* Nil is the end of the map. */ + return (&p_map->nil); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_fmap_t structure whose end to return. +* +* RETURN VALUE +* Pointer to the end of the map. +* +* NOTES +* cl_fmap_end is useful for determining the validity of map items returned +* by cl_fmap_head, cl_fmap_tail, cl_fmap_next, or cl_fmap_prev. If the +* map item pointer returned by any of these functions compares to the end, +* the end of the map was encoutered. +* When using cl_fmap_head or cl_fmap_tail, this condition indicates that +* the map is empty. +* +* SEE ALSO +* Flexi Map, cl_fmap_head, cl_fmap_tail, cl_fmap_next, cl_fmap_prev +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_head +* NAME +* cl_fmap_head +* +* DESCRIPTION +* The cl_fmap_head function returns the map item with the lowest key +* value stored in a flexi map. +* +* SYNOPSIS +*/ +static inline cl_fmap_item_t *cl_fmap_head(IN const cl_fmap_t * const p_map) +{ + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + return ((cl_fmap_item_t *) p_map->nil.pool_item.list_item.p_next); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_fmap_t structure whose item with the lowest key +* is returned. +* +* RETURN VALUES +* Pointer to the map item with the lowest key in the flexi map. +* +* Pointer to the map end if the flexi map was empty. +* +* NOTES +* cl_fmap_head does not remove the item from the map. +* +* SEE ALSO +* Flexi Map, cl_fmap_tail, cl_fmap_next, cl_fmap_prev, cl_fmap_end, +* cl_fmap_item_t +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_tail +* NAME +* cl_fmap_tail +* +* DESCRIPTION +* The cl_fmap_tail function returns the map item with the highest key +* value stored in a flexi map. +* +* SYNOPSIS +*/ +static inline cl_fmap_item_t *cl_fmap_tail(IN const cl_fmap_t * const p_map) +{ + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + return ((cl_fmap_item_t *) p_map->nil.pool_item.list_item.p_prev); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_fmap_t structure whose item with the highest key +* is returned. +* +* RETURN VALUES +* Pointer to the map item with the highest key in the flexi map. +* +* Pointer to the map end if the flexi map was empty. +* +* NOTES +* cl_fmap_end does not remove the item from the map. +* +* SEE ALSO +* Flexi Map, cl_fmap_head, cl_fmap_next, cl_fmap_prev, cl_fmap_end, +* cl_fmap_item_t +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_next +* NAME +* cl_fmap_next +* +* DESCRIPTION +* The cl_fmap_next function returns the map item with the next higher +* key value than a specified map item. +* +* SYNOPSIS +*/ +static inline cl_fmap_item_t *cl_fmap_next(IN const cl_fmap_item_t * + const p_item) +{ + CL_ASSERT(p_item); + return ((cl_fmap_item_t *) p_item->pool_item.list_item.p_next); +} + +/* +* PARAMETERS +* p_item +* [in] Pointer to a map item whose successor to return. +* +* RETURN VALUES +* Pointer to the map item with the next higher key value in a flexi map. +* +* Pointer to the map end if the specified item was the last item in +* the flexi map. +* +* SEE ALSO +* Flexi Map, cl_fmap_head, cl_fmap_tail, cl_fmap_prev, cl_fmap_end, +* cl_fmap_item_t +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_prev +* NAME +* cl_fmap_prev +* +* DESCRIPTION +* The cl_fmap_prev function returns the map item with the next lower +* key value than a precified map item. +* +* SYNOPSIS +*/ +static inline cl_fmap_item_t *cl_fmap_prev(IN const cl_fmap_item_t * + const p_item) +{ + CL_ASSERT(p_item); + return ((cl_fmap_item_t *) p_item->pool_item.list_item.p_prev); +} + +/* +* PARAMETERS +* p_item +* [in] Pointer to a map item whose predecessor to return. +* +* RETURN VALUES +* Pointer to the map item with the next lower key value in a flexi map. +* +* Pointer to the map end if the specifid item was the first item in +* the flexi map. +* +* SEE ALSO +* Flexi Map, cl_fmap_head, cl_fmap_tail, cl_fmap_next, cl_fmap_end, +* cl_fmap_item_t +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_insert +* NAME +* cl_fmap_insert +* +* DESCRIPTION +* The cl_fmap_insert function inserts a map item into a flexi map. +* +* SYNOPSIS +*/ +cl_fmap_item_t *cl_fmap_insert(IN cl_fmap_t * const p_map, + IN const void *const p_key, + IN cl_fmap_item_t * const p_item); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_fmap_t structure into which to add the item. +* +* p_key +* [in] Pointer to the key value to assign to the item. Storage +* for the key must be persistant, as only the pointer is stored. +* Users are responsible for maintaining the validity of key +* pointers while they are in use. +* +* p_item +* [in] Pointer to a cl_fmap_item_t stucture to insert into the flexi map. +* +* RETURN VALUE +* Pointer to the item in the map with the specified key. If insertion +* was successful, this is the pointer to the item. If an item with the +* specified key already exists in the map, the pointer to that item is +* returned. +* +* NOTES +* Insertion operations may cause the flexi map to rebalance. +* +* SEE ALSO +* Flexi Map, cl_fmap_remove, cl_fmap_item_t +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_get +* NAME +* cl_fmap_get +* +* DESCRIPTION +* The cl_fmap_get function returns the map item associated with a key. +* +* SYNOPSIS +*/ +cl_fmap_item_t *cl_fmap_get(IN const cl_fmap_t * const p_map, + IN const void *const p_key); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_fmap_t structure from which to retrieve the +* item with the specified key. +* +* p_key +* [in] Pointer to a key value used to search for the desired map item. +* +* RETURN VALUES +* Pointer to the map item with the desired key value. +* +* Pointer to the map end if there was no item with the desired key value +* stored in the flexi map. +* +* NOTES +* cl_fmap_get does not remove the item from the flexi map. +* +* SEE ALSO +* Flexi Map, cl_fmap_remove, cl_fmap_get_next +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_get_next +* NAME +* cl_fmap_get_next +* +* DESCRIPTION +* The cl_fmap_get_next function returns the first map item associated with a +* key > the key specified. +* +* SYNOPSIS +*/ +cl_fmap_item_t *cl_fmap_get_next(IN const cl_fmap_t * const p_map, + IN const void *const p_key); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_fmap_t structure from which to retrieve the +* item with the specified key. +* +* p_key +* [in] Pointer to a key value used to search for the desired map item. +* +* RETURN VALUES +* Pointer to the first map item with a key > the desired key value. +* +* Pointer to the map end if there was no item with a key > the desired key +* value stored in the flexi map. +* +* NOTES +* cl_fmap_get_next does not remove the item from the flexi map. +* +* SEE ALSO +* Flexi Map, cl_fmap_remove, cl_fmap_get +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_remove_item +* NAME +* cl_fmap_remove_item +* +* DESCRIPTION +* The cl_fmap_remove_item function removes the specified map item +* from a flexi map. +* +* SYNOPSIS +*/ +void +cl_fmap_remove_item(IN cl_fmap_t * const p_map, + IN cl_fmap_item_t * const p_item); +/* +* PARAMETERS +* p_item +* [in] Pointer to a map item to remove from its flexi map. +* +* RETURN VALUES +* This function does not return a value. +* +* In a debug build, cl_fmap_remove_item asserts that the item being +* removed es in the specified map. +* +* NOTES +* Removes the map item pointed to by p_item from its flexi map. +* +* SEE ALSO +* Flexi Map, cl_fmap_remove, cl_fmap_remove_all, cl_fmap_insert +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_remove +* NAME +* cl_fmap_remove +* +* DESCRIPTION +* The cl_fmap_remove function removes the map item with the specified key +* from a flexi map. +* +* SYNOPSIS +*/ +cl_fmap_item_t *cl_fmap_remove(IN cl_fmap_t * const p_map, + IN const void *const p_key); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_fmap_t structure from which to remove the +* item with the specified key. +* +* p_key +* [in] Pointer to the key value used to search for the map item +* to remove. +* +* RETURN VALUES +* Pointer to the removed map item if it was found. +* +* Pointer to the map end if no item with the specified key exists in the +* flexi map. +* +* SEE ALSO +* Flexi Map, cl_fmap_remove_item, cl_fmap_remove_all, cl_fmap_insert +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_remove_all +* NAME +* cl_fmap_remove_all +* +* DESCRIPTION +* The cl_fmap_remove_all function removes all items in a flexi map, +* leaving it empty. +* +* SYNOPSIS +*/ +static inline void cl_fmap_remove_all(IN cl_fmap_t * const p_map) +{ + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + + p_map->root.p_left = &p_map->nil; + p_map->nil.pool_item.list_item.p_next = &p_map->nil.pool_item.list_item; + p_map->nil.pool_item.list_item.p_prev = &p_map->nil.pool_item.list_item; + p_map->count = 0; +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_fmap_t structure to empty. +* +* RETURN VALUES +* This function does not return a value. +* +* SEE ALSO +* Flexi Map, cl_fmap_remove, cl_fmap_remove_item +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_merge +* NAME +* cl_fmap_merge +* +* DESCRIPTION +* The cl_fmap_merge function moves all items from one map to another, +* excluding duplicates. +* +* SYNOPSIS +*/ +void +cl_fmap_merge(OUT cl_fmap_t * const p_dest_map, + IN OUT cl_fmap_t * const p_src_map); +/* +* PARAMETERS +* p_dest_map +* [out] Pointer to a cl_fmap_t structure to which items should be added. +* +* p_src_map +* [in/out] Pointer to a cl_fmap_t structure whose items to add +* to p_dest_map. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* Items are evaluated based on their keys only. +* +* Upon return from cl_fmap_merge, the flexi map referenced by p_src_map +* contains all duplicate items. +* +* SEE ALSO +* Flexi Map, cl_fmap_delta +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_delta +* NAME +* cl_fmap_delta +* +* DESCRIPTION +* The cl_fmap_delta function computes the differences between two maps. +* +* SYNOPSIS +*/ +void +cl_fmap_delta(IN OUT cl_fmap_t * const p_map1, + IN OUT cl_fmap_t * const p_map2, + OUT cl_fmap_t * const p_new, OUT cl_fmap_t * const p_old); +/* +* PARAMETERS +* p_map1 +* [in/out] Pointer to the first of two cl_fmap_t structures whose +* differences to compute. +* +* p_map2 +* [in/out] Pointer to the second of two cl_fmap_t structures whose +* differences to compute. +* +* p_new +* [out] Pointer to an empty cl_fmap_t structure that contains the +* items unique to p_map2 upon return from the function. +* +* p_old +* [out] Pointer to an empty cl_fmap_t structure that contains the +* items unique to p_map1 upon return from the function. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* Items are evaluated based on their keys. Items that exist in both +* p_map1 and p_map2 remain in their respective maps. Items that +* exist only p_map1 are moved to p_old. Likewise, items that exist only +* in p_map2 are moved to p_new. This function can be useful in evaluating +* changes between two maps. +* +* Both maps pointed to by p_new and p_old must be empty on input. This +* requirement removes the possibility of failures. +* +* SEE ALSO +* Flexi Map, cl_fmap_merge +*********/ + +/****f* Component Library: Flexi Map/cl_fmap_apply_func +* NAME +* cl_fmap_apply_func +* +* DESCRIPTION +* The cl_fmap_apply_func function executes a specified function +* for every item stored in a flexi map. +* +* SYNOPSIS +*/ +void +cl_fmap_apply_func(IN const cl_fmap_t * const p_map, + IN cl_pfn_fmap_apply_t pfn_func, + IN const void *const context); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_fmap_t structure. +* +* pfn_func +* [in] Function invoked for every item in the flexi map. +* See the cl_pfn_fmap_apply_t function type declaration for +* details about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* The function provided must not perform any map operations, as these +* would corrupt the flexi map. +* +* SEE ALSO +* Flexi Map, cl_pfn_fmap_apply_t +*********/ + +END_C_DECLS +#endif /* _CL_FLEXIMAP_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_list.h b/contrib/ofed/management/opensm/include/complib/cl_list.h new file mode 100644 index 000000000000..5d40b19bad66 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_list.h @@ -0,0 +1,1292 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of list. + */ + +#ifndef _CL_LIST_H_ +#define _CL_LIST_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/List +* NAME +* List +* +* DESCRIPTION +* List stores objects in a doubly linked list. +* +* Unlike quick list, users pass pointers to the object being stored, rather +* than to a cl_list_item_t structure. Insertion operations on a list can +* fail, and callers should trap for such failures. +* +* Use quick list in situations where insertion failures cannot be tolerated. +* +* List is not thread safe, and users must provide serialization. +* +* The list functions operates on a cl_list_t structure which should be +* treated as opaque and should be manipulated only through the provided +* functions. +* +* SEE ALSO +* Types: +* cl_list_iterator_t +* +* Structures: +* cl_list_t +* +* Callbacks: +* cl_pfn_list_apply_t, cl_pfn_list_find_t +* +* Initialization/Destruction: +* cl_list_construct, cl_list_init, cl_list_destroy +* +* Iteration: +* cl_list_next, cl_list_prev, cl_list_head, cl_list_tail, +* cl_list_end +* +* Manipulation: +* cl_list_insert_head, cl_list_insert_tail, +* cl_list_insert_array_head, cl_list_insert_array_tail, +* cl_list_insert_prev, cl_list_insert_next, +* cl_list_remove_head, cl_list_remove_tail, +* cl_list_remove_object, cl_list_remove_item, cl_list_remove_all +* +* Search: +* cl_is_object_in_list, cl_list_find_from_head, cl_list_find_from_tail, +* cl_list_apply_func +* +* Attributes: +* cl_list_count, cl_is_list_empty, cl_is_list_inited +*********/ +/****s* Component Library: List/cl_list_t +* NAME +* cl_list_t +* +* DESCRIPTION +* List structure. +* +* The cl_list_t structure should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_list { + cl_qlist_t list; + cl_qpool_t list_item_pool; +} cl_list_t; +/* +* FIELDS +* list +* Quick list of items stored in the list. +* +* list_item_pool +* Quick pool of list objects for storing objects in the quick list. +* +* SEE ALSO +* List +*********/ + +/****d* Component Library: List/cl_list_iterator_t +* NAME +* cl_list_iterator_t +* +* DESCRIPTION +* Iterator type used to walk a list. +* +* SYNOPSIS +*/ +typedef const cl_list_item_t *cl_list_iterator_t; +/* +* NOTES +* The iterator should be treated as opaque to prevent corrupting the list. +* +* SEE ALSO +* List, cl_list_head, cl_list_tail, cl_list_next, cl_list_prev, +* cl_list_obj +*********/ + +/****d* Component Library: List/cl_pfn_list_apply_t +* NAME +* cl_pfn_list_apply_t +* +* DESCRIPTION +* The cl_pfn_list_apply_t function type defines the prototype for functions +* used to iterate objects in a list. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_list_apply_t) (IN void *const p_object, IN void *context); +/* +* PARAMETERS +* p_object +* [in] Pointer to an object stored in a list. +* +* context +* [in] Context provided in a call to cl_list_apply_func. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function type is provided as function prototype reference for the +* function provided by users as a parameter to the cl_list_apply_func +* function. +* +* SEE ALSO +* List, cl_list_apply_func +*********/ + +/****d* Component Library: List/cl_pfn_list_find_t +* NAME +* cl_pfn_list_find_t +* +* DESCRIPTION +* The cl_pfn_list_find_t function type defines the prototype for functions +* used to find objects in a list. +* +* SYNOPSIS +*/ +typedef cl_status_t + (*cl_pfn_list_find_t) (IN const void *const p_object, IN void *context); +/* +* PARAMETERS +* p_object +* [in] Pointer to an object stored in a list. +* +* context +* [in] Context provided in a call to ListFindFromHead or ListFindFromTail. +* +* RETURN VALUES +* Return CL_SUCCESS if the desired item was found. This stops list iteration. +* +* Return CL_NOT_FOUND to continue the list iteration. +* +* NOTES +* This function type is provided as function prototype reference for the +* function provided by users as a parameter to the cl_list_find_from_head +* and cl_list_find_from_tail functions. +* +* SEE ALSO +* List, cl_list_find_from_head, cl_list_find_from_tail +*********/ + +/****f* Component Library: List/cl_list_construct +* NAME +* cl_list_construct +* +* DESCRIPTION +* The cl_list_construct function constructs a list. +* +* SYNOPSIS +*/ +void cl_list_construct(IN cl_list_t * const p_list); +/* +* PARAMETERS +* p_list +* [in] Pointer to cl_list_t object whose state to initialize. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_list_init, cl_list_destroy and cl_is_list_inited. +* +* Calling cl_list_construct is a prerequisite to calling any other +* list function except cl_list_init. +* +* SEE ALSO +* List, cl_list_init, cl_list_destroy, cl_is_list_inited +*********/ + +/****f* Component Library: List/cl_is_list_inited +* NAME +* cl_is_list_inited +* +* DESCRIPTION +* The cl_is_list_inited function returns whether a list was +* initialized successfully. +* +* SYNOPSIS +*/ +static inline boolean_t cl_is_list_inited(IN const cl_list_t * const p_list) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* + * The pool is the last thing initialized. If it is initialized, the + * list is initialized too. + */ + return (cl_is_qpool_inited(&p_list->list_item_pool)); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure whose initilization state +* to check. +* +* RETURN VALUES +* TRUE if the list was initialized successfully. +* +* FALSE otherwise. +* +* NOTES +* Allows checking the state of a list to determine if invoking +* member functions is appropriate. +* +* SEE ALSO +* List +*********/ + +/****f* Component Library: List/cl_list_init +* NAME +* cl_list_init +* +* DESCRIPTION +* The cl_list_init function initializes a list for use. +* +* SYNOPSIS +*/ +cl_status_t +cl_list_init(IN cl_list_t * const p_list, IN const size_t min_items); +/* +* PARAMETERS +* p_list +* [in] Pointer to cl_list_t structure to initialize. +* +* min_items +* [in] Minimum number of items that can be stored. All necessary +* allocations to allow storing the minimum number of items is performed +* at initialization time. +* +* RETURN VALUES +* CL_SUCCESS if the list was initialized successfully. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory for initialization. +* +* NOTES +* The list will always be able to store at least as many items as specified +* by the min_items parameter. +* +* SEE ALSO +* List, cl_list_construct, cl_list_destroy, cl_list_insert_head, +* cl_list_insert_tail, cl_list_remove_head, cl_list_remove_tail +*********/ + +/****f* Component Library: List/cl_list_destroy +* NAME +* cl_list_destroy +* +* DESCRIPTION +* The cl_list_destroy function destroys a list. +* +* SYNOPSIS +*/ +void cl_list_destroy(IN cl_list_t * const p_list); +/* +* PARAMETERS +* p_list +* [in] Pointer to cl_list_t structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_list_destroy does not affect any of the objects stored in the list, +* but does release all memory allocated internally. Further operations +* should not be attempted on the list after cl_list_destroy is invoked. +* +* This function should only be called after a call to cl_list_construct +* or cl_list_init. +* +* In debug builds, cl_list_destroy asserts if the list is not empty. +* +* SEE ALSO +* List, cl_list_construct, cl_list_init +*********/ + +/****f* Component Library: List/cl_is_list_empty +* NAME +* cl_is_list_empty +* +* DESCRIPTION +* The cl_is_list_empty function returns whether a list is empty. +* +* SYNOPSIS +*/ +static inline boolean_t cl_is_list_empty(IN const cl_list_t * const p_list) +{ + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + return (cl_is_qlist_empty(&p_list->list)); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure. +* +* RETURN VALUES +* TRUE if the specified list is empty. +* +* FALSE otherwise. +* +* SEE ALSO +* List, cl_list_count, cl_list_remove_all +*********/ + +/****f* Component Library: List/cl_list_insert_head +* NAME +* cl_list_insert_head +* +* DESCRIPTION +* The cl_list_insert_head function inserts an object at the head of a list. +* +* SYNOPSIS +*/ +static inline cl_status_t +cl_list_insert_head(IN cl_list_t * const p_list, IN const void *const p_object) +{ + cl_pool_obj_t *p_pool_obj; + + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + + /* Get a list item to add to the list. */ + p_pool_obj = (cl_pool_obj_t *) cl_qpool_get(&p_list->list_item_pool); + if (!p_pool_obj) + return (CL_INSUFFICIENT_MEMORY); + + p_pool_obj->p_object = p_object; + cl_qlist_insert_head(&p_list->list, &p_pool_obj->pool_item.list_item); + return (CL_SUCCESS); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure into which to insert the object. +* +* p_object +* [in] Pointer to an object to insert into the list. +* +* RETURN VALUES +* CL_SUCCESS if the insertion was successful. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory for the insertion. +* +* NOTES +* Inserts the specified object at the head of the list. List insertion +* operations are guaranteed to work for the minimum number of items as +* specified in cl_list_init by the min_items parameter. +* +* SEE ALSO +* List, cl_list_insert_tail, cl_list_insert_array_head, +* cl_list_insert_array_tail, cl_list_insert_prev, cl_list_insert_next, +* cl_list_remove_head +*********/ + +/****f* Component Library: List/cl_list_insert_tail +* NAME +* cl_list_insert_tail +* +* DESCRIPTION +* The cl_list_insert_tail function inserts an object at the tail of a list. +* +* SYNOPSIS +*/ +static inline cl_status_t +cl_list_insert_tail(IN cl_list_t * const p_list, IN const void *const p_object) +{ + cl_pool_obj_t *p_pool_obj; + + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + + /* Get a list item to add to the list. */ + p_pool_obj = (cl_pool_obj_t *) cl_qpool_get(&p_list->list_item_pool); + if (!p_pool_obj) + return (CL_INSUFFICIENT_MEMORY); + + p_pool_obj->p_object = p_object; + cl_qlist_insert_tail(&p_list->list, &p_pool_obj->pool_item.list_item); + return (CL_SUCCESS); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure into which to insert the object. +* +* p_object +* [in] Pointer to an object to insert into the list. +* +* RETURN VALUES +* CL_SUCCESS if the insertion was successful. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory for the insertion. +* +* NOTES +* Inserts the specified object at the tail of the list. List insertion +* operations are guaranteed to work for the minimum number of items as +* specified in cl_list_init by the min_items parameter. +* +* SEE ALSO +* List, cl_list_insert_head, cl_list_insert_array_head, +* cl_list_insert_array_tail, cl_list_insert_prev, cl_list_insert_next, +* cl_list_remove_tail +*********/ + +/****f* Component Library: List/cl_list_insert_array_head +* NAME +* cl_list_insert_array_head +* +* DESCRIPTION: +* The cl_list_insert_array_head function inserts an array of objects +* at the head of a list. +* +* SYNOPSIS +*/ +cl_status_t +cl_list_insert_array_head(IN cl_list_t * const p_list, + IN const void *const p_array, + IN uint32_t item_count, IN const uint32_t item_size); +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure into which to insert the objects. +* +* p_array +* [in] Pointer to the first object in an array. +* +* item_count +* [in] Number of objects in the array. +* +* item_size +* [in] Size of the objects added to the list. This is the stride in the +* array from one object to the next. +* +* RETURN VALUES +* CL_SUCCESS if the insertion was successful. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory for the insertion. +* +* NOTES +* Inserts all objects in the array to the head of the list, preserving the +* ordering of the objects. If not successful, no items are added. +* List insertion operations are guaranteed to work for the minimum number +* of items as specified in cl_list_init by the min_items parameter. +* +* SEE ALSO +* List, cl_list_insert_array_tail, cl_list_insert_head, cl_list_insert_tail, +* cl_list_insert_prev, cl_list_insert_next +*********/ + +/****f* Component Library: List/cl_list_insert_array_tail +* NAME +* cl_list_insert_array_tail +* +* DESCRIPTION +* The cl_list_insert_array_tail function inserts an array of objects +* at the tail of a list. +* +* SYNOPSIS +*/ +cl_status_t +cl_list_insert_array_tail(IN cl_list_t * const p_list, + IN const void *const p_array, + IN uint32_t item_count, IN const uint32_t item_size); +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure into which to insert the objects. +* +* p_array +* [in] Pointer to the first object in an array. +* +* item_count +* [in] Number of objects in the array. +* +* item_size +* [in] Size of the objects added to the list. This is the stride in the +* array from one object to the next. +* +* RETURN VALUES +* CL_SUCCESS if the insertion was successful. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory for the insertion. +* +* NOTES +* Inserts all objects in the array to the tail of the list, preserving the +* ordering of the objects. If not successful, no items are added. +* List insertion operations are guaranteed to work for the minimum number +* of items as specified in cl_list_init by the min_items parameter. +* +* SEE ALSO +* List, cl_list_insert_array_head, cl_list_insert_head, cl_list_insert_tail, +* cl_list_insert_prev, cl_list_insert_next +*********/ + +/****f* Component Library: List/cl_list_insert_next +* NAME +* cl_list_insert_next +* +* DESCRIPTION +* The cl_list_insert_next function inserts an object in a list after +* the object associated with a given iterator. +* +* SYNOPSIS +*/ +static inline cl_status_t +cl_list_insert_next(IN cl_list_t * const p_list, + IN cl_list_iterator_t iterator, + IN const void *const p_object) +{ + cl_pool_obj_t *p_pool_obj; + + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + + /* Get a list item to add to the list. */ + p_pool_obj = (cl_pool_obj_t *) cl_qpool_get(&p_list->list_item_pool); + if (!p_pool_obj) + return (CL_INSUFFICIENT_MEMORY); + + p_pool_obj->p_object = p_object; + cl_qlist_insert_next(&p_list->list, (cl_list_item_t *) iterator, + &p_pool_obj->pool_item.list_item); + return (CL_SUCCESS); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure into which to insert the object. +* +* iterator +* [in] cl_list_iterator_t returned by a previous call to cl_list_head, +* cl_list_tail, cl_list_next, or cl_list_prev. +* +* p_object +* [in] Pointer to an object to insert into the list. +* +* RETURN VALUES +* CL_SUCCESS if the insertion was successful. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory for the insertion. +* +* SEE ALSO +* List, cl_list_insert_prev, cl_list_insert_head, cl_list_insert_tail, +* cl_list_insert_array_head, cl_list_insert_array_tail +*********/ + +/****f* Component Library: List/cl_list_insert_prev +* NAME +* cl_list_insert_prev +* +* DESCRIPTION +* The cl_list_insert_prev function inserts an object in a list before +* the object associated with a given iterator. +* +* SYNOPSIS +*/ +static inline cl_status_t +cl_list_insert_prev(IN cl_list_t * const p_list, + IN cl_list_iterator_t iterator, + IN const void *const p_object) +{ + cl_pool_obj_t *p_pool_obj; + + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + + /* Get a list item to add to the list. */ + p_pool_obj = (cl_pool_obj_t *) cl_qpool_get(&p_list->list_item_pool); + if (!p_pool_obj) + return (CL_INSUFFICIENT_MEMORY); + + p_pool_obj->p_object = p_object; + cl_qlist_insert_prev(&p_list->list, (cl_list_item_t *) iterator, + &p_pool_obj->pool_item.list_item); + return (CL_SUCCESS); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure into which to insert the object. +* +* iterator +* [in] cl_list_iterator_t returned by a previous call to cl_list_head, +* cl_list_tail, cl_list_next, or cl_list_prev. +* +* p_object +* [in] Pointer to an object to insert into the list. +* +* RETURN VALUES +* CL_SUCCESS if the insertion was successful. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory for the insertion. +* +* SEE ALSO +* List, cl_list_insert_next, cl_list_insert_head, cl_list_insert_tail, +* cl_list_insert_array_head, cl_list_insert_array_tail +*********/ + +/****f* Component Library: List/cl_list_remove_head +* NAME +* cl_list_remove_head +* +* DESCRIPTION +* The cl_list_remove_head function removes an object from the head of a list. +* +* SYNOPSIS +*/ +static inline void *cl_list_remove_head(IN cl_list_t * const p_list) +{ + cl_pool_obj_t *p_pool_obj; + void *p_obj; + + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + + /* See if the list is empty. */ + if (cl_is_qlist_empty(&p_list->list)) + return (NULL); + + /* Get the item at the head of the list. */ + p_pool_obj = (cl_pool_obj_t *) cl_qlist_remove_head(&p_list->list); + + p_obj = (void *)p_pool_obj->p_object; + /* Place the pool item back into the pool. */ + cl_qpool_put(&p_list->list_item_pool, &p_pool_obj->pool_item); + + return (p_obj); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure from which to remove an object. +* +* RETURN VALUES +* Returns the pointer to the object formerly at the head of the list. +* +* NULL if the list was empty. +* +* SEE ALSO +* List, cl_list_remove_tail, cl_list_remove_all, cl_list_remove_object, +* cl_list_remove_item, cl_list_insert_head +*********/ + +/****f* Component Library: List/cl_list_remove_tail +* NAME +* cl_list_remove_tail +* +* DESCRIPTION +* The cl_list_remove_tail function removes an object from the tail of a list. +* +* SYNOPSIS +*/ +static inline void *cl_list_remove_tail(IN cl_list_t * const p_list) +{ + cl_pool_obj_t *p_pool_obj; + + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + + /* See if the list is empty. */ + if (cl_is_qlist_empty(&p_list->list)) + return (NULL); + + /* Get the item at the head of the list. */ + p_pool_obj = (cl_pool_obj_t *) cl_qlist_remove_tail(&p_list->list); + + /* Place the list item back into the pool. */ + cl_qpool_put(&p_list->list_item_pool, &p_pool_obj->pool_item); + + return ((void *)p_pool_obj->p_object); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure from which to remove an object. +* +* RETURN VALUES +* Returns the pointer to the object formerly at the tail of the list. +* +* NULL if the list was empty. +* +* SEE ALSO +* List, cl_list_remove_head, cl_list_remove_all, cl_list_remove_object, +* cl_list_remove_item, cl_list_insert_head +*********/ + +/****f* Component Library: List/cl_list_remove_all +* NAME +* cl_list_remove_all +* +* DESCRIPTION +* The cl_list_remove_all function removes all objects from a list, +* leaving it empty. +* +* SYNOPSIS +*/ +static inline void cl_list_remove_all(IN cl_list_t * const p_list) +{ + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + + /* Return all the list items to the pool. */ + cl_qpool_put_list(&p_list->list_item_pool, &p_list->list); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure from which to remove all objects. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* List, cl_list_remove_head, cl_list_remove_tail, cl_list_remove_object, +* cl_list_remove_item +*********/ + +/****f* Component Library: List/cl_list_remove_object +* NAME +* cl_list_remove_object +* +* DESCRIPTION +* The cl_list_remove_object function removes a specific object from a list. +* +* SYNOPSIS +*/ +cl_status_t +cl_list_remove_object(IN cl_list_t * const p_list, + IN const void *const p_object); +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure from which to remove the object. +* +* p_object +* [in] Pointer to an object to remove from the list. +* +* RETURN VALUES +* CL_SUCCESS if the object was removed. +* +* CL_NOT_FOUND if the object was not found in the list. +* +* NOTES +* Removes the first occurrence of an object from a list. +* +* SEE ALSO +* List, cl_list_remove_item, cl_list_remove_head, cl_list_remove_tail, +* cl_list_remove_all +*********/ + +/****f* Component Library: List/cl_list_remove_item +* NAME +* cl_list_remove_item +* +* DESCRIPTION +* The cl_list_remove_item function removes an object from the head of a list. +* +* SYNOPSIS +*/ +static inline void +cl_list_remove_item(IN cl_list_t * const p_list, IN cl_list_iterator_t iterator) +{ + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + + cl_qlist_remove_item(&p_list->list, (cl_list_item_t *) iterator); + + /* Place the list item back into the pool. */ + cl_qpool_put(&p_list->list_item_pool, (cl_pool_item_t *) iterator); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure from which to remove the item. +* +* iterator +* [in] cl_list_iterator_t returned by a previous call to cl_list_head, +* cl_list_tail, cl_list_next, or cl_list_prev. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* List, cl_list_remove_object, cl_list_remove_head, cl_list_remove_tail, +* cl_list_remove_all +*********/ + +/****f* Component Library: List/cl_is_object_in_list +* NAME +* cl_is_object_in_list +* +* DESCRIPTION +* The cl_is_object_in_list function returns whether an object +* is stored in a list. +* +* SYNOPSIS +*/ +boolean_t +cl_is_object_in_list(IN const cl_list_t * const p_list, + IN const void *const p_object); +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure in which to look for the object. +* +* p_object +* [in] Pointer to an object stored in a list. +* +* RETURN VALUES +* TRUE if p_object was found in the list. +* +* FALSE otherwise. +* +* SEE ALSO +* List +*********/ + +/****f* Component Library: List/cl_list_end +* NAME +* cl_list_end +* +* DESCRIPTION +* The cl_list_end function returns returns the list iterator for +* the end of a list. +* +* SYNOPSIS +*/ +static inline cl_list_iterator_t cl_list_end(IN const cl_list_t * const p_list) +{ + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + + return (cl_qlist_end(&p_list->list)); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure for which the iterator for the +* object at the head is to be returned. +* +* RETURN VALUE +* cl_list_iterator_t for the end of the list. +* +* NOTES +* Use cl_list_obj to retrieve the object associated with the +* returned cl_list_iterator_t. +* +* SEE ALSO +* List, cl_list_head, cl_list_tail, cl_list_next, cl_list_prev, +* cl_list_obj +*********/ + +/****f* Component Library: List/cl_list_head +* NAME +* cl_list_head +* +* DESCRIPTION +* The cl_list_head function returns returns a list iterator for +* the head of a list. +* +* SYNOPSIS +*/ +static inline cl_list_iterator_t cl_list_head(IN const cl_list_t * const p_list) +{ + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + + return (cl_qlist_head(&p_list->list)); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure for which the iterator for the +* object at the head is to be returned. +* +* RETURN VALUES +* cl_list_iterator_t for the head of the list. +* +* cl_list_iterator_t for the end of the list if the list is empty. +* +* NOTES +* Use cl_list_obj to retrieve the object associated with the +* returned cl_list_iterator_t. +* +* SEE ALSO +* List, cl_list_tail, cl_list_next, cl_list_prev, cl_list_end, +* cl_list_obj +*********/ + +/****f* Component Library: List/cl_list_tail +* NAME +* cl_list_tail +* +* DESCRIPTION +* The cl_list_tail function returns returns a list iterator for +* the tail of a list. +* +* SYNOPSIS +*/ +static inline cl_list_iterator_t cl_list_tail(IN const cl_list_t * const p_list) +{ + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + + return (cl_qlist_tail(&p_list->list)); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure for which the iterator for the +* object at the tail is to be returned. +* +* RETURN VALUES +* cl_list_iterator_t for the tail of the list. +* +* cl_list_iterator_t for the end of the list if the list is empty. +* +* NOTES +* Use cl_list_obj to retrieve the object associated with the +* +* returned cl_list_iterator_t. +* +* SEE ALSO +* List, cl_list_head, cl_list_next, cl_list_prev, cl_list_end, +* cl_list_obj +*********/ + +/****f* Component Library: List/cl_list_next +* NAME +* cl_list_next +* +* DESCRIPTION +* The cl_list_next function returns a list iterator for the object stored +* in a list after the object associated with a given list iterator. +* +* SYNOPSIS +*/ +static inline cl_list_iterator_t cl_list_next(IN cl_list_iterator_t iterator) +{ + CL_ASSERT(iterator); + + return (cl_qlist_next(iterator)); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure for which the iterator for the +* next object is to be returned. +* +* iterator +* [in] cl_list_iterator_t returned by a previous call to cl_list_head, +* cl_list_tail, cl_list_next, or cl_list_prev. +* +* RETURN VALUES +* cl_list_iterator_t for the object following the object associated with +* the list iterator specified by the iterator parameter. +* +* cl_list_iterator_t for the end of the list if the list is empty. +* +* NOTES +* Use cl_list_obj to retrieve the object associated with the +* returned cl_list_iterator_t. +* +* SEE ALSO +* List, cl_list_prev, cl_list_head, cl_list_tail, cl_list_end, +* cl_list_obj +*********/ + +/****f* Component Library: List/cl_list_prev +* NAME +* cl_list_prev +* +* DESCRIPTION +* The cl_list_prev function returns a list iterator for the object stored +* in a list before the object associated with a given list iterator. +* +* SYNOPSIS +*/ +static inline cl_list_iterator_t cl_list_prev(IN cl_list_iterator_t iterator) +{ + CL_ASSERT(iterator); + + return (cl_qlist_prev(iterator)); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure for which the iterator for the +* next object is to be returned. +* +* iterator +* [in] cl_list_iterator_t returned by a previous call to cl_list_head, +* cl_list_tail, cl_list_next, or cl_list_prev. +* +* RETURN VALUES +* cl_list_iterator_t for the object preceding the object associated with +* the list iterator specified by the iterator parameter. +* +* cl_list_iterator_t for the end of the list if the list is empty. +* +* NOTES +* Use cl_list_obj to retrieve the object associated with the +* returned cl_list_iterator_t. +* +* SEE ALSO +* List, cl_list_next, cl_list_head, cl_list_tail, cl_list_end, +* cl_list_obj +*********/ + +/****f* Component Library: List/cl_list_obj +* NAME +* cl_list_obj +* +* DESCRIPTION +* The cl_list_obj function returns the object associated +* with a list iterator. +* +* SYNOPSIS +*/ +static inline void *cl_list_obj(IN cl_list_iterator_t iterator) +{ + CL_ASSERT(iterator); + + return ((void *)((cl_pool_obj_t *) iterator)->p_object); +} + +/* +* PARAMETERS +* iterator +* [in] cl_list_iterator_t returned by a previous call to cl_list_head, +* cl_list_tail, cl_list_next, or cl_list_prev whose object is requested. +* +* RETURN VALUE +* Pointer to the object associated with the list iterator specified +* by the iterator parameter. +* +* SEE ALSO +* List, cl_list_head, cl_list_tail, cl_list_next, cl_list_prev +*********/ + +/****f* Component Library: List/cl_list_find_from_head +* NAME +* cl_list_find_from_head +* +* DESCRIPTION +* The cl_list_find_from_head function uses a specified function +* to search for an object starting from the head of a list. +* +* SYNOPSIS +*/ +cl_list_iterator_t +cl_list_find_from_head(IN const cl_list_t * const p_list, + IN cl_pfn_list_find_t pfn_func, + IN const void *const context); +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure to search. +* +* pfn_func +* [in] Function invoked to determine if a match was found. +* See the cl_pfn_list_find_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context. +* +* RETURN VALUES +* Returns the iterator for the object if found. +* +* Returns the iterator for the list end otherwise. +* +* NOTES +* cl_list_find_from_head does not remove the found object from +* the list. The iterator for the object is returned when the function +* provided by the pfn_func parameter returns CL_SUCCESS. The function +* specified by the pfn_func parameter must not perform any list +* operations as these would corrupt the list. +* +* SEE ALSO +* List, cl_list_find_from_tail, cl_list_apply_func_t, +* cl_pfn_list_find_t +*********/ + +/****f* Component Library: List/cl_list_find_from_tail +* NAME +* cl_list_find_from_tail +* +* DESCRIPTION +* The cl_list_find_from_tail function uses a specified function +* to search for an object starting from the tail of a list. +* +* SYNOPSIS +*/ +cl_list_iterator_t +cl_list_find_from_tail(IN const cl_list_t * const p_list, + IN cl_pfn_list_find_t pfn_func, + IN const void *const context); +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure to search. +* +* pfn_func +* [in] Function invoked to determine if a match was found. +* See the cl_pfn_list_find_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context. +* +* RETURN VALUES +* Returns the iterator for the object if found. +* +* Returns the iterator for the list end otherwise. +* +* NOTES +* cl_list_find_from_tail does not remove the found object from +* the list. The iterator for the object is returned when the function +* provided by the pfn_func parameter returns CL_SUCCESS. The function +* specified by the pfn_func parameter must not perform any list +* operations as these would corrupt the list. +* +* SEE ALSO +* List, cl_list_find_from_head, cl_list_apply_func_t, +* cl_pfn_list_find_t +*********/ + +/****f* Component Library: List/cl_list_apply_func +* NAME +* cl_list_apply_func +* +* DESCRIPTION +* The cl_list_apply_func function executes a specified function for every +* object stored in a list. +* +* SYNOPSIS +*/ +void +cl_list_apply_func(IN const cl_list_t * const p_list, + IN cl_pfn_list_apply_t pfn_func, + IN const void *const context); +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure to iterate. +* +* pfn_func +* [in] Function invoked for every item in a list. +* See the cl_pfn_list_apply_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_list_apply_func invokes the specified callback function for every +* object stored in the list, starting from the head. The function specified +* by the pfn_func parameter must not perform any list operations as these +* would corrupt the list. +* +* SEE ALSO +* List, cl_list_find_from_head, cl_list_find_from_tail, +* cl_pfn_list_apply_t +*********/ + +/****f* Component Library: List/cl_list_count +* NAME +* cl_list_count +* +* DESCRIPTION +* The cl_list_count function returns the number of objects stored in a list. +* +* SYNOPSIS +*/ +static inline size_t cl_list_count(IN const cl_list_t * const p_list) +{ + CL_ASSERT(p_list); + CL_ASSERT(cl_is_qpool_inited(&p_list->list_item_pool)); + + return (cl_qlist_count(&p_list->list)); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_list_t structure whose object to count. +* +* RETURN VALUES +* Number of objects stored in the specified list. +* +* SEE ALSO +* List +*********/ + +END_C_DECLS +#endif /* _CL_LIST_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_log.h b/contrib/ofed/management/opensm/include/complib/cl_log.h new file mode 100644 index 000000000000..45c7ec35ed66 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_log.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of logging mechanisms. + */ + +#ifndef _CL_LOG_H_ +#define _CL_LOG_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Log Provider +* NAME +* Log Provider +* +* DESCRIPTION +* The log provider allows users to log information in a system log instead of +* the console or debugger target. +**********/ +/****d* Component Library: Log Provider/cl_log_type_t +* NAME +* cl_log_type_t +* +* DESCRIPTION +* The cl_log_type_t enumerated type is used to differentiate between +* different types of log entries. +* +* SYNOPSIS +*/ +typedef enum _cl_log_type { + CL_LOG_INFO, + CL_LOG_WARN, + CL_LOG_ERROR +} cl_log_type_t; +/* +* VALUES +* CL_LOG_INFO +* Indicates a log entry is purely informational. +* +* CL_LOG_WARN +* Indicates a log entry is a warning but non-fatal. +* +* CL_LOG_ERROR +* Indicates a log entry is a fatal error. +* +* SEE ALSO +* Log Provider, cl_log_event +*********/ + +/****f* Component Library: Log Provider/cl_log_event +* NAME +* cl_log_event +* +* DESCRIPTION +* The cl_log_event function adds a new entry to the system log. +* +* SYNOPSIS +*/ +void +cl_log_event(IN const char *const name, + IN const cl_log_type_t type, + IN const char *const message, + IN const void *const p_data OPTIONAL, IN const uint32_t data_len); +/* +* PARAMETERS +* name +* [in] Pointer to an ANSI string containing the name of the source for +* the log entry. +* +* type +* [in] Defines the type of log entry to add to the system log. +* See the definition of cl_log_type_t for acceptable values. +* +* message +* [in] Pointer to an ANSI string containing the text for the log entry. +* The message should not be terminated with a new line, as the log +* provider appends a new line to all log entries. +* +* p_data +* [in] Optional pointer to data providing context for the log entry. +* At most 256 bytes of data can be successfully logged. +* +* data_len +* [in] Length of the buffer pointed to by the p_data parameter. Ignored +* if p_data is NULL. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* If the data length exceeds the maximum supported, the event is logged +* without its accompanying data. +* +* SEE ALSO +* Log Provider, cl_log_type_t +*********/ + +END_C_DECLS +#endif /* _CL_LOG_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_map.h b/contrib/ofed/management/opensm/include/complib/cl_map.h new file mode 100644 index 000000000000..5bf779c927b2 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_map.h @@ -0,0 +1,846 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of map, a binary tree. + */ + +#ifndef _CL_MAP_H_ +#define _CL_MAP_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Map +* NAME +* Map +* +* DESCRIPTION +* Map implements a binary tree that stores user objects. Each item stored +* in a map has a unique 64-bit key (duplicates are not allowed). Map +* provides the ability to efficiently search for an item given a key. +* +* Map may allocate memory when inserting objects, and can therefore fail +* operations due to insufficient memory. Use quick map in situations +* where such insertion failures cannot be tolerated. +* +* Map is not thread safe, and users must provide serialization when adding +* and removing items from the map. +* +* The map functions operates on a cl_map_t structure which should be treated +* as opaque and should be manipulated only through the provided functions. +* +* SEE ALSO +* Types: +* cl_map_iterator_t +* +* Structures: +* cl_map_t, cl_map_item_t, cl_map_obj_t +* +* Item Manipulation: +* cl_map_obj, cl_map_key +* +* Initialization: +* cl_map_construct, cl_map_init, cl_map_destroy +* +* Iteration: +* cl_map_end, cl_map_head, cl_map_tail, cl_map_next, cl_map_prev +* +* Manipulation +* cl_map_insert, cl_map_get, cl_map_remove_item, cl_map_remove, +* cl_map_remove_all, cl_map_merge, cl_map_delta, cl_map_get_next +* +* Attributes: +* cl_map_count, cl_is_map_empty, cl_is_map_inited +*********/ +/****s* Component Library: Map/cl_map_t +* NAME +* cl_map_t +* +* DESCRIPTION +* Quick map structure. +* +* The cl_map_t structure should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_map { + cl_qmap_t qmap; + cl_qpool_t pool; +} cl_map_t; +/* +* FIELDS +* qmap +* Quick map object that maintains the map. +* +* pool +* Pool of cl_map_obj_t structures used to store user objects +* in the map. +* +* SEE ALSO +* Map, cl_map_obj_t +*********/ + +/****d* Component Library: Map/cl_map_iterator_t +* NAME +* cl_map_iterator_t +* +* DESCRIPTION +* Iterator type used to walk a map. +* +* SYNOPSIS +*/ +typedef const cl_map_item_t *cl_map_iterator_t; +/* +* NOTES +* The iterator should be treated as opaque to prevent corrupting the map. +* +* SEE ALSO +* Map, cl_map_head, cl_map_tail, cl_map_next, cl_map_prev, cl_map_key +*********/ + +/****f* Component Library: Map/cl_map_count +* NAME +* cl_map_count +* +* DESCRIPTION +* The cl_map_count function returns the number of items stored +* in a map. +* +* SYNOPSIS +*/ +static inline size_t cl_map_count(IN const cl_map_t * const p_map) +{ + CL_ASSERT(p_map); + return (cl_qmap_count(&p_map->qmap)); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a map whose item count to return. +* +* RETURN VALUE +* Returns the number of items stored in the map. +* +* SEE ALSO +* Map, cl_is_map_empty +*********/ + +/****f* Component Library: Map/cl_is_map_empty +* NAME +* cl_is_map_empty +* +* DESCRIPTION +* The cl_is_map_empty function returns whether a map is empty. +* +* SYNOPSIS +*/ +static inline boolean_t cl_is_map_empty(IN const cl_map_t * const p_map) +{ + CL_ASSERT(p_map); + return (cl_is_qmap_empty(&p_map->qmap)); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a map to test for emptiness. +* +* RETURN VALUES +* TRUE if the map is empty. +* +* FALSE otherwise. +* +* SEE ALSO +* Map, cl_map_count, cl_map_remove_all +*********/ + +/****f* Component Library: Map/cl_map_key +* NAME +* cl_map_key +* +* DESCRIPTION +* The cl_map_key function retrieves the key value of a map item. +* +* SYNOPSIS +*/ +static inline uint64_t cl_map_key(IN const cl_map_iterator_t itor) +{ + return (cl_qmap_key(itor)); +} + +/* +* PARAMETERS +* itor +* [in] Iterator for the item whose key to return. +* +* RETURN VALUE +* Returns the 64-bit key value for the specified iterator. +* +* NOTES +* The iterator specified by the itor parameter must have been retrived by +* a previous call to cl_map_head, cl_map_tail, cl_map_next, or cl_map_prev. +* +* The key value is set in a call to cl_map_insert. +* +* SEE ALSO +* Map, cl_map_insert, cl_map_head, cl_map_tail, cl_map_next, cl_map_prev +*********/ + +/****f* Component Library: Map/cl_map_construct +* NAME +* cl_map_construct +* +* DESCRIPTION +* The cl_map_construct function constructs a map. +* +* SYNOPSIS +*/ +void cl_map_construct(IN cl_map_t * const p_map); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_map_t structure to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_map_init, cl_map_destroy, and cl_is_map_inited. +* +* Calling cl_map_construct is a prerequisite to calling any other +* map function except cl_map_init. +* +* SEE ALSO +* Map, cl_map_init, cl_map_destroy, cl_is_map_inited +*********/ + +/****f* Component Library: Event/cl_is_map_inited +* NAME +* cl_is_map_inited +* +* DESCRIPTION +* The cl_is_map_inited function returns whether a map was +* successfully initialized. +* +* SYNOPSIS +*/ +static inline boolean_t cl_is_map_inited(IN const cl_map_t * const p_map) +{ + /* + * The map's pool of map items is the last thing initialized. + * We can therefore use it to test for initialization. + */ + return (cl_is_qpool_inited(&p_map->pool)); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_map_t structure whose initialization state +* to check. +* +* RETURN VALUES +* TRUE if the map was initialized successfully. +* +* FALSE otherwise. +* +* NOTES +* Allows checking the state of a map to determine if invoking +* member functions is appropriate. +* +* SEE ALSO +* Map +*********/ + +/****f* Component Library: Map/cl_map_init +* NAME +* cl_map_init +* +* DESCRIPTION +* The cl_map_init function initialized a map for use. +* +* SYNOPSIS +*/ +cl_status_t cl_map_init(IN cl_map_t * const p_map, IN const uint32_t min_items); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_map_t structure to initialize. +* +* min_items +* [in] Minimum number of items that can be stored. All necessary +* allocations to allow storing the minimum number of items is +* performed at initialization time. +* +* RETURN VALUES +* CL_SUCCESS if the map was initialized successfully. +* +* NOTES +* Allows calling map manipulation functions. +* +* SEE ALSO +* Map, cl_map_destroy, cl_map_insert, cl_map_remove +*********/ + +/****f* Component Library: Map/cl_map_destroy +* NAME +* cl_map_destroy +* +* DESCRIPTION +* The cl_map_destroy function destroys a map. +* +* SYNOPSIS +*/ +void cl_map_destroy(IN cl_map_t * const p_map); +/* +* PARAMETERS +* p_map +* [in] Pointer to a map to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified map. Further +* operations should not be attempted on the map. cl_map_destroy does +* not affect any of the objects stored in the map. +* This function should only be called after a call to cl_map_construct. +* +* In debug builds, cl_map_destroy asserts that the map is empty. +* +* SEE ALSO +* Map, cl_map_construct, cl_map_init +*********/ + +/****f* Component Library: Map/cl_map_end +* NAME +* cl_map_end +* +* DESCRIPTION +* The cl_map_end function returns the iterator for the end of a map. +* +* SYNOPSIS +*/ +static inline cl_map_iterator_t cl_map_end(IN const cl_map_t * const p_map) +{ + CL_ASSERT(p_map); + return (cl_qmap_end(&p_map->qmap)); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_map_t structure whose end to return. +* +* RETURN VALUE +* Iterator for the end of the map. +* +* NOTES +* cl_map_end is useful for determining the validity of map items returned +* by cl_map_head, cl_map_tail, cl_map_next, cl_map_prev. If the iterator +* by any of these functions compares to the end, the end of the map was +* encoutered. +* When using cl_map_head or cl_map_tail, this condition indicates that +* the map is empty. +* +* SEE ALSO +* Map, cl_qmap_head, cl_qmap_tail, cl_qmap_next, cl_qmap_prev +*********/ + +/****f* Component Library: Map/cl_map_head +* NAME +* cl_map_head +* +* DESCRIPTION +* The cl_map_head function returns the map item with the lowest key +* value stored in a map. +* +* SYNOPSIS +*/ +static inline cl_map_iterator_t cl_map_head(IN const cl_map_t * const p_map) +{ + CL_ASSERT(p_map); + return (cl_qmap_head(&p_map->qmap)); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a map whose item with the lowest key is returned. +* +* RETURN VALUES +* Iterator for the object with the lowest key in the map. +* +* Iterator for the map end if the map was empty. +* +* NOTES +* cl_map_head does not remove the object from the map. +* +* SEE ALSO +* Map, cl_map_tail, cl_map_next, cl_map_prev, cl_map_end +*********/ + +/****f* Component Library: Map/cl_map_tail +* NAME +* cl_map_tail +* +* DESCRIPTION +* The cl_map_tail function returns the map item with the highest key +* value stored in a map. +* +* SYNOPSIS +*/ +static inline cl_map_iterator_t cl_map_tail(IN const cl_map_t * const p_map) +{ + CL_ASSERT(p_map); + return (cl_qmap_tail(&p_map->qmap)); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a map whose item with the highest key +* is returned. +* +* RETURN VALUES +* Iterator for the object with the highest key in the map. +* +* Iterator for the map end if the map was empty. +* +* NOTES +* cl_map_end does no remove the object from the map. +* +* SEE ALSO +* Map, cl_map_head, cl_map_next, cl_map_prev, cl_map_end +*********/ + +/****f* Component Library: Map/cl_map_next +* NAME +* cl_map_next +* +* DESCRIPTION +* The cl_map_next function returns the map item with the next higher +* key value than a specified map item. +* +* SYNOPSIS +*/ +static inline cl_map_iterator_t cl_map_next(IN const cl_map_iterator_t itor) +{ + CL_ASSERT(itor); + return (cl_qmap_next(itor)); +} + +/* +* PARAMETERS +* itor +* [in] Iterator for an object in a map whose successor to return. +* +* RETURN VALUES +* Iterator for the object with the next higher key value in a map. +* +* Iterator for the map end if the specified object was the last item in +* the map. +* +* NOTES +* The iterator must have been retrieved by a previous call to cl_map_head, +* cl_map_tail, cl_map_next, or cl_map_prev. +* +* SEE ALSO +* Map, cl_map_head, cl_map_tail, cl_map_prev, cl_map_end +*********/ + +/****f* Component Library: Map/cl_map_prev +* NAME +* cl_map_prev +* +* DESCRIPTION +* The cl_map_prev function returns the map item with the next lower +* key value than a precified map item. +* +* SYNOPSIS +*/ +static inline cl_map_iterator_t cl_map_prev(IN const cl_map_iterator_t itor) +{ + CL_ASSERT(itor); + return (cl_qmap_prev(itor)); +} + +/* +* PARAMETERS +* itor +* [in] Iterator for an object in a map whose predecessor to return. +* +* RETURN VALUES +* Iterator for the object with the next lower key value in a map. +* +* Iterator for the map end if the specified object was the first item in +* the map. +* +* NOTES +* The iterator must have been retrieved by a previous call to cl_map_head, +* cl_map_tail, cl_map_next, or cl_map_prev. +* +* SEE ALSO +* Map, cl_map_head, cl_map_tail, cl_map_next, cl_map_end +*********/ + +/****f* Component Library: Map/cl_map_insert +* NAME +* cl_map_insert +* +* DESCRIPTION +* The cl_map_insert function inserts a map item into a map. +* +* SYNOPSIS +*/ +void *cl_map_insert(IN cl_map_t * const p_map, + IN const uint64_t key, IN const void *const p_object); +/* +* PARAMETERS +* p_map +* [in] Pointer to a map into which to add the item. +* +* key +* [in] Value to associate with the object. +* +* p_object +* [in] Pointer to an object to insert into the map. +* +* RETURN VALUES +* Pointer to the object in the map with the specified key after the call +* completes. +* +* NULL if there was not enough memory to insert the desired item. +* +* NOTES +* Insertion operations may cause the map to rebalance. +* +* If the map already contains an object already with the specified key, +* that object will not be replaced and the pointer to that object is +* returned. +* +* SEE ALSO +* Map, cl_map_remove, cl_map_item_t +*********/ + +/****f* Component Library: Map/cl_map_get +* NAME +* cl_map_get +* +* DESCRIPTION +* The cl_map_get function returns the object associated with a key. +* +* SYNOPSIS +*/ +void *cl_map_get(IN const cl_map_t * const p_map, IN const uint64_t key); +/* +* PARAMETERS +* p_map +* [in] Pointer to a map from which to retrieve the object with +* the specified key. +* +* key +* [in] Key value used to search for the desired object. +* +* RETURN VALUES +* Pointer to the object with the desired key value. +* +* NULL if there was no item with the desired key value stored in +* the map. +* +* NOTES +* cl_map_get does not remove the item from the map. +* +* SEE ALSO +* Map, cl_map_remove, cl_map_get_next +*********/ + +/****f* Component Library: Map/cl_map_get_next +* NAME +* cl_map_get_next +* +* DESCRIPTION +* The cl_qmap_get_next function returns the first object associated with a +* key > the key specified. +* +* SYNOPSIS +*/ +void *cl_map_get_next(IN const cl_map_t * const p_map, IN const uint64_t key); +/* +* PARAMETERS +* p_map +* [in] Pointer to a map from which to retrieve the object with +* the specified key. +* +* key +* [in] Key value used to search for the desired object. +* +* RETURN VALUES +* Pointer to the first object with a key > the desired key value. +* +* NULL if there was no item with a key > the desired key +* value stored in the map. +* +* NOTES +* cl_map_get does not remove the item from the map. +* +* SEE ALSO +* Map, cl_map_remove, cl_map_get +*********/ + +/****f* Component Library: Map/cl_map_remove_item +* NAME +* cl_map_remove_item +* +* DESCRIPTION +* The cl_map_remove_item function removes the specified map item +* from a map. +* +* SYNOPSIS +*/ +void +cl_map_remove_item(IN cl_map_t * const p_map, IN const cl_map_iterator_t itor); +/* +* PARAMETERS +* p_map +* [in] Pointer to a map from which to remove the object associated +* with the specified iterator. +* +* itor +* [in] Iterator for an object to remove from its map. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Removes the object associated with the specifid iterator from its map. +* +* The specified iterator is no longer valid after the call completes. +* +* The iterator must have been retrieved by a previous call to cl_map_head, +* cl_map_tail, cl_map_next, or cl_map_prev. +* +* SEE ALSO +* Map, cl_map_remove, cl_map_remove_all, cl_map_insert, cl_map_head, +* cl_map_tail, cl_map_next, cl_map_prev +*********/ + +/****f* Component Library: Map/cl_map_remove +* NAME +* cl_map_remove +* +* DESCRIPTION +* The cl_map_remove function removes the map item with the specified key +* from a map. +* +* SYNOPSIS +*/ +void *cl_map_remove(IN cl_map_t * const p_map, IN const uint64_t key); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_map_t structure from which to remove the +* item with the specified key. +* +* key +* [in] Key value used to search for the object to remove. +* +* RETURN VALUES +* Pointer to the object associated with the specified key if +* it was found and removed. +* +* NULL if no object with the specified key exists in the map. +* +* SEE ALSO +* Map, cl_map_remove_item, cl_map_remove_all, cl_map_insert +*********/ + +/****f* Component Library: Map/cl_map_remove_all +* NAME +* cl_map_remove_all +* +* DESCRIPTION +* The cl_map_remove_all function removes all objects from a map, +* leaving it empty. +* +* SYNOPSIS +*/ +void cl_map_remove_all(IN cl_map_t * const p_map); +/* +* PARAMETERS +* p_map +* [in] Pointer to a map to empty. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Map, cl_map_remove, cl_map_remove_item +*********/ + +/****f* Component Library: Map/cl_map_obj +* NAME +* cl_map_obj +* +* DESCRIPTION +* The cl_map_obj function returns the object associated with an iterator. +* +* SYNOPSIS +*/ +static inline void *cl_map_obj(IN const cl_map_iterator_t itor) +{ + return (cl_qmap_obj(PARENT_STRUCT(itor, cl_map_obj_t, item))); +} + +/* +* PARAMETERS +* itor +* [in] Iterator whose object to return. +* +* RETURN VALUES +* Returns the value of the object pointer associated with the iterator. +* +* The iterator must have been retrieved by a previous call to cl_map_head, +* cl_map_tail, cl_map_next, or cl_map_prev. +* +* SEE ALSO +* Map, cl_map_head, cl_map_tail, cl_map_next, cl_map_prev +*********/ + +/****f* Component Library: Map/cl_map_merge +* NAME +* cl_map_merge +* +* DESCRIPTION +* The cl_map_merge function moves all items from one map to another, +* excluding duplicates. +* +* SYNOPSIS +*/ +cl_status_t +cl_map_merge(OUT cl_map_t * const p_dest_map, + IN OUT cl_map_t * const p_src_map); +/* +* PARAMETERS +* p_dest_map +* [out] Pointer to a cl_map_t structure to which items should be added. +* +* p_src_map +* [in/out] Pointer to a cl_map_t structure whose items to add +* to p_dest_map. +* +* RETURN VALUES +* CL_SUCCESS if the operation succeeded. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory for the operation +* to succeed. +* +* NOTES +* Items are evaluated based on their keys only. +* +* Upon return from cl_map_merge, the map referenced by p_src_map contains +* all duplicate items. +* +* SEE ALSO +* Map, cl_map_delta +*********/ + +/****f* Component Library: Map/cl_map_delta +* NAME +* cl_map_delta +* +* DESCRIPTION +* The cl_map_delta function computes the differences between two maps. +* +* SYNOPSIS +*/ +cl_status_t +cl_map_delta(IN OUT cl_map_t * const p_map1, + IN OUT cl_map_t * const p_map2, + OUT cl_map_t * const p_new, OUT cl_map_t * const p_old); +/* +* PARAMETERS +* p_map1 +* [in/out] Pointer to the first of two cl_map_t structures whose +* differences to compute. +* +* p_map2 +* [in/out] Pointer to the second of two cl_map_t structures whose +* differences to compute. +* +* p_new +* [out] Pointer to an empty cl_map_t structure that contains the +* items unique to p_map2 upon return from the function. +* +* p_old +* [out] Pointer to an empty cl_map_t structure that contains the +* items unique to p_map1 upon return from the function. +* +* RETURN VALUES +* CL_SUCCESS if the operation succeeded. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory for the operation +* to succeed. +* +* NOTES +* Items are evaluated based on their keys. Items that exist in both +* p_map1 and p_map2 remain in their respective maps. Items that +* exist only p_map1 are moved to p_old. Likewise, items that exist only +* in p_map2 are moved to p_new. This function can be useful in evaluating +* changes between two maps. +* +* Both maps pointed to by p_new and p_old must be empty on input. +* +* Upon failure, all input maps are restored to their original state. +* +* SEE ALSO +* Map, cl_map_merge +*********/ + +END_C_DECLS +#endif /* _CL_MAP_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_math.h b/contrib/ofed/management/opensm/include/complib/cl_math.h new file mode 100644 index 000000000000..47489bd77f33 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_math.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Defines standard math related macros and functions. + */ + +#ifndef _CL_MATH_H_ +#define _CL_MATH_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****d* Component Library: Math/MAX +* NAME +* MAX +* +* DESCRIPTION +* The MAX macro returns the greater of two values. +* +* SYNOPSIS +* MAX( x, y ); +* +* PARAMETERS +* x +* [in] First of two values to compare. +* +* y +* [in] Second of two values to compare. +* +* RETURN VALUE +* Returns the greater of the x and y parameters. +* +* SEE ALSO +* MIN, ROUNDUP +*********/ +#ifndef MAX +#define MAX(x,y) ((x) > (y) ? (x) : (y)) +#endif +/****d* Component Library: Math/MIN +* NAME +* MIN +* +* DESCRIPTION +* The MIN macro returns the greater of two values. +* +* SYNOPSIS +* MIN( x, y ); +* +* PARAMETERS +* x +* [in] First of two values to compare. +* +* y +* [in] Second of two values to compare. +* +* RETURN VALUE +* Returns the lesser of the x and y parameters. +* +* SEE ALSO +* MAX, ROUNDUP +*********/ +#ifndef MIN +#define MIN(x,y) ((x) < (y) ? (x) : (y)) +#endif +/****d* Component Library: Math/ROUNDUP +* NAME +* ROUNDUP +* +* DESCRIPTION +* The ROUNDUP macro rounds a value up to a given multiple. +* +* SYNOPSIS +* ROUNDUP( val, align ); +* +* PARAMETERS +* val +* [in] Value that is to be rounded up. The type of the value is +* indeterminate, but must be at most the size of a natural integer +* for the platform. +* +* align +* [in] Multiple to which the val parameter must be rounded up. +* +* RETURN VALUE +* Returns a value that is the input value specified by val rounded up to +* the nearest multiple of align. +* +* NOTES +* The value provided must be of a type at most the size of a natural integer. +*********/ +#ifndef ROUNDUP +#define ROUNDUP(val, align) \ + ((((val) / (align))*(align)) + (((val) % (align)) ? (align) : 0)) +#endif +END_C_DECLS +#endif /* _CL_MATH_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_nodenamemap.h b/contrib/ofed/management/opensm/include/complib/cl_nodenamemap.h new file mode 100644 index 000000000000..9b2ada49724a --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_nodenamemap.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2007 Lawrence Livermore National Lab + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _CL_NODE_NAME_MAP_H_ +#define _CL_NODE_NAME_MAP_H_ + +#include +#include +#include + +/* NOTE: this may modify the parameter "nodedesc". */ +char *clean_nodedesc(char *nodedesc); + +typedef struct _name_map_item { + cl_map_item_t item; + uint64_t guid; + char *name; +} name_map_item_t; + +typedef cl_qmap_t nn_map_t; + +/** + * Node name map interface. + * It is OK to pass NULL for the node_name_map[_fp] parameters. + */ +nn_map_t *open_node_name_map(char *node_name_map); +void close_node_name_map(nn_map_t *map); +char *remap_node_name(nn_map_t *map, uint64_t target_guid, + char *nodedesc); + /* NOTE: parameter "nodedesc" may be modified here. */ +int parse_node_map(const char *file_name, + int (*create)(void *, uint64_t, char *), void *cxt); + +#endif /* _CL_NODE_NAME_MAP_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_packoff.h b/contrib/ofed/management/opensm/include/complib/cl_packoff.h new file mode 100644 index 000000000000..52ee381f985d --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_packoff.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Turns off byte packing, which is necessary for passing information from + * system to system over a network to ensure no padding by the compiler has + * taken place. + */ + +#ifdef PACK_SUFFIX +#undef PACK_SUFFIX +#endif + +#ifdef _MSC_VER +#pragma pack (pop) +#endif diff --git a/contrib/ofed/management/opensm/include/complib/cl_packon.h b/contrib/ofed/management/opensm/include/complib/cl_packon.h new file mode 100644 index 000000000000..ffc8e11c65ac --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_packon.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Turns on byte packing, which is necessary for passing information from + * system to system over a network to ensure no padding by the compiler has + * taken place. + */ + +/****h* Component Library/Structure Packing +* NAME +* Structure Packing +* +* DESCRIPTION +* The structure packing header files allow packing structures on byte +* boundaries. +* +* Structure packing should be used whenever a structure is transmitted +* between systems, as different platforms pad structures differently if +* they are not packed. Packing a structure that is not transmitted between +* systems can be detrimental to performance, as fields in the structure may +* not align properly for some platforms. Care must be taken when creating +* packed structures that the alignment rules for all platforms are followed. +* +* To pack a structure, include ipackon.h before defining the structure, and +* include ipackoff.h after the structure definition. Multiple structures +* can be packed between the two include statements if desired. +* +* The structure definition itself must use the PACK_SUFFIX keyword. +* +* EXAMPLE +* #include +* +* typedef _my_struct_t +* { +* uint64 large; +* uint32 medium; +* uint16 small; +* +* } PACK_SUFFIX my_struct_t; +* #include +*********/ + +#ifndef PACK_SUFFIX +#define PACK_SUFFIX __attribute__((packed)) +#endif + +#ifdef _MSC_VER +#pragma pack (push, 1) +#endif diff --git a/contrib/ofed/management/opensm/include/complib/cl_passivelock.h b/contrib/ofed/management/opensm/include/complib/cl_passivelock.h new file mode 100644 index 000000000000..bafd3398f9b8 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_passivelock.h @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * This file contains the passive lock, which synchronizes passive threads. + * The passive lock allows multiple readers to access a resource + * simultaneously, exclusive from a single thread allowed writing. + * Several writer threads are allowed - but only one can write at a given time + */ + +#ifndef _CL_PASSIVE_LOCK_H_ +#define _CL_PASSIVE_LOCK_H_ +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Passive Lock +* NAME +* Passive Lock +* +* DESCRIPTION +* The Passive Lock provides synchronization between multiple threads that +* are sharing the lock with a single thread holding the lock exclusively. +* +* Passive lock works exclusively between threads and cannot be used in +* situations where the caller cannot be put into a waiting state. +* +* The passive lock functions operate a cl_plock_t structure which should +* be treated as opaque and should be manipulated only through the provided +* functions. +* +* SEE ALSO +* Structures: +* cl_plock_t +* +* Initialization: +* cl_plock_construct, cl_plock_init, cl_plock_destroy +* +* Manipulation +* cl_plock_acquire, cl_plock_excl_acquire, cl_plock_release +*********/ +/****s* Component Library: Passive Lock/cl_plock_t +* NAME +* cl_plock_t +* +* DESCRIPTION +* Passive Lock structure. +* +* The cl_plock_t structure should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_plock { + pthread_rwlock_t lock; + cl_state_t state; +} cl_plock_t; +/* +* FIELDS +* lock +* Pthread RWLOCK object +* +* state +* Records the current state of the lock, such as initialized, +* destroying, etc. +* +* SEE ALSO +* Passive Lock +*********/ + +/****f* Component Library: Passive Lock/cl_plock_construct +* NAME +* cl_plock_construct +* +* DESCRIPTION +* The cl_plock_construct function initializes the state of a +* passive lock. +* +* SYNOPSIS +*/ +static inline void cl_plock_construct(IN cl_plock_t * const p_lock) +{ + CL_ASSERT(p_lock); + + p_lock->state = CL_UNINITIALIZED; +} + +/* +* PARAMETERS +* p_lock +* [in] Pointer to a cl_plock_t structure whose state to initialize. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_plock_destroy without first calling cl_plock_init. +* +* Calling cl_plock_construct is a prerequisite to calling any other +* passive lock function except cl_plock_init. +* +* SEE ALSO +* Passive Lock, cl_plock_init, cl_plock_destroy +*********/ + +/****f* Component Library: Passive Lock/cl_plock_destroy +* NAME +* cl_plock_destroy +* +* DESCRIPTION +* The cl_plock_destroy function performs any necessary cleanup +* of a passive lock. +* +* SYNOPSIS +*/ +static inline void cl_plock_destroy(IN cl_plock_t * const p_lock) +{ + CL_ASSERT(p_lock); + p_lock->state = CL_DESTROYING; + pthread_rwlock_destroy(&p_lock->lock); + p_lock->state = CL_DESTROYED; +} + +/* +* PARAMETERS +* p_lock +* [in] Pointer to a cl_plock_t structure whose state to initialize. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_plock_destroy performs any necessary cleanup of the specified +* passive lock. +* +* This function must only be called if cl_plock_construct or +* cl_plock_init has been called. The passive lock must not be held +* when calling this function. +* +* SEE ALSO +* Passive Lock, cl_plock_construct, cl_plock_init +*********/ + +/****f* Component Library: Passive Lock/cl_plock_init +* NAME +* cl_plock_init +* +* DESCRIPTION +* The cl_plock_init function initializes a passive lock. +* +* SYNOPSIS +*/ +static inline cl_status_t cl_plock_init(IN cl_plock_t * const p_lock) +{ + cl_status_t status; + + CL_ASSERT(p_lock); + status = (cl_status_t) pthread_rwlock_init(&p_lock->lock, NULL); + if (status) + return CL_ERROR; + p_lock->state = CL_INITIALIZED; + return (CL_SUCCESS); +} + +/* +* PARAMETERS +* p_lock +* [in] Pointer to a cl_plock_t structure to initialize. +* +* RETURN VALUES +* CL_SUCCESS if the passive lock was initialized successfully. +* +* CL_ERROR otherwise. +* +* NOTES +* Allows calling cl_plock_acquire, cl_plock_release, +* cl_plock_excl_acquire +* +* SEE ALSO +* Passive Lock, cl_plock_construct, cl_plock_destroy, +* cl_plock_excl_acquire, cl_plock_acquire, cl_plock_release +*********/ + +/****f* Component Library: Passive Lock/cl_plock_acquire +* NAME +* cl_plock_acquire +* +* DESCRIPTION +* The cl_plock_acquire function acquires a passive lock for +* shared access. +* +* SYNOPSIS +*/ +static inline void cl_plock_acquire(IN cl_plock_t * const p_lock) +{ + cl_status_t status; + CL_ASSERT(p_lock); + CL_ASSERT(p_lock->state == CL_INITIALIZED); + + status = (cl_status_t) pthread_rwlock_rdlock(&p_lock->lock); + CL_ASSERT(status == 0); +} + +/* +* PARAMETERS +* p_lock +* [in] Pointer to a cl_plock_t structure to acquire. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Passive Lock, cl_plock_release, cl_plock_excl_acquire +*********/ + +/****f* Component Library: Passive Lock/cl_plock_excl_acquire +* NAME +* cl_plock_excl_acquire +* +* DESCRIPTION +* The cl_plock_excl_acquire function acquires exclusive access +* to a passive lock. +* +* SYNOPSIS +*/ +static inline void cl_plock_excl_acquire(IN cl_plock_t * const p_lock) +{ + cl_status_t status; + + CL_ASSERT(p_lock); + CL_ASSERT(p_lock->state == CL_INITIALIZED); + + status = (cl_status_t) pthread_rwlock_wrlock(&p_lock->lock); + CL_ASSERT(status == 0); +} + +/* +* PARAMETERS +* p_lock +* [in] Pointer to a cl_plock_t structure to acquire exclusively. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Passive Lock, cl_plock_release, cl_plock_acquire +*********/ + +/****f* Component Library: Passive Lock/cl_plock_release +* NAME +* cl_plock_release +* +* DESCRIPTION +* The cl_plock_release function releases a passive lock from +* shared or exclusive access. +* +* SYNOPSIS +*/ +static inline void cl_plock_release(IN cl_plock_t * const p_lock) +{ + cl_status_t status; + CL_ASSERT(p_lock); + CL_ASSERT(p_lock->state == CL_INITIALIZED); + + status = (cl_status_t) pthread_rwlock_unlock(&p_lock->lock); + CL_ASSERT(status == 0); +} + +/* +* PARAMETERS +* p_lock +* [in] Pointer to a cl_plock_t structure to release. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Passive Lock, cl_plock_acquire, cl_plock_excl_acquire +*********/ + +END_C_DECLS +#endif /* _CL_PASSIVE_LOCK_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_pool.h b/contrib/ofed/management/opensm/include/complib/cl_pool.h new file mode 100644 index 000000000000..f01de96fe2a6 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_pool.h @@ -0,0 +1,561 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of the pool. + * The pool manages a pool of objects. + * The pool can grow to meet demand, limited only by system memory. + */ + +#ifndef _CL_POOL_H_ +#define _CL_POOL_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Pool +* NAME +* Pool +* +* DESCRIPTION +* The pool provides a self-contained and self-sustaining pool +* of user defined objects. +* +* To aid in object oriented design, the pool provides the user +* the ability to specify callbacks that are invoked for each object for +* construction, initialization, and destruction. Constructor and destructor +* callback functions may not fail. +* +* A pool does not return memory to the system as the user returns +* objects to the pool. The only method of returning memory to the system is +* to destroy the pool. +* +* The Pool functions operate on a cl_pool_t structure which should be treated +* as opaque and should be manipulated only through the provided functions. +* +* SEE ALSO +* Structures: +* cl_pool_t +* +* Callbacks: +* cl_pfn_pool_init_t, cl_pfn_pool_dtor_t +* +* Initialization/Destruction: +* cl_pool_construct, cl_pool_init, cl_pool_destroy +* +* Manipulation: +* cl_pool_get, cl_pool_put, cl_pool_grow +* +* Attributes: +* cl_is_pool_inited, cl_pool_count +*********/ +/****d* Component Library: Pool/cl_pfn_pool_init_t +* NAME +* cl_pfn_pool_init_t +* +* DESCRIPTION +* The cl_pfn_pool_init_t function type defines the prototype for +* functions used as initializers for objects being allocated by a +* pool. +* +* SYNOPSIS +*/ +typedef cl_status_t + (*cl_pfn_pool_init_t) (IN void *const p_object, IN void *context); +/* +* PARAMETERS +* p_object +* [in] Pointer to an object to initialize. +* +* context +* [in] Context provided in a call to cl_pool_init. +* +* RETURN VALUES +* Return CL_SUCCESS to indicates that initialization of the object +* was successful and initialization of further objects may continue. +* +* Other cl_status_t values will be returned by cl_pool_init +* and cl_pool_grow. +* +* NOTES +* This function type is provided as function prototype reference for +* the function provided by the user as an optional parameter to the +* cl_pool_init function. +* +* The initializer is invoked once per allocated object, allowing the user +* to trap initialization failures. Returning a status other than CL_SUCCESS +* aborts a grow operation, initiated either through cl_pool_init or +* cl_pool_grow, and causes the initiating function to fail. +* Any non-CL_SUCCESS status will be returned by the function that initiated +* the grow operation. +* +* SEE ALSO +* Pool, cl_pool_init, cl_pool_grow +*********/ + +/****d* Component Library: Pool/cl_pfn_pool_dtor_t +* NAME +* cl_pfn_pool_dtor_t +* +* DESCRIPTION +* The cl_pfn_pool_dtor_t function type defines the prototype for +* functions used as destructor for objects being deallocated by a +* pool. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_pool_dtor_t) (IN void *const p_object, IN void *context); +/* +* PARAMETERS +* p_object +* [in] Pointer to an object to destruct. +* +* context +* [in] Context provided in the call to cl_pool_init. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function type is provided as function prototype reference for +* the function provided by the user as an optional parameter to the +* cl_pool_init function. +* +* The destructor is invoked once per allocated object, allowing the user +* to perform any necessary cleanup. Users should not attempt to deallocate +* the memory for the object, as the pool manages object +* allocation and deallocation. +* +* SEE ALSO +* Pool, cl_pool_init +*********/ + +/****s* Component Library: Pool/cl_pool_t +* NAME +* cl_pool_t +* +* DESCRIPTION +* pool structure. +* +* The cl_pool_t structure should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_pool { + cl_qcpool_t qcpool; + cl_pfn_pool_init_t pfn_init; + cl_pfn_pool_dtor_t pfn_dtor; + const void *context; +} cl_pool_t; +/* +* FIELDS +* qcpool +* Quick composite pool that manages all objects. +* +* pfn_init +* Pointer to the user's initializer callback, used by the pool +* to translate the quick composite pool's initializer callback to +* a pool initializer callback. +* +* pfn_dtor +* Pointer to the user's destructor callback, used by the pool +* to translate the quick composite pool's destructor callback to +* a pool destructor callback. +* +* context +* User's provided context for callback functions, used by the pool +* to when invoking callbacks. +* +* SEE ALSO +* Pool +*********/ + +/****f* Component Library: Pool/cl_pool_construct +* NAME +* cl_pool_construct +* +* DESCRIPTION +* The cl_pool_construct function constructs a pool. +* +* SYNOPSIS +*/ +void cl_pool_construct(IN cl_pool_t * const p_pool); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_pool_t structure whose state to initialize. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_pool_init, cl_pool_destroy, and cl_is_pool_inited. +* +* Calling cl_pool_construct is a prerequisite to calling any other +* pool function except cl_pool_init. +* +* SEE ALSO +* Pool, cl_pool_init, cl_pool_destroy, cl_is_pool_inited +*********/ + +/****f* Component Library: Pool/cl_is_pool_inited +* NAME +* cl_is_pool_inited +* +* DESCRIPTION +* The cl_is_pool_inited function returns whether a pool was successfully +* initialized. +* +* SYNOPSIS +*/ +static inline uint32_t cl_is_pool_inited(IN const cl_pool_t * const p_pool) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_pool); + return (cl_is_qcpool_inited(&p_pool->qcpool)); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_pool_t structure whose initialization state +* to check. +* +* RETURN VALUES +* TRUE if the pool was initialized successfully. +* +* FALSE otherwise. +* +* NOTES +* Allows checking the state of a pool to determine if invoking member +* functions is appropriate. +* +* SEE ALSO +* Pool +*********/ + +/****f* Component Library: Pool/cl_pool_init +* NAME +* cl_pool_init +* +* DESCRIPTION +* The cl_pool_init function initializes a pool for use. +* +* SYNOPSIS +*/ +cl_status_t +cl_pool_init(IN cl_pool_t * const p_pool, + IN const size_t min_count, + IN const size_t max_count, + IN const size_t grow_size, + IN const size_t object_size, + IN cl_pfn_pool_init_t pfn_initializer OPTIONAL, + IN cl_pfn_pool_dtor_t pfn_destructor OPTIONAL, + IN const void *const context); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_pool_t structure to initialize. +* +* min_count +* [in] Minimum number of objects that the pool should support. All +* necessary allocations to allow storing the minimum number of items +* are performed at initialization time, and all necessary callbacks +* invoked. +* +* max_count +* [in] Maximum number of objects to which the pool is allowed to grow. +* A value of zero specifies no maximum. +* +* grow_size +* [in] Number of objects to allocate when incrementally growing the pool. +* A value of zero disables automatic growth. +* +* object_size +* [in] Size, in bytes, of each object. +* +* pfn_initializer +* [in] Initialization callback to invoke for every new object when +* growing the pool. This parameter is optional and may be NULL. +* See the cl_pfn_pool_init_t function type declaration for details +* about the callback function. +* +* pfn_destructor +* [in] Destructor callback to invoke for every object before memory for +* that object is freed. This parameter is optional and may be NULL. +* See the cl_pfn_pool_dtor_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context. +* +* RETURN VALUES +* CL_SUCCESS if the pool was initialized successfully. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to initialize the +* pool. +* +* CL_INVALID_SETTING if a the maximum size is non-zero and less than the +* minimum size. +* +* Other cl_status_t value returned by optional initialization callback function +* specified by the pfn_initializer parameter. +* +* NOTES +* cl_pool_init initializes, and if necessary, grows the pool to +* the capacity desired. +* +* SEE ALSO +* Pool, cl_pool_construct, cl_pool_destroy, +* cl_pool_get, cl_pool_put, cl_pool_grow, +* cl_pool_count, cl_pfn_pool_init_t, cl_pfn_pool_dtor_t +*********/ + +/****f* Component Library: Pool/cl_pool_destroy +* NAME +* cl_pool_destroy +* +* DESCRIPTION +* The cl_pool_destroy function destroys a pool. +* +* SYNOPSIS +*/ +static inline void cl_pool_destroy(IN cl_pool_t * const p_pool) +{ + CL_ASSERT(p_pool); + cl_qcpool_destroy(&p_pool->qcpool); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_pool_t structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* All memory allocated for objects is freed. The destructor callback, +* if any, will be invoked for every allocated object. Further operations +* on the pool should not be attempted after cl_pool_destroy +* is invoked. +* +* This function should only be called after a call to +* cl_pool_construct or cl_pool_init. +* +* In a debug build, cl_pool_destroy asserts that all objects are in +* the pool. +* +* SEE ALSO +* Pool, cl_pool_construct, cl_pool_init +*********/ + +/****f* Component Library: Pool/cl_pool_count +* NAME +* cl_pool_count +* +* DESCRIPTION +* The cl_pool_count function returns the number of available objects +* in a pool. +* +* SYNOPSIS +*/ +static inline size_t cl_pool_count(IN cl_pool_t * const p_pool) +{ + CL_ASSERT(p_pool); + return (cl_qcpool_count(&p_pool->qcpool)); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_pool_t structure for which the number of +* available objects is requested. +* +* RETURN VALUE +* Returns the number of objects available in the specified pool. +* +* SEE ALSO +* Pool +*********/ + +/****f* Component Library: Pool/cl_pool_get +* NAME +* cl_pool_get +* +* DESCRIPTION +* The cl_pool_get function retrieves an object from a pool. +* +* SYNOPSIS +*/ +static inline void *cl_pool_get(IN cl_pool_t * const p_pool) +{ + cl_pool_obj_t *p_pool_obj; + + CL_ASSERT(p_pool); + + p_pool_obj = (cl_pool_obj_t *) cl_qcpool_get(&p_pool->qcpool); + if (!p_pool_obj) + return (NULL); + + CL_ASSERT(p_pool_obj->p_object); + return ((void *)p_pool_obj->p_object); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_pool_t structure from which to retrieve +* an object. +* +* RETURN VALUES +* Returns a pointer to an object. +* +* Returns NULL if the pool is empty and can not be grown automatically. +* +* NOTES +* cl_pool_get returns the object at the head of the pool. If the pool is +* empty, it is automatically grown to accommodate this request unless the +* grow_size parameter passed to the cl_pool_init function was zero. +* +* SEE ALSO +* Pool, cl_pool_get_tail, cl_pool_put, cl_pool_grow, cl_pool_count +*********/ + +/****f* Component Library: Pool/cl_pool_put +* NAME +* cl_pool_put +* +* DESCRIPTION +* The cl_pool_put function returns an object to a pool. +* +* SYNOPSIS +*/ +static inline void +cl_pool_put(IN cl_pool_t * const p_pool, IN void *const p_object) +{ + cl_pool_obj_t *p_pool_obj; + + CL_ASSERT(p_pool); + CL_ASSERT(p_object); + + /* Calculate the offset to the list object representing this object. */ + p_pool_obj = (cl_pool_obj_t *) + (((uint8_t *) p_object) - sizeof(cl_pool_obj_t)); + + /* good sanity check */ + CL_ASSERT(p_pool_obj->p_object == p_object); + + cl_qcpool_put(&p_pool->qcpool, &p_pool_obj->pool_item); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_pool_t structure to which to return +* an object. +* +* p_object +* [in] Pointer to an object to return to the pool. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_pool_put places the returned object at the head of the pool. +* +* The object specified by the p_object parameter must have been +* retrieved from the pool by a previous call to cl_pool_get. +* +* SEE ALSO +* Pool, cl_pool_put_tail, cl_pool_get +*********/ + +/****f* Component Library: Pool/cl_pool_grow +* NAME +* cl_pool_grow +* +* DESCRIPTION +* The cl_pool_grow function grows a pool by +* the specified number of objects. +* +* SYNOPSIS +*/ +static inline cl_status_t +cl_pool_grow(IN cl_pool_t * const p_pool, IN const size_t obj_count) +{ + CL_ASSERT(p_pool); + return (cl_qcpool_grow(&p_pool->qcpool, obj_count)); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_pool_t structure whose capacity to grow. +* +* obj_count +* [in] Number of objects by which to grow the pool. +* +* RETURN VALUES +* CL_SUCCESS if the pool grew successfully. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to grow the +* pool. +* +* cl_status_t value returned by optional initialization callback function +* specified by the pfn_initializer parameter passed to the +* cl_pool_init function. +* +* NOTES +* It is not necessary to call cl_pool_grow if the pool is +* configured to grow automatically. +* +* SEE ALSO +* Pool +*********/ + +END_C_DECLS +#endif /* _CL_POOL_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_ptr_vector.h b/contrib/ofed/management/opensm/include/complib/cl_ptr_vector.h new file mode 100644 index 000000000000..d4af0fede952 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_ptr_vector.h @@ -0,0 +1,825 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * This file contains pointer vector definitions. Pointer Vector provides + * dynmically resizable array functionality. + */ + +#ifndef _CL_PTR_VECTOR_H_ +#define _CL_PTR_VECTOR_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Pointer Vector +* NAME +* Pointer Vector +* +* DESCRIPTION +* The Pointer Vector is a self-sizing array of pointers. Like a traditonal +* array, a pointer vector allows efficient constant time access to elements +* with a specified index. A pointer vector grows transparently as the +* user adds elements to the array. +* +* The cl_pointer vector_t structure should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SEE ALSO +* Structures: +* cl_ptr_vector_t +* +* Callbacks: +* cl_pfn_ptr_vec_apply_t, cl_pfn_ptr_vec_find_t +* +* Item Manipulation: +* cl_ptr_vector_set, cl_ptr_vector_obj +* +* Initialization: +* cl_ptr_vector_construct, cl_ptr_vector_init, cl_ptr_vector_destroy +* +* Manipulation: +* cl_ptr_vector_get_capacity, cl_ptr_vector_set_capacity, +* cl_ptr_vector_get_size, cl_ptr_vector_set_size, cl_ptr_vector_set_min_size +* cl_ptr_vector_get_ptr, cl_ptr_vector_get, cl_ptr_vector_at, cl_ptr_vector_set +* +* Search: +* cl_ptr_vector_find_from_start, cl_ptr_vector_find_from_end +* cl_ptr_vector_apply_func +*********/ +/****d* Component Library: Pointer Vector/cl_pfn_ptr_vec_apply_t +* NAME +* cl_pfn_ptr_vec_apply_t +* +* DESCRIPTION +* The cl_pfn_ptr_vec_apply_t function type defines the prototype for +* functions used to iterate elements in a pointer vector. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_ptr_vec_apply_t) (IN const size_t index, + IN void *const element, IN void *context); +/* +* PARAMETERS +* index +* [in] Index of the element. +* +* p_element +* [in] Pointer to an element at the specified index in the pointer vector. +* +* context +* [in] Context provided in a call to cl_ptr_vector_apply_func. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function type is provided as function prototype reference for +* the function passed by users as a parameter to the cl_ptr_vector_apply_func +* function. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_apply_func +*********/ + +/****d* Component Library: Pointer Vector/cl_pfn_ptr_vec_find_t +* NAME +* cl_pfn_ptr_vec_find_t +* +* DESCRIPTION +* The cl_pfn_ptr_vec_find_t function type defines the prototype for +* functions used to find elements in a pointer vector. +* +* SYNOPSIS +*/ +typedef cl_status_t + (*cl_pfn_ptr_vec_find_t) (IN const size_t index, + IN const void *const element, IN void *context); +/* +* PARAMETERS +* index +* [in] Index of the element. +* +* p_element +* [in] Pointer to an element at the specified index in the +* pointer vector. +* +* context +* [in] Context provided in a call to cl_ptr_vector_find_from_start or +* cl_ptr_vector_find_from_end. +* +* RETURN VALUES +* Return CL_SUCCESS if the element was found. This stops pointer vector +* iteration. +* +* CL_NOT_FOUND to continue the pointer vector iteration. +* +* NOTES +* This function type is provided as function prototype reference for the +* function provided by users as a parameter to the +* cl_ptr_vector_find_from_start and cl_ptr_vector_find_from_end functions. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_find_from_start, cl_ptr_vector_find_from_end +*********/ + +/****s* Component Library: Pointer Vector/cl_ptr_vector_t +* NAME +* cl_ptr_vector_t +* +* DESCRIPTION +* Pointer Vector structure. +* +* The cl_ptr_vector_t structure should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_ptr_vector { + size_t size; + size_t grow_size; + size_t capacity; + const void **p_ptr_array; + cl_state_t state; +} cl_ptr_vector_t; +/* +* FIELDS +* size +* Number of elements successfully initialized in the pointer vector. +* +* grow_size +* Number of elements to allocate when growing. +* +* capacity +* total # of elements allocated. +* +* alloc_list +* List of allocations. +* +* p_ptr_array +* Internal array of pointers to elements. +* +* state +* State of the pointer vector. +* +* SEE ALSO +* Pointer Vector +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_construct +* NAME +* cl_ptr_vector_construct +* +* DESCRIPTION +* The cl_ptr_vector_construct function constructs a pointer vector. +* +* SYNOPSIS +*/ +void cl_ptr_vector_construct(IN cl_ptr_vector_t * const p_vector); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_ptr_vector_destroy without first calling +* cl_ptr_vector_init. +* +* Calling cl_ptr_vector_construct is a prerequisite to calling any other +* pointer vector function except cl_ptr_vector_init. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_init, cl_ptr_vector_destroy +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_init +* NAME +* cl_ptr_vector_init +* +* DESCRIPTION +* The cl_ptr_vector_init function initializes a pointer vector for use. +* +* SYNOPSIS +*/ +cl_status_t +cl_ptr_vector_init(IN cl_ptr_vector_t * const p_vector, + IN const size_t min_size, IN const size_t grow_size); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure to inititalize. +* +* initial_size +* [in] Initial number of elements. +* +* grow_size +* [in] Number of elements to allocate when incrementally growing +* the pointer vector. A value of zero disables automatic growth. +* +* RETURN VALUES +* CL_SUCCESS if the pointer vector was initialized successfully. +* +* CL_INSUFFICIENT_MEMORY if the initialization failed. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_construct, cl_ptr_vector_destroy, +* cl_ptr_vector_set, cl_ptr_vector_get, cl_ptr_vector_at +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_destroy +* NAME +* cl_ptr_vector_destroy +* +* DESCRIPTION +* The cl_ptr_vector_destroy function destroys a pointer vector. +* +* SYNOPSIS +*/ +void cl_ptr_vector_destroy(IN cl_ptr_vector_t * const p_vector); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_ptr_vector_destroy frees all memory allocated for the pointer vector. +* +* This function should only be called after a call to cl_ptr_vector_construct +* or cl_ptr_vector_init. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_construct, cl_ptr_vector_init +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_get_capacity +* NAME +* cl_ptr_vector_get_capacity +* +* DESCRIPTION +* The cl_ptr_vector_get_capacity function returns the capacity of +* a pointer vector. +* +* SYNOPSIS +*/ +static inline size_t +cl_ptr_vector_get_capacity(IN const cl_ptr_vector_t * const p_vector) +{ + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + + return (p_vector->capacity); +} + +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure whose capacity to return. +* +* RETURN VALUE +* Capacity, in elements, of the pointer vector. +* +* NOTES +* The capacity is the number of elements that the pointer vector can store, +* and can be greater than the number of elements stored. To get the number +* of elements stored in the pointer vector, use cl_ptr_vector_get_size. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_set_capacity, cl_ptr_vector_get_size +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_get_size +* NAME +* cl_ptr_vector_get_size +* +* DESCRIPTION +* The cl_ptr_vector_get_size function returns the size of a pointer vector. +* +* SYNOPSIS +*/ +static inline uint32_t +cl_ptr_vector_get_size(IN const cl_ptr_vector_t * const p_vector) +{ + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + return ((uint32_t) p_vector->size); + +} + +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure whose size to return. +* +* RETURN VALUE +* Size, in elements, of the pointer vector. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_set_size, cl_ptr_vector_get_capacity +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_get +* NAME +* cl_ptr_vector_get +* +* DESCRIPTION +* The cl_ptr_vector_get function returns the pointer stored in a +* pointer vector at a specified index. +* +* SYNOPSIS +*/ +static inline void *cl_ptr_vector_get(IN const cl_ptr_vector_t * const p_vector, + IN const size_t index) +{ + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + CL_ASSERT(p_vector->size > index); + + return ((void *)p_vector->p_ptr_array[index]); +} + +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure from which to get an +* element. +* +* index +* [in] Index of the element. +* +* RETURN VALUE +* Value of the pointer stored at the specified index. +* +* NOTES +* cl_ptr_vector_get provides constant access times regardless of the index. +* +* cl_ptr_vector_get does not perform boundary checking. Callers are +* responsible for providing an index that is within the range of the pointer +* vector. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_at, cl_ptr_vector_set, cl_ptr_vector_get_size +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_at +* NAME +* cl_ptr_vector_at +* +* DESCRIPTION +* The cl_ptr_vector_at function copies an element stored in a pointer +* vector at a specified index, performing boundary checks. +* +* SYNOPSIS +*/ +cl_status_t +cl_ptr_vector_at(IN const cl_ptr_vector_t * const p_vector, + IN const size_t index, OUT void **const p_element); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure from which to get a copy of +* an element. +* +* index +* [in] Index of the element. +* +* p_element +* [out] Pointer to storage for the pointer element. Contains a copy of +* the desired pointer upon successful completion of the call. +* +* RETURN VALUES +* CL_SUCCESS if an element was found at the specified index. +* +* CL_INVALID_SETTING if the index was out of range. +* +* NOTES +* cl_ptr_vector_at provides constant time access regardless of +* the index, and performs boundary checking on the pointer vector. +* +* Upon success, the p_element parameter contains a copy of the +* desired element. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_get +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_set +* NAME +* cl_ptr_vector_set +* +* DESCRIPTION +* The cl_ptr_vector_set function sets the element at the specified index. +* +* SYNOPSIS +*/ +cl_status_t +cl_ptr_vector_set(IN cl_ptr_vector_t * const p_vector, + IN const size_t index, IN const void *const element); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure into which to store +* an element. +* +* index +* [in] Index of the element. +* +* element +* [in] Pointer to store in the pointer vector. +* +* RETURN VALUES +* CL_SUCCESS if the element was successfully set. +* +* CL_INSUFFICIENT_MEMORY if the pointer vector could not be resized to +* accommodate the new element. +* +* NOTES +* cl_ptr_vector_set grows the pointer vector as needed to accommodate +* the new element, unless the grow_size parameter passed into the +* cl_ptr_vector_init function was zero. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_get +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_insert +* NAME +* cl_ptr_vector_insert +* +* DESCRIPTION +* The cl_ptr_vector_insert function inserts an element into a pointer vector. +* +* SYNOPSIS +*/ +static inline cl_status_t +cl_ptr_vector_insert(IN cl_ptr_vector_t * const p_vector, + IN const void *const element, + OUT size_t * const p_index OPTIONAL) +{ + cl_status_t status; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + + status = cl_ptr_vector_set(p_vector, p_vector->size, element); + if (status == CL_SUCCESS && p_index) + *p_index = p_vector->size - 1; + + return (status); +} + +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure into which to store +* an element. +* +* element +* [in] Pointer to store in the pointer vector. +* +* p_index +* [out] Pointer to the index of the element. Valid only if +* insertion was successful. +* +* RETURN VALUES +* CL_SUCCESS if the element was successfully inserted. +* +* CL_INSUFFICIENT_MEMORY if the pointer vector could not be resized to +* accommodate the new element. +* +* NOTES +* cl_ptr_vector_insert places the new element at the end of +* the pointer vector. +* +* cl_ptr_vector_insert grows the pointer vector as needed to accommodate +* the new element, unless the grow_size parameter passed into the +* cl_ptr_vector_init function was zero. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_remove, cl_ptr_vector_set +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_remove +* NAME +* cl_ptr_vector_remove +* +* DESCRIPTION +* The cl_ptr_vector_remove function removes and returns the pointer stored +* in a pointer vector at a specified index. Items beyond the removed item +* are shifted down and the size of the pointer vector is decremented. +* +* SYNOPSIS +*/ +void *cl_ptr_vector_remove(IN cl_ptr_vector_t * const p_vector, + IN const size_t index); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure from which to get an +* element. +* +* index +* [in] Index of the element. +* +* RETURN VALUE +* Value of the pointer stored at the specified index. +* +* NOTES +* cl_ptr_vector_get does not perform boundary checking. Callers are +* responsible for providing an index that is within the range of the pointer +* vector. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_insert, cl_ptr_vector_get_size +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_set_capacity +* NAME +* cl_ptr_vector_set_capacity +* +* DESCRIPTION +* The cl_ptr_vector_set_capacity function reserves memory in a +* pointer vector for a specified number of pointers. +* +* SYNOPSIS +*/ +cl_status_t +cl_ptr_vector_set_capacity(IN cl_ptr_vector_t * const p_vector, + IN const size_t new_capacity); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure whose capacity to set. +* +* new_capacity +* [in] Total number of elements for which the pointer vector should +* allocate memory. +* +* RETURN VALUES +* CL_SUCCESS if the capacity was successfully set. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to satisfy the +* operation. The pointer vector is left unchanged. +* +* NOTES +* cl_ptr_vector_set_capacity increases the capacity of the pointer vector. +* It does not change the size of the pointer vector. If the requested +* capacity is less than the current capacity, the pointer vector is left +* unchanged. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_get_capacity, cl_ptr_vector_set_size, +* cl_ptr_vector_set_min_size +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_set_size +* NAME +* cl_ptr_vector_set_size +* +* DESCRIPTION +* The cl_ptr_vector_set_size function resizes a pointer vector, either +* increasing or decreasing its size. +* +* SYNOPSIS +*/ +cl_status_t +cl_ptr_vector_set_size(IN cl_ptr_vector_t * const p_vector, + IN const size_t size); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure whose size to set. +* +* size +* [in] Number of elements desired in the pointer vector. +* +* RETURN VALUES +* CL_SUCCESS if the size of the pointer vector was set successfully. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to complete the +* operation. The pointer vector is left unchanged. +* +* NOTES +* cl_ptr_vector_set_size sets the pointer vector to the specified size. +* If size is smaller than the current size of the pointer vector, the size +* is reduced. +* +* This function can only fail if size is larger than the current capacity. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_get_size, cl_ptr_vector_set_min_size, +* cl_ptr_vector_set_capacity +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_set_min_size +* NAME +* cl_ptr_vector_set_min_size +* +* DESCRIPTION +* The cl_ptr_vector_set_min_size function resizes a pointer vector to a +* specified size if the pointer vector is smaller than the specified size. +* +* SYNOPSIS +*/ +cl_status_t +cl_ptr_vector_set_min_size(IN cl_ptr_vector_t * const p_vector, + IN const size_t min_size); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure whose minimum size to set. +* +* min_size +* [in] Minimum number of elements that the pointer vector should contain. +* +* RETURN VALUES +* CL_SUCCESS if the pointer vector size is greater than or equal to min_size. +* This could indicate that the pointer vector's capacity was increased to +* min_size or that the pointer vector was already of sufficient size. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to resize the +* pointer vector. The pointer vector is left unchanged. +* +* NOTES +* If min_size is smaller than the current size of the pointer vector, +* the pointer vector is unchanged. The pointer vector is unchanged if the +* size could not be changed due to insufficient memory being available to +* perform the operation. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_get_size, cl_ptr_vector_set_size, +* cl_ptr_vector_set_capacity +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_apply_func +* NAME +* cl_ptr_vector_apply_func +* +* DESCRIPTION +* The cl_ptr_vector_apply_func function invokes a specified function for +* every element in a pointer vector. +* +* SYNOPSIS +*/ +void +cl_ptr_vector_apply_func(IN const cl_ptr_vector_t * const p_vector, + IN cl_pfn_ptr_vec_apply_t pfn_callback, + IN const void *const context); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure whose elements to iterate. +* +* pfn_callback +* [in] Function invoked for every element in the array. +* See the cl_pfn_ptr_vec_apply_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback function. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_ptr_vector_apply_func invokes the specified function for every element +* in the pointer vector, starting from the beginning of the pointer vector. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_find_from_start, cl_ptr_vector_find_from_end, +* cl_pfn_ptr_vec_apply_t +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_find_from_start +* NAME +* cl_ptr_vector_find_from_start +* +* DESCRIPTION +* The cl_ptr_vector_find_from_start function uses a specified function to +* search for elements in a pointer vector starting from the lowest index. +* +* SYNOPSIS +*/ +size_t +cl_ptr_vector_find_from_start(IN const cl_ptr_vector_t * const p_vector, + IN cl_pfn_ptr_vec_find_t pfn_callback, + IN const void *const context); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure to inititalize. +* +* pfn_callback +* [in] Function invoked to determine if a match was found. +* See the cl_pfn_ptr_vec_find_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback function. +* +* RETURN VALUES +* Index of the element, if found. +* +* Size of the pointer vector if the element was not found. +* +* NOTES +* cl_ptr_vector_find_from_start does not remove the found element from +* the pointer vector. The index of the element is returned when the function +* provided by the pfn_callback parameter returns CL_SUCCESS. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_find_from_end, cl_ptr_vector_apply_func, +* cl_pfn_ptr_vec_find_t +*********/ + +/****f* Component Library: Pointer Vector/cl_ptr_vector_find_from_end +* NAME +* cl_ptr_vector_find_from_end +* +* DESCRIPTION +* The cl_ptr_vector_find_from_end function uses a specified function to +* search for elements in a pointer vector starting from the highest index. +* +* SYNOPSIS +*/ +size_t +cl_ptr_vector_find_from_end(IN const cl_ptr_vector_t * const p_vector, + IN cl_pfn_ptr_vec_find_t pfn_callback, + IN const void *const context); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_ptr_vector_t structure to inititalize. +* +* pfn_callback +* [in] Function invoked to determine if a match was found. +* See the cl_pfn_ptr_vec_find_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback function. +* +* RETURN VALUES +* Index of the element, if found. +* +* Size of the pointer vector if the element was not found. +* +* NOTES +* cl_ptr_vector_find_from_end does not remove the found element from +* the pointer vector. The index of the element is returned when the function +* provided by the pfn_callback parameter returns CL_SUCCESS. +* +* SEE ALSO +* Pointer Vector, cl_ptr_vector_find_from_start, cl_ptr_vector_apply_func, +* cl_pfn_ptr_vec_find_t +*********/ + +END_C_DECLS +#endif /* _CL_PTR_VECTOR_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_qcomppool.h b/contrib/ofed/management/opensm/include/complib/cl_qcomppool.h new file mode 100644 index 000000000000..58862e394d7c --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_qcomppool.h @@ -0,0 +1,736 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of the quick composite pool. The quick composite pool + * manages a pool of composite objects. A composite object is an object + * that is made of multiple sub objects. + * It can grow to meet demand, limited only by system memory. + */ + +#ifndef _CL_QUICK_COMPOSITE_POOL_H_ +#define _CL_QUICK_COMPOSITE_POOL_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Quick Composite Pool +* NAME +* Quick Composite Pool +* +* DESCRIPTION +* The Quick Composite Pool provides a self-contained and self-sustaining +* pool of user defined composite objects. +* +* A composite object is an object that is composed of one or more +* sub-objects, each of which needs to be treated separately for +* initialization. Objects can be retrieved from the pool as long as there +* is memory in the system. +* +* To aid in object oriented design, the Quick Composite Pool provides users +* the ability to specify callbacks that are invoked for each object for +* construction, initialization, and destruction. Constructor and destructor +* callback functions may not fail. +* +* A Quick Composite Pool does not return memory to the system as the user +* returns objects to the pool. The only method of returning memory to the +* system is to destroy the pool. +* +* The Quick Composite Pool operates on cl_pool_item_t structures that +* describe composite objects. This provides for more efficient memory use. +* If using a cl_pool_item_t is not desired, the Composite Pool provides +* similar functionality but operates on opaque objects. +* +* The Quick Composit Pool functions operate on a cl_qcpool_t structure +* which should be treated as opaque and should be manipulated only through +* the provided functions. +* +* SEE ALSO +* Structures: +* cl_qcpool_t, cl_pool_item_t +* +* Callbacks: +* cl_pfn_qcpool_init_t, cl_pfn_qcpool_dtor_t +* +* Initialization/Destruction: +* cl_qcpool_construct, cl_qcpool_init, cl_qcpool_destroy +* +* Manipulation: +* cl_qcpool_get, cl_qcpool_put, cl_qcpool_put_list, cl_qcpool_grow +* +* Attributes: +* cl_is_qcpool_inited, cl_qcpool_count +*********/ +/****s* Component Library: Quick Composite Pool/cl_pool_item_t +* NAME +* cl_pool_item_t +* +* DESCRIPTION +* The cl_pool_item_t structure is used by pools to store objects. +* +* SYNOPSIS +*/ +typedef struct _cl_pool_item { + cl_list_item_t list_item; +#ifdef _DEBUG_ + /* Pointer to the owner pool used for sanity checks. */ + struct _cl_qcpool *p_pool; +#endif +} cl_pool_item_t; +/* +* FIELDS +* list_item +* Used internally by the pool. Users should not use this field. +* +* p_pool +* Used internally by the pool in debug builds to check for consistency. +* +* NOTES +* The pool item structure is defined in such a way as to safely allow +* users to cast from a pool item to a list item for storing items +* retrieved from a quick pool in a quick list. +* +* SEE ALSO +* Quick Composite Pool, cl_list_item_t +*********/ + +/****i* Component Library: Quick List/cl_pool_obj_t +* NAME +* cl_pool_obj_t +* +* DESCRIPTION +* The cl_pool_obj_t structure is used by pools to store objects. +* +* SYNOPSIS +*/ +typedef struct _cl_pool_obj { + /* The pool item must be the first item to allow casting. */ + cl_pool_item_t pool_item; + const void *p_object; +} cl_pool_obj_t; +/* +* FIELDS +* pool_item +* Used internally by the pool. Users should not use this field. +* +* p_object +* Pointer to the user's object being stored in the pool. +* +* NOTES +* The pool object structure is used by non-quick pools to store object. +* +* SEE ALSO +* cl_pool_item_t +*********/ + +/****d* Component Library: Quick Composite Pool/cl_pfn_qcpool_init_t +* NAME +* cl_pfn_qcpool_init_t +* +* DESCRIPTION +* The cl_pfn_qcpool_init_t function type defines the prototype for +* functions used as initializer for objects being allocated by a +* quick composite pool. +* +* SYNOPSIS +*/ +typedef cl_status_t + (*cl_pfn_qcpool_init_t) (IN void **const p_comp_array, + IN const uint32_t num_components, + IN void *context, + OUT cl_pool_item_t ** const pp_pool_item); +/* +* PARAMETERS +* p_comp_array +* [in] Pointer to the first entry in an array of pointers, each of +* which points to a component that makes up a composite object. +* +* num_components +* [in] Number of components that in the component array. +* +* context +* [in] Context provided in a call to cl_qcpool_init. +* +* pp_pool_item +* [out] Users should set this pointer to reference the cl_pool_item_t +* structure that represents the composite object. This pointer must +* not be NULL if the function returns CL_SUCCESS. +* +* RETURN VALUE +* Return CL_SUCCESS to indicate that initialization of the object +* was successful and that initialization of further objects may continue. +* +* Other cl_status_t values will be returned by cl_qcpool_init +* and cl_qcpool_grow. +* +* NOTES +* This function type is provided as function prototype reference for +* the function provided by the user as a parameter to the +* cl_qcpool_init function. +* +* The initializer is invoked once per allocated object, allowing the user +* to chain components to form a composite object and perform any necessary +* initialization. Returning a status other than CL_SUCCESS aborts a grow +* operation, initiated either through cl_qcpool_init or cl_qcpool_grow, +* and causes the initiating function to fail. Any non-CL_SUCCESS status +* will be returned by the function that initiated the grow operation. +* +* All memory for the requested number of components is pre-allocated. Users +* should include space in one of their components for the cl_pool_item_t +* structure that will represent the composite object to avoid having to +* allocate that structure in the initialization callback. Alternatively, +* users may specify an additional component for the cl_pool_item_t structure. +* +* When later performing a cl_qcpool_get call, the return value is a pointer +* to the cl_pool_item_t returned by this function in the pp_pool_item +* parameter. Users must set pp_pool_item to a valid pointer to the +* cl_pool_item_t representing the object if they return CL_SUCCESS. +* +* SEE ALSO +* Quick Composite Pool, cl_qcpool_init +*********/ + +/****d* Component Library: Quick Composite Pool/cl_pfn_qcpool_dtor_t +* NAME +* cl_pfn_qcpool_dtor_t +* +* DESCRIPTION +* The cl_pfn_qcpool_dtor_t function type defines the prototype for +* functions used as destructor for objects being deallocated by a +* quick composite pool. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_qcpool_dtor_t) (IN const cl_pool_item_t * const p_pool_item, + IN void *context); +/* +* PARAMETERS +* p_pool_item +* [in] Pointer to a cl_pool_item_t structure representing an object. +* +* context +* [in] Context provided in a call to cl_qcpool_init. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function type is provided as function prototype reference for +* the function provided by the user as an optional parameter to the +* cl_qcpool_init function. +* +* The destructor is invoked once per allocated object, allowing the user +* to perform any necessary cleanup. Users should not attempt to deallocate +* the memory for the composite object, as the quick composite pool manages +* object allocation and deallocation. +* +* SEE ALSO +* Quick Composite Pool, cl_qcpool_init +*********/ + +/****s* Component Library: Quick Composite Pool/cl_qcpool_t +* NAME +* cl_qcpool_t +* +* DESCRIPTION +* Quick composite pool structure. +* +* The cl_qcpool_t structure should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_qcpool { + uint32_t num_components; + size_t *component_sizes; + void **p_components; + size_t num_objects; + size_t max_objects; + size_t grow_size; + cl_pfn_qcpool_init_t pfn_init; + cl_pfn_qcpool_dtor_t pfn_dtor; + const void *context; + cl_qlist_t free_list; + cl_qlist_t alloc_list; + cl_state_t state; +} cl_qcpool_t; +/* +* FIELDS +* num_components +* Number of components per object. +* +* component_sizes +* Array of sizes, one for each component. +* +* p_components +* Array of pointers to components, used for the constructor callback. +* +* num_objects +* Number of objects managed by the pool +* +* grow_size +* Number of objects to add when automatically growing the pool. +* +* pfn_init +* Pointer to the user's initializer callback to invoke when initializing +* new objects. +* +* pfn_dtor +* Pointer to the user's destructor callback to invoke before deallocating +* memory allocated for objects. +* +* context +* User's provided context for callback functions, used by the pool +* when invoking callbacks. +* +* free_list +* Quick list of objects available. +* +* alloc_list +* Quick list used to store information about allocations. +* +* state +* State of the pool. +* +* SEE ALSO +* Quick Composite Pool +*********/ + +/****f* Component Library: Quick Composite Pool/cl_qcpool_construct +* NAME +* cl_qcpool_construct +* +* DESCRIPTION +* The cl_qcpool_construct function constructs a quick composite pool. +* +* SYNOPSIS +*/ +void cl_qcpool_construct(IN cl_qcpool_t * const p_pool); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qcpool_t structure whose state to initialize. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_qcpool_init, cl_qcpool_destroy, cl_is_qcpool_inited. +* +* Calling cl_qcpool_construct is a prerequisite to calling any other +* quick composite pool function except cl_qcpool_init. +* +* SEE ALSO +* Quick Composite Pool, cl_qcpool_init, cl_qcpool_destroy, +* cl_is_qcpool_inited +*********/ + +/****f* Component Library: Quick Composite Pool/cl_is_qcpool_inited +* NAME +* cl_is_qcpool_inited +* +* DESCRIPTION +* The cl_is_qcpool_inited function returns whether a quick composite pool was +* successfully initialized. +* +* SYNOPSIS +*/ +static inline uint32_t cl_is_qcpool_inited(IN const cl_qcpool_t * const p_pool) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_pool); + /* CL_ASSERT that the pool is not in some invalid state. */ + CL_ASSERT(cl_is_state_valid(p_pool->state)); + + return (p_pool->state == CL_INITIALIZED); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qcpool_t structure to check. +* +* RETURN VALUES +* TRUE if the quick composite pool was initialized successfully. +* +* FALSE otherwise. +* +* NOTES +* Allows checking the state of a quick composite pool to determine if +* invoking member functions is appropriate. +* +* SEE ALSO +* Quick Composite Pool +*********/ + +/****f* Component Library: Quick Composite Pool/cl_qcpool_init +* NAME +* cl_qcpool_init +* +* DESCRIPTION +* The cl_qcpool_init function initializes a quick composite pool for use. +* +* SYNOPSIS +*/ +cl_status_t +cl_qcpool_init(IN cl_qcpool_t * const p_pool, + IN const size_t min_size, + IN const size_t max_size, + IN const size_t grow_size, + IN const size_t * const component_sizes, + IN const uint32_t num_components, + IN cl_pfn_qcpool_init_t pfn_initializer OPTIONAL, + IN cl_pfn_qcpool_dtor_t pfn_destructor OPTIONAL, + IN const void *const context); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qcpool_t structure to initialize. +* +* min_size +* [in] Minimum number of objects that the pool should support. All +* necessary allocations to allow storing the minimum number of items +* are performed at initialization time, and all necessary callbacks +* successfully invoked. +* +* max_size +* [in] Maximum number of objects to which the pool is allowed to grow. +* A value of zero specifies no maximum. +* +* grow_size +* [in] Number of objects to allocate when incrementally growing the pool. +* A value of zero disables automatic growth. +* +* component_sizes +* [in] Pointer to the first entry in an array of sizes describing, +* in order, the sizes of the components that make up a composite object. +* +* num_components +* [in] Number of components that make up a composite object. +* +* pfn_initializer +* [in] Initializer callback to invoke for every new object when growing +* the pool. This parameter may be NULL only if the objects stored in +* the quick composite pool consist of only one component. If NULL, the +* pool assumes the cl_pool_item_t structure describing objects is +* located at the head of each object. See the cl_pfn_qcpool_init_t +* function type declaration for details about the callback function. +* +* pfn_destructor +* [in] Destructor callback to invoke for every object before memory for +* that object is freed. This parameter is optional and may be NULL. +* See the cl_pfn_qcpool_dtor_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context. +* +* RETURN VALUES +* CL_SUCCESS if the quick composite pool was initialized successfully. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to initialize the +* quick composite pool. +* +* CL_INVALID_SETTING if a NULL constructor was provided for composite objects +* consisting of more than one component. Also returns CL_INVALID_SETTING if +* the maximum size is non-zero and less than the minimum size. +* +* Other cl_status_t value returned by optional initialization callback function +* specified by the pfn_initializer parameter. +* +* If initialization fails, the pool is left in a destroyed state. Callers +* may still safely call cl_qcpool_destroy. +* +* NOTES +* cl_qcpool_init initializes, and if necessary, grows the pool to +* the capacity desired. +* +* SEE ALSO +* Quick Composite Pool, cl_qcpool_construct, cl_qcpool_destroy, +* cl_qcpool_get, cl_qcpool_put, cl_qcpool_grow, +* cl_qcpool_count, cl_pfn_qcpool_init_t, cl_pfn_qcpool_dtor_t +*********/ + +/****f* Component Library: Quick Composite Pool/cl_qcpool_destroy +* NAME +* cl_qcpool_destroy +* +* DESCRIPTION +* The cl_qcpool_destroy function destroys a quick composite pool. +* +* SYNOPSIS +*/ +void cl_qcpool_destroy(IN cl_qcpool_t * const p_pool); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qcpool_t structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* All memory allocated for composite objects is freed. The destructor +* callback, if any, will be invoked for every allocated object. Further +* operations on the composite pool should not be attempted after +* cl_qcpool_destroy is invoked. +* +* This function should only be called after a call to +* cl_qcpool_construct or cl_qcpool_init. +* +* In a debug build, cl_qcpool_destroy asserts that all objects are in +* the pool. +* +* SEE ALSO +* Quick Composite Pool, cl_qcpool_construct, cl_qcpool_init +*********/ + +/****f* Component Library: Quick Composite Pool/cl_qcpool_count +* NAME +* cl_qcpool_count +* +* DESCRIPTION +* The cl_qcpool_count function returns the number of available objects +* in a quick composite pool. +* +* SYNOPSIS +*/ +static inline size_t cl_qcpool_count(IN cl_qcpool_t * const p_pool) +{ + CL_ASSERT(p_pool); + CL_ASSERT(p_pool->state == CL_INITIALIZED); + + return (cl_qlist_count(&p_pool->free_list)); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qcpool_t structure for which the number of +* available objects is requested. +* +* RETURN VALUE +* Returns the number of objects available in the specified +* quick composite pool. +* +* SEE ALSO +* Quick Composite Pool +*********/ + +/****f* Component Library: Quick Composite Pool/cl_qcpool_get +* NAME +* cl_qcpool_get +* +* DESCRIPTION +* The cl_qcpool_get function retrieves an object from a +* quick composite pool. +* +* SYNOPSIS +*/ +cl_pool_item_t *cl_qcpool_get(IN cl_qcpool_t * const p_pool); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qcpool_t structure from which to retrieve +* an object. +* +* RETURN VALUES +* Returns a pointer to a cl_pool_item_t for a composite object. +* +* Returns NULL if the pool is empty and can not be grown automatically. +* +* NOTES +* cl_qcpool_get returns the object at the head of the pool. If the pool is +* empty, it is automatically grown to accommodate this request unless the +* grow_size parameter passed to the cl_qcpool_init function was zero. +* +* SEE ALSO +* Quick Composite Pool, cl_qcpool_get_tail, cl_qcpool_put, +* cl_qcpool_grow, cl_qcpool_count +*********/ + +/****f* Component Library: Quick Composite Pool/cl_qcpool_put +* NAME +* cl_qcpool_put +* +* DESCRIPTION +* The cl_qcpool_put function returns an object to a quick composite pool. +* +* SYNOPSIS +*/ +static inline void +cl_qcpool_put(IN cl_qcpool_t * const p_pool, + IN cl_pool_item_t * const p_pool_item) +{ + CL_ASSERT(p_pool); + CL_ASSERT(p_pool->state == CL_INITIALIZED); + CL_ASSERT(p_pool_item); + /* Make sure items being returned came from the specified pool. */ + CL_ASSERT(p_pool_item->p_pool == p_pool); + + /* return this lil' doggy to the pool */ + cl_qlist_insert_head(&p_pool->free_list, &p_pool_item->list_item); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qcpool_t structure to which to return +* an object. +* +* p_pool_item +* [in] Pointer to a cl_pool_item_t structure for the object +* being returned. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_qcpool_put places the returned object at the head of the pool. +* +* The object specified by the p_pool_item parameter must have been +* retrieved from the pool by a previous call to cl_qcpool_get. +* +* SEE ALSO +* Quick Composite Pool, cl_qcpool_put_tail, cl_qcpool_get +*********/ + +/****f* Component Library: Quick Composite Pool/cl_qcpool_put_list +* NAME +* cl_qcpool_put_list +* +* DESCRIPTION +* The cl_qcpool_put_list function returns a list of objects to the head of +* a quick composite pool. +* +* SYNOPSIS +*/ +static inline void +cl_qcpool_put_list(IN cl_qcpool_t * const p_pool, IN cl_qlist_t * const p_list) +{ +#ifdef _DEBUG_ + cl_list_item_t *p_item; +#endif + + CL_ASSERT(p_pool); + CL_ASSERT(p_pool->state == CL_INITIALIZED); + CL_ASSERT(p_list); + +#ifdef _DEBUG_ + /* Chech that all items in the list came from this pool. */ + p_item = cl_qlist_head(p_list); + while (p_item != cl_qlist_end(p_list)) { + CL_ASSERT(((cl_pool_item_t *) p_item)->p_pool == p_pool); + p_item = cl_qlist_next(p_item); + } +#endif + + /* return these lil' doggies to the pool */ + cl_qlist_insert_list_head(&p_pool->free_list, p_list); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qcpool_t structure to which to return +* a list of objects. +* +* p_list +* [in] Pointer to a cl_qlist_t structure for the list of objects +* being returned. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_qcpool_put_list places the returned objects at the head of the pool. +* +* The objects in the list specified by the p_list parameter must have been +* retrieved from the pool by a previous call to cl_qcpool_get. +* +* SEE ALSO +* Quick Composite Pool, cl_qcpool_put, cl_qcpool_put_tail, cl_qcpool_get +*********/ + +/****f* Component Library: Quick Composite Pool/cl_qcpool_grow +* NAME +* cl_qcpool_grow +* +* DESCRIPTION +* The cl_qcpool_grow function grows a quick composite pool by +* the specified number of objects. +* +* SYNOPSIS +*/ +cl_status_t cl_qcpool_grow(IN cl_qcpool_t * const p_pool, IN size_t obj_count); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qcpool_t structure whose capacity to grow. +* +* obj_count +* [in] Number of objects by which to grow the pool. +* +* RETURN VALUES +* CL_SUCCESS if the quick composite pool grew successfully. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to grow the +* quick composite pool. +* +* cl_status_t value returned by optional initialization callback function +* specified by the pfn_initializer parameter passed to the +* cl_qcpool_init function. +* +* NOTES +* It is not necessary to call cl_qcpool_grow if the pool is +* configured to grow automatically. +* +* SEE ALSO +* Quick Composite Pool +*********/ + +END_C_DECLS +#endif /* _CL_QUICK_COMPOSITE_POOL_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_qlist.h b/contrib/ofed/management/opensm/include/complib/cl_qlist.h new file mode 100644 index 000000000000..accbd985c316 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_qlist.h @@ -0,0 +1,1702 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of quick list. + */ + +#ifndef _CL_QUICK_LIST_H_ +#define _CL_QUICK_LIST_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Quick List +* NAME +* Quick List +* +* DESCRIPTION +* Quick list implements a doubly linked that stores user provided +* cl_list_item_t structures. +* Quick list does not allocate any memory, and can therefore not fail any +* operations. Quick list can therefore be useful in minimizing the error +* paths in code. +* +* Quick list is not thread safe, and users must provide serialization when +* adding and removing items from the list. Note that it is possible to +* walk a quick list while simultaneously adding to it. +* +* The Quick List functions operate on a cl_qlist_t structure which should be +* treated as opaque and should be manipulated only through the provided +* functions. +* +* SEE ALSO +* Structures: +* cl_qlist_t, cl_list_item_t, cl_list_obj_t +* +* Callbacks: +* cl_pfn_qlist_apply_t, cl_pfn_qlist_find_t +* +* Item Manipulation: +* cl_qlist_set_obj, cl_qlist_obj +* +* Initialization: +* cl_qlist_init +* +* Iteration: +* cl_qlist_next, cl_qlist_prev, cl_qlist_head, cl_qlist_tail, +* cl_qlist_end +* +* Manipulation: +* cl_qlist_insert_head, cl_qlist_insert_tail, +* cl_qlist_insert_list_head, cl_qlist_insert_list_tail, +* cl_qlist_insert_array_head, cl_qlist_insert_array_tail, +* cl_qlist_insert_prev, cl_qlist_insert_next, +* cl_qlist_remove_head, cl_qlist_remove_tail, +* cl_qlist_remove_item, cl_qlist_remove_all +* +* Search: +* cl_is_item_in_qlist, cl_qlist_find_next, cl_qlist_find_prev, +* cl_qlist_find_from_head, cl_qlist_find_from_tail +* cl_qlist_apply_func, cl_qlist_move_items +* +* Attributes: +* cl_qlist_count, cl_is_qlist_empty +*********/ +/****s* Component Library: Quick List/cl_list_item_t +* NAME +* cl_list_item_t +* +* DESCRIPTION +* The cl_list_item_t structure is used by lists to store objects. +* +* SYNOPSIS +*/ +typedef struct _cl_list_item { + struct _cl_list_item *p_next; + struct _cl_list_item *p_prev; +#ifdef _DEBUG_ + struct _cl_qlist *p_list; +#endif +} cl_list_item_t; +/* +* FIELDS +* p_next +* Used internally by the list. Users should not use this field. +* +* p_prev +* Used internally by the list. Users should not use this field. +* +* SEE ALSO +* Quick List +*********/ + +#define cl_item_obj(item_ptr, obj_ptr, item_field) (typeof(obj_ptr)) \ + ((void *)item_ptr - (unsigned long)&((typeof(obj_ptr))0)->item_field) + + +/****s* Component Library: Quick List/cl_list_obj_t +* NAME +* cl_list_obj_t +* +* DESCRIPTION +* The cl_list_obj_t structure is used by lists to store objects. +* +* SYNOPSIS +*/ +typedef struct _cl_list_obj { + cl_list_item_t list_item; + const void *p_object; /* User's context */ +} cl_list_obj_t; +/* +* FIELDS +* list_item +* Used internally by the list. Users should not use this field. +* +* p_object +* User defined context. Users should not access this field directly. +* Use cl_qlist_set_obj and cl_qlist_obj to set and retrieve the value +* of this field. +* +* NOTES +* Users can use the cl_qlist_set_obj and cl_qlist_obj functions to store +* and retrieve context information in the list item. +* +* SEE ALSO +* Quick List, cl_qlist_set_obj, cl_qlist_obj, cl_list_item_t +*********/ + +/****s* Component Library: Quick List/cl_qlist_t +* NAME +* cl_qlist_t +* +* DESCRIPTION +* Quick list structure. +* +* The cl_qlist_t structure should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_qlist { + cl_list_item_t end; + size_t count; + cl_state_t state; +} cl_qlist_t; +/* +* FIELDS +* end +* List item used to mark the end of the list. +* +* count +* Number of items in the list. +* +* state +* State of the quick list. +* +* SEE ALSO +* Quick List +*********/ + +/****d* Component Library: Quick List/cl_pfn_qlist_apply_t +* NAME +* cl_pfn_qlist_apply_t +* +* DESCRIPTION +* The cl_pfn_qlist_apply_t function type defines the prototype for functions +* used to iterate items in a quick list. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_qlist_apply_t) (IN cl_list_item_t * const p_list_item, + IN void *context); +/* +* PARAMETERS +* p_list_item +* [in] Pointer to a cl_list_item_t structure. +* +* context +* [in] Value passed to the callback function. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function type is provided as function prototype reference for the +* function provided by users as a parameter to the cl_qlist_apply_func +* function. +* +* SEE ALSO +* Quick List, cl_qlist_apply_func +*********/ + +/****d* Component Library: Quick List/cl_pfn_qlist_find_t +* NAME +* cl_pfn_qlist_find_t +* +* DESCRIPTION +* The cl_pfn_qlist_find_t function type defines the prototype for functions +* used to find items in a quick list. +* +* SYNOPSIS +*/ +typedef cl_status_t + (*cl_pfn_qlist_find_t) (IN const cl_list_item_t * const p_list_item, + IN void *context); +/* +* PARAMETERS +* p_list_item +* [in] Pointer to a cl_list_item_t. +* +* context +* [in] Value passed to the callback function. +* +* RETURN VALUES +* Return CL_SUCCESS if the desired item was found. This stops list iteration. +* +* Return CL_NOT_FOUND to continue list iteration. +* +* NOTES +* This function type is provided as function prototype reference for the +* function provided by users as a parameter to the cl_qlist_find_from_head, +* cl_qlist_find_from_tail, cl_qlist_find_next, and cl_qlist_find_prev +* functions. +* +* SEE ALSO +* Quick List, cl_qlist_find_from_head, cl_qlist_find_from_tail, +* cl_qlist_find_next, cl_qlist_find_prev +*********/ + +/****i* Component Library: Quick List/__cl_primitive_insert +* NAME +* __cl_primitive_insert +* +* DESCRIPTION +* Add a new item in front of the specified item. This is a low level +* function for use internally by the queuing routines. +* +* SYNOPSIS +*/ +static inline void +__cl_primitive_insert(IN cl_list_item_t * const p_list_item, + IN cl_list_item_t * const p_new_item) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list_item); + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_new_item); + + p_new_item->p_next = p_list_item; + p_new_item->p_prev = p_list_item->p_prev; + p_list_item->p_prev = p_new_item; + p_new_item->p_prev->p_next = p_new_item; +} + +/* +* PARAMETERS +* p_list_item +* [in] Pointer to cl_list_item_t to insert in front of +* +* p_new_item +* [in] Pointer to cl_list_item_t to add +* +* RETURN VALUE +* This function does not return a value. +*********/ + +/****i* Component Library: Quick List/__cl_primitive_remove +* NAME +* __cl_primitive_remove +* +* DESCRIPTION +* Remove an item from a list. This is a low level routine +* for use internally by the queuing routines. +* +* SYNOPSIS +*/ +static inline void __cl_primitive_remove(IN cl_list_item_t * const p_list_item) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list_item); + + /* set the back pointer */ + p_list_item->p_next->p_prev = p_list_item->p_prev; + /* set the next pointer */ + p_list_item->p_prev->p_next = p_list_item->p_next; + + /* if we're debugging, spruce up the pointers to help find bugs */ +#if defined( _DEBUG_ ) + if (p_list_item != p_list_item->p_next) { + p_list_item->p_next = NULL; + p_list_item->p_prev = NULL; + } +#endif /* defined( _DEBUG_ ) */ +} + +/* +* PARAMETERS +* p_list_item +* [in] Pointer to cl_list_item_t to remove +* +* RETURN VALUE +* This function does not return a value. +*********/ + +/* + * Declaration of quick list functions + */ + +/****f* Component Library: Quick List/cl_qlist_set_obj +* NAME +* cl_qlist_set_obj +* +* DESCRIPTION +* The cl_qlist_set_obj function sets the object stored in a list object. +* +* SYNOPSIS +*/ +static inline void +cl_qlist_set_obj(IN cl_list_obj_t * const p_list_obj, + IN const void *const p_object) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list_obj); + p_list_obj->p_object = p_object; +} + +/* +* PARAMETERS +* p_list_obj +* [in] Pointer to a cl_list_obj_t structure. +* +* p_object +* [in] User defined context. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Quick List, cl_qlist_obj +*********/ + +/****f* Component Library: Quick List/cl_qlist_obj +* NAME +* cl_qlist_obj +* +* DESCRIPTION +* The cl_qlist_set_obj function returns the object stored in a list object. +* +* SYNOPSIS +*/ +static inline void *cl_qlist_obj(IN const cl_list_obj_t * const p_list_obj) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list_obj); + + return ((void *)p_list_obj->p_object); +} + +/* +* PARAMETERS +* p_list_obj +* [in] Pointer to a cl_list_obj_t structure. +* +* RETURN VALUE +* Returns the value of the object pointer stored in the list object. +* +* SEE ALSO +* Quick List, cl_qlist_set_obj +*********/ + +static inline void __cl_qlist_reset(IN cl_qlist_t * const p_list) +{ + /* Point the end item to itself. */ + p_list->end.p_next = &p_list->end; + p_list->end.p_prev = &p_list->end; +#if defined( _DEBUG_ ) + p_list->end.p_list = p_list; +#endif + + /* Clear the count. */ + p_list->count = 0; +} + +/****f* Component Library: Quick List/cl_qlist_init +* NAME +* cl_qlist_init +* +* DESCRIPTION +* The cl_qlist_init function initializes a quick list. +* +* SYNOPSIS +*/ +static inline void cl_qlist_init(IN cl_qlist_t * const p_list) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + + p_list->state = CL_INITIALIZED; + + /* Reset the quick list data structure. */ + __cl_qlist_reset(p_list); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure to initialize. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* Allows calling quick list manipulation functions. +* +* SEE ALSO +* Quick List, cl_qlist_insert_head, cl_qlist_insert_tail, +* cl_qlist_remove_head, cl_qlist_remove_tail +*********/ + +/****f* Component Library: Quick List/cl_qlist_count +* NAME +* cl_qlist_count +* +* DESCRIPTION +* The cl_qlist_count function returns the number of list items stored +* in a quick list. +* +* SYNOPSIS +*/ +static inline uint32_t cl_qlist_count(IN const cl_qlist_t * const p_list) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + return ((uint32_t) p_list->count); + +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure. +* +* RETURN VALUE +* Number of items in the list. This function iterates though the quick +* list to count the items. +* +* SEE ALSO +* Quick List, cl_is_qlist_empty +*********/ + +/****f* Component Library: Quick List/cl_is_qlist_empty +* NAME +* cl_is_qlist_empty +* +* DESCRIPTION +* The cl_is_qlist_empty function returns whether a quick list is empty. +* +* SYNOPSIS +*/ +static inline boolean_t cl_is_qlist_empty(IN const cl_qlist_t * const p_list) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + + return (!cl_qlist_count(p_list)); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure. +* +* RETURN VALUES +* TRUE if the specified quick list is empty. +* +* FALSE otherwise. +* +* SEE ALSO +* Quick List, cl_qlist_count, cl_qlist_remove_all +*********/ + +/****f* Component Library: Quick List/cl_qlist_next +* NAME +* cl_qlist_next +* +* DESCRIPTION +* The cl_qlist_next function returns a pointer to the list item following +* a given list item in a quick list. +* +* SYNOPSIS +*/ +static inline cl_list_item_t *cl_qlist_next(IN const cl_list_item_t * + const p_list_item) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list_item); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list_item->p_list->state == CL_INITIALIZED); + + /* Return the next item. */ + return (p_list_item->p_next); +} + +/* +* PARAMETERS +* p_list_item +* [in] Pointer to the cl_list_item_t whose successor to return. +* +* Returns: +* Pointer to the list item following the list item specified by +* the p_list_item parameter in the quick list. +* +* Pointer to the list end if p_list_item was at the tail of the list. +* +* SEE ALSO +* Quick List, cl_qlist_head, cl_qlist_tail, cl_qlist_prev, cl_qlist_end, +* cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_prev +* NAME +* cl_qlist_prev +* +* DESCRIPTION +* The cl_qlist_prev function returns a poirter to the list item preceding +* a given list item in a quick list. +* +* SYNOPSIS +*/ +static inline cl_list_item_t *cl_qlist_prev(IN const cl_list_item_t * + const p_list_item) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list_item); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list_item->p_list->state == CL_INITIALIZED); + + /* Return the previous item. */ + return (p_list_item->p_prev); +} + +/* +* PARAMETERS +* p_list_item +* [in] Pointer to the cl_list_item_t whose predecessor to return. +* +* Returns: +* Pointer to the list item preceding the list item specified by +* the p_list_item parameter in the quick list. +* +* Pointer to the list end if p_list_item was at the tail of the list. +* +* SEE ALSO +* Quick List, cl_qlist_head, cl_qlist_tail, cl_qlist_next, cl_qlist_end, +* cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_head +* NAME +* cl_qlist_head +* +* DESCRIPTION +* The cl_qlist_head function returns the list item at +* the head of a quick list. +* +* SYNOPSIS +*/ +static inline cl_list_item_t *cl_qlist_head(IN const cl_qlist_t * const p_list) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + + return (cl_qlist_next(&p_list->end)); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure. +* +* RETURN VALUES +* Pointer to the list item at the head of the quick list. +* +* Pointer to the list end if the list was empty. +* +* NOTES +* cl_qlist_head does not remove the item from the list. +* +* SEE ALSO +* Quick List, cl_qlist_tail, cl_qlist_next, cl_qlist_prev, cl_qlist_end, +* cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_tail +* NAME +* cl_qlist_tail +* +* DESCRIPTION +* The cl_qlist_tail function returns the list item at +* the tail of a quick list. +* +* SYNOPSIS +*/ +static inline cl_list_item_t *cl_qlist_tail(IN const cl_qlist_t * const p_list) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + + return (cl_qlist_prev(&p_list->end)); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure. +* +* RETURN VALUES +* Pointer to the list item at the tail of the quick list. +* +* Pointer to the list end if the list was empty. +* +* NOTES +* cl_qlist_tail does not remove the item from the list. +* +* SEE ALSO +* Quick List, cl_qlist_head, cl_qlist_next, cl_qlist_prev, cl_qlist_end, +* cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_end +* NAME +* cl_qlist_end +* +* DESCRIPTION +* The cl_qlist_end function returns the end of a quick list. +* +* SYNOPSIS +*/ +static inline const cl_list_item_t *cl_qlist_end(IN const cl_qlist_t * + const p_list) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + + return (&p_list->end); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure. +* +* RETURN VALUE +* Pointer to the end of the list. +* +* NOTES +* cl_qlist_end is useful for determining the validity of list items returned +* by cl_qlist_head, cl_qlist_tail, cl_qlist_next, cl_qlist_prev, as well as +* the cl_qlist_find functions. If the list item pointer returned by any of +* these functions compares to the end, the end of the list was encoutered. +* When using cl_qlist_head or cl_qlist_tail, this condition indicates that +* the list is empty. +* +* SEE ALSO +* Quick List, cl_qlist_head, cl_qlist_tail, cl_qlist_next, cl_qlist_prev, +* cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_insert_head +* NAME +* cl_qlist_insert_head +* +* DESCRIPTION +* The cl_qlist_insert_head function inserts a list item at the +* head of a quick list. +* +* SYNOPSIS +*/ +static inline void +cl_qlist_insert_head(IN cl_qlist_t * const p_list, + IN cl_list_item_t * const p_list_item) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list_item); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + + /* + * The list item must not already be part of the list. Note that this + * assertion may fail if an uninitialized list item happens to have its + * list pointer equal to the specified list. The chances of this + * happening are acceptable in light of the value of this check. + */ + CL_ASSERT(p_list_item->p_list != p_list); + +#if defined( _DEBUG_ ) + p_list_item->p_list = p_list; +#endif + + /* Insert before the head. */ + __cl_primitive_insert(cl_qlist_head(p_list), p_list_item); + + p_list->count++; +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure into which to insert the object. +* +* p_list_item +* [in] Pointer to a cl_list_item_t structure to add. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* In debug builds, cl_qlist_insert_head asserts that the specified list item +* is not already in the list. +* +* SEE ALSO +* Quick List, cl_qlist_insert_tail, cl_qlist_insert_list_head, +* cl_qlist_insert_list_tail, cl_qlist_insert_array_head, +* cl_qlist_insert_array_tail, cl_qlist_insert_prev, cl_qlist_insert_next, +* cl_qlist_remove_head, cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_insert_tail +* NAME +* cl_qlist_insert_tail +* +* DESCRIPTION +* The cl_qlist_insert_tail function inserts a list item at the tail +* of a quick list. +* +* SYNOPSIS +*/ +static inline void +cl_qlist_insert_tail(IN cl_qlist_t * const p_list, + IN cl_list_item_t * const p_list_item) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list_item); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + + /* + * The list item must not already be part of the list. Note that this + * assertion may fail if an uninitialized list item happens to have its + * list pointer equal to the specified list. The chances of this + * happening are acceptable in light of the value of this check. + */ + CL_ASSERT(p_list_item->p_list != p_list); + +#if defined( _DEBUG_ ) + p_list_item->p_list = p_list; +#endif + + /* + * Put the new element in front of the end which is the same + * as being at the tail + */ + __cl_primitive_insert(&p_list->end, p_list_item); + + p_list->count++; +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure into which to insert the object. +* +* p_list_item +* [in] Pointer to cl_list_item_t structure to add. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* In debug builds, cl_qlist_insert_tail asserts that the specified list item +* is not already in the list. +* +* SEE ALSO +* Quick List, cl_qlist_insert_head, cl_qlist_insert_list_head, +* cl_qlist_insert_list_tail, cl_qlist_insert_array_head, +* cl_qlist_insert_array_tail, cl_qlist_insert_prev, cl_qlist_insert_next, +* cl_qlist_remove_tail, cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_insert_list_head +* NAME +* cl_qlist_insert_list_head +* +* DESCRIPTION +* The cl_qlist_insert_list_head function merges two quick lists by +* inserting one at the head of the other. +* +* SYNOPSIS +*/ +void +cl_qlist_insert_list_head(IN cl_qlist_t * const p_dest_list, + IN cl_qlist_t * const p_src_list); +/* +* PARAMETERS +* p_dest_list +* [in] Pointer to destination quicklist object. +* +* p_src_list +* [in] Pointer to quicklist to add. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Inserts all list items in the source list to the head of the +* destination list. The ordering of the list items is preserved. +* +* The list pointed to by the p_src_list parameter is empty when +* the call returns. +* +* SEE ALSO +* Quick List, cl_qlist_insert_list_tail, cl_qlist_insert_head, +* cl_qlist_insert_tail, cl_qlist_insert_array_head, +* cl_qlist_insert_array_tail, cl_qlist_insert_prev, cl_qlist_insert_next, +* cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_insert_list_tail +* NAME +* cl_qlist_insert_list_tail +* +* DESCRIPTION +* The cl_qlist_insert_list_tail function merges two quick lists by +* inserting one at the tail of the other. +* +* SYNOPSIS +*/ +void +cl_qlist_insert_list_tail(IN cl_qlist_t * const p_dest_list, + IN cl_qlist_t * const p_src_list); +/* +* PARAMETERS +* p_dest_list +* [in] Pointer to destination quicklist object +* +* p_src_list +* [in] Pointer to quicklist to add +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Inserts all list items in the source list to the tail of the +* destination list. The ordering of the list items is preserved. +* +* The list pointed to by the p_src_list parameter is empty when +* the call returns. +* +* SEE ALSO +* Quick List, cl_qlist_insert_list_head, cl_qlist_insert_head, +* cl_qlist_insert_tail, cl_qlist_insert_array_head, +* cl_qlist_insert_array_tail, cl_qlist_insert_prev, cl_qlist_insert_next, +* cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_insert_array_head +* NAME +* cl_qlist_insert_array_head +* +* DESCRIPTION +* The cl_qlist_insert_array_head function inserts an array of list items +* at the head of a quick list. +* +* SYNOPSIS +*/ +void +cl_qlist_insert_array_head(IN cl_qlist_t * const p_list, + IN cl_list_item_t * const p_array, + IN uint32_t item_count, IN const uint32_t item_size); +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure into which to insert +* the objects. +* +* p_array +* [in] Pointer to the first list item in an array of cl_list_item_t +* structures. +* +* item_count +* [in] Number of cl_list_item_t structures in the array. +* +* item_size +* [in] Size of the items added to the list. This is the stride in the +* array from one cl_list_item_t structure to the next. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Inserts all the list items in the array specified by the p_array parameter +* to the head of the quick list specified by the p_list parameter, +* preserving ordering of the list items. +* +* The array pointer passed into the function points to the cl_list_item_t +* in the first element of the caller's element array. There is no +* restriction on where the element is stored in the parent structure. +* +* SEE ALSO +* Quick List, cl_qlist_insert_array_tail, cl_qlist_insert_head, +* cl_qlist_insert_tail, cl_qlist_insert_list_head, cl_qlist_insert_list_tail, +* cl_qlist_insert_prev, cl_qlist_insert_next, cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_insert_array_tail +* NAME +* cl_qlist_insert_array_tail +* +* DESCRIPTION +* The cl_qlist_insert_array_tail function inserts an array of list items +* at the tail of a quick list. +* +* SYNOPSIS +*/ +void +cl_qlist_insert_array_tail(IN cl_qlist_t * const p_list, + IN cl_list_item_t * const p_array, + IN uint32_t item_count, IN const uint32_t item_size); +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure into which to insert +* the objects. +* +* p_array +* [in] Pointer to the first list item in an array of cl_list_item_t +* structures. +* +* item_count +* [in] Number of cl_list_item_t structures in the array. +* +* item_size +* [in] Size of the items added to the list. This is the stride in the +* array from one cl_list_item_t structure to the next. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Inserts all the list items in the array specified by the p_array parameter +* to the tail of the quick list specified by the p_list parameter, +* preserving ordering of the list items. +* +* The array pointer passed into the function points to the cl_list_item_t +* in the first element of the caller's element array. There is no +* restriction on where the element is stored in the parent structure. +* +* SEE ALSO +* Quick List, cl_qlist_insert_array_head, cl_qlist_insert_head, +* cl_qlist_insert_tail, cl_qlist_insert_list_head, cl_qlist_insert_list_tail, +* cl_qlist_insert_prev, cl_qlist_insert_next, cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_insert_prev +* NAME +* cl_qlist_insert_prev +* +* DESCRIPTION +* The cl_qlist_insert_prev function inserts a list item before a +* specified list item in a quick list. +* +* SYNOPSIS +*/ +static inline void +cl_qlist_insert_prev(IN cl_qlist_t * const p_list, + IN cl_list_item_t * const p_list_item, + IN cl_list_item_t * const p_new_item) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list_item); + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_new_item); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + + /* + * The list item must not already be part of the list. Note that this + * assertion may fail if an uninitialized list item happens to have its + * list pointer equal to the specified list. The chances of this + * happening are acceptable in light of the value of this check. + */ + CL_ASSERT(p_new_item->p_list != p_list); + +#if defined( _DEBUG_ ) + p_new_item->p_list = p_list; +#endif + + __cl_primitive_insert(p_list_item, p_new_item); + + p_list->count++; +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure into which to add the new item. +* +* p_list_item +* [in] Pointer to a cl_list_item_t structure. +* +* p_new_item +* [in] Pointer to a cl_list_item_t structure to add to the quick list. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Inserts the new list item before the list item specified by p_list_item. +* +* SEE ALSO +* Quick List, cl_qlist_insert_next, cl_qlist_insert_head, +* cl_qlist_insert_tail, cl_qlist_insert_list_head, cl_qlist_insert_list_tail, +* cl_qlist_insert_array_head, cl_qlist_insert_array_tail, cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_insert_next +* NAME +* cl_qlist_insert_next +* +* DESCRIPTION +* The cl_qlist_insert_next function inserts a list item after a specified +* list item in a quick list. +* +* SYNOPSIS +*/ +static inline void +cl_qlist_insert_next(IN cl_qlist_t * const p_list, + IN cl_list_item_t * const p_list_item, + IN cl_list_item_t * const p_new_item) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list_item); + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_new_item); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + + /* + * The list item must not already be part of the list. Note that this + * assertion may fail if an uninitialized list item happens to have its + * list pointer equal to the specified list. The chances of this + * happening are acceptable in light of the value of this check. + */ + CL_ASSERT(p_new_item->p_list != p_list); + +#if defined( _DEBUG_ ) + p_new_item->p_list = p_list; +#endif + + __cl_primitive_insert(cl_qlist_next(p_list_item), p_new_item); + + p_list->count++; +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure into which to add the new item. +* +* p_list_item +* [in] Pointer to a cl_list_item_t structure. +* +* p_new_item +* [in] Pointer to a cl_list_item_t structure to add to the quick list. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Inserts the new list item after the list item specified by p_list_item. +* The list item specified by p_list_item must be in the quick list. +* +* SEE ALSO +* Quick List, cl_qlist_insert_prev, cl_qlist_insert_head, +* cl_qlist_insert_tail, cl_qlist_insert_list_head, cl_qlist_insert_list_tail, +* cl_qlist_insert_array_head, cl_qlist_insert_array_tail, cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_remove_head +* NAME +* cl_qlist_remove_head +* +* DESCRIPTION +* The cl_qlist_remove_head function removes and returns the list item +* at the head of a quick list. +* +* SYNOPSIS +*/ +static inline cl_list_item_t *cl_qlist_remove_head(IN cl_qlist_t * const p_list) +{ + cl_list_item_t *p_item; + + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + + p_item = cl_qlist_head(p_list); + /* CL_ASSERT that the list item is part of the list. */ + CL_ASSERT(p_item->p_list == p_list); + + if (p_item == cl_qlist_end(p_list)) + return (p_item); + +#if defined( _DEBUG_ ) + /* Clear the item's link to the list. */ + p_item->p_list = NULL; +#endif + + __cl_primitive_remove(p_item); + + p_list->count--; + + return (p_item); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure. +* +* RETURN VALUES +* Returns a pointer to the list item formerly at the head of the quick list. +* +* Pointer to the list end if the list was empty. +* +* SEE ALSO +* Quick List, cl_qlist_remove_tail, cl_qlist_remove_all, cl_qlist_remove_item, +* cl_qlist_end, cl_qlist_head, cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_remove_tail +* NAME +* cl_qlist_remove_tail +* +* DESCRIPTION +* The cl_qlist_remove_tail function removes and returns the list item +* at the tail of a quick list. +* +* SYNOPSIS +*/ +static inline cl_list_item_t *cl_qlist_remove_tail(IN cl_qlist_t * const p_list) +{ + cl_list_item_t *p_item; + + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + + p_item = cl_qlist_tail(p_list); + /* CL_ASSERT that the list item is part of the list. */ + CL_ASSERT(p_item->p_list == p_list); + + if (p_item == cl_qlist_end(p_list)) + return (p_item); + +#if defined( _DEBUG_ ) + /* Clear the item's link to the list. */ + p_item->p_list = NULL; +#endif + + __cl_primitive_remove(p_item); + + p_list->count--; + + return (p_item); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure. +* +* RETURN VALUES +* Returns a pointer to the list item formerly at the tail of the quick list. +* +* Pointer to the list end if the list was empty. +* +* SEE ALSO +* Quick List, cl_qlist_remove_head, cl_qlist_remove_all, cl_qlist_remove_item, +* cl_qlist_end, cl_qlist_tail, cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_remove_item +* NAME +* cl_qlist_remove_item +* +* DESCRIPTION +* The cl_qlist_remove_item function removes a specific list item from a quick list. +* +* SYNOPSIS +*/ +static inline void +cl_qlist_remove_item(IN cl_qlist_t * const p_list, + IN cl_list_item_t * const p_list_item) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list_item); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + /* CL_ASSERT that the list item is part of the list. */ + CL_ASSERT(p_list_item->p_list == p_list); + + if (p_list_item == cl_qlist_end(p_list)) + return; + +#if defined( _DEBUG_ ) + /* Clear the item's link to the list. */ + p_list_item->p_list = NULL; +#endif + + __cl_primitive_remove(p_list_item); + + p_list->count--; +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure from which to remove the item. +* +* p_list_item +* [in] Pointer to a cl_list_item_t structure to remove. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Removes the list item pointed to by the p_list_item parameter from +* its list. +* +* SEE ALSO +* Quick List, cl_qlist_remove_head, cl_qlist_remove_tail, cl_qlist_remove_all, +* cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_remove_all +* NAME +* cl_qlist_remove_all +* +* DESCRIPTION +* The cl_qlist_remove_all function removes all items from a quick list. +* +* SYNOPSIS +*/ +static inline void cl_qlist_remove_all(IN cl_qlist_t * const p_list) +{ +#if defined( _DEBUG_ ) + cl_list_item_t *p_list_item; + + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + p_list_item = cl_qlist_head(p_list); + while (p_list_item != cl_qlist_end(p_list)) { + p_list_item = cl_qlist_next(p_list_item); + cl_qlist_prev(p_list_item)->p_list = NULL; + } +#endif + + __cl_qlist_reset(p_list); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Quick List, cl_qlist_remove_head, cl_qlist_remove_tail, +* cl_qlist_remove_item, cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_is_item_in_qlist +* NAME +* cl_is_item_in_qlist +* +* DESCRIPTION +* The cl_is_item_in_qlist function checks for the presence of a +* list item in a quick list. +* +* SYNOPSIS +*/ +boolean_t +cl_is_item_in_qlist(IN const cl_qlist_t * const p_list, + IN const cl_list_item_t * const p_list_item); +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure. +* +* p_list_item +* [in] Pointer to the cl_list_item_t to find. +* +* RETURN VALUES +* TRUE if the list item was found in the quick list. +* +* FALSE otherwise. +* +* SEE ALSO +* Quick List, cl_qlist_remove_item, cl_list_item_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_find_next +* NAME +* cl_qlist_find_next +* +* DESCRIPTION +* The cl_qlist_find_next function invokes a specified function to +* search for an item, starting from a given list item. +* +* SYNOPSIS +*/ +cl_list_item_t *cl_qlist_find_next(IN const cl_qlist_t * const p_list, + IN const cl_list_item_t * const p_list_item, + IN cl_pfn_qlist_find_t pfn_func, + IN const void *const context); +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure in which to search. +* +* p_list_item +* [in] Pointer to a cl_list_item_t structure from which to start the search. +* +* pfn_func +* [in] Function invoked to determine if a match was found. +* See the cl_pfn_qlist_find_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context if a +* callback function is provided, or value compared to the quick list's +* list items. +* +* Returns: +* Pointer to the list item, if found. +* +* p_list_item if not found. +* +* NOTES +* cl_qlist_find_next does not remove list items from the list. +* The list item is returned when the function specified by the pfn_func +* parameter returns CL_SUCCESS. The list item from which the search starts is +* excluded from the search. +* +* The function provided by the pfn_func must not perform any list operations, +* as these would corrupt the list. +* +* SEE ALSO +* Quick List, cl_qlist_find_prev, cl_qlist_find_from_head, +* cl_qlist_find_from_tail, cl_qlist_end, cl_qlist_apply_func, +* cl_qlist_move_items, cl_list_item_t, cl_pfn_qlist_find_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_find_prev +* NAME +* cl_qlist_find_prev +* +* DESCRIPTION +* The cl_qlist_find_prev function invokes a specified function to +* search backward for an item, starting from a given list item. +* +* SYNOPSIS +*/ +cl_list_item_t *cl_qlist_find_prev(IN const cl_qlist_t * const p_list, + IN const cl_list_item_t * const p_list_item, + IN cl_pfn_qlist_find_t pfn_func, + IN const void *const context); +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure in which to search. +* +* p_list_item +* [in] Pointer to a cl_list_item_t structure from which to start the search. +* +* pfn_func +* [in] Function invoked to determine if a match was found. +* See the cl_pfn_qlist_find_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context if a +* callback function is provided, or value compared to the quick list's +* list items. +* +* Returns: +* Pointer to the list item, if found. +* +* p_list_item if not found. +* +* NOTES +* cl_qlist_find_prev does not remove list items from the list. +* The list item is returned when the function specified by the pfn_func +* parameter returns CL_SUCCESS. The list item from which the search starts is +* excluded from the search. +* +* The function provided by the pfn_func must not perform any list operations, +* as these would corrupt the list. +* +* SEE ALSO +* Quick List, cl_qlist_find_next, cl_qlist_find_from_head, +* cl_qlist_find_from_tail, cl_qlist_end, cl_qlist_apply_func, +* cl_qlist_move_items, cl_list_item_t, cl_pfn_qlist_find_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_find_from_head +* NAME +* cl_qlist_find_from_head +* +* DESCRIPTION +* The cl_qlist_find_from_head function invokes a specified function to +* search for an item, starting at the head of a quick list. +* +* SYNOPSIS +*/ +static inline cl_list_item_t *cl_qlist_find_from_head(IN const cl_qlist_t * + const p_list, + IN cl_pfn_qlist_find_t + pfn_func, + IN const void *const + context) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + /* CL_ASSERT that a find function is provided. */ + CL_ASSERT(pfn_func); + + return (cl_qlist_find_next(p_list, cl_qlist_end(p_list), pfn_func, + context)); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure. +* +* pfn_func +* [in] Function invoked to determine if a match was found. +* See the cl_pfn_qlist_find_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context if a +* callback function is provided, or value compared to the quick list's +* list items. +* +* Returns: +* Pointer to the list item, if found. +* +* Pointer to the list end otherwise +* +* NOTES +* cl_qlist_find_from_head does not remove list items from the list. +* The list item is returned when the function specified by the pfn_func +* parameter returns CL_SUCCESS. +* +* The function provided by the pfn_func parameter must not perform any list +* operations, as these would corrupt the list. +* +* SEE ALSO +* Quick List, cl_qlist_find_from_tail, cl_qlist_find_next, cl_qlist_find_prev, +* cl_qlist_end, cl_qlist_apply_func, cl_qlist_move_items, cl_list_item_t, +* cl_pfn_qlist_find_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_find_from_tail +* NAME +* cl_qlist_find_from_tail +* +* DESCRIPTION +* The cl_qlist_find_from_tail function invokes a specified function to +* search for an item, starting at the tail of a quick list. +* +* SYNOPSIS +*/ +static inline cl_list_item_t *cl_qlist_find_from_tail(IN const cl_qlist_t * + const p_list, + IN cl_pfn_qlist_find_t + pfn_func, + IN const void *const + context) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_list); + /* CL_ASSERT that the list was initialized. */ + CL_ASSERT(p_list->state == CL_INITIALIZED); + /* CL_ASSERT that a find function is provided. */ + CL_ASSERT(pfn_func); + + return (cl_qlist_find_prev(p_list, cl_qlist_end(p_list), pfn_func, + context)); +} + +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure. +* +* pfn_func +* [in] Function invoked to determine if a match was found. +* See the cl_pfn_qlist_find_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context if a +* callback function is provided, or value compared to the quick list's +* list items. +* +* Returns: +* Pointer to the list item, if found. +* +* Pointer to the list end otherwise +* +* NOTES +* cl_qlist_find_from_tail does not remove list items from the list. +* The list item is returned when the function specified by the pfn_func +* parameter returns CL_SUCCESS. +* +* The function provided by the pfn_func parameter must not perform any list +* operations, as these would corrupt the list. +* +* SEE ALSO +* Quick List, cl_qlist_find_from_head, cl_qlist_find_next, cl_qlist_find_prev, +* cl_qlist_apply_func, cl_qlist_end, cl_qlist_move_items, cl_list_item_t, +* cl_pfn_qlist_find_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_apply_func +* NAME +* cl_qlist_apply_func +* +* DESCRIPTION +* The cl_qlist_apply_func function executes a specified function +* for every list item stored in a quick list. +* +* SYNOPSIS +*/ +void +cl_qlist_apply_func(IN const cl_qlist_t * const p_list, + IN cl_pfn_qlist_apply_t pfn_func, + IN const void *const context); +/* +* PARAMETERS +* p_list +* [in] Pointer to a cl_qlist_t structure. +* +* pfn_func +* [in] Function invoked for every item in the quick list. +* See the cl_pfn_qlist_apply_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* The function provided must not perform any list operations, as these +* would corrupt the quick list. +* +* SEE ALSO +* Quick List, cl_qlist_find_from_head, cl_qlist_find_from_tail, +* cl_qlist_move_items, cl_pfn_qlist_apply_t +*********/ + +/****f* Component Library: Quick List/cl_qlist_move_items +* NAME +* cl_qlist_move_items +* +* DESCRIPTION +* The cl_qlist_move_items function moves list items from one list to +* another based on the return value of a user supplied function. +* +* SYNOPSIS +*/ +void +cl_qlist_move_items(IN cl_qlist_t * const p_src_list, + IN cl_qlist_t * const p_dest_list, + IN cl_pfn_qlist_find_t pfn_func, + IN const void *const context); +/* +* PARAMETERS +* p_src_list +* [in] Pointer to a cl_qlist_t structure from which +* list items are removed. +* +* p_dest_list +* [in] Pointer to a cl_qlist_t structure to which the source +* list items are added. +* +* pfn_func +* [in] Function invoked to determine if a match was found. +* See the cl_pfn_qlist_find_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* If the function specified by the pfn_func parameter returns CL_SUCCESS, +* the related list item is removed from p_src_list and inserted at the tail +* of the p_dest_list. +* +* The cl_qlist_move_items function continues iterating through p_src_list +* from the last item moved, allowing multiple items to be located and moved +* in a single list iteration. +* +* The function specified by pfn_func must not perform any list operations, +* as these would corrupt the list. +* +* SEE ALSO +* Quick List, cl_qlist_find_from_head, cl_qlist_find_from_tail, +* cl_qlist_apply_func, cl_pfn_qlist_find_t +*********/ + +END_C_DECLS +#endif /* _CL_QUICK_LIST_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_qmap.h b/contrib/ofed/management/opensm/include/complib/cl_qmap.h new file mode 100644 index 000000000000..130c2efcac4c --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_qmap.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of quick map, a binary tree where the caller always provides + * all necessary storage. + */ + +#ifndef _CL_QMAP_H_ +#define _CL_QMAP_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Quick Map +* NAME +* Quick Map +* +* DESCRIPTION +* Quick map implements a binary tree that stores user provided cl_map_item_t +* structures. Each item stored in a quick map has a unique 64-bit key +* (duplicates are not allowed). Quick map provides the ability to +* efficiently search for an item given a key. +* +* Quick map does not allocate any memory, and can therefore not fail +* any operations due to insufficient memory. Quick map can thus be useful +* in minimizing the error paths in code. +* +* Quick map is not thread safe, and users must provide serialization when +* adding and removing items from the map. +* +* The quick map functions operate on a cl_qmap_t structure which should be +* treated as opaque and should be manipulated only through the provided +* functions. +* +* SEE ALSO +* Structures: +* cl_qmap_t, cl_map_item_t, cl_map_obj_t +* +* Callbacks: +* cl_pfn_qmap_apply_t +* +* Item Manipulation: +* cl_qmap_set_obj, cl_qmap_obj, cl_qmap_key +* +* Initialization: +* cl_qmap_init +* +* Iteration: +* cl_qmap_end, cl_qmap_head, cl_qmap_tail, cl_qmap_next, cl_qmap_prev +* +* Manipulation: +* cl_qmap_insert, cl_qmap_get, cl_qmap_remove_item, cl_qmap_remove, +* cl_qmap_remove_all, cl_qmap_merge, cl_qmap_delta, cl_qmap_get_next +* +* Search: +* cl_qmap_apply_func +* +* Attributes: +* cl_qmap_count, cl_is_qmap_empty, +*********/ +/****i* Component Library: Quick Map/cl_map_color_t +* NAME +* cl_map_color_t +* +* DESCRIPTION +* The cl_map_color_t enumerated type is used to note the color of +* nodes in a map. +* +* SYNOPSIS +*/ +typedef enum _cl_map_color { + CL_MAP_RED, + CL_MAP_BLACK +} cl_map_color_t; +/* +* VALUES +* CL_MAP_RED +* The node in the map is red. +* +* CL_MAP_BLACK +* The node in the map is black. +* +* SEE ALSO +* Quick Map, cl_map_item_t +*********/ + +/****s* Component Library: Quick Map/cl_map_item_t +* NAME +* cl_map_item_t +* +* DESCRIPTION +* The cl_map_item_t structure is used by maps to store objects. +* +* The cl_map_item_t structure should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_map_item { + /* Must be first to allow casting. */ + cl_pool_item_t pool_item; + struct _cl_map_item *p_left; + struct _cl_map_item *p_right; + struct _cl_map_item *p_up; + cl_map_color_t color; + uint64_t key; +#ifdef _DEBUG_ + struct _cl_qmap *p_map; +#endif +} cl_map_item_t; +/* +* FIELDS +* pool_item +* Used to store the item in a doubly linked list, allowing more +* efficient map traversal. +* +* p_left +* Pointer to the map item that is a child to the left of the node. +* +* p_right +* Pointer to the map item that is a child to the right of the node. +* +* p_up +* Pointer to the map item that is the parent of the node. +* +* p_nil +* Pointer to the map's NIL item, used as a terminator for leaves. +* The NIL sentinel is in the cl_qmap_t structure. +* +* color +* Indicates whether a node is red or black in the map. +* +* key +* Value that uniquely represents a node in a map. This value is +* set by calling cl_qmap_insert and can be retrieved by calling +* cl_qmap_key. +* +* NOTES +* None of the fields of this structure should be manipulated by users, as +* they are crititcal to the proper operation of the map in which they +* are stored. +* +* To allow storing items in either a quick list, a quick pool, or a quick +* map, the map implementation guarantees that the map item can be safely +* cast to a pool item used for storing an object in a quick pool, or cast +* to a list item used for storing an object in a quick list. This removes +* the need to embed a map item, a list item, and a pool item in objects +* that need to be stored in a quick list, a quick pool, and a quick map. +* +* SEE ALSO +* Quick Map, cl_qmap_insert, cl_qmap_key, cl_pool_item_t, cl_list_item_t +*********/ + +/****s* Component Library: Quick Map/cl_map_obj_t +* NAME +* cl_map_obj_t +* +* DESCRIPTION +* The cl_map_obj_t structure is used to store objects in maps. +* +* The cl_map_obj_t structure should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_map_obj { + cl_map_item_t item; + const void *p_object; +} cl_map_obj_t; +/* +* FIELDS +* item +* Map item used by internally by the map to store an object. +* +* p_object +* User defined context. Users should not access this field directly. +* Use cl_qmap_set_obj and cl_qmap_obj to set and retrieve the value +* of this field. +* +* NOTES +* None of the fields of this structure should be manipulated by users, as +* they are crititcal to the proper operation of the map in which they +* are stored. +* +* Use cl_qmap_set_obj and cl_qmap_obj to set and retrieve the object +* stored in a map item, respectively. +* +* SEE ALSO +* Quick Map, cl_qmap_set_obj, cl_qmap_obj, cl_map_item_t +*********/ + +/****s* Component Library: Quick Map/cl_qmap_t +* NAME +* cl_qmap_t +* +* DESCRIPTION +* Quick map structure. +* +* The cl_qmap_t structure should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_qmap { + cl_map_item_t root; + cl_map_item_t nil; + cl_state_t state; + size_t count; +} cl_qmap_t; +/* +* PARAMETERS +* root +* Map item that serves as root of the map. The root is set up to +* always have itself as parent. The left pointer is set to point +* to the item at the root. +* +* nil +* Map item that serves as terminator for all leaves, as well as +* providing the list item used as quick list for storing map items +* in a list for faster traversal. +* +* state +* State of the map, used to verify that operations are permitted. +* +* count +* Number of items in the map. +* +* SEE ALSO +* Quick Map +*********/ + +/****d* Component Library: Quick Map/cl_pfn_qmap_apply_t +* NAME +* cl_pfn_qmap_apply_t +* +* DESCRIPTION +* The cl_pfn_qmap_apply_t function type defines the prototype for +* functions used to iterate items in a quick map. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_qmap_apply_t) (IN cl_map_item_t * const p_map_item, IN void *context); +/* +* PARAMETERS +* p_map_item +* [in] Pointer to a cl_map_item_t structure. +* +* context +* [in] Value passed to the callback function. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function type is provided as function prototype reference for the +* function provided by users as a parameter to the cl_qmap_apply_func +* function. +* +* SEE ALSO +* Quick Map, cl_qmap_apply_func +*********/ + +/****f* Component Library: Quick Map/cl_qmap_count +* NAME +* cl_qmap_count +* +* DESCRIPTION +* The cl_qmap_count function returns the number of items stored +* in a quick map. +* +* SYNOPSIS +*/ +static inline uint32_t cl_qmap_count(IN const cl_qmap_t * const p_map) +{ + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + return ((uint32_t) p_map->count); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_qmap_t structure whose item count to return. +* +* RETURN VALUE +* Returns the number of items stored in the map. +* +* SEE ALSO +* Quick Map, cl_is_qmap_empty +*********/ + +/****f* Component Library: Quick Map/cl_is_qmap_empty +* NAME +* cl_is_qmap_empty +* +* DESCRIPTION +* The cl_is_qmap_empty function returns whether a quick map is empty. +* +* SYNOPSIS +*/ +static inline boolean_t cl_is_qmap_empty(IN const cl_qmap_t * const p_map) +{ + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + + return (p_map->count == 0); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_qmap_t structure to test for emptiness. +* +* RETURN VALUES +* TRUE if the quick map is empty. +* +* FALSE otherwise. +* +* SEE ALSO +* Quick Map, cl_qmap_count, cl_qmap_remove_all +*********/ + +/****f* Component Library: Quick Map/cl_qmap_set_obj +* NAME +* cl_qmap_set_obj +* +* DESCRIPTION +* The cl_qmap_set_obj function sets the object stored in a map object. +* +* SYNOPSIS +*/ +static inline void +cl_qmap_set_obj(IN cl_map_obj_t * const p_map_obj, + IN const void *const p_object) +{ + CL_ASSERT(p_map_obj); + p_map_obj->p_object = p_object; +} + +/* +* PARAMETERS +* p_map_obj +* [in] Pointer to a map object stucture whose object pointer +* is to be set. +* +* p_object +* [in] User defined context. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Quick Map, cl_qmap_obj +*********/ + +/****f* Component Library: Quick Map/cl_qmap_obj +* NAME +* cl_qmap_obj +* +* DESCRIPTION +* The cl_qmap_obj function returns the object stored in a map object. +* +* SYNOPSIS +*/ +static inline void *cl_qmap_obj(IN const cl_map_obj_t * const p_map_obj) +{ + CL_ASSERT(p_map_obj); + return ((void *)p_map_obj->p_object); +} + +/* +* PARAMETERS +* p_map_obj +* [in] Pointer to a map object stucture whose object pointer to return. +* +* RETURN VALUE +* Returns the value of the object pointer stored in the map object. +* +* SEE ALSO +* Quick Map, cl_qmap_set_obj +*********/ + +/****f* Component Library: Quick Map/cl_qmap_key +* NAME +* cl_qmap_key +* +* DESCRIPTION +* The cl_qmap_key function retrieves the key value of a map item. +* +* SYNOPSIS +*/ +static inline uint64_t cl_qmap_key(IN const cl_map_item_t * const p_item) +{ + CL_ASSERT(p_item); + return (p_item->key); +} + +/* +* PARAMETERS +* p_item +* [in] Pointer to a map item whose key value to return. +* +* RETURN VALUE +* Returns the 64-bit key value for the specified map item. +* +* NOTES +* The key value is set in a call to cl_qmap_insert. +* +* SEE ALSO +* Quick Map, cl_qmap_insert +*********/ + +/****f* Component Library: Quick Map/cl_qmap_init +* NAME +* cl_qmap_init +* +* DESCRIPTION +* The cl_qmap_init function initialized a quick map for use. +* +* SYNOPSIS +*/ +void cl_qmap_init(IN cl_qmap_t * const p_map); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_qmap_t structure to initialize. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* Allows calling quick map manipulation functions. +* +* SEE ALSO +* Quick Map, cl_qmap_insert, cl_qmap_remove +*********/ + +/****f* Component Library: Quick Map/cl_qmap_end +* NAME +* cl_qmap_end +* +* DESCRIPTION +* The cl_qmap_end function returns the end of a quick map. +* +* SYNOPSIS +*/ +static inline const cl_map_item_t *cl_qmap_end(IN const cl_qmap_t * const p_map) +{ + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + /* Nil is the end of the map. */ + return (&p_map->nil); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_qmap_t structure whose end to return. +* +* RETURN VALUE +* Pointer to the end of the map. +* +* NOTES +* cl_qmap_end is useful for determining the validity of map items returned +* by cl_qmap_head, cl_qmap_tail, cl_qmap_next, or cl_qmap_prev. If the +* map item pointer returned by any of these functions compares to the end, +* the end of the map was encoutered. +* When using cl_qmap_head or cl_qmap_tail, this condition indicates that +* the map is empty. +* +* SEE ALSO +* Quick Map, cl_qmap_head, cl_qmap_tail, cl_qmap_next, cl_qmap_prev +*********/ + +/****f* Component Library: Quick Map/cl_qmap_head +* NAME +* cl_qmap_head +* +* DESCRIPTION +* The cl_qmap_head function returns the map item with the lowest key +* value stored in a quick map. +* +* SYNOPSIS +*/ +static inline cl_map_item_t *cl_qmap_head(IN const cl_qmap_t * const p_map) +{ + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + return ((cl_map_item_t *) p_map->nil.pool_item.list_item.p_next); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_qmap_t structure whose item with the lowest +* key is returned. +* +* RETURN VALUES +* Pointer to the map item with the lowest key in the quick map. +* +* Pointer to the map end if the quick map was empty. +* +* NOTES +* cl_qmap_head does not remove the item from the map. +* +* SEE ALSO +* Quick Map, cl_qmap_tail, cl_qmap_next, cl_qmap_prev, cl_qmap_end, +* cl_qmap_item_t +*********/ + +/****f* Component Library: Quick Map/cl_qmap_tail +* NAME +* cl_qmap_tail +* +* DESCRIPTION +* The cl_qmap_tail function returns the map item with the highest key +* value stored in a quick map. +* +* SYNOPSIS +*/ +static inline cl_map_item_t *cl_qmap_tail(IN const cl_qmap_t * const p_map) +{ + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + return ((cl_map_item_t *) p_map->nil.pool_item.list_item.p_prev); +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_qmap_t structure whose item with the +* highest key is returned. +* +* RETURN VALUES +* Pointer to the map item with the highest key in the quick map. +* +* Pointer to the map end if the quick map was empty. +* +* NOTES +* cl_qmap_end does not remove the item from the map. +* +* SEE ALSO +* Quick Map, cl_qmap_head, cl_qmap_next, cl_qmap_prev, cl_qmap_end, +* cl_qmap_item_t +*********/ + +/****f* Component Library: Quick Map/cl_qmap_next +* NAME +* cl_qmap_next +* +* DESCRIPTION +* The cl_qmap_next function returns the map item with the next higher +* key value than a specified map item. +* +* SYNOPSIS +*/ +static inline cl_map_item_t *cl_qmap_next(IN const cl_map_item_t * const p_item) +{ + CL_ASSERT(p_item); + return ((cl_map_item_t *) p_item->pool_item.list_item.p_next); +} + +/* +* PARAMETERS +* p_item +* [in] Pointer to a map item whose successor to return. +* +* RETURN VALUES +* Pointer to the map item with the next higher key value in a quick map. +* +* Pointer to the map end if the specified item was the last item in +* the quick map. +* +* SEE ALSO +* Quick Map, cl_qmap_head, cl_qmap_tail, cl_qmap_prev, cl_qmap_end, +* cl_map_item_t +*********/ + +/****f* Component Library: Quick Map/cl_qmap_prev +* NAME +* cl_qmap_prev +* +* DESCRIPTION +* The cl_qmap_prev function returns the map item with the next lower +* key value than a precified map item. +* +* SYNOPSIS +*/ +static inline cl_map_item_t *cl_qmap_prev(IN const cl_map_item_t * const p_item) +{ + CL_ASSERT(p_item); + return ((cl_map_item_t *) p_item->pool_item.list_item.p_prev); +} + +/* +* PARAMETERS +* p_item +* [in] Pointer to a map item whose predecessor to return. +* +* RETURN VALUES +* Pointer to the map item with the next lower key value in a quick map. +* +* Pointer to the map end if the specifid item was the first item in +* the quick map. +* +* SEE ALSO +* Quick Map, cl_qmap_head, cl_qmap_tail, cl_qmap_next, cl_qmap_end, +* cl_map_item_t +*********/ + +/****f* Component Library: Quick Map/cl_qmap_insert +* NAME +* cl_qmap_insert +* +* DESCRIPTION +* The cl_qmap_insert function inserts a map item into a quick map. +* NOTE: Only if such a key does not alerady exist in the map !!!! +* +* SYNOPSIS +*/ +cl_map_item_t *cl_qmap_insert(IN cl_qmap_t * const p_map, + IN const uint64_t key, + IN cl_map_item_t * const p_item); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_qmap_t structure into which to add the item. +* +* key +* [in] Value to assign to the item. +* +* p_item +* [in] Pointer to a cl_map_item_t stucture to insert into the quick map. +* +* RETURN VALUE +* Pointer to the item in the map with the specified key. If insertion +* was successful, this is the pointer to the item. If an item with the +* specified key already exists in the map, the pointer to that item is +* returned - but the new key is NOT inserted... +* +* NOTES +* Insertion operations may cause the quick map to rebalance. +* +* SEE ALSO +* Quick Map, cl_qmap_remove, cl_map_item_t +*********/ + +/****f* Component Library: Quick Map/cl_qmap_get +* NAME +* cl_qmap_get +* +* DESCRIPTION +* The cl_qmap_get function returns the map item associated with a key. +* +* SYNOPSIS +*/ +cl_map_item_t *cl_qmap_get(IN const cl_qmap_t * const p_map, + IN const uint64_t key); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_qmap_t structure from which to retrieve the +* item with the specified key. +* +* key +* [in] Key value used to search for the desired map item. +* +* RETURN VALUES +* Pointer to the map item with the desired key value. +* +* Pointer to the map end if there was no item with the desired key value +* stored in the quick map. +* +* NOTES +* cl_qmap_get does not remove the item from the quick map. +* +* SEE ALSO +* Quick Map, cl_qmap_get_next, cl_qmap_remove +*********/ + +/****f* Component Library: Quick Map/cl_qmap_get_next +* NAME +* cl_qmap_get_next +* +* DESCRIPTION +* The cl_qmap_get_next function returns the first map item associated with a +* key > the key specified. +* +* SYNOPSIS +*/ +cl_map_item_t *cl_qmap_get_next(IN const cl_qmap_t * const p_map, + IN const uint64_t key); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_qmap_t structure from which to retrieve the +* first item with a key > the specified key. +* +* key +* [in] Key value used to search for the desired map item. +* +* RETURN VALUES +* Pointer to the first map item with a key > the desired key value. +* +* Pointer to the map end if there was no item with a key > the desired key +* value stored in the quick map. +* +* NOTES +* cl_qmap_get_next does not remove the item from the quick map. +* +* SEE ALSO +* Quick Map, cl_qmap_get, cl_qmap_remove +*********/ + +/****f* Component Library: Quick Map/cl_qmap_remove_item +* NAME +* cl_qmap_remove_item +* +* DESCRIPTION +* The cl_qmap_remove_item function removes the specified map item +* from a quick map. +* +* SYNOPSIS +*/ +void +cl_qmap_remove_item(IN cl_qmap_t * const p_map, + IN cl_map_item_t * const p_item); +/* +* PARAMETERS +* p_item +* [in] Pointer to a map item to remove from its quick map. +* +* RETURN VALUES +* This function does not return a value. +* +* In a debug build, cl_qmap_remove_item asserts that the item being removed +* is in the specified map. +* +* NOTES +* Removes the map item pointed to by p_item from its quick map. +* +* SEE ALSO +* Quick Map, cl_qmap_remove, cl_qmap_remove_all, cl_qmap_insert +*********/ + +/****f* Component Library: Quick Map/cl_qmap_remove +* NAME +* cl_qmap_remove +* +* DESCRIPTION +* The cl_qmap_remove function removes the map item with the specified key +* from a quick map. +* +* SYNOPSIS +*/ +cl_map_item_t *cl_qmap_remove(IN cl_qmap_t * const p_map, + IN const uint64_t key); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_qmap_t structure from which to remove the item +* with the specified key. +* +* key +* [in] Key value used to search for the map item to remove. +* +* RETURN VALUES +* Pointer to the removed map item if it was found. +* +* Pointer to the map end if no item with the specified key exists in the +* quick map. +* +* SEE ALSO +* Quick Map, cl_qmap_remove_item, cl_qmap_remove_all, cl_qmap_insert +*********/ + +/****f* Component Library: Quick Map/cl_qmap_remove_all +* NAME +* cl_qmap_remove_all +* +* DESCRIPTION +* The cl_qmap_remove_all function removes all items in a quick map, +* leaving it empty. +* +* SYNOPSIS +*/ +static inline void cl_qmap_remove_all(IN cl_qmap_t * const p_map) +{ + CL_ASSERT(p_map); + CL_ASSERT(p_map->state == CL_INITIALIZED); + + p_map->root.p_left = &p_map->nil; + p_map->nil.pool_item.list_item.p_next = &p_map->nil.pool_item.list_item; + p_map->nil.pool_item.list_item.p_prev = &p_map->nil.pool_item.list_item; + p_map->count = 0; +} + +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_qmap_t structure to empty. +* +* RETURN VALUES +* This function does not return a value. +* +* SEE ALSO +* Quick Map, cl_qmap_remove, cl_qmap_remove_item +*********/ + +/****f* Component Library: Quick Map/cl_qmap_merge +* NAME +* cl_qmap_merge +* +* DESCRIPTION +* The cl_qmap_merge function moves all items from one map to another, +* excluding duplicates. +* +* SYNOPSIS +*/ +void +cl_qmap_merge(OUT cl_qmap_t * const p_dest_map, + IN OUT cl_qmap_t * const p_src_map); +/* +* PARAMETERS +* p_dest_map +* [out] Pointer to a cl_qmap_t structure to which items should be added. +* +* p_src_map +* [in/out] Pointer to a cl_qmap_t structure whose items to add +* to p_dest_map. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* Items are evaluated based on their keys only. +* +* Upon return from cl_qmap_merge, the quick map referenced by p_src_map +* contains all duplicate items. +* +* SEE ALSO +* Quick Map, cl_qmap_delta +*********/ + +/****f* Component Library: Quick Map/cl_qmap_delta +* NAME +* cl_qmap_delta +* +* DESCRIPTION +* The cl_qmap_delta function computes the differences between two maps. +* +* SYNOPSIS +*/ +void +cl_qmap_delta(IN OUT cl_qmap_t * const p_map1, + IN OUT cl_qmap_t * const p_map2, + OUT cl_qmap_t * const p_new, OUT cl_qmap_t * const p_old); +/* +* PARAMETERS +* p_map1 +* [in/out] Pointer to the first of two cl_qmap_t structures whose +* differences to compute. +* +* p_map2 +* [in/out] Pointer to the second of two cl_qmap_t structures whose +* differences to compute. +* +* p_new +* [out] Pointer to an empty cl_qmap_t structure that contains the +* items unique to p_map2 upon return from the function. +* +* p_old +* [out] Pointer to an empty cl_qmap_t structure that contains the +* items unique to p_map1 upon return from the function. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* Items are evaluated based on their keys. Items that exist in both +* p_map1 and p_map2 remain in their respective maps. Items that +* exist only p_map1 are moved to p_old. Likewise, items that exist only +* in p_map2 are moved to p_new. This function can be useful in evaluating +* changes between two maps. +* +* Both maps pointed to by p_new and p_old must be empty on input. This +* requirement removes the possibility of failures. +* +* SEE ALSO +* Quick Map, cl_qmap_merge +*********/ + +/****f* Component Library: Quick Map/cl_qmap_apply_func +* NAME +* cl_qmap_apply_func +* +* DESCRIPTION +* The cl_qmap_apply_func function executes a specified function +* for every item stored in a quick map. +* +* SYNOPSIS +*/ +void +cl_qmap_apply_func(IN const cl_qmap_t * const p_map, + IN cl_pfn_qmap_apply_t pfn_func, + IN const void *const context); +/* +* PARAMETERS +* p_map +* [in] Pointer to a cl_qmap_t structure. +* +* pfn_func +* [in] Function invoked for every item in the quick map. +* See the cl_pfn_qmap_apply_t function type declaration for +* details about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* The function provided must not perform any map operations, as these +* would corrupt the quick map. +* +* SEE ALSO +* Quick Map, cl_pfn_qmap_apply_t +*********/ + +END_C_DECLS +#endif /* _CL_QMAP_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_qpool.h b/contrib/ofed/management/opensm/include/complib/cl_qpool.h new file mode 100644 index 000000000000..f144cb3524ac --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_qpool.h @@ -0,0 +1,606 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of the quick pool. + * The quick pool manages a pool of objects. + * The pool can grow to meet demand, limited only by system memory. + */ + +#ifndef _CL_QUICK_POOL_H_ +#define _CL_QUICK_POOL_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Quick Pool +* NAME +* Quick Pool +* +* DESCRIPTION +* The quick pool provides a self-contained and self-sustaining pool +* of user defined objects. +* +* To aid in object oriented design, the quick pool provides the user +* the ability to specify callbacks that are invoked for each object for +* construction, initialization, and destruction. Constructor and destructor +* callback functions may not fail. +* +* A quick pool does not return memory to the system as the user returns +* objects to the pool. The only method of returning memory to the system is +* to destroy the pool. +* +* The quick pool operates on cl_pool_item_t structures that describe +* objects. This can provides for more efficient memory use and operation. +* If using a cl_pool_item_t is not desired, the Pool provides similar +* functionality but operates on opaque objects. +* +* The quick pool functions operates on a cl_qpool_t structure which should +* be treated as opaque and should be manipulated only through the provided +* functions. +* +* SEE ALSO +* Structures: +* cl_qpool_t, cl_pool_item_t +* +* Callbacks: +* cl_pfn_qpool_init_t, cl_pfn_qpool_dtor_t +* +* Initialization/Destruction: +* cl_qpool_construct, cl_qpool_init, cl_qpool_destroy +* +* Manipulation: +* cl_qpool_get, cl_qpool_put, cl_qpool_put_list, cl_qpool_grow +* +* Attributes: +* cl_is_qpool_inited, cl_qpool_count +*********/ +/****d* Component Library: Quick Pool/cl_pfn_qpool_init_t +* NAME +* cl_pfn_qpool_init_t +* +* DESCRIPTION +* The cl_pfn_qpool_init_t function type defines the prototype for +* functions used as constructor for objects being allocated by a +* quick pool. +* +* SYNOPSIS +*/ +typedef cl_status_t + (*cl_pfn_qpool_init_t) (IN void *const p_object, + IN void *context, + OUT cl_pool_item_t ** const pp_pool_item); +/* +* PARAMETERS +* p_object +* [in] Pointer to an object to initialize. +* +* context +* [in] Context provided in a call to cl_qpool_init. +* +* RETURN VALUES +* Return CL_SUCCESS to indicate that initialization of the object +* was successful and that initialization of further objects may continue. +* +* Other cl_status_t values will be returned by cl_qcpool_init +* and cl_qcpool_grow. +* +* NOTES +* This function type is provided as function prototype reference for +* the function provided by the user as an optional parameter to the +* cl_qpool_init function. +* +* The initializer is invoked once per allocated object, allowing the user +* to perform any necessary initialization. Returning a status other than +* CL_SUCCESS aborts a grow operation, initiated either through cl_qcpool_init +* or cl_qcpool_grow, causing the initiating function to fail. +* Any non-CL_SUCCESS status will be returned by the function that initiated +* the grow operation. +* +* All memory for the object is pre-allocated. Users should include space in +* their objects for the cl_pool_item_t structure that will represent the +* object to avoid having to allocate that structure in the initialization +* callback. +* +* When later performing a cl_qcpool_get call, the return value is a pointer +* to the cl_pool_item_t returned by this function in the pp_pool_item +* parameter. Users must set pp_pool_item to a valid pointer to the +* cl_pool_item_t representing the object if they return CL_SUCCESS. +* +* SEE ALSO +* Quick Pool, cl_qpool_init +*********/ + +/****d* Component Library: Quick Pool/cl_pfn_qpool_dtor_t +* NAME +* cl_pfn_qpool_dtor_t +* +* DESCRIPTION +* The cl_pfn_qpool_dtor_t function type defines the prototype for +* functions used as destructor for objects being deallocated by a +* quick pool. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_qpool_dtor_t) (IN const cl_pool_item_t * const p_pool_item, + IN void *context); +/* +* PARAMETERS +* p_pool_item +* [in] Pointer to a cl_pool_item_t structure representing an object. +* +* context +* [in] Context provided in a call to cl_qpool_init. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function type is provided as function prototype reference for +* the function provided by the user as an optional parameter to the +* cl_qpool_init function. +* +* The destructor is invoked once per allocated object, allowing the user +* to perform any necessary cleanup. Users should not attempt to deallocate +* the memory for the object, as the quick pool manages object +* allocation and deallocation. +* +* SEE ALSO +* Quick Pool, cl_qpool_init +*********/ + +/****s* Component Library: Quick Pool/cl_qpool_t +* NAME +* cl_qpool_t +* +* DESCRIPTION +* Quick pool structure. +* +* The cl_qpool_t structure should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_qpool { + cl_qcpool_t qcpool; + cl_pfn_qpool_init_t pfn_init; + cl_pfn_qpool_dtor_t pfn_dtor; + const void *context; +} cl_qpool_t; +/* +* FIELDS +* qcpool +* Quick composite pool that manages all objects. +* +* pfn_init +* Pointer to the user's initializer callback, used by the pool +* to translate the quick composite pool's initializer callback to +* a quick pool initializer callback. +* +* pfn_dtor +* Pointer to the user's destructor callback, used by the pool +* to translate the quick composite pool's destructor callback to +* a quick pool destructor callback. +* +* context +* User's provided context for callback functions, used by the pool +* to when invoking callbacks. +* +* SEE ALSO +* Quick Pool +*********/ + +/****f* Component Library: Quick Pool/cl_qpool_construct +* NAME +* cl_qpool_construct +* +* DESCRIPTION +* The cl_qpool_construct function constructs a quick pool. +* +* SYNOPSIS +*/ +void cl_qpool_construct(IN cl_qpool_t * const p_pool); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qpool_t structure whose state to initialize. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_qpool_init, cl_qpool_destroy, cl_is_qpool_inited. +* +* Calling cl_qpool_construct is a prerequisite to calling any other +* quick pool function except cl_pool_init. +* +* SEE ALSO +* Quick Pool, cl_qpool_init, cl_qpool_destroy, cl_is_qpool_inited. +*********/ + +/****f* Component Library: Quick Pool/cl_is_qpool_inited +* NAME +* cl_is_qpool_inited +* +* DESCRIPTION +* The cl_is_qpool_inited function returns whether a quick pool was +* successfully initialized. +* +* SYNOPSIS +*/ +static inline uint32_t cl_is_qpool_inited(IN const cl_qpool_t * const p_pool) +{ + /* CL_ASSERT that a non-null pointer is provided. */ + CL_ASSERT(p_pool); + return (cl_is_qcpool_inited(&p_pool->qcpool)); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qpool_t structure whose initialization state +* to check. +* +* RETURN VALUES +* TRUE if the quick pool was initialized successfully. +* +* FALSE otherwise. +* +* NOTES +* Allows checking the state of a quick pool to determine if +* invoking member functions is appropriate. +* +* SEE ALSO +* Quick Pool +*********/ + +/****f* Component Library: Quick Pool/cl_qpool_init +* NAME +* cl_qpool_init +* +* DESCRIPTION +* The cl_qpool_init function initializes a quick pool for use. +* +* SYNOPSIS +*/ +cl_status_t +cl_qpool_init(IN cl_qpool_t * const p_pool, + IN const size_t min_size, + IN const size_t max_size, + IN const size_t grow_size, + IN const size_t object_size, + IN cl_pfn_qpool_init_t pfn_initializer OPTIONAL, + IN cl_pfn_qpool_dtor_t pfn_destructor OPTIONAL, + IN const void *const context); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qpool_t structure to initialize. +* +* min_size +* [in] Minimum number of objects that the pool should support. All +* necessary allocations to allow storing the minimum number of items +* are performed at initialization time, and all necessary callbacks +* successfully invoked. +* +* max_size +* [in] Maximum number of objects to which the pool is allowed to grow. +* A value of zero specifies no maximum. +* +* grow_size +* [in] Number of objects to allocate when incrementally growing the pool. +* A value of zero disables automatic growth. +* +* object_size +* [in] Size, in bytes, of each object. +* +* pfn_initializer +* [in] Initialization callback to invoke for every new object when +* growing the pool. This parameter is optional and may be NULL. If NULL, +* the pool assumes the cl_pool_item_t structure describing objects is +* located at the head of each object. See the cl_pfn_qpool_init_t +* function type declaration for details about the callback function. +* +* pfn_destructor +* [in] Destructor callback to invoke for every object before memory for +* that object is freed. This parameter is optional and may be NULL. +* See the cl_pfn_qpool_dtor_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context. +* +* RETURN VALUES +* CL_SUCCESS if the quick pool was initialized successfully. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to initialize the +* quick pool. +* +* CL_INVALID_SETTING if a the maximum size is non-zero and less than the +* minimum size. +* +* Other cl_status_t value returned by optional initialization callback function +* specified by the pfn_initializer parameter. +* +* NOTES +* cl_qpool_init initializes, and if necessary, grows the pool to +* the capacity desired. +* +* SEE ALSO +* Quick Pool, cl_qpool_construct, cl_qpool_destroy, +* cl_qpool_get, cl_qpool_put, cl_qpool_grow, +* cl_qpool_count, cl_pfn_qpool_init_t, cl_pfn_qpool_init_t, +* cl_pfn_qpool_dtor_t +*********/ + +/****f* Component Library: Quick Pool/cl_qpool_destroy +* NAME +* cl_qpool_destroy +* +* DESCRIPTION +* The cl_qpool_destroy function destroys a quick pool. +* +* SYNOPSIS +*/ +static inline void cl_qpool_destroy(IN cl_qpool_t * const p_pool) +{ + CL_ASSERT(p_pool); + cl_qcpool_destroy(&p_pool->qcpool); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qpool_t structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* All memory allocated for objects is freed. The destructor callback, +* if any, will be invoked for every allocated object. Further operations +* on the pool should not be attempted after cl_qpool_destroy +* is invoked. +* +* This function should only be called after a call to +* cl_qpool_construct or cl_qpool_init. +* +* In a debug build, cl_qpool_destroy asserts that all objects are in +* the pool. +* +* SEE ALSO +* Quick Pool, cl_qpool_construct, cl_qpool_init +*********/ + +/****f* Component Library: Quick Pool/cl_qpool_count +* NAME +* cl_qpool_count +* +* DESCRIPTION +* The cl_qpool_count function returns the number of available objects +* in a quick pool. +* +* SYNOPSIS +*/ +static inline size_t cl_qpool_count(IN cl_qpool_t * const p_pool) +{ + CL_ASSERT(p_pool); + return (cl_qcpool_count(&p_pool->qcpool)); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qpool_t structure for which the number of +* available objects is requested. +* +* RETURN VALUE +* Returns the number of objects available in the specified quick pool. +* +* SEE ALSO +* Quick Pool +*********/ + +/****f* Component Library: Quick Pool/cl_qpool_get +* NAME +* cl_qpool_get +* +* DESCRIPTION +* The cl_qpool_get function retrieves an object from a +* quick pool. +* +* SYNOPSIS +*/ +static inline cl_pool_item_t *cl_qpool_get(IN cl_qpool_t * const p_pool) +{ + CL_ASSERT(p_pool); + return (cl_qcpool_get(&p_pool->qcpool)); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qpool_t structure from which to retrieve +* an object. +* +* RETURN VALUES +* Returns a pointer to a cl_pool_item_t for an object. +* +* Returns NULL if the pool is empty and can not be grown automatically. +* +* NOTES +* cl_qpool_get returns the object at the head of the pool. If the pool is +* empty, it is automatically grown to accommodate this request unless the +* grow_size parameter passed to the cl_qpool_init function was zero. +* +* SEE ALSO +* Quick Pool, cl_qpool_get_tail, cl_qpool_put, cl_qpool_grow, cl_qpool_count +*********/ + +/****f* Component Library: Quick Pool/cl_qpool_put +* NAME +* cl_qpool_put +* +* DESCRIPTION +* The cl_qpool_put function returns an object to the head of a quick pool. +* +* SYNOPSIS +*/ +static inline void +cl_qpool_put(IN cl_qpool_t * const p_pool, + IN cl_pool_item_t * const p_pool_item) +{ + CL_ASSERT(p_pool); + cl_qcpool_put(&p_pool->qcpool, p_pool_item); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qpool_t structure to which to return +* an object. +* +* p_pool_item +* [in] Pointer to a cl_pool_item_t structure for the object +* being returned. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_qpool_put places the returned object at the head of the pool. +* +* The object specified by the p_pool_item parameter must have been +* retrieved from the pool by a previous call to cl_qpool_get. +* +* SEE ALSO +* Quick Pool, cl_qpool_put_tail, cl_qpool_get +*********/ + +/****f* Component Library: Quick Pool/cl_qpool_put_list +* NAME +* cl_qpool_put_list +* +* DESCRIPTION +* The cl_qpool_put_list function returns a list of objects to the head +* of a quick pool. +* +* SYNOPSIS +*/ +static inline void +cl_qpool_put_list(IN cl_qpool_t * const p_pool, IN cl_qlist_t * const p_list) +{ + CL_ASSERT(p_pool); + cl_qcpool_put_list(&p_pool->qcpool, p_list); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qpool_t structure to which to return +* a list of objects. +* +* p_list +* [in] Pointer to a cl_qlist_t structure for the list of objects +* being returned. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_qpool_put_list places the returned objects at the head of the pool. +* +* The objects in the list specified by the p_list parameter must have been +* retrieved from the pool by a previous call to cl_qpool_get. +* +* SEE ALSO +* Quick Pool, cl_qpool_put, cl_qpool_put_tail, cl_qpool_get +*********/ + +/****f* Component Library: Quick Pool/cl_qpool_grow +* NAME +* cl_qpool_grow +* +* DESCRIPTION +* The cl_qpool_grow function grows a quick pool by +* the specified number of objects. +* +* SYNOPSIS +*/ +static inline cl_status_t +cl_qpool_grow(IN cl_qpool_t * const p_pool, IN const size_t obj_count) +{ + CL_ASSERT(p_pool); + return (cl_qcpool_grow(&p_pool->qcpool, obj_count)); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to a cl_qpool_t structure whose capacity to grow. +* +* obj_count +* [in] Number of objects by which to grow the pool. +* +* RETURN VALUES +* CL_SUCCESS if the quick pool grew successfully. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to grow the +* quick pool. +* +* cl_status_t value returned by optional initialization callback function +* specified by the pfn_initializer parameter passed to the +* cl_qpool_init function. +* +* NOTES +* It is not necessary to call cl_qpool_grow if the pool is +* configured to grow automatically. +* +* SEE ALSO +* Quick Pool +*********/ + +END_C_DECLS +#endif /* _CL_QUICK_POOL_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_spinlock.h b/contrib/ofed/management/opensm/include/complib/cl_spinlock.h new file mode 100644 index 000000000000..1a04b56797b5 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_spinlock.h @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of spin lock object. + */ + +#ifndef _CL_SPINLOCK_H_ +#define _CL_SPINLOCK_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Public/Spinlock +* NAME +* Spinlock +* +* DESCRIPTION +* Spinlock provides synchronization between threads for exclusive access to +* a resource. +* +* The spinlock functions manipulate a cl_spinlock_t structure which should +* be treated as opaque and should be manipulated only through the provided +* functions. +* +* SEE ALSO +* Structures: +* cl_spinlock_t +* +* Initialization: +* cl_spinlock_construct, cl_spinlock_init, cl_spinlock_destroy +* +* Manipulation +* cl_spinlock_acquire, cl_spinlock_release +* cl_spinlock_acquire_irq, cl_spinlock_release_irq +*********/ +/****f* Component Library: Spinlock/cl_spinlock_construct +* NAME +* cl_spinlock_construct +* +* DESCRIPTION +* The cl_spinlock_construct function initializes the state of a +* spin lock. +* +* SYNOPSIS +*/ +void cl_spinlock_construct(IN cl_spinlock_t * const p_spinlock); +/* +* PARAMETERS +* p_spin_lock +* [in] Pointer to a spin lock structure whose state to initialize. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_spinlock_destroy without first calling +* cl_spinlock_init. +* +* Calling cl_spinlock_construct is a prerequisite to calling any other +* spin lock function except cl_spinlock_init. +* +* SEE ALSO +* Spinlock, cl_spinlock_init, cl_spinlock_destroy +*********/ + +/****f* Component Library: Spinlock/cl_spinlock_init +* NAME +* cl_spinlock_init +* +* DESCRIPTION +* The cl_spinlock_init function initializes a spin lock for use. +* +* SYNOPSIS +*/ +cl_status_t cl_spinlock_init(IN cl_spinlock_t * const p_spinlock); +/* +* PARAMETERS +* p_spin_lock +* [in] Pointer to a spin lock structure to initialize. +* +* RETURN VALUES +* CL_SUCCESS if initialization succeeded. +* +* CL_ERROR if initialization failed. Callers should call +* cl_spinlock_destroy to clean up any resources allocated during +* initialization. +* +* NOTES +* Initialize the spin lock structure. Allows calling cl_spinlock_aquire +* and cl_spinlock_release. +* +* SEE ALSO +* Spinlock, cl_spinlock_construct, cl_spinlock_destroy, +* cl_spinlock_acquire, cl_spinlock_acquire_irq, +* cl_spinlock_release, cl_spinlock_release +* cl_spinlock_release_irq, cl_spinlock_release_irq +*********/ + +/****f* Component Library: Spinlock/cl_spinlock_destroy +* NAME +* cl_spinlock_destroy +* +* DESCRIPTION +* The cl_spinlock_destroy function performs all necessary cleanup of a +* spin lock. +* +* SYNOPSIS +*/ +void cl_spinlock_destroy(IN cl_spinlock_t * const p_spinlock); +/* +* PARAMETERS +* p_spin_lock +* [in] Pointer to a spin lock structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of a spin lock. This function must only +* be called if either cl_spinlock_construct or cl_spinlock_init has been +* called. +* +* SEE ALSO +* Spinlock, cl_spinlock_construct, cl_spinlock_init +*********/ + +/****f* Component Library: Spinlock/cl_spinlock_acquire +* NAME +* cl_spinlock_acquire +* +* DESCRIPTION +* The cl_spinlock_acquire function acquires a spin lock. +* This version of lock does not prevent an interrupt from +* occuring on the processor on which the code is being +* executed. To protect from an interrupt level resource +* use the cl_spinlock_acquire_irq function. +* +* SYNOPSIS +*/ +void cl_spinlock_acquire(IN cl_spinlock_t * const p_spinlock); +/* +* PARAMETERS +* p_spin_lock +* [in] Pointer to a spin lock structure to acquire. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Spinlock, cl_spinlock_acquire_irq, cl_spinlock_release +* cl_spinlock_release_irq +*********/ + +/****f* Component Library: Spinlock/cl_spinlock_acquire_irq +* NAME +* cl_spinlock_acquire_irq +* +* DESCRIPTION +* The cl_spinlock_acquire_irq function acquires a spin lock and protects +* the current processor from taking interrupts. If you need to protect +* a variable from an interrupt resource, use this version to acquire +* a lock. +* +* SYNOPSIS +*/ +void cl_spinlock_acquire_irq(IN cl_spinlock_t * const p_spinlock); +/* +* PARAMETERS +* p_spin_lock +* [in] Pointer to a spin lock structure to acquire. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Spinlock, cl_spinlock_release_irq +*********/ + +/****f* Component Library: Spinlock/cl_spinlock_release +* NAME +* cl_spinlock_release +* +* DESCRIPTION +* The cl_spinlock_release function releases a spin lock object. +* +* SYNOPSIS +*/ +void cl_spinlock_release(IN cl_spinlock_t * const p_spinlock); +/* +* PARAMETERS +* p_spin_lock +* [in] Pointer to a spin lock structure to release. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Releases a spin lock after a call to cl_spinlock_acquire. +* +* SEE ALSO +* Spinlock, cl_spinlock_acquire +*********/ + +/****f* Component Library: Spinlock/cl_spinlock_release_irq +* NAME +* cl_spinlock_release_irq +* +* DESCRIPTION +* The cl_spinlock_release_irq function releases a spin lock object. +* +* SYNOPSIS +*/ +void cl_spinlock_release_irq(IN cl_spinlock_t * const p_spinlock); +/* +* PARAMETERS +* p_spin_lock +* [in] Pointer to a spin lock structure to release. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Releases a spin lock after a call to cl_spinlock_acquire. +* +* SEE ALSO +* Spinlock, cl_spinlock_acquire_irq +*********/ + +END_C_DECLS +#endif /* _CL_SPINLOCK_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_spinlock_osd.h b/contrib/ofed/management/opensm/include/complib/cl_spinlock_osd.h new file mode 100644 index 000000000000..beb64057e030 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_spinlock_osd.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of spin lock object. + */ + +#ifndef _CL_SPINLOCK_OSD_H_ +#define _CL_SPINLOCK_OSD_H_ + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#include +#include /* usr/include/ */ +typedef struct _cl_spinlock_t { + pthread_mutex_t mutex; + cl_state_t state; +} cl_spinlock_t; + +END_C_DECLS +#endif /* _CL_SPINLOCK_OSD_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_thread.h b/contrib/ofed/management/opensm/include/complib/cl_thread.h new file mode 100644 index 000000000000..0a622a1abffa --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_thread.h @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of thread abstraction and thread related operations. + */ + +#ifndef _CL_THREAD_H_ +#define _CL_THREAD_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****i* Component Library/Thread +* NAME +* Thread +* +* DESCRIPTION +* The Thread provides a separate thread of execution. +* +* The cl_thread_t structure should be treated as opaque and should be +* manipulated only through the provided functions. +*********/ +/****d* Component Library: Thread/cl_pfn_thread_callback_t +* NAME +* cl_pfn_thread_callback_t +* +* DESCRIPTION +* The cl_pfn_thread_callback_t function type defines the prototype +* for functions invoked by thread objects +* +* SYNOPSIS +*/ +typedef void (*cl_pfn_thread_callback_t) (IN void *context); +/* +* PARAMETERS +* context +* [in] Value specified in a call to cl_thread_init. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function type is provided as function prototype reference for +* the function provided by users as a parameter to cl_thread_init. +* +* SEE ALSO +* Thread Pool +*********/ + +/****i* Component Library: Thread/cl_thread_t +* NAME +* cl_thread_t +* +* DESCRIPTION +* Thread structure. +* +* The cl_thread_t structure should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_thread { + cl_thread_osd_t osd; + cl_pfn_thread_callback_t pfn_callback; + const void *context; + char name[16]; +} cl_thread_t; +/* +* FIELDS +* osd +* Implementation specific structure for managing thread information. +* +* pfn_callback +* Callback function for the thread to invoke. +* +* context +* Context to pass to the thread callback function. +* +* name +* Name to assign to the thread. +* +* SEE ALSO +* Thread +*********/ + +/****i* Component Library: Thread/cl_thread_construct +* NAME +* cl_thread_construct +* +* DESCRIPTION +* The cl_thread_construct function initializes the state of a thread. +* +* SYNOPSIS +*/ +void cl_thread_construct(IN cl_thread_t * const p_thread); +/* +* PARAMETERS +* p_thread +* [in] Pointer to a cl_thread_t structure whose state to initialize. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_thread_destroy without first calling cl_thread_init. +* +* Calling cl_thread_construct is a prerequisite to calling any other +* thread function except cl_thread_init. +* +* SEE ALSO +* Thread, cl_thread_init, cl_thread_destroy +*********/ + +/****i* Component Library: Thread/cl_thread_init +* NAME +* cl_thread_init +* +* DESCRIPTION +* The cl_thread_init function creates a new thread of execution. +* +* SYNOPSIS +*/ +cl_status_t +cl_thread_init(IN cl_thread_t * const p_thread, + IN cl_pfn_thread_callback_t pfn_callback, + IN const void *const context, IN const char *const name); +/* +* PARAMETERS +* p_thread +* [in] Pointer to a cl_thread_t structure to initialize. +* +* pfn_callback +* [in] Address of a function to be invoked by a thread. +* See the cl_pfn_thread_callback_t function type definition for +* details about the callback function. +* +* context +* [in] Value to pass to the callback function. +* +* name +* [in] Name to associate with the thread. The name may be up to 16 +* characters, including a terminating null character. +* +* RETURN VALUES +* CL_SUCCESS if thread creation succeeded. +* +* CL_ERROR if thread creation failed. +* +* NOTES +* The thread created with cl_thread_init will invoke the callback +* specified by the callback parameter with context as single parameter. +* +* The callback function is invoked once, and the thread exits when the +* callback returns. +* +* It is invalid to call cl_thread_destroy from the callback function, +* as doing so will result in a deadlock. +* +* SEE ALSO +* Thread, cl_thread_construct, cl_thread_destroy, cl_thread_suspend, +* cl_thread_stall, cl_pfn_thread_callback_t +*********/ + +/****i* Component Library: Thread/cl_thread_destroy +* NAME +* cl_thread_destroy +* +* DESCRIPTION +* The cl_thread_destroy function performs any necessary cleanup to free +* resources associated with the specified thread. +* +* SYNOPSIS +*/ +void cl_thread_destroy(IN cl_thread_t * const p_thread); +/* +* PARAMETERS +* p_thread +* [in] Pointer to a cl_thread_t structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function blocks until the thread exits and must not be called by the +* thread itself. Callers must therefore ensure that such a blocking call is +* possible from the context of the call. +* +* This function must only be called after a call to cl_thread_construct or +* cl_thread_init. +* +* SEE ALSO +* Thread, cl_thread_construct, cl_thread_init +*********/ + +/****f* Component Library: Thread/cl_thread_suspend +* NAME +* cl_thread_suspend +* +* DESCRIPTION +* The cl_thread_suspend function suspends the calling thread for a minimum +* of the specified number of milliseconds. +* +* SYNOPSIS +*/ +void cl_thread_suspend(IN const uint32_t pause_ms); +/* +* PARAMETERS +* pause_ms +* [in] Number of milliseconds to suspend the calling thread. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function should only be called if it is valid for the caller's thread +* to enter a wait state. For stalling a thread that cannot enter a wait +* state, callers should use cl_thread_stall. +* +* SEE ALSO +* Thread, cl_thread_stall +*********/ + +/****f* Component Library: Thread/cl_thread_stall +* NAME +* cl_thread_stall +* +* DESCRIPTION +* The cl_thread_stall function stalls the calling thread for a minimum of +* the specified number of microseconds. +* +* SYNOPSIS +*/ +void cl_thread_stall(IN const uint32_t pause_us); +/* +* PARAMETERS +* pause_us +* [in] Number of microseconds to stall the calling thread. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* The cl_thread_stall function performs a busy wait for the specified +* number of microseconds. Care should be taken when using this function as +* it does not relinquish its quantum of operation. For longer wait +* operations, users should call cl_thread_suspend if possible. +* +* SEE ALSO +* Thread, cl_thread_suspend +*********/ + +/****f* Component Library: Thread/cl_proc_count +* NAME +* cl_proc_count +* +* DESCRIPTION +* The cl_proc_count function returns the number of processors in the system. +* +* SYNOPSIS +*/ +int cl_proc_count(void); +/* +* RETURN VALUE +* Returns the number of processors in the system. +*********/ + +/****i* Component Library: Thread/cl_is_current_thread +* NAME +* cl_is_current_thread +* +* DESCRIPTION +* The cl_is_current_thread function compares the calling thread to the +* specified thread and returns whether they are the same. +* +* SYNOPSIS +*/ +boolean_t cl_is_current_thread(IN const cl_thread_t * const p_thread); +/* +* PARAMETERS +* p_thread +* [in] Pointer to a cl_thread_t structure to compare to the +* caller's thead. +* +* RETURN VALUES +* TRUE if the thread specified by the p_thread parameter is the +* calling thread. +* +* FALSE otherwise. +* +* SEE ALSO +* Thread, cl_threadinit_t +*********/ + +/****f* Component Library: Thread/cl_is_blockable +* NAME +* cl_is_blockable +* +* DESCRIPTION +* The cl_is_blockable indicates if the current caller context is +* blockable. +* +* SYNOPSIS +*/ +boolean_t cl_is_blockable(void); +/* +* RETURN VALUE +* TRUE +* Current caller context can be blocked, i.e it is safe to perform +* a sleep, or call a down operation on a semaphore. +* +*********/ + +END_C_DECLS +#endif /* _CL_THREAD_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_thread_osd.h b/contrib/ofed/management/opensm/include/complib/cl_thread_osd.h new file mode 100644 index 000000000000..ad7df90844b0 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_thread_osd.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of thread abstraction and thread related operations. + */ + +#ifndef _CL_THREAD_OSD_H_ +#define _CL_THREAD_OSD_H_ + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#include +#include +#include +/* Linux user mode thread object structure definition. */ +typedef struct _cl_thread_osd_t { + pthread_t id; + cl_state_t state; +} cl_thread_osd_t; + +static inline boolean_t cl_is_blockable(void) +{ + return TRUE; +} + +END_C_DECLS +#endif /* _CL_THREAD_OSD_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_threadpool.h b/contrib/ofed/management/opensm/include/complib/cl_threadpool.h new file mode 100644 index 000000000000..e9b2c780e654 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_threadpool.h @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of thread pool. + */ + +#ifndef _CL_THREAD_POOL_H_ +#define _CL_THREAD_POOL_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Thread Pool +* NAME +* Thread Pool +* +* DESCRIPTION +* The Thread Pool manages a user specified number of threads. +* +* Each thread in the thread pool waits for a user initiated signal before +* invoking a user specified callback function. All threads in the thread +* pool invoke the same callback function. +* +* The thread pool functions operate on a cl_thread_pool_t structure which +* should be treated as opaque, and should be manipulated only through the +* provided functions. +* +* SEE ALSO +* Structures: +* cl_thread_pool_t +* +* Initialization: +* cl_thread_pool_construct, cl_thread_pool_init, cl_thread_pool_destroy +* +* Manipulation +* cl_thread_pool_signal +*********/ +/****s* Component Library: Thread Pool/cl_thread_pool_t +* NAME +* cl_thread_pool_t +* +* DESCRIPTION +* Thread pool structure. +* +* The cl_thread_pool_t structure should be treated as opaque, and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_thread_pool { + void (*pfn_callback) (void *); + void *context; + unsigned running_count; + unsigned events; + pthread_cond_t cond; + pthread_mutex_t mutex; + pthread_t *tid; +} cl_thread_pool_t; +/* +* FIELDS +* pfn_callback +* Callback function for the thread to invoke. +* +* context +* Context to pass to the thread callback function. +* +* running_count +* Number of threads running. +* +* events +* events counter +* +* mutex +* mutex for cond variable protection +* +* cond +* conditional variable to signal an event to thread +* +* tid +* array of allocated thread ids. +* +* SEE ALSO +* Thread Pool +*********/ + +/****f* Component Library: Thread Pool/cl_thread_pool_init +* NAME +* cl_thread_pool_init +* +* DESCRIPTION +* The cl_thread_pool_init function creates the threads to be +* managed by a thread pool. +* +* SYNOPSIS +*/ +cl_status_t +cl_thread_pool_init(IN cl_thread_pool_t * const p_thread_pool, + IN unsigned count, + IN void (*pfn_callback) (void *), + IN void *context, IN const char *const name); +/* +* PARAMETERS +* p_thread_pool +* [in] Pointer to a thread pool structure to initialize. +* +* thread_count +* [in] Number of threads to be managed by the thread pool. +* +* pfn_callback +* [in] Address of a function to be invoked by a thread. +* See the cl_pfn_thread_callback_t function type definition for +* details about the callback function. +* +* context +* [in] Value to pass to the callback function. +* +* name +* [in] Name to associate with the threads. The name may be up to 16 +* characters, including a terminating null character. All threads +* created in the pool have the same name. +* +* RETURN VALUES +* CL_SUCCESS if the thread pool creation succeeded. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to inititalize +* the thread pool. +* +* CL_ERROR if the threads could not be created. +* +* NOTES +* cl_thread_pool_init creates and starts the specified number of threads. +* If thread_count is zero, the thread pool creates as many threads as there +* are processors in the system. +* +* SEE ALSO +* Thread Pool, cl_thread_pool_construct, cl_thread_pool_destroy, +* cl_thread_pool_signal, cl_pfn_thread_callback_t +*********/ + +/****f* Component Library: Thread Pool/cl_thread_pool_destroy +* NAME +* cl_thread_pool_destroy +* +* DESCRIPTION +* The cl_thread_pool_destroy function performs any necessary cleanup +* for a thread pool. +* +* SYNOPSIS +*/ +void cl_thread_pool_destroy(IN cl_thread_pool_t * const p_thread_pool); +/* +* PARAMETERS +* p_thread_pool +* [in] Pointer to a thread pool structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function blocks until all threads exit, and must therefore not +* be called from any of the thread pool's threads. Because of its blocking +* nature, callers of cl_thread_pool_destroy must ensure that entering a wait +* state is valid from the calling thread context. +* +* This function should only be called after a call to +* cl_thread_pool_construct or cl_thread_pool_init. +* +* SEE ALSO +* Thread Pool, cl_thread_pool_construct, cl_thread_pool_init +*********/ + +/****f* Component Library: Thread Pool/cl_thread_pool_signal +* NAME +* cl_thread_pool_signal +* +* DESCRIPTION +* The cl_thread_pool_signal function signals a single thread of +* the thread pool to invoke the thread pool's callback function. +* +* SYNOPSIS +*/ +cl_status_t cl_thread_pool_signal(IN cl_thread_pool_t * const p_thread_pool); +/* +* PARAMETERS +* p_thread_pool +* [in] Pointer to a thread pool structure to signal. +* +* RETURN VALUES +* CL_SUCCESS if the thread pool was successfully signalled. +* +* CL_ERROR otherwise. +* +* NOTES +* Each call to this function wakes up at most one waiting thread in +* the thread pool. +* +* If all threads are running, cl_thread_pool_signal has no effect. +* +* SEE ALSO +* Thread Pool +*********/ + +END_C_DECLS +#endif /* _CL_THREAD_POOL_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_timer.h b/contrib/ofed/management/opensm/include/complib/cl_timer.h new file mode 100644 index 000000000000..194e3741b3a4 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_timer.h @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of timer abstraction. + */ + +#ifndef _CL_TIMER_H_ +#define _CL_TIMER_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Timer +* NAME +* Timer +* +* DESCRIPTION +* The Timer provides the ability to schedule a function to be invoked at +* a given time in the future. +* +* The timer callback function must not perform any blocking operations. +* +* The timer functions operate on a cl_timer_t structure which should be +* treated as opaque and should be manipulated only through the provided +* functions. +* +* SEE ALSO +* Structures: +* cl_timer_t +* +* Callbacks: +* cl_pfn_timer_callback_t +* +* Initialization: +* cl_timer_construct, cl_timer_init, cl_timer_destroy +* +* Manipulation: +* cl_timer_start, cl_timer_stop +*********/ +/****d* Component Library: Timer/cl_pfn_timer_callback_t +* NAME +* cl_pfn_timer_callback_t +* +* DESCRIPTION +* The cl_pfn_timer_callback_t function type defines the prototype for +* functions used to notify users of a timer expiration. +* +* SYNOPSIS +*/ +typedef void (*cl_pfn_timer_callback_t) (IN void *context); +/* +* PARAMETERS +* context +* [in] Value specified in a previous call to cl_timer_init. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function type is provided as function prototype reference for the +* function provided by users as a parameter to the cl_timer_init function. +* +* SEE ALSO +* Timer, cl_timer_init +*********/ + +/* + * This include file defines the timer structure, and depends on the timer + * callback definition. + */ +#include + +/****f* Component Library: Timer/cl_timer_construct +* NAME +* cl_timer_construct +* +* DESCRIPTION +* The cl_timer_construct function initializes the state of a timer. +* +* SYNOPSIS +*/ +void cl_timer_construct(IN cl_timer_t * const p_timer); +/* +* PARAMETERS +* p_timer +* [in] Pointer to a cl_timer_t structure whose state to initialize. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_timer_destroy without first calling cl_timer_init. +* +* Calling cl_timer_construct is a prerequisite to calling any other +* timer function except cl_timer_init. +* +* SEE ALSO +* Timer, cl_timer_init, cl_timer_destroy +*********/ + +/****f* Component Library: Timer/cl_timer_init +* NAME +* cl_timer_init +* +* DESCRIPTION +* The cl_timer_init function initializes a timer for use. +* +* SYNOPSIS +*/ +cl_status_t +cl_timer_init(IN cl_timer_t * const p_timer, + IN cl_pfn_timer_callback_t pfn_callback, + IN const void *const context); +/* +* PARAMETERS +* p_timer +* [in] Pointer to a cl_timer_t structure to initialize. +* +* pfn_callback +* [in] Address of a callback function to be invoked when a timer expires. +* See the cl_pfn_timer_callback_t function type definition for details +* about the callback function. +* +* context +* [in] Value to pass to the callback function. +* +* RETURN VALUES +* CL_SUCCESS if the timer was successfully initialized. +* +* CL_ERROR otherwise. +* +* NOTES +* Allows calling cl_timer_start and cl_timer_stop. +* +* SEE ALSO +* Timer, cl_timer_construct, cl_timer_destroy, cl_timer_start, +* cl_timer_stop, cl_pfn_timer_callback_t +*********/ + +/****f* Component Library: Timer/cl_timer_destroy +* NAME +* cl_timer_destroy +* +* DESCRIPTION +* The cl_timer_destroy function performs any necessary cleanup of a timer. +* +* SYNOPSIS +*/ +void cl_timer_destroy(IN cl_timer_t * const p_timer); +/* +* PARAMETERS +* p_timer +* [in] Pointer to a cl_timer_t structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_timer_destroy cancels any pending callbacks. +* +* This function should only be called after a call to cl_timer_construct +* or cl_timer_init. +* +* SEE ALSO +* Timer, cl_timer_construct, cl_timer_init +*********/ + +/****f* Component Library: Timer/cl_timer_start +* NAME +* cl_timer_start +* +* DESCRIPTION +* The cl_timer_start function sets a timer to expire after a given interval. +* +* SYNOPSIS +*/ +cl_status_t +cl_timer_start(IN cl_timer_t * const p_timer, IN const uint32_t time_ms); +/* +* PARAMETERS +* p_timer +* [in] Pointer to a cl_timer_t structure to schedule. +* +* time_ms +* [in] Time, in milliseconds, before the timer should expire. +* +* RETURN VALUES +* CL_SUCCESS if the timer was successfully scheduled. +* +* CL_ERROR otherwise. +* +* NOTES +* cl_timer_start implicitly stops the timer before being scheduled. +* +* The interval specified by the time_ms parameter is a minimum interval. +* The timer is guaranteed to expire no sooner than the desired interval, but +* may take longer to expire. +* +* SEE ALSO +* Timer, cl_timer_stop, cl_timer_trim +*********/ + +/****f* Component Library: Timer/cl_timer_stop +* NAME +* cl_timer_stop +* +* DESCRIPTION +* The cl_timer_stop function stops a pending timer from expiring. +* +* SYNOPSIS +*/ +void cl_timer_stop(IN cl_timer_t * const p_timer); +/* +* PARAMETERS +* p_timer +* [in] Pointer to a cl_timer_t structure. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Timer, cl_timer_start, cl_timer_trim +*********/ + +/****f* Component Library: Timer/cl_timer_trim +* NAME +* cl_timer_trim +* +* DESCRIPTION +* The cl_timer_trim function pulls in the absolute expiration +* time of a timer if the current expiration time exceeds the specified +* interval. +* +* sets a timer to expire after a given +* interval if that interval is less than the current timer expiration. +* +* SYNOPSIS +*/ +cl_status_t +cl_timer_trim(IN cl_timer_t * const p_timer, IN const uint32_t time_ms); +/* +* PARAMETERS +* p_timer +* [in] Pointer to a cl_timer_t structure to schedule. +* +* time_ms +* [in] Maximum time, in milliseconds, before the timer should expire. +* +* RETURN VALUES +* CL_SUCCESS if the timer was successfully scheduled. +* +* CL_ERROR otherwise. +* +* NOTES +* cl_timer_trim has no effect if the time interval is greater than the +* remaining time when the timer is set. +* +* If the new interval time is less than the remaining time, cl_timer_trim +* implicitly stops the timer before resetting it. +* +* If the timer is reset, it is guaranteed to expire no sooner than the +* new interval, but may take longer to expire. +* +* SEE ALSO +* Timer, cl_timer_start, cl_timer_stop +*********/ + +/****f* Component Library: Time Stamp/cl_get_time_stamp +* NAME +* cl_get_time_stamp +* +* DESCRIPTION +* The cl_get_time_stamp function returns the current time stamp in +* microseconds since the system was booted. +* +* SYNOPSIS +*/ +uint64_t cl_get_time_stamp(void); +/* +* RETURN VALUE +* Time elapsed, in microseconds, since the system was booted. +* +* SEE ALSO +* Timer, cl_get_time_stamp_sec +*********/ + +/****f* Component Library: Time Stamp/cl_get_time_stamp_sec +* NAME +* cl_get_time_stamp_sec +* +* DESCRIPTION +* The cl_get_time_stamp_sec function returns the current time stamp in +* seconds since the system was booted. +* +* SYNOPSIS +*/ +uint32_t cl_get_time_stamp_sec(void); +/* +* RETURN VALUE +* Time elapsed, in seconds, since the system was booted. +* +* SEE ALSO +* Timer, cl_get_time_stamp +*********/ + +END_C_DECLS +#endif /* _CL_TIMER_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_timer_osd.h b/contrib/ofed/management/opensm/include/complib/cl_timer_osd.h new file mode 100644 index 000000000000..ed36fea18112 --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_timer_osd.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of timer object. + */ + +#ifndef _CL_TIMER_OSD_H_ +#define _CL_TIMER_OSD_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#include +#include +typedef enum _cl_timer_state { + CL_TIMER_IDLE, + CL_TIMER_QUEUED, + CL_TIMER_RUNNING +} cl_timer_state_t; + +typedef struct _cl_timer_t { + cl_list_item_t list_item; + cl_timer_state_t timer_state; + cl_state_t state; + cl_pfn_timer_callback_t pfn_callback; + const void *context; + pthread_cond_t cond; + struct timespec timeout; +} cl_timer_t; + +/* Internal functions to create the timer provider. */ +cl_status_t __cl_timer_prov_create(void); + +/* Internal function to destroy the timer provider. */ +void __cl_timer_prov_destroy(void); + +END_C_DECLS +#endif /* _CL_TIMER_OSD_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_types.h b/contrib/ofed/management/opensm/include/complib/cl_types.h new file mode 100644 index 000000000000..848b9d93351e --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_types.h @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Defines standard return codes, keywords, macros, and debug levels. + */ + +#ifdef __WIN__ +#pragma warning(disable : 4996) +#endif + +#ifndef _CL_TYPES_H_ +#define _CL_TYPES_H_ + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#include +#include +typedef uint16_t net16_t; +typedef uint32_t net32_t; +typedef uint64_t net64_t; + +#ifndef __WORDSIZE +#ifdef __LP64__ +#define __WORDSIZE 64 +#else +#define __WORDSIZE 32 +#endif +#endif + +/* explicit cast of void* to uint32_t */ +#ifndef ASSERT_VOIDP2UINTN +#if __WORDSIZE == 64 +#define ASSERT_VOIDP2UINTN(var) \ + CL_ASSERT( (intptr_t)var <= 0xffffffffffffffffL ) +#else /* __WORDSIZE == 64 */ +#if __WORDSIZE == 32 + /* need to cast carefully to avoid the warining of un-needed check */ +#define ASSERT_VOIDP2UINTN(var) \ + CL_ASSERT( (intptr_t)var <= 0x100000000ULL ) +#else /* __WORDSIZE == 32 */ +#error "Need to know WORDSIZE to tell how to cast to unsigned long int" +#endif /* __WORDSIZE == 32 */ +#endif /* __WORDSIZE == 64 */ +#endif + +/* explicit casting of void* to long */ +#ifndef CAST_P2LONG +#define CAST_P2LONG(var) ((intptr_t)(var)) +#endif + +/****d* Component Library: Pointer Manipulation/offsetof +* NAME +* offsetof +* +* DESCRIPTION +* The offsetof macro returns the offset of a member within a structure. +* +* SYNOPSIS +* uintn_t +* offsetof( +* IN TYPE, +* IN MEMBER ); +* +* PARAMETERS +* TYPE +* [in] Name of the structure containing the specified member. +* +* MEMBER +* [in] Name of the member whose offset in the specified structure +* is to be returned. +* +* RETURN VALUE +* Number of bytes from the beginning of the structure to the +* specified member. +* +* SEE ALSO +* PARENT_STRUCT +*********/ +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((uintn_t) &((TYPE *)0)->MEMBER) +#endif + +/****d* Component Library: Pointer Manipulation/PARENT_STRUCT +* NAME +* PARENT_STRUCT +* +* DESCRIPTION +* The PARENT_STRUCT macro returns a pointer to a structure +* given a name and pointer to one of its members. +* +* SYNOPSIS +* PARENT_TYPE* +* PARENT_STRUCT( +* IN void* const p_member, +* IN PARENT_TYPE, +* IN MEMBER_NAME ); +* +* PARAMETERS +* p_member +* [in] Pointer to the MEMBER_NAME member of a PARENT_TYPE structure. +* +* PARENT_TYPE +* [in] Name of the structure containing the specified member. +* +* MEMBER_NAME +* [in] Name of the member whose address is passed in the p_member +* parameter. +* +* RETURN VALUE +* Pointer to a structure of type PARENT_TYPE whose MEMBER_NAME member is +* located at p_member. +* +* SEE ALSO +* offsetof +*********/ +#define PARENT_STRUCT(p_member, PARENT_TYPE, MEMBER_NAME) \ + ((PARENT_TYPE*)((uint8_t*)(p_member) - offsetof(PARENT_TYPE, MEMBER_NAME))) + +/****d* Component Library/Parameter Keywords +* NAME +* Parameter Keywords +* +* DESCRIPTION +* The Parameter Keywords can be used to clarify the usage of function +* parameters to users. +* +* VALUES +* IN +* Designates that the parameter is used as input to a function. +* +* OUT +* Designates that the parameter's value will be set by the function. +* +* OPTIONAL +* Designates that the parameter is optional, and may be NULL. +* The OPTIONAL keyword, if used, follows the parameter name. +* +* EXAMPLE +* // Function declaration. +* void* +* my_func( +* IN void* const p_param1, +* OUT void** const p_handle OPTIONAL ); +* +* NOTES +* Multiple keywords can apply to a single parameter. The IN and OUT +* keywords precede the parameter type. The OPTIONAL +* keyword, if used, follows the parameter name. +*********/ +#ifndef IN +#define IN /* Function input parameter */ +#endif +#ifndef OUT +#define OUT /* Function output parameter */ +#endif +#ifndef OPTIONAL +#define OPTIONAL /* Optional function parameter - NULL if not used */ +#endif + +/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Function Returns And Completion Codes %% +%% %% +%% The text for any addition to this enumerated type must be added to the %% +%% string array defined in . %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ + +/****d* Component Library/Data Types +* NAME +* Data Types +* +* DESCRIPTION +* The component library provides and uses explicitly sized types. +* +* VALUES +* char +* 8-bit, defined by compiler. +* +* void +* 0-bit, defined by compiler. +* +* int8_t +* 8-bit signed integer. +* +* uint8_t +* 8-bit unsigned integer. +* +* int16_t +* 16-bit signed integer. +* +* uint16_t +* 16-bit unsigned integer. +* +* net16_t +* 16-bit network byte order value. +* +* int32_t +* 32-bit signed integer. +* +* uint32_t +* 32-bit unsigned integer. +* +* net32_t +* 32-bit network byte order value. +* +* int64_t +* 64-bit signed integer. +* +* uint64_t +* 64-bit unsigned integer. +* +* net64_t +* 64-bit network byte order value. +* +* intn_t +* Signed natural sized integer. 32-bit on a 32-bit platform, 64-bit on +* a 64-bit platform. +* +* uintn_t +* Unsigned natural sized integer. 32-bit on a 32-bit platform, 64-bit on +* a 64-bit platform. +* +* boolean_t +* integral sized. Set to TRUE or FALSE and used in logical expressions. +* +* NOTES +* Pointer types are not defined as these provide no value and can potentially +* lead to naming confusion. +*********/ + +/****d* Component Library: Data Types/cl_status_t +* NAME +* cl_status_t +* +* DESCRIPTION +* The cl_status_t return types are used by the component library to +* provide detailed function return values. +* +* SYNOPSIS +*/ +typedef enum _cl_status { + CL_SUCCESS = 0, + CL_ERROR, + CL_INVALID_STATE, + CL_INVALID_OPERATION, + CL_INVALID_SETTING, + CL_INVALID_PARAMETER, + CL_INSUFFICIENT_RESOURCES, + CL_INSUFFICIENT_MEMORY, + CL_INVALID_PERMISSION, + CL_COMPLETED, + CL_NOT_DONE, + CL_PENDING, + CL_TIMEOUT, + CL_CANCELED, + CL_REJECT, + CL_OVERRUN, + CL_NOT_FOUND, + CL_UNAVAILABLE, + CL_BUSY, + CL_DISCONNECT, + CL_DUPLICATE, + + CL_STATUS_COUNT /* should be the last value */ +} cl_status_t; +/* +* SEE ALSO +* Data Types, CL_STATUS_MSG +*********/ + +/* Status values above converted to text for easier printing. */ +extern const char *cl_status_text[]; + +#ifndef cl_panic +/****f* Component Library: Error Trapping/cl_panic +* NAME +* cl_panic +* +* DESCRIPTION +* Halts execution of the current process. Halts the system if called in +* from the kernel. +* +* SYNOPSIS +*/ +void cl_panic(IN const char *const message, IN ...); +/* +* PARAMETERS +* message +* [in] ANSI string formatted identically as for a call to the standard C +* function printf describing the cause for the panic. +* +* ... +* [in] Extra parameters for string formatting, as defined for the +* standard C function printf. +* +* RETURN VALUE +* This function does not return. +* +* NOTES +* The formatting of the message string is the same as for printf +* +* cl_panic sends the message to the current message logging target. +*********/ +#endif /* cl_panic */ + +/****d* Component Library: Data Types/CL_STATUS_MSG +* NAME +* CL_STATUS_MSG +* +* DESCRIPTION +* The CL_STATUS_MSG macro returns a textual representation of +* an cl_status_t code. +* +* SYNOPSIS +* const char* +* CL_STATUS_MSG( +* IN cl_status_t errcode ); +* +* PARAMETERS +* errcode +* [in] cl_status_t code for which to return a text representation. +* +* RETURN VALUE +* Pointer to a string containing a textual representation of the errcode +* parameter. +* +* NOTES +* This function performs boundary checking on the cl_status_t value, +* masking off the upper 24-bits. If the value is out of bounds, the string +* "invalid status code" is returned. +* +* SEE ALSO +* cl_status_t +*********/ +#define CL_STATUS_MSG( errcode ) \ + ((errcode < CL_STATUS_COUNT)?cl_status_text[errcode]:"invalid status code") + +#if !defined( FALSE ) +#define FALSE 0 +#endif /* !defined( FALSE ) */ + +#if !defined( TRUE ) +#define TRUE (!FALSE) +#endif /* !defined( TRUE ) */ + +/****d* Component Library: Unreferenced Parameters/UNUSED_PARAM +* NAME +* UNUSED_PARAM +* +* DESCRIPTION +* The UNUSED_PARAM macro can be used to eliminates compiler warnings related +* to intentionally unused formal parameters in function implementations. +* +* SYNOPSIS +* UNUSED_PARAM( P ) +* +* EXAMPLE +* void my_func( int32_t value ) +* { +* UNUSED_PARAM( value ); +* } +*********/ + +/****d* Component Library/Object States +* NAME +* Object States +* +* DESCRIPTION +* The object states enumerated type defines the valid states of components. +* +* SYNOPSIS +*/ +typedef enum _cl_state { + CL_UNINITIALIZED = 1, + CL_INITIALIZED, + CL_DESTROYING, + CL_DESTROYED +} cl_state_t; +/* +* VALUES +* CL_UNINITIALIZED +* Indicates that initialization was not invoked successfully. +* +* CL_INITIALIZED +* Indicates initialization was successful. +* +* CL_DESTROYING +* Indicates that the object is undergoing destruction. +* +* CL_DESTROYED +* Indicates that the object's destructor has already been called. Most +* objects set their final state to CL_DESTROYED before freeing the +* memory associated with the object. +*********/ + +/****d* Component Library: Object States/cl_is_state_valid +* NAME +* cl_is_state_valid +* +* DESCRIPTION +* The cl_is_state_valid function returns whether a state has a valid value. +* +* SYNOPSIS +*/ +static inline boolean_t cl_is_state_valid(IN const cl_state_t state) +{ + return ((state == CL_UNINITIALIZED) || (state == CL_INITIALIZED) || + (state == CL_DESTROYING) || (state == CL_DESTROYED)); +} + +/* +* PARAMETERS +* state +* State whose value to validate. +* +* RETURN VALUES +* TRUE if the specified state has a valid value. +* +* FALSE otherwise. +* +* NOTES +* This function is used in debug builds to check for valid states. If an +* uninitialized object is passed, the memory for the state may cause the +* state to have an invalid value. +* +* SEE ALSO +* Object States +*********/ + +END_C_DECLS +#endif /* _DATA_TYPES_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_types_osd.h b/contrib/ofed/management/opensm/include/complib/cl_types_osd.h new file mode 100644 index 000000000000..d12aa4cc478d --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_types_osd.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Defines sized datatypes for Linux User mode + * exported sizes are int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t + * int64_t, uint64_t. uintn_t is a polymorphic type, size is native size and + * also size of the pointer. + */ + +#ifndef _CL_TYPES_OSD_H_ +#define _CL_TYPES_OSD_H_ + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#if defined (_DEBUG_) +#ifdef __IA64__ +#define cl_break() asm(" break 0") +#else /* __IA64__ */ +#define cl_break() asm(" int $3") +#endif /* __IA64__ */ +#else /* _DEBUG_ */ +#define cl_break +#endif +#include +#include +#include +#if defined (_DEBUG_) +#define CL_ASSERT assert +#else /* _DEBUG_ */ +#define CL_ASSERT( __exp__ ) +#endif /* _DEBUG_ */ +/* + * Types not explicitly defined are native to the platform. + */ +typedef unsigned long uintn_t; +typedef long intn_t; +typedef int boolean_t; +typedef volatile int32_t atomic32_t; + +#ifndef NULL +#define NULL (void*)0 +#endif + +#define UNUSED_PARAM( P ) + +END_C_DECLS +#endif /* _CL_TYPES_OSD_H_ */ diff --git a/contrib/ofed/management/opensm/include/complib/cl_vector.h b/contrib/ofed/management/opensm/include/complib/cl_vector.h new file mode 100644 index 000000000000..11c45f88bbbf --- /dev/null +++ b/contrib/ofed/management/opensm/include/complib/cl_vector.h @@ -0,0 +1,945 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * This file contains vector definitions. Vector provides dynmically + * resizable array functionality. Objects in a Vector are not relocated + * when the array is resized. + */ + +#ifndef _CL_VECTOR_H_ +#define _CL_VECTOR_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* Component Library/Vector +* NAME +* Vector +* +* DESCRIPTION +* The Vector is a self-sizing array. Like a traditonal array, a vector +* allows efficient constant time access to elements with a specified index. +* A vector grows transparently as the user adds elements to the array. +* +* As the vector grows in size, it does not relocate existing elements in +* memory. This allows using pointers to elements stored in a Vector. +* +* Users can supply an initializer functions that allow a vector to ensure +* that new items added to the vector are properly initialized. A vector +* calls the initializer function on a per object basis when growing the +* array. The initializer is optional. +* +* The initializer function can fail, and returns a cl_status_t. The vector +* will call the destructor function, if provided, for an element that +* failed initialization. If an initializer fails, a vector does not call +* the initializer for objects in the remainder of the new memory allocation. +* +* The cl_vector_t structure should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SEE ALSO +* Structures: +* cl_vector_t +* +* Callbacks: +* cl_pfn_vec_init_t, cl_pfn_vec_dtor_t, cl_pfn_vec_apply_t, +* cl_pfn_vec_find_t +* +* Item Manipulation: +* cl_vector_set_obj, cl_vector_obj +* +* Initialization: +* cl_vector_construct, cl_vector_init, cl_vector_destroy +* +* Manipulation: +* cl_vector_get_capacity, cl_vector_set_capacity, +* cl_vector_get_size, cl_vector_set_size, cl_vector_set_min_size +* cl_vector_get_ptr, cl_vector_get, cl_vector_at, cl_vector_set +* +* Search: +* cl_vector_find_from_start, cl_vector_find_from_end +* cl_vector_apply_func +*********/ +/****d* Component Library: Vector/cl_pfn_vec_init_t +* NAME +* cl_pfn_vec_init_t +* +* DESCRIPTION +* The cl_pfn_vec_init_t function type defines the prototype for functions +* used as initializer for elements being allocated by a vector. +* +* SYNOPSIS +*/ +typedef cl_status_t + (*cl_pfn_vec_init_t) (IN void *const p_element, IN void *context); +/* +* PARAMETERS +* p_element +* [in] Pointer to an element being added to a vector. +* +* context +* [in] Context provided in a call to cl_vector_init. +* +* RETURN VALUES +* Return CL_SUCCESS to indicate that the element was initialized successfully. +* +* Other cl_status_t values will be returned by the cl_vector_init, +* cl_vector_set_size, and cl_vector_set_min_size functions. +* +* In situations where the vector's size needs to grows in order to satisfy +* a call to cl_vector_set, a non-successful status returned by the +* initializer callback causes the growth to stop. +* +* NOTES +* This function type is provided as function prototype reference for +* the initializer function provided by users as an optional parameter to +* the cl_vector_init function. +* +* SEE ALSO +* Vector, cl_vector_init +*********/ + +/****d* Component Library: Vector/cl_pfn_vec_dtor_t +* NAME +* cl_pfn_vec_dtor_t +* +* DESCRIPTION +* The cl_pfn_vec_dtor_t function type defines the prototype for functions +* used as destructor for elements being deallocated from a vector. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_vec_dtor_t) (IN void *const p_element, IN void *context); +/* +* PARAMETERS +* p_element +* [in] Pointer to an element being deallocated from a vector. +* +* context +* [in] Context provided in a call to cl_vector_init. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function type is provided as function prototype reference for +* the destructor function provided by users as an optional parameter to +* the cl_vector_init function. +* +* SEE ALSO +* Vector, cl_vector_init +*********/ + +/****d* Component Library: Vector/cl_pfn_vec_apply_t +* NAME +* cl_pfn_vec_apply_t +* +* DESCRIPTION +* The cl_pfn_vec_apply_t function type defines the prototype for functions +* used to iterate elements in a vector. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_vec_apply_t) (IN const size_t index, + IN void *const p_element, IN void *context); +/* +* PARAMETERS +* index +* [in] Index of the element. +* +* p_element +* [in] Pointer to an element at the specified index in the vector. +* +* context +* [in] Context provided in a call to cl_vector_apply_func. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* This function type is provided as function prototype reference for +* the function passed by users as a parameter to the cl_vector_apply_func +* function. +* +* SEE ALSO +* Vector, cl_vector_apply_func +*********/ + +/****d* Component Library: Vector/cl_pfn_vec_find_t +* NAME +* cl_pfn_vec_find_t +* +* DESCRIPTION +* The cl_pfn_vec_find_t function type defines the prototype for functions +* used to find elements in a vector. +* +* SYNOPSIS +*/ +typedef cl_status_t + (*cl_pfn_vec_find_t) (IN const size_t index, + IN const void *const p_element, IN void *context); +/* +* PARAMETERS +* index +* [in] Index of the element. +* +* p_element +* [in] Pointer to an element at the specified index in the vector. +* +* context +* [in] Context provided in a call to cl_vector_find_from_start or +* cl_vector_find_from_end. +* +* RETURN VALUES +* Return CL_SUCCESS if the element was found. This stops vector iteration. +* +* CL_NOT_FOUND to continue the vector iteration. +* +* NOTES +* This function type is provided as function prototype reference for the +* function provided by users as a parameter to the cl_vector_find_from_start +* and cl_vector_find_from_end functions. +* +* SEE ALSO +* Vector, cl_vector_find_from_start, cl_vector_find_from_end +*********/ + +/****i* Component Library: Vector/cl_pfn_vec_copy_t +* NAME +* cl_pfn_vec_copy_t +* +* DESCRIPTION +* The cl_pfn_vec_copy_t function type defines the prototype for functions +* used to copy elements in a vector. +* +* SYNOPSIS +*/ +typedef void + (*cl_pfn_vec_copy_t) (IN void *const p_dest, + IN const void *const p_src, IN const size_t size); +/* +* PARAMETERS +* p_dest +* [in] Pointer to the destination buffer into which to copy p_src. +* +* p_src +* [in] Pointer to the destination buffer from which to copy. +* +* size +* [in] Number of bytes to copy. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* Vector +*********/ + +/****s* Component Library: Vector/cl_vector_t +* NAME +* cl_vector_t +* +* DESCRIPTION +* Vector structure. +* +* The cl_vector_t structure should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct _cl_vector { + size_t size; + size_t grow_size; + size_t capacity; + size_t element_size; + cl_pfn_vec_init_t pfn_init; + cl_pfn_vec_dtor_t pfn_dtor; + cl_pfn_vec_copy_t pfn_copy; + const void *context; + cl_qlist_t alloc_list; + void **p_ptr_array; + cl_state_t state; +} cl_vector_t; +/* +* FIELDS +* size +* Number of elements successfully initialized in the vector. +* +* grow_size +* Number of elements to allocate when growing. +* +* capacity +* total # of elements allocated. +* +* element_size +* Size of each element. +* +* pfn_init +* User supplied element initializer. +* +* pfn_dtor +* User supplied element destructor. +* +* pfn_copy +* Copy operator. +* +* context +* User context for callbacks. +* +* alloc_list +* List of allocations. +* +* p_ptr_array +* Internal array of pointers to elements. +* +* state +* State of the vector. +* +* SEE ALSO +* Vector +*********/ + +/****f* Component Library: Vector/cl_vector_construct +* NAME +* cl_vector_construct +* +* DESCRIPTION +* The cl_vector_construct function constructs a vector. +* +* SYNOPSIS +*/ +void cl_vector_construct(IN cl_vector_t * const p_vector); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling cl_vector_destroy without first calling cl_vector_init. +* +* Calling cl_vector_construct is a prerequisite to calling any other +* vector function except cl_vector_init. +* +* SEE ALSO +* Vector, cl_vector_init, cl_vector_destroy +*********/ + +/****f* Component Library: Vector/cl_vector_init +* NAME +* cl_vector_init +* +* DESCRIPTION +* The cl_vector_init function initializes a vector for use. +* +* SYNOPSIS +*/ +cl_status_t +cl_vector_init(IN cl_vector_t * const p_vector, + IN const size_t min_size, + IN const size_t grow_size, + IN const size_t element_size, + IN cl_pfn_vec_init_t pfn_init OPTIONAL, + IN cl_pfn_vec_dtor_t pfn_dtor OPTIONAL, + IN const void *const context); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure to inititalize. +* +* initial_size +* [in] Initial number of elements. +* +* grow_size +* [in] Number of elements to allocate when incrementally growing +* the vector. A value of zero disables automatic growth. +* +* element_size +* [in] Size of each element. +* +* pfn_init +* [in] Initializer callback to invoke for every new element. +* See the cl_pfn_vec_init_t function type declaration for details about +* the callback function. +* +* pfn_dtor +* [in] Destructor callback to invoke for elements being deallocated. +* See the cl_pfn_vec_dtor_t function type declaration for details about +* the callback function. +* +* context +* [in] Value to pass to the callback functions to provide context. +* +* RETURN VALUES +* CL_SUCCESS if the vector was initialized successfully. +* +* CL_INSUFFICIENT_MEMORY if the initialization failed. +* +* cl_status_t value returned by optional initializer function specified by +* the pfn_init parameter. +* +* NOTES +* The constructor and initializer functions, if any, are invoked for every +* new element in the array. +* +* SEE ALSO +* Vector, cl_vector_construct, cl_vector_destroy, cl_vector_set, +* cl_vector_get, cl_vector_get_ptr, cl_vector_at +*********/ + +/****f* Component Library: Vector/cl_vector_destroy +* NAME +* cl_vector_destroy +* +* DESCRIPTION +* The cl_vector_destroy function destroys a vector. +* +* SYNOPSIS +*/ +void cl_vector_destroy(IN cl_vector_t * const p_vector); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_vector_destroy frees all memory allocated for the vector. The vector +* is left initialized to a zero capacity and size. +* +* This function should only be called after a call to cl_vector_construct +* or cl_vector_init. +* +* SEE ALSO +* Vector, cl_vector_construct, cl_vector_init +*********/ + +/****f* Component Library: Vector/cl_vector_get_capacity +* NAME +* cl_vector_get_capacity +* +* DESCRIPTION +* The cl_vector_get_capacity function returns the capacity of a vector. +* +* SYNOPSIS +*/ +static inline size_t +cl_vector_get_capacity(IN const cl_vector_t * const p_vector) +{ + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + + return (p_vector->capacity); +} + +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure whose capacity to return. +* +* RETURN VALUE +* Capacity, in elements, of the vector. +* +* NOTES +* The capacity is the number of elements that the vector can store, and +* can be greater than the number of elements stored. To get the number of +* elements stored in the vector, use cl_vector_get_size. +* +* SEE ALSO +* Vector, cl_vector_set_capacity, cl_vector_get_size +*********/ + +/****f* Component Library: Vector/cl_vector_get_size +* NAME +* cl_vector_get_size +* +* DESCRIPTION +* The cl_vector_get_size function returns the size of a vector. +* +* SYNOPSIS +*/ +static inline size_t cl_vector_get_size(IN const cl_vector_t * const p_vector) +{ + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + + return (p_vector->size); +} + +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure whose size to return. +* +* RETURN VALUE +* Size, in elements, of the vector. +* +* SEE ALSO +* Vector, cl_vector_set_size, cl_vector_get_capacity +*********/ + +/****f* Component Library: Vector/cl_vector_get_ptr +* NAME +* cl_vector_get_ptr +* +* DESCRIPTION +* The cl_vector_get_ptr function returns a pointer to an element +* stored in a vector at a specified index. +* +* SYNOPSIS +*/ +static inline void *cl_vector_get_ptr(IN const cl_vector_t * const p_vector, + IN const size_t index) +{ + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + + return (p_vector->p_ptr_array[index]); +} + +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure from which to get a +* pointer to an element. +* +* index +* [in] Index of the element. +* +* RETURN VALUE +* Pointer to the element stored at specified index. +* +* NOTES +* cl_vector_get_ptr provides constant access times regardless of the index. +* +* cl_vector_get_ptr does not perform boundary checking. Callers are +* responsible for providing an index that is within the range of the vector. +* +* SEE ALSO +* Vector, cl_vector_get, cl_vector_at, cl_vector_set, cl_vector_get_size +*********/ + +/****f* Component Library: Vector/cl_vector_get +* NAME +* cl_vector_get +* +* DESCRIPTION +* The cl_vector_get function copies an element stored in a vector at a +* specified index. +* +* SYNOPSIS +*/ +static inline void +cl_vector_get(IN const cl_vector_t * const p_vector, + IN const size_t index, OUT void *const p_element) +{ + void *p_src; + + CL_ASSERT(p_vector); + CL_ASSERT(p_vector->state == CL_INITIALIZED); + CL_ASSERT(p_element); + + /* Get a pointer to the element. */ + p_src = cl_vector_get_ptr(p_vector, index); + p_vector->pfn_copy(p_src, p_element, p_vector->element_size); +} + +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure from which to get a copy of +* an element. +* +* index +* [in] Index of the element. +* +* p_element +* [out] Pointer to storage for the element. Contains a copy of the +* desired element upon successful completion of the call. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_vector_get provides constant time access regardless of the index. +* +* cl_vector_get does not perform boundary checking on the vector, and +* callers are responsible for providing an index that is within the range +* of the vector. To access elements after performing boundary checks, +* use cl_vector_at. +* +* The p_element parameter contains a copy of the desired element upon +* return from this function. +* +* SEE ALSO +* Vector, cl_vector_get_ptr, cl_vector_at +*********/ + +/****f* Component Library: Vector/cl_vector_at +* NAME +* cl_vector_at +* +* DESCRIPTION +* The cl_vector_at function copies an element stored in a vector at a +* specified index, performing boundary checks. +* +* SYNOPSIS +*/ +cl_status_t +cl_vector_at(IN const cl_vector_t * const p_vector, + IN const size_t index, OUT void *const p_element); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure from which to get a copy of +* an element. +* +* index +* [in] Index of the element. +* +* p_element +* [out] Pointer to storage for the element. Contains a copy of the +* desired element upon successful completion of the call. +* +* RETURN VALUES +* CL_SUCCESS if an element was found at the specified index. +* +* CL_INVALID_SETTING if the index was out of range. +* +* NOTES +* cl_vector_at provides constant time access regardless of the index, and +* performs boundary checking on the vector. +* +* Upon success, the p_element parameter contains a copy of the desired element. +* +* SEE ALSO +* Vector, cl_vector_get, cl_vector_get_ptr +*********/ + +/****f* Component Library: Vector/cl_vector_set +* NAME +* cl_vector_set +* +* DESCRIPTION +* The cl_vector_set function sets the element at the specified index. +* +* SYNOPSIS +*/ +cl_status_t +cl_vector_set(IN cl_vector_t * const p_vector, + IN const size_t index, IN void *const p_element); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure into which to store +* an element. +* +* index +* [in] Index of the element. +* +* p_element +* [in] Pointer to an element to store in the vector. +* +* RETURN VALUES +* CL_SUCCESS if the element was successfully set. +* +* CL_INSUFFICIENT_MEMORY if the vector could not be resized to accommodate +* the new element. +* +* NOTES +* cl_vector_set grows the vector as needed to accommodate the new element, +* unless the grow_size parameter passed into the cl_vector_init function +* was zero. +* +* SEE ALSO +* Vector, cl_vector_get +*********/ + +/****f* Component Library: Vector/cl_vector_set_capacity +* NAME +* cl_vector_set_capacity +* +* DESCRIPTION +* The cl_vector_set_capacity function reserves memory in a vector for a +* specified number of elements. +* +* SYNOPSIS +*/ +cl_status_t +cl_vector_set_capacity(IN cl_vector_t * const p_vector, + IN const size_t new_capacity); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure whose capacity to set. +* +* new_capacity +* [in] Total number of elements for which the vector should +* allocate memory. +* +* RETURN VALUES +* CL_SUCCESS if the capacity was successfully set. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to satisfy the +* operation. The vector is left unchanged. +* +* NOTES +* cl_vector_set_capacity increases the capacity of the vector. It does +* not change the size of the vector. If the requested capacity is less +* than the current capacity, the vector is left unchanged. +* +* SEE ALSO +* Vector, cl_vector_get_capacity, cl_vector_set_size, +* cl_vector_set_min_size +*********/ + +/****f* Component Library: Vector/cl_vector_set_size +* NAME +* cl_vector_set_size +* +* DESCRIPTION +* The cl_vector_set_size function resizes a vector, either increasing or +* decreasing its size. +* +* SYNOPSIS +*/ +cl_status_t +cl_vector_set_size(IN cl_vector_t * const p_vector, IN const size_t size); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure whose size to set. +* +* size +* [in] Number of elements desired in the vector. +* +* RETURN VALUES +* CL_SUCCESS if the size of the vector was set successfully. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to complete the +* operation. The vector is left unchanged. +* +* NOTES +* cl_vector_set_size sets the vector to the specified size. If size is +* smaller than the current size of the vector, the size is reduced. +* The destructor function, if any, will be invoked for all elements that +* are above size. Likewise, the constructor and initializer, if any, will +* be invoked for all new elements. +* +* This function can only fail if size is larger than the current capacity. +* +* SEE ALSO +* Vector, cl_vector_get_size, cl_vector_set_min_size, +* cl_vector_set_capacity +*********/ + +/****f* Component Library: Vector/cl_vector_set_min_size +* NAME +* cl_vector_set_min_size +* +* DESCRIPTION +* The cl_vector_set_min_size function resizes a vector to a specified size +* if the vector is smaller than the specified size. +* +* SYNOPSIS +*/ +cl_status_t +cl_vector_set_min_size(IN cl_vector_t * const p_vector, + IN const size_t min_size); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure whose minimum size to set. +* +* min_size +* [in] Minimum number of elements that the vector should contain. +* +* RETURN VALUES +* CL_SUCCESS if the vector size is greater than or equal to min_size. This +* could indicate that the vector's capacity was increased to min_size or +* that the vector was already of sufficient size. +* +* CL_INSUFFICIENT_MEMORY if there was not enough memory to resize the vector. +* The vector is left unchanged. +* +* NOTES +* If min_size is smaller than the current size of the vector, the vector is +* unchanged. The vector is unchanged if the size could not be changed due +* to insufficient memory being available to perform the operation. +* +* SEE ALSO +* Vector, cl_vector_get_size, cl_vector_set_size, cl_vector_set_capacity +*********/ + +/****f* Component Library: Vector/cl_vector_apply_func +* NAME +* cl_vector_apply_func +* +* DESCRIPTION +* The cl_vector_apply_func function invokes a specified function for every +* element in a vector. +* +* SYNOPSIS +*/ +void +cl_vector_apply_func(IN const cl_vector_t * const p_vector, + IN cl_pfn_vec_apply_t pfn_callback, + IN const void *const context); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure whose elements to iterate. +* +* pfn_callback +* [in] Function invoked for every element in the array. +* See the cl_pfn_vec_apply_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback function. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* cl_vector_apply_func invokes the specified function for every element +* in the vector, starting from the beginning of the vector. +* +* SEE ALSO +* Vector, cl_vector_find_from_start, cl_vector_find_from_end, +* cl_pfn_vec_apply_t +*********/ + +/****f* Component Library: Vector/cl_vector_find_from_start +* NAME +* cl_vector_find_from_start +* +* DESCRIPTION +* The cl_vector_find_from_start function uses a specified function to +* search for elements in a vector starting from the lowest index. +* +* SYNOPSIS +*/ +size_t +cl_vector_find_from_start(IN const cl_vector_t * const p_vector, + IN cl_pfn_vec_find_t pfn_callback, + IN const void *const context); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure to inititalize. +* +* pfn_callback +* [in] Function invoked to determine if a match was found. +* See the cl_pfn_vec_find_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback function. +* +* RETURN VALUES +* Index of the element, if found. +* +* Size of the vector if the element was not found. +* +* NOTES +* cl_vector_find_from_start does not remove the found element from +* the vector. The index of the element is returned when the function +* provided by the pfn_callback parameter returns CL_SUCCESS. +* +* SEE ALSO +* Vector, cl_vector_find_from_end, cl_vector_apply_func, cl_pfn_vec_find_t +*********/ + +/****f* Component Library: Vector/cl_vector_find_from_end +* NAME +* cl_vector_find_from_end +* +* DESCRIPTION +* The cl_vector_find_from_end function uses a specified function to search +* for elements in a vector starting from the highest index. +* +* SYNOPSIS +*/ +size_t +cl_vector_find_from_end(IN const cl_vector_t * const p_vector, + IN cl_pfn_vec_find_t pfn_callback, + IN const void *const context); +/* +* PARAMETERS +* p_vector +* [in] Pointer to a cl_vector_t structure to inititalize. +* +* pfn_callback +* [in] Function invoked to determine if a match was found. +* See the cl_pfn_vec_find_t function type declaration for details +* about the callback function. +* +* context +* [in] Value to pass to the callback function. +* +* RETURN VALUES +* Index of the element, if found. +* +* Size of the vector if the element was not found. +* +* NOTES +* cl_vector_find_from_end does not remove the found element from +* the vector. The index of the element is returned when the function +* provided by the pfn_callback parameter returns CL_SUCCESS. +* +* SEE ALSO +* Vector, cl_vector_find_from_start, cl_vector_apply_func, +* cl_pfn_vec_find_t +*********/ + +END_C_DECLS +#endif /* _CL_VECTOR_H_ */ diff --git a/contrib/ofed/management/opensm/include/iba/ib_cm_types.h b/contrib/ofed/management/opensm/include/iba/ib_cm_types.h new file mode 100644 index 000000000000..c1fbfafd2330 --- /dev/null +++ b/contrib/ofed/management/opensm/include/iba/ib_cm_types.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if !defined(__IB_CM_TYPES_H__) +#define __IB_CM_TYPES_H__ + +#ifndef WIN32 + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + * Defines known Communication management class versions + */ +#define IB_MCLASS_CM_VER_2 2 +#define IB_MCLASS_CM_VER_1 1 +/* + * Defines the size of user available data in communication management MADs + */ +#define IB_REQ_PDATA_SIZE_VER2 92 +#define IB_MRA_PDATA_SIZE_VER2 222 +#define IB_REJ_PDATA_SIZE_VER2 148 +#define IB_REP_PDATA_SIZE_VER2 196 +#define IB_RTU_PDATA_SIZE_VER2 224 +#define IB_LAP_PDATA_SIZE_VER2 168 +#define IB_APR_PDATA_SIZE_VER2 148 +#define IB_DREQ_PDATA_SIZE_VER2 220 +#define IB_DREP_PDATA_SIZE_VER2 224 +#define IB_SIDR_REQ_PDATA_SIZE_VER2 216 +#define IB_SIDR_REP_PDATA_SIZE_VER2 136 +#define IB_REQ_PDATA_SIZE_VER1 92 +#define IB_MRA_PDATA_SIZE_VER1 222 +#define IB_REJ_PDATA_SIZE_VER1 148 +#define IB_REP_PDATA_SIZE_VER1 204 +#define IB_RTU_PDATA_SIZE_VER1 224 +#define IB_LAP_PDATA_SIZE_VER1 168 +#define IB_APR_PDATA_SIZE_VER1 151 +#define IB_DREQ_PDATA_SIZE_VER1 220 +#define IB_DREP_PDATA_SIZE_VER1 224 +#define IB_SIDR_REQ_PDATA_SIZE_VER1 216 +#define IB_SIDR_REP_PDATA_SIZE_VER1 140 +#define IB_ARI_SIZE 72 // redefine +#define IB_APR_INFO_SIZE 72 +/****d* Access Layer/ib_rej_status_t +* NAME +* ib_rej_status_t +* +* DESCRIPTION +* Rejection reasons. +* +* SYNOPSIS +*/ +typedef ib_net16_t ib_rej_status_t; +/* +* SEE ALSO +* ib_cm_rej, ib_cm_rej_rec_t +* +* SOURCE +*/ +#define IB_REJ_INSUF_QP CL_HTON16(1) +#define IB_REJ_INSUF_EEC CL_HTON16(2) +#define IB_REJ_INSUF_RESOURCES CL_HTON16(3) +#define IB_REJ_TIMEOUT CL_HTON16(4) +#define IB_REJ_UNSUPPORTED CL_HTON16(5) +#define IB_REJ_INVALID_COMM_ID CL_HTON16(6) +#define IB_REJ_INVALID_COMM_INSTANCE CL_HTON16(7) +#define IB_REJ_INVALID_SID CL_HTON16(8) +#define IB_REJ_INVALID_XPORT CL_HTON16(9) +#define IB_REJ_STALE_CONN CL_HTON16(10) +#define IB_REJ_RDC_NOT_EXIST CL_HTON16(11) +#define IB_REJ_INVALID_GID CL_HTON16(12) +#define IB_REJ_INVALID_LID CL_HTON16(13) +#define IB_REJ_INVALID_SL CL_HTON16(14) +#define IB_REJ_INVALID_TRAFFIC_CLASS CL_HTON16(15) +#define IB_REJ_INVALID_HOP_LIMIT CL_HTON16(16) +#define IB_REJ_INVALID_PKT_RATE CL_HTON16(17) +#define IB_REJ_INVALID_ALT_GID CL_HTON16(18) +#define IB_REJ_INVALID_ALT_LID CL_HTON16(19) +#define IB_REJ_INVALID_ALT_SL CL_HTON16(20) +#define IB_REJ_INVALID_ALT_TRAFFIC_CLASS CL_HTON16(21) +#define IB_REJ_INVALID_ALT_HOP_LIMIT CL_HTON16(22) +#define IB_REJ_INVALID_ALT_PKT_RATE CL_HTON16(23) +#define IB_REJ_PORT_REDIRECT CL_HTON16(24) +#define IB_REJ_INVALID_MTU CL_HTON16(26) +#define IB_REJ_INSUFFICIENT_RESP_RES CL_HTON16(27) +#define IB_REJ_USER_DEFINED CL_HTON16(28) +#define IB_REJ_INVALID_RNR_RETRY CL_HTON16(29) +#define IB_REJ_DUPLICATE_LOCAL_COMM_ID CL_HTON16(30) +#define IB_REJ_INVALID_CLASS_VER CL_HTON16(31) +#define IB_REJ_INVALID_FLOW_LBL CL_HTON16(32) +#define IB_REJ_INVALID_ALT_FLOW_LBL CL_HTON16(33) + +#define IB_REJ_SERVICE_HANDOFF CL_HTON16(65535) +/******/ + +/****d* Access Layer/ib_apr_status_t +* NAME +* ib_apr_status_t +* +* DESCRIPTION +* Automatic path migration status information. +* +* SYNOPSIS +*/ +typedef uint8_t ib_apr_status_t; +/* +* SEE ALSO +* ib_cm_apr, ib_cm_apr_rec_t +* +* SOURCE + */ +#define IB_AP_SUCCESS 0 +#define IB_AP_INVALID_COMM_ID 1 +#define IB_AP_UNSUPPORTED 2 +#define IB_AP_REJECT 3 +#define IB_AP_REDIRECT 4 +#define IB_AP_IS_CURRENT 5 +#define IB_AP_INVALID_QPN_EECN 6 +#define IB_AP_INVALID_LID 7 +#define IB_AP_INVALID_GID 8 +#define IB_AP_INVALID_FLOW_LBL 9 +#define IB_AP_INVALID_TCLASS 10 +#define IB_AP_INVALID_HOP_LIMIT 11 +#define IB_AP_INVALID_PKT_RATE 12 +#define IB_AP_INVALID_SL 13 +/******/ + +/****d* Access Layer/ib_cm_cap_mask_t +* NAME +* ib_cm_cap_mask_t +* +* DESCRIPTION +* Capability mask values in ClassPortInfo. +* +* SYNOPSIS +*/ +#define IB_CM_RELIABLE_CONN_CAPABLE CL_HTON16(9) +#define IB_CM_RELIABLE_DGRM_CAPABLE CL_HTON16(10) +#define IB_CM_RDGRM_CAPABLE CL_HTON16(11) +#define IB_CM_UNRELIABLE_CONN_CAPABLE CL_HTON16(12) +#define IB_CM_SIDR_CAPABLE CL_HTON16(13) +/* +* SEE ALSO +* ib_cm_rep, ib_class_port_info_t +* +* SOURCE +* +*******/ + +/* + * Service ID resolution status + */ +typedef uint16_t ib_sidr_status_t; +#define IB_SIDR_SUCCESS 0 +#define IB_SIDR_UNSUPPORTED 1 +#define IB_SIDR_REJECT 2 +#define IB_SIDR_NO_QP 3 +#define IB_SIDR_REDIRECT 4 +#define IB_SIDR_UNSUPPORTED_VER 5 + +END_C_DECLS +#endif /* ndef WIN32 */ +#endif /* __IB_CM_TYPES_H__ */ diff --git a/contrib/ofed/management/opensm/include/iba/ib_types.h b/contrib/ofed/management/opensm/include/iba/ib_types.h new file mode 100644 index 000000000000..0f9d11023dde --- /dev/null +++ b/contrib/ofed/management/opensm/include/iba/ib_types.h @@ -0,0 +1,10720 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if !defined(__IB_TYPES_H__) +#define __IB_TYPES_H__ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#if defined( WIN32 ) || defined( _WIN64 ) +#if defined( EXPORT_AL_SYMBOLS ) +#define OSM_EXPORT __declspec(dllexport) +#else +#define OSM_EXPORT __declspec(dllimport) +#endif +#define OSM_API __stdcall +#define OSM_CDECL __cdecl +#else +#define OSM_EXPORT extern +#define OSM_API +#define OSM_CDECL +#define __ptr64 +#endif +/****h* IBA Base/Constants +* NAME +* Constants +* +* DESCRIPTION +* The following constants are used throughout the IBA code base. +* +* Definitions are from the InfiniBand Architecture Specification v1.2 +* +*********/ +/****d* IBA Base: Constants/MAD_BLOCK_SIZE +* NAME +* MAD_BLOCK_SIZE +* +* DESCRIPTION +* Size of a non-RMPP MAD datagram. +* +* SOURCE +*/ +#define MAD_BLOCK_SIZE 256 +/**********/ +/****d* IBA Base: Constants/MAD_RMPP_HDR_SIZE +* NAME +* MAD_RMPP_HDR_SIZE +* +* DESCRIPTION +* Size of an RMPP header, including the common MAD header. +* +* SOURCE +*/ +#define MAD_RMPP_HDR_SIZE 36 +/**********/ +/****d* IBA Base: Constants/MAD_RMPP_DATA_SIZE +* NAME +* MAD_RMPP_DATA_SIZE +* +* DESCRIPTION +* Size of an RMPP transaction data section. +* +* SOURCE +*/ +#define MAD_RMPP_DATA_SIZE (MAD_BLOCK_SIZE - MAD_RMPP_HDR_SIZE) +/**********/ +/****d* IBA Base: Constants/MAD_BLOCK_GRH_SIZE +* NAME +* MAD_BLOCK_GRH_SIZE +* +* DESCRIPTION +* Size of a MAD datagram, including the GRH. +* +* SOURCE +*/ +#define MAD_BLOCK_GRH_SIZE 296 +/**********/ +/****d* IBA Base: Constants/IB_LID_PERMISSIVE +* NAME +* IB_LID_PERMISSIVE +* +* DESCRIPTION +* Permissive LID +* +* SOURCE +*/ +#define IB_LID_PERMISSIVE 0xFFFF +/**********/ +/****d* IBA Base: Constants/IB_DEFAULT_PKEY +* NAME +* IB_DEFAULT_PKEY +* +* DESCRIPTION +* P_Key value for the default partition. +* +* SOURCE +*/ +#define IB_DEFAULT_PKEY 0xFFFF +/**********/ +/****d* IBA Base: Constants/IB_QP1_WELL_KNOWN_Q_KEY +* NAME +* IB_QP1_WELL_KNOWN_Q_KEY +* +* DESCRIPTION +* Well-known Q_Key for QP1 privileged mode access (15.4.2). +* +* SOURCE +*/ +#define IB_QP1_WELL_KNOWN_Q_KEY CL_HTON32(0x80010000) +/*********/ +#define IB_QP0 0 +#define IB_QP1 CL_HTON32(1) +#define IB_QP_PRIVILEGED_Q_KEY CL_HTON32(0x80000000) +/****d* IBA Base: Constants/IB_LID_UCAST_START +* NAME +* IB_LID_UCAST_START +* +* DESCRIPTION +* Lowest valid unicast LID value. +* +* SOURCE +*/ +#define IB_LID_UCAST_START_HO 0x0001 +#define IB_LID_UCAST_START (CL_HTON16(IB_LID_UCAST_START_HO)) +/**********/ +/****d* IBA Base: Constants/IB_LID_UCAST_END +* NAME +* IB_LID_UCAST_END +* +* DESCRIPTION +* Highest valid unicast LID value. +* +* SOURCE +*/ +#define IB_LID_UCAST_END_HO 0xBFFF +#define IB_LID_UCAST_END (CL_HTON16(IB_LID_UCAST_END_HO)) +/**********/ +/****d* IBA Base: Constants/IB_LID_MCAST_START +* NAME +* IB_LID_MCAST_START +* +* DESCRIPTION +* Lowest valid multicast LID value. +* +* SOURCE +*/ +#define IB_LID_MCAST_START_HO 0xC000 +#define IB_LID_MCAST_START (CL_HTON16(IB_LID_MCAST_START_HO)) +/**********/ +/****d* IBA Base: Constants/IB_LID_MCAST_END +* NAME +* IB_LID_MCAST_END +* +* DESCRIPTION +* Highest valid multicast LID value. +* +* SOURCE +*/ +#define IB_LID_MCAST_END_HO 0xFFFE +#define IB_LID_MCAST_END (CL_HTON16(IB_LID_MCAST_END_HO)) +/**********/ +/****d* IBA Base: Constants/IB_DEFAULT_SUBNET_PREFIX +* NAME +* IB_DEFAULT_SUBNET_PREFIX +* +* DESCRIPTION +* Default subnet GID prefix. +* +* SOURCE +*/ +#define IB_DEFAULT_SUBNET_PREFIX (CL_HTON64(0xFE80000000000000ULL)) +/**********/ +/****d* IBA Base: Constants/IB_NODE_NUM_PORTS_MAX +* NAME +* IB_NODE_NUM_PORTS_MAX +* +* DESCRIPTION +* Maximum number of ports in a single node (14.2.5.7). +* SOURCE +*/ +#define IB_NODE_NUM_PORTS_MAX 0xFE +/**********/ +/****d* IBA Base: Constants/IB_INVALID_PORT_NUM +* NAME +* IB_INVALID_PORT_NUM +* +* DESCRIPTION +* Value used to indicate an invalid port number (14.2.5.10). +* +* SOURCE +*/ +#define IB_INVALID_PORT_NUM 0xFF +/*********/ +/****d* IBA Base: Constants/IB_SUBNET_PATH_HOPS_MAX +* NAME +* IB_SUBNET_PATH_HOPS_MAX +* +* DESCRIPTION +* Maximum number of directed route switch hops in a subnet (14.2.1.2). +* +* SOURCE +*/ +#define IB_SUBNET_PATH_HOPS_MAX 64 +/*********/ +/****d* IBA Base: Constants/IB_HOPLIMIT_MAX +* NAME +* IB_HOPLIMIT_MAX +* +* DESCRIPTION +* Maximum number of router hops allowed. +* +* SOURCE +*/ +#define IB_HOPLIMIT_MAX 255 +/*********/ +/****d* IBA Base: Constants/IB_MC_SCOPE_* +* NAME +* IB_MC_SCOPE_* +* +* DESCRIPTION +* Scope component definitions from IBA 1.2 (Table 3 p. 146) +*/ +#define IB_MC_SCOPE_LINK_LOCAL 0x2 +#define IB_MC_SCOPE_SITE_LOCAL 0x5 +#define IB_MC_SCOPE_ORG_LOCAL 0x8 +#define IB_MC_SCOPE_GLOBAL 0xE +/*********/ +/****d* IBA Base: Constants/IB_PKEY_MAX_BLOCKS +* NAME +* IB_PKEY_MAX_BLOCKS +* +* DESCRIPTION +* Maximum number of PKEY blocks (14.2.5.7). +* +* SOURCE +*/ +#define IB_PKEY_MAX_BLOCKS 2048 +/*********/ +/****d* IBA Base: Constants/IB_MCAST_MAX_BLOCK_ID +* NAME +* IB_MCAST_MAX_BLOCK_ID +* +* DESCRIPTION +* Maximum number of Multicast port mask blocks +* +* SOURCE +*/ +#define IB_MCAST_MAX_BLOCK_ID 511 +/*********/ +/****d* IBA Base: Constants/IB_MCAST_BLOCK_ID_MASK_HO +* NAME +* IB_MCAST_BLOCK_ID_MASK_HO +* +* DESCRIPTION +* Mask (host order) to recover the Multicast block ID. +* +* SOURCE +*/ +#define IB_MCAST_BLOCK_ID_MASK_HO 0x000001FF +/*********/ +/****d* IBA Base: Constants/IB_MCAST_BLOCK_SIZE +* NAME +* IB_MCAST_BLOCK_SIZE +* +* DESCRIPTION +* Number of port mask entries in a multicast forwarding table block. +* +* SOURCE +*/ +#define IB_MCAST_BLOCK_SIZE 32 +/*********/ +/****d* IBA Base: Constants/IB_MCAST_MASK_SIZE +* NAME +* IB_MCAST_MASK_SIZE +* +* DESCRIPTION +* Number of port mask bits in each entry in the multicast forwarding table. +* +* SOURCE +*/ +#define IB_MCAST_MASK_SIZE 16 +/*********/ +/****d* IBA Base: Constants/IB_MCAST_POSITION_MASK_HO +* NAME +* IB_MCAST_POSITION_MASK_HO +* +* DESCRIPTION +* Mask (host order) to recover the multicast block position. +* +* SOURCE +*/ +#define IB_MCAST_POSITION_MASK_HO 0xF0000000 +/*********/ +/****d* IBA Base: Constants/IB_MCAST_POSITION_MAX +* NAME +* IB_MCAST_POSITION_MAX +* +* DESCRIPTION +* Maximum value for the multicast block position. +* +* SOURCE +*/ +#define IB_MCAST_POSITION_MAX 0xF +/*********/ +/****d* IBA Base: Constants/IB_MCAST_POSITION_SHIFT +* NAME +* IB_MCAST_POSITION_SHIFT +* +* DESCRIPTION +* Shift value to normalize the multicast block position value. +* +* SOURCE +*/ +#define IB_MCAST_POSITION_SHIFT 28 +/*********/ +/****d* IBA Base: Constants/IB_PKEY_ENTRIES_MAX +* NAME +* IB_PKEY_ENTRIES_MAX +* +* DESCRIPTION +* Maximum number of PKEY entries per port (14.2.5.7). +* +* SOURCE +*/ +#define IB_PKEY_ENTRIES_MAX (IB_PKEY_MAX_BLOCKS * IB_NUM_PKEY_ELEMENTS_IN_BLOCK) +/*********/ +/****d* IBA Base: Constants/IB_PKEY_BASE_MASK +* NAME +* IB_PKEY_BASE_MASK +* +* DESCRIPTION +* Masks for the base P_Key value given a P_Key Entry. +* +* SOURCE +*/ +#define IB_PKEY_BASE_MASK (CL_HTON16(0x7FFF)) +/*********/ +/****d* IBA Base: Constants/IB_PKEY_TYPE_MASK +* NAME +* IB_PKEY_TYPE_MASK +* +* DESCRIPTION +* Masks for the P_Key membership type given a P_Key Entry. +* +* SOURCE +*/ +#define IB_PKEY_TYPE_MASK (CL_HTON16(0x8000)) +/*********/ +/****d* IBA Base: Constants/IB_DEFAULT_PARTIAL_PKEY +* NAME +* IB_DEFAULT_PARTIAL_PKEY +* +* DESCRIPTION +* 0x7FFF in network order +* +* SOURCE +*/ +#define IB_DEFAULT_PARTIAL_PKEY (CL_HTON16(0x7FFF)) +/**********/ +/****d* IBA Base: Constants/IB_MCLASS_SUBN_LID +* NAME +* IB_MCLASS_SUBN_LID +* +* DESCRIPTION +* Subnet Management Class, Subnet Manager LID routed (13.4.4) +* +* SOURCE +*/ +#define IB_MCLASS_SUBN_LID 0x01 +/**********/ +/****d* IBA Base: Constants/IB_MCLASS_SUBN_DIR +* NAME +* IB_MCLASS_SUBN_DIR +* +* DESCRIPTION +* Subnet Management Class, Subnet Manager directed route (13.4.4) +* +* SOURCE +*/ +#define IB_MCLASS_SUBN_DIR 0x81 +/**********/ +/****d* IBA Base: Constants/IB_MCLASS_SUBN_ADM +* NAME +* IB_MCLASS_SUBN_ADM +* +* DESCRIPTION +* Management Class, Subnet Administration (13.4.4) +* +* SOURCE +*/ +#define IB_MCLASS_SUBN_ADM 0x03 +/**********/ +/****d* IBA Base: Constants/IB_MCLASS_PERF +* NAME +* IB_MCLASS_PERF +* +* DESCRIPTION +* Management Class, Performance Management (13.4.4) +* +* SOURCE +*/ +#define IB_MCLASS_PERF 0x04 +/**********/ +/****d* IBA Base: Constants/IB_MCLASS_BM +* NAME +* IB_MCLASS_BM +* +* DESCRIPTION +* Management Class, Baseboard Management (13.4.4) +* +* SOURCE +*/ +#define IB_MCLASS_BM 0x05 +/**********/ +/****d* IBA Base: Constants/IB_MCLASS_DEV_MGMT +* NAME +* IB_MCLASS_DEV_MGMT +* +* DESCRIPTION +* Management Class, Device Management (13.4.4) +* +* SOURCE +*/ +#define IB_MCLASS_DEV_MGMT 0x06 +/**********/ +/****d* IBA Base: Constants/IB_MCLASS_COMM_MGMT +* NAME +* IB_MCLASS_COMM_MGMT +* +* DESCRIPTION +* Management Class, Communication Management (13.4.4) +* +* SOURCE +*/ +#define IB_MCLASS_COMM_MGMT 0x07 +/**********/ +/****d* IBA Base: Constants/IB_MCLASS_SNMP +* NAME +* IB_MCLASS_SNMP +* +* DESCRIPTION +* Management Class, SNMP Tunneling (13.4.4) +* +* SOURCE +*/ +#define IB_MCLASS_SNMP 0x08 +/**********/ +/****d* IBA Base: Constants/IB_MCLASS_VENDOR_LOW_RANGE_MIN +* NAME +* IB_MCLASS_VENDOR_LOW_RANGE_MIN +* +* DESCRIPTION +* Management Class, Vendor Specific Low Range Start +* +* SOURCE +*/ +#define IB_MCLASS_VENDOR_LOW_RANGE_MIN 0x09 +/**********/ +/****d* IBA Base: Constants/IB_MCLASS_VENDOR_LOW_RANGE_MAX +* NAME +* IB_MCLASS_VENDOR_LOW_RANGE_MAX +* +* DESCRIPTION +* Management Class, Vendor Specific Low Range End +* +* SOURCE +*/ +#define IB_MCLASS_VENDOR_LOW_RANGE_MAX 0x0f +/**********/ +/****d* IBA Base: Constants/IB_MCLASS_DEV_ADM +* NAME +* IB_MCLASS_DEV_ADM +* +* DESCRIPTION +* Management Class, Device Administration +* +* SOURCE +*/ +#define IB_MCLASS_DEV_ADM 0x10 +/**********/ +/****d* IBA Base: Constants/IB_MCLASS_BIS +* NAME +* IB_MCLASS_BIS +* +* DESCRIPTION +* Management Class, BIS +* +* SOURCE +*/ +#define IB_MCLASS_BIS 0x12 +/**********/ +/****d* IBA Base: Constants/IB_MCLASS_VENDOR_HIGH_RANGE_MIN +* NAME +* IB_MCLASS_VENDOR_HIGH_RANGE_MIN +* +* DESCRIPTION +* Management Class, Vendor Specific High Range Start +* +* SOURCE +*/ +#define IB_MCLASS_VENDOR_HIGH_RANGE_MIN 0x30 +/**********/ +/****d* IBA Base: Constants/IB_MCLASS_VENDOR_HIGH_RANGE_MAX +* NAME +* IB_MCLASS_VENDOR_HIGH_RANGE_MAX +* +* DESCRIPTION +* Management Class, Vendor Specific High Range End +* +* SOURCE +*/ +#define IB_MCLASS_VENDOR_HIGH_RANGE_MAX 0x4f +/**********/ +/****f* IBA Base: Types/ib_class_is_vendor_specific_low +* NAME +* ib_class_is_vendor_specific_low +* +* DESCRIPTION +* Indicates if the Class Code if a vendor specific class from +* the low range +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_class_is_vendor_specific_low(IN const uint8_t class_code) +{ + return ((class_code >= IB_MCLASS_VENDOR_LOW_RANGE_MIN) && + (class_code <= IB_MCLASS_VENDOR_LOW_RANGE_MAX)); +} + +/* +* PARAMETERS +* class_code +* [in] The Management Datagram Class Code +* +* RETURN VALUE +* TRUE if the class is in the Low range of Vendor Specific MADs +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* IB_MCLASS_VENDOR_LOW_RANGE_MIN, IB_MCLASS_VENDOR_LOW_RANGE_MAX +*********/ + +/****f* IBA Base: Types/ib_class_is_vendor_specific_high +* NAME +* ib_class_is_vendor_specific_high +* +* DESCRIPTION +* Indicates if the Class Code if a vendor specific class from +* the high range +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_class_is_vendor_specific_high(IN const uint8_t class_code) +{ + return ((class_code >= IB_MCLASS_VENDOR_HIGH_RANGE_MIN) && + (class_code <= IB_MCLASS_VENDOR_HIGH_RANGE_MAX)); +} + +/* +* PARAMETERS +* class_code +* [in] The Management Datagram Class Code +* +* RETURN VALUE +* TRUE if the class is in the High range of Vendor Specific MADs +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* IB_MCLASS_VENDOR_HIGH_RANGE_MIN, IB_MCLASS_VENDOR_HIGH_RANGE_MAX +*********/ + +/****f* IBA Base: Types/ib_class_is_vendor_specific +* NAME +* ib_class_is_vendor_specific +* +* DESCRIPTION +* Indicates if the Class Code if a vendor specific class +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_class_is_vendor_specific(IN const uint8_t class_code) +{ + return (ib_class_is_vendor_specific_low(class_code) || + ib_class_is_vendor_specific_high(class_code)); +} + +/* +* PARAMETERS +* class_code +* [in] The Management Datagram Class Code +* +* RETURN VALUE +* TRUE if the class is a Vendor Specific MAD +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* ib_class_is_vendor_specific_low, ib_class_is_vendor_specific_high +*********/ + +/****f* IBA Base: Types/ib_class_is_rmpp +* NAME +* ib_class_is_rmpp +* +* DESCRIPTION +* Indicates if the Class Code supports RMPP +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API ib_class_is_rmpp(IN const uint8_t class_code) +{ + return ((class_code == IB_MCLASS_SUBN_ADM) || + (class_code == IB_MCLASS_DEV_MGMT) || + (class_code == IB_MCLASS_DEV_ADM) || + (class_code == IB_MCLASS_BIS) || + ib_class_is_vendor_specific_high(class_code)); +} + +/* +* PARAMETERS +* class_code +* [in] The Management Datagram Class Code +* +* RETURN VALUE +* TRUE if the class supports RMPP +* FALSE otherwise. +* +* NOTES +* +*********/ + +/* + * MAD methods + */ + +/****d* IBA Base: Constants/IB_MAX_METHOD +* NAME +* IB_MAX_METHOD +* +* DESCRIPTION +* Total number of methods available to a class, not including the R-bit. +* +* SOURCE +*/ +#define IB_MAX_METHODS 128 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_RESP_MASK +* NAME +* IB_MAD_METHOD_RESP_MASK +* +* DESCRIPTION +* Response mask to extract 'R' bit from the method field. (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_RESP_MASK 0x80 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_GET +* NAME +* IB_MAD_METHOD_GET +* +* DESCRIPTION +* Get() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_GET 0x01 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_SET +* NAME +* IB_MAD_METHOD_SET +* +* DESCRIPTION +* Set() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_SET 0x02 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_GET_RESP +* NAME +* IB_MAD_METHOD_GET_RESP +* +* DESCRIPTION +* GetResp() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_GET_RESP 0x81 +/**********/ + +#define IB_MAD_METHOD_DELETE 0x15 + +/****d* IBA Base: Constants/IB_MAD_METHOD_GETTABLE +* NAME +* IB_MAD_METHOD_GETTABLE +* +* DESCRIPTION +* SubnAdmGetTable() Method (15.2.2) +* +* SOURCE +*/ +#define IB_MAD_METHOD_GETTABLE 0x12 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_GETTABLE_RESP +* NAME +* IB_MAD_METHOD_GETTABLE_RESP +* +* DESCRIPTION +* SubnAdmGetTableResp() Method (15.2.2) +* +* SOURCE +*/ +#define IB_MAD_METHOD_GETTABLE_RESP 0x92 + +/**********/ + +#define IB_MAD_METHOD_GETTRACETABLE 0x13 +#define IB_MAD_METHOD_GETMULTI 0x14 +#define IB_MAD_METHOD_GETMULTI_RESP 0x94 + +/****d* IBA Base: Constants/IB_MAD_METHOD_SEND +* NAME +* IB_MAD_METHOD_SEND +* +* DESCRIPTION +* Send() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_SEND 0x03 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_TRAP +* NAME +* IB_MAD_METHOD_TRAP +* +* DESCRIPTION +* Trap() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_TRAP 0x05 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_REPORT +* NAME +* IB_MAD_METHOD_REPORT +* +* DESCRIPTION +* Report() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_REPORT 0x06 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_REPORT_RESP +* NAME +* IB_MAD_METHOD_REPORT_RESP +* +* DESCRIPTION +* ReportResp() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_REPORT_RESP 0x86 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_METHOD_TRAP_REPRESS +* NAME +* IB_MAD_METHOD_TRAP_REPRESS +* +* DESCRIPTION +* TrapRepress() Method (13.4.5) +* +* SOURCE +*/ +#define IB_MAD_METHOD_TRAP_REPRESS 0x07 +/**********/ + +/****d* IBA Base: Constants/IB_MAD_STATUS_BUSY +* NAME +* IB_MAD_STATUS_BUSY +* +* DESCRIPTION +* Temporarily busy, MAD discarded (13.4.7) +* +* SOURCE +*/ +#define IB_MAD_STATUS_BUSY (CL_HTON16(0x0001)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_STATUS_REDIRECT +* NAME +* IB_MAD_STATUS_REDIRECT +* +* DESCRIPTION +* QP Redirection required (13.4.7) +* +* SOURCE +*/ +#define IB_MAD_STATUS_REDIRECT (CL_HTON16(0x0002)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_STATUS_UNSUP_CLASS_VER +* NAME +* IB_MAD_STATUS_UNSUP_CLASS_VER +* +* DESCRIPTION +* Unsupported class version (13.4.7) +* +* SOURCE +*/ +#define IB_MAD_STATUS_UNSUP_CLASS_VER (CL_HTON16(0x0004)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_STATUS_UNSUP_METHOD +* NAME +* IB_MAD_STATUS_UNSUP_METHOD +* +* DESCRIPTION +* Unsupported method (13.4.7) +* +* SOURCE +*/ +#define IB_MAD_STATUS_UNSUP_METHOD (CL_HTON16(0x0008)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_STATUS_UNSUP_METHOD_ATTR +* NAME +* IB_MAD_STATUS_UNSUP_METHOD_ATTR +* +* DESCRIPTION +* Unsupported method/attribute combination (13.4.7) +* +* SOURCE +*/ +#define IB_MAD_STATUS_UNSUP_METHOD_ATTR (CL_HTON16(0x000C)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_STATUS_INVALID_FIELD +* NAME +* IB_MAD_STATUS_INVALID_FIELD +* +* DESCRIPTION +* Attribute contains one or more invalid fields (13.4.7) +* +* SOURCE +*/ +#define IB_MAD_STATUS_INVALID_FIELD (CL_HTON16(0x001C)) +/**********/ + +#define IB_MAD_STATUS_CLASS_MASK (CL_HTON16(0xFF00)) + +#define IB_SA_MAD_STATUS_SUCCESS (CL_HTON16(0x0000)) +#define IB_SA_MAD_STATUS_NO_RESOURCES (CL_HTON16(0x0100)) +#define IB_SA_MAD_STATUS_REQ_INVALID (CL_HTON16(0x0200)) +#define IB_SA_MAD_STATUS_NO_RECORDS (CL_HTON16(0x0300)) +#define IB_SA_MAD_STATUS_TOO_MANY_RECORDS (CL_HTON16(0x0400)) +#define IB_SA_MAD_STATUS_INVALID_GID (CL_HTON16(0x0500)) +#define IB_SA_MAD_STATUS_INSUF_COMPS (CL_HTON16(0x0600)) +#define IB_SA_MAD_STATUS_DENIED (CL_HTON16(0x0700)) +#define IB_SA_MAD_STATUS_PRIO_SUGGESTED (CL_HTON16(0x0800)) + +#define IB_DM_MAD_STATUS_NO_IOC_RESP (CL_HTON16(0x0100)) +#define IB_DM_MAD_STATUS_NO_SVC_ENTRIES (CL_HTON16(0x0200)) +#define IB_DM_MAD_STATUS_IOC_FAILURE (CL_HTON16(0x8000)) + +/****d* IBA Base: Constants/IB_MAD_ATTR_CLASS_PORT_INFO +* NAME +* IB_MAD_ATTR_CLASS_PORT_INFO +* +* DESCRIPTION +* ClassPortInfo attribute (13.4.8) +* +* SOURCE +*/ +#define IB_MAD_ATTR_CLASS_PORT_INFO (CL_HTON16(0x0001)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_NOTICE +* NAME +* IB_MAD_ATTR_NOTICE +* +* DESCRIPTION +* Notice attribute (13.4.8) +* +* SOURCE +*/ +#define IB_MAD_ATTR_NOTICE (CL_HTON16(0x0002)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_INFORM_INFO +* NAME +* IB_MAD_ATTR_INFORM_INFO +* +* DESCRIPTION +* InformInfo attribute (13.4.8) +* +* SOURCE +*/ +#define IB_MAD_ATTR_INFORM_INFO (CL_HTON16(0x0003)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_NODE_DESC +* NAME +* IB_MAD_ATTR_NODE_DESC +* +* DESCRIPTION +* NodeDescription attribute (14.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_NODE_DESC (CL_HTON16(0x0010)) + +/****d* IBA Base: Constants/IB_MAD_ATTR_PORT_SMPL_CTRL +* NAME +* IB_MAD_ATTR_PORT_SMPL_CTRL +* +* DESCRIPTION +* PortSamplesControl attribute (16.1.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_PORT_SMPL_CTRL (CL_HTON16(0x0010)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_NODE_INFO +* NAME +* IB_MAD_ATTR_NODE_INFO +* +* DESCRIPTION +* NodeInfo attribute (14.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_NODE_INFO (CL_HTON16(0x0011)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_PORT_SMPL_RSLT +* NAME +* IB_MAD_ATTR_PORT_SMPL_RSLT +* +* DESCRIPTION +* PortSamplesResult attribute (16.1.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_PORT_SMPL_RSLT (CL_HTON16(0x0011)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_SWITCH_INFO +* NAME +* IB_MAD_ATTR_SWITCH_INFO +* +* DESCRIPTION +* SwitchInfo attribute (14.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_SWITCH_INFO (CL_HTON16(0x0012)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_PORT_CNTRS +* NAME +* IB_MAD_ATTR_PORT_CNTRS +* +* DESCRIPTION +* PortCounters attribute (16.1.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_PORT_CNTRS (CL_HTON16(0x0012)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_GUID_INFO +* NAME +* IB_MAD_ATTR_GUID_INFO +* +* DESCRIPTION +* GUIDInfo attribute (14.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_GUID_INFO (CL_HTON16(0x0014)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_PORT_INFO +* NAME +* IB_MAD_ATTR_PORT_INFO +* +* DESCRIPTION +* PortInfo attribute (14.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_PORT_INFO (CL_HTON16(0x0015)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_P_KEY_TABLE +* NAME +* IB_MAD_ATTR_P_KEY_TABLE +* +* DESCRIPTION +* PartitionTable attribute (14.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_P_KEY_TABLE (CL_HTON16(0x0016)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_SLVL_TABLE +* NAME +* IB_MAD_ATTR_SLVL_TABLE +* +* DESCRIPTION +* SL VL Mapping Table attribute (14.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_SLVL_TABLE (CL_HTON16(0x0017)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_VL_ARBITRATION +* NAME +* IB_MAD_ATTR_VL_ARBITRATION +* +* DESCRIPTION +* VL Arbitration Table attribute (14.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_VL_ARBITRATION (CL_HTON16(0x0018)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_LIN_FWD_TBL +* NAME +* IB_MAD_ATTR_LIN_FWD_TBL +* +* DESCRIPTION +* Switch linear forwarding table +* +* SOURCE +*/ +#define IB_MAD_ATTR_LIN_FWD_TBL (CL_HTON16(0x0019)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_RND_FWD_TBL +* NAME +* IB_MAD_ATTR_RND_FWD_TBL +* +* DESCRIPTION +* Switch random forwarding table +* +* SOURCE +*/ +#define IB_MAD_ATTR_RND_FWD_TBL (CL_HTON16(0x001A)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_MCAST_FWD_TBL +* NAME +* IB_MAD_ATTR_MCAST_FWD_TBL +* +* DESCRIPTION +* Switch multicast forwarding table +* +* SOURCE +*/ +#define IB_MAD_ATTR_MCAST_FWD_TBL (CL_HTON16(0x001B)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_NODE_RECORD +* NAME +* IB_MAD_ATTR_NODE_RECORD +* +* DESCRIPTION +* NodeRecord attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_NODE_RECORD (CL_HTON16(0x0011)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_PORTINFO_RECORD +* NAME +* IB_MAD_ATTR_PORTINFO_RECORD +* +* DESCRIPTION +* PortInfoRecord attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_PORTINFO_RECORD (CL_HTON16(0x0012)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_SWITCH_INFO_RECORD +* NAME +* IB_MAD_ATTR_SWITCH_INFO_RECORD +* +* DESCRIPTION +* SwitchInfoRecord attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_SWITCH_INFO_RECORD (CL_HTON16(0x0014)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_LINK_RECORD +* NAME +* IB_MAD_ATTR_LINK_RECORD +* +* DESCRIPTION +* LinkRecord attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_LINK_RECORD (CL_HTON16(0x0020)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_SM_INFO +* NAME +* IB_MAD_ATTR_SM_INFO +* +* DESCRIPTION +* SMInfo attribute (14.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_SM_INFO (CL_HTON16(0x0020)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_SMINFO_RECORD +* NAME +* IB_MAD_ATTR_SMINFO_RECORD +* +* DESCRIPTION +* SMInfoRecord attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_SMINFO_RECORD (CL_HTON16(0x0018)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_GUIDINFO_RECORD +* NAME +* IB_MAD_ATTR_GUIDINFO_RECORD +* +* DESCRIPTION +* GuidInfoRecord attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_GUIDINFO_RECORD (CL_HTON16(0x0030)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_VENDOR_DIAG +* NAME +* IB_MAD_ATTR_VENDOR_DIAG +* +* DESCRIPTION +* VendorDiag attribute (14.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_VENDOR_DIAG (CL_HTON16(0x0030)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_LED_INFO +* NAME +* IB_MAD_ATTR_LED_INFO +* +* DESCRIPTION +* LedInfo attribute (14.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_LED_INFO (CL_HTON16(0x0031)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_SERVICE_RECORD +* NAME +* IB_MAD_ATTR_SERVICE_RECORD +* +* DESCRIPTION +* ServiceRecord attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_SERVICE_RECORD (CL_HTON16(0x0031)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_LFT_RECORD +* NAME +* IB_MAD_ATTR_LFT_RECORD +* +* DESCRIPTION +* LinearForwardingTableRecord attribute (15.2.5.6) +* +* SOURCE +*/ +#define IB_MAD_ATTR_LFT_RECORD (CL_HTON16(0x0015)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_MFT_RECORD +* NAME +* IB_MAD_ATTR_MFT_RECORD +* +* DESCRIPTION +* MulticastForwardingTableRecord attribute (15.2.5.8) +* +* SOURCE +*/ +#define IB_MAD_ATTR_MFT_RECORD (CL_HTON16(0x0017)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_PKEYTBL_RECORD +* NAME +* IB_MAD_ATTR_PKEYTBL_RECORD +* +* DESCRIPTION +* PKEY Table Record attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_PKEY_TBL_RECORD (CL_HTON16(0x0033)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_PATH_RECORD +* NAME +* IB_MAD_ATTR_PATH_RECORD +* +* DESCRIPTION +* PathRecord attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_PATH_RECORD (CL_HTON16(0x0035)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_VLARB_RECORD +* NAME +* IB_MAD_ATTR_VLARB_RECORD +* +* DESCRIPTION +* VL Arbitration Table Record attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_VLARB_RECORD (CL_HTON16(0x0036)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_SLVL_RECORD +* NAME +* IB_MAD_ATTR_SLVL_RECORD +* +* DESCRIPTION +* SLtoVL Mapping Table Record attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_SLVL_RECORD (CL_HTON16(0x0013)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_MCMEMBER_RECORD +* NAME +* IB_MAD_ATTR_MCMEMBER_RECORD +* +* DESCRIPTION +* MCMemberRecord attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_MCMEMBER_RECORD (CL_HTON16(0x0038)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_TRACE_RECORD +* NAME +* IB_MAD_ATTR_TRACE_RECORD +* +* DESCRIPTION +* TraceRecord attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_TRACE_RECORD (CL_HTON16(0x0039)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_MULTIPATH_RECORD +* NAME +* IB_MAD_ATTR_MULTIPATH_RECORD +* +* DESCRIPTION +* MultiPathRecord attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_MULTIPATH_RECORD (CL_HTON16(0x003A)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_SVC_ASSOCIATION_RECORD +* NAME +* IB_MAD_ATTR_SVC_ASSOCIATION_RECORD +* +* DESCRIPTION +* Service Association Record attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_SVC_ASSOCIATION_RECORD (CL_HTON16(0x003B)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_INFORM_INFO_RECORD +* NAME +* IB_MAD_ATTR_INFORM_INFO_RECORD +* +* DESCRIPTION +* InformInfo Record attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_INFORM_INFO_RECORD (CL_HTON16(0x00F3)) + +/****d* IBA Base: Constants/IB_MAD_ATTR_IO_UNIT_INFO +* NAME +* IB_MAD_ATTR_IO_UNIT_INFO +* +* DESCRIPTION +* IOUnitInfo attribute (16.3.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_IO_UNIT_INFO (CL_HTON16(0x0010)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_IO_CONTROLLER_PROFILE +* NAME +* IB_MAD_ATTR_IO_CONTROLLER_PROFILE +* +* DESCRIPTION +* IOControllerProfile attribute (16.3.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_IO_CONTROLLER_PROFILE (CL_HTON16(0x0011)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_SERVICE_ENTRIES +* NAME +* IB_MAD_ATTR_SERVICE_ENTRIES +* +* DESCRIPTION +* ServiceEntries attribute (16.3.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_SERVICE_ENTRIES (CL_HTON16(0x0012)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_DIAGNOSTIC_TIMEOUT +* NAME +* IB_MAD_ATTR_DIAGNOSTIC_TIMEOUT +* +* DESCRIPTION +* DiagnosticTimeout attribute (16.3.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_DIAGNOSTIC_TIMEOUT (CL_HTON16(0x0020)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_PREPARE_TO_TEST +* NAME +* IB_MAD_ATTR_PREPARE_TO_TEST +* +* DESCRIPTION +* PrepareToTest attribute (16.3.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_PREPARE_TO_TEST (CL_HTON16(0x0021)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_TEST_DEVICE_ONCE +* NAME +* IB_MAD_ATTR_TEST_DEVICE_ONCE +* +* DESCRIPTION +* TestDeviceOnce attribute (16.3.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_TEST_DEVICE_ONCE (CL_HTON16(0x0022)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_TEST_DEVICE_LOOP +* NAME +* IB_MAD_ATTR_TEST_DEVICE_LOOP +* +* DESCRIPTION +* TestDeviceLoop attribute (16.3.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_TEST_DEVICE_LOOP (CL_HTON16(0x0023)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_DIAG_CODE +* NAME +* IB_MAD_ATTR_DIAG_CODE +* +* DESCRIPTION +* DiagCode attribute (16.3.3) +* +* SOURCE +*/ +#define IB_MAD_ATTR_DIAG_CODE (CL_HTON16(0x0024)) +/**********/ + +/****d* IBA Base: Constants/IB_MAD_ATTR_SVC_ASSOCIATION_RECORD +* NAME +* IB_MAD_ATTR_SVC_ASSOCIATION_RECORD +* +* DESCRIPTION +* Service Association Record attribute (15.2.5) +* +* SOURCE +*/ +#define IB_MAD_ATTR_SVC_ASSOCIATION_RECORD (CL_HTON16(0x003B)) +/**********/ + +/****d* IBA Base: Constants/IB_NODE_TYPE_CA +* NAME +* IB_NODE_TYPE_CA +* +* DESCRIPTION +* Encoded generic node type used in MAD attributes (13.4.8.2) +* +* SOURCE +*/ +#define IB_NODE_TYPE_CA 0x01 +/**********/ + +/****d* IBA Base: Constants/IB_NODE_TYPE_SWITCH +* NAME +* IB_NODE_TYPE_SWITCH +* +* DESCRIPTION +* Encoded generic node type used in MAD attributes (13.4.8.2) +* +* SOURCE +*/ +#define IB_NODE_TYPE_SWITCH 0x02 +/**********/ + +/****d* IBA Base: Constants/IB_NODE_TYPE_ROUTER +* NAME +* IB_NODE_TYPE_ROUTER +* +* DESCRIPTION +* Encoded generic node type used in MAD attributes (13.4.8.2) +* +* SOURCE +*/ +#define IB_NODE_TYPE_ROUTER 0x03 +/**********/ + +/****d* IBA Base: Constants/IB_NOTICE_PRODUCER_TYPE_CA +* NAME +* IB_NOTICE_PRODUCER_TYPE_CA +* +* DESCRIPTION +* Encoded generic producer type used in Notice attribute (13.4.8.2) +* +* SOURCE +*/ +#define IB_NOTICE_PRODUCER_TYPE_CA (CL_HTON32(0x000001)) +/**********/ + +/****d* IBA Base: Constants/IB_NOTICE_PRODUCER_TYPE_SWITCH +* NAME +* IB_NOTICE_PRODUCER_TYPE_SWITCH +* +* DESCRIPTION +* Encoded generic producer type used in Notice attribute (13.4.8.2) +* +* SOURCE +*/ +#define IB_NOTICE_PRODUCER_TYPE_SWITCH (CL_HTON32(0x000002)) +/**********/ + +/****d* IBA Base: Constants/IB_NOTICE_PRODUCER_TYPE_ROUTER +* NAME +* IB_NOTICE_PRODUCER_TYPE_ROUTER +* +* DESCRIPTION +* Encoded generic producer type used in Notice attribute (13.4.8.2) +* +* SOURCE +*/ +#define IB_NOTICE_PRODUCER_TYPE_ROUTER (CL_HTON32(0x000003)) +/**********/ + +/****d* IBA Base: Constants/IB_NOTICE_PRODUCER_TYPE_CLASS_MGR +* NAME +* IB_NOTICE_PRODUCER_TYPE_CLASS_MGR +* +* DESCRIPTION +* Encoded generic producer type used in Notice attribute (13.4.8.2) +* +* SOURCE +*/ +#define IB_NOTICE_PRODUCER_TYPE_CLASS_MGR (CL_HTON32(0x000004)) +/**********/ + +/****d* IBA Base: Constants/IB_MTU_LEN_TYPE +* NAME +* IB_MTU_LEN_TYPE +* +* DESCRIPTION +* Encoded path MTU. +* 1: 256 +* 2: 512 +* 3: 1024 +* 4: 2048 +* 5: 4096 +* others: reserved +* +* SOURCE +*/ +#define IB_MTU_LEN_256 1 +#define IB_MTU_LEN_512 2 +#define IB_MTU_LEN_1024 3 +#define IB_MTU_LEN_2048 4 +#define IB_MTU_LEN_4096 5 + +#define IB_MIN_MTU IB_MTU_LEN_256 +#define IB_MAX_MTU IB_MTU_LEN_4096 + +/**********/ + +/****d* IBA Base: Constants/IB_PATH_SELECTOR_TYPE +* NAME +* IB_PATH_SELECTOR_TYPE +* +* DESCRIPTION +* Path selector. +* 0: greater than specified +* 1: less than specified +* 2: exactly the specified +* 3: largest available +* +* SOURCE +*/ +#define IB_PATH_SELECTOR_GREATER_THAN 0 +#define IB_PATH_SELECTOR_LESS_THAN 1 +#define IB_PATH_SELECTOR_EXACTLY 2 +#define IB_PATH_SELECTOR_LARGEST 3 +/**********/ + +/****d* IBA Base: Constants/IB_SMINFO_STATE_NOTACTIVE +* NAME +* IB_SMINFO_STATE_NOTACTIVE +* +* DESCRIPTION +* Encoded state value used in the SMInfo attribute. +* +* SOURCE +*/ +#define IB_SMINFO_STATE_NOTACTIVE 0 +/**********/ + +/****d* IBA Base: Constants/IB_SMINFO_STATE_DISCOVERING +* NAME +* IB_SMINFO_STATE_DISCOVERING +* +* DESCRIPTION +* Encoded state value used in the SMInfo attribute. +* +* SOURCE +*/ +#define IB_SMINFO_STATE_DISCOVERING 1 +/**********/ + +/****d* IBA Base: Constants/IB_SMINFO_STATE_STANDBY +* NAME +* IB_SMINFO_STATE_STANDBY +* +* DESCRIPTION +* Encoded state value used in the SMInfo attribute. +* +* SOURCE +*/ +#define IB_SMINFO_STATE_STANDBY 2 +/**********/ + +/****d* IBA Base: Constants/IB_SMINFO_STATE_MASTER +* NAME +* IB_SMINFO_STATE_MASTER +* +* DESCRIPTION +* Encoded state value used in the SMInfo attribute. +* +* SOURCE +*/ +#define IB_SMINFO_STATE_MASTER 3 +/**********/ + +/****d* IBA Base: Constants/IB_PATH_REC_SL_MASK +* NAME +* IB_PATH_REC_SL_MASK +* +* DESCRIPTION +* Mask for the sl field for path record +* +* SOURCE +*/ +#define IB_PATH_REC_SL_MASK 0x000F + +/****d* IBA Base: Constants/IB_MULTIPATH_REC_SL_MASK +* NAME +* IB_MILTIPATH_REC_SL_MASK +* +* DESCRIPTION +* Mask for the sl field for MultiPath record +* +* SOURCE +*/ +#define IB_MULTIPATH_REC_SL_MASK 0x000F + +/****d* IBA Base: Constants/IB_PATH_REC_QOS_CLASS_MASK +* NAME +* IB_PATH_REC_QOS_CLASS_MASK +* +* DESCRIPTION +* Mask for the QoS class field for path record +* +* SOURCE +*/ +#define IB_PATH_REC_QOS_CLASS_MASK 0xFFF0 + +/****d* IBA Base: Constants/IB_MULTIPATH_REC_QOS_CLASS_MASK +* NAME +* IB_MULTIPATH_REC_QOS_CLASS_MASK +* +* DESCRIPTION +* Mask for the QoS class field for MultiPath record +* +* SOURCE +*/ +#define IB_MULTIPATH_REC_QOS_CLASS_MASK 0xFFF0 + +/****d* IBA Base: Constants/IB_PATH_REC_SELECTOR_MASK +* NAME +* IB_PATH_REC_SELECTOR_MASK +* +* DESCRIPTION +* Mask for the selector field for path record MTU, rate, +* and packet lifetime. +* +* SOURCE +*/ +#define IB_PATH_REC_SELECTOR_MASK 0xC0 + +/****d* IBA Base: Constants/IB_MULTIPATH_REC_SELECTOR_MASK +* NAME +* IB_MULTIPATH_REC_SELECTOR_MASK +* +* DESCRIPTION +* Mask for the selector field for multipath record MTU, rate, +* and packet lifetime. +* +* SOURCE +*/ +#define IB_MULTIPATH_REC_SELECTOR_MASK 0xC0 +/**********/ + +/****d* IBA Base: Constants/IB_PATH_REC_BASE_MASK +* NAME +* IB_PATH_REC_BASE_MASK +* +* DESCRIPTION +* Mask for the base value field for path record MTU, rate, +* and packet lifetime. +* +* SOURCE +*/ +#define IB_PATH_REC_BASE_MASK 0x3F +/**********/ + +/****d* IBA Base: Constants/IB_MULTIPATH_REC_BASE_MASK +* NAME +* IB_MULTIPATH_REC_BASE_MASK +* +* DESCRIPTION +* Mask for the base value field for multipath record MTU, rate, +* and packet lifetime. +* +* SOURCE +*/ +#define IB_MULTIPATH_REC_BASE_MASK 0x3F +/**********/ + +/****h* IBA Base/Type Definitions +* NAME +* Type Definitions +* +* DESCRIPTION +* Definitions are from the InfiniBand Architecture Specification v1.2 +* +*********/ + +/****d* IBA Base: Types/ib_net16_t +* NAME +* ib_net16_t +* +* DESCRIPTION +* Defines the network ordered type for 16-bit values. +* +* SOURCE +*/ +typedef uint16_t ib_net16_t; +/**********/ + +/****d* IBA Base: Types/ib_net32_t +* NAME +* ib_net32_t +* +* DESCRIPTION +* Defines the network ordered type for 32-bit values. +* +* SOURCE +*/ +typedef uint32_t ib_net32_t; +/**********/ + +/****d* IBA Base: Types/ib_net64_t +* NAME +* ib_net64_t +* +* DESCRIPTION +* Defines the network ordered type for 64-bit values. +* +* SOURCE +*/ +typedef uint64_t ib_net64_t; +/**********/ + +/****d* IBA Base: Types/ib_gid_prefix_t +* NAME +* ib_gid_prefix_t +* +* DESCRIPTION +* +* SOURCE +*/ +typedef ib_net64_t ib_gid_prefix_t; +/**********/ + +/****d* IBA Base: Constants/ib_link_states_t +* NAME +* ib_link_states_t +* +* DESCRIPTION +* Defines the link states of a port. +* +* SOURCE +*/ +#define IB_LINK_NO_CHANGE 0 +#define IB_LINK_DOWN 1 +#define IB_LINK_INIT 2 +#define IB_LINK_ARMED 3 +#define IB_LINK_ACTIVE 4 +#define IB_LINK_ACT_DEFER 5 +/**********/ + +static const char *const __ib_node_type_str[] = { + "UNKNOWN", + "Channel Adapter", + "Switch", + "Router" +}; + +/****f* IBA Base: Types/ib_get_node_type_str +* NAME +* ib_get_node_type_str +* +* DESCRIPTION +* Returns a string for the specified node type. +* 14.2.5.3 NodeInfo +* +* SYNOPSIS +*/ +static inline const char *OSM_API ib_get_node_type_str(IN uint8_t node_type) +{ + if (node_type > IB_NODE_TYPE_ROUTER) + node_type = 0; + return (__ib_node_type_str[node_type]); +} + +/* +* PARAMETERS +* node_type +* [in] Encoded node type as returned in the NodeInfo attribute. + +* RETURN VALUES +* Pointer to the node type string. +* +* NOTES +* +* SEE ALSO +* ib_node_info_t +*********/ + +static const char *const __ib_producer_type_str[] = { + "UNKNOWN", + "Channel Adapter", + "Switch", + "Router", + "Class Manager" +}; + +/****f* IBA Base: Types/ib_get_producer_type_str +* NAME +* ib_get_producer_type_str +* +* DESCRIPTION +* Returns a string for the specified producer type +* 13.4.8.2 Notice +* 13.4.8.3 InformInfo +* +* SYNOPSIS +*/ +static inline const char *OSM_API +ib_get_producer_type_str(IN ib_net32_t producer_type) +{ + if (cl_ntoh32(producer_type) > + CL_NTOH32(IB_NOTICE_PRODUCER_TYPE_CLASS_MGR)) + producer_type = 0; + return (__ib_producer_type_str[cl_ntoh32(producer_type)]); +} + +/* +* PARAMETERS +* producer_type +* [in] Encoded producer type from the Notice attribute + +* RETURN VALUES +* Pointer to the producer type string. +* +* NOTES +* +* SEE ALSO +* ib_notice_get_prod_type +*********/ + +static const char *const __ib_port_state_str[] = { + "No State Change (NOP)", + "DOWN", + "INIT", + "ARMED", + "ACTIVE", + "ACTDEFER", + "UNKNOWN" +}; + +/****f* IBA Base: Types/ib_get_port_state_str +* NAME +* ib_get_port_state_str +* +* DESCRIPTION +* Returns a string for the specified port state. +* +* SYNOPSIS +*/ +static inline const char *OSM_API ib_get_port_state_str(IN uint8_t port_state) +{ + if (port_state > IB_LINK_ACTIVE) + port_state = IB_LINK_ACTIVE + 1; + return (__ib_port_state_str[port_state]); +} + +/* +* PARAMETERS +* port_state +* [in] Encoded port state as returned in the PortInfo attribute. + +* RETURN VALUES +* Pointer to the port state string. +* +* NOTES +* +* SEE ALSO +* ib_port_info_t +*********/ + +/****f* IBA Base: Types/ib_get_port_state_from_str +* NAME +* ib_get_port_state_from_str +* +* DESCRIPTION +* Returns a string for the specified port state. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_get_port_state_from_str(IN char *p_port_state_str) +{ + if (!strncmp(p_port_state_str, "No State Change (NOP)", 12)) + return (0); + else if (!strncmp(p_port_state_str, "DOWN", 4)) + return (1); + else if (!strncmp(p_port_state_str, "INIT", 4)) + return (2); + else if (!strncmp(p_port_state_str, "ARMED", 5)) + return (3); + else if (!strncmp(p_port_state_str, "ACTIVE", 6)) + return (4); + else if (!strncmp(p_port_state_str, "ACTDEFER", 8)) + return (5); + return (6); +} + +/* +* PARAMETERS +* p_port_state_str +* [in] A string matching one returned by ib_get_port_state_str +* +* RETURN VALUES +* The appropriate code. +* +* NOTES +* +* SEE ALSO +* ib_port_info_t +*********/ + +/****d* IBA Base: Constants/Join States +* NAME +* Join States +* +* DESCRIPTION +* Defines the join state flags for multicast group management. +* +* SOURCE +*/ +#define IB_JOIN_STATE_FULL 1 +#define IB_JOIN_STATE_NON 2 +#define IB_JOIN_STATE_SEND_ONLY 4 +/**********/ + +/****f* IBA Base: Types/ib_pkey_get_base +* NAME +* ib_pkey_get_base +* +* DESCRIPTION +* Returns the base P_Key value with the membership bit stripped. +* +* SYNOPSIS +*/ +static inline ib_net16_t OSM_API ib_pkey_get_base(IN const ib_net16_t pkey) +{ + return ((ib_net16_t) (pkey & IB_PKEY_BASE_MASK)); +} + +/* +* PARAMETERS +* pkey +* [in] P_Key value +* +* RETURN VALUE +* Returns the base P_Key value with the membership bit stripped. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_pkey_is_full_member +* NAME +* ib_pkey_is_full_member +* +* DESCRIPTION +* Indicates if the port is a full member of the parition. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API ib_pkey_is_full_member(IN const ib_net16_t pkey) +{ + return ((pkey & IB_PKEY_TYPE_MASK) == IB_PKEY_TYPE_MASK); +} + +/* +* PARAMETERS +* pkey +* [in] P_Key value +* +* RETURN VALUE +* TRUE if the port is a full member of the partition. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* ib_pkey_get_base, ib_net16_t +*********/ + +/****f* IBA Base: Types/ib_pkey_is_invalid +* NAME +* ib_pkey_is_invalid +* +* DESCRIPTION +* Returns TRUE if the given P_Key is an invalid P_Key +* C10-116: the CI shall regard a P_Key as invalid if its low-order +* 15 bits are all zero... +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API ib_pkey_is_invalid(IN const ib_net16_t pkey) +{ + if (ib_pkey_get_base(pkey) == 0x0000) + return TRUE; + + return FALSE; +} + +/* +* PARAMETERS +* pkey +* [in] P_Key value +* +* RETURN VALUE +* Returns the base P_Key value with the membership bit stripped. +* +* NOTES +* +* SEE ALSO +*********/ + +/****d* IBA Base: Types/ib_gid_t +* NAME +* ib_gid_t +* +* DESCRIPTION +* +* SYNOPSIS +*/ +#include +typedef union _ib_gid { + uint8_t raw[16]; + struct _ib_gid_unicast { + ib_gid_prefix_t prefix; + ib_net64_t interface_id; + + } PACK_SUFFIX unicast; + + struct _ib_gid_multicast { + uint8_t header[2]; + uint8_t raw_group_id[14]; + + } PACK_SUFFIX multicast; + +} PACK_SUFFIX ib_gid_t; +#include +/* +* FIELDS +* raw +* GID represented as an unformated byte array. +* +* unicast +* Typical unicast representation with subnet prefix and +* port GUID. +* +* multicast +* Representation for multicast use. +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_gid_is_multicast +* NAME +* ib_gid_is_multicast +* +* DESCRIPTION +* Returns a boolean indicating whether a GID is a multicast GID. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API ib_gid_is_multicast(IN const ib_gid_t * p_gid) +{ + return (p_gid->raw[0] == 0xFF); +} + +/****f* IBA Base: Types/ib_gid_get_scope +* NAME +* ib_gid_get_scope +* +* DESCRIPTION +* Returns scope of (assumed) multicast GID. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API ib_mgid_get_scope(IN const ib_gid_t * p_gid) +{ + return (p_gid->raw[1] & 0x0F); +} + +/****f* IBA Base: Types/ib_gid_set_scope +* NAME +* ib_gid_set_scope +* +* DESCRIPTION +* Sets scope of (assumed) multicast GID. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_mgid_set_scope(IN ib_gid_t * const p_gid, IN const uint8_t scope) +{ + p_gid->raw[1] &= 0xF0; + p_gid->raw[1] |= scope & 0x0F; +} + +/****f* IBA Base: Types/ib_gid_set_default +* NAME +* ib_gid_set_default +* +* DESCRIPTION +* Sets a GID to the default value. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_gid_set_default(IN ib_gid_t * const p_gid, IN const ib_net64_t interface_id) +{ + p_gid->unicast.prefix = IB_DEFAULT_SUBNET_PREFIX; + p_gid->unicast.interface_id = interface_id; +} + +/* +* PARAMETERS +* p_gid +* [in] Pointer to the GID object. +* +* interface_id +* [in] Manufacturer assigned EUI64 value of a port. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* ib_gid_t +*********/ + +/****f* IBA Base: Types/ib_gid_get_subnet_prefix +* NAME +* ib_gid_get_subnet_prefix +* +* DESCRIPTION +* Gets the subnet prefix from a GID. +* +* SYNOPSIS +*/ +static inline ib_net64_t OSM_API +ib_gid_get_subnet_prefix(IN const ib_gid_t * const p_gid) +{ + return (p_gid->unicast.prefix); +} + +/* +* PARAMETERS +* p_gid +* [in] Pointer to the GID object. +* +* RETURN VALUES +* 64-bit subnet prefix value. +* +* NOTES +* +* SEE ALSO +* ib_gid_t +*********/ + +/****f* IBA Base: Types/ib_gid_is_link_local +* NAME +* ib_gid_is_link_local +* +* DESCRIPTION +* Returns TRUE if the unicast GID scoping indicates link local, +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_gid_is_link_local(IN const ib_gid_t * const p_gid) +{ + return ((ib_gid_get_subnet_prefix(p_gid) & + CL_HTON64(0xFFC0000000000000ULL)) == IB_DEFAULT_SUBNET_PREFIX); +} + +/* +* PARAMETERS +* p_gid +* [in] Pointer to the GID object. +* +* RETURN VALUES +* Returns TRUE if the unicast GID scoping indicates link local, +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* ib_gid_t +*********/ + +/****f* IBA Base: Types/ib_gid_is_site_local +* NAME +* ib_gid_is_site_local +* +* DESCRIPTION +* Returns TRUE if the unicast GID scoping indicates site local, +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_gid_is_site_local(IN const ib_gid_t * const p_gid) +{ + return ((ib_gid_get_subnet_prefix(p_gid) & + CL_HTON64(0xFFFFFFFFFFFF0000ULL)) == + CL_HTON64(0xFEC0000000000000ULL)); +} + +/* +* PARAMETERS +* p_gid +* [in] Pointer to the GID object. +* +* RETURN VALUES +* Returns TRUE if the unicast GID scoping indicates site local, +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* ib_gid_t +*********/ + +/****f* IBA Base: Types/ib_gid_get_guid +* NAME +* ib_gid_get_guid +* +* DESCRIPTION +* Gets the guid from a GID. +* +* SYNOPSIS +*/ +static inline ib_net64_t OSM_API +ib_gid_get_guid(IN const ib_gid_t * const p_gid) +{ + return (p_gid->unicast.interface_id); +} + +/* +* PARAMETERS +* p_gid +* [in] Pointer to the GID object. +* +* RETURN VALUES +* 64-bit GUID value. +* +* NOTES +* +* SEE ALSO +* ib_gid_t +*********/ + +/****s* IBA Base: Types/ib_path_rec_t +* NAME +* ib_path_rec_t +* +* DESCRIPTION +* Path records encapsulate the properties of a given +* route between two end-points on a subnet. +* +* SYNOPSIS +*/ +#include +typedef struct _ib_path_rec { + ib_net64_t service_id; + ib_gid_t dgid; + ib_gid_t sgid; + ib_net16_t dlid; + ib_net16_t slid; + ib_net32_t hop_flow_raw; + uint8_t tclass; + uint8_t num_path; + ib_net16_t pkey; + ib_net16_t qos_class_sl; + uint8_t mtu; + uint8_t rate; + uint8_t pkt_life; + uint8_t preference; + uint8_t resv2[6]; + +} PACK_SUFFIX ib_path_rec_t; +#include +/* +* FIELDS +* service_id +* Service ID for QoS. +* +* dgid +* GID of destination port. +* +* sgid +* GID of source port. +* +* dlid +* LID of destination port. +* +* slid +* LID of source port. +* +* hop_flow_raw +* Global routing parameters: hop count, flow label and raw bit. +* +* tclass +* Another global routing parameter. +* +* num_path +* Reversible path - 1 bit to say if path is reversible. +* num_path [6:0] In queries, maximum number of paths to return. +* In responses, undefined. +* +* pkey +* Partition key (P_Key) to use on this path. +* +* qos_class_sl +* QoS class and service level to use on this path. +* +* mtu +* MTU and MTU selector fields to use on this path +* +* rate +* Rate and rate selector fields to use on this path. +* +* pkt_life +* Packet lifetime +* +* preference +* Indicates the relative merit of this path versus other path +* records returned from the SA. Lower numbers are better. +* +* resv2 +* Reserved bytes. +* SEE ALSO +*********/ + +/* Path Record Component Masks */ +#define IB_PR_COMPMASK_SERVICEID_MSB (CL_HTON64(((uint64_t)1)<<0)) +#define IB_PR_COMPMASK_SERVICEID_LSB (CL_HTON64(((uint64_t)1)<<1)) +#define IB_PR_COMPMASK_DGID (CL_HTON64(((uint64_t)1)<<2)) +#define IB_PR_COMPMASK_SGID (CL_HTON64(((uint64_t)1)<<3)) +#define IB_PR_COMPMASK_DLID (CL_HTON64(((uint64_t)1)<<4)) +#define IB_PR_COMPMASK_SLID (CL_HTON64(((uint64_t)1)<<5)) +#define IB_PR_COMPMASK_RAWTRAFFIC (CL_HTON64(((uint64_t)1)<<6)) +#define IB_PR_COMPMASK_RESV0 (CL_HTON64(((uint64_t)1)<<7)) +#define IB_PR_COMPMASK_FLOWLABEL (CL_HTON64(((uint64_t)1)<<8)) +#define IB_PR_COMPMASK_HOPLIMIT (CL_HTON64(((uint64_t)1)<<9)) +#define IB_PR_COMPMASK_TCLASS (CL_HTON64(((uint64_t)1)<<10)) +#define IB_PR_COMPMASK_REVERSIBLE (CL_HTON64(((uint64_t)1)<<11)) +#define IB_PR_COMPMASK_NUMBPATH (CL_HTON64(((uint64_t)1)<<12)) +#define IB_PR_COMPMASK_PKEY (CL_HTON64(((uint64_t)1)<<13)) +#define IB_PR_COMPMASK_QOS_CLASS (CL_HTON64(((uint64_t)1)<<14)) +#define IB_PR_COMPMASK_SL (CL_HTON64(((uint64_t)1)<<15)) +#define IB_PR_COMPMASK_MTUSELEC (CL_HTON64(((uint64_t)1)<<16)) +#define IB_PR_COMPMASK_MTU (CL_HTON64(((uint64_t)1)<<17)) +#define IB_PR_COMPMASK_RATESELEC (CL_HTON64(((uint64_t)1)<<18)) +#define IB_PR_COMPMASK_RATE (CL_HTON64(((uint64_t)1)<<19)) +#define IB_PR_COMPMASK_PKTLIFETIMESELEC (CL_HTON64(((uint64_t)1)<<20)) +#define IB_PR_COMPMASK_PKTLIFETIME (CL_HTON64(((uint64_t)1)<<21)) + +/* Link Record Component Masks */ +#define IB_LR_COMPMASK_FROM_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_LR_COMPMASK_FROM_PORT (CL_HTON64(((uint64_t)1)<<1)) +#define IB_LR_COMPMASK_TO_PORT (CL_HTON64(((uint64_t)1)<<2)) +#define IB_LR_COMPMASK_TO_LID (CL_HTON64(((uint64_t)1)<<3)) + +/* VL Arbitration Record Masks */ +#define IB_VLA_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_VLA_COMPMASK_OUT_PORT (CL_HTON64(((uint64_t)1)<<1)) +#define IB_VLA_COMPMASK_BLOCK (CL_HTON64(((uint64_t)1)<<2)) + +/* SLtoVL Mapping Record Masks */ +#define IB_SLVL_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_SLVL_COMPMASK_IN_PORT (CL_HTON64(((uint64_t)1)<<1)) +#define IB_SLVL_COMPMASK_OUT_PORT (CL_HTON64(((uint64_t)1)<<2)) + +/* P_Key Table Record Masks */ +#define IB_PKEY_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_PKEY_COMPMASK_BLOCK (CL_HTON64(((uint64_t)1)<<1)) +#define IB_PKEY_COMPMASK_PORT (CL_HTON64(((uint64_t)1)<<2)) + +/* Switch Info Record Masks */ +#define IB_SWIR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_SWIR_COMPMASK_RESERVED1 (CL_HTON64(((uint64_t)1)<<1)) + +/* LFT Record Masks */ +#define IB_LFTR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_LFTR_COMPMASK_BLOCK (CL_HTON64(((uint64_t)1)<<1)) + +/* MFT Record Masks */ +#define IB_MFTR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_MFTR_COMPMASK_POSITION (CL_HTON64(((uint64_t)1)<<1)) +#define IB_MFTR_COMPMASK_RESERVED1 (CL_HTON64(((uint64_t)1)<<2)) +#define IB_MFTR_COMPMASK_BLOCK (CL_HTON64(((uint64_t)1)<<3)) +#define IB_MFTR_COMPMASK_RESERVED2 (CL_HTON64(((uint64_t)1)<<4)) + +/* NodeInfo Record Masks */ +#define IB_NR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_NR_COMPMASK_RESERVED1 (CL_HTON64(((uint64_t)1)<<1)) +#define IB_NR_COMPMASK_BASEVERSION (CL_HTON64(((uint64_t)1)<<2)) +#define IB_NR_COMPMASK_CLASSVERSION (CL_HTON64(((uint64_t)1)<<3)) +#define IB_NR_COMPMASK_NODETYPE (CL_HTON64(((uint64_t)1)<<4)) +#define IB_NR_COMPMASK_NUMPORTS (CL_HTON64(((uint64_t)1)<<5)) +#define IB_NR_COMPMASK_SYSIMAGEGUID (CL_HTON64(((uint64_t)1)<<6)) +#define IB_NR_COMPMASK_NODEGUID (CL_HTON64(((uint64_t)1)<<7)) +#define IB_NR_COMPMASK_PORTGUID (CL_HTON64(((uint64_t)1)<<8)) +#define IB_NR_COMPMASK_PARTCAP (CL_HTON64(((uint64_t)1)<<9)) +#define IB_NR_COMPMASK_DEVID (CL_HTON64(((uint64_t)1)<<10)) +#define IB_NR_COMPMASK_REV (CL_HTON64(((uint64_t)1)<<11)) +#define IB_NR_COMPMASK_PORTNUM (CL_HTON64(((uint64_t)1)<<12)) +#define IB_NR_COMPMASK_VENDID (CL_HTON64(((uint64_t)1)<<13)) +#define IB_NR_COMPMASK_NODEDESC (CL_HTON64(((uint64_t)1)<<14)) + +/* Service Record Component Masks Sec 15.2.5.14 Ver 1.1*/ +#define IB_SR_COMPMASK_SID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_SR_COMPMASK_SGID (CL_HTON64(((uint64_t)1)<<1)) +#define IB_SR_COMPMASK_SPKEY (CL_HTON64(((uint64_t)1)<<2)) +#define IB_SR_COMPMASK_RES1 (CL_HTON64(((uint64_t)1)<<3)) +#define IB_SR_COMPMASK_SLEASE (CL_HTON64(((uint64_t)1)<<4)) +#define IB_SR_COMPMASK_SKEY (CL_HTON64(((uint64_t)1)<<5)) +#define IB_SR_COMPMASK_SNAME (CL_HTON64(((uint64_t)1)<<6)) +#define IB_SR_COMPMASK_SDATA8_0 (CL_HTON64(((uint64_t)1)<<7)) +#define IB_SR_COMPMASK_SDATA8_1 (CL_HTON64(((uint64_t)1)<<8)) +#define IB_SR_COMPMASK_SDATA8_2 (CL_HTON64(((uint64_t)1)<<9)) +#define IB_SR_COMPMASK_SDATA8_3 (CL_HTON64(((uint64_t)1)<<10)) +#define IB_SR_COMPMASK_SDATA8_4 (CL_HTON64(((uint64_t)1)<<11)) +#define IB_SR_COMPMASK_SDATA8_5 (CL_HTON64(((uint64_t)1)<<12)) +#define IB_SR_COMPMASK_SDATA8_6 (CL_HTON64(((uint64_t)1)<<13)) +#define IB_SR_COMPMASK_SDATA8_7 (CL_HTON64(((uint64_t)1)<<14)) +#define IB_SR_COMPMASK_SDATA8_8 (CL_HTON64(((uint64_t)1)<<15)) +#define IB_SR_COMPMASK_SDATA8_9 (CL_HTON64(((uint64_t)1)<<16)) +#define IB_SR_COMPMASK_SDATA8_10 (CL_HTON64(((uint64_t)1)<<17)) +#define IB_SR_COMPMASK_SDATA8_11 (CL_HTON64(((uint64_t)1)<<18)) +#define IB_SR_COMPMASK_SDATA8_12 (CL_HTON64(((uint64_t)1)<<19)) +#define IB_SR_COMPMASK_SDATA8_13 (CL_HTON64(((uint64_t)1)<<20)) +#define IB_SR_COMPMASK_SDATA8_14 (CL_HTON64(((uint64_t)1)<<21)) +#define IB_SR_COMPMASK_SDATA8_15 (CL_HTON64(((uint64_t)1)<<22)) +#define IB_SR_COMPMASK_SDATA16_0 (CL_HTON64(((uint64_t)1)<<23)) +#define IB_SR_COMPMASK_SDATA16_1 (CL_HTON64(((uint64_t)1)<<24)) +#define IB_SR_COMPMASK_SDATA16_2 (CL_HTON64(((uint64_t)1)<<25)) +#define IB_SR_COMPMASK_SDATA16_3 (CL_HTON64(((uint64_t)1)<<26)) +#define IB_SR_COMPMASK_SDATA16_4 (CL_HTON64(((uint64_t)1)<<27)) +#define IB_SR_COMPMASK_SDATA16_5 (CL_HTON64(((uint64_t)1)<<28)) +#define IB_SR_COMPMASK_SDATA16_6 (CL_HTON64(((uint64_t)1)<<29)) +#define IB_SR_COMPMASK_SDATA16_7 (CL_HTON64(((uint64_t)1)<<30)) +#define IB_SR_COMPMASK_SDATA32_0 (CL_HTON64(((uint64_t)1)<<31)) +#define IB_SR_COMPMASK_SDATA32_1 (CL_HTON64(((uint64_t)1)<<32)) +#define IB_SR_COMPMASK_SDATA32_2 (CL_HTON64(((uint64_t)1)<<33)) +#define IB_SR_COMPMASK_SDATA32_3 (CL_HTON64(((uint64_t)1)<<34)) +#define IB_SR_COMPMASK_SDATA64_0 (CL_HTON64(((uint64_t)1)<<35)) +#define IB_SR_COMPMASK_SDATA64_1 (CL_HTON64(((uint64_t)1)<<36)) + +/* Port Info Record Component Masks */ +#define IB_PIR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_PIR_COMPMASK_PORTNUM (CL_HTON64(((uint64_t)1)<<1)) +#define IB_PIR_COMPMASK_RESV1 (CL_HTON64(((uint64_t)1)<<2)) +#define IB_PIR_COMPMASK_MKEY (CL_HTON64(((uint64_t)1)<<3)) +#define IB_PIR_COMPMASK_GIDPRE (CL_HTON64(((uint64_t)1)<<4)) +#define IB_PIR_COMPMASK_BASELID (CL_HTON64(((uint64_t)1)<<5)) +#define IB_PIR_COMPMASK_SMLID (CL_HTON64(((uint64_t)1)<<6)) +#define IB_PIR_COMPMASK_CAPMASK (CL_HTON64(((uint64_t)1)<<7)) +#define IB_PIR_COMPMASK_DIAGCODE (CL_HTON64(((uint64_t)1)<<8)) +#define IB_PIR_COMPMASK_MKEYLEASEPRD (CL_HTON64(((uint64_t)1)<<9)) +#define IB_PIR_COMPMASK_LOCALPORTNUM (CL_HTON64(((uint64_t)1)<<10)) +#define IB_PIR_COMPMASK_LINKWIDTHENABLED (CL_HTON64(((uint64_t)1)<<11)) +#define IB_PIR_COMPMASK_LNKWIDTHSUPPORT (CL_HTON64(((uint64_t)1)<<12)) +#define IB_PIR_COMPMASK_LNKWIDTHACTIVE (CL_HTON64(((uint64_t)1)<<13)) +#define IB_PIR_COMPMASK_LNKSPEEDSUPPORT (CL_HTON64(((uint64_t)1)<<14)) +#define IB_PIR_COMPMASK_PORTSTATE (CL_HTON64(((uint64_t)1)<<15)) +#define IB_PIR_COMPMASK_PORTPHYSTATE (CL_HTON64(((uint64_t)1)<<16)) +#define IB_PIR_COMPMASK_LINKDWNDFLTSTATE (CL_HTON64(((uint64_t)1)<<17)) +#define IB_PIR_COMPMASK_MKEYPROTBITS (CL_HTON64(((uint64_t)1)<<18)) +#define IB_PIR_COMPMASK_RESV2 (CL_HTON64(((uint64_t)1)<<19)) +#define IB_PIR_COMPMASK_LMC (CL_HTON64(((uint64_t)1)<<20)) +#define IB_PIR_COMPMASK_LINKSPEEDACTIVE (CL_HTON64(((uint64_t)1)<<21)) +#define IB_PIR_COMPMASK_LINKSPEEDENABLE (CL_HTON64(((uint64_t)1)<<22)) +#define IB_PIR_COMPMASK_NEIGHBORMTU (CL_HTON64(((uint64_t)1)<<23)) +#define IB_PIR_COMPMASK_MASTERSMSL (CL_HTON64(((uint64_t)1)<<24)) +#define IB_PIR_COMPMASK_VLCAP (CL_HTON64(((uint64_t)1)<<25)) +#define IB_PIR_COMPMASK_INITTYPE (CL_HTON64(((uint64_t)1)<<26)) +#define IB_PIR_COMPMASK_VLHIGHLIMIT (CL_HTON64(((uint64_t)1)<<27)) +#define IB_PIR_COMPMASK_VLARBHIGHCAP (CL_HTON64(((uint64_t)1)<<28)) +#define IB_PIR_COMPMASK_VLARBLOWCAP (CL_HTON64(((uint64_t)1)<<29)) +#define IB_PIR_COMPMASK_INITTYPEREPLY (CL_HTON64(((uint64_t)1)<<30)) +#define IB_PIR_COMPMASK_MTUCAP (CL_HTON64(((uint64_t)1)<<31)) +#define IB_PIR_COMPMASK_VLSTALLCNT (CL_HTON64(((uint64_t)1)<<32)) +#define IB_PIR_COMPMASK_HOQLIFE (CL_HTON64(((uint64_t)1)<<33)) +#define IB_PIR_COMPMASK_OPVLS (CL_HTON64(((uint64_t)1)<<34)) +#define IB_PIR_COMPMASK_PARENFIN (CL_HTON64(((uint64_t)1)<<35)) +#define IB_PIR_COMPMASK_PARENFOUT (CL_HTON64(((uint64_t)1)<<36)) +#define IB_PIR_COMPMASK_FILTERRAWIN (CL_HTON64(((uint64_t)1)<<37)) +#define IB_PIR_COMPMASK_FILTERRAWOUT (CL_HTON64(((uint64_t)1)<<38)) +#define IB_PIR_COMPMASK_MKEYVIO (CL_HTON64(((uint64_t)1)<<39)) +#define IB_PIR_COMPMASK_PKEYVIO (CL_HTON64(((uint64_t)1)<<40)) +#define IB_PIR_COMPMASK_QKEYVIO (CL_HTON64(((uint64_t)1)<<41)) +#define IB_PIR_COMPMASK_GUIDCAP (CL_HTON64(((uint64_t)1)<<42)) +#define IB_PIR_COMPMASK_RESV3 (CL_HTON64(((uint64_t)1)<<43)) +#define IB_PIR_COMPMASK_SUBNTO (CL_HTON64(((uint64_t)1)<<44)) +#define IB_PIR_COMPMASK_RESV4 (CL_HTON64(((uint64_t)1)<<45)) +#define IB_PIR_COMPMASK_RESPTIME (CL_HTON64(((uint64_t)1)<<46)) +#define IB_PIR_COMPMASK_LOCALPHYERR (CL_HTON64(((uint64_t)1)<<47)) +#define IB_PIR_COMPMASK_OVERRUNERR (CL_HTON64(((uint64_t)1)<<48)) + +/* Multicast Member Record Component Masks */ +#define IB_MCR_COMPMASK_GID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_MCR_COMPMASK_MGID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_MCR_COMPMASK_PORT_GID (CL_HTON64(((uint64_t)1)<<1)) +#define IB_MCR_COMPMASK_QKEY (CL_HTON64(((uint64_t)1)<<2)) +#define IB_MCR_COMPMASK_MLID (CL_HTON64(((uint64_t)1)<<3)) +#define IB_MCR_COMPMASK_MTU_SEL (CL_HTON64(((uint64_t)1)<<4)) +#define IB_MCR_COMPMASK_MTU (CL_HTON64(((uint64_t)1)<<5)) +#define IB_MCR_COMPMASK_TCLASS (CL_HTON64(((uint64_t)1)<<6)) +#define IB_MCR_COMPMASK_PKEY (CL_HTON64(((uint64_t)1)<<7)) +#define IB_MCR_COMPMASK_RATE_SEL (CL_HTON64(((uint64_t)1)<<8)) +#define IB_MCR_COMPMASK_RATE (CL_HTON64(((uint64_t)1)<<9)) +#define IB_MCR_COMPMASK_LIFE_SEL (CL_HTON64(((uint64_t)1)<<10)) +#define IB_MCR_COMPMASK_LIFE (CL_HTON64(((uint64_t)1)<<11)) +#define IB_MCR_COMPMASK_SL (CL_HTON64(((uint64_t)1)<<12)) +#define IB_MCR_COMPMASK_FLOW (CL_HTON64(((uint64_t)1)<<13)) +#define IB_MCR_COMPMASK_HOP (CL_HTON64(((uint64_t)1)<<14)) +#define IB_MCR_COMPMASK_SCOPE (CL_HTON64(((uint64_t)1)<<15)) +#define IB_MCR_COMPMASK_JOIN_STATE (CL_HTON64(((uint64_t)1)<<16)) +#define IB_MCR_COMPMASK_PROXY (CL_HTON64(((uint64_t)1)<<17)) + +/* GUID Info Record Component Masks */ +#define IB_GIR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_GIR_COMPMASK_BLOCKNUM (CL_HTON64(((uint64_t)1)<<1)) +#define IB_GIR_COMPMASK_RESV1 (CL_HTON64(((uint64_t)1)<<2)) +#define IB_GIR_COMPMASK_RESV2 (CL_HTON64(((uint64_t)1)<<3)) +#define IB_GIR_COMPMASK_GID0 (CL_HTON64(((uint64_t)1)<<4)) +#define IB_GIR_COMPMASK_GID1 (CL_HTON64(((uint64_t)1)<<5)) +#define IB_GIR_COMPMASK_GID2 (CL_HTON64(((uint64_t)1)<<6)) +#define IB_GIR_COMPMASK_GID3 (CL_HTON64(((uint64_t)1)<<7)) +#define IB_GIR_COMPMASK_GID4 (CL_HTON64(((uint64_t)1)<<8)) +#define IB_GIR_COMPMASK_GID5 (CL_HTON64(((uint64_t)1)<<9)) +#define IB_GIR_COMPMASK_GID6 (CL_HTON64(((uint64_t)1)<<10)) +#define IB_GIR_COMPMASK_GID7 (CL_HTON64(((uint64_t)1)<<11)) + +/* MultiPath Record Component Masks */ +#define IB_MPR_COMPMASK_RAWTRAFFIC (CL_HTON64(((uint64_t)1)<<0)) +#define IB_MPR_COMPMASK_RESV0 (CL_HTON64(((uint64_t)1)<<1)) +#define IB_MPR_COMPMASK_FLOWLABEL (CL_HTON64(((uint64_t)1)<<2)) +#define IB_MPR_COMPMASK_HOPLIMIT (CL_HTON64(((uint64_t)1)<<3)) +#define IB_MPR_COMPMASK_TCLASS (CL_HTON64(((uint64_t)1)<<4)) +#define IB_MPR_COMPMASK_REVERSIBLE (CL_HTON64(((uint64_t)1)<<5)) +#define IB_MPR_COMPMASK_NUMBPATH (CL_HTON64(((uint64_t)1)<<6)) +#define IB_MPR_COMPMASK_PKEY (CL_HTON64(((uint64_t)1)<<7)) +#define IB_MPR_COMPMASK_QOS_CLASS (CL_HTON64(((uint64_t)1)<<8)) +#define IB_MPR_COMPMASK_SL (CL_HTON64(((uint64_t)1)<<9)) +#define IB_MPR_COMPMASK_MTUSELEC (CL_HTON64(((uint64_t)1)<<10)) +#define IB_MPR_COMPMASK_MTU (CL_HTON64(((uint64_t)1)<<11)) +#define IB_MPR_COMPMASK_RATESELEC (CL_HTON64(((uint64_t)1)<<12)) +#define IB_MPR_COMPMASK_RATE (CL_HTON64(((uint64_t)1)<<13)) +#define IB_MPR_COMPMASK_PKTLIFETIMESELEC (CL_HTON64(((uint64_t)1)<<14)) +#define IB_MPR_COMPMASK_PKTLIFETIME (CL_HTON64(((uint64_t)1)<<15)) +#define IB_MPR_COMPMASK_SERVICEID_MSB (CL_HTON64(((uint64_t)1)<<16)) +#define IB_MPR_COMPMASK_INDEPSELEC (CL_HTON64(((uint64_t)1)<<17)) +#define IB_MPR_COMPMASK_RESV3 (CL_HTON64(((uint64_t)1)<<18)) +#define IB_MPR_COMPMASK_SGIDCOUNT (CL_HTON64(((uint64_t)1)<<19)) +#define IB_MPR_COMPMASK_DGIDCOUNT (CL_HTON64(((uint64_t)1)<<20)) +#define IB_MPR_COMPMASK_SERVICEID_LSB (CL_HTON64(((uint64_t)1)<<21)) + +/* SMInfo Record Component Masks */ +#define IB_SMIR_COMPMASK_LID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_SMIR_COMPMASK_RESV0 (CL_HTON64(((uint64_t)1)<<1)) +#define IB_SMIR_COMPMASK_GUID (CL_HTON64(((uint64_t)1)<<2)) +#define IB_SMIR_COMPMASK_SMKEY (CL_HTON64(((uint64_t)1)<<3)) +#define IB_SMIR_COMPMASK_ACTCOUNT (CL_HTON64(((uint64_t)1)<<4)) +#define IB_SMIR_COMPMASK_PRIORITY (CL_HTON64(((uint64_t)1)<<5)) +#define IB_SMIR_COMPMASK_SMSTATE (CL_HTON64(((uint64_t)1)<<6)) + +/* InformInfo Record Component Masks */ +#define IB_IIR_COMPMASK_SUBSCRIBERGID (CL_HTON64(((uint64_t)1)<<0)) +#define IB_IIR_COMPMASK_ENUM (CL_HTON64(((uint64_t)1)<<1)) +#define IB_IIR_COMPMASK_RESV0 (CL_HTON64(((uint64_t)1)<<2)) +#define IB_IIR_COMPMASK_GID (CL_HTON64(((uint64_t)1)<<3)) +#define IB_IIR_COMPMASK_LIDRANGEBEGIN (CL_HTON64(((uint64_t)1)<<4)) +#define IB_IIR_COMPMASK_LIDRANGEEND (CL_HTON64(((uint64_t)1)<<5)) +#define IB_IIR_COMPMASK_RESV1 (CL_HTON64(((uint64_t)1)<<6)) +#define IB_IIR_COMPMASK_ISGENERIC (CL_HTON64(((uint64_t)1)<<7)) +#define IB_IIR_COMPMASK_SUBSCRIBE (CL_HTON64(((uint64_t)1)<<8)) +#define IB_IIR_COMPMASK_TYPE (CL_HTON64(((uint64_t)1)<<9)) +#define IB_IIR_COMPMASK_TRAPNUMB (CL_HTON64(((uint64_t)1)<<10)) +#define IB_IIR_COMPMASK_DEVICEID (CL_HTON64(((uint64_t)1)<<10)) +#define IB_IIR_COMPMASK_QPN (CL_HTON64(((uint64_t)1)<<11)) +#define IB_IIR_COMPMASK_RESV2 (CL_HTON64(((uint64_t)1)<<12)) +#define IB_IIR_COMPMASK_RESPTIME (CL_HTON64(((uint64_t)1)<<13)) +#define IB_IIR_COMPMASK_RESV3 (CL_HTON64(((uint64_t)1)<<14)) +#define IB_IIR_COMPMASK_PRODTYPE (CL_HTON64(((uint64_t)1)<<15)) +#define IB_IIR_COMPMASK_VENDID (CL_HTON64(((uint64_t)1)<<15)) + +/****f* IBA Base: Types/ib_path_rec_init_local +* NAME +* ib_path_rec_init_local +* +* DESCRIPTION +* Initializes a subnet local path record. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_path_rec_init_local(IN ib_path_rec_t * const p_rec, + IN ib_gid_t * const p_dgid, + IN ib_gid_t * const p_sgid, + IN ib_net16_t dlid, + IN ib_net16_t slid, + IN uint8_t num_path, + IN ib_net16_t pkey, + IN uint8_t sl, + IN uint16_t qos_class, + IN uint8_t mtu_selector, + IN uint8_t mtu, + IN uint8_t rate_selector, + IN uint8_t rate, + IN uint8_t pkt_life_selector, + IN uint8_t pkt_life, IN uint8_t preference) +{ + p_rec->dgid = *p_dgid; + p_rec->sgid = *p_sgid; + p_rec->dlid = dlid; + p_rec->slid = slid; + p_rec->num_path = num_path; + p_rec->pkey = pkey; + p_rec->qos_class_sl = cl_hton16((sl & IB_PATH_REC_SL_MASK) | + (qos_class << 4)); + p_rec->mtu = (uint8_t) ((mtu & IB_PATH_REC_BASE_MASK) | + (uint8_t) (mtu_selector << 6)); + p_rec->rate = (uint8_t) ((rate & IB_PATH_REC_BASE_MASK) | + (uint8_t) (rate_selector << 6)); + p_rec->pkt_life = (uint8_t) ((pkt_life & IB_PATH_REC_BASE_MASK) | + (uint8_t) (pkt_life_selector << 6)); + p_rec->preference = preference; + + /* Clear global routing fields for local path records */ + p_rec->hop_flow_raw = 0; + p_rec->tclass = 0; + p_rec->service_id = 0; + + *((uint32_t *) p_rec->resv2) = 0; + *((uint16_t *) p_rec->resv2 + 2) = 0; +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* dgid +* [in] GID of destination port. +* +* sgid +* [in] GID of source port. +* +* dlid +* [in] LID of destination port. +* +* slid +* [in] LID of source port. +* +* num_path +* [in] Reversible path - 1 bit to say if path is reversible. +* num_path [6:0] In queries, maximum number of paths to return. +* In responses, undefined. +* +* pkey +* [in] Partition key (P_Key) to use on this path. +* +* qos_class +* [in] QoS class to use on this path. Lower 12-bits are valid. +* +* sl +* [in] Service level to use on this path. Lower 4-bits are valid. +* +* mtu_selector +* [in] Encoded MTU selector value to use on this path +* +* mtu +* [in] Encoded MTU to use on this path +* +* rate_selector +* [in] Encoded rate selector value to use on this path. +* +* rate +* [in] Encoded rate to use on this path. +* +* pkt_life_selector +* [in] Encoded Packet selector value lifetime for this path. +* +* pkt_life +* [in] Encoded Packet lifetime for this path. +* +* preference +* [in] Indicates the relative merit of this path versus other path +* records returned from the SA. Lower numbers are better. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* ib_gid_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_num_path +* NAME +* ib_path_rec_num_path +* +* DESCRIPTION +* Get max number of paths to return. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_num_path(IN const ib_path_rec_t * const p_rec) +{ + return (p_rec->num_path & 0x7F); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Maximum number of paths to return for each unique SGID_DGID combination. +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_set_sl +* NAME +* ib_path_rec_set_sl +* +* DESCRIPTION +* Set path service level. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_path_rec_set_sl(IN ib_path_rec_t * const p_rec, IN const uint8_t sl) +{ + p_rec->qos_class_sl = + (p_rec->qos_class_sl & CL_HTON16(IB_PATH_REC_QOS_CLASS_MASK)) | + cl_hton16(sl & IB_PATH_REC_SL_MASK); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* sl +* [in] Service level to set. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_sl +* NAME +* ib_path_rec_sl +* +* DESCRIPTION +* Get path service level. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_sl(IN const ib_path_rec_t * const p_rec) +{ + return (uint8_t)(cl_ntoh16(p_rec->qos_class_sl) & IB_PATH_REC_SL_MASK); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* SL. +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_set_qos_class +* NAME +* ib_path_rec_set_qos_class +* +* DESCRIPTION +* Set path QoS class. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_path_rec_set_qos_class(IN ib_path_rec_t * const p_rec, + IN const uint16_t qos_class) +{ + p_rec->qos_class_sl = + (p_rec->qos_class_sl & CL_HTON16(IB_PATH_REC_SL_MASK)) | + cl_hton16(qos_class << 4); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* qos_class +* [in] QoS class to set. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_qos_class +* NAME +* ib_path_rec_qos_class +* +* DESCRIPTION +* Get QoS class. +* +* SYNOPSIS +*/ +static inline uint16_t OSM_API +ib_path_rec_qos_class(IN const ib_path_rec_t * const p_rec) +{ + return (cl_ntoh16(p_rec->qos_class_sl) >> 4); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* QoS class of the path record. +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_mtu +* NAME +* ib_path_rec_mtu +* +* DESCRIPTION +* Get encoded path MTU. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_mtu(IN const ib_path_rec_t * const p_rec) +{ + return ((uint8_t) (p_rec->mtu & IB_PATH_REC_BASE_MASK)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Encoded path MTU. +* 1: 256 +* 2: 512 +* 3: 1024 +* 4: 2048 +* 5: 4096 +* others: reserved +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_mtu_sel +* NAME +* ib_path_rec_mtu_sel +* +* DESCRIPTION +* Get encoded path MTU selector. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_mtu_sel(IN const ib_path_rec_t * const p_rec) +{ + return ((uint8_t) ((p_rec->mtu & IB_PATH_REC_SELECTOR_MASK) >> 6)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Encoded path MTU selector value (for queries). +* 0: greater than MTU specified +* 1: less than MTU specified +* 2: exactly the MTU specified +* 3: largest MTU available +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_rate +* NAME +* ib_path_rec_rate +* +* DESCRIPTION +* Get encoded path rate. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_rate(IN const ib_path_rec_t * const p_rec) +{ + return ((uint8_t) (p_rec->rate & IB_PATH_REC_BASE_MASK)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Encoded path rate. +* 2: 2.5 Gb/sec. +* 3: 10 Gb/sec. +* 4: 30 Gb/sec. +* 5: 5 Gb/sec. +* 6: 20 Gb/sec. +* 7: 40 Gb/sec. +* 8: 60 Gb/sec. +* 9: 80 Gb/sec. +* 10: 120 Gb/sec. +* others: reserved +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_rate_sel +* NAME +* ib_path_rec_rate_sel +* +* DESCRIPTION +* Get encoded path rate selector. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_rate_sel(IN const ib_path_rec_t * const p_rec) +{ + return ((uint8_t) ((p_rec->rate & IB_PATH_REC_SELECTOR_MASK) >> 6)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Encoded path rate selector value (for queries). +* 0: greater than rate specified +* 1: less than rate specified +* 2: exactly the rate specified +* 3: largest rate available +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_pkt_life +* NAME +* ib_path_rec_pkt_life +* +* DESCRIPTION +* Get encoded path pkt_life. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_pkt_life(IN const ib_path_rec_t * const p_rec) +{ + return ((uint8_t) (p_rec->pkt_life & IB_PATH_REC_BASE_MASK)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Encoded path pkt_life = 4.096 usec * 2 ** PacketLifeTime. +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_pkt_life_sel +* NAME +* ib_path_rec_pkt_life_sel +* +* DESCRIPTION +* Get encoded path pkt_lifetime selector. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_pkt_life_sel(IN const ib_path_rec_t * const p_rec) +{ + return ((uint8_t) ((p_rec->pkt_life & IB_PATH_REC_SELECTOR_MASK) >> 6)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Encoded path pkt_lifetime selector value (for queries). +* 0: greater than rate specified +* 1: less than rate specified +* 2: exactly the rate specified +* 3: smallest packet lifetime available +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_flow_lbl +* NAME +* ib_path_rec_flow_lbl +* +* DESCRIPTION +* Get flow label. +* +* SYNOPSIS +*/ +static inline uint32_t OSM_API +ib_path_rec_flow_lbl(IN const ib_path_rec_t * const p_rec) +{ + return (((cl_ntoh32(p_rec->hop_flow_raw) >> 8) & 0x000FFFFF)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Flow label of the path record. +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****f* IBA Base: Types/ib_path_rec_hop_limit +* NAME +* ib_path_rec_hop_limit +* +* DESCRIPTION +* Get hop limit. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_rec_hop_limit(IN const ib_path_rec_t * const p_rec) +{ + return ((uint8_t) (cl_ntoh32(p_rec->hop_flow_raw) & 0x000000FF)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the path record object. +* +* RETURN VALUES +* Hop limit of the path record. +* +* NOTES +* +* SEE ALSO +* ib_path_rec_t +*********/ + +/****s* IBA Base: Constants/IB_CLASS_CAP_TRAP +* NAME +* IB_CLASS_CAP_TRAP +* +* DESCRIPTION +* ClassPortInfo CapabilityMask bits. This bit will be set +* if the class supports Trap() MADs (13.4.8.1). +* +* SEE ALSO +* ib_class_port_info_t, IB_CLASS_CAP_GETSET +* +* SOURCE +*/ +#define IB_CLASS_CAP_TRAP 0x0001 +/*********/ + +/****s* IBA Base: Constants/IB_CLASS_CAP_GETSET +* NAME +* IB_CLASS_CAP_GETSET +* +* DESCRIPTION +* ClassPortInfo CapabilityMask bits. This bit will be set +* if the class supports Get(Notice) and Set(Notice) MADs (13.4.8.1). +* +* SEE ALSO +* ib_class_port_info_t, IB_CLASS_CAP_TRAP +* +* SOURCE +*/ +#define IB_CLASS_CAP_GETSET 0x0002 +/*********/ + +/****s* IBA Base: Constants/IB_CLASS_RESP_TIME_MASK +* NAME +* IB_CLASS_RESP_TIME_MASK +* +* DESCRIPTION +* Mask bits to extract the reponse time value from the +* resp_time_val field of ib_class_port_info_t. +* +* SEE ALSO +* ib_class_port_info_t +* +* SOURCE +*/ +#define IB_CLASS_RESP_TIME_MASK 0x1F +/*********/ + +/****s* IBA Base: Types/ib_class_port_info_t +* NAME +* ib_class_port_info_t +* +* DESCRIPTION +* IBA defined ClassPortInfo attribute (13.4.8.1) +* route between two end-points on a subnet. +* +* SYNOPSIS +*/ +#include +typedef struct _ib_class_port_info { + uint8_t base_ver; + uint8_t class_ver; + ib_net16_t cap_mask; + ib_net32_t cap_mask2_resp_time; + ib_gid_t redir_gid; + ib_net32_t redir_tc_sl_fl; + ib_net16_t redir_lid; + ib_net16_t redir_pkey; + ib_net32_t redir_qp; + ib_net32_t redir_qkey; + ib_gid_t trap_gid; + ib_net32_t trap_tc_sl_fl; + ib_net16_t trap_lid; + ib_net16_t trap_pkey; + ib_net32_t trap_hop_qp; + ib_net32_t trap_qkey; + +} PACK_SUFFIX ib_class_port_info_t; +#include +/* +* FIELDS +* base_ver +* Maximum supported MAD Base Version. +* +* class_ver +* Maximum supported management class version. +* +* cap_mask +* Supported capabilities of this management class. +* +* cap_mask2_resp_time +* Maximum expected response time and additional +* supported capabilities of this management class. +* +* redr_gid +* GID to use for redirection, or zero +* +* recdir_tc_sl_fl +* Traffic class, service level and flow label the requester +* should use if the service is redirected. +* +* redir_lid +* LID used for redirection, or zero +* +* redir_pkey +* P_Key used for redirection +* +* redir_qp +* QP number used for redirection +* +* redir_qkey +* Q_Key associated with the redirected QP. This shall be the +* well known Q_Key value. +* +* trap_gid +* GID value used for trap messages from this service. +* +* trap_tc_sl_fl +* Traffic class, service level and flow label used for +* trap messages originated by this service. +* +* trap_lid +* LID used for trap messages, or zero +* +* trap_pkey +* P_Key used for trap messages +* +* trap_hop_qp +* Hop limit (upper 8 bits) and QP number used for trap messages +* +* trap_qkey +* Q_Key associated with the trap messages QP. +* +* SEE ALSO +* IB_CLASS_CAP_GETSET, IB_CLASS_CAP_TRAP +* +*********/ + +/****f* IBA Base: Types/ib_class_set_resp_time_val +* NAME +* ib_class_set_resp_time_val +* +* DESCRIPTION +* Set maximum expected response time. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_class_set_resp_time_val(IN ib_class_port_info_t * const p_cpi, + IN const uint8_t val) +{ + p_cpi->cap_mask2_resp_time = + (p_cpi->cap_mask2_resp_time & CL_HTON32(~IB_CLASS_RESP_TIME_MASK)) | + cl_hton32(val & IB_CLASS_RESP_TIME_MASK); +} + +/* +* PARAMETERS +* p_cpi +* [in] Pointer to the class port info object. +* +* val +* [in] Response time value to set. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +* ib_class_port_info_t +*********/ + +/****f* IBA Base: Types/ib_class_resp_time_val +* NAME +* ib_class_resp_time_val +* +* DESCRIPTION +* Get response time value. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_class_resp_time_val(IN ib_class_port_info_t * const p_cpi) +{ + return (uint8_t)(cl_ntoh32(p_cpi->cap_mask2_resp_time) & + IB_CLASS_RESP_TIME_MASK); +} + +/* +* PARAMETERS +* p_cpi +* [in] Pointer to the class port info object. +* +* RETURN VALUES +* Response time value. +* +* NOTES +* +* SEE ALSO +* ib_class_port_info_t +*********/ + +/****f* IBA Base: Types/ib_class_set_cap_mask2 +* NAME +* ib_class_set_cap_mask2 +* +* DESCRIPTION +* Set ClassPortInfo:CapabilityMask2. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_class_set_cap_mask2(IN ib_class_port_info_t * const p_cpi, + IN const uint32_t cap_mask2) +{ + p_cpi->cap_mask2_resp_time = (p_cpi->cap_mask2_resp_time & + CL_HTON32(IB_CLASS_RESP_TIME_MASK)) | + cl_hton32(cap_mask2 << 5); +} + +/* +* PARAMETERS +* p_cpi +* [in] Pointer to the class port info object. +* +* cap_mask2 +* [in] CapabilityMask2 value to set. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +* ib_class_port_info_t +*********/ + +/****f* IBA Base: Types/ib_class_cap_mask2 +* NAME +* ib_class_cap_mask2 +* +* DESCRIPTION +* Get ClassPortInfo:CapabilityMask2. +* +* SYNOPSIS +*/ +static inline uint32_t OSM_API +ib_class_cap_mask2(IN const ib_class_port_info_t * const p_cpi) +{ + return (cl_ntoh32(p_cpi->cap_mask2_resp_time) >> 5); +} + +/* +* PARAMETERS +* p_cpi +* [in] Pointer to the class port info object. +* +* RETURN VALUES +* CapabilityMask2 of the ClassPortInfo. +* +* NOTES +* +* SEE ALSO +* ib_class_port_info_t +*********/ + +/****s* IBA Base: Types/ib_sm_info_t +* NAME +* ib_sm_info_t +* +* DESCRIPTION +* SMInfo structure (14.2.5.13). +* +* SYNOPSIS +*/ +#include +typedef struct _ib_sm_info { + ib_net64_t guid; + ib_net64_t sm_key; + ib_net32_t act_count; + uint8_t pri_state; + +} PACK_SUFFIX ib_sm_info_t; +#include +/* +* FIELDS +* guid +* Port GUID for this SM. +* +* sm_key +* SM_Key of this SM. +* +* act_count +* Activity counter used as a heartbeat. +* +* pri_state +* Priority and State information +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_sminfo_get_priority +* NAME +* ib_sminfo_get_priority +* +* DESCRIPTION +* Returns the priority value. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_sminfo_get_priority(IN const ib_sm_info_t * const p_smi) +{ + return ((uint8_t) ((p_smi->pri_state & 0xF0) >> 4)); +} + +/* +* PARAMETERS +* p_smi +* [in] Pointer to the SMInfo Attribute. +* +* RETURN VALUES +* Returns the priority value. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_sminfo_get_state +* NAME +* ib_sminfo_get_state +* +* DESCRIPTION +* Returns the state value. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_sminfo_get_state(IN const ib_sm_info_t * const p_smi) +{ + return ((uint8_t) (p_smi->pri_state & 0x0F)); +} + +/* +* PARAMETERS +* p_smi +* [in] Pointer to the SMInfo Attribute. +* +* RETURN VALUES +* Returns the state value. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* IBA Base: Types/ib_mad_t +* NAME +* ib_mad_t +* +* DESCRIPTION +* IBA defined MAD header (13.4.3) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_mad { + uint8_t base_ver; + uint8_t mgmt_class; + uint8_t class_ver; + uint8_t method; + ib_net16_t status; + ib_net16_t class_spec; + ib_net64_t trans_id; + ib_net16_t attr_id; + ib_net16_t resv; + ib_net32_t attr_mod; +} PACK_SUFFIX ib_mad_t; +#include +/* +* FIELDS +* base_ver +* MAD base format. +* +* mgmt_class +* Class of operation. +* +* class_ver +* Version of MAD class-specific format. +* +* method +* Method to perform, including 'R' bit. +* +* status +* Status of operation. +* +* class_spec +* Reserved for subnet management. +* +* trans_id +* Transaction ID. +* +* attr_id +* Attribute ID. +* +* resv +* Reserved field. +* +* attr_mod +* Attribute modifier. +* +* SEE ALSO +*********/ + +/****s* IBA Base: Types/ib_rmpp_mad_t +* NAME +* ib_rmpp_mad_t +* +* DESCRIPTION +* IBA defined MAD RMPP header (13.6.2.1) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_rmpp_mad { + ib_mad_t common_hdr; + + uint8_t rmpp_version; + uint8_t rmpp_type; + uint8_t rmpp_flags; + uint8_t rmpp_status; + + ib_net32_t seg_num; + ib_net32_t paylen_newwin; + +} PACK_SUFFIX ib_rmpp_mad_t; +#include +/* +* SEE ALSO +* ib_mad_t +*********/ + +/****f* IBA Base: Types/ib_mad_init_new +* NAME +* ib_mad_init_new +* +* DESCRIPTION +* Initializes a MAD common header. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_mad_init_new(IN ib_mad_t * const p_mad, + IN const uint8_t mgmt_class, + IN const uint8_t class_ver, + IN const uint8_t method, + IN const ib_net64_t trans_id, + IN const ib_net16_t attr_id, IN const ib_net32_t attr_mod) +{ + CL_ASSERT(p_mad); + p_mad->base_ver = 1; + p_mad->mgmt_class = mgmt_class; + p_mad->class_ver = class_ver; + p_mad->method = method; + p_mad->status = 0; + p_mad->class_spec = 0; + p_mad->trans_id = trans_id; + p_mad->attr_id = attr_id; + p_mad->resv = 0; + p_mad->attr_mod = attr_mod; +} + +/* +* PARAMETERS +* p_mad +* [in] Pointer to the MAD common header. +* +* mgmt_class +* [in] Class of operation. +* +* class_ver +* [in] Version of MAD class-specific format. +* +* method +* [in] Method to perform, including 'R' bit. +* +* trans_Id +* [in] Transaction ID. +* +* attr_id +* [in] Attribute ID. +* +* attr_mod +* [in] Attribute modifier. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* ib_mad_t +*********/ + +/****f* IBA Base: Types/ib_mad_init_response +* NAME +* ib_mad_init_response +* +* DESCRIPTION +* Initializes a MAD common header as a response. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_mad_init_response(IN const ib_mad_t * const p_req_mad, + IN ib_mad_t * const p_mad, IN const ib_net16_t status) +{ + CL_ASSERT(p_req_mad); + CL_ASSERT(p_mad); + *p_mad = *p_req_mad; + p_mad->status = status; + if (p_mad->method == IB_MAD_METHOD_SET) + p_mad->method = IB_MAD_METHOD_GET; + p_mad->method |= IB_MAD_METHOD_RESP_MASK; +} + +/* +* PARAMETERS +* p_req_mad +* [in] Pointer to the MAD common header in the original request MAD. +* +* p_mad +* [in] Pointer to the MAD common header to initialize. +* +* status +* [in] MAD Status value to return; +* +* RETURN VALUES +* None. +* +* NOTES +* p_req_mad and p_mad may point to the same MAD. +* +* SEE ALSO +* ib_mad_t +*********/ + +/****f* IBA Base: Types/ib_mad_is_response +* NAME +* ib_mad_is_response +* +* DESCRIPTION +* Returns TRUE if the MAD is a response ('R' bit set), +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_mad_is_response(IN const ib_mad_t * const p_mad) +{ + CL_ASSERT(p_mad); + return ((p_mad->method & IB_MAD_METHOD_RESP_MASK) == + IB_MAD_METHOD_RESP_MASK); +} + +/* +* PARAMETERS +* p_mad +* [in] Pointer to the MAD. +* +* RETURN VALUES +* Returns TRUE if the MAD is a response ('R' bit set), +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* ib_mad_t +*********/ + +#define IB_RMPP_TYPE_DATA 1 +#define IB_RMPP_TYPE_ACK 2 +#define IB_RMPP_TYPE_STOP 3 +#define IB_RMPP_TYPE_ABORT 4 + +#define IB_RMPP_NO_RESP_TIME 0x1F +#define IB_RMPP_FLAG_ACTIVE 0x01 +#define IB_RMPP_FLAG_FIRST 0x02 +#define IB_RMPP_FLAG_LAST 0x04 + +#define IB_RMPP_STATUS_SUCCESS 0 +#define IB_RMPP_STATUS_RESX 1 /* resources exhausted */ +#define IB_RMPP_STATUS_T2L 118 /* time too long */ +#define IB_RMPP_STATUS_BAD_LEN 119 /* incon. last and payload len */ +#define IB_RMPP_STATUS_BAD_SEG 120 /* incon. first and segment no */ +#define IB_RMPP_STATUS_BADT 121 /* bad rmpp type */ +#define IB_RMPP_STATUS_W2S 122 /* newwindowlast too small */ +#define IB_RMPP_STATUS_S2B 123 /* segment no too big */ +#define IB_RMPP_STATUS_BAD_STATUS 124 /* illegal status */ +#define IB_RMPP_STATUS_UNV 125 /* unsupported version */ +#define IB_RMPP_STATUS_TMR 126 /* too many retries */ +#define IB_RMPP_STATUS_UNSPEC 127 /* unspecified */ + +/****f* IBA Base: Types/ib_rmpp_is_flag_set +* NAME +* ib_rmpp_is_flag_set +* +* DESCRIPTION +* Returns TRUE if the MAD has the given RMPP flag set. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_rmpp_is_flag_set(IN const ib_rmpp_mad_t * const p_rmpp_mad, + IN const uint8_t flag) +{ + CL_ASSERT(p_rmpp_mad); + return ((p_rmpp_mad->rmpp_flags & flag) == flag); +} + +/* +* PARAMETERS +* ib_rmpp_mad_t +* [in] Pointer to a MAD with an RMPP header. +* +* flag +* [in] The RMPP flag being examined. +* +* RETURN VALUES +* Returns TRUE if the MAD has the given RMPP flag set. +* +* NOTES +* +* SEE ALSO +* ib_mad_t, ib_rmpp_mad_t +*********/ + +static inline void OSM_API +ib_rmpp_set_resp_time(IN ib_rmpp_mad_t * const p_rmpp_mad, + IN const uint8_t resp_time) +{ + CL_ASSERT(p_rmpp_mad); + p_rmpp_mad->rmpp_flags |= (resp_time << 3); +} + +static inline uint8_t OSM_API +ib_rmpp_get_resp_time(IN const ib_rmpp_mad_t * const p_rmpp_mad) +{ + CL_ASSERT(p_rmpp_mad); + return ((uint8_t) (p_rmpp_mad->rmpp_flags >> 3)); +} + +/****d* IBA Base: Constants/IB_SMP_DIRECTION +* NAME +* IB_SMP_DIRECTION +* +* DESCRIPTION +* The Direction bit for directed route SMPs. +* +* SOURCE +*/ +#define IB_SMP_DIRECTION_HO 0x8000 +#define IB_SMP_DIRECTION (CL_HTON16(IB_SMP_DIRECTION_HO)) +/**********/ + +/****d* IBA Base: Constants/IB_SMP_STATUS_MASK +* NAME +* IB_SMP_STATUS_MASK +* +* DESCRIPTION +* Mask value for extracting status from a directed route SMP. +* +* SOURCE +*/ +#define IB_SMP_STATUS_MASK_HO 0x7FFF +#define IB_SMP_STATUS_MASK (CL_HTON16(IB_SMP_STATUS_MASK_HO)) +/**********/ + +/****s* IBA Base: Types/ib_smp_t +* NAME +* ib_smp_t +* +* DESCRIPTION +* IBA defined SMP. (14.2.1.2) +* +* SYNOPSIS +*/ +#define IB_SMP_DATA_SIZE 64 +#include +typedef struct _ib_smp { + uint8_t base_ver; + uint8_t mgmt_class; + uint8_t class_ver; + uint8_t method; + ib_net16_t status; + uint8_t hop_ptr; + uint8_t hop_count; + ib_net64_t trans_id; + ib_net16_t attr_id; + ib_net16_t resv; + ib_net32_t attr_mod; + ib_net64_t m_key; + ib_net16_t dr_slid; + ib_net16_t dr_dlid; + uint32_t resv1[7]; + uint8_t data[IB_SMP_DATA_SIZE]; + uint8_t initial_path[IB_SUBNET_PATH_HOPS_MAX]; + uint8_t return_path[IB_SUBNET_PATH_HOPS_MAX]; + +} PACK_SUFFIX ib_smp_t; +#include +/* +* FIELDS +* base_ver +* MAD base format. +* +* mgmt_class +* Class of operation. +* +* class_ver +* Version of MAD class-specific format. +* +* method +* Method to perform, including 'R' bit. +* +* status +* Status of operation. +* +* hop_ptr +* Hop pointer for directed route MADs. +* +* hop_count +* Hop count for directed route MADs. +* +* trans_Id +* Transaction ID. +* +* attr_id +* Attribute ID. +* +* resv +* Reserved field. +* +* attr_mod +* Attribute modifier. +* +* m_key +* Management key value. +* +* dr_slid +* Directed route source LID. +* +* dr_dlid +* Directed route destination LID. +* +* resv0 +* Reserved for 64 byte alignment. +* +* data +* MAD data payload. +* +* initial_path +* Outbound port list. +* +* return_path +* Inbound port list. +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_smp_get_status +* NAME +* ib_smp_get_status +* +* DESCRIPTION +* Returns the SMP status value in network order. +* +* SYNOPSIS +*/ +static inline ib_net16_t OSM_API +ib_smp_get_status(IN const ib_smp_t * const p_smp) +{ + return ((ib_net16_t) (p_smp->status & IB_SMP_STATUS_MASK)); +} + +/* +* PARAMETERS +* p_smp +* [in] Pointer to the SMP packet. +* +* RETURN VALUES +* Returns the SMP status value in network order. +* +* NOTES +* +* SEE ALSO +* ib_smp_t +*********/ + +/****f* IBA Base: Types/ib_smp_is_response +* NAME +* ib_smp_is_response +* +* DESCRIPTION +* Returns TRUE if the SMP is a response MAD, FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_smp_is_response(IN const ib_smp_t * const p_smp) +{ + return (ib_mad_is_response((const ib_mad_t *)p_smp)); +} + +/* +* PARAMETERS +* p_smp +* [in] Pointer to the SMP packet. +* +* RETURN VALUES +* Returns TRUE if the SMP is a response MAD, FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* ib_smp_t +*********/ + +/****f* IBA Base: Types/ib_smp_is_d +* NAME +* ib_smp_is_d +* +* DESCRIPTION +* Returns TRUE if the SMP 'D' (direction) bit is set. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API ib_smp_is_d(IN const ib_smp_t * const p_smp) +{ + return ((p_smp->status & IB_SMP_DIRECTION) == IB_SMP_DIRECTION); +} + +/* +* PARAMETERS +* p_smp +* [in] Pointer to the SMP packet. +* +* RETURN VALUES +* Returns TRUE if the SMP 'D' (direction) bit is set. +* +* NOTES +* +* SEE ALSO +* ib_smp_t +*********/ + +/****f* IBA Base: Types/ib_smp_init_new +* NAME +* ib_smp_init_new +* +* DESCRIPTION +* Initializes a MAD common header. +* +* TODO +* This is too big for inlining, but leave it here for now +* since there is not yet another convient spot. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_smp_init_new(IN ib_smp_t * const p_smp, + IN const uint8_t method, + IN const ib_net64_t trans_id, + IN const ib_net16_t attr_id, + IN const ib_net32_t attr_mod, + IN const uint8_t hop_count, + IN const ib_net64_t m_key, + IN const uint8_t * path_out, + IN const ib_net16_t dr_slid, IN const ib_net16_t dr_dlid) +{ + CL_ASSERT(p_smp); + CL_ASSERT(hop_count < IB_SUBNET_PATH_HOPS_MAX); + p_smp->base_ver = 1; + p_smp->mgmt_class = IB_MCLASS_SUBN_DIR; + p_smp->class_ver = 1; + p_smp->method = method; + p_smp->status = 0; + p_smp->hop_ptr = 0; + p_smp->hop_count = hop_count; + p_smp->trans_id = trans_id; + p_smp->attr_id = attr_id; + p_smp->resv = 0; + p_smp->attr_mod = attr_mod; + p_smp->m_key = m_key; + p_smp->dr_slid = dr_slid; + p_smp->dr_dlid = dr_dlid; + + memset(p_smp->resv1, 0, + sizeof(p_smp->resv1) + + sizeof(p_smp->data) + + sizeof(p_smp->initial_path) + sizeof(p_smp->return_path)); + + /* copy the path */ + memcpy(&p_smp->initial_path, path_out, sizeof(p_smp->initial_path)); +} + +/* +* PARAMETERS +* p_smp +* [in] Pointer to the SMP packet. +* +* method +* [in] Method to perform, including 'R' bit. +* +* trans_Id +* [in] Transaction ID. +* +* attr_id +* [in] Attribute ID. +* +* attr_mod +* [in] Attribute modifier. +* +* hop_count +* [in] Number of hops in the path. +* +* m_key +* [in] Management key for this SMP. +* +* path_out +* [in] Port array for outbound path. +* +* +* RETURN VALUES +* None. +* +* NOTES +* Payload area is initialized to zero. +* +* +* SEE ALSO +* ib_mad_t +*********/ + +/****f* IBA Base: Types/ib_smp_get_payload_ptr +* NAME +* ib_smp_get_payload_ptr +* +* DESCRIPTION +* Gets a pointer to the SMP payload area. +* +* SYNOPSIS +*/ +static inline void *OSM_API +ib_smp_get_payload_ptr(IN const ib_smp_t * const p_smp) +{ + return ((void *)p_smp->data); +} + +/* +* PARAMETERS +* p_smp +* [in] Pointer to the SMP packet. +* +* RETURN VALUES +* Pointer to SMP payload area. +* +* NOTES +* +* SEE ALSO +* ib_mad_t +*********/ + +/****s* IBA Base: Types/ib_node_info_t +* NAME +* ib_node_info_t +* +* DESCRIPTION +* IBA defined NodeInfo. (14.2.5.3) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_node_info { + uint8_t base_version; + uint8_t class_version; + uint8_t node_type; + uint8_t num_ports; + ib_net64_t sys_guid; + ib_net64_t node_guid; + ib_net64_t port_guid; + ib_net16_t partition_cap; + ib_net16_t device_id; + ib_net32_t revision; + ib_net32_t port_num_vendor_id; + +} PACK_SUFFIX ib_node_info_t; +#include +/************/ + +/****s* IBA Base: Types/ib_sa_mad_t +* NAME +* ib_sa_mad_t +* +* DESCRIPTION +* IBA defined SA MAD format. (15.2.1) +* +* SYNOPSIS +*/ +#define IB_SA_DATA_SIZE 200 + +#include +typedef struct _ib_sa_mad { + uint8_t base_ver; + uint8_t mgmt_class; + uint8_t class_ver; + uint8_t method; + ib_net16_t status; + ib_net16_t resv; + ib_net64_t trans_id; + ib_net16_t attr_id; + ib_net16_t resv1; + ib_net32_t attr_mod; + + uint8_t rmpp_version; + uint8_t rmpp_type; + uint8_t rmpp_flags; + uint8_t rmpp_status; + + ib_net32_t seg_num; + ib_net32_t paylen_newwin; + + ib_net64_t sm_key; + + ib_net16_t attr_offset; + ib_net16_t resv3; + + ib_net64_t comp_mask; + + uint8_t data[IB_SA_DATA_SIZE]; +} PACK_SUFFIX ib_sa_mad_t; +#include +/**********/ +#define IB_SA_MAD_HDR_SIZE (sizeof(ib_sa_mad_t) - IB_SA_DATA_SIZE) + +static inline uint32_t OSM_API ib_get_attr_size(IN const ib_net16_t attr_offset) +{ + return (((uint32_t) cl_ntoh16(attr_offset)) << 3); +} + +static inline ib_net16_t OSM_API ib_get_attr_offset(IN const uint32_t attr_size) +{ + return (cl_hton16((uint16_t) (attr_size >> 3))); +} + +/****f* IBA Base: Types/ib_sa_mad_get_payload_ptr +* NAME +* ib_sa_mad_get_payload_ptr +* +* DESCRIPTION +* Gets a pointer to the SA MAD's payload area. +* +* SYNOPSIS +*/ +static inline void *OSM_API +ib_sa_mad_get_payload_ptr(IN const ib_sa_mad_t * const p_sa_mad) +{ + return ((void *)p_sa_mad->data); +} + +/* +* PARAMETERS +* p_sa_mad +* [in] Pointer to the SA MAD packet. +* +* RETURN VALUES +* Pointer to SA MAD payload area. +* +* NOTES +* +* SEE ALSO +* ib_mad_t +*********/ + +#define IB_NODE_INFO_PORT_NUM_MASK (CL_HTON32(0xFF000000)) +#define IB_NODE_INFO_VEND_ID_MASK (CL_HTON32(0x00FFFFFF)) +#if CPU_LE +#define IB_NODE_INFO_PORT_NUM_SHIFT 0 +#else +#define IB_NODE_INFO_PORT_NUM_SHIFT 24 +#endif + +/****f* IBA Base: Types/ib_node_info_get_local_port_num +* NAME +* ib_node_info_get_local_port_num +* +* DESCRIPTION +* Gets a the local port number from the NodeInfo attribute. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_node_info_get_local_port_num(IN const ib_node_info_t * const p_ni) +{ + return ((uint8_t) ((p_ni->port_num_vendor_id & + IB_NODE_INFO_PORT_NUM_MASK) + >> IB_NODE_INFO_PORT_NUM_SHIFT)); +} + +/* +* PARAMETERS +* p_ni +* [in] Pointer to a NodeInfo attribute. +* +* RETURN VALUES +* Local port number that returned the attribute. +* +* NOTES +* +* SEE ALSO +* ib_node_info_t +*********/ + +/****f* IBA Base: Types/ib_node_info_get_vendor_id +* NAME +* ib_node_info_get_vendor_id +* +* DESCRIPTION +* Gets the VendorID from the NodeInfo attribute. +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_node_info_get_vendor_id(IN const ib_node_info_t * const p_ni) +{ + return ((ib_net32_t) (p_ni->port_num_vendor_id & + IB_NODE_INFO_VEND_ID_MASK)); +} + +/* +* PARAMETERS +* p_ni +* [in] Pointer to a NodeInfo attribute. +* +* RETURN VALUES +* VendorID that returned the attribute. +* +* NOTES +* +* SEE ALSO +* ib_node_info_t +*********/ + +#define IB_NODE_DESCRIPTION_SIZE 64 + +#include +typedef struct _ib_node_desc { + // Node String is an array of UTF-8 character that + // describes the node in text format + // Note that this string is NOT NULL TERMINATED! + uint8_t description[IB_NODE_DESCRIPTION_SIZE]; + +} PACK_SUFFIX ib_node_desc_t; +#include + +#include +typedef struct _ib_node_record_t { + ib_net16_t lid; + ib_net16_t resv; + ib_node_info_t node_info; + ib_node_desc_t node_desc; + uint8_t pad[4]; + +} PACK_SUFFIX ib_node_record_t; +#include + +/****s* IBA Base: Types/ib_port_info_t +* NAME +* ib_port_info_t +* +* DESCRIPTION +* IBA defined PortInfo. (14.2.5.6) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_port_info { + ib_net64_t m_key; + ib_net64_t subnet_prefix; + ib_net16_t base_lid; + ib_net16_t master_sm_base_lid; + ib_net32_t capability_mask; + ib_net16_t diag_code; + ib_net16_t m_key_lease_period; + uint8_t local_port_num; + uint8_t link_width_enabled; + uint8_t link_width_supported; + uint8_t link_width_active; + uint8_t state_info1; /* LinkSpeedSupported and PortState */ + uint8_t state_info2; /* PortPhysState and LinkDownDefaultState */ + uint8_t mkey_lmc; + uint8_t link_speed; /* LinkSpeedEnabled and LinkSpeedActive */ + uint8_t mtu_smsl; + uint8_t vl_cap; /* VLCap and InitType */ + uint8_t vl_high_limit; + uint8_t vl_arb_high_cap; + uint8_t vl_arb_low_cap; + uint8_t mtu_cap; + uint8_t vl_stall_life; + uint8_t vl_enforce; + ib_net16_t m_key_violations; + ib_net16_t p_key_violations; + ib_net16_t q_key_violations; + uint8_t guid_cap; + uint8_t subnet_timeout; /* cli_rereg(1b), resrv( + 2b), timeout(5b) */ + uint8_t resp_time_value; + uint8_t error_threshold; + +} PACK_SUFFIX ib_port_info_t; +#include +/************/ + +#define IB_PORT_STATE_MASK 0x0F +#define IB_PORT_LMC_MASK 0x07 +#define IB_PORT_LMC_MAX 0x07 +#define IB_PORT_MPB_MASK 0xC0 +#define IB_PORT_MPB_SHIFT 6 +#define IB_PORT_LINK_SPEED_SHIFT 4 +#define IB_PORT_LINK_SPEED_SUPPORTED_MASK 0xF0 +#define IB_PORT_LINK_SPEED_ACTIVE_MASK 0xF0 +#define IB_PORT_LINK_SPEED_ENABLED_MASK 0x0F +#define IB_PORT_PHYS_STATE_MASK 0xF0 +#define IB_PORT_PHYS_STATE_SHIFT 4 +#define IB_PORT_PHYS_STATE_NO_CHANGE 0 +#define IB_PORT_PHYS_STATE_SLEEP 1 +#define IB_PORT_PHYS_STATE_POLLING 2 +#define IB_PORT_PHYS_STATE_DISABLED 3 +#define IB_PORT_PHYS_STATE_PORTCONFTRAIN 4 +#define IB_PORT_PHYS_STATE_LINKUP 5 +#define IB_PORT_PHYS_STATE_LINKERRRECOVER 6 +#define IB_PORT_PHYS_STATE_PHYTEST 7 +#define IB_PORT_LNKDWNDFTSTATE_MASK 0x0F + +#define IB_PORT_CAP_RESV0 (CL_HTON32(0x00000001)) +#define IB_PORT_CAP_IS_SM (CL_HTON32(0x00000002)) +#define IB_PORT_CAP_HAS_NOTICE (CL_HTON32(0x00000004)) +#define IB_PORT_CAP_HAS_TRAP (CL_HTON32(0x00000008)) +#define IB_PORT_CAP_HAS_IPD (CL_HTON32(0x00000010)) +#define IB_PORT_CAP_HAS_AUTO_MIG (CL_HTON32(0x00000020)) +#define IB_PORT_CAP_HAS_SL_MAP (CL_HTON32(0x00000040)) +#define IB_PORT_CAP_HAS_NV_MKEY (CL_HTON32(0x00000080)) +#define IB_PORT_CAP_HAS_NV_PKEY (CL_HTON32(0x00000100)) +#define IB_PORT_CAP_HAS_LED_INFO (CL_HTON32(0x00000200)) +#define IB_PORT_CAP_SM_DISAB (CL_HTON32(0x00000400)) +#define IB_PORT_CAP_HAS_SYS_IMG_GUID (CL_HTON32(0x00000800)) +#define IB_PORT_CAP_HAS_PKEY_SW_EXT_PORT_TRAP (CL_HTON32(0x00001000)) +#define IB_PORT_CAP_RESV13 (CL_HTON32(0x00002000)) +#define IB_PORT_CAP_RESV14 (CL_HTON32(0x00004000)) +#define IB_PORT_CAP_RESV15 (CL_HTON32(0x00008000)) +#define IB_PORT_CAP_HAS_COM_MGT (CL_HTON32(0x00010000)) +#define IB_PORT_CAP_HAS_SNMP (CL_HTON32(0x00020000)) +#define IB_PORT_CAP_REINIT (CL_HTON32(0x00040000)) +#define IB_PORT_CAP_HAS_DEV_MGT (CL_HTON32(0x00080000)) +#define IB_PORT_CAP_HAS_VEND_CLS (CL_HTON32(0x00100000)) +#define IB_PORT_CAP_HAS_DR_NTC (CL_HTON32(0x00200000)) +#define IB_PORT_CAP_HAS_CAP_NTC (CL_HTON32(0x00400000)) +#define IB_PORT_CAP_HAS_BM (CL_HTON32(0x00800000)) +#define IB_PORT_CAP_HAS_LINK_RT_LATENCY (CL_HTON32(0x01000000)) +#define IB_PORT_CAP_HAS_CLIENT_REREG (CL_HTON32(0x02000000)) +#define IB_PORT_CAP_HAS_OTHER_LOCAL_CHANGES_NTC (CL_HTON32(0x04000000)) +#define IB_PORT_CAP_HAS_LINK_SPEED_WIDTH_PAIRS_TBL (CL_HTON32(0x08000000)) +#define IB_PORT_CAP_RESV28 (CL_HTON32(0x10000000)) +#define IB_PORT_CAP_RESV29 (CL_HTON32(0x20000000)) +#define IB_PORT_CAP_RESV30 (CL_HTON32(0x40000000)) +#define IB_PORT_CAP_RESV31 (CL_HTON32(0x80000000)) + +/****f* IBA Base: Types/ib_port_info_get_port_state +* NAME +* ib_port_info_get_port_state +* +* DESCRIPTION +* Returns the port state. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_port_state(IN const ib_port_info_t * const p_pi) +{ + return ((uint8_t) (p_pi->state_info1 & IB_PORT_STATE_MASK)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Port state. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_port_state +* NAME +* ib_port_info_set_port_state +* +* DESCRIPTION +* Sets the port state. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_port_state(IN ib_port_info_t * const p_pi, + IN const uint8_t port_state) +{ + p_pi->state_info1 = (uint8_t) ((p_pi->state_info1 & 0xF0) | port_state); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* port_state +* [in] Port state value to set. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_vl_cap +* NAME +* ib_port_info_get_vl_cap +* +* DESCRIPTION +* Gets the VL Capability of a port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_vl_cap(IN const ib_port_info_t * const p_pi) +{ + return ((p_pi->vl_cap >> 4) & 0x0F); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* VL_CAP field +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_init_type +* NAME +* ib_port_info_get_init_type +* +* DESCRIPTION +* Gets the init type of a port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_init_type(IN const ib_port_info_t * const p_pi) +{ + return (uint8_t) (p_pi->vl_cap & 0x0F); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* InitType field +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_op_vls +* NAME +* ib_port_info_get_op_vls +* +* DESCRIPTION +* Gets the operational VLs on a port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_op_vls(IN const ib_port_info_t * const p_pi) +{ + return ((p_pi->vl_enforce >> 4) & 0x0F); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* OP_VLS field +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_op_vls +* NAME +* ib_port_info_set_op_vls +* +* DESCRIPTION +* Sets the operational VLs on a port. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_op_vls(IN ib_port_info_t * const p_pi, IN const uint8_t op_vls) +{ + p_pi->vl_enforce = + (uint8_t) ((p_pi->vl_enforce & 0x0F) | (op_vls << 4)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* op_vls +* [in] Encoded operation VLs value. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_state_no_change +* NAME +* ib_port_info_set_state_no_change +* +* DESCRIPTION +* Sets the port state fields to the value for "no change". +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_state_no_change(IN ib_port_info_t * const p_pi) +{ + ib_port_info_set_port_state(p_pi, IB_LINK_NO_CHANGE); + p_pi->state_info2 = 0; +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_link_speed_sup +* NAME +* ib_port_info_get_link_speed_sup +* +* DESCRIPTION +* Returns the encoded value for the link speed supported. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_link_speed_sup(IN const ib_port_info_t * const p_pi) +{ + return ((uint8_t) ((p_pi->state_info1 & + IB_PORT_LINK_SPEED_SUPPORTED_MASK) >> + IB_PORT_LINK_SPEED_SHIFT)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the encoded value for the link speed supported. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_link_speed_sup +* NAME +* ib_port_info_set_link_speed_sup +* +* DESCRIPTION +* Given an integer of the supported link speed supported. +* Set the appropriate bits in state_info1 +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_link_speed_sup(IN uint8_t const speed, + IN ib_port_info_t * p_pi) +{ + p_pi->state_info1 = + (~IB_PORT_LINK_SPEED_SUPPORTED_MASK & p_pi->state_info1) | + (IB_PORT_LINK_SPEED_SUPPORTED_MASK & + (speed << IB_PORT_LINK_SPEED_SHIFT)); +} + +/* +* PARAMETERS +* speed +* [in] Supported Speeds Code. +* +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_port_phys_state +* NAME +* ib_port_info_get_port_phys_state +* +* DESCRIPTION +* Returns the encoded value for the port physical state. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_port_phys_state(IN const ib_port_info_t * const p_pi) +{ + return ((uint8_t) ((p_pi->state_info2 & + IB_PORT_PHYS_STATE_MASK) >> + IB_PORT_PHYS_STATE_SHIFT)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the encoded value for the port physical state. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_port_phys_state +* NAME +* ib_port_info_set_port_phys_state +* +* DESCRIPTION +* Given an integer of the port physical state, +* Set the appropriate bits in state_info2 +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_port_phys_state(IN uint8_t const phys_state, + IN ib_port_info_t * p_pi) +{ + p_pi->state_info2 = + (~IB_PORT_PHYS_STATE_MASK & p_pi->state_info2) | + (IB_PORT_PHYS_STATE_MASK & + (phys_state << IB_PORT_PHYS_STATE_SHIFT)); +} + +/* +* PARAMETERS +* phys_state +* [in] port physical state. +* +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_link_down_def_state +* NAME +* ib_port_info_get_link_down_def_state +* +* DESCRIPTION +* Returns the link down default state. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_link_down_def_state(IN const ib_port_info_t * const p_pi) +{ + return ((uint8_t) (p_pi->state_info2 & IB_PORT_LNKDWNDFTSTATE_MASK)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* link down default state of the port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_link_down_def_state +* NAME +* ib_port_info_set_link_down_def_state +* +* DESCRIPTION +* Sets the link down default state of the port. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_link_down_def_state(IN ib_port_info_t * const p_pi, + IN const uint8_t link_dwn_state) +{ + p_pi->state_info2 = + (uint8_t) ((p_pi->state_info2 & 0xF0) | link_dwn_state); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* link_dwn_state +* [in] Link down default state of the port. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_link_speed_active +* NAME +* ib_port_info_get_link_speed_active +* +* DESCRIPTION +* Returns the Link Speed Active value assigned to this port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_link_speed_active(IN const ib_port_info_t * const p_pi) +{ + return ((uint8_t) ((p_pi->link_speed & + IB_PORT_LINK_SPEED_ACTIVE_MASK) >> + IB_PORT_LINK_SPEED_SHIFT)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the link speed active value assigned to this port. +* +* NOTES +* +* SEE ALSO +*********/ + +#define IB_LINK_WIDTH_ACTIVE_1X 1 +#define IB_LINK_WIDTH_ACTIVE_4X 2 +#define IB_LINK_WIDTH_ACTIVE_8X 4 +#define IB_LINK_WIDTH_ACTIVE_12X 8 +#define IB_LINK_SPEED_ACTIVE_2_5 1 +#define IB_LINK_SPEED_ACTIVE_5 2 +#define IB_LINK_SPEED_ACTIVE_10 4 + +/* following v1 ver1.2 p901 */ +#define IB_PATH_RECORD_RATE_2_5_GBS 2 +#define IB_PATH_RECORD_RATE_10_GBS 3 +#define IB_PATH_RECORD_RATE_30_GBS 4 +#define IB_PATH_RECORD_RATE_5_GBS 5 +#define IB_PATH_RECORD_RATE_20_GBS 6 +#define IB_PATH_RECORD_RATE_40_GBS 7 +#define IB_PATH_RECORD_RATE_60_GBS 8 +#define IB_PATH_RECORD_RATE_80_GBS 9 +#define IB_PATH_RECORD_RATE_120_GBS 10 + +#define IB_MIN_RATE IB_PATH_RECORD_RATE_2_5_GBS +#define IB_MAX_RATE IB_PATH_RECORD_RATE_120_GBS + +/****f* IBA Base: Types/ib_port_info_compute_rate +* NAME +* ib_port_info_compute_rate +* +* DESCRIPTION +* Returns the encoded value for the path rate. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_compute_rate(IN const ib_port_info_t * const p_pi) +{ + uint8_t rate = 0; + + switch (ib_port_info_get_link_speed_active(p_pi)) { + case IB_LINK_SPEED_ACTIVE_2_5: + switch (p_pi->link_width_active) { + case IB_LINK_WIDTH_ACTIVE_1X: + rate = IB_PATH_RECORD_RATE_2_5_GBS; + break; + + case IB_LINK_WIDTH_ACTIVE_4X: + rate = IB_PATH_RECORD_RATE_10_GBS; + break; + + case IB_LINK_WIDTH_ACTIVE_8X: + rate = IB_PATH_RECORD_RATE_20_GBS; + break; + + case IB_LINK_WIDTH_ACTIVE_12X: + rate = IB_PATH_RECORD_RATE_30_GBS; + break; + + default: + rate = IB_PATH_RECORD_RATE_2_5_GBS; + break; + } + break; + case IB_LINK_SPEED_ACTIVE_5: + switch (p_pi->link_width_active) { + case IB_LINK_WIDTH_ACTIVE_1X: + rate = IB_PATH_RECORD_RATE_5_GBS; + break; + + case IB_LINK_WIDTH_ACTIVE_4X: + rate = IB_PATH_RECORD_RATE_20_GBS; + break; + + case IB_LINK_WIDTH_ACTIVE_8X: + rate = IB_PATH_RECORD_RATE_40_GBS; + break; + + case IB_LINK_WIDTH_ACTIVE_12X: + rate = IB_PATH_RECORD_RATE_60_GBS; + break; + + default: + rate = IB_PATH_RECORD_RATE_5_GBS; + break; + } + break; + case IB_LINK_SPEED_ACTIVE_10: + switch (p_pi->link_width_active) { + case IB_LINK_WIDTH_ACTIVE_1X: + rate = IB_PATH_RECORD_RATE_10_GBS; + break; + + case IB_LINK_WIDTH_ACTIVE_4X: + rate = IB_PATH_RECORD_RATE_40_GBS; + break; + + case IB_LINK_WIDTH_ACTIVE_8X: + rate = IB_PATH_RECORD_RATE_80_GBS; + break; + + case IB_LINK_WIDTH_ACTIVE_12X: + rate = IB_PATH_RECORD_RATE_120_GBS; + break; + + default: + rate = IB_PATH_RECORD_RATE_10_GBS; + break; + } + break; + default: + rate = IB_PATH_RECORD_RATE_2_5_GBS; + break; + } + + return rate; +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the encoded value for the link speed supported. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_path_get_ipd +* NAME +* ib_path_get_ipd +* +* DESCRIPTION +* Returns the encoded value for the inter packet delay. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_path_get_ipd(IN uint8_t local_link_width_supported, IN uint8_t path_rec_rate) +{ + uint8_t ipd = 0; + + switch (local_link_width_supported) { + /* link_width_supported = 1: 1x */ + case 1: + break; + + /* link_width_supported = 3: 1x or 4x */ + case 3: + switch (path_rec_rate & 0x3F) { + case IB_PATH_RECORD_RATE_2_5_GBS: + ipd = 3; + break; + default: + break; + } + break; + + /* link_width_supported = 11: 1x or 4x or 12x */ + case 11: + switch (path_rec_rate & 0x3F) { + case IB_PATH_RECORD_RATE_2_5_GBS: + ipd = 11; + break; + case IB_PATH_RECORD_RATE_10_GBS: + ipd = 2; + break; + default: + break; + } + break; + + default: + break; + } + + return ipd; +} + +/* +* PARAMETERS +* local_link_width_supported +* [in] link with supported for this port +* +* path_rec_rate +* [in] rate field of the path record +* +* RETURN VALUES +* Returns the ipd +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_mtu_cap +* NAME +* ib_port_info_get_mtu_cap +* +* DESCRIPTION +* Returns the encoded value for the maximum MTU supported by this port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_mtu_cap(IN const ib_port_info_t * const p_pi) +{ + return ((uint8_t) (p_pi->mtu_cap & 0x0F)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the encooded value for the maximum MTU supported by this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_neighbor_mtu +* NAME +* ib_port_info_get_neighbor_mtu +* +* DESCRIPTION +* Returns the encoded value for the neighbor MTU supported by this port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_neighbor_mtu(IN const ib_port_info_t * const p_pi) +{ + return ((uint8_t) ((p_pi->mtu_smsl & 0xF0) >> 4)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the encoded value for the neighbor MTU at this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_neighbor_mtu +* NAME +* ib_port_info_set_neighbor_mtu +* +* DESCRIPTION +* Sets the Neighbor MTU value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_neighbor_mtu(IN ib_port_info_t * const p_pi, + IN const uint8_t mtu) +{ + CL_ASSERT(mtu <= 5); + CL_ASSERT(mtu != 0); + p_pi->mtu_smsl = (uint8_t) ((p_pi->mtu_smsl & 0x0F) | (mtu << 4)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* mtu +* [in] Encoded MTU value to set +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_master_smsl +* NAME +* ib_port_info_get_master_smsl +* +* DESCRIPTION +* Returns the encoded value for the Master SMSL at this port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_master_smsl(IN const ib_port_info_t * const p_pi) +{ + return (uint8_t) (p_pi->mtu_smsl & 0x0F); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the encoded value for the Master SMSL at this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_master_smsl +* NAME +* ib_port_info_set_master_smsl +* +* DESCRIPTION +* Sets the Master SMSL value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_master_smsl(IN ib_port_info_t * const p_pi, + IN const uint8_t smsl) +{ + p_pi->mtu_smsl = (uint8_t) ((p_pi->mtu_smsl & 0xF0) | smsl); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* mtu +* [in] Encoded Master SMSL value to set +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_timeout +* NAME +* ib_port_info_set_timeout +* +* DESCRIPTION +* Sets the encoded subnet timeout value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_timeout(IN ib_port_info_t * const p_pi, + IN const uint8_t timeout) +{ + CL_ASSERT(timeout <= 0x1F); + p_pi->subnet_timeout = + (uint8_t) ((p_pi->subnet_timeout & 0x80) | (timeout & 0x1F)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* timeout +* [in] Encoded timeout value to set +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_client_rereg +* NAME +* ib_port_info_set_client_rereg +* +* DESCRIPTION +* Sets the encoded client reregistration bit value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_client_rereg(IN ib_port_info_t * const p_pi, + IN const uint8_t client_rereg) +{ + CL_ASSERT(client_rereg <= 0x1); + p_pi->subnet_timeout = + (uint8_t) ((p_pi-> + subnet_timeout & 0x1F) | ((client_rereg << 7) & 0x80)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* client_rereg +* [in] Client reregistration value to set (either 1 or 0). +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_timeout +* NAME +* ib_port_info_get_timeout +* +* DESCRIPTION +* Gets the encoded subnet timeout value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_timeout(IN ib_port_info_t const *p_pi) +{ + return (p_pi->subnet_timeout & 0x1F); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* The encoded timeout value +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_client_rereg +* NAME +* ib_port_info_get_client_rereg +* +* DESCRIPTION +* Gets the encoded client reregistration bit value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_client_rereg(IN ib_port_info_t const *p_pi) +{ + return ((p_pi->subnet_timeout & 0x80) >> 7); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Client reregistration value (either 1 or 0). +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_hoq_lifetime +* NAME +* ib_port_info_set_hoq_lifetime +* +* DESCRIPTION +* Sets the Head of Queue Lifetime for which a packet can live in the head +* of VL queue +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_hoq_lifetime(IN ib_port_info_t * const p_pi, + IN const uint8_t hoq_life) +{ + p_pi->vl_stall_life = (uint8_t) ((hoq_life & 0x1f) | + (p_pi->vl_stall_life & 0xe0)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* hoq_life +* [in] Encoded lifetime value to set +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_hoq_lifetime +* NAME +* ib_port_info_get_hoq_lifetime +* +* DESCRIPTION +* Gets the Head of Queue Lifetime for which a packet can live in the head +* of VL queue +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_hoq_lifetime(IN const ib_port_info_t * const p_pi) +{ + return ((uint8_t) (p_pi->vl_stall_life & 0x1f)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Encoded lifetime value +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_vl_stall_count +* NAME +* ib_port_info_set_vl_stall_count +* +* DESCRIPTION +* Sets the VL Stall Count which define the number of contiguous +* HLL (hoq) drops that will put the VL into stalled mode. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_vl_stall_count(IN ib_port_info_t * const p_pi, + IN const uint8_t vl_stall_count) +{ + p_pi->vl_stall_life = (uint8_t) ((p_pi->vl_stall_life & 0x1f) | + ((vl_stall_count << 5) & 0xe0)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* vl_stall_count +* [in] value to set +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_vl_stall_count +* NAME +* ib_port_info_get_vl_stall_count +* +* DESCRIPTION +* Gets the VL Stall Count which define the number of contiguous +* HLL (hoq) drops that will put the VL into stalled mode +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_vl_stall_count(IN const ib_port_info_t * const p_pi) +{ + return ((uint8_t) (p_pi->vl_stall_life & 0xe0) >> 5); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* vl stall count +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_lmc +* NAME +* ib_port_info_get_lmc +* +* DESCRIPTION +* Returns the LMC value assigned to this port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_lmc(IN const ib_port_info_t * const p_pi) +{ + return ((uint8_t) (p_pi->mkey_lmc & IB_PORT_LMC_MASK)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the LMC value assigned to this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_lmc +* NAME +* ib_port_info_set_lmc +* +* DESCRIPTION +* Sets the LMC value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_lmc(IN ib_port_info_t * const p_pi, IN const uint8_t lmc) +{ + CL_ASSERT(lmc <= IB_PORT_LMC_MAX); + p_pi->mkey_lmc = (uint8_t) ((p_pi->mkey_lmc & 0xF8) | lmc); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* lmc +* [in] LMC value to set, must be less than 7. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_link_speed_enabled +* NAME +* ib_port_info_get_link_speed_enabled +* +* DESCRIPTION +* Returns the link speed enabled value assigned to this port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_link_speed_enabled(IN const ib_port_info_t * const p_pi) +{ + return ((uint8_t) (p_pi->link_speed & IB_PORT_LINK_SPEED_ENABLED_MASK)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Port state. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_link_speed_enabled +* NAME +* ib_port_info_set_link_speed_enabled +* +* DESCRIPTION +* Sets the link speed enabled value in the PortInfo attribute. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_link_speed_enabled(IN ib_port_info_t * const p_pi, + IN const uint8_t link_speed_enabled) +{ + p_pi->link_speed = + (uint8_t) ((p_pi->link_speed & 0xF0) | link_speed_enabled); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* link_speed_enabled +* [in] link speed enabled value to set. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_mpb +* NAME +* ib_port_info_get_mpb +* +* DESCRIPTION +* Returns the M_Key protect bits assigned to this port. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_mpb(IN const ib_port_info_t * const p_pi) +{ + return ((uint8_t) ((p_pi->mkey_lmc & IB_PORT_MPB_MASK) >> + IB_PORT_MPB_SHIFT)); +} + +/* +* PARAMETERS +* p_ni +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the M_Key protect bits assigned to this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_mpb +* NAME +* ib_port_info_set_mpb +* +* DESCRIPTION +* Set the M_Key protect bits of this port. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_mpb(IN ib_port_info_t * p_pi, IN uint8_t mpb) +{ + p_pi->mkey_lmc = + (~IB_PORT_MPB_MASK & p_pi->mkey_lmc) | + (IB_PORT_MPB_MASK & (mpb << IB_PORT_MPB_SHIFT)); +} + +/* +* PARAMETERS +* mpb +* [in] M_Key protect bits +* p_ni +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_local_phy_err_thd +* NAME +* ib_port_info_get_local_phy_err_thd +* +* DESCRIPTION +* Returns the Phy Link Threshold +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_local_phy_err_thd(IN const ib_port_info_t * const p_pi) +{ + return (uint8_t) ((p_pi->error_threshold & 0xF0) >> 4); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the Phy Link error threshold assigned to this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_get_overrun_err_thd +* NAME +* ib_port_info_get_local_overrun_err_thd +* +* DESCRIPTION +* Returns the Credits Overrun Errors Threshold +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_port_info_get_overrun_err_thd(IN const ib_port_info_t * const p_pi) +{ + return (uint8_t) (p_pi->error_threshold & 0x0F); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the Credits Overrun errors threshold assigned to this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_port_info_set_phy_and_overrun_err_thd +* NAME +* ib_port_info_set_phy_and_overrun_err_thd +* +* DESCRIPTION +* Sets the Phy Link and Credits Overrun Errors Threshold +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_port_info_set_phy_and_overrun_err_thd(IN ib_port_info_t * const p_pi, + IN uint8_t phy_threshold, + IN uint8_t overrun_threshold) +{ + p_pi->error_threshold = + (uint8_t) (((phy_threshold & 0x0F) << 4) | + (overrun_threshold & 0x0F)); +} + +/* +* PARAMETERS +* p_pi +* [in] Pointer to a PortInfo attribute. +* +* phy_threshold +* [in] Physical Link Errors Threshold above which Trap 129 is generated +* +* overrun_threshold +* [in] Credits overrun Errors Threshold above which Trap 129 is generated +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +typedef uint8_t ib_svc_name_t[64]; + +#include +typedef struct _ib_service_record { + ib_net64_t service_id; + ib_gid_t service_gid; + ib_net16_t service_pkey; + ib_net16_t resv; + ib_net32_t service_lease; + uint8_t service_key[16]; + ib_svc_name_t service_name; + uint8_t service_data8[16]; + ib_net16_t service_data16[8]; + ib_net32_t service_data32[4]; + ib_net64_t service_data64[2]; + +} PACK_SUFFIX ib_service_record_t; +#include + +#include +typedef struct _ib_portinfo_record { + ib_net16_t lid; + uint8_t port_num; + uint8_t resv; + ib_port_info_t port_info; + uint8_t pad[6]; + +} PACK_SUFFIX ib_portinfo_record_t; +#include + +#include +typedef struct _ib_link_record { + ib_net16_t from_lid; + uint8_t from_port_num; + uint8_t to_port_num; + ib_net16_t to_lid; + uint8_t pad[2]; + +} PACK_SUFFIX ib_link_record_t; +#include + +#include +typedef struct _ib_sminfo_record { + ib_net16_t lid; + uint16_t resv0; + ib_sm_info_t sm_info; + uint8_t pad[7]; + +} PACK_SUFFIX ib_sminfo_record_t; +#include + +/****s* IBA Base: Types/ib_lft_record_t +* NAME +* ib_lft_record_t +* +* DESCRIPTION +* IBA defined LinearForwardingTableRecord (15.2.5.6) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_lft_record { + ib_net16_t lid; + ib_net16_t block_num; + uint32_t resv0; + uint8_t lft[64]; +} PACK_SUFFIX ib_lft_record_t; +#include +/************/ + +/****s* IBA Base: Types/ib_mft_record_t +* NAME +* ib_mft_record_t +* +* DESCRIPTION +* IBA defined MulticastForwardingTableRecord (15.2.5.8) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_mft_record { + ib_net16_t lid; + ib_net16_t position_block_num; + uint32_t resv0; + ib_net16_t mft[IB_MCAST_BLOCK_SIZE]; +} PACK_SUFFIX ib_mft_record_t; +#include +/************/ + +/****s* IBA Base: Types/ib_switch_info_t +* NAME +* ib_switch_info_t +* +* DESCRIPTION +* IBA defined SwitchInfo. (14.2.5.4) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_switch_info { + ib_net16_t lin_cap; + ib_net16_t rand_cap; + ib_net16_t mcast_cap; + ib_net16_t lin_top; + uint8_t def_port; + uint8_t def_mcast_pri_port; + uint8_t def_mcast_not_port; + uint8_t life_state; + ib_net16_t lids_per_port; + ib_net16_t enforce_cap; + uint8_t flags; + +} PACK_SUFFIX ib_switch_info_t; +#include +/************/ + +#include +typedef struct _ib_switch_info_record { + ib_net16_t lid; + uint16_t resv0; + ib_switch_info_t switch_info; + uint8_t pad[3]; + +} PACK_SUFFIX ib_switch_info_record_t; +#include + +#define IB_SWITCH_PSC 0x04 + +/****f* IBA Base: Types/ib_switch_info_get_state_change +* NAME +* ib_switch_info_get_state_change +* +* DESCRIPTION +* Returns the value of the state change flag. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_switch_info_get_state_change(IN const ib_switch_info_t * const p_si) +{ + return ((p_si->life_state & IB_SWITCH_PSC) == IB_SWITCH_PSC); +} + +/* +* PARAMETERS +* p_si +* [in] Pointer to a SwitchInfo attribute. +* +* RETURN VALUES +* Returns the value of the state change flag. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_switch_info_clear_state_change +* NAME +* ib_switch_info_clear_state_change +* +* DESCRIPTION +* Clears the switch's state change bit. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_switch_info_clear_state_change(IN ib_switch_info_t * const p_si) +{ + p_si->life_state = (uint8_t) (p_si->life_state & 0xFB); +} + +/* +* PARAMETERS +* p_ni +* [in] Pointer to a PortInfo attribute. +* +* RETURN VALUES +* Returns the LMC value assigned to this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_switch_info_is_enhanced_port0 +* NAME +* ib_switch_info_is_enhanced_port0 +* +* DESCRIPTION +* Returns TRUE if the enhancedPort0 bit is on (meaning the switch +* port zero supports enhanced functions). +* Returns FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_switch_info_is_enhanced_port0(IN const ib_switch_info_t * const p_si) +{ + return ((p_si->flags & 0x08) == 0x08); +} + +/* +* PARAMETERS +* p_si +* [in] Pointer to a SwitchInfo attribute. +* +* RETURN VALUES +* Returns TRUE if the switch supports enhanced port 0. FALSE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* IBA Base: Types/ib_guid_info_t +* NAME +* ib_guid_info_t +* +* DESCRIPTION +* IBA defined GuidInfo. (14.2.5.5) +* +* SYNOPSIS +*/ +#define GUID_TABLE_MAX_ENTRIES 8 + +#include +typedef struct _ib_guid_info { + ib_net64_t guid[GUID_TABLE_MAX_ENTRIES]; + +} PACK_SUFFIX ib_guid_info_t; +#include +/************/ + +#include +typedef struct _ib_guidinfo_record { + ib_net16_t lid; + uint8_t block_num; + uint8_t resv; + uint32_t reserved; + ib_guid_info_t guid_info; +} PACK_SUFFIX ib_guidinfo_record_t; +#include + +#define IB_MULTIPATH_MAX_GIDS 11 /* Support max that can fit into first MAD (for now) */ + +#include +typedef struct _ib_multipath_rec_t { + ib_net32_t hop_flow_raw; + uint8_t tclass; + uint8_t num_path; + ib_net16_t pkey; + ib_net16_t qos_class_sl; + uint8_t mtu; + uint8_t rate; + uint8_t pkt_life; + uint8_t service_id_8msb; + uint8_t independence; /* formerly resv2 */ + uint8_t sgid_count; + uint8_t dgid_count; + uint8_t service_id_56lsb[7]; + ib_gid_t gids[IB_MULTIPATH_MAX_GIDS]; +} PACK_SUFFIX ib_multipath_rec_t; +#include +/* +* FIELDS +* hop_flow_raw +* Global routing parameters: hop count, flow label and raw bit. +* +* tclass +* Another global routing parameter. +* +* num_path +* Reversible path - 1 bit to say if path is reversible. +* num_path [6:0] In queries, maximum number of paths to return. +* In responses, undefined. +* +* pkey +* Partition key (P_Key) to use on this path. +* +* qos_class_sl +* QoS class and service level to use on this path. +* +* mtu +* MTU and MTU selector fields to use on this path +* rate +* Rate and rate selector fields to use on this path. +* +* pkt_life +* Packet lifetime +* +* service_id_8msb +* 8 most significant bits of Service ID +* +* service_id_56lsb +* 56 least significant bits of Service ID +* +* preference +* Indicates the relative merit of this path versus other path +* records returned from the SA. Lower numbers are better. +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_num_path +* NAME +* ib_multipath_rec_num_path +* +* DESCRIPTION +* Get max number of paths to return. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_num_path(IN const ib_multipath_rec_t * const p_rec) +{ + return (p_rec->num_path & 0x7F); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Maximum number of paths to return for each unique SGID_DGID combination. +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_set_sl +* NAME +* ib_multipath_rec_set_sl +* +* DESCRIPTION +* Set path service level. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_multipath_rec_set_sl( + IN ib_multipath_rec_t* const p_rec, + IN const uint8_t sl ) +{ + p_rec->qos_class_sl = + (p_rec->qos_class_sl & CL_HTON16(IB_MULTIPATH_REC_QOS_CLASS_MASK)) | + cl_hton16(sl & IB_MULTIPATH_REC_SL_MASK); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the MultiPath record object. +* +* sl +* [in] Service level to set. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_sl +* NAME +* ib_multipath_rec_sl +* +* DESCRIPTION +* Get multipath service level. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_sl(IN const ib_multipath_rec_t * const p_rec) +{ + return ((uint8_t) ((cl_ntoh16(p_rec->qos_class_sl)) & IB_MULTIPATH_REC_SL_MASK)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* SL. +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_set_qos_class +* NAME +* ib_multipath_rec_set_qos_class +* +* DESCRIPTION +* Set path QoS class. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_multipath_rec_set_qos_class( + IN ib_multipath_rec_t* const p_rec, + IN const uint16_t qos_class ) +{ + p_rec->qos_class_sl = + (p_rec->qos_class_sl & CL_HTON16(IB_MULTIPATH_REC_SL_MASK)) | + cl_hton16(qos_class << 4); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the MultiPath record object. +* +* qos_class +* [in] QoS class to set. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_qos_class +* NAME +* ib_multipath_rec_qos_class +* +* DESCRIPTION +* Get QoS class. +* +* SYNOPSIS +*/ +static inline uint16_t OSM_API +ib_multipath_rec_qos_class( + IN const ib_multipath_rec_t* const p_rec ) +{ + return (cl_ntoh16( p_rec->qos_class_sl ) >> 4); +} +/* +* PARAMETERS +* p_rec +* [in] Pointer to the MultiPath record object. +* +* RETURN VALUES +* QoS class of the MultiPath record. +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_mtu +* NAME +* ib_multipath_rec_mtu +* +* DESCRIPTION +* Get encoded path MTU. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_mtu(IN const ib_multipath_rec_t * const p_rec) +{ + return ((uint8_t) (p_rec->mtu & IB_MULTIPATH_REC_BASE_MASK)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Encoded path MTU. +* 1: 256 +* 2: 512 +* 3: 1024 +* 4: 2048 +* 5: 4096 +* others: reserved +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_mtu_sel +* NAME +* ib_multipath_rec_mtu_sel +* +* DESCRIPTION +* Get encoded multipath MTU selector. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_mtu_sel(IN const ib_multipath_rec_t * const p_rec) +{ + return ((uint8_t) ((p_rec->mtu & IB_MULTIPATH_REC_SELECTOR_MASK) >> 6)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Encoded path MTU selector value (for queries). +* 0: greater than MTU specified +* 1: less than MTU specified +* 2: exactly the MTU specified +* 3: largest MTU available +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_rate +* NAME +* ib_multipath_rec_rate +* +* DESCRIPTION +* Get encoded multipath rate. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_rate(IN const ib_multipath_rec_t * const p_rec) +{ + return ((uint8_t) (p_rec->rate & IB_MULTIPATH_REC_BASE_MASK)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Encoded multipath rate. +* 2: 2.5 Gb/sec. +* 3: 10 Gb/sec. +* 4: 30 Gb/sec. +* others: reserved +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_rate_sel +* NAME +* ib_multipath_rec_rate_sel +* +* DESCRIPTION +* Get encoded multipath rate selector. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_rate_sel(IN const ib_multipath_rec_t * const p_rec) +{ + return ((uint8_t) + ((p_rec->rate & IB_MULTIPATH_REC_SELECTOR_MASK) >> 6)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Encoded path rate selector value (for queries). +* 0: greater than rate specified +* 1: less than rate specified +* 2: exactly the rate specified +* 3: largest rate available +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_pkt_life +* NAME +* ib_multipath_rec_pkt_life +* +* DESCRIPTION +* Get encoded multipath pkt_life. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_pkt_life(IN const ib_multipath_rec_t * const p_rec) +{ + return ((uint8_t) (p_rec->pkt_life & IB_MULTIPATH_REC_BASE_MASK)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Encoded multipath pkt_life = 4.096 usec * 2 ** PacketLifeTime. +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_pkt_life_sel +* NAME +* ib_multipath_rec_pkt_life_sel +* +* DESCRIPTION +* Get encoded multipath pkt_lifetime selector. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_multipath_rec_pkt_life_sel(IN const ib_multipath_rec_t * const p_rec) +{ + return ((uint8_t) + ((p_rec->pkt_life & IB_MULTIPATH_REC_SELECTOR_MASK) >> 6)); +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Encoded path pkt_lifetime selector value (for queries). +* 0: greater than rate specified +* 1: less than rate specified +* 2: exactly the rate specified +* 3: smallest packet lifetime available +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +/****f* IBA Base: Types/ib_multipath_rec_service_id +* NAME +* ib_multipath_rec_service_id +* +* DESCRIPTION +* Get multipath service id. +* +* SYNOPSIS +*/ +static inline ib_net64_t OSM_API +ib_multipath_rec_service_id(IN const ib_multipath_rec_t * const p_rec) +{ + union { + ib_net64_t sid; + uint8_t sid_arr[8]; + } sid_union; + sid_union.sid_arr[0] = p_rec->service_id_8msb; + memcpy(&sid_union.sid_arr[1], p_rec->service_id_56lsb, 7); + return sid_union.sid; +} + +/* +* PARAMETERS +* p_rec +* [in] Pointer to the multipath record object. +* +* RETURN VALUES +* Service ID +* +* NOTES +* +* SEE ALSO +* ib_multipath_rec_t +*********/ + +#define IB_NUM_PKEY_ELEMENTS_IN_BLOCK 32 +/****s* IBA Base: Types/ib_pkey_table_t +* NAME +* ib_pkey_table_t +* +* DESCRIPTION +* IBA defined PKey table. (14.2.5.7) +* +* SYNOPSIS +*/ + +#include +typedef struct _ib_pkey_table { + ib_net16_t pkey_entry[IB_NUM_PKEY_ELEMENTS_IN_BLOCK]; + +} PACK_SUFFIX ib_pkey_table_t; +#include +/************/ + +/****s* IBA Base: Types/ib_pkey_table_record_t +* NAME +* ib_pkey_table_record_t +* +* DESCRIPTION +* IBA defined P_Key Table Record for SA Query. (15.2.5.11) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_pkey_table_record { + ib_net16_t lid; // for CA: lid of port, for switch lid of port 0 + uint16_t block_num; + uint8_t port_num; // for switch: port number, for CA: reserved + uint8_t reserved1; + uint16_t reserved2; + ib_pkey_table_t pkey_tbl; + +} PACK_SUFFIX ib_pkey_table_record_t; +#include +/************/ + +#define IB_DROP_VL 15 +#define IB_MAX_NUM_VLS 16 +/****s* IBA Base: Types/ib_slvl_table_t +* NAME +* ib_slvl_table_t +* +* DESCRIPTION +* IBA defined SL2VL Mapping Table Attribute. (14.2.5.8) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_slvl_table { + uint8_t raw_vl_by_sl[IB_MAX_NUM_VLS / 2]; +} PACK_SUFFIX ib_slvl_table_t; +#include +/************/ + +/****s* IBA Base: Types/ib_slvl_table_record_t +* NAME +* ib_slvl_table_record_t +* +* DESCRIPTION +* IBA defined SL to VL Mapping Table Record for SA Query. (15.2.5.4) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_slvl_table_record { + ib_net16_t lid; // for CA: lid of port, for switch lid of port 0 + uint8_t in_port_num; // reserved for CAs + uint8_t out_port_num; // reserved for CAs + uint32_t resv; + ib_slvl_table_t slvl_tbl; + +} PACK_SUFFIX ib_slvl_table_record_t; +#include +/************/ + +/****f* IBA Base: Types/ib_slvl_table_set +* NAME +* ib_slvl_table_set +* +* DESCRIPTION +* Set slvl table entry. +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_slvl_table_set(IN ib_slvl_table_t * p_slvl_tbl, + IN uint8_t sl_index, IN uint8_t vl) +{ + uint8_t idx = sl_index / 2; + CL_ASSERT(vl <= 15); + CL_ASSERT(sl_index <= 15); + + if (sl_index % 2) { + /* this is an odd sl. Need to update the ls bits */ + p_slvl_tbl->raw_vl_by_sl[idx] = + (p_slvl_tbl->raw_vl_by_sl[idx] & 0xF0) | vl; + } else { + /* this is an even sl. Need to update the ms bits */ + p_slvl_tbl->raw_vl_by_sl[idx] = + (vl << 4) | (p_slvl_tbl->raw_vl_by_sl[idx] & 0x0F); + } +} + +/* +* PARAMETERS +* p_slvl_tbl +* [in] pointer to ib_slvl_table_t object. +* +* sl_index +* [in] the sl index in the table to be updated. +* +* vl +* [in] the vl value to update for that sl. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +* ib_slvl_table_t +*********/ + +/****f* IBA Base: Types/ib_slvl_table_get +* NAME +* ib_slvl_table_get +* +* DESCRIPTION +* Get slvl table entry. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_slvl_table_get(IN const ib_slvl_table_t * p_slvl_tbl, IN uint8_t sl_index) +{ + uint8_t idx = sl_index / 2; + CL_ASSERT(sl_index <= 15); + + if (sl_index % 2) { + /* this is an odd sl. Need to return the ls bits. */ + return (p_slvl_tbl->raw_vl_by_sl[idx] & 0x0F); + } else { + /* this is an even sl. Need to return the ms bits. */ + return ((p_slvl_tbl->raw_vl_by_sl[idx] & 0xF0) >> 4); + } +} + +/* +* PARAMETERS +* p_slvl_tbl +* [in] pointer to ib_slvl_table_t object. +* +* sl_index +* [in] the sl index in the table whose value should be returned. +* +* RETURN VALUES +* vl for the requested sl_index. +* +* NOTES +* +* SEE ALSO +* ib_slvl_table_t +*********/ + +/****s* IBA Base: Types/ib_vl_arb_element_t +* NAME +* ib_vl_arb_element_t +* +* DESCRIPTION +* IBA defined VL Arbitration Table Element. (14.2.5.9) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_vl_arb_element { + uint8_t vl; + uint8_t weight; +} PACK_SUFFIX ib_vl_arb_element_t; +#include +/************/ + +#define IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK 32 + +/****s* IBA Base: Types/ib_vl_arb_table_t +* NAME +* ib_vl_arb_table_t +* +* DESCRIPTION +* IBA defined VL Arbitration Table. (14.2.5.9) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_vl_arb_table { + ib_vl_arb_element_t vl_entry[IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK]; +} PACK_SUFFIX ib_vl_arb_table_t; +#include +/************/ + +/****s* IBA Base: Types/ib_vl_arb_table_record_t +* NAME +* ib_vl_arb_table_record_t +* +* DESCRIPTION +* IBA defined VL Arbitration Table Record for SA Query. (15.2.5.9) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_vl_arb_table_record { + ib_net16_t lid; // for CA: lid of port, for switch lid of port 0 + uint8_t port_num; + uint8_t block_num; + uint32_t reserved; + ib_vl_arb_table_t vl_arb_tbl; +} PACK_SUFFIX ib_vl_arb_table_record_t; +#include +/************/ + +/* + * Global route header information received with unreliable datagram messages + */ +#include +typedef struct _ib_grh { + ib_net32_t ver_class_flow; + ib_net16_t resv1; + uint8_t resv2; + uint8_t hop_limit; + ib_gid_t src_gid; + ib_gid_t dest_gid; +} PACK_SUFFIX ib_grh_t; +#include + +/****f* IBA Base: Types/ib_grh_get_ver_class_flow +* NAME +* ib_grh_get_ver_class_flow +* +* DESCRIPTION +* Get encoded version, traffic class and flow label in grh +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_grh_get_ver_class_flow(IN const ib_net32_t ver_class_flow, + OUT uint8_t * const p_ver, + OUT uint8_t * const p_tclass, + OUT uint32_t * const p_flow_lbl) +{ + ib_net32_t tmp_ver_class_flow; + + if (p_ver) + *p_ver = (uint8_t) (ver_class_flow & 0x0f); + + tmp_ver_class_flow = ver_class_flow >> 4; + + if (p_tclass) + *p_tclass = (uint8_t) (tmp_ver_class_flow & 0xff); + + tmp_ver_class_flow = tmp_ver_class_flow >> 8; + + if (p_flow_lbl) + *p_flow_lbl = tmp_ver_class_flow & 0xfffff; +} + +/* +* PARAMETERS +* ver_class_flow +* [in] the version, traffic class and flow label info. +* +* RETURN VALUES +* p_ver +* [out] pointer to the version info. +* +* p_tclass +* [out] pointer to the traffic class info. +* +* p_flow_lbl +* [out] pointer to the flow label info +* +* NOTES +* +* SEE ALSO +* ib_grh_t +*********/ + +/****f* IBA Base: Types/ib_grh_set_ver_class_flow +* NAME +* ib_grh_set_ver_class_flow +* +* DESCRIPTION +* Set encoded version, traffic class and flow label in grh +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_grh_set_ver_class_flow(IN const uint8_t ver, + IN const uint8_t tclass, IN const uint32_t flow_lbl) +{ + ib_net32_t ver_class_flow; + + ver_class_flow = flow_lbl; + ver_class_flow = ver_class_flow << 8; + ver_class_flow = ver_class_flow | tclass; + ver_class_flow = ver_class_flow << 4; + ver_class_flow = ver_class_flow | ver; + return (ver_class_flow); +} + +/* +* PARAMETERS +* ver +* [in] the version info. +* +* tclass +* [in] the traffic class info. +* +* flow_lbl +* [in] the flow label info +* +* RETURN VALUES +* ver_class_flow +* [out] the version, traffic class and flow label info. +* +* NOTES +* +* SEE ALSO +* ib_grh_t +*********/ + +/****s* IBA Base: Types/ib_member_rec_t +* NAME +* ib_member_rec_t +* +* DESCRIPTION +* Multicast member record, used to create, join, and leave multicast +* groups. +* +* SYNOPSIS +*/ +#include +typedef struct _ib_member_rec { + ib_gid_t mgid; + ib_gid_t port_gid; + ib_net32_t qkey; + ib_net16_t mlid; + uint8_t mtu; + uint8_t tclass; + ib_net16_t pkey; + uint8_t rate; + uint8_t pkt_life; + ib_net32_t sl_flow_hop; + uint8_t scope_state; + uint8_t proxy_join:1; + uint8_t reserved[2]; + uint8_t pad[4]; + +} PACK_SUFFIX ib_member_rec_t; +#include +/* +* FIELDS +* mgid +* Multicast GID address for this multicast group. +* +* port_gid +* Valid GID of the endpoint joining this multicast group. +* +* qkey +* Q_Key to be sued by this multicast group. +* +* mlid +* Multicast LID for this multicast group. +* +* mtu +* MTU and MTU selector fields to use on this path +* +* tclass +* Another global routing parameter. +* +* pkey +* Partition key (P_Key) to use for this member. +* +* rate +* Rate and rate selector fields to use on this path. +* +* pkt_life +* Packet lifetime +* +* sl_flow_hop +* Global routing parameters: service level, hop count, and flow label. +* +* scope_state +* MGID scope and JoinState of multicast request. +* +* proxy_join +* Enables others in the Partition to proxy add/remove from the group +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/ib_member_get_sl_flow_hop +* NAME +* ib_member_get_sl_flow_hop +* +* DESCRIPTION +* Get encoded sl, flow label, and hop limit +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_member_get_sl_flow_hop(IN const ib_net32_t sl_flow_hop, + OUT uint8_t * const p_sl, + OUT uint32_t * const p_flow_lbl, + OUT uint8_t * const p_hop) +{ + uint32_t tmp; + + tmp = cl_ntoh32(sl_flow_hop); + if (p_hop) + *p_hop = (uint8_t) tmp; + tmp >>= 8; + + if (p_flow_lbl) + *p_flow_lbl = (uint32_t) (tmp & 0xfffff); + tmp >>= 20; + + if (p_sl) + *p_sl = (uint8_t) tmp; +} + +/* +* PARAMETERS +* sl_flow_hop +* [in] the sl, flow label, and hop limit of MC Group +* +* RETURN VALUES +* p_sl +* [out] pointer to the service level +* +* p_flow_lbl +* [out] pointer to the flow label info +* +* p_hop +* [out] pointer to the hop count limit. +* +* NOTES +* +* SEE ALSO +* ib_member_rec_t +*********/ + +/****f* IBA Base: Types/ib_member_set_sl_flow_hop +* NAME +* ib_member_set_sl_flow_hop +* +* DESCRIPTION +* Set encoded sl, flow label, and hop limit +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_member_set_sl_flow_hop(IN const uint8_t sl, + IN const uint32_t flow_label, + IN const uint8_t hop_limit) +{ + uint32_t tmp; + + tmp = (sl << 28) | ((flow_label & 0xfffff) << 8) | hop_limit; + return cl_hton32(tmp); +} + +/* +* PARAMETERS +* sl +* [in] the service level. +* +* flow_lbl +* [in] the flow label info +* +* hop_limit +* [in] the hop limit. +* +* RETURN VALUES +* sl_flow_hop +* [out] the encoded sl, flow label, and hop limit +* +* NOTES +* +* SEE ALSO +* ib_member_rec_t +*********/ + +/****f* IBA Base: Types/ib_member_get_scope_state +* NAME +* ib_member_get_scope_state +* +* DESCRIPTION +* Get encoded MGID scope and JoinState +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_member_get_scope_state(IN const uint8_t scope_state, + OUT uint8_t * const p_scope, + OUT uint8_t * const p_state) +{ + uint8_t tmp_scope_state; + + if (p_state) + *p_state = (uint8_t) (scope_state & 0x0f); + + tmp_scope_state = scope_state >> 4; + + if (p_scope) + *p_scope = (uint8_t) (tmp_scope_state & 0x0f); + +} + +/* +* PARAMETERS +* scope_state +* [in] the scope and state +* +* RETURN VALUES +* p_scope +* [out] pointer to the MGID scope +* +* p_state +* [out] pointer to the join state +* +* NOTES +* +* SEE ALSO +* ib_member_rec_t +*********/ + +/****f* IBA Base: Types/ib_member_set_scope_state +* NAME +* ib_member_set_scope_state +* +* DESCRIPTION +* Set encoded version, MGID scope and JoinState +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_member_set_scope_state(IN const uint8_t scope, IN const uint8_t state) +{ + uint8_t scope_state; + + scope_state = scope; + scope_state = scope_state << 4; + scope_state = scope_state | state; + return (scope_state); +} + +/* +* PARAMETERS +* scope +* [in] the MGID scope +* +* state +* [in] the JoinState +* +* RETURN VALUES +* scope_state +* [out] the encoded one +* +* NOTES +* +* SEE ALSO +* ib_member_rec_t +*********/ + +/****f* IBA Base: Types/ib_member_set_join_state +* NAME +* ib_member_set_join_state +* +* DESCRIPTION +* Set JoinState +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_member_set_join_state(IN OUT ib_member_rec_t * p_mc_rec, + IN const uint8_t state) +{ + /* keep the scope as it is */ + p_mc_rec->scope_state = (p_mc_rec->scope_state & 0xF0) | (0x0f & state); +} + +/* +* PARAMETERS +* p_mc_rec +* [in] pointer to the member record +* +* state +* [in] the JoinState +* +* RETURN VALUES +* NONE +* +* NOTES +* +* SEE ALSO +* ib_member_rec_t +*********/ + +/* + * Join State Codes: + */ +#define IB_MC_REC_STATE_FULL_MEMBER 0x01 +#define IB_MC_REC_STATE_NON_MEMBER 0x02 +#define IB_MC_REC_STATE_SEND_ONLY_NON_MEMBER 0x04 + +/* + * Generic MAD notice types + */ +#define IB_NOTICE_TYPE_FATAL 0x00 +#define IB_NOTICE_TYPE_URGENT 0x01 +#define IB_NOTICE_TYPE_SECURITY 0x02 +#define IB_NOTICE_TYPE_SUBN_MGMT 0x03 +#define IB_NOTICE_TYPE_INFO 0x04 +#define IB_NOTICE_TYPE_EMPTY 0x7F + +#include +typedef struct _ib_mad_notice_attr // Total Size calc Accumulated +{ + uint8_t generic_type; // 1 1 + + union _notice_g_or_v { + struct _notice_generic // 5 6 + { + uint8_t prod_type_msb; + ib_net16_t prod_type_lsb; + ib_net16_t trap_num; + } PACK_SUFFIX generic; + + struct _notice_vend { + uint8_t vend_id_msb; + ib_net16_t vend_id_lsb; + ib_net16_t dev_id; + } PACK_SUFFIX vend; + } g_or_v; + + ib_net16_t issuer_lid; // 2 8 + ib_net16_t toggle_count; // 2 10 + + union _data_details // 54 64 + { + struct _raw_data { + uint8_t details[54]; + } PACK_SUFFIX raw_data; + + struct _ntc_64_67 { + uint8_t res[6]; + ib_gid_t gid; // the Node or Multicast Group that came in/out + } PACK_SUFFIX ntc_64_67; + + struct _ntc_128 { + ib_net16_t sw_lid; // the sw lid of which link state changed + } PACK_SUFFIX ntc_128; + + struct _ntc_129_131 { + ib_net16_t pad; + ib_net16_t lid; // lid and port number of the violation + uint8_t port_num; + } PACK_SUFFIX ntc_129_131; + + struct _ntc_144 { + ib_net16_t pad1; + ib_net16_t lid; // lid where change occured + uint8_t pad2; // reserved + uint8_t local_changes; // 7b reserved 1b local changes + ib_net32_t new_cap_mask; // new capability mask + ib_net16_t change_flgs; // 13b reserved 3b change flags + } PACK_SUFFIX ntc_144; + + struct _ntc_145 { + ib_net16_t pad1; + ib_net16_t lid; // lid where sys guid changed + ib_net16_t pad2; + ib_net64_t new_sys_guid; // new system image guid + } PACK_SUFFIX ntc_145; + + struct _ntc_256 { // total: 54 + ib_net16_t pad1; // 2 + ib_net16_t lid; // 2 + ib_net16_t dr_slid; // 2 + uint8_t method; // 1 + uint8_t pad2; // 1 + ib_net16_t attr_id; // 2 + ib_net32_t attr_mod; // 4 + ib_net64_t mkey; // 8 + uint8_t pad3; // 1 + uint8_t dr_trunc_hop; // 1 + uint8_t dr_rtn_path[30]; // 30 + } PACK_SUFFIX ntc_256; + + struct _ntc_257_258 // violation of p/q_key // 49 + { + ib_net16_t pad1; // 2 + ib_net16_t lid1; // 2 + ib_net16_t lid2; // 2 + ib_net32_t key; // 2 + uint8_t sl; // 1 + ib_net32_t qp1; // 4 + ib_net32_t qp2; // 4 + ib_gid_t gid1; // 16 + ib_gid_t gid2; // 16 + } PACK_SUFFIX ntc_257_258; + + struct _ntc_259 // pkey violation from switch 51 + { + ib_net16_t data_valid; // 2 + ib_net16_t lid1; // 2 + ib_net16_t lid2; // 2 + ib_net16_t pkey; // 2 + ib_net32_t sl_qp1; // 4b sl, 4b pad, 24b qp1 + ib_net32_t qp2; // 8b pad, 24b qp2 + ib_gid_t gid1; // 16 + ib_gid_t gid2; // 16 + ib_net16_t sw_lid; // 2 + uint8_t port_no; // 1 + } PACK_SUFFIX ntc_259; + + } data_details; + + ib_gid_t issuer_gid; // 16 80 + +} PACK_SUFFIX ib_mad_notice_attr_t; +#include + +/** + * Trap 259 masks + */ +#define TRAP_259_MASK_SL (CL_HTON32(0xF0000000)) +#define TRAP_259_MASK_QP (CL_HTON32(0x00FFFFFF)) + +/** + * Trap 144 masks + */ +#define TRAP_144_MASK_OTHER_LOCAL_CHANGES 0x01 +#define TRAP_144_MASK_SM_PRIORITY_CHANGE (CL_HTON16(0x0008)) +#define TRAP_144_MASK_LINK_SPEED_ENABLE_CHANGE (CL_HTON16(0x0004)) +#define TRAP_144_MASK_LINK_WIDTH_ENABLE_CHANGE (CL_HTON16(0x0002)) +#define TRAP_144_MASK_NODE_DESCRIPTION_CHANGE (CL_HTON16(0x0001)) + +/****f* IBA Base: Types/ib_notice_is_generic +* NAME +* ib_notice_is_generic +* +* DESCRIPTION +* Check if the notice is generic +* +* SYNOPSIS +*/ +static inline boolean_t OSM_API +ib_notice_is_generic(IN const ib_mad_notice_attr_t * p_ntc) +{ + return (p_ntc->generic_type & 0x80); +} + +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* RETURN VALUES +* TRUE if mad is generic +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +/****f* IBA Base: Types/ib_notice_get_type +* NAME +* ib_notice_get_type +* +* DESCRIPTION +* Get the notice type +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_notice_get_type(IN const ib_mad_notice_attr_t * p_ntc) +{ + return p_ntc->generic_type & 0x7f; +} + +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* RETURN VALUES +* TRUE if mad is generic +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +/****f* IBA Base: Types/ib_notice_get_prod_type +* NAME +* ib_notice_get_prod_type +* +* DESCRIPTION +* Get the notice Producer Type of Generic Notice +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_notice_get_prod_type(IN const ib_mad_notice_attr_t * p_ntc) +{ + uint32_t pt; + + pt = cl_ntoh16(p_ntc->g_or_v.generic.prod_type_lsb) | + (p_ntc->g_or_v.generic.prod_type_msb << 16); + return cl_hton32(pt); +} + +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* RETURN VALUES +* The producer type +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +/****f* IBA Base: Types/ib_notice_set_prod_type +* NAME +* ib_notice_set_prod_type +* +* DESCRIPTION +* Set the notice Producer Type of Generic Notice +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_notice_set_prod_type(IN ib_mad_notice_attr_t * p_ntc, + IN ib_net32_t prod_type_val) +{ + uint32_t ptv = cl_ntoh32(prod_type_val); + p_ntc->g_or_v.generic.prod_type_lsb = + cl_hton16((uint16_t) (ptv & 0x0000ffff)); + p_ntc->g_or_v.generic.prod_type_msb = + (uint8_t) ((ptv & 0x00ff0000) >> 16); +} + +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* prod_type +* [in] The producer Type code +* +* RETURN VALUES +* None +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +/****f* IBA Base: Types/ib_notice_set_prod_type_ho +* NAME +* ib_notice_set_prod_type_ho +* +* DESCRIPTION +* Set the notice Producer Type of Generic Notice given Host Order +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_notice_set_prod_type_ho(IN ib_mad_notice_attr_t * p_ntc, + IN uint32_t prod_type_val_ho) +{ + p_ntc->g_or_v.generic.prod_type_lsb = + cl_hton16((uint16_t) (prod_type_val_ho & 0x0000ffff)); + p_ntc->g_or_v.generic.prod_type_msb = + (uint8_t) ((prod_type_val_ho & 0x00ff0000) >> 16); +} + +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* prod_type +* [in] The producer Type code in host order +* +* RETURN VALUES +* None +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +/****f* IBA Base: Types/ib_notice_get_vend_id +* NAME +* ib_notice_get_vend_id +* +* DESCRIPTION +* Get the Vendor Id of Vendor type Notice +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_notice_get_vend_id(IN const ib_mad_notice_attr_t * p_ntc) +{ + uint32_t vi; + + vi = cl_ntoh16(p_ntc->g_or_v.vend.vend_id_lsb) | + (p_ntc->g_or_v.vend.vend_id_msb << 16); + return cl_hton32(vi); +} + +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* RETURN VALUES +* The Vendor Id of Vendor type Notice +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +/****f* IBA Base: Types/ib_notice_set_vend_id +* NAME +* ib_notice_set_vend_id +* +* DESCRIPTION +* Set the notice Producer Type of Generic Notice +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_notice_set_vend_id(IN ib_mad_notice_attr_t * p_ntc, IN ib_net32_t vend_id) +{ + uint32_t vi = cl_ntoh32(vend_id); + p_ntc->g_or_v.vend.vend_id_lsb = + cl_hton16((uint16_t) (vi & 0x0000ffff)); + p_ntc->g_or_v.vend.vend_id_msb = (uint8_t) ((vi & 0x00ff0000) >> 16); +} + +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* vend_id +* [in] The producer Type code +* +* RETURN VALUES +* None +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +/****f* IBA Base: Types/ib_notice_set_vend_id_ho +* NAME +* ib_notice_set_vend_id_ho +* +* DESCRIPTION +* Set the notice Producer Type of Generic Notice given a host order value +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_notice_set_vend_id_ho(IN ib_mad_notice_attr_t * p_ntc, + IN uint32_t vend_id_ho) +{ + p_ntc->g_or_v.vend.vend_id_lsb = + cl_hton16((uint16_t) (vend_id_ho & 0x0000ffff)); + p_ntc->g_or_v.vend.vend_id_msb = + (uint8_t) ((vend_id_ho & 0x00ff0000) >> 16); +} + +/* +* PARAMETERS +* p_ntc +* [in] Pointer to the notice MAD attribute +* +* vend_id_ho +* [in] The producer Type code in host order +* +* RETURN VALUES +* None +* +* SEE ALSO +* ib_mad_notice_attr_t +*********/ + +#include +typedef struct _ib_inform_info { + ib_gid_t gid; + ib_net16_t lid_range_begin; + ib_net16_t lid_range_end; + ib_net16_t reserved1; + uint8_t is_generic; + uint8_t subscribe; + ib_net16_t trap_type; + union _inform_g_or_v { + struct _inform_generic { + ib_net16_t trap_num; + ib_net32_t qpn_resp_time_val; + uint8_t reserved2; + uint8_t node_type_msb; + ib_net16_t node_type_lsb; + } PACK_SUFFIX generic; + + struct _inform_vend { + ib_net16_t dev_id; + ib_net32_t qpn_resp_time_val; + uint8_t reserved2; + uint8_t vendor_id_msb; + ib_net16_t vendor_id_lsb; + } PACK_SUFFIX vend; + + } PACK_SUFFIX g_or_v; + +} PACK_SUFFIX ib_inform_info_t; +#include + +/****f* IBA Base: Types/ib_inform_info_get_qpn_resp_time +* NAME +* ib_inform_info_get_qpn_resp_time +* +* DESCRIPTION +* Get QPN of the inform info +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_inform_info_get_qpn_resp_time(IN const ib_net32_t qpn_resp_time_val, + OUT ib_net32_t * const p_qpn, + OUT uint8_t * const p_resp_time_val) +{ + uint32_t tmp = cl_ntoh32(qpn_resp_time_val); + + if (p_qpn) + *p_qpn = cl_hton32((tmp & 0xffffff00) >> 8); + + if (p_resp_time_val) + *p_resp_time_val = (uint8_t) (tmp & 0x0000001f); +} + +/* +* PARAMETERS +* qpn_resp_time_val +* [in] the qpn and resp time val from the mad +* +* RETURN VALUES +* p_qpn +* [out] pointer to the qpn +* +* p_state +* [out] pointer to the resp time val +* +* NOTES +* +* SEE ALSO +* ib_inform_info_t +*********/ + +/****f* IBA Base: Types/ib_inform_info_set_qpn +* NAME +* ib_inform_info_set_qpn +* +* DESCRIPTION +* Set the QPN of the inform info +* +* SYNOPSIS +*/ +static inline void OSM_API +ib_inform_info_set_qpn(IN ib_inform_info_t * p_ii, IN ib_net32_t const qpn) +{ + uint32_t tmp = cl_ntoh32(p_ii->g_or_v.generic.qpn_resp_time_val); + + p_ii->g_or_v.generic.qpn_resp_time_val = + cl_hton32((tmp & 0x000000ff) | ((cl_ntoh32(qpn) << 8) & 0xffffff00) + ); +} + +/* +* PARAMETERS +* +* NOTES +* +* SEE ALSO +* ib_inform_info_t +*********/ + +/****f* IBA Base: Types/ib_inform_info_get_prod_type +* NAME +* ib_inform_info_get_prod_type +* +* DESCRIPTION +* Get Producer Type of the Inform Info +* 13.4.8.3 InformInfo +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_inform_info_get_prod_type(IN const ib_inform_info_t * p_inf) +{ + uint32_t nt; + + nt = cl_ntoh16(p_inf->g_or_v.generic.node_type_lsb) | + (p_inf->g_or_v.generic.node_type_msb << 16); + return cl_hton32(nt); +} + +/* +* PARAMETERS +* p_inf +* [in] pointer to an inform info +* +* RETURN VALUES +* The producer type +* +* NOTES +* +* SEE ALSO +* ib_inform_info_t +*********/ + +/****f* IBA Base: Types/ib_inform_info_get_vend_id +* NAME +* ib_inform_info_get_vend_id +* +* DESCRIPTION +* Get Node Type of the Inform Info +* +* SYNOPSIS +*/ +static inline ib_net32_t OSM_API +ib_inform_info_get_vend_id(IN const ib_inform_info_t * p_inf) +{ + uint32_t vi; + + vi = cl_ntoh16(p_inf->g_or_v.vend.vendor_id_lsb) | + (p_inf->g_or_v.vend.vendor_id_msb << 16); + return cl_hton32(vi); +} + +/* +* PARAMETERS +* p_inf +* [in] pointer to an inform info +* +* RETURN VALUES +* The node type +* +* NOTES +* +* SEE ALSO +* ib_inform_info_t +*********/ + +/****s* IBA Base: Types/ib_inform_info_record_t +* NAME +* ib_inform_info_record_t +* +* DESCRIPTION +* IBA defined InformInfo Record. (15.2.5.12) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_inform_info_record { + ib_gid_t subscriber_gid; + ib_net16_t subscriber_enum; + uint8_t reserved[6]; + ib_inform_info_t inform_info; + uint8_t pad[4]; +} PACK_SUFFIX ib_inform_info_record_t; +#include + +/****s* IBA Base: Types/ib_perfmgt_mad_t +* NAME +* ib_perfmgt_mad_t +* +* DESCRIPTION +* IBA defined Perf Management MAD (16.3.1) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_perfmgt_mad { + ib_mad_t header; + uint8_t resv[40]; + +#define IB_PM_DATA_SIZE 192 + uint8_t data[IB_PM_DATA_SIZE]; + +} PACK_SUFFIX ib_perfmgt_mad_t; +#include +/* +* FIELDS +* header +* Common MAD header. +* +* resv +* Reserved. +* +* data +* Performance Management payload. The structure and content of this field +* depends upon the method, attr_id, and attr_mod fields in the header. +* +* SEE ALSO +* ib_mad_t +*********/ + +/****s* IBA Base: Types/ib_port_counters +* NAME +* ib_port_counters_t +* +* DESCRIPTION +* IBA defined PortCounters Attribute. (16.1.3.5) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_port_counters { + uint8_t reserved; + uint8_t port_select; + ib_net16_t counter_select; + ib_net16_t symbol_err_cnt; + uint8_t link_err_recover; + uint8_t link_downed; + ib_net16_t rcv_err; + ib_net16_t rcv_rem_phys_err; + ib_net16_t rcv_switch_relay_err; + ib_net16_t xmit_discards; + uint8_t xmit_constraint_err; + uint8_t rcv_constraint_err; + uint8_t res1; + uint8_t link_int_buffer_overrun; + ib_net16_t res2; + ib_net16_t vl15_dropped; + ib_net32_t xmit_data; + ib_net32_t rcv_data; + ib_net32_t xmit_pkts; + ib_net32_t rcv_pkts; +} PACK_SUFFIX ib_port_counters_t; +#include + +#define PC_LINK_INT(integ_buf_over) ((integ_buf_over & 0xF0) >> 4) +#define PC_BUF_OVERRUN(integ_buf_over) (integ_buf_over & 0x0F) + +/****s* IBA Base: Types/ib_port_counters_ext +* NAME +* ib_port_counters_ext_t +* +* DESCRIPTION +* IBA defined PortCounters Extended Attribute. (16.1.4.11) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_port_counters_ext { + uint8_t reserved; + uint8_t port_select; + ib_net16_t counter_select; + ib_net32_t reserved2; + ib_net64_t xmit_data; + ib_net64_t rcv_data; + ib_net64_t xmit_pkts; + ib_net64_t rcv_pkts; + ib_net64_t unicast_xmit_pkts; + ib_net64_t unicast_rcv_pkts; + ib_net64_t multicast_xmit_pkts; + ib_net64_t multicast_rcv_pkts; +} PACK_SUFFIX ib_port_counters_ext_t; +#include + +/****s* IBA Base: Types/ib_port_samples_control +* NAME +* ib_port_samples_control_t +* +* DESCRIPTION +* IBA defined PortSamplesControl Attribute. (16.1.3.2) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_port_samples_control { + uint8_t op_code; + uint8_t port_select; + uint8_t tick; + uint8_t counter_width; /* 5 bits res : 3bits counter_width */ + ib_net32_t counter_mask; /* 2 bits res : 3 bits counter_mask : 27 bits counter_masks_1to9 */ + ib_net16_t counter_mask_10to14; /* 1 bits res : 15 bits counter_masks_10to14 */ + uint8_t sample_mech; + uint8_t sample_status; /* 6 bits res : 2 bits sample_status */ + ib_net64_t option_mask; + ib_net64_t vendor_mask; + ib_net32_t sample_start; + ib_net32_t sample_interval; + ib_net16_t tag; + ib_net16_t counter_select0; + ib_net16_t counter_select1; + ib_net16_t counter_select2; + ib_net16_t counter_select3; + ib_net16_t counter_select4; + ib_net16_t counter_select5; + ib_net16_t counter_select6; + ib_net16_t counter_select7; + ib_net16_t counter_select8; + ib_net16_t counter_select9; + ib_net16_t counter_select10; + ib_net16_t counter_select11; + ib_net16_t counter_select12; + ib_net16_t counter_select13; + ib_net16_t counter_select14; +} PACK_SUFFIX ib_port_samples_control_t; +#include + +/****d* IBA Base: Types/CounterSelect values +* NAME +* Counter select values +* +* DESCRIPTION +* Mandatory counter select values (16.1.3.3) +* +* SYNOPSIS +*/ +#define IB_CS_PORT_XMIT_DATA (CL_HTON16(0x0001)) +#define IB_CS_PORT_RCV_DATA (CL_HTON16(0x0002)) +#define IB_CS_PORT_XMIT_PKTS (CL_HTON16(0x0003)) +#define IB_CS_PORT_RCV_PKTS (CL_HTON16(0x0004)) +#define IB_CS_PORT_XMIT_WAIT (CL_HTON16(0x0005)) + +/****s* IBA Base: Types/ib_port_samples_result +* NAME +* ib_port_samples_result_t +* +* DESCRIPTION +* IBA defined PortSamplesControl Attribute. (16.1.3.2) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_port_samples_result { + ib_net16_t tag; + ib_net16_t sample_status; /* 14 bits res : 2 bits sample_status */ + ib_net32_t counter0; + ib_net32_t counter1; + ib_net32_t counter2; + ib_net32_t counter3; + ib_net32_t counter4; + ib_net32_t counter5; + ib_net32_t counter6; + ib_net32_t counter7; + ib_net32_t counter8; + ib_net32_t counter9; + ib_net32_t counter10; + ib_net32_t counter11; + ib_net32_t counter12; + ib_net32_t counter13; + ib_net32_t counter14; +} PACK_SUFFIX ib_port_samples_result_t; +#include + +/****d* IBA Base: Types/DM_SVC_NAME +* NAME +* DM_SVC_NAME +* +* DESCRIPTION +* IBA defined Device Management service name (16.3) +* +* SYNOPSIS +*/ +#define DM_SVC_NAME "DeviceManager.IBTA" +/* +* SEE ALSO +*********/ + +/****s* IBA Base: Types/ib_dm_mad_t +* NAME +* ib_dm_mad_t +* +* DESCRIPTION +* IBA defined Device Management MAD (16.3.1) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_dm_mad { + ib_mad_t header; + uint8_t resv[40]; + +#define IB_DM_DATA_SIZE 192 + uint8_t data[IB_DM_DATA_SIZE]; + +} PACK_SUFFIX ib_dm_mad_t; +#include +/* +* FIELDS +* header +* Common MAD header. +* +* resv +* Reserved. +* +* data +* Device Management payload. The structure and content of this field +* depend upon the method, attr_id, and attr_mod fields in the header. +* +* SEE ALSO +* ib_mad_t +*********/ + +/****s* IBA Base: Types/ib_iou_info_t +* NAME +* ib_iou_info_t +* +* DESCRIPTION +* IBA defined IO Unit information structure (16.3.3.3) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_iou_info { + ib_net16_t change_id; + uint8_t max_controllers; + uint8_t diag_rom; + +#define IB_DM_CTRL_LIST_SIZE 128 + + uint8_t controller_list[IB_DM_CTRL_LIST_SIZE]; +#define IOC_NOT_INSTALLED 0x0 +#define IOC_INSTALLED 0x1 +// Reserved values 0x02-0xE +#define SLOT_DOES_NOT_EXIST 0xF + +} PACK_SUFFIX ib_iou_info_t; +#include +/* +* FIELDS +* change_id +* Value incremented, with rollover, by any change to the controller_list. +* +* max_controllers +* Number of slots in controller_list. +* +* diag_rom +* A byte containing two fields: DiagDeviceID and OptionROM. +* These fields may be read using the ib_iou_info_diag_dev_id +* and ib_iou_info_option_rom functions. +* +* controller_list +* A series of 4-bit nibbles, with each nibble representing a slot +* in the IO Unit. Individual nibbles may be read using the +* ioc_at_slot function. +* +* SEE ALSO +* ib_dm_mad_t, ib_iou_info_diag_dev_id, ib_iou_info_option_rom, ioc_at_slot +*********/ + +/****f* IBA Base: Types/ib_iou_info_diag_dev_id +* NAME +* ib_iou_info_diag_dev_id +* +* DESCRIPTION +* Returns the DiagDeviceID. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_iou_info_diag_dev_id(IN const ib_iou_info_t * const p_iou_info) +{ + return ((uint8_t) (p_iou_info->diag_rom >> 6 & 1)); +} + +/* +* PARAMETERS +* p_iou_info +* [in] Pointer to the IO Unit information structure. +* +* RETURN VALUES +* DiagDeviceID field of the IO Unit information. +* +* NOTES +* +* SEE ALSO +* ib_iou_info_t +*********/ + +/****f* IBA Base: Types/ib_iou_info_option_rom +* NAME +* ib_iou_info_option_rom +* +* DESCRIPTION +* Returns the OptionROM. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ib_iou_info_option_rom(IN const ib_iou_info_t * const p_iou_info) +{ + return ((uint8_t) (p_iou_info->diag_rom >> 7)); +} + +/* +* PARAMETERS +* p_iou_info +* [in] Pointer to the IO Unit information structure. +* +* RETURN VALUES +* OptionROM field of the IO Unit information. +* +* NOTES +* +* SEE ALSO +* ib_iou_info_t +*********/ + +/****f* IBA Base: Types/ioc_at_slot +* NAME +* ioc_at_slot +* +* DESCRIPTION +* Returns the IOC value at the specified slot. +* +* SYNOPSIS +*/ +static inline uint8_t OSM_API +ioc_at_slot(IN const ib_iou_info_t * const p_iou_info, IN uint8_t slot) +{ + if (slot >= IB_DM_CTRL_LIST_SIZE) + return SLOT_DOES_NOT_EXIST; + else + return (int8_t) + ((slot % 2) ? + ((p_iou_info->controller_list[slot / 2] & 0xf0) >> 4) : + (p_iou_info->controller_list[slot / 2] & 0x0f)); +} + +/* +* PARAMETERS +* p_iou_info +* [in] Pointer to the IO Unit information structure. +* +* slot +* [in] Pointer to the IO Unit information structure. +* +* RETURN VALUES +* OptionROM field of the IO Unit information. +* +* NOTES +* +* SEE ALSO +* ib_iou_info_t +*********/ + +/****s* IBA Base: Types/ib_ioc_profile_t +* NAME +* ib_ioc_profile_t +* +* DESCRIPTION +* IBA defined IO Controller profile structure (16.3.3.4) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_ioc_profile { + ib_net64_t ioc_guid; + + ib_net32_t vend_id; + + ib_net32_t dev_id; + ib_net16_t dev_ver; + ib_net16_t resv2; + + ib_net32_t subsys_vend_id; + ib_net32_t subsys_id; + + ib_net16_t io_class; + ib_net16_t io_subclass; + ib_net16_t protocol; + ib_net16_t protocol_ver; + + ib_net32_t resv3; + ib_net16_t send_msg_depth; + uint8_t resv4; + uint8_t rdma_read_depth; + ib_net32_t send_msg_size; + ib_net32_t rdma_size; + + uint8_t ctrl_ops_cap; +#define CTRL_OPS_CAP_ST 0x01 +#define CTRL_OPS_CAP_SF 0x02 +#define CTRL_OPS_CAP_RT 0x04 +#define CTRL_OPS_CAP_RF 0x08 +#define CTRL_OPS_CAP_WT 0x10 +#define CTRL_OPS_CAP_WF 0x20 +#define CTRL_OPS_CAP_AT 0x40 +#define CTRL_OPS_CAP_AF 0x80 + + uint8_t resv5; + + uint8_t num_svc_entries; +#define MAX_NUM_SVC_ENTRIES 0xff + + uint8_t resv6[9]; + +#define CTRL_ID_STRING_LEN 64 + char id_string[CTRL_ID_STRING_LEN]; + +} PACK_SUFFIX ib_ioc_profile_t; +#include +/* +* FIELDS +* ioc_guid +* An EUI-64 GUID used to uniquely identify the IO controller. +* +* vend_id +* IO controller vendor ID, IEEE format. +* +* dev_id +* A number assigned by the vendor to identify the type of controller. +* +* dev_ver +* A number assigned by the vendor to identify the divice version. +* +* subsys_vend_id +* ID of the vendor of the enclosure, if any, in which the IO controller +* resides in IEEE format; otherwise zero. +* +* subsys_id +* A number identifying the subsystem where the controller resides. +* +* io_class +* 0x0000 - 0xfffe = reserved for IO classes encompased by InfiniBand +* Architecture. 0xffff = Vendor specific. +* +* io_subclass +* 0x0000 - 0xfffe = reserved for IO subclasses encompased by InfiniBand +* Architecture. 0xffff = Vendor specific. This shall be set to 0xfff +* if the io_class component is 0xffff. +* +* protocol +* 0x0000 - 0xfffe = reserved for IO subclasses encompased by InfiniBand +* Architecture. 0xffff = Vendor specific. This shall be set to 0xfff +* if the io_class component is 0xffff. +* +* protocol_ver +* Protocol specific. +* +* send_msg_depth +* Maximum depth of the send message queue. +* +* rdma_read_depth +* Maximum depth of the per-channel RDMA read queue. +* +* send_msg_size +* Maximum size of send messages. +* +* ctrl_ops_cap +* Supported operation types of this IO controller. A bit set to one +* for affirmation of supported capability. +* +* num_svc_entries +* Number of entries in the service entries table. +* +* id_string +* UTF-8 encoded string for identifying the controller to an operator. +* +* SEE ALSO +* ib_dm_mad_t +*********/ + +static inline uint32_t OSM_API +ib_ioc_profile_get_vend_id(IN const ib_ioc_profile_t * const p_ioc_profile) +{ + return (cl_ntoh32(p_ioc_profile->vend_id) >> 8); +} + +static inline void OSM_API +ib_ioc_profile_set_vend_id(IN ib_ioc_profile_t * const p_ioc_profile, + IN const uint32_t vend_id) +{ + p_ioc_profile->vend_id = (cl_hton32(vend_id) << 8); +} + +/****s* IBA Base: Types/ib_svc_entry_t +* NAME +* ib_svc_entry_t +* +* DESCRIPTION +* IBA defined IO Controller service entry structure (16.3.3.5) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_svc_entry { +#define MAX_SVC_ENTRY_NAME_LEN 40 + char name[MAX_SVC_ENTRY_NAME_LEN]; + + ib_net64_t id; + +} PACK_SUFFIX ib_svc_entry_t; +#include +/* +* FIELDS +* name +* UTF-8 encoded, null-terminated name of the service. +* +* id +* An identifier of the associated Service. +* +* SEE ALSO +* ib_svc_entries_t +*********/ + +/****s* IBA Base: Types/ib_svc_entries_t +* NAME +* ib_svc_entries_t +* +* DESCRIPTION +* IBA defined IO Controller service entry array (16.3.3.5) +* +* SYNOPSIS +*/ +#include +typedef struct _ib_svc_entries { +#define SVC_ENTRY_COUNT 4 + ib_svc_entry_t service_entry[SVC_ENTRY_COUNT]; + +} PACK_SUFFIX ib_svc_entries_t; +#include +/* +* FIELDS +* service_entry +* An array of IO controller service entries. +* +* SEE ALSO +* ib_dm_mad_t, ib_svc_entry_t +*********/ + +static inline void OSM_API +ib_dm_get_slot_lo_hi(IN const ib_net32_t slot_lo_hi, + OUT uint8_t * const p_slot, + OUT uint8_t * const p_lo, OUT uint8_t * const p_hi) +{ + ib_net32_t tmp_slot_lo_hi = CL_NTOH32(slot_lo_hi); + + if (p_slot) + *p_slot = (uint8_t) ((tmp_slot_lo_hi >> 16) & 0x0f); + + if (p_hi) + *p_hi = (uint8_t) ((tmp_slot_lo_hi >> 8) & 0xff); + + if (p_lo) + *p_lo = (uint8_t) ((tmp_slot_lo_hi >> 0) & 0xff); +} + +/* + * IBA defined information describing an I/O controller + */ +#include +typedef struct _ib_ioc_info { + ib_net64_t module_guid; + ib_net64_t iou_guid; + ib_ioc_profile_t ioc_profile; + ib_net64_t access_key; + uint16_t initiators_conf; + uint8_t resv[38]; + +} PACK_SUFFIX ib_ioc_info_t; +#include + +/* + * The following definitions are shared between the Access Layer and VPD + */ +typedef struct _ib_ca *__ptr64 ib_ca_handle_t; +typedef struct _ib_pd *__ptr64 ib_pd_handle_t; +typedef struct _ib_rdd *__ptr64 ib_rdd_handle_t; +typedef struct _ib_mr *__ptr64 ib_mr_handle_t; +typedef struct _ib_mw *__ptr64 ib_mw_handle_t; +typedef struct _ib_qp *__ptr64 ib_qp_handle_t; +typedef struct _ib_eec *__ptr64 ib_eec_handle_t; +typedef struct _ib_cq *__ptr64 ib_cq_handle_t; +typedef struct _ib_av *__ptr64 ib_av_handle_t; +typedef struct _ib_mcast *__ptr64 ib_mcast_handle_t; + +/* Currently for windows branch, use the extended version of ib special verbs struct + in order to be compliant with Infinicon ib_types; later we'll change it to support + OpenSM ib_types.h */ + +#ifndef WIN32 +/****d* Access Layer/ib_api_status_t +* NAME +* ib_api_status_t +* +* DESCRIPTION +* Function return codes indicating the success or failure of an API call. +* Note that success is indicated by the return value IB_SUCCESS, which +* is always zero. +* +* NOTES +* IB_VERBS_PROCESSING_DONE is used by UVP library to terminate a verbs call +* in the pre-ioctl step itself. +* +* SYNOPSIS +*/ +typedef enum _ib_api_status_t { + IB_SUCCESS, + IB_INSUFFICIENT_RESOURCES, + IB_INSUFFICIENT_MEMORY, + IB_INVALID_PARAMETER, + IB_INVALID_SETTING, + IB_NOT_FOUND, + IB_TIMEOUT, + IB_CANCELED, + IB_INTERRUPTED, + IB_INVALID_PERMISSION, + IB_UNSUPPORTED, + IB_OVERFLOW, + IB_MAX_MCAST_QPS_REACHED, + IB_INVALID_QP_STATE, + IB_INVALID_EEC_STATE, + IB_INVALID_APM_STATE, + IB_INVALID_PORT_STATE, + IB_INVALID_STATE, + IB_RESOURCE_BUSY, + IB_INVALID_PKEY, + IB_INVALID_LKEY, + IB_INVALID_RKEY, + IB_INVALID_MAX_WRS, + IB_INVALID_MAX_SGE, + IB_INVALID_CQ_SIZE, + IB_INVALID_SERVICE_TYPE, + IB_INVALID_GID, + IB_INVALID_LID, + IB_INVALID_GUID, + IB_INVALID_CA_HANDLE, + IB_INVALID_AV_HANDLE, + IB_INVALID_CQ_HANDLE, + IB_INVALID_EEC_HANDLE, + IB_INVALID_QP_HANDLE, + IB_INVALID_PD_HANDLE, + IB_INVALID_MR_HANDLE, + IB_INVALID_MW_HANDLE, + IB_INVALID_RDD_HANDLE, + IB_INVALID_MCAST_HANDLE, + IB_INVALID_CALLBACK, + IB_INVALID_AL_HANDLE, /* InfiniBand Access Layer */ + IB_INVALID_HANDLE, /* InfiniBand Access Layer */ + IB_ERROR, /* InfiniBand Access Layer */ + IB_REMOTE_ERROR, /* Infiniband Access Layer */ + IB_VERBS_PROCESSING_DONE, /* See Notes above */ + IB_INVALID_WR_TYPE, + IB_QP_IN_TIMEWAIT, + IB_EE_IN_TIMEWAIT, + IB_INVALID_PORT, + IB_NOT_DONE, + IB_UNKNOWN_ERROR /* ALWAYS LAST ENUM VALUE! */ +} ib_api_status_t; +/*****/ + +OSM_EXPORT const char *ib_error_str[]; + +/****f* IBA Base: Types/ib_get_err_str +* NAME +* ib_get_err_str +* +* DESCRIPTION +* Returns a string for the specified status value. +* +* SYNOPSIS +*/ +static inline const char *OSM_API ib_get_err_str(IN ib_api_status_t status) +{ + if (status > IB_UNKNOWN_ERROR) + status = IB_UNKNOWN_ERROR; + return (ib_error_str[status]); +} + +/* +* PARAMETERS +* status +* [in] status value +* +* RETURN VALUES +* Pointer to the status description string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****d* Verbs/ib_async_event_t +* NAME +* ib_async_event_t -- Async event types +* +* DESCRIPTION +* This type indicates the reason the async callback was called. +* The context in the ib_event_rec_t indicates the resource context +* that associated with the callback. For example, for IB_AE_CQ_ERROR +* the context provided during the ib_create_cq is returned in the event. +* +* SYNOPSIS +*/ +typedef enum _ib_async_event_t { + IB_AE_SQ_ERROR = 1, + IB_AE_SQ_DRAINED, + IB_AE_RQ_ERROR, + IB_AE_CQ_ERROR, + IB_AE_QP_FATAL, + IB_AE_QP_COMM, + IB_AE_QP_APM, + IB_AE_EEC_FATAL, + IB_AE_EEC_COMM, + IB_AE_EEC_APM, + IB_AE_LOCAL_FATAL, + IB_AE_PKEY_TRAP, + IB_AE_QKEY_TRAP, + IB_AE_MKEY_TRAP, + IB_AE_PORT_TRAP, + IB_AE_SYSIMG_GUID_TRAP, + IB_AE_BUF_OVERRUN, + IB_AE_LINK_INTEGRITY, + IB_AE_FLOW_CTRL_ERROR, + IB_AE_BKEY_TRAP, + IB_AE_QP_APM_ERROR, + IB_AE_EEC_APM_ERROR, + IB_AE_WQ_REQ_ERROR, + IB_AE_WQ_ACCESS_ERROR, + IB_AE_PORT_ACTIVE, + IB_AE_PORT_DOWN, + IB_AE_UNKNOWN /* ALWAYS LAST ENUM VALUE */ +} ib_async_event_t; +/* +* VALUES +* IB_AE_SQ_ERROR +* An error occurred when accessing the send queue of the QP or EEC. +* This event is optional. +* +* IB_AE_SQ_DRAINED +* The send queue of the specified QP has completed the outstanding +* messages in progress when the state change was requested and, if +* applicable, has received all acknowledgements for those messages. +* +* IB_AE_RQ_ERROR +* An error occurred when accessing the receive queue of the QP or EEC. +* This event is optional. +* +* IB_AE_CQ_ERROR +* An error occurred when writing an entry to the CQ. +* +* IB_AE_QP_FATAL +* A catastrophic error occurred while accessing or processing the +* work queue that prevents reporting of completions. +* +* IB_AE_QP_COMM +* The first packet has arrived for the receive work queue where the +* QP is still in the RTR state. +* +* IB_AE_QP_APM +* If alternate path migration is supported, this event indicates that +* the QP connection has migrated to the alternate path. +* +* IB_AE_EEC_FATAL +* If reliable datagram service is supported, this event indicates that +* a catastrophic error occurred while accessing or processing the EEC +* that prevents reporting of completions. +* +* IB_AE_EEC_COMM +* If reliable datagram service is supported, this event indicates that +* the first packet has arrived for the receive work queue where the +* EEC is still in the RTR state. +* +* IB_AE_EEC_APM +* If reliable datagram service and alternate path migration is supported, +* this event indicates that the EEC connection has migrated to the +* alternate path. +* +* IB_AE_LOCAL_FATAL +* A catastrophic HCA error occurred which cannot be attributed to any +* resource; behavior is indeterminate. +* +* IB_AE_PKEY_TRAP +* A PKEY violation was detected. This event is optional. +* +* IB_AE_QKEY_TRAP +* A QKEY violation was detected. This event is optional. +* +* IB_AE_MKEY_TRAP +* An MKEY violation was detected. This event is optional. +* +* IB_AE_PORT_TRAP +* A port capability change was detected. This event is optional. +* +* IB_AE_SYSIMG_GUID_TRAP +* If the system image GUID is supported, this event indicates that the +* system image GUID of this HCA has been changed. This event is +* optional. +* +* IB_AE_BUF_OVERRUN +* The number of consecutive flow control update periods with at least +* one overrun error in each period has exceeded the threshold specified +* in the port info attributes. This event is optional. +* +* IB_AE_LINK_INTEGRITY +* The detection of excessively frequent local physical errors has +* exceeded the threshold specified in the port info attributes. This +* event is optional. +* +* IB_AE_FLOW_CTRL_ERROR +* An HCA watchdog timer monitoring the arrival of flow control updates +* has expired without receiving an update. This event is optional. +* +* IB_AE_BKEY_TRAP +* An BKEY violation was detected. This event is optional. +* +* IB_AE_QP_APM_ERROR +* If alternate path migration is supported, this event indicates that +* an incoming path migration request to this QP was not accepted. +* +* IB_AE_EEC_APM_ERROR +* If reliable datagram service and alternate path migration is supported, +* this event indicates that an incoming path migration request to this +* EEC was not accepted. +* +* IB_AE_WQ_REQ_ERROR +* An OpCode violation was detected at the responder. +* +* IB_AE_WQ_ACCESS_ERROR +* An access violation was detected at the responder. +* +* IB_AE_PORT_ACTIVE +* If the port active event is supported, this event is generated +* when the link becomes active: IB_LINK_ACTIVE. +* +* IB_AE_PORT_DOWN +* The link is declared unavailable: IB_LINK_INIT, IB_LINK_ARMED, +* IB_LINK_DOWN. +* +* IB_AE_UNKNOWN +* An unknown error occurred which cannot be attributed to any +* resource; behavior is indeterminate. +* +*****/ + +OSM_EXPORT const char *ib_async_event_str[]; + +/****f* IBA Base: Types/ib_get_async_event_str +* NAME +* ib_get_async_event_str +* +* DESCRIPTION +* Returns a string for the specified asynchronous event. +* +* SYNOPSIS +*/ +static inline const char *OSM_API +ib_get_async_event_str(IN ib_async_event_t event) +{ + if (event > IB_AE_UNKNOWN) + event = IB_AE_UNKNOWN; + return (ib_async_event_str[event]); +} + +/* +* PARAMETERS +* event +* [in] event value +* +* RETURN VALUES +* Pointer to the asynchronous event description string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* Verbs/ib_event_rec_t +* NAME +* ib_event_rec_t -- Async event notification record +* +* DESCRIPTION +* When an async event callback is made, this structure is passed to indicate +* the type of event, the source of event that caused it, and the context +* associated with this event. +* +* context -- Context of the resource that caused the event. +* -- ca_context if this is a port/adapter event. +* -- qp_context if the source is a QP event +* -- cq_context if the source is a CQ event. +* -- ee_context if the source is an EE event. +* +* SYNOPSIS +*/ +typedef struct _ib_event_rec { + void *context; + ib_async_event_t type; + + /* HCA vendor specific event information. */ + uint64_t vendor_specific; + + /* The following structures are valid only for trap types. */ + union _trap { + struct { + uint16_t lid; + ib_net64_t port_guid; + uint8_t port_num; + + /* + * The following structure is valid only for + * P_KEY, Q_KEY, and M_KEY violation traps. + */ + struct { + uint8_t sl; + uint16_t src_lid; + uint16_t dest_lid; + union _key { + uint16_t pkey; + uint32_t qkey; + uint64_t mkey; + } key; + uint32_t src_qp; + uint32_t dest_qp; + ib_gid_t src_gid; + ib_gid_t dest_gid; + + } violation; + + } info; + + ib_net64_t sysimg_guid; + + } trap; + +} ib_event_rec_t; +/*******/ + +/****d* Access Layer/ib_atomic_t +* NAME +* ib_atomic_t +* +* DESCRIPTION +* Indicates atomicity levels supported by an adapter. +* +* SYNOPSIS +*/ +typedef enum _ib_atomic_t { + IB_ATOMIC_NONE, + IB_ATOMIC_LOCAL, + IB_ATOMIC_GLOBAL +} ib_atomic_t; +/* +* VALUES +* IB_ATOMIC_NONE +* Atomic operations not supported. +* +* IB_ATOMIC_LOCAL +* Atomic operations guaranteed between QPs of a single CA. +* +* IB_ATOMIC_GLOBAL +* Atomic operations are guaranteed between CA and any other entity +* in the system. +*****/ + +/****s* Access Layer/ib_port_cap_t +* NAME +* ib_port_cap_t +* +* DESCRIPTION +* Indicates which management agents are currently available on the specified +* port. +* +* SYNOPSIS +*/ +typedef struct _ib_port_cap { + boolean_t cm; + boolean_t snmp; + boolean_t dev_mgmt; + boolean_t vend; + boolean_t sm; + boolean_t sm_disable; + boolean_t qkey_ctr; + boolean_t pkey_ctr; + boolean_t notice; + boolean_t trap; + boolean_t apm; + boolean_t slmap; + boolean_t pkey_nvram; + boolean_t mkey_nvram; + boolean_t sysguid; + boolean_t dr_notice; + boolean_t boot_mgmt; + boolean_t capm_notice; + boolean_t reinit; + boolean_t ledinfo; + boolean_t port_active; + +} ib_port_cap_t; +/*****/ + +/****d* Access Layer/ib_init_type_t +* NAME +* ib_init_type_t +* +* DESCRIPTION +* If supported by the HCA, the type of initialization requested by +* this port before SM moves it to the active or armed state. If the +* SM implements reinitialization, it shall set these bits to indicate +* the type of initialization performed prior to activating the port. +* Otherwise, these bits shall be set to 0. +* +* SYNOPSIS +*/ +typedef uint8_t ib_init_type_t; +#define IB_INIT_TYPE_NO_LOAD 0x01 +#define IB_INIT_TYPE_PRESERVE_CONTENT 0x02 +#define IB_INIT_TYPE_PRESERVE_PRESENCE 0x04 +#define IB_INIT_TYPE_DO_NOT_RESUSCITATE 0x08 +/*****/ + +/****s* Access Layer/ib_port_attr_mod_t +* NAME +* ib_port_attr_mod_t +* +* DESCRIPTION +* Port attributes that may be modified. +* +* SYNOPSIS +*/ +typedef struct _ib_port_attr_mod { + ib_port_cap_t cap; + uint16_t pkey_ctr; + uint16_t qkey_ctr; + + ib_init_type_t init_type; + ib_net64_t system_image_guid; + +} ib_port_attr_mod_t; +/* +* SEE ALSO +* ib_port_cap_t +*****/ + +/****s* Access Layer/ib_port_attr_t +* NAME +* ib_port_attr_t +* +* DESCRIPTION +* Information about a port on a given channel adapter. +* +* SYNOPSIS +*/ +typedef struct _ib_port_attr { + ib_net64_t port_guid; + uint8_t port_num; + uint8_t mtu; + uint64_t max_msg_size; + ib_net16_t lid; + uint8_t lmc; + + /* + * LinkWidthSupported as defined in PortInfo. Required to calculate + * inter-packet delay (a.k.a. static rate). + */ + uint8_t link_width_supported; + + uint16_t max_vls; + + ib_net16_t sm_lid; + uint8_t sm_sl; + uint8_t link_state; + + ib_init_type_t init_type_reply; /* Optional */ + + /* + * subnet_timeout: + * The maximum expected subnet propagation delay to reach any port on + * the subnet. This value also determines the rate at which traps can + * be generated from this node. + * + * timeout = 4.096 microseconds * 2^subnet_timeout + */ + uint8_t subnet_timeout; + + ib_port_cap_t cap; + uint16_t pkey_ctr; + uint16_t qkey_ctr; + + uint16_t num_gids; + uint16_t num_pkeys; + /* + * Pointers at the end of the structure to allow doing a simple + * memory comparison of contents up to the first pointer. + */ + ib_gid_t *p_gid_table; + ib_net16_t *p_pkey_table; + +} ib_port_attr_t; +/* +* SEE ALSO +* uint8_t, ib_port_cap_t, ib_link_states_t +*****/ + +/****s* Access Layer/ib_ca_attr_t +* NAME +* ib_ca_attr_t +* +* DESCRIPTION +* Information about a channel adapter. +* +* SYNOPSIS +*/ +typedef struct _ib_ca_attr { + ib_net64_t ca_guid; + + uint32_t vend_id; + uint16_t dev_id; + uint16_t revision; + uint64_t fw_ver; + + /* + * Total size of the ca attributes in bytes + */ + uint32_t size; + uint32_t max_qps; + uint32_t max_wrs; + + uint32_t max_sges; + uint32_t max_rd_sges; + + uint32_t max_cqs; + uint32_t max_cqes; + + uint32_t max_pds; + + uint32_t init_regions; + uint64_t init_region_size; + + uint32_t init_windows; + uint32_t max_addr_handles; + + uint32_t max_partitions; + + ib_atomic_t atomicity; + + uint8_t max_qp_resp_res; + uint8_t max_eec_resp_res; + uint8_t max_resp_res; + + uint8_t max_qp_init_depth; + uint8_t max_eec_init_depth; + + uint32_t max_eecs; + uint32_t max_rdds; + + uint32_t max_ipv6_qps; + uint32_t max_ether_qps; + + uint32_t max_mcast_grps; + uint32_t max_mcast_qps; + uint32_t max_qps_per_mcast_grp; + uint32_t max_fmr; + uint32_t max_map_per_fmr; + + /* + * local_ack_delay: + * Specifies the maximum time interval between the local CA receiving + * a message and the transmission of the associated ACK or NAK. + * + * timeout = 4.096 microseconds * 2^local_ack_delay + */ + uint8_t local_ack_delay; + + boolean_t bad_pkey_ctr_support; + boolean_t bad_qkey_ctr_support; + boolean_t raw_mcast_support; + boolean_t apm_support; + boolean_t av_port_check; + boolean_t change_primary_port; + boolean_t modify_wr_depth; + boolean_t current_qp_state_support; + boolean_t shutdown_port_capability; + boolean_t init_type_support; + boolean_t port_active_event_support; + boolean_t system_image_guid_support; + boolean_t hw_agents; + + ib_net64_t system_image_guid; + + uint32_t num_page_sizes; + uint8_t num_ports; + + uint32_t *p_page_size; + ib_port_attr_t *p_port_attr; + +} ib_ca_attr_t; +/* +* FIELDS +* ca_guid +* GUID for this adapter. +* +* vend_id +* IEEE vendor ID for this adapter +* +* dev_id +* Device ID of this adapter. (typically from PCI device ID) +* +* revision +* Revision ID of this adapter +* +* fw_ver +* Device Firmware version. +* +* size +* Total size in bytes for the HCA attributes. This size includes total +* size required for all the variable members of the structure. If a +* vendor requires to pass vendor specific fields beyond this structure, +* the HCA vendor can choose to report a larger size. If a vendor is +* reporting extended vendor specific features, they should also provide +* appropriate access functions to aid with the required interpretation. +* +* max_qps +* Maximum number of QP's supported by this HCA. +* +* max_wrs +* Maximum number of work requests supported by this HCA. +* +* max_sges +* Maximum number of scatter gather elements supported per work request. +* +* max_rd_sges +* Maximum number of scatter gather elements supported for READ work +* requests for a Reliable Datagram QP. This value must be zero if RD +* service is not supported. +* +* max_cqs +* Maximum number of Completion Queues supported. +* +* max_cqes +* Maximum number of CQ elements supported per CQ. +* +* max_pds +* Maximum number of protection domains supported. +* +* init_regions +* Initial number of memory regions supported. These are only informative +* values. HCA vendors can extended and grow these limits on demand. +* +* init_region_size +* Initial limit on the size of the registered memory region. +* +* init_windows +* Initial number of window entries supported. +* +* max_addr_handles +* Maximum number of address handles supported. +* +* max_partitions +* Maximum number of partitions supported. +* +* atomicity +* Indicates level of atomic operations supported by this HCA. +* +* max_qp_resp_res +* max_eec_resp_res +* Maximum limit on number of responder resources for incoming RDMA +* operations, on QPs and EEC's respectively. +* +* max_resp_res +* Maximum number of responder resources per HCA, with this HCA used as +* the target. +* +* max_qp_init_depth +* max_eec_init_depth +* Maximimum initiator depth per QP or EEC for initiating RDMA reads and +* atomic operations. +* +* max_eecs +* Maximimum number of EEC's supported by the HCA. +* +* max_rdds +* Maximum number of Reliable datagram domains supported. +* +* max_ipv6_qps +* max_ether_qps +* Maximum number of IPV6 and raw ether QP's supported by this HCA. +* +* max_mcast_grps +* Maximum number of multicast groups supported. +* +* max_mcast_qps +* Maximum number of QP's that can support multicast operations. +* +* max_qps_per_mcast_grp +* Maximum number of multicast QP's per multicast group. +* +* local_ack_delay +* Specifies the maximum time interval between the local CA receiving +* a message and the transmission of the associated ACK or NAK. +* timeout = 4.096 microseconds * 2^local_ack_delay +* +* bad_pkey_ctr_support +* bad_qkey_ctr_support +* Indicates support for the bad pkey and qkey counters. +* +* raw_mcast_support +* Indicates support for raw packet multicast. +* +* apm_support +* Indicates support for Automatic Path Migration. +* +* av_port_check +* Indicates ability to check port number in address handles. +* +* change_primary_port +* Indicates ability to change primary port for a QP or EEC during a +* SQD->RTS transition. +* +* modify_wr_depth +* Indicates ability to modify QP depth during a modify QP operation. +* Check the verb specification for permitted states. +* +* current_qp_state_support +* Indicates ability of the HCA to support the current QP state modifier +* during a modify QP operation. +* +* shutdown_port_capability +* Shutdown port capability support indicator. +* +* init_type_support +* Indicates init_type_reply and ability to set init_type is supported. +* +* port_active_event_support +* Port active event support indicator. +* +* system_image_guid_support +* System image GUID support indicator. +* +* hw_agents +* Indicates SMA is implemented in HW. +* +* system_image_guid +* Optional system image GUID. This field is valid only if the +* system_image_guid_support flag is set. +* +* num_page_sizes +* Indicates support for different page sizes supported by the HCA. +* The variable size array can be obtained from p_page_size. +* +* num_ports +* Number of physical ports supported on this HCA. +* +* p_page_size +* Array holding different page size supported. +* +* p_port_attr +* Array holding port attributes. +* +* NOTES +* This structure contains the attributes of a channel adapter. Users must +* call ib_copy_ca_attr to copy the contents of this structure to a new +* memory region. +* +* SEE ALSO +* ib_port_attr_t, ib_atomic_t, ib_copy_ca_attr +*****/ + +/****f* Access layer/ib_copy_ca_attr +* NAME +* ib_copy_ca_attr +* +* DESCRIPTION +* Copies CA attributes. +* +* SYNOPSIS +*/ +ib_ca_attr_t *ib_copy_ca_attr(IN ib_ca_attr_t * const p_dest, + IN const ib_ca_attr_t * const p_src); +/* +* PARAMETERS +* p_dest +* Pointer to the buffer that is the destination of the copy. +* +* p_src +* Pointer to the CA attributes to copy. +* +* RETURN VALUE +* Pointer to the copied CA attributes. +* +* NOTES +* The buffer pointed to by the p_dest parameter must be at least the size +* specified in the size field of the buffer pointed to by p_src. +* +* SEE ALSO +* ib_ca_attr_t, ib_dup_ca_attr, ib_free_ca_attr +*****/ + +/****s* Access Layer/ib_av_attr_t +* NAME +* ib_av_attr_t +* +* DESCRIPTION +* IBA address vector. +* +* SYNOPSIS +*/ +typedef struct _ib_av_attr { + uint8_t port_num; + + uint8_t sl; + ib_net16_t dlid; + + boolean_t grh_valid; + ib_grh_t grh; + uint8_t static_rate; + uint8_t path_bits; + + struct _av_conn { + uint8_t path_mtu; + uint8_t local_ack_timeout; + uint8_t seq_err_retry_cnt; + uint8_t rnr_retry_cnt; + + } conn; + +} ib_av_attr_t; +/* +* SEE ALSO +* ib_gid_t +*****/ + +/****d* Access Layer/ib_qp_type_t +* NAME +* ib_qp_type_t +* +* DESCRIPTION +* Indicates the type of queue pair being created. +* +* SYNOPSIS +*/ +typedef enum _ib_qp_type { + IB_QPT_RELIABLE_CONN = 0, /* Matches CM REQ transport type */ + IB_QPT_UNRELIABLE_CONN = 1, /* Matches CM REQ transport type */ + IB_QPT_RELIABLE_DGRM = 2, /* Matches CM REQ transport type */ + IB_QPT_UNRELIABLE_DGRM, + IB_QPT_QP0, + IB_QPT_QP1, + IB_QPT_RAW_IPV6, + IB_QPT_RAW_ETHER, + IB_QPT_MAD, /* InfiniBand Access Layer */ + IB_QPT_QP0_ALIAS, /* InfiniBand Access Layer */ + IB_QPT_QP1_ALIAS /* InfiniBand Access Layer */ +} ib_qp_type_t; +/* +* VALUES +* IB_QPT_RELIABLE_CONN +* Reliable, connected queue pair. +* +* IB_QPT_UNRELIABLE_CONN +* Unreliable, connected queue pair. +* +* IB_QPT_RELIABLE_DGRM +* Reliable, datagram queue pair. +* +* IB_QPT_UNRELIABLE_DGRM +* Unreliable, datagram queue pair. +* +* IB_QPT_QP0 +* Queue pair 0. +* +* IB_QPT_QP1 +* Queue pair 1. +* +* IB_QPT_RAW_DGRM +* Raw datagram queue pair. +* +* IB_QPT_RAW_IPV6 +* Raw IP version 6 queue pair. +* +* IB_QPT_RAW_ETHER +* Raw Ethernet queue pair. +* +* IB_QPT_MAD +* Unreliable, datagram queue pair that will send and receive management +* datagrams with assistance from the access layer. +* +* IB_QPT_QP0_ALIAS +* Alias to queue pair 0. Aliased QPs can only be created on an aliased +* protection domain. +* +* IB_QPT_QP1_ALIAS +* Alias to queue pair 1. Aliased QPs can only be created on an aliased +* protection domain. +*****/ + +/****d* Access Layer/ib_access_t +* NAME +* ib_access_t +* +* DESCRIPTION +* Indicates the type of access is permitted on resources such as QPs, +* memory regions and memory windows. +* +* SYNOPSIS +*/ +typedef uint32_t ib_access_t; +#define IB_AC_RDMA_READ 0x00000001 +#define IB_AC_RDMA_WRITE 0x00000002 +#define IB_AC_ATOMIC 0x00000004 +#define IB_AC_LOCAL_WRITE 0x00000008 +#define IB_AC_MW_BIND 0x00000010 +/* +* NOTES +* Users may combine access rights using a bit-wise or operation to specify +* additional access. For example: IB_AC_RDMA_READ | IB_AC_RDMA_WRITE grants +* RDMA read and write access. +*****/ + +/****d* Access Layer/ib_qp_state_t +* NAME +* ib_qp_state_t +* +* DESCRIPTION +* Indicates or sets the state of a queue pair. The current state of a queue +* pair is returned through the ib_qp_query call and set via the +* ib_qp_modify call. +* +* SYNOPSIS +*/ +typedef uint32_t ib_qp_state_t; +#define IB_QPS_RESET 0x00000001 +#define IB_QPS_INIT 0x00000002 +#define IB_QPS_RTR 0x00000004 +#define IB_QPS_RTS 0x00000008 +#define IB_QPS_SQD 0x00000010 +#define IB_QPS_SQD_DRAINING 0x00000030 +#define IB_QPS_SQD_DRAINED 0x00000050 +#define IB_QPS_SQERR 0x00000080 +#define IB_QPS_ERROR 0x00000100 +#define IB_QPS_TIME_WAIT 0xDEAD0000 /* InfiniBand Access Layer */ +/*****/ + +/****d* Access Layer/ib_apm_state_t +* NAME +* ib_apm_state_t +* +* DESCRIPTION +* The current automatic path migration state of a queue pair +* +* SYNOPSIS +*/ +typedef enum _ib_apm_state { + IB_APM_MIGRATED = 1, + IB_APM_REARM, + IB_APM_ARMED +} ib_apm_state_t; +/*****/ + +/****s* Access Layer/ib_qp_create_t +* NAME +* ib_qp_create_t +* +* DESCRIPTION +* Attributes used to initialize a queue pair at creation time. +* +* SYNOPSIS +*/ +typedef struct _ib_qp_create { + ib_qp_type_t qp_type; + + ib_rdd_handle_t h_rdd; + + uint32_t sq_depth; + uint32_t rq_depth; + uint32_t sq_sge; + uint32_t rq_sge; + + ib_cq_handle_t h_sq_cq; + ib_cq_handle_t h_rq_cq; + + boolean_t sq_signaled; + +} ib_qp_create_t; +/* +* FIELDS +* type +* Specifies the type of queue pair to create. +* +* h_rdd +* A handle to a reliable datagram domain to associate with the queue +* pair. This field is ignored if the queue pair is not a reliable +* datagram type queue pair. +* +* sq_depth +* Indicates the requested maximum number of work requests that may be +* outstanding on the queue pair's send queue. This value must be less +* than or equal to the maximum reported by the channel adapter associated +* with the queue pair. +* +* rq_depth +* Indicates the requested maximum number of work requests that may be +* outstanding on the queue pair's receive queue. This value must be less +* than or equal to the maximum reported by the channel adapter associated +* with the queue pair. +* +* sq_sge +* Indicates the maximum number scatter-gather elements that may be +* given in a send work request. This value must be less +* than or equal to the maximum reported by the channel adapter associated +* with the queue pair. +* +* rq_sge +* Indicates the maximum number scatter-gather elements that may be +* given in a receive work request. This value must be less +* than or equal to the maximum reported by the channel adapter associated +* with the queue pair. +* +* h_sq_cq +* A handle to the completion queue that will be used to report send work +* request completions. This handle must be NULL if the type is +* IB_QPT_MAD, IB_QPT_QP0_ALIAS, or IB_QPT_QP1_ALIAS. +* +* h_rq_cq +* A handle to the completion queue that will be used to report receive +* work request completions. This handle must be NULL if the type is +* IB_QPT_MAD, IB_QPT_QP0_ALIAS, or IB_QPT_QP1_ALIAS. +* +* sq_signaled +* A flag that is used to indicate whether the queue pair will signal +* an event upon completion of a send work request. If set to +* TRUE, send work requests will always generate a completion +* event. If set to FALSE, a completion event will only be +* generated if the send_opt field of the send work request has the +* IB_SEND_OPT_SIGNALED flag set. +* +* SEE ALSO +* ib_qp_type_t, ib_qp_attr_t +*****/ + +/****s* Access Layer/ib_qp_attr_t +* NAME +* ib_qp_attr_t +* +* DESCRIPTION +* Queue pair attributes returned through ib_query_qp. +* +* SYNOPSIS +*/ +typedef struct _ib_qp_attr { + ib_pd_handle_t h_pd; + ib_qp_type_t qp_type; + ib_access_t access_ctrl; + uint16_t pkey_index; + + uint32_t sq_depth; + uint32_t rq_depth; + uint32_t sq_sge; + uint32_t rq_sge; + uint8_t init_depth; + uint8_t resp_res; + + ib_cq_handle_t h_sq_cq; + ib_cq_handle_t h_rq_cq; + ib_rdd_handle_t h_rdd; + + boolean_t sq_signaled; + + ib_qp_state_t state; + ib_net32_t num; + ib_net32_t dest_num; + ib_net32_t qkey; + + ib_net32_t sq_psn; + ib_net32_t rq_psn; + + uint8_t primary_port; + uint8_t alternate_port; + ib_av_attr_t primary_av; + ib_av_attr_t alternate_av; + ib_apm_state_t apm_state; + +} ib_qp_attr_t; +/* +* FIELDS +* h_pd +* This is a handle to a protection domain associated with the queue +* pair, or NULL if the queue pair is type IB_QPT_RELIABLE_DGRM. +* +* NOTES +* Other fields are defined by the Infiniband specification. +* +* SEE ALSO +* ib_qp_type_t, ib_access_t, ib_qp_state_t, ib_av_attr_t, ib_apm_state_t +*****/ + +/****d* Access Layer/ib_qp_opts_t +* NAME +* ib_qp_opts_t +* +* DESCRIPTION +* Optional fields supplied in the modify QP operation. +* +* SYNOPSIS +*/ +typedef uint32_t ib_qp_opts_t; +#define IB_MOD_QP_ALTERNATE_AV 0x00000001 +#define IB_MOD_QP_PKEY 0x00000002 +#define IB_MOD_QP_APM_STATE 0x00000004 +#define IB_MOD_QP_PRIMARY_AV 0x00000008 +#define IB_MOD_QP_RNR_NAK_TIMEOUT 0x00000010 +#define IB_MOD_QP_RESP_RES 0x00000020 +#define IB_MOD_QP_INIT_DEPTH 0x00000040 +#define IB_MOD_QP_PRIMARY_PORT 0x00000080 +#define IB_MOD_QP_ACCESS_CTRL 0x00000100 +#define IB_MOD_QP_QKEY 0x00000200 +#define IB_MOD_QP_SQ_DEPTH 0x00000400 +#define IB_MOD_QP_RQ_DEPTH 0x00000800 +#define IB_MOD_QP_CURRENT_STATE 0x00001000 +#define IB_MOD_QP_RETRY_CNT 0x00002000 +#define IB_MOD_QP_LOCAL_ACK_TIMEOUT 0x00004000 +#define IB_MOD_QP_RNR_RETRY_CNT 0x00008000 +/* +* SEE ALSO +* ib_qp_mod_t +*****/ + +/****s* Access Layer/ib_qp_mod_t +* NAME +* ib_qp_mod_t +* +* DESCRIPTION +* Information needed to change the state of a queue pair through the +* ib_modify_qp call. +* +* SYNOPSIS +*/ +typedef struct _ib_qp_mod { + ib_qp_state_t req_state; + + union _qp_state { + struct _qp_reset { + /* + * Time, in milliseconds, that the QP needs to spend in + * the time wait state before being reused. + */ + uint32_t timewait; + + } reset; + + struct _qp_init { + ib_qp_opts_t opts; + uint8_t primary_port; + ib_net32_t qkey; + uint16_t pkey_index; + ib_access_t access_ctrl; + + } init; + + struct _qp_rtr { + ib_net32_t rq_psn; + ib_net32_t dest_qp; + ib_av_attr_t primary_av; + uint8_t resp_res; + + ib_qp_opts_t opts; + ib_av_attr_t alternate_av; + ib_net32_t qkey; + uint16_t pkey_index; + ib_access_t access_ctrl; + uint32_t sq_depth; + uint32_t rq_depth; + uint8_t rnr_nak_timeout; + + } rtr; + + struct _qp_rts { + ib_net32_t sq_psn; + uint8_t retry_cnt; + uint8_t rnr_retry_cnt; + uint8_t rnr_nak_timeout; + uint8_t local_ack_timeout; + uint8_t init_depth; + + ib_qp_opts_t opts; + ib_qp_state_t current_state; + ib_net32_t qkey; + ib_access_t access_ctrl; + uint8_t resp_res; + + ib_av_attr_t primary_av; + ib_av_attr_t alternate_av; + + uint32_t sq_depth; + uint32_t rq_depth; + + ib_apm_state_t apm_state; + uint8_t primary_port; + uint16_t pkey_index; + + } rts; + + struct _qp_sqd { + boolean_t sqd_event; + + } sqd; + + } state; + +} ib_qp_mod_t; +/* +* SEE ALSO +* ib_qp_state_t, ib_access_t, ib_av_attr_t, ib_apm_state_t +*****/ + +/****s* Access Layer/ib_eec_attr_t +* NAME +* ib_eec_attr_t +* +* DESCRIPTION +* Information about an end-to-end context. +* +* SYNOPSIS +*/ +typedef struct _ib_eec_attr { + ib_qp_state_t state; + ib_rdd_handle_t h_rdd; + ib_net32_t local_eecn; + + ib_net32_t sq_psn; + ib_net32_t rq_psn; + uint8_t primary_port; + uint16_t pkey_index; + uint32_t resp_res; + ib_net32_t remote_eecn; + uint32_t init_depth; + uint32_t dest_num; // ??? What is this? + ib_av_attr_t primary_av; + ib_av_attr_t alternate_av; + ib_apm_state_t apm_state; + +} ib_eec_attr_t; +/* +* SEE ALSO +* ib_qp_state_t, ib_av_attr_t, ib_apm_state_t +*****/ + +/****d* Access Layer/ib_eec_opts_t +* NAME +* ib_eec_opts_t +* +* DESCRIPTION +* Optional fields supplied in the modify EEC operation. +* +* SYNOPSIS +*/ +typedef uint32_t ib_eec_opts_t; +#define IB_MOD_EEC_ALTERNATE_AV 0x00000001 +#define IB_MOD_EEC_PKEY 0x00000002 +#define IB_MOD_EEC_APM_STATE 0x00000004 +#define IB_MOD_EEC_PRIMARY_AV 0x00000008 +#define IB_MOD_EEC_RNR 0x00000010 +#define IB_MOD_EEC_RESP_RES 0x00000020 +#define IB_MOD_EEC_OUTSTANDING 0x00000040 +#define IB_MOD_EEC_PRIMARY_PORT 0x00000080 +/* +* NOTES +* +* +*****/ + +/****s* Access Layer/ib_eec_mod_t +* NAME +* ib_eec_mod_t +* +* DESCRIPTION +* Information needed to change the state of an end-to-end context through +* the ib_modify_eec function. +* +* SYNOPSIS +*/ +typedef struct _ib_eec_mod { + ib_qp_state_t req_state; + + union _eec_state { + struct _eec_init { + uint8_t primary_port; + uint16_t pkey_index; + + } init; + + struct _eec_rtr { + ib_net32_t rq_psn; + ib_net32_t remote_eecn; + ib_av_attr_t primary_av; + uint8_t resp_res; + + ib_eec_opts_t opts; + ib_av_attr_t alternate_av; + uint16_t pkey_index; + + } rtr; + + struct _eec_rts { + ib_net32_t sq_psn; + uint8_t retry_cnt; + uint8_t rnr_retry_cnt; + uint8_t local_ack_timeout; + uint8_t init_depth; + + ib_eec_opts_t opts; + ib_av_attr_t alternate_av; + ib_apm_state_t apm_state; + + ib_av_attr_t primary_av; + uint16_t pkey_index; + uint8_t primary_port; + + } rts; + + struct _eec_sqd { + boolean_t sqd_event; + + } sqd; + + } state; + +} ib_eec_mod_t; +/* +* SEE ALSO +* ib_qp_state_t, ib_av_attr_t, ib_apm_state_t +*****/ + +/****d* Access Layer/ib_wr_type_t +* NAME +* ib_wr_type_t +* +* DESCRIPTION +* Identifies the type of work request posted to a queue pair. +* +* SYNOPSIS +*/ +typedef enum _ib_wr_type_t { + WR_SEND = 1, + WR_RDMA_WRITE, + WR_RDMA_READ, + WR_COMPARE_SWAP, + WR_FETCH_ADD +} ib_wr_type_t; +/*****/ + +/****s* Access Layer/ib_local_ds_t +* NAME +* ib_local_ds_t +* +* DESCRIPTION +* Local data segment information referenced by send and receive work +* requests. This is used to specify local data buffers used as part of a +* work request. +* +* SYNOPSIS +*/ +typedef struct _ib_local_ds { + void *vaddr; + uint32_t length; + uint32_t lkey; + +} ib_local_ds_t; +/*****/ + +/****d* Access Layer/ib_send_opt_t +* NAME +* ib_send_opt_t +* +* DESCRIPTION +* Optional flags used when posting send work requests. These flags +* indicate specific processing for the send operation. +* +* SYNOPSIS +*/ +typedef uint32_t ib_send_opt_t; +#define IB_SEND_OPT_IMMEDIATE 0x00000001 +#define IB_SEND_OPT_FENCE 0x00000002 +#define IB_SEND_OPT_SIGNALED 0x00000004 +#define IB_SEND_OPT_SOLICITED 0x00000008 +#define IB_SEND_OPT_INLINE 0x00000010 +#define IB_SEND_OPT_LOCAL 0x00000020 +#define IB_SEND_OPT_VEND_MASK 0xFFFF0000 +/* +* VALUES +* The following flags determine the behavior of a work request when +* posted to the send side. +* +* IB_SEND_OPT_IMMEDIATE +* Send immediate data with the given request. +* +* IB_SEND_OPT_FENCE +* The operation is fenced. Complete all pending send operations +* before processing this request. +* +* IB_SEND_OPT_SIGNALED +* If the queue pair is configured for signaled completion, then +* generate a completion queue entry when this request completes. +* +* IB_SEND_OPT_SOLICITED +* Set the solicited bit on the last packet of this request. +* +* IB_SEND_OPT_INLINE +* Indicates that the requested send data should be copied into a VPD +* owned data buffer. This flag permits the user to issue send operations +* without first needing to register the buffer(s) associated with the +* send operation. Verb providers that support this operation may place +* vendor specific restrictions on the size of send operation that may +* be performed as inline. +* +* +* IB_SEND_OPT_LOCAL +* Indicates that a sent MAD request should be given to the local VPD for +* processing. MADs sent using this option are not placed on the wire. +* This send option is only valid for MAD send operations. +* +* +* IB_SEND_OPT_VEND_MASK +* This mask indicates bits reserved in the send options that may be used +* by the verbs provider to indicate vendor specific options. Bits set +* in this area of the send options are ignored by the Access Layer, but +* may have specific meaning to the underlying VPD. +* +*****/ + +/****s* Access Layer/ib_send_wr_t +* NAME +* ib_send_wr_t +* +* DESCRIPTION +* Information used to submit a work request to the send queue of a queue +* pair. +* +* SYNOPSIS +*/ +typedef struct _ib_send_wr { + struct _ib_send_wr *p_next; + uint64_t wr_id; + ib_wr_type_t wr_type; + ib_send_opt_t send_opt; + uint32_t num_ds; + ib_local_ds_t *ds_array; + ib_net32_t immediate_data; + + union _send_dgrm { + struct _send_ud { + ib_net32_t remote_qp; + ib_net32_t remote_qkey; + ib_av_handle_t h_av; + + } ud; + + struct _send_rd { + ib_net32_t remote_qp; + ib_net32_t remote_qkey; + ib_net32_t eecn; + + } rd; + + struct _send_raw_ether { + ib_net16_t dest_lid; + uint8_t path_bits; + uint8_t sl; + uint8_t max_static_rate; + ib_net16_t ether_type; + + } raw_ether; + + struct _send_raw_ipv6 { + ib_net16_t dest_lid; + uint8_t path_bits; + uint8_t sl; + uint8_t max_static_rate; + + } raw_ipv6; + + } dgrm; + + struct _send_remote_ops { + uint64_t vaddr; + uint32_t rkey; + + ib_net64_t atomic1; + ib_net64_t atomic2; + + } remote_ops; + +} ib_send_wr_t; +/* +* FIELDS +* p_next +* A pointer used to chain work requests together. This permits multiple +* work requests to be posted to a queue pair through a single function +* call. This value is set to NULL to mark the end of the chain. +* +* wr_id +* A 64-bit work request identifier that is returned to the consumer +* as part of the work completion. +* +* wr_type +* The type of work request being submitted to the send queue. +* +* send_opt +* Optional send control parameters. +* +* num_ds +* Number of local data segments specified by this work request. +* +* ds_array +* A reference to an array of local data segments used by the send +* operation. +* +* immediate_data +* 32-bit field sent as part of a message send or RDMA write operation. +* This field is only valid if the send_opt flag IB_SEND_OPT_IMMEDIATE +* has been set. +* +* dgrm.ud.remote_qp +* Identifies the destination queue pair of an unreliable datagram send +* operation. +* +* dgrm.ud.remote_qkey +* The qkey for the destination queue pair. +* +* dgrm.ud.h_av +* An address vector that specifies the path information used to route +* the outbound datagram to the destination queue pair. +* +* dgrm.rd.remote_qp +* Identifies the destination queue pair of a reliable datagram send +* operation. +* +* dgrm.rd.remote_qkey +* The qkey for the destination queue pair. +* +* dgrm.rd.eecn +* The local end-to-end context number to use with the reliable datagram +* send operation. +* +* dgrm.raw_ether.dest_lid +* The destination LID that will receive this raw ether send. +* +* dgrm.raw_ether.path_bits +* path bits... +* +* dgrm.raw_ether.sl +* service level... +* +* dgrm.raw_ether.max_static_rate +* static rate... +* +* dgrm.raw_ether.ether_type +* ether type... +* +* dgrm.raw_ipv6.dest_lid +* The destination LID that will receive this raw ether send. +* +* dgrm.raw_ipv6.path_bits +* path bits... +* +* dgrm.raw_ipv6.sl +* service level... +* +* dgrm.raw_ipv6.max_static_rate +* static rate... +* +* remote_ops.vaddr +* The registered virtual memory address of the remote memory to access +* with an RDMA or atomic operation. +* +* remote_ops.rkey +* The rkey associated with the specified remote vaddr. This data must +* be presented exactly as obtained from the remote node. No swapping +* of data must be performed. +* +* atomic1 +* The first operand for an atomic operation. +* +* atomic2 +* The second operand for an atomic operation. +* +* NOTES +* The format of data sent over the fabric is user-defined and is considered +* opaque to the access layer. The sole exception to this are MADs posted +* to a MAD QP service. MADs are expected to match the format defined by +* the Infiniband specification and must be in network-byte order when posted +* to the MAD QP service. +* +* SEE ALSO +* ib_wr_type_t, ib_local_ds_t, ib_send_opt_t +*****/ + +/****s* Access Layer/ib_recv_wr_t +* NAME +* ib_recv_wr_t +* +* DESCRIPTION +* Information used to submit a work request to the receive queue of a queue +* pair. +* +* SYNOPSIS +*/ +typedef struct _ib_recv_wr { + struct _ib_recv_wr *p_next; + uint64_t wr_id; + uint32_t num_ds; + ib_local_ds_t *ds_array; +} ib_recv_wr_t; +/* +* FIELDS +* p_next +* A pointer used to chain work requests together. This permits multiple +* work requests to be posted to a queue pair through a single function +* call. This value is set to NULL to mark the end of the chain. +* +* wr_id +* A 64-bit work request identifier that is returned to the consumer +* as part of the work completion. +* +* num_ds +* Number of local data segments specified by this work request. +* +* ds_array +* A reference to an array of local data segments used by the send +* operation. +* +* SEE ALSO +* ib_local_ds_t +*****/ + +/****s* Access Layer/ib_bind_wr_t +* NAME +* ib_bind_wr_t +* +* DESCRIPTION +* Information used to submit a memory window bind work request to the send +* queue of a queue pair. +* +* SYNOPSIS +*/ +typedef struct _ib_bind_wr { + uint64_t wr_id; + ib_send_opt_t send_opt; + + ib_mr_handle_t h_mr; + ib_access_t access_ctrl; + uint32_t current_rkey; + + ib_local_ds_t local_ds; + +} ib_bind_wr_t; +/* +* FIELDS +* wr_id +* A 64-bit work request identifier that is returned to the consumer +* as part of the work completion. +* +* send_opt +* Optional send control parameters. +* +* h_mr +* Handle to the memory region to which this window is being bound. +* +* access_ctrl +* Access rights for this memory window. +* +* current_rkey +* The current rkey assigned to this window for remote access. +* +* local_ds +* A reference to a local data segment used by the bind operation. +* +* SEE ALSO +* ib_send_opt_t, ib_access_t, ib_local_ds_t +*****/ + +/****d* Access Layer/ib_wc_status_t +* NAME +* ib_wc_status_t +* +* DESCRIPTION +* Indicates the status of a completed work request. These VALUES are +* returned to the user when retrieving completions. Note that success is +* identified as IB_WCS_SUCCESS, which is always zero. +* +* SYNOPSIS +*/ +typedef enum _ib_wc_status_t { + IB_WCS_SUCCESS, + IB_WCS_LOCAL_LEN_ERR, + IB_WCS_LOCAL_OP_ERR, + IB_WCS_LOCAL_EEC_OP_ERR, + IB_WCS_LOCAL_PROTECTION_ERR, + IB_WCS_WR_FLUSHED_ERR, + IB_WCS_MEM_WINDOW_BIND_ERR, + IB_WCS_REM_ACCESS_ERR, + IB_WCS_REM_OP_ERR, + IB_WCS_RNR_RETRY_ERR, + IB_WCS_TIMEOUT_RETRY_ERR, + IB_WCS_REM_INVALID_REQ_ERR, + IB_WCS_REM_INVALID_RD_REQ_ERR, + IB_WCS_INVALID_EECN, + IB_WCS_INVALID_EEC_STATE, + IB_WCS_UNMATCHED_RESPONSE, /* InfiniBand Access Layer */ + IB_WCS_CANCELED, /* InfiniBand Access Layer */ + IB_WCS_UNKNOWN /* Must be last. */ +} ib_wc_status_t; +/* +* VALUES +* IB_WCS_SUCCESS +* Work request completed successfully. +* +* IB_WCS_MAD +* The completed work request was associated with a managmenet datagram +* that requires post processing. The MAD will be returned to the user +* through a callback once all post processing has completed. +* +* IB_WCS_LOCAL_LEN_ERR +* Generated for a work request posted to the send queue when the +* total of the data segment lengths exceeds the message length of the +* channel. Generated for a work request posted to the receive queue when +* the total of the data segment lengths is too small for a +* valid incoming message. +* +* IB_WCS_LOCAL_OP_ERR +* An internal QP consistency error was generated while processing this +* work request. This may indicate that the QP was in an incorrect state +* for the requested operation. +* +* IB_WCS_LOCAL_EEC_OP_ERR +* An internal EEC consistency error was generated while processing +* this work request. This may indicate that the EEC was in an incorrect +* state for the requested operation. +* +* IB_WCS_LOCAL_PROTECTION_ERR +* The data segments of the locally posted work request did not refer to +* a valid memory region. The memory may not have been properly +* registered for the requested operation. +* +* IB_WCS_WR_FLUSHED_ERR +* The work request was flushed from the QP before being completed. +* +* IB_WCS_MEM_WINDOW_BIND_ERR +* A memory window bind operation failed due to insufficient access +* rights. +* +* IB_WCS_REM_ACCESS_ERR, +* A protection error was detected at the remote node for a RDMA or atomic +* operation. +* +* IB_WCS_REM_OP_ERR, +* The operation could not be successfully completed at the remote node. +* This may indicate that the remote QP was in an invalid state or +* contained an invalid work request. +* +* IB_WCS_RNR_RETRY_ERR, +* The RNR retry count was exceeded while trying to send this message. +* +* IB_WCS_TIMEOUT_RETRY_ERR +* The local transport timeout counter expired while trying to send this +* message. +* +* IB_WCS_REM_INVALID_REQ_ERR, +* The remote node detected an invalid message on the channel. This error +* is usually a result of one of the following: +* - The operation was not supported on receive queue. +* - There was insufficient buffers to receive a new RDMA request. +* - There was insufficient buffers to receive a new atomic operation. +* - An RDMA request was larger than 2^31 bytes. +* +* IB_WCS_REM_INVALID_RD_REQ_ERR, +* Responder detected an invalid RD message. This may be the result of an +* invalid qkey or an RDD mismatch. +* +* IB_WCS_INVALID_EECN +* An invalid EE context number was detected. +* +* IB_WCS_INVALID_EEC_STATE +* The EEC was in an invalid state for the specified request. +* +* IB_WCS_UNMATCHED_RESPONSE +* A response MAD was received for which there was no matching send. The +* send operation may have been canceled by the user or may have timed +* out. +* +* IB_WCS_CANCELED +* The completed work request was canceled by the user. +*****/ + +OSM_EXPORT const char *ib_wc_status_str[]; + +/****f* IBA Base: Types/ib_get_wc_status_str +* NAME +* ib_get_wc_status_str +* +* DESCRIPTION +* Returns a string for the specified work completion status. +* +* SYNOPSIS +*/ +static inline const char *OSM_API +ib_get_wc_status_str(IN ib_wc_status_t wc_status) +{ + if (wc_status > IB_WCS_UNKNOWN) + wc_status = IB_WCS_UNKNOWN; + return (ib_wc_status_str[wc_status]); +} + +/* +* PARAMETERS +* wc_status +* [in] work completion status value +* +* RETURN VALUES +* Pointer to the work completion status description string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****d* Access Layer/ib_wc_type_t +* NAME +* ib_wc_type_t +* +* DESCRIPTION +* Indicates the type of work completion. +* +* SYNOPSIS +*/ +typedef enum _ib_wc_type_t { + IB_WC_SEND, + IB_WC_RDMA_WRITE, + IB_WC_RECV, + IB_WC_RDMA_READ, + IB_WC_MW_BIND, + IB_WC_FETCH_ADD, + IB_WC_COMPARE_SWAP, + IB_WC_RECV_RDMA_WRITE +} ib_wc_type_t; +/*****/ + +/****d* Access Layer/ib_recv_opt_t +* NAME +* ib_recv_opt_t +* +* DESCRIPTION +* Indicates optional fields valid in a receive work completion. +* +* SYNOPSIS +*/ +typedef uint32_t ib_recv_opt_t; +#define IB_RECV_OPT_IMMEDIATE 0x00000001 +#define IB_RECV_OPT_FORWARD 0x00000002 +#define IB_RECV_OPT_GRH_VALID 0x00000004 +#define IB_RECV_OPT_VEND_MASK 0xFFFF0000 +/* +* VALUES +* IB_RECV_OPT_IMMEDIATE +* Indicates that immediate data is valid for this work completion. +* +* IB_RECV_OPT_FORWARD +* Indicates that the received trap should be forwarded to the SM. +* +* IB_RECV_OPT_GRH_VALID +* Indicates presence of the global route header. When set, the +* first 40 bytes received are the GRH. +* +* IB_RECV_OPT_VEND_MASK +* This mask indicates bits reserved in the receive options that may be +* used by the verbs provider to indicate vendor specific options. Bits +* set in this area of the receive options are ignored by the Access Layer, +* but may have specific meaning to the underlying VPD. +*****/ + +/****s* Access Layer/ib_wc_t +* NAME +* ib_wc_t +* +* DESCRIPTION +* Work completion information. +* +* SYNOPSIS +*/ +typedef struct _ib_wc { + struct _ib_wc *p_next; + uint64_t wr_id; + ib_wc_type_t wc_type; + + uint32_t length; + ib_wc_status_t status; + uint64_t vendor_specific; + + union _wc_recv { + struct _wc_conn { + ib_recv_opt_t recv_opt; + ib_net32_t immediate_data; + + } conn; + + struct _wc_ud { + ib_recv_opt_t recv_opt; + ib_net32_t immediate_data; + ib_net32_t remote_qp; + uint16_t pkey_index; + ib_net16_t remote_lid; + uint8_t remote_sl; + uint8_t path_bits; + + } ud; + + struct _wc_rd { + ib_net32_t remote_eecn; + ib_net32_t remote_qp; + ib_net16_t remote_lid; + uint8_t remote_sl; + uint32_t free_cnt; + + } rd; + + struct _wc_raw_ipv6 { + ib_net16_t remote_lid; + uint8_t remote_sl; + uint8_t path_bits; + + } raw_ipv6; + + struct _wc_raw_ether { + ib_net16_t remote_lid; + uint8_t remote_sl; + uint8_t path_bits; + ib_net16_t ether_type; + + } raw_ether; + + } recv; + +} ib_wc_t; +/* +* FIELDS +* p_next +* A pointer used to chain work completions. This permits multiple +* work completions to be retrieved from a completion queue through a +* single function call. This value is set to NULL to mark the end of +* the chain. +* +* wr_id +* The 64-bit work request identifier that was specified when posting the +* work request. +* +* wc_type +* Indicates the type of work completion. +* +* +* length +* The total length of the data sent or received with the work request. +* +* status +* The result of the work request. +* +* vendor_specific +* HCA vendor specific information returned as part of the completion. +* +* recv.conn.recv_opt +* Indicates optional fields valid as part of a work request that +* completed on a connected (reliable or unreliable) queue pair. +* +* recv.conn.immediate_data +* 32-bit field received as part of an inbound message on a connected +* queue pair. This field is only valid if the recv_opt flag +* IB_RECV_OPT_IMMEDIATE has been set. +* +* recv.ud.recv_opt +* Indicates optional fields valid as part of a work request that +* completed on an unreliable datagram queue pair. +* +* recv.ud.immediate_data +* 32-bit field received as part of an inbound message on a unreliable +* datagram queue pair. This field is only valid if the recv_opt flag +* IB_RECV_OPT_IMMEDIATE has been set. +* +* recv.ud.remote_qp +* Identifies the source queue pair of a received datagram. +* +* recv.ud.pkey_index +* The pkey index for the source queue pair. This is valid only for +* GSI type QP's. +* +* recv.ud.remote_lid +* The source LID of the received datagram. +* +* recv.ud.remote_sl +* The service level used by the source of the received datagram. +* +* recv.ud.path_bits +* path bits... +* +* recv.rd.remote_eecn +* The remote end-to-end context number that sent the received message. +* +* recv.rd.remote_qp +* Identifies the source queue pair of a received message. +* +* recv.rd.remote_lid +* The source LID of the received message. +* +* recv.rd.remote_sl +* The service level used by the source of the received message. +* +* recv.rd.free_cnt +* The number of available entries in the completion queue. Reliable +* datagrams may complete out of order, so this field may be used to +* determine the number of additional completions that may occur. +* +* recv.raw_ipv6.remote_lid +* The source LID of the received message. +* +* recv.raw_ipv6.remote_sl +* The service level used by the source of the received message. +* +* recv.raw_ipv6.path_bits +* path bits... +* +* recv.raw_ether.remote_lid +* The source LID of the received message. +* +* recv.raw_ether.remote_sl +* The service level used by the source of the received message. +* +* recv.raw_ether.path_bits +* path bits... +* +* recv.raw_ether.ether_type +* ether type... +* NOTES +* When the work request completes with error, the only values that the +* consumer can depend on are the wr_id field, and the status of the +* operation. +* +* If the consumer is using the same CQ for completions from more than +* one type of QP (i.e Reliable Connected, Datagram etc), then the consumer +* must have additional information to decide what fields of the union are +* valid. +* SEE ALSO +* ib_wc_type_t, ib_qp_type_t, ib_wc_status_t, ib_recv_opt_t +*****/ + +/****s* Access Layer/ib_mr_create_t +* NAME +* ib_mr_create_t +* +* DESCRIPTION +* Information required to create a registered memory region. +* +* SYNOPSIS +*/ +typedef struct _ib_mr_create { + void *vaddr; + uint64_t length; + ib_access_t access_ctrl; +} ib_mr_create_t; +/* +* FIELDS +* vaddr +* Starting virtual address of the region being registered. +* +* length +* Length of the buffer to register. +* +* access_ctrl +* Access rights of the registered region. +* +* SEE ALSO +* ib_access_t +*****/ + +/****s* Access Layer/ib_phys_create_t +* NAME +* ib_phys_create_t +* +* DESCRIPTION +* Information required to create a physical memory region. +* +* SYNOPSIS +*/ +typedef struct _ib_phys_create { + uint64_t length; + uint32_t num_bufs; + uint64_t *buf_array; + uint32_t buf_offset; + uint32_t page_size; + ib_access_t access_ctrl; +} ib_phys_create_t; +/* +* length +* The length of the memory region in bytes. +* +* num_bufs +* Number of buffers listed in the specified buffer array. +* +* buf_array +* An array of physical buffers to be registered as a single memory +* region. +* +* buf_offset +* The offset into the first physical page of the specified memory +* region to start the virtual address. +* +* page_size +* The physical page size of the memory being registered. +* +* access_ctrl +* Access rights of the registered region. +* +* SEE ALSO +* ib_access_t +*****/ + +/****s* Access Layer/ib_mr_attr_t +* NAME +* ib_mr_attr_t +* +* DESCRIPTION +* Attributes of a registered memory region. +* +* SYNOPSIS +*/ +typedef struct _ib_mr_attr { + ib_pd_handle_t h_pd; + void *local_lb; + void *local_ub; + void *remote_lb; + void *remote_ub; + ib_access_t access_ctrl; + uint32_t lkey; + uint32_t rkey; +} ib_mr_attr_t; +/* +* DESCRIPTION +* h_pd +* Handle to the protection domain for this memory region. +* +* local_lb +* The virtual address of the lower bound of protection for local +* memory access. +* +* local_ub +* The virtual address of the upper bound of protection for local +* memory access. +* +* remote_lb +* The virtual address of the lower bound of protection for remote +* memory access. +* +* remote_ub +* The virtual address of the upper bound of protection for remote +* memory access. +* +* access_ctrl +* Access rights for the specified memory region. +* +* lkey +* The lkey associated with this memory region. +* +* rkey +* The rkey associated with this memory region. +* +* NOTES +* The remote_lb, remote_ub, and rkey are only valid if remote memory access +* is enabled for this memory region. +* +* SEE ALSO +* ib_access_t +*****/ + +/****d* Access Layer/ib_ca_mod_t +* NAME +* ib_ca_mod_t -- Modify port attributes and error counters +* +* DESCRIPTION +* Specifies modifications to the port attributes of a channel adapter. +* +* SYNOPSIS +*/ +typedef uint32_t ib_ca_mod_t; +#define IB_CA_MOD_IS_CM_SUPPORTED 0x00000001 +#define IB_CA_MOD_IS_SNMP_SUPPORTED 0x00000002 +#define IB_CA_MOD_IS_DEV_MGMT_SUPPORTED 0x00000004 +#define IB_CA_MOD_IS_VEND_SUPPORTED 0x00000008 +#define IB_CA_MOD_IS_SM 0x00000010 +#define IB_CA_MOD_IS_SM_DISABLED 0x00000020 +#define IB_CA_MOD_QKEY_CTR 0x00000040 +#define IB_CA_MOD_PKEY_CTR 0x00000080 +#define IB_CA_MOD_IS_NOTICE_SUPPORTED 0x00000100 +#define IB_CA_MOD_IS_TRAP_SUPPORTED 0x00000200 +#define IB_CA_MOD_IS_APM_SUPPORTED 0x00000400 +#define IB_CA_MOD_IS_SLMAP_SUPPORTED 0x00000800 +#define IB_CA_MOD_IS_PKEY_NVRAM_SUPPORTED 0x00001000 +#define IB_CA_MOD_IS_MKEY_NVRAM_SUPPORTED 0x00002000 +#define IB_CA_MOD_IS_SYSGUID_SUPPORTED 0x00004000 +#define IB_CA_MOD_IS_DR_NOTICE_SUPPORTED 0x00008000 +#define IB_CA_MOD_IS_BOOT_MGMT_SUPPORTED 0x00010000 +#define IB_CA_MOD_IS_CAPM_NOTICE_SUPPORTED 0x00020000 +#define IB_CA_MOD_IS_REINIT_SUPORTED 0x00040000 +#define IB_CA_MOD_IS_LEDINFO_SUPPORTED 0x00080000 +#define IB_CA_MOD_SHUTDOWN_PORT 0x00100000 +#define IB_CA_MOD_INIT_TYPE_VALUE 0x00200000 +#define IB_CA_MOD_SYSTEM_IMAGE_GUID 0x00400000 +/* +* VALUES +* IB_CA_MOD_IS_CM_SUPPORTED +* Indicates if there is a communication manager accessible through +* the port. +* +* IB_CA_MOD_IS_SNMP_SUPPORTED +* Indicates if there is an SNMP agent accessible through the port. +* +* IB_CA_MOD_IS_DEV_MGMT_SUPPORTED +* Indicates if there is a device management agent accessible +* through the port. +* +* IB_CA_MOD_IS_VEND_SUPPORTED +* Indicates if there is a vendor supported agent accessible +* through the port. +* +* IB_CA_MOD_IS_SM +* Indicates if there is a subnet manager accessible through +* the port. +* +* IB_CA_MOD_IS_SM_DISABLED +* Indicates if the port has been disabled for configuration by the +* subnet manager. +* +* IB_CA_MOD_QKEY_CTR +* Used to reset the qkey violation counter associated with the +* port. +* +* IB_CA_MOD_PKEY_CTR +* Used to reset the pkey violation counter associated with the +* port. +* +* IB_CA_MOD_IS_NOTICE_SUPPORTED +* Indicates that this CA supports ability to generate Notices for +* Port State changes. (only applicable to switches) +* +* IB_CA_MOD_IS_TRAP_SUPPORTED +* Indicates that this management port supports ability to generate +* trap messages. (only applicable to switches) +* +* IB_CA_MOD_IS_APM_SUPPORTED +* Indicates that this port is capable of performing Automatic +* Path Migration. +* +* IB_CA_MOD_IS_SLMAP_SUPPORTED +* Indicates this port supports SLMAP capability. +* +* IB_CA_MOD_IS_PKEY_NVRAM_SUPPORTED +* Indicates that PKEY is supported in NVRAM +* +* IB_CA_MOD_IS_MKEY_NVRAM_SUPPORTED +* Indicates that MKEY is supported in NVRAM +* +* IB_CA_MOD_IS_SYSGUID_SUPPORTED +* Indicates System Image GUID support. +* +* IB_CA_MOD_IS_DR_NOTICE_SUPPORTED +* Indicate support for generating Direct Routed Notices +* +* IB_CA_MOD_IS_BOOT_MGMT_SUPPORTED +* Indicates support for Boot Management +* +* IB_CA_MOD_IS_CAPM_NOTICE_SUPPORTED +* Indicates capability to generate notices for changes to CAPMASK +* +* IB_CA_MOD_IS_REINIT_SUPORTED +* Indicates type of node init supported. Refer to Chapter 14 for +* Initialization actions. +* +* IB_CA_MOD_IS_LEDINFO_SUPPORTED +* Indicates support for LED info. +* +* IB_CA_MOD_SHUTDOWN_PORT +* Used to modify the port active indicator. +* +* IB_CA_MOD_INIT_TYPE_VALUE +* Used to modify the init_type value for the port. +* +* IB_CA_MOD_SYSTEM_IMAGE_GUID +* Used to modify the system image GUID for the port. +*****/ + +/****d* Access Layer/ib_mr_mod_t +* NAME +* ib_mr_mod_t +* +* DESCRIPTION +* Mask used to specify which attributes of a registered memory region are +* being modified. +* +* SYNOPSIS +*/ +typedef uint32_t ib_mr_mod_t; +#define IB_MR_MOD_ADDR 0x00000001 +#define IB_MR_MOD_PD 0x00000002 +#define IB_MR_MOD_ACCESS 0x00000004 +/* +* PARAMETERS +* IB_MEM_MOD_ADDR +* The address of the memory region is being modified. +* +* IB_MEM_MOD_PD +* The protection domain associated with the memory region is being +* modified. +* +* IB_MEM_MOD_ACCESS +* The access rights the memory region are being modified. +*****/ + +/****d* IBA Base: Constants/IB_SMINFO_ATTR_MOD_HANDOVER +* NAME +* IB_SMINFO_ATTR_MOD_HANDOVER +* +* DESCRIPTION +* Encoded attribute modifier value used on SubnSet(SMInfo) SMPs. +* +* SOURCE +*/ +#define IB_SMINFO_ATTR_MOD_HANDOVER (CL_HTON32(0x000001)) +/**********/ + +/****d* IBA Base: Constants/IB_SMINFO_ATTR_MOD_ACKNOWLEDGE +* NAME +* IB_SMINFO_ATTR_MOD_ACKNOWLEDGE +* +* DESCRIPTION +* Encoded attribute modifier value used on SubnSet(SMInfo) SMPs. +* +* SOURCE +*/ +#define IB_SMINFO_ATTR_MOD_ACKNOWLEDGE (CL_HTON32(0x000002)) +/**********/ + +/****d* IBA Base: Constants/IB_SMINFO_ATTR_MOD_DISABLE +* NAME +* IB_SMINFO_ATTR_MOD_DISABLE +* +* DESCRIPTION +* Encoded attribute modifier value used on SubnSet(SMInfo) SMPs. +* +* SOURCE +*/ +#define IB_SMINFO_ATTR_MOD_DISABLE (CL_HTON32(0x000003)) +/**********/ + +/****d* IBA Base: Constants/IB_SMINFO_ATTR_MOD_STANDBY +* NAME +* IB_SMINFO_ATTR_MOD_STANDBY +* +* DESCRIPTION +* Encoded attribute modifier value used on SubnSet(SMInfo) SMPs. +* +* SOURCE +*/ +#define IB_SMINFO_ATTR_MOD_STANDBY (CL_HTON32(0x000004)) +/**********/ + +/****d* IBA Base: Constants/IB_SMINFO_ATTR_MOD_DISCOVER +* NAME +* IB_SMINFO_ATTR_MOD_DISCOVER +* +* DESCRIPTION +* Encoded attribute modifier value used on SubnSet(SMInfo) SMPs. +* +* SOURCE +*/ +#define IB_SMINFO_ATTR_MOD_DISCOVER (CL_HTON32(0x000005)) +/**********/ + +/****s* Access Layer/ib_ci_op_t +* NAME +* ib_ci_op_t +* +* DESCRIPTION +* A structure used for vendor specific CA interface communication. +* +* SYNOPSIS +*/ +typedef struct _ib_ci_op { + IN uint32_t command; + IN OUT void *p_buf OPTIONAL; + IN uint32_t buf_size; + IN OUT uint32_t num_bytes_ret; + IN OUT int32_t status; + +} ib_ci_op_t; +/* +* FIELDS +* command +* A command code that is understood by the verbs provider. +* +* p_buf +* A reference to a buffer containing vendor specific data. The verbs +* provider must not access pointers in the p_buf between user-mode and +* kernel-mode. Any pointers embedded in the p_buf are invalidated by +* the user-mode/kernel-mode transition. +* +* buf_size +* The size of the buffer in bytes. +* +* num_bytes_ret +* The size in bytes of the vendor specific data returned in the buffer. +* This field is set by the verbs provider. The verbs provider should +* verify that the buffer size is sufficient to hold the data being +* returned. +* +* status +* The completion status from the verbs provider. This field should be +* initialize to indicate an error to allow detection and cleanup in +* case a communication error occurs between user-mode and kernel-mode. +* +* NOTES +* This structure is provided to allow the exchange of vendor specific +* data between the originator and the verbs provider. Users of this +* structure are expected to know the format of data in the p_buf based +* on the structure command field or the usage context. +*****/ + +END_C_DECLS +#endif /* ndef WIN32 */ +#if defined( __WIN__ ) +#include +#endif +#endif /* __IB_TYPES_H__ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_attrib_req.h b/contrib/ofed/management/opensm/include/opensm/osm_attrib_req.h new file mode 100644 index 000000000000..e79073bf1870 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_attrib_req.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_ATTRIB_REQ_H_ +#define _OSM_ATTRIB_REQ_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + * Abstract: + * Declaration of the attribute request object. This object + * encapsulates information needed by the generic request controller + * to request an attribute from a node. + * These objects are part of the OpenSM family of objects. + */ +/****h* OpenSM/Attribute Request +* NAME +* Attribute Request +* +* DESCRIPTION +* The Attribute Request structure encapsulates +* encapsulates information needed by the generic request controller +* to request an attribute from a node. +* +* This structure allows direct access to member variables. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Attribute Request/osm_attrib_req_t +* NAME +* osm_attrib_req_t +* +* DESCRIPTION +* Attribute request structure. +* +* This structure allows direct access to member variables. +* +* SYNOPSIS +*/ +typedef struct osm_attrib_req { + uint16_t attrib_id; + uint32_t attrib_mod; + osm_madw_context_t context; + osm_dr_path_t path; + cl_disp_msgid_t err_msg; +} osm_attrib_req_t; +/* +* FIELDS +* attrib_id +* Attribute ID for this request. +* +* attrib_mod +* Attribute modifier for this request. +* +* context +* Context to insert in outbound mad wrapper context. +* +* path +* The directed route path to the node. +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_ATTRIB_REQ_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_base.h b/contrib/ofed/management/opensm/include/opensm/osm_base.h new file mode 100644 index 000000000000..54df41e3360b --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_base.h @@ -0,0 +1,898 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Basic OpenSM definitions and structures. + * This object represents an OpenSM "base class". + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_BASE_H_ +#define _OSM_BASE_H_ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef __WIN__ +#include +#define OSM_CDECL __cdecl +#else +#define OSM_CDECL +#endif + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Constants +* NAME +* Constants +* +* DESCRIPTION +* The following constants are used throughout the OpenSM. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****h* OpenSM/Base +* NAME +* Base +* +* DESCRIPTION +* The Base object encapsulates basic information needed by the +* OpenSM to manage objects. Each OpenSM object includes the +* Base object as the first member. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Base/OSM_DEFAULT_M_KEY +* NAME +* OSM_DEFAULT_M_KEY +* +* DESCRIPTION +* Managment key value used by the OpenSM. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_M_KEY 0 +/********/ +/****s* OpenSM: Base/OSM_DEFAULT_SM_KEY +* NAME +* OSM_DEFAULT_SM_KEY +* +* DESCRIPTION +* Subnet Manager key value used by the OpenSM. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SM_KEY CL_HTON64(1) +/********/ +/****s* OpenSM: Base/OSM_DEFAULT_SA_KEY +* NAME +* OSM_DEFAULT_SA_KEY +* +* DESCRIPTION +* Subnet Adminstration key value. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SA_KEY OSM_DEFAULT_SM_KEY +/********/ +/****s* OpenSM: Base/OSM_DEFAULT_LMC +* NAME +* OSM_DEFAULT_LMC +* +* DESCRIPTION +* Default LMC value used by the OpenSM. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_LMC 0 +/********/ +/****s* OpenSM: Base/OSM_DEFAULT_MAX_OP_VLS +* NAME +* OSM_DEFAULT_MAX_OP_VLS +* +* DESCRIPTION +* Default Maximal Operational VLs to be initialized on +* the link ports PortInfo by the OpenSM. +* Default value provides backward compatibility. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_MAX_OP_VLS 5 +/********/ +/****s* OpenSM: Base/OSM_DEFAULT_SL +* NAME +* OSM_DEFAULT_SL +* +* DESCRIPTION +* Default SL value used by the OpenSM. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SL 0 +/********/ +/****s* OpenSM: Base/OSM_DEFAULT_SM_PRIORITY +* NAME +* OSM_DEFAULT_SM_PRIORITY +* +* DESCRIPTION +* Default SM priority value used by the OpenSM, +* as defined in the SMInfo attribute. 0 is the lowest priority. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SM_PRIORITY 0 +/********/ +/****d* OpenSM: Base/OSM_DEFAULT_TMP_DIR +* NAME +* OSM_DEFAULT_TMP_DIR +* +* DESCRIPTION +* Specifies the default temporary directory for the log file, +* osm-subnet.lst, and other log files. +* +* SYNOPSIS +*/ +#ifdef __WIN__ +#define OSM_DEFAULT_TMP_DIR GetOsmTempPath() +#else +#define OSM_DEFAULT_TMP_DIR "/var/log/" +#endif +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_CACHE_DIR +* NAME +* OSM_DEFAULT_CACHE_DIR +* +* DESCRIPTION +* Specifies the default cache directory for the db files. +* Note that the directory must appear with "/" ("\\" for windows) at the end. +* +* SYNOPSIS +*/ +#ifdef __WIN__ +#define OSM_DEFAULT_CACHE_DIR GetOsmCachePath() +#else +#define OSM_DEFAULT_CACHE_DIR "/var/cache/opensm/" +#endif +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_LOG_FILE +* NAME +* OSM_DEFAULT_LOG_FILE +* +* DESCRIPTION +* Specifies the default log file name +* +* SYNOPSIS +*/ +#ifdef __WIN__ +#define OSM_DEFAULT_LOG_FILE strcat(GetOsmTempPath(), "osm.log") +#else +#define OSM_DEFAULT_LOG_FILE "/var/log/opensm.log" +#endif +/***********/ + +/****d* OpenSM: Base/OSM_DEFAULT_CONFIG_FILE +* NAME +* OSM_DEFAULT_CONFIG_FILE +* +* DESCRIPTION +* Specifies the default OpenSM config file name +* +* SYNOPSIS +*/ +#ifdef __WIN__ +#define OSM_DEFAULT_CONFIG_FILE strcat(GetOsmCachePath(), "opensm.conf") +#elif defined(HAVE_DEFAULT_OPENSM_CONFIG_FILE) +#define OSM_DEFAULT_CONFIG_FILE HAVE_DEFAULT_OPENSM_CONFIG_FILE +#elif defined (OPENSM_CONFIG_DIR) +#define OSM_DEFAULT_CONFIG_FILE OPENSM_CONFIG_DIR "/opensm.conf" +#else +#define OSM_DEFAULT_CONFIG_FILE "/etc/opensm/opensm.conf" +#endif /* __WIN__ */ +/***********/ + +/****d* OpenSM: Base/OSM_DEFAULT_PARTITION_CONFIG_FILE +* NAME +* OSM_DEFAULT_PARTITION_CONFIG_FILE +* +* DESCRIPTION +* Specifies the default partition config file name +* +* SYNOPSIS +*/ +#ifdef __WIN__ +#define OSM_DEFAULT_PARTITION_CONFIG_FILE strcat(GetOsmCachePath(), "osm-partitions.conf") +#elif defined(HAVE_DEFAULT_PARTITION_CONFIG_FILE) +#define OSM_DEFAULT_PARTITION_CONFIG_FILE HAVE_DEFAULT_PARTITION_CONFIG_FILE +#elif defined(OPENSM_CONFIG_DIR) +#define OSM_DEFAULT_PARTITION_CONFIG_FILE OPENSM_CONFIG_DIR "/partitions.conf" +#else +#define OSM_DEFAULT_PARTITION_CONFIG_FILE "/etc/opensm/partitions.conf" +#endif /* __WIN__ */ +/***********/ + +/****d* OpenSM: Base/OSM_DEFAULT_QOS_POLICY_FILE +* NAME +* OSM_DEFAULT_QOS_POLICY_FILE +* +* DESCRIPTION +* Specifies the default QoS policy file name +* +* SYNOPSIS +*/ +#ifdef __WIN__ +#define OSM_DEFAULT_QOS_POLICY_FILE strcat(GetOsmCachePath(), "osm-qos-policy.conf") +#elif defined(HAVE_DEFAULT_QOS_POLICY_FILE) +#define OSM_DEFAULT_QOS_POLICY_FILE HAVE_DEFAULT_QOS_POLICY_FILE +#elif defined(OPENSM_CONFIG_DIR) +#define OSM_DEFAULT_QOS_POLICY_FILE OPENSM_CONFIG_DIR "/qos-policy.conf" +#else +#define OSM_DEFAULT_QOS_POLICY_FILE "/etc/opensm/qos-policy.conf" +#endif /* __WIN__ */ +/***********/ + +/****d* OpenSM: Base/OSM_DEFAULT_PREFIX_ROUTES_FILE +* NAME +* OSM_DEFAULT_PREFIX_ROUTES_FILE +* +* DESCRIPTION +* Specifies the default prefix routes file name +* +* SYNOPSIS +*/ +#ifdef __WIN__ +#define OSM_DEFAULT_PREFIX_ROUTES_FILE strcat(GetOsmCachePath(), "osm-prefix-routes.conf") +#elif defined(HAVE_DEFAULT_PREFIX_ROUTES_FILE) +#define OSM_DEFAULT_PREFIX_ROUTES_FILE HAVE_DEFAULT_PREFIX_ROUTES_FILE +#elif defined(OPENSM_CONFIG_DIR) +#define OSM_DEFAULT_PREFIX_ROUTES_FILE OPENSM_CONFIG_DIR "/prefix-routes.conf" +#else +#define OSM_DEFAULT_PREFIX_ROUTES_FILE "/etc/opensm/prefix-routes.conf" +#endif +/***********/ + +/****d* OpenSM: Base/OSM_DEFAULT_SWEEP_INTERVAL_SECS +* NAME +* OSM_DEFAULT_SWEEP_INTERVAL_SECS +* +* DESCRIPTION +* Specifies the default number of seconds between subnet sweeps. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SWEEP_INTERVAL_SECS 10 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC +* NAME +* OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC +* +* DESCRIPTION +* Specifies the default transaction timeout in milliseconds. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC 200 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_SUBNET_TIMEOUT +* NAME +* OSM_DEFAULT_SUBNET_TIMEOUT +* +* DESCRIPTION +* Specifies the default subnet timeout. +* timeout time = 4us * 2^timeout. +* We use here ~1sec. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SUBNET_TIMEOUT 0x12 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_SWITCH_PACKET_LIFE +* NAME +* OSM_DEFAULT_SWITCH_PACKET_LIFE +* +* DESCRIPTION +* Specifies the default max life time for a pcket on the switch. +* timeout time = 4us * 2^timeout. +* We use here the value of ~1sec +* A Value > 19dec disables this mechanism. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SWITCH_PACKET_LIFE 0x12 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_HEAD_OF_QUEUE_LIFE +* NAME +* OSM_DEFAULT_HEAD_OF_QUEUE_LIFE +* +* DESCRIPTION +* Sets the time a packet can live in the head of the VL Queue +* We use here the value of ~1sec +* A Value > 19dec disables this mechanism. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_HEAD_OF_QUEUE_LIFE 0x12 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_LEAF_HEAD_OF_QUEUE_LIFE +* NAME +* OSM_DEFAULT_LEAF_HEAD_OF_QUEUE_LIFE +* +* DESCRIPTION +* Sets the time a packet can live in the head of the VL Queue +* of a port that drives a CA port. +* We use here the value of ~256msec +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_LEAF_HEAD_OF_QUEUE_LIFE 0x10 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_VL_STALL_COUNT +* NAME +* OSM_DEFAULT_LEAF_VL_COUNT +* +* DESCRIPTION +* Sets the number of consecutive head of queue life time drops that +* puts the VL into stalled state. In stalled state, the port is supposed +* to drop everything for 8*(head of queue lifetime) +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_VL_STALL_COUNT 0x7 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_LEAF_VL_STALL_COUNT +* NAME +* OSM_DEFAULT_LEAF_VL_STALL_COUNT +* +* DESCRIPTION +* Sets the number of consecutive head of queue life time drops that +* puts the VL into stalled state. In stalled state, the port is supposed +* to drop everything for 8*(head of queue lifetime). This value is for +* switch ports driving a CA port. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_LEAF_VL_STALL_COUNT 0x7 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_TRAP_SUPRESSION_TIMEOUT +* NAME +* OSM_DEFAULT_TRAP_SUPRESSION_TIMEOUT +* +* DESCRIPTION +* Specifies the default timeout for ignoring same trap. +* timeout time = 5000000us +* We use here ~5sec. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_TRAP_SUPRESSION_TIMEOUT 5000000 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_UNHEALTHY_TIMEOUT +* NAME +* OSM_DEFAULT_UNHEALTHY_TIMEOUT +* +* DESCRIPTION +* Specifies the default timeout for setting port as unhealthy. +* timeout time = 60000000us +* We use here ~60sec. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_UNHEALTHY_TIMEOUT 60000000 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_ERROR_THRESHOLD +* NAME +* OSM_DEFAULT_ERROR_THRESHOLD +* +* DESCRIPTION +* Specifies default link error threshold to be set by SubnSet(PortInfo). +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_ERROR_THRESHOLD 0x08 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_SMP_MAX_ON_WIRE +* NAME +* OSM_DEFAULT_SMP_MAX_ON_WIRE +* +* DESCRIPTION +* Specifies the default number of VL15 SMP MADs allowed on +* the wire at any one time. +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_SMP_MAX_ON_WIRE 4 +/***********/ +/****d* OpenSM: Base/OSM_SM_DEFAULT_QP0_RCV_SIZE +* NAME +* OSM_SM_DEFAULT_QP0_RCV_SIZE +* +* DESCRIPTION +* Specifies the default size (in MADs) of the QP0 receive queue +* +* SYNOPSIS +*/ +#define OSM_SM_DEFAULT_QP0_RCV_SIZE 256 +/***********/ +/****d* OpenSM: Base/OSM_SM_DEFAULT_QP0_SEND_SIZE +* NAME +* OSM_SM_DEFAULT_QP0_SEND_SIZE +* +* DESCRIPTION +* Specifies the default size (in MADs) of the QP0 send queue +* +* SYNOPSIS +*/ +#define OSM_SM_DEFAULT_QP0_SEND_SIZE 256 +/***********/ +/****d* OpenSM: Base/OSM_SM_DEFAULT_QP1_RCV_SIZE +* NAME +* OSM_SM_DEFAULT_QP1_RCV_SIZE +* +* DESCRIPTION +* Specifies the default size (in MADs) of the QP1 receive queue +* +* SYNOPSIS +*/ +#define OSM_SM_DEFAULT_QP1_RCV_SIZE 256 +/***********/ +/****d* OpenSM: Base/OSM_SM_DEFAULT_QP1_SEND_SIZE +* NAME +* OSM_SM_DEFAULT_QP1_SEND_SIZE +* +* DESCRIPTION +* Specifies the default size (in MADs) of the QP1 send queue +* +* SYNOPSIS +*/ +#define OSM_SM_DEFAULT_QP1_SEND_SIZE 256 +/****d* OpenSM: Base/OSM_PM_DEFAULT_QP1_RCV_SIZE +* NAME +* OSM_PM_DEFAULT_QP1_RCV_SIZE +* +* DESCRIPTION +* Specifies the default size (in MADs) of the QP1 receive queue +* +* SYNOPSIS +*/ +#define OSM_PM_DEFAULT_QP1_RCV_SIZE 256 +/***********/ +/****d* OpenSM: Base/OSM_PM_DEFAULT_QP1_SEND_SIZE +* NAME +* OSM_PM_DEFAULT_QP1_SEND_SIZE +* +* DESCRIPTION +* Specifies the default size (in MADs) of the QP1 send queue +* +* SYNOPSIS +*/ +#define OSM_PM_DEFAULT_QP1_SEND_SIZE 256 +/****d* OpenSM: Base/OSM_SM_DEFAULT_POLLING_TIMEOUT_MILLISECS +* NAME +* OSM_SM_DEFAULT_POLLING_TIMEOUT_MILLISECS +* +* DESCRIPTION +* Specifies the polling timeout (in miliseconds) - the timeout +* between one poll to another. +* +* SYNOPSIS +*/ +#define OSM_SM_DEFAULT_POLLING_TIMEOUT_MILLISECS 10000 +/**********/ +/****d* OpenSM: Base/OSM_SM_DEFAULT_POLLING_RETRY_NUMBER +* NAME +* OSM_SM_DEFAULT_POLLING_RETRY_NUMBER +* +* DESCRIPTION +* Specifies the number of polling retries before the SM goes back +* to DISCOVERY stage. So the default total time for handoff is 40 sec. +* +* SYNOPSIS +*/ +#define OSM_SM_DEFAULT_POLLING_RETRY_NUMBER 4 +/**********/ +/****d* OpenSM: MC Member Record Receiver/OSM_DEFAULT_MGRP_MTU +* Name +* OSM_DEFAULT_MGRP_MTU +* +* DESCRIPTION +* Default MTU used for new MGRP creation (2048 bytes) +* Note it includes the MTUSelector which is set to "Greater Than" +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_MGRP_MTU 0x04 +/***********/ +/****d* OpenSM: MC Member Record Receiver/OSM_DEFAULT_MGRP_RATE +* Name +* OSM_DEFAULT_MGRP_RATE +* +* DESCRIPTION +* Default RATE used for new MGRP creation (10Gb/sec) +* Note it includes the RateSelector which is set to "Greater Than" +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_MGRP_RATE 0x03 +/***********/ +/****d* OpenSM: MC Member Record Receiver/OSM_DEFAULT_MGRP_SCOPE +* Name +* OSM_DEFAULT_MGRP_SCOPE +* +* DESCRIPTION +* Default SCOPE used for new MGRP creation (link local) +* +* SYNOPSIS +*/ +#define OSM_DEFAULT_MGRP_SCOPE IB_MC_SCOPE_LINK_LOCAL +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_QOS_MAX_VLS + * Name + * OSM_DEFAULT_QOS_MAX_VLS + * + * DESCRIPTION + * Default Maximum VLs used by the OpenSM. + * + * SYNOPSIS + */ +#define OSM_DEFAULT_QOS_MAX_VLS 15 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_QOS_HIGH_LIMIT + * Name + * OSM_DEFAULT_QOS_HIGH_LIMIT + * + * DESCRIPTION + * Default Limit of High Priority in VL Arbitration used by OpenSM. + * + * SYNOPSIS + */ +#define OSM_DEFAULT_QOS_HIGH_LIMIT 0 +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_QOS_VLARB_HIGH + * Name + * OSM_DEFAULT_QOS_VLARB_HIGH + * + * DESCRIPTION + * Default High Priority VL Arbitration table used by the OpenSM. + * + * SYNOPSIS + */ +#define OSM_DEFAULT_QOS_VLARB_HIGH "0:4,1:0,2:0,3:0,4:0,5:0,6:0,7:0,8:0,9:0,10:0,11:0,12:0,13:0,14:0" +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_QOS_VLARB_LOW + * Name + * OSM_DEFAULT_QOS_VLARB_LOW + * + * DESCRIPTION + * Default Low Priority VL Arbitration table used by the OpenSM. + * + * SYNOPSIS + */ +#define OSM_DEFAULT_QOS_VLARB_LOW "0:0,1:4,2:4,3:4,4:4,5:4,6:4,7:4,8:4,9:4,10:4,11:4,12:4,13:4,14:4" +/***********/ +/****d* OpenSM: Base/OSM_DEFAULT_QOS_SL2VL + * Name + * OSM_DEFAULT_QOS_SL2VL + * + * DESCRIPTION + * Default QoS SL2VL Mapping Table used by the OpenSM. + * + * SYNOPSIS + */ +#define OSM_DEFAULT_QOS_SL2VL "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7" +/***********/ +/****d* OpenSM: Base/OSM_NO_PATH +* NAME +* OSM_NO_PATH +* +* DESCRIPTION +* Value indicating there is no path to the given LID. +* +* SYNOPSIS +*/ +#define OSM_NO_PATH 0xFF +/**********/ +/****d* OpenSM: Base/OSM_NODE_DESC_UNKNOWN +* NAME +* OSM_NODE_DESC_UNKNOWN +* +* DESCRIPTION +* Value indicating the Node Description is not set and is "unknown" +* +* SYNOPSIS +*/ +#define OSM_NODE_DESC_UNKNOWN "" +/**********/ +/****d* OpenSM: Base/osm_thread_state_t +* NAME +* osm_thread_state_t +* +* DESCRIPTION +* Enumerates the possible states of worker threads, such +* as the subnet sweeper. +* +* SYNOPSIS +*/ +typedef enum _osm_thread_state { + OSM_THREAD_STATE_NONE = 0, + OSM_THREAD_STATE_INIT, + OSM_THREAD_STATE_RUN, + OSM_THREAD_STATE_EXIT +} osm_thread_state_t; +/***********/ + +/* + * OSM_CAP are from Table 117 and C15-0.1.7 Table 186 + */ + +/****d* OpenSM: Base/OSM_CAP_IS_TRAP_SUP +* Name +* OSM_CAP_IS_SUBN_TRAP_SUP +* +* DESCRIPTION +* Management class generates Trap() MADs +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_SUBN_TRAP_SUP (1 << 0) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_GET_SET_NOTICE_SUP +* Name +* OSM_CAP_IS_GET_SET_NOTICE_SUP +* +* DESCRIPTION +* Management class supports Get/Set(Notice) +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_SUBN_GET_SET_NOTICE_SUP (1 << 1) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_SUBN_OPT_RECS_SUP +* Name +* OSM_CAP_IS_SUBN_OPT_RECS_SUP +* +* DESCRIPTION +* Support all optional attributes except: +* MCMemberRecord, TraceRecord, MultiPathRecord +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_SUBN_OPT_RECS_SUP (1 << 8) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_UD_MCAST_SUP +* Name +* OSM_CAP_IS_UD_MCAST_SUP +* +* DESCRIPTION +* Multicast is supported +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_UD_MCAST_SUP (1 << 9) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_MULTIPATH_SUP +* Name +* OSM_CAP_IS_MULTIPATH_SUP +* +* DESCRIPTION +* MultiPathRecord and TraceRecord are supported +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_MULTIPATH_SUP (1 << 10) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_REINIT_SUP +* Name +* OSM_CAP_IS_REINIT_SUP +* +* DESCRIPTION +* SM/SA supports re-initialization supported +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_REINIT_SUP (1 << 11) +/***********/ + +/****d* OpenSM: Base/OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED +* Name +* OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED +* +* DESCRIPTION +* SM/SA supports enhanced SA PortInfoRecord searches per 1.2 Errata: +* ClassPortInfo:CapabilityMask.IsPortInfoCapMaskMatchSupported is 1, +* then the AttributeModifier of the SubnAdmGet() and SubnAdmGetTable() +* methods affects the matching behavior on the PortInfo:CapabilityMask +* component. If the high-order bit (bit 31) of the AttributeModifier +* is set to 1, matching on the CapabilityMask component will not be an +* exact bitwise match as described in . Instead, +* matching will only be performed on those bits which are set to 1 in +* the PortInfo:CapabilityMask embedded in the query. +* +* SYNOPSIS +*/ +#define OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED (1 << 13) +/***********/ + +/****d* OpenSM: Base/OSM_CAP2_IS_QOS_SUPPORTED +* Name +* OSM_CAP2_IS_QOS_SUPPORTED +* +* DESCRIPTION +* QoS is supported +* +* SYNOPSIS +*/ +#define OSM_CAP2_IS_QOS_SUPPORTED (1 << 1) +/***********/ + +/****d* OpenSM: Base/osm_signal_t +* NAME +* osm_signal_t +* +* DESCRIPTION +* Enumerates the possible signal codes used by the OSM managers +* This cannot be an enum type, since conversion to and from +* integral types is necessary when passing signals through +* the dispatcher. +* +* SYNOPSIS +*/ +#define OSM_SIGNAL_NONE 0 +#define OSM_SIGNAL_SWEEP 1 +#define OSM_SIGNAL_IDLE_TIME_PROCESS_REQUEST 2 +#define OSM_SIGNAL_PERFMGR_SWEEP 3 +#define OSM_SIGNAL_MAX 3 + +/* status values for sweep managers - can be removed later */ +#define OSM_SIGNAL_DONE 16 +#define OSM_SIGNAL_DONE_PENDING 17 + +typedef unsigned int osm_signal_t; +/***********/ + +/****d* OpenSM: Base/osm_sm_signal_t +* NAME +* osm_sm_signal_t +* +* DESCRIPTION +* Enumerates the possible signals used by the OSM_SM_MGR +* +* SYNOPSIS +*/ +typedef enum _osm_sm_signal { + OSM_SM_SIGNAL_NONE = 0, + OSM_SM_SIGNAL_DISCOVERY_COMPLETED, + OSM_SM_SIGNAL_POLLING_TIMEOUT, + OSM_SM_SIGNAL_DISCOVER, + OSM_SM_SIGNAL_DISABLE, + OSM_SM_SIGNAL_HANDOVER, + OSM_SM_SIGNAL_HANDOVER_SENT, + OSM_SM_SIGNAL_ACKNOWLEDGE, + OSM_SM_SIGNAL_STANDBY, + OSM_SM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED, + OSM_SM_SIGNAL_WAIT_FOR_HANDOVER, + OSM_SM_SIGNAL_MAX +} osm_sm_signal_t; +/***********/ + +/****d* OpenSM/osm_mcast_req_type_t +* NAME +* osm_mcast_req_type_t +* +* DESCRIPTION +* Enumerates the possible signals used by the OSM_MCAST_REQUEST +* +* SYNOPSIS +*/ +typedef enum _osm_mcast_req_type { + OSM_MCAST_REQ_TYPE_CREATE, + OSM_MCAST_REQ_TYPE_JOIN, + OSM_MCAST_REQ_TYPE_LEAVE, + OSM_MCAST_REQ_TYPE_SUBNET_CHANGE +} osm_mcast_req_type_t; +/***********/ + +/****s* OpenSM: Base/MAX_GUID_FILE_LINE_LENGTH +* NAME +* MAX_GUID_FILE_LINE_LENGTH +* +* DESCRIPTION +* The maximum line number when reading guid file +* +* SYNOPSIS +*/ +#define MAX_GUID_FILE_LINE_LENGTH 120 +/**********/ + +/****s* OpenSM: Base/VendorOUIs +* NAME +* VendorOUIs +* +* DESCRIPTION +* Known device vendor ID and GUID OUIs +* +* SYNOPSIS +*/ +#define OSM_VENDOR_ID_INTEL 0x00D0B7 +#define OSM_VENDOR_ID_MELLANOX 0x0002C9 +#define OSM_VENDOR_ID_REDSWITCH 0x000617 +#define OSM_VENDOR_ID_SILVERSTORM 0x00066A +#define OSM_VENDOR_ID_TOPSPIN 0x0005AD +#define OSM_VENDOR_ID_FUJITSU 0x00E000 +#define OSM_VENDOR_ID_FUJITSU2 0x000B5D +#define OSM_VENDOR_ID_VOLTAIRE 0x0008F1 +#define OSM_VENDOR_ID_YOTTAYOTTA 0x000453 +#define OSM_VENDOR_ID_PATHSCALE 0x001175 +#define OSM_VENDOR_ID_IBM 0x000255 +#define OSM_VENDOR_ID_DIVERGENET 0x00084E +#define OSM_VENDOR_ID_FLEXTRONICS 0x000B8C +#define OSM_VENDOR_ID_AGILENT 0x0030D3 +#define OSM_VENDOR_ID_OBSIDIAN 0x001777 +#define OSM_VENDOR_ID_BAYMICRO 0x000BC1 +#define OSM_VENDOR_ID_LSILOGIC 0x00A0B8 +#define OSM_VENDOR_ID_DDN 0x0001FF +#define OSM_VENDOR_ID_PANTA 0x001393 +#define OSM_VENDOR_ID_HP 0x001708 +#define OSM_VENDOR_ID_RIOWORKS 0x005045 +#define OSM_VENDOR_ID_SUN 0x0003BA +#define OSM_VENDOR_ID_3LEAFNTWKS 0x0016A1 +#define OSM_VENDOR_ID_XSIGO 0x001397 +#define OSM_VENDOR_ID_HP2 0x0018FE + +/**********/ + +END_C_DECLS +#endif /* _OSM_BASE_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_config.h b/contrib/ofed/management/opensm/include/opensm/osm_config.h new file mode 100644 index 000000000000..8ecaa7902c24 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_config.h @@ -0,0 +1,65 @@ +/* include/opensm/osm_config.h. Generated from osm_config.h.in by configure. */ +/* include/osm_config.h.in + * + * Defines various OpenSM configuration parameters to be used by various + * plugins and third party tools. + * + * NOTE: Defines used in header files MUST be included here to ensure plugin + * compatibility. + */ + +#ifndef _OSM_CONFIG_H_ +#define _OSM_CONFIG_H_ 1 + +/* define 1 if OpenSM build is in a debug mode */ +/* #undef OSM_DEBUG */ + +/* Define as 1 if you want Dual Sided RMPP Support */ +#define DUAL_SIDED_RMPP 1 + +/* Define as 1 if you want to enable a console on a socket connection */ +/* #undef ENABLE_OSM_CONSOLE_SOCKET */ + +/* Define as 1 if you want to enable the event plugin */ +/* #undef ENABLE_OSM_DEFAULT_EVENT_PLUGIN */ + +/* Define as 1 if you want to enable the performance manager */ +/* #undef ENABLE_OSM_PERF_MGR */ + +/* Define as 1 if you want to enable the performance manager profiling code */ +/* #undef ENABLE_OSM_PERF_MGR_PROFILE */ + +/* Define a default node name map file */ +#define HAVE_DEFAULT_NODENAME_MAP "/usr/local/etc/opensm/ib-node-name-map" + +/* Define a default OpenSM config file */ +#define HAVE_DEFAULT_OPENSM_CONFIG_FILE "/usr/local/etc/opensm/opensm.conf" + +/* Define a Partition config file */ +#define HAVE_DEFAULT_PARTITION_CONFIG_FILE "/usr/local/etc/opensm/partitions.conf" + +/* Define a Prefix Routes config file */ +#define HAVE_DEFAULT_PREFIX_ROUTES_FILE "/usr/local/etc/opensm/prefix-routes.conf" + +/* Define a QOS policy config file */ +#define HAVE_DEFAULT_QOS_POLICY_FILE "/usr/local/etc/opensm/qos-policy.conf" + +/* Define OpenSM config directory */ +#define OPENSM_CONFIG_DIR "/usr/local/etc/opensm" + +/* Define as 1 for vapi vendor */ +/* #undef OSM_VENDOR_INTF_MTL */ + +/* Define as 1 for OpenIB vendor */ +#define OSM_VENDOR_INTF_OPENIB 1 + +/* Define as 1 for sim vendor */ +/* #undef OSM_VENDOR_INTF_SIM */ + +/* Define as 1 for ts vendor */ +/* #undef OSM_VENDOR_INTF_TS */ + +/* Define as 1 if you want Vendor RMPP Support */ +#define VENDOR_RMPP_SUPPORT 1 + +#endif /* _OSM_CONFIG_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_config.h.in b/contrib/ofed/management/opensm/include/opensm/osm_config.h.in new file mode 100644 index 000000000000..b12006f3865b --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_config.h.in @@ -0,0 +1,64 @@ +/* include/osm_config.h.in + * + * Defines various OpenSM configuration parameters to be used by various + * plugins and third party tools. + * + * NOTE: Defines used in header files MUST be included here to ensure plugin + * compatibility. + */ + +#ifndef _OSM_CONFIG_H_ +#define _OSM_CONFIG_H_ + +/* define 1 if OpenSM build is in a debug mode */ +#undef OSM_DEBUG + +/* Define as 1 if you want Dual Sided RMPP Support */ +#undef DUAL_SIDED_RMPP + +/* Define as 1 if you want to enable a console on a socket connection */ +#undef ENABLE_OSM_CONSOLE_SOCKET + +/* Define as 1 if you want to enable the event plugin */ +#undef ENABLE_OSM_DEFAULT_EVENT_PLUGIN + +/* Define as 1 if you want to enable the performance manager */ +#undef ENABLE_OSM_PERF_MGR + +/* Define as 1 if you want to enable the performance manager profiling code */ +#undef ENABLE_OSM_PERF_MGR_PROFILE + +/* Define a default node name map file */ +#undef HAVE_DEFAULT_NODENAME_MAP + +/* Define a default OpenSM config file */ +#undef HAVE_DEFAULT_OPENSM_CONFIG_FILE + +/* Define a Partition config file */ +#undef HAVE_DEFAULT_PARTITION_CONFIG_FILE + +/* Define a Prefix Routes config file */ +#undef HAVE_DEFAULT_PREFIX_ROUTES_FILE + +/* Define a QOS policy config file */ +#undef HAVE_DEFAULT_QOS_POLICY_FILE + +/* Define OpenSM config directory */ +#undef OPENSM_CONFIG_DIR + +/* Define as 1 for vapi vendor */ +#undef OSM_VENDOR_INTF_MTL + +/* Define as 1 for OpenIB vendor */ +#undef OSM_VENDOR_INTF_OPENIB + +/* Define as 1 for sim vendor */ +#undef OSM_VENDOR_INTF_SIM + +/* Define as 1 for ts vendor */ +#undef OSM_VENDOR_INTF_TS + +/* Define as 1 if you want Vendor RMPP Support */ +#undef VENDOR_RMPP_SUPPORT + +#endif /* _OSM_CONFIG_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_console.h b/contrib/ofed/management/opensm/include/opensm/osm_console.h new file mode 100644 index 000000000000..3ea8fa5b66c7 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_console.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2005-2007 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_CONSOLE_H_ +#define _OSM_CONSOLE_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +// TODO replace p_osm +void osm_console(osm_opensm_t * p_osm); +END_C_DECLS +#endif /* _OSM_CONSOLE_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_console_io.h b/contrib/ofed/management/opensm/include/opensm/osm_console_io.h new file mode 100644 index 000000000000..5fe233df54e6 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_console_io.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2005-2007 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +/* + * Abstract: + * Declaration of osm_console_t. + * This object represents the OpenSM Console object. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_CONSOLE_IO_H_ +#define _OSM_CONSOLE_IO_H_ + +#include +#include + +#define OSM_DISABLE_CONSOLE "off" +#define OSM_LOCAL_CONSOLE "local" +#define OSM_REMOTE_CONSOLE "socket" +#define OSM_LOOPBACK_CONSOLE "loopback" +#define OSM_CONSOLE_NAME "OSM Console" + +#define OSM_DEFAULT_CONSOLE OSM_DISABLE_CONSOLE +#define OSM_DEFAULT_CONSOLE_PORT 10000 +#define OSM_DAEMON_NAME "opensm" + +#define OSM_COMMAND_PROMPT "$ " + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +typedef struct osm_console { + int socket; + int in_fd; + int out_fd; + int authorized; + FILE *in; + FILE *out; + char client_type[32]; + char client_ip[64]; + char client_hn[128]; +} osm_console_t; + +void osm_console_prompt(FILE * out); +int osm_console_init(osm_subn_opt_t * opt, osm_console_t * p_oct, osm_log_t * p_log); +void osm_console_exit(osm_console_t * p_oct, osm_log_t * p_log); +int is_console_enabled(osm_subn_opt_t *p_opt); + +#ifdef ENABLE_OSM_CONSOLE_SOCKET +int cio_open(osm_console_t * p_oct, int new_fd, osm_log_t * p_log); +int is_authorized(osm_console_t * p_oct); +#endif + +END_C_DECLS +#endif /* _OSM_CONSOLE_IO_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_db.h b/contrib/ofed/management/opensm/include/opensm/osm_db.h new file mode 100644 index 000000000000..56bae317df2b --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_db.h @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_DB_H_ +#define _OSM_DB_H_ + +/* + * Abstract: + * Declaration of the DB interface. + */ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Database +* NAME +* Database +* +* DESCRIPTION +* The OpenSM database interface provide the means to restore persistent +* data, query, modify, delete and eventually commit it back to the +* persistent media. +* +* The interface is defined such that it can is not "data dependent": +* All keys and data items are texts. +* +* The DB implementation should be thread safe, thus callers do not need to +* provide serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox Technologies LTD +* +*********/ +/****s* OpenSM: Database/osm_db_domain_t +* NAME +* osm_db_domain_t +* +* DESCRIPTION +* A domain of the database. Can be viewed as a database table. +* +* The osm_db_domain_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_db_domain { + struct osm_db *p_db; + void *p_domain_imp; +} osm_db_domain_t; +/* +* FIELDS +* p_db +* Pointer to the parent database object. +* +* p_domain_imp +* Pointer to the db implementation object +* +* SEE ALSO +* osm_db_t +*********/ + +/****s* OpenSM: Database/osm_db_t +* NAME +* osm_db_t +* +* DESCRIPTION +* The main database object. +* +* The osm_db_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_db { + void *p_db_imp; + osm_log_t *p_log; + cl_list_t domains; +} osm_db_t; +/* +* FIELDS +* p_db_imp +* Pointer to the database implementation object +* +* p_log +* Pointer to the OSM logging facility +* +* domains +* List of initialize domains +* +* SEE ALSO +*********/ + +/****f* OpenSM: Database/osm_db_construct +* NAME +* osm_db_construct +* +* DESCRIPTION +* Construct a database. +* +* SYNOPSIS +*/ +void osm_db_construct(IN osm_db_t * const p_db); +/* +* PARAMETERS +* p_db +* [in] Pointer to the database object to construct +* +* RETURN VALUES +* NONE +* +* SEE ALSO +* Database, osm_db_init, osm_db_destroy +*********/ + +/****f* OpenSM: Database/osm_db_destroy +* NAME +* osm_db_destroy +* +* DESCRIPTION +* Destroys the osm_db_t structure. +* +* SYNOPSIS +*/ +void osm_db_destroy(IN osm_db_t * const p_db); +/* +* PARAMETERS +* p_db +* [in] Pointer to osm_db_t structure to destroy +* +* SEE ALSO +* Database, osm_db_construct, osm_db_init +*********/ + +/****f* OpenSM: Database/osm_db_init +* NAME +* osm_db_init +* +* DESCRIPTION +* Initializes the osm_db_t structure. +* +* SYNOPSIS +*/ +int osm_db_init(IN osm_db_t * const p_db, IN osm_log_t * p_log); +/* +* PARAMETERS +* +* p_db +* [in] Pointer to the database object to initialize +* +* p_log +* [in] Pointer to the OSM logging facility +* +* RETURN VALUES +* 0 on success 1 otherwise +* +* SEE ALSO +* Database, osm_db_construct, osm_db_destroy +*********/ + +/****f* OpenSM: Database/osm_db_domain_init +* NAME +* osm_db_domain_init +* +* DESCRIPTION +* Initializes the osm_db_domain_t structure. +* +* SYNOPSIS +*/ +osm_db_domain_t *osm_db_domain_init(IN osm_db_t * const p_db, + IN char *domain_name); +/* +* PARAMETERS +* +* p_db +* [in] Pointer to the database object to initialize +* +* domain_name +* [in] a char array with the domain name. +* +* RETURN VALUES +* pointer to the new domain object or NULL if failed. +* +* SEE ALSO +* Database, osm_db_construct, osm_db_destroy +*********/ + +/****f* OpenSM: Database/osm_db_restore +* NAME +* osm_db_restore +* +* DESCRIPTION +* Reads the entire domain from persistent storage - overrides all +* existing cached data (if any). +* +* SYNOPSIS +*/ +int osm_db_restore(IN osm_db_domain_t * p_domain); +/* +* PARAMETERS +* +* p_domain +* [in] Pointer to the database domain object to restore +* from persistent db +* +* RETURN VALUES +* 0 if successful 1 otherwize +* +* SEE ALSO +* Database, osm_db_domain_init, osm_db_clear, osm_db_store, +* osm_db_keys, osm_db_lookup, osm_db_update, osm_db_delete +*********/ + +/****f* OpenSM: Database/osm_db_clear +* NAME +* osm_db_clear +* +* DESCRIPTION +* Clears the entire domain values from/in the cache +* +* SYNOPSIS +*/ +int osm_db_clear(IN osm_db_domain_t * p_domain); +/* +* PARAMETERS +* +* p_domain +* [in] Pointer to the database domain object to clear +* +* RETURN VALUES +* 0 if successful 1 otherwize +* +* SEE ALSO +* Database, osm_db_domain_init, osm_db_restore, osm_db_store, +* osm_db_keys, osm_db_lookup, osm_db_update, osm_db_delete +*********/ + +/****f* OpenSM: Database/osm_db_store +* NAME +* osm_db_store +* +* DESCRIPTION +* Store the domain cache back to the database (commit) +* +* SYNOPSIS +*/ +int osm_db_store(IN osm_db_domain_t * p_domain); +/* +* PARAMETERS +* +* p_domain +* [in] Pointer to the database domain object to restore from +* persistent db +* +* RETURN VALUES +* 0 if successful 1 otherwize +* +* SEE ALSO +* Database, osm_db_domain_init, osm_db_restore, osm_db_clear, +* osm_db_keys, osm_db_lookup, osm_db_update, osm_db_delete +*********/ + +/****f* OpenSM: Database/osm_db_keys +* NAME +* osm_db_keys +* +* DESCRIPTION +* Retrive all keys of the domain +* +* SYNOPSIS +*/ +int osm_db_keys(IN osm_db_domain_t * p_domain, OUT cl_list_t * p_key_list); +/* +* PARAMETERS +* +* p_domain +* [in] Pointer to the database domain object +* +* p_key_list +* [out] List of key values. It should be PRE constructed and initialized. +* +* RETURN VALUES +* 0 if successful 1 otherwize +* +* NOTE: the caller needs to free and destruct the list, +* the keys returned are intrnal to the hash and should NOT be free'ed +* +* SEE ALSO +* Database, osm_db_domain_init, osm_db_restore, osm_db_clear, osm_db_store, +* osm_db_lookup, osm_db_update, osm_db_delete +*********/ + +/****f* OpenSM: Database/osm_db_lookup +* NAME +* osm_db_lookup +* +* DESCRIPTION +* Lookup an entry in the domain by the given key +* +* SYNOPSIS +*/ +/* lookup value by key */ +char *osm_db_lookup(IN osm_db_domain_t * p_domain, IN char *const p_key); +/* +* PARAMETERS +* +* p_domain +* [in] Pointer to the database domain object +* +* key +* [in] The key to look for +* +* RETURN VALUES +* the value as char * or NULL if not found +* +* SEE ALSO +* Database, osm_db_domain_init, osm_db_restore, osm_db_clear, osm_db_store, +* osm_db_keys, osm_db_update, osm_db_delete +*********/ + +/****f* OpenSM: Database/osm_db_update +* NAME +* osm_db_update +* +* DESCRIPTION +* Set the value of the given key +* +* SYNOPSIS +*/ +int +osm_db_update(IN osm_db_domain_t * p_domain, + IN char *const p_key, IN char *const p_val); +/* +* PARAMETERS +* +* p_domain +* [in] Pointer to the database domain object +* +* p_key +* [in] The key to update +* +* p_val +* [in] The value to update +* +* RETURN VALUES +* 0 on success +* +* NOTE: the value will be duplicated so can be free'ed +* +* SEE ALSO +* Database, osm_db_domain_init, osm_db_restore, osm_db_clear, osm_db_store, +* osm_db_keys, osm_db_lookup, osm_db_delete +*********/ + +/****f* OpenSM: Database/osm_db_delete +* NAME +* osm_db_delete +* +* DESCRIPTION +* Delete an entry by the given key +* +* SYNOPSIS +*/ +int osm_db_delete(IN osm_db_domain_t * p_domain, IN char *const p_key); +/* +* PARAMETERS +* +* p_domain +* [in] Pointer to the database domain object +* +* p_key +* [in] The key to look for +* +* RETURN VALUES +* 0 on success +* +* SEE ALSO +* Database, osm_db_domain_init, osm_db_restore, osm_db_clear, osm_db_store, +* osm_db_keys, osm_db_lookup, osm_db_update +*********/ + +END_C_DECLS +#endif /* _OSM_DB_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_db_pack.h b/contrib/ofed/management/opensm/include/opensm/osm_db_pack.h new file mode 100644 index 000000000000..83861a6d3c47 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_db_pack.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/****h* OpenSM/DB-Pack +* NAME +* Database Types +* +* DESCRIPTION +* This module provides packing and unpacking of the database +* storage into specific types. +* +* The following domains/conversions are supported: +* guid2lid - key is a guid and data is a lid. +* +* AUTHOR +* Eitan Zahavi, Mellanox Technologies LTD +* +*********/ + +#ifndef _OSM_DB_PACK_H_ +#define _OSM_DB_PACK_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****f* OpenSM: DB-Pack/osm_db_guid2lid_init +* NAME +* osm_db_guid2lid_init +* +* DESCRIPTION +* Initialize a domain for the guid2lid table +* +* SYNOPSIS +*/ +static inline osm_db_domain_t *osm_db_guid2lid_init(IN osm_db_t * const p_db) +{ + return (osm_db_domain_init(p_db, "guid2lid")); +} + +/* +* PARAMETERS +* p_db +* [in] Pointer to the database object to construct +* +* RETURN VALUES +* The pointer to the new allocated domain object or NULL. +* +* NOTE: DB domains are destroyed by the osm_db_destroy +* +* SEE ALSO +* Database, osm_db_init, osm_db_destroy +*********/ + +/****f* OpenSM: DB-Pack/osm_db_guid2lid_init +* NAME +* osm_db_guid2lid_init +* +* DESCRIPTION +* Initialize a domain for the guid2lid table +* +* SYNOPSIS +*/ +typedef struct osm_db_guid_elem { + cl_list_item_t item; + uint64_t guid; +} osm_db_guid_elem_t; +/* +* FIELDS +* item +* required for list manipulations +* +* guid +* +************/ + +/****f* OpenSM: DB-Pack/osm_db_guid2lid_guids +* NAME +* osm_db_guid2lid_guids +* +* DESCRIPTION +* Provides back a list of guid elements. +* +* SYNOPSIS +*/ +int +osm_db_guid2lid_guids(IN osm_db_domain_t * const p_g2l, + OUT cl_qlist_t * p_guid_list); +/* +* PARAMETERS +* p_g2l +* [in] Pointer to the guid2lid domain +* +* p_guid_list +* [out] A quick list of guid elements of type osm_db_guid_elem_t +* +* RETURN VALUES +* 0 if successful +* +* NOTE: the output qlist should be initialized and each item freed +* by the caller, then destroyed. +* +* SEE ALSO +* osm_db_guid2lid_init, osm_db_guid2lid_guids, osm_db_guid2lid_get +* osm_db_guid2lid_set, osm_db_guid2lid_delete +*********/ + +/****f* OpenSM: DB-Pack/osm_db_guid2lid_get +* NAME +* osm_db_guid2lid_get +* +* DESCRIPTION +* Get a lid range by given guid. +* +* SYNOPSIS +*/ +int +osm_db_guid2lid_get(IN osm_db_domain_t * const p_g2l, + IN uint64_t guid, + OUT uint16_t * p_min_lid, OUT uint16_t * p_max_lid); +/* +* PARAMETERS +* p_g2l +* [in] Pointer to the guid2lid domain +* +* guid +* [in] The guid to look for +* +* p_min_lid +* [out] Pointer to the resulting min lid in host order. +* +* p_max_lid +* [out] Pointer to the resulting max lid in host order. +* +* RETURN VALUES +* 0 if successful. The lid will be set to 0 if not found. +* +* SEE ALSO +* osm_db_guid2lid_init, osm_db_guid2lid_guids +* osm_db_guid2lid_set, osm_db_guid2lid_delete +*********/ + +/****f* OpenSM: DB-Pack/osm_db_guid2lid_set +* NAME +* osm_db_guid2lid_set +* +* DESCRIPTION +* Set a lid range for the given guid. +* +* SYNOPSIS +*/ +int +osm_db_guid2lid_set(IN osm_db_domain_t * const p_g2l, + IN uint64_t guid, IN uint16_t min_lid, IN uint16_t max_lid); +/* +* PARAMETERS +* p_g2l +* [in] Pointer to the guid2lid domain +* +* guid +* [in] The guid to look for +* +* min_lid +* [in] The min lid value to set +* +* max_lid +* [in] The max lid value to set +* +* RETURN VALUES +* 0 if successful +* +* SEE ALSO +* osm_db_guid2lid_init, osm_db_guid2lid_guids +* osm_db_guid2lid_get, osm_db_guid2lid_delete +*********/ + +/****f* OpenSM: DB-Pack/osm_db_guid2lid_delete +* NAME +* osm_db_guid2lid_delete +* +* DESCRIPTION +* Delete the entry by the given guid +* +* SYNOPSIS +*/ +int osm_db_guid2lid_delete(IN osm_db_domain_t * const p_g2l, IN uint64_t guid); +/* +* PARAMETERS +* p_g2l +* [in] Pointer to the guid2lid domain +* +* guid +* [in] The guid to look for +* +* RETURN VALUES +* 0 if successful otherwise 1 +* +* SEE ALSO +* osm_db_guid2lid_init, osm_db_guid2lid_guids +* osm_db_guid2lid_get, osm_db_guid2lid_set +*********/ + +END_C_DECLS +#endif /* _OSM_DB_PACK_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_errors.h b/contrib/ofed/management/opensm/include/opensm/osm_errors.h new file mode 100644 index 000000000000..aff4300b824c --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_errors.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of error code ranges for the various OpenSM modules. + */ + +#ifndef _OSM_ERRORS_H_ +#define _OSM_ERRORS_H_ + +/* + Generic Request Controller + 0100 - 01FF + + Node Info Receive Controller + 0200 - 02FF + + Generic Requester + 0300 - 03FF + + Node Info Receiver + 0400 - 04FF + + Node Description Receiver + 0500 - 05FF + + Node Description Receive Controller + 0600 - 06FF + + Port Info Receiver + 0700 - 07FF + + Port Info Receive Controller + 0800 - 08FF + + Mad Pool + 0900 - 09FF + + SM + 1000 - 10FF + + SM MAD Controller + 1100 - 11FF + + VL15 Interface + 1200 - 12FF + + Switch Info Receive Controller + 1300 - 13FF + + Switch Info Receiver + 1400 - 14FF + + State Manager + 1500 - 15FF + + State Manager Controller + 1600 - 16FF + + LID Manager + 1700 - 17FF + + Link Manager + 1800 - 18FF + + Drop Manager + 1900 - 19FF + + Linear Forwarding Receive Controller + 2000 - 20FF + + Linear Forwarding Receiver + 2100 - 21FF + + Vendor Specific + 2200 - 22FF + + SMInfo Receive Controller + 2300 - 23FF + + SMInfo Info Receiver + 2400 - 24FF + + Generic Responder + 2500 - 25FF + + Linear Forwarding Receive Controller + 2600 - 26FF + + Linear Forwarding Receiver + 2700 - 27FF + + SA MAD controller + 2800 - 28FF + + Node Record Controller + 2900 - 29FF + + PortInfo Record Controller + 3000 - 30FF + + Link Record Controller + 3100 - 31FF + + Path Record Controller + 3200 - 32FF + + SMInfo Record Controller + 3300 - 33FF + + Multicast Record Controller + 3400 - 34FF + + Unicast Manager + 3500 - 35FF + + Multicast Manager + 3600 - 36FF + + SA Response + 3700 - 37FF + + Link Record Receiver + 3800 - 38FF + + Multicast Forwarding Receive Controller + 3900 - 39FF + + Multicast Forwarding Receiver + 4000 - 40FF + + SMInfo Record Receiver + 4100 - 41FF + + PortInfo Record Receiver + 4200 - 42FF + + Service Record Receiver + 4300 - 43FF + +*/ + +#endif /* _OSM_ERRORS_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_event_plugin.h b/contrib/ofed/management/opensm/include/opensm/osm_event_plugin.h new file mode 100644 index 000000000000..0922c65d6aa8 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_event_plugin.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2007 The Regents of the University of California. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_EVENT_PLUGIN_H_ +#define _OSM_EVENT_PLUGIN_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM Event plugin interface +* DESCRIPTION +* Database interface to record subnet events +* +* Implementations of this object _MUST_ be thread safe. +* +* AUTHOR +* Ira Weiny, LLNL +* +*********/ + +#define OSM_EPI_NODE_NAME_LEN (128) + +struct osm_opensm; +/** ========================================================================= + * Event types + */ +typedef enum { + OSM_EVENT_ID_PORT_ERRORS = 0, + OSM_EVENT_ID_PORT_DATA_COUNTERS, + OSM_EVENT_ID_PORT_SELECT, + OSM_EVENT_ID_TRAP, + OSM_EVENT_ID_SUBNET_UP, + OSM_EVENT_ID_MAX +} osm_epi_event_id_t; + +typedef struct osm_epi_port_id { + uint64_t node_guid; + uint8_t port_num; + char node_name[OSM_EPI_NODE_NAME_LEN]; +} osm_epi_port_id_t; + +/** ========================================================================= + * Port error event + * OSM_EVENT_ID_PORT_COUNTER + * This is a difference from the last reading. NOT an absolute reading. + */ +typedef struct osm_epi_pe_event { + osm_epi_port_id_t port_id; + uint64_t symbol_err_cnt; + uint64_t link_err_recover; + uint64_t link_downed; + uint64_t rcv_err; + uint64_t rcv_rem_phys_err; + uint64_t rcv_switch_relay_err; + uint64_t xmit_discards; + uint64_t xmit_constraint_err; + uint64_t rcv_constraint_err; + uint64_t link_integrity; + uint64_t buffer_overrun; + uint64_t vl15_dropped; + time_t time_diff_s; +} osm_epi_pe_event_t; + +/** ========================================================================= + * Port data counter event + * This is a difference from the last reading. NOT an absolute reading. + */ +typedef struct osm_epi_dc_event { + osm_epi_port_id_t port_id; + uint64_t xmit_data; + uint64_t rcv_data; + uint64_t xmit_pkts; + uint64_t rcv_pkts; + uint64_t unicast_xmit_pkts; + uint64_t unicast_rcv_pkts; + uint64_t multicast_xmit_pkts; + uint64_t multicast_rcv_pkts; + time_t time_diff_s; +} osm_epi_dc_event_t; + +/** ========================================================================= + * Port select event + * This is a difference from the last reading. NOT an absolute reading. + */ +typedef struct osm_api_ps_event { + osm_epi_port_id_t port_id; + uint64_t xmit_wait; + time_t time_diff_s; +} osm_epi_ps_event_t; + +/** ========================================================================= + * Trap events + */ +typedef struct osm_epi_trap_event { + osm_epi_port_id_t port_id; + uint8_t type; + uint32_t prod_type; + uint16_t trap_num; + uint16_t issuer_lid; + time_t time; +} osm_epi_trap_event_t; + +/** ========================================================================= + * Plugin creators should allocate an object of this type + * (named OSM_EVENT_PLUGIN_IMPL_NAME) + * The version should be set to OSM_EVENT_PLUGIN_INTERFACE_VER + */ +#define OSM_EVENT_PLUGIN_IMPL_NAME "osm_event_plugin" +#define OSM_ORIG_EVENT_PLUGIN_INTERFACE_VER 1 +#define OSM_EVENT_PLUGIN_INTERFACE_VER 2 +typedef struct osm_event_plugin { + const char *osm_version; + void *(*create) (struct osm_opensm *osm); + void (*delete) (void *plugin_data); + void (*report) (void *plugin_data, + osm_epi_event_id_t event_id, void *event_data); +} osm_event_plugin_t; + +/** ========================================================================= + * The plugin structure should be considered opaque + */ +typedef struct osm_epi_plugin { + cl_list_item_t list; + void *handle; + osm_event_plugin_t *impl; + void *plugin_data; + char *plugin_name; +} osm_epi_plugin_t; + +/** + * functions + */ +osm_epi_plugin_t *osm_epi_construct(struct osm_opensm *osm, char *plugin_name); +void osm_epi_destroy(osm_epi_plugin_t * plugin); + +/** ========================================================================= + * Helper functions + */ +static inline void +osm_epi_create_port_id(osm_epi_port_id_t * port_id, uint64_t node_guid, + uint8_t port_num, char *node_name) +{ + port_id->node_guid = node_guid; + port_id->port_num = port_num; + strncpy(port_id->node_name, node_name, OSM_EPI_NODE_NAME_LEN); + port_id->node_name[OSM_EPI_NODE_NAME_LEN - 1] = '\0'; +} + +END_C_DECLS +#endif /* _OSM_EVENT_PLUGIN_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_helper.h b/contrib/ofed/management/opensm/include/opensm/osm_helper.h new file mode 100644 index 000000000000..922285302e70 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_helper.h @@ -0,0 +1,550 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_HELPER_H_ +#define _OSM_HELPER_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + * Abstract: + * Declaration of helpful functions. + */ +/****f* OpenSM: Helper/ib_get_sa_method_str + * NAME + * ib_get_sa_method_str + * + * DESCRIPTION + * Returns a string for the specified SA Method value. + * + * SYNOPSIS + */ +const char *ib_get_sa_method_str(IN uint8_t method); +/* + * PARAMETERS + * method + * [in] Network order METHOD ID value. + * + * RETURN VALUES + * Pointer to the method string. + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OpenSM: Helper/ib_get_sm_method_str +* NAME +* ib_get_sm_method_str +* +* DESCRIPTION +* Returns a string for the specified SM Method value. +* +* SYNOPSIS +*/ +const char *ib_get_sm_method_str(IN uint8_t method); +/* +* PARAMETERS +* method +* [in] Network order METHOD ID value. +* +* RETURN VALUES +* Pointer to the method string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/ib_get_sm_attr_str +* NAME +* ib_get_sm_attr_str +* +* DESCRIPTION +* Returns a string for the specified SM attribute value. +* +* SYNOPSIS +*/ +const char *ib_get_sm_attr_str(IN ib_net16_t attr); +/* +* PARAMETERS +* attr +* [in] Network order attribute ID value. +* +* RETURN VALUES +* Pointer to the attribute string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/ib_get_sa_attr_str +* NAME +* ib_get_sa_attr_str +* +* DESCRIPTION +* Returns a string for the specified SA attribute value. +* +* SYNOPSIS +*/ +const char *ib_get_sa_attr_str(IN ib_net16_t attr); +/* +* PARAMETERS +* attr +* [in] Network order attribute ID value. +* +* RETURN VALUES +* Pointer to the attribute string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/ib_get_trap_str +* NAME +* ib_get_trap_str +* +* DESCRIPTION +* Returns a name for the specified trap. +* +* SYNOPSIS +*/ +const char *ib_get_trap_str(uint16_t trap_num); +/* +* PARAMETERS +* trap_num +* [in] Network order trap number. +* +* RETURN VALUES +* Name of the trap. +* +*********/ + +/****f* OpenSM: Helper/osm_dump_port_info +* NAME +* osm_dump_port_info +* +* DESCRIPTION +* Dumps the PortInfo attribute to the log. +* +* SYNOPSIS +*/ +void osm_dump_port_info(IN osm_log_t * const p_log, + IN const ib_net64_t node_guid, + IN const ib_net64_t port_guid, + IN const uint8_t port_num, + IN const ib_port_info_t * const p_pi, + IN const osm_log_level_t log_level); +/* +* PARAMETERS +* p_log +* [in] Pointer to the osm_log_t object +* +* node_guid +* [in] Node GUID that owns this port. +* +* port_guid +* [in] Port GUID for this port. +* +* port_num +* [in] Port number for this port. +* +* p_pi +* [in] Pointer to the PortInfo attribute +* +* log_level +* [in] Log verbosity level with which to dump the data. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +void +osm_dump_path_record(IN osm_log_t * const p_log, + IN const ib_path_rec_t * const p_pr, + IN const osm_log_level_t log_level); + +void +osm_dump_multipath_record(IN osm_log_t * const p_log, + IN const ib_multipath_rec_t * const p_mpr, + IN const osm_log_level_t log_level); + +void +osm_dump_node_record(IN osm_log_t * const p_log, + IN const ib_node_record_t * const p_nr, + IN const osm_log_level_t log_level); + +void +osm_dump_mc_record(IN osm_log_t * const p_log, + IN const ib_member_rec_t * const p_mcmr, + IN const osm_log_level_t log_level); + +void +osm_dump_link_record(IN osm_log_t * const p_log, + IN const ib_link_record_t * const p_lr, + IN const osm_log_level_t log_level); + +void +osm_dump_service_record(IN osm_log_t * const p_log, + IN const ib_service_record_t * const p_sr, + IN const osm_log_level_t log_level); + +void +osm_dump_portinfo_record(IN osm_log_t * const p_log, + IN const ib_portinfo_record_t * const p_pir, + IN const osm_log_level_t log_level); + +void +osm_dump_guidinfo_record(IN osm_log_t * const p_log, + IN const ib_guidinfo_record_t * const p_gir, + IN const osm_log_level_t log_level); + +void +osm_dump_inform_info(IN osm_log_t * const p_log, + IN const ib_inform_info_t * const p_ii, + IN const osm_log_level_t log_level); + +void +osm_dump_inform_info_record(IN osm_log_t * const p_log, + IN const ib_inform_info_record_t * const p_iir, + IN const osm_log_level_t log_level); + +void +osm_dump_switch_info_record(IN osm_log_t * const p_log, + IN const ib_switch_info_record_t * const p_sir, + IN const osm_log_level_t log_level); + +void +osm_dump_sm_info_record(IN osm_log_t * const p_log, + IN const ib_sminfo_record_t * const p_smir, + IN const osm_log_level_t log_level); + +void +osm_dump_pkey_block(IN osm_log_t * const p_log, + IN uint64_t port_guid, + IN uint16_t block_num, + IN uint8_t port_num, + IN const ib_pkey_table_t * const p_pkey_tbl, + IN const osm_log_level_t log_level); + +void +osm_dump_slvl_map_table(IN osm_log_t * const p_log, + IN uint64_t port_guid, + IN uint8_t in_port_num, + IN uint8_t out_port_num, + IN const ib_slvl_table_t * const p_slvl_tbl, + IN const osm_log_level_t log_level); + +void +osm_dump_vl_arb_table(IN osm_log_t * const p_log, + IN uint64_t port_guid, + IN uint8_t block_num, + IN uint8_t port_num, + IN const ib_vl_arb_table_t * const p_vla_tbl, + IN const osm_log_level_t log_level); + +/****f* OpenSM: Helper/osm_dump_port_info +* NAME +* osm_dump_port_info +* +* DESCRIPTION +* Dumps the PortInfo attribute to the log. +* +* SYNOPSIS +*/ +void osm_dump_node_info(IN osm_log_t * const p_log, + IN const ib_node_info_t * const p_ni, + IN const osm_log_level_t log_level); +/* +* PARAMETERS +* p_log +* [in] Pointer to the osm_log_t object +* +* p_ni +* [in] Pointer to the NodeInfo attribute +* +* log_level +* [in] Log verbosity level with which to dump the data. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/osm_dump_sm_info +* NAME +* osm_dump_sm_info +* +* DESCRIPTION +* Dumps the SMInfo attribute to the log. +* +* SYNOPSIS +*/ +void +osm_dump_sm_info(IN osm_log_t * const p_log, + IN const ib_sm_info_t * const p_smi, + IN const osm_log_level_t log_level); +/* +* PARAMETERS +* p_log +* [in] Pointer to the osm_log_t object +* +* p_smi +* [in] Pointer to the SMInfo attribute +* +* log_level +* [in] Log verbosity level with which to dump the data. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/osm_dump_switch_info +* NAME +* osm_dump_switch_info +* +* DESCRIPTION +* Dumps the SwitchInfo attribute to the log. +* +* SYNOPSIS +*/ +void +osm_dump_switch_info(IN osm_log_t * const p_log, + IN const ib_switch_info_t * const p_si, + IN const osm_log_level_t log_level); +/* +* PARAMETERS +* p_log +* [in] Pointer to the osm_log_t object +* +* p_si +* [in] Pointer to the SwitchInfo attribute +* +* log_level +* [in] Log verbosity level with which to dump the data. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/osm_dump_notice +* NAME +* osm_dump_notice +* +* DESCRIPTION +* Dumps the Notice attribute to the log. +* +* SYNOPSIS +*/ +void +osm_dump_notice(IN osm_log_t * const p_log, + IN const ib_mad_notice_attr_t * p_ntci, + IN const osm_log_level_t log_level); +/* +* PARAMETERS +* p_log +* [in] Pointer to the osm_log_t object +* +* p_ntci +* [in] Pointer to the Notice attribute +* +* log_level +* [in] Log verbosity level with which to dump the data. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/osm_get_disp_msg_str +* NAME +* osm_get_disp_msg_str +* +* DESCRIPTION +* Returns a string for the specified Dispatcher message. +* +* SYNOPSIS +*/ +const char *osm_get_disp_msg_str(IN cl_disp_msgid_t msg); +/* +* PARAMETERS +* msg +* [in] Dispatcher message ID value. +* +* RETURN VALUES +* Pointer to the message discription string. +* +* NOTES +* +* SEE ALSO +*********/ + +void osm_dump_dr_path(IN osm_log_t * const p_log, + IN const osm_dr_path_t * const p_path, + IN const osm_log_level_t level); + +void osm_dump_smp_dr_path(IN osm_log_t * const p_log, + IN const ib_smp_t * const p_smp, + IN const osm_log_level_t level); + +void osm_dump_dr_smp(IN osm_log_t * const p_log, + IN const ib_smp_t * const p_smp, + IN const osm_log_level_t level); + +void osm_dump_sa_mad(IN osm_log_t * const p_log, + IN const ib_sa_mad_t * const p_smp, + IN const osm_log_level_t level); + +/****f* IBA Base: Types/osm_get_sm_signal_str +* NAME +* osm_get_sm_signal_str +* +* DESCRIPTION +* Returns a string for the specified SM state. +* +* SYNOPSIS +*/ +const char *osm_get_sm_signal_str(IN osm_signal_t signal); +/* +* PARAMETERS +* state +* [in] Signal value +* +* RETURN VALUES +* Pointer to the signal discription string. +* +* NOTES +* +* SEE ALSO +*********/ + +const char *osm_get_port_state_str_fixed_width(IN uint8_t port_state); + +const char *osm_get_node_type_str_fixed_width(IN uint8_t node_type); + +const char *osm_get_manufacturer_str(IN uint64_t const guid_ho); + +const char *osm_get_mtu_str(IN uint8_t const mtu); + +const char *osm_get_lwa_str(IN uint8_t const lwa); + +const char *osm_get_mtu_str(IN uint8_t const mtu); + +const char *osm_get_lwa_str(IN uint8_t const lwa); + +const char *osm_get_lsa_str(IN uint8_t const lsa); + +/****f* IBA Base: Types/osm_get_sm_mgr_signal_str +* NAME +* osm_get_sm_mgr_signal_str +* +* DESCRIPTION +* Returns a string for the specified SM manager signal. +* +* SYNOPSIS +*/ +const char *osm_get_sm_mgr_signal_str(IN osm_sm_signal_t signal); +/* +* PARAMETERS +* signal +* [in] SM manager signal +* +* RETURN VALUES +* Pointer to the signal discription string. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* IBA Base: Types/osm_get_sm_mgr_state_str +* NAME +* osm_get_sm_mgr_state_str +* +* DESCRIPTION +* Returns a string for the specified SM manager state. +* +* SYNOPSIS +*/ +const char *osm_get_sm_mgr_state_str(IN uint16_t state); +/* +* PARAMETERS +* state +* [in] SM manager state +* +* RETURN VALUES +* Pointer to the state discription string. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_HELPER_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_inform.h b/contrib/ofed/management/opensm/include/opensm/osm_inform.h new file mode 100644 index 000000000000..1528642b2669 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_inform.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_inform_rec_t. + * This object represents an IBA Inform Record. + * This object is part of the OpenSM family of objects. + * + * Author: + * Eitan Zahavi, Mellanox + */ + +#ifndef _OSM_INFR_H_ +#define _OSM_INFR_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Inform Record +* NAME +* Inform Record +* +* DESCRIPTION +* The Inform record encapsulates the information needed by the +* SA to manage InformInfo registrations and sending Reports(Notice) +* when SM receives Traps for registered LIDs. +* +* The inform records is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Eitan Zahavi, Mellanox +* +*********/ +/****s* OpenSM: Inform Record/osm_infr_t +* NAME +* osm_infr_t +* +* DESCRIPTION +* Inform Record structure. +* +* The osm_infr_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_infr { + cl_list_item_t list_item; + osm_bind_handle_t h_bind; + osm_sa_t *sa; + osm_mad_addr_t report_addr; + ib_inform_info_record_t inform_record; +} osm_infr_t; +/* +* FIELDS +* list_item +* List Item for qlist linkage. Must be first element!! +* +* h_bind +* A handle of lower level mad srvc +* +* sa +* A pointer to osm_sa object +* +* report_addr +* Report address +* +* inform_record +* The Inform Info Record +* +* SEE ALSO +*********/ + +/****f* OpenSM: Inform Record/osm_infr_new +* NAME +* osm_infr_new +* +* DESCRIPTION +* Allocates and initializes a Inform Record for use. +* +* SYNOPSIS +*/ +osm_infr_t *osm_infr_new(IN const osm_infr_t * p_infr_rec); +/* +* PARAMETERS +* p_inf_rec +* [in] Pointer to IB Inform Record +* +* RETURN VALUES +* pointer to osm_infr_t structure. +* +* NOTES +* Allows calling other inform record methods. +* +* SEE ALSO +* Inform Record, osm_infr_delete +*********/ + +/****f* OpenSM: Inform Record/osm_infr_delete +* NAME +* osm_infr_delete +* +* DESCRIPTION +* Destroys and deallocates the osm_infr_t structure. +* +* SYNOPSIS +*/ +void osm_infr_delete(IN osm_infr_t * const p_infr); +/* +* PARAMETERS +* p_infr +* [in] Pointer to osm_infr_t structure +* +* SEE ALSO +* Inform Record, osm_infr_new +*********/ + +/****f* OpenSM: Inform Record/osm_infr_get_by_rec +* NAME +* osm_infr_get_by_rec +* +* DESCRIPTION +* Find a matching osm_infr_t in the subnet DB by inform_info_record +* +* SYNOPSIS +*/ +osm_infr_t *osm_infr_get_by_rec(IN osm_subn_t const *p_subn, + IN osm_log_t * p_log, + IN osm_infr_t * const p_infr_rec); +/* +* PARAMETERS +* p_subn +* [in] Pointer to the subnet object +* +* p_log +* [in] Pointer to the log object +* +* p_inf_rec +* [in] Pointer to an inform_info record +* +* RETURN +* The matching osm_infr_t +* SEE ALSO +* Inform Record, osm_infr_new, osm_infr_delete +*********/ + +void +osm_infr_insert_to_db(IN osm_subn_t * p_subn, + IN osm_log_t * p_log, IN osm_infr_t * p_infr); + +void +osm_infr_remove_from_db(IN osm_subn_t * p_subn, + IN osm_log_t * p_log, IN osm_infr_t * p_infr); + +/****f* OpenSM: Inform Record/osm_report_notice +* NAME +* osm_report_notice +* +* DESCRIPTION +* Once a Trap was received by the osm_trap_rcv, or a Trap sourced in +* the SM was sent (Traps 64-67) this routine is called with a copy of +* the notice data. +* Given a notice attribute - compare and see if it matches the InformInfo +* Element and if it does - call the Report(Notice) for the +* target QP registered by the address stored in the InformInfo element +* +* SYNOPSIS +*/ +ib_api_status_t +osm_report_notice(IN osm_log_t * const p_log, + IN osm_subn_t * p_subn, IN ib_mad_notice_attr_t * p_ntc); +/* +* PARAMETERS +* p_rcv +* [in] Pointer to the trap receiver +* +* p_ntc +* [in] Pointer to a copy of the incoming trap notice attribute. +* +* RETURN +* IB_SUCCESS on good completion +* +* SEE ALSO +* Inform Record, osm_trap_rcv +*********/ + +END_C_DECLS +#endif /* _OSM_INFR_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_lid_mgr.h b/contrib/ofed/management/opensm/include/opensm/osm_lid_mgr.h new file mode 100644 index 000000000000..714ba41b201b --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_lid_mgr.h @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_lid_mgr_t. + * This object represents the LID Manager object. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_LID_MGR_H_ +#define _OSM_LID_MGR_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#define OSM_LID_MGR_LIST_SIZE_MIN 256 +/****h* OpenSM/LID Manager +* NAME +* LID Manager +* +* DESCRIPTION +* The LID Manager object encapsulates the information +* needed to control LID assignments on the subnet. +* +* The LID Manager object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +struct osm_sm; +/****s* OpenSM: LID Manager/osm_lid_mgr_t +* NAME +* osm_lid_mgr_t +* +* DESCRIPTION +* LID Manager structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_lid_mgr { + struct osm_sm *sm; + osm_subn_t *p_subn; + osm_db_t *p_db; + osm_log_t *p_log; + cl_plock_t *p_lock; + boolean_t send_set_reqs; + osm_db_domain_t *p_g2l; + cl_ptr_vector_t used_lids; + cl_qlist_t free_ranges; +} osm_lid_mgr_t; +/* +* FIELDS +* sm +* Pointer to the SM object. +* +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_db +* Pointer to the database (persistency) object +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* send_set_reqs +* Boolean to indicate whether any set requests sent. +* +* p_g2l +* Pointer to the database domain storing guid to lid mapping. +* +* used_lids +* A vector the maps from the lid to its guid. keeps track of +* existing and non existing mapping of guid->lid +* +* free_ranges +* A list of available free lid ranges. The list is initialized +* by the code that initializes the lid assignment and is consumed +* by the procedure that finds a free range. It holds elements of +* type osm_lid_mgr_range_t +* +* SEE ALSO +* LID Manager object +*********/ + +/****f* OpenSM: LID Manager/osm_lid_mgr_construct +* NAME +* osm_lid_mgr_construct +* +* DESCRIPTION +* This function constructs a LID Manager object. +* +* SYNOPSIS +*/ +void osm_lid_mgr_construct(IN osm_lid_mgr_t * const p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to a LID Manager object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows osm_lid_mgr_destroy +* +* Calling osm_lid_mgr_construct is a prerequisite to calling any other +* method except osm_lid_mgr_init. +* +* SEE ALSO +* LID Manager object, osm_lid_mgr_init, +* osm_lid_mgr_destroy +*********/ + +/****f* OpenSM: LID Manager/osm_lid_mgr_destroy +* NAME +* osm_lid_mgr_destroy +* +* DESCRIPTION +* The osm_lid_mgr_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_lid_mgr_destroy(IN osm_lid_mgr_t * const p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* LID Manager object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_lid_mgr_construct or osm_lid_mgr_init. +* +* SEE ALSO +* LID Manager object, osm_lid_mgr_construct, +* osm_lid_mgr_init +*********/ + +/****f* OpenSM: LID Manager/osm_lid_mgr_init +* NAME +* osm_lid_mgr_init +* +* DESCRIPTION +* The osm_lid_mgr_init function initializes a +* LID Manager object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_lid_mgr_init(IN osm_lid_mgr_t * const p_mgr, IN struct osm_sm * sm); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_lid_mgr_t object to initialize. +* +* sm +* [in] Pointer to the SM object for this subnet. +* +* RETURN VALUES +* CL_SUCCESS if the LID Manager object was initialized +* successfully. +* +* NOTES +* Allows calling other LID Manager methods. +* +* SEE ALSO +* LID Manager object, osm_lid_mgr_construct, +* osm_lid_mgr_destroy +*********/ + +/****f* OpenSM: LID Manager/osm_lid_mgr_process_sm +* NAME +* osm_lid_mgr_process_sm +* +* DESCRIPTION +* Configures the SM's port with its designated LID values. +* +* SYNOPSIS +*/ +osm_signal_t osm_lid_mgr_process_sm(IN osm_lid_mgr_t * const p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_lid_mgr_t object. +* +* RETURN VALUES +* Returns the appropriate signal to the caller: +* OSM_SIGNAL_DONE - operation is complete +* OSM_SIGNAL_DONE_PENDING - local operations are complete, but +* transactions are still pending on the wire. +* +* NOTES +* +* SEE ALSO +* LID Manager +*********/ + +/****f* OpenSM: LID Manager/osm_lid_mgr_process_subnet +* NAME +* osm_lid_mgr_process_subnet +* +* DESCRIPTION +* Configures subnet ports (except the SM port itself) with their +* designated LID values. +* +* SYNOPSIS +*/ +osm_signal_t osm_lid_mgr_process_subnet(IN osm_lid_mgr_t * const p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_lid_mgr_t object. +* +* RETURN VALUES +* Returns the appropriate signal to the caller: +* OSM_SIGNAL_DONE - operation is complete +* OSM_SIGNAL_DONE_PENDING - local operations are complete, but +* transactions are still pending on the wire. +* +* NOTES +* +* SEE ALSO +* LID Manager +*********/ + +END_C_DECLS +#endif /* _OSM_LID_MGR_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_log.h b/contrib/ofed/management/opensm/include/opensm/osm_log.h new file mode 100644 index 000000000000..20999d9fd296 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_log.h @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_log_t. + * This object represents the log file. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_LOG_H_ +#define _OSM_LOG_H_ + +#ifndef __WIN__ +#include +#endif +#include +#include +#include +#include + +#ifdef __GNUC__ +#define STRICT_OSM_LOG_FORMAT __attribute__((format(printf, 3, 4))) +#else +#define STRICT_OSM_LOG_FORMAT +#endif + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#define LOG_ENTRY_SIZE_MAX 4096 +#define BUF_SIZE LOG_ENTRY_SIZE_MAX +#define __func__ __FUNCTION__ +#define OSM_LOG_ENTER( OSM_LOG_PTR ) \ + osm_log( OSM_LOG_PTR, OSM_LOG_FUNCS, \ + "%s: [\n", __func__); +#define OSM_LOG_EXIT( OSM_LOG_PTR ) \ + osm_log( OSM_LOG_PTR, OSM_LOG_FUNCS, \ + "%s: ]\n", __func__); +/****h* OpenSM/Log +* NAME +* Log +* +* DESCRIPTION +* +* AUTHOR +* +*********/ +typedef uint8_t osm_log_level_t; + +#define OSM_LOG_NONE 0x00 +#define OSM_LOG_ERROR 0x01 +#define OSM_LOG_INFO 0x02 +#define OSM_LOG_VERBOSE 0x04 +#define OSM_LOG_DEBUG 0x08 +#define OSM_LOG_FUNCS 0x10 +#define OSM_LOG_FRAMES 0x20 +#define OSM_LOG_ROUTING 0x40 +#define OSM_LOG_ALL 0x7f +#define OSM_LOG_SYS 0x80 + +/* + DEFAULT - turn on ERROR and INFO only +*/ +#define OSM_LOG_DEFAULT_LEVEL OSM_LOG_ERROR | OSM_LOG_INFO + +/****s* OpenSM: MAD Wrapper/osm_log_t +* NAME +* osm_log_t +* +* DESCRIPTION +* +* SYNOPSIS +*/ +typedef struct osm_log { + osm_log_level_t level; + cl_spinlock_t lock; + unsigned long count; + unsigned long max_size; + boolean_t flush; + FILE *out_port; + boolean_t accum_log_file; + boolean_t daemon; + char *log_file_name; +} osm_log_t; +/*********/ + +/****f* OpenSM: Log/osm_log_construct +* NAME +* osm_log_construct +* +* DESCRIPTION +* This function constructs a Log object. +* +* SYNOPSIS +*/ +static inline void osm_log_construct(IN osm_log_t * const p_log) +{ + cl_spinlock_construct(&p_log->lock); +} + +/* +* PARAMETERS +* p_log +* [in] Pointer to a Log object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_log_init, osm_log_init_v2, osm_log_destroy +* +* Calling osm_log_construct is a prerequisite to calling any other +* method except osm_log_init or osm_log_init_v2. +* +* SEE ALSO +* Log object, osm_log_init, osm_log_init_v2, +* osm_log_destroy +*********/ + +/****f* OpenSM: Log/osm_log_destroy +* NAME +* osm_log_destroy +* +* DESCRIPTION +* The osm_log_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +static inline void osm_log_destroy(IN osm_log_t * const p_log) +{ + cl_spinlock_destroy(&p_log->lock); + if (p_log->out_port != stdout) { + fclose(p_log->out_port); + p_log->out_port = stdout; + } + closelog(); +} + +/* +* PARAMETERS +* p_log +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Log object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_log_construct, osm_log_init, or osm_log_init_v2. +* +* SEE ALSO +* Log object, osm_log_construct, +* osm_log_init, osm_log_init_v2 +*********/ + +/****f* OpenSM: Log/osm_log_init_v2 +* NAME +* osm_log_init_v2 +* +* DESCRIPTION +* The osm_log_init_v2 function initializes a +* Log object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_log_init_v2(IN osm_log_t * const p_log, + IN const boolean_t flush, + IN const uint8_t log_flags, + IN const char *log_file, + IN const unsigned long max_size, + IN const boolean_t accum_log_file); +/* +* PARAMETERS +* p_log +* [in] Pointer to the log object. +* +* flush +* [in] Set to TRUE directs the log to flush all log messages +* immediately. This severely degrades log performance, +* and is normally used for debugging only. +* +* log_flags +* [in] The log verbosity level to be used. +* +* log_file +* [in] if not NULL defines the name of the log file. Otherwise +* it is stdout. +* +* RETURN VALUES +* CL_SUCCESS if the Log object was initialized +* successfully. +* +* NOTES +* Allows calling other Log methods. +* +* SEE ALSO +* Log object, osm_log_construct, +* osm_log_destroy +*********/ + +/****f* OpenSM: Log/osm_log_reopen_file +* NAME +* osm_log_reopen_file +* +* DESCRIPTION +* The osm_log_reopen_file function reopens the log file +* +* SYNOPSIS +*/ +int osm_log_reopen_file(osm_log_t * p_log); +/* +* PARAMETERS +* p_log +* [in] Pointer to the log object. +* +* RETURN VALUES +* 0 on success or nonzero value otherwise. +*********/ + +/****f* OpenSM: Log/osm_log_init +* NAME +* osm_log_init +* +* DESCRIPTION +* The osm_log_init function initializes a +* Log object for use. It is a wrapper for osm_log_init_v2(). +* +* SYNOPSIS +*/ +ib_api_status_t +osm_log_init(IN osm_log_t * const p_log, + IN const boolean_t flush, + IN const uint8_t log_flags, + IN const char *log_file, IN const boolean_t accum_log_file); +/* + * Same as osm_log_init_v2() but without max_size parameter + */ + +void +osm_log(IN osm_log_t * const p_log, + IN const osm_log_level_t verbosity, + IN const char *p_str, ...) STRICT_OSM_LOG_FORMAT; + +/****f* OpenSM: Log/osm_log_get_level +* NAME +* osm_log_get_level +* +* DESCRIPTION +* Returns the current log level. +* +* SYNOPSIS +*/ +static inline osm_log_level_t +osm_log_get_level(IN const osm_log_t * const p_log) +{ + return (p_log->level); +} + +/* +* PARAMETERS +* p_log +* [in] Pointer to the log object. +* +* RETURN VALUES +* Returns the current log level. +* +* NOTES +* +* SEE ALSO +* Log object, osm_log_construct, +* osm_log_destroy +*********/ + +/****f* OpenSM: Log/osm_log_set_level +* NAME +* osm_log_set_level +* +* DESCRIPTION +* Sets the current log level. +* +* SYNOPSIS +*/ +static inline void +osm_log_set_level(IN osm_log_t * const p_log, IN const osm_log_level_t level) +{ + p_log->level = level; + osm_log(p_log, OSM_LOG_ALL, "Setting log level to: 0x%02x\n", level); +} + +/* +* PARAMETERS +* p_log +* [in] Pointer to the log object. +* +* level +* [in] New level to set. +* +* RETURN VALUES +* Returns the current log level. +* +* NOTES +* +* SEE ALSO +* Log object, osm_log_construct, +* osm_log_destroy +*********/ + +/****f* OpenSM: Log/osm_log_is_active +* NAME +* osm_log_is_active +* +* DESCRIPTION +* Returns TRUE if the specified log level would be logged. +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_log_is_active(IN const osm_log_t * const p_log, + IN const osm_log_level_t level) +{ + return ((p_log->level & level) != 0); +} + +/* +* PARAMETERS +* p_log +* [in] Pointer to the log object. +* +* level +* [in] Level to check. +* +* RETURN VALUES +* Returns TRUE if the specified log level would be logged. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Log object, osm_log_construct, +* osm_log_destroy +*********/ + +extern void osm_log_msg_box(osm_log_t *log, osm_log_level_t level, + const char *func_name, const char *msg); +extern void osm_log_raw(IN osm_log_t * const p_log, + IN const osm_log_level_t verbosity, IN const char *p_buf); + +#define OSM_LOG(log, level, fmt, arg...) do { \ + if (osm_log_is_active(log, (level))) \ + osm_log(log, level, "%s: " fmt, __func__, ##arg); \ + } while (0) + +#define OSM_LOG_MSG_BOX(log, level, msg) \ + osm_log_msg_box(log, level, __func__, msg) + +#define DBG_CL_LOCK 0 + +#define CL_PLOCK_EXCL_ACQUIRE( __exp__ ) \ +{ \ + if (DBG_CL_LOCK) \ + printf("cl_plock_excl_acquire: Acquiring %p file %s, line %d\n", \ + __exp__,__FILE__, __LINE__); \ + cl_plock_excl_acquire( __exp__ ); \ + if (DBG_CL_LOCK) \ + printf("cl_plock_excl_acquire: Acquired %p file %s, line %d\n", \ + __exp__,__FILE__, __LINE__); \ +} + +#define CL_PLOCK_ACQUIRE( __exp__ ) \ +{ \ + if (DBG_CL_LOCK) \ + printf("cl_plock_acquire: Acquiring %p file %s, line %d\n", \ + __exp__,__FILE__, __LINE__); \ + cl_plock_acquire( __exp__ ); \ + if (DBG_CL_LOCK) \ + printf("cl_plock_acquire: Acquired %p file %s, line %d\n", \ + __exp__,__FILE__, __LINE__); \ +} + +#define CL_PLOCK_RELEASE( __exp__ ) \ +{ \ + if (DBG_CL_LOCK) \ + printf("cl_plock_release: Releasing %p file %s, line %d\n", \ + __exp__,__FILE__, __LINE__); \ + cl_plock_release( __exp__ ); \ + if (DBG_CL_LOCK) \ + printf("cl_plock_release: Released %p file %s, line %d\n", \ + __exp__,__FILE__, __LINE__); \ +} + +#define DBG_CL_SPINLOCK 0 +#define CL_SPINLOCK_RELEASE( __exp__ ) \ +{ \ + if (DBG_CL_SPINLOCK) \ + printf("cl_spinlock_release: Releasing %p file %s, line %d\n", \ + __exp__,__FILE__, __LINE__); \ + cl_spinlock_release( __exp__ ); \ + if (DBG_CL_SPINLOCK) \ + printf("cl_spinlock_release: Released %p file %s, line %d\n", \ + __exp__,__FILE__, __LINE__); \ +} + +#define CL_SPINLOCK_ACQUIRE( __exp__ ) \ +{ \ + if (DBG_CL_SPINLOCK) \ + printf("cl_spinlock_acquire: Acquiring %p file %s, line %d\n", \ + __exp__,__FILE__, __LINE__); \ + cl_spinlock_acquire( __exp__ ); \ + if (DBG_CL_SPINLOCK) \ + printf("cl_spinlock_acquire: Acquired %p file %s, line %d\n", \ + __exp__,__FILE__, __LINE__); \ +} + +/****f* OpenSM: Helper/osm_is_debug +* NAME +* osm_is_debug +* +* DESCRIPTION +* The osm_is_debug function returns TRUE if the opensm was compiled +* in debug mode, and FALSE otherwise. +* +* SYNOPSIS +*/ +boolean_t osm_is_debug(void); +/* +* PARAMETERS +* None +* +* RETURN VALUE +* TRUE if compiled in debug version. FALSE otherwise. +* +* NOTES +* +*********/ + +END_C_DECLS +#endif /* _OSM_LOG_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_mad_pool.h b/contrib/ofed/management/opensm/include/opensm/osm_mad_pool.h new file mode 100644 index 000000000000..0aa5b464c2d4 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_mad_pool.h @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mad_pool_t. + * This object represents a pool of management datagram (MAD) objects. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_MAD_POOL_H_ +#define _OSM_MAD_POOL_H_ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/MAD Pool +* NAME +* MAD Pool +* +* DESCRIPTION +* The MAD Pool encapsulates the information needed by the +* OpenSM to manage a pool of MAD objects. The OpenSM allocates +* one MAD Pool per IBA subnet. +* +* The MAD Pool is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: MAD Pool/osm_mad_pool_t +* NAME +* osm_mad_pool_t +* +* DESCRIPTION +* MAD Pool structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_mad_pool { + atomic32_t mads_out; +} osm_mad_pool_t; +/* +* FIELDS +* mads_out +* Running total of the number of MADs outstanding. +* +* SEE ALSO +* MAD Pool +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_construct +* NAME +* osm_mad_pool_construct +* +* DESCRIPTION +* This function constructs a MAD Pool. +* +* SYNOPSIS +*/ +void osm_mad_pool_construct(IN osm_mad_pool_t * const p_pool); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a MAD Pool to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_mad_pool_init, osm_mad_pool_destroy +* +* Calling osm_mad_pool_construct is a prerequisite to calling any other +* method except osm_mad_pool_init. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_init, osm_mad_pool_destroy +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_destroy +* NAME +* osm_mad_pool_destroy +* +* DESCRIPTION +* The osm_mad_pool_destroy function destroys a node, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_mad_pool_destroy(IN osm_mad_pool_t * const p_pool); +/* +* PARAMETERS +* p_pool +* [in] Pointer to a MAD Pool to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified MAD Pool. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_mad_pool_construct or +* osm_mad_pool_init. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_construct, osm_mad_pool_init +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_init +* NAME +* osm_mad_pool_init +* +* DESCRIPTION +* The osm_mad_pool_init function initializes a MAD Pool for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_mad_pool_init(IN osm_mad_pool_t * const p_pool); +/* +* PARAMETERS +* p_pool +* [in] Pointer to an osm_mad_pool_t object to initialize. +* +* RETURN VALUES +* CL_SUCCESS if the MAD Pool was initialized successfully. +* +* NOTES +* Allows calling other MAD Pool methods. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_construct, osm_mad_pool_destroy +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_get +* NAME +* osm_mad_pool_get +* +* DESCRIPTION +* Gets a MAD wrapper and wire MAD from the pool. +* +* SYNOPSIS +*/ +osm_madw_t *osm_mad_pool_get(IN osm_mad_pool_t * const p_pool, + IN osm_bind_handle_t h_bind, + IN const uint32_t total_size, + IN const osm_mad_addr_t * const p_mad_addr); +/* +* PARAMETERS +* p_pool +* [in] Pointer to an osm_mad_pool_t object. +* +* h_bind +* [in] Handle returned from osm_vendor_bind() call to the +* port over which this mad will be sent. +* +* total_size +* [in] Total size, including MAD header of the requested MAD. +* +* p_mad_addr +* [in] Pointer to the MAD address structure. This parameter +* may be NULL for directed route MADs. +* +* RETURN VALUES +* Returns a pointer to a MAD wrapper containing the MAD. +* A return value of NULL means no MADs are available. +* +* NOTES +* The MAD must eventually be returned to the pool with a call to +* osm_mad_pool_put. +* +* The osm_mad_pool_construct or osm_mad_pool_init must be called before +* using this function. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_put +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_put +* NAME +* osm_mad_pool_put +* +* DESCRIPTION +* Returns a MAD to the pool. +* +* SYNOPSIS +*/ +void osm_mad_pool_put(IN osm_mad_pool_t * const p_pool, + IN osm_madw_t * const p_madw); +/* +* PARAMETERS +* p_pool +* [in] Pointer to an osm_mad_pool_t object. +* +* p_madw +* [in] Pointer to a MAD Wrapper for a MAD that was previously +* retrieved from the pool. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* The osm_mad_pool_construct or osm_mad_pool_init must be called before +* using this function. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_get +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_get_wrapper +* NAME +* osm_mad_pool_get_wrapper +* +* DESCRIPTION +* Gets a only MAD wrapper from the pool (no wire MAD). +* +* SYNOPSIS +*/ +osm_madw_t *osm_mad_pool_get_wrapper(IN osm_mad_pool_t * const p_pool, + IN osm_bind_handle_t h_bind, + IN const uint32_t total_size, + IN const ib_mad_t * const p_mad, + IN const osm_mad_addr_t * + const p_mad_addr); +/* +* PARAMETERS +* p_pool +* [in] Pointer to an osm_mad_pool_t object. +* +* h_bind +* [in] Handle returned from osm_vendor_bind() call to the +* port for which this mad wrapper will be used. +* +* total_size +* [in] Total size, including MAD header of the MAD that will +* be attached to this wrapper. +* +* p_mad +* [in] Pointer to the MAD to attach to this wrapper. +* +* p_mad_addr +* [in] Pointer to the MAD address structure. This parameter +* may be NULL for directed route MADs. +* +* RETURN VALUES +* Returns a pointer to a MAD wrapper. +* A return value of NULL means no MAD wrappers are available. +* +* NOTES +* The MAD must eventually be returned to the pool with a call to +* osm_mad_pool_put. +* +* The osm_mad_pool_construct or osm_mad_pool_init must be called before +* using this function. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_put +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_get_wrapper_raw +* NAME +* osm_mad_pool_get_wrapper_raw +* +* DESCRIPTION +* Gets a only an uninitialized MAD wrapper from the pool (no wire MAD). +* +* SYNOPSIS +*/ +osm_madw_t *osm_mad_pool_get_wrapper_raw(IN osm_mad_pool_t * const p_pool); +/* +* PARAMETERS +* p_pool +* [in] Pointer to an osm_mad_pool_t object. +* +* RETURN VALUES +* Returns a pointer to a MAD wrapper. +* A return value of NULL means no MAD wrappers are available. +* +* NOTES +* The MAD must eventually be returned to the pool with a call to +* osm_mad_pool_put. +* +* The osm_mad_pool_construct or osm_mad_pool_init must be called before +* using this function. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_put +*********/ + +/****f* OpenSM: MAD Pool/osm_mad_pool_get_outstanding +* NAME +* osm_mad_pool_get_count +* +* DESCRIPTION +* Returns the running count of MADs currently outstanding from the pool. +* +* SYNOPSIS +*/ +static inline uint32_t +osm_mad_pool_get_outstanding(IN const osm_mad_pool_t * const p_pool) +{ + return (p_pool->mads_out); +} + +/* +* PARAMETERS +* p_pool +* [in] Pointer to an osm_mad_pool_t object. +* +* RETURN VALUES +* Returns the running count of MADs currently outstanding from the pool. +* +* NOTES +* The osm_mad_pool_construct or osm_mad_pool_init must be called before +* using this function. +* +* SEE ALSO +* MAD Pool, osm_mad_pool_get +*********/ + +END_C_DECLS +#endif /* _OSM_MAD_POOL_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_madw.h b/contrib/ofed/management/opensm/include/opensm/osm_madw.h new file mode 100644 index 000000000000..f47142d4fcab --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_madw.h @@ -0,0 +1,1115 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mad_wrapper_t. + * This object represents the context wrapper for OpenSM MAD processing. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_MADW_H_ +#define _OSM_MADW_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM: MAD Wrapper/osm_bind_info_t +* NAME +* osm_bind_info_t +* +* DESCRIPTION +* +* SYNOPSIS +*/ +typedef struct osm_bind_info { + ib_net64_t port_guid; + uint8_t mad_class; + uint8_t class_version; + boolean_t is_responder; + boolean_t is_trap_processor; + boolean_t is_report_processor; + uint32_t send_q_size; + uint32_t recv_q_size; +} osm_bind_info_t; +/* +* FIELDS +* portguid +* PortGuid of local port +* +* mad_class +* Mgmt Class ID +* +* class_version +* Mgmt Class version +* +* is_responder +* True if this is a GSI Agent +* +* is_trap_processor +* True if GSI Trap msgs are handled +* +* is_report_processor +* True if GSI Report msgs are handled +* +* send_q_size +* SendQueueSize +* +* recv_q_size +* Receive Queue Size +* +* SEE ALSO +*********/ + +/****h* OpenSM/MAD Wrapper +* NAME +* MAD Wrapper +* +* DESCRIPTION +* The MAD Wrapper object encapsulates the information needed by the +* OpenSM to manage individual MADs. The OpenSM allocates one MAD Wrapper +* per MAD. +* +* The MAD Wrapper is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: MAD Wrapper/osm_ni_context_t +* NAME +* osm_ni_context_t +* +* DESCRIPTION +* Context needed by recipient of NodeInfo attribute. +* +* SYNOPSIS +*/ +typedef struct osm_ni_context { + ib_net64_t node_guid; + uint8_t port_num; + ib_net64_t dup_node_guid; + uint8_t dup_port_num; + unsigned dup_count; +} osm_ni_context_t; +/* +* FIELDS +* p_node +* Pointer to the node thru which we got to this node. +* +* p_sw +* Pointer to the switch object (if any) of the switch +* thru which we got to this node. +* +* port_num +* Port number on the node or switch thru which we got +* to this node. +* +* SEE ALSO +*********/ + +/****s* OpenSM: MAD Wrapper/osm_pi_context_t +* NAME +* osm_pi_context_t +* +* DESCRIPTION +* Context needed by recipient of PortInfo attribute. +* +* SYNOPSIS +*/ +typedef struct osm_pi_context { + ib_net64_t node_guid; + ib_net64_t port_guid; + boolean_t set_method; + boolean_t light_sweep; + boolean_t active_transition; +} osm_pi_context_t; +/*********/ + +/****s* OpenSM: MAD Wrapper/osm_nd_context_t +* NAME +* osm_nd_context_t +* +* DESCRIPTION +* Context needed by recipient of NodeDescription attribute. +* +* SYNOPSIS +*/ +typedef struct osm_nd_context { + ib_net64_t node_guid; +} osm_nd_context_t; +/*********/ + +/****s* OpenSM: MAD Wrapper/osm_si_context_t +* NAME +* osm_si_context_t +* +* DESCRIPTION +* Context needed by recipient of SwitchInfo attribute. +* +* SYNOPSIS +*/ +typedef struct osm_si_context { + ib_net64_t node_guid; + boolean_t set_method; + boolean_t light_sweep; +} osm_si_context_t; +/*********/ + +/****s* OpenSM: MAD Wrapper/osm_lft_context_t +* NAME +* osm_lft_context_t +* +* DESCRIPTION +* Context needed by recipient of LinearForwardingTable attribute. +* +* SYNOPSIS +*/ +typedef struct osm_lft_context { + ib_net64_t node_guid; + boolean_t set_method; +} osm_lft_context_t; +/*********/ + +/****s* OpenSM: MAD Wrapper/osm_mft_context_t +* NAME +* osm_mft_context_t +* +* DESCRIPTION +* Context needed by recipient of MulticastForwardingTable attribute. +* +* SYNOPSIS +*/ +typedef struct osm_mft_context { + ib_net64_t node_guid; + boolean_t set_method; +} osm_mft_context_t; +/*********/ + +/****s* OpenSM: MAD Wrapper/osm_smi_context_t +* NAME +* osm_smi_context_t +* +* DESCRIPTION +* Context needed by recipient of SMInfo attribute. +* +* SYNOPSIS +*/ +typedef struct osm_smi_context { + ib_net64_t port_guid; + boolean_t set_method; + boolean_t light_sweep; +} osm_smi_context_t; +/*********/ + +/****s* OpenSM: MAD Wrapper/osm_pkey_context_t +* NAME +* osm_pkey_context_t +* +* DESCRIPTION +* Context needed by recipient of P_Key attribute. +* +* SYNOPSIS +*/ +typedef struct osm_pkey_context { + ib_net64_t node_guid; + ib_net64_t port_guid; + boolean_t set_method; +} osm_pkey_context_t; +/*********/ + +/****s* OpenSM: MAD Wrapper/osm_slvl_context_t +* NAME +* osm_slvl_context_t +* +* DESCRIPTION +* Context needed by recipient of PortInfo attribute. +* +* SYNOPSIS +*/ +typedef struct osm_slvl_context { + ib_net64_t node_guid; + ib_net64_t port_guid; + boolean_t set_method; +} osm_slvl_context_t; +/*********/ + +/****s* OpenSM: MAD Wrapper/osm_vla_context_t +* NAME +* osm_vla_context_t +* +* DESCRIPTION +* Context needed by recipient of VL Arb attribute. +* +* SYNOPSIS +*/ +typedef struct osm_vla_context { + ib_net64_t node_guid; + ib_net64_t port_guid; + boolean_t set_method; +} osm_vla_context_t; +/*********/ + +/****s* OpenSM: MAD Wrapper/osm_perfmgr_context_t +* DESCRIPTION +* Context for Performance manager queries +*/ +typedef struct osm_perfmgr_context { + uint64_t node_guid; + uint16_t port; + uint8_t mad_method; /* was this a get or a set */ +#if ENABLE_OSM_PERF_MGR_PROFILE + struct timeval query_start; +#endif +} osm_perfmgr_context_t; +/*********/ + +#ifndef OSM_VENDOR_INTF_OPENIB +/****s* OpenSM: MAD Wrapper/osm_arbitrary_context_t +* NAME +* osm_arbitrary_context_t +* +* DESCRIPTION +* Context needed by arbitrary recipient. +* +* SYNOPSIS +*/ +typedef struct osm_arbitrary_context { + void *context1; + void *context2; +} osm_arbitrary_context_t; +/*********/ +#endif + +/****s* OpenSM: MAD Wrapper/osm_madw_context_t +* NAME +* osm_madw_context_t +* +* DESCRIPTION +* Context needed by recipients of MAD responses. +* +* SYNOPSIS +*/ +typedef union _osm_madw_context { + osm_ni_context_t ni_context; + osm_pi_context_t pi_context; + osm_nd_context_t nd_context; + osm_si_context_t si_context; + osm_lft_context_t lft_context; + osm_mft_context_t mft_context; + osm_smi_context_t smi_context; + osm_slvl_context_t slvl_context; + osm_pkey_context_t pkey_context; + osm_vla_context_t vla_context; + osm_perfmgr_context_t perfmgr_context; +#ifndef OSM_VENDOR_INTF_OPENIB + osm_arbitrary_context_t arb_context; +#endif +} osm_madw_context_t; +/*********/ + +/****s* OpenSM: MAD Wrapper/osm_mad_addr_t +* NAME +* osm_mad_addr_t +* +* DESCRIPTION +* +* SYNOPSIS +*/ +typedef struct osm_mad_addr { + ib_net16_t dest_lid; + uint8_t path_bits; + uint8_t static_rate; + union addr_type { + struct _smi { + ib_net16_t source_lid; + uint8_t port_num; + } smi; + + struct _gsi { + ib_net32_t remote_qp; + ib_net32_t remote_qkey; + uint16_t pkey_ix; + uint8_t service_level; + boolean_t global_route; + ib_grh_t grh_info; + } gsi; + } addr_type; +} osm_mad_addr_t; +/* +* FIELDS +* +* SEE ALSO +*********/ + +/****s* OpenSM: MAD Wrapper/osm_madw_t +* NAME +* osm_madw_t +* +* DESCRIPTION +* Context needed for processing individual MADs +* +* SYNOPSIS +*/ +typedef struct osm_madw { + cl_list_item_t list_item; + osm_bind_handle_t h_bind; + osm_vend_wrap_t vend_wrap; + osm_mad_addr_t mad_addr; + osm_bind_info_t bind_info; + osm_madw_context_t context; + uint32_t mad_size; + ib_api_status_t status; + cl_disp_msgid_t fail_msg; + boolean_t resp_expected; + const ib_mad_t *p_mad; +} osm_madw_t; +/* +* FIELDS +* list_item +* List linkage for lists. MUST BE FIRST MEMBER! +* +* h_bind +* Bind handle for the port on which this MAD will be sent +* or was received. +* +* vend_wrap +* Transport vendor specific context. This structure is not +* used outside MAD transport vendor specific code. +* +* context +* Union of controller specific contexts needed for this MAD. +* This structure allows controllers to indirectly communicate +* with each other through the dispatcher. +* +* mad_size +* Size of this MAD in bytes. +* +* status +* Status of completed operation on the MAD. +* CL_SUCCESS if the operation was successful. +* +* fail_msg +* Dispatcher message with which to post this MAD on failure. +* This value is set by the originator of the MAD. +* If an operation on this MAD fails, for example due to a timeout, +* then the transport layer will dispose of the MAD by sending +* it through the Dispatcher with this message type. Presumably, +* there is a controller listening for the failure message that can +* properly clean up. +* +* resp_expected +* TRUE if a response is expected to this MAD. +* FALSE otherwise. +* +* p_mad +* Pointer to the wire MAD. The MAD itself cannot be part of the +* wrapper, since wire MADs typically reside in special memory +* registered with the local HCA. +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_init +* NAME +* osm_madw_init +* +* DESCRIPTION +* Initializes a MAD Wrapper object for use. +* +* SYNOPSIS +*/ +static inline void +osm_madw_init(IN osm_madw_t * const p_madw, + IN osm_bind_handle_t h_bind, + IN const uint32_t mad_size, + IN const osm_mad_addr_t * const p_mad_addr) +{ + memset(p_madw, 0, sizeof(*p_madw)); + p_madw->h_bind = h_bind; + p_madw->fail_msg = CL_DISP_MSGID_NONE; + p_madw->mad_size = mad_size; + if (p_mad_addr) + p_madw->mad_addr = *p_mad_addr; + p_madw->resp_expected = FALSE; +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object to initialize. +* +* h_bind +* [in] Pointer to the wire MAD. +* +* p_mad_addr +* [in] Pointer to the MAD address structure. This parameter may +* be NULL for directed route MADs. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_smp_ptr +* NAME +* osm_madw_get_smp_ptr +* +* DESCRIPTION +* Gets a pointer to the SMP in this MAD. +* +* SYNOPSIS +*/ +static inline ib_smp_t *osm_madw_get_smp_ptr(IN const osm_madw_t * const p_madw) +{ + return ((ib_smp_t *) p_madw->p_mad); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object to initialize. +* +* RETURN VALUES +* Pointer to the start of the SMP MAD. +* +* NOTES +* +* SEE ALSO +* MAD Wrapper object +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_sa_mad_ptr +* NAME +* osm_madw_get_sa_mad_ptr +* +* DESCRIPTION +* Gets a pointer to the SA MAD in this MAD wrapper. +* +* SYNOPSIS +*/ +static inline ib_sa_mad_t *osm_madw_get_sa_mad_ptr(IN const osm_madw_t * + const p_madw) +{ + return ((ib_sa_mad_t *) p_madw->p_mad); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the SA MAD. +* +* NOTES +* +* SEE ALSO +* MAD Wrapper object +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_perfmgt_mad_ptr +* DESCRIPTION +* Gets a pointer to the PerfMgt MAD in this MAD wrapper. +* +* SYNOPSIS +*/ +static inline ib_perfmgt_mad_t *osm_madw_get_perfmgt_mad_ptr(IN const osm_madw_t + * const p_madw) +{ + return ((ib_perfmgt_mad_t *) p_madw->p_mad); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the PerfMgt MAD. +* +* NOTES +* +* SEE ALSO +* MAD Wrapper object +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_ni_context_ptr +* NAME +* osm_madw_get_ni_context_ptr +* +* DESCRIPTION +* Gets a pointer to the NodeInfo context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_ni_context_t *osm_madw_get_ni_context_ptr(IN const osm_madw_t + * const p_madw) +{ + return ((osm_ni_context_t *) & p_madw->context); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_pi_context_ptr +* NAME +* osm_madw_get_pi_context_ptr +* +* DESCRIPTION +* Gets a pointer to the PortInfo context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_pi_context_t *osm_madw_get_pi_context_ptr(IN const osm_madw_t + * const p_madw) +{ + return ((osm_pi_context_t *) & p_madw->context); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_nd_context_ptr +* NAME +* osm_madw_get_nd_context_ptr +* +* DESCRIPTION +* Gets a pointer to the NodeDescription context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_nd_context_t *osm_madw_get_nd_context_ptr(IN const osm_madw_t + * const p_madw) +{ + return ((osm_nd_context_t *) & p_madw->context); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_lft_context_ptr +* NAME +* osm_madw_get_lft_context_ptr +* +* DESCRIPTION +* Gets a pointer to the LFT context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_lft_context_t *osm_madw_get_lft_context_ptr(IN const + osm_madw_t * + const p_madw) +{ + return ((osm_lft_context_t *) & p_madw->context); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_mft_context_ptr +* NAME +* osm_madw_get_mft_context_ptr +* +* DESCRIPTION +* Gets a pointer to the MFT context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_mft_context_t *osm_madw_get_mft_context_ptr(IN const + osm_madw_t * + const p_madw) +{ + return ((osm_mft_context_t *) & p_madw->context); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_si_context_ptr +* NAME +* osm_madw_get_si_context_ptr +* +* DESCRIPTION +* Gets a pointer to the SwitchInfo context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_si_context_t *osm_madw_get_si_context_ptr(IN const osm_madw_t + * const p_madw) +{ + return ((osm_si_context_t *) & p_madw->context); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_smi_context_ptr +* NAME +* osm_madw_get_smi_context_ptr +* +* DESCRIPTION +* Gets a pointer to the SMInfo context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_smi_context_t *osm_madw_get_smi_context_ptr(IN const + osm_madw_t * + const p_madw) +{ + return ((osm_smi_context_t *) & p_madw->context); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_pkey_context_ptr +* NAME +* osm_madw_get_pkey_context_ptr +* +* DESCRIPTION +* Gets a pointer to the P_Key context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_pkey_context_t *osm_madw_get_pkey_context_ptr(IN const + osm_madw_t * + const p_madw) +{ + return ((osm_pkey_context_t *) & p_madw->context); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_slvl_context_ptr +* NAME +* osm_madw_get_slvl_context_ptr +* +* DESCRIPTION +* Gets a pointer to the PortInfo context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_slvl_context_t *osm_madw_get_slvl_context_ptr(IN const + osm_madw_t * + const p_madw) +{ + return ((osm_slvl_context_t *) & p_madw->context); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_vla_context_ptr +* NAME +* osm_madw_get_vla_context_ptr +* +* DESCRIPTION +* Gets a pointer to the Vl Arb context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_vla_context_t *osm_madw_get_vla_context_ptr(IN const + osm_madw_t * + const p_madw) +{ + return ((osm_vla_context_t *) & p_madw->context); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ + +#ifndef OSM_VENDOR_INTF_OPENIB +/****f* OpenSM: MAD Wrapper/osm_madw_get_arbitrary_context_ptr +* NAME +* osm_madw_get_arbitrary_context_ptr +* +* DESCRIPTION +* Gets a pointer to the arbitrary context in this MAD. +* +* SYNOPSIS +*/ +static inline osm_arbitrary_context_t *osm_madw_get_arbitrary_context_ptr(IN + const + osm_madw_t + * + const + p_madw) +{ + return ((osm_arbitrary_context_t *) & p_madw->context); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Pointer to the start of the context structure. +* +* NOTES +* +* SEE ALSO +*********/ +#endif + +/****f* OpenSM: MAD Wrapper/osm_madw_get_vend_ptr +* NAME +* osm_madw_get_vend_ptr +* +* DESCRIPTION +* Gets a pointer to the vendor specific MAD wrapper component. +* +* SYNOPSIS +*/ +static inline osm_vend_wrap_t *osm_madw_get_vend_ptr(IN const osm_madw_t * + const p_madw) +{ + return ((osm_vend_wrap_t *) & p_madw->vend_wrap); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Gets a pointer to the vendor specific MAD wrapper component. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_vend_ptr +* NAME +* osm_madw_get_vend_ptr +* +* DESCRIPTION +* Returns the bind handle associated with this MAD. +* +* SYNOPSIS +*/ +static inline osm_bind_handle_t +osm_madw_get_bind_handle(IN const osm_madw_t * const p_madw) +{ + return ((osm_bind_handle_t) p_madw->h_bind); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Returns the bind handle associated with this MAD. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_mad_addr_ptr +* NAME +* osm_madw_get_mad_addr_ptr +* +* DESCRIPTION +* Returns the mad address structure associated with this MAD. +* +* SYNOPSIS +*/ +static inline osm_mad_addr_t *osm_madw_get_mad_addr_ptr(IN const osm_madw_t * + const p_madw) +{ + return ((osm_mad_addr_t *) & p_madw->mad_addr); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Returns the mad address structure associated with this MAD. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_mad_ptr +* NAME +* osm_madw_get_mad_ptr +* +* DESCRIPTION +* Returns the mad address structure associated with this MAD. +* +* SYNOPSIS +*/ +static inline ib_mad_t *osm_madw_get_mad_ptr(IN const osm_madw_t * const p_madw) +{ + return ((ib_mad_t *) p_madw->p_mad); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Returns the mad address structure associated with this MAD. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_get_err_msg +* NAME +* osm_madw_get_err_msg +* +* DESCRIPTION +* Returns the message with which to post this mad wrapper if +* an error occurs during processing the mad. +* +* SYNOPSIS +*/ +static inline cl_disp_msgid_t +osm_madw_get_err_msg(IN const osm_madw_t * const p_madw) +{ + return ((cl_disp_msgid_t) p_madw->fail_msg); +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* RETURN VALUES +* Returns the message with which to post this mad wrapper if +* an error occurs during processing the mad. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_set_mad +* NAME +* osm_madw_set_mad +* +* DESCRIPTION +* Associates a wire MAD with this MAD Wrapper object. +* +* SYNOPSIS +*/ +static inline void +osm_madw_set_mad(IN osm_madw_t * const p_madw, IN const ib_mad_t * const p_mad) +{ + p_madw->p_mad = p_mad; +} + +/* +* PARAMETERS +* p_madw +* [in] Pointer to an osm_madw_t object. +* +* p_mad +* [in] Pointer to the wire MAD to attach to this wrapper. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: MAD Wrapper/osm_madw_copy_context +* NAME +* osm_madw_copy_context +* +* DESCRIPTION +* Copies the controller context from one MAD Wrapper to another. +* +* SYNOPSIS +*/ +static inline void +osm_madw_copy_context(IN osm_madw_t * const p_dest, + IN const osm_madw_t * const p_src) +{ + p_dest->context = p_src->context; +} + +/* +* PARAMETERS +* p_dest +* [in] Pointer to the destination osm_madw_t object. +* +* p_src +* [in] Pointer to the source osm_madw_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_MADW_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_mcast_tbl.h b/contrib/ofed/management/opensm/include/opensm/osm_mcast_tbl.h new file mode 100644 index 000000000000..15b95cfb9772 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_mcast_tbl.h @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mcast_tbl_t. + * This object represents a multicast forwarding table. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_MCAST_TBL_H_ +#define _OSM_MCAST_TBL_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM: Forwarding Table/osm_mcast_tbl_t +* NAME +* osm_mcast_tbl_t +* +* DESCRIPTION +* Multicast Forwarding Table structure. +* +* Callers may directly access this object. +* +* SYNOPSIS +*/ +typedef struct osm_mcast_fwdbl { + uint8_t num_ports; + uint8_t max_position; + uint16_t max_block; + int16_t max_block_in_use; + uint16_t num_entries; + uint16_t max_mlid_ho; + uint16_t(*p_mask_tbl)[][IB_MCAST_POSITION_MAX]; +} osm_mcast_tbl_t; +/* +* FIELDS +* num_ports +* The number of ports in the port mask. This value +* is the same as the number of ports on the switch +* +* max_position +* Maximum bit mask position for this table. This value +* is computed from the number of ports on the switch. +* +* max_block +* Maximum block number supported in the table. This value +* is approximately the number of MLID entries divided by the +* number of MLIDs per block +* +* num_entries +* Number of entries in the table (aka number of MLIDs supported). +* +* max_mlid_ho +* Maximum MLID value (host order). +* +* pp_mask_tbl +* Pointer to a two dimensional array of port_masks for this switch. +* The first dimension is MLID, the second dimension is mask position. +* This pointer is null for switches that do not support multicast. +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_init +* NAME +* osm_mcast_tbl_init +* +* DESCRIPTION +* This function initializes a Multicast Forwarding Table object. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_mcast_tbl_init(IN osm_mcast_tbl_t * const p_tbl, + IN uint8_t const num_ports, IN uint16_t const capacity); +/* +* PARAMETERS +* num_ports +* [in] Number of ports in the switch owning this table. +* +* capacity +* [in] The number of MLID entries (starting at 0xC000) supported +* by this switch. +* +* RETURN VALUE +* IB_SUCCESS on success. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_delete +* NAME +* osm_mcast_tbl_delete +* +* DESCRIPTION +* This destroys and deallocates a Multicast Forwarding Table object. +* +* SYNOPSIS +*/ +void osm_mcast_tbl_delete(IN osm_mcast_tbl_t ** const pp_tbl); +/* +* PARAMETERS +* pp_tbl +* [in] Pointer a Pointer to the Multicast Forwarding Table object. +* +* RETURN VALUE +* On success, returns a pointer to a new Multicast Forwarding Table object +* of the specified size. +* NULL otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_destroy +* NAME +* osm_mcast_tbl_destroy +* +* DESCRIPTION +* This destroys and deallocates a Multicast Forwarding Table object. +* +* SYNOPSIS +*/ +void osm_mcast_tbl_destroy(IN osm_mcast_tbl_t * const p_tbl); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Multicast Forwarding Table object. +* +* RETURN VALUE +* None +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_set +* NAME +* osm_mcast_tbl_set +* +* DESCRIPTION +* Adds the port to the multicast group. +* +* SYNOPSIS +*/ +void +osm_mcast_tbl_set(IN osm_mcast_tbl_t * const p_tbl, + IN const uint16_t mlid_ho, IN const uint8_t port_num); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Multicast Forwarding Table object. +* +* mlid_ho +* [in] MLID value (host order) for which to set the route. +* +* port_num +* [in] Port to add to the multicast group. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_clear_mlid +* NAME +* osm_mcast_tbl_clear_mlid +* +* DESCRIPTION +* Removes all multicast paths for the specified MLID. +* +* SYNOPSIS +*/ +void +osm_mcast_tbl_clear_mlid(IN osm_mcast_tbl_t * const p_tbl, + IN const uint16_t mlid_ho); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Multicast Forwarding Table object. +* +* mlid_ho +* [in] MLID value (host order) for which to clear. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_is_port +* NAME +* osm_mcast_tbl_is_port +* +* DESCRIPTION +* Returns TRUE if the port is in the multicast group. +* +* SYNOPSIS +*/ +boolean_t +osm_mcast_tbl_is_port(IN const osm_mcast_tbl_t * const p_tbl, + IN const uint16_t mlid_ho, IN const uint8_t port_num); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Multicast Forwarding Table object. +* +* mlid_ho +* [in] MLID value (host order). +* +* port_num +* [in] Port number on the switch +* +* RETURN VALUE +* Returns the port that routes the specified LID. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_is_any_port +* NAME +* osm_mcast_tbl_is_any_port +* +* DESCRIPTION +* Returns TRUE if any port is in the multicast group. +* +* SYNOPSIS +*/ +boolean_t +osm_mcast_tbl_is_any_port(IN const osm_mcast_tbl_t * const p_tbl, + IN const uint16_t mlid_ho); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Multicast Forwarding Table object. +* +* mlid_ho +* [in] MLID value (host order). +* +* RETURN VALUE +* Returns TRUE if any port is in the multicast group. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_set_block +* NAME +* osm_mcast_tbl_set_block +* +* DESCRIPTION +* Copies the specified block into the Multicast Forwarding Table. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_mcast_tbl_set_block(IN osm_mcast_tbl_t * const p_tbl, + IN const ib_net16_t * const p_block, + IN const int16_t block_num, IN const uint8_t position); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to the Multicast Forwarding Table object. +* +* p_block +* [in] Pointer to the Forwarding Table block. +* +* block_num +* [in] Block number of this block. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_get_tbl_block +* NAME +* osm_mcast_get_tbl_block +* +* DESCRIPTION +* Retrieve a multicast forwarding table block. +* +* SYNOPSIS +*/ +boolean_t +osm_mcast_tbl_get_block(IN osm_mcast_tbl_t * const p_tbl, + IN const int16_t block_num, + IN const uint8_t position, + OUT ib_net16_t * const p_block); +/* +* PARAMETERS +* p_tbl +* [in] Pointer to an osm_mcast_tbl_t object. +* +* p_block +* [in] Pointer to the Forwarding Table block. +* +* block_num +* [in] Block number of this block. +* +* p_block +* [out] Pointer to the 32 entry array to store the +* forwarding table clock specified by block_id. +* +* RETURN VALUES +* Returns true if there are more blocks necessary to +* configure all the MLIDs reachable from this switch. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_get_max_block +* NAME +* osm_mcast_tbl_get_max_block +* +* DESCRIPTION +* Returns the maximum block ID in this table. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_mcast_tbl_get_max_block(IN osm_mcast_tbl_t * const p_tbl) +{ + return (p_tbl->max_block); +} + +/* +* PARAMETERS +* p_tbl +* [in] Pointer to an osm_mcast_tbl_t object. +* +* RETURN VALUES +* Returns the maximum block ID in this table. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_get_max_block_in_use +* NAME +* osm_mcast_tbl_get_max_block_in_use +* +* DESCRIPTION +* Returns the maximum block ID in use in this table. +* A value of -1 indicates no blocks are in use. +* +* SYNOPSIS +*/ +static inline int16_t +osm_mcast_tbl_get_max_block_in_use(IN osm_mcast_tbl_t * const p_tbl) +{ + return (p_tbl->max_block_in_use); +} + +/* +* PARAMETERS +* p_tbl +* [in] Pointer to an osm_mcast_tbl_t object. +* +* RETURN VALUES +* Returns the maximum block ID in use in this table. +* A value of -1 indicates no blocks are in use. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Forwarding Table/osm_mcast_tbl_get_max_position +* NAME +* osm_mcast_tbl_get_max_position +* +* DESCRIPTION +* Returns the maximum position in this table. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_mcast_tbl_get_max_position(IN osm_mcast_tbl_t * const p_tbl) +{ + return (p_tbl->max_position); +} + +/* +* PARAMETERS +* p_tbl +* [in] Pointer to an osm_mcast_tbl_t object. +* +* RETURN VALUES +* Returns the maximum position in this table. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_MCAST_TBL_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_mcm_info.h b/contrib/ofed/management/opensm/include/opensm/osm_mcm_info.h new file mode 100644 index 000000000000..dec607fe4d33 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_mcm_info.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mcm_info_t. + * This object represents a Multicast Forwarding Information object. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_MCM_INFO_H_ +#define _OSM_MCM_INFO_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM: Multicast Member Info/osm_mcm_info_t +* NAME +* osm_mcm_info_t +* +* DESCRIPTION +* Multicast Membership Info object. +* This object contains information about a node's membership +* in a particular multicast group. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_mcm_info { + cl_list_item_t list_item; + ib_net16_t mlid; +} osm_mcm_info_t; +/* +* FIELDS +* list_item +* Linkage structure for cl_qlist. MUST BE FIRST MEMBER! +* +* mlid +* MLID of this multicast group. +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Member Info/osm_mcm_info_new +* NAME +* osm_mcm_info_new +* +* DESCRIPTION +* Returns an initialized a Multicast Member Info object for use. +* +* SYNOPSIS +*/ +osm_mcm_info_t *osm_mcm_info_new(IN const ib_net16_t mlid); +/* +* PARAMETERS +* mlid +* [in] MLID value for this multicast group. +* +* RETURN VALUES +* Pointer to an initialized tree node. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Member Info/osm_mcm_info_delete +* NAME +* osm_mcm_info_delete +* +* DESCRIPTION +* Destroys and deallocates the specified object. +* +* SYNOPSIS +*/ +void osm_mcm_info_delete(IN osm_mcm_info_t * const p_mcm); +/* +* PARAMETERS +* p_mcm +* Pointer to the object to destroy. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_MCM_INFO_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_mcm_port.h b/contrib/ofed/management/opensm/include/opensm/osm_mcm_port.h new file mode 100644 index 000000000000..c2b18de5ed2b --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_mcm_port.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mcm_port_t. + * This object represents the membership of a port in a multicast group. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_MCM_PORT_H_ +#define _OSM_MCM_PORT_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM: MCM Port Object/osm_mcm_port_t +* NAME +* osm_mcm_port_t +* +* DESCRIPTION +* This object represents a particular port as a member of a +* multicast group. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_mcm_port { + cl_map_item_t map_item; + ib_gid_t port_gid; + uint8_t scope_state; + boolean_t proxy_join; +} osm_mcm_port_t; +/* +* FIELDS +* map_item +* Map Item for qmap linkage. Must be first element!! +* +* port_gid +* GID of the member port. +* +* scope_state +* ??? +* +* proxy_join +* If FALSE - Join was performed by the endport identified +* by PortGID. If TRUE - Join was performed on behalf of +* the endport identified by PortGID by another port within +* the same partition. +* +* SEE ALSO +* MCM Port Object +*********/ + +/****f* OpenSM: MCM Port Object/osm_mcm_port_new +* NAME +* osm_mcm_port_new +* +* DESCRIPTION +* The osm_mcm_port_new function allocates and initializes a +* MCM Port Object for use. +* +* SYNOPSIS +*/ +osm_mcm_port_t *osm_mcm_port_new(IN const ib_gid_t * const p_port_gid, + IN const uint8_t scope_state, + IN const boolean_t proxy_join); +/* +* PARAMETERS +* p_port_gid +* [in] Pointer to the GID of the port to add to the multicast group. +* +* scope_state +* [in] scope state of the join request +* +* proxy_join +* [in] proxy_join state analyzed from the request +* +* RETURN VALUES +* Pointer to the allocated and initialized MCM Port object. +* +* NOTES +* +* SEE ALSO +* MCM Port Object, osm_mcm_port_delete, +*********/ + +/****f* OpenSM: MCM Port Object/osm_mcm_port_delete +* NAME +* osm_mcm_port_delete +* +* DESCRIPTION +* The osm_mcm_port_delete function destroys and dellallocates an +* MCM Port Object, releasing all resources. +* +* SYNOPSIS +*/ +void osm_mcm_port_delete(IN osm_mcm_port_t * const p_mcm); +/* +* PARAMETERS +* p_mcm +* [in] Pointer to a MCM Port Object to delete. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +* MCM Port Object, osm_mcm_port_new +*********/ + +END_C_DECLS +#endif /* _OSM_MCM_PORT_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_msgdef.h b/contrib/ofed/management/opensm/include/opensm/osm_msgdef.h new file mode 100644 index 000000000000..dbf3e53cc3e4 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_msgdef.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of Dispatcher message values. + */ + +#ifndef _OSM_MSGDEF_H_ +#define _OSM_MSGDEF_H_ + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Dispatcher Messages +* NAME +* Dispatcher Messages +* +* DESCRIPTION +* These constants define the messages sent between OpenSM controllers +* attached to the Dispatcher. +* +* Each message description contains the following information: +* Sent by: which controller(s) send this message +* Received by: which controller receives this message +* Delivery notice: Indicates if the sender requires confirmation +* that the message has been delivered. Typically a "yes" here +* means that some resources associated with sending the +* message must be freed. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Dispatcher Messages/OSM_MSG_MAD_NODE_INFO +* NAME +* OSM_MSG_MAD_NODE_INFO +* +* DESCRIPTION +* Message for received NodeInfo MADs. +* +* NOTES +* Sent by: osm_mad_ctrl_t +* Received by: osm_ni_rcv_ctrl_t +* Delivery notice: yes +* +* +***********/ +/****s* OpenSM: Dispatcher Messages/OSM_MSG_MAD_PORT_INFO +* NAME +* OSM_MSG_MAD_PORT_INFO +* +* DESCRIPTION +* Message for received PortInfo MADs. +* +* NOTES +* Sent by: osm_mad_ctrl_t +* Received by: osm_pi_rcv_ctrl_t +* Delivery notice: yes +* +* +***********/ +/****s* OpenSM: Dispatcher Messages/OSM_MSG_MAD_SWITCH_INFO +* NAME +* OSM_MSG_MAD_SWITCH_INFO +* +* DESCRIPTION +* Message for received SwitchInfo MADs. +* +* NOTES +* Sent by: osm_mad_ctrl_t +* Received by: osm_si_rcv_ctrl_t +* Delivery notice: yes +* +***********/ +/****s* OpenSM: Dispatcher Messages/OSM_MSG_MAD_NODE_DESC +* NAME +* OSM_MSG_MAD_NODE_DESC +* +* DESCRIPTION +* Message for received NodeDescription MADs. +* +* NOTES +* Sent by: osm_mad_ctrl_t +* Received by: osm_nd_rcv_ctrl_t +* Delivery notice: yes +* +* SOURCE +***********/ +enum { + OSM_MSG_NONE = 0, + OSM_MSG_MAD_NODE_INFO, + OSM_MSG_MAD_PORT_INFO, + OSM_MSG_MAD_SWITCH_INFO, + OSM_MSG_MAD_NODE_DESC, + OSM_MSG_MAD_NODE_RECORD, + OSM_MSG_MAD_PORTINFO_RECORD, + OSM_MSG_MAD_SERVICE_RECORD, + OSM_MSG_MAD_PATH_RECORD, + OSM_MSG_MAD_MCMEMBER_RECORD, + OSM_MSG_MAD_LINK_RECORD, + OSM_MSG_MAD_SMINFO_RECORD, + OSM_MSG_MAD_CLASS_PORT_INFO, + OSM_MSG_MAD_INFORM_INFO, + OSM_MSG_MAD_LFT_RECORD, + OSM_MSG_MAD_LFT, + OSM_MSG_MAD_SM_INFO, + OSM_MSG_MAD_NOTICE, + OSM_MSG_LIGHT_SWEEP_FAIL, + OSM_MSG_MAD_MFT, + OSM_MSG_MAD_PKEY_TBL_RECORD, + OSM_MSG_MAD_VL_ARB_RECORD, + OSM_MSG_MAD_SLVL_TBL_RECORD, + OSM_MSG_MAD_PKEY, + OSM_MSG_MAD_VL_ARB, + OSM_MSG_MAD_SLVL, + OSM_MSG_MAD_GUIDINFO_RECORD, + OSM_MSG_MAD_INFORM_INFO_RECORD, + OSM_MSG_MAD_SWITCH_INFO_RECORD, + OSM_MSG_MAD_MFT_RECORD, +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + OSM_MSG_MAD_MULTIPATH_RECORD, +#endif + OSM_MSG_MAD_PORT_COUNTERS, + OSM_MSG_MAX +}; + +END_C_DECLS +#endif /* _OSM_MSGDEF_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_mtree.h b/contrib/ofed/management/opensm/include/opensm/osm_mtree.h new file mode 100644 index 000000000000..ef696dae82ae --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_mtree.h @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mtree_t. + * This object represents multicast spanning tree. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_MTREE_H_ +#define _OSM_MTREE_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#define OSM_MTREE_LEAF ((void*)-1) +/****h* OpenSM/Multicast Tree +* NAME +* Multicast Tree +* +* DESCRIPTION +* The Multicast Tree object encapsulates the information needed by the +* OpenSM to manage multicast fabric routes. It is a tree structure +* in which each node in the tree represents a switch, and may have a +* varying number of children. +* +* Multicast trees do not contain loops. +* +* The Multicast Tree is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Multicast Tree/osm_mtree_node_t +* NAME +* osm_mtree_node_t +* +* DESCRIPTION +* The MTree Node object encapsulates the information needed by the +* OpenSM for a particular switch in the multicast tree. +* +* The MTree Node object is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_mtree_node { + cl_map_item_t map_item; + osm_switch_t *p_sw; + uint8_t max_children; + struct osm_mtree_node *p_up; + struct osm_mtree_node *child_array[1]; +} osm_mtree_node_t; +/* +* FIELDS +* map_item +* Linkage for quick map. MUST BE FIRST ELEMENT!!! +* +* p_sw +* Pointer to the switch represented by this tree node. +* +* max_children +* Maximum number of child nodes of this node. Equal to the +* the number of ports on the switch if the switch supports +* multicast. Equal to 1 (default route) if the switch does +* not support multicast. +* +* p_up +* Pointer to the parent of this node. If this pointer is +* NULL, the node is at the root of the tree. +* +* child_array +* Array (indexed by port number) of pointers to the +* child osm_mtree_node_t objects of this tree node, if any. +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Tree/osm_mtree_node_new +* NAME +* osm_mtree_node_new +* +* DESCRIPTION +* Returns an initialized a Multicast Tree object for use. +* +* SYNOPSIS +*/ +osm_mtree_node_t *osm_mtree_node_new(IN const osm_switch_t * const p_sw); +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch represented by this node. +* +* RETURN VALUES +* Pointer to an initialized tree node. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Tree/osm_mtree_destroy +* NAME +* osm_mtree_destroy +* +* DESCRIPTION +* Destroys a Multicast Tree object given by the p_mtn +* +* SYNOPSIS +*/ +void osm_mtree_destroy(IN osm_mtree_node_t * p_mtn); +/* +* PARAMETERS +* p_mtn +* [in] Pointer to an osm_mtree_node_t object to destroy. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Tree/osm_mtree_node_get_max_children +* NAME +* osm_mtree_node_get_max_children +* +* DESCRIPTION +* Returns the number maximum number of children of this node. +* The return value is 1 greater than the highest valid port +* number on the switch. +* +* +* SYNOPSIS +*/ +static inline uint8_t +osm_mtree_node_get_max_children(IN const osm_mtree_node_t * const p_mtn) +{ + return (p_mtn->max_children); +} +/* +* PARAMETERS +* p_mtn +* [in] Pointer to the multicast tree node. +* +* RETURN VALUES +* See description. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Tree/osm_mtree_node_get_child +* NAME +* osm_mtree_node_get_child +* +* DESCRIPTION +* Returns the specified child node of this node. +* +* SYNOPSIS +*/ +static inline osm_mtree_node_t *osm_mtree_node_get_child(IN const + osm_mtree_node_t * + const p_mtn, + IN const uint8_t child) +{ + CL_ASSERT(child < p_mtn->max_children); + return (p_mtn->child_array[child]); +} +/* +* PARAMETERS +* p_mtn +* [in] Pointer to the multicast tree node. +* +* child +* [in] Index of the child to retrieve. +* +* RETURN VALUES +* Returns the specified child node of this node. +* +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Tree/osm_mtree_node_get_switch_ptr +* NAME +* osm_mtree_node_get_switch_ptr +* +* DESCRIPTION +* Returns a pointer to the switch object represented by this tree node. +* +* SYNOPSIS +*/ +static inline osm_switch_t *osm_mtree_node_get_switch_ptr(IN const + osm_mtree_node_t * + const p_mtn) +{ + return (p_mtn->p_sw); +} +/* +* PARAMETERS +* p_mtn +* [in] Pointer to the multicast tree node. +* +* child +* [in] Index of the child to retrieve. +* +* RETURN VALUES +* Returns a pointer to the switch object represented by this tree node. +* +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_MTREE_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_multicast.h b/contrib/ofed/management/opensm/include/opensm/osm_multicast.h new file mode 100644 index 000000000000..bd219d12a2f6 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_multicast.h @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mgrp_t. + * This object represents an IBA Multicast Group. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_MULTICAST_H_ +#define _OSM_MULTICAST_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Multicast Group +* NAME +* Multicast Group +* +* DESCRIPTION +* The Multicast Group encapsulates the information needed by the +* OpenSM to manage Multicast Groups. The OpenSM allocates one +* Multicast Group object per Multicast Group in the IBA subnet. +* +* The Multicast Group is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Multicast Group/osm_mcast_mgr_ctxt_t +* NAME +* osm_mcast_mgr_ctxt_t +* +* DESCRIPTION +* Struct for passing context arguments to the multicast manager. +* +* The osm_mcast_mgr_ctxt_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_mcast_mgr_ctxt { + cl_list_item_t list_item; + ib_net16_t mlid; + osm_mcast_req_type_t req_type; + ib_net64_t port_guid; +} osm_mcast_mgr_ctxt_t; +/* +* FIELDS +* +* mlid +* The network ordered LID of this Multicast Group +* (must be >= 0xC000). +* +* req_type +* The type of the request that caused this call +* (multicast create/join/leave). +* +* port_guid +* The port guid of the port that is being added/removed from +* the multicast group due to this call. +* +* SEE ALSO +*********/ + +/****s* OpenSM: Multicast Group/osm_mgrp_t +* NAME +* osm_mgrp_t +* +* DESCRIPTION +* Multicast Group structure. +* +* The osm_mgrp_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_mgrp { + cl_map_item_t map_item; + ib_net16_t mlid; + osm_mtree_node_t *p_root; + cl_qmap_t mcm_port_tbl; + ib_member_rec_t mcmember_rec; + boolean_t well_known; + boolean_t to_be_deleted; + uint32_t last_change_id; + uint32_t last_tree_id; + unsigned full_members; +} osm_mgrp_t; +/* +* FIELDS +* map_item +* Map Item for qmap linkage. Must be first element!! +* +* mlid +* The network ordered LID of this Multicast Group (must be +* >= 0xC000). +* +* p_root +* Pointer to the root "tree node" in the single spanning tree +* for this multicast group. The nodes of the tree represent +* switches. Member ports are not represented in the tree. +* +* mcm_port_tbl +* Table (sorted by port GUID) of osm_mcm_port_t objects +* representing the member ports of this multicast group. +* +* mcmember_rec +* Holds the parameters of the Multicast Group. +* +* well_known +* Indicates that this is the wellknown multicast group which +* is created during the initialization of SM/SA and will be +* present even if there are no ports for this group +* +* to_be_deleted +* Since groups are deleted only after re-route we need to +* track the fact the group is about to be deleted so we can +* track the fact a new join is actually a create request. +* +* last_change_id +* a counter for the number of changes applied to the group. +* This counter shuold be incremented on any modification +* to the group: joining or leaving of ports. +* +* last_tree_id +* the last change id used for building the current tree. +* +* SEE ALSO +*********/ + +/****f* OpenSM: Vendor API/osm_mgrp_func_t +* NAME +* osm_mgrp_func_t +* +* DESCRIPTION +* Callback for the osm_mgrp_apply_func function. +* The callback function must not modify the tree linkage. +* +* SYNOPSIS +*/ +typedef void (*osm_mgrp_func_t) (IN const osm_mgrp_t * const p_mgrp, + IN const osm_mtree_node_t * const p_mtn, + IN void *context); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to the multicast group object. +* +* p_mtn +* [in] Pointer to the multicast tree node. +* +* context +* [in] User context. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_new +* NAME +* osm_mgrp_new +* +* DESCRIPTION +* Allocates and initializes a Multicast Group for use. +* +* SYNOPSIS +*/ +osm_mgrp_t *osm_mgrp_new(IN const ib_net16_t mlid); +/* +* PARAMETERS +* mlid +* [in] Multicast LID for this multicast group. +* +* RETURN VALUES +* IB_SUCCESS if initialization was successful. +* +* NOTES +* Allows calling other Multicast Group methods. +* +* SEE ALSO +* Multicast Group, osm_mgrp_delete +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_delete +* NAME +* osm_mgrp_delete +* +* DESCRIPTION +* Destroys and deallocates a Multicast Group. +* +* SYNOPSIS +*/ +void osm_mgrp_delete(IN osm_mgrp_t * const p_mgrp); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Multicast Group, osm_mgrp_new +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_is_guid +* NAME +* osm_mgrp_is_guid +* +* DESCRIPTION +* Indicates if the specified port GUID is a member of the Multicast Group. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_mgrp_is_guid(IN const osm_mgrp_t * const p_mgrp, + IN const ib_net64_t port_guid) +{ + return (cl_qmap_get(&p_mgrp->mcm_port_tbl, port_guid) != + cl_qmap_end(&p_mgrp->mcm_port_tbl)); +} + +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* port_guid +* [in] Port GUID. +* +* RETURN VALUES +* TRUE if the port GUID is a member of the group, +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Multicast Group +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_is_empty +* NAME +* osm_mgrp_is_empty +* +* DESCRIPTION +* Indicates if the multicast group has any member ports. +* +* SYNOPSIS +*/ +static inline boolean_t osm_mgrp_is_empty(IN const osm_mgrp_t * const p_mgrp) +{ + return (cl_qmap_count(&p_mgrp->mcm_port_tbl) == 0); +} + +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* RETURN VALUES +* TRUE if there are no ports in the multicast group. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Multicast Group +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_get_mlid +* NAME +* osm_mgrp_get_mlid +* +* DESCRIPTION +* The osm_mgrp_get_mlid function returns the multicast LID of this group. +* +* SYNOPSIS +*/ +static inline ib_net16_t osm_mgrp_get_mlid(IN const osm_mgrp_t * const p_mgrp) +{ + return (p_mgrp->mlid); +} + +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* RETURN VALUES +* MLID of the Multicast Group. +* +* NOTES +* +* SEE ALSO +* Multicast Group +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_add_port +* NAME +* osm_mgrp_add_port +* +* DESCRIPTION +* Adds a port to the multicast group. +* +* SYNOPSIS +*/ +osm_mcm_port_t *osm_mgrp_add_port(osm_subn_t *subn, osm_log_t *log, + IN osm_mgrp_t * const p_mgrp, + IN const ib_gid_t * const p_port_gid, + IN const uint8_t join_state, + IN boolean_t proxy_join); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object to initialize. +* +* p_port_gid +* [in] Pointer to the GID of the port to add to the multicast group. +* +* join_state +* [in] The join state for this port in the group. +* +* RETURN VALUES +* IB_SUCCESS +* IB_INSUFFICIENT_MEMORY +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_is_port_present +* NAME +* osm_mgrp_is_port_present +* +* DESCRIPTION +* checks a port from the multicast group. +* +* SYNOPSIS +*/ + +boolean_t +osm_mgrp_is_port_present(IN const osm_mgrp_t * const p_mgrp, + IN const ib_net64_t port_guid, + OUT osm_mcm_port_t ** const pp_mcm_port); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* port_guid +* [in] Port guid of the departing port. +* +* pp_mcm_port +* [out] Pointer to a pointer to osm_mcm_port_t +* Updated to the member on success or NULLed +* +* RETURN VALUES +* TRUE if port present +* FALSE if port is not present. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Multicast Group/osm_mgrp_remove_port +* NAME +* osm_mgrp_remove_port +* +* DESCRIPTION +* Removes a port from the multicast group. +* +* SYNOPSIS +*/ +void +osm_mgrp_delete_port(IN osm_subn_t * const p_subn, + IN osm_log_t * const p_log, + IN osm_mgrp_t * const p_mgrp, + IN const ib_net64_t port_guid); +/* +* PARAMETERS +* +* p_subn +* [in] Pointer to the subnet object +* +* p_log +* [in] The log object pointer +* +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* port_guid +* [in] Port guid of the departing port. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +int osm_mgrp_remove_port(osm_subn_t *subn, osm_log_t *log, osm_mgrp_t *mgrp, + osm_mcm_port_t *mcm, uint8_t join_state); + +/****f* OpenSM: Multicast Group/osm_mgrp_apply_func +* NAME +* osm_mgrp_apply_func +* +* DESCRIPTION +* Calls the specified function for each element in the tree. +* Elements are passed to the callback function in no particular order. +* +* SYNOPSIS +*/ +void +osm_mgrp_apply_func(const osm_mgrp_t * const p_mgrp, + osm_mgrp_func_t p_func, void *context); +/* +* PARAMETERS +* p_mgrp +* [in] Pointer to an osm_mgrp_t object. +* +* p_func +* [in] Pointer to the users callback function. +* +* context +* [in] User context passed to the callback function. +* +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Multicast Group +*********/ + +END_C_DECLS +#endif /* _OSM_MULTICAST_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_node.h b/contrib/ofed/management/opensm/include/opensm/osm_node.h new file mode 100644 index 000000000000..50b3598ad8c9 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_node.h @@ -0,0 +1,679 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_node_t. + * This object represents an IBA node. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_NODE_H_ +#define _OSM_NODE_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +struct osm_switch; + +/****h* OpenSM/Node +* NAME +* Node +* +* DESCRIPTION +* The Node object encapsulates the information needed by the +* OpenSM to manage nodes. The OpenSM allocates one Node object +* per node in the IBA subnet. +* +* The Node object is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Node/osm_node_t +* NAME +* osm_node_t +* +* DESCRIPTION +* Node structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_node { + cl_map_item_t map_item; + struct osm_switch *sw; + ib_node_info_t node_info; + ib_node_desc_t node_desc; + uint32_t discovery_count; + uint32_t physp_tbl_size; + char *print_desc; + osm_physp_t physp_table[1]; +} osm_node_t; +/* +* FIELDS +* map_item +* Linkage structure for cl_qmap. MUST BE FIRST MEMBER! +* +* sw +* For switch node contains pointer to appropriate osm_switch +* structure. NULL for non-switch nodes. Can be used for fast +* access to switch object and for simple node type detection +* +* node_info +* The IBA defined NodeInfo data for this node. +* +* node_desc +* The IBA defined NodeDescription data for this node. +* +* discovery_count +* The number of times this node has been discovered +* during the current fabric sweep. This number is reset +* to zero at the start of a sweep. +* +* phsyp_tbl_size +* The size of the physp_table array. This value is one greater +* than the number of ports in the node, since port numbers +* start with 1 for some bizzare reason. +* +* print_desc +* A printable version of the node description. +* +* phsyp_table +* Array of physical port objects belonging to this node. +* Index is contiguous by local port number. +* For switches, port 0 is the always the management port (14.2.5.6). +* MUST BE LAST MEMBER! - Since it grows !!!! +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_delete +* NAME +* osm_node_delete +* +* DESCRIPTION +* The osm_node_delete function destroys a node, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_node_delete(IN OUT osm_node_t ** const p_node); +/* +* PARAMETERS +* p_node +* [in][out] Pointer to a Pointer a Node object to destroy. +* On return, the pointer to set to NULL. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified Node object. +* This function should only be called after a call to osm_node_new. +* +* SEE ALSO +* Node object, osm_node_new +*********/ + +/****f* OpenSM: Node/osm_node_new +* NAME +* osm_node_new +* +* DESCRIPTION +* The osm_node_new function initializes a Node object for use. +* +* SYNOPSIS +*/ +osm_node_t *osm_node_new(IN const osm_madw_t * const p_madw); +/* +* PARAMETERS +* p_madw +* [in] Pointer to a osm_madw_t object containing a mad with +* the node's NodeInfo attribute. The caller may discard the +* osm_madw_t structure after calling osm_node_new. +* +* RETURN VALUES +* On success, a pointer to the new initialized osm_node_t structure. +* NULL otherwise. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_physp_ptr +* NAME +* osm_node_get_physp_ptr +* +* DESCRIPTION +* Returns a pointer to the physical port object at the +* specified local port number. +* +* SYNOPSIS +*/ +static inline osm_physp_t *osm_node_get_physp_ptr(IN osm_node_t * const p_node, + IN const uint32_t port_num) +{ + + CL_ASSERT(port_num < p_node->physp_tbl_size); + return osm_physp_is_valid(&p_node->physp_table[port_num]) ? + &p_node->physp_table[port_num] : NULL; +} + +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Local port number. +* +* RETURN VALUES +* Returns a pointer to the physical port object at the +* specified local port number. +* A return value of zero means the port number was out of range. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_type +* NAME +* osm_node_get_type +* +* DESCRIPTION +* Returns the type of this node. +* +* SYNOPSIS +*/ +static inline uint8_t osm_node_get_type(IN const osm_node_t * const p_node) +{ + return (p_node->node_info.node_type); +} + +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* RETURN VALUES +* Returns the IBA defined type of this node. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_num_physp +* NAME +* osm_node_get_num_physp +* +* DESCRIPTION +* Returns the type of this node. +* +* SYNOPSIS +*/ +static inline uint8_t osm_node_get_num_physp(IN const osm_node_t * const p_node) +{ + return ((uint8_t) p_node->physp_tbl_size); +} + +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* RETURN VALUES +* Returns the IBA defined type of this node. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_remote_node +* NAME +* osm_node_get_remote_node +* +* DESCRIPTION +* Returns a pointer to the node on the other end of the +* specified port. +* Returns NULL if no remote node exists. +* +* SYNOPSIS +*/ +osm_node_t *osm_node_get_remote_node(IN osm_node_t * const p_node, + IN const uint8_t port_num, + OUT uint8_t * p_remote_port_num); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Port number in p_node through which to get the remote node. +* +* p_remote_port_num +* [out] Port number in the remote's node through which this +* link exists. The caller may specify NULL for this pointer +* if the port number isn't needed. +* +* RETURN VALUES +* Returns a pointer to the node on the other end of the +* specified port. +* Returns NULL if no remote node exists. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_base_lid +* NAME +* osm_node_get_base_lid +* +* DESCRIPTION +* Returns the LID value of the specified port on this node. +* +* SYNOPSIS +*/ +static inline ib_net16_t +osm_node_get_base_lid(IN const osm_node_t * const p_node, + IN const uint32_t port_num) +{ + CL_ASSERT(port_num < p_node->physp_tbl_size); + return (osm_physp_get_base_lid(&p_node->physp_table[port_num])); +} + +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Local port number. +* +* RETURN VALUES +* Returns a pointer to the physical port object at the +* specified local port number. +* A return value of zero means the port number was out of range. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_remote_base_lid +* NAME +* osm_node_get_remote_base_lid +* +* DESCRIPTION +* Returns the base LID value of the port on the other side +* of the wire from the specified port on this node. +* +* SYNOPSIS +*/ +ib_net16_t +osm_node_get_remote_base_lid(IN osm_node_t * const p_node, + IN const uint32_t port_num); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Local port number. +* +* RETURN VALUES +* Returns a pointer to the physical port object at the +* specified local port number. +* A return value of zero means the port number was out of range. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_get_lmc +* NAME +* osm_node_get_lmc +* +* DESCRIPTION +* Returns the LMC value of the specified port on this node. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_node_get_lmc(IN const osm_node_t * const p_node, IN const uint32_t port_num) +{ + CL_ASSERT(port_num < p_node->physp_tbl_size); + return (osm_physp_get_lmc(&p_node->physp_table[port_num])); +} + +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Local port number. +* +* RETURN VALUES +* Returns the LMC value of the specified port on this node. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_init_physp +* NAME +* osm_node_init_physp +* +* DESCRIPTION +* Initializes a physical port for the given node. +* +* SYNOPSIS +*/ +void +osm_node_init_physp(IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* p_madw +* [in] Pointer to a osm_madw_t object containing a mad with +* the node's NodeInfo attribute as discovered through the +* Physical Port to add to the node. The caller may discard the +* osm_madw_t structure after calling osm_node_new. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Node object, Physical Port object. +*********/ + +/****f* OpenSM: Node/osm_node_get_node_guid +* NAME +* osm_node_get_node_guid +* +* DESCRIPTION +* Returns the node GUID of this node. +* +* SYNOPSIS +*/ +static inline ib_net64_t +osm_node_get_node_guid(IN const osm_node_t * const p_node) +{ + return (p_node->node_info.node_guid); +} + +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* RETURN VALUES +* Returns the node GUID of this node. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_link +* NAME +* osm_node_link +* +* DESCRIPTION +* Logically connects a node to another node through the specified port. +* +* SYNOPSIS +*/ +void +osm_node_link(IN osm_node_t * const p_node, + IN const uint8_t port_num, + IN osm_node_t * const p_remote_node, + IN const uint8_t remote_port_num); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Port number in p_node through which to create the link. +* +* p_remote_node +* [in] Pointer to the remote port object. +* +* remote_port_num +* [in] Port number in the remote's node through which to +* create this link. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_unlink +* NAME +* osm_node_unlink +* +* DESCRIPTION +* Logically disconnects a node from another node through +* the specified port. +* +* SYNOPSIS +*/ +void +osm_node_unlink(IN osm_node_t * const p_node, + IN const uint8_t port_num, + IN osm_node_t * const p_remote_node, + IN const uint8_t remote_port_num); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Port number in p_node through which to unlink. +* +* p_remote_node +* [in] Pointer to the remote port object. +* +* remote_port_num +* [in] Port number in the remote's node through which to unlink. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_link_exists +* NAME +* osm_node_link_exists +* +* DESCRIPTION +* Return TRUE if a link exists between the specified nodes on +* the specified ports. +* Returns FALSE otherwise. +* +* SYNOPSIS +*/ +boolean_t +osm_node_link_exists(IN osm_node_t * const p_node, + IN const uint8_t port_num, + IN osm_node_t * const p_remote_node, + IN const uint8_t remote_port_num); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Port number in p_node through which to check the link. +* +* p_remote_node +* [in] Pointer to the remote port object. +* +* remote_port_num +* [in] Port number in the remote's node through which to +* check this link. +* +* RETURN VALUES +* Return TRUE if a link exists between the specified nodes on +* the specified ports. +* Returns FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_has_any_link +* NAME +* osm_node_has_any_link +* +* DESCRIPTION +* Return TRUE if a any link exists from the specified nodes on +* the specified port. +* Returns FALSE otherwise. +* +* SYNOPSIS +*/ +boolean_t +osm_node_has_any_link(IN osm_node_t * const p_node, IN const uint8_t port_num); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Port number in p_node through which to check the link. +* +* RETURN VALUES +* Return TRUE if a any link exists from the specified nodes on +* the specified port. +* Returns FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +/****f* OpenSM: Node/osm_node_link_has_valid_ports +* NAME +* osm_node_link_has_valid_ports +* +* DESCRIPTION +* Return TRUE if both ports in the link are valid (initialized). +* Returns FALSE otherwise. +* +* SYNOPSIS +*/ +boolean_t +osm_node_link_has_valid_ports(IN osm_node_t * const p_node, + IN const uint8_t port_num, + IN osm_node_t * const p_remote_node, + IN const uint8_t remote_port_num); +/* +* PARAMETERS +* p_node +* [in] Pointer to an osm_node_t object. +* +* port_num +* [in] Port number in p_node through which to check the link. +* +* RETURN VALUES +* Return TRUE if both ports in the link are valid (initialized). +* Returns FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Node object +*********/ + +END_C_DECLS +#endif /* _OSM_NODE_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_opensm.h b/contrib/ofed/management/opensm/include/opensm/osm_opensm.h new file mode 100644 index 000000000000..c121be49bc43 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_opensm.h @@ -0,0 +1,527 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_opensm_t. + * This object represents the OpenSM super object. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_OPENSM_H_ +#define _OSM_OPENSM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/OpenSM +* NAME +* OpenSM +* +* DESCRIPTION +* The OpenSM object encapsulates the information needed by the +* OpenSM to govern itself. The OpenSM is one OpenSM object. +* +* The OpenSM object is thread safe. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****d* OpenSM: OpenSM/osm_routing_engine_type_t +* NAME +* osm_routing_engine_type_t +* +* DESCRIPTION +* Enumerates the possible routing engines that +* could be used to route a subnet. +* +* SYNOPSIS +*/ +typedef enum _osm_routing_engine_type { + OSM_ROUTING_ENGINE_TYPE_NONE = 0, + OSM_ROUTING_ENGINE_TYPE_MINHOP, + OSM_ROUTING_ENGINE_TYPE_UPDN, + OSM_ROUTING_ENGINE_TYPE_FILE, + OSM_ROUTING_ENGINE_TYPE_FTREE, + OSM_ROUTING_ENGINE_TYPE_LASH, + OSM_ROUTING_ENGINE_TYPE_DOR, + OSM_ROUTING_ENGINE_TYPE_UNKNOWN +} osm_routing_engine_type_t; +/***********/ + +/****s* OpenSM: OpenSM/osm_routing_engine +* NAME +* struct osm_routing_engine +* +* DESCRIPTION +* OpenSM routing engine module definition. +* NOTES +* routing engine structure - multicast callbacks may be +* added later. +*/ +struct osm_routing_engine { + const char *name; + void *context; + int (*build_lid_matrices) (void *context); + int (*ucast_build_fwd_tables) (void *context); + void (*ucast_dump_tables) (void *context); + void (*delete) (void *context); + struct osm_routing_engine *next; +}; +/* +* FIELDS +* name +* The routing engine name (will be used in logs). +* +* context +* The routing engine context. Will be passed as parameter +* to the callback functions. +* +* build_lid_matrices +* The callback for lid matrices generation. +* +* ucast_build_fwd_tables +* The callback for unicast forwarding table generation. +* +* ucast_dump_tables +* The callback for dumping unicast routing tables. +* +* delete +* The delete method, may be used for routing engine +* internals cleanup. +* +* next +* Pointer to next routing engine in the list. +*/ + +/****s* OpenSM: OpenSM/osm_opensm_t +* NAME +* osm_opensm_t +* +* DESCRIPTION +* OpenSM structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_opensm { + const char *osm_version; + osm_subn_t subn; + osm_sm_t sm; + osm_sa_t sa; +#ifdef ENABLE_OSM_PERF_MGR + osm_perfmgr_t perfmgr; +#endif /* ENABLE_OSM_PERF_MGR */ + cl_qlist_t plugin_list; + osm_db_t db; + osm_mad_pool_t mad_pool; + osm_vendor_t *p_vendor; + osm_vl15_t vl15; + osm_log_t log; + cl_dispatcher_t disp; + cl_plock_t lock; + struct osm_routing_engine *routing_engine_list; + osm_routing_engine_type_t routing_engine_used; + osm_stats_t stats; + osm_console_t console; + nn_map_t *node_name_map; +} osm_opensm_t; +/* +* FIELDS +* osm_version +* OpenSM version (as generated in osm_version.h) +* +* subn +* Subnet object for this subnet. +* +* sm +* The Subnet Manager (SM) object for this subnet. +* +* sa +* The Subnet Administration (SA) object for this subnet. +* +* db +* Persistant storage of some data required between sessions. +* +* mad_pool +* Pool of Management Datagram (MAD) objects. +* +* p_vendor +* Pointer to the Vendor specific adapter for various +* transport interfaces, such as UMADT, AL, etc. The +* particular interface is set at compile time. +* +* vl15 +* The VL15 interface. +* +* log +* Log facility used by all OpenSM components. +* +* disp +* Central dispatcher containing the OpenSM worker threads. +* +* lock +* Shared lock guarding most OpenSM structures. +* +* routing_engine_list +* List of routing engines that should be tried for use. +* +* routing_engine_used +* Indicates which routing engine was used to route a subnet. +* +* stats +* Open SM statistics block +* +* SEE ALSO +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_construct +* NAME +* osm_opensm_construct +* +* DESCRIPTION +* This function constructs an OpenSM object. +* +* SYNOPSIS +*/ +void osm_opensm_construct(IN osm_opensm_t * const p_osm); +/* +* PARAMETERS +* p_osm +* [in] Pointer to a OpenSM object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_opensm_init, osm_opensm_destroy +* +* Calling osm_opensm_construct is a prerequisite to calling any other +* method except osm_opensm_init. +* +* SEE ALSO +* SM object, osm_opensm_init, osm_opensm_destroy +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_destroy +* NAME +* osm_opensm_destroy +* +* DESCRIPTION +* The osm_opensm_destroy function destroys an SM, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_opensm_destroy(IN osm_opensm_t * const p_osm); +/* +* PARAMETERS +* p_osm +* [in] Pointer to a OpenSM object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified OpenSM object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_opensm_construct or +* osm_opensm_init. +* +* SEE ALSO +* SM object, osm_opensm_construct, osm_opensm_init +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_init +* NAME +* osm_opensm_init +* +* DESCRIPTION +* The osm_opensm_init function initializes a OpenSM object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_opensm_init(IN osm_opensm_t * const p_osm, + IN const osm_subn_opt_t * const p_opt); +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object to initialize. +* +* p_opt +* [in] Pointer to the subnet options structure. +* +* RETURN VALUES +* IB_SUCCESS if the OpenSM object was initialized successfully. +* +* NOTES +* Allows calling other OpenSM methods. +* +* SEE ALSO +* SM object, osm_opensm_construct, osm_opensm_destroy +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_sweep +* NAME +* osm_opensm_sweep +* +* DESCRIPTION +* Initiates a subnet sweep. +* +* SYNOPSIS +*/ +static inline void osm_opensm_sweep(IN osm_opensm_t * const p_osm) +{ + osm_sm_sweep(&p_osm->sm); +} + +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object on which to +* initiate a sweep. +* +* RETURN VALUES +* None +* +* NOTES +* If the OpenSM object is not bound to a port, this function +* does nothing. +* +* SEE ALSO +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_set_log_flags +* NAME +* osm_opensm_set_log_flags +* +* DESCRIPTION +* Sets the log level. +* +* SYNOPSIS +*/ +static inline void +osm_opensm_set_log_flags(IN osm_opensm_t * const p_osm, + IN const osm_log_level_t log_flags) +{ + osm_log_set_level(&p_osm->log, log_flags); +} + +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object. +* +* log_flags +* [in] Log level flags to set. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_bind +* NAME +* osm_opensm_bind +* +* DESCRIPTION +* Binds the opensm object to a port guid. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_opensm_bind(IN osm_opensm_t * const p_osm, IN const ib_net64_t guid); +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object to bind. +* +* guid +* [in] Local port GUID with which to bind. +* +* RETURN VALUES +* None +* +* NOTES +* A given opensm object can only be bound to one port at a time. +* +* SEE ALSO +*********/ + +/****f* OpenSM: OpenSM/osm_opensm_wait_for_subnet_up +* NAME +* osm_opensm_wait_for_subnet_up +* +* DESCRIPTION +* Blocks the calling thread until the subnet is up. +* +* SYNOPSIS +*/ +static inline cl_status_t +osm_opensm_wait_for_subnet_up(IN osm_opensm_t * const p_osm, + IN uint32_t const wait_us, + IN boolean_t const interruptible) +{ + return (osm_sm_wait_for_subnet_up(&p_osm->sm, wait_us, interruptible)); +} + +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object. +* +* wait_us +* [in] Number of microseconds to wait. +* +* interruptible +* [in] Indicates whether the wait operation can be interrupted +* by external signals. +* +* RETURN VALUES +* CL_SUCCESS if the wait operation succeeded in response to the event +* being set. +* +* CL_TIMEOUT if the specified time period elapses. +* +* CL_NOT_DONE if the wait was interrupted by an external signal. +* +* CL_ERROR if the wait operation failed. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: OpenSM/osm_routing_engine_type_str +* NAME +* osm_routing_engine_type_str +* +* DESCRIPTION +* Returns a string for the specified routing engine type. +* +* SYNOPSIS +*/ +const char *osm_routing_engine_type_str(IN osm_routing_engine_type_t type); +/* +* PARAMETERS +* type +* [in] routing engine type. +* +* RETURN VALUES +* Pointer to routing engine name. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: OpenSM/osm_routing_engine_type +* NAME +* osm_routing_engine_type +* +* DESCRIPTION +* Returns a routing engine type specified routing engine name string. +* +* SYNOPSIS +*/ +osm_routing_engine_type_t osm_routing_engine_type(IN const char *str); +/* +* PARAMETERS +* str +* [in] routing engine name string. +* +* RETURN VALUES +* Routing engine type. +* +* NOTES +* +* SEE ALSO +*********/ + +void osm_opensm_report_event(osm_opensm_t *osm, osm_epi_event_id_t event_id, + void *event_data); + +/* dump helpers */ +void osm_dump_mcast_routes(osm_opensm_t * osm); +void osm_dump_all(osm_opensm_t * osm); +void osm_dump_qmap_to_file(osm_opensm_t * p_osm, const char *file_name, + cl_qmap_t * map, + void (*func) (cl_map_item_t *, FILE *, void *), + void *cxt); + +/****v* OpenSM/osm_exit_flag +*/ +extern volatile unsigned int osm_exit_flag; +/* +* DESCRIPTION +* Set to one to cause all threads to leave +*********/ + +END_C_DECLS +#endif /* _OSM_OPENSM_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_partition.h b/contrib/ofed/management/opensm/include/opensm/osm_partition.h new file mode 100644 index 000000000000..38acdc99b8f4 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_partition.h @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_prtn_t. + * This object represents an IBA Partition. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_PARTITION_H_ +#define _OSM_PARTITION_H_ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Partition +* NAME +* Partition +* +* DESCRIPTION +* The Partition object encapsulates the information needed by the +* OpenSM to manage Partitions. The OpenSM allocates one Partition +* object per Partition in the IBA subnet. +* +* The Partition is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Partition/osm_prtn_t +* NAME +* osm_prtn_t +* +* DESCRIPTION +* Partition structure. +* +* The osm_prtn_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_prtn { + cl_map_item_t map_item; + ib_net16_t pkey; + ib_net16_t mlid; + uint8_t sl; + cl_map_t full_guid_tbl; + cl_map_t part_guid_tbl; + char name[32]; +} osm_prtn_t; +/* +* FIELDS +* map_item +* Linkage structure for cl_qmap. MUST BE FIRST MEMBER! +* +* pkey +* The IBA defined P_KEY of this Partition. +* +* mlid +* The network ordered LID of the well known Multicast Group +* that was created for this partition. +* +* sl +* The Service Level (SL) associated with this Partiton. +* +* full_guid_tbl +* Container of pointers to all Port objects in the Partition +* with full membership, indexed by port GUID. +* +* part_guid_tbl +* Container of pointers to all Port objects in the Partition +* with limited membership, indexed by port GUID. +* +* name +* Name of the Partition as specified in partition +* configuration. +* +* SEE ALSO +* Partition +*********/ + +/****f* OpenSM: Partition/osm_prtn_delete +* NAME +* osm_prtn_delete +* +* DESCRIPTION +* This function destroys and deallocates a Partition object. +* +* SYNOPSIS +*/ +void osm_prtn_delete(IN OUT osm_prtn_t ** const pp_prtn); +/* +* PARAMETERS +* pp_prtn +* [in][out] Pointer to a pointer to a Partition object to +* delete. On return, this pointer is NULL. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified Partition object. +* +* SEE ALSO +* Partition, osm_prtn_new +*********/ + +/****f* OpenSM: Partition/osm_prtn_new +* NAME +* osm_prtn_new +* +* DESCRIPTION +* This function allocates and initializes a Partition object. +* +* SYNOPSIS +*/ +osm_prtn_t *osm_prtn_new(IN const char *name, IN const uint16_t pkey); +/* +* PARAMETERS +* name +* [in] Partition name string +* +* pkey +* [in] Partition P_Key value +* +* RETURN VALUE +* Pointer to the initialize Partition object. +* +* NOTES +* Allows calling other partition methods. +* +* SEE ALSO +* Partition +*********/ + +/****f* OpenSM: Partition/osm_prtn_is_guid +* NAME +* osm_prtn_is_guid +* +* DESCRIPTION +* Indicates if a port is a member of the partition. +* +* SYNOPSIS +*/ +static inline boolean_t osm_prtn_is_guid(IN const osm_prtn_t * const p_prtn, + IN const ib_net64_t guid) +{ + return (cl_map_get(&p_prtn->full_guid_tbl, guid) != NULL) || + (cl_map_get(&p_prtn->part_guid_tbl, guid) != NULL); +} + +/* +* PARAMETERS +* p_prtn +* [in] Pointer to an osm_prtn_t object. +* +* guid +* [in] Port GUID. +* +* RETURN VALUES +* TRUE if the specified port GUID is a member of the partition, +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Partition/osm_prtn_make_partitions +* NAME +* osm_prtn_make_partitions +* +* DESCRIPTION +* Makes all partitions in subnet. +* +* SYNOPSIS +*/ +ib_api_status_t osm_prtn_make_partitions(IN osm_log_t * const p_log, + IN osm_subn_t * const p_subn); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to subnet object. +* +* RETURN VALUES +* IB_SUCCESS value on success. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Partition/osm_prtn_find_by_name +* NAME +* osm_prtn_find_by_name +* +* DESCRIPTION +* Fides partition by name. +* +* SYNOPSIS +*/ +osm_prtn_t *osm_prtn_find_by_name(IN osm_subn_t * p_subn, IN const char *name); +/* +* PARAMETERS +* p_subn +* [in] Pointer to a subnet object. +* +* name +* [in] Required partition name. +* +* RETURN VALUES +* Pointer to the partition object on success. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_PARTITION_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_path.h b/contrib/ofed/management/opensm/include/opensm/osm_path.h new file mode 100644 index 000000000000..8d65d2c463c9 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_path.h @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_PATH_H_ +#define _OSM_PATH_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + * Abstract: + * Declaration of path related objects. + * These objects are part of the OpenSM family of objects. + */ +/****h* OpenSM/DR Path +* NAME +* DR Path +* +* DESCRIPTION +* The DR Path structure encapsulates a directed route through the subnet. +* +* This structure allows direct access to member variables. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: DR Path/osm_dr_path_t +* NAME +* osm_dr_path_t +* +* DESCRIPTION +* Directed Route structure. +* +* This structure allows direct access to member variables. +* +* SYNOPSIS +*/ +typedef struct osm_dr_path { + osm_bind_handle_t h_bind; + uint8_t hop_count; + uint8_t path[IB_SUBNET_PATH_HOPS_MAX]; +} osm_dr_path_t; +/* +* FIELDS +* h_bind +* Bind handle for port to which this path applies. +* +* hop_count +* The number of hops in this path. +* +* path +* The array of port numbers that comprise this path. +* +* SEE ALSO +* DR Path structure +*********/ +/****f* OpenSM: DR Path/osm_dr_path_construct +* NAME +* osm_dr_path_construct +* +* DESCRIPTION +* This function constructs a directed route path object. +* +* SYNOPSIS +*/ +static inline void osm_dr_path_construct(IN osm_dr_path_t * const p_path) +{ + /* The first location in the path array is reserved. */ + memset(p_path, 0, sizeof(*p_path)); + p_path->h_bind = OSM_BIND_INVALID_HANDLE; +} + +/* +* PARAMETERS +* p_path +* [in] Pointer to a directed route path object to initialize. +* +* h_bind +* [in] Bind handle for the port on which this path applies. +* +* hop_count +* [in] Hop count needed to reach this node. +* +* path +* [in] Directed route path to reach this node. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: DR Path/osm_dr_path_init +* NAME +* osm_dr_path_init +* +* DESCRIPTION +* This function initializes a directed route path object. +* +* SYNOPSIS +*/ +static inline void +osm_dr_path_init(IN osm_dr_path_t * const p_path, + IN const osm_bind_handle_t h_bind, + IN const uint8_t hop_count, + IN const uint8_t path[IB_SUBNET_PATH_HOPS_MAX]) +{ + /* The first location in the path array is reserved. */ + CL_ASSERT(path[0] == 0); + CL_ASSERT(hop_count < IB_SUBNET_PATH_HOPS_MAX); + p_path->h_bind = h_bind; + p_path->hop_count = hop_count; + memcpy(p_path->path, path, IB_SUBNET_PATH_HOPS_MAX); +} + +/* +* PARAMETERS +* p_path +* [in] Pointer to a directed route path object to initialize. +* +* h_bind +* [in] Bind handle for the port on which this path applies. +* +* hop_count +* [in] Hop count needed to reach this node. +* +* path +* [in] Directed route path to reach this node. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ +/****f* OpenSM: DR Path/osm_dr_path_extend +* NAME +* osm_dr_path_extend +* +* DESCRIPTION +* Adds a new hop to a path. +* +* SYNOPSIS +*/ +static inline void +osm_dr_path_extend(IN osm_dr_path_t * const p_path, IN const uint8_t port_num) +{ + p_path->hop_count++; + CL_ASSERT(p_path->hop_count < IB_SUBNET_PATH_HOPS_MAX); + /* + Location 0 in the path array is reserved per IB spec. + */ + p_path->path[p_path->hop_count] = port_num; +} + +/* +* PARAMETERS +* p_path +* [in] Pointer to a directed route path object to initialize. +* +* port_num +* [in] Additional port to add to the DR path. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: DR Path/osm_dr_path_get_bind_handle +* NAME +* osm_dr_path_get_bind_handle +* +* DESCRIPTION +* Gets the bind handle from a path. +* +* SYNOPSIS +*/ +static inline osm_bind_handle_t +osm_dr_path_get_bind_handle(IN const osm_dr_path_t * const p_path) +{ + return (p_path->h_bind); +} + +/* +* PARAMETERS +* p_path +* [in] Pointer to a directed route path object to initialize. +* +* port_num +* [in] Additional port to add to the DR path. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_PATH_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_perfmgr.h b/contrib/ofed/management/opensm/include/opensm/osm_perfmgr.h new file mode 100644 index 000000000000..d48d2eea5cb8 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_perfmgr.h @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2007 The Regents of the University of California. + * Copyright (c) 2007-2008 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_PERFMGR_H_ +#define _OSM_PERFMGR_H_ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef ENABLE_OSM_PERF_MGR + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/****h* OpenSM/PerfMgr +* NAME +* PerfMgr +* +* DESCRIPTION +* Performance manager thread which takes care of polling the fabric for +* Port counters values. +* +* The PerfMgr object is thread safe. +* +* AUTHOR +* Ira Weiny, LLNL +* +*********/ + +#define OSM_PERFMGR_DEFAULT_SWEEP_TIME_S 180 +#define OSM_PERFMGR_DEFAULT_DUMP_FILE "opensm_port_counters.log" +#define OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES 500 + +/****s* OpenSM: PerfMgr/osm_perfmgr_state_t */ +typedef enum { + PERFMGR_STATE_DISABLE, + PERFMGR_STATE_ENABLED, + PERFMGR_STATE_NO_DB +} osm_perfmgr_state_t; + +/****s* OpenSM: PerfMgr/osm_perfmgr_sweep_state_t */ +typedef enum { + PERFMGR_SWEEP_SLEEP, + PERFMGR_SWEEP_ACTIVE, + PERFMGR_SWEEP_SUSPENDED +} osm_perfmgr_sweep_state_t; + +/* Redirection information */ +typedef struct redir { + ib_net16_t redir_lid; + ib_net32_t redir_qp; +} redir_t; + +/* Node to store information about which nodes we are monitoring */ +typedef struct _monitored_node { + cl_map_item_t map_item; + struct _monitored_node *next; + uint64_t guid; + char *name; + uint32_t redir_tbl_size; + redir_t redir_port[1]; /* redirection on a per port basis */ +} __monitored_node_t; + +struct osm_opensm; +/****s* OpenSM: PerfMgr/osm_perfmgr_t +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +*/ +typedef struct osm_perfmgr { + cl_event_t sig_sweep; + cl_timer_t sweep_timer; + struct osm_opensm *osm; + osm_subn_t *subn; + osm_sm_t *sm; + cl_plock_t *lock; + osm_log_t *log; + osm_mad_pool_t *mad_pool; + atomic32_t trans_id; + osm_vendor_t *vendor; + osm_bind_handle_t bind_handle; + cl_disp_reg_handle_t pc_disp_h; + osm_perfmgr_state_t state; + osm_perfmgr_sweep_state_t sweep_state; + uint16_t sweep_time_s; + perfmgr_db_t *db; + atomic32_t outstanding_queries; /* this along with sig_query */ + cl_event_t sig_query; /* will throttle our querys */ + uint32_t max_outstanding_queries; + cl_qmap_t monitored_map; /* map the nodes we are tracking */ + __monitored_node_t *remove_list; +} osm_perfmgr_t; +/* +* FIELDS +* subn +* Subnet object for this subnet. +* +* log +* Pointer to the log object. +* +* mad_pool +* Pointer to the MAD pool. +* +* mad_ctrl +* Mad Controller +*********/ + +/****f* OpenSM: Creation Functions */ +void osm_perfmgr_shutdown(osm_perfmgr_t * const p_perfmgr); +void osm_perfmgr_destroy(osm_perfmgr_t * const p_perfmgr); + +/****f* OpenSM: Inline accessor functions */ +inline static void osm_perfmgr_set_state(osm_perfmgr_t * p_perfmgr, + osm_perfmgr_state_t state) +{ + p_perfmgr->state = state; + if (state == PERFMGR_STATE_ENABLED) + osm_sm_signal(p_perfmgr->sm, OSM_SIGNAL_PERFMGR_SWEEP); +} + +inline static osm_perfmgr_state_t osm_perfmgr_get_state(osm_perfmgr_t + * p_perfmgr) +{ + return (p_perfmgr->state); +} + +inline static char *osm_perfmgr_get_state_str(osm_perfmgr_t * p_perfmgr) +{ + switch (p_perfmgr->state) { + case PERFMGR_STATE_DISABLE: + return ("Disabled"); + break; + case PERFMGR_STATE_ENABLED: + return ("Enabled"); + break; + case PERFMGR_STATE_NO_DB: + return ("No Database"); + break; + } + return ("UNKNOWN"); +} + +inline static char *osm_perfmgr_get_sweep_state_str(osm_perfmgr_t * perfmgr) +{ + switch (perfmgr->sweep_state) { + case PERFMGR_SWEEP_SLEEP: + return ("Sleeping"); + break; + case PERFMGR_SWEEP_ACTIVE: + return ("Active"); + break; + case PERFMGR_SWEEP_SUSPENDED: + return ("Suspended"); + break; + } + return ("UNKNOWN"); +} + +inline static void osm_perfmgr_set_sweep_time_s(osm_perfmgr_t * p_perfmgr, + uint16_t time_s) +{ + p_perfmgr->sweep_time_s = time_s; + osm_sm_signal(p_perfmgr->sm, OSM_SIGNAL_PERFMGR_SWEEP); +} + +inline static uint16_t osm_perfmgr_get_sweep_time_s(osm_perfmgr_t * p_perfmgr) +{ + return (p_perfmgr->sweep_time_s); +} + +void osm_perfmgr_clear_counters(osm_perfmgr_t * p_perfmgr); +void osm_perfmgr_dump_counters(osm_perfmgr_t * p_perfmgr, + perfmgr_db_dump_t dump_type); +void osm_perfmgr_print_counters(osm_perfmgr_t *pm, char *nodename, + FILE *fp); + +ib_api_status_t osm_perfmgr_bind(osm_perfmgr_t * const p_perfmgr, + const ib_net64_t port_guid); + +void osm_perfmgr_process(osm_perfmgr_t * pm); + +/****f* OpenSM: PerfMgr/osm_perfmgr_init */ +ib_api_status_t osm_perfmgr_init(osm_perfmgr_t * const perfmgr, + struct osm_opensm *osm, + const osm_subn_opt_t * const p_opt); +/* +* PARAMETERS +* perfmgr +* [in] Pointer to an osm_perfmgr_t object to initialize. +* +* osm +* [in] Pointer to the OpenSM object. +* +* p_opt +* [in] Starting options +* +* RETURN VALUES +* IB_SUCCESS if the PerfMgr object was initialized successfully. +*********/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* ENABLE_OSM_PERF_MGR */ + +#endif /* _OSM_PERFMGR_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_perfmgr_db.h b/contrib/ofed/management/opensm/include/opensm/osm_perfmgr_db.h new file mode 100644 index 000000000000..c28d5bb1100a --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_perfmgr_db.h @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2007 The Regents of the University of California. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _PERFMGR_EVENT_DB_H_ +#define _PERFMGR_EVENT_DB_H_ + +#ifdef ENABLE_OSM_PERF_MGR + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +struct osm_perfmgr; +/****h* OpenSM/PerfMgr Event Database +* DESCRIPTION +* Database interface to record subnet events +* +* Implementations of this object _MUST_ be thread safe. +* +* AUTHOR +* Ira Weiny, LLNL +* +*********/ +typedef enum { + PERFMGR_EVENT_DB_SUCCESS = 0, + PERFMGR_EVENT_DB_FAIL, + PERFMGR_EVENT_DB_NOMEM, + PERFMGR_EVENT_DB_GUIDNOTFOUND, + PERFMGR_EVENT_DB_PORTNOTFOUND, + PERFMGR_EVENT_DB_NOT_IMPL +} perfmgr_db_err_t; + +/** ========================================================================= + * Port error reading + */ +typedef struct { + uint64_t symbol_err_cnt; + uint64_t link_err_recover; + uint64_t link_downed; + uint64_t rcv_err; + uint64_t rcv_rem_phys_err; + uint64_t rcv_switch_relay_err; + uint64_t xmit_discards; + uint64_t xmit_constraint_err; + uint64_t rcv_constraint_err; + uint64_t link_integrity; + uint64_t buffer_overrun; + uint64_t vl15_dropped; + time_t time; +} perfmgr_db_err_reading_t; + +/** ========================================================================= + * Port data count reading + */ +typedef struct { + uint64_t xmit_data; /* can be used for std or extended */ + uint64_t rcv_data; /* can be used for std or extended */ + uint64_t xmit_pkts; /* can be used for std or extended */ + uint64_t rcv_pkts; /* can be used for std or extended */ + uint64_t unicast_xmit_pkts; + uint64_t unicast_rcv_pkts; + uint64_t multicast_xmit_pkts; + uint64_t multicast_rcv_pkts; + time_t time; +} perfmgr_db_data_cnt_reading_t; + +/** ========================================================================= + * Port select errors + */ +typedef struct { + uint64_t xmit_wait; + time_t time; +} perfmgr_db_ps_reading_t; + +/** ========================================================================= + * Dump output options + */ +typedef enum { + PERFMGR_EVENT_DB_DUMP_HR = 0, /* Human readable */ + PERFMGR_EVENT_DB_DUMP_MR /* Machine readable */ +} perfmgr_db_dump_t; + +/** ========================================================================= + * Port counter object. + * Store all the port counters for a single port. + */ +typedef struct _db_port { + perfmgr_db_err_reading_t err_total; + perfmgr_db_err_reading_t err_previous; + perfmgr_db_data_cnt_reading_t dc_total; + perfmgr_db_data_cnt_reading_t dc_previous; + time_t last_reset; +} _db_port_t; + +/** ========================================================================= + * group port counters for ports into the nodes + */ +#define NODE_NAME_SIZE (IB_NODE_DESCRIPTION_SIZE << 1) +typedef struct _db_node { + cl_map_item_t map_item; /* must be first */ + uint64_t node_guid; + _db_port_t *ports; + uint8_t num_ports; + char node_name[NODE_NAME_SIZE]; +} _db_node_t; + +/** ========================================================================= + * all nodes in the system. + */ +typedef struct _db { + cl_qmap_t pc_data; /* stores type (_db_node_t *) */ + cl_plock_t lock; + struct osm_perfmgr *perfmgr; +} perfmgr_db_t; + +/** + * functions + */ +perfmgr_db_t *perfmgr_db_construct(struct osm_perfmgr *perfmgr); +void perfmgr_db_destroy(perfmgr_db_t * db); + +perfmgr_db_err_t perfmgr_db_create_entry(perfmgr_db_t * db, uint64_t guid, + uint8_t num_ports, char *node_name); + +perfmgr_db_err_t perfmgr_db_add_err_reading(perfmgr_db_t * db, uint64_t guid, + uint8_t port, + perfmgr_db_err_reading_t * reading); +perfmgr_db_err_t perfmgr_db_get_prev_err(perfmgr_db_t * db, uint64_t guid, + uint8_t port, + perfmgr_db_err_reading_t * reading); +perfmgr_db_err_t perfmgr_db_clear_prev_err(perfmgr_db_t * db, uint64_t guid, + uint8_t port); + +perfmgr_db_err_t perfmgr_db_add_dc_reading(perfmgr_db_t * db, uint64_t guid, + uint8_t port, + perfmgr_db_data_cnt_reading_t * + reading); +perfmgr_db_err_t perfmgr_db_get_prev_dc(perfmgr_db_t * db, uint64_t guid, + uint8_t port, + perfmgr_db_data_cnt_reading_t * + reading); +perfmgr_db_err_t perfmgr_db_clear_prev_dc(perfmgr_db_t * db, uint64_t guid, + uint8_t port); + +void perfmgr_db_clear_counters(perfmgr_db_t * db); +perfmgr_db_err_t perfmgr_db_dump(perfmgr_db_t * db, char *file, + perfmgr_db_dump_t dump_type); +void perfmgr_db_print_by_name(perfmgr_db_t * db, char *nodename, FILE *fp); +void perfmgr_db_print_by_guid(perfmgr_db_t * db, uint64_t guid, FILE *fp); + +/** ========================================================================= + * helper functions to fill in the various db objects from wire objects + */ + +void perfmgr_db_fill_err_read(ib_port_counters_t * wire_read, + perfmgr_db_err_reading_t * reading); +void perfmgr_db_fill_data_cnt_read_pc(ib_port_counters_t * wire_read, + perfmgr_db_data_cnt_reading_t * reading); +void perfmgr_db_fill_data_cnt_read_epc(ib_port_counters_ext_t * wire_read, + perfmgr_db_data_cnt_reading_t * reading); + +END_C_DECLS + +#endif /* ENABLE_OSM_PERF_MGR */ + +#endif /* _PERFMGR_PM_DB_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_pkey.h b/contrib/ofed/management/opensm/include/opensm/osm_pkey.h new file mode 100644 index 000000000000..94b7207c7eff --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_pkey.h @@ -0,0 +1,636 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_PKEY_H_ +#define _OSM_PKEY_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + Forward references. +*/ +struct osm_physp; +struct osm_port; +struct osm_subn; +struct osm_node; +struct osm_physp; + +/* + * Abstract: + * Declaration of pkey manipulation functions. + */ + +/****s* OpenSM: osm_pkey_tbl_t +* NAME +* osm_pkey_tbl_t +* +* DESCRIPTION +* This object represents a pkey table. The need for a special object +* is required to optimize search performance of a PKey in the IB standard +* non sorted table. +* +* The osm_pkey_tbl_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_pkeybl { + cl_ptr_vector_t blocks; + cl_ptr_vector_t new_blocks; + cl_map_t keys; + cl_qlist_t pending; + uint16_t used_blocks; + uint16_t max_blocks; +} osm_pkey_tbl_t; +/* +* FIELDS +* blocks +* The IBA defined blocks of pkey values, updated from the subnet +* +* new_blocks +* The blocks of pkey values, will be used for updates by SM +* +* keys +* A set holding all keys +* +* pending +* A list of osm_pending_pkey structs that is temporarily set by +* the pkey mgr and used during pkey mgr algorithm only +* +* used_blocks +* Tracks the number of blocks having non-zero pkeys +* +* max_blocks +* The maximal number of blocks this partition table might hold +* this value is based on node_info (for port 0 or CA) or +* switch_info updated on receiving the node_info or switch_info +* GetResp +* +* NOTES +* 'blocks' vector should be used to store pkey values obtained from +* the port and SM pkey manager should not change it directly, for this +* purpose 'new_blocks' should be used. +* +* The only pkey values stored in 'blocks' vector will be mapped with +* 'keys' map +* +*********/ + +/****s* OpenSM: osm_pending_pkey_t +* NAME +* osm_pending_pkey_t +* +* DESCRIPTION +* This objects stores temporary information on pkeys, their target block, +* and index during the pkey manager operation +* +* SYNOPSIS +*/ +typedef struct osm_pending_pkey { + cl_list_item_t list_item; + uint16_t pkey; + uint16_t block; + uint8_t index; + boolean_t is_new; +} osm_pending_pkey_t; +/* +* FIELDS +* pkey +* The actual P_Key +* +* block +* The block index based on the previous table extracted from the +* device +* +* index +* The index of the pkey within the block +* +* is_new +* TRUE for new P_Keys such that the block and index are invalid +* in that case +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_construct +* NAME +* osm_pkey_tbl_construct +* +* DESCRIPTION +* Constructs the PKey table object +* +* SYNOPSIS +*/ +void osm_pkey_tbl_construct(IN osm_pkey_tbl_t * p_pkey_tbl); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_init +* NAME +* osm_pkey_tbl_init +* +* DESCRIPTION +* Inits the PKey table object +* +* SYNOPSIS +*/ +ib_api_status_t osm_pkey_tbl_init(IN osm_pkey_tbl_t * p_pkey_tbl); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_destroy +* NAME +* osm_pkey_tbl_destroy +* +* DESCRIPTION +* Destroys the PKey table object +* +* SYNOPSIS +*/ +void osm_pkey_tbl_destroy(IN osm_pkey_tbl_t * p_pkey_tbl); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_get_num_blocks +* NAME +* osm_pkey_get_num_blocks +* +* DESCRIPTION +* Obtain the number of blocks in IB PKey table +* +* SYNOPSIS +*/ +static inline uint16_t +osm_pkey_tbl_get_num_blocks(IN const osm_pkey_tbl_t * p_pkey_tbl) +{ + return ((uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->blocks))); +} + +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* RETURN VALUES +* The IB pkey table of that pkey table element +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_block_get +* NAME +* osm_pkey_tbl_block_get +* +* DESCRIPTION +* Obtain the pointer to the IB PKey table block stored in the object +* +* SYNOPSIS +*/ +static inline ib_pkey_table_t *osm_pkey_tbl_block_get(const osm_pkey_tbl_t * + p_pkey_tbl, + uint16_t block) +{ + return ((block < cl_ptr_vector_get_size(&p_pkey_tbl->blocks)) ? + cl_ptr_vector_get(&p_pkey_tbl->blocks, block) : NULL); +}; + +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* block +* [in] The lock number to get +* +* RETURN VALUES +* The IB pkey table of that pkey table element +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_new_block_get +* NAME +* osm_pkey_tbl_new_block_get +* +* DESCRIPTION +* The same as above but for new block +* +* SYNOPSIS +*/ +static inline ib_pkey_table_t *osm_pkey_tbl_new_block_get(const osm_pkey_tbl_t * + p_pkey_tbl, + uint16_t block) +{ + return (block < cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks)) ? + cl_ptr_vector_get(&p_pkey_tbl->new_blocks, block) : NULL; +}; + +/****f* OpenSM: osm_pkey_tbl_set_new_entry +* NAME +* osm_pkey_tbl_set_new_entry +* +* DESCRIPTION +* Stores the given pkey in the "new" blocks array and update +* the "map" to show that on the "old" blocks +* +* SYNOPSIS +*/ +ib_api_status_t +osm_pkey_tbl_set_new_entry(IN osm_pkey_tbl_t * p_pkey_tbl, + IN uint16_t block_idx, + IN uint8_t pkey_idx, IN uint16_t pkey); +/* +* p_pkey_tbl +* [in] Pointer to the PKey table +* +* block_idx +* [in] The block index to use +* +* pkey_idx +* [in] The index within the block +* +* pkey +* [in] PKey to store +* +* RETURN VALUES +* IB_SUCCESS if OK +* IB_ERROR if failed +* +*********/ + +/****f* OpenSM: osm_pkey_find_next_free_entry +* NAME +* osm_pkey_find_next_free_entry +* +* DESCRIPTION +* Find the next free entry in the PKey table starting at the given +* index and block number. The user should increment pkey_idx before +* next call +* Inspect the "new" blocks array for empty space. +* +* SYNOPSIS +*/ +boolean_t +osm_pkey_find_next_free_entry(IN osm_pkey_tbl_t * p_pkey_tbl, + OUT uint16_t * p_block_idx, + OUT uint8_t * p_pkey_idx); +/* +* p_pkey_tbl +* [in] Pointer to the PKey table +* +* p_block_idx +* [out] The block index to use +* +* p_pkey_idx +* [out] The index within the block to use +* +* RETURN VALUES +* TRUE if found +* FALSE if did not find +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_init_new_blocks +* NAME +* osm_pkey_tbl_init_new_blocks +* +* DESCRIPTION +* Initializes new_blocks vector content (allocate and clear) +* +* SYNOPSIS +*/ +void osm_pkey_tbl_init_new_blocks(const osm_pkey_tbl_t * p_pkey_tbl); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_get_block_and_idx +* NAME +* osm_pkey_tbl_get_block_and_idx +* +* DESCRIPTION +* Set the block index and pkey index the given +* pkey is found in. Return IB_NOT_FOUND if could +* not find it, IB_SUCCESS if OK +* +* SYNOPSIS +*/ +ib_api_status_t +osm_pkey_tbl_get_block_and_idx(IN osm_pkey_tbl_t * p_pkey_tbl, + IN uint16_t * p_pkey, + OUT uint16_t * block_idx, + OUT uint8_t * pkey_index); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* p_pkey +* [in] Pointer to the P_Key entry searched +* +* p_block_idx +* [out] Pointer to the block index to be updated +* +* p_pkey_idx +* [out] Pointer to the pkey index (in the block) to be updated +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_pkey_tbl_set +* NAME +* osm_pkey_tbl_set +* +* DESCRIPTION +* Set the PKey table block provided in the PKey object. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_pkey_tbl_set(IN osm_pkey_tbl_t * p_pkey_tbl, + IN uint16_t block, IN ib_pkey_table_t * p_tbl); +/* +* p_pkey_tbl +* [in] Pointer to osm_pkey_tbl_t object. +* +* block +* [in] The block number to set +* +* p_tbl +* [in] The IB PKey block to copy to the object +* +* RETURN VALUES +* IB_SUCCESS or IB_ERROR +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_physp_share_this_pkey +* NAME +* osm_physp_share_this_pkey +* +* DESCRIPTION +* Checks if the given physical ports share the specified pkey. +* +* SYNOPSIS +*/ +boolean_t osm_physp_share_this_pkey(IN const struct osm_physp *const p_physp1, + IN const struct osm_physp *const p_physp2, + IN const ib_net16_t pkey); +/* +* PARAMETERS +* +* p_physp1 +* [in] Pointer to an osm_physp_t object. +* +* p_physp2 +* [in] Pointer to an osm_physp_t object. +* +* pkey +* [in] value of P_Key to check. +* +* RETURN VALUES +* Returns TRUE if the two ports are matching. +* FALSE otherwise. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_physp_find_common_pkey +* NAME +* osm_physp_find_common_pkey +* +* DESCRIPTION +* Returns first matching P_Key values for specified physical ports. +* +* SYNOPSIS +*/ +ib_net16_t osm_physp_find_common_pkey(IN const struct osm_physp *const + p_physp1, + IN const struct osm_physp *const + p_physp2); +/* +* PARAMETERS +* +* p_physp1 +* [in] Pointer to an osm_physp_t object. +* +* p_physp2 +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns value of first shared P_Key or INVALID P_Key (0x0) if not +* found. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_physp_share_pkey +* NAME +* osm_physp_share_pkey +* +* DESCRIPTION +* Checks if the given physical ports share a pkey. +* The meaning P_Key matching: +* 10.9.3 : +* In the following, let M_P_Key(Message P_Key) be the P_Key in the incoming +* packet and E_P_Key(Endnode P_Key) be the P_Key it is being compared against +* in the packet's destination endnode. +* +* If: +* * neither M_P_Key nor E_P_Key are the invalid P_Key +* * and the low-order 15 bits of the M_P_Key match the low order 15 +* bits of the E_P_Key +* * and the high order bit(membership type) of both the M_P_Key and +* E_P_Key are not both 0 (i.e., both are not Limited members of +* the partition) +* +* then the P_Keys are said to match. +* +* SYNOPSIS +*/ +boolean_t osm_physp_share_pkey(IN osm_log_t * p_log, + IN const struct osm_physp *const p_physp_1, + IN const struct osm_physp *const p_physp_2); + +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_physp_1 +* [in] Pointer to an osm_physp_t object. +* +* p_physp_2 +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns TRUE if the 2 physical ports are matching. +* FALSE otherwise. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_port_share_pkey +* NAME +* osm_port_share_pkey +* +* DESCRIPTION +* Checks if the given ports (on their default physical port) share a pkey. +* The meaning P_Key matching: +* 10.9.3 : +* In the following, let M_P_Key(Message P_Key) be the P_Key in the incoming +* packet and E_P_Key(Endnode P_Key) be the P_Key it is being compared against +* in the packet's destination endnode. +* +* If: +* * neither M_P_Key nor E_P_Key are the invalid P_Key +* * and the low-order 15 bits of the M_P_Key match the low order 15 +* bits of the E_P_Key +* * and the high order bit(membership type) of both the M_P_Key and +* E_P_Key are not both 0 (i.e., both are not Limited members of +* the partition) +* +* then the P_Keys are said to match. +* +* SYNOPSIS +*/ +boolean_t osm_port_share_pkey(IN osm_log_t * p_log, + IN const struct osm_port *const p_port_1, + IN const struct osm_port *const p_port_2); + +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_port_1 +* [in] Pointer to an osm_port_t object. +* +* p_port_2 +* [in] Pointer to an osm_port_t object. +* +* RETURN VALUES +* Returns TRUE if the 2 ports are matching. +* FALSE otherwise. +* +* NOTES +* +*********/ + +/****f* OpenSM: osm_physp_has_pkey +* NAME +* osm_physp_has_pkey +* +* DESCRIPTION +* Checks if the given lids and port_numbers share a pkey. +* The meaning P_Key matching: +* 10.9.3 : +* In the following, let M_P_Key(Message P_Key) be the P_Key in the incoming +* packet and E_P_Key(Endnode P_Key) be the P_Key it is being compared against +* in the packet's destination endnode. +* +* If: +* * neither M_P_Key nor E_P_Key are the invalid P_Key +* * and the low-order 15 bits of the M_P_Key match the low order 15 +* bits of the E_P_Key +* * and the high order bit(membership type) of both the M_P_Key and +* E_P_Key are not both 0 (i.e., both are not Limited members of +* the partition) +* +* then the P_Keys are said to match. +* +* SYNOPSIS +*/ +boolean_t osm_physp_has_pkey(IN osm_log_t * p_log, + IN const ib_net16_t pkey, + IN const struct osm_physp *const p_physp); + +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* pkey +* [in] pkey number to look for. +* +* p_physp +* [in] Pointer to osm_physp_t object. +* +* RETURN VALUES +* Returns TRUE if the p_physp has the pkey given. False otherwise. +* +* NOTES +* +*********/ + +END_C_DECLS +#endif /* _OSM_PKEY_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_pkey_mgr.h b/contrib/ofed/management/opensm/include/opensm/osm_pkey_mgr.h new file mode 100644 index 000000000000..91587bd73f7d --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_pkey_mgr.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Prototype for osm_pkey_mgr_process() function + * This is part of the OpenSM family of objects. + */ + +#ifndef _OSM_PKEY_MGR_H_ +#define _OSM_PKEY_MGR_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****f* OpenSM: P_Key Manager/osm_pkey_mgr_process +* NAME +* osm_pkey_mgr_process +* +* DESCRIPTION +* This function enforces the pkey rules on the SM DB. +* +* SYNOPSIS +*/ +osm_signal_t osm_pkey_mgr_process(IN osm_opensm_t * p_osm); +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_PKEY_MGR_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_port.h b/contrib/ofed/management/opensm/include/opensm/osm_port.h new file mode 100644 index 000000000000..3dda5414ffa9 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_port.h @@ -0,0 +1,1591 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of port related objects. + * These objects comprise an IBA port. + * These objects are part of the OpenSM family of objects. + */ + +#ifndef _OSM_PORT_H_ +#define _OSM_PORT_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + Forward references. +*/ +struct osm_port; +struct osm_node; + +/****h* OpenSM/Physical Port +* NAME +* Physical Port +* +* DESCRIPTION +* The Physical Port object encapsulates the information needed by the +* OpenSM to manage physical ports. The OpenSM allocates one Physical Port +* per physical port in the IBA subnet. +* +* In a switch, one multiple Physical Port objects share the same port GUID. +* In an end-point, Physical Ports do not share GUID values. +* +* The Physical Port is not thread safe, thus callers must provide +* serialization. +* +* These objects should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Physical Port/osm_physp_t +* NAME +* osm_physp_t +* +* DESCRIPTION +* This object represents a physical port on a switch, router or end-point. +* +* The osm_physp_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_physp { + ib_port_info_t port_info; + ib_net64_t port_guid; + uint8_t port_num; + struct osm_node *p_node; + struct osm_physp *p_remote_physp; + boolean_t healthy; + uint8_t vl_high_limit; + unsigned need_update; + unsigned is_prof_ignored; + osm_dr_path_t dr_path; + osm_pkey_tbl_t pkeys; + ib_vl_arb_table_t vl_arb[4]; + cl_ptr_vector_t slvl_by_port; +} osm_physp_t; +/* +* FIELDS +* port_info +* The IBA defined PortInfo data for this port. +* +* port_guid +* Port GUID value of this port. For switches, +* all ports share the same GUID value. +* +* port_num +* The port number of this port. The PortInfo also +* contains a port_number, but that number is not +* the port number of this port, but rather the number +* of the port that received the SMP during discovery. +* Therefore, we must keep a separate record for this +* port's port number. +* +* p_node +* Pointer to the parent Node object of this Physical Port. +* +* p_remote_physp +* Pointer to the Physical Port on the other side of the wire. +* If this pointer is NULL no link exists at this port. +* +* healthy +* Tracks the health of the port. Normally should be TRUE but +* might change as a result of incoming traps indicating the port +* healthy is questionable. +* +* vl_high_limit +* PortInfo:VLHighLimit value which installed by QoS manager +* and should be uploaded to port's PortInfo +* +* need_update +* When set indicates that port was probably reset and port +* related tables (PKey, SL2VL, VLArb) require refreshing. +* +* is_prof_ignored +* When set indicates that switch port will be ignored by +* the link load equalization algorithm. +* +* dr_path +* The directed route path to this port. +* +* pkeys +* osm_pkey_tbl_t object holding the port PKeys. +* +* vl_arb[] +* Each Physical Port has 4 sections of VL Arbitration table. +* +* slvl_by_port +* A vector of pointers to the sl2vl tables (ordered by input port). +* Switches have an entry for every other input port (inc SMA=0). +* On CAs only one per port. +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_construct +* NAME +* osm_physp_construct +* +* DESCRIPTION +* Constructs a Physical Port. +* +* SYNOPSIS +*/ +void osm_physp_construct(IN osm_physp_t * const p_physp); +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object to initialize. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_init +* NAME +* osm_physp_init +* +* DESCRIPTION +* Initializes a Physical Port for use. +* +* SYNOPSIS +*/ +void +osm_physp_init(IN osm_physp_t * const p_physp, + IN const ib_net64_t port_guid, + IN const uint8_t port_num, + IN const struct osm_node *const p_node, + IN const osm_bind_handle_t h_bind, + IN const uint8_t hop_count, + IN const uint8_t * const p_initial_path); +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object to initialize. +* +* port_guid +* [in] GUID value of this port. Switch ports all share +* the same value. +* Caller should use 0 if the guid is unknown. +* +* port_num +* [in] The port number of this port. +* +* p_node +* [in] Pointer to the parent Node object of this Physical Port. +* +* h_bind +* [in] Bind handle on which this port is accessed. +* Caller should use OSM_INVALID_BIND_HANDLE if the bind +* handle to this port is unknown. +* +* hop_count +* [in] Directed route hop count to reach this port. +* Caller should use 0 if the hop count is unknown. +* +* p_initial_path +* [in] Pointer to the directed route path to reach this node. +* Caller should use NULL if the path is unknown. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Port/void osm_physp_destroy +* NAME +* osm_physp_destroy +* +* DESCRIPTION +* This function destroys a Port object. +* +* SYNOPSIS +*/ +void osm_physp_destroy(IN osm_physp_t * const p_physp); +/* +* PARAMETERS +* p_port +* [in] Pointer to a PhysPort object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified PhysPort object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_physp_construct or +* osm_physp_init. +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_is_valid +* NAME +* osm_physp_is_valid +* +* DESCRIPTION +* Returns TRUE if the Physical Port has been successfully initialized. +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t osm_physp_is_valid(IN const osm_physp_t * const p_physp) +{ + CL_ASSERT(p_physp); + return (p_physp->port_guid != 0); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns TRUE if the Physical Port has been successfully initialized. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_is_healthy +* NAME +* osm_physp_is_healthy +* +* DESCRIPTION +* Returns TRUE if the Physical Port has been maked as healthy +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_physp_is_healthy(IN const osm_physp_t * const p_physp) +{ + CL_ASSERT(p_physp); + return (p_physp->healthy); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns TRUE if the Physical Port has been maked as healthy +* FALSE otherwise. +* All physical ports are initialized as "healthy" but may be marked +* otherwise if a received trap claims otherwise. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_link_is_healthy +* NAME +* osm_link_is_healthy +* +* DESCRIPTION +* Returns TRUE if the link given by the physical port is health, +* and FALSE otherwise. Link is healthy if both its physical ports are +* healthy +* +* SYNOPSIS +*/ +boolean_t osm_link_is_healthy(IN const osm_physp_t * const p_physp); +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* TRUE if both physical ports on the link are healthy, and FALSE otherwise. +* All physical ports are initialized as "healthy" but may be marked +* otherwise if a received trap claiming otherwise. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_set_health +* NAME +* osm_physp_set_health +* +* DESCRIPTION +* Sets the port health flag. TRUE means the port is healthy and +* should be used for packet routing. FALSE means it should be avoided. +* +* SYNOPSIS +*/ +static inline void +osm_physp_set_health(IN osm_physp_t * const p_physp, IN boolean_t is_healthy) +{ + CL_ASSERT(p_physp); + p_physp->healthy = is_healthy; +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* is_healthy +* [in] The health value to be assigned to the port. +* TRUE if the Physical Port should been maked as healthy +* FALSE otherwise. +* +* RETURN VALUES +* NONE +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_set_port_info +* NAME +* osm_physp_set_port_info +* +* DESCRIPTION +* Copies the PortInfo attribute into the Physical Port object +* based on the PortState. +* +* SYNOPSIS +*/ +static inline void +osm_physp_set_port_info(IN osm_physp_t * const p_physp, + IN const ib_port_info_t * const p_pi) +{ + CL_ASSERT(p_pi); + CL_ASSERT(osm_physp_is_valid(p_physp)); + + if (ib_port_info_get_port_state(p_pi) == IB_LINK_DOWN) { + /* If PortState is down, only copy PortState */ + /* and PortPhysicalState per C14-24-2.1 */ + ib_port_info_set_port_state(&p_physp->port_info, IB_LINK_DOWN); + ib_port_info_set_port_phys_state + (ib_port_info_get_port_phys_state(p_pi), + &p_physp->port_info); + } else { + p_physp->port_info = *p_pi; + } +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* p_pi +* [in] Pointer to the IBA defined PortInfo at this port number. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_set_pkey_tbl +* NAME +* osm_physp_set_pkey_tbl +* +* DESCRIPTION +* Copies the P_Key table into the Physical Port object. +* +* SYNOPSIS +*/ +void +osm_physp_set_pkey_tbl(IN osm_log_t * p_log, + IN const osm_subn_t * p_subn, + IN osm_physp_t * const p_physp, + IN ib_pkey_table_t * p_pkey_tbl, IN uint16_t block_num); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to the subnet data structure. +* +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* p_pkey_tbl +* [in] Pointer to the IBA defined P_Key table for this port +* number. +* +* block_num +* [in] The part of the P_Key table as defined in the IBA +* (valid values 0-2047, and is further limited by the +* partitionCap). +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_pkey_tbl +* NAME +* osm_physp_get_pkey_tbl +* +* DESCRIPTION +* Returns a pointer to the P_Key table object of the Physical Port object. +* +* SYNOPSIS +*/ +static inline const osm_pkey_tbl_t *osm_physp_get_pkey_tbl(IN const osm_physp_t + * const p_physp) +{ + CL_ASSERT(osm_physp_is_valid(p_physp)); + /* + (14.2.5.7) - the block number valid values are 0-2047, and are + further limited by the size of the P_Key table specified by the + PartitionCap on the node. + */ + return (&p_physp->pkeys); +}; + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* The pointer to the P_Key table object. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_set_slvl_tbl +* NAME +* osm_physp_set_slvl_tbl +* +* DESCRIPTION +* Copies the SLtoVL attribute into the Physical Port object. +* +* SYNOPSIS +*/ +static inline void +osm_physp_set_slvl_tbl(IN osm_physp_t * const p_physp, + IN ib_slvl_table_t * p_slvl_tbl, IN uint8_t in_port_num) +{ + ib_slvl_table_t *p_tbl; + + CL_ASSERT(p_slvl_tbl); + CL_ASSERT(osm_physp_is_valid(p_physp)); + p_tbl = cl_ptr_vector_get(&p_physp->slvl_by_port, in_port_num); + *p_tbl = *p_slvl_tbl; +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* p_slvl_tbl +* [in] Pointer to the IBA defined SLtoVL map table for this +* port number. +* +* in_port_num +* [in] Input Port Number for this SLtoVL. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_slvl_tbl +* NAME +* osm_physp_get_slvl_tbl +* +* DESCRIPTION +* Returns a pointer to the SLtoVL attribute of the Physical Port object. +* +* SYNOPSIS +*/ +static inline ib_slvl_table_t *osm_physp_get_slvl_tbl(IN const osm_physp_t * + const p_physp, + IN uint8_t in_port_num) +{ + ib_slvl_table_t *p_tbl; + + CL_ASSERT(osm_physp_is_valid(p_physp)); + p_tbl = cl_ptr_vector_get(&p_physp->slvl_by_port, in_port_num); + return (p_tbl); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* in_port_num +* [in] Input Port Number for this SLtoVL. +* +* RETURN VALUES +* The pointer to the slvl table +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_set_vla_tbl +* NAME +* osm_physp_set_vla_tbl +* +* DESCRIPTION +* Copies the VL Arbitration attribute into the Physical Port object. +* +* SYNOPSIS +*/ +static inline void +osm_physp_set_vla_tbl(IN osm_physp_t * const p_physp, + IN ib_vl_arb_table_t * p_vla_tbl, IN uint8_t block_num) +{ + CL_ASSERT(p_vla_tbl); + CL_ASSERT(osm_physp_is_valid(p_physp)); + CL_ASSERT((1 <= block_num) && (block_num <= 4)); + p_physp->vl_arb[block_num - 1] = *p_vla_tbl; +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* p_vla_tbl +* [in] Pointer to the IBA defined VL Arbitration table for this +* port number. +* +* block_num +* [in] The part of the VL arbitration as defined in the IBA +* (valid values 1-4) +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_vla_tbl +* NAME +* osm_physp_get_vla_tbl +* +* DESCRIPTION +* Returns a pointer to the VL Arbitration table of the Physical Port object. +* +* SYNOPSIS +*/ +static inline ib_vl_arb_table_t *osm_physp_get_vla_tbl(IN osm_physp_t * + const p_physp, + IN uint8_t block_num) +{ + CL_ASSERT(osm_physp_is_valid(p_physp)); + CL_ASSERT((1 <= block_num) && (block_num <= 4)); + return (&(p_physp->vl_arb[block_num - 1])); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* block_num +* [in] The part of the VL arbitration as defined in the IBA +* (valid values 1-4) +* +* RETURN VALUES +* The pointer to the VL Arbitration table +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_remote +* NAME +* osm_physp_get_remote +* +* DESCRIPTION +* Returns a pointer to the Physical Port on the other side the wire. +* +* SYNOPSIS +*/ +static inline osm_physp_t *osm_physp_get_remote(IN const osm_physp_t * + const p_physp) +{ + CL_ASSERT(osm_physp_is_valid(p_physp)); + return (p_physp->p_remote_physp); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns a pointer to the Physical Port on the other side of +* the wire. A return value of NULL means there is no link at this port. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_port_guid +* NAME +* osm_physp_get_port_guid +* +* DESCRIPTION +* Returns the port guid of this physical port. +* +* SYNOPSIS +*/ +static inline ib_net64_t +osm_physp_get_port_guid(IN const osm_physp_t * const p_physp) +{ + CL_ASSERT(osm_physp_is_valid(p_physp)); + return (p_physp->port_guid); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns the port guid of this physical port. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_subnet_prefix +* NAME +* osm_physp_get_subnet_prefix +* +* DESCRIPTION +* Returns the subnet prefix for this physical port. +* +* SYNOPSIS +*/ +static inline ib_net64_t +osm_physp_get_subnet_prefix(IN const osm_physp_t * const p_physp) +{ + CL_ASSERT(osm_physp_is_valid(p_physp)); + return (p_physp->port_info.subnet_prefix); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns the subnet prefix for this physical port. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_link_exists +* NAME +* osm_physp_link_exists +* +* DESCRIPTION +* Returns TRUE if the Physical Port has a link to the specified port. +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_physp_link_exists(IN const osm_physp_t * const p_physp, + IN const osm_physp_t * const p_remote_physp) +{ + CL_ASSERT(p_physp); + CL_ASSERT(osm_physp_is_valid(p_physp)); + CL_ASSERT(p_remote_physp); + CL_ASSERT(osm_physp_is_valid(p_remote_physp)); + return ((p_physp->p_remote_physp == p_remote_physp) && + (p_remote_physp->p_remote_physp == p_physp)); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* p_remote_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns TRUE if the Physical Port has a link to another port. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_link +* NAME +* osm_physp_link +* +* DESCRIPTION +* Sets the pointers to the Physical Ports on the other side the wire. +* +* SYNOPSIS +*/ +static inline void +osm_physp_link(IN osm_physp_t * const p_physp, + IN osm_physp_t * const p_remote_physp) +{ + CL_ASSERT(p_physp); + CL_ASSERT(p_remote_physp); + p_physp->p_remote_physp = p_remote_physp; + p_remote_physp->p_remote_physp = p_physp; +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object to link. +* +* p_remote_physp +* [in] Pointer to the adjacent osm_physp_t object to link. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_unlink +* NAME +* osm_physp_unlink +* +* DESCRIPTION +* Clears the pointers to the Physical Port on the other side the wire. +* +* SYNOPSIS +*/ +static inline void +osm_physp_unlink(IN osm_physp_t * const p_physp, + IN osm_physp_t * const p_remote_physp) +{ + CL_ASSERT(p_physp); + CL_ASSERT(p_remote_physp); + CL_ASSERT(osm_physp_link_exists(p_physp, p_remote_physp)); + p_physp->p_remote_physp = NULL; + p_remote_physp->p_remote_physp = NULL; +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object to link. +* +* p_remote_physp +* [in] Pointer to the adjacent osm_physp_t object to link. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_has_any_link +* NAME +* osm_physp_has_any_link +* +* DESCRIPTION +* Returns TRUE if the Physical Port has a link to another port. +* FALSE otherwise. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_physp_has_any_link(IN const osm_physp_t * const p_physp) +{ + CL_ASSERT(p_physp); + if (osm_physp_is_valid(p_physp)) + return (p_physp->p_remote_physp != NULL); + else + return (FALSE); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns TRUE if the Physical Port has a link to another port. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* Port, Physical Port +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_port_num +* NAME +* osm_physp_get_port_num +* +* DESCRIPTION +* Returns the local port number of this Physical Port. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_physp_get_port_num(IN const osm_physp_t * const p_physp) +{ + CL_ASSERT(p_physp); + CL_ASSERT(osm_physp_is_valid(p_physp)); + return (p_physp->port_num); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns the local port number of this Physical Port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_node_ptr +* NAME +* osm_physp_get_node_ptr +* +* DESCRIPTION +* Returns a pointer to the parent Node object for this port. +* +* SYNOPSIS +*/ +static inline struct osm_node *osm_physp_get_node_ptr(IN const osm_physp_t * + const p_physp) +{ + CL_ASSERT(p_physp); + CL_ASSERT(osm_physp_is_valid(p_physp)); + return ((struct osm_node *)p_physp->p_node); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns a pointer to the parent Node object for this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_port_state +* NAME +* osm_physp_get_port_state +* +* DESCRIPTION +* Returns the port state of this Physical Port. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_physp_get_port_state(IN const osm_physp_t * const p_physp) +{ + CL_ASSERT(p_physp); + CL_ASSERT(osm_physp_is_valid(p_physp)); + return (ib_port_info_get_port_state(&p_physp->port_info)); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns the local port number of this Physical Port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_base_lid +* NAME +* osm_physp_get_base_lid +* +* DESCRIPTION +* Returns the base lid of this Physical Port. +* +* SYNOPSIS +*/ +static inline ib_net16_t +osm_physp_get_base_lid(IN const osm_physp_t * const p_physp) +{ + CL_ASSERT(p_physp); + CL_ASSERT(osm_physp_is_valid(p_physp)); + return (p_physp->port_info.base_lid); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns the base lid of this Physical Port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_lmc +* NAME +* osm_physp_get_lmc +* +* DESCRIPTION +* Returns the LMC value of this Physical Port. +* +* SYNOPSIS +*/ +static inline uint8_t osm_physp_get_lmc(IN const osm_physp_t * const p_physp) +{ + CL_ASSERT(p_physp); + CL_ASSERT(osm_physp_is_valid(p_physp)); + return (ib_port_info_get_lmc(&p_physp->port_info)); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* Returns the LMC value of this Physical Port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Physical Port/osm_physp_get_dr_path_ptr +* NAME +* osm_physp_get_dr_path_ptr +* +* DESCRIPTION +* Returns a pointer to the directed route path for this port. +* +* SYNOPSIS +*/ +static inline osm_dr_path_t *osm_physp_get_dr_path_ptr(IN const osm_physp_t * + const p_physp) +{ + CL_ASSERT(p_physp); + CL_ASSERT(osm_physp_is_valid(p_physp)); + return ((osm_dr_path_t *) & p_physp->dr_path); +} + +/* +* PARAMETERS +* p_physp +* [in] Pointer to a Physical Port object. +* +* RETURN VALUES +* Returns a pointer to the directed route path for this port. +* +* NOTES +* +* SEE ALSO +* Physical Port object +*********/ + +/****h* OpenSM/Port +* NAME +* Port +* +* DESCRIPTION +* The Port object encapsulates the information needed by the +* OpenSM to manage ports. The OpenSM allocates one Port object +* per port in the IBA subnet. +* +* Each Port object is associated with a single port GUID. A Port object +* contains 1 or more Physical Port objects. An end point node has +* one Physical Port per Port. A switch node has more than +* one Physical Port per Port. +* +* The Port object is not thread safe, thus callers must provide +* serialization. +* +* These objects should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Port/osm_port_t +* NAME +* osm_port_t +* +* DESCRIPTION +* This object represents a logical port on a switch, router or end-point. +* +* The osm_port_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_port { + cl_map_item_t map_item; + cl_list_item_t list_item; + struct osm_node *p_node; + ib_net64_t guid; + uint32_t discovery_count; + unsigned is_new; + osm_physp_t *p_physp; + cl_qlist_t mcm_list; + int flag; + void *priv; +} osm_port_t; +/* +* FIELDS +* map_item +* Linkage structure for cl_qmap. MUST BE FIRST MEMBER! +* +* list_item +* Linkage structure for cl_qlist. Used by ucast mgr during LFT calculation. +* +* p_node +* Points to the Node object that owns this port. +* +* guid +* Manufacturer assigned GUID for this port. +* +* discovery_count +* The number of times this port has been discovered +* during the current fabric sweep. This number is reset +* to zero at the start of a sweep. +* +* p_physp +* The pointer to physical port used when physical +* characteristics contained in the Physical Port are needed. +* +* mcm_list +* Multicast member list +* +* flag +* Utility flag for port management +* +* SEE ALSO +* Port, Physical Port, Physical Port Table +*********/ + +/****f* OpenSM: Port/osm_port_delete +* NAME +* osm_port_delete +* +* DESCRIPTION +* This function destroys and deallocates a Port object. +* +* SYNOPSIS +*/ +void osm_port_delete(IN OUT osm_port_t ** const pp_port); +/* +* PARAMETERS +* pp_port +* [in][out] Pointer to a pointer to a Port object to delete. +* On return, this pointer is NULL. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified Port object. +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_new +* NAME +* osm_port_new +* +* DESCRIPTION +* This function allocates and initializes a Port object. +* +* SYNOPSIS +*/ +osm_port_t *osm_port_new(IN const ib_node_info_t * p_ni, + IN struct osm_node *const p_parent_node); +/* +* PARAMETERS +* p_ni +* [in] Pointer to the NodeInfo attribute relavent for this port. +* +* p_parent_node +* [in] Pointer to the initialized parent osm_node_t object +* that owns this port. +* +* RETURN VALUE +* Pointer to the initialize Port object. +* +* NOTES +* Allows calling other port methods. +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_get_base_lid +* NAME +* osm_port_get_base_lid +* +* DESCRIPTION +* Gets the base LID of a port. +* +* SYNOPSIS +*/ +static inline ib_net16_t +osm_port_get_base_lid(IN const osm_port_t * const p_port) +{ + CL_ASSERT(p_port->p_physp && osm_physp_is_valid(p_port->p_physp)); + return (osm_physp_get_base_lid(p_port->p_physp)); +} + +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object. +* +* RETURN VALUE +* Base LID of the port. +* If the return value is 0, then this port has no assigned LID. +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_get_lmc +* NAME +* osm_port_get_lmc +* +* DESCRIPTION +* Gets the LMC value of a port. +* +* SYNOPSIS +*/ +static inline uint8_t osm_port_get_lmc(IN const osm_port_t * const p_port) +{ + CL_ASSERT(p_port->p_physp && osm_physp_is_valid(p_port->p_physp)); + return (osm_physp_get_lmc(p_port->p_physp)); +} + +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object. +* +* RETURN VALUE +* Gets the LMC value of a port. +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_get_guid +* NAME +* osm_port_get_guid +* +* DESCRIPTION +* Gets the GUID of a port. +* +* SYNOPSIS +*/ +static inline ib_net64_t osm_port_get_guid(IN const osm_port_t * const p_port) +{ + return (p_port->guid); +} + +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object. +* +* RETURN VALUE +* Manufacturer assigned GUID of the port. +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_get_lid_range_ho +* NAME +* osm_port_get_lid_range_ho +* +* DESCRIPTION +* Returns the HOST ORDER lid min and max values for this port, +* based on the lmc value. +* +* SYNOPSIS +*/ +void +osm_port_get_lid_range_ho(IN const osm_port_t * const p_port, + OUT uint16_t * const p_min_lid, + OUT uint16_t * const p_max_lid); +/* +* PARAMETERS +* p_port +* [in] Pointer to a Port object. +* +* p_min_lid +* [out] Pointer to the minimum LID value occupied by this port. +* +* p_max_lid +* [out] Pointer to the maximum LID value occupied by this port. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_get_port_by_base_lid +* NAME +* osm_get_port_by_base_lid +* +* DESCRIPTION +* Returns a status on whether a Port was able to be +* determined based on the LID supplied and if so, return the Port. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_get_port_by_base_lid(IN const osm_subn_t * const p_subn, + IN const ib_net16_t lid, + IN OUT const osm_port_t ** const pp_port); +/* +* PARAMETERS +* p_subn +* [in] Pointer to the subnet data structure. +* +* lid +* [in] LID requested. +* +* pp_port +* [in][out] Pointer to pointer to Port object. +* +* RETURN VALUES +* IB_SUCCESS +* IB_NOT_FOUND +* +* NOTES +* +* SEE ALSO +* Port +*********/ + +/****f* OpenSM: Port/osm_port_add_mgrp +* NAME +* osm_port_add_mgrp +* +* DESCRIPTION +* Logically connects a port to a multicast group. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_port_add_mgrp(IN osm_port_t * const p_port, IN const ib_net16_t mlid); +/* +* PARAMETERS +* p_port +* [in] Pointer to an osm_port_t object. +* +* mlid +* [in] MLID of the multicast group. +* +* RETURN VALUES +* IB_SUCCESS +* IB_INSUFFICIENT_MEMORY +* +* NOTES +* +* SEE ALSO +* Port object +*********/ + +/****f* OpenSM: Port/osm_port_remove_mgrp +* NAME +* osm_port_remove_mgrp +* +* DESCRIPTION +* Logically disconnects a port from a multicast group. +* +* SYNOPSIS +*/ +void +osm_port_remove_mgrp(IN osm_port_t * const p_port, IN const ib_net16_t mlid); +/* +* PARAMETERS +* p_port +* [in] Pointer to an osm_port_t object. +* +* mlid +* [in] MLID of the multicast group. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Port object +*********/ + +/****f* OpenSM: Port/osm_port_remove_all_mgrp +* NAME +* osm_port_remove_all_mgrp +* +* DESCRIPTION +* Logically disconnects a port from all its multicast groups. +* +* SYNOPSIS +*/ +void osm_port_remove_all_mgrp(IN osm_port_t * const p_port); +/* +* PARAMETERS +* p_port +* [in] Pointer to an osm_port_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* Port object +*********/ + +/****f* OpenSM: Physical Port/osm_physp_calc_link_mtu +* NAME +* osm_physp_calc_link_mtu +* +* DESCRIPTION +* Calculate the Port MTU based on current and remote +* physical ports MTU CAP values. +* +* SYNOPSIS +*/ +uint8_t +osm_physp_calc_link_mtu(IN osm_log_t * p_log, IN const osm_physp_t * p_physp); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* The MTU of the link to be used. +* +* NOTES +* +* SEE ALSO +* PhysPort object +*********/ + +/****f* OpenSM: Physical Port/osm_physp_calc_link_op_vls +* NAME +* osm_physp_calc_link_op_vls +* +* DESCRIPTION +* Calculate the Port OP_VLS based on current and remote +* physical ports VL CAP values. Allowing user option for a max limit. +* +* SYNOPSIS +*/ +uint8_t +osm_physp_calc_link_op_vls(IN osm_log_t * p_log, + IN const osm_subn_t * p_subn, + IN const osm_physp_t * p_physp); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to the subnet object for accessing of the options. +* +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* RETURN VALUES +* The OP_VLS of the link to be used. +* +* NOTES +* +* SEE ALSO +* PhysPort object +*********/ + +/****f* OpenSM: Physical Port/osm_physp_replace_dr_path_with_alternate_dr_path +* NAME +* osm_physp_replace_dr_path_with_alternate_dr_path +* +* DESCRIPTION +* Replace the direct route path for the given phys port with an +* alternate path going through forien set of phys port. +* +* SYNOPSIS +*/ +void +osm_physp_replace_dr_path_with_alternate_dr_path(IN osm_log_t * p_log, + IN osm_subn_t const *p_subn, + IN osm_physp_t const *p_physp, + IN osm_bind_handle_t * h_bind); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to the subnet object for accessing of the options. +* +* p_physp +* [in] Pointer to an osm_physp_t object. +* +* h_bind +* [in] Pointer to osm_bind_handle_t object. +* +* RETURN VALUES +* NONE +* +* NOTES +* +* SEE ALSO +* PhysPort object +*********/ + +END_C_DECLS +#endif /* _OSM_PORT_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_port_profile.h b/contrib/ofed/management/opensm/include/opensm/osm_port_profile.h new file mode 100644 index 000000000000..fd2271905127 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_port_profile.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of Switch/osm_port_profile_t. + * This object represents a port profile for an IBA switch. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_PORT_PROFILE_H_ +#define _OSM_PORT_PROFILE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Port Profile +* NAME +* Port Profile +* +* DESCRIPTION +* The Port Profile object contains profiling information for +* each Physical Port on a switch. The profile information +* may be used to optimize path selection. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Switch/osm_port_profile_t +* NAME +* osm_port_profile_t +* +* DESCRIPTION +* The Port Profile object contains profiling information for +* each Physical Port on the switch. The profile information +* may be used to optimize path selection. +* +* This object should be treated as opaque and should be +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_port_profile { + uint32_t num_paths; +} osm_port_profile_t; +/* +* FIELDS +* num_paths +* The number of paths using this port. +* +* SEE ALSO +*********/ + +/****s* OpenSM: Switch/osm_port_mask_t +* NAME +* osm_port_mask_t +* +* DESCRIPTION +* The Port Mask object contains a port numbered bit mask +* for whether the port should be ignored by the link load +* equalization algorithm. +* +* SYNOPSIS +*/ +typedef long osm_port_mask_t[32 / sizeof(long)]; +/* +* FIELDS +* osm_port_mask_t +* Bit mask by port number +* +* SEE ALSO +*********/ + +/****f* OpenSM: Port Profile/osm_port_prof_construct +* NAME +* osm_port_prof_construct +* +* DESCRIPTION +* +* +* SYNOPSIS +*/ +static inline void osm_port_prof_construct(IN osm_port_profile_t * const p_prof) +{ + CL_ASSERT(p_prof); + memset(p_prof, 0, sizeof(*p_prof)); +} +/* +* PARAMETERS +* p_prof +* [in] Pointer to the Port Profile object to construct. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Port Profile/osm_port_prof_path_count_inc +* NAME +* osm_port_prof_path_count_inc +* +* DESCRIPTION +* Increments the count of the number of paths going through this port. +* +* +* SYNOPSIS +*/ +static inline void +osm_port_prof_path_count_inc(IN osm_port_profile_t * const p_prof) +{ + CL_ASSERT(p_prof); + p_prof->num_paths++; +} +/* +* PARAMETERS +* p_prof +* [in] Pointer to the Port Profile object. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Port Profile/osm_port_prof_path_count_get +* NAME +* osm_port_prof_path_count_get +* +* DESCRIPTION +* Returns the count of the number of paths going through this port. +* +* SYNOPSIS +*/ +static inline uint32_t +osm_port_prof_path_count_get(IN const osm_port_profile_t * const p_prof) +{ + return (p_prof->num_paths); +} +/* +* PARAMETERS +* p_prof +* [in] Pointer to the Port Profile object. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_PORT_PROFILE_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_prefix_route.h b/contrib/ofed/management/opensm/include/opensm/osm_prefix_route.h new file mode 100644 index 000000000000..829a9ffe318e --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_prefix_route.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_PREFIX_ROUTE_H_ +#define _OSM_PREFIX_ROUTE_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +typedef struct { + cl_list_item_t list_item; /* must be first */ + ib_net64_t prefix; /* zero means "any" */ + ib_net64_t guid; /* zero means "any" */ +} osm_prefix_route_t; + +#ifdef ROUTER_EXP +#error ROUTER_EXP is deprecated, specify prefix routes at runtime instead (see opensm man page for details) +#endif + +END_C_DECLS +#endif /* _OSM_PREFIX_ROUTE_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_qos_policy.h b/contrib/ofed/management/opensm/include/opensm/osm_qos_policy.h new file mode 100644 index 000000000000..c38624ba7f75 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_qos_policy.h @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of OSM QoS Policy data types and functions. + * + * Author: + * Yevgeny Kliteynik, Mellanox + */ + +#ifndef OSM_QOS_POLICY_H +#define OSM_QOS_POLICY_H + +#include +#include +#include +#include +#include + +#define YYSTYPE char * +#define OSM_QOS_POLICY_MAX_PORTS_ON_SWITCH 128 +#define OSM_QOS_POLICY_DEFAULT_LEVEL_NAME "default" + +#define OSM_QOS_POLICY_ULP_SDP_SERVICE_ID 0x0000000000010000ULL +#define OSM_QOS_POLICY_ULP_RDS_SERVICE_ID 0x0000000001060000ULL +#define OSM_QOS_POLICY_ULP_RDS_PORT 0x48CA +#define OSM_QOS_POLICY_ULP_ISER_SERVICE_ID 0x0000000001060000ULL +#define OSM_QOS_POLICY_ULP_ISER_PORT 0x0CBC + +#define OSM_QOS_POLICY_NODE_TYPE_CA (((uint8_t)1)< +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Remote SM +* NAME +* Remote SM +* +* DESCRIPTION +* The Remote SM object encapsulates the information tracked for +* other SM ports on the subnet. +* +* The Remote SM object is thread safe. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Remote SM/osm_remote_sm_t +* NAME +* osm_remote_sm_t +* +* DESCRIPTION +* Remote Subnet Manager structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_remote_sm { + cl_map_item_t map_item; + const osm_port_t *p_port; + ib_sm_info_t smi; +} osm_remote_sm_t; +/* +* FIELDS +* map_item +* Linkage for the cl_qmap container. MUST BE FIRST ELEMENT!! +* p_port +* Pointer to the port object for this SM. +* +* smi +* The SMInfo attribute for this SM. +* +* SEE ALSO +*********/ + +/****f* OpenSM: SM/osm_remote_sm_construct +* NAME +* osm_remote_sm_construct +* +* DESCRIPTION +* This function constructs an Remote SM object. +* +* SYNOPSIS +*/ +void osm_remote_sm_construct(IN osm_remote_sm_t * const p_sm); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an Remote SM object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_remote_sm_init, osm_remote_sm_destroy +* +* Calling osm_remote_sm_construct is a prerequisite to calling any other +* method except osm_remote_sm_init. +* +* SEE ALSO +* SM object, osm_remote_sm_init, osm_remote_sm_destroy +*********/ + +/****f* OpenSM: SM/osm_remote_sm_destroy +* NAME +* osm_remote_sm_destroy +* +* DESCRIPTION +* The osm_remote_sm_destroy function destroys an SM, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_remote_sm_destroy(IN osm_remote_sm_t * const p_sm); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an Remote SM object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified Remote SM object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_remote_sm_construct or osm_remote_sm_init. +* +* SEE ALSO +* Remote SM object, osm_remote_sm_construct, osm_remote_sm_init +*********/ + +/****f* OpenSM: SM/osm_remote_sm_init +* NAME +* osm_remote_sm_init +* +* DESCRIPTION +* The osm_remote_sm_init function initializes an Remote SM object for use. +* +* SYNOPSIS +*/ +void +osm_remote_sm_init(IN osm_remote_sm_t * const p_sm, + IN const osm_port_t * const p_port, + IN const ib_sm_info_t * const p_smi); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_remote_sm_t object to initialize. +* +* p_port +* [in] Pointer to the Remote SM's port object. +* +* p_smi +* [in] Pointer to the SMInfo attribute for this SM. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* Allows calling other Remote SM methods. +* +* SEE ALSO +* Remote SM object, osm_remote_sm_construct, osm_remote_sm_destroy +*********/ + +END_C_DECLS +#endif /* _OSM_REMOTE_SM_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_router.h b/contrib/ofed/management/opensm/include/opensm/osm_router.h new file mode 100644 index 000000000000..4901aca4d337 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_router.h @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_router_t. + * This object represents an IBA router. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_ROUTER_H_ +#define _OSM_ROUTER_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Router +* NAME +* Router +* +* DESCRIPTION +* The Router object encapsulates the information needed by the +* OpenSM to manage routers. The OpenSM allocates one router object +* per router in the IBA subnet. +* +* The Router object is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Hal Rosenstock, Voltaire +* +*********/ +/****s* OpenSM: Router/osm_router_t +* NAME +* osm_router_t +* +* DESCRIPTION +* Router structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_router { + cl_map_item_t map_item; + osm_port_t *p_port; +} osm_router_t; +/* +* FIELDS +* map_item +* Linkage structure for cl_qmap. MUST BE FIRST MEMBER! +* +* p_port +* Pointer to the Port object for this router. +* +* SEE ALSO +* Router object +*********/ + +/****f* OpenSM: Router/osm_router_delete +* NAME +* osm_router_delete +* +* DESCRIPTION +* Destroys and deallocates the object. +* +* SYNOPSIS +*/ +void osm_router_delete(IN OUT osm_router_t ** const pp_rtr); +/* +* PARAMETERS +* p_rtr +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +* Router object, osm_router_new +*********/ + +/****f* OpenSM: Router/osm_router_new +* NAME +* osm_router_new +* +* DESCRIPTION +* The osm_router_new function initializes a Router object for use. +* +* SYNOPSIS +*/ +osm_router_t *osm_router_new(IN osm_port_t * const p_port); +/* +* PARAMETERS +* p_node +* [in] Pointer to the node object of this router +* +* RETURN VALUES +* Pointer to the new initialized router object. +* +* NOTES +* +* SEE ALSO +* Router object, osm_router_new +*********/ + +/****f* OpenSM: Router/osm_router_get_port_ptr +* NAME +* osm_router_get_port_ptr +* +* DESCRIPTION +* Returns a pointer to the Port object for this router. +* +* SYNOPSIS +*/ +static inline osm_port_t *osm_router_get_port_ptr(IN const osm_router_t * + const p_rtr) +{ + return (p_rtr->p_port); +} + +/* +* PARAMETERS +* p_rtr +* [in] Pointer to an osm_router_t object. +* +* RETURN VALUES +* Returns a pointer to the Port object for this router. +* +* NOTES +* +* SEE ALSO +* Router object +*********/ + +/****f* OpenSM: Router/osm_router_get_node_ptr +* NAME +* osm_router_get_node_ptr +* +* DESCRIPTION +* Returns a pointer to the Node object for this router. +* +* SYNOPSIS +*/ +static inline osm_node_t *osm_router_get_node_ptr(IN const osm_router_t * + const p_rtr) +{ + return (p_rtr->p_port->p_node); +} + +/* +* PARAMETERS +* p_rtr +* [in] Pointer to an osm_router_t object. +* +* RETURN VALUES +* Returns a pointer to the Node object for this router. +* +* NOTES +* +* SEE ALSO +* Router object +*********/ + +END_C_DECLS +#endif /* _OSM_ROUTER_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_sa.h b/contrib/ofed/management/opensm/include/opensm/osm_sa.h new file mode 100644 index 000000000000..5a0ae9f4eac7 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_sa.h @@ -0,0 +1,496 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_sa_t. + * This object represents an IBA subnet. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_SA_H_ +#define _OSM_SA_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/SA +* NAME +* SA +* +* DESCRIPTION +* The SA object encapsulates the information needed by the +* OpenSM to instantiate a subnet administrator. The OpenSM allocates +* one SA object per subnet manager. +* +* The SA object is thread safe. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* AUTHOR +* Ranjit Pandit, Intel +* Anil Keshavamurthy, Intel +* +*********/ +/****d* OpenSM: SA/osm_sa_state_t +* NAME +* osm_sa_state_t +* +* DESCRIPTION +* Enumerates the possible states of SA object. +* +* SYNOPSIS +*/ +typedef enum _osm_sa_state { + OSM_SA_STATE_INIT = 0, + OSM_SA_STATE_READY +} osm_sa_state_t; +/***********/ + +/****s* OpenSM: SM/osm_sa_t +* NAME +* osm_sa_t +* +* DESCRIPTION +* Subnet Administration structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_sa { + osm_sa_state_t state; + osm_sm_t *sm; + osm_subn_t *p_subn; + osm_vendor_t *p_vendor; + osm_log_t *p_log; + osm_mad_pool_t *p_mad_pool; + cl_dispatcher_t *p_disp; + cl_plock_t *p_lock; + atomic32_t sa_trans_id; + osm_sa_mad_ctrl_t mad_ctrl; + cl_timer_t sr_timer; + cl_disp_reg_handle_t cpi_disp_h; + cl_disp_reg_handle_t nr_disp_h; + cl_disp_reg_handle_t pir_disp_h; + cl_disp_reg_handle_t gir_disp_h; + cl_disp_reg_handle_t lr_disp_h; + cl_disp_reg_handle_t pr_disp_h; + cl_disp_reg_handle_t smir_disp_h; + cl_disp_reg_handle_t mcmr_disp_h; + cl_disp_reg_handle_t sr_disp_h; +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + cl_disp_reg_handle_t mpr_disp_h; +#endif + cl_disp_reg_handle_t infr_disp_h; + cl_disp_reg_handle_t infir_disp_h; + cl_disp_reg_handle_t vlarb_disp_h; + cl_disp_reg_handle_t slvl_disp_h; + cl_disp_reg_handle_t pkey_disp_h; + cl_disp_reg_handle_t lft_disp_h; + cl_disp_reg_handle_t sir_disp_h; + cl_disp_reg_handle_t mft_disp_h; +} osm_sa_t; +/* +* FIELDS +* state +* State of this SA object +* +* sm +* Pointer to the Subnet Manager object. +* +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_vendor +* Pointer to the vendor specific interfaces object. +* +* p_log +* Pointer to the log object. +* +* p_mad_pool +* Pointer to the MAD pool. +* +* p_disp +* Pointer to dispatcher +* +* p_lock +* Pointer to Lock for serialization +* +* sa_trans_id +* Transaction ID +* +* mad_ctrl +* Mad Controller +* +* SEE ALSO +* SM object +*********/ + +/****f* OpenSM: SA/osm_sa_construct +* NAME +* osm_sa_construct +* +* DESCRIPTION +* This function constructs an SA object. +* +* SYNOPSIS +*/ +void osm_sa_construct(IN osm_sa_t * const p_sa); +/* +* PARAMETERS +* p_sa +* [in] Pointer to a SA object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sa_destroy. +* +* Calling osm_sa_construct is a prerequisite to calling any other +* method except osm_sa_init. +* +* SEE ALSO +* SA object, osm_sa_init, osm_sa_destroy +*********/ + +/****f* OpenSM: SA/osm_sa_shutdown +* NAME +* osm_sa_shutdown +* +* DESCRIPTION +* The osm_sa_shutdown function shutdowns an SA, unregistering from all +* dispatcher messages and unbinding the QP1 mad service +* +* SYNOPSIS +*/ +void osm_sa_shutdown(IN osm_sa_t * const p_sa); +/* +* PARAMETERS +* p_sa +* [in] Pointer to a SA object to shutdown. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* SA object, osm_sa_construct, osm_sa_init +*********/ + +/****f* OpenSM: SA/osm_sa_destroy +* NAME +* osm_sa_destroy +* +* DESCRIPTION +* The osm_sa_destroy function destroys an SA, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_sa_destroy(IN osm_sa_t * const p_sa); +/* +* PARAMETERS +* p_sa +* [in] Pointer to a SA object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified SA object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_sa_construct or +* osm_sa_init. +* +* SEE ALSO +* SA object, osm_sa_construct, osm_sa_init +*********/ + +/****f* OpenSM: SA/osm_sa_init +* NAME +* osm_sa_init +* +* DESCRIPTION +* The osm_sa_init function initializes a SA object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_sa_init(IN osm_sm_t * const p_sm, + IN osm_sa_t * const p_sa, + IN osm_subn_t * const p_subn, + IN osm_vendor_t * const p_vendor, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_log_t * const p_log, + IN osm_stats_t * const p_stats, + IN cl_dispatcher_t * const p_disp, + IN cl_plock_t * const p_lock); +/* +* PARAMETERS +* p_sa +* [in] Pointer to an osm_sa_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_vendor +* [in] Pointer to the vendor specific interfaces object. +* +* p_mad_pool +* [in] Pointer to the MAD pool. +* +* p_log +* [in] Pointer to the log object. +* +* p_stats +* [in] Pointer to the statistics object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* CL_SUCCESS if the SA object was initialized successfully. +* +* NOTES +* Allows calling other SA methods. +* +* SEE ALSO +* SA object, osm_sa_construct, osm_sa_destroy +*********/ + +/****f* OpenSM: SA/osm_sa_bind +* NAME +* osm_sa_bind +* +* DESCRIPTION +* Binds the SA object to a port guid. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sa_bind(IN osm_sa_t * const p_sa, IN const ib_net64_t port_guid); +/* +* PARAMETERS +* p_sa +* [in] Pointer to an osm_sa_t object to bind. +* +* port_guid +* [in] Local port GUID with which to bind. +* +* +* RETURN VALUES +* None +* +* NOTES +* A given SA object can only be bound to one port at a time. +* +* SEE ALSO +*********/ + +/****f* OpenSM: SA/osm_sa_send +* NAME +* osm_sa_send +* +* DESCRIPTION +* Sends SA MAD via osm_vendor_send and maintains the QP1 sent statistic +* +* SYNOPSIS +*/ +ib_api_status_t osm_sa_send(osm_sa_t *sa, IN osm_madw_t * const p_madw, + IN boolean_t const resp_expected); + +/****f* IBA Base: Types/osm_sa_send_error +* NAME +* osm_sa_send_error +* +* DESCRIPTION +* Sends a generic SA response with the specified error status. +* The payload is simply replicated from the request MAD. +* +* SYNOPSIS +*/ +void osm_sa_send_error(IN osm_sa_t * sa, IN const osm_madw_t * const p_madw, + IN const ib_net16_t sa_status); +/* +* PARAMETERS +* sa +* [in] Pointer to an osm_sa_t object. +* +* p_madw +* [in] Original MAD to which the response must be sent. +* +* sa_status +* [in] Status to send in the response. +* +* RETURN VALUES +* None. +* +* SEE ALSO +* SA object +*********/ + +/****f* OpenSM: SA/osm_sa_respond +* NAME +* osm_sa_respond +* +* DESCRIPTION +* Sends SA MAD response +*/ +void osm_sa_respond(osm_sa_t *sa, osm_madw_t *madw, size_t attr_size, + cl_qlist_t *list); +/* +* PARAMETERS +* sa +* [in] Pointer to an osm_sa_t object. +* +* p_madw +* [in] Original MAD to which the response must be sent. +* +* attr_size +* [in] Size of this SA attribute. +* +* list +* [in] List of attribute to respond - it will be freed after +* sending. +* +* RETURN VALUES +* None. +* +* SEE ALSO +* SA object +*********/ + +struct osm_opensm; +/****f* OpenSM: SA/osm_sa_db_file_dump +* NAME +* osm_sa_db_file_dump +* +* DESCRIPTION +* Dumps the SA DB to the dump file. +* +* SYNOPSIS +*/ +int osm_sa_db_file_dump(struct osm_opensm *p_osm); +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object. +* +* RETURN VALUES +* None +* +*********/ + +/****f* OpenSM: SA/osm_sa_db_file_load +* NAME +* osm_sa_db_file_load +* +* DESCRIPTION +* Loads SA DB from the file. +* +* SYNOPSIS +*/ +int osm_sa_db_file_load(struct osm_opensm *p_osm); +/* +* PARAMETERS +* p_osm +* [in] Pointer to an osm_opensm_t object. +* +* RETURN VALUES +* 0 on success, other value on failure. +* +*********/ + +/****f* OpenSM: MC Member Record Receiver/osm_mcmr_rcv_find_or_create_new_mgrp +* NAME +* osm_mcmr_rcv_find_or_create_new_mgrp +* +* DESCRIPTION +* Create new Multicast group +* +* SYNOPSIS +*/ + +ib_api_status_t +osm_mcmr_rcv_find_or_create_new_mgrp(IN osm_sa_t * sa, + IN uint64_t comp_mask, + IN ib_member_rec_t * + const p_recvd_mcmember_rec, + OUT osm_mgrp_t ** pp_mgrp); +/* +* PARAMETERS +* p_sa +* [in] Pointer to an osm_sa_t object. +* p_recvd_mcmember_rec +* [in] Received Multicast member record +* +* pp_mgrp +* [out] pointer the osm_mgrp_t object +* +* RETURN VALUES +* IB_SUCCESS, IB_ERROR +* +*********/ + +osm_mgrp_t *osm_get_mgrp_by_mgid(IN osm_sa_t * sa, IN ib_gid_t * p_mgid); + +END_C_DECLS +#endif /* _OSM_SA_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_sa_mad_ctrl.h b/contrib/ofed/management/opensm/include/opensm/osm_sa_mad_ctrl.h new file mode 100644 index 000000000000..cc2ac531d224 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_sa_mad_ctrl.h @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_sa_mad_ctrl_t. + * This object represents a controller that receives the IBA SA + * attributes from a node. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_SA_MAD_CTRL_H_ +#define _OSM_SA_MAD_CTRL_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/SA MAD Controller +* NAME +* SA MAD Controller +* +* DESCRIPTION +* The SA MAD Controller object encapsulates +* the information needed to receive MADs from the transport layer. +* +* The SA MAD Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Ranjit Pandit, Intel +* +*********/ + +struct osm_sa; +/****s* OpenSM: SA MAD Controller/osm_sa_mad_ctrl_t +* NAME +* osm_sa_mad_ctrl_t +* +* DESCRIPTION +* SA MAD Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_sa_mad_ctrl { + struct osm_sa *sa; + osm_log_t *p_log; + osm_mad_pool_t *p_mad_pool; + osm_vendor_t *p_vendor; + osm_bind_handle_t h_bind; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + osm_stats_t *p_stats; + osm_subn_t *p_subn; +} osm_sa_mad_ctrl_t; +/* +* FIELDS +* sa +* Pointer to the SA object. +* +* p_log +* Pointer to the log object. +* +* p_mad_pool +* Pointer to the MAD pool. +* +* p_vendor +* Pointer to the vendor specific interfaces object. +* +* h_bind +* Bind handle returned by the transport layer. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* p_stats +* Pointer to the OpenSM statistics block. +* +* SEE ALSO +* SA MAD Controller object +* SA MADr object +*********/ + +/****f* OpenSM: SA MAD Controller/osm_sa_mad_ctrl_construct +* NAME +* osm_sa_mad_ctrl_construct +* +* DESCRIPTION +* This function constructs a SA MAD Controller object. +* +* SYNOPSIS +*/ +void osm_sa_mad_ctrl_construct(IN osm_sa_mad_ctrl_t * const p_ctrl); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a SA MAD Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sa_mad_ctrl_init, and osm_sa_mad_ctrl_destroy. +* +* Calling osm_sa_mad_ctrl_construct is a prerequisite to calling any other +* method except osm_sa_mad_ctrl_init. +* +* SEE ALSO +* SA MAD Controller object, osm_sa_mad_ctrl_init, +* osm_sa_mad_ctrl_destroy +*********/ + +/****f* OpenSM: SA MAD Controller/osm_sa_mad_ctrl_destroy +* NAME +* osm_sa_mad_ctrl_destroy +* +* DESCRIPTION +* The osm_sa_mad_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_sa_mad_ctrl_destroy(IN osm_sa_mad_ctrl_t * const p_ctrl); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* SA MAD Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_sa_mad_ctrl_construct or osm_sa_mad_ctrl_init. +* +* SEE ALSO +* SA MAD Controller object, osm_sa_mad_ctrl_construct, +* osm_sa_mad_ctrl_init +*********/ + +/****f* OpenSM: SA MAD Controller/osm_sa_mad_ctrl_init +* NAME +* osm_sa_mad_ctrl_init +* +* DESCRIPTION +* The osm_sa_mad_ctrl_init function initializes a +* SA MAD Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t osm_sa_mad_ctrl_init(IN osm_sa_mad_ctrl_t * const p_ctrl, + IN struct osm_sa * sa, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vendor_t * const p_vendor, + IN osm_subn_t * const p_subn, + IN osm_log_t * const p_log, + IN osm_stats_t * const p_stats, + IN cl_dispatcher_t * const p_disp); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sa_mad_ctrl_t object to initialize. +* +* sa +* [in] Pointer to the SA object. +* +* p_mad_pool +* [in] Pointer to the MAD pool. +* +* p_vendor +* [in] Pointer to the vendor specific interfaces object. +* +* p_log +* [in] Pointer to the log object. +* +* p_stats +* [in] Pointer to the OpenSM stastics block. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* IB_SUCCESS if the SA MAD Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other SA MAD Controller methods. +* +* SEE ALSO +* SA MAD Controller object, osm_sa_mad_ctrl_construct, +* osm_sa_mad_ctrl_destroy +*********/ + +/****f* OpenSM: SA/osm_sa_mad_ctrl_bind +* NAME +* osm_sa_mad_ctrl_bind +* +* DESCRIPTION +* Binds the SA MAD Controller object to a port guid. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sa_mad_ctrl_bind(IN osm_sa_mad_ctrl_t * const p_ctrl, + IN const ib_net64_t port_guid); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sa_mad_ctrl_t object to initialize. +* +* port_guid +* [in] Local port GUID with which to bind. +* +* +* RETURN VALUES +* None +* +* NOTES +* A given SA MAD Controller object can only be bound to one +* port at a time. +* +* SEE ALSO +*********/ + +/****f* OpenSM: SA/osm_sa_mad_ctrl_unbind +* NAME +* osm_sa_mad_ctrl_unbind +* +* DESCRIPTION +* Un-Binds the SA MAD Controller object from the IB port +* +* SYNOPSIS +*/ +ib_api_status_t osm_sa_mad_ctrl_unbind(IN osm_sa_mad_ctrl_t * const p_ctrl); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sa_mad_ctrl_t object to initialize. +* +* RETURN VALUES +* None +* +* NOTES +* A given SA MAD Controller should be previously bound to IB +* port. +* +* SEE ALSO +*********/ + +/****f* OpenSM: SA/osm_sa_mad_ctrl_get_bind_handle +* NAME +* osm_sa_mad_ctrl_get_bind_handle +* +* DESCRIPTION +* Returns the bind handle. +* +* SYNOPSIS +*/ +static inline osm_bind_handle_t +osm_sa_mad_ctrl_get_bind_handle(IN const osm_sa_mad_ctrl_t * const p_ctrl) +{ + return (p_ctrl->h_bind); +} + +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sa_mad_ctrl_t object. +* +* RETURN VALUES +* Returns the bind handle, which may be OSM_BIND_INVALID_HANDLE +* if no port has been bound. +* +* NOTES +* A given SA MAD Controller object can only be bound to one +* port at a time. +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_SA_MAD_CTRL_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_service.h b/contrib/ofed/management/opensm/include/opensm/osm_service.h new file mode 100644 index 000000000000..1d97a68716e6 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_service.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_SVCR_H_ +#define _OSM_SVCR_H_ + +/* + * Abstract: + * Declaration of osm_service_rec_t. + * This object represents an IBA Service Record. + * This object is part of the OpenSM family of objects. + */ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Service Record +* NAME +* Service Record +* +* DESCRIPTION +* The service record encapsulates the information needed by the +* SA to manage service registrations. +* +* The service records is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Anil S Keshavamurthy, Intel +* +*********/ +/****s* OpenSM: Service Record/osm_svcr_t +* NAME +* osm_svcr_t +* +* DESCRIPTION +* Service Record structure. +* +* The osm_svcr_t object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_svcr { + cl_list_item_t list_item; + ib_service_record_t service_record; + uint32_t modified_time; + uint32_t lease_period; +} osm_svcr_t; +/* +* FIELDS +* map_item +* Map Item for qmap linkage. Must be first element!! +* +* svc_rec +* IB Service record structure +* +* modified_time +* Last modified time of this record in milliseconds +* +* lease_period +* Remaining lease period for this record +* +* +* SEE ALSO +*********/ + +/****f* OpenSM: Service Record/osm_svcr_new +* NAME +* osm_svcr_new +* +* DESCRIPTION +* Allocates and initializes a Service Record for use. +* +* SYNOPSIS +*/ +osm_svcr_t *osm_svcr_new(IN const ib_service_record_t * p_svc_rec); +/* +* PARAMETERS +* p_svc_rec +* [in] Pointer to IB Service Record +* +* RETURN VALUES +* pointer to osm_svcr_t structure. +* +* NOTES +* Allows calling other service record methods. +* +* SEE ALSO +* Service Record, osm_svcr_delete +*********/ + +/****f* OpenSM: Service Record/osm_svcr_init +* NAME +* osm_svcr_init +* +* DESCRIPTION +* Initializes the osm_svcr_t structure. +* +* SYNOPSIS +*/ +void +osm_svcr_init(IN osm_svcr_t * const p_svcr, + IN const ib_service_record_t * p_svc_rec); +/* +* PARAMETERS +* p_svc_rec +* [in] Pointer to osm_svcr_t structure +* p_svc_rec +* [in] Pointer to the ib_service_record_t +* +* SEE ALSO +* Service Record +*********/ + +/****f* OpenSM: Service Record/osm_svcr_delete +* NAME +* osm_svcr_delete +* +* DESCRIPTION +* Deallocates the osm_svcr_t structure. +* +* SYNOPSIS +*/ +void osm_svcr_delete(IN osm_svcr_t * const p_svcr); +/* +* PARAMETERS +* p_svc_rec +* [in] Pointer to osm_svcr_t structure +* +* SEE ALSO +* Service Record, osm_svcr_new +*********/ + +osm_svcr_t *osm_svcr_get_by_rid(IN osm_subn_t const *p_subn, + IN osm_log_t * p_log, + IN ib_service_record_t * const p_svc_rec); + +void +osm_svcr_insert_to_db(IN osm_subn_t * p_subn, + IN osm_log_t * p_log, IN osm_svcr_t * p_svcr); +void +osm_svcr_remove_from_db(IN osm_subn_t * p_subn, + IN osm_log_t * p_log, IN osm_svcr_t * p_svcr); + +END_C_DECLS +#endif /* _OSM_SVCR_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_sm.h b/contrib/ofed/management/opensm/include/opensm/osm_sm.h new file mode 100644 index 000000000000..ebe3dc33d3eb --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_sm.h @@ -0,0 +1,798 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_sm_t. + * This object represents an IBA subnet. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_SM_H_ +#define _OSM_SM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/SM +* NAME +* SM +* +* DESCRIPTION +* The SM object encapsulates the information needed by the +* OpenSM to instantiate a subnet manager. The OpenSM allocates +* one SM object per subnet manager. +* +* The SM object is thread safe. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: SM/osm_sm_t +* NAME +* osm_sm_t +* +* DESCRIPTION +* Subnet Manager structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_sm { + osm_thread_state_t thread_state; + unsigned signal_mask; + cl_spinlock_t signal_lock; + cl_spinlock_t state_lock; + cl_event_t signal_event; + cl_event_t subnet_up_event; + cl_timer_t sweep_timer; + cl_timer_t polling_timer; + cl_event_wheel_t trap_aging_tracker; + cl_thread_t sweeper; + unsigned master_sm_found; + uint32_t retry_number; + ib_net64_t master_sm_guid; + osm_remote_sm_t *p_polling_sm; + osm_subn_t *p_subn; + osm_db_t *p_db; + osm_vendor_t *p_vendor; + osm_log_t *p_log; + osm_mad_pool_t *p_mad_pool; + osm_vl15_t *p_vl15; + cl_dispatcher_t *p_disp; + cl_plock_t *p_lock; + atomic32_t sm_trans_id; + cl_spinlock_t mgrp_lock; + cl_qlist_t mgrp_list; + osm_sm_mad_ctrl_t mad_ctrl; + osm_lid_mgr_t lid_mgr; + osm_ucast_mgr_t ucast_mgr; + cl_disp_reg_handle_t sweep_fail_disp_h; + cl_disp_reg_handle_t ni_disp_h; + cl_disp_reg_handle_t pi_disp_h; + cl_disp_reg_handle_t nd_disp_h; + cl_disp_reg_handle_t si_disp_h; + cl_disp_reg_handle_t lft_disp_h; + cl_disp_reg_handle_t mft_disp_h; + cl_disp_reg_handle_t sm_info_disp_h; + cl_disp_reg_handle_t trap_disp_h; + cl_disp_reg_handle_t slvl_disp_h; + cl_disp_reg_handle_t vla_disp_h; + cl_disp_reg_handle_t pkey_disp_h; +} osm_sm_t; +/* +* FIELDS +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_db +* Pointer to the database (persistency) object +* +* p_vendor +* Pointer to the vendor specific interfaces object. +* +* p_log +* Pointer to the log object. +* +* p_mad_pool +* Pointer to the MAD pool. +* +* p_vl15 +* Pointer to the VL15 interface. +* +* mad_ctrl +* MAD Controller. +* +* p_disp +* Pointer to the Dispatcher. +* +* p_lock +* Pointer to the serializing lock. +* +* SEE ALSO +* SM object +*********/ + +/****f* OpenSM: SM/osm_sm_construct +* NAME +* osm_sm_construct +* +* DESCRIPTION +* This function constructs an SM object. +* +* SYNOPSIS +*/ +void osm_sm_construct(IN osm_sm_t * const p_sm); +/* +* PARAMETERS +* p_sm +* [in] Pointer to a SM object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sm_init, osm_sm_destroy +* +* Calling osm_sm_construct is a prerequisite to calling any other +* method except osm_sm_init. +* +* SEE ALSO +* SM object, osm_sm_init, osm_sm_destroy +*********/ + +/****f* OpenSM: SM/osm_sm_shutdown +* NAME +* osm_sm_shutdown +* +* DESCRIPTION +* The osm_sm_shutdown function shutdowns an SM, stopping the sweeper +* and unregistering all messages from the dispatcher +* +* SYNOPSIS +*/ +void osm_sm_shutdown(IN osm_sm_t * const p_sm); +/* +* PARAMETERS +* p_sm +* [in] Pointer to a SM object to shutdown. +* +* RETURN VALUE +* This function does not return a value. +* +* SEE ALSO +* SM object, osm_sm_construct, osm_sm_init +*********/ + +/****f* OpenSM: SM/osm_sm_destroy +* NAME +* osm_sm_destroy +* +* DESCRIPTION +* The osm_sm_destroy function destroys an SM, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_sm_destroy(IN osm_sm_t * const p_sm); +/* +* PARAMETERS +* p_sm +* [in] Pointer to a SM object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified SM object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_sm_construct or +* osm_sm_init. +* +* SEE ALSO +* SM object, osm_sm_construct, osm_sm_init +*********/ + +/****f* OpenSM: SM/osm_sm_init +* NAME +* osm_sm_init +* +* DESCRIPTION +* The osm_sm_init function initializes a SM object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sm_init(IN osm_sm_t * const p_sm, + IN osm_subn_t * const p_subn, + IN osm_db_t * const p_db, + IN osm_vendor_t * const p_vendor, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vl15_t * const p_vl15, + IN osm_log_t * const p_log, + IN osm_stats_t * const p_stats, + IN cl_dispatcher_t * const p_disp, IN cl_plock_t * const p_lock); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_sm_t object to initialize. +* +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_vendor +* [in] Pointer to the vendor specific interfaces object. +* +* p_mad_pool +* [in] Pointer to the MAD pool. +* +* p_vl15 +* [in] Pointer to the VL15 interface. +* +* p_log +* [in] Pointer to the log object. +* +* p_stats +* [in] Pointer to the statistics object. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* RETURN VALUES +* IB_SUCCESS if the SM object was initialized successfully. +* +* NOTES +* Allows calling other SM methods. +* +* SEE ALSO +* SM object, osm_sm_construct, osm_sm_destroy +*********/ + +/****f* OpenSM: SM/osm_sm_signal +* NAME +* osm_sm_signal +* +* DESCRIPTION +* Signal event to SM +* +* SYNOPSIS +*/ +void osm_sm_signal(IN osm_sm_t * const p_sm, osm_signal_t signal); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_sm_t object. +* +* signal +* [in] sm signal number. +* +* NOTES +* +* SEE ALSO +* SM object +*********/ + +/****f* OpenSM: SM/osm_sm_sweep +* NAME +* osm_sm_sweep +* +* DESCRIPTION +* Initiates a subnet sweep. +* +* SYNOPSIS +*/ +void osm_sm_sweep(IN osm_sm_t * const p_sm); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_sm_t object. +* +* RETURN VALUES +* IB_SUCCESS if the sweep completed successfully. +* +* NOTES +* +* SEE ALSO +* SM object +*********/ + +/****f* OpenSM: SM/osm_sm_bind +* NAME +* osm_sm_bind +* +* DESCRIPTION +* Binds the sm object to a port guid. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sm_bind(IN osm_sm_t * const p_sm, IN const ib_net64_t port_guid); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_sm_t object to bind. +* +* port_guid +* [in] Local port GUID with which to bind. +* +* +* RETURN VALUES +* None +* +* NOTES +* A given SM object can only be bound to one port at a time. +* +* SEE ALSO +*********/ + +/****f* OpenSM: SM/osm_req_get +* NAME +* osm_req_get +* +* DESCRIPTION +* Starts the process to transmit a directed route request for +* the attribute. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_req_get(IN osm_sm_t * sm, + IN const osm_dr_path_t * const p_path, + IN const uint16_t attr_id, + IN const uint32_t attr_mod, + IN const cl_disp_msgid_t err_msg, + IN const osm_madw_context_t * const p_context); +/* +* PARAMETERS +* sm +* [in] Pointer to an osm_sm_t object. +* +* p_path +* [in] Pointer to the directed route path to the node +* from which to retrieve the attribute. +* +* attr_id +* [in] Attribute ID to request. +* +* attr_mod +* [in] Attribute modifier for this request. +* +* err_msg +* [in] Message id with which to post this MAD if an error occurs. +* +* p_context +* [in] Mad wrapper context structure to be copied into the wrapper +* context, and thus visible to the recipient of the response. +* +* RETURN VALUES +* IB_SUCCESS if the request was successful. +* +* NOTES +* This function asynchronously requests the specified attribute. +* The response from the node will be routed through the Dispatcher +* to the appropriate receive controller object. +*********/ +/****f* OpenSM: SM/osm_req_set +* NAME +* osm_req_set +* +* DESCRIPTION +* Starts the process to transmit a directed route Set() request. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_req_set(IN osm_sm_t * sm, + IN const osm_dr_path_t * const p_path, + IN const uint8_t * const p_payload, + IN const size_t payload_size, + IN const uint16_t attr_id, + IN const uint32_t attr_mod, + IN const cl_disp_msgid_t err_msg, + IN const osm_madw_context_t * const p_context); +/* +* PARAMETERS +* sm +* [in] Pointer to an osm_sm_t object. +* +* p_path +* [in] Pointer to the directed route path of the recipient. +* +* p_payload +* [in] Pointer to the SMP payload to send. +* +* payload_size +* [in] The size of the payload to be copied to the SMP data field. +* +* attr_id +* [in] Attribute ID to request. +* +* attr_mod +* [in] Attribute modifier for this request. +* +* err_msg +* [in] Message id with which to post this MAD if an error occurs. +* +* p_context +* [in] Mad wrapper context structure to be copied into the wrapper +* context, and thus visible to the recipient of the response. +* +* RETURN VALUES +* IB_SUCCESS if the request was successful. +* +* NOTES +* This function asynchronously requests the specified attribute. +* The response from the node will be routed through the Dispatcher +* to the appropriate receive controller object. +*********/ +/****f* OpenSM: SM/osm_resp_send +* NAME +* osm_resp_send +* +* DESCRIPTION +* Starts the process to transmit a directed route response. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_resp_send(IN osm_sm_t * sm, + IN const osm_madw_t * const p_req_madw, + IN const ib_net16_t status, IN const uint8_t * const p_payload); +/* +* PARAMETERS +* p_resp +* [in] Pointer to an osm_resp_t object. +* +* p_madw +* [in] Pointer to the MAD Wrapper object for the requesting MAD +* to which this response is generated. +* +* status +* [in] Status for this response. +* +* p_payload +* [in] Pointer to the payload of the response MAD. +* +* RETURN VALUES +* IB_SUCCESS if the response was successful. +* +*********/ + +/****f* OpenSM: SM/osm_sm_mcgrp_join +* NAME +* osm_sm_mcgrp_join +* +* DESCRIPTION +* Adds a port to the multicast group. Creates the multicast group +* if necessary. +* +* This function is called by the SA. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sm_mcgrp_join(IN osm_sm_t * const p_sm, + IN const ib_net16_t mlid, + IN const ib_net64_t port_guid, + IN osm_mcast_req_type_t req_type); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_sm_t object. +* +* mlid +* [in] Multicast LID +* +* port_guid +* [in] Port GUID to add to the group. +* +* req_type +* [in] Type of the MC request that caused this join +* (MC create/join). +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: SM/osm_sm_mcgrp_leave +* NAME +* osm_sm_mcgrp_leave +* +* DESCRIPTION +* Removes a port from the multicast group. +* +* This function is called by the SA. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sm_mcgrp_leave(IN osm_sm_t * const p_sm, + IN const ib_net16_t mlid, IN const ib_net64_t port_guid); +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_sm_t object. +* +* mlid +* [in] Multicast LID +* +* port_guid +* [in] Port GUID to remove from the group. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: OpenSM/osm_sm_wait_for_subnet_up +* NAME +* osm_sm_wait_for_subnet_up +* +* DESCRIPTION +* Blocks the calling thread until the subnet is up. +* +* SYNOPSIS +*/ +static inline cl_status_t +osm_sm_wait_for_subnet_up(IN osm_sm_t * const p_sm, + IN uint32_t const wait_us, + IN boolean_t const interruptible) +{ + return (cl_event_wait_on(&p_sm->subnet_up_event, + wait_us, interruptible)); +} + +/* +* PARAMETERS +* p_sm +* [in] Pointer to an osm_sm_t object. +* +* wait_us +* [in] Number of microseconds to wait. +* +* interruptible +* [in] Indicates whether the wait operation can be interrupted +* by external signals. +* +* RETURN VALUES +* CL_SUCCESS if the wait operation succeeded in response to the event +* being set. +* +* CL_TIMEOUT if the specified time period elapses. +* +* CL_NOT_DONE if the wait was interrupted by an external signal. +* +* CL_ERROR if the wait operation failed. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: State Manager/osm_sm_is_greater_than +* NAME +* osm_sm_is_greater_than +* +* DESCRIPTION +* Compares two SM's (14.4.1.2) +* +* SYNOPSIS +*/ +static inline boolean_t +osm_sm_is_greater_than(IN const uint8_t l_priority, + IN const ib_net64_t l_guid, + IN const uint8_t r_priority, IN const ib_net64_t r_guid) +{ + return (l_priority > r_priority + || (l_priority == r_priority + && cl_ntoh64(l_guid) < cl_ntoh64(r_guid))); +} + +/* +* PARAMETERS +* l_priority +* [in] Priority of the SM on the "left" +* +* l_guid +* [in] GUID of the SM on the "left" +* +* r_priority +* [in] Priority of the SM on the "right" +* +* r_guid +* [in] GUID of the SM on the "right" +* +* RETURN VALUES +* Return TRUE if an sm with l_priority and l_guid is higher than an sm +* with r_priority and r_guid, return FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* State Manager +*********/ + +/****f* OpenSM: SM State Manager/osm_sm_state_mgr_process +* NAME +* osm_sm_state_mgr_process +* +* DESCRIPTION +* Processes and maintains the states of the SM. +* +* SYNOPSIS +*/ +ib_api_status_t osm_sm_state_mgr_process(IN osm_sm_t *sm, + IN osm_sm_signal_t signal); +/* +* PARAMETERS +* sm +* [in] Pointer to an osm_sm_t object. +* +* signal +* [in] Signal to the state SM engine. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* State Manager +*********/ + +/****f* OpenSM: SM State Manager/osm_sm_state_mgr_signal_master_is_alive +* NAME +* osm_sm_state_mgr_signal_master_is_alive +* +* DESCRIPTION +* Signals that the remote Master SM is alive. +* Need to clear the retry_number variable. +* +* SYNOPSIS +*/ +void osm_sm_state_mgr_signal_master_is_alive(IN osm_sm_t *sm); +/* +* PARAMETERS +* sm +* [in] Pointer to an osm_sm_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* State Manager +*********/ + +/****f* OpenSM: SM State Manager/osm_sm_state_mgr_check_legality +* NAME +* osm_sm_state_mgr_check_legality +* +* DESCRIPTION +* Checks the legality of the signal received, according to the +* current state of the SM state machine. +* +* SYNOPSIS +*/ +ib_api_status_t osm_sm_state_mgr_check_legality(IN osm_sm_t *sm, + IN osm_sm_signal_t signal); +/* +* PARAMETERS +* sm +* [in] Pointer to an osm_sm_t object. +* +* signal +* [in] Signal to the state SM engine. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* State Manager +*********/ + +void osm_report_sm_state(osm_sm_t *sm); + +/****f* OpenSM: SM State Manager/osm_send_trap144 +* NAME +* osm_send_trap144 +* +* DESCRIPTION +* Send trap 144 to the master SM. +* +* SYNOPSIS +*/ +int osm_send_trap144(osm_sm_t *sm, ib_net16_t local); +/* +* PARAMETERS +* sm +* [in] Pointer to an osm_sm_t object. +* +* local +* [in] OtherLocalChanges mask in network byte order. +* +* RETURN VALUES +* 0 on success, non-zero value otherwise. +* +*********/ + +void osm_set_sm_priority(osm_sm_t *sm, uint8_t priority); + +END_C_DECLS +#endif /* _OSM_SM_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_sm_mad_ctrl.h b/contrib/ofed/management/opensm/include/opensm/osm_sm_mad_ctrl.h new file mode 100644 index 000000000000..1c41168d76c2 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_sm_mad_ctrl.h @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_sm_mad_ctrl_t. + * This object represents a controller that receives the IBA NodeInfo + * attribute from a node. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_SM_MAD_CTRL_H_ +#define _OSM_SM_MAD_CTRL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/SM MAD Controller +* NAME +* SM MAD Controller +* +* DESCRIPTION +* The SM MAD Controller object encapsulates +* the information needed to receive MADs from the transport layer. +* +* The SM MAD Controller object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: SM MAD Controller/osm_sm_mad_ctrl_t +* NAME +* osm_sm_mad_ctrl_t +* +* DESCRIPTION +* SM MAD Controller structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_sm_mad_ctrl { + osm_log_t *p_log; + osm_subn_t *p_subn; + osm_mad_pool_t *p_mad_pool; + osm_vl15_t *p_vl15; + osm_vendor_t *p_vendor; + osm_bind_handle_t h_bind; + cl_plock_t *p_lock; + cl_dispatcher_t *p_disp; + cl_disp_reg_handle_t h_disp; + osm_stats_t *p_stats; +} osm_sm_mad_ctrl_t; +/* +* FIELDS +* p_log +* Pointer to the log object. +* +* p_subn +* Pointer to the subnet object. +* +* p_mad_pool +* Pointer to the MAD pool. +* +* p_vendor +* Pointer to the vendor specific interfaces object. +* +* h_bind +* Bind handle returned by the transport layer. +* +* p_lock +* Pointer to the serializing lock. +* +* p_disp +* Pointer to the Dispatcher. +* +* h_disp +* Handle returned from dispatcher registration. +* +* p_stats +* Pointer to the OpenSM statistics block. +* +* SEE ALSO +* SM MAD Controller object +* SM MADr object +*********/ + +/****f* OpenSM: SM MAD Controller/osm_sm_mad_ctrl_construct +* NAME +* osm_sm_mad_ctrl_construct +* +* DESCRIPTION +* This function constructs a SM MAD Controller object. +* +* SYNOPSIS +*/ +void osm_sm_mad_ctrl_construct(IN osm_sm_mad_ctrl_t * const p_ctrl); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to a SM MAD Controller +* object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_sm_mad_ctrl_init, and osm_sm_mad_ctrl_destroy. +* +* Calling osm_sm_mad_ctrl_construct is a prerequisite to calling any other +* method except osm_sm_mad_ctrl_init. +* +* SEE ALSO +* SM MAD Controller object, osm_sm_mad_ctrl_init, +* osm_sm_mad_ctrl_destroy +*********/ + +/****f* OpenSM: SM MAD Controller/osm_sm_mad_ctrl_destroy +* NAME +* osm_sm_mad_ctrl_destroy +* +* DESCRIPTION +* The osm_sm_mad_ctrl_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_sm_mad_ctrl_destroy(IN osm_sm_mad_ctrl_t * const p_ctrl); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* SM MAD Controller object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_sm_mad_ctrl_construct or osm_sm_mad_ctrl_init. +* +* SEE ALSO +* SM MAD Controller object, osm_sm_mad_ctrl_construct, +* osm_sm_mad_ctrl_init +*********/ + +/****f* OpenSM: SM MAD Controller/osm_sm_mad_ctrl_init +* NAME +* osm_sm_mad_ctrl_init +* +* DESCRIPTION +* The osm_sm_mad_ctrl_init function initializes a +* SM MAD Controller object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sm_mad_ctrl_init(IN osm_sm_mad_ctrl_t * const p_ctrl, + IN osm_subn_t * const p_subn, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vl15_t * const p_vl15, + IN osm_vendor_t * const p_vendor, + IN osm_log_t * const p_log, + IN osm_stats_t * const p_stats, + IN cl_plock_t * const p_lock, + IN cl_dispatcher_t * const p_disp); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sm_mad_ctrl_t object to initialize. +* +* p_mad_pool +* [in] Pointer to the MAD pool. +* +* p_vl15 +* [in] Pointer to the VL15 interface object. +* +* p_vendor +* [in] Pointer to the vendor specific interfaces object. +* +* p_log +* [in] Pointer to the log object. +* +* p_stats +* [in] Pointer to the OpenSM stastics block. +* +* p_lock +* [in] Pointer to the OpenSM serializing lock. +* +* p_disp +* [in] Pointer to the OpenSM central Dispatcher. +* +* RETURN VALUES +* IB_SUCCESS if the SM MAD Controller object was initialized +* successfully. +* +* NOTES +* Allows calling other SM MAD Controller methods. +* +* SEE ALSO +* SM MAD Controller object, osm_sm_mad_ctrl_construct, +* osm_sm_mad_ctrl_destroy +*********/ + +/****f* OpenSM: SM/osm_sm_mad_ctrl_bind +* NAME +* osm_sm_mad_ctrl_bind +* +* DESCRIPTION +* Binds the SM MAD Controller object to a port guid. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_sm_mad_ctrl_bind(IN osm_sm_mad_ctrl_t * const p_ctrl, + IN const ib_net64_t port_guid); +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sm_mad_ctrl_t object to initialize. +* +* port_guid +* [in] Local port GUID with which to bind. +* +* +* RETURN VALUES +* None +* +* NOTES +* A given SM MAD Controller object can only be bound to one +* port at a time. +* +* SEE ALSO +*********/ + +/****f* OpenSM: SM/osm_sm_mad_ctrl_get_bind_handle +* NAME +* osm_sm_mad_ctrl_get_bind_handle +* +* DESCRIPTION +* Returns the bind handle. +* +* SYNOPSIS +*/ +static inline osm_bind_handle_t +osm_sm_mad_ctrl_get_bind_handle(IN const osm_sm_mad_ctrl_t * const p_ctrl) +{ + return (p_ctrl->h_bind); +} + +/* +* PARAMETERS +* p_ctrl +* [in] Pointer to an osm_sm_mad_ctrl_t object. +* +* RETURN VALUES +* Returns the bind handle, which may be OSM_BIND_INVALID_HANDLE +* if no port has been bound. +* +* NOTES +* A given SM MAD Controller object can only be bound to one +* port at a time. +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_SM_MAD_CTRL_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_stats.h b/contrib/ofed/management/opensm/include/opensm/osm_stats.h new file mode 100644 index 000000000000..4331cfa3d353 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_stats.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_stats_t. + * This object represents the OpenSM statistics object. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_STATS_H_ +#define _OSM_STATS_H_ + +#ifdef HAVE_LIBPTHREAD +#include +#else +#include +#endif +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Statistics +* NAME +* OpenSM +* +* DESCRIPTION +* The OpenSM object encapsulates the information needed by the +* OpenSM to track interesting traffic and internal statistics. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Statistics/osm_stats_t +* NAME +* osm_stats_t +* +* DESCRIPTION +* OpenSM statistics block. +* +* SYNOPSIS +*/ +typedef struct osm_stats { + atomic32_t qp0_mads_outstanding; + atomic32_t qp0_mads_outstanding_on_wire; + atomic32_t qp0_mads_rcvd; + atomic32_t qp0_mads_sent; + atomic32_t qp0_unicasts_sent; + atomic32_t qp0_mads_rcvd_unknown; + atomic32_t sa_mads_outstanding; + atomic32_t sa_mads_rcvd; + atomic32_t sa_mads_sent; + atomic32_t sa_mads_rcvd_unknown; + atomic32_t sa_mads_ignored; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_t mutex; + pthread_cond_t cond; +#else + cl_event_t event; +#endif +} osm_stats_t; +/* +* FIELDS +* qp0_mads_outstanding +* Contains the number of MADs outstanding on QP0. +* When this value reaches zero, OpenSM has discovered all +* nodes on the subnet, and finished retrieving attributes. +* At that time, subnet configuration may begin. +* This variable must be manipulated using atomic instructions. +* +* qp0_mads_outstanding_on_wire +* The number of MADs outstanding on the wire at any moment. +* +* qp0_mads_rcvd +* Total number of QP0 MADs received. +* +* qp0_mads_sent +* Total number of QP0 MADs sent. +* +* qp0_unicasts_sent +* Total number of response-less MADs sent on the wire. This count +* includes getresp(), send() and trap() methods. +* +* qp0_mads_rcvd_unknown +* Total number of unknown QP0 MADs received. This includes +* unrecognized attribute IDs and methods. +* +* sa_mads_outstanding +* Contains the number of SA MADs outstanding on QP1. +* +* sa_mads_rcvd +* Total number of SA MADs received. +* +* sa_mads_sent +* Total number of SA MADs sent. +* +* sa_mads_rcvd_unknown +* Total number of unknown SA MADs received. This includes +* unrecognized attribute IDs and methods. +* +* sa_mads_ignored +* Total number of SA MADs received because SM is not +* master or SM is in first time sweep. +* +* SEE ALSO +***************/ + +static inline uint32_t osm_stats_inc_qp0_outstanding(osm_stats_t *stats) +{ + uint32_t outstanding; + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&stats->mutex); + outstanding = ++stats->qp0_mads_outstanding; + pthread_mutex_unlock(&stats->mutex); +#else + outstanding = cl_atomic_inc(&stats->qp0_mads_outstanding); +#endif + + return outstanding; +} + +static inline uint32_t osm_stats_dec_qp0_outstanding(osm_stats_t *stats) +{ + uint32_t outstanding; + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&stats->mutex); + outstanding = --stats->qp0_mads_outstanding; + if (!outstanding) + pthread_cond_signal(&stats->cond); + pthread_mutex_unlock(&stats->mutex); +#else + outstanding = cl_atomic_dec(&stats->qp0_mads_outstanding); + if (!outstanding) + cl_event_signal(&stats->event); +#endif + + return outstanding; +} + +END_C_DECLS +#endif /* _OSM_STATS_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_subnet.h b/contrib/ofed/management/opensm/include/opensm/osm_subnet.h new file mode 100644 index 000000000000..d97d5f44f7e3 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_subnet.h @@ -0,0 +1,1106 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_subn_t. + * This object represents an IBA subnet. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_SUBNET_H_ +#define _OSM_SUBNET_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#define OSM_SUBNET_VECTOR_MIN_SIZE 0 +#define OSM_SUBNET_VECTOR_GROW_SIZE 1 +#define OSM_SUBNET_VECTOR_CAPACITY 256 +struct osm_opensm; +struct osm_qos_policy; + +/****h* OpenSM/Subnet +* NAME +* Subnet +* +* DESCRIPTION +* The Subnet object encapsulates the information needed by the +* OpenSM to manage a subnet. The OpenSM allocates one Subnet object +* per IBA subnet. +* +* The Subnet object is not thread safe, thus callers must provide +* serialization. +* +* This object is essentially a container for the various components +* of a subnet. Callers may directly access the member variables. +* +* AUTHOR +* Steve King, Intel +* +*********/ + +/****s* OpenSM: Subnet/osm_qos_options_t +* NAME +* osm_qos_options_t +* +* DESCRIPTION +* Subnet QoS options structure. This structure contains the various +* QoS specific configuration parameters for the subnet. +* +* SYNOPSIS +*/ +typedef struct osm_qos_options { + unsigned max_vls; + int high_limit; + char *vlarb_high; + char *vlarb_low; + char *sl2vl; +} osm_qos_options_t; +/* +* FIELDS +* +* max_vls +* The number of maximum VLs on the Subnet (0 == use default) +* +* high_limit +* The limit of High Priority component of VL Arbitration +* table (IBA 7.6.9) (-1 == use default) +* +* vlarb_high +* High priority VL Arbitration table template. (NULL == use default) +* +* vlarb_low +* Low priority VL Arbitration table template. (NULL == use default) +* +* sl2vl +* SL2VL Mapping table (IBA 7.6.6) template. (NULL == use default) +* +*********/ + +/****s* OpenSM: Subnet/osm_subn_opt_t +* NAME +* osm_subn_opt_t +* +* DESCRIPTION +* Subnet options structure. This structure contains the various +* site specific configuration parameters for the subnet. +* +* SYNOPSIS +*/ +typedef struct osm_subn_opt { + char *config_file; + ib_net64_t guid; + ib_net64_t m_key; + ib_net64_t sm_key; + ib_net64_t sa_key; + ib_net64_t subnet_prefix; + ib_net16_t m_key_lease_period; + uint32_t sweep_interval; + uint32_t max_wire_smps; + uint32_t transaction_timeout; + uint8_t sm_priority; + uint8_t lmc; + boolean_t lmc_esp0; + uint8_t max_op_vls; + uint8_t force_link_speed; + boolean_t reassign_lids; + boolean_t ignore_other_sm; + boolean_t single_thread; + boolean_t disable_multicast; + boolean_t force_log_flush; + uint8_t subnet_timeout; + uint8_t packet_life_time; + uint8_t vl_stall_count; + uint8_t leaf_vl_stall_count; + uint8_t head_of_queue_lifetime; + uint8_t leaf_head_of_queue_lifetime; + uint8_t local_phy_errors_threshold; + uint8_t overrun_errors_threshold; + uint32_t sminfo_polling_timeout; + uint32_t polling_retry_number; + uint32_t max_msg_fifo_timeout; + boolean_t force_heavy_sweep; + uint8_t log_flags; + char *dump_files_dir; + char *log_file; + unsigned long log_max_size; + char *partition_config_file; + boolean_t no_partition_enforcement; + boolean_t qos; + char *qos_policy_file; + boolean_t accum_log_file; + char *console; + uint16_t console_port; + char *port_prof_ignore_file; + boolean_t port_profile_switch_nodes; + boolean_t sweep_on_trap; + char *routing_engine_names; + boolean_t use_ucast_cache; + boolean_t connect_roots; + char *lid_matrix_dump_file; + char *lfts_file; + char *root_guid_file; + char *cn_guid_file; + char *ids_guid_file; + char *guid_routing_order_file; + char *sa_db_file; + boolean_t exit_on_fatal; + boolean_t honor_guid2lid_file; + boolean_t daemon; + boolean_t sm_inactive; + boolean_t babbling_port_policy; + osm_qos_options_t qos_options; + osm_qos_options_t qos_ca_options; + osm_qos_options_t qos_sw0_options; + osm_qos_options_t qos_swe_options; + osm_qos_options_t qos_rtr_options; + boolean_t enable_quirks; + boolean_t no_clients_rereg; +#ifdef ENABLE_OSM_PERF_MGR + boolean_t perfmgr; + boolean_t perfmgr_redir; + uint16_t perfmgr_sweep_time_s; + uint32_t perfmgr_max_outstanding_queries; + char *event_db_dump_file; +#endif /* ENABLE_OSM_PERF_MGR */ + char *event_plugin_name; + char *node_name_map_name; + char *prefix_routes_file; + boolean_t consolidate_ipv6_snm_req; +} osm_subn_opt_t; +/* +* FIELDS +* +* config_file +* The name of the config file. +* +* guid +* The port guid that the SM is binding to. +* +* m_key +* M_Key value sent to all ports qualifying all Set(PortInfo). +* +* sm_key +* SM_Key value of the SM used for SM authentication. +* +* sa_key +* SM_Key value to qualify rcv SA queries as "trusted". +* +* subnet_prefix +* Subnet prefix used on this subnet. +* +* m_key_lease_period +* The lease period used for the M_Key on this subnet. +* +* sweep_interval +* The number of seconds between subnet sweeps. A value of 0 +* disables sweeping. +* +* max_wire_smps +* The maximum number of SMPs sent in parallel. Default is 4. +* +* transaction_timeout +* The maximum time in milliseconds allowed for a transaction +* to complete. Default is 200. +* +* sm_priority +* The priority of this SM as specified by the user. This +* value is made available in the SMInfo attribute. +* +* lmc +* The LMC value used on this subnet. +* +* lmc_esp0 +* Whether LMC value used on subnet should be used for +* enhanced switch port 0 or not. If TRUE, it is used. +* Otherwise (the default), LMC is set to 0 for ESP0. +* +* max_op_vls +* Limit the maximal operational VLs. default is 1. +* +* reassign_lids +* If TRUE cause all lids to be re-assigend. +* Otherwise (the default), +* OpenSM always tries to preserve as LIDs as much as possible. +* +* ignore_other_sm_option +* This flag is TRUE if other SMs on the subnet should be ignored. +* +* disable_multicast +* This flag is TRUE if OpenSM should disable multicast support. +* +* max_msg_fifo_timeout +* The maximal time a message can stay in the incoming message +* queue. If there is more than one message in the queue and the +* last message stayed in the queue more than this value the SA +* request will be immediately returned with a BUSY status. +* +* subnet_timeout +* The subnet_timeout that will be set for all the ports in the +* design SubnSet(PortInfo.vl_stall_life)) +* +* vl_stall_count +* The number of sequential packets dropped that cause the port +* to enter the VLStalled state. +* +* leaf_vl_stall_count +* The number of sequential packets dropped that cause the port +* to enter the VLStalled state. This is for switch ports driving +* a CA or router port. +* +* head_of_queue_lifetime +* The maximal time a packet can live at the head of a VL queue +* on any port not driving a CA or router port. +* +* leaf_head_of_queue_lifetime +* The maximal time a packet can live at the head of a VL queue +* on switch ports driving a CA or router. +* +* local_phy_errors_threshold +* Threshold of local phy errors for sending Trap 129 +* +* overrun_errors_threshold +* Threshold of credits overrun errors for sending Trap 129 +* +* sminfo_polling_timeout +* Specifies the polling timeout (in milliseconds) - the timeout +* between one poll to another. +* +* packet_life_time +* The maximal time a packet can stay in a switch. +* The value is send to all switches as +* SubnSet(SwitchInfo.life_state) +* +* dump_files_dir +* The directory to be used for opensm-subnet.lst, opensm.fdbs, +* opensm.mcfdbs, and default log file (the latter for Windows, +* not Linux). +* +* log_file +* Name of the log file (or NULL) for stdout. +* +* log_max_size +* This option defines maximal log file size in MB. When +* specified the log file will be truncated upon reaching +* this limit. +* +* qos +* Boolean that specifies whether the OpenSM QoS functionality +* should be off or on. +* +* qos_policy_file +* Name of the QoS policy file. +* +* accum_log_file +* If TRUE (default) - the log file will be accumulated. +* If FALSE - the log file will be erased before starting +* current opensm run. +* +* port_prof_ignore_file +* Name of file with port guids to be ignored by port profiling. +* +* port_profile_switch_nodes +* If TRUE will count the number of switch nodes routed through +* the link. If FALSE - only CA/RT nodes are counted. +* +* sweep_on_trap +* Received traps will initiate a new sweep. +* +* routing_engine_names +* Name of routing engine(s) to use. +* +* connect_roots +* The option which will enforce root to root connectivity with +* up/down routing engine (even if this violates "pure" deadlock +* free up/down algorithm) +* +* use_ucast_cache +* When TRUE enables unicast routing cache. +* +* lid_matrix_dump_file +* Name of the lid matrix dump file from where switch +* lid matrices (min hops tables) will be loaded +* +* lfts_file +* Name of the unicast LFTs routing file from where switch +* forwarding tables will be loaded +* +* root_guid_file +* Name of the file that contains list of root guids that +* will be used by fat-tree or up/dn routing (provided by User) +* +* cn_guid_file +* Name of the file that contains list of compute node guids that +* will be used by fat-tree routing (provided by User) +* +* ids_guid_file +* Name of the file that contains list of ids which should be +* used by Up/Down algorithm instead of node GUIDs +* +* guid_routing_order_file +* Name of the file that contains list of guids for routing order +* that will be used by minhop and up/dn routing (provided by User). +* +* sa_db_file +* Name of the SA database file. +* +* exit_on_fatal +* If TRUE (default) - SM will exit on fatal subnet initialization +* issues. +* If FALSE - SM will not exit. +* Fatal initialization issues: +* a. SM recognizes 2 different nodes with the same guid, or +* 12x link with lane reversal badly configured. +* +* honor_guid2lid_file +* Always honor the guid2lid file if it exists and is valid. This +* means that the file will be honored when SM is coming out of +* STANDBY. By default this is FALSE. +* +* daemon +* OpenSM will run in daemon mode. +* +* sm_inactive +* OpenSM will start with SM in not active state. +* +* babbling_port_policy +* OpenSM will enforce its "babbling" port policy. +* +* perfmgr +* Enable or disable the performance manager +* +* perfmgr_redir +* Enable or disable the saving of redirection by PerfMgr +* +* perfmgr_sweep_time_s +* Define the period (in seconds) of PerfMgr sweeps +* +* event_db_dump_file +* File to dump the event database to +* +* event_db_plugin +* Specify the name of the event plugin +* +* qos_options +* Default set of QoS options +* +* qos_ca_options +* QoS options for CA ports +* +* qos_sw0_options +* QoS options for switches' port 0 +* +* qos_swe_options +* QoS options for switches' external ports +* +* qos_rtr_options +* QoS options for router ports +* +* enable_quirks +* Enable high risk new features and not fully qualified +* hardware specific work arounds +* +* no_clients_rereg +* When TRUE disables clients reregistration request. +* +* SEE ALSO +* Subnet object +*********/ + +/****s* OpenSM: Subnet/osm_subn_t +* NAME +* osm_subn_t +* +* DESCRIPTION +* Subnet structure. Callers may directly access member components, +* after grabbing a lock. +* +* TO DO +* This structure should probably be volatile. +* +* SYNOPSIS +*/ +typedef struct osm_subn { + struct osm_opensm *p_osm; + cl_qmap_t sw_guid_tbl; + cl_qmap_t node_guid_tbl; + cl_qmap_t port_guid_tbl; + cl_qmap_t rtr_guid_tbl; + cl_qlist_t prefix_routes_list; + cl_qmap_t prtn_pkey_tbl; + cl_qmap_t sm_guid_tbl; + cl_qlist_t sa_sr_list; + cl_qlist_t sa_infr_list; + cl_ptr_vector_t port_lid_tbl; + ib_net16_t master_sm_base_lid; + ib_net16_t sm_base_lid; + ib_net64_t sm_port_guid; + uint8_t sm_state; + osm_subn_opt_t opt; + struct osm_qos_policy *p_qos_policy; + uint16_t max_ucast_lid_ho; + uint16_t max_mcast_lid_ho; + uint8_t min_ca_mtu; + uint8_t min_ca_rate; + boolean_t ignore_existing_lfts; + boolean_t subnet_initialization_error; + boolean_t force_heavy_sweep; + boolean_t force_reroute; + boolean_t in_sweep_hop_0; + boolean_t first_time_master_sweep; + boolean_t coming_out_of_standby; + unsigned need_update; + void *mgroups[IB_LID_MCAST_END_HO - IB_LID_MCAST_START_HO + 1]; +} osm_subn_t; +/* +* FIELDS +* sw_guid_tbl +* Container of pointers to all Switch objects in the subent. +* Indexed by node GUID. +* +* node_guid_tbl +* Container of pointers to all Node objects in the subent. +* Indexed by node GUID. +* +* port_guid_tbl +* Container of pointers to all Port objects in the subent. +* Indexed by port GUID - network order! +* +* rtr_guid_tbl +* Container of pointers to all Router objects in the subent. +* Indexed by node GUID. +* +* prtn_pkey_tbl +* Container of pointers to all Partition objects in the subnet. +* Indexed by P_KEY. +* +* sm_guid_tbl +* Container of pointers to SM objects representing other SMs +* on the subnet. +* +* port_lid_tbl +* Container of pointers to all Port objects in the subent. +* Indexed by port LID. +* +* master_sm_base_lid +* The base LID owned by the subnet's master SM. +* +* sm_base_lid +* The base LID of the local port where the SM is. +* +* sm_port_guid +* This SM's own port GUID. +* +* sm_state +* The high-level state of the SM. This value is made available +* in the SMInfo attribute. +* +* opt +* Subnet options structure contains site specific configuration. +* +* p_qos_policy +* Subnet QoS policy structure. +* +* max_ucast_lid_ho +* The minimal max unicast lid reported by all switches +* +* max_mcast_lid_ho +* The minimal max multicast lid reported by all switches +* +* min_ca_mtu +* The minimal MTU reported by all CAs ports on the subnet +* +* min_ca_rate +* The minimal rate reported by all CA ports on the subnet +* +* ignore_existing_lfts +* This flag is a dynamic flag to instruct the LFT assignment to +* ignore existing legal LFT settings. +* The value will be set according to : +* - Any change to the list of switches will set it to high +* - Coming out of STANDBY it will be cleared (other SM worked) +* - Set to FALSE upon end of all lft assignments. +* +* subnet_initalization_error +* Similar to the force_heavy_sweep flag. If TRUE - means that +* we had errors during initialization (due to SubnSet requests +* that failed). We want to declare the subnet as unhealthy, and +* force another heavy sweep. +* +* force_heavy_sweep +* If TRUE - we want to force a heavy sweep. This can be done +* either due to receiving of trap - meaning there is some change +* on the subnet, or we received a handover from a remote sm. +* In this case we want to sweep and reconfigure the entire +* subnet. This will cause another heavy sweep to occure when +* the current sweep is done. +* +* force_reroute +* If TRUE - we want to force switches in the fabric to be +* rerouted. +* +* in_sweep_hop_0 +* When in_sweep_hop_0 flag is set to TRUE - this means we are +* in sweep_hop_0 - meaning we do not want to continue beyond +* the current node. +* This is relevant for the case of SM on switch, since in the +* switch info we need to signal somehow not to continue +* the sweeping. +* +* first_time_master_sweep +* This flag is used for the PortInfo setting. On the first +* sweep as master (meaning after moving from Standby|Discovering +* state), the SM must send a PortInfoSet to all ports. After +* that - we want to minimize the number of PortInfoSet requests +* sent, and to send only requests that change the value from +* what is updated in the port (or send a first request if this +* is a new port). We will set this flag to TRUE when entering +* the master state, and set it back to FALSE at the end of the +* drop manager. This is done since at the end of the drop manager +* we have updated all the ports that are reachable, and from now +* on these are the only ports we have data of. We don't want +* to send extra set requests to these ports anymore. +* +* coming_out_of_standby +* TRUE on the first sweep after the SM was in standby. +* Used for nulling any cache of LID and Routing. +* The flag is set true if the SM state was standby and now +* changed to MASTER it is reset at the end of the sweep. +* +* need_update +* This flag should be on during first non-master heavy +* (including pre-master discovery stage) +* +* mgroups +* Array of pointers to all Multicast Group objects in the subnet. +* Indexed by MLID offset from base MLID. +* +* SEE ALSO +* Subnet object +*********/ + +/****f* OpenSM: Subnet/osm_subn_construct +* NAME +* osm_subn_construct +* +* DESCRIPTION +* This function constructs a Subnet object. +* +* SYNOPSIS +*/ +void osm_subn_construct(IN osm_subn_t * const p_subn); +/* +* PARAMETERS +* p_subn +* [in] Pointer to a Subnet object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_subn_init, and osm_subn_destroy. +* +* Calling osm_subn_construct is a prerequisite to calling any other +* method except osm_subn_init. +* +* SEE ALSO +* Subnet object, osm_subn_init, osm_subn_destroy +*********/ + +/****f* OpenSM: Subnet/osm_subn_destroy +* NAME +* osm_subn_destroy +* +* DESCRIPTION +* The osm_subn_destroy function destroys a subnet, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_subn_destroy(IN osm_subn_t * const p_subn); +/* +* PARAMETERS +* p_subn +* [in] Pointer to a Subnet object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified Subnet object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_subn_construct +* or osm_subn_init. +* +* SEE ALSO +* Subnet object, osm_subn_construct, osm_subn_init +*********/ + +/****f* OpenSM: Subnet/osm_subn_init +* NAME +* osm_subn_init +* +* DESCRIPTION +* The osm_subn_init function initializes a Subnet object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_subn_init(IN osm_subn_t * const p_subn, + IN struct osm_opensm *const p_osm, + IN const osm_subn_opt_t * const p_opt); +/* +* PARAMETERS +* p_subn +* [in] Pointer to an osm_subn_t object to initialize. +* +* p_opt +* [in] Pointer to the subnet options structure. +* +* RETURN VALUES +* IB_SUCCESS if the Subnet object was initialized successfully. +* +* NOTES +* Allows calling other Subnet methods. +* +* SEE ALSO +* Subnet object, osm_subn_construct, osm_subn_destroy +*********/ + +/* + Forward references. +*/ +struct osm_mad_addr; +struct osm_log; +struct osm_switch; +struct osm_physp; +struct osm_port; +struct osm_mgrp; + +/****f* OpenSM: Helper/osm_get_gid_by_mad_addr +* NAME +* osm_get_gid_by_mad_addr +* +* DESCRIPTION +* Looks for the requester gid in the mad address. +* +* Note: This code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_get_gid_by_mad_addr(IN struct osm_log *p_log, + IN const osm_subn_t * p_subn, + IN const struct osm_mad_addr *p_mad_addr, + OUT ib_gid_t * p_gid); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to subnet object. +* +* p_mad_addr +* [in] Pointer to mad address object. +* +* p_gid +* [out] Pointer to the GID structure to fill in. +* +* RETURN VALUES +* IB_SUCCESS if able to find the GID by address given. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/osm_get_physp_by_mad_addr +* NAME +* osm_get_physp_by_mad_addr +* +* DESCRIPTION +* Looks for the requester physical port in the mad address. +* +* Note: This code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +struct osm_physp *osm_get_physp_by_mad_addr(IN struct osm_log *p_log, + IN const osm_subn_t * p_subn, + IN struct osm_mad_addr + *p_mad_addr); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to subnet object. +* +* p_mad_addr +* [in] Pointer to mad address object. +* +* RETURN VALUES +* Pointer to requester physical port object if found. Null otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Helper/osm_get_port_by_mad_addr +* NAME +* osm_get_port_by_mad_addr +* +* DESCRIPTION +* Looks for the requester port in the mad address. +* +* Note: This code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +struct osm_port *osm_get_port_by_mad_addr(IN struct osm_log *p_log, + IN const osm_subn_t * p_subn, + IN struct osm_mad_addr *p_mad_addr); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to subnet object. +* +* p_mad_addr +* [in] Pointer to mad address object. +* +* RETURN VALUES +* Pointer to requester port object if found. Null otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Subnet/osm_get_switch_by_guid +* NAME +* osm_get_switch_by_guid +* +* DESCRIPTION +* Looks for the given switch guid in the subnet table of switches by guid. +* NOTE: this code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +struct osm_switch *osm_get_switch_by_guid(IN const osm_subn_t * p_subn, + IN uint64_t guid); +/* +* PARAMETERS +* p_subn +* [in] Pointer to an osm_subn_t object +* +* guid +* [in] The node guid in host order +* +* RETURN VALUES +* The switch structure pointer if found. NULL otherwise. +* +* SEE ALSO +* Subnet object, osm_subn_construct, osm_subn_destroy, +* osm_switch_t +*********/ + +/****f* OpenSM: Subnet/osm_get_node_by_guid +* NAME +* osm_get_node_by_guid +* +* DESCRIPTION +* The looks for the given node giud in the subnet table of nodes by guid. +* NOTE: this code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +struct osm_node *osm_get_node_by_guid(IN osm_subn_t const *p_subn, + IN uint64_t guid); +/* +* PARAMETERS +* p_subn +* [in] Pointer to an osm_subn_t object +* +* guid +* [in] The node guid in host order +* +* RETURN VALUES +* The node structure pointer if found. NULL otherwise. +* +* SEE ALSO +* Subnet object, osm_subn_construct, osm_subn_destroy, +* osm_node_t +*********/ + +/****f* OpenSM: Subnet/osm_get_port_by_guid +* NAME +* osm_get_port_by_guid +* +* DESCRIPTION +* The looks for the given port guid in the subnet table of ports by guid. +* NOTE: this code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +struct osm_port *osm_get_port_by_guid(IN osm_subn_t const *p_subn, + IN ib_net64_t guid); +/* +* PARAMETERS +* p_subn +* [in] Pointer to an osm_subn_t object +* +* guid +* [in] The port guid in network order +* +* RETURN VALUES +* The port structure pointer if found. NULL otherwise. +* +* SEE ALSO +* Subnet object, osm_subn_construct, osm_subn_destroy, +* osm_port_t +*********/ + +/****f* OpenSM: Subnet/osm_get_mgrp_by_mlid +* NAME +* osm_get_mgrp_by_mlid +* +* DESCRIPTION +* The looks for the given multicast group in the subnet table by mlid. +* NOTE: this code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +static inline +struct osm_mgrp *osm_get_mgrp_by_mlid(osm_subn_t const *p_subn, ib_net16_t mlid) +{ + return p_subn->mgroups[cl_ntoh16(mlid) - IB_LID_MCAST_START_HO]; +} +/* +* PARAMETERS +* p_subn +* [in] Pointer to an osm_subn_t object +* +* mlid +* [in] The multicast group mlid in network order +* +* RETURN VALUES +* The multicast group structure pointer if found. NULL otherwise. +*********/ + +/****f* OpenSM: Helper/osm_get_physp_by_mad_addr +* NAME +* osm_get_physp_by_mad_addr +* +* DESCRIPTION +* Looks for the requester physical port in the mad address. +* +* Note: This code is not thread safe. Need to grab the lock before +* calling it. +* +* SYNOPSIS +*/ +struct osm_physp *osm_get_physp_by_mad_addr(IN struct osm_log *p_log, + IN const osm_subn_t * p_subn, + IN struct osm_mad_addr + *p_mad_addr); +/* +* PARAMETERS +* p_log +* [in] Pointer to a log object. +* +* p_subn +* [in] Pointer to subnet object. +* +* p_mad_addr +* [in] Pointer to mad address object. +* +* RETURN VALUES +* Pointer to requester physical port object if found. Null otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Subnet/osm_subn_set_default_opt +* NAME +* osm_subn_set_default_opt +* +* DESCRIPTION +* The osm_subn_set_default_opt function sets the default options. +* +* SYNOPSIS +*/ +void osm_subn_set_default_opt(IN osm_subn_opt_t * const p_opt); +/* +* PARAMETERS +* +* p_opt +* [in] Pointer to the subnet options structure. +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +* Subnet object, osm_subn_construct, osm_subn_destroy +*********/ + +/****f* OpenSM: Subnet/osm_subn_parse_conf_file +* NAME +* osm_subn_parse_conf_file +* +* DESCRIPTION +* The osm_subn_parse_conf_file function parses the configuration file +* and sets the defaults accordingly. +* +* SYNOPSIS +*/ +int osm_subn_parse_conf_file(char *conf_file, osm_subn_opt_t * const p_opt); +/* +* PARAMETERS +* +* p_opt +* [in] Pointer to the subnet options structure. +* +* RETURN VALUES +* 0 on success, positive value if file doesn't exist, +* negative value otherwise +*********/ + +/****f* OpenSM: Subnet/osm_subn_rescan_conf_files +* NAME +* osm_subn_rescan_conf_files +* +* DESCRIPTION +* The osm_subn_rescan_conf_files function parses the configuration +* files and update selected subnet options +* +* SYNOPSIS +*/ +int osm_subn_rescan_conf_files(IN osm_subn_t * const p_subn); +/* +* PARAMETERS +* +* p_subn +* [in] Pointer to the subnet structure. +* +* RETURN VALUES +* 0 on success, positive value if file doesn't exist, +* negative value otherwise +* +*********/ + +/****f* OpenSM: Subnet/osm_subn_output_conf +* NAME +* osm_subn_output_conf +* +* DESCRIPTION +* Output configuration info +* +* SYNOPSIS +*/ +int osm_subn_output_conf(FILE *out, IN osm_subn_opt_t * const p_opt); +/* +* PARAMETERS +* +* out +* [in] File stream to output to. +* +* p_opt +* [in] Pointer to the subnet options structure. +* +* RETURN VALUES +* 0 on success, negative value otherwise +*********/ + +/****f* OpenSM: Subnet/osm_subn_write_conf_file +* NAME +* osm_subn_write_conf_file +* +* DESCRIPTION +* Write the configuration file into the cache +* +* SYNOPSIS +*/ +int osm_subn_write_conf_file(char *file_name, IN osm_subn_opt_t * const p_opt); +/* +* PARAMETERS +* +* p_opt +* [in] Pointer to the subnet options structure. +* +* RETURN VALUES +* 0 on success, negative value otherwise +* +* NOTES +* Assumes the conf file is part of the cache dir which defaults to +* OSM_DEFAULT_CACHE_DIR or OSM_CACHE_DIR the name is opensm.opts +*********/ +int osm_subn_verify_config(osm_subn_opt_t * const p_opt); + +END_C_DECLS +#endif /* _OSM_SUBNET_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_switch.h b/contrib/ofed/management/opensm/include/opensm/osm_switch.h new file mode 100644 index 000000000000..dbc22e51b6da --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_switch.h @@ -0,0 +1,1152 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_switch_t. + * This object represents an IBA switch. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_SWITCH_H_ +#define _OSM_SWITCH_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Switch +* NAME +* Switch +* +* DESCRIPTION +* The Switch object encapsulates the information needed by the +* OpenSM to manage switches. The OpenSM allocates one switch object +* per switch in the IBA subnet. +* +* The Switch object is not thread safe, thus callers must provide +* serialization. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Switch/osm_switch_t +* NAME +* osm_switch_t +* +* DESCRIPTION +* Switch structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_switch { + cl_map_item_t map_item; + osm_node_t *p_node; + ib_switch_info_t switch_info; + uint16_t max_lid_ho; + uint8_t num_ports; + uint16_t num_hops; + uint8_t **hops; + osm_port_profile_t *p_prof; + uint8_t *lft; + uint8_t *new_lft; + osm_mcast_tbl_t mcast_tbl; + uint32_t discovery_count; + unsigned need_update; + void *priv; +} osm_switch_t; +/* +* FIELDS +* map_item +* Linkage structure for cl_qmap. MUST BE FIRST MEMBER! +* +* p_node +* Pointer to the Node object for this switch. +* +* switch_info +* IBA defined SwitchInfo structure for this switch. +* +* max_lid_ho +* Max LID that is accessible from this switch. +* +* num_ports +* Number of ports for this switch. +* +* num_hops +* Size of hops table for this switch. +* +* hops +* LID Matrix for this switch containing the hop count +* to every LID from every port. +* +* p_prof +* Pointer to array of Port Profile objects for this switch. +* +* lft +* This switch's linear forwarding table. +* +* new_lft +* This switch's linear forwarding table, as was +* calculated by the last routing engine execution. +* +* mcast_tbl +* Multicast forwarding table for this switch. +* +* discovery_count +* The number of times this switch has been discovered +* during the current fabric sweep. This number is reset +* to zero at the start of a sweep. +* +* need_update +* When set indicates that switch was probably reset, so +* fwd tables and rest cached data should be flushed +* +* SEE ALSO +* Switch object +*********/ + +/****s* OpenSM: Switch/struct osm_remote_guids_count +* NAME +* struct osm_remote_guids_count +* +* DESCRIPTION +* Stores array of pointers to remote node and the numbers of +* times a switch has forwarded to it. +* +* SYNOPSIS +*/ +struct osm_remote_guids_count { + unsigned count; + struct osm_remote_node { + osm_node_t *node; + unsigned forwarded_to; + } guids[0]; +}; +/* +* FIELDS +* count +* A number of used entries in array. +* +* node +* A pointer to node. +* +* forwarded_to +* A count of lids forwarded to this node. +*********/ + +/****f* OpenSM: Switch/osm_switch_delete +* NAME +* osm_switch_delete +* +* DESCRIPTION +* Destroys and deallocates the object. +* +* SYNOPSIS +*/ +void osm_switch_delete(IN OUT osm_switch_t ** const pp_sw); +/* +* PARAMETERS +* p_sw +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +* Switch object, osm_switch_new +*********/ + +/****f* OpenSM: Switch/osm_switch_new +* NAME +* osm_switch_new +* +* DESCRIPTION +* The osm_switch_new function initializes a Switch object for use. +* +* SYNOPSIS +*/ +osm_switch_t *osm_switch_new(IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw); +/* +* PARAMETERS +* p_node +* [in] Pointer to the node object of this switch +* +* p_madw +* [in] Pointer to the MAD Wrapper containing the switch's +* SwitchInfo attribute. +* +* RETURN VALUES +* Pointer to the new initialized switch object. +* +* NOTES +* +* SEE ALSO +* Switch object, osm_switch_delete +*********/ + +/****f* OpenSM: Switch/osm_switch_get_hop_count +* NAME +* osm_switch_get_hop_count +* +* DESCRIPTION +* Returns the hop count at the specified LID/Port intersection. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_switch_get_hop_count(IN const osm_switch_t * const p_sw, + IN const uint16_t lid_ho, IN const uint8_t port_num) +{ + return (lid_ho > p_sw->max_lid_ho || !p_sw->hops[lid_ho]) ? + OSM_NO_PATH : p_sw->hops[lid_ho][port_num]; +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to a Switch object. +* +* lid_ho +* [in] LID value (host order) for which to return the hop count +* +* port_num +* [in] Port number in the switch +* +* RETURN VALUES +* Returns the hop count at the specified LID/Port intersection. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_set_hops +* NAME +* osm_switch_set_hops +* +* DESCRIPTION +* Sets the hop count at the specified LID/Port intersection. +* +* SYNOPSIS +*/ +cl_status_t +osm_switch_set_hops(IN osm_switch_t * const p_sw, + IN const uint16_t lid_ho, + IN const uint8_t port_num, IN const uint8_t num_hops); +/* +* PARAMETERS +* p_sw +* [in] Pointer to a Switch object. +* +* lid_ho +* [in] LID value (host order) for which to set the count. +* +* port_num +* [in] port number for which to set the count. +* +* num_hops +* [in] value to assign to this entry. +* +* RETURN VALUES +* Returns the hop count at the specified LID/Port intersection. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_clear_hops +* NAME +* osm_switch_clear_hops +* +* DESCRIPTION +* Cleanup existing hops tables (lid matrix) +* +* SYNOPSIS +*/ +void osm_switch_clear_hops(IN osm_switch_t * p_sw); +/* +* PARAMETERS +* p_sw +* [in] Pointer to a Switch object. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_get_least_hops +* NAME +* osm_switch_get_least_hops +* +* DESCRIPTION +* Returns the number of hops in the short path to this lid from +* any port on the switch. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_switch_get_least_hops(IN const osm_switch_t * const p_sw, + IN const uint16_t lid_ho) +{ + return (lid_ho > p_sw->max_lid_ho || !p_sw->hops[lid_ho]) ? + OSM_NO_PATH : p_sw->hops[lid_ho][0]; +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* lid_ho +* [in] LID (host order) for which to retrieve the shortest hop count. +* +* RETURN VALUES +* Returns the number of hops in the short path to this lid from +* any port on the switch. +* +* NOTES +* +* SEE ALSO +* Switch object +*********/ + +/****f* OpenSM: Switch/osm_switch_get_port_least_hops +* NAME +* osm_switch_get_port_least_hops +* +* DESCRIPTION +* Returns the number of hops in the short path to this port from +* any port on the switch. +* +* SYNOPSIS +*/ +uint8_t +osm_switch_get_port_least_hops(IN const osm_switch_t * const p_sw, + IN const osm_port_t * p_port); +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* p_port +* [in] Pointer to an osm_port_t object for which to +* retrieve the shortest hop count. +* +* RETURN VALUES +* Returns the number of hops in the short path to this lid from +* any port on the switch. +* +* NOTES +* +* SEE ALSO +* Switch object +*********/ + +/****f* OpenSM: Switch/osm_switch_get_port_by_lid +* NAME +* osm_switch_get_port_by_lid +* +* DESCRIPTION +* Returns the switch port number on which the specified LID is routed. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_switch_get_port_by_lid(IN const osm_switch_t * const p_sw, + IN const uint16_t lid_ho) +{ + if (lid_ho == 0 || lid_ho > IB_LID_UCAST_END_HO) + return OSM_NO_PATH; + return p_sw->lft[lid_ho]; +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* lid_ho +* [in] LID (host order) for which to retrieve the shortest hop count. +* +* RETURN VALUES +* Returns the switch port on which the specified LID is routed. +* +* NOTES +* +* SEE ALSO +* Switch object +*********/ + +/****f* OpenSM: Switch/osm_switch_get_physp_ptr +* NAME +* osm_switch_get_physp_ptr +* +* DESCRIPTION +* Gets the Physical Port Object at the specified port number. +* +* SYNOPSIS +*/ +osm_physp_t *osm_switch_get_physp_ptr(IN const osm_switch_t * const p_sw, + IN const uint32_t port_num); +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* port_num +* [in] Port number for which to retrieve the Physical Port Object. +* +* RETURN VALUES +* Returns a pointer to the Physical Port Object object at the specified +* port number. +* A return value of zero means the port number was out of range. +* +* +* NOTES +* +* SEE ALSO +* Switch object +*********/ + +/****f* OpenSM: Switch/osm_switch_get_route_by_lid +* NAME +* osm_switch_get_route_by_lid +* +* DESCRIPTION +* Gets the physical port object that routes the specified LID. +* +* SYNOPSIS +*/ +static inline osm_physp_t *osm_switch_get_route_by_lid(IN const osm_switch_t * + const p_sw, + IN const ib_net16_t lid) +{ + uint8_t port_num; + + CL_ASSERT(p_sw); + CL_ASSERT(lid); + + port_num = osm_switch_get_port_by_lid(p_sw, cl_ntoh16(lid)); + + /* + In order to avoid holes in the subnet (usually happens when + running UPDN algorithm), i.e. cases where port is + unreachable through a switch (we put an OSM_NO_PATH value at + the port entry, we do not assert on unreachable lid entries + at the fwd table but return NULL + */ + if (port_num != OSM_NO_PATH) + return (osm_node_get_physp_ptr(p_sw->p_node, port_num)); + else + return NULL; +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* lid +* [in] LID for which to find a route. This must be a unicast +* LID value < 0xC000. +* +* RETURN VALUES +* Returns a pointer to the Physical Port Object object that +* routes the specified LID. A return value of zero means +* there is no route for the lid through this switch. +* The lid value must be a unicast LID. +* +* NOTES +* +* SEE ALSO +* Switch object +*********/ + +/****f* OpenSM: Switch/osm_switch_sp0_is_lmc_capable +* NAME +* osm_switch_sp0_is_lmc_capable +* +* DESCRIPTION +* Returns whether switch port 0 (SP0) can support LMC +* +*/ +static inline unsigned +osm_switch_sp0_is_lmc_capable(IN const osm_switch_t * const p_sw, + IN osm_subn_t * p_subn) +{ + return (p_subn->opt.lmc_esp0 && + ib_switch_info_is_enhanced_port0(&p_sw->switch_info)) ? 1 : 0; +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* p_subn +* [in] Pointer to an osm_subn_t object. +* +* RETURN VALUES +* TRUE if SP0 is enhanced and globally enabled. FALSE otherwise. +* +* NOTES +* This is workaround function, it takes into account user defined +* p_subn->opt.lmc_esp0 parameter. +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_get_max_block_id_in_use +* NAME +* osm_switch_get_max_block_id_in_use +* +* DESCRIPTION +* Returns the maximum block ID (host order) of this switch that +* is used for unicast routing. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_switch_get_max_block_id_in_use(IN const osm_switch_t * const p_sw) +{ + return cl_ntoh16(p_sw->switch_info.lin_top) / IB_SMP_DATA_SIZE; +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* RETURN VALUES +* Returns the maximum block ID (host order) of this switch. +* +* NOTES +* +* SEE ALSO +* Switch object +*********/ + +/****f* OpenSM: Switch/osm_switch_get_lft_block +* NAME +* osm_switch_get_lft_block +* +* DESCRIPTION +* Retrieve a linear forwarding table block. +* +* SYNOPSIS +*/ +boolean_t +osm_switch_get_lft_block(IN const osm_switch_t * const p_sw, + IN const uint16_t block_id, + OUT uint8_t * const p_block); +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* block_ID +* [in] The block_id to retrieve. +* +* p_block +* [out] Pointer to the 64 byte array to store the +* forwarding table clock specified by block_id. +* +* RETURN VALUES +* Returns true if there are more blocks necessary to +* configure all the LIDs reachable from this switch. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_supports_mcast +* NAME +* osm_switch_supports_mcast +* +* DESCRIPTION +* Indicates if a switch supports multicast. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_switch_supports_mcast(IN const osm_switch_t * const p_sw) +{ + return (p_sw->switch_info.mcast_cap != 0); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to an osm_switch_t object. +* +* RETURN VALUES +* Returns TRUE if the switch supports multicast. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_set_switch_info +* NAME +* osm_switch_set_switch_info +* +* DESCRIPTION +* Updates the switch info attribute of this switch. +* +* SYNOPSIS +*/ +static inline void +osm_switch_set_switch_info(IN osm_switch_t * const p_sw, + IN const ib_switch_info_t * const p_si) +{ + CL_ASSERT(p_sw); + CL_ASSERT(p_si); + p_sw->switch_info = *p_si; +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to a Switch object. +* +* p_si +* [in] Pointer to the SwitchInfo attribute for this switch. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_count_path +* NAME +* osm_switch_count_path +* +* DESCRIPTION +* Counts this path in port profile. +* +* SYNOPSIS +*/ +static inline void +osm_switch_count_path(IN osm_switch_t * const p_sw, IN const uint8_t port) +{ + osm_port_prof_path_count_inc(&p_sw->p_prof[port]); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* port +* [in] Port to count path. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_set_lft_block +* NAME +* osm_switch_set_lft_block +* +* DESCRIPTION +* Copies in the specified block into +* the switch's Linear Forwarding Table. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +osm_switch_set_lft_block(IN osm_switch_t * const p_sw, + IN const uint8_t * const p_block, + IN const uint32_t block_num) +{ + uint16_t lid_start = + (uint16_t) (block_num * IB_SMP_DATA_SIZE); + CL_ASSERT(p_sw); + + if (lid_start + IB_SMP_DATA_SIZE > IB_LID_UCAST_END_HO) + return IB_INVALID_PARAMETER; + + memcpy(&p_sw->lft[lid_start], p_block, IB_SMP_DATA_SIZE); + return IB_SUCCESS; +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* p_block +* [in] Pointer to the forwarding table block. +* +* block_num +* [in] Block number for this block +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_set_mft_block +* NAME +* osm_switch_set_mft_block +* +* DESCRIPTION +* Sets a block of multicast port masks into the multicast table. +* +* SYNOPSIS +*/ +static inline ib_api_status_t +osm_switch_set_mft_block(IN osm_switch_t * const p_sw, + IN const ib_net16_t * const p_block, + IN const uint16_t block_num, IN const uint8_t position) +{ + CL_ASSERT(p_sw); + return (osm_mcast_tbl_set_block(&p_sw->mcast_tbl, p_block, + block_num, position)); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* p_block +* [in] Pointer to the block of port masks to set. +* +* block_num +* [in] Block number (0-511) to set. +* +* position +* [in] Port mask position (0-15) to set. +* +* RETURN VALUE +* IB_SUCCESS on success. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_get_mft_block +* NAME +* osm_switch_get_mft_block +* +* DESCRIPTION +* Retrieve a block of multicast port masks from the multicast table. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_switch_get_mft_block(IN osm_switch_t * const p_sw, + IN const uint16_t block_num, + IN const uint8_t position, + OUT ib_net16_t * const p_block) +{ + CL_ASSERT(p_sw); + return (osm_mcast_tbl_get_block(&p_sw->mcast_tbl, + block_num, position, p_block)); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* block_num +* [in] Block number (0-511) to set. +* +* position +* [in] Port mask position (0-15) to set. +* +* p_block +* [out] Pointer to the block of port masks stored. +* +* RETURN VALUES +* Returns true if there are more blocks necessary to +* configure all the MLIDs reachable from this switch. +* FALSE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_get_mft_max_block +* NAME +* osm_switch_get_mft_max_block +* +* DESCRIPTION +* Get the max_block from the associated multicast table. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_switch_get_mft_max_block(IN osm_switch_t * const p_sw) +{ + CL_ASSERT(p_sw); + return (osm_mcast_tbl_get_max_block(&p_sw->mcast_tbl)); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* RETURN VALUE +*/ + +/****f* OpenSM: Switch/osm_switch_get_mft_max_block_in_use +* NAME +* osm_switch_get_mft_max_block_in_use +* +* DESCRIPTION +* Get the max_block_in_use from the associated multicast table. +* +* SYNOPSIS +*/ +static inline int16_t +osm_switch_get_mft_max_block_in_use(IN osm_switch_t * const p_sw) +{ + CL_ASSERT(p_sw); + return (osm_mcast_tbl_get_max_block_in_use(&p_sw->mcast_tbl)); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* RETURN VALUES +* Returns the maximum block ID in use in this switch's mcast table. +* A value of -1 indicates no blocks are in use. +* +* NOTES +* +* SEE ALSO +*/ + +/****f* OpenSM: Switch/osm_switch_get_mft_max_position +* NAME +* osm_switch_get_mft_max_position +* +* DESCRIPTION +* Get the max_position from the associated multicast table. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_switch_get_mft_max_position(IN osm_switch_t * const p_sw) +{ + CL_ASSERT(p_sw); + return (osm_mcast_tbl_get_max_position(&p_sw->mcast_tbl)); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* RETURN VALUE +*/ + +/****f* OpenSM: Switch/osm_switch_recommend_path +* NAME +* osm_switch_recommend_path +* +* DESCRIPTION +* Returns the recommended port on which to route this LID. +* In cases where LMC > 0, the remote side system and node +* used for the routing are tracked in the provided arrays +* (and counts) such that other lid for the same port will +* try and avoid going through the same remote system/node. +* +* SYNOPSIS +*/ +uint8_t +osm_switch_recommend_path(IN const osm_switch_t * const p_sw, + IN osm_port_t * p_port, + IN const uint16_t lid_ho, + IN unsigned start_from, + IN const boolean_t ignore_existing, + IN const boolean_t dor); +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* p_port +* [in] Pointer to the port object for which to get a path +* advisory. +* +* lid_ho +* [in] LID value (host order) for which to get a path advisory. +* +* start_from +* [in] Port number from where to start balance counting. +* +* ignore_existing +* [in] Set to cause the switch to choose the optimal route +* regardless of existing paths. +* If false, the switch will choose an existing route if one +* exists, otherwise will choose the optimal route. +* +* dor +* [in] If TRUE, Dimension Order Routing will be done. +* +* RETURN VALUE +* Returns the recommended port on which to route this LID. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_recommend_mcast_path +* NAME +* osm_switch_recommend_mcast_path +* +* DESCRIPTION +* Returns the recommended port on which to route this LID. +* +* SYNOPSIS +*/ +uint8_t +osm_switch_recommend_mcast_path(IN osm_switch_t * const p_sw, + IN osm_port_t * p_port, + IN const uint16_t mlid_ho, + IN const boolean_t ignore_existing); +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch object. +* +* p_port +* [in] Pointer to the port object for which to get +* the multicast path. +* +* mlid_ho +* [in] MLID for the multicast group in question. +* +* ignore_existing +* [in] Set to cause the switch to choose the optimal route +* regardless of existing paths. +* If false, the switch will choose an existing route if one exists, +* otherwise will choose the optimal route. +* +* RETURN VALUE +* Returns the recommended port on which to route this LID. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_get_mcast_fwd_tbl_size +* NAME +* osm_switch_get_mcast_fwd_tbl_size +* +* DESCRIPTION +* Returns the number of entries available in the multicast forwarding table. +* +* SYNOPSIS +*/ +static inline uint16_t +osm_switch_get_mcast_fwd_tbl_size(IN const osm_switch_t * const p_sw) +{ + return (cl_ntoh16(p_sw->switch_info.mcast_cap)); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch. +* +* RETURN VALUE +* Returns the number of entries available in the multicast forwarding table. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_path_count_get +* NAME +* osm_switch_path_count_get +* +* DESCRIPTION +* Returns the count of the number of paths going through this port. +* +* SYNOPSIS +*/ +static inline uint32_t +osm_switch_path_count_get(IN const osm_switch_t * const p_sw, + IN const uint8_t port_num) +{ + return (osm_port_prof_path_count_get(&p_sw->p_prof[port_num])); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the Switch object. +* +* port_num +* [in] Port number for which to get path count. +* +* RETURN VALUE +* Returns the count of the number of paths going through this port. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_prepare_path_rebuild +* NAME +* osm_switch_prepare_path_rebuild +* +* DESCRIPTION +* Prepares a switch to rebuild pathing information. +* +* SYNOPSIS +*/ +int +osm_switch_prepare_path_rebuild(IN osm_switch_t * p_sw, IN uint16_t max_lids); +/* +* PARAMETERS +* p_sw +* [in] Pointer to the Switch object. +* +* max_lids +* [in] Max number of lids in the subnet. +* +* RETURN VALUE +* Returns zero on success, or negative value if an error occurred. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_get_mcast_tbl_ptr +* NAME +* osm_switch_get_mcast_tbl_ptr +* +* DESCRIPTION +* Returns a pointer to the switch's multicast table. +* +* SYNOPSIS +*/ +static inline osm_mcast_tbl_t *osm_switch_get_mcast_tbl_ptr(IN const + osm_switch_t * + const p_sw) +{ + return ((osm_mcast_tbl_t *) & p_sw->mcast_tbl); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch. +* +* RETURN VALUE +* Returns a pointer to the switch's multicast table. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Switch/osm_switch_is_in_mcast_tree +* NAME +* osm_switch_is_in_mcast_tree +* +* DESCRIPTION +* Returns true if this switch already belongs in the tree for the specified +* multicast group. +* +* SYNOPSIS +*/ +static inline boolean_t +osm_switch_is_in_mcast_tree(IN const osm_switch_t * const p_sw, + IN const uint16_t mlid_ho) +{ + const osm_mcast_tbl_t *p_tbl; + + p_tbl = &p_sw->mcast_tbl; + if (p_tbl) + return (osm_mcast_tbl_is_any_port(&p_sw->mcast_tbl, mlid_ho)); + else + return (FALSE); +} +/* +* PARAMETERS +* p_sw +* [in] Pointer to the switch. +* +* mlid_ho +* [in] MLID (host order) of the multicast tree to check. +* +* RETURN VALUE +* Returns true if this switch already belongs in the tree for the specified +* multicast group. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_SWITCH_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_ucast_cache.h b/contrib/ofed/management/opensm/include/opensm/osm_ucast_cache.h new file mode 100644 index 000000000000..11335c7315b1 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_ucast_cache.h @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2008 Mellanox Technologies LTD. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Header file that describes Unicast Cache functions. + * + * Environment: + * Linux User Mode + * + * $Revision: 1.4 $ + */ + +#ifndef _OSM_UCAST_CACHE_H_ +#define _OSM_UCAST_CACHE_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +struct osm_ucast_mgr; + +/****h* OpenSM/Unicast Manager/Unicast Cache +* NAME +* Unicast Cache +* +* DESCRIPTION +* The Unicast Cache object encapsulates the information +* needed to cache and write unicast routing of the subnet. +* +* The Unicast Cache object is NOT thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Yevgeny Kliteynik, Mellanox +* +*********/ + +/****f* OpenSM: Unicast Cache/osm_ucast_cache_invalidate +* NAME +* osm_ucast_cache_invalidate +* +* DESCRIPTION +* The osm_ucast_cache_invalidate function purges the +* unicast cache and marks the cache as invalid. +* +* SYNOPSIS +*/ +void osm_ucast_cache_invalidate(struct osm_ucast_mgr *p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the ucast mgr object. +* +* RETURN VALUE +* This function does not return any value. +* +* NOTES +* +* SEE ALSO +* Unicast Manager object +*********/ + +/****f* OpenSM: Unicast Cache/osm_ucast_cache_check_new_link +* NAME +* osm_ucast_cache_check_new_link +* +* DESCRIPTION +* The osm_ucast_cache_check_new_link checks whether +* the newly discovered link still allows us to use +* cached unicast routing. +* +* SYNOPSIS +*/ +void osm_ucast_cache_check_new_link(struct osm_ucast_mgr *p_mgr, + osm_node_t * p_node_1, uint8_t port_num_1, + osm_node_t * p_node_2, uint8_t port_num_2); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the unicast manager object. +* +* physp1 +* [in] Pointer to the first physical port of the link. +* +* physp2 +* [in] Pointer to the second physical port of the link. +* +* RETURN VALUE +* This function does not return any value. +* +* NOTES +* The function checks whether the link was previously +* cached/dropped or is this a completely new link. +* If it decides that the new link makes cached routing +* invalid, the cache is purged and marked as invalid. +* +* SEE ALSO +* Unicast Cache object +*********/ + +/****f* OpenSM: Unicast Cache/osm_ucast_cache_add_link +* NAME +* osm_ucast_cache_add_link +* +* DESCRIPTION +* The osm_ucast_cache_add_link adds link to the cache. +* +* SYNOPSIS +*/ +void osm_ucast_cache_add_link(struct osm_ucast_mgr *p_mgr, + osm_physp_t * physp1, osm_physp_t * physp2); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the unicast manager object. +* +* physp1 +* [in] Pointer to the first physical port of the link. +* +* physp2 +* [in] Pointer to the second physical port of the link. +* +* RETURN VALUE +* This function does not return any value. +* +* NOTES +* Since the cache operates with ports and not links, +* the function adds two port entries (both sides of the +* link) to the cache. +* If it decides that the dropped link makes cached routing +* invalid, the cache is purged and marked as invalid. +* +* SEE ALSO +* Unicast Manager object +*********/ + +/****f* OpenSM: Unicast Cache/osm_ucast_cache_add_node +* NAME +* osm_ucast_cache_add_node +* +* DESCRIPTION +* The osm_ucast_cache_add_node adds node and all +* its links to the cache. +* +* SYNOPSIS +*/ +void osm_ucast_cache_add_node(struct osm_ucast_mgr *p_mgr, osm_node_t * p_node); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the unicast manager object. +* +* p_node +* [in] Pointer to the node object that should be cached. +* +* RETURN VALUE +* This function does not return any value. +* +* NOTES +* If the function decides that the dropped node makes cached +* routing invalid, the cache is purged and marked as invalid. +* +* SEE ALSO +* Unicast Manager object +*********/ + +/****f* OpenSM: Unicast Cache/osm_ucast_cache_process +* NAME +* osm_ucast_cache_process +* +* DESCRIPTION +* The osm_ucast_cache_process function writes the +* cached unicast routing on the subnet switches. +* +* SYNOPSIS +*/ +int osm_ucast_cache_process(struct osm_ucast_mgr *p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the unicast manager object. +* +* RETURN VALUE +* This function returns zero on sucess and non-zero +* value otherwise. +* +* NOTES +* Iterates through all the subnet switches and writes +* the LFTs that were calculated during the last routing +* engine execution to the switches. +* +* SEE ALSO +* Unicast Manager object +*********/ + +END_C_DECLS +#endif /* _OSM_UCAST_CACHE_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_ucast_mgr.h b/contrib/ofed/management/opensm/include/opensm/osm_ucast_mgr.h new file mode 100644 index 000000000000..a04047645e8a --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_ucast_mgr.h @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_ucast_mgr_t. + * This object represents the Unicast Manager object. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_UCAST_MGR_H_ +#define _OSM_UCAST_MGR_H_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Unicast Manager +* NAME +* Unicast Manager +* +* DESCRIPTION +* The Unicast Manager object encapsulates the information +* needed to control unicast LID forwarding on the subnet. +* +* The Unicast Manager object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +struct osm_sm; +/****s* OpenSM: Unicast Manager/osm_ucast_mgr_t +* NAME +* osm_ucast_mgr_t +* +* DESCRIPTION +* Unicast Manager structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_ucast_mgr { + struct osm_sm *sm; + osm_subn_t *p_subn; + osm_log_t *p_log; + cl_plock_t *p_lock; + cl_qlist_t port_order_list; + boolean_t is_dor; + boolean_t some_hop_count_set; + cl_qmap_t cache_sw_tbl; + boolean_t cache_valid; +} osm_ucast_mgr_t; +/* +* FIELDS +* sm +* Pointer to the SM object. +* +* p_subn +* Pointer to the Subnet object for this subnet. +* +* p_log +* Pointer to the log object. +* +* p_lock +* Pointer to the serializing lock. +* +* is_dor +* Dimension Order Routing (DOR) will be done +* +* port_order_list +* List of ports ordered for routing. +* +* any_change +* Initialized to FALSE at the beginning of the algorithm, +* set to TRUE by osm_ucast_mgr_set_fwd_table() if any mad +* was sent. +* +* some_hop_count_set +* Initialized to FALSE at the beginning of each the min hop +* tables calculation iteration cycle, set to TRUE to indicate +* that some hop count changes were done. +* +* cache_sw_tbl +* Cached switches table. +* +* cache_valid +* TRUE if the unicast cache is valid. +* +* SEE ALSO +* Unicast Manager object +*********/ + +/****f* OpenSM: Unicast Manager/osm_ucast_mgr_construct +* NAME +* osm_ucast_mgr_construct +* +* DESCRIPTION +* This function constructs a Unicast Manager object. +* +* SYNOPSIS +*/ +void osm_ucast_mgr_construct(IN osm_ucast_mgr_t * const p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to a Unicast Manager object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows osm_ucast_mgr_destroy +* +* Calling osm_ucast_mgr_construct is a prerequisite to calling any other +* method except osm_ucast_mgr_init. +* +* SEE ALSO +* Unicast Manager object, osm_ucast_mgr_init, +* osm_ucast_mgr_destroy +*********/ + +/****f* OpenSM: Unicast Manager/osm_ucast_mgr_destroy +* NAME +* osm_ucast_mgr_destroy +* +* DESCRIPTION +* The osm_ucast_mgr_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void osm_ucast_mgr_destroy(IN osm_ucast_mgr_t * const p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to the object to destroy. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified +* Unicast Manager object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to +* osm_ucast_mgr_construct or osm_ucast_mgr_init. +* +* SEE ALSO +* Unicast Manager object, osm_ucast_mgr_construct, +* osm_ucast_mgr_init +*********/ + +/****f* OpenSM: Unicast Manager/osm_ucast_mgr_init +* NAME +* osm_ucast_mgr_init +* +* DESCRIPTION +* The osm_ucast_mgr_init function initializes a +* Unicast Manager object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_ucast_mgr_init(IN osm_ucast_mgr_t * const p_mgr, IN struct osm_sm * sm); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_ucast_mgr_t object to initialize. +* +* sm +* [in] Pointer to the SM object. +* +* RETURN VALUES +* IB_SUCCESS if the Unicast Manager object was initialized +* successfully. +* +* NOTES +* Allows calling other Unicast Manager methods. +* +* SEE ALSO +* Unicast Manager object, osm_ucast_mgr_construct, +* osm_ucast_mgr_destroy +*********/ + +/****f* OpenSM: Unicast Manager/osm_ucast_mgr_set_fwd_table +* NAME +* osm_ucast_mgr_set_fwd_table +* +* DESCRIPTION +* Setup forwarding table for the switch (from prepared new_lft). +* +* SYNOPSIS +*/ +int osm_ucast_mgr_set_fwd_table(IN osm_ucast_mgr_t * const p_mgr, + IN osm_switch_t * const p_sw); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_ucast_mgr_t object. +* +* p_mgr +* [in] Pointer to an osm_switch_t object. +* +* SEE ALSO +* Unicast Manager +*********/ + +/****f* OpenSM: Unicast Manager/osm_ucast_mgr_build_lid_matrices +* NAME +* osm_ucast_mgr_build_lid_matrices +* +* DESCRIPTION +* Build switches's lid matrices. +* +* SYNOPSIS +*/ +int osm_ucast_mgr_build_lid_matrices(IN osm_ucast_mgr_t * const p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_ucast_mgr_t object. +* +* NOTES +* This function processes the subnet, configuring switches' +* min hops tables (aka lid matrices). +* +* SEE ALSO +* Unicast Manager +*********/ + +/****f* OpenSM: Unicast Manager/osm_ucast_mgr_process +* NAME +* osm_ucast_mgr_process +* +* DESCRIPTION +* Process and configure the subnet's unicast forwarding tables. +* +* SYNOPSIS +*/ +int osm_ucast_mgr_process(IN osm_ucast_mgr_t * const p_mgr); +/* +* PARAMETERS +* p_mgr +* [in] Pointer to an osm_ucast_mgr_t object. +* +* RETURN VALUES +* Returns zero on success and negative value on failure. +* +* NOTES +* This function processes the subnet, configuring switch +* unicast forwarding tables. +* +* SEE ALSO +* Unicast Manager, Node Info Response Controller +*********/ +END_C_DECLS +#endif /* _OSM_UCAST_MGR_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_version.h b/contrib/ofed/management/opensm/include/opensm/osm_version.h new file mode 100644 index 000000000000..697e2fdfeaa7 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_version.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_VERSION_H_ +#define _OSM_VERSION_H_ + +/****s* OpenSM: Base/OSM_VERSION +* NAME +* OSM_VERSION +* +* DESCRIPTION +* The version string for OpenSM +* +* SYNOPSIS +*/ +#define OSM_VERSION "OpenSM 3.3.1" +/********/ + +#endif /* _OSM_VERSION_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_version.h.in b/contrib/ofed/management/opensm/include/opensm/osm_version.h.in new file mode 100644 index 000000000000..d78324532582 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_version.h.in @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_VERSION_H_ +#define _OSM_VERSION_H_ + +/****s* OpenSM: Base/OSM_VERSION +* NAME +* OSM_VERSION +* +* DESCRIPTION +* The version string for OpenSM +* +* SYNOPSIS +*/ +#define OSM_VERSION "OpenSM @VERSION@" +/********/ + +#endif /* _OSM_VERSION_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/osm_vl15intf.h b/contrib/ofed/management/opensm/include/opensm/osm_vl15intf.h new file mode 100644 index 000000000000..028eec0c7829 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/osm_vl15intf.h @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_vl15_t. + * This object represents an IBA subnet. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_VL15INTF_H_ +#define _OSM_VL15INTF_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/VL15 +* NAME +* VL15 +* +* DESCRIPTION +* The VL15 object encapsulates the information needed by the +* OpenSM to instantiate the VL15 interface. The OpenSM allocates +* one VL15 object per subnet. +* +* The VL15 object transmits MADs to the wire at a throttled rate, +* so as to not overload the VL15 buffering of subnet components. +* OpenSM modules may post VL15 MADs to the VL15 interface as fast +* as possible. +* +* The VL15 object is thread safe. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****d* OpenSM: SM/osm_vl15_state_t +* NAME +* osm_vl15_state_t +* +* DESCRIPTION +* Enumerates the possible states of SM object. +* +* SYNOPSIS +*/ +typedef enum _osm_vl15_state { + OSM_VL15_STATE_INIT = 0, + OSM_VL15_STATE_READY +} osm_vl15_state_t; +/***********/ + +/****s* OpenSM: VL15/osm_vl15_t +* NAME +* osm_vl15_t +* +* DESCRIPTION +* VL15 structure. +* +* This object should be treated as opaque and should +* be manipulated only through the provided functions. +* +* SYNOPSIS +*/ +typedef struct osm_vl15 { + osm_thread_state_t thread_state; + osm_vl15_state_t state; + uint32_t max_wire_smps; + cl_event_t signal; + cl_thread_t poller; + cl_qlist_t rfifo; + cl_qlist_t ufifo; + cl_spinlock_t lock; + osm_vendor_t *p_vend; + osm_log_t *p_log; + osm_stats_t *p_stats; +} osm_vl15_t; +/* +* FIELDS +* thread_state +* Tracks the thread state of the poller thread. +* +* state +* Tracks the state of the VL15 interface itself. +* +* max_wire_smps +* Maximum number of VL15 MADs allowed on the wire at one time. +* +* signal +* Event on which the poller sleeps. +* +* rfifo +* First-in First-out queue for outbound VL15 MADs for which +* a response is expected, aka the "response fifo" +* +* ufifo +* First-in First-out queue for outbound VL15 MADs for which +* no response is expected, aka the "unicast fifo". +* +* poller +* Worker thread pool that services the fifo to transmit VL15 MADs +* +* lock +* Spinlock guarding the FIFO. +* +* p_vend +* Pointer to the vendor transport object. +* +* p_log +* Pointer to the log object. +* +* p_stats +* Pointer to the OpenSM statistics block. +* +* SEE ALSO +* VL15 object +*********/ + +/****f* OpenSM: VL15/osm_vl15_construct +* NAME +* osm_vl15_construct +* +* DESCRIPTION +* This function constructs an VL15 object. +* +* SYNOPSIS +*/ +void osm_vl15_construct(IN osm_vl15_t * const p_vl15); +/* +* PARAMETERS +* p_vl15 +* [in] Pointer to a VL15 object to construct. +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Allows calling osm_vl15_destroy. +* +* Calling osm_vl15_construct is a prerequisite to calling any other +* method except osm_vl15_init. +* +* SEE ALSO +* VL15 object, osm_vl15_init, osm_vl15_destroy +*********/ + +/****f* OpenSM: VL15/osm_vl15_destroy +* NAME +* osm_vl15_destroy +* +* DESCRIPTION +* The osm_vl15_destroy function destroys the object, releasing +* all resources. +* +* SYNOPSIS +*/ +void +osm_vl15_destroy(IN osm_vl15_t * const p_vl15, IN struct osm_mad_pool *p_pool); +/* +* PARAMETERS +* p_vl15 +* [in] Pointer to a VL15 object to destroy. +* +* p_pool +* [in] The pointer to the mad pool to return outstanding mads to +* +* RETURN VALUE +* This function does not return a value. +* +* NOTES +* Performs any necessary cleanup of the specified VL15 object. +* Further operations should not be attempted on the destroyed object. +* This function should only be called after a call to osm_vl15_construct or +* osm_vl15_init. +* +* SEE ALSO +* VL15 object, osm_vl15_construct, osm_vl15_init +*********/ + +/* + Initialization. + Rate specifies the minimum number of microseconds between transmissions + on VL15. +*/ +/****f* OpenSM: VL15/osm_vl15_init +* NAME +* osm_vl15_init +* +* DESCRIPTION +* The osm_vl15_init function initializes a VL15 object for use. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_vl15_init(IN osm_vl15_t * const p_vl15, + IN osm_vendor_t * const p_vend, + IN osm_log_t * const p_log, + IN osm_stats_t * const p_stats, + IN const int32_t max_wire_smps); +/* +* PARAMETERS +* p_vl15 +* [in] Pointer to an osm_vl15_t object to initialize. +* +* p_vend +* [in] Pointer to the vendor transport object. +* +* p_log +* [in] Pointer to the log object. +* +* p_stats +* [in] Pointer to the OpenSM stastics block. +* +* max_wire_smps +* [in] Maximum number of MADs allowed on the wire at one time. +* +* RETURN VALUES +* IB_SUCCESS if the VL15 object was initialized successfully. +* +* NOTES +* Allows calling other VL15 methods. +* +* SEE ALSO +* VL15 object, osm_vl15_construct, osm_vl15_destroy +*********/ + +/****f* OpenSM: VL15/osm_vl15_post +* NAME +* osm_vl15_post +* +* DESCRIPTION +* Posts a MAD to the VL15 interface for transmission. +* +* SYNOPSIS +*/ +void osm_vl15_post(IN osm_vl15_t * const p_vl15, IN osm_madw_t * const p_madw); +/* +* PARAMETERS +* p_vl15 +* [in] Pointer to an osm_vl15_t object. +* +* p_madw +* [in] Pointer to a MAD wrapper structure containing the MAD. +* +* RETURN VALUES +* This function does not return a value. +* +* NOTES +* The osm_vl15_construct or osm_vl15_init must be called before using +* this function. +* +* SEE ALSO +* VL15 object, osm_vl15_construct, osm_vl15_init +*********/ + +/****f* OpenSM: VL15/osm_vl15_poll +* NAME +* osm_vl15_poll +* +* DESCRIPTION +* Causes the VL15 Interface to consider sending another QP0 MAD. +* +* SYNOPSIS +*/ +void osm_vl15_poll(IN osm_vl15_t * const p_vl); +/* +* PARAMETERS +* p_vl15 +* [in] Pointer to an osm_vl15_t object. +* +* RETURN VALUES +* None. +* +* NOTES +* This function signals the VL15 that it may be possible to send +* a SMP. This function checks three criteria before sending a SMP: +* 1) The VL15 worker is IDLE +* 2) There are no QP0 SMPs currently outstanding +* 3) There is something on the VL15 FIFO to send +* +* SEE ALSO +* VL15 object, osm_vl15_construct, osm_vl15_init +*********/ + +/****f* OpenSM: VL15/osm_vl15_shutdown +* NAME +* osm_vl15_shutdown +* +* DESCRIPTION +* Cleanup all outstanding MADs on both fifo's. +* This is required to return all outstanding MAD resources. +* +* SYNOPSIS +*/ +void +osm_vl15_shutdown(IN osm_vl15_t * const p_vl, + IN osm_mad_pool_t * const p_mad_pool); +/* +* PARAMETERS +* p_vl15 +* [in] Pointer to an osm_vl15_t object. +* +* p_mad_pool +* [in] The MAD pool owning the mads. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +* VL15 object, osm_vl15_construct, osm_vl15_init +*********/ + +END_C_DECLS +#endif /* _OSM_VL15INTF_H_ */ diff --git a/contrib/ofed/management/opensm/include/opensm/st.h b/contrib/ofed/management/opensm/include/opensm/st.h new file mode 100644 index 000000000000..30cc30823301 --- /dev/null +++ b/contrib/ofed/management/opensm/include/opensm/st.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* @(#) st.h 5.1 89/12/14 */ + +#ifndef ST_INCLUDED +#define ST_INCLUDED + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#define st_ptr_t unsigned long +typedef st_ptr_t st_data_t; + +#define ST_DATA_T_DEFINED + +typedef struct st_table st_table; + +struct st_hash_type { + int (*compare) (void *, void *); + st_ptr_t(*hash) (void *); +}; + +struct st_table { + struct st_hash_type *type; + int num_bins; + int num_entries; + struct st_table_entry **bins; +}; + +#define st_is_member(table,key) st_lookup(table,key,(st_data_t *)0) + +enum st_retval { ST_CONTINUE, ST_STOP, ST_DELETE }; + +st_table *st_init_table(struct st_hash_type *); +st_table *st_init_table_with_size(struct st_hash_type *, size_t); +st_table *st_init_numtable(void); +st_table *st_init_numtable_with_size(size_t); +st_table *st_init_strtable(void); +st_table *st_init_strtable_with_size(size_t); +int st_delete(st_table *, st_data_t *, st_data_t *); +int st_delete_safe(st_table *, st_data_t *, st_data_t *, st_data_t); +int st_insert(st_table *, st_data_t, st_data_t); +int st_lookup(st_table *, st_data_t, st_data_t *); +void st_foreach(st_table *, + int (*)(st_data_t key, st_data_t val, st_data_t arg), + st_data_t); +void st_add_direct(st_table *, st_data_t, st_data_t); +void st_free_table(st_table *); +void st_cleanup_safe(st_table *, st_data_t); +st_table *st_copy(st_table *); + +#define ST_NUMCMP ((int (*)()) 0) +#define ST_NUMHASH ((int (*)()) -2) + +#define st_numcmp ST_NUMCMP +#define st_numhash ST_NUMHASH + +/* int st_strhash(void); */ + +END_C_DECLS +#endif /* ST_INCLUDED */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_mtl_bind.h b/contrib/ofed/management/opensm/include/vendor/osm_mtl_bind.h new file mode 100644 index 000000000000..3994d5984d52 --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_mtl_bind.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_BIND_H_ +#define _OSM_BIND_H_ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM: Vendor/osm_vendor_mgt_bind +* NAME +* osm_vendor_mgt_bind_t +* +* DESCRIPTION +* Tracks the handles returned by IB_MGT to the SMI and GSI +* Nulled on init of the vendor obj. Populated on first bind. +* +* SYNOPSIS +*/ +typedef struct _osm_vendor_mgt_bind { + boolean_t smi_init, gsi_init; + IB_MGT_mad_hndl_t smi_mads_hdl; + IB_MGT_mad_hndl_t gsi_mads_hdl; + struct _osm_mtl_bind_info *smi_p_bind; +} osm_vendor_mgt_bind_t; + +/* +* FIELDS +* smi_mads_hdl +* Handle returned by IB_MGT_get_handle to the IB_MGT_SMI +* +* gsi_mads_hdl +* Handle returned by IB_MGT_get_handle to the IB_MGT_GSI +* +* SEE ALSO +*********/ + +/****s* OpenSM: Vendor osm_mtl_bind_info_t +* NAME +* osm_mtl_bind_info_t +* +* DESCRIPTION +* Handle to the result of binding a class callbacks to IB_MGT. +* +* SYNOPSIS +*/ +typedef struct _osm_mtl_bind_info { + IB_MGT_mad_hndl_t mad_hndl; + osm_vendor_t *p_vend; + void *client_context; + VAPI_hca_hndl_t hca_hndl; + VAPI_hca_id_t hca_id; + uint8_t port_num; + osm_vend_mad_recv_callback_t rcv_callback; + osm_vend_mad_send_err_callback_t send_err_callback; + osm_mad_pool_t *p_osm_pool; +} osm_mtl_bind_info_t; + +/* +* FIELDS +* mad_hndl +* the handle returned from the registration in IB_MGT +* +* p_vend +* Pointer to the vendor object. +* +* client_context +* User's context passed during osm_bind +* +* hca_id +* HCA Id we bind to. +* +* port_num +* Port number (within the HCA) of the bound port. +* +* rcv_callback +* OSM Callback function to be called on receive of MAD. +* +* send_err_callback +* OSM Callback to be called on send error. +* +* p_osm_pool +* Points to the MAD pool used by OSM +* +* +* SEE ALSO +*********/ +ib_api_status_t +osm_mtl_send_mad(IN osm_mtl_bind_info_t * p_bind, IN osm_madw_t * const p_madw); + +END_C_DECLS +#endif // _OSM_BIND_H_ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_pkt_randomizer.h b/contrib/ofed/management/opensm/include/vendor/osm_pkt_randomizer.h new file mode 100644 index 000000000000..5a8ef5fb7306 --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_pkt_randomizer.h @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_subn_t. + * This object represents an IBA subnet. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_PKT_RANDOMIZER_H_ +#define _OSM_PKT_RANDOMIZER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Packet Randomizer +* NAME +* Packet Randomizer +* +* DESCRIPTION +* The Packet Randomizer object encapsulates the information needed for +* randomly dropping packets for debug. +* +* The Packet Randomizer object is not thread safe, thus callers must +* provide serialization. +* +* AUTHOR +* Yael Kalka, Mellanox +* +*********/ +/****d* OpenSM: Pkt_Randomizer/osm_pkt_randomizer_t +* NAME +* osm_pkt_randomizer_t +* +* DESCRIPTION +* Packet randomizer structure. This structure contains the various +* parameters needed by the packet randomizer. +* +* SYNOPSIS +*/ +typedef struct _osm_pkt_randomizer { + uint8_t osm_pkt_drop_rate; + uint8_t osm_pkt_num_unstable_links; + uint8_t osm_pkt_unstable_link_rate; + osm_dr_path_t *fault_dr_paths; + uint8_t num_paths_initialized; +} osm_pkt_randomizer_t; + +/* +* FIELDS +* +* osm_pkt_drop_rate +* Used by the randomizer whether to drop a packet or not. +* Taken from the global variable OSM_PKT_DROP_RATE. If not given or +* if set to zero, the randomizer will not run. +* +* osm_pkt_num_unstable_links +* The number of unstable links to be drawn. +* Taken from the global variable OSM_PKT_NUM_UNSTABLE_LINKS. default = 1. +* +* osm_pkt_unstable_link_rate +* Used by the randomizer whether to add a packet to the unstable links +* list or not. Taken from the global variable OSM_PKT_UNSTABLE_LINK_RATE. +* default = 20. +* +* fault_dr_path +* Array of osm_dr_path_t objects, that includes all the dr_paths +* that are marked as errored. +* +* num_paths_initialized +* Describes the number of paths from the fault_dr_paths array that +* have already been initialized. +* +* SEE ALSO +* Packet Randomizer object +*********/ + +/****f* OpenSM: Pkt_Randomizer/osm_pkt_randomizer_init +* NAME +* osm_pkt_randomizer_init +* +* DESCRIPTION +* The osm_pkt_randomizer_init function initializes the Packet Randomizer object. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_pkt_randomizer_init(IN OUT osm_pkt_randomizer_t ** pp_pkt_randomizer, + IN osm_log_t * p_log); +/* +* PARAMETERS +* p_pkt_randomizer +* [in] Pointer to the Packet Randomizer object to be initialized. +* +* p_log +* [in] Pointer to the log object. +* +* RETURN VALUE +* None +* +* NOTES +* +* SEE ALSO +* +*********/ + +/****f* OpenSM: Pkt_Randomizer/osm_pkt_randomizer_destroy +* NAME +* osm_pkt_randomizer_destroy +* +* DESCRIPTION +* The osm_pkt_randomizer_destroy function destroys the Packet Randomizer object. +* +* SYNOPSIS +*/ +void +osm_pkt_randomizer_destroy(IN osm_pkt_randomizer_t ** pp_pkt_randomizer, + IN osm_log_t * p_log); +/* +* PARAMETERS +* p_pkt_randomizer +* [in] Pointer to the Packet Randomizer object to be destroyed. +* +* p_log +* [in] Pointer to the log object. +* +* RETURN VALUE +* None +* +* NOTES +* +* SEE ALSO +* +*********/ + +/****f* OpenSM: Pkt_Randomizer/osm_pkt_randomizer_madw_drop +* NAME +* osm_pkt_randomizer_madw_drop +* +* DESCRIPTION +* The osm_pkt_randomizer_madw_drop is base function of the packet +* randomizer. +* It decides according to different random criteria whether or not +* the packet received should be dropped (according to its dr_path). +* This function is relevant both for mads sent by the SM and mads +* received by the SM. +* It returns TRUE if the mad should be dropped, and FALSE otherwise. +* +* SYNOPSIS +*/ +boolean_t +osm_pkt_randomizer_mad_drop(IN osm_log_t * p_log, + IN osm_pkt_randomizer_t * p_pkt_randomizer, + IN const ib_mad_t * p_mad); +/* +* PARAMETERS +* p_subn +* [in] Pointer to the Subnet object for this subnet. +* +* p_log +* [in] Pointer to the log object. +* +* p_mad +* [in] Pointer to the ib_mad_t mad to be checked. +* +* RETURN VALUE +* TRUE if the mad should be dropped. FALSE otherwise. +* +* NOTES +* +* SEE ALSO +* +*********/ + +END_C_DECLS +#endif /* _OSM_PKT_RANDOMIZER_H */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_ts_useraccess.h b/contrib/ofed/management/opensm/include/vendor/osm_ts_useraccess.h new file mode 100644 index 000000000000..d68c924f363b --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_ts_useraccess.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include "ts_ib_useraccess.h" + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +typedef struct ib_user_mad_filter osm_ts_user_mad_filter; +typedef struct ib_set_port_info_ioctl osm_ts_set_port_info_ioctl; +typedef struct ib_get_port_info_ioctl osm_ts_get_port_info_ioctl; +typedef struct ib_gid_entry_ioctl osm_ts_gid_entry_ioctl; + +END_C_DECLS diff --git a/contrib/ofed/management/opensm/include/vendor/osm_umadt.h b/contrib/ofed/management/opensm/include/vendor/osm_umadt.h new file mode 100644 index 000000000000..129627d7906b --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_umadt.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mad_wrapper_t. + * This object represents the context wrapper for OpenSM MAD processing. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_UMADT_h_ +#define _OSM_UMADT_h_ + +#include "iba/ib_types.h" +#include +#include +#include "umadt.h" +#include "ibt.h" + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +typedef struct _umadt_obj_t { + void *umadt_handle; + UMADT_INTERFACE uMadtInterface; + IBT_INTERFACE IbtInterface; + boolean init_done; + cl_spinlock_t register_lock; + cl_qlist_t register_list; + osm_log_t *p_log; + uint32_t timeout; + +} umadt_obj_t; +/*********/ + +/****s* OpenSM: Umadt MAD Wrapper/osm_bind_info +* NAME +* osm_bind_info +* +* DESCRIPTION +* Context needed for processing individual MADs +* +* SYNOPSIS +*/ + +typedef struct _mad_bind_info_t { + cl_list_item_t list_item; + umadt_obj_t *p_umadt_obj; + osm_mad_pool_t *p_mad_pool; + osm_vend_mad_recv_callback_t mad_recv_callback; + void *client_context; + cl_thread_t recv_processor_thread; + cl_spinlock_t trans_ctxt_lock; + cl_qlist_t trans_ctxt_list; + cl_timer_t timeout_timer; + cl_spinlock_t timeout_list_lock; + cl_qlist_t timeout_list; + RegisterClassStruct umadt_reg_class; + MADT_HANDLE umadt_handle; /* Umadt type */ + +} mad_bind_info_t; + +typedef struct _trans_context_t { + cl_list_item_t list_item; + uint64_t trans_id; + uint64_t sent_time; /* micro secs */ + void *context; +} trans_context_t; + +/* +* FIELDS +* list_item +* List linkage for pools and lists. MUST BE FIRST MEMBER! +* +* p_mad_pool +* Pointer to the MAD pool to be used by mads with this bind handle. +* +* mad_recv_callback +* Callback function called by the mad receive processor. +* +* client_context +* context to be passed to the receive callback. +* +* recv_processor_thread +* Thread structure for the receive processor thread. +* +* umadt_reg_class +* Umadt register class struct used to register with Umadt. +* +* umadt_handle +* Umadt returns this handle from a registration call. The transport layer +* uses this handle to talk to Umadt. +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /*_OSM_UMADT_h_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor.h new file mode 100644 index 000000000000..4d0ae4c009ee --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Include file used by OpenSM to pull in the correct vendor file. + */ + +/* + this is the generic include file which includes + the proper vendor specific file +*/ +#include + +#if defined( OSM_VENDOR_INTF_TEST ) +#include +#elif defined( OSM_VENDOR_INTF_UMADT ) +#include +#elif defined( OSM_VENDOR_INTF_MTL ) +/* HACK - I do not know how to prevent complib from loading kernel H files */ +#undef __init +#include +#elif defined( OSM_VENDOR_INTF_TS ) +#undef __init +#include +#elif defined( OSM_VENDOR_INTF_ANAFA ) +#undef __init +#include +#elif defined( OSM_VENDOR_INTF_SIM ) +#undef __init +#include +#elif defined( OSM_VENDOR_INTF_OPENIB ) +#include +#elif defined( OSM_VENDOR_INTF_AL ) +#include +#elif +#error No MAD Interface selected! +#error Choose an interface in osm_config.h +#endif diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_al.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_al.h new file mode 100644 index 000000000000..e7371c948c7e --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_al.h @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mad_wrapper_t. + * This object represents the context wrapper for OpenSM MAD processing. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_VENDOR_AL_H_ +#define _OSM_VENDOR_AL_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Vendor AL +* NAME +* Vendor AL +* +* DESCRIPTION +* +* The Vendor AL object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* Enable various hacks to compensate for bugs in external code... +* +* +* AUTHOR +* +* +*********/ +/****h* OpenSM/Vendor Access Layer (AL) +* NAME +* Vendor AL +* +* DESCRIPTION +* This file is the vendor specific file for the AL Infiniband API. +* +* AUTHOR +* Steve King, Intel +* +*********/ +#define OSM_AL_SQ_SGE 256 +#define OSM_AL_RQ_SGE 256 +#define OSM_DEFAULT_RETRY_COUNT 3 +/* AL supports RMPP */ +#define VENDOR_RMPP_SUPPORT 1 +/****s* OpenSM: Vendor AL/osm_ca_info_t +* NAME +* osm_ca_info_t +* +* DESCRIPTION +* Structure containing information about local Channle Adapters. +* +* SYNOPSIS +*/ +typedef struct _osm_ca_info { + ib_net64_t guid; + size_t attr_size; + ib_ca_attr_t *p_attr; + +} osm_ca_info_t; +/* +* FIELDS +* guid +* Node GUID of the local CA. +* +* attr_size +* Size of the CA attributes for this CA. +* +* p_attr +* Pointer to dynamicly allocated CA Attribute structure. +* +* SEE ALSO +*********/ + +/****f* OpenSM: CA Info/osm_ca_info_get_num_ports +* NAME +* osm_ca_info_get_num_ports +* +* DESCRIPTION +* Returns the number of ports owned by this CA. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_ca_info_get_num_ports(IN const osm_ca_info_t * const p_ca_info) +{ + return (p_ca_info->p_attr->num_ports); +} + +/* +* PARAMETERS +* p_ca_info +* [in] Pointer to a CA Info object. +* +* RETURN VALUE +* Returns the number of ports owned by this CA. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: CA Info/osm_ca_info_get_port_guid +* NAME +* osm_ca_info_get_port_guid +* +* DESCRIPTION +* Returns the port GUID of the specified port owned by this CA. +* +* SYNOPSIS +*/ +static inline ib_net64_t +osm_ca_info_get_port_guid(IN const osm_ca_info_t * const p_ca_info, + IN const uint8_t index) +{ + return (p_ca_info->p_attr->p_port_attr[index].port_guid); +} + +/* +* PARAMETERS +* p_ca_info +* [in] Pointer to a CA Info object. +* +* index +* [in] Port "index" for which to retrieve the port GUID. +* The index is the offset into the ca's internal array +* of port attributes. +* +* RETURN VALUE +* Returns the port GUID of the specified port owned by this CA. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: CA Info/osm_ca_info_get_port_num +* NAME +* osm_ca_info_get_port_num +* +* DESCRIPTION +* Returns the port number of the specified port owned by this CA. +* Port numbers start with 1 for HCA's. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_ca_info_get_port_num(IN const osm_ca_info_t * const p_ca_info, + IN const uint8_t index) +{ + return (p_ca_info->p_attr->p_port_attr[index].port_num); +} + +/* +* PARAMETERS +* p_ca_info +* [in] Pointer to a CA Info object. +* +* index +* [in] Port "index" for which to retrieve the port GUID. +* The index is the offset into the ca's internal array +* of port attributes. +* +* RETURN VALUE +* Returns the port GUID of the specified port owned by this CA. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: CA Info/osm_ca_info_get_ca_guid +* NAME +* osm_ca_info_get_ca_guid +* +* DESCRIPTION +* Returns the GUID of the specified CA. +* +* SYNOPSIS +*/ +static inline ib_net64_t +osm_ca_info_get_ca_guid(IN const osm_ca_info_t * const p_ca_info) +{ + return (p_ca_info->p_attr->ca_guid); +} + +/* +* PARAMETERS +* p_ca_info +* [in] Pointer to a CA Info object. +* +* RETURN VALUE +* Returns the GUID of the specified CA. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* OpenSM: Vendor AL/osm_bind_handle_t +* NAME +* osm_bind_handle_t +* +* DESCRIPTION +* handle returned by the vendor transport bind call. +* +* SYNOPSIS +*/ +typedef struct _osm_vendor { + ib_al_handle_t h_al; + osm_log_t *p_log; + uint32_t ca_count; + osm_ca_info_t *p_ca_info; + uint32_t timeout; + ib_ca_handle_t h_ca; + ib_pd_handle_t h_pd; + +} osm_vendor_t; +/* +* FIELDS +* h_al +* Handle returned by AL open call (ib_open_al). +* +* p_log +* Pointer to the log object. +* +* ca_count +* Number of CA's in the array pointed to by p_ca_info. +* +* p_ca_info +* Pointer to dynamically allocated array of CA info objects. +* +* h_pool +* MAD Pool handle returned by ib_create_mad_pool at init time. +* +* timeout +* Transaction timeout time in milliseconds. +* +* SEE ALSO +*********/ + +#define OSM_BIND_INVALID_HANDLE 0 + +/****s* OpenSM: Vendor AL/osm_bind_handle_t +* NAME +* osm_bind_handle_t +* +* DESCRIPTION +* handle returned by the vendor transport bind call. +* +* SYNOPSIS +*/ +typedef void *osm_bind_handle_t; +/***********/ + +/****s* OpenSM/osm_vend_wrap_t +* NAME +* AL Vendor MAD Wrapper +* +* DESCRIPTION +* AL specific MAD wrapper. AL transport layer uses this for +* housekeeping. +* +* SYNOPSIS +*********/ +typedef struct _osm_vend_wrap_t { + uint32_t size; + osm_bind_handle_t h_bind; + ib_mad_element_t *p_elem; + ib_av_handle_t h_av; + void *p_resp_madw; + +} osm_vend_wrap_t; +/* +* FIELDS +* size +* Size of the allocated MAD +* +* h_bind +* Bind handle used on this transaction +* +* p_elem +* Pointer to the mad element structure associated with +* this mad. +* +* h_av +* Address vector handle used for this transaction. +* +* p_resp_madw +* Pointer to the mad wrapper structure used to hold the pending +* reponse to the mad, if any. If a response is expected, the +* wrapper for the reponse is allocated during the send call. +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_VENDOR_AL_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_api.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_api.h new file mode 100644 index 000000000000..70eb6ccf2d15 --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_api.h @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Specification of the OpenSM transport API. This API is OpenSM's view + * of the Infiniband transport. + */ + +#ifndef _OSM_VENDOR_API_H_ +#define _OSM_VENDOR_API_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM Vendor API/osm_vend_mad_recv_callback_t +* NAME +* osm_vend_mad_recv_callback_t +* +* DESCRIPTION +* Function prototype for the vendor MAD receive callback. +* The vendor layer calls this function for MAD receives. +* +* SYNOPSIS +*/ +typedef void (*osm_vend_mad_recv_callback_t) (IN osm_madw_t * p_madw, + IN void *bind_context, + IN osm_madw_t * p_req_madw); +/* +* PARAMETERS +* p_madw +* [in] The received MAD wrapper. +* +* bind_context +* [in] User context supplied during the bind call. +* +* p_req_madw +* [in] Pointer to the request mad wrapper that generated this response. +* If the inbound MAD is not a response, this field is NULL. +* +* RETURN VALUES +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* OpenSM Vendor API/osm_vend_mad_send_err_callback_t +* NAME +* osm_vend_mad_send_err_callback_t +* +* DESCRIPTION +* Function prototype for the vendor send failure callback. +* The vendor layer calls this function when MADs expecting +* a response are completed in error, most likely due to a +* timeout. +* +* SYNOPSIS +*/ +typedef void (*osm_vend_mad_send_err_callback_t) (IN void *bind_context, + IN osm_madw_t * p_madw); +/* +* PARAMETERS +* bind_context +* [in] User context supplied during the bind call. +* +* p_madw +* [in] Pointer to the request mad that failed. +* +* RETURN VALUES +* None. +* +* NOTES +* The vendor layer does not call this function (or any other) +* for MADs that were not expecting a response. +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_new +* NAME +* osm_vendor_new +* +* DESCRIPTION +* Allocates and initializes a new osm_vendor_t object. +* OpenSM calls this function before any other in the vendor API. +* This object is passed as a parameter to all other vendor functions. +* +* SYNOPSIS +*/ +osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log, + IN const uint32_t timeout); +/* +* PARAMETERS +* p_log +* [in] Pointer to the log object to use. +* +* timeout +* [in] transaction timeout +* +* RETURN VALUES +* Returns a pointer to the vendor object. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* OpenSM Vendor API/osm_vendor_delete +* NAME +* osm_vendor_delete +* +* DESCRIPTION +* Dealocate the vendor object. +* +* SYNOPSIS +*/ +void osm_vendor_delete(IN osm_vendor_t ** const pp_vend); +/* +* PARAMETERS +* pp_vend +* [in/out] pointer to pointer to vendor objcet to be deleted +* +* RETURN VALUES +* None +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_get_ports +* NAME +* osm_vendor_get_ports +* +* DESCRIPTION +* Returns an array of available port attribute structures. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * const p_attr_array, + IN uint32_t * const p_num_ports); +/* +* PARAMETERS +* p_vend +* [in] Pointer to the vendor object to initialize. +* +* p_attr_array +* [in/out] Pointer to pre-allocated array of port attributes. +* If it is NULL - then the command only updates the p_num_ports, +* and return IB_INSUFFICIENT_MEMORY. +* +* p_num_ports +* [in/out] Pointer to a variable to hold the total number of ports +* available on the local machine.. +* +* RETURN VALUES +* IB_SUCCESS on success. +* IB_INSUFFICIENT_MEMORY if the attribute array was not large enough. +* The number of attributes needed is returned in num_guids. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_init +* NAME +* osm_vendor_init +* +* DESCRIPTION +* The osm_vendor_init function initializes the vendor transport layer. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_vendor_init(IN osm_vendor_t * const p_vend, + IN osm_log_t * const p_log, IN const uint32_t timeout); +/* +* PARAMETERS +* p_vend +* [in] Pointer to the vendor object to initialize. +* +* p_log +* [in] Pointer to OpenSM's log object. Vendor code may +* use the log object to send messages to OpenSM's log. +* +* timeout +* [in] Transaction timeout value in milliseconds. +* A value of 0 disables timeouts. +* +* RETURN VALUE +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_bind +* NAME +* osm_vendor_bind +* +* DESCRIPTION +* The osm_vendor_bind function registers with the vendor transport layer +* per Mad Class per PortGuid for mad transport capability. +* +* SYNOPSIS +*/ +osm_bind_handle_t +osm_vendor_bind(IN osm_vendor_t * const p_vend, + IN osm_bind_info_t * const p_bind_info, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vend_mad_recv_callback_t mad_recv_callback, + IN osm_vend_mad_send_err_callback_t send_err_callback, + IN void *context); +/* +* PARAMETERS +* p_vend +* [in] pointer to the vendor object +* +* p_osm_bind_info +* [in] pointer to a struct defining the type of bind to perform. +* +* p_mad_pool +* [in] pointer to a mad wrappers pool to be used for allocating +* mad wrappers on send and receive. +* +* mad_recv_callback +* [in] the callback function to be invoked on mad receive. +* +* send_err_callback +* [in] the callback function to be invoked on mad transaction errors. +* +* context +* [in] the context to be provided to the callbacks as bind_ctx. +* +* RETURN VALUE +* On success, a valid bind handle. +* OSM_BIND_INVALID_HANDLE otherwise. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_unbind +* NAME +* osm_vendor_unbind +* +* DESCRIPTION +* Unbind the given bind handle (obtained by osm_vendor_bind). +* +* SYNOPSIS +*/ +void osm_vendor_unbind(IN osm_bind_handle_t h_bind); +/* +* PARAMETERS +* h_bind +* [in] the bind handle to release. +* +* RETURN VALUE +* NONE. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_get +* NAME +* osm_vendor_get +* +* DESCRIPTION +* Obtain a mad wrapper holding actual mad buffer to be sent via +* the transport. +* +* SYNOPSIS +*/ +ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind, + IN const uint32_t mad_size, + IN osm_vend_wrap_t * const p_vend_wrap); +/* +* PARAMETERS +* h_bind +* [in] the bind handle obtained by calling osm_vendor_bind +* +* mad_size +* [in] the actual mad size required +* +* p_vend_wrap +* [out] the returned mad vendor wrapper +* +* RETURN VALUE +* IB_SUCCESS on succesful completion. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_send +* NAME +* osm_vendor_send +* +* DESCRIPTION +* +* SYNOPSIS +*/ +ib_api_status_t +osm_vendor_send(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, IN boolean_t const resp_expected); +/* +* PARAMETERS +* h_bind +* [in] the bind handle obtained by calling osm_vendor_bind +* +* p_madw +* [in] pointer to the Mad Wrapper structure for the MAD to be sent. +* +* resp_expected +* [in] boolean value declaring the mad as a request (expecting a response). +* +* RETURN VALUE +* IB_SUCCESS on succesful completion. +* +* NOTES +* 1. Only mads that expect a response are tracked for transaction competion. +* 2. A mad that does not expect a response is being put back immediatly after +* being sent. +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_put +* NAME +* osm_vendor_put +* +* DESCRIPTION +* Return a mad vendor wrapper to the mad pool. It also means that the +* mad buffer is returned to the transport. +* +* SYNOPSIS +*/ +void +osm_vendor_put(IN osm_bind_handle_t h_bind, + IN osm_vend_wrap_t * const p_vend_wrap); +/* +* PARAMETERS +* h_bind +* [in] the bind handle obtained by calling osm_vendor_bind +* +* p_vend_wrap +* [in] pointer to the mad vendor wrapper to put back into the pool. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****i* OpenSM Vendor API/osm_vendor_local_lid_change +* NAME +* osm_vendor_local_lid_change +* +* DESCRIPTION +* Notifies the vendor transport layer that the local address +* has changed. This allows the vendor layer to perform housekeeping +* functions such as address vector updates. +* +* SYNOPSIS +*/ +ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind); +/* +* PARAMETERS +* h_bind +* [in] the bind handle obtained by calling osm_vendor_bind +* +* RETURN VALUE +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_set_sm +* NAME +* osm_vendor_set_sm +* +* DESCRIPTION +* Modifies the port info for the bound port to set the "IS_SM" bit +* according to the value given (TRUE or FALSE). +* +* SYNOPSIS +*/ +void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val); +/* +* PARAMETERS +* h_bind +* [in] bind handle for this port. +* +* is_sm_val +* [in] If TRUE - will set the is_sm to TRUE, if FALSE - will set the +* the is_sm to FALSE. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM Vendor API/osm_vendor_set_debug +* NAME +* osm_vendor_set_debug +* +* DESCRIPTION +* Modifies the vendor specific debug level. +* +* SYNOPSIS +*/ +void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level); +/* +* PARAMETERS +* p_vend +* [in] vendor handle. +* +* level +* [in] vendor specific debug level. +* +* RETURN VALUE +* None. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_VENDOR_API_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_ibumad.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_ibumad.h new file mode 100644 index 000000000000..3a3f0700a2bd --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_ibumad.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_VENDOR_UMAD_H_ +#define _OSM_VENDOR_UMAD_H_ + +#include +#include +#include +#include + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Vendor Access Layer (UMAD) +* NAME +* Vendor UMAD +* +* DESCRIPTION +* This file is the vendor specific file for the UMAD Infiniband API. +* +* AUTHOR +* +* +*********/ +#define OSM_DEFAULT_RETRY_COUNT 3 +#define OSM_UMAD_MAX_CAS 32 +#define OSM_UMAD_MAX_PORTS_PER_CA 2 +/****s* OpenSM: Vendor UMAD/osm_ca_info_t +* NAME +* osm_ca_info_t +* +* DESCRIPTION +* Structure containing information about local Channle Adapters. +* +* SYNOPSIS +*/ +typedef struct _osm_ca_info { + ib_net64_t guid; + size_t attr_size; + ib_ca_attr_t *p_attr; +} osm_ca_info_t; +/* +* FIELDS +* guid +* Node GUID of the local CA. +* +* attr_size +* Size of the CA attributes for this CA. +* +* p_attr +* Pointer to dynamicly allocated CA Attribute structure. +* +* SEE ALSO +*********/ + +/****f* OpenSM: CA Info/osm_ca_info_get_num_ports +* NAME +* osm_ca_info_get_num_ports +* +* DESCRIPTION +* Returns the number of ports owned by this CA. +* +* SYNOPSIS +*/ +static inline uint8_t +osm_ca_info_get_num_ports(IN const osm_ca_info_t * const p_ca_info) +{ + return (p_ca_info->p_attr->num_ports); +} + +/* +* PARAMETERS +* p_ca_info +* [in] Pointer to a CA Info object. +* +* RETURN VUMADUE +* Returns the number of ports owned by this CA. +* +* NOTES +* +* SEE ALSO +*********/ + +/****s* OpenSM: Vendor UMAD/osm_bind_handle_t +* NAME +* osm_bind_handle_t +* +* DESCRIPTION +* handle returned by the vendor transport bind call. +* +* SYNOPSIS +*/ +typedef void *osm_bind_handle_t; +/***********/ + +typedef struct _umad_match { + ib_net64_t tid; + void *v; + uint32_t version; +} umad_match_t; + +#define DEFAULT_OSM_UMAD_MAX_PENDING 1000 + +typedef struct vendor_match_tbl { + uint32_t last_version; + int max; + umad_match_t *tbl; +} vendor_match_tbl_t; + +typedef struct _osm_vendor { + osm_log_t *p_log; + uint32_t ca_count; + osm_ca_info_t *p_ca_info; + uint32_t timeout; + int max_retries; + osm_bind_handle_t agents[UMAD_CA_MAX_AGENTS]; + char ca_names[OSM_UMAD_MAX_CAS][UMAD_CA_NAME_LEN]; + vendor_match_tbl_t mtbl; + umad_port_t umad_port; + pthread_mutex_t cb_mutex; + pthread_mutex_t match_tbl_mutex; + int umad_port_id; + void *receiver; + int issmfd; + char issm_path[256]; +} osm_vendor_t; + +#define OSM_BIND_INVALID_HANDLE 0 + +typedef struct _osm_vend_wrap { + int agent; + int size; + int retries; + void *umad; + osm_bind_handle_t h_bind; +} osm_vend_wrap_t; + +END_C_DECLS +#endif /* _OSM_VENDOR_UMAD_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx.h new file mode 100644 index 000000000000..106e0b4e717e --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_H_ +#define _OSMV_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + Forward reference +*/ +struct _osm_pkt_randomizer; + +/* The structure behind the OSM Vendor handle */ + +typedef struct _osm_vendor { + + /* for holding common transport info - useful at ibmgt transport */ + void *p_transport_info; + + osm_log_t *p_log; + + /* Uniform timeout for every ACK/single MAD */ + uint32_t resp_timeout; + + /* Uniform timeout for every rmpp transaction */ + uint32_t ttime_timeout; + + /* All the bind handles associated with the vendor */ + cl_qlist_t bind_handles; + + /* run randomizer flag */ + boolean_t run_randomizer; + + /* Packet Randomizer object */ + struct _osm_pkt_randomizer *p_pkt_randomizer; + +} osm_vendor_t; + +/* Repeating the definitions in osm_vendor_api.h */ + +typedef void *osm_bind_handle_t; + +typedef struct _osm_vend_wrap { + ib_mad_t *p_mad; +} osm_vend_wrap_t; + +#ifndef OSM_BIND_INVALID_HANDLE +#define OSM_BIND_INVALID_HANDLE NULL +#endif + +END_C_DECLS +#endif diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_defs.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_defs.h new file mode 100644 index 000000000000..d4c2c30b02c6 --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_defs.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_DEFS_H_ +#define _OSMV_DEFS_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* The maximum number of outstanding MADs an RMPP sender can transmit */ +#define OSMV_RMPP_RECV_WIN 16 +/* The maximum number of retransmissions of the same MAD */ +#define OSMV_MAX_RETRANSMIT 3 +/* Transaction Timeout = OSMV_TXN_TIMEOUT_FACTOR * Response Timeout */ +#define OSMV_TXN_TIMEOUT_FACTOR 128 +/************/ +/****s* OSM Vendor: Types/osmv_bind_obj_t +* NAME +* osmv_bind_obj_t +* +* DESCRIPTION +* The object managing a single bind context. +* The bind handle is a direct pointer to it. +* +* SYNOPSIS +*/ +typedef struct _osmv_bind_obj { + /* Used to signal when the struct is being destroyed */ + struct _osmv_bind_obj *magic_ptr; + + osm_vendor_t /*const */ * p_vendor; + + uint32_t hca_hndl; + uint32_t port_num; + + /* Atomic access protector */ + cl_spinlock_t lock; + + /* is_closing == TRUE --> the handle is being unbound */ + boolean_t is_closing; + + /* Event callbacks */ + osm_vend_mad_recv_callback_t recv_cb; + osm_vend_mad_send_err_callback_t send_err_cb; + /* ... and their context */ + void *cb_context; + + /* A pool to manage MAD wrappers */ + osm_mad_pool_t *p_osm_pool; + + /* each subvendor implements its own transport mgr */ + void *p_transp_mgr; + + /* The transaction DB */ + osmv_txn_mgr_t txn_mgr; + +} osmv_bind_obj_t; + +END_C_DECLS +#endif /* _OSMV_DEFS_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_dispatcher.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_dispatcher.h new file mode 100644 index 000000000000..ba83f3019036 --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_dispatcher.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_MAD_DISPATCHER_H_ +#define _OSMV_MAD_DISPATCHER_H_ + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + * NAME + * osmv_dispatch_mad + * + * DESCRIPTION + * Lower-level MAD dispatcher. + * Implements a switch between the following MAD consumers: + * (1) Non-RMPP consumer (DATA) + * (2) RMPP receiver (DATA/ABORT/STOP) + * (3) RMPP sender (ACK/ABORT/STOP) + * + * PARAMETERS + * h_bind The bind handle + * p_mad_buf The 256 byte buffer of individual MAD + * p_mad_addr The MAD originator's address + */ +ib_api_status_t +osmv_dispatch_mad(IN osm_bind_handle_t h_bind, + IN const void *p_mad_buf, + IN const osm_mad_addr_t * p_mad_addr); + +END_C_DECLS +#endif diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_hca.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_hca.h new file mode 100644 index 000000000000..9b569432a0c5 --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_hca.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_HCA_H_ +#define _OSMV_HCA_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#if defined( OSM_VENDOR_INTF_TS_NO_VAPI ) || defined( OSM_VENDOR_INTF_SIM ) +#define VAPI_hca_hndl_t uint32_t +#define VAPI_hca_id_t char* +#endif +ib_api_status_t +osm_vendor_get_guid_ca_and_port(IN osm_vendor_t const *p_vend, + IN ib_net64_t const guid, + OUT uint32_t * p_hca_hndl, + OUT char *p_hca_id, + OUT uint8_t * p_hca_idx, + OUT uint32_t * p_port_num); + +END_C_DECLS +#endif /* _OSMV_HCA_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_inout.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_inout.h new file mode 100644 index 000000000000..868639b9a87d --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_inout.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_INOUT_H_ +#define _OSMV_INOUT_H_ + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#ifdef IN +#undef IN +#endif +#ifdef OUT +#undef OUT +#endif +#ifndef OSM_VENDOR_INTF_ANAFA +#ifndef OSM_VENDOR_INTF_TS_NO_VAPI +#ifndef OSM_VENDOR_INTF_SIM +#include +#endif +#endif +#endif +#ifndef IN +#define IN +#endif +#ifndef OUT +#define OUT +#endif +#ifndef OSM_VENDOR_INTF_TS_NO_VAPI +#ifndef OSM_VENDOR_INTF_ANAFA +#ifndef OSM_VENDOR_INTF_SIM +#include +#include +#endif +#endif +#endif +END_C_DECLS +#endif /* _OSMV_INOUT_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_rmpp_ctx.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_rmpp_ctx.h new file mode 100644 index 000000000000..dac1f1370031 --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_rmpp_ctx.h @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_RMPP_CTX_H +#define _OSMV_RMPP_CTX_H + +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +typedef struct _osmv_rmpp_send_ctx { + + uint8_t status; + + uint32_t window_first; + uint32_t window_last; + + uint32_t mad_sz; + boolean_t is_sa_mad; + + cl_event_t event; + + /* Segmentation engine */ + osmv_rmpp_sar_t sar; + osm_log_t *p_log; + +} osmv_rmpp_send_ctx_t; + +typedef struct _osmv_rmpp_recv_ctx { + + boolean_t is_sa_mad; + + uint32_t expected_seg; + + /* Reassembly buffer */ + cl_qlist_t *p_rbuf; + + /* Reassembly engine */ + osmv_rmpp_sar_t sar; + osm_log_t *p_log; + +} osmv_rmpp_recv_ctx_t; + +/* + * NAME + * osmv_rmpp_send_ctx_init + * + * DESCRIPTION + * c'tor for rmpp_send_ctx obj + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_rmpp_send_ctx_init(osmv_rmpp_send_ctx_t * p_ctx, void *arbt_mad, + uint32_t mad_sz, osm_log_t * p_log); + +/* + * NAME + * osmv_rmpp_send_ctx_done + * + * DESCRIPTION + * d'tor for rmpp_send_ctx obj + * + * SEE ALSO + * + */ +void osmv_rmpp_send_ctx_done(IN osmv_rmpp_send_ctx_t * ctx); + +/* + * NAME + * osmv_rmpp_send_ctx_get_wf + * + * DESCRIPTION + * returns number of first segment in current window + * SEE ALSO + * + */ +static inline uint32_t +osmv_rmpp_send_ctx_get_wf(IN const osmv_rmpp_send_ctx_t * p_ctx) +{ + CL_ASSERT(p_ctx); + return p_ctx->window_first; +} + +/* + * NAME + * osmv_rmpp_send_ctx_set_wf + * + * DESCRIPTION + * sets number of first segment in current window + * SEE ALSO + * + */ +static inline void +osmv_rmpp_send_ctx_set_wf(IN osmv_rmpp_send_ctx_t * p_ctx, IN uint32_t val) +{ + CL_ASSERT(p_ctx); + p_ctx->window_first = val; +} + +/* + * NAME + * osmv_rmpp_send_ctx_get_wl + * + * DESCRIPTION + * returns number of last segment in current window + * SEE ALSO + * + */ +static inline uint32_t +osmv_rmpp_send_ctx_get_wl(IN const osmv_rmpp_send_ctx_t * p_send_ctx) +{ + CL_ASSERT(p_send_ctx); + return p_send_ctx->window_last; +} + +/* + * NAME + * osmv_rmpp_send_ctx_set_wl + * + * DESCRIPTION + * sets number of last segment in current window + * SEE ALSO + * + */ +static inline void +osmv_rmpp_send_ctx_set_wl(IN osmv_rmpp_send_ctx_t * p_ctx, IN uint32_t val) +{ + CL_ASSERT(p_ctx); + p_ctx->window_last = val; +} + +/* + * NAME + * osmv_rmpp_send_ctx_get_num_segs + * + * DESCRIPTION + * returns the total number of mad segments to send + * SEE ALSO + * + */ +uint32_t osmv_rmpp_send_ctx_get_num_segs(IN osmv_rmpp_send_ctx_t * p_send_ctx); + +/* + * NAME + * osmv_rmpp_send_ctx_get_seg + * + * DESCRIPTION + * Retrieves the mad segment by seg number (including setting the mad relevant bits & hdrs) + * SEE ALSO + * + */ +ib_api_status_t +osmv_rmpp_send_ctx_get_seg(IN osmv_rmpp_send_ctx_t * p_send_ctx, + IN uint32_t seg_idx, IN uint32_t resp_timeout, + OUT void *p_mad); + +/* + * NAME + * osmv_rmpp_recv_ctx_init + * + * DESCRIPTION + * c'tor for rmpp_recv_ctx obj + * SEE ALSO + * + */ +ib_api_status_t +osmv_rmpp_recv_ctx_init(osmv_rmpp_recv_ctx_t * p_ctx, osm_log_t * p_log); + +/* + * NAME + * osmv_rmpp_recv_ctx_done + * + * DESCRIPTION + * d'tor for rmpp_recv_ctx obj + * SEE ALSO + * + */ +void osmv_rmpp_recv_ctx_done(IN osmv_rmpp_recv_ctx_t * p_ctx); + +/* + * NAME + * osmv_rmpp_recv_ctx_get_es + * + * DESCRIPTION + * retrunes index of expected segement in the curr window + * + */ +static inline uint32_t +osmv_rmpp_recv_ctx_get_es(IN const osmv_rmpp_recv_ctx_t * p_recv_ctx) +{ + CL_ASSERT(p_recv_ctx); + return p_recv_ctx->expected_seg; +} + +/* + * NAME + * osmv_rmpp_recv_ctx_set_es + * + * DESCRIPTION + * sets index of expected segement in the curr window + * + */ +static inline void +osmv_rmpp_recv_ctx_set_es(IN osmv_rmpp_recv_ctx_t * p_recv_ctx, IN uint32_t val) +{ + CL_ASSERT(p_recv_ctx); + p_recv_ctx->expected_seg = val; +} + +/* + * NAME + * osmv_rmpp_recv_ctx_store_madw_seg + * + * DESCRIPTION + * stores rmpp mad in the list + * + */ +ib_api_status_t +osmv_rmpp_recv_ctx_store_mad_seg(IN osmv_rmpp_recv_ctx_t * p_recv_ctx, + IN void *p_mad); + +uint32_t +osmv_rmpp_recv_ctx_get_cur_byte_num(IN osmv_rmpp_recv_ctx_t * p_recv_ctx); + +uint32_t +osmv_rmpp_recv_ctx_get_byte_num_from_first(IN osmv_rmpp_recv_ctx_t * + p_recv_ctx); + +uint32_t +osmv_rmpp_recv_ctx_get_byte_num_from_last(IN osmv_rmpp_recv_ctx_t * p_recv_ctx); + +/* + * NAME + * osmv_rmpp_recv_ctx_reassemble_arbt_mad + * + * DESCRIPTION + * reassembles all rmpp buffs to one big arbitrary mad + */ +ib_api_status_t +osmv_rmpp_recv_ctx_reassemble_arbt_mad(IN osmv_rmpp_recv_ctx_t * p_recv_ctx, + IN uint32_t size, IN void *p_arbt_mad); + +END_C_DECLS +#endif diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_sar.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_sar.h new file mode 100644 index 000000000000..a65b4f2ee85d --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_sar.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_SAR_H_ +#define _OSMV_SAR_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +typedef struct _osmv_rmpp_sar { + void *p_arbt_mad; + uint32_t data_len; /* total data len in all the mads */ + /* these data members contain only constants */ + uint32_t hdr_sz; + uint32_t data_sz; /*typical data sz for this kind of mad (sa or regular */ + +} osmv_rmpp_sar_t; + +/* + * NAME + * osmv_rmpp_sar_alloc + * + * DESCRIPTION + * c'tor for rmpp_sar object + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_rmpp_sar_init(osmv_rmpp_sar_t * p_sar, void *p_arbt_mad, + uint32_t mad_size, boolean_t is_sa_mad); + +/* + * NAME + * osmv_rmpp_sar_dealloc + * + * DESCRIPTION + * d'tor for rmpp_sar object + * + * SEE ALSO + * + */ +void osmv_rmpp_sar_done(osmv_rmpp_sar_t * p_sar); + +/* + * NAME + * osmv_rmpp_sar_get_mad_seg + * + * DESCRIPTION + * segments the original mad buffer . returnes a mad with the data of the i-th segment + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_rmpp_sar_get_mad_seg(osmv_rmpp_sar_t * p_sar, uint32_t seg_idx, + void *p_buf); + +/* + * NAME + * osmv_rmpp_sar_reassemble_arbt_mad + * + * DESCRIPTION + * gets a qlist of mads and reassmbles to one big mad buffer + * ALSO - deallocates the mad list + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_rmpp_sar_reassemble_arbt_mad(osmv_rmpp_sar_t * p_sar, cl_qlist_t * p_bufs); + +END_C_DECLS +#endif /* _OSMV_SAR_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_sender.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_sender.h new file mode 100644 index 000000000000..e84974442e32 --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_sender.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_RMPP_SENDER_H_ +#define _OSMV_RMPP_SENDER_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****d* OSM Vendor/osmv_simple_send_madw + * NAME + * osmv_simple_send_madw + * + * DESCRIPTION + * Send a single MAD (256 bytes). + * + * If this MAD requires a response, set the timeout event. + * The function call returns when the MAD's send completion is received. + * + */ +ib_api_status_t +osmv_simple_send_madw(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, + IN osmv_txn_ctx_t * p_txn, IN boolean_t is_retry); + +/****d* OSM Vendor/osmv_rmpp_send_madw + * NAME + * osmv_rmpp_send_madw + * + * DESCRIPTION + * Send a single MAD wrapper (of arbitrary length). + * Follow the RMPP semantics + * (segmentation, send window, timeouts etc). + * + * The function call returns either when the whole MAD + * has been acknowledged, or upon error. + */ +ib_api_status_t +osmv_rmpp_send_madw(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, + IN osmv_txn_ctx_t * p_txn, IN boolean_t is_rmpp_ds); + +/* + * NAME osmv_rmpp_send_ack + * + * DESCRIPTION + */ + +ib_api_status_t +osmv_rmpp_send_ack(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_req_mad, + IN uint32_t seg_num, + IN uint32_t nwl, IN const osm_mad_addr_t * p_mad_addr); + +/* + * NAME osmv_rmpp_send_nak + * + * DESCRIPTION Send the RMPP ABORT or STOP packet + */ + +ib_api_status_t +osmv_rmpp_send_nak(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_req_mad, + IN const osm_mad_addr_t * p_mad_addr, + IN uint8_t nak_type, IN uint8_t status); + +/* + * NAME osmv_rmpp_snd_error + * + * DESCRIPTION Mark an error status and signal the sender thread to handle it + */ + +static inline void +osmv_rmpp_snd_error(IN osmv_rmpp_send_ctx_t * p_send_ctx, + IN ib_api_status_t status) +{ + p_send_ctx->status = status; + + /* Release the thread waiting on send() + * It will release the transaction's context + */ + cl_event_signal(&p_send_ctx->event); +} + +END_C_DECLS +#endif /* _OSMV_RMPP_SENDER_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_svc.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_svc.h new file mode 100644 index 000000000000..f23a77d3ea98 --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_svc.h @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_SVC_H_ +#define _OSMV_SVC_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +inline static boolean_t osmv_mad_is_response(IN const ib_mad_t * p_mad) +{ + return (ib_mad_is_response(p_mad) || + (p_mad->method == IB_MAD_METHOD_TRAP_REPRESS)); +} + +inline static uint8_t osmv_invert_method(IN uint8_t req_method) +{ + switch (req_method) { + case IB_MAD_METHOD_GET_RESP: + /* Not a 1-1 mapping! */ + return IB_MAD_METHOD_GET; + + case IB_MAD_METHOD_GET: + return IB_MAD_METHOD_GET_RESP; + + case IB_MAD_METHOD_SET: + return IB_MAD_METHOD_GET_RESP; + + case IB_MAD_METHOD_GETTABLE_RESP: + return IB_MAD_METHOD_GETTABLE; + + case IB_MAD_METHOD_GETTABLE: + return IB_MAD_METHOD_GETTABLE_RESP; + + case IB_MAD_METHOD_GETMULTI_RESP: + /* Not a 1-1 mapping! */ + return IB_MAD_METHOD_GETMULTI; + + case IB_MAD_METHOD_GETTRACETABLE: + case IB_MAD_METHOD_GETMULTI: + return IB_MAD_METHOD_GETMULTI_RESP; + + case IB_MAD_METHOD_TRAP: + return IB_MAD_METHOD_TRAP_REPRESS; + + case IB_MAD_METHOD_TRAP_REPRESS: + return IB_MAD_METHOD_TRAP; + + case IB_MAD_METHOD_REPORT: + return IB_MAD_METHOD_REPORT_RESP; + + case IB_MAD_METHOD_REPORT_RESP: + return IB_MAD_METHOD_REPORT; + + /* IB_MAD_METHOD_SEND does not have a response */ + case IB_MAD_METHOD_SEND: + return IB_MAD_METHOD_SEND; + + default: + CL_ASSERT(FALSE); + } + + return 0; /* Just make the compiler happy */ +} + +inline static boolean_t osmv_mad_is_rmpp(IN const ib_mad_t * p_mad) +{ + uint8_t rmpp_flags; + CL_ASSERT(NULL != p_mad); + + rmpp_flags = ((ib_rmpp_mad_t *) p_mad)->rmpp_flags; + /* HACK - JUST SA and DevMgt for now - need to add BIS and DevAdm */ + if ((p_mad->mgmt_class != IB_MCLASS_SUBN_ADM) && + (p_mad->mgmt_class != IB_MCLASS_DEV_MGMT)) + return (0); + return (0 != (rmpp_flags & IB_RMPP_FLAG_ACTIVE)); +} + +inline static boolean_t osmv_mad_is_multi_resp(IN const ib_mad_t * p_mad) +{ + CL_ASSERT(NULL != p_mad); + return (IB_MAD_METHOD_GETMULTI == p_mad->method + || IB_MAD_METHOD_GETTRACETABLE == p_mad->method); +} + +inline static boolean_t osmv_mad_is_sa(IN const ib_mad_t * p_mad) +{ + CL_ASSERT(NULL != p_mad); + return (IB_MCLASS_SUBN_ADM == p_mad->mgmt_class); +} + +inline static boolean_t osmv_rmpp_is_abort_stop(IN const ib_mad_t * p_mad) +{ + uint8_t rmpp_type; + CL_ASSERT(p_mad); + + rmpp_type = ((ib_rmpp_mad_t *) p_mad)->rmpp_type; + return (IB_RMPP_TYPE_STOP == rmpp_type + || IB_RMPP_TYPE_ABORT == rmpp_type); +} + +inline static boolean_t osmv_rmpp_is_data(IN const ib_mad_t * p_mad) +{ + CL_ASSERT(p_mad); + return (IB_RMPP_TYPE_DATA == ((ib_rmpp_mad_t *) p_mad)->rmpp_type); +} + +inline static boolean_t osmv_rmpp_is_ack(IN const ib_mad_t * p_mad) +{ + CL_ASSERT(p_mad); + return (IB_RMPP_TYPE_ACK == ((ib_rmpp_mad_t *) p_mad)->rmpp_type); +} + +inline static boolean_t osmv_rmpp_is_first(IN const ib_mad_t * p_mad) +{ + uint8_t rmpp_flags; + CL_ASSERT(NULL != p_mad); + + rmpp_flags = ((ib_rmpp_mad_t *) p_mad)->rmpp_flags; + return (0 != (IB_RMPP_FLAG_FIRST & rmpp_flags)); +} + +inline static boolean_t osmv_rmpp_is_last(IN const ib_mad_t * p_mad) +{ + uint8_t rmpp_flags; + CL_ASSERT(NULL != p_mad); + + rmpp_flags = ((ib_rmpp_mad_t *) p_mad)->rmpp_flags; + return (0 != (IB_RMPP_FLAG_LAST & rmpp_flags)); +} + +inline static uint8_t *osmv_mad_copy(IN const ib_mad_t * p_mad) +{ + uint8_t *p_copy; + + CL_ASSERT(p_mad); + p_copy = malloc(MAD_BLOCK_SIZE); + + if (NULL != p_copy) { + memset(p_copy, 0, MAD_BLOCK_SIZE); + memcpy(p_copy, p_mad, MAD_BLOCK_SIZE); + } + + return p_copy; +} + +/* Should be passed externally from the Makefile */ +/* #define OSMV_RANDOM_DROP 1 */ +#define OSMV_DROP_RATE 0.3 + +inline static boolean_t osmv_random_drop(void) +{ + srand(1); /* Pick a new base */ + return (rand() / (double)RAND_MAX < OSMV_DROP_RATE); +} + +END_C_DECLS +#endif /* _OSMV_SVC_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_transport.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_transport.h new file mode 100644 index 000000000000..2840e490d528 --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_transport.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/** + * FILE osmv_transport.h + * AUTHOR Edward Bortnikov + * + * DESCRIPTION + * The lower-level MAD transport interface implementation + * that allows sending a single MAD/receiving a callback + * when a single MAD is received. +*/ + +#ifndef _OSMV_TRANSPORT_H_ +#define _OSMV_TRANSPORT_H_ + +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* + * NAME + * osmv_transport_init + * + * DESCRIPTION + * Setup the MAD transport infrastructure (filters, callbacks etc). + */ +#define VENDOR_HCA_MAXNAMES 32 +ib_api_status_t +osmv_transport_init(IN osm_bind_info_t * p_info, + IN char hca_id[VENDOR_HCA_MAXNAMES], + IN uint8_t hca_idx, IN osmv_bind_obj_t * p_bo); + +/* + * NAME + * osmv_transport_send_mad + * + * DESCRIPTION + * Send a single MAD (256 byte) + */ +ib_api_status_t +osmv_transport_mad_send(IN const osm_bind_handle_t h_bind, + IN void *p_mad, IN const osm_mad_addr_t * p_mad_addr); + +/* + * NAME + * osmv_transport_done + * + * DESCRIPTION + * deallocator of transportation infrastructure + */ +void osmv_transport_done(IN const osm_bind_handle_t h_bind); + +END_C_DECLS +#endif /* _OSMV_TRANSPORT_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_transport_anafa.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_transport_anafa.h new file mode 100644 index 000000000000..dac26edd7d2c --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_transport_anafa.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/** + * FILE osmv_transport.h + * AUTHOR Edward Bortnikov + * + * DESCRIPTION + * The lower-level MAD transport interface implementation + * that allows sending a single MAD/receiving a callback + * when a single MAD is received. +*/ + +#ifndef _OSMV_TRANSPORT_ANAFA_H_ +#define _OSMV_TRANSPORT_ANAFA_H_ + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +#define OSMV_ANAFA_ID 0 +typedef struct _osmv_TOPSPIN_ANAFA_transport_mgr_ { + int device_fd; + cl_thread_t receiver; +} osmv_TOPSPIN_ANAFA_transport_mgr_t; + +typedef struct _osmv_TOPSPIN_ANAFA_transport_info_ { + int device_fd; +} osmv_TOPSPIN_ANAFA_transport_info_t; + +END_C_DECLS +#endif /* _OSMV_TRANSPORT_ANAFA_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_txn.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_txn.h new file mode 100644 index 000000000000..ce591918c856 --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_txn.h @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSMV_TXN_H_ +#define _OSMV_TXN_H_ + +#include +#include + +#include +#include +#include + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS + +typedef enum _osmv_txn_rmpp_state { + + OSMV_TXN_RMPP_NONE = 0, /* Not part of RMPP transaction */ + + OSMV_TXN_RMPP_SENDER, + OSMV_TXN_RMPP_RECEIVER +} osmv_txn_rmpp_state_t; + +typedef struct _osmv_rmpp_txfr { + + osmv_txn_rmpp_state_t rmpp_state; + boolean_t is_rmpp_init_by_peer; + osmv_rmpp_send_ctx_t *p_rmpp_send_ctx; + osmv_rmpp_recv_ctx_t *p_rmpp_recv_ctx; + +} osmv_rmpp_txfr_t; + +typedef struct _osmv_txn_ctx { + + /* The original Transaction ID */ + uint64_t tid; + /* The key by which the Transaction is stored */ + uint64_t key; + + /* RMPP Send/Receive contexts, if applicable */ + osmv_rmpp_txfr_t rmpp_txfr; + + /* A MAD that was sent during the transaction (request or response) */ + osm_madw_t *p_madw; + + /* Reference to a log to enable tracing */ + osm_log_t *p_log; + +} osmv_txn_ctx_t; + +typedef struct _osmv_txn_mgr { + + /* Container of all the transactions */ + cl_qmap_t *p_txn_map; + + /* The timeouts DB */ + cl_event_wheel_t *p_event_wheel; + + /* Reference to a log to enable tracing */ + osm_log_t *p_log; + +} osmv_txn_mgr_t; + +/* * * * * * * osmv_txn_ctx_t functions * * * * * * * * */ + +/* + * NAME + * osmv_txn_init + * + * DESCRIPTION + * allocs & inits the osmv_txn_ctx obj and insert it into the db + * SEE ALSO + * + */ +ib_api_status_t +osmv_txn_init(IN osm_bind_handle_t h_bind, + IN uint64_t tid, IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn); + +/* + * NAME + * osmv_rmpp_txfr_init_sender + * + * DESCRIPTION + * init the rmpp send ctx in the transaction + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_txn_init_rmpp_sender(IN osm_bind_handle_t h_bind, + IN osmv_txn_ctx_t * p_txn, IN osm_madw_t * p_madw); + +/* + * NAME + * osmv_rmpp_txfr_init_receiver + * + * DESCRIPTION + * init the rmpp recv ctx in the transaction + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_txn_init_rmpp_receiver(IN osm_bind_handle_t h_bind, + IN osmv_txn_ctx_t * p_txn, + IN boolean_t is_init_by_peer); + +/* + * NAME + * osmv_txn_done + * + * DESCRIPTION + * destroys txn object and removes it from the db + * + * SEE ALSO + * + */ +void +osmv_txn_done(IN osm_bind_handle_t h_bind, + IN uint64_t key, IN boolean_t is_in_cb); +/* + * NAME + * osmv_txn_get_tid + * + * DESCRIPTION + * returns tid of the transaction + * SEE ALSO + * + */ +static inline uint64_t osmv_txn_get_tid(IN osmv_txn_ctx_t * p_txn) +{ + CL_ASSERT(NULL != p_txn); + return p_txn->tid; +} + +/* + * NAME + * osmv_txn_get_key + * + * DESCRIPTION + * returns key of the transaction + * SEE ALSO + * + */ + +static inline uint64_t osmv_txn_get_key(IN osmv_txn_ctx_t * p_txn) +{ + CL_ASSERT(NULL != p_txn); + return p_txn->key; +} + +/* + * NAME + * osmv_txn_is_rmpp_init_by_peer + * + * DESCRIPTION + * returns whether the rmpp txfr was init by the peer + * + * SEE ALSO + * + */ +static inline boolean_t osmv_txn_is_rmpp_init_by_peer(IN osmv_txn_ctx_t * p_txn) +{ + CL_ASSERT(NULL != p_txn); + return p_txn->rmpp_txfr.is_rmpp_init_by_peer; +} + +/* + * NAME + * osmv_txn_get_rmpp_send_ctx + * + * DESCRIPTION + * returns osmv_rmpp_send_ctx obj + * SEE ALSO + * + */ +static inline osmv_rmpp_send_ctx_t *osmv_txn_get_rmpp_send_ctx(IN osmv_txn_ctx_t + * p_txn) +{ + CL_ASSERT(NULL != p_txn); + return p_txn->rmpp_txfr.p_rmpp_send_ctx; +} + +/* + * NAME + * osmv_txn_get_rmpp_recv_ctx + * + * DESCRIPTION + * returns osmv_rmpp_recv_ctx obj + * SEE ALSO + * + */ +static inline osmv_rmpp_recv_ctx_t *osmv_txn_get_rmpp_recv_ctx(IN osmv_txn_ctx_t + * p_txn) +{ + CL_ASSERT(NULL != p_txn); + return p_txn->rmpp_txfr.p_rmpp_recv_ctx; +} + +/* + * NAME + * osmv_txn_get_rmpp_state + * + * DESCRIPTION + * returns the rmpp role of the transactino ( send/ recv) + * SEE ALSO + * + */ +static inline osmv_txn_rmpp_state_t +osmv_txn_get_rmpp_state(IN osmv_txn_ctx_t * p_txn) +{ + CL_ASSERT(NULL != p_txn); + return p_txn->rmpp_txfr.rmpp_state; +} + +/* + * NAME + * osmv_txn_set_rmpp_state + * + * DESCRIPTION + * sets the rmpp role of the transaction (send/ recv) + * SEE ALSO + * + */ +static inline void +osmv_txn_set_rmpp_state(IN osmv_txn_ctx_t * p_txn, + IN osmv_txn_rmpp_state_t state) +{ + CL_ASSERT(NULL != p_txn); + p_txn->rmpp_txfr.rmpp_state = state; +} + +/* + * NAME + * osmv_txn_get_madw + * + * DESCRIPTION + * returns the requester madw + * SEE ALSO + * + */ +static inline osm_madw_t *osmv_txn_get_madw(IN osmv_txn_ctx_t * p_txn) +{ + CL_ASSERT(NULL != p_txn); + return p_txn->p_madw; +} + +/* + * NAME + * osmv_txn_set_madw + * + * DESCRIPTION + * sets the requester madw + * SEE ALSO + * + */ +static inline void +osmv_txn_set_madw(IN osmv_txn_ctx_t * p_txn, IN osm_madw_t * p_madw) +{ + CL_ASSERT(NULL != p_txn); + p_txn->p_madw = p_madw; +} + +/* + * NAME + * osmv_txn_set_timeout_ev + * + * DESCRIPTION + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_txn_set_timeout_ev(IN osm_bind_handle_t h_bind, + IN uint64_t key, IN uint64_t msec); +/* + * NAME + * osmv_txn_remove_timeout_ev + * + * DESCRIPTION + + * SEE ALSO + * + */ +void osmv_txn_remove_timeout_ev(IN osm_bind_handle_t h_bind, IN uint64_t key); +/* + * NAME + * osmv_txn_lookup + * + * DESCRIPTION + * get a transaction by its key + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_txn_lookup(IN osm_bind_handle_t h_bind, + IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn); + +void osmv_txn_abort_rmpp_txns(IN osm_bind_handle_t h_bind); + +/* * * * * * * * * * * * */ +/* + * NAME + * osmv_txnmgr_init + * + * DESCRIPTION + * c'tor for txn mgr obj + * SEE ALSO + * + */ +ib_api_status_t +osmv_txnmgr_init(IN osmv_txn_mgr_t * p_tx_mgr, + IN osm_log_t * p_log, IN cl_spinlock_t * p_lock); + +/* + * NAME + * osmv_txnmgr_done + * + * DESCRIPTION + * c'tor for txn mgr obj + * SEE ALSO + * + */ +void osmv_txnmgr_done(IN osm_bind_handle_t h_bind); + +void osmv_txn_lock(IN osm_bind_handle_t h_bind); +void osmv_txn_unlock(IN osm_bind_handle_t h_bind); + +inline static uint64_t osmv_txn_uniq_key(IN uint64_t tid) +{ + uint64_t pid = getpid(); + + return ((pid << 32) | (tid & 0xFFFFFFFF)); +} + +END_C_DECLS +#endif /* _OSMV_TXN_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mtl.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mtl.h new file mode 100644 index 000000000000..df48260b622f --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mtl.h @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Definition of interface for the MTL Vendor + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_VENDOR_MTL_H_ +#define _OSM_VENDOR_MTL_H_ + +#undef IN +#undef OUT +#include +#include +#include +#define IN +#define OUT +#include "iba/ib_types.h" +#include "iba/ib_al.h" +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/Vendor MTL +* NAME +* Vendor MTL +* +* DESCRIPTION +* +* The Vendor MTL object is thread safe. +* +* This object should be treated as opaque and should be +* manipulated only through the provided functions. +* +* +* AUTHOR +* +* +*********/ +/****s* OpenSM: Vendor MTL/osm_ca_info_t +* NAME +* osm_ca_info_t +* +* DESCRIPTION +* Structure containing information about local Channle Adapters. +* +* SYNOPSIS +*/ +typedef struct _osm_ca_info { + ib_net64_t guid; + size_t attr_size; + ib_ca_attr_t *p_attr; + +} osm_ca_info_t; + +/* +* FIELDS +* guid +* Node GUID of the local CA. +* +* attr_size +* Size of the CA attributes for this CA. +* +* p_attr +* Pointer to dynamicly allocated CA Attribute structure. +* +* SEE ALSO +*********/ + +#define OSM_DEFAULT_RETRY_COUNT 3 + +/***** OpenSM: Vendor MTL/osm_vendor_t +* NAME +* osm_vendor_t +* +* DESCRIPTION +* The structure defining a vendor +* +* SYNOPSIS +*/ +typedef struct _osm_vendor { + ib_al_handle_t h_al; + osm_log_t *p_log; + uint32_t ca_count; + osm_ca_info_t *p_ca_info; + uint32_t timeout; + struct osm_transaction_mgr_t *p_transaction_mgr; +} osm_vendor_t; + +/* +* FIELDS +* h_al +* Handle returned by MTL open call (ib_open_al). +* +* p_log +* Pointer to the log object. +* +* ca_count +* Number of CA's in the array pointed to by p_ca_info. +* +* p_ca_info +* Pointer to dynamically allocated array of CA info objects. +* +* timeout +* Transaction timeout time in milliseconds. +* +* p_transaction_mgr +* Pointer to Transaction Manager. +* +* SEE ALSO +*********/ + +/****f* OpenSM: Vendor MTL/CA Info/osm_ca_info_get_port_guid +* NAME +* osm_ca_info_get_port_guid +* +* DESCRIPTION +* Returns the port GUID of the specified port owned by this CA. +* +* SYNOPSIS +*/ +static inline ib_net64_t +osm_ca_info_get_port_guid(IN const osm_ca_info_t * const p_ca_info, + IN const uint8_t index) +{ + return (p_ca_info->p_attr->p_port_attr[index].port_guid); +} + +/* +* PARAMETERS +* p_ca_info +* [in] Pointer to a CA Info object. +* +* index +* [in] Port "index" for which to retrieve the port GUID. +* The index is the offset into the ca's internal array +* of port attributes. +* +* RETURN VALUE +* Returns the port GUID of the specified port owned by this CA. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Vendor MTL/CA Info/osm_ca_info_get_num_ports +* NAME +* osm_ca_info_get_num_ports +* +* DESCRIPTION +* Returns the number of ports of the given ca_info +* +* SYNOPSIS +*/ +static inline uint8_t +osm_ca_info_get_num_ports(IN const osm_ca_info_t * const p_ca_info) +{ + return (p_ca_info->p_attr->num_ports); +} + +/* +* PARAMETERS +* p_ca_info +* [in] Pointer to a CA Info object. +* +* RETURN VALUE +* Returns the number of CA ports +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: SM Vendor/osm_vendor_get_guid_ca_and_port + * NAME + * osm_vendor_get_guid_ca_and_port + * + * DESCRIPTION + * Given the vendor obj and a guid + * return the ca id and port number that have that guid + * + * SYNOPSIS + */ +ib_api_status_t +osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend, + IN ib_net64_t const guid, + OUT VAPI_hca_hndl_t * p_hca_hndl, + OUT VAPI_hca_id_t * p_hca_id, + OUT uint32_t * p_port_num); + +/* +* PARAMETERS +* p_vend +* [in] Pointer to an osm_vendor_t object. +* +* guid +* [in] The guid to search for. +* +* p_hca_id +* [out] The HCA Id (VAPI_hca_id_t *) that the port is found on. +* +* p_port_num +* [out] Pointer to a port number arg to be filled with the port number with the given guid. +* +* RETURN VALUES +* IB_SUCCESS on SUCCESS +* IB_INVALID_GUID if the guid is notfound on any Local HCA Port +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: Vendor MTL/osm_vendor_get_all_port_attr + * NAME + * osm_vendor_get_all_port_attr + * + * DESCRIPTION + * Fill in the array of port_attr with all available ports on ALL the + * avilable CAs on this machine. + * ALSO - + * UPDATE THE VENDOR OBJECT LIST OF CA_INFO STRUCTS + * + * SYNOPSIS + */ +ib_api_status_t osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * + const p_attr_array, + IN uint32_t * const p_num_ports); + +/* +* PARAMETERS +* p_vend +* [in] Pointer to an osm_vendor_t object. +* +* p_attr_array +* [out] Pre-allocated array of port attributes to be filled in +* +* p_num_ports +* [out] The size of the given array. Filled in by the actual numberof ports found. +* +* RETURN VALUES +* IB_SUCCESS if OK +* IB_INSUFFICIENT_MEMORY if not enough place for all ports was provided. +* +* NOTES +* +* SEE ALSO +*********/ + +#define OSM_BIND_INVALID_HANDLE 0 + +/****s* OpenSM: Vendor MTL/osm_bind_handle_t +* NAME +* osm_bind_handle_t +* +* DESCRIPTION +* handle returned by the vendor transport bind call. +* +* SYNOPSIS +*/ +typedef void *osm_bind_handle_t; + +/***********/ + +/****s* OpenSM: Vendor MTL/osm_vend_wrap_t +* NAME +* MTL Vendor MAD Wrapper +* +* DESCRIPTION +* MTL specific MAD wrapper. MTL transport layer uses this for +* housekeeping. +* +* SYNOPSIS +*********/ +typedef struct _osm_vend_wrap_t { + uint32_t size; + osm_bind_handle_t h_bind; + // ib_av_handle_t h_av; + ib_mad_t *mad_buf_p; + void *p_resp_madw; +} osm_vend_wrap_t; + +/* +* FIELDS +* size +* Size of the allocated MAD +* +* h_bind +* Bind handle used on this transaction +* +* h_av +* Address vector handle used for this transaction. +* +* p_resp_madw +* Pointer to the mad wrapper structure used to hold the pending +* reponse to the mad, if any. If a response is expected, the +* wrapper for the reponse is allocated during the send call. +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_VENDOR_MTL_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mtl_hca_guid.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mtl_hca_guid.h new file mode 100644 index 000000000000..1b3da8856bd0 --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mtl_hca_guid.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Provides interface over VAPI for obtaining the local ports guids or from guid + * obtaining the HCA and port number. + */ + +#ifndef _OSM_VENDOR_HCA_GUID_H_ +#define _OSM_VENDOR_HCA_GUID_H_ + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM: Vendor AL/osm_ca_info_t +* NAME +* osm_ca_info_t +* +* DESCRIPTION +* Structure containing information about local Channle Adapters. +* +* SYNOPSIS +*/ +typedef struct _osm_ca_info { + ib_net64_t guid; + size_t attr_size; + ib_ca_attr_t *p_attr; + +} osm_ca_info_t; + +/* +* FIELDS +* guid +* Node GUID of the local CA. +* +* attr_size +* Size of the CA attributes for this CA. +* +* p_attr +* Pointer to dynamicly allocated CA Attribute structure. +* +* SEE ALSO +*********/ + +/****f* OpenSM: CA Info/osm_ca_info_get_port_guid +* NAME +* osm_ca_info_get_port_guid +* +* DESCRIPTION +* Returns the port GUID of the specified port owned by this CA. +* +* SYNOPSIS +*/ +static inline ib_net64_t +osm_ca_info_get_port_guid(IN const osm_ca_info_t * const p_ca_info, + IN const uint8_t index) +{ + return (p_ca_info->p_attr->p_port_attr[index].port_guid); +} + +/* +* PARAMETERS +* p_ca_info +* [in] Pointer to a CA Info object. +* +* index +* [in] Port "index" for which to retrieve the port GUID. +* The index is the offset into the ca's internal array +* of port attributes. +* +* RETURN VALUE +* Returns the port GUID of the specified port owned by this CA. +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: SM Vendor/osm_vendor_get_guid_ca_and_port + * NAME + * osm_vendor_get_guid_ca_and_port + * + * DESCRIPTION + * Given the vendor obj and a guid + * return the ca id and port number that have that guid + * + * SYNOPSIS + */ +ib_api_status_t +osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend, + IN ib_net64_t const guid, + OUT VAPI_hca_id_t * p_hca_id, + OUT uint32_t * p_port_num); + +/* +* PARAMETERS +* p_vend +* [in] Pointer to an osm_vendor_t object. +* +* guid +* [in] The guid to search for. +* +* p_hca_id +* [out] The HCA Id (VAPI_hca_id_t *) that the port is found on. +* +* p_port_num +* [out] Pointer to a port number arg to be filled with the port number with the given guid. +* +* RETURN VALUES +* IB_SUCCESS on SUCCESS +* IB_INVALID_GUID if the guid is notfound on any Local HCA Port +* +* NOTES +* +* SEE ALSO +*********/ + +/****f* OpenSM: SM Vendor/osm_vendor_get_all_port_attr + * NAME + * osm_vendor_get_all_port_attr + * + * DESCRIPTION + * Fill in the array of port_attr with all available ports on ALL the + * avilable CAs on this machine. + * ALSO - + * UPDATE THE VENDOR OBJECT LIST OF CA_INFO STRUCTS + * + * SYNOPSIS + */ +ib_api_status_t osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * + const p_attr_array, + IN uint32_t * const p_num_ports); + +/* +* PARAMETERS +* p_vend +* [in] Pointer to an osm_vendor_t object. +* +* p_attr_array +* [out] Pre-allocated array of port attributes to be filled in +* +* p_num_ports +* [out] The size of the given array. Filled in by the actual numberof ports found. +* +* RETURN VALUES +* IB_SUCCESS if OK +* IB_INSUFFICIENT_MEMORY if not enough place for all ports was provided. +* +* NOTES +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_VENDOR_HCA_GUID_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_mtl_transaction_mgr.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mtl_transaction_mgr.h new file mode 100644 index 000000000000..6ec5b860135c --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_mtl_transaction_mgr.h @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Definition of interface for the MTL Vendor + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_TRANSACTION_MGR_H_ +#define _OSM_TRANSACTION_MGR_H_ + + /* + #include + #include + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef OSM_VENDOR_INTF_MTL +#include +#include +#endif + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM: Transaction Manager/osm_madw_req_t +* NAME +* osm_madw_req_t +* +* DESCRIPTION +* The structure defining each object in the transaction_mgr. +* For every request mad sent, we will save such an object for it. +* +* SYNOPSIS +*/ +typedef struct _osm_madw_req { + cl_list_item_t list_item; + cl_map_item_t map_item; + osm_madw_t *p_madw; + uint64_t waking_time; + uint8_t retry_cnt; + osm_bind_handle_t *p_bind; +} osm_madw_req_t; + +/* +* FIELDS +* list_item +* List item for qlist linkage. Must be first element!! +* +* map_item +* Map item for qmap linkage. +* +* p_madw +* pointer to mad wrapper that is expecting to get a response. +* +* waking_time +* Time stamp (in microseconds) when the p_madw needs to wake up. +* This value is +* cl_get_time_stamp() + timeout during the sending of the mad. +* where timeout should be given in microseconds. +* +* retry_cnt +* The number of outstanding retries to be called. +*********/ + +/****s* OpenSM: Transaction Manager/osm_transaction_mgr_t +* NAME +* osm_transaction_mgr_t +* +* DESCRIPTION +* This structure defines the transaction manager. +* It holds a qlist and a qmap, a lock on the transaction manager, and +* a timer used for the list. +* The manager is responsible for keeping track of every request mad that was +* sent. It is used for finding mads according to their transaction id, and for +* acting as an event wheel - reporting as error each packet was supposed to get +* a response and didn't get one by the timeout time expected. +* +* Both the list and the map hold the osm_madw_req_t objects - one for every madw. +* +* Managing of the list: +* The timer wakes on the timeout of the first madw. If the waking_time is greater than +* the current time - then the mad received a response. If not - the mad didn't get +* its response. +* +* SYNOPSIS +*/ +typedef struct _osm_transaction_mgr { + cl_qmap_t *madw_by_tid_map_p; + cl_qlist_t *madw_reqs_list_p; + cl_spinlock_t transaction_mgr_lock; + cl_timer_t madw_list_timer; +} osm_transaction_mgr_t; + +/* +* FIELDS +* madw_by_tid_map_p +* A qmap with key = transaction id. and value of osm_madw_req_t. +* +* madw_reqs_list_p +* A qlist of all the madw with their waking time. +* +* transaction_mgr_lock +* Lock used on the transaction manager - make sure changes on it are serial. +* +* madw_list_timer +* Timer on the list. +*********/ + +/****f* OpenSM: Transaction Manager/osm_transaction_mgr_init +* NAME +* osm_transaction_mgr_init +* +* DESCRIPTION +* Initialize the transaction manager. +* Will update the p_transaction_mgr in the vendor object with +* the new Transaction Manager created.* +* +* SYNOPSIS +*/ +void osm_transaction_mgr_init(IN osm_vendor_t * const p_vend); + +/* +* PARAMETERS +* p_vend +* [in] Pointer to a Osm Vendor object. +* +*********/ + +/****f* OpenSM: Transaction Manager/osm_transaction_mgr_destroy +* NAME +* osm_transaction_mgr_destroy +* +* DESCRIPTION +* Destroy the transaction manager. +* Will de-allocate all memory allocated by the Transaction +* Manager up to now. +* +* SYNOPSIS +*/ +void osm_transaction_mgr_destroy(IN osm_vendor_t * const p_vend); + +/* +* PARAMETERS +* p_vend +* [in] Pointer to a Osm Vendor object. +* +*********/ + +/****f* OpenSM: Transaction Manager/osm_transaction_mgr_insert_madw +* NAME +* osm_transaction_mgr_insert_madw +* +* DESCRIPTION +* Insert a new madw to the manager. The madw is added with a waking_time, +* Which is equal to the current_time + timeout. This is the maximum time +* that the madw can leave without being handled (e.g - get a response). +* If there are no madw saved in the manager - start the timer for vendor +* timeout period. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_transaction_mgr_insert_madw(IN osm_bind_handle_t * p_bind, + IN osm_madw_t * p_madw); +/* +* PARAMETERS +* p_vend +* [in] Pointer to a mtl bind object. +* +* p_madw +* [in] Pointer to the Mad Wrapper to be added. +* +*********/ + +/****f* OpenSM: Transaction Manager/osm_transaction_mgr_erase_madw +* NAME +* osm_transaction_mgr_erase_madw +* +* DESCRIPTION +* Erase a madw object from the manager. +* The removal is done using the transaction id of the mad - using +* it the madw_p is allocated (in the qmap) and removed from the +* qmap and qlist. +* +* SYNOPSIS +*/ +ib_api_status_t +osm_transaction_mgr_erase_madw(IN osm_vendor_t * const p_vend, + IN ib_mad_t * p_mad); +/* +* PARAMETERS +* p_vend +* [in] Pointer to a Osm Vendor object. +* +* p_mad +* [in] Pointer to the Mad to be removed. +* +*********/ + +/****f* OpenSM: Transaction Manager/osm_transaction_mgr_get_madw_for_tid +* NAME +* osm_transaction_mgr_get_madw_for_tid +* +* DESCRIPTION +* Return the mad wrapper, given the p_mad (and in it the transaction id) +* +* SYNOPSIS +*/ +ib_api_status_t +osm_transaction_mgr_get_madw_for_tid(IN osm_vendor_t * const p_vend, + IN ib_mad_t * const p_mad, + OUT osm_madw_t ** req_madw_p); +/* +* PARAMETERS +* p_vend +* [in] Pointer to a Osm Vendor object. +* +* p_mad +* [in] Pointer to the Mad to be located. +* +* req_madw_p +* [out] Pointer to the mad Wrapper to be found. +* +*********/ + +/****f* OpenSM: Transaction Manager/osm_transaction_mgr_callback +* NAME +* osm_transaction_mgr_callback +* +* DESCRIPTION +* This callback is called on timeout of the timer. +* It checks the time of the head madw in the qlist, and compares it to +* the current time. +* Will send an error callback if the time of the madw is less than the +* current time - this means that the madw wasn't removed in the timeout +* it was supposed to be handled. +* +* SYNOPSIS +*/ +void osm_transaction_mgr_callback(IN void *context); +/* +* PARAMETERS +* context +* [in] void* context +* +*********/ + +END_C_DECLS +#endif /* _OSM_TRANSACTION_MGR_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_sa_api.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_sa_api.h new file mode 100644 index 000000000000..4a4eeafce8dc --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_sa_api.h @@ -0,0 +1,866 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Specification of the OpenSM SA Client API. This API uses the basic osm + * vendor API to provide SA Client interface. + */ + +#ifndef _OSM_VENDOR_SA_API_H_ +#define _OSM_VENDOR_SA_API_H_ + +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****d* OpenSM Vendor SA Client/osmv_flags_t +* NAME +* osmv_flags_t +* +* DESCRIPTION +* Access layer flags used to direct the operation of various calls. +* +* SYNOPSIS +*/ +typedef uint32_t osmv_flags_t; +#define OSM_SA_FLAGS_SYNC 0x00000001 +/* +* VALUES +* OSM_SA_FLAGS_SYNC +* Indicates that the given operation should be performed synchronously. +* The call will block until it completes. Callbacks will still be +* invoked. +* +* SEE ALSO +* osmv_query_sa +*****/ + +/****d* OpenSM Vendor SA Client/osmv_query_type_t +* NAME +* osmv_query_type_t +* +* DESCRIPTION +* Abstracted queries supported by the access layer. +* +* SYNOPSIS +*/ +typedef enum _osmv_query_type { + OSMV_QUERY_USER_DEFINED, + + OSMV_QUERY_ALL_SVC_RECS, + OSMV_QUERY_SVC_REC_BY_NAME, + OSMV_QUERY_SVC_REC_BY_ID, + + OSMV_QUERY_CLASS_PORT_INFO, + + OSMV_QUERY_NODE_REC_BY_NODE_GUID, + OSMV_QUERY_PORT_REC_BY_LID, + OSMV_QUERY_PORT_REC_BY_LID_AND_NUM, + + OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK, + OSMV_QUERY_SLVL_BY_LID_AND_PORTS, + + OSMV_QUERY_PATH_REC_BY_PORT_GUIDS, + OSMV_QUERY_PATH_REC_BY_GIDS, + OSMV_QUERY_PATH_REC_BY_LIDS, + + OSMV_QUERY_UD_MULTICAST_SET, + OSMV_QUERY_UD_MULTICAST_DELETE, + + OSMV_QUERY_MULTIPATH_REC, + +} osmv_query_type_t; +/* +* VALUES +* OSMV_QUERY_USER_DEFINED +* Query the SA based on user-defined input. Queries of this type +* should reference an osmv_user_query_t structure as input to the +* query. +* +* OSMV_QUERY_SVC_REC_BY_NAME +* Query for service records based on the service name. Queries of +* this type should reference an ib_svc_name_t structure as input +* to the query. +* +* OSMV_QUERY_SVC_REC_BY_ID +* Query for service records based on the service ID. Queries of +* this type should reference an ib_net64_t value that indicates +* the ID of the service being requested. +* +* OSMV_QUERY_NODE_REC_BY_NODE_GUID +* Query for node information based on the node's GUID. Queries of +* this type should reference an ib_net64_t value that indicates +* the GUID of the node being requested. +* +* OSMV_QUERY_PORT_REC_BY_LID +* Query for port information based on the port's base LID. Queries +* of this type should reference an ib_net16_t value that indicates +* the base LID of the port being requested. +* +* OSMV_QUERY_PORT_REC_BY_LID_AND_NUM +* Query for port information based on the port's LID and port num. +* Queries of this type should reference an osmv_user_query_t +* structure as input to the query. The port num and lid should +* be provided by it. +* +* OSMV_QUERY_PATH_REC_BY_PORT_GUIDS +* Query for path records between the specified pair of port GUIDs. +* Queries of this type should reference an osmv_guid_pair_t +* structure that indicates the GUIDs of the path being requested. +* +* OSMV_QUERY_PATH_REC_BY_GIDS +* Query for path records between the specified pair of port GIDs. +* Queries of this type should reference an osmv_gid_pair_t +* structure that indicates the GIDs of the path being requested. +* +* OSMV_QUERY_PATH_REC_BY_LIDS +* Query for path records between the specified pair of port LIDs. +* Queries of this type should reference an osmv_lid_pair_t +* structure that indicates the LIDs of the path being requested. +* +* NOTES +* This enum is used to define abstracted queries provided by the access +* layer. Users may issue queries not listed here by sending MADs directly +* to subnet administration or a class manager. These queries are +* intended to represent those most often used by clients. +* +* SEE ALSO +* osmv_query, osmv_query_req_t, osmv_user_query_t, osmv_gid_pair_t, +* osmv_lid_pair_t osmv_guid_pair_t +*****/ + +/****s* OpenSM Vendor SA Client/osmv_user_query_t +* NAME +* osmv_user_query_t +* +* DESCRIPTION +* User-defined query information. +* +* SYNOPSIS +*/ +typedef struct _osmv_user_query { + uint8_t method; + ib_net16_t attr_id; + ib_net16_t attr_offset; + ib_net32_t attr_mod; + ib_net64_t comp_mask; + void *p_attr; +} osmv_user_query_t; +/* +* FIELDS +* +* method +* Method to be used +* +* attr_id +* Attribute identifier of query data. +* +* attr_offset +* Size of the query attribute, in 8-byte words. Users can set +* this value by passing in the sizeof( attribute ) into the +* ib_get_attr_offset() routine. +* +* attr_mod +* Attribute modifier for query request. +* +* comp_mask +* Indicates the attribute components that are specified for the +* query. +* +* p_attr +* References the attribute structure used as input into the query. +* This field is ignored if comp_mask is set to 0. +* +* NOTES +* This structure is used to describe a user-defined query. The attribute +* ID, attribute offset, component mask, and attribute structure must match +* those defined by the IBA specification. Users should refer to chapter +* 15 of the IBA specification for additional details. +* +* SEE ALSO +* osmv_query_type_t, ib_get_attr_offset, ib_get_attr_size, osmv_query_sa +*****/ + +/****s* OpenSM Vendor SA Client/osmv_gid_pair_t +* NAME +* osmv_gid_pair_t +* +* DESCRIPTION +* Source and destination GIDs. +* +* SYNOPSIS +*/ +typedef struct _osmv_gid_pair { + ib_gid_t src_gid; + ib_gid_t dest_gid; +} osmv_gid_pair_t; +/* +* FIELDS +* src_gid +* Source GID of a path. +* +* dest_gid +* Destination GID of a path. +* +* NOTES +* This structure is used to describe the endpoints of a path. +* +* SEE ALSO +* ib_gid_t +*****/ + +/****s* OpenSM Vendor SA Client/osmv_lid_pair_t +* NAME +* osmv_lid_pair_t +* +* DESCRIPTION +* Source and destination LIDs. +* +* SYNOPSIS +*/ +typedef struct _osmv_lid_pair { + ib_net16_t src_lid; + ib_net16_t dest_lid; +} osmv_lid_pair_t; +/* +* FIELDS +* src_lid +* Source LID of a path. +* +* dest_lid +* Destination LID of a path. +* +* NOTES +* This structure is used to describe the endpoints of a path. +*****/ + +/****s* OpenSM Vendor SA Client/osmv_guid_pair_t +* NAME +* osmv_guid_pair_t +* +* DESCRIPTION +* Source and destination GUIDs. These may be port or channel adapter +* GUIDs, depending on the context in which this structure is used. +* +* SYNOPSIS +*/ +typedef struct _osmv_guid_pair { + ib_net64_t src_guid; + ib_net64_t dest_guid; +} osmv_guid_pair_t; +/* +* FIELDS +* src_guid +* Source GUID of a path. +* +* dest_guid +* Destination GUID of a path. +* +* NOTES +* This structure is used to describe the endpoints of a path. The given +* GUID pair may belong to either ports or channel adapters. +* +* SEE ALSO +* ib_guid_t +*****/ + +/****s* OpenSM Vendor SA Client/osmv_multipath_req_t +* NAME +* osmv_multipath_req_t +* +* DESCRIPTION +* Fields from which to generate a MultiPathRecord request. +* +* SYNOPSIS +*/ +typedef struct _osmv_multipath_req_t { + ib_net64_t comp_mask; + uint16_t pkey; + boolean_t reversible; + uint8_t num_path; + uint8_t sl; + uint8_t independence; + uint8_t sgid_count; + uint8_t dgid_count; + ib_gid_t gids[IB_MULTIPATH_MAX_GIDS]; +} osmv_multipath_req_t; +/* +* FIELDS +* +* NOTES +* This structure is used to describe a multipath request. +* +* SEE ALSO +*****/ + +/****s* OpenSM Vendor SA Client/osmv_query_res_t +* NAME +* osmv_query_res_t +* +* DESCRIPTION +* Contains the results of a subnet administration query. +* +* SYNOPSIS +*/ +typedef struct _osmv_query_res { + const void *query_context; + ib_api_status_t status; + osmv_query_type_t query_type; + uint32_t result_cnt; + osm_madw_t *p_result_madw; +} osmv_query_res_t; +/* +* FIELDS +* query_context +* User-defined context information associated with the query +* through the osm_vendor_query_sa call. +* +* status +* Indicates the success of the query operation. +* +* query_type +* Indicates the type of query for which the results are being +* returned. This matches the query_type specified through the +* osm_vendor_query_sa call. +* +* result_cnt +* The number of result structures that were returned by the query. +* +* p_result_madw +* For queries returning IB_SUCCESS or IB_REMOTE_ERROR, this +* references the MAD wrapper returned by subnet administration +* containing the list of results or the returned error code. +* +* NOTES +* A query result structure is returned to a client through their +* osmv_pfn_query_cb_t routine to notify them of the results of a subnet +* administration query. If the query was successful or received an error +* from subnet administration, p_result_madw will reference a MAD wrapper +* containing the results. The MAD referenced by p_result_madw is owned by +* the user and remains available even after their callback returns. Users +* must call osm_mad_pool_put() to return the MAD wrapper back to the +* mad pool when they are done accessing the results. +* +* To retrieve individual result structures from the p_result_madw, users +* may call osmv_get_query_result(). +* +* SEE ALSO +* osmv_query_sa, osmv_pfn_query_cb_t, ib_api_status_t, +* osmv_query_status_t, osmv_query_type_t, +* osmv_get_query_result +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_result +* NAME +* osmv_get_query_result +* +* DESCRIPTION +* Retrieves a result structure from a MADW returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline void *osmv_get_query_result(IN osm_madw_t * p_result_madw, + IN uint32_t result_index) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT(p_result_madw); + p_sa_mad = (ib_sa_mad_t *) osm_madw_get_mad_ptr(p_result_madw); + CL_ASSERT(p_sa_mad); + CL_ASSERT(ib_get_attr_size(p_sa_mad->attr_offset) * (result_index + 1) + + IB_SA_MAD_HDR_SIZE <= p_result_madw->mad_size); + + return (p_sa_mad->data + + (ib_get_attr_size(p_sa_mad->attr_offset) * result_index)); +} + +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a result structure from a +* call to osmv_query_sa(). The type of result structure must be known to +* the user either through the user's context or the query_type returned as +* part of the osmv_query_res_t structure. +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_path_rec +* NAME +* osmv_get_query_path_rec +* +* DESCRIPTION +* Retrieves a path record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_path_rec_t *osmv_get_query_path_rec(IN osm_madw_t * + p_result_madw, + IN uint32_t result_index) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT(p_result_madw); + p_sa_mad = (ib_sa_mad_t *) osm_madw_get_mad_ptr(p_result_madw); + CL_ASSERT(p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD); + + return ((ib_path_rec_t *) + osmv_get_query_result(p_result_madw, result_index)); +} + +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a path record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_path_rec_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_portinfo_rec +* NAME +* osmv_get_query_portinfo_rec +* +* DESCRIPTION +* Retrieves a port info record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_portinfo_record_t *osmv_get_query_portinfo_rec(IN osm_madw_t * + p_result_madw, + IN uint32_t + result_index) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT(p_result_madw); + p_sa_mad = (ib_sa_mad_t *) osm_madw_get_mad_ptr(p_result_madw); + CL_ASSERT(p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_PORTINFO_RECORD); + + return ((ib_portinfo_record_t *) osmv_get_query_result(p_result_madw, + result_index)); +} + +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a port info record result +* from a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_portinfo_record_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_node_rec +* NAME +* osmv_get_query_node_rec +* +* DESCRIPTION +* Retrieves a node record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_node_record_t *osmv_get_query_node_rec(IN osm_madw_t * + p_result_madw, + IN uint32_t + result_index) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT(p_result_madw); + p_sa_mad = (ib_sa_mad_t *) osm_madw_get_mad_ptr(p_result_madw); + CL_ASSERT(p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_NODE_RECORD); + + return ((ib_node_record_t *) osmv_get_query_result(p_result_madw, + result_index)); +} + +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a node record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_node_record_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_svc_rec +* NAME +* osmv_get_query_svc_rec +* +* DESCRIPTION +* Retrieves a service record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_service_record_t *osmv_get_query_svc_rec(IN osm_madw_t * + p_result_madw, + IN uint32_t + result_index) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT(p_result_madw); + p_sa_mad = (ib_sa_mad_t *) osm_madw_get_mad_ptr(p_result_madw); + CL_ASSERT(p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_SERVICE_RECORD); + + return ((ib_service_record_t *) osmv_get_query_result(p_result_madw, + result_index)); +} + +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a service record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_service_record_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_mc_rec +* NAME +* osmv_get_query_mc_rec +* +* DESCRIPTION +* Retrieves a multicast record result from a MAD returned by a call to +* osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_member_rec_t *osmv_get_query_mc_rec(IN osm_madw_t * + p_result_madw, + IN uint32_t result_index) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT(p_result_madw); + p_sa_mad = (ib_sa_mad_t *) osm_madw_get_mad_ptr(p_result_madw); + CL_ASSERT(p_sa_mad && p_sa_mad->attr_id == IB_MAD_ATTR_MCMEMBER_RECORD); + + return ((ib_member_rec_t *) osmv_get_query_result(p_result_madw, + result_index)); +} + +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a service record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_member_rec_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_get_query_inform_info_rec +* NAME +* osmv_get_query_inform_info_rec +* +* DESCRIPTION +* Retrieves an InformInfo record result from a MAD returned by +* a call to osmv_query_sa(). +* +* SYNOPSIS +*/ +static inline ib_inform_info_record_t *osmv_get_query_inform_info_rec(IN + osm_madw_t + * + p_result_madw, + IN + uint32_t + result_index) +{ + ib_sa_mad_t *p_sa_mad; + + CL_ASSERT(p_result_madw); + p_sa_mad = (ib_sa_mad_t *) osm_madw_get_mad_ptr(p_result_madw); + CL_ASSERT(p_sa_mad + && p_sa_mad->attr_id == IB_MAD_ATTR_INFORM_INFO_RECORD); + + return ((ib_inform_info_record_t *) osmv_get_query_result(p_result_madw, + result_index)); +} + +/* +* PARAMETERS +* p_result_madw +* [in] This is a reference to the MAD returned as a result of the +* query. +* +* result_index +* [in] A zero-based index indicating which result to return. +* +* NOTES +* This call returns a pointer to the start of a service record result from +* a call to osmv_query_sa(). +* +* SEE ALSO +* osmv_query_res_t, osm_madw_t, osmv_get_query_result, ib_inform_info_record_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_pfn_query_cb_t +* NAME +* osmv_pfn_query_cb_t +* +* DESCRIPTION +* User-defined callback invoked on completion of subnet administration +* query. +* +* SYNOPSIS +*/ +typedef void + (*osmv_pfn_query_cb_t) (IN osmv_query_res_t * p_query_res); +/* +* PARAMETERS +* p_query_res +* [in] This is a reference to a structure containing the result of +* the query. +* +* NOTES +* This routine is invoked to notify a client of the result of a subnet +* administration query. The p_query_rec parameter references the result +* of the query and, in the case of a successful query, any information +* returned by subnet administration. +* +* In the kernel, this callback is usually invoked using a tasklet, +* dependent on the implementation of the underlying verbs provider driver. +* +* SEE ALSO +* osmv_query_res_t +*****/ + +/****s* OpenSM Vendor SA Client/osmv_query_req_t +* NAME +* osmv_query_req_t +* +* DESCRIPTION +* Information used to request an access layer provided query of subnet +* administration. +* +* SYNOPSIS +*/ +typedef struct _osmv_query_req { + osmv_query_type_t query_type; + const void *p_query_input; + ib_net64_t sm_key; + + uint32_t timeout_ms; + uint32_t retry_cnt; + osmv_flags_t flags; + + const void *query_context; + osmv_pfn_query_cb_t pfn_query_cb; +} osmv_query_req_t; +/* +* FIELDS +* query_type +* Indicates the type of query that the access layer should +* perform. +* +* p_query_input +* A pointer to the input for the query. The data referenced by +* this structure is dependent on the type of query being requested +* and is determined by the specified query_type. +* +* sm_key +* The M_Key to be provided with the SA MAD for authentication. +* Normally 0 is used. +* +* timeout_ms +* Specifies the number of milliseconds to wait for a response for +* this query until retrying or timing out the request. +* +* retry_cnt +* Specifies the number of times that the query will be retried +* before failing the request. +* +* flags +* Used to describe the mode of operation. Set to IB_FLAGS_SYNC to +* process the called routine synchronously. +* +* query_context +* User-defined context information associated with this query. +* The context data is returned to the user as a part of their +* query callback. +* +* pfn_query_cb +* A user-defined callback that is invoked upon completion of the +* query. +* +* NOTES +* This structure is used when requesting an osm vendor provided query +* of subnet administration. Clients specify the type of query through +* the query_type field. Based on the type of query, the p_query_input +* field is set to reference the appropriate data structure. +* +* The information referenced by the p_query_input field is one of the +* following: +* +* -- a NULL terminated service name +* -- a service id +* -- a single GUID +* -- a pair of GUIDs specified through an osmv_guid_pair_t structure +* -- a pair of GIDs specified through an osmv_gid_pair_t structure +* +* SEE ALSO +* osmv_query_type_t, osmv_pfn_query_cb_t, osmv_guid_pair_t, +* osmv_gid_pair_t +*****/ + +/****f* OpenSM Vendor SA Client/osmv_bind_sa +* NAME +* osmv_bind_sa +* +* DESCRIPTION +* Bind to the SA service and return a handle to be used for later +* queries. +* +* +* SYNOPSIS +*/ +osm_bind_handle_t +osmv_bind_sa(IN osm_vendor_t * const p_vend, + IN osm_mad_pool_t * const p_mad_pool, IN ib_net64_t port_guid); +/* +* PARAMETERS +* p_vend +* [in] an osm_vendor object to work with +* +* p_mad_pool +* [in] mad pool to obtain madw from +* +* port_guid +* [in] the port guid to attach to. +* +* RETURN VALUE +* Bind handle to be used for later SA queries or OSM_BIND_INVALID_HANDLE +* +* NOTES +* +* SEE ALSO +* osmv_query_sa +*********/ + +/****f* OpenSM Vendor SA Client/osmv_query_sa +* NAME +* osmv_query_sa +* +* DESCRIPTION +* Query the SA given an SA query request (similar to IBAL ib_query). +* +* SYNOPSIS +*/ +ib_api_status_t +osmv_query_sa(IN osm_bind_handle_t h_bind, + IN const osmv_query_req_t * const p_query_req); +/* +* PARAMETERS +* h_bind +* [in] bind handle for this port. Should be previously +* obtained by calling osmv_bind_sa +* +* p_query_req +* [in] an SA query request structure. +* +* RETURN VALUE +* IB_SUCCESS if completed successfuly (or in ASYNC mode +* if the request was sent). +* +* NOTES +* +* SEE ALSO +* osmv_bind_sa +*********/ + +END_C_DECLS +#endif /* _OSM_VENDOR_SA_API_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_test.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_test.h new file mode 100644 index 000000000000..a1ae1ebb2f7e --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_test.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _OSM_VENDOR_TEST_H_ +#define _OSM_VENDOR_TEST_H_ + +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/* This value must be zero for the TEST transport. */ +#define OSM_BIND_INVALID_HANDLE 0 +/* + * Abstract: + * Declaration of vendor specific transport interface. + * This is the "Test" vendor which allows compilation and some + * testing without a real vendor interface. + * These objects are part of the OpenSM family of objects. + */ +/****h* OpenSM/Vendor Test +* NAME +* Vendor Test +* +* DESCRIPTION +* The Vendor Test structure encapsulates an artificial transport layer +* interface for testing. +* +* AUTHOR +* Steve King, Intel +* +*********/ +/****s* OpenSM: Vendor Test/osm_vend_wrap_t +* NAME +* osm_vend_wrap_t +* +* DESCRIPTION +* Vendor specific MAD wrapper context. +* +* This structure allows direct access to member variables. +* +* SYNOPSIS +*/ +typedef struct _osm_vend_wrap { + uint32_t dummy; + +} osm_vend_wrap_t; +/*********/ + +/****s* OpenSM: Vendor Test/osm_vendor_t +* NAME +* osm_vendor_t +* +* DESCRIPTION +* Vendor specific MAD interface. +* +* This interface defines access to the vendor specific MAD +* transport layer. +* +* SYNOPSIS +*/ +typedef struct _osm_vendor { + osm_log_t *p_log; + uint32_t timeout; + +} osm_vendor_t; +/*********/ + +typedef struct _osm_bind_handle { + osm_vendor_t *p_vend; + ib_net64_t port_guid; + uint8_t mad_class; + uint8_t class_version; + boolean_t is_responder; + boolean_t is_trap_processor; + boolean_t is_report_processor; + uint32_t send_q_size; + uint32_t recv_q_size; + +} *osm_bind_handle_t; + +END_C_DECLS +#endif /* _OSM_VENDOR_TEST_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_ts.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_ts.h new file mode 100644 index 000000000000..a43f4e4daf71 --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_ts.h @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Definition of interface for the TS Vendor + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_VENDOR_TS_H_ +#define _OSM_VENDOR_TS_H_ + +#undef IN +#undef OUT +#include +#include +#include +#define IN +#define OUT +#include "iba/ib_types.h" +#include "iba/ib_al.h" +#include +#include +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****s* OpenSM: Vendor TS/osm_bind_handle_t + * NAME + * osm_bind_handle_t + * + * DESCRIPTION + * handle returned by the vendor transport bind call. + * + * SYNOPSIS + */ +typedef void *osm_bind_handle_t; +/* +**********/ +#define OSM_DEFAULT_RETRY_COUNT 3 + +/****s* OpenSM: Vendor osm_ts_bind_info_t + * NAME + * osm_ts_bind_info_t + * + * DESCRIPTION + * Handle to the result of binding a class callbacks . + * + * SYNOPSIS + */ +typedef struct _osm_ts_bind_info { + int ul_dev_fd; + VAPI_hca_hndl_t hca_hndl; + struct _osm_vendor *p_vend; + void *client_context; + uint8_t port_num; + void *rcv_callback; + void *send_err_callback; + struct _osm_mad_pool *p_osm_pool; + cl_thread_t poller; +} osm_ts_bind_info_t; +/* + * FIELDS + * ul_dev_file_hdl + * the file handle to be used for sending the MADs + * + * hca_hndl + * Handle to the HCA provided by the underlying VAPI + * + * p_vend + * Pointer to the vendor object. + * + * client_context + * User's context passed during osm_bind + * + * hca_id + * HCA Id we bind to. + * + * port_num + * Port number (within the HCA) of the bound port. + * + * rcv_callback + * OSM Callback function to be called on receive of MAD. + * + * send_err_callback + * OSM Callback to be called on send error. + * + * p_osm_pool + * Points to the MAD pool used by OSM + * + * poller + * A thread reading from the device file handle + * + * SEE ALSO + *********/ + +/****h* OpenSM/Vendor TS + * NAME + * Vendor TS + * + * DESCRIPTION + * + * The Vendor TS object is thread safe. + * + * This object should be treated as opaque and should be + * manipulated only through the provided functions. + * + * + * AUTHOR + * + * + *********/ + +/****s* OpenSM: Vendor TS/osm_ca_info_t + * NAME + * osm_ca_info_t + * + * DESCRIPTION + * Structure containing information about local Channle Adapters. + * + * SYNOPSIS + */ +typedef struct _osm_ca_info { + ib_net64_t guid; + size_t attr_size; + ib_ca_attr_t *p_attr; + +} osm_ca_info_t; + +/* + * FIELDS + * guid + * Node GUID of the local CA. + * + * attr_size + * Size of the CA attributes for this CA. + * + * p_attr + * Pointer to dynamicly allocated CA Attribute structure. + * + * SEE ALSO + *********/ + +/***** OpenSM: Vendor TS/osm_vendor_t + * NAME + * osm_vendor_t + * + * DESCRIPTION + * The structure defining a TS vendor + * + * SYNOPSIS + */ +typedef struct _osm_vendor { + osm_log_t *p_log; + uint32_t ca_count; + osm_ca_info_t *p_ca_info; + uint32_t timeout; + struct _osm_transaction_mgr *p_transaction_mgr; + osm_ts_bind_info_t smi_bind; + osm_ts_bind_info_t gsi_bind; +} osm_vendor_t; + +/* + * FIELDS + * h_al + * Handle returned by TS open call . + * + * p_log + * Pointer to the log object. + * + * ca_count + * Number of CA's in the array pointed to by p_ca_info. + * + * p_ca_info + * Pointer to dynamically allocated array of CA info objects. + * + * timeout + * Transaction timeout time in milliseconds. + * + * p_transaction_mgr + * Pointer to Transaction Manager. + * + * smi_bind + * Bind information for handling SMI MADs + * + * gsi_bind + * Bind information for GSI MADs + * + * SEE ALSO + *********/ + +/****f* OpenSM: Vendor TS/CA Info/osm_ca_info_get_port_guid + * NAME + * osm_ca_info_get_port_guid + * + * DESCRIPTION + * Returns the port GUID of the specified port owned by this CA. + * + * SYNOPSIS + */ +static inline ib_net64_t +osm_ca_info_get_port_guid(IN const osm_ca_info_t * const p_ca_info, + IN const uint8_t index) +{ + return (p_ca_info->p_attr->p_port_attr[index].port_guid); +} + +/* + * PARAMETERS + * p_ca_info + * [in] Pointer to a CA Info object. + * + * index + * [in] Port "index" for which to retrieve the port GUID. + * The index is the offset into the ca's internal array + * of port attributes. + * + * RETURN VALUE + * Returns the port GUID of the specified port owned by this CA. + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OpenSM: Vendor TS/CA Info/osm_ca_info_get_num_ports + * NAME + * osm_ca_info_get_num_ports + * + * DESCRIPTION + * Returns the number of ports of the given ca_info + * + * SYNOPSIS + */ +static inline uint8_t +osm_ca_info_get_num_ports(IN const osm_ca_info_t * const p_ca_info) +{ + return (p_ca_info->p_attr->num_ports); +} + +/* + * PARAMETERS + * p_ca_info + * [in] Pointer to a CA Info object. + * + * RETURN VALUE + * Returns the number of CA ports + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OpenSM: SM Vendor/osm_vendor_get_guid_ca_and_port + * NAME + * osm_vendor_get_guid_ca_and_port + * + * DESCRIPTION + * Given the vendor obj and a guid + * return the ca id and port number that have that guid + * + * SYNOPSIS + */ +ib_api_status_t +osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend, + IN ib_net64_t const guid, + OUT VAPI_hca_hndl_t * p_hca_hndl, + OUT VAPI_hca_id_t * p_hca_id, + OUT uint32_t * p_port_num); + +/* + * PARAMETERS + * p_vend + * [in] Pointer to an osm_vendor_t object. + * + * guid + * [in] The guid to search for. + * + * p_hca_id + * [out] The HCA Id (VAPI_hca_id_t *) that the port is found on. + * + * p_port_num + * [out] Pointer to a port number arg to be filled with the port number with the given guid. + * + * RETURN VALUES + * IB_SUCCESS on SUCCESS + * IB_INVALID_GUID if the guid is notfound on any Local HCA Port + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OpenSM: Vendor TS/osm_vendor_get_all_port_attr + * NAME + * osm_vendor_get_all_port_attr + * + * DESCRIPTION + * Fill in the array of port_attr with all available ports on ALL the + * avilable CAs on this machine. + * ALSO - + * UPDATE THE VENDOR OBJECT LIST OF CA_INFO STRUCTS + * + * SYNOPSIS + */ +ib_api_status_t osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * + const p_attr_array, + IN uint32_t * const p_num_ports); + +/* + * PARAMETERS + * p_vend + * [in] Pointer to an osm_vendor_t object. + * + * p_attr_array + * [out] Pre-allocated array of port attributes to be filled in + * + * p_num_ports + * [out] The size of the given array. Filled in by the actual numberof ports found. + * + * RETURN VALUES + * IB_SUCCESS if OK + * IB_INSUFFICIENT_MEMORY if not enough place for all ports was provided. + * + * NOTES + * + * SEE ALSO + *********/ + +#define OSM_BIND_INVALID_HANDLE 0 + +/****s* OpenSM: Vendor TS/osm_vend_wrap_t + * NAME + * TS Vendor MAD Wrapper + * + * DESCRIPTION + * TS specific MAD wrapper. TS transport layer uses this for + * housekeeping. + * + * SYNOPSIS + *********/ +typedef struct _osm_vend_wrap_t { + uint32_t size; + osm_bind_handle_t h_bind; + ib_mad_t *p_mad_buf; + void *p_resp_madw; +} osm_vend_wrap_t; + +/* + * FIELDS + * size + * Size of the allocated MAD + * + * h_bind + * Bind handle used on this transaction + * + * h_av + * Address vector handle used for this transaction. + * + * p_resp_madw + * Pointer to the mad wrapper structure used to hold the pending + * reponse to the mad, if any. If a response is expected, the + * wrapper for the reponse is allocated during the send call. + * + * SEE ALSO + *********/ + +END_C_DECLS +#endif /* _OSM_VENDOR_TS_H_ */ diff --git a/contrib/ofed/management/opensm/include/vendor/osm_vendor_umadt.h b/contrib/ofed/management/opensm/include/vendor/osm_vendor_umadt.h new file mode 100644 index 000000000000..8cdb63181023 --- /dev/null +++ b/contrib/ofed/management/opensm/include/vendor/osm_vendor_umadt.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mad_wrapper_t. + * This object represents the context wrapper for OpenSM MAD processing. + * This object is part of the OpenSM family of objects. + */ + +#ifndef _OSM_VENDOR_UMADT_h_ +#define _OSM_VENDOR_UMADT_h_ + +#include "iba/ib_types.h" +#include "complib/cl_qlist.h" +#include "complib/cl_thread.h" +#include +#include + +#ifdef __cplusplus +# define BEGIN_C_DECLS extern "C" { +# define END_C_DECLS } +#else /* !__cplusplus */ +# define BEGIN_C_DECLS +# define END_C_DECLS +#endif /* __cplusplus */ + +BEGIN_C_DECLS +/****h* OpenSM/ Vendor Umadt +* NAME +* MAD Wrapper +* +* DESCRIPTION +* +* +* AUTHOR +* Ranjit Pandit, Intel +* +*********/ +typedef void *osm_vendor_t; +#define OSM_BIND_INVALID_HANDLE 0 + +/****s* OpenSM: Vendor Umadt /osm_bind_handle_t +* NAME +* osm_bind_handle_t +* +* DESCRIPTION +* handle returned by the vendor transport bind call. +* +* SYNOPSIS +*/ + +typedef void *osm_bind_handle_t; + +/****s* OpenSM: Vendor Umadt /mad_direction_t +* NAME +* mad_direction_t +* +* DESCRIPTION +* Tags for mad wrapper to indicate the direction of mads. +* Umadt vendor transport layer uses this tag to call the appropriate +* Umadt APIs. +* +* SYNOPSIS +*/ +typedef enum _mad_direction_t { + SEND = 0, + RECEIVE, +} mad_direction_t; + +/****s* OpenSM/ osm_vend_wrap_t +* NAME +* Umadt Vendor MAD Wrapper +* +* DESCRIPTION +* Umadt specific MAD wrapper. Umadt transport layer sets this for +* housekeeping. +* +* SYNOPSIS +*********/ +typedef struct _osm_vend_wrap_t { + MadtStruct *p_madt_struct; + mad_direction_t direction; // send or receive + uint32_t size; +} osm_vend_wrap_t; +/* +* FIELDS +* p_madt_struct +* Umadt mad structure to identify a mad. +* +* direction +* Used to identify a mad with it's direction. +* +* SEE ALSO +*********/ + +END_C_DECLS +#endif /* _OSM_VENDOR_UMADT_h_ */ diff --git a/contrib/ofed/management/opensm/libvendor/ChangeLog b/contrib/ofed/management/opensm/libvendor/ChangeLog new file mode 100644 index 000000000000..c9648ec9ef34 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/ChangeLog @@ -0,0 +1,64 @@ +2007-07-11 Hal Rosenstock + + * configure.in: Bump version to 2.2.1 + +2007-07-10 Sean Hefty + + * osm_vendor_ibumad.c: Use pkey index, rather than pkey + on umad_set_pkey call. Using index 0 for now. + +2007-05-07 Hal Rosenstock + + * osm_vendor_ibumad.(h c): Remove support for issmdisabled + +2007-03-29 Hal Rosenstock + + * configure.in: Bump version to 2.2.0 + +2007-03-27 Hal Rosenstock + + * osm_vendor_ibumad.(h c): Add support for issmdisabled + +2007-03-13 Hal Rosenstock + + * osm_vendor_ibumad.c: In osm_vendor_set_sm, set issmfd to + -1 on open error + +2007-03-12 Hal Rosenstock + + * osm_vendor_ibumad.c: In umad_receiver, display DR path of + sent MAD when it times out. In osm_vendor_send, simplify redundant + code. Cosmetic change to osm_log message in osm_vendor_bind. + +2007-02-20 Hal Rosenstock + + * configure.in: Bump version to 2.1.1 + +2007-02-20 Sasha Khapyorsky + + * osm_vendor_ibumad.(h c): Fix termination crash associated + with umad_receiver thread termination. + + * osm_vendor_mlx_sa.c, osm_vendor_mlx_sim.c: Changes for + compilation failures detected during ibutils/ibmgtsim building + +2007=01-10 Sasha Khapyorsky + + * osm_vendor_ibumad.c: Close umad port in + osm_vendor_delete so same process can reinitialize + and resuse vendor layer. + +2006-10-12 Hal Rosenstock + + * osm_vendor_ibumad.c (umad_receiver): Fix endian of LID + displayed in send timeout error message. + +2006-10-10 Hal Rosenstock + + * osm_vendor_ibumad.c: Print errors to stderr rather than + stdout. + +2006-09-28 Eitan Zahavi + + * osm_vendor_mlx_sa.c: Missing status on timeout SA query. + diff --git a/contrib/ofed/management/opensm/libvendor/Makefile.am b/contrib/ofed/management/opensm/libvendor/Makefile.am new file mode 100644 index 000000000000..22f7a0838f54 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/Makefile.am @@ -0,0 +1,86 @@ + +SUBDIRS = . + +if DEBUG +DBGFLAGS = -ggdb -D_DEBUG_ +else +DBGFLAGS = -g +endif + +INCLUDES = $(OSMV_INCLUDES) + +lib_LTLIBRARIES = libosmvendor.la + +libosmvendor_la_CFLAGS = -Wall $(DBGFLAGS) + +if HAVE_LD_VERSION_SCRIPT + libosmvendor_version_script = -Wl,--version-script=$(srcdir)/libosmvendor.map +else + libosmvendor_version_script = +endif + +osmvendor_api_version=$(shell grep LIBVERSION= $(srcdir)/libosmvendor.ver | sed 's/LIBVERSION=//') + +COMM_HDRS= $(srcdir)/../include/vendor/osm_vendor_api.h \ + $(srcdir)/../include/vendor/osm_vendor.h \ + $(srcdir)/../include/vendor/osm_vendor_sa_api.h + +if OSMV_OPENIB +libosmvendor_la_SOURCES = osm_vendor_ibumad.c \ + osm_vendor_ibumad_sa.c +HDRS =$(COMM_HDRS) $(srcdir)/../include/vendor/osm_vendor_ibumad.h +endif +if OSMV_SIM +libosmvendor_la_SOURCES = osm_vendor_mlx.c \ + osm_vendor_mlx_sim.c \ + osm_vendor_mlx_hca_sim.c \ + osm_vendor_mlx_dispatcher.c \ + osm_vendor_mlx_rmpp_ctx.c \ + osm_vendor_mlx_sar.c \ + osm_vendor_mlx_sender.c \ + osm_vendor_mlx_txn.c \ + osm_vendor_mlx_sa.c \ + osm_pkt_randomizer.c +HDRS =$(COMM_HDRS) $(srcdir)/../include/vendor/osm_vendor_mlx.h \ + $(srcdir)/../include/vendor/osm_pkt_randomizer.h +endif +if OSMV_GEN1 +libosmvendor_la_SOURCES = osm_vendor_mlx.c \ + osm_pkt_randomizer.c \ + osm_vendor_mlx_hca.c \ + osm_vendor_mlx_dispatcher.c \ + osm_vendor_mlx_rmpp_ctx.c \ + osm_vendor_mlx_sar.c \ + osm_vendor_mlx_sender.c \ + osm_vendor_mlx_ts.c \ + osm_vendor_mlx_txn.c \ + osm_vendor_mlx_sa.c +HDRS =$(COMM_HDRS) $(srcdir)/../include/vendor/osm_vendor_mlx.h \ + $(srcdir)/../include/vendor/osm_pkt_randomizer.h +endif +if OSMV_VAPI +libosmvendor_la_SOURCES = osm_vendor_mlx.c \ + osm_pkt_randomizer.c \ + osm_vendor_mlx_hca.c \ + osm_vendor_mlx_dispatcher.c \ + osm_vendor_mlx_rmpp_ctx.c \ + osm_vendor_mlx_sar.c \ + osm_vendor_mlx_sender.c \ + osm_vendor_mlx_ibmgt.c \ + osm_vendor_mlx_txn.c \ + osm_vendor_mlx_sa.c +HDRS =$(COMM_HDRS) $(srcdir)/../include/vendor/osm_vendor_mlx.h \ + $(srcdir)/../include/vendor/osm_pkt_randomizer.h +endif + +libosmvendor_la_LIBADD = -L../complib -losmcomp +libosmvendor_la_LDFLAGS = -version-info $(osmvendor_api_version) \ + -export-dynamic $(libosmvendor_version_script) +libosmvendor_la_DEPENDENCIES = $(srcdir)/libosmvendor.map + +libosmvendorincludedir = $(includedir)/infiniband/vendor + +libosmvendorinclude_HEADERS = $(HDRS) + +# headers are distributed as part of the include dir +EXTRA_DIST = $(srcdir)/libosmvendor.map $(srcdir)/libosmvendor.ver diff --git a/contrib/ofed/management/opensm/libvendor/libosmvendor.map b/contrib/ofed/management/opensm/libvendor/libosmvendor.map new file mode 100644 index 000000000000..17416b35e9fb --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/libosmvendor.map @@ -0,0 +1,20 @@ +OSMVENDOR_2.0 { + global: + umad_receiver; + osm_vendor_init; + osm_vendor_new; + osm_vendor_delete; + osm_vendor_get_all_port_attr; + osm_vendor_bind; + osm_vendor_unbind; + osm_vendor_get; + osm_vendor_put; + osm_vendor_send; + osm_vendor_local_lid_change; + osm_vendor_set_sm; + osm_vendor_set_debug; + osmv_bind_sa; + osmv_query_sa; + osm_vendor_get_guid_ca_and_port; + local: *; +}; diff --git a/contrib/ofed/management/opensm/libvendor/libosmvendor.ver b/contrib/ofed/management/opensm/libvendor/libosmvendor.ver new file mode 100644 index 000000000000..0c3a85b77e05 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/libosmvendor.ver @@ -0,0 +1,9 @@ +# In this file we track the current API version +# of the vendor interface (and libraries) +# The version is built of the following +# tree numbers: +# API_REV:RUNNING_REV:AGE +# API_REV - advance on any added API +# RUNNING_REV - advance any change to the vendor files +# AGE - number of backward versions the API still supports +LIBVERSION=2:0:0 diff --git a/contrib/ofed/management/opensm/libvendor/osm_pkt_randomizer.c b/contrib/ofed/management/opensm/libvendor/osm_pkt_randomizer.c new file mode 100644 index 000000000000..3e77b56b6971 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_pkt_randomizer.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_pkt_randomizer_t. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#ifndef WIN32 +#include +#include +#endif + +/********************************************************************** + * Return TRUE if the path is in a fault path, and FALSE otherwise. + * By in a fault path the meaning is that there is a path in the fault + * paths that the given path includes it. + * E.g: if there is a fault path: 0,1,4 + * For the given path: 0,1,4,7 the return value will be TRUE, also for + * the given path: 0,1,4 the return value will be TRUE, but for + * the given paths: 0,1 or 0,3,1,4 - the return value will be FALSE. + **********************************************************************/ +boolean_t +__osm_pkt_randomizer_is_path_in_fault_paths(IN osm_log_t * p_log, + IN osm_dr_path_t * p_dr_path, + IN osm_pkt_randomizer_t * + p_pkt_rand) +{ + boolean_t res = FALSE, found_path; + osm_dr_path_t *p_found_dr_path; + uint8_t ind1, ind2; + + OSM_LOG_ENTER(p_log); + + for (ind1 = 0; ind1 < p_pkt_rand->num_paths_initialized; ind1++) { + found_path = TRUE; + p_found_dr_path = &(p_pkt_rand->fault_dr_paths[ind1]); + /* if the hop count of the found path is greater than the + hop count of the input path - then it is not part of it. + Check the next path. */ + if (p_found_dr_path->hop_count > p_dr_path->hop_count) + continue; + + /* go over all the ports in the found path and see if they match + the ports in the input path */ + for (ind2 = 0; ind2 <= p_found_dr_path->hop_count; ind2++) + if (p_found_dr_path->path[ind2] != + p_dr_path->path[ind2]) + found_path = FALSE; + + /* If found_path is TRUE then there is a full match of the path */ + if (found_path == TRUE) { + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "Given path is in a fault path\n"); + res = TRUE; + break; + } + } + + OSM_LOG_EXIT(p_log); + return res; +} + +/********************************************************************** + * For a given dr_path - return TRUE if the path should be dropped, + * return FALSE otherwise. + * The check uses random criteria in order to determine whether or not + * the path should be dropped. + * First - if not all paths are initialized, it randomally chooses if + * to use this path as a fault path or not. + * Second - if the path is in the fault paths (meaning - it is equal + * to or includes one of the fault paths) - then it randomally chooses + * if to drop it or not. + **********************************************************************/ +boolean_t +__osm_pkt_randomizer_process_path(IN osm_log_t * p_log, + IN osm_pkt_randomizer_t * p_pkt_rand, + IN osm_dr_path_t * p_dr_path) +{ + boolean_t res = FALSE; + static boolean_t rand_value_init = FALSE; + static int rand_value; + boolean_t in_fault_paths; + uint8_t i; + char buf[BUF_SIZE]; + char line[BUF_SIZE]; + + OSM_LOG_ENTER(p_log); + + if (rand_value_init == FALSE) { + int seed; +#ifdef WIN32 + SYSTEMTIME st; +#else + struct timeval tv; + struct timezone tz; +#endif /* WIN32 */ + + /* initiate the rand_value according to timeofday */ + rand_value_init = TRUE; + +#ifdef WIN32 + GetLocalTime(&st); + seed = st.wMilliseconds; +#else + gettimeofday(&tv, &tz); + seed = tv.tv_usec; +#endif /* WIN32 */ + + srand(seed); + } + + /* If the hop_count is 1 - then this is a mad down to our local port - don't drop it */ + if (p_dr_path->hop_count <= 1) + goto Exit; + + rand_value = rand(); + + sprintf(buf, "Path: "); + /* update the dr_path into the buf */ + for (i = 0; i <= p_dr_path->hop_count; i++) { + sprintf(line, "[%X]", p_dr_path->path[i]); + strcat(buf, line); + } + + /* Check if the path given is in one of the fault paths */ + in_fault_paths = + __osm_pkt_randomizer_is_path_in_fault_paths(p_log, p_dr_path, + p_pkt_rand); + + /* Check if all paths are initialized */ + if (p_pkt_rand->num_paths_initialized < + p_pkt_rand->osm_pkt_num_unstable_links) { + /* Not all packets are initialized. */ + if (in_fault_paths == FALSE) { + /* the path is not in the false paths. Check using the rand value + if to update it there or not. */ + if (rand_value % + (p_pkt_rand->osm_pkt_unstable_link_rate) == 0) { + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "%s added to the fault_dr_paths list\n" + "\t\t\t rand_value:%u, unstable_link_rate:%u \n", + buf, rand_value, + p_pkt_rand->osm_pkt_unstable_link_rate); + + /* update the path in the fault paths */ + memcpy(& + (p_pkt_rand-> + fault_dr_paths[p_pkt_rand-> + num_paths_initialized]), + p_dr_path, sizeof(osm_dr_path_t)); + p_pkt_rand->num_paths_initialized++; + in_fault_paths = TRUE; + } + } + } + + if (in_fault_paths == FALSE) { + /* If in_fault_paths is FALSE - just ignore the path */ + OSM_LOG(p_log, OSM_LOG_VERBOSE, "%s not in fault paths\n", buf); + goto Exit; + } + + /* The path is in the fault paths. Need to choose (randomally if to drop it + or not. */ + rand_value = rand(); + + if (rand_value % (p_pkt_rand->osm_pkt_drop_rate) == 0) { + /* drop the current packet */ + res = TRUE; + OSM_LOG(p_log, OSM_LOG_VERBOSE, "Dropping path:%s\n", buf); + } + +Exit: + OSM_LOG_EXIT(p_log); + return res; +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_pkt_randomizer_mad_drop(IN osm_log_t * p_log, + IN osm_pkt_randomizer_t * p_pkt_randomizer, + IN const ib_mad_t * p_mad) +{ + const ib_smp_t *p_smp; + boolean_t res = FALSE; + osm_dr_path_t dr_path; + + OSM_LOG_ENTER(p_log); + + p_smp = (ib_smp_t *) p_mad; + + if (p_smp->mgmt_class != IB_MCLASS_SUBN_DIR) + /* This is a lid route mad. Don't drop it */ + goto Exit; + + osm_dr_path_init(&dr_path, 0, /* The h_bind is not really important for us to save */ + p_smp->hop_count, p_smp->initial_path); + + if (__osm_pkt_randomizer_process_path + (p_log, p_pkt_randomizer, &dr_path)) { + /* the mad should be dropped o */ + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "mad TID: 0x%" PRIx64 " is being dropped\n", + cl_ntoh64(p_smp->trans_id)); + res = TRUE; + } + +Exit: + OSM_LOG_EXIT(p_log); + return res; +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_pkt_randomizer_init(IN OUT osm_pkt_randomizer_t ** pp_pkt_randomizer, + IN osm_log_t * p_log) +{ + uint8_t tmp; + ib_api_status_t res = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + *pp_pkt_randomizer = malloc(sizeof(osm_pkt_randomizer_t)); + if (*pp_pkt_randomizer == NULL) { + res = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + memset(*pp_pkt_randomizer, 0, sizeof(osm_pkt_randomizer_t)); + (*pp_pkt_randomizer)->num_paths_initialized = 0; + + tmp = atol(getenv("OSM_PKT_DROP_RATE")); + (*pp_pkt_randomizer)->osm_pkt_drop_rate = tmp; + + if (getenv("OSM_PKT_NUM_UNSTABLE_LINKS") != NULL + && (tmp = atol(getenv("OSM_PKT_NUM_UNSTABLE_LINKS"))) > 0) + (*pp_pkt_randomizer)->osm_pkt_num_unstable_links = tmp; + else + (*pp_pkt_randomizer)->osm_pkt_num_unstable_links = 1; + + if (getenv("OSM_PKT_UNSTABLE_LINK_RATE") != NULL + && (tmp = atol(getenv("OSM_PKT_UNSTABLE_LINK_RATE"))) > 0) + (*pp_pkt_randomizer)->osm_pkt_unstable_link_rate = tmp; + else + (*pp_pkt_randomizer)->osm_pkt_unstable_link_rate = 20; + + OSM_LOG(p_log, OSM_LOG_VERBOSE, "Using OSM_PKT_DROP_RATE=%u \n" + "\t\t\t\t OSM_PKT_NUM_UNSTABLE_LINKS=%u \n" + "\t\t\t\t OSM_PKT_UNSTABLE_LINK_RATE=%u \n", + (*pp_pkt_randomizer)->osm_pkt_drop_rate, + (*pp_pkt_randomizer)->osm_pkt_num_unstable_links, + (*pp_pkt_randomizer)->osm_pkt_unstable_link_rate); + + /* allocate the fault_dr_paths variable */ + /* It is the number of the paths that will be saved as fault = osm_pkt_num_unstable_links */ + (*pp_pkt_randomizer)->fault_dr_paths = malloc(sizeof(osm_dr_path_t) * + (*pp_pkt_randomizer)-> + osm_pkt_num_unstable_links); + if ((*pp_pkt_randomizer)->fault_dr_paths == NULL) { + res = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + + memset((*pp_pkt_randomizer)->fault_dr_paths, 0, + sizeof(osm_dr_path_t) * + (*pp_pkt_randomizer)->osm_pkt_num_unstable_links); + +Exit: + OSM_LOG_EXIT(p_log); + return (res); +} + +/********************************************************************** + **********************************************************************/ +void +osm_pkt_randomizer_destroy(IN OUT osm_pkt_randomizer_t ** pp_pkt_randomizer, + IN osm_log_t * p_log) +{ + OSM_LOG_ENTER(p_log); + + if (*pp_pkt_randomizer != NULL) { + free((*pp_pkt_randomizer)->fault_dr_paths); + free(*pp_pkt_randomizer); + } + OSM_LOG_EXIT(p_log); +} diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_al.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_al.c new file mode 100644 index 000000000000..d5d78c9dab21 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_al.c @@ -0,0 +1,1320 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_req_t. + * This object represents the generic attribute requester. + * This object is part of the opensm family of objects. + * + */ + +/* + Next available error code: 0x300 +*/ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef OSM_VENDOR_INTF_AL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****s* OpenSM: Vendor AL/osm_al_bind_info_t + * NAME + * osm_al_bind_info_t + * + * DESCRIPTION + * Structure containing bind information. + * + * SYNOPSIS + */ +typedef struct _osm_al_bind_info { + osm_vendor_t *p_vend; + void *client_context; + ib_qp_handle_t h_qp; + ib_mad_svc_handle_t h_svc; + uint8_t port_num; + ib_pool_key_t pool_key; + osm_vend_mad_recv_callback_t rcv_callback; + osm_vend_mad_send_err_callback_t send_err_callback; + osm_mad_pool_t *p_osm_pool; + ib_av_handle_t h_dr_av; + +} osm_al_bind_info_t; +/* + * FIELDS + * p_vend + * Pointer to the vendor object. + * + * client_context + * User's context passed during osm_bind + * + * h_qp + * Handle the QP for this bind. + * + * h_qp_svc + * Handle the QP mad service for this bind. + * + * port_num + * Port number (within the HCA) of the bound port. + * + * pool_key + * Pool key returned by all for this QP. + * + * h_dr_av + * Address vector handle used for all directed route SMPs. + * + * SEE ALSO + *********/ + +/********************************************************************** + **********************************************************************/ +inline static ib_api_status_t +__osm_al_convert_wcs(IN ib_wc_status_t const wc_status) +{ + switch (wc_status) { + case IB_WCS_SUCCESS: + return (IB_SUCCESS); + + case IB_WCS_TIMEOUT_RETRY_ERR: + return (IB_TIMEOUT); + + default: + return (IB_ERROR); + } +} + +/********************************************************************** + **********************************************************************/ +static void __osm_al_ca_err_callback(IN ib_async_event_rec_t * p_async_rec) +{ + osm_vendor_t *p_vend = (osm_vendor_t *) p_async_rec->context; + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_al_ca_err_callback: ERR 3B01: " + "Event on channel adapter (%s).\n", + ib_get_async_event_str(p_async_rec->code)); + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void __osm_al_ca_destroy_callback(IN void *context) +{ + osm_al_bind_info_t *p_bind = (osm_al_bind_info_t *) context; + osm_vendor_t *p_vend = p_bind->p_vend; + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_INFO, + "__osm_al_ca_destroy_callback: " + "Closing local channel adapter.\n"); + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void __osm_al_err_callback(IN ib_async_event_rec_t * p_async_rec) +{ + osm_al_bind_info_t *p_bind = + (osm_al_bind_info_t *) p_async_rec->context; + osm_vendor_t *p_vend = p_bind->p_vend; + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_al_err_callback: ERR 3B02: " + "Error on QP (%s).\n", + ib_get_async_event_str(p_async_rec->code)); + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_al_send_callback(IN void *mad_svc_context, IN ib_mad_element_t * p_elem) +{ + osm_al_bind_info_t *const p_bind = + (osm_al_bind_info_t *) mad_svc_context; + osm_vendor_t *const p_vend = p_bind->p_vend; + osm_madw_t *const p_madw = (osm_madw_t *) p_elem->context1; + osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw); + ib_mad_t *p_mad; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vw); + CL_ASSERT(p_vw->h_av); + + /* + Destroy the address vector as necessary. + */ + if (p_vw->h_av != p_bind->h_dr_av) { + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_al_send_callback: " + "Destroying av handle %p.\n", p_vw->h_av); + } + + ib_destroy_av(p_vw->h_av); + } + + p_mad = ib_get_mad_buf(p_elem); + + if (p_elem->resp_expected) { + /* + If the send was unsuccessful, notify the user + for MADs that were expecting a response. + A NULL mad wrapper parameter is the user's clue + that the transaction turned sour. + + Otherwise, do nothing for successful sends when a + reponse is expected. The mad will be returned to the + pool later. + */ + p_madw->status = __osm_al_convert_wcs(p_elem->status); + if (p_elem->status != IB_WCS_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_al_send_callback: " + "MAD completed with work queue error: %s.\n", + ib_get_wc_status_str(p_elem->status)); + /* + Return any wrappers to the pool that may have been + pre-emptively allocated to handle a receive. + */ + if (p_vw->p_resp_madw) { + osm_mad_pool_put(p_bind->p_osm_pool, + p_vw->p_resp_madw); + p_vw->p_resp_madw = NULL; + } + + p_bind->send_err_callback(p_bind->client_context, + p_madw); + } + } else { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_al_send_callback: " + "Returning MAD to pool, TID = 0x%" PRIx64 ".\n", + cl_ntoh64(p_mad->trans_id)); + osm_mad_pool_put(p_bind->p_osm_pool, p_madw); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_al_rcv_callback(IN void *mad_svc_context, IN ib_mad_element_t * p_elem) +{ + osm_al_bind_info_t *const p_bind = + (osm_al_bind_info_t *) mad_svc_context; + osm_vendor_t *const p_vend = p_bind->p_vend; + osm_madw_t *p_old_madw; + osm_madw_t *p_new_madw; + osm_vend_wrap_t *p_old_vw; + osm_vend_wrap_t *p_new_vw; + ib_mad_t *p_new_mad; + osm_mad_addr_t mad_addr; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_elem->context1 == NULL); + CL_ASSERT(p_elem->context2 == NULL); + + p_new_mad = ib_get_mad_buf(p_elem); + + /* + In preperation for initializing the new mad wrapper, + Initialize the mad_addr structure for the received wire MAD. + */ + mad_addr.dest_lid = p_elem->remote_lid; + mad_addr.path_bits = p_elem->path_bits; + + /* TO DO - figure out which #define to use for the 2.5 Gb rate... */ + mad_addr.static_rate = 0; + + if (p_new_mad->mgmt_class == IB_MCLASS_SUBN_LID || + p_new_mad->mgmt_class == IB_MCLASS_SUBN_DIR) { + mad_addr.addr_type.smi.source_lid = p_elem->remote_lid; + } else { + mad_addr.addr_type.gsi.remote_qp = p_elem->remote_qp; + mad_addr.addr_type.gsi.remote_qkey = p_elem->remote_qkey; + mad_addr.addr_type.gsi.pkey_ix = p_elem->pkey_index; + mad_addr.addr_type.gsi.service_level = p_elem->remote_sl; + mad_addr.addr_type.gsi.global_route = FALSE; + } + + /* + If this MAD is a response to a previous request, + then grab our pre-allocated MAD wrapper. + Otherwise, allocate a new MAD wrapper. + */ + if (ib_mad_is_response(p_new_mad)) { + CL_ASSERT(p_elem->send_context1 != NULL); + CL_ASSERT(p_elem->send_context2 == NULL); + + p_old_madw = (osm_madw_t *) p_elem->send_context1; + p_old_vw = osm_madw_get_vend_ptr(p_old_madw); + p_new_madw = p_old_vw->p_resp_madw; + + CL_ASSERT(p_new_madw); + + osm_madw_init(p_new_madw, p_bind, p_elem->size, &mad_addr); + osm_madw_set_mad(p_new_madw, p_new_mad); + } else { + CL_ASSERT(p_elem->send_context1 == NULL); + CL_ASSERT(p_elem->send_context2 == NULL); + + p_new_madw = osm_mad_pool_get_wrapper(p_bind->p_osm_pool, + p_bind, p_elem->size, + p_new_mad, &mad_addr); + } + + CL_ASSERT(p_new_madw); + p_new_vw = osm_madw_get_vend_ptr(p_new_madw); + + p_new_vw->h_bind = p_bind; + p_new_vw->size = p_elem->size; + p_new_vw->p_elem = p_elem; + p_new_vw->h_av = 0; + p_new_vw->p_resp_madw = NULL; + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_al_rcv_callback: " + "Calling receive callback function %p.\n", + p_bind->rcv_callback); + + p_bind->rcv_callback(p_new_madw, p_bind->client_context, + p_elem->send_context1); + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vendor_init(IN osm_vendor_t * const p_vend, + IN osm_log_t * const p_log, IN const uint32_t timeout) +{ + ib_api_status_t status; + OSM_LOG_ENTER(p_log); + + p_vend->p_log = p_log; + + /* + Open our instance of AL. + */ + status = ib_open_al(&p_vend->h_al); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_init: ERR 3B03: " + "Error opening AL (%s).\n", ib_get_err_str(status)); + + goto Exit; + } + + p_vend->timeout = timeout; + +Exit: + OSM_LOG_EXIT(p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log, + IN const uint32_t timeout) +{ + ib_api_status_t status; + osm_vendor_t *p_vend; + + OSM_LOG_ENTER(p_log); + + p_vend = malloc(sizeof(*p_vend)); + if (p_vend == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_new: ERR 3B04: " + "Unable to allocate vendor object.\n"); + goto Exit; + } + + memset(p_vend, 0, sizeof(*p_vend)); + + status = osm_vendor_init(p_vend, p_log, timeout); + if (status != IB_SUCCESS) { + free(p_vend); + p_vend = NULL; + } + +Exit: + OSM_LOG_EXIT(p_log); + return (p_vend); +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_delete(IN osm_vendor_t ** const pp_vend) +{ + /* TO DO - fill this in */ + ib_close_al((*pp_vend)->h_al); + free(*pp_vend); + *pp_vend = NULL; +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_ca_info_init(IN osm_vendor_t * const p_vend, + IN osm_ca_info_t * const p_ca_info, + IN const ib_net64_t ca_guid) +{ + ib_api_status_t status; + + OSM_LOG_ENTER(p_vend->p_log); + + p_ca_info->guid = ca_guid; + + if (osm_log_is_active(p_vend->p_log, OSM_LOG_VERBOSE)) { + osm_log(p_vend->p_log, OSM_LOG_VERBOSE, + "__osm_ca_info_init: " + "Querying CA 0x%" PRIx64 ".\n", cl_ntoh64(ca_guid)); + } + + status = ib_query_ca_by_guid(p_vend->h_al, ca_guid, NULL, + &p_ca_info->attr_size); + if ((status != IB_INSUFFICIENT_MEMORY) && (status != IB_SUCCESS)) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 3B05: " + "Unexpected status getting CA attributes (%s).\n", + ib_get_err_str(status)); + goto Exit; + } + + CL_ASSERT(p_ca_info->attr_size); + + p_ca_info->p_attr = malloc(p_ca_info->attr_size); + if (p_ca_info->p_attr == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 3B06: " + "Unable to allocate attribute storage.\n"); + goto Exit; + } + + status = ib_query_ca_by_guid(p_vend->h_al, ca_guid, p_ca_info->p_attr, + &p_ca_info->attr_size); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 3B07: " + "Unexpected status getting CA attributes (%s).\n", + ib_get_err_str(status)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +void +osm_ca_info_destroy(IN osm_vendor_t * const p_vend, + IN osm_ca_info_t * const p_ca_info) +{ + OSM_LOG_ENTER(p_vend->p_log); + + if (p_ca_info->p_attr) + free(p_ca_info->p_attr); + + free(p_ca_info); + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + **********************************************************************/ +osm_ca_info_t *osm_ca_info_new(IN osm_vendor_t * const p_vend, + IN const ib_net64_t ca_guid) +{ + ib_api_status_t status; + osm_ca_info_t *p_ca_info; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(ca_guid); + + p_ca_info = malloc(sizeof(*p_ca_info)); + if (p_ca_info == NULL) + goto Exit; + + memset(p_ca_info, 0, sizeof(*p_ca_info)); + + status = __osm_ca_info_init(p_vend, p_ca_info, ca_guid); + if (status != IB_SUCCESS) { + osm_ca_info_destroy(p_vend, p_ca_info); + p_ca_info = NULL; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (p_ca_info); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_vendor_get_ca_guids(IN osm_vendor_t * const p_vend, + IN ib_net64_t ** const p_guids, + IN uintn_t * const p_num_guids) +{ + ib_api_status_t status; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_guids); + CL_ASSERT(p_num_guids); + + status = ib_get_ca_guids(p_vend->h_al, NULL, p_num_guids); + if ((status != IB_INSUFFICIENT_MEMORY) && (status != IB_SUCCESS)) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_guids: ERR 3B08: " + "Unexpected status getting CA GUID array (%s).\n", + ib_get_err_str(status)); + goto Exit; + } + + if (*p_num_guids == 0) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_guids: ERR 3B09: " + "No available channel adapters.\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + *p_guids = malloc(*p_num_guids * sizeof(**p_guids)); + if (*p_guids == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_guids: ERR 3B10: " + "Unable to allocate CA GUID array.\n"); + goto Exit; + } + + status = ib_get_ca_guids(p_vend->h_al, *p_guids, p_num_guids); + CL_ASSERT(*p_num_guids); + + if (osm_log_is_active(p_vend->p_log, OSM_LOG_VERBOSE)) { + osm_log(p_vend->p_log, OSM_LOG_VERBOSE, + "__osm_vendor_get_ca_guids: " + "Detected %u local channel adapters.\n", *p_num_guids); + } + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/****f* OpenSM: CA Info/osm_ca_info_get_pi_ptr + * NAME + * osm_ca_info_get_pi_ptr + * + * DESCRIPTION + * Returns a pointer to the port attribute of the specified port + * owned by this CA. + * + * SYNOPSIS + */ +static ib_port_attr_t *__osm_ca_info_get_port_attr_ptr(IN const osm_ca_info_t * + const p_ca_info, + IN const uint8_t index) +{ + return (&p_ca_info->p_attr->p_port_attr[index]); +} + +/* + * PARAMETERS + * p_ca_info + * [in] Pointer to a CA Info object. + * + * index + * [in] Port "index" for which to retrieve the port attribute. + * The index is the offset into the ca's internal array + * of port attributes. + * + * RETURN VALUE + * Returns a pointer to the port attribute of the specified port + * owned by this CA. + * + * NOTES + * + * SEE ALSO + *********/ + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * const p_attr_array, + IN uint32_t * const p_num_ports) +{ + ib_api_status_t status; + + uint32_t ca; + uintn_t ca_count; + uint32_t port_count = 0; + uint8_t port_num; + uint32_t total_ports = 0; + ib_net64_t *p_ca_guid = NULL; + osm_ca_info_t *p_ca_info; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + CL_ASSERT(p_vend->p_ca_info == NULL); + + /* + 1) Determine the number of CA's + 2) Allocate an array big enough to hold the ca info objects. + 3) Call again to retrieve the guids. + */ + status = __osm_vendor_get_ca_guids(p_vend, &p_ca_guid, &ca_count); + + p_vend->p_ca_info = malloc(ca_count * sizeof(*p_vend->p_ca_info)); + if (p_vend->p_ca_info == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 3B11: " + "Unable to allocate CA information array.\n"); + goto Exit; + } + + memset(p_vend->p_ca_info, 0, ca_count * sizeof(*p_vend->p_ca_info)); + p_vend->ca_count = ca_count; + + /* + For each CA, retrieve the port info attributes + */ + for (ca = 0; ca < ca_count; ca++) { + p_ca_info = &p_vend->p_ca_info[ca]; + + status = __osm_ca_info_init(p_vend, p_ca_info, p_ca_guid[ca]); + + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 3B12: " + "Unable to initialize CA Info object (%s).\n", + ib_get_err_str(status)); + } + + total_ports += osm_ca_info_get_num_ports(p_ca_info); + } + + /* + If the user supplied enough storage, return the port guids, + otherwise, return the appropriate error. + */ + if (*p_num_ports >= total_ports) { + for (ca = 0; ca < ca_count; ca++) { + uint32_t num_ports; + + p_ca_info = &p_vend->p_ca_info[ca]; + + num_ports = osm_ca_info_get_num_ports(p_ca_info); + + for (port_num = 0; port_num < num_ports; port_num++) { + p_attr_array[port_count] = + *__osm_ca_info_get_port_attr_ptr(p_ca_info, + port_num); + port_count++; + } + } + } else { + status = IB_INSUFFICIENT_MEMORY; + } + + *p_num_ports = total_ports; + +Exit: + if (p_ca_guid) + free(p_ca_guid); + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_net64_t +osm_vendor_get_ca_guid(IN osm_vendor_t * const p_vend, + IN const ib_net64_t port_guid) +{ + uint8_t index; + uint8_t num_ports; + uint32_t num_guids = 0; + osm_ca_info_t *p_ca_info; + uint32_t ca; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(port_guid); + /* + First, locate the HCA that owns this port. + */ + if (p_vend->p_ca_info == NULL) { + /* + Initialize the osm_ca_info_t array which allows + us to match port GUID to CA. + */ + osm_vendor_get_all_port_attr(p_vend, NULL, &num_guids); + } + + CL_ASSERT(p_vend->p_ca_info); + CL_ASSERT(p_vend->ca_count); + + for (ca = 0; ca < p_vend->ca_count; ca++) { + p_ca_info = &p_vend->p_ca_info[ca]; + + num_ports = osm_ca_info_get_num_ports(p_ca_info); + CL_ASSERT(num_ports); + + for (index = 0; index < num_ports; index++) { + if (port_guid == + osm_ca_info_get_port_guid(p_ca_info, index)) { + OSM_LOG_EXIT(p_vend->p_log); + return (osm_ca_info_get_ca_guid(p_ca_info)); + } + } + } + + /* + No local CA owns this guid! + */ + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_ca_guid: ERR 3B13: " + "Unable to determine CA guid.\n"); + + OSM_LOG_EXIT(p_vend->p_log); + return (0); +} + +/********************************************************************** + **********************************************************************/ +uint8_t +osm_vendor_get_port_num(IN osm_vendor_t * const p_vend, + IN const ib_net64_t port_guid) +{ + uint8_t index; + uint8_t num_ports; + uint32_t num_guids = 0; + osm_ca_info_t *p_ca_info; + uint32_t ca; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(port_guid); + /* + First, locate the HCA that owns this port. + */ + if (p_vend->p_ca_info == NULL) { + /* + Initialize the osm_ca_info_t array which allows + us to match port GUID to CA. + */ + osm_vendor_get_all_port_attr(p_vend, NULL, &num_guids); + } + + CL_ASSERT(p_vend->p_ca_info); + CL_ASSERT(p_vend->ca_count); + + for (ca = 0; ca < p_vend->ca_count; ca++) { + p_ca_info = &p_vend->p_ca_info[ca]; + + num_ports = osm_ca_info_get_num_ports(p_ca_info); + CL_ASSERT(num_ports); + + for (index = 0; index < num_ports; index++) { + if (port_guid == + osm_ca_info_get_port_guid(p_ca_info, index)) { + OSM_LOG_EXIT(p_vend->p_log); + return (osm_ca_info_get_port_num + (p_ca_info, index)); + } + } + } + + /* + No local CA owns this guid! + */ + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_port_num: ERR 3B30: " + "Unable to determine CA guid.\n"); + + OSM_LOG_EXIT(p_vend->p_log); + return (0); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_vendor_open_ca(IN osm_vendor_t * const p_vend, + IN const ib_net64_t port_guid) +{ + ib_net64_t ca_guid; + ib_api_status_t status; + + OSM_LOG_ENTER(p_vend->p_log); + + ca_guid = osm_vendor_get_ca_guid(p_vend, port_guid); + if (ca_guid == 0) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_open_ca: ERR 3B31: " + "Bad port GUID value 0x%" PRIx64 ".\n", + cl_ntoh64(port_guid)); + status = IB_ERROR; + goto Exit; + } + + osm_log(p_vend->p_log, OSM_LOG_VERBOSE, + "__osm_vendor_open_ca: " + "Opening HCA 0x%" PRIx64 ".\n", cl_ntoh64(ca_guid)); + + status = ib_open_ca(p_vend->h_al, + ca_guid, + __osm_al_ca_err_callback, p_vend, &p_vend->h_ca); + + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_open_ca: ERR 3B15: " + "Unable to open CA (%s).\n", ib_get_err_str(status)); + goto Exit; + } + + CL_ASSERT(p_vend->h_ca); + + status = ib_alloc_pd(p_vend->h_ca, IB_PDT_ALIAS, p_vend, &p_vend->h_pd); + + if (status != IB_SUCCESS) { + ib_close_ca(p_vend->h_ca, __osm_al_ca_destroy_callback); + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_open_ca: ERR 3B16: " + "Unable to allocate protection domain (%s).\n", + ib_get_err_str(status)); + goto Exit; + } + + CL_ASSERT(p_vend->h_pd); + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_vendor_init_av(IN const osm_al_bind_info_t * p_bind, + IN ib_av_attr_t * p_av) +{ + memset(p_av, 0, sizeof(*p_av)); + p_av->port_num = p_bind->port_num; + p_av->dlid = IB_LID_PERMISSIVE; +} + +/********************************************************************** + **********************************************************************/ +osm_bind_handle_t +osm_vendor_bind(IN osm_vendor_t * const p_vend, + IN osm_bind_info_t * const p_user_bind, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vend_mad_recv_callback_t mad_recv_callback, + IN osm_vend_mad_send_err_callback_t send_err_callback, + IN void *context) +{ + ib_net64_t port_guid; + osm_al_bind_info_t *p_bind = 0; + ib_api_status_t status; + ib_qp_create_t qp_create; + ib_mad_svc_t mad_svc; + ib_av_attr_t av; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_user_bind); + CL_ASSERT(p_mad_pool); + CL_ASSERT(mad_recv_callback); + CL_ASSERT(send_err_callback); + + port_guid = p_user_bind->port_guid; + + osm_log(p_vend->p_log, OSM_LOG_INFO, + "osm_vendor_bind: " + "Binding to port 0x%" PRIx64 ".\n", cl_ntoh64(port_guid)); + + if (p_vend->h_ca == 0) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_bind: " + "Opening CA that owns port 0x%" PRIx64 ".\n", + port_guid); + + status = __osm_vendor_open_ca(p_vend, port_guid); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 3B17: " + "Unable to Open CA (%s).\n", + ib_get_err_str(status)); + goto Exit; + } + } + + p_bind = malloc(sizeof(*p_bind)); + if (p_bind == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 3B18: " + "Unable to allocate internal bind object.\n"); + goto Exit; + } + + memset(p_bind, 0, sizeof(*p_bind)); + p_bind->p_vend = p_vend; + p_bind->client_context = context; + p_bind->port_num = osm_vendor_get_port_num(p_vend, port_guid); + p_bind->rcv_callback = mad_recv_callback; + p_bind->send_err_callback = send_err_callback; + p_bind->p_osm_pool = p_mad_pool; + + CL_ASSERT(p_bind->port_num); + + /* + Get the proper QP. + */ + memset(&qp_create, 0, sizeof(qp_create)); + + switch (p_user_bind->mad_class) { + case IB_MCLASS_SUBN_LID: + case IB_MCLASS_SUBN_DIR: + qp_create.qp_type = IB_QPT_QP0_ALIAS; + break; + + case IB_MCLASS_SUBN_ADM: + default: + qp_create.qp_type = IB_QPT_QP1_ALIAS; + break; + } + + qp_create.sq_depth = p_user_bind->send_q_size; + qp_create.rq_depth = p_user_bind->recv_q_size; + qp_create.sq_sge = OSM_AL_SQ_SGE; + qp_create.rq_sge = OSM_AL_RQ_SGE; + + status = ib_get_spl_qp(p_vend->h_pd, + port_guid, + &qp_create, + p_bind, + __osm_al_err_callback, + &p_bind->pool_key, &p_bind->h_qp); + + if (status != IB_SUCCESS) { + free(p_bind); + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 3B19: " + "Unable to get QP handle (%s).\n", + ib_get_err_str(status)); + goto Exit; + } + + CL_ASSERT(p_bind->h_qp); + CL_ASSERT(p_bind->pool_key); + + memset(&mad_svc, 0, sizeof(mad_svc)); + + mad_svc.mad_svc_context = p_bind; + mad_svc.pfn_mad_send_cb = __osm_al_send_callback; + mad_svc.pfn_mad_recv_cb = __osm_al_rcv_callback; + mad_svc.mgmt_class = p_user_bind->mad_class; + mad_svc.mgmt_version = p_user_bind->class_version; + mad_svc.support_unsol = p_user_bind->is_responder; + mad_svc.method_array[IB_MAD_METHOD_GET] = TRUE; + mad_svc.method_array[IB_MAD_METHOD_SET] = TRUE; + mad_svc.method_array[IB_MAD_METHOD_DELETE] = TRUE; + mad_svc.method_array[IB_MAD_METHOD_TRAP] = TRUE; + mad_svc.method_array[IB_MAD_METHOD_GETTABLE] = TRUE; + + status = ib_reg_mad_svc(p_bind->h_qp, &mad_svc, &p_bind->h_svc); + + if (status != IB_SUCCESS) { + free(p_bind); + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 3B21: " + "Unable to register QP0 MAD service (%s).\n", + ib_get_err_str(status)); + goto Exit; + } + + __osm_vendor_init_av(p_bind, &av); + + status = ib_create_av(p_vend->h_pd, &av, &p_bind->h_dr_av); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 3B22: " + "Unable to create address vector (%s).\n", + ib_get_err_str(status)); + + goto Exit; + } + + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_bind: " + "Allocating av handle %p.\n", p_bind->h_dr_av); + } + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return ((osm_bind_handle_t) p_bind); +} + +/********************************************************************** + **********************************************************************/ +ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind, + IN const uint32_t mad_size, + IN osm_vend_wrap_t * const p_vw) +{ + ib_mad_t *p_mad; + osm_al_bind_info_t *p_bind = (osm_al_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + ib_api_status_t status; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vw); + + p_vw->size = mad_size; + p_vw->h_bind = h_bind; + + /* + Retrieve a MAD element from the pool and give the user direct + access to its buffer. + */ + status = ib_get_mad(p_bind->pool_key, mad_size, &p_vw->p_elem); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get: ERR 3B25: " + "Unable to acquire MAD (%s).\n", + ib_get_err_str(status)); + + p_mad = NULL; + goto Exit; + } + + CL_ASSERT(p_vw->p_elem); + p_mad = ib_get_mad_buf(p_vw->p_elem); + + if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get: " + "Acquired MAD %p, size = %u.\n", p_mad, mad_size); + } + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (p_mad); +} + +/********************************************************************** + **********************************************************************/ +void +osm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw) +{ + osm_al_bind_info_t *p_bind = (osm_al_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + ib_api_status_t status; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vw); + CL_ASSERT(p_vw->p_elem); + CL_ASSERT(p_vw->h_bind == h_bind); + + if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_put: " + "Retiring MAD %p.\n", ib_get_mad_buf(p_vw->p_elem)); + } + + status = ib_put_mad(p_vw->p_elem); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_put: ERR 3B26: " + "Unable to retire MAD (%s).\n", ib_get_err_str(status)); + } + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vendor_send(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, IN boolean_t const resp_expected) +{ + osm_al_bind_info_t *const p_bind = h_bind; + osm_vendor_t *const p_vend = p_bind->p_vend; + osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw); + osm_mad_addr_t *const p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw); + ib_mad_t *const p_mad = osm_madw_get_mad_ptr(p_madw); + ib_api_status_t status; + ib_mad_element_t *p_elem; + ib_av_attr_t av; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vw->h_bind == h_bind); + CL_ASSERT(p_vw->p_elem); + + p_elem = p_vw->p_elem; + + /* + If a response is expected to this MAD, then preallocate + a mad wrapper to contain the wire MAD received in the + response. Allocating a wrapper here allows for easier + failure paths than after we already received the wire mad. + */ + if (resp_expected) { + p_vw->p_resp_madw = + osm_mad_pool_get_wrapper_raw(p_bind->p_osm_pool); + if (p_vw->p_resp_madw == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_send: ERR 3B27: " + "Unable to allocate MAD wrapper.\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + } else + p_vw->p_resp_madw = NULL; + + /* + For all sends other than directed route SM MADs, + acquire an address vector for the destination. + */ + if (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) { + memset(&av, 0, sizeof(av)); + av.port_num = p_bind->port_num; + av.dlid = p_mad_addr->dest_lid; + av.static_rate = p_mad_addr->static_rate; + av.path_bits = p_mad_addr->path_bits; + + if ((p_mad->mgmt_class != IB_MCLASS_SUBN_LID) && + (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR)) { + av.sl = p_mad_addr->addr_type.gsi.service_level; + + if (p_mad_addr->addr_type.gsi.global_route) { + av.grh_valid = TRUE; + /* ANIL */ + /* av.grh = p_mad_addr->addr_type.gsi.grh_info; */ + } + } + + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_send: " + "av.port_num 0x%X, " + "av.dlid 0x%X, " + "av.static_rate %d, " + "av.path_bits %d.\n", + av.port_num, cl_ntoh16(av.dlid), + av.static_rate, av.path_bits); + } + + status = ib_create_av(p_vend->h_pd, &av, &p_vw->h_av); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_send: ERR 3B28: " + "Unable to create address vector (%s).\n", + ib_get_err_str(status)); + + if (p_vw->p_resp_madw) + osm_mad_pool_put(p_bind->p_osm_pool, + p_vw->p_resp_madw); + goto Exit; + } + + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_send: " + "Allocating av handle %p.\n", p_vw->h_av); + } + } else { + p_vw->h_av = p_bind->h_dr_av; + } + + p_elem->h_av = p_vw->h_av; + + p_elem->context1 = p_madw; + p_elem->context2 = NULL; + + p_elem->immediate_data = 0; + p_elem->p_grh = NULL; + p_elem->resp_expected = resp_expected; + p_elem->retry_cnt = OSM_DEFAULT_RETRY_COUNT; + + p_elem->send_opt = IB_SEND_OPT_SIGNALED; + p_elem->timeout_ms = p_vend->timeout; + + /* Completion information. */ + p_elem->status = 0; /* Not trusting AL */ + + if ((p_mad->mgmt_class == IB_MCLASS_SUBN_LID) || + (p_mad->mgmt_class == IB_MCLASS_SUBN_DIR)) { + p_elem->remote_qp = 0; + p_elem->remote_qkey = 0; + } else { + p_elem->remote_qp = p_mad_addr->addr_type.gsi.remote_qp; + p_elem->remote_qkey = p_mad_addr->addr_type.gsi.remote_qkey; + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_send: " + "remote qp = 0x%X, remote qkey = 0x%X.\n", + cl_ntoh32(p_elem->remote_qp), + cl_ntoh32(p_elem->remote_qkey)); + } + + status = ib_send_mad(p_bind->h_svc, p_elem, NULL); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_send: ERR 3B29: " + "Send failed (%s).\n", ib_get_err_str(status)); + if (p_vw->p_resp_madw) + osm_mad_pool_put(p_bind->p_osm_pool, p_vw->p_resp_madw); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind) +{ + osm_al_bind_info_t *p_bind = (osm_al_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + ib_av_attr_t av; + ib_api_status_t status; + + OSM_LOG_ENTER(p_vend->p_log); + + /* + The only thing we need to do is refresh the directed + route address vector. + */ + __osm_vendor_init_av(p_bind, &av); + + status = ib_destroy_av(p_bind->h_dr_av); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_local_lid_change: ERR 3B32: " + "Unable to destroy address vector (%s).\n", + ib_get_err_str(status)); + + goto Exit; + } + + status = ib_create_av(p_vend->h_pd, &av, &p_bind->h_dr_av); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_local_lid_change: ERR 3B33: " + "Unable to create address vector (%s).\n", + ib_get_err_str(status)); + + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val) +{ + osm_al_bind_info_t *p_bind = (osm_al_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + ib_api_status_t status; + ib_port_attr_mod_t attr_mod; + + OSM_LOG_ENTER(p_vend->p_log); + + memset(&attr_mod, 0, sizeof(attr_mod)); + + attr_mod.cap.sm = is_sm_val; + + status = ib_modify_ca(p_vend->h_ca, p_bind->port_num, + IB_CA_MOD_IS_SM, &attr_mod); + + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_set_sm: ERR 3B34: " + "Unable set 'IS_SM' bit to:%u in port attributes (%s).\n", + is_sm_val, ib_get_err_str(status)); + } + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level) +{ + +} + +#endif /* OSM_VENDOR_INTF_AL */ diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_ibumad.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_ibumad.c new file mode 100644 index 000000000000..734a8602eb2d --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_ibumad.c @@ -0,0 +1,1154 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_vendor_t (for umad). + * This object represents the OpenIB vendor layer. + * This object is part of the opensm family of objects. + * + * Environment: + * Linux User Mode + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef OSM_VENDOR_INTF_OPENIB + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****s* OpenSM: Vendor UMAD/osm_umad_bind_info_t + * NAME + * osm_umad_bind_info_t + * + * DESCRIPTION + * Structure containing bind information. + * + * SYNOPSIS + */ +typedef struct _osm_umad_bind_info { + osm_vendor_t *p_vend; + void *client_context; + osm_mad_pool_t *p_mad_pool; + osm_vend_mad_recv_callback_t mad_recv_callback; + osm_vend_mad_send_err_callback_t send_err_callback; + ib_net64_t port_guid; + int port_id; + int agent_id; + int agent_id1; /* SMI requires two agents */ +} osm_umad_bind_info_t; + +typedef struct _umad_receiver { + pthread_t tid; + osm_vendor_t *p_vend; + osm_log_t *p_log; +} umad_receiver_t; + +static void osm_vendor_close_port(osm_vendor_t * const p_vend); + +static void clear_madw(osm_vendor_t * p_vend) +{ + umad_match_t *m, *e, *old_m; + ib_net64_t old_tid; + + OSM_LOG_ENTER(p_vend->p_log); + pthread_mutex_lock(&p_vend->match_tbl_mutex); + for (m = p_vend->mtbl.tbl, e = m + p_vend->mtbl.max; m < e; m++) { + if (m->tid) { + old_m = m; + old_tid = m->tid; + m->tid = 0; + osm_mad_pool_put(((osm_umad_bind_info_t + *) ((osm_madw_t *) m->v)->h_bind)-> + p_mad_pool, m->v); + pthread_mutex_unlock(&p_vend->match_tbl_mutex); + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5401: " + "evicting entry %p (tid was 0x%" PRIx64 ")\n", + old_m, old_tid); + goto Exit; + } + } + pthread_mutex_unlock(&p_vend->match_tbl_mutex); + +Exit: + OSM_LOG_EXIT(p_vend->p_log); +} + +static osm_madw_t *get_madw(osm_vendor_t * p_vend, ib_net64_t * tid) +{ + umad_match_t *m, *e; + ib_net64_t mtid = (*tid & CL_HTON64(0x00000000ffffffffllu)); + osm_madw_t *res; + + /* + * Since mtid == 0 is the empty key, we should not + * waste time looking for it + */ + if (mtid == 0) + return 0; + + pthread_mutex_lock(&p_vend->match_tbl_mutex); + for (m = p_vend->mtbl.tbl, e = m + p_vend->mtbl.max; m < e; m++) { + if (m->tid == mtid) { + m->tid = 0; + *tid = mtid; + res = m->v; + pthread_mutex_unlock(&p_vend->match_tbl_mutex); + return res; + } + } + + pthread_mutex_unlock(&p_vend->match_tbl_mutex); + return 0; +} + +static void +put_madw(osm_vendor_t * p_vend, osm_madw_t * p_madw, ib_net64_t tid) +{ + umad_match_t *m, *e, *old_lru, *lru = 0; + osm_madw_t *p_req_madw; + osm_umad_bind_info_t *p_bind; + ib_net64_t old_tid; + uint32_t oldest = ~0; + + pthread_mutex_lock(&p_vend->match_tbl_mutex); + for (m = p_vend->mtbl.tbl, e = m + p_vend->mtbl.max; m < e; m++) { + if (m->tid == 0) { + m->tid = tid; + m->v = p_madw; + m->version = + cl_atomic_inc((atomic32_t *) & p_vend->mtbl. + last_version); + pthread_mutex_unlock(&p_vend->match_tbl_mutex); + return; + } + if (oldest > m->version) { + oldest = m->version; + lru = m; + } + } + + old_lru = lru; + old_tid = lru->tid; + p_req_madw = old_lru->v; + p_bind = p_req_madw->h_bind; + p_req_madw->status = IB_CANCELED; + pthread_mutex_lock(&p_vend->cb_mutex); + (*p_bind->send_err_callback) (p_bind->client_context, p_req_madw); + pthread_mutex_unlock(&p_vend->cb_mutex); + lru->tid = tid; + lru->v = p_madw; + lru->version = + cl_atomic_inc((atomic32_t *) & p_vend->mtbl.last_version); + pthread_mutex_unlock(&p_vend->match_tbl_mutex); + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5402: " + "evicting entry %p (tid was 0x%" PRIx64 ")\n", old_lru, + cl_ntoh64(old_tid)); +} + +static void +ib_mad_addr_conv(ib_user_mad_t * umad, osm_mad_addr_t * osm_mad_addr, + int is_smi) +{ + ib_mad_addr_t *ib_mad_addr = umad_get_mad_addr(umad); + osm_mad_addr->dest_lid = ib_mad_addr->lid; + osm_mad_addr->path_bits = ib_mad_addr->path_bits; + osm_mad_addr->static_rate = 0; + + if (is_smi) { + osm_mad_addr->addr_type.smi.source_lid = osm_mad_addr->dest_lid; + osm_mad_addr->addr_type.smi.port_num = 255; /* not used */ + return; + } + + osm_mad_addr->addr_type.gsi.remote_qp = ib_mad_addr->qpn; + osm_mad_addr->addr_type.gsi.remote_qkey = ib_mad_addr->qkey; + osm_mad_addr->addr_type.gsi.pkey_ix = umad_get_pkey(umad); + osm_mad_addr->addr_type.gsi.service_level = ib_mad_addr->sl; + osm_mad_addr->addr_type.gsi.global_route = 0; /* FIXME: handle GRH */ + memset(&osm_mad_addr->addr_type.gsi.grh_info, 0, + sizeof osm_mad_addr->addr_type.gsi.grh_info); +} + +static void *swap_mad_bufs(osm_madw_t * p_madw, void *umad) +{ + void *old; + + old = p_madw->vend_wrap.umad; + p_madw->vend_wrap.umad = umad; + p_madw->p_mad = umad_get_mad(umad); + + return old; +} + +static void unlock_mutex(void *arg) +{ + pthread_mutex_unlock(arg); +} + +static void *umad_receiver(void *p_ptr) +{ + umad_receiver_t *const p_ur = (umad_receiver_t *) p_ptr; + osm_vendor_t *p_vend = p_ur->p_vend; + osm_umad_bind_info_t *p_bind; + ib_mad_addr_t *ib_mad_addr; + osm_mad_addr_t osm_addr; + osm_madw_t *p_madw, *p_req_madw; + ib_mad_t *mad; + void *umad = 0; + int mad_agent, length; + + OSM_LOG_ENTER(p_ur->p_log); + + for (;;) { + if (!umad && + !(umad = umad_alloc(1, umad_size() + MAD_BLOCK_SIZE))) { + OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, "ERR 5403: " + "can't alloc MAD sized umad\n"); + break; + } + + length = MAD_BLOCK_SIZE; + if ((mad_agent = umad_recv(p_vend->umad_port_id, umad, + &length, -1)) < 0) { + if (length <= MAD_BLOCK_SIZE) { + OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, "ERR 5404: " + "recv error on MAD sized umad (%m)\n"); + continue; + } else { + umad_free(umad); + /* Need a larger buffer for RMPP */ + umad = umad_alloc(1, umad_size() + length); + if (!umad) { + OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, + "ERR 5405: " + "can't alloc umad length %d\n", + length); + continue; + } + + if ((mad_agent = umad_recv(p_vend->umad_port_id, + umad, &length, + -1)) < 0) { + OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, + "ERR 5406: " + "recv error on umad length %d (%m)\n", + length); + continue; + } + } + } + + if (mad_agent >= UMAD_CA_MAX_AGENTS || + !(p_bind = p_vend->agents[mad_agent])) { + OSM_LOG(p_ur->p_log, OSM_LOG_ERROR, "ERR 5407: " + "invalid mad agent %d - dropping\n", mad_agent); + continue; + } + + mad = (ib_mad_t *) umad_get_mad(umad); + ib_mad_addr = umad_get_mad_addr(umad); + + ib_mad_addr_conv(umad, &osm_addr, + mad->mgmt_class == IB_MCLASS_SUBN_LID || + mad->mgmt_class == IB_MCLASS_SUBN_DIR); + + if (!(p_madw = osm_mad_pool_get(p_bind->p_mad_pool, + (osm_bind_handle_t) p_bind, + MAX(length, MAD_BLOCK_SIZE), + &osm_addr))) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5408: " + "request for a new madw failed -- dropping packet\n"); + continue; + } + + /* Need to fix up MAD size if short RMPP packet */ + if (length < MAD_BLOCK_SIZE) + p_madw->mad_size = length; + + /* + * Avoid copying by swapping mad buf pointers. + * Do not use umad after this line of code. + */ + umad = swap_mad_bufs(p_madw, umad); + + /* if status != 0 then we are handling recv timeout on send */ + if (umad_status(p_madw->vend_wrap.umad)) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5409: " + "send completed with error" + " (method=0x%X attr=0x%X trans_id=0x%" PRIx64 + ") -- dropping\n", + mad->method, cl_ntoh16(mad->attr_id), + cl_ntoh64(mad->trans_id)); + if (mad->mgmt_class != IB_MCLASS_SUBN_DIR) { + /* LID routed */ + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, + "ERR 5410: class 0x%x LID 0x%x\n", + mad->mgmt_class, + cl_ntoh16(ib_mad_addr->lid)); + } else { + ib_smp_t *smp; + + /* Direct routed SMP */ + smp = (ib_smp_t *) mad; + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, + "ERR 5411: DR SMP Hop Ptr: 0x%X\n", + smp->hop_ptr); + osm_dump_smp_dr_path(p_vend->p_log, smp, + OSM_LOG_ERROR); + } + + if (!(p_req_madw = get_madw(p_vend, &mad->trans_id))) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, + "ERR 5412: " + "Failed to obtain request madw for timed out MAD" + "(method=0x%X attr=0x%X tid=0x%"PRIx64") -- dropping\n", + mad->method, cl_ntoh16(mad->attr_id), + cl_ntoh64(mad->trans_id)); + } else { + p_req_madw->status = IB_TIMEOUT; + /* cb frees req_madw */ + pthread_mutex_lock(&p_vend->cb_mutex); + pthread_cleanup_push(unlock_mutex, + &p_vend->cb_mutex); + (*p_bind->send_err_callback) (p_bind-> + client_context, + p_req_madw); + pthread_cleanup_pop(1); + } + + osm_mad_pool_put(p_bind->p_mad_pool, p_madw); + continue; + } + + p_req_madw = 0; + if (ib_mad_is_response(mad) && + !(p_req_madw = get_madw(p_vend, &mad->trans_id))) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5413: " + "Failed to obtain request madw for received MAD" + "(method=0x%X attr=0x%X tid=0x%"PRIx64") -- dropping\n", + mad->method, cl_ntoh16((mad)->attr_id), + cl_ntoh64(mad->trans_id)); + osm_mad_pool_put(p_bind->p_mad_pool, p_madw); + continue; + } +#ifndef VENDOR_RMPP_SUPPORT + if ((mad->mgmt_class != IB_MCLASS_SUBN_DIR) && + (mad->mgmt_class != IB_MCLASS_SUBN_LID) && + (ib_rmpp_is_flag_set((ib_rmpp_mad_t *) mad, + IB_RMPP_FLAG_ACTIVE))) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5414: " + "class 0x%x method 0x%x RMPP version %d type " + "%d flags 0x%x received -- dropping\n", + mad->mgmt_class, mad->method, + ((ib_rmpp_mad_t *) mad)->rmpp_version, + ((ib_rmpp_mad_t *) mad)->rmpp_type, + ((ib_rmpp_mad_t *) mad)->rmpp_flags); + osm_mad_pool_put(p_bind->p_mad_pool, p_madw); + continue; + } +#endif + + /* call the CB */ + pthread_mutex_lock(&p_vend->cb_mutex); + pthread_cleanup_push(unlock_mutex, &p_vend->cb_mutex); + (*p_bind->mad_recv_callback) (p_madw, p_bind->client_context, + p_req_madw); + pthread_cleanup_pop(1); + } + + OSM_LOG_EXIT(p_vend->p_log); + return NULL; +} + +static int umad_receiver_start(osm_vendor_t * p_vend) +{ + umad_receiver_t *p_ur = p_vend->receiver; + + p_ur->p_vend = p_vend; + p_ur->p_log = p_vend->p_log; + + if (pthread_create(&p_ur->tid, NULL, umad_receiver, p_ur) < 0) + return -1; + + return 0; +} + +static void umad_receiver_stop(umad_receiver_t * p_ur) +{ + pthread_cancel(p_ur->tid); + pthread_join(p_ur->tid, NULL); + p_ur->tid = 0; + p_ur->p_vend = NULL; + p_ur->p_log = NULL; +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vendor_init(IN osm_vendor_t * const p_vend, + IN osm_log_t * const p_log, IN const uint32_t timeout) +{ + char *max = NULL; + int r, n_cas; + + OSM_LOG_ENTER(p_log); + + p_vend->p_log = p_log; + p_vend->timeout = timeout; + p_vend->max_retries = OSM_DEFAULT_RETRY_COUNT; + pthread_mutex_init(&p_vend->cb_mutex, NULL); + pthread_mutex_init(&p_vend->match_tbl_mutex, NULL); + p_vend->umad_port_id = -1; + p_vend->issmfd = -1; + + /* + * Open our instance of UMAD. + */ + if ((r = umad_init()) < 0) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, + "ERR 5415: Error opening UMAD\n"); + } + + if ((n_cas = umad_get_cas_names(p_vend->ca_names, + OSM_UMAD_MAX_CAS)) < 0) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, + "ERR 5416: umad_get_cas_names failed\n"); + r = n_cas; + goto Exit; + } + + p_vend->ca_count = n_cas; + p_vend->mtbl.max = DEFAULT_OSM_UMAD_MAX_PENDING; + + if ((max = getenv("OSM_UMAD_MAX_PENDING")) != NULL) { + int tmp = strtol(max, NULL, 0); + if (tmp > 0) + p_vend->mtbl.max = tmp; + else + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "Error:" + "OSM_UMAD_MAX_PENDING=%d is invalid", + tmp); + } + + OSM_LOG(p_vend->p_log, OSM_LOG_INFO, "%d pending umads specified\n", + p_vend->mtbl.max); + + p_vend->mtbl.tbl = calloc(p_vend->mtbl.max, sizeof(*(p_vend->mtbl.tbl))); + if (!p_vend->mtbl.tbl) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "Error:" + "failed to allocate vendor match table\n"); + r = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_log); + return (r); +} + +/********************************************************************** + **********************************************************************/ +osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log, + IN const uint32_t timeout) +{ + osm_vendor_t *p_vend = NULL; + + OSM_LOG_ENTER(p_log); + + if (!timeout) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 5433: " + "transaction timeout cannot be 0\n"); + goto Exit; + } + + p_vend = malloc(sizeof(*p_vend)); + if (p_vend == NULL) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 5417: " + "Unable to allocate vendor object\n"); + goto Exit; + } + + memset(p_vend, 0, sizeof(*p_vend)); + + if (osm_vendor_init(p_vend, p_log, timeout) < 0) { + free(p_vend); + p_vend = NULL; + } + +Exit: + OSM_LOG_EXIT(p_log); + return (p_vend); +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_delete(IN osm_vendor_t ** const pp_vend) +{ + osm_vendor_close_port(*pp_vend); + + clear_madw(*pp_vend); + /* make sure all ports are closed */ + umad_done(); + + pthread_mutex_destroy(&(*pp_vend)->cb_mutex); + pthread_mutex_destroy(&(*pp_vend)->match_tbl_mutex); + free((*pp_vend)->mtbl.tbl); + free(*pp_vend); + *pp_vend = NULL; +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * const p_attr_array, + IN uint32_t * const p_num_ports) +{ + umad_ca_t ca; + ib_port_attr_t *attr = p_attr_array; + unsigned done = 0; + int r, i, j; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend && p_num_ports); + + if (!*p_num_ports) { + r = IB_INVALID_PARAMETER; + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5418: " + "Ports in should be > 0\n"); + goto Exit; + } + + if (!p_attr_array) { + r = IB_INSUFFICIENT_MEMORY; + *p_num_ports = 0; + goto Exit; + } + + for (i = 0; i < p_vend->ca_count && !done; i++) { + /* + * For each CA, retrieve the port guids + */ + if (umad_get_ca(p_vend->ca_names[i], &ca) == 0) { + if (ca.node_type < 1 || ca.node_type > 3) + continue; + for (j = 0; j <= ca.numports; j++) { + if (!ca.ports[j]) + continue; + attr->port_guid = ca.ports[j]->port_guid; + attr->lid = ca.ports[j]->base_lid; + attr->port_num = ca.ports[j]->portnum; + attr->sm_lid = ca.ports[j]->sm_lid; + attr->link_state = ca.ports[j]->state; + attr++; + if (attr - p_attr_array > *p_num_ports) { + done = 1; + break; + } + } + umad_release_ca(&ca); + } + } + + *p_num_ports = attr - p_attr_array; + r = 0; + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return r; +} + +/********************************************************************** + **********************************************************************/ +static int +osm_vendor_open_port(IN osm_vendor_t * const p_vend, + IN const ib_net64_t port_guid) +{ + ib_net64_t portguids[OSM_UMAD_MAX_PORTS_PER_CA + 1]; + umad_ca_t umad_ca; + int i = 0, umad_port_id = -1; + char *name; + int ca, r; + + CL_ASSERT(p_vend); + + OSM_LOG_ENTER(p_vend->p_log); + + if (p_vend->umad_port_id >= 0) { + umad_port_id = p_vend->umad_port_id; + goto Exit; + } + + if (!port_guid) { + name = NULL; + i = 0; + goto _found; + } + + for (ca = 0; ca < p_vend->ca_count; ca++) { + if ((r = umad_get_ca_portguids(p_vend->ca_names[ca], + portguids, + OSM_UMAD_MAX_CAS)) < 0) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5421: " + "Unable to get CA %s port guids (%s)\n", + p_vend->ca_names[ca], strerror(r)); + goto Exit; + } + for (i = 0; i < r; i++) + if (port_guid == portguids[i]) { + name = p_vend->ca_names[ca]; + goto _found; + } + } + + /* + * No local CA owns this guid! + */ + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5422: " + "Unable to find requested CA guid 0x%" PRIx64 "\n", + cl_ntoh64(port_guid)); + goto Exit; + +_found: + /* Validate that node is an IB node type (not iWARP) */ + if (umad_get_ca(name, &umad_ca) < 0) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542A: " + "umad_get_ca() failed\n"); + goto Exit; + } + + if (umad_ca.node_type < 1 || umad_ca.node_type > 3) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542D: " + "Type %d of node \'%s\' is not an IB node type\n", + umad_ca.node_type, umad_ca.ca_name); + fprintf(stderr, + "Type %d of node \'%s\' is not an IB node type\n", + umad_ca.node_type, umad_ca.ca_name); + umad_release_ca(&umad_ca); + goto Exit; + } + umad_release_ca(&umad_ca); + + /* Port found, try to open it */ + if (umad_get_port(name, i, &p_vend->umad_port) < 0) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542B: " + "umad_get_port() failed\n"); + goto Exit; + } + + if ((umad_port_id = umad_open_port(p_vend->umad_port.ca_name, + p_vend->umad_port.portnum)) < 0) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542C: " + "umad_open_port() failed\n"); + goto Exit; + } + + p_vend->umad_port_id = umad_port_id; + + /* start receiver thread */ + if (!(p_vend->receiver = calloc(1, sizeof(umad_receiver_t)))) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5423: " + "Unable to alloc receiver struct\n"); + umad_close_port(umad_port_id); + umad_release_port(&p_vend->umad_port); + p_vend->umad_port.port_guid = 0; + p_vend->umad_port_id = umad_port_id = -1; + goto Exit; + } + if (umad_receiver_start(p_vend) != 0) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5420: " + "umad_receiver_init failed\n"); + umad_close_port(umad_port_id); + umad_release_port(&p_vend->umad_port); + p_vend->umad_port.port_guid = 0; + p_vend->umad_port_id = umad_port_id = -1; + } + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return umad_port_id; +} + +static void osm_vendor_close_port(osm_vendor_t * const p_vend) +{ + umad_receiver_t *p_ur; + int i; + + p_ur = p_vend->receiver; + p_vend->receiver = NULL; + if (p_ur) { + umad_receiver_stop(p_ur); + free(p_ur); + } + + if (p_vend->umad_port_id >= 0) { + for (i = 0; i < UMAD_CA_MAX_AGENTS; i++) + if (p_vend->agents[i]) + umad_unregister(p_vend->umad_port_id, i); + umad_close_port(p_vend->umad_port_id); + umad_release_port(&p_vend->umad_port); + p_vend->umad_port.port_guid = 0; + p_vend->umad_port_id = -1; + } +} + +static int set_bit(int nr, void *method_mask) +{ + long mask, *addr = method_mask; + int retval; + + addr += nr / (8 * sizeof(long)); + mask = 1L << (nr % (8 * sizeof(long))); + retval = (mask & *addr) != 0; + *addr |= mask; + return retval; +} + +/********************************************************************** + **********************************************************************/ +osm_bind_handle_t +osm_vendor_bind(IN osm_vendor_t * const p_vend, + IN osm_bind_info_t * const p_user_bind, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vend_mad_recv_callback_t mad_recv_callback, + IN osm_vend_mad_send_err_callback_t send_err_callback, + IN void *context) +{ + ib_net64_t port_guid; + osm_umad_bind_info_t *p_bind = 0; + long method_mask[16 / sizeof(long)]; + int umad_port_id; + uint8_t rmpp_version; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_user_bind); + CL_ASSERT(p_mad_pool); + CL_ASSERT(mad_recv_callback); + CL_ASSERT(send_err_callback); + + port_guid = p_user_bind->port_guid; + + OSM_LOG(p_vend->p_log, OSM_LOG_INFO, + "Binding to port 0x%" PRIx64 "\n", cl_ntoh64(port_guid)); + + if ((umad_port_id = osm_vendor_open_port(p_vend, port_guid)) < 0) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5424: " + "Unable to open port 0x%" PRIx64 "\n", + cl_ntoh64(port_guid)); + goto Exit; + } + + if (umad_get_issm_path(p_vend->umad_port.ca_name, + p_vend->umad_port.portnum, + p_vend->issm_path, + sizeof(p_vend->issm_path)) < 0) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 542E: " + "Cannot resolve issm path for port %s:%u\n", + p_vend->umad_port.ca_name, p_vend->umad_port.portnum); + goto Exit; + } + + if (!(p_bind = malloc(sizeof(*p_bind)))) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5425: " + "Unable to allocate internal bind object\n"); + goto Exit; + } + + memset(p_bind, 0, sizeof(*p_bind)); + p_bind->p_vend = p_vend; + p_bind->port_id = umad_port_id; + p_bind->client_context = context; + p_bind->mad_recv_callback = mad_recv_callback; + p_bind->send_err_callback = send_err_callback; + p_bind->p_mad_pool = p_mad_pool; + p_bind->port_guid = port_guid; + + memset(method_mask, 0, sizeof method_mask); + if (p_user_bind->is_responder) { + set_bit(IB_MAD_METHOD_GET, &method_mask); + set_bit(IB_MAD_METHOD_SET, &method_mask); + if (p_user_bind->mad_class == IB_MCLASS_SUBN_ADM) { + set_bit(IB_MAD_METHOD_GETTABLE, &method_mask); + set_bit(IB_MAD_METHOD_DELETE, &method_mask); +#ifdef DUAL_SIDED_RMPP + set_bit(IB_MAD_METHOD_GETMULTI, &method_mask); +#endif + /* Add in IB_MAD_METHOD_GETTRACETABLE */ + /* when supported by OpenSM */ + } + } + if (p_user_bind->is_report_processor) + set_bit(IB_MAD_METHOD_REPORT, &method_mask); + if (p_user_bind->is_trap_processor) { + set_bit(IB_MAD_METHOD_TRAP, &method_mask); + set_bit(IB_MAD_METHOD_TRAP_REPRESS, &method_mask); + } +#ifndef VENDOR_RMPP_SUPPORT + rmpp_version = 0; +#else + /* If SA class, set rmpp_version */ + if (p_user_bind->mad_class == IB_MCLASS_SUBN_ADM) + rmpp_version = 1; + else + rmpp_version = 0; +#endif + + if ((p_bind->agent_id = umad_register(p_vend->umad_port_id, + p_user_bind->mad_class, + p_user_bind->class_version, + rmpp_version, method_mask)) < 0) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5426: " + "Unable to register class %u version %u\n", + p_user_bind->mad_class, p_user_bind->class_version); + free(p_bind); + p_bind = 0; + goto Exit; + } + + if (p_bind->agent_id >= UMAD_CA_MAX_AGENTS || + p_vend->agents[p_bind->agent_id]) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5427: " + "bad agent id %u or duplicate agent for class %u vers %u\n", + p_bind->agent_id, p_user_bind->mad_class, + p_user_bind->class_version); + free(p_bind); + p_bind = 0; + goto Exit; + } + + p_vend->agents[p_bind->agent_id] = p_bind; + + /* If Subn Directed Route class, register Subn LID routed class */ + if (p_user_bind->mad_class == IB_MCLASS_SUBN_DIR) { + if ((p_bind->agent_id1 = umad_register(p_vend->umad_port_id, + IB_MCLASS_SUBN_LID, + p_user_bind-> + class_version, 0, + method_mask)) < 0) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5428: " + "Unable to register class 1 version %u\n", + p_user_bind->class_version); + free(p_bind); + p_bind = 0; + goto Exit; + } + + if (p_bind->agent_id1 >= UMAD_CA_MAX_AGENTS || + p_vend->agents[p_bind->agent_id1]) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5429: " + "bad agent id %u or duplicate agent for class 1 vers %u\n", + p_bind->agent_id1, p_user_bind->class_version); + free(p_bind); + p_bind = 0; + goto Exit; + } + + p_vend->agents[p_bind->agent_id1] = p_bind; + } + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return ((osm_bind_handle_t) p_bind); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_vendor_recv_dummy_cb(IN osm_madw_t * p_madw, + IN void *bind_context, IN osm_madw_t * p_req_madw) +{ +#ifdef _DEBUG_ + fprintf(stderr, + "__osm_vendor_recv_dummy_cb: Ignoring received MAD after osm_vendor_unbind\n"); +#endif +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_vendor_send_err_dummy_cb(IN void *bind_context, + IN osm_madw_t * p_req_madw) +{ +#ifdef _DEBUG_ + fprintf(stderr, + "__osm_vendor_send_err_dummy_cb: Ignoring send error after osm_vendor_unbind\n"); +#endif +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_unbind(IN osm_bind_handle_t h_bind) +{ + osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + + OSM_LOG_ENTER(p_vend->p_log); + + pthread_mutex_lock(&p_vend->cb_mutex); + p_bind->mad_recv_callback = __osm_vendor_recv_dummy_cb; + p_bind->send_err_callback = __osm_vendor_send_err_dummy_cb; + pthread_mutex_unlock(&p_vend->cb_mutex); + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + **********************************************************************/ +ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind, + IN const uint32_t mad_size, + IN osm_vend_wrap_t * const p_vw) +{ + osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + + OSM_LOG_ENTER(p_vend->p_log); + + OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG, + "Acquiring UMAD for p_madw = %p, size = %u\n", p_vw, mad_size); + CL_ASSERT(p_vw); + p_vw->size = mad_size; + p_vw->umad = umad_alloc(1, mad_size + umad_size()); + + /* track locally */ + p_vw->h_bind = h_bind; + + OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG, + "Acquired UMAD %p, size = %u\n", p_vw->umad, p_vw->size); + + OSM_LOG_EXIT(p_vend->p_log); + return umad_get_mad(p_vw->umad); +} + +/********************************************************************** + **********************************************************************/ +void +osm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw) +{ + osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + osm_madw_t *p_madw; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vw); + + OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG, "Retiring UMAD %p\n", p_vw->umad); + + /* + * We moved the removal of the transaction to immediately after + * it was looked up. + */ + + /* free the mad but the wrapper is part of the madw object */ + umad_free(p_vw->umad); + p_vw->umad = 0; + p_madw = PARENT_STRUCT(p_vw, osm_madw_t, vend_wrap); + p_madw->p_mad = NULL; + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vendor_send(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, IN boolean_t const resp_expected) +{ + osm_umad_bind_info_t *const p_bind = h_bind; + osm_vendor_t *const p_vend = p_bind->p_vend; + osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw); + osm_mad_addr_t *const p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw); + ib_mad_t *const p_mad = osm_madw_get_mad_ptr(p_madw); + ib_sa_mad_t *const p_sa = (ib_sa_mad_t *) p_mad; + int ret = -1; + int is_rmpp = 0; + uint32_t sent_mad_size; +#ifndef VENDOR_RMPP_SUPPORT + uint32_t paylen = 0; +#endif + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vw->h_bind == h_bind); + CL_ASSERT(p_mad == umad_get_mad(p_vw->umad)); + + if (p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) { + umad_set_addr_net(p_vw->umad, 0xffff, 0, 0, 0); + umad_set_grh(p_vw->umad, 0); + goto Resp; + } + if (p_mad->mgmt_class == IB_MCLASS_SUBN_LID) { + umad_set_addr_net(p_vw->umad, p_mad_addr->dest_lid, 0, 0, 0); + umad_set_grh(p_vw->umad, 0); + goto Resp; + } + /* GSI classes */ + umad_set_addr_net(p_vw->umad, p_mad_addr->dest_lid, + p_mad_addr->addr_type.gsi.remote_qp, + p_mad_addr->addr_type.gsi.service_level, + IB_QP1_WELL_KNOWN_Q_KEY); + umad_set_grh(p_vw->umad, 0); /* FIXME: GRH support */ + umad_set_pkey(p_vw->umad, p_mad_addr->addr_type.gsi.pkey_ix); + if (ib_class_is_rmpp(p_mad->mgmt_class)) { /* RMPP GSI classes FIXME: no GRH */ + if (!ib_rmpp_is_flag_set((ib_rmpp_mad_t *) p_sa, + IB_RMPP_FLAG_ACTIVE)) { + /* Clear RMPP header when RMPP not ACTIVE */ + p_sa->rmpp_version = 0; + p_sa->rmpp_type = 0; + p_sa->rmpp_flags = 0; + p_sa->rmpp_status = 0; +#ifdef VENDOR_RMPP_SUPPORT + } else + is_rmpp = 1; + OSM_LOG(p_vend->p_log, OSM_LOG_VERBOSE, "RMPP %d length %d\n", + ib_rmpp_is_flag_set((ib_rmpp_mad_t *) p_sa, + IB_RMPP_FLAG_ACTIVE), + p_madw->mad_size); +#else + } else { + p_sa->rmpp_version = 1; + p_sa->seg_num = cl_ntoh32(1); /* first DATA is seg 1 */ + p_sa->rmpp_flags |= (uint8_t) 0x70; /* RRespTime of 14 (high 5 bits) */ + p_sa->rmpp_status = 0; + paylen = p_madw->mad_size - IB_SA_MAD_HDR_SIZE; + paylen += (IB_SA_MAD_HDR_SIZE - MAD_RMPP_HDR_SIZE); + p_sa->paylen_newwin = cl_ntoh32(paylen); + } +#endif + } + +Resp: + if (resp_expected) + put_madw(p_vend, p_madw, p_mad->trans_id); + +#ifdef VENDOR_RMPP_SUPPORT + sent_mad_size = p_madw->mad_size; +#else + sent_mad_size = is_rmpp ? p_madw->mad_size - IB_SA_MAD_HDR_SIZE : + p_madw->mad_size; +#endif + if ((ret = umad_send(p_bind->port_id, p_bind->agent_id, p_vw->umad, + sent_mad_size, + resp_expected ? p_vend->timeout : 0, + p_vend->max_retries)) < 0) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5430: " + "Send p_madw = %p of size %d failed %d (%m)\n", + p_madw, sent_mad_size, ret); + if (resp_expected) { + get_madw(p_vend, &p_mad->trans_id); /* remove from aging table */ + p_madw->status = IB_ERROR; + pthread_mutex_lock(&p_vend->cb_mutex); + (*p_bind->send_err_callback) (p_bind->client_context, p_madw); /* cb frees madw */ + pthread_mutex_unlock(&p_vend->cb_mutex); + } else + osm_mad_pool_put(p_bind->p_mad_pool, p_madw); + goto Exit; + } + + if (!resp_expected) + osm_mad_pool_put(p_bind->p_mad_pool, p_madw); + + OSM_LOG(p_vend->p_log, OSM_LOG_DEBUG, "Completed sending %s p_madw = %p\n", + resp_expected ? "request" : "response or unsolicited", p_madw); +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (ret); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind) +{ + osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + + OSM_LOG_ENTER(p_vend->p_log); + ; + OSM_LOG_EXIT(p_vend->p_log); + return (0); +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val) +{ + osm_umad_bind_info_t *p_bind = (osm_umad_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + + OSM_LOG_ENTER(p_vend->p_log); + if (TRUE == is_sm_val) { + p_vend->issmfd = open(p_vend->issm_path, O_NONBLOCK); + if (p_vend->issmfd < 0) { + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5431: " + "setting IS_SM capmask: cannot open file " + "\'%s\': %s\n", + p_vend->issm_path, strerror(errno)); + p_vend->issmfd = -1; + } + } else if (p_vend->issmfd != -1) { + if (0 != close(p_vend->issmfd)) + OSM_LOG(p_vend->p_log, OSM_LOG_ERROR, "ERR 5432: " + "clearing IS_SM capmask: cannot close: %s\n", + strerror(errno)); + p_vend->issmfd = -1; + } + OSM_LOG_EXIT(p_vend->p_log); +} + +void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level) +{ + umad_debug(level); +} + +#endif /* OSM_VENDOR_INTF_OPENIB */ diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_ibumad_sa.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_ibumad_sa.c new file mode 100644 index 000000000000..800b30894031 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_ibumad_sa.c @@ -0,0 +1,736 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +/***************************************************************************** + *****************************************************************************/ + +/* this struct is the internal rep of the bind handle */ +typedef struct _osmv_sa_bind_info { + osm_bind_handle_t h_bind; + osm_log_t *p_log; + osm_vendor_t *p_vendor; + osm_mad_pool_t *p_mad_pool; + cl_event_t sync_event; + time_t last_lids_update_sec; +} osmv_sa_bind_info_t; + +/***************************************************************************** + *****************************************************************************/ + +/* + Call back on new mad received: + + We basically only need to set the context of the query. + Or report an error. + + A pointer to the actual context of the request (a copy of the oriignal + request structure) is attached as the p_madw->context.ni_context.node_guid +*/ +static void +__osmv_sa_mad_rcv_cb(IN osm_madw_t * p_madw, + IN void *bind_context, IN osm_madw_t * p_req_madw) +{ + osmv_sa_bind_info_t *p_bind = (osmv_sa_bind_info_t *) bind_context; + osmv_query_req_t *p_query_req_copy = NULL; + osmv_query_res_t query_res; + ib_sa_mad_t *p_sa_mad; + ib_net16_t mad_status; + + OSM_LOG_ENTER(p_bind->p_log); + + if (!p_req_madw) { + OSM_LOG(p_bind->p_log, OSM_LOG_DEBUG, + "Ignoring a non-response mad\n"); + osm_mad_pool_put(p_bind->p_mad_pool, p_madw); + goto Exit; + } + + /* obtain the sent context since we store it during send in the ni_ctx */ + p_query_req_copy = + (osmv_query_req_t *) (long *)(long)(p_req_madw->context.ni_context. + node_guid); + + /* provide the context of the original request in the result */ + query_res.query_context = p_query_req_copy->query_context; + + /* provide the resulting madw */ + query_res.p_result_madw = p_madw; + + /* update the req fields */ + p_sa_mad = (ib_sa_mad_t *) p_madw->p_mad; + + /* if we got a remote error track it in the status */ + mad_status = (ib_net16_t) (p_sa_mad->status & IB_SMP_STATUS_MASK); + if (mad_status != IB_SUCCESS) { + OSM_LOG(p_bind->p_log, OSM_LOG_ERROR, "ERR 5501: " + "Remote error:0x%04X\n", cl_ntoh16(mad_status)); + query_res.status = IB_REMOTE_ERROR; + } else + query_res.status = IB_SUCCESS; + + /* what if we have got back an empty mad ? */ + if (!p_madw->mad_size) { + OSM_LOG(p_bind->p_log, OSM_LOG_ERROR, "ERR 5502: " + "Got an empty mad\n"); + query_res.status = IB_ERROR; + } + + if (IB_SUCCESS == mad_status) { + + /* if we are in not in a method response of an rmpp nature we must get only 1 */ + /* HACK: in the future we might need to be smarter for other methods... */ + if (p_sa_mad->method != IB_MAD_METHOD_GETTABLE_RESP) { + query_res.result_cnt = 1; + } else { +#ifndef VENDOR_RMPP_SUPPORT + if (mad_status != IB_SUCCESS) + query_res.result_cnt = 0; + else + query_res.result_cnt = 1; +#else + if (ib_get_attr_size(p_sa_mad->attr_offset)) { + /* we used the offset value to calculate the + number of records in here */ + query_res.result_cnt = (uintn_t) + ((p_madw->mad_size - IB_SA_MAD_HDR_SIZE) / + ib_get_attr_size(p_sa_mad->attr_offset)); + OSM_LOG(p_bind->p_log, OSM_LOG_DEBUG, + "Count = %u = %zu / %u (%zu)\n", + query_res.result_cnt, + p_madw->mad_size - IB_SA_MAD_HDR_SIZE, + ib_get_attr_size(p_sa_mad->attr_offset), + (p_madw->mad_size - + IB_SA_MAD_HDR_SIZE) % + ib_get_attr_size(p_sa_mad->attr_offset)); + } else + query_res.result_cnt = 0; +#endif + } + } + + query_res.query_type = p_query_req_copy->query_type; + + p_query_req_copy->pfn_query_cb(&query_res); + + if ((p_query_req_copy->flags & OSM_SA_FLAGS_SYNC) == OSM_SA_FLAGS_SYNC) + cl_event_signal(&p_bind->sync_event); + +Exit: + + /* free the copied query request if found */ + if (p_query_req_copy) + free(p_query_req_copy); + + /* put back the request madw */ + if (p_req_madw) + osm_mad_pool_put(p_bind->p_mad_pool, p_req_madw); + + OSM_LOG_EXIT(p_bind->p_log); +} + +/***************************************************************************** + ****************************************************************************/ +/* + Send Error Callback: + + Only report the error and get rid of the mad wrapper +*/ +static void __osmv_sa_mad_err_cb(IN void *bind_context, IN osm_madw_t * p_madw) +{ + osmv_sa_bind_info_t *p_bind = (osmv_sa_bind_info_t *) bind_context; + osmv_query_req_t *p_query_req_copy = NULL; + osmv_query_res_t query_res; + + OSM_LOG_ENTER(p_bind->p_log); + + /* Obtain the sent context etc */ + p_query_req_copy = + (osmv_query_req_t *) (long *)(long)(p_madw->context.ni_context. + node_guid); + + /* provide the context of the original request in the result */ + query_res.query_context = p_query_req_copy->query_context; + + query_res.p_result_madw = p_madw; + + query_res.status = IB_TIMEOUT; + query_res.result_cnt = 0; + + query_res.query_type = p_query_req_copy->query_type; + + p_query_req_copy->pfn_query_cb(&query_res); + + if ((p_query_req_copy->flags & OSM_SA_FLAGS_SYNC) == OSM_SA_FLAGS_SYNC) + cl_event_signal(&p_bind->sync_event); + + if (p_query_req_copy) + free(p_query_req_copy); + OSM_LOG_EXIT(p_bind->p_log); +} + +/***************************************************************************** + Update lids of vendor umad_port. + *****************************************************************************/ +static ib_api_status_t update_umad_port(osm_vendor_t * p_vend) +{ + umad_port_t port; + if (umad_get_port(p_vend->umad_port.ca_name, + p_vend->umad_port.portnum, &port) < 0) + return IB_ERROR; + p_vend->umad_port.base_lid = port.base_lid; + p_vend->umad_port.sm_lid = port.sm_lid; + umad_release_port(&port); + return IB_SUCCESS; +} + +/***************************************************************************** + *****************************************************************************/ +osm_bind_handle_t +osmv_bind_sa(IN osm_vendor_t * const p_vend, + IN osm_mad_pool_t * const p_mad_pool, IN ib_net64_t port_guid) +{ + osm_bind_info_t bind_info; + osm_log_t *p_log = p_vend->p_log; + osmv_sa_bind_info_t *p_sa_bind_info; + cl_status_t cl_status; + + OSM_LOG_ENTER(p_log); + + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Binding to port 0x%" PRIx64 "\n", cl_ntoh64(port_guid)); + + bind_info.port_guid = port_guid; + bind_info.mad_class = IB_MCLASS_SUBN_ADM; + bind_info.class_version = 2; + bind_info.is_responder = FALSE; + bind_info.is_trap_processor = FALSE; + bind_info.is_report_processor = FALSE; + bind_info.send_q_size = OSM_SM_DEFAULT_QP1_RCV_SIZE; + bind_info.recv_q_size = OSM_SM_DEFAULT_QP1_SEND_SIZE; + + /* allocate the new sa bind info */ + p_sa_bind_info = + (osmv_sa_bind_info_t *) malloc(sizeof(osmv_sa_bind_info_t)); + if (!p_sa_bind_info) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 5505: " + "Failed to allocate new bind structure\n"); + p_sa_bind_info = OSM_BIND_INVALID_HANDLE; + goto Exit; + } + + /* store some important context */ + p_sa_bind_info->p_log = p_log; + p_sa_bind_info->p_mad_pool = p_mad_pool; + p_sa_bind_info->p_vendor = p_vend; + + /* Bind to the lower level */ + p_sa_bind_info->h_bind = osm_vendor_bind(p_vend, &bind_info, p_mad_pool, __osmv_sa_mad_rcv_cb, __osmv_sa_mad_err_cb, p_sa_bind_info); /* context provided to CBs */ + + if (p_sa_bind_info->h_bind == OSM_BIND_INVALID_HANDLE) { + free(p_sa_bind_info); + p_sa_bind_info = OSM_BIND_INVALID_HANDLE; + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 5506: " + "Failed to bind to vendor GSI\n"); + goto Exit; + } + + /* update time umad_port is initilized now */ + p_sa_bind_info->last_lids_update_sec = time(NULL); + + /* initialize the sync_event */ + cl_event_construct(&p_sa_bind_info->sync_event); + cl_status = cl_event_init(&p_sa_bind_info->sync_event, TRUE); + if (cl_status != CL_SUCCESS) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 5508: " + "cl_init_event failed: %s\n", ib_get_err_str(cl_status)); + free(p_sa_bind_info); + p_sa_bind_info = OSM_BIND_INVALID_HANDLE; + } + +Exit: + OSM_LOG_EXIT(p_log); + return (p_sa_bind_info); +} + +/***************************************************************************** + *****************************************************************************/ + +/****t* OSM Vendor SA Client/osmv_sa_mad_data + * NAME + * osmv_sa_mad_data + * + * DESCRIPTION + * Extra fields required to perform a mad query + * This struct is passed to the actual send method + * + * SYNOPSIS + */ +typedef struct _osmv_sa_mad_data { + /* MAD data. */ + uint8_t method; + ib_net16_t attr_id; + ib_net16_t attr_offset; + ib_net32_t attr_mod; + ib_net64_t comp_mask; + void *p_attr; +} osmv_sa_mad_data_t; +/* + * method + * The method of the mad to be sent + * + * attr_id + * Attribute ID + * + * attr_offset + * Offset as defined by RMPP + * + * attr_mod + * Attribute modifier + * + * comp_mask + * The component mask of the query + * + * p_attr + * A pointer to the record of the attribute to be sent. + * + *****/ + +/***************************************************************************** + *****************************************************************************/ +/* Send a MAD out on the GSI interface */ +static ib_api_status_t +__osmv_send_sa_req(IN osmv_sa_bind_info_t * p_bind, + IN const osmv_sa_mad_data_t * const p_sa_mad_data, + IN const osmv_query_req_t * const p_query_req) +{ + ib_api_status_t status; + ib_mad_t *p_mad_hdr; + ib_sa_mad_t *p_sa_mad; + osm_madw_t *p_madw; + osm_log_t *p_log = p_bind->p_log; + static atomic32_t trans_id; + boolean_t sync; + osmv_query_req_t *p_query_req_copy; + + OSM_LOG_ENTER(p_log); + + /* + since the sm_lid might change we obtain it every send + (actually it is cached in the bind object and refreshed + every 30sec by this proc) + */ + if (time(NULL) > p_bind->last_lids_update_sec + 30) { + status = update_umad_port(p_bind->p_vendor); + if (status != IB_SUCCESS) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 5509: " + "Failed to obtain the SM lid\n"); + goto Exit; + } + p_bind->last_lids_update_sec = time(NULL); + } + + /* Get a MAD wrapper for the send */ + p_madw = osm_mad_pool_get(p_bind->p_mad_pool, + p_bind->h_bind, MAD_BLOCK_SIZE, NULL); + + if (p_madw == NULL) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 5510: " + "Unable to acquire MAD\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* Initialize the Sent MAD: */ + + /* Initialize the MAD buffer for the send operation. */ + p_mad_hdr = osm_madw_get_mad_ptr(p_madw); + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + + /* Get a new transaction Id */ + cl_atomic_inc(&trans_id); + + /* Cleanup the MAD from any residue */ + memset(p_sa_mad, 0, MAD_BLOCK_SIZE); + + /* Initialize the standard MAD header. */ + ib_mad_init_new(p_mad_hdr, /* mad pointer */ + IB_MCLASS_SUBN_ADM, /* class */ + (uint8_t) 2, /* version */ + p_sa_mad_data->method, /* method */ + cl_hton64((uint64_t) trans_id), /* tid */ + p_sa_mad_data->attr_id, /* attr id */ + p_sa_mad_data->attr_mod /* attr mod */); + + /* Set the query information. */ + p_sa_mad->sm_key = p_query_req->sm_key; + p_sa_mad->attr_offset = 0; + p_sa_mad->comp_mask = p_sa_mad_data->comp_mask; +#ifdef DUAL_SIDED_RMPP + if (p_sa_mad->method == IB_MAD_METHOD_GETMULTI) + p_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + if (p_sa_mad->comp_mask) { + memcpy(p_sa_mad->data, p_sa_mad_data->p_attr, + ib_get_attr_size(p_sa_mad_data->attr_offset)); + } + + /* + Provide the address to send to + */ + p_madw->mad_addr.dest_lid = + cl_hton16(p_bind->p_vendor->umad_port.sm_lid); + p_madw->mad_addr.addr_type.smi.source_lid = + cl_hton16(p_bind->p_vendor->umad_port.base_lid); + p_madw->mad_addr.addr_type.gsi.remote_qp = CL_HTON32(1); + p_madw->resp_expected = TRUE; + p_madw->fail_msg = CL_DISP_MSGID_NONE; + + /* + Provide MAD context such that the call back will know what to do. + We have to keep the entire request structure so we know the CB. + Since we can not rely on the client to keep it around until + the response - we duplicate it and will later dispose it (in CB). + To store on the MADW we cast it into what opensm has: + p_madw->context.ni_context.node_guid + */ + p_query_req_copy = malloc(sizeof(*p_query_req_copy)); + *p_query_req_copy = *p_query_req; + p_madw->context.ni_context.node_guid = + (ib_net64_t) (long)p_query_req_copy; + + /* we can support async as well as sync calls */ + sync = ((p_query_req->flags & OSM_SA_FLAGS_SYNC) == OSM_SA_FLAGS_SYNC); + + /* send the mad asynchronously */ + status = osm_vendor_send(osm_madw_get_bind_handle(p_madw), + p_madw, p_madw->resp_expected); + + /* if synchronous - wait on the event */ + if (sync) { + OSM_LOG(p_log, OSM_LOG_DEBUG, "Waiting for async event\n"); + cl_event_wait_on(&p_bind->sync_event, EVENT_NO_TIMEOUT, FALSE); + cl_event_reset(&p_bind->sync_event); + status = p_madw->status; + } + +Exit: + OSM_LOG_EXIT(p_log); + return status; +} + +/***************************************************************************** + *****************************************************************************/ +/* + * Query the SA based on the user's request. + */ +ib_api_status_t +osmv_query_sa(IN osm_bind_handle_t h_bind, + IN const osmv_query_req_t * const p_query_req) +{ + osmv_sa_bind_info_t *p_bind = (osmv_sa_bind_info_t *) h_bind; + osmv_sa_mad_data_t sa_mad_data; + osmv_user_query_t *p_user_query; + ib_service_record_t svc_rec; + ib_node_record_t node_rec; + ib_portinfo_record_t port_info; + ib_path_rec_t path_rec; +#ifdef DUAL_SIDED_RMPP + ib_multipath_rec_t multipath_rec; + osmv_multipath_req_t *p_mpr_req; + int i, j; +#endif + ib_class_port_info_t class_port_info; + osm_log_t *p_log = p_bind->p_log; + ib_api_status_t status; + + OSM_LOG_ENTER(p_log); + + /* Set the request information. */ + sa_mad_data.method = IB_MAD_METHOD_GETTABLE; + sa_mad_data.attr_mod = 0; + + /* Set the MAD attributes and component mask correctly. */ + switch (p_query_req->query_type) { + + case OSMV_QUERY_USER_DEFINED: + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 USER_DEFINED\n"); + p_user_query = (osmv_user_query_t *) p_query_req->p_query_input; + if (p_user_query->method) + sa_mad_data.method = p_user_query->method; + sa_mad_data.attr_offset = p_user_query->attr_offset; + sa_mad_data.attr_id = p_user_query->attr_id; + sa_mad_data.attr_mod = p_user_query->attr_mod; + sa_mad_data.comp_mask = p_user_query->comp_mask; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + case OSMV_QUERY_ALL_SVC_RECS: + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 SVC_REC_BY_NAME\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_service_record_t)); + sa_mad_data.comp_mask = 0; + sa_mad_data.p_attr = &svc_rec; + break; + + case OSMV_QUERY_SVC_REC_BY_NAME: + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 SVC_REC_BY_NAME\n"); + sa_mad_data.method = IB_MAD_METHOD_GET; + sa_mad_data.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + sa_mad_data.comp_mask = IB_SR_COMPMASK_SNAME; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_service_record_t)); + sa_mad_data.p_attr = &svc_rec; + memcpy(svc_rec.service_name, p_query_req->p_query_input, + sizeof(ib_svc_name_t)); + break; + + case OSMV_QUERY_SVC_REC_BY_ID: + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 SVC_REC_BY_ID\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + sa_mad_data.comp_mask = IB_SR_COMPMASK_SID; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_service_record_t)); + sa_mad_data.p_attr = &svc_rec; + svc_rec.service_id = + *(ib_net64_t *) (p_query_req->p_query_input); + break; + + case OSMV_QUERY_CLASS_PORT_INFO: + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 CLASS_PORT_INFO\n"); + sa_mad_data.method = IB_MAD_METHOD_GET; + sa_mad_data.attr_id = IB_MAD_ATTR_CLASS_PORT_INFO; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_class_port_info_t)); + sa_mad_data.comp_mask = 0; + sa_mad_data.p_attr = &class_port_info; + break; + + case OSMV_QUERY_NODE_REC_BY_NODE_GUID: + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 NODE_REC_BY_NODE_GUID\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_NODE_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_node_record_t)); + sa_mad_data.comp_mask = IB_NR_COMPMASK_NODEGUID; + sa_mad_data.p_attr = &node_rec; + node_rec.node_info.node_guid = + *(ib_net64_t *) (p_query_req->p_query_input); + break; + + case OSMV_QUERY_PORT_REC_BY_LID: + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 PORT_REC_BY_LID\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_PORTINFO_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_portinfo_record_t)); + sa_mad_data.comp_mask = IB_PIR_COMPMASK_LID; + sa_mad_data.p_attr = &port_info; + port_info.lid = *(ib_net16_t *) (p_query_req->p_query_input); + break; + + case OSMV_QUERY_PORT_REC_BY_LID_AND_NUM: + sa_mad_data.method = IB_MAD_METHOD_GET; + p_user_query = (osmv_user_query_t *) p_query_req->p_query_input; + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 PORT_REC_BY_LID_AND_NUM\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_PORTINFO_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_portinfo_record_t)); + sa_mad_data.comp_mask = + IB_PIR_COMPMASK_LID | IB_PIR_COMPMASK_PORTNUM; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + case OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK: + sa_mad_data.method = IB_MAD_METHOD_GET; + p_user_query = (osmv_user_query_t *) p_query_req->p_query_input; + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_VLARB_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_vl_arb_table_record_t)); + sa_mad_data.comp_mask = + IB_VLA_COMPMASK_LID | IB_VLA_COMPMASK_OUT_PORT | + IB_VLA_COMPMASK_BLOCK; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + case OSMV_QUERY_SLVL_BY_LID_AND_PORTS: + sa_mad_data.method = IB_MAD_METHOD_GET; + p_user_query = (osmv_user_query_t *) p_query_req->p_query_input; + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_SLVL_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_slvl_table_record_t)); + sa_mad_data.comp_mask = + IB_SLVL_COMPMASK_LID | IB_SLVL_COMPMASK_OUT_PORT | + IB_SLVL_COMPMASK_IN_PORT; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + case OSMV_QUERY_PATH_REC_BY_PORT_GUIDS: + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 PATH_REC_BY_PORT_GUIDS\n"); + memset(&path_rec, 0, sizeof(ib_path_rec_t)); + sa_mad_data.attr_id = IB_MAD_ATTR_PATH_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_path_rec_t)); + sa_mad_data.comp_mask = + (IB_PR_COMPMASK_DGID | IB_PR_COMPMASK_SGID); + sa_mad_data.p_attr = &path_rec; + ib_gid_set_default(&path_rec.dgid, + ((osmv_guid_pair_t *) (p_query_req-> + p_query_input))-> + dest_guid); + ib_gid_set_default(&path_rec.sgid, + ((osmv_guid_pair_t *) (p_query_req-> + p_query_input))-> + src_guid); + break; + + case OSMV_QUERY_PATH_REC_BY_GIDS: + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 PATH_REC_BY_GIDS\n"); + memset(&path_rec, 0, sizeof(ib_path_rec_t)); + sa_mad_data.attr_id = IB_MAD_ATTR_PATH_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_path_rec_t)); + sa_mad_data.comp_mask = + (IB_PR_COMPMASK_DGID | IB_PR_COMPMASK_SGID); + sa_mad_data.p_attr = &path_rec; + memcpy(&path_rec.dgid, + &((osmv_gid_pair_t *) (p_query_req->p_query_input))-> + dest_gid, sizeof(ib_gid_t)); + memcpy(&path_rec.sgid, + &((osmv_gid_pair_t *) (p_query_req->p_query_input))-> + src_gid, sizeof(ib_gid_t)); + break; + + case OSMV_QUERY_PATH_REC_BY_LIDS: + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 PATH_REC_BY_LIDS\n"); + memset(&path_rec, 0, sizeof(ib_path_rec_t)); + sa_mad_data.method = IB_MAD_METHOD_GET; + sa_mad_data.attr_id = IB_MAD_ATTR_PATH_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_path_rec_t)); + sa_mad_data.comp_mask = + (IB_PR_COMPMASK_DLID | IB_PR_COMPMASK_SLID); + sa_mad_data.p_attr = &path_rec; + path_rec.dlid = + ((osmv_lid_pair_t *) (p_query_req->p_query_input))-> + dest_lid; + path_rec.slid = + ((osmv_lid_pair_t *) (p_query_req->p_query_input))->src_lid; + break; + + case OSMV_QUERY_UD_MULTICAST_SET: + sa_mad_data.method = IB_MAD_METHOD_SET; + p_user_query = (osmv_user_query_t *) p_query_req->p_query_input; + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 OSMV_QUERY_UD_MULTICAST_SET\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_member_rec_t)); + sa_mad_data.comp_mask = p_user_query->comp_mask; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + case OSMV_QUERY_UD_MULTICAST_DELETE: + sa_mad_data.method = IB_MAD_METHOD_DELETE; + p_user_query = (osmv_user_query_t *) p_query_req->p_query_input; + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 OSMV_QUERY_UD_MULTICAST_DELETE\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_member_rec_t)); + sa_mad_data.comp_mask = p_user_query->comp_mask; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + +#ifdef DUAL_SIDED_RMPP + case OSMV_QUERY_MULTIPATH_REC: + OSM_LOG(p_log, OSM_LOG_DEBUG, "DBG:001 MULTIPATH_REC\n"); + /* Validate sgid/dgid counts against SA client limit */ + p_mpr_req = (osmv_multipath_req_t *) p_query_req->p_query_input; + if (p_mpr_req->sgid_count + p_mpr_req->dgid_count > + IB_MULTIPATH_MAX_GIDS) { + OSM_LOG(p_log, OSM_LOG_ERROR, "DBG:001 MULTIPATH_REC " + "SGID count %d DGID count %d max count %d\n", + p_mpr_req->sgid_count, p_mpr_req->dgid_count, + IB_MULTIPATH_MAX_GIDS); + CL_ASSERT(0); + return IB_ERROR; + } + memset(&multipath_rec, 0, sizeof(ib_multipath_rec_t)); + sa_mad_data.method = IB_MAD_METHOD_GETMULTI; + sa_mad_data.attr_id = IB_MAD_ATTR_MULTIPATH_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_multipath_rec_t)); + sa_mad_data.p_attr = &multipath_rec; + sa_mad_data.comp_mask = p_mpr_req->comp_mask; + multipath_rec.num_path = p_mpr_req->num_path; + if (p_mpr_req->reversible) + multipath_rec.num_path |= 0x80; + else + multipath_rec.num_path &= ~0x80; + multipath_rec.pkey = p_mpr_req->pkey; + ib_multipath_rec_set_sl(&multipath_rec, p_mpr_req->sl); + ib_multipath_rec_set_qos_class(&multipath_rec, 0); + multipath_rec.independence = p_mpr_req->independence; + multipath_rec.sgid_count = p_mpr_req->sgid_count; + multipath_rec.dgid_count = p_mpr_req->dgid_count; + j = 0; + for (i = 0; i < p_mpr_req->sgid_count; i++, j++) + multipath_rec.gids[j] = p_mpr_req->gids[j]; + for (i = 0; i < p_mpr_req->dgid_count; i++, j++) + multipath_rec.gids[j] = p_mpr_req->gids[j]; + break; +#endif + + default: + OSM_LOG(p_log, OSM_LOG_ERROR, "DBG:001 UNKNOWN\n"); + CL_ASSERT(0); + return IB_ERROR; + } + + status = __osmv_send_sa_req(h_bind, &sa_mad_data, p_query_req); + + OSM_LOG_EXIT(p_log); + return status; +} diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx.c new file mode 100644 index 000000000000..683f56d8151e --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx.c @@ -0,0 +1,770 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * FORWARD REFERENCES + */ +static ib_api_status_t +__osmv_get_send_txn(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, + IN boolean_t is_rmpp, + IN boolean_t resp_expected, OUT osmv_txn_ctx_t ** pp_txn); + +static void __osm_vendor_internal_unbind(osm_bind_handle_t h_bind); + +/* + * NAME osm_vendor_new + * + * DESCRIPTION Create and Initialize the osm_vendor_t Object + */ + +osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log, + IN const uint32_t timeout) +{ + ib_api_status_t status; + osm_vendor_t *p_vend; + + OSM_LOG_ENTER(p_log); + + CL_ASSERT(p_log); + + p_vend = malloc(sizeof(*p_vend)); + if (p_vend != NULL) { + memset(p_vend, 0, sizeof(*p_vend)); + + status = osm_vendor_init(p_vend, p_log, timeout); + if (status != IB_SUCCESS) { + osm_vendor_delete(&p_vend); + } + } else { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_new: ERR 7301: " + "Fail to allocate vendor object.\n"); + } + + OSM_LOG_EXIT(p_log); + return (p_vend); +} + +/* + * NAME osm_vendor_delete + * + * DESCRIPTION Delete all the binds behind the vendor + free the vendor object + */ + +void osm_vendor_delete(IN osm_vendor_t ** const pp_vend) +{ + cl_list_item_t *p_item; + cl_list_obj_t *p_obj; + osm_bind_handle_t bind_h; + osm_log_t *p_log; + + OSM_LOG_ENTER((*pp_vend)->p_log); + p_log = (*pp_vend)->p_log; + + /* go over the bind handles , unbind them and remove from list */ + p_item = cl_qlist_remove_head(&((*pp_vend)->bind_handles)); + while (p_item != cl_qlist_end(&((*pp_vend)->bind_handles))) { + + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + bind_h = (osm_bind_handle_t *) cl_qlist_obj(p_obj); + osm_log(p_log, OSM_LOG_DEBUG, + "osm_vendor_delete: unbinding bind_h:%p \n", bind_h); + + __osm_vendor_internal_unbind(bind_h); + + free(p_obj); + /*removing from list */ + p_item = cl_qlist_remove_head(&((*pp_vend)->bind_handles)); + } + + if (NULL != ((*pp_vend)->p_transport_info)) { + free((*pp_vend)->p_transport_info); + (*pp_vend)->p_transport_info = NULL; + } + + /* remove the packet randomizer object */ + if ((*pp_vend)->run_randomizer == TRUE) + osm_pkt_randomizer_destroy(&((*pp_vend)->p_pkt_randomizer), + p_log); + + free(*pp_vend); + *pp_vend = NULL; + + OSM_LOG_EXIT(p_log); +} + +/* + * NAME osm_vendor_init + * + * DESCRIPTION Initialize the vendor object + */ + +ib_api_status_t +osm_vendor_init(IN osm_vendor_t * const p_vend, + IN osm_log_t * const p_log, IN const uint32_t timeout) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + p_vend->p_transport_info = NULL; + p_vend->p_log = p_log; + p_vend->resp_timeout = timeout; + p_vend->ttime_timeout = timeout * OSMV_TXN_TIMEOUT_FACTOR; + + cl_qlist_init(&p_vend->bind_handles); + + /* update the run_randomizer flag */ + if (getenv("OSM_PKT_DROP_RATE") != NULL + && atol(getenv("OSM_PKT_DROP_RATE")) != 0) { + /* if the OSM_PKT_DROP_RATE global variable is defined to a non-zero value - + then the randomizer should be called. + Need to create the packet randomizer object */ + p_vend->run_randomizer = TRUE; + status = + osm_pkt_randomizer_init(&(p_vend->p_pkt_randomizer), p_log); + if (status != IB_SUCCESS) + return status; + } else { + p_vend->run_randomizer = FALSE; + p_vend->p_pkt_randomizer = NULL; + } + + OSM_LOG_EXIT(p_log); + return (IB_SUCCESS); +} + +/* + * NAME osm_vendor_bind + * + * DESCRIPTION Create a new bind object under the vendor object + */ + +osm_bind_handle_t +osm_vendor_bind(IN osm_vendor_t * const p_vend, + IN osm_bind_info_t * const p_bind_info, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vend_mad_recv_callback_t mad_recv_callback, + IN osm_vend_mad_send_err_callback_t send_err_callback, + IN void *context) +{ + osmv_bind_obj_t *p_bo; + ib_api_status_t status; + char hca_id[32]; + cl_status_t cl_st; + cl_list_obj_t *p_obj; + uint8_t hca_index; + + if (NULL == p_vend || NULL == p_bind_info || NULL == p_mad_pool + || NULL == mad_recv_callback || NULL == send_err_callback) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 7302: " + "NULL parameter passed in: p_vend=%p p_bind_info=%p p_mad_pool=%p recv_cb=%p send_err_cb=%p\n", + p_vend, p_bind_info, p_mad_pool, mad_recv_callback, + send_err_callback); + + return OSM_BIND_INVALID_HANDLE; + } + + p_bo = malloc(sizeof(osmv_bind_obj_t)); + if (NULL == p_bo) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 7303: could not allocate the bind object\n"); + return OSM_BIND_INVALID_HANDLE; + } + + memset(p_bo, 0, sizeof(osmv_bind_obj_t)); + p_bo->p_vendor = p_vend; + p_bo->recv_cb = mad_recv_callback; + p_bo->send_err_cb = send_err_callback; + p_bo->cb_context = context; + p_bo->p_osm_pool = p_mad_pool; + + /* obtain the hca name and port num from the guid */ + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osm_vendor_bind: " + "Finding CA and Port that owns port guid 0x%" PRIx64 ".\n", + cl_ntoh64(p_bind_info->port_guid)); + + status = osm_vendor_get_guid_ca_and_port(p_bo->p_vendor, + p_bind_info->port_guid, + &(p_bo->hca_hndl), + hca_id, + &hca_index, &(p_bo->port_num)); + if (status != IB_SUCCESS) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 7304: " + "Fail to find port number of port guid:0x%016" PRIx64 + "\n", p_bind_info->port_guid); + free(p_bo); + return OSM_BIND_INVALID_HANDLE; + } + + /* Initialize the magic_ptr to the pointer of the p_bo info. + This will be used to signal when the object is being destroyed, so no + real action will be done then. */ + p_bo->magic_ptr = p_bo; + + p_bo->is_closing = FALSE; + + cl_spinlock_construct(&(p_bo->lock)); + cl_st = cl_spinlock_init(&(p_bo->lock)); + if (cl_st != CL_SUCCESS) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 7305: " + "could not initialize the spinlock ...\n"); + free(p_bo); + return OSM_BIND_INVALID_HANDLE; + } + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osm_vendor_bind: osmv_txnmgr_init ... \n"); + if (osmv_txnmgr_init(&p_bo->txn_mgr, p_vend->p_log, &(p_bo->lock)) != + IB_SUCCESS) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 7306: " + "osmv_txnmgr_init failed \n"); + cl_spinlock_destroy(&p_bo->lock); + free(p_bo); + return OSM_BIND_INVALID_HANDLE; + } + + /* Do the real job! (Transport-dependent) */ + if (IB_SUCCESS != + osmv_transport_init(p_bind_info, hca_id, hca_index, p_bo)) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 7307: " + "osmv_transport_init failed \n"); + osmv_txnmgr_done((osm_bind_handle_t) p_bo); + cl_spinlock_destroy(&p_bo->lock); + free(p_bo); + return OSM_BIND_INVALID_HANDLE; + } + + /* insert bind handle into db */ + p_obj = malloc(sizeof(cl_list_obj_t)); + if (NULL == p_obj) { + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 7308: " + "osm_vendor_bind: could not allocate the list object\n"); + + osmv_transport_done(p_bo->p_transp_mgr); + osmv_txnmgr_done((osm_bind_handle_t) p_bo); + cl_spinlock_destroy(&p_bo->lock); + free(p_bo); + return OSM_BIND_INVALID_HANDLE; + } + memset(p_obj, 0, sizeof(cl_list_obj_t)); + cl_qlist_set_obj(p_obj, p_bo); + + cl_qlist_insert_head(&p_vend->bind_handles, &p_obj->list_item); + + return (osm_bind_handle_t) p_bo; +} + +/* + * NAME osm_vendor_unbind + * + * DESCRIPTION Destroy the bind object and remove it from the vendor's list + */ + +void osm_vendor_unbind(IN osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_log_t *p_log = p_bo->p_vendor->p_log; + cl_list_obj_t *p_obj = NULL; + cl_list_item_t *p_item, *p_item_tmp; + cl_qlist_t *const p_bh_list = + (cl_qlist_t * const)&p_bo->p_vendor->bind_handles; + + OSM_LOG_ENTER(p_log); + + /* go over all the items in the list and remove the specific item */ + p_item = cl_qlist_head(p_bh_list); + while (p_item != cl_qlist_end(p_bh_list)) { + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + if (cl_qlist_obj(p_obj) == h_bind) { + break; + } + p_item_tmp = cl_qlist_next(p_item); + p_item = p_item_tmp; + } + + CL_ASSERT(p_item != cl_qlist_end(p_bh_list)); + + cl_qlist_remove_item(p_bh_list, p_item); + if (p_obj) + free(p_obj); + + if (h_bind != 0) { + __osm_vendor_internal_unbind(h_bind); + } + + OSM_LOG_EXIT(p_log); +} + +/* + * NAME osm_vendor_get + * + * DESCRIPTION Allocate the space for a new MAD + */ + +ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind, + IN const uint32_t mad_size, + IN osm_vend_wrap_t * const p_vw) +{ + ib_mad_t *p_mad; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + uint32_t act_mad_size; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vw); + + if (mad_size < MAD_BLOCK_SIZE) { + /* Stupid, but the applications want that! */ + act_mad_size = MAD_BLOCK_SIZE; + } else { + act_mad_size = mad_size; + } + + /* allocate it */ + p_mad = (ib_mad_t *) malloc(act_mad_size); + if (p_mad == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get: ERR 7309: " + "Error Obtaining MAD buffer.\n"); + goto Exit; + } + + memset(p_mad, 0, act_mad_size); + + if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get: " + "Allocated MAD %p, size = %u.\n", p_mad, act_mad_size); + } + p_vw->p_mad = p_mad; + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (p_mad); +} + +/* + * NAME osm_vendor_send + * + * DESCRIPTION Send a MAD buffer (RMPP or simple send). + * + * Semantics: + * (1) The RMPP send completes when every segment + * is acknowledged (synchronous) + * (2) The simple send completes when the send completion + * is received (asynchronous) + */ + +ib_api_status_t +osm_vendor_send(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, IN boolean_t const resp_expected) +{ + ib_api_status_t ret = IB_SUCCESS; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + boolean_t is_rmpp = FALSE, is_rmpp_ds = FALSE; + osmv_txn_ctx_t *p_txn = NULL; + ib_mad_t *p_mad; + osm_log_t *p_log = p_bo->p_vendor->p_log; + osm_mad_pool_t *p_mad_pool = p_bo->p_osm_pool; + OSM_LOG_ENTER(p_log); + + if (NULL == h_bind || NULL == p_madw || + NULL == (p_mad = osm_madw_get_mad_ptr(p_madw)) || + NULL == osm_madw_get_mad_addr_ptr(p_madw)) { + + return IB_INVALID_PARAMETER; + } + + is_rmpp = (p_madw->mad_size > MAD_BLOCK_SIZE + || osmv_mad_is_rmpp(p_mad)); + /* is this rmpp double sided? This means we expect a response that can be + an rmpp or not */ + is_rmpp_ds = (TRUE == is_rmpp && TRUE == resp_expected); + + /* Make our operations with the send context atomic */ + osmv_txn_lock(p_bo); + + if (TRUE == p_bo->is_closing) { + + osm_log(p_log, OSM_LOG_ERROR, + "osm_vendor_send: ERR 7310: " + "The handle %p is being unbound, cannot send.\n", + h_bind); + ret = IB_INTERRUPTED; + /* When closing p_bo could be detroyed or is going to , thus could not refer to it */ + goto send_done; + } + + if (TRUE == resp_expected || TRUE == is_rmpp) { + + /* We must run under a transaction framework. + * Get the transaction object (old or new) */ + ret = __osmv_get_send_txn(h_bind, p_madw, is_rmpp, + resp_expected, &p_txn); + if (IB_SUCCESS != ret) { + goto send_done; + } + } + + if (TRUE == is_rmpp) { + /* Do the job - RMPP! + * The call returns as all the packets are ACK'ed/upon error + * The txn lock will be released each time the function sleeps + * and re-acquired when it wakes up + */ + ret = osmv_rmpp_send_madw(h_bind, p_madw, p_txn, is_rmpp_ds); + } else { + + /* Do the job - single MAD! + * The call returns as soon as the MAD is put on the wire + */ + ret = osmv_simple_send_madw(h_bind, p_madw, p_txn, FALSE); + } + + if (IB_SUCCESS == ret) { + + if ((TRUE == is_rmpp) && (FALSE == is_rmpp_ds)) { + /* For double-sided sends, the txn continues to live */ + osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), + FALSE /*not in callback */ ); + } + + if (FALSE == resp_expected) { + osm_mad_pool_put(p_mad_pool, p_madw); + } + } else if (IB_INTERRUPTED != ret) { + if (NULL != p_txn) { + osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), + FALSE /*not in callback */ ); + } + + osm_log(p_log, OSM_LOG_ERROR, + "osm_vendor_send: ERR 7311: failed to send MADW %p\n", + p_madw); + + if (TRUE == resp_expected) { + /* Change the status on the p_madw */ + p_madw->status = ret; + /* Only the requester expects the error callback */ + p_bo->send_err_cb(p_bo->cb_context, p_madw); + } else { + /* put back the mad - it is useless ... */ + osm_mad_pool_put(p_mad_pool, p_madw); + } + } else { /* the transaction was aborted due to p_bo exit */ + + osm_mad_pool_put(p_mad_pool, p_madw); + goto aborted; + } +send_done: + + osmv_txn_unlock(p_bo); +aborted: + OSM_LOG_EXIT(p_log); + return ret; +} + +/* + * NAME osm_vendor_put + * + * DESCRIPTION Free the MAD's memory + */ + +void +osm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw) +{ + + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + + if (p_bo->is_closing != TRUE) { + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vw); + CL_ASSERT(p_vw->p_mad); + + if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_put: " "Retiring MAD %p.\n", + p_vw->p_mad); + } + + free(p_vw->p_mad); + p_vw->p_mad = NULL; + + OSM_LOG_EXIT(p_vend->p_log); + } +} + +/* + * NAME osm_vendor_local_lid_change + * + * DESCRIPTION Notifies the vendor transport layer that the local address + * has changed. This allows the vendor layer to perform + * housekeeping functions such as address vector updates. + */ + +ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind) +{ + osm_vendor_t const *p_vend = ((osmv_bind_obj_t *) h_bind)->p_vendor; + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_local_lid_change: " "Change of LID.\n"); + + OSM_LOG_EXIT(p_vend->p_log); + + return (IB_SUCCESS); + +} + +/* + * NAME osm_vendor_set_sm + * + * DESCRIPTION Modifies the port info for the bound port to set the "IS_SM" bit + * according to the value given (TRUE or FALSE). + */ +#if !(defined(OSM_VENDOR_INTF_TS_NO_VAPI) || defined(OSM_VENDOR_INTF_SIM) || defined(OSM_VENDOR_INTF_TS)) +void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + VAPI_ret_t status; + VAPI_hca_attr_t attr_mod; + VAPI_hca_attr_mask_t attr_mask; + + OSM_LOG_ENTER(p_vend->p_log); + + memset(&attr_mod, 0, sizeof(attr_mod)); + memset(&attr_mask, 0, sizeof(attr_mask)); + + attr_mod.is_sm = is_sm_val; + attr_mask = HCA_ATTR_IS_SM; + + status = + VAPI_modify_hca_attr(p_bo->hca_hndl, p_bo->port_num, &attr_mod, + &attr_mask); + if (status != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_set_sm: ERR 7312: " + "Unable set 'IS_SM' bit to:%u in port attributes (%d).\n", + is_sm_val, status); + } + + OSM_LOG_EXIT(p_vend->p_log); +} + +#endif + +/* + * NAME __osm_vendor_internal_unbind + * + * DESCRIPTION Destroying a bind: + * (1) Wait for the completion of the sends in flight + * (2) Destroy the associated data structures + */ + +static void __osm_vendor_internal_unbind(osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_log_t *p_log = p_bo->p_vendor->p_log; + + OSM_LOG_ENTER(p_log); + + /* "notifying" all that from now on no new sends can be done */ + p_bo->txn_mgr.p_event_wheel->closing = TRUE; + + osmv_txn_lock(p_bo); + + /* + the is_closing is set under lock we we know we only need to + check for it after obtaining the lock + */ + p_bo->is_closing = TRUE; + + /* notifying all sleeping rmpp sends to exit */ + osmv_txn_abort_rmpp_txns(h_bind); + + /* unlock the bo to allow for any residual mads to be dispatched */ + osmv_txn_unlock(p_bo); + osm_log(p_log, OSM_LOG_DEBUG, + "__osm_vendor_internal_unbind: destroying transport mgr.. \n"); + /* wait for the receiver thread to exit */ + osmv_transport_done(h_bind); + + /* lock to avoid any collissions while we cleanup the structs */ + osmv_txn_lock(p_bo); + osm_log(p_log, OSM_LOG_DEBUG, + "__osm_vendor_internal_unbind: destroying txn mgr.. \n"); + osmv_txnmgr_done(h_bind); + osm_log(p_log, OSM_LOG_DEBUG, + "__osm_vendor_internal_unbind: destroying bind lock.. \n"); + osmv_txn_unlock(p_bo); + + /* + we intentionally let the p_bo and its lock leak - + as we did not implement a way to track active bind handles provided to + the client - and the client might use them + + cl_spinlock_destroy(&p_bo->lock); + free(p_bo); + */ + + OSM_LOG_EXIT(p_log); +} + +/* + * NAME __osmv_get_send_txn + * + * DESCRIPTION Return a transaction object that corresponds to this MAD. + * Optionally, create it, if the new request (query) is sent or received. + */ + +static ib_api_status_t +__osmv_get_send_txn(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, + IN boolean_t is_rmpp, + IN boolean_t resp_expected, OUT osmv_txn_ctx_t ** pp_txn) +{ + ib_api_status_t ret; + uint64_t tid, key; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + ib_mad_t *p_mad = osm_madw_get_mad_ptr(p_madw); + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + CL_ASSERT(NULL != pp_txn); + + key = tid = cl_ntoh64(p_mad->trans_id); + if (TRUE == resp_expected) { + /* Create a unique identifier at the requester side */ + key = osmv_txn_uniq_key(tid); + } + + /* We must run under a transaction framework */ + ret = osmv_txn_lookup(h_bind, key, pp_txn); + if (IB_NOT_FOUND == ret) { + /* Generally, we start a new transaction */ + ret = osmv_txn_init(h_bind, tid, key, pp_txn); + if (IB_SUCCESS != ret) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_get_send_txn: ERR 7313: " + "The transaction id=0x%llX failed to init.\n", + tid); + goto get_send_txn_done; + } + } else { + CL_ASSERT(NULL != *pp_txn); + /* The transaction context exists. + * This is legal only if I am going to return an + * (RMPP?) reply to an RMPP request sent by the other part + * (double-sided RMPP transfer) + */ + if (FALSE == is_rmpp + || FALSE == osmv_txn_is_rmpp_init_by_peer(*pp_txn)) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_get_send_txn: ERR 7314: " + "The transaction id=0x%llX is not unique. Send failed.\n", + tid); + + ret = IB_INVALID_SETTING; + goto get_send_txn_done; + } + + if (TRUE == resp_expected) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_get_send_txn: ERR 7315: " + "The transaction id=%llX can't expect a response. Send failed.\n", + tid); + + ret = IB_INVALID_PARAMETER; + goto get_send_txn_done; + } + } + + if (TRUE == is_rmpp) { + ret = osmv_txn_init_rmpp_sender(h_bind, *pp_txn, p_madw); + if (IB_SUCCESS != ret) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_get_send_txn: ERR 7316: " + "The transaction id=%llX failed to init the rmpp mad. Send failed.\n", + tid); + osmv_txn_done(h_bind, tid, FALSE); + goto get_send_txn_done; + } + } + + /* Save a reference to the MAD in the txn context + * We'll need to match it in two cases: + * (1) When the response is returned, if I am the requester + * (2) In RMPP retransmissions + */ + osmv_txn_set_madw(*pp_txn, p_madw); + +get_send_txn_done: + OSM_LOG_EXIT(p_bo->p_vendor->p_log); + + return ret; +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level) +{ + +} diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_anafa.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_anafa.c new file mode 100644 index 000000000000..bb04530e11af --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_anafa.c @@ -0,0 +1,753 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/** + * FORWARD REFERENCES + */ +static ib_api_status_t +__osmv_get_send_txn(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, + IN boolean_t is_rmpp, + IN boolean_t resp_expected, OUT osmv_txn_ctx_t ** pp_txn); + +static void __osm_vendor_internal_unbind(osm_bind_handle_t h_bind); + +/* + * NAME osm_vendor_new + * + * DESCRIPTION Create and Initialize the osm_vendor_t Object + */ + +osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log, + IN const uint32_t timeout) +{ + ib_api_status_t status; + osm_vendor_t *p_vend; + + OSM_LOG_ENTER(p_log); + + CL_ASSERT(p_log); + + p_vend = malloc(sizeof(*p_vend)); + if (p_vend != NULL) { + memset(p_vend, 0, sizeof(*p_vend)); + status = osm_vendor_init(p_vend, p_log, timeout); + if (status != IB_SUCCESS) { + osm_vendor_delete(&p_vend); + } + } else { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_new: ERR 7401: " + "Fail to allocate vendor object.\n"); + } + + OSM_LOG_EXIT(p_log); + return (p_vend); +} + +/* + * NAME osm_vendor_delete + * + * DESCRIPTION Delete all the binds behind the vendor + free the vendor object + */ + +void osm_vendor_delete(IN osm_vendor_t ** const pp_vend) +{ + cl_list_item_t *p_item; + cl_list_obj_t *p_obj; + osm_bind_handle_t bind_h; + osm_log_t *p_log; + + OSM_LOG_ENTER((*pp_vend)->p_log); + p_log = (*pp_vend)->p_log; + + /* go over the bind handles , unbind them and remove from list */ + /* Note that if we reached here due to problem in the init, then + the bind_handles list is not initialized yet */ + if ((*pp_vend)->bind_handles.state == CL_INITIALIZED) { + p_item = cl_qlist_remove_head(&((*pp_vend)->bind_handles)); + while (p_item != cl_qlist_end(&((*pp_vend)->bind_handles))) { + + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + bind_h = (osm_bind_handle_t *) cl_qlist_obj(p_obj); + osm_log(p_log, OSM_LOG_DEBUG, + "osm_vendor_delete: unbinding bind_h:%p \n", + bind_h); + + __osm_vendor_internal_unbind(bind_h); + + free(p_obj); + /* removing from list */ + p_item = + cl_qlist_remove_head(&((*pp_vend)->bind_handles)); + } + } + + if (NULL != ((*pp_vend)->p_transport_info)) { + free((*pp_vend)->p_transport_info); + (*pp_vend)->p_transport_info = NULL; + } + + /* remove the packet randomizer object */ + if ((*pp_vend)->run_randomizer == TRUE) + osm_pkt_randomizer_destroy(&((*pp_vend)->p_pkt_randomizer), + p_log); + + free(*pp_vend); + *pp_vend = NULL; + + OSM_LOG_EXIT(p_log); +} + +/* + * NAME osm_vendor_init + * + * DESCRIPTION Initialize the vendor object + */ + +ib_api_status_t +osm_vendor_init(IN osm_vendor_t * const p_vend, + IN osm_log_t * const p_log, IN const uint32_t timeout) +{ + ib_api_status_t status = IB_SUCCESS; + char device_file[16]; + int device_fd; + + OSM_LOG_ENTER(p_log); + + p_vend->p_log = p_log; + p_vend->resp_timeout = timeout; + p_vend->ttime_timeout = timeout * OSMV_TXN_TIMEOUT_FACTOR; + + p_vend->p_transport_info = (osmv_TOPSPIN_ANAFA_transport_info_t *) + malloc(sizeof(osmv_TOPSPIN_ANAFA_transport_info_t)); + if (!p_vend->p_transport_info) { + return IB_ERROR; + } + + memset(p_vend->p_transport_info, 0, + sizeof(osmv_TOPSPIN_ANAFA_transport_info_t)); + + /* update the run_randomizer flag */ + if (getenv("OSM_PKT_DROP_RATE") != NULL + && atol(getenv("OSM_PKT_DROP_RATE")) != 0) { + /* if the OSM_PKT_DROP_RATE global variable is defined + to a non-zero value - + then the randomizer should be called. + Need to create the packet randomizer object */ + p_vend->run_randomizer = TRUE; + status = + osm_pkt_randomizer_init(&(p_vend->p_pkt_randomizer), p_log); + if (status != IB_SUCCESS) + return status; + } else { + p_vend->run_randomizer = FALSE; + p_vend->p_pkt_randomizer = NULL; + } + + /* open TopSpin file device */ + sprintf(device_file, "/dev/ts_ua0"); + device_fd = open("/dev/ts_ua0", O_RDWR); + if (device_fd < 0) { + fprintf(stderr, "Fatal: Fail to open the file:%s(%d)\n", + device_file, errno); + return IB_ERROR; + } + + ((osmv_TOPSPIN_ANAFA_transport_info_t *) p_vend->p_transport_info)-> + device_fd = device_fd; + + cl_qlist_init(&p_vend->bind_handles); + + OSM_LOG_EXIT(p_log); + return (IB_SUCCESS); +} + +/* + * NAME osm_vendor_bind + * + * DESCRIPTION Create a new bind object under the vendor object + */ + +osm_bind_handle_t +osm_vendor_bind(IN osm_vendor_t * const p_vend, + IN osm_bind_info_t * const p_bind_info, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vend_mad_recv_callback_t mad_recv_callback, + IN osm_vend_mad_send_err_callback_t send_err_callback, + IN void *context) +{ + osmv_bind_obj_t *p_bo; + cl_status_t cl_st; + cl_list_obj_t *p_obj; + uint8_t hca_idx = 0; + + if (NULL == p_vend || NULL == p_bind_info || NULL == p_mad_pool + || NULL == mad_recv_callback || NULL == send_err_callback) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 7402: " + "NULL parameter passed in: p_vend=%p p_bind_info=%p p_mad_pool=%p recv_cb=%p send_err_cb=%p\n", + p_vend, p_bind_info, p_mad_pool, mad_recv_callback, + send_err_callback); + + return OSM_BIND_INVALID_HANDLE; + } + + p_bo = malloc(sizeof(osmv_bind_obj_t)); + if (NULL == p_bo) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 7403: " + "could not allocate the bind object\n"); + return OSM_BIND_INVALID_HANDLE; + } + + memset(p_bo, 0, sizeof(osmv_bind_obj_t)); + p_bo->p_vendor = p_vend; + p_bo->recv_cb = mad_recv_callback; + p_bo->send_err_cb = send_err_callback; + p_bo->cb_context = context; + p_bo->p_osm_pool = p_mad_pool; + p_bo->port_num = 1; /* anafa2 has one port */ + p_bo->hca_hndl = 0; /* only one ca on anafa system */ + + /* obtain the hca name and port num from the guid */ + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osm_vendor_bind: " + "Finding CA and Port that owns port guid 0x%" PRIx64 ".\n", + cl_ntoh64(p_bind_info->port_guid)); + + p_bo->is_closing = FALSE; + cl_spinlock_construct(&(p_bo->lock)); + cl_st = cl_spinlock_init(&(p_bo->lock)); + if (cl_st != CL_SUCCESS) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 7405: " + "could not initialize the spinlock ...\n"); + free(p_bo); + return OSM_BIND_INVALID_HANDLE; + } + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osm_vendor_bind: osmv_txnmgr_init ... \n"); + if (osmv_txnmgr_init(&p_bo->txn_mgr, p_vend->p_log, &(p_bo->lock)) != + IB_SUCCESS) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 7406: " + "osmv_txnmgr_init failed \n"); + cl_spinlock_destroy(&p_bo->lock); + free(p_bo); + return OSM_BIND_INVALID_HANDLE; + } + + /* Do the real job! (Transport-dependent) */ + if (IB_SUCCESS != + osmv_transport_init(p_bind_info, OSMV_ANAFA_ID, hca_idx, p_bo)) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 7407: " + "osmv_transport_init failed \n"); + osmv_txnmgr_done((osm_bind_handle_t) p_bo); + cl_spinlock_destroy(&p_bo->lock); + free(p_bo); + return OSM_BIND_INVALID_HANDLE; + } + + /* insert bind handle into db */ + p_obj = malloc(sizeof(cl_list_obj_t)); + if (NULL == p_obj) { + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 7408: " + "osm_vendor_bind: could not allocate the list object\n"); + + osmv_transport_done(p_bo->p_transp_mgr); + osmv_txnmgr_done((osm_bind_handle_t) p_bo); + cl_spinlock_destroy(&p_bo->lock); + free(p_bo); + return OSM_BIND_INVALID_HANDLE; + } + if (p_obj) + memset(p_obj, 0, sizeof(cl_list_obj_t)); + cl_qlist_set_obj(p_obj, p_bo); + + cl_qlist_insert_head(&p_vend->bind_handles, &p_obj->list_item); + + return (osm_bind_handle_t) p_bo; +} + +/* + * NAME osm_vendor_unbind + * + * DESCRIPTION Destroy the bind object and remove it from the vendor's list + */ + +void osm_vendor_unbind(IN osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_log_t *p_log = p_bo->p_vendor->p_log; + cl_list_obj_t *p_obj; + cl_list_item_t *p_item, *p_item_tmp; + cl_qlist_t *const p_bh_list = + (cl_qlist_t * const)&p_bo->p_vendor->bind_handles; + + OSM_LOG_ENTER(p_log); + + /* go over all the items in the list and remove the specific item */ + p_item = cl_qlist_head(&p_bo->p_vendor->bind_handles); + while (p_item != cl_qlist_end(&p_bo->p_vendor->bind_handles)) { + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + if (cl_qlist_obj(p_obj) == h_bind) { + break; + } + p_item_tmp = cl_qlist_next(p_item); + p_item = p_item_tmp; + } + + CL_ASSERT(p_item != cl_qlist_end(p_bh_list)); + + cl_qlist_remove_item(p_bh_list, p_item); + free(p_obj); + + __osm_vendor_internal_unbind(h_bind); + + OSM_LOG_EXIT(p_bo->p_vendor->p_log); +} + +/* + * NAME osm_vendor_get + * + * DESCRIPTION Allocate the space for a new MAD + */ + +ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind, + IN const uint32_t mad_size, + IN osm_vend_wrap_t * const p_vw) +{ + ib_mad_t *p_mad; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + uint32_t act_mad_size; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vw); + + if (mad_size < MAD_BLOCK_SIZE) { + /* Stupid, but the applications want that! */ + act_mad_size = MAD_BLOCK_SIZE; + } else { + act_mad_size = mad_size; + } + + /* allocate it */ + p_mad = (ib_mad_t *) malloc(act_mad_size); + if (p_mad == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get: ERR 7409: " + "Error Obtaining MAD buffer.\n"); + goto Exit; + } + + memset(p_mad, 0, act_mad_size); + + if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get: " + "Allocated MAD %p, size = %u.\n", p_mad, act_mad_size); + } + p_vw->p_mad = p_mad; + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (p_mad); +} + +/* + * NAME osm_vendor_send + * + * DESCRIPTION Send a MAD buffer (RMPP or simple send). + * + * Semantics: + * (1) The RMPP send completes when every segment + * is acknowledged (synchronous) + * (2) The simple send completes when the send completion + * is received (asynchronous) + */ + +ib_api_status_t +osm_vendor_send(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, IN boolean_t const resp_expected) +{ + ib_api_status_t ret = IB_SUCCESS; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + boolean_t is_rmpp = FALSE, is_rmpp_ds = FALSE; + osmv_txn_ctx_t *p_txn = NULL; + ib_mad_t *p_mad; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + if (NULL == h_bind || NULL == p_madw || + NULL == (p_mad = osm_madw_get_mad_ptr(p_madw)) || + NULL == osm_madw_get_mad_addr_ptr(p_madw)) { + + return IB_INVALID_PARAMETER; + } + + is_rmpp = (p_madw->mad_size > MAD_BLOCK_SIZE + || osmv_mad_is_rmpp(p_mad)); + is_rmpp_ds = (TRUE == is_rmpp && TRUE == resp_expected); + + /* Make our operations with the send context atomic */ + osmv_txn_lock(p_bo); + + if (TRUE == p_bo->is_closing) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osm_vendor_send: ERR 7410: " + "The handle %p is being unbound, cannot send.\n", + h_bind); + ret = IB_INTERRUPTED; + goto send_done; + } + + if (TRUE == resp_expected || TRUE == is_rmpp) { + + /* We must run under a transaction framework. + * Get the transaction object (old or new) */ + ret = __osmv_get_send_txn(h_bind, p_madw, is_rmpp, + resp_expected, &p_txn); + if (IB_SUCCESS != ret) { + goto send_done; + } + } + + if (TRUE == is_rmpp) { + /* Do the job - RMPP! + * The call returns as all the packets are ACK'ed/upon error + * The txn lock will be released each time the function sleeps + * and re-acquired when it wakes up + */ + ret = osmv_rmpp_send_madw(h_bind, p_madw, p_txn, is_rmpp_ds); + } else { + + /* Do the job - single MAD! + * The call returns as soon as the MAD is put on the wire + */ + ret = osmv_simple_send_madw(h_bind, p_madw, p_txn, FALSE); /* anafa2 */ + } + + if (IB_SUCCESS == ret) { + + if ((TRUE == is_rmpp) && (FALSE == is_rmpp_ds)) { + /* For double-sided sends, the txn continues to live */ + osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), + FALSE /*not in callback */ ); + } + + if (FALSE == resp_expected) { + osm_mad_pool_put(p_bo->p_osm_pool, p_madw); + } + } else { + if (NULL != p_txn) { + osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), + FALSE /*not in callback */ ); + } + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osm_vendor_send: ERR 7411: failed to send MADW %p\n", + p_madw); + + if (TRUE == resp_expected) { + /* Change the status on the p_madw */ + p_madw->status = ret; + /* Only the requester expects the error callback */ + p_bo->send_err_cb(p_bo->cb_context, p_madw); + } else { + /* put back the mad - it is useless ... */ + osm_mad_pool_put(p_bo->p_osm_pool, p_madw); + } + } + +send_done: + + osmv_txn_unlock(p_bo); + + OSM_LOG_EXIT(p_bo->p_vendor->p_log); + return ret; +} + +/* + * NAME osm_vendor_put + * + * DESCRIPTION Free the MAD's memory + */ + +void +osm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw) +{ + + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vw); + CL_ASSERT(p_vw->p_mad); + + if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_put: " "Retiring MAD %p.\n", p_vw->p_mad); + } + + free(p_vw->p_mad); + p_vw->p_mad = NULL; + + OSM_LOG_EXIT(p_vend->p_log); +} + +/* + * NAME osm_vendor_local_lid_change + * + * DESCRIPTION Notifies the vendor transport layer that the local address + * has changed. This allows the vendor layer to perform + * housekeeping functions such as address vector updates. + */ + +ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind) +{ + osm_vendor_t const *p_vend = ((osmv_bind_obj_t *) h_bind)->p_vendor; + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_local_lid_change: " "Change of LID.\n"); + + OSM_LOG_EXIT(p_vend->p_log); + + return (IB_SUCCESS); + +} + +/* + * NAME osm_vendor_set_sm + * + * DESCRIPTION Modifies the port info for the bound port to set the "IS_SM" bit. + */ + +void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + osmv_TOPSPIN_ANAFA_transport_mgr_t *p_mgr; + int ioctl_ret; + osm_ts_set_port_info_ioctl port_info; + + OSM_LOG_ENTER(p_vend->p_log); + + port_info.port = 0; /* anafa has only 1 port */ + port_info.port_info.valid_fields = IB_PORT_IS_SM; + port_info.port_info.is_sm = is_sm_val; + + p_mgr = (osmv_TOPSPIN_ANAFA_transport_mgr_t *) p_bo->p_transp_mgr; + ioctl_ret = ioctl(p_mgr->device_fd, TS_IB_IOCSPORTINFO, &port_info); + + if (ioctl_ret < 0) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_set_sm: ERR 7412: " + "Unable set 'IS_SM' bit to:%u in port attributes (%d). errno=%d\n", + is_sm_val, ioctl_ret, errno); + } + + OSM_LOG_EXIT(p_vend->p_log); +} + +/* + * NAME __osm_vendor_internal_unbind + * + * DESCRIPTION Destroying a bind: + * (1) Wait for the completion of the sends in flight + * (2) Destroy the associated data structures + */ + +static void __osm_vendor_internal_unbind(osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_log_t *p_log = p_bo->p_vendor->p_log; + + OSM_LOG_ENTER(p_log); + + /* "notifying" all that from now on no new sends can be done */ + p_bo->txn_mgr.p_event_wheel->closing = TRUE; + + osmv_txn_lock(p_bo); + p_bo->is_closing = TRUE; + + /* notifying all sleeping rmpp sends to exit */ + osmv_txn_abort_rmpp_txns(h_bind); + + /* frees all data in bind handle */ + osm_log(p_log, OSM_LOG_DEBUG, + "__osm_vendor_internal_unbind: destroying transport mgr.. \n"); + osmv_txn_unlock(p_bo); + + osmv_transport_done(h_bind); + osm_log(p_log, OSM_LOG_DEBUG, + "__osm_vendor_internal_unbind: destroying txn mgr.. \n"); + osmv_txn_lock(p_bo); + osmv_txnmgr_done(h_bind); + osm_log(p_log, OSM_LOG_DEBUG, + "__osm_vendor_internal_unbind: destroying bind lock.. \n"); + + osmv_txn_unlock(p_bo); + /* + we intentionally let the p_bo and its lock leak - + as we did not implement a way to track active bind handles provided to + the client - and the client might use them + + cl_spinlock_destroy(&p_bo->lock); + free(p_bo); + */ + + OSM_LOG_EXIT(p_log); +} + +/* + * NAME __osmv_get_send_txn + * + * DESCRIPTION Return a transaction object that corresponds to this MAD. + * Optionally, create it, if the new request (query) is sent or received. + */ + +static ib_api_status_t +__osmv_get_send_txn(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, + IN boolean_t is_rmpp, + IN boolean_t resp_expected, OUT osmv_txn_ctx_t ** pp_txn) +{ + ib_api_status_t ret; + uint64_t tid, key; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + ib_mad_t *p_mad = osm_madw_get_mad_ptr(p_madw); + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + CL_ASSERT(NULL != pp_txn); + + key = tid = cl_ntoh64(p_mad->trans_id); + if (TRUE == resp_expected) { + /* Create a unique identifier at the requester side */ + key = osmv_txn_uniq_key(tid); + } + + /* We must run under a transaction framework */ + ret = osmv_txn_lookup(h_bind, key, pp_txn); + if (IB_NOT_FOUND == ret) { + /* Generally, we start a new transaction */ + ret = osmv_txn_init(h_bind, tid, key, pp_txn); + if (IB_SUCCESS != ret) { + goto get_send_txn_done; + } + } else { + CL_ASSERT(NULL != *pp_txn); + /* The transaction context exists. + * This is legal only if I am going to return an + * (RMPP?) reply to an RMPP request sent by the other part + * (double-sided RMPP transfer) + */ + if (FALSE == is_rmpp + || FALSE == osmv_txn_is_rmpp_init_by_peer(*pp_txn)) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_get_send_txn: ERR 7413: " + "The transaction id=0x%llX is not unique. Send failed.\n", + tid); + + ret = IB_INVALID_SETTING; + goto get_send_txn_done; + } + + if (TRUE == resp_expected) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_get_send_txn: ERR 7414: " + "The transaction id=%llX can\'t expect a response. Send failed.\n", + tid); + + ret = IB_INVALID_PARAMETER; + goto get_send_txn_done; + } + } + + if (TRUE == is_rmpp) { + ret = osmv_txn_init_rmpp_sender(h_bind, *pp_txn, p_madw); + if (IB_SUCCESS != ret) { + osmv_txn_done(h_bind, tid, FALSE); + goto get_send_txn_done; + } + } + + /* Save a reference to the MAD in the txn context + * We'll need to match it in two cases: + * (1) When the response is returned, if I am the requester + * (2) In RMPP retransmissions + */ + osmv_txn_set_madw(*pp_txn, p_madw); + +get_send_txn_done: + OSM_LOG_EXIT(p_bo->p_vendor->p_log); + + return ret; +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level) +{ + +} diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_dispatcher.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_dispatcher.c new file mode 100644 index 000000000000..d47638275e0c --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_dispatcher.c @@ -0,0 +1,710 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +typedef enum _osmv_disp_route { + + OSMV_ROUTE_DROP, + OSMV_ROUTE_SIMPLE, + OSMV_ROUTE_RMPP, + +} osmv_disp_route_t; + +/** + * FORWARD REFERENCES TO PRIVATE FUNCTIONS + */ + +static osmv_disp_route_t +__osmv_dispatch_route(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_mad, OUT osmv_txn_ctx_t ** pp_txn); + +static void +__osmv_dispatch_simple_mad(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_mad, + IN osmv_txn_ctx_t * p_txn, + IN const osm_mad_addr_t * p_mad_addr); + +static void +__osmv_dispatch_rmpp_mad(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_mad, + IN osmv_txn_ctx_t * p_txn, + IN const osm_mad_addr_t * p_mad_addr); + +static void +__osmv_dispatch_rmpp_snd(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_mad, + IN osmv_txn_ctx_t * p_txn, + IN const osm_mad_addr_t * p_mad_addr); + +static ib_api_status_t +__osmv_dispatch_rmpp_rcv(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_mad, + IN osmv_txn_ctx_t * p_txn, + IN const osm_mad_addr_t * p_mad_addr); + +static ib_api_status_t +__osmv_dispatch_accept_seg(IN osm_bind_handle_t h_bind, + IN osmv_txn_ctx_t * p_txn, + IN const ib_mad_t * p_mad); +static void +__osmv_dispatch_send_ack(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_req_mad, + IN osmv_txn_ctx_t * p_txn, + IN const osm_mad_addr_t * p_mad_addr); + +/* + * NAME + * osmv_dispatch_mad + * + * DESCRIPTION + * Lower-level MAD dispatcher. + * Implements a switch between the following MAD consumers: + * (1) Non-RMPP consumer (DATA) + * (2) RMPP receiver (DATA/ABORT/STOP) + * (3) RMPP sender (ACK/ABORT/STOP) + * + * PARAMETERS + * h_bind The bind handle + * p_mad_buf The 256 byte buffer of individual MAD + * p_mad_addr The MAD originator's address + */ + +ib_api_status_t +osmv_dispatch_mad(IN osm_bind_handle_t h_bind, + IN const void *p_mad_buf, + IN const osm_mad_addr_t * p_mad_addr) +{ + ib_api_status_t ret = IB_SUCCESS; + const ib_mad_t *p_mad = (ib_mad_t *) p_mad_buf; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osmv_txn_ctx_t *p_txn = NULL; + osm_log_t *p_log = p_bo->p_vendor->p_log; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + CL_ASSERT(NULL != h_bind && NULL != p_mad && NULL != p_mad_addr); + + osmv_txn_lock(p_bo); + + if (TRUE == p_bo->is_closing) { + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "The bind handle %p is being closed. " + "The MAD will not be dispatched.\n", p_bo); + + ret = IB_INTERRUPTED; + goto dispatch_mad_done; + } + + /* + Add call for packet drop randomizer. + This is a testing feature. If run_randomizer flag is set to TRUE, + the randomizer will be called, and randomally will drop + a packet. This is used for simulating unstable fabric. + */ + if (p_bo->p_vendor->run_randomizer == TRUE) { + /* Try the randomizer */ + if (osm_pkt_randomizer_mad_drop(p_bo->p_vendor->p_log, + p_bo->p_vendor-> + p_pkt_randomizer, + p_mad) == TRUE) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "The MAD will not be dispatched.\n"); + goto dispatch_mad_done; + } + } + + switch (__osmv_dispatch_route(h_bind, p_mad, &p_txn)) { + + case OSMV_ROUTE_DROP: + break; /* Do nothing */ + + case OSMV_ROUTE_SIMPLE: + __osmv_dispatch_simple_mad(h_bind, p_mad, p_txn, p_mad_addr); + break; + + case OSMV_ROUTE_RMPP: + __osmv_dispatch_rmpp_mad(h_bind, p_mad, p_txn, p_mad_addr); + break; + + default: + CL_ASSERT(FALSE); + } + +dispatch_mad_done: + osmv_txn_unlock(p_bo); + + OSM_LOG_EXIT(p_log); + return ret; +} + +/* + * NAME __osmv_dispatch_route() + * + * DESCRIPTION Decide which way to handle the received MAD: simple txn/RMPP/drop + */ + +static osmv_disp_route_t +__osmv_dispatch_route(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_mad, OUT osmv_txn_ctx_t ** pp_txn) +{ + ib_api_status_t ret; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + boolean_t is_resp = osmv_mad_is_response(p_mad); + boolean_t is_txn; + uint64_t key = cl_ntoh64(p_mad->trans_id); + + CL_ASSERT(NULL != pp_txn); + + ret = osmv_txn_lookup(h_bind, key, pp_txn); + is_txn = (IB_SUCCESS == ret); + + if (FALSE == is_txn && TRUE == is_resp) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "Received a response to a non-started/aged-out transaction (tid=0x%llX). " + "Dropping the MAD.\n", key); + return OSMV_ROUTE_DROP; + } + + if (TRUE == osmv_mad_is_rmpp(p_mad)) { + /* An RMPP transaction. The filtering is more delicate there */ + return OSMV_ROUTE_RMPP; + } + + if (TRUE == is_txn && FALSE == is_resp) { + /* Does this MAD try to start a transaction with duplicate tid? */ + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "Duplicate TID 0x%llX received (not a response). " + "Dropping the MAD.\n", key); + + return OSMV_ROUTE_DROP; + } + + return OSMV_ROUTE_SIMPLE; +} + +/* + * NAME __osmv_dispatch_simple_mad() + * + * DESCRIPTION Handle a MAD that is part of non-RMPP transfer + */ + +static void +__osmv_dispatch_simple_mad(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_mad, + IN osmv_txn_ctx_t * p_txn, + IN const osm_mad_addr_t * p_mad_addr) +{ + osm_madw_t *p_madw; + ib_mad_t *p_mad_buf; + osm_madw_t *p_req_madw = NULL; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + /* Build the MAD wrapper to be returned to the user. + * The actual storage for the MAD is allocated there. + */ + p_madw = + osm_mad_pool_get(p_bo->p_osm_pool, h_bind, MAD_BLOCK_SIZE, + p_mad_addr); + + if (NULL == p_madw) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_dispatch_simple_mad: ERR 6501: " + "Out Of Memory - could not allocate a buffer of size %d\n", + MAD_BLOCK_SIZE); + + goto dispatch_simple_mad_done; + } + + p_mad_buf = osm_madw_get_mad_ptr(p_madw); + /* Copy the payload to the MAD buffer */ + memcpy((void *)p_mad_buf, (void *)p_mad, MAD_BLOCK_SIZE); + + if (NULL != p_txn) { + /* This is a RESPONSE MAD. Pair it with the REQUEST MAD, pass upstream */ + p_req_madw = p_txn->p_madw; + CL_ASSERT(NULL != p_req_madw); + + p_mad_buf->trans_id = cl_hton64(osmv_txn_get_tid(p_txn)); + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "Restoring the original TID to 0x%llX\n", + cl_ntoh64(p_mad_buf->trans_id)); + + /* Reply matched, transaction complete */ + osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE); + } else { + /* This is a REQUEST MAD. Don't create a context, pass upstream */ + } + + /* Do the job ! */ + p_bo->recv_cb(p_madw, p_bo->cb_context, p_req_madw); + +dispatch_simple_mad_done: + OSM_LOG_EXIT(p_bo->p_vendor->p_log); +} + +/* + * NAME __osmv_dispatch_rmpp_mad() + * + * DESCRIPTION Handle a MAD that is part of RMPP transfer + */ + +static void +__osmv_dispatch_rmpp_mad(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_mad, + IN osmv_txn_ctx_t * p_txn, + IN const osm_mad_addr_t * p_mad_addr) +{ + ib_api_status_t status = IB_SUCCESS; + uint64_t key = cl_ntoh64(p_mad->trans_id); + boolean_t is_init_by_peer = FALSE; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_madw_t *p_madw; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + if (NULL == p_txn) { + if (FALSE == osmv_rmpp_is_data(p_mad) + || FALSE == osmv_rmpp_is_first(p_mad)) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "The MAD does not match any transaction " + "and does not start a sender-initiated RMPP transfer.\n"); + goto dispatch_rmpp_mad_done; + } + + /* IB Spec 13.6.2.2. This is a Sender Initiated Transfer. + My peer is the requester and RMPP Sender. I am the RMPP Receiver. + */ + status = osmv_txn_init(h_bind, /*tid==key */ key, key, &p_txn); + if (IB_SUCCESS != status) { + goto dispatch_rmpp_mad_done; + } + + is_init_by_peer = TRUE; + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "A new sender-initiated transfer (TID=0x%llX) started\n", + key); + } + + if (OSMV_TXN_RMPP_NONE == osmv_txn_get_rmpp_state(p_txn)) { + /* Case 1: Fall through from above. + * Case 2: When the transaction was initiated by me + * (a single request MAD), there was an uncertainty + * whether the reply will be RMPP. Now it's resolved, + * since the reply is RMPP! + */ + status = + osmv_txn_init_rmpp_receiver(h_bind, p_txn, is_init_by_peer); + if (IB_SUCCESS != status) { + goto dispatch_rmpp_mad_done; + } + } + + switch (osmv_txn_get_rmpp_state(p_txn)) { + + case OSMV_TXN_RMPP_RECEIVER: + status = + __osmv_dispatch_rmpp_rcv(h_bind, p_mad, p_txn, p_mad_addr); + if (IB_SUCCESS != status) { + if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn)) { + /* This is a requester, still waiting for the reply. Apply the callback */ + /* update the status of the p_madw */ + p_madw = osmv_txn_get_madw(p_txn); + p_madw->status = status; + p_bo->send_err_cb(p_bo->cb_context, p_madw); + } + + /* ABORT/STOP/LOCAL ERROR */ + osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE); + } + break; + + case OSMV_TXN_RMPP_SENDER: + __osmv_dispatch_rmpp_snd(h_bind, p_mad, p_txn, p_mad_addr); + /* If an error happens here, it's the sender thread to cleanup the txn */ + break; + + default: + CL_ASSERT(FALSE); + } + +dispatch_rmpp_mad_done: + OSM_LOG_EXIT(p_bo->p_vendor->p_log); +} + +/* + * NAME __osmv_dispatch_rmpp_snd() + * + * DESCRIPTION MAD handling by an RMPP sender (ACK/ABORT/STOP) + */ + +static void +__osmv_dispatch_rmpp_snd(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_mad, + IN osmv_txn_ctx_t * p_txn, + IN const osm_mad_addr_t * p_mad_addr) +{ + osmv_rmpp_send_ctx_t *p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); + + uint32_t old_wl = p_send_ctx->window_last; + uint32_t total_segs = osmv_rmpp_send_ctx_get_num_segs(p_send_ctx); + uint32_t seg_num = cl_ntoh32(((ib_rmpp_mad_t *) p_mad)->seg_num); + uint32_t new_wl = cl_ntoh32(((ib_rmpp_mad_t *) p_mad)->paylen_newwin); + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + if (TRUE == osmv_rmpp_is_abort_stop(p_mad)) { + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_dispatch_rmpp_snd: ERR 6502: " + "The remote side sent an ABORT/STOP indication.\n"); + osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR); + goto dispatch_rmpp_snd_done; + } + + if (FALSE == osmv_rmpp_is_ack(p_mad)) { + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "Not supposed to receive DATA packets --> dropping the MAD\n"); + goto dispatch_rmpp_snd_done; + } + + /* Continue processing the ACK */ + if (seg_num > old_wl) { + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_dispatch_rmpp_snd: ERR 6503: " + "ACK received for a non-sent segment %d\n", seg_num); + + osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, + IB_RMPP_TYPE_ABORT, IB_RMPP_STATUS_S2B); + + osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR); + goto dispatch_rmpp_snd_done; + } + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "__osmv_dispatch_rmpp_snd: " + "New WL = %u Old WL = %u Total Segs = %u\n", + new_wl, old_wl, total_segs); + + if (new_wl < old_wl) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_dispatch_rmpp_snd: ERR 6508: " + "The receiver requests a smaller WL (%d) than before (%d)\n", + new_wl, old_wl); + + osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, + IB_RMPP_TYPE_ABORT, IB_RMPP_STATUS_W2S); + + osmv_rmpp_snd_error(p_send_ctx, IB_REMOTE_ERROR); + goto dispatch_rmpp_snd_done; + } + + /* Update the sender's window, and optionally wake up the sender thread + * Note! A single ACK can acknowledge a whole range of segments: [WF..SEG_NUM] + */ + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "ACK for seg_num #%d accepted.\n", seg_num); + + if (seg_num == old_wl) { + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "The send window [%d:%d] is totally acknowledged.\n", + p_send_ctx->window_first, old_wl); + + p_send_ctx->window_first = seg_num + 1; + p_send_ctx->window_last = + (new_wl < total_segs) ? new_wl : total_segs; + + /* Remove the response timeout event for the window */ + osmv_txn_remove_timeout_ev(h_bind, osmv_txn_get_key(p_txn)); + + /* Wake up the sending thread */ + cl_event_signal(&p_send_ctx->event); + } + +dispatch_rmpp_snd_done: + OSM_LOG_EXIT(p_bo->p_vendor->p_log); +} + +/* + * NAME __osmv_dispatch_rmpp_rcv() + * + * DESCRIPTION MAD handling by an RMPP receiver (DATA/ABORT/STOP) + */ + +static ib_api_status_t +__osmv_dispatch_rmpp_rcv(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_mad, + IN osmv_txn_ctx_t * p_txn, + IN const osm_mad_addr_t * p_mad_addr) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_rmpp_recv_ctx_t *p_recv_ctx = osmv_txn_get_rmpp_recv_ctx(p_txn); + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + boolean_t is_last1 = FALSE, is_last2 = FALSE; + osm_madw_t *p_new_madw = NULL, *p_req_madw = NULL; + ib_mad_t *p_mad_buf; + uint32_t size = 0; + uint64_t key = osmv_txn_get_key(p_txn); + uint64_t tid = osmv_txn_get_tid(p_txn); + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + if (TRUE == osmv_rmpp_is_ack(p_mad)) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "Not supposed to receive ACK's --> dropping the MAD\n"); + + goto dispatch_rmpp_rcv_done; + } + + if (TRUE == osmv_rmpp_is_abort_stop(p_mad)) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "__osmv_dispatch_rmpp_rcv: ERR 6504: " + "The Remote Side stopped sending\n"); + + status = IB_REMOTE_ERROR; + goto dispatch_rmpp_rcv_done; + } + + status = __osmv_dispatch_accept_seg(h_bind, p_txn, p_mad); + switch (status) { + + case IB_SUCCESS: + + /* Check wheter this is the legal last MAD */ + /* Criteria #1: the received MAD is marked last */ + is_last1 = osmv_rmpp_is_last(p_mad); + + /* Criteria #2: the total accumulated length hits the advertised one */ + is_last2 = is_last1; + + size = osmv_rmpp_recv_ctx_get_byte_num_from_first(p_recv_ctx); + if (size > 0) { + is_last2 = + (osmv_rmpp_recv_ctx_get_cur_byte_num(p_recv_ctx) >= + size); + } + + if (is_last1 != is_last2) { + + osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, + IB_RMPP_TYPE_ABORT, + IB_RMPP_STATUS_BAD_LEN); + + status = IB_ERROR; + goto dispatch_rmpp_rcv_done; + } + + /* TBD Consider an optimization - sending an ACK + * only for the last segment in the window + */ + __osmv_dispatch_send_ack(h_bind, p_mad, p_txn, p_mad_addr); + break; + + case IB_INSUFFICIENT_RESOURCES: + /* An out-of-order segment received. Send the ACK anyway */ + __osmv_dispatch_send_ack(h_bind, p_mad, p_txn, p_mad_addr); + status = IB_SUCCESS; + goto dispatch_rmpp_rcv_done; + + case IB_INSUFFICIENT_MEMORY: + osmv_rmpp_send_nak(h_bind, p_mad, p_mad_addr, + IB_RMPP_TYPE_STOP, IB_RMPP_STATUS_RESX); + goto dispatch_rmpp_rcv_done; + + default: + /* Illegal return code */ + CL_ASSERT(FALSE); + } + + if (TRUE != is_last1) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "RMPP MADW assembly continues, TID=0x%llX\n", tid); + goto dispatch_rmpp_rcv_done; + } + + /* This is the last packet. */ + if (0 == size) { + /* The total size was not advertised in the first packet */ + size = osmv_rmpp_recv_ctx_get_byte_num_from_last(p_recv_ctx); + } + + /* + NOTE: the received mad might not be >= 256 bytes. + some MADs might contain several SA records but still be + less then a full MAD. + We have to use RMPP to send them over since on a regular + "simple" MAD there is no way to know how many records were sent + */ + + /* Build the MAD wrapper to be returned to the user. + * The actual storage for the MAD is allocated there. + */ + p_new_madw = + osm_mad_pool_get(p_bo->p_osm_pool, h_bind, size, p_mad_addr); + if (NULL == p_new_madw) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_dispatch_rmpp_rcv: ERR 6506: " + "Out Of Memory - could not allocate %d bytes for the MADW\n", + size); + + status = IB_INSUFFICIENT_MEMORY; + goto dispatch_rmpp_rcv_done; + } + + p_req_madw = osmv_txn_get_madw(p_txn); + p_mad_buf = osm_madw_get_mad_ptr(p_new_madw); + status = osmv_rmpp_recv_ctx_reassemble_arbt_mad(p_recv_ctx, size, + (uint8_t *) p_mad_buf); + if (IB_SUCCESS != status) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_dispatch_rmpp_rcv: ERR 6507: " + "Internal error - could not reassemble the result MAD\n"); + goto dispatch_rmpp_rcv_done; /* What can happen here? */ + } + + /* The MAD is assembled, we are about to apply the callback. + * Delete the transaction context, unless the transaction is double sided */ + if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn) + || FALSE == osmv_mad_is_multi_resp(p_mad)) { + + osmv_txn_done(h_bind, key, FALSE); + } + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "RMPP MADW %p assembly complete, TID=0x%llX\n", p_new_madw, + tid); + + p_mad_buf->trans_id = cl_hton64(tid); + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "Restoring the original TID to 0x%llX\n", + cl_ntoh64(p_mad_buf->trans_id)); + + /* Finally, do the job! */ + p_bo->recv_cb(p_new_madw, p_bo->cb_context, p_req_madw); + +dispatch_rmpp_rcv_done: + OSM_LOG_EXIT(p_bo->p_vendor->p_log); + return status; +} + +/* + * NAME __osmv_dispatch_accept_seg() + * + * DESCRIPTION Store a DATA segment at the RMPP receiver side, + * if one is received in order. + */ + +static ib_api_status_t +__osmv_dispatch_accept_seg(IN osm_bind_handle_t h_bind, + IN osmv_txn_ctx_t * p_txn, IN const ib_mad_t * p_mad) +{ + ib_api_status_t ret = IB_SUCCESS; + uint32_t seg_num = cl_ntoh32(((ib_rmpp_mad_t *) p_mad)->seg_num); + osmv_rmpp_recv_ctx_t *p_recv_ctx = osmv_txn_get_rmpp_recv_ctx(p_txn); + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + uint64_t tid = osmv_txn_get_tid(p_txn); + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + if (seg_num != p_recv_ctx->expected_seg) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "TID 0x%llX: can't accept this segment (%d) - " + "this is a Go-Back-N implementation\n", tid, seg_num); + return IB_INSUFFICIENT_RESOURCES; + } + + /* Store the packet's copy in the reassembly list. + * Promote the expected segment counter. + */ + ret = osmv_rmpp_recv_ctx_store_mad_seg(p_recv_ctx, (uint8_t *) p_mad); + if (IB_SUCCESS != ret) { + return ret; + } + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "TID 0x%llX: segment %d accepted\n", tid, seg_num); + p_recv_ctx->expected_seg = seg_num + 1; + + OSM_LOG_EXIT(p_bo->p_vendor->p_log); + return IB_SUCCESS; +} + +/* + * NAME __osmv_dispatch_send_ack() + * + * DESCRIPTION + * + * ISSUES + * Consider sending the ACK from an async thread + * if problems with the receiving side processing arise. + */ + +static void +__osmv_dispatch_send_ack(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_req_mad, + IN osmv_txn_ctx_t * p_txn, + IN const osm_mad_addr_t * p_mad_addr) +{ + osmv_rmpp_recv_ctx_t *p_recv_ctx = osmv_txn_get_rmpp_recv_ctx(p_txn); + + /* ACK the segment # that was accepted */ + uint32_t seg_num = cl_ntoh32(((ib_rmpp_mad_t *) p_req_mad)->seg_num); + + /* NOTE! The receiver can publish the New Window Last (NWL) value + * that is greater than the total number of segments to be sent. + * It's the sender's responsibility to compute the correct number + * of segments to send in the next burst. + */ + uint32_t nwl = p_recv_ctx->expected_seg + OSMV_RMPP_RECV_WIN - 1; + + osmv_rmpp_send_ack(h_bind, p_req_mad, seg_num, nwl, p_mad_addr); +} diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca.c new file mode 100644 index 000000000000..e98e272139c8 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca.c @@ -0,0 +1,524 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#if defined(OSM_VENDOR_INTF_MTL) | defined(OSM_VENDOR_INTF_TS) +#undef IN +#undef OUT +#include +#include +#include +#include +#include +#include + +/******************************************************************************** + * + * Provide the functionality for selecting an HCA Port and Obtaining it's guid. + * + ********************************************************************************/ + +typedef struct _osm_ca_info { + ib_net64_t guid; + size_t attr_size; + ib_ca_attr_t *p_attr; +} osm_ca_info_t; + +/********************************************************************** + * Convert the given GID to GUID by copy of it's upper 8 bytes + **********************************************************************/ +ib_api_status_t +__osm_vendor_gid_to_guid(IN u_int8_t * gid, OUT VAPI_gid_t * guid) +{ + memcpy(guid, gid + 8, 8); + return (IB_SUCCESS); +} + +/********************************************************************** + * Returns a pointer to the port attribute of the specified port + * owned by this CA. + ************************************************************************/ +static ib_port_attr_t *__osm_ca_info_get_port_attr_ptr(IN const osm_ca_info_t * + const p_ca_info, + IN const uint8_t index) +{ + return (&p_ca_info->p_attr->p_port_attr[index]); +} + +/******************************************************************************** + * get the CA names available on the system + * NOTE: user of this function needs to deallocate p_hca_ids after usage. + ********************************************************************************/ +static ib_api_status_t +__osm_vendor_get_ca_ids(IN osm_vendor_t * const p_vend, + IN VAPI_hca_id_t ** const p_hca_ids, + IN uint32_t * const p_num_guids) +{ + ib_api_status_t status; + VAPI_ret_t vapi_res; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_hca_ids); + CL_ASSERT(p_num_guids); + + /* first call is just to get the number */ + vapi_res = EVAPI_list_hcas(0, p_num_guids, NULL); + + /* fail ? */ + if (vapi_res == VAPI_EINVAL_PARAM) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_ids: ERR 3D08: : " + "Bad parameter in calling: EVAPI_list_hcas. (%d)\n", + vapi_res); + status = IB_ERROR; + goto Exit; + } + + /* NO HCA ? */ + if (*p_num_guids == 0) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_ids: ERR 3D09: " + "No available channel adapters.\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* allocate and really call - user of this function needs to deallocate it */ + *p_hca_ids = + (VAPI_hca_id_t *) malloc(*p_num_guids * sizeof(VAPI_hca_id_t)); + + /* now call it really */ + vapi_res = EVAPI_list_hcas(*p_num_guids, p_num_guids, *p_hca_ids); + + /* too many ? */ + if (vapi_res == VAPI_EAGAIN) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_ids: ERR 3D10: " + "More CA GUIDs than allocated array (%d).\n", + *p_num_guids); + status = IB_ERROR; + goto Exit; + } + + /* fail ? */ + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_ids: ERR 3D11: : " + "Bad parameter in calling: EVAPI_list_hcas.\n"); + status = IB_ERROR; + goto Exit; + } + + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_vendor_get_ca_ids: " + "Detected %u local channel adapters.\n", *p_num_guids); + } + + status = IB_SUCCESS; + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + * Initialize an Info Struct for the Given HCA by its Id + **********************************************************************/ +static ib_api_status_t +__osm_ca_info_init(IN osm_vendor_t * const p_vend, + IN VAPI_hca_id_t ca_id, OUT osm_ca_info_t * const p_ca_info) +{ + ib_api_status_t status = IB_ERROR; + VAPI_ret_t vapi_res; + VAPI_hca_hndl_t hca_hndl; + VAPI_hca_vendor_t hca_vendor; + VAPI_hca_cap_t hca_cap; + VAPI_hca_port_t hca_port; + uint8_t port_num; + IB_gid_t *p_port_gid; + uint16_t maxNumGids; + + OSM_LOG_ENTER(p_vend->p_log); + + /* get the HCA handle */ + vapi_res = EVAPI_get_hca_hndl(ca_id, &hca_hndl); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 3D05: " + "Fail to get HCA handle (%u).\n", vapi_res); + goto Exit; + } + + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_ca_info_init: " "Querying CA %s.\n", ca_id); + } + + /* query and get the HCA capability */ + vapi_res = VAPI_query_hca_cap(hca_hndl, &hca_vendor, &hca_cap); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 3D06: " + "Fail to get HCA Capabilities (%u).\n", vapi_res); + goto Exit; + } + + /* get the guid of the HCA */ + memcpy(&(p_ca_info->guid), hca_cap.node_guid, 8 * sizeof(u_int8_t)); + p_ca_info->attr_size = 1; + p_ca_info->p_attr = (ib_ca_attr_t *) malloc(sizeof(ib_ca_attr_t)); + memcpy(&(p_ca_info->p_attr->ca_guid), hca_cap.node_guid, + 8 * sizeof(u_int8_t)); + + /* now obtain the attributes of the ports */ + p_ca_info->p_attr->num_ports = hca_cap.phys_port_num; + p_ca_info->p_attr->p_port_attr = + (ib_port_attr_t *) malloc(hca_cap.phys_port_num * + sizeof(ib_port_attr_t)); + + for (port_num = 0; port_num < p_ca_info->p_attr->num_ports; port_num++) { + + /* query the port attributes */ + vapi_res = + VAPI_query_hca_port_prop(hca_hndl, port_num + 1, &hca_port); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 3D07: " + "Fail to get HCA Port Attributes (%d).\n", + vapi_res); + goto Exit; + } + + /* first call to know the size of the gid table */ + vapi_res = + VAPI_query_hca_gid_tbl(hca_hndl, port_num + 1, 0, + &maxNumGids, NULL); + p_port_gid = (IB_gid_t *) malloc(maxNumGids * sizeof(IB_gid_t)); + + vapi_res = + VAPI_query_hca_gid_tbl(hca_hndl, port_num + 1, maxNumGids, + &maxNumGids, p_port_gid); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 3D12: " + "Fail to get HCA Port GID (%d).\n", vapi_res); + goto Exit; + } + + __osm_vendor_gid_to_guid(p_port_gid[0], + (IB_gid_t *) & p_ca_info->p_attr-> + p_port_attr[port_num].port_guid); + p_ca_info->p_attr->p_port_attr[port_num].lid = hca_port.lid; + p_ca_info->p_attr->p_port_attr[port_num].link_state = + hca_port.state; + p_ca_info->p_attr->p_port_attr[port_num].sm_lid = + hca_port.sm_lid; + + free(p_port_gid); + } + + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +void +osm_ca_info_destroy(IN osm_vendor_t * const p_vend, + IN osm_ca_info_t * const p_ca_info, IN uint8_t num_ca) +{ + osm_ca_info_t *p_ca; + uint8_t i; + + OSM_LOG_ENTER(p_vend->p_log); + + for (i = 0; i < num_ca; i++) { + p_ca = &p_ca_info[i]; + + if (NULL != p_ca->p_attr) { + if (0 != p_ca->p_attr->num_ports) { + free(p_ca->p_attr->p_port_attr); + } + + free(p_ca->p_attr); + } + } + + free(p_ca_info); + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + * Fill in the array of port_attr with all available ports on ALL the + * avilable CAs on this machine. + * ALSO - + * Update the vendor object list of ca_info structs + **********************************************************************/ +ib_api_status_t +osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * const p_attr_array, + IN uint32_t * const p_num_ports) +{ + ib_api_status_t status; + + uint32_t ca; + uint32_t ca_count = 0; + uint32_t port_count = 0; + uint8_t port_num; + uint32_t total_ports = 0; + VAPI_hca_id_t *p_ca_ids = NULL; + osm_ca_info_t *p_ca_infos = NULL; + uint32_t attr_array_sz = *p_num_ports; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + + /* determine the number of CA's */ + status = __osm_vendor_get_ca_ids(p_vend, &p_ca_ids, &ca_count); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 3D13: " + "Fail to get CA Ids.\n"); + goto Exit; + } + + /* Allocate an array big enough to hold the ca info objects */ + p_ca_infos = malloc(ca_count * sizeof(osm_ca_info_t)); + if (p_ca_infos == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 3D14: " + "Unable to allocate CA information array.\n"); + goto Exit; + } + + memset(p_ca_infos, 0, ca_count * sizeof(osm_ca_info_t)); + + /* + * For each CA, retrieve the CA info attributes + */ + for (ca = 0; ca < ca_count; ca++) { + status = + __osm_ca_info_init(p_vend, p_ca_ids[ca], &p_ca_infos[ca]); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 3D15: " + "Unable to initialize CA Info object (%s).\n", + ib_get_err_str(status)); + goto Exit; + } + total_ports += p_ca_infos[ca].p_attr->num_ports; + } + + *p_num_ports = total_ports; + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get_all_port_attr: total ports:%u \n", total_ports); + + /* + * If the user supplied enough storage, return the port guids, + * otherwise, return the appropriate error. + */ + if (attr_array_sz >= total_ports) { + for (ca = 0; ca < ca_count; ca++) { + uint32_t num_ports; + + num_ports = p_ca_infos[ca].p_attr->num_ports; + + for (port_num = 0; port_num < num_ports; port_num++) { + p_attr_array[port_count] = + *__osm_ca_info_get_port_attr_ptr(&p_ca_infos + [ca], + port_num); + port_count++; + } + } + } else { + status = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + + status = IB_SUCCESS; + +Exit: + if (p_ca_ids) + free(p_ca_ids); + + if (p_ca_infos) { + osm_ca_info_destroy(p_vend, p_ca_infos, ca_count); + } + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + * Given the vendor obj and a guid + * return the ca id and port number that have that guid + **********************************************************************/ + +ib_api_status_t +osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend, + IN ib_net64_t const guid, + OUT VAPI_hca_hndl_t * p_hca_hndl, + OUT VAPI_hca_id_t * p_hca_id, + OUT uint8_t * p_hca_idx, + OUT uint32_t * p_port_num) +{ + + ib_api_status_t status; + VAPI_hca_id_t *p_ca_ids = NULL; + VAPI_ret_t vapi_res; + VAPI_hca_hndl_t hca_hndl; + VAPI_hca_vendor_t hca_vendor; + VAPI_hca_cap_t hca_cap; + IB_gid_t *p_port_gid = NULL; + uint16_t maxNumGids; + ib_net64_t port_guid; + uint32_t ca, portIdx, ca_count; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + + /* + * 1) Determine the number of CA's + * 2) Allocate an array big enough to hold the ca info objects. + * 3) Call again to retrieve the guids. + */ + status = __osm_vendor_get_ca_ids(p_vend, &p_ca_ids, &ca_count); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 3D16: " + "Fail to get CA Ids.\n"); + goto Exit; + } + + /* + * For each CA, retrieve the CA info attributes + */ + for (ca = 0; ca < ca_count; ca++) { + /* get the HCA handle */ + vapi_res = EVAPI_get_hca_hndl(p_ca_ids[ca], &hca_hndl); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 3D17: " + "Fail to get HCA handle (%u).\n", vapi_res); + goto Exit; + } + + /* get the CA attributes - to know how many ports it has: */ + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get_guid_ca_and_port: " + "Querying CA %s.\n", p_ca_ids[ca]); + } + + /* query and get the HCA capability */ + vapi_res = VAPI_query_hca_cap(hca_hndl, &hca_vendor, &hca_cap); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 3D18: " + "Fail to get HCA Capabilities (%u).\n", + vapi_res); + goto Exit; + } + + /* go over all ports - to obtail their guids */ + for (portIdx = 0; portIdx < hca_cap.phys_port_num; portIdx++) { + vapi_res = + VAPI_query_hca_gid_tbl(hca_hndl, portIdx + 1, 0, + &maxNumGids, NULL); + p_port_gid = + (IB_gid_t *) malloc(maxNumGids * sizeof(IB_gid_t)); + + /* get the port guid */ + vapi_res = + VAPI_query_hca_gid_tbl(hca_hndl, portIdx + 1, + maxNumGids, &maxNumGids, + p_port_gid); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 3D19: " + "Fail to get HCA Port GID (%d).\n", + vapi_res); + goto Exit; + } + + /* convert to SF style */ + __osm_vendor_gid_to_guid(p_port_gid[0], + (VAPI_gid_t *) & port_guid); + + /* finally did we find it ? */ + if (port_guid == guid) { + *p_hca_hndl = hca_hndl; + memcpy(p_hca_id, p_ca_ids[ca], + sizeof(VAPI_hca_id_t)); + *p_hca_idx = ca; + *p_port_num = portIdx + 1; + status = IB_SUCCESS; + goto Exit; + } + + free(p_port_gid); + p_port_gid = NULL; + } /* ALL PORTS */ + } /* all HCAs */ + + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 3D20: " + "Fail to find HCA and Port for Port Guid 0x%" PRIx64 "\n", + cl_ntoh64(guid)); + status = IB_INVALID_GUID; + +Exit: + if (p_ca_ids != NULL) + free(p_ca_ids); + if (p_port_gid != NULL) + free(p_port_gid); + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +#endif diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca_anafa.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca_anafa.c new file mode 100644 index 000000000000..81506e4a6ff3 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca_anafa.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#if defined(OSM_VENDOR_INTF_ANAFA) +#undef IN +#undef OUT + +#include +#include +#include + +#include +#include +#include + +#include +#include + +/******************************************************************************** + * + * Provide the functionality for selecting an HCA Port and Obtaining it's guid. + * + ********************************************************************************/ + +typedef struct _osm_ca_info { + /* ib_net64_t guid; ?? */ + /* size_t attr_size; ?? */ + ib_ca_attr_t attr; +} osm_ca_info_t; + +/********************************************************************** + * Convert the given GID to GUID by copy of it's upper 8 bytes + **********************************************************************/ +ib_api_status_t +__osm_vendor_gid_to_guid(IN tTS_IB_GID gid, OUT ib_net64_t * p_guid) +{ + memcpy(p_guid, gid + 8, 8); + return (IB_SUCCESS); +} + +/********************************************************************** + * Initialize an Info Struct for the Given HCA by its Id + **********************************************************************/ +static ib_api_status_t +__osm_ca_info_init(IN osm_vendor_t * const p_vend, + OUT osm_ca_info_t * const p_ca_info) +{ + ib_api_status_t status = IB_ERROR; + int ioctl_ret = 0; + osmv_TOPSPIN_ANAFA_transport_info_t *p_tpot_info = + p_vend->p_transport_info; + osm_ts_gid_entry_ioctl gid_ioctl; + osm_ts_get_port_info_ioctl port_info; + struct ib_get_dev_info_ioctl dev_info; + + OSM_LOG_ENTER(p_vend->p_log); + + /* query HCA guid */ + ioctl_ret = ioctl(p_tpot_info->device_fd, TS_IB_IOCGDEVINFO, &dev_info); + if (ioctl_ret != 0) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 7001: " + "Fail to get HCA Capabilities (%d).\n", ioctl_ret); + goto Exit; + } + + memcpy(&(p_ca_info->attr.ca_guid), dev_info.dev_info.node_guid, + 8 * sizeof(uint8_t)); + +/* now obtain the attributes of the ports - on our case port 1*/ + + p_ca_info->attr.num_ports = 1; + p_ca_info->attr.p_port_attr = + (ib_port_attr_t *) malloc(1 * sizeof(ib_port_attr_t)); + + port_info.port = 1; + ioctl_ret = + ioctl(p_tpot_info->device_fd, TS_IB_IOCGPORTINFO, &port_info); + if (ioctl_ret) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 7002: " + "Fail to get HCA Port Attributes (%d).\n", ioctl_ret); + goto Exit; + } + + gid_ioctl.port = 1; + gid_ioctl.index = 0; + ioctl_ret = + ioctl(p_tpot_info->device_fd, TS_IB_IOCGGIDENTRY, &gid_ioctl); + if (ioctl_ret) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 7003: " + "Fail to get HCA Port GID (%d).\n", ioctl_ret); + goto Exit; + } + + __osm_vendor_gid_to_guid(gid_ioctl.gid_entry, + &(p_ca_info->attr.p_port_attr[0].port_guid)); + p_ca_info->attr.p_port_attr[0].lid = port_info.port_info.lid; + p_ca_info->attr.p_port_attr[0].link_state = + port_info.port_info.port_state; + p_ca_info->attr.p_port_attr[0].sm_lid = port_info.port_info.sm_lid; + + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +/********************************************************************** + * Fill in port_attr + * ALSO - + * Update the vendor object list of ca_info structs + **********************************************************************/ +ib_api_status_t +osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * const p_attr_array, + IN uint32_t * const p_num_ports) +{ + ib_api_status_t status; + osm_ca_info_t ca_info; + uint32_t attr_array_sz = *p_num_ports; + + OSM_LOG_ENTER(p_vend->p_log); + CL_ASSERT(p_vend); + + /* anafa has one port - the user didnt supply enough storage space */ + if (attr_array_sz < 1) { + status = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + + /* + * retrieve the CA info attributes + */ + status = __osm_ca_info_init(p_vend, &ca_info); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 7004: " + "Unable to initialize CA Info object (%s).\n", + ib_get_err_str(status)); + goto Exit; + } + + *p_num_ports = 1; + + p_attr_array[0] = ca_info.attr.p_port_attr[0]; /* anafa has only one port */ + status = IB_SUCCESS; + +Exit: + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +#endif diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca_pfs.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca_pfs.c new file mode 100644 index 000000000000..512b7bf21df2 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca_pfs.c @@ -0,0 +1,751 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#if defined(OSM_VENDOR_INTF_MTL) | defined(OSM_VENDOR_INTF_TS) +#undef IN +#undef OUT +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/******************************************************************************** + * + * Provides the functionality for selecting an HCA Port and Obtaining it's guid. + * This version is based on /proc/infiniband file system. So it is limited to + * The gen1 of openib.org stack. + * + ********************************************************************************/ + +typedef struct _osm_ca_info { + ib_net64_t guid; + size_t attr_size; + ib_ca_attr_t *p_attr; + +} osm_ca_info_t; + +/********************************************************************** + * Returns a pointer to the port attribute of the specified port + * owned by this CA. + ************************************************************************/ +static ib_port_attr_t *__osm_ca_info_get_port_attr_ptr(IN const osm_ca_info_t * + const p_ca_info, + IN const uint8_t index) +{ + return (&p_ca_info->p_attr->p_port_attr[index]); +} + +/********************************************************************** + * Obtain the number of local CAs by scanning /proc/infiniband/core + **********************************************************************/ +int __hca_pfs_get_num_cas() +{ + int num_cas = 0; + DIR *dp; + struct dirent *ep; + + dp = opendir("/proc/infiniband/core"); + if (dp != NULL) { + while ((ep = readdir(dp))) { + /* CAs are directories with the format ca[1-9][0-9]* */ + if ((ep->d_type == DT_DIR) + && !strncmp(ep->d_name, "ca", 2)) { + num_cas++; + } + } + closedir(dp); + } + return num_cas; +} + +/* + name: InfiniHost0 + provider: tavor + node GUID: 0002:c900:0120:3470 + ports: 2 + vendor ID: 0x2c9 + device ID: 0x5a44 + HW revision: 0xa1 + FW revision: 0x300020080 +*/ +typedef struct _pfs_ca_info { + char name[32]; + char provider[32]; + uint64_t guid; + uint8_t num_ports; + uint32_t vend_id; + uint16_t dev_id; + uint16_t rev_id; + uint64_t fw_rev; +} pfs_ca_info_t; + +/********************************************************************** + * Parse the CA Info file available in /proc/infiniband/core/caN/info + **********************************************************************/ +static ib_api_status_t +__parse_ca_info_file(IN osm_vendor_t * const p_vend, + IN uint32_t idx, OUT pfs_ca_info_t * pfs_ca_info) +{ + ib_api_status_t status = IB_ERROR; + int info_file; + char file_name[256]; + char file_buffer[3200]; + char *p_ch; + int g1, g2, g3, g4; + int num_ports; + uint32_t len; + + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__parse_ca_info_file: " "Querying CA %d.\n", idx); + + /* we use the proc file system so we must be able to open the info file .. */ + sprintf(file_name, "/proc/infiniband/core/ca%d/info", idx); + info_file = open(file_name, O_RDONLY); + if (!info_file) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5205: " + "Fail to open HCA:%d info file:(%s).\n", idx, + file_name); + goto Exit; + } + + /* read in the file */ + len = read(info_file, file_buffer, 3200); + close(info_file); + file_buffer[len] = '\0'; + + /* + parse the file ... + name: InfiniHost0 + provider: tavor + node GUID: 0002:c900:0120:3470 + ports: 2 + vendor ID: 0x2c9 + device ID: 0x5a44 + HW revision: 0xa1 + FW revision: 0x300020080 + */ + if (!(p_ch = strstr(file_buffer, "name:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5206: " + "Fail to obtain HCA name. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "name: %s", pfs_ca_info->name) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5207: " + "Fail to parse name in info file:(%s).\n", p_ch); + goto Exit; + } + + /* get the guid of the HCA */ + if (!(p_ch = strstr(file_buffer, "node GUID:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5208: " + "Fail to obtain GUID in info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "node GUID: %x:%x:%x:%x", &g1, &g2, &g3, &g4) != 4) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5209: " + "Fail to parse GUID in info file:(%s).\n", p_ch); + goto Exit; + } + pfs_ca_info->guid = (uint64_t) g1 << 48 | (uint64_t) g1 << 32 + | (uint64_t) g1 << 16 | (uint64_t) g3; + + /* obtain number of ports */ + if (!(p_ch = strstr(file_buffer, "ports:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5210: " + "Fail to obtain number of ports in info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "ports: %d", &num_ports) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5211: " + "Fail to parse num ports in info file:(%s).\n", p_ch); + goto Exit; + } + pfs_ca_info->num_ports = num_ports; + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__parse_ca_info_file: " + "CA1 = name:%s guid:0x%016llx ports:%d\n", + pfs_ca_info->name, pfs_ca_info->guid, pfs_ca_info->num_ports); + + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return status; +} + +/* + state: ACTIVE + LID: 0x0001 + LMC: 0x0000 + SM LID: 0x0001 + SM SL: 0x0000 + Capabilities: IsSM + IsTrapSupported + IsAutomaticMigrationSupported + IsSLMappingSupported + IsLEDInfoSupported + IsSystemImageGUIDSupported + IsVendorClassSupported + IsCapabilityMaskNoticeSupported +*/ +typedef struct _pfs_port_info { + uint8_t state; + uint16_t lid; + uint8_t lmc; + uint16_t sm_lid; + uint8_t sm_sl; +} pfs_port_info_t; + +/********************************************************************** + * Parse the Port Info file available in /proc/infiniband/core/caN/portM/info + * Port num is 1..N + **********************************************************************/ +static ib_api_status_t +__parse_port_info_file(IN osm_vendor_t * const p_vend, + IN uint32_t hca_idx, + IN uint8_t port_num, OUT pfs_port_info_t * pfs_port_info) +{ + ib_api_status_t status = IB_ERROR; + int info_file; + char file_name[256]; + char file_buffer[3200]; + char state[12]; + char *p_ch; + int lid, sm_lid, lmc, sm_sl; + uint32_t len; + + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__parse_port_info_file: " + "Parsing Proc File System Port Info CA %d Port %d.\n", hca_idx, + port_num); + + /* we use the proc file system so we must be able to open the info file .. */ + sprintf(file_name, "/proc/infiniband/core/ca%d/port%d/info", hca_idx, + port_num); + info_file = open(file_name, O_RDONLY); + if (!info_file) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5212: " + "Fail to open HCA:%d Port:%d info file:(%s).\n", + hca_idx, port_num, file_name); + goto Exit; + } + + /* read in the file */ + len = read(info_file, file_buffer, 3200); + close(info_file); + file_buffer[len] = '\0'; + + /* + parse the file ... + state: ACTIVE + LID: 0x0001 + LMC: 0x0000 + SM LID: 0x0001 + SM SL: 0x0000 + ... + */ + if (!(p_ch = strstr(file_buffer, "state:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5213: " + "Fail to obtain port state. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "state: %s", state) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5214: " + "Fail to parse state from info file:(%s).\n", p_ch); + goto Exit; + } + + if (!strcmp(state, "ACTIVE")) + pfs_port_info->state = IB_LINK_ACTIVE; + else if (!strcmp(state, "DOWN")) + pfs_port_info->state = IB_LINK_DOWN; + else if (!strcmp(state, "INIT")) + pfs_port_info->state = IB_LINK_INIT; + else if (!strcmp(state, "ARMED")) + pfs_port_info->state = IB_LINK_ARMED; + else + pfs_port_info->state = 0; + + /* get lid */ + if (!(p_ch = strstr(file_buffer, "LID:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5215: " + "Fail to obtain port lid. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "LID: %x", &lid) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5216: " + "Fail to parse lid from info file:(%s).\n", p_ch); + goto Exit; + } + pfs_port_info->lid = lid; + /* get LMC */ + if (!(p_ch = strstr(file_buffer, "LMC:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5217: " + "Fail to obtain port LMC. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "LMC: %x", &lmc) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5218: " + "Fail to parse LMC from info file:(%s).\n", p_ch); + goto Exit; + } + pfs_port_info->lmc = lmc; + + /* get SM LID */ + if (!(p_ch = strstr(file_buffer, "SM LID:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5219: " + "Fail to obtain port SM LID. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "SM LID: %x", &sm_lid) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5220: " + "Fail to parse SM LID from info file:(%s).\n", p_ch); + goto Exit; + } + pfs_port_info->sm_lid = sm_lid; + + /* get SM LID */ + if (!(p_ch = strstr(file_buffer, "SM SL:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5221: " + "Fail to obtain port SM SL. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "SM SL: %x", &sm_sl) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5222: " + "Fail to parse SM SL from info file:(%s).\n", p_ch); + goto Exit; + } + pfs_port_info->sm_sl = sm_sl; + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__parse_port_info_file: " + "Obtained Port:%d = state:%d, lid:0x%04X, lmc:%d, sm_lid:0x%04X, sm_sl:%d\n", + port_num, pfs_port_info->state, pfs_port_info->lid, + pfs_port_info->lmc, pfs_port_info->sm_lid, + pfs_port_info->sm_sl); + + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return status; +} + +/********************************************************************** + * Parse the port guid_tbl file to obtain the port guid. + * File format is: + * [ 0] fe80:0000:0000:0000:0002:c900:0120:3472 + **********************************************************************/ +static ib_api_status_t +__get_port_guid_from_port_gid_tbl(IN osm_vendor_t * const p_vend, + IN uint32_t hca_idx, + IN uint8_t port_num, OUT uint64_t * port_guid) +{ + ib_api_status_t status = IB_ERROR; + int info_file; + char file_name[256]; + char file_buffer[3200]; + char *p_ch; + int g[8]; + uint32_t len; + + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__get_port_guid_from_port_gid_tbl: " + "Parsing Proc File System Port Guid Table CA %d Port %d.\n", + hca_idx, port_num); + + /* we use the proc file system so we must be able to open the info file .. */ + sprintf(file_name, "/proc/infiniband/core/ca%d/port%d/gid_table", + hca_idx, port_num); + info_file = open(file_name, O_RDONLY); + if (!info_file) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__get_port_guid_from_port_gid_tbl: ERR 5223: " + "Fail to open HCA:%d Port:%d gid_table file:(%s).\n", + hca_idx, port_num, file_name); + goto Exit; + } + + /* read in the file */ + len = read(info_file, file_buffer, 3200); + close(info_file); + file_buffer[len] = '\0'; + + /* + parse the file ... + [ 0] fe80:0000:0000:0000:0002:c900:0120:3472 + ... + */ + if (!(p_ch = strstr(file_buffer, "[ 0]"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__get_port_guid_from_port_gid_tbl: ERR 5224: " + "Fail to obtain first gid index. In gid_table file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch + 6, "%x:%x:%x:%x:%x:%x:%x:%x", + &g[7], &g[6], &g[5], &g[4], &g[3], &g[2], &g[1], &g[0]) != 8) + { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__get_port_guid_from_port_gid_tbl: ERR 5225: " + "Fail to parse gid from gid_table file:(%s).\n", p_ch); + goto Exit; + } + + *port_guid = + (uint64_t) g[3] << 48 | (uint64_t) g[2] << 32 | (uint64_t) g[1] << + 16 | g[0]; + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return status; +} + +/********************************************************************** + * Initialize an Info Struct for the Given HCA by its index 1..N + **********************************************************************/ +static ib_api_status_t +__osm_ca_info_init(IN osm_vendor_t * const p_vend, + IN uint32_t const idx, OUT osm_ca_info_t * const p_ca_info) +{ + ib_api_status_t status = IB_ERROR; + uint8_t port_num; + uint64_t port_guid; + + pfs_ca_info_t pfs_ca_info; + + OSM_LOG_ENTER(p_vend->p_log); + + /* parse the CA info file */ + if (__parse_ca_info_file(p_vend, idx, &pfs_ca_info) != IB_SUCCESS) + goto Exit; + + p_ca_info->guid = cl_hton64(pfs_ca_info.guid); + + /* set size of attributes and allocate them */ + p_ca_info->attr_size = 1; + p_ca_info->p_attr = (ib_ca_attr_t *) malloc(sizeof(ib_ca_attr_t)); + + p_ca_info->p_attr->ca_guid = p_ca_info->guid; + p_ca_info->p_attr->num_ports = pfs_ca_info.num_ports; + + /* now obtain the attributes of the ports */ + p_ca_info->p_attr->p_port_attr = + (ib_port_attr_t *) malloc(pfs_ca_info.num_ports * + sizeof(ib_port_attr_t)); + + /* get all the ports info */ + for (port_num = 1; port_num <= pfs_ca_info.num_ports; port_num++) { + pfs_port_info_t pfs_port_info; + /* query the port attributes */ + if (__parse_port_info_file + (p_vend, idx, port_num, &pfs_port_info)) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 5226: " + "Fail to get HCA:%d Port:%d Attributes.\n", idx, + port_num); + goto Exit; + } + + /* HACK: the lids should have been converted to network but the rest of the code + is wrong and provdes them as is (host order) - so we stick with it. */ + p_ca_info->p_attr->p_port_attr[port_num - 1].lid = + pfs_port_info.lid; + p_ca_info->p_attr->p_port_attr[port_num - 1].link_state = + pfs_port_info.state; + p_ca_info->p_attr->p_port_attr[port_num - 1].sm_lid = + pfs_port_info.sm_lid; + + /* get the port guid */ + if (__get_port_guid_from_port_gid_tbl + (p_vend, idx, port_num, &port_guid)) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 5227: " + "Fail to get HCA:%d Port:%d Guid.\n", idx, + port_num); + goto Exit; + } + p_ca_info->p_attr->p_port_attr[port_num - 1].port_guid = + cl_hton64(port_guid); + } + + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +void +osm_ca_info_destroy(IN osm_vendor_t * const p_vend, + IN osm_ca_info_t * const p_ca_info, IN uint8_t num_ca) +{ + osm_ca_info_t *p_ca; + uint8_t i; + + OSM_LOG_ENTER(p_vend->p_log); + + for (i = 0; i < num_ca; i++) { + p_ca = &p_ca_info[i]; + + if (NULL != p_ca->p_attr) { + if (0 != p_ca->p_attr->num_ports) { + free(p_ca->p_attr->p_port_attr); + } + + free(p_ca->p_attr); + } + } + + free(p_ca_info); + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + * Fill in the array of port_attr with all available ports on ALL the + * avilable CAs on this machine. + **********************************************************************/ +ib_api_status_t +osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * const p_attr_array, + IN uint32_t * const p_num_ports) +{ + ib_api_status_t status = IB_SUCCESS; + + uint32_t caIdx; + uint32_t ca_count = 0; + uint32_t port_count = 0; + uint8_t port_num; + uint32_t total_ports = 0; + osm_ca_info_t *p_ca_infos = NULL; + uint32_t attr_array_sz = *p_num_ports; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + + /* determine the number of CA's */ + ca_count = __hca_pfs_get_num_cas(); + if (!ca_count) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 5228: " + "Fail to get Any CA Ids.\n"); + goto Exit; + } + + /* Allocate an array big enough to hold the ca info objects */ + p_ca_infos = malloc(ca_count * sizeof(osm_ca_info_t)); + if (p_ca_infos == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 5229: " + "Unable to allocate CA information array.\n"); + goto Exit; + } + + memset(p_ca_infos, 0, ca_count * sizeof(osm_ca_info_t)); + + /* + * For each CA, retrieve the CA info attributes + */ + for (caIdx = 1; caIdx <= ca_count; caIdx++) { + status = + __osm_ca_info_init(p_vend, caIdx, &p_ca_infos[caIdx - 1]); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 5230: " + "Unable to initialize CA Info object (%s).\n", + ib_get_err_str(status)); + goto Exit; + } + total_ports += p_ca_infos[caIdx - 1].p_attr->num_ports; + } + + *p_num_ports = total_ports; + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get_all_port_attr: total ports:%u \n", total_ports); + + /* + * If the user supplied enough storage, return the port guids, + * otherwise, return the appropriate error. + */ + if (attr_array_sz >= total_ports) { + for (caIdx = 1; caIdx <= ca_count; caIdx++) { + uint32_t num_ports; + + num_ports = p_ca_infos[caIdx - 1].p_attr->num_ports; + + for (port_num = 0; port_num < num_ports; port_num++) { + p_attr_array[port_count] = + *__osm_ca_info_get_port_attr_ptr(&p_ca_infos + [caIdx - + 1], + port_num); + port_count++; + } + } + } else { + status = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + + status = IB_SUCCESS; + +Exit: + if (p_ca_infos) { + osm_ca_info_destroy(p_vend, p_ca_infos, ca_count); + } + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + * Given the vendor obj and a port guid + * return the ca id and port number that have that guid + **********************************************************************/ + +ib_api_status_t +osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend, + IN ib_net64_t const guid, + OUT uint32_t * p_hca_hndl, + OUT char *p_hca_id, + OUT uint8_t * p_hca_idx, + OUT uint32_t * p_port_num) +{ + uint32_t caIdx; + uint32_t ca_count = 0; + uint8_t port_num; + ib_api_status_t status = IB_ERROR; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + + /* determine the number of CA's */ + ca_count = __hca_pfs_get_num_cas(); + if (!ca_count) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 5231: " + "Fail to get Any CA Ids.\n"); + goto Exit; + } + + /* + * For each CA, retrieve the CA info attributes + */ + for (caIdx = 1; caIdx <= ca_count; caIdx++) { + pfs_ca_info_t pfs_ca_info; + if (__parse_ca_info_file(p_vend, caIdx, &pfs_ca_info) == + IB_SUCCESS) { + /* get all the ports info */ + for (port_num = 1; port_num <= pfs_ca_info.num_ports; + port_num++) { + uint64_t port_guid; + if (!__get_port_guid_from_port_gid_tbl + (p_vend, caIdx, port_num, &port_guid)) { + if (cl_hton64(port_guid) == guid) { + osm_log(p_vend->p_log, + OSM_LOG_DEBUG, + "osm_vendor_get_guid_ca_and_port: " + "Found Matching guid on HCA:%d Port:%d.\n", + caIdx, port_num); + strcpy(p_hca_id, + pfs_ca_info.name); + *p_port_num = port_num; + *p_hca_idx = caIdx - 1; + *p_hca_hndl = 0; + status = IB_SUCCESS; + goto Exit; + } + } + } + } + } + + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 5232: " + "Fail to find HCA and Port for Port Guid 0x%" PRIx64 "\n", + cl_ntoh64(guid)); + status = IB_INVALID_GUID; + +Exit: + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +#endif diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca_sim.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca_sim.c new file mode 100644 index 000000000000..b6c0193f07fd --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca_sim.c @@ -0,0 +1,864 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#if defined(OSM_VENDOR_INTF_SIM) +#undef IN +#undef OUT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** +* +* Provides the functionality for selecting an HCA Port and Obtaining it's guid. +* This version is based on $IBMGTSIM_DIR/$IBMGTSIM_NODE file system. +* This is a mimic of the OpenIB gen1 file system +* +******************************************************************************/ + +char *__get_simulator_dir(void) +{ + static char *ibmgtSimDir = NULL; + static char *defaultIbmgtSimDir = "/tmp/ibmgtsim"; + static char *ibmgtSimNode = NULL; + static char dirName[1024]; + + /* we use the first pointer to know if we were here */ + if (ibmgtSimDir == NULL) { + /* obtain the simulator directory */ + ibmgtSimDir = getenv("IBMGTSIM_DIR"); + if (ibmgtSimDir == NULL) { + printf + ("-W- Environment variable: IBMGTSIM_DIR does not exist.\n"); + printf + (" Please create one used by the simulator.\n"); + printf(" Using /tmp/ibmgtsim as default.\n"); + ibmgtSimDir = defaultIbmgtSimDir; + } + + /* obtain the node name we simulate */ + ibmgtSimNode = getenv("IBMGTSIM_NODE"); + if (ibmgtSimNode == NULL) { + printf + ("-W- Environment variable: IBMGTSIM_NODE does not exist.\n"); + printf + (" This variable should be the name of the node you wish to simulate.\n"); + printf(" Using H-1 as default.\n"); + ibmgtSimNode = "H-1"; + } + sprintf(dirName, "%s/%s", ibmgtSimDir, ibmgtSimNode); + } + + return dirName; +} + +typedef struct _osm_ca_info { + ib_net64_t guid; + size_t attr_size; + ib_ca_attr_t *p_attr; + +} osm_ca_info_t; + +/********************************************************************** + * Returns a pointer to the port attribute of the specified port + * owned by this CA. + ************************************************************************/ +static ib_port_attr_t *__osm_ca_info_get_port_attr_ptr(IN const osm_ca_info_t * + const p_ca_info, + IN const uint8_t index) +{ + return (&p_ca_info->p_attr->p_port_attr[index]); +} + +/********************************************************************** + * Obtain the number of local CAs by scanning /proc/infiniband/core + **********************************************************************/ +int __hca_sim_get_num_cas(void) +{ + int num_cas = 0; + DIR *dp; + struct dirent *ep; + + dp = opendir(__get_simulator_dir()); + + if (dp != NULL) { + while ((ep = readdir(dp))) { + /* CAs are directories with the format ca[1-9][0-9]* */ + /* if ((ep->d_type == DT_DIR) && !strncmp(ep->d_name, "ca", 2)) */ + if (!strncmp(ep->d_name, "ca", 2)) { + num_cas++; + } + } + closedir(dp); + } else { + printf("__hca_sim_get_num_cas: ERROR : ail to open dir %s\n", + __get_simulator_dir()); + exit(1); + } + + if (!num_cas) + exit(1); + return num_cas; +} + +/* + name: InfiniHost0 + provider: tavor + node GUID: 0002:c900:0120:3470 + ports: 2 + vendor ID: 0x2c9 + device ID: 0x5a44 + HW revision: 0xa1 + FW revision: 0x300020080 +*/ +typedef struct _sim_ca_info { + char name[32]; + char provider[32]; + uint64_t guid; + uint8_t num_ports; + uint32_t vend_id; + uint16_t dev_id; + uint16_t rev_id; + uint64_t fw_rev; +} sim_ca_info_t; + +/********************************************************************** + * Parse the CA Info file available in ibmgtSimDir/caN/info + **********************************************************************/ +static ib_api_status_t +__parse_ca_info_file(IN osm_vendor_t * const p_vend, + IN uint32_t idx, OUT sim_ca_info_t * sim_ca_info) +{ + ib_api_status_t status = IB_ERROR; + int info_file; + char file_name[256]; + char file_buffer[3200]; + char *p_ch; + int g1, g2, g3, g4; + int num_ports; + uint32_t len; + + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__parse_ca_info_file: " "Querying CA %d.\n", idx); + + /* we use the proc file system so we must be able to open the info file .. */ + sprintf(file_name, "%s/ca%d/info", __get_simulator_dir(), idx); + info_file = open(file_name, O_RDONLY); + if (!info_file) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5105: " + "Fail to open HCA:%d info file:(%s).\n", idx, + file_name); + goto Exit; + } + + /* read in the file */ + len = read(info_file, file_buffer, 3200); + close(info_file); + file_buffer[len] = '\0'; + + /* + parse the file ... + name: InfiniHost0 + provider: tavor + node GUID: 0002:c900:0120:3470 + ports: 2 + vendor ID: 0x2c9 + device ID: 0x5a44 + HW revision: 0xa1 + FW revision: 0x300020080 + */ + if (!(p_ch = strstr(file_buffer, "name:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5106: " + "Fail to obtain HCA name. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "name: %s", sim_ca_info->name) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5107: " + "Fail to parse name in info file:(%s).\n", p_ch); + goto Exit; + } + + /* get the guid of the HCA */ + if (!(p_ch = strstr(file_buffer, "node GUID:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5108: " + "Fail to obtain GUID in info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "node GUID: %x:%x:%x:%x", &g1, &g2, &g3, &g4) != 4) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5109: " + "Fail to parse GUID in info file:(%s).\n", p_ch); + goto Exit; + } + sim_ca_info->guid = (uint64_t) g1 << 48 | (uint64_t) g1 << 32 + | (uint64_t) g1 << 16 | (uint64_t) g3; + + /* obtain number of ports */ + if (!(p_ch = strstr(file_buffer, "ports:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5110: " + "Fail to obtain number of ports in info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "ports: %d", &num_ports) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_ca_info_file: ERR 5111: " + "Fail to parse num ports in info file:(%s).\n", p_ch); + goto Exit; + } + sim_ca_info->num_ports = num_ports; + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__parse_ca_info_file: " + "CA1 = name:%s guid:0x%016llx ports:%d\n", + sim_ca_info->name, sim_ca_info->guid, sim_ca_info->num_ports); + + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return status; +} + +/* + state: ACTIVE + LID: 0x0001 + LMC: 0x0000 + SM LID: 0x0001 + SM SL: 0x0000 + Capabilities: IsSM + IsTrapSupported + IsAutomaticMigrationSupported + IsSLMappingSupported + IsLEDInfoSupported + IsSystemImageGUIDSupported + IsVendorClassSupported + IsCapabilityMaskNoticeSupported +*/ +typedef struct _sim_port_info { + uint8_t state; + uint16_t lid; + uint8_t lmc; + uint16_t sm_lid; + uint8_t sm_sl; +} sim_port_info_t; + +/********************************************************************** + * Parse the Port Info file available in ibmgtSimDir/caN/portM/info + * Port num is 1..N + **********************************************************************/ +static ib_api_status_t +__parse_port_info_file(IN osm_vendor_t * const p_vend, + IN uint32_t hca_idx, + IN uint8_t port_num, OUT sim_port_info_t * sim_port_info) +{ + ib_api_status_t status = IB_ERROR; + int info_file; + char file_name[256]; + char file_buffer[3200]; + char state[12]; + char *p_ch; + int lid, sm_lid, lmc, sm_sl; + uint32_t len; + + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__parse_port_info_file: " + "Parsing Proc File System Port Info CA %d Port %d.\n", hca_idx, + port_num); + + /* we use the proc file system so we must be able to open the info file .. */ + sprintf(file_name, "%s/ca%d/port%d/info", __get_simulator_dir(), + hca_idx, port_num); + info_file = open(file_name, O_RDONLY); + if (!info_file) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5112: " + "Fail to open HCA:%d Port:%d info file:(%s).\n", + hca_idx, port_num, file_name); + goto Exit; + } + + /* read in the file */ + len = read(info_file, file_buffer, 3200); + close(info_file); + file_buffer[len] = '\0'; + + /* + parse the file ... + state: ACTIVE + LID: 0x0001 + LMC: 0x0000 + SM LID: 0x0001 + SM SL: 0x0000 + ... + */ + if (!(p_ch = strstr(file_buffer, "state:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5113: " + "Fail to obtain port state. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "state: %s", state) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5114: " + "Fail to parse state from info file:(%s).\n", p_ch); + goto Exit; + } + + if (!strcmp(state, "ACTIVE")) + sim_port_info->state = IB_LINK_ACTIVE; + else if (!strcmp(state, "DOWN")) + sim_port_info->state = IB_LINK_DOWN; + else if (!strcmp(state, "INIT")) + sim_port_info->state = IB_LINK_INIT; + else if (!strcmp(state, "ARMED")) + sim_port_info->state = IB_LINK_ARMED; + else + sim_port_info->state = 0; + + /* get lid */ + if (!(p_ch = strstr(file_buffer, "LID:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5115: " + "Fail to obtain port lid. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "LID: %x", &lid) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5116: " + "Fail to parse lid from info file:(%s).\n", p_ch); + goto Exit; + } + sim_port_info->lid = lid; + /* get LMC */ + if (!(p_ch = strstr(file_buffer, "LMC:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5117: " + "Fail to obtain port LMC. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "LMC: %x", &lmc) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5118: " + "Fail to parse LMC from info file:(%s).\n", p_ch); + goto Exit; + } + sim_port_info->lmc = lmc; + + /* get SM LID */ + if (!(p_ch = strstr(file_buffer, "SM LID:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5119: " + "Fail to obtain port SM LID. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "SM LID: %x", &sm_lid) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5120: " + "Fail to parse SM LID from info file:(%s).\n", p_ch); + goto Exit; + } + sim_port_info->sm_lid = sm_lid; + + /* get SM LID */ + if (!(p_ch = strstr(file_buffer, "SM SL:"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5121: " + "Fail to obtain port SM SL. In info file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch, "SM SL: %x", &sm_sl) != 1) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__parse_port_info_file: ERR 5122: " + "Fail to parse SM SL from info file:(%s).\n", p_ch); + goto Exit; + } + sim_port_info->sm_sl = sm_sl; + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__parse_port_info_file: " + "Obtained Port:%d = state:%d, lid:0x%04X, lmc:%d, sm_lid:0x%04X, sm_sl:%d\n", + port_num, sim_port_info->state, sim_port_info->lid, + sim_port_info->lmc, sim_port_info->sm_lid, + sim_port_info->sm_sl); + + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return status; +} + +/********************************************************************** + * Parse the port guid_tbl file to obtain the port guid. + * File format is: + * [ 0] fe80:0000:0000:0000:0002:c900:0120:3472 + **********************************************************************/ +static ib_api_status_t +__get_port_guid_from_port_gid_tbl(IN osm_vendor_t * const p_vend, + IN uint32_t hca_idx, + IN uint8_t port_num, OUT uint64_t * port_guid) +{ + ib_api_status_t status = IB_ERROR; + int info_file; + char file_name[256]; + char file_buffer[3200]; + char *p_ch; + int g[8]; + uint32_t len; + + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__get_port_guid_from_port_gid_tbl: " + "Parsing Proc File System Port Guid Table CA %d Port %d.\n", + hca_idx, port_num); + + /* we use the proc file system so we must be able to open the info file .. */ + sprintf(file_name, "%s/ca%d/port%d/gid_table", + __get_simulator_dir(), hca_idx, port_num); + info_file = open(file_name, O_RDONLY); + if (!info_file) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__get_port_guid_from_port_gid_tbl: ERR 5123: " + "Fail to open HCA:%d Port:%d gid_table file:(%s).\n", + hca_idx, port_num, file_name); + goto Exit; + } + + /* read in the file */ + len = read(info_file, file_buffer, 3200); + close(info_file); + file_buffer[len] = '\0'; + + /* + parse the file ... + [ 0] fe80:0000:0000:0000:0002:c900:0120:3472 + ... + */ + if (!(p_ch = strstr(file_buffer, "[ 0]"))) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__get_port_guid_from_port_gid_tbl: ERR 5124: " + "Fail to obtain first gid index. In gid_table file:(%s).\n", + file_buffer); + goto Exit; + } + if (sscanf(p_ch + 6, "%x:%x:%x:%x:%x:%x:%x:%x", + &g[7], &g[6], &g[5], &g[4], &g[3], &g[2], &g[1], &g[0]) != 8) + { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__get_port_guid_from_port_gid_tbl: ERR 5125: " + "Fail to parse gid from gid_table file:(%s).\n", p_ch); + goto Exit; + } + + *port_guid = + (uint64_t) g[3] << 48 | (uint64_t) g[2] << 32 | (uint64_t) g[1] << + 16 | g[0]; + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return status; +} + +/********************************************************************** + * Initialize an Info Struct for the Given HCA by its index 1..N + **********************************************************************/ +static ib_api_status_t +__osm_ca_info_init(IN osm_vendor_t * const p_vend, + IN uint32_t const idx, OUT osm_ca_info_t * const p_ca_info) +{ + ib_api_status_t status = IB_ERROR; + uint8_t port_num; + uint64_t port_guid; + + sim_ca_info_t sim_ca_info; + + OSM_LOG_ENTER(p_vend->p_log); + + /* parse the CA info file */ + if (__parse_ca_info_file(p_vend, idx, &sim_ca_info) != IB_SUCCESS) + goto Exit; + + p_ca_info->guid = cl_hton64(sim_ca_info.guid); + + /* set size of attributes and allocate them */ + p_ca_info->attr_size = 1; + p_ca_info->p_attr = (ib_ca_attr_t *) malloc(sizeof(ib_ca_attr_t)); + + p_ca_info->p_attr->ca_guid = p_ca_info->guid; + p_ca_info->p_attr->num_ports = sim_ca_info.num_ports; + + /* now obtain the attributes of the ports */ + p_ca_info->p_attr->p_port_attr = + (ib_port_attr_t *) malloc(sim_ca_info.num_ports * + sizeof(ib_port_attr_t)); + + /* get all the ports info */ + for (port_num = 1; port_num <= sim_ca_info.num_ports; port_num++) { + sim_port_info_t sim_port_info; + /* query the port attributes */ + if (__parse_port_info_file + (p_vend, idx, port_num, &sim_port_info)) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 5126: " + "Fail to get HCA:%d Port:%d Attributes.\n", idx, + port_num); + goto Exit; + } + + /* HACK: the lids should have been converted to network but the rest of the code + is wrong and provdes them as is (host order) - so we stick with it. */ + p_ca_info->p_attr->p_port_attr[port_num - 1].lid = + sim_port_info.lid; + p_ca_info->p_attr->p_port_attr[port_num - 1].link_state = + sim_port_info.state; + p_ca_info->p_attr->p_port_attr[port_num - 1].sm_lid = + sim_port_info.sm_lid; + + /* get the port guid */ + if (__get_port_guid_from_port_gid_tbl + (p_vend, idx, port_num, &port_guid)) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 5127: " + "Fail to get HCA:%d Port:%d Guid.\n", idx, + port_num); + goto Exit; + } + p_ca_info->p_attr->p_port_attr[port_num - 1].port_guid = + cl_hton64(port_guid); + } + + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +void +osm_ca_info_destroy(IN osm_vendor_t * const p_vend, + IN osm_ca_info_t * const p_ca_info, IN uint8_t num_ca) +{ + osm_ca_info_t *p_ca; + uint8_t i; + + OSM_LOG_ENTER(p_vend->p_log); + + for (i = 0; i < num_ca; i++) { + p_ca = &p_ca_info[i]; + + if (NULL != p_ca->p_attr) { + if (0 != p_ca->p_attr->num_ports) { + free(p_ca->p_attr->p_port_attr); + } + + free(p_ca->p_attr); + } + } + + free(p_ca_info); + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + * Fill in the array of port_attr with all available ports on ALL the + * avilable CAs on this machine. + **********************************************************************/ +ib_api_status_t +osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * const p_attr_array, + IN uint32_t * const p_num_ports) +{ + ib_api_status_t status = IB_SUCCESS; + + uint32_t caIdx; + uint32_t ca_count = 0; + uint32_t port_count = 0; + uint8_t port_num; + uint32_t total_ports = 0; + osm_ca_info_t *p_ca_infos = NULL; + uint32_t attr_array_sz = *p_num_ports; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + + /* determine the number of CA's */ + ca_count = __hca_sim_get_num_cas(); + if (!ca_count) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 5128: " + "Fail to get Any CA Ids.\n"); + goto Exit; + } + + /* Allocate an array big enough to hold the ca info objects */ + p_ca_infos = malloc(ca_count * sizeof(osm_ca_info_t)); + if (p_ca_infos == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 5129: " + "Unable to allocate CA information array.\n"); + goto Exit; + } + + memset(p_ca_infos, 0, ca_count * sizeof(osm_ca_info_t)); + + /* + * For each CA, retrieve the CA info attributes + */ + for (caIdx = 1; caIdx <= ca_count; caIdx++) { + status = + __osm_ca_info_init(p_vend, caIdx, &p_ca_infos[caIdx - 1]); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 5130: " + "Unable to initialize CA Info object (%s).\n", + ib_get_err_str(status)); + goto Exit; + } + total_ports += p_ca_infos[caIdx - 1].p_attr->num_ports; + } + + *p_num_ports = total_ports; + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get_all_port_attr: total ports:%u \n", total_ports); + + /* + * If the user supplied enough storage, return the port guids, + * otherwise, return the appropriate error. + */ + if (attr_array_sz >= total_ports) { + for (caIdx = 1; caIdx <= ca_count; caIdx++) { + uint32_t num_ports; + + num_ports = p_ca_infos[caIdx - 1].p_attr->num_ports; + + for (port_num = 0; port_num < num_ports; port_num++) { + p_attr_array[port_count] = + *__osm_ca_info_get_port_attr_ptr(&p_ca_infos + [caIdx - + 1], + port_num); + port_count++; + } + } + } else { + status = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + + status = IB_SUCCESS; + +Exit: + if (p_ca_infos) { + osm_ca_info_destroy(p_vend, p_ca_infos, ca_count); + } + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + * Given the vendor obj and a port guid + * return the ca id and port number that have that guid + **********************************************************************/ + +ib_api_status_t +osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend, + IN ib_net64_t const guid, + OUT uint32_t * p_hca_hndl, + OUT char *p_hca_id, + OUT uint8_t * p_hca_idx, + OUT uint32_t * p_port_num) +{ + uint32_t caIdx; + uint32_t ca_count = 0; + uint8_t port_num; + ib_api_status_t status = IB_ERROR; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + + /* determine the number of CA's */ + ca_count = __hca_sim_get_num_cas(); + if (!ca_count) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 5131: " + "Fail to get Any CA Ids.\n"); + goto Exit; + } + + /* + * For each CA, retrieve the CA info attributes + */ + for (caIdx = 1; caIdx <= ca_count; caIdx++) { + sim_ca_info_t sim_ca_info; + if (__parse_ca_info_file(p_vend, caIdx, &sim_ca_info) == + IB_SUCCESS) { + /* get all the ports info */ + for (port_num = 1; port_num <= sim_ca_info.num_ports; + port_num++) { + uint64_t port_guid; + if (!__get_port_guid_from_port_gid_tbl + (p_vend, caIdx, port_num, &port_guid)) { + if (cl_hton64(port_guid) == guid) { + osm_log(p_vend->p_log, + OSM_LOG_DEBUG, + "osm_vendor_get_guid_ca_and_port: " + "Found Matching guid on HCA:%d Port:%d.\n", + caIdx, port_num); + strcpy(p_hca_id, + sim_ca_info.name); + *p_port_num = port_num; + *p_hca_idx = caIdx - 1; + *p_hca_hndl = 0; + status = IB_SUCCESS; + goto Exit; + } + } + } + } + } + + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 5132: " + "Fail to find HCA and Port for Port Guid 0x%" PRIx64 "\n", + cl_ntoh64(guid)); + status = IB_INVALID_GUID; + +Exit: + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + * Given the vendor obj HCA ID and Port Num + * update the given port guid if found. Return 0 on success. + **********************************************************************/ + +ib_api_status_t +osm_vendor_get_guid_by_ca_and_port(IN osm_vendor_t * const p_vend, + IN char *hca_id, + IN uint32_t port_num, + OUT uint64_t * p_port_guid) +{ + uint32_t caIdx; + uint32_t ca_count = 0; + ib_api_status_t status = IB_ERROR; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + + /* determine the number of CA's */ + ca_count = __hca_sim_get_num_cas(); + if (!ca_count) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_by_ca_and_port: ERR 5133: " + "Fail to get Any CA Ids.\n"); + goto Exit; + } + + /* + * For each CA, retrieve the CA info attributes + */ + for (caIdx = 1; caIdx <= ca_count; caIdx++) { + sim_ca_info_t sim_ca_info; + if (__parse_ca_info_file(p_vend, caIdx, &sim_ca_info) == + IB_SUCCESS) { + /* if not identical by id - go to next one */ + if (strcmp(sim_ca_info.name, hca_id)) + continue; + + if ((port_num < 1) + || (port_num > sim_ca_info.num_ports)) { + return 1; + } + + if (!__get_port_guid_from_port_gid_tbl + (p_vend, caIdx, port_num, p_port_guid)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get_guid_by_ca_and_port: " + "Found Matching guid on HCA:%d Port:%d.\n", + caIdx, port_num); + status = IB_SUCCESS; + goto Exit; + } + } + } + + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_by_ca_and_port: ERR 5134: " + "Fail to find HCA:%s\n", hca_id); + status = IB_INVALID_GUID; + +Exit: + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +#endif diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_ibmgt.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_ibmgt.c new file mode 100644 index 000000000000..9df6624f670c --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_ibmgt.c @@ -0,0 +1,783 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* AUTHOR Edward Bortnikov + * + * DESCRIPTION + * The lower-level MAD transport interface implementation + * that allows sending a single MAD/receiving a callback + * when a single MAD is received. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +typedef struct _osmv_IBMGT_transport_mgr_ { + IB_MGT_mad_type_t mad_type; + uint8_t mgmt_class; /* for gsi */ + /* for communication between send call back and send mad */ + boolean_t is_send_ok; + cl_event_t send_done; +} osmv_IBMGT_transport_mgr_t; + +typedef struct _osmv_IBMGT_transport_info_ { + IB_MGT_mad_hndl_t smi_h; + cl_qlist_t *p_smi_list; + + IB_MGT_mad_hndl_t gsi_h; + /* holds bind object list for every binded mgmt class */ + cl_qlist_t *gsi_mgmt_lists[15]; +} osmv_IBMGT_transport_info_t; + +static void +__osmv_IBMGT_rcv_desc_to_osm_addr(IN IB_MGT_mad_rcv_desc_t * p_rcv_desc, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_mad_addr); + +static void +__osmv_IBMGT_osm_addr_to_ibmgt_addr(IN const osm_mad_addr_t * p_mad_addr, + IN uint8_t is_smi, OUT IB_ud_av_t * p_av); + +void +__osmv_IBMGT_send_cb(IN IB_MGT_mad_hndl_t mad_hndl, + IN u_int64_t wrid, + IN IB_comp_status_t status, IN void *private_ctx_p); + +void +__osmv_IBMGT_rcv_cb(IN IB_MGT_mad_hndl_t mad_hndl, + IN void *private_ctx_p, + IN void *payload_p, + IN IB_MGT_mad_rcv_desc_t * rcv_remote_info_p); + +/* + * NAME + * osmv_transport_init + * + * DESCRIPTION + * Setup the MAD transport infrastructure (filters, callbacks etc). + */ + +ib_api_status_t +osmv_transport_init(IN osm_bind_info_t * p_info, + IN char hca_id[VENDOR_HCA_MAXNAMES], + IN uint8_t hca_idx, IN osmv_bind_obj_t * p_bo) +{ + ib_api_status_t st = IB_SUCCESS; + IB_MGT_ret_t ret; + IB_MGT_mad_type_t mad_type; + osmv_IBMGT_transport_mgr_t *p_mgr; + osmv_IBMGT_transport_info_t *p_tpot_info; + cl_list_obj_t *p_obj = NULL; + osm_log_t *p_log = p_bo->p_vendor->p_log; + int i; + + UNUSED_PARAM(hca_idx); + + /* if first bind, allocate tranport_info at vendor */ + if (NULL == p_bo->p_vendor->p_transport_info) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_init: first bind() for the vendor\n"); + p_bo->p_vendor->p_transport_info + = (osmv_IBMGT_transport_info_t *) + malloc(sizeof(osmv_IBMGT_transport_info_t)); + if (NULL == p_bo->p_vendor->p_transport_info) { + return IB_INSUFFICIENT_MEMORY; + } + memset(p_bo->p_vendor->p_transport_info, 0, + sizeof(osmv_IBMGT_transport_info_t)); + p_tpot_info = + (osmv_IBMGT_transport_info_t *) (p_bo->p_vendor-> + p_transport_info); + + p_tpot_info->smi_h = 0xffffffff; + p_tpot_info->p_smi_list = NULL; + + p_tpot_info->gsi_h = 0xffffffff; + for (i = 0; i < 15; i++) { + + p_tpot_info->gsi_mgmt_lists[i] = NULL; + } + + } else { + + p_tpot_info = + (osmv_IBMGT_transport_info_t *) (p_bo->p_vendor-> + p_transport_info); + } + + /* Initialize the magic_ptr to the pointer of the p_bo info. + This will be used to signal when the object is being destroyed, so no + real action will be done then. */ + p_bo->magic_ptr = p_bo; + + /* allocate transport mgr */ + p_mgr = malloc(sizeof(osmv_IBMGT_transport_mgr_t)); + if (NULL == p_mgr) { + free(p_tpot_info); + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7201: " "alloc failed \n"); + return IB_INSUFFICIENT_MEMORY; + } + + memset(p_mgr, 0, sizeof(osmv_IBMGT_transport_mgr_t)); + + p_bo->p_transp_mgr = p_mgr; + + switch (p_info->mad_class) { + case IB_MCLASS_SUBN_LID: + case IB_MCLASS_SUBN_DIR: + mad_type = IB_MGT_SMI; + break; + + case IB_MCLASS_SUBN_ADM: + default: + mad_type = IB_MGT_GSI; + break; + } + + /* we only support one class registration per SMI/GSI !!! */ + switch (mad_type) { + case IB_MGT_SMI: + /* we do not need to bind the handle if already available */ + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_init: SMI bind\n"); + + if (p_tpot_info->smi_h == 0xffffffff) { + ret = IB_MGT_get_handle(hca_id, + p_bo->port_num, + IB_MGT_SMI, + &(p_tpot_info->smi_h)); + if (IB_MGT_OK != ret) { + osm_log(p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7202: " + "IB_MGT_get_handle for smi failed \n"); + st = IB_ERROR; + free(p_mgr); + goto Exit; + } + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_init: got smi handle:%d \n", + p_tpot_info->smi_h); + + ret = IB_MGT_bind_sm(p_tpot_info->smi_h); + if (IB_MGT_OK != ret) { + osm_log(p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7203: " + "IB_MGT_bind_sm failed \n"); + st = IB_ERROR; + free(p_mgr); + goto Exit; + } + + /* init smi list */ + p_tpot_info->p_smi_list = malloc(sizeof(cl_qlist_t)); + if (NULL == p_tpot_info->p_smi_list) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7204: " + "alloc failed \n"); + IB_MGT_unbind_sm(p_tpot_info->smi_h); + IB_MGT_release_handle(p_tpot_info->smi_h); + free(p_mgr); + return IB_INSUFFICIENT_MEMORY; + } + memset(p_tpot_info->p_smi_list, 0, sizeof(cl_qlist_t)); + cl_qlist_init(p_tpot_info->p_smi_list); + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_init: before reg_cb\n"); + ret = IB_MGT_reg_cb(p_tpot_info->smi_h, + &__osmv_IBMGT_rcv_cb, + p_bo, + &__osmv_IBMGT_send_cb, + p_tpot_info->p_smi_list, + IB_MGT_RCV_CB_MASK | + IB_MGT_SEND_CB_MASK); + if (ret != IB_SUCCESS) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7205: " + "reg_cb failed with return code:%x \n", + ret); + IB_MGT_unbind_sm(p_tpot_info->smi_h); + IB_MGT_release_handle(p_tpot_info->smi_h); + free(p_tpot_info->p_smi_list); + free(p_mgr); + st = IB_ERROR; + goto Exit; + } + + } + /* insert to list of smi's - for raising callbacks later on */ + p_obj = malloc(sizeof(cl_list_obj_t)); + if (p_obj) + memset(p_obj, 0, sizeof(cl_list_obj_t)); + cl_qlist_set_obj(p_obj, p_bo); + cl_qlist_insert_tail(p_tpot_info->p_smi_list, + &p_obj->list_item); + + break; + + case IB_MGT_GSI: + /* we do not need to bind the handle if already available */ + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_init: ERR 7206: GSI bind\n"); + if (p_tpot_info->gsi_h == 0xffffffff) { + ret = IB_MGT_get_handle(hca_id, + p_bo->port_num, + IB_MGT_GSI, + &(p_tpot_info->gsi_h)); + if (IB_MGT_OK != ret) { + osm_log(p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7207: " + "IB_MGT_get_handle for gsi failed \n"); + st = IB_ERROR; + free(p_mgr); + goto Exit; + } + } + + /* this mgmt class was not binded yet */ + if (p_tpot_info->gsi_mgmt_lists[p_info->mad_class] == NULL) { + ret = + IB_MGT_bind_gsi_class(p_tpot_info->gsi_h, + p_info->mad_class); + if (IB_MGT_OK != ret) { + osm_log(p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7208: " + "IB_MGT_bind_gsi_class failed \n"); + st = IB_ERROR; + free(p_mgr); + goto Exit; + } + + p_tpot_info->gsi_mgmt_lists[p_info->mad_class] = + malloc(sizeof(cl_qlist_t)); + if (NULL == + p_tpot_info->gsi_mgmt_lists[p_info->mad_class]) { + IB_MGT_unbind_gsi_class(p_tpot_info->gsi_h, + p_info->mad_class); + free(p_mgr); + return IB_INSUFFICIENT_MEMORY; + } + memset(p_tpot_info->gsi_mgmt_lists[p_info->mad_class], + 0, sizeof(cl_qlist_t)); + cl_qlist_init(p_tpot_info-> + gsi_mgmt_lists[p_info->mad_class]); + } + /* insert to list of smi's - for raising callbacks later on */ + p_obj = malloc(sizeof(cl_list_obj_t)); + if (p_obj) + memset(p_obj, 0, sizeof(cl_list_obj_t)); + cl_qlist_set_obj(p_obj, p_bo); + cl_qlist_insert_tail(p_tpot_info-> + gsi_mgmt_lists[p_info->mad_class], + &p_obj->list_item); + + p_mgr->mgmt_class = p_info->mad_class; + ret = IB_MGT_reg_cb(p_tpot_info->gsi_h, + &__osmv_IBMGT_rcv_cb, + p_bo, + &__osmv_IBMGT_send_cb, + p_bo, + IB_MGT_RCV_CB_MASK | IB_MGT_SEND_CB_MASK); + + if (ret != IB_SUCCESS) { + IB_MGT_unbind_gsi_class(p_tpot_info->gsi_h, + p_mgr->mgmt_class); + free(p_tpot_info->gsi_mgmt_lists[p_mgr->mgmt_class]); + free(p_mgr); + st = IB_ERROR; + goto Exit; + } + + break; + + default: + osm_log(p_log, OSM_LOG_ERROR, + "osmv_transport_init: ERR 7209: unrecognized mgmt class \n"); + st = IB_ERROR; + free(p_mgr); + goto Exit; + } + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_init: GSI bind\n"); + cl_event_construct(&p_mgr->send_done); + cl_event_init(&p_mgr->send_done, TRUE); + p_mgr->is_send_ok = FALSE; + p_mgr->mad_type = mad_type; + +Exit: + /* OSM_LOG_EXIT(p_log ); */ + return (ib_api_status_t) st; +} + +/* + * NAME + * osmv_transport_send_mad + * + * DESCRIPTION + * Send a single MAD (256 byte) + */ + +ib_api_status_t +osmv_transport_mad_send(IN const osm_bind_handle_t h_bind, + IN void *p_ib_mad, IN const osm_mad_addr_t * p_mad_addr) +{ + + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osmv_IBMGT_transport_info_t *p_tpot_info = + (osmv_IBMGT_transport_info_t *) (p_bo->p_vendor->p_transport_info); + osm_vendor_t const *p_vend = p_bo->p_vendor; + ib_api_status_t status; + IB_ud_av_t av; + IB_MGT_ret_t ret; + ib_mad_t *p_mad = p_ib_mad; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_bo->p_vendor->p_transport_info); + + /* + * For all sends other than directed route SM MADs, + * acquire an address vector for the destination. + */ + if (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) { + __osmv_IBMGT_osm_addr_to_ibmgt_addr(p_mad_addr, + p_mad->mgmt_class == + IB_MCLASS_SUBN_LID, &av); + } else { + /* is a directed route - we need to construct a permissive address */ + memset(&av, 0, sizeof(av)); + /* we do not need port number since it is part of the mad_hndl */ + av.dlid = IB_LID_PERMISSIVE; + } + + /* send it */ + if ((p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) || + (p_mad->mgmt_class == IB_MCLASS_SUBN_LID)) { + + /* SMI CASE */ + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osmv_transport_mad_send: " + "av.dlid:0x%X, " + "av.static_rate:%d, " + "av.path_bits:%d.\n", + cl_ntoh16(av.dlid), av.static_rate, + av.src_path_bits); + } + + ret = IB_MGT_send_mad(p_tpot_info->smi_h, p_mad, /* actual payload */ + &av, /* address vector */ + (u_int64_t) CAST_P2LONG(p_bo), + IB_MGT_DEFAULT_SEND_TIME); + } else { + /* GSI CASE - Support Remote QP */ + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osmv_transport_mad_send: " + "av.dlid:0x%X, av.static_rate:%d, av.path_bits:%d, remote qp:%d \n", + cl_ntoh16(av.dlid), av.static_rate, + av.src_path_bits, + cl_ntoh32(p_mad_addr->addr_type.gsi.remote_qp) + ); + } + + ret = IB_MGT_send_mad_to_qp(p_tpot_info->gsi_h, p_mad, /* actual payload */ + &av, /* address vector */ + (u_int64_t) CAST_P2LONG(p_bo), + IB_MGT_DEFAULT_SEND_TIME, + cl_ntoh32(p_mad_addr->addr_type.gsi. + remote_qp)); + + } + + status = IB_SUCCESS; + if (ret != IB_MGT_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osmv_transport_mad_send: ERR 7210: " + "Error sending mad (%d).\n", ret); + status = IB_ERROR; + } else { + osmv_IBMGT_transport_mgr_t *p_mgr = + (osmv_IBMGT_transport_mgr_t *) (p_bo->p_transp_mgr); + + /* Let the others work when I am sleeping ... */ + osmv_txn_unlock(p_bo); + + cl_event_wait_on(&(p_mgr->send_done), 0xffffffff, TRUE); + + /* Re-acquire the lock */ + osmv_txn_lock(p_bo); + + if (TRUE == p_bo->is_closing) { + + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osmv_transport_mad_send: ERR 7211: " + "The handle %p is being unbound, cannot send.\n", + h_bind); + status = IB_ERROR; + } + + if (p_mgr->is_send_ok == FALSE) { + status = IB_ERROR; + } + } + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +void osmv_transport_done(IN const osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_log_t *p_log = p_bo->p_vendor->p_log; + osmv_IBMGT_transport_mgr_t *p_mgr; + osmv_IBMGT_transport_info_t *p_tpot_info; + IB_MGT_ret_t ret; + cl_list_obj_t *p_obj = NULL; + cl_list_item_t *p_item, *p_item_tmp; + int i; + cl_qlist_t *p_list = NULL; + + OSM_LOG_ENTER(p_log); + + CL_ASSERT(p_bo); + + /* First of all - zero out the magic_ptr, so if a callback is called - + it'll know that we are currently closing down, and will not handle the + mad. */ + p_bo->magic_ptr = 0; + + p_mgr = (osmv_IBMGT_transport_mgr_t *) (p_bo->p_transp_mgr); + p_tpot_info = + (osmv_IBMGT_transport_info_t *) (p_bo->p_vendor->p_transport_info); + + switch (p_mgr->mad_type) { + case IB_MGT_SMI: + p_list = p_tpot_info->p_smi_list; + + /* remove from the bindings list */ + p_item = cl_qlist_head(p_list); + while (p_item != cl_qlist_end(p_list)) { + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + if (cl_qlist_obj(p_obj) == h_bind) { + break; + } + p_item_tmp = cl_qlist_next(p_item); + p_item = p_item_tmp; + } + + CL_ASSERT(p_item != cl_qlist_end(p_list)); + cl_qlist_remove_item(p_list, p_item); + if (p_obj) + free(p_obj); + + /* no one is binded to smi anymore - we can free the list, unbind & realease the hndl */ + if (cl_is_qlist_empty(p_list) == TRUE) { + free(p_list); + p_list = NULL; + + ret = IB_MGT_unbind_sm(p_tpot_info->smi_h); + if (ret != IB_MGT_OK) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_transport_done: ERR 7212: " + "Failed to unbind sm\n"); + } + + ret = IB_MGT_release_handle(p_tpot_info->smi_h); + if (ret != IB_MGT_OK) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_transport_done: ERR 7213: " + "Failed to release smi handle\n"); + } + p_tpot_info->smi_h = 0xffffffff; + } + break; + + case IB_MGT_GSI: + p_list = p_tpot_info->gsi_mgmt_lists[p_mgr->mgmt_class]; + /* remove from the bindings list */ + p_item = cl_qlist_head(p_list); + while (p_item != cl_qlist_end(p_list)) { + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + if (cl_qlist_obj(p_obj) == h_bind) { + break; + } + p_item_tmp = cl_qlist_next(p_item); + p_item = p_item_tmp; + } + + CL_ASSERT(p_item != cl_qlist_end(p_list)); + cl_qlist_remove_item(p_list, p_item); + if (p_obj) + free(p_obj); + + /* no one is binded to this class anymore - we can free the list and unbind this class */ + if (cl_is_qlist_empty(p_list) == TRUE) { + free(p_list); + p_list = NULL; + + ret = + IB_MGT_unbind_gsi_class(p_tpot_info->gsi_h, + p_mgr->mgmt_class); + if (ret != IB_MGT_OK) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_transport_done: ERR 7214: " + "Failed to unbind gsi class\n"); + } + } + + /* all the mgmt classes are unbinded - release gsi handle */ + for (i = 0; i < 15; i++) { + if (p_tpot_info->gsi_mgmt_lists[i] != NULL) { + break; + } + } + + if (i == 15) { + ret = IB_MGT_release_handle(p_tpot_info->gsi_h); + if (ret != IB_MGT_OK) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_transport_done: ERR 7215: " + "Failed to release gsi handle\n"); + } + p_tpot_info->gsi_h = 0xffffffff; + } + } /* end switch */ + + free(p_mgr); +} + +/********************************************************************** + * IB_MGT Receive callback : invoked after each receive + **********************************************************************/ +void +__osmv_IBMGT_rcv_cb(IN IB_MGT_mad_hndl_t mad_hndl, + IN void *private_ctx_p, + IN void *payload_p, + IN IB_MGT_mad_rcv_desc_t * rcv_remote_info_p) +{ + osmv_bind_obj_t *p_bo; + osm_mad_addr_t mad_addr; + cl_list_item_t *p_item; + cl_list_obj_t *p_obj; + cl_qlist_t *p_list; + ib_mad_t *p_mad = (ib_mad_t *) payload_p; + osm_vendor_t *p_vendor; + osmv_IBMGT_transport_info_t *p_tinfo; + + __osmv_IBMGT_rcv_desc_to_osm_addr(rcv_remote_info_p, + ((p_mad->mgmt_class == + IB_MCLASS_SUBN_LID) + || (p_mad->mgmt_class == + IB_MCLASS_SUBN_DIR)), &mad_addr); + + /* different handling of SMI and GSI */ + if ((p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) || + (p_mad->mgmt_class == IB_MCLASS_SUBN_LID)) { + /* SMI CASE */ + p_bo = (osmv_bind_obj_t *) private_ctx_p; + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + p_vendor = p_bo->p_vendor; + p_tinfo = + (osmv_IBMGT_transport_info_t *) p_vendor->p_transport_info; + p_list = p_tinfo->p_smi_list; + } else { + /* GSI CASE */ + p_bo = (osmv_bind_obj_t *) private_ctx_p; + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + p_vendor = p_bo->p_vendor; + p_tinfo = + (osmv_IBMGT_transport_info_t *) p_vendor->p_transport_info; + p_list = p_tinfo->gsi_mgmt_lists[p_mad->mgmt_class]; + } + + /* go over the bindings list and send the mad, one of them will accept it, + the others will drope + */ + p_item = cl_qlist_head(p_list); + while (p_item != cl_qlist_end(p_list)) { + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + p_bo = cl_qlist_obj(p_obj); + /* give upper layer the mad */ + osmv_dispatch_mad((osm_bind_handle_t) p_bo, payload_p, + &mad_addr); + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + p_item = cl_qlist_next(p_item); + } +} + +/********************************************************************** + * IB_MGT Send callback : invoked after each send + **********************************************************************/ +void +__osmv_IBMGT_send_cb(IN IB_MGT_mad_hndl_t mad_hndl, + IN u_int64_t wrid, + IN IB_comp_status_t status, IN void *private_ctx_p) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) CAST_P2LONG(wrid); + + osmv_IBMGT_transport_mgr_t *p_mgr = + (osmv_IBMGT_transport_mgr_t *) p_bo->p_transp_mgr; + + /* Make sure the p_bo object is still relevant */ + if (p_bo->magic_ptr != p_bo) + return; + + /* we assume that each send on a bind object is synchronized, and no paralel sends + from diffrent threads with same object can be made */ + if (status == IB_COMP_SUCCESS) { + p_mgr->is_send_ok = TRUE; + } else + p_mgr->is_send_ok = FALSE; + cl_event_signal(&p_mgr->send_done); + +} + +/********************************************************************** + * IB_MGT to OSM ADDRESS VECTOR + **********************************************************************/ +static void +__osmv_IBMGT_rcv_desc_to_osm_addr(IN IB_MGT_mad_rcv_desc_t * p_rcv_desc, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_mad_addr) +{ + /* p_mad_addr->dest_lid = p_osm->subn.sm_base_lid; - for resp we use the dest lid ... */ + p_mad_addr->dest_lid = cl_hton16(p_rcv_desc->remote_lid); + p_mad_addr->static_rate = 0; /* HACK - we do not know the rate ! */ + p_mad_addr->path_bits = p_rcv_desc->local_path_bits; + /* Clear the grh any way to avoid unset fields */ + memset(&p_mad_addr->addr_type.gsi.grh_info, 0, + sizeof(p_mad_addr->addr_type.gsi.grh_info)); + + if (is_smi) { + /* SMI */ + p_mad_addr->addr_type.smi.source_lid = + cl_hton16(p_rcv_desc->remote_lid); + p_mad_addr->addr_type.smi.port_num = 99; /* HACK - if used - should fail */ + } else { + /* GSI */ + /* seems to me there is a IBMGT bug reversing the QPN ... */ + /* Does IBMGT supposed to provide the QPN is network or HOST ? */ + p_mad_addr->addr_type.gsi.remote_qp = cl_hton32(p_rcv_desc->qp); + + p_mad_addr->addr_type.gsi.remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + /* we do have the p_mad_addr->pkey_ix but how to get the PKey by index ? */ + /* the only way seems to be to use VAPI_query_hca_pkey_tbl and obtain */ + /* the full PKey table - than go by the index. */ + /* since this does not seem reasonable to me I simply use the default */ + /* There is a TAVOR limitation that only one P_KEY is supported per */ + /* QP - so QP1 must use IB_DEFAULT_PKEY */ + p_mad_addr->addr_type.gsi.pkey_ix = 0; + p_mad_addr->addr_type.gsi.service_level = p_rcv_desc->sl; + + p_mad_addr->addr_type.gsi.global_route = p_rcv_desc->grh_flag; + /* copy the GRH data if relevant */ + if (p_mad_addr->addr_type.gsi.global_route) { + p_mad_addr->addr_type.gsi.grh_info.ver_class_flow = + ib_grh_set_ver_class_flow(p_rcv_desc->grh. + IP_version, + p_rcv_desc->grh. + traffic_class, + p_rcv_desc->grh. + flow_label); + p_mad_addr->addr_type.gsi.grh_info.hop_limit = + p_rcv_desc->grh.hop_limit; + memcpy(&p_mad_addr->addr_type.gsi.grh_info.src_gid.raw, + &p_rcv_desc->grh.sgid, sizeof(ib_net64_t)); + memcpy(&p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw, + p_rcv_desc->grh.dgid, sizeof(ib_net64_t)); + } + } +} + +/********************************************************************** + * OSM ADDR VECTOR TO IB_MGT + **********************************************************************/ +void +__osmv_IBMGT_osm_addr_to_ibmgt_addr(IN const osm_mad_addr_t * p_mad_addr, + IN uint8_t is_smi, OUT IB_ud_av_t * p_av) +{ + + /* For global destination or Multicast address: */ + u_int8_t ver; + + memset(p_av, 0, sizeof(IB_ud_av_t)); + + p_av->src_path_bits = p_mad_addr->path_bits; + p_av->static_rate = p_mad_addr->static_rate; + p_av->dlid = cl_ntoh16(p_mad_addr->dest_lid); + + if (is_smi) { + p_av->sl = 0; /* Just to note we use 0 here. */ + } else { + p_av->sl = p_mad_addr->addr_type.gsi.service_level; + p_av->grh_flag = p_mad_addr->addr_type.gsi.global_route; + + if (p_mad_addr->addr_type.gsi.global_route) { + ib_grh_get_ver_class_flow(p_mad_addr->addr_type.gsi. + grh_info.ver_class_flow, &ver, + &p_av->traffic_class, + &p_av->flow_label); + p_av->hop_limit = + p_mad_addr->addr_type.gsi.grh_info.hop_limit; + p_av->sgid_index = 0; /* we always use source GID 0 */ + memcpy(&p_av->dgid, + &p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw, + sizeof(ib_net64_t)); + + } + } +} diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_rmpp_ctx.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_rmpp_ctx.c new file mode 100644 index 000000000000..bbd42c34fc69 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_rmpp_ctx.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#include +#include + +ib_api_status_t +osmv_rmpp_send_ctx_init(osmv_rmpp_send_ctx_t * p_ctx, void *p_arbt_mad, + uint32_t mad_sz, osm_log_t * p_log) +{ + ib_api_status_t st = IB_SUCCESS; + cl_status_t cl_st; + + CL_ASSERT(p_ctx); + if (NULL == p_arbt_mad) { + return IB_INVALID_PARAMETER; + } + + if (osmv_mad_is_sa((ib_mad_t *) p_arbt_mad)) { + p_ctx->is_sa_mad = TRUE; + } else + p_ctx->is_sa_mad = FALSE; + + p_ctx->mad_sz = mad_sz; + + cl_event_construct(&p_ctx->event); + cl_st = cl_event_init(&p_ctx->event, FALSE); + if (cl_st != CL_SUCCESS) { + return IB_ERROR; + } + + st = osmv_rmpp_sar_init(&p_ctx->sar, p_arbt_mad, p_ctx->mad_sz, + p_ctx->is_sa_mad); + if (st == IB_SUCCESS) { + p_ctx->window_first = 1; + p_ctx->window_last = 1; + } + + p_ctx->p_log = p_log; + return st; +} + +void osmv_rmpp_send_ctx_done(IN osmv_rmpp_send_ctx_t * p_ctx) +{ + CL_ASSERT(p_ctx); + cl_event_destroy(&p_ctx->event); + osmv_rmpp_sar_done(&p_ctx->sar); + free(p_ctx); +} + +uint32_t osmv_rmpp_send_ctx_get_num_segs(IN osmv_rmpp_send_ctx_t * p_send_ctx) +{ + uint32_t data_len, data_sz, num; + + CL_ASSERT(p_send_ctx); + + if (p_send_ctx->is_sa_mad) { + data_len = p_send_ctx->mad_sz - IB_SA_MAD_HDR_SIZE; + data_sz = IB_SA_DATA_SIZE; + } else { + data_len = p_send_ctx->mad_sz - MAD_RMPP_HDR_SIZE; + data_sz = MAD_RMPP_DATA_SIZE; + } + + num = data_len / data_sz; + if (0 == data_len || (data_len % data_sz) > 0) { + num++; + } + + return num; +} + +ib_api_status_t +osmv_rmpp_send_ctx_get_seg(IN osmv_rmpp_send_ctx_t * p_send_ctx, + IN uint32_t seg_idx, + IN uint32_t resp_timeout, OUT void *p_buf) +{ + ib_api_status_t st = IB_SUCCESS; + uint32_t num_segs, paylen = 0; + ib_rmpp_mad_t *p_rmpp_mad; + + OSM_LOG_ENTER(p_send_ctx->p_log); + CL_ASSERT(p_send_ctx); + + st = osmv_rmpp_sar_get_mad_seg(&p_send_ctx->sar, seg_idx, p_buf); + if (st != IB_SUCCESS) { + goto Exit; + } + + p_rmpp_mad = (ib_rmpp_mad_t *) p_buf; + /* Set the relevant bits in the RMPP hdr */ + p_rmpp_mad->rmpp_status = IB_RMPP_STATUS_SUCCESS; + p_rmpp_mad->rmpp_flags |= IB_RMPP_FLAG_ACTIVE; + p_rmpp_mad->rmpp_flags |= resp_timeout << 3; + + num_segs = osmv_rmpp_send_ctx_get_num_segs(p_send_ctx); + + if (1 == seg_idx) { + p_rmpp_mad->rmpp_flags |= IB_RMPP_FLAG_FIRST; + + /* This is the first segment - + the reported paylen is the total amount of data. + */ + if (p_send_ctx->is_sa_mad) { + /* sa mad hdr sz */ + paylen = p_send_ctx->mad_sz - IB_SA_MAD_HDR_SIZE; + paylen += + num_segs * (IB_SA_MAD_HDR_SIZE - MAD_RMPP_HDR_SIZE); + } else { + /* mad hdr sz */ + paylen = p_send_ctx->mad_sz - MAD_RMPP_HDR_SIZE; + } + } + + if (seg_idx == num_segs) { + p_rmpp_mad->rmpp_flags |= IB_RMPP_FLAG_LAST; + + /* + This is the last segment - + the reported paylen is only the amount of data left on this segment. + */ + if (p_send_ctx->is_sa_mad) { + paylen = p_send_ctx->mad_sz - IB_SA_MAD_HDR_SIZE; + paylen -= (num_segs - 1) * IB_SA_DATA_SIZE; + paylen += (IB_SA_MAD_HDR_SIZE - MAD_RMPP_HDR_SIZE); + } else { + paylen = p_send_ctx->mad_sz - MAD_RMPP_HDR_SIZE; + paylen -= + (num_segs - 1) * (MAD_BLOCK_SIZE - + MAD_RMPP_HDR_SIZE); + } + } + + p_rmpp_mad->rmpp_type = IB_RMPP_TYPE_DATA; + p_rmpp_mad->rmpp_version = 1; + p_rmpp_mad->paylen_newwin = cl_ntoh32(paylen); + p_rmpp_mad->seg_num = cl_ntoh32(seg_idx); + +Exit: + OSM_LOG_EXIT(p_send_ctx->p_log); + return st; +} + +ib_api_status_t +osmv_rmpp_recv_ctx_init(osmv_rmpp_recv_ctx_t * p_ctx, osm_log_t * p_log) +{ + ib_api_status_t st = IB_SUCCESS; + + CL_ASSERT(p_ctx); + + p_ctx->is_sa_mad = FALSE; + + p_ctx->p_rbuf = malloc(sizeof(cl_qlist_t)); + if (p_ctx->p_rbuf) { + memset(p_ctx->p_rbuf, 0, sizeof(cl_qlist_t)); + cl_qlist_init(p_ctx->p_rbuf); + p_ctx->expected_seg = 1; + } else + st = IB_INSUFFICIENT_MEMORY; + + p_ctx->p_log = p_log; + + return st; +} + +void osmv_rmpp_recv_ctx_done(IN osmv_rmpp_recv_ctx_t * p_ctx) +{ + cl_list_item_t *p_list_item; + cl_list_obj_t *p_obj; + + CL_ASSERT(p_ctx); + + /* go over all the items in the list and remove them */ + p_list_item = cl_qlist_remove_head(p_ctx->p_rbuf); + while (p_list_item != cl_qlist_end(p_ctx->p_rbuf)) { + + p_obj = PARENT_STRUCT(p_list_item, cl_list_obj_t, list_item); + + free(cl_qlist_obj(p_obj)); + free(p_obj); + + p_list_item = cl_qlist_remove_head(p_ctx->p_rbuf); + } + + osmv_rmpp_sar_done(&p_ctx->sar); + + free(p_ctx->p_rbuf); + free(p_ctx); +} + +ib_api_status_t +osmv_rmpp_recv_ctx_store_mad_seg(IN osmv_rmpp_recv_ctx_t * p_recv_ctx, + IN void *p_mad) +{ + cl_list_obj_t *p_obj = NULL; + void *p_list_mad; + + OSM_LOG_ENTER(p_recv_ctx->p_log); + + CL_ASSERT(p_recv_ctx); + p_list_mad = malloc(MAD_BLOCK_SIZE); + if (NULL == p_list_mad) { + return IB_INSUFFICIENT_MEMORY; + } + memset(p_list_mad, 0, MAD_BLOCK_SIZE); + memcpy(p_list_mad, p_mad, MAD_BLOCK_SIZE); + + p_obj = malloc(sizeof(cl_list_obj_t)); + if (NULL == p_obj) { + free(p_list_mad); + return IB_INSUFFICIENT_MEMORY; + } + memset(p_obj, 0, sizeof(cl_list_obj_t)); + cl_qlist_set_obj(p_obj, p_list_mad); + + cl_qlist_insert_tail(p_recv_ctx->p_rbuf, &p_obj->list_item); + + if (osmv_mad_is_sa((ib_mad_t *) p_mad)) { + p_recv_ctx->is_sa_mad = TRUE; + } + + return IB_SUCCESS; + +} + +uint32_t +osmv_rmpp_recv_ctx_get_cur_byte_num(IN osmv_rmpp_recv_ctx_t * p_recv_ctx) +{ + uint32_t num_segs; + + num_segs = cl_qlist_count(p_recv_ctx->p_rbuf); + if (p_recv_ctx->is_sa_mad) + return ((num_segs * IB_SA_DATA_SIZE) + IB_SA_MAD_HDR_SIZE); + else + return ((num_segs * MAD_RMPP_DATA_SIZE) + MAD_RMPP_HDR_SIZE); +} + +uint32_t +osmv_rmpp_recv_ctx_get_byte_num_from_first(IN osmv_rmpp_recv_ctx_t * p_recv_ctx) +{ + cl_list_item_t *p_item; + cl_list_obj_t *p_obj; + void *p_list_mad; + uint32_t num_bytes, num_segs; + + p_item = cl_qlist_head(p_recv_ctx->p_rbuf); + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + p_list_mad = cl_qlist_obj(p_obj); + + /* mad data sz */ + num_bytes = cl_ntoh32(((ib_rmpp_mad_t *) p_list_mad)->paylen_newwin); + if (0 != num_bytes) { + if (p_recv_ctx->is_sa_mad) { + /* sa mad hdr sz */ + num_segs = cl_qlist_count(p_recv_ctx->p_rbuf); + num_bytes -= + num_segs * (IB_SA_MAD_HDR_SIZE - MAD_RMPP_HDR_SIZE); + num_bytes += IB_SA_MAD_HDR_SIZE; + } else { + /* mad hdr sz */ + num_bytes += MAD_RMPP_HDR_SIZE; + } + } + + return num_bytes; +} + +uint32_t +osmv_rmpp_recv_ctx_get_byte_num_from_last(IN osmv_rmpp_recv_ctx_t * p_recv_ctx) +{ + cl_list_item_t *p_item; + cl_list_obj_t *p_obj; + void *p_list_mad; + uint32_t num_bytes, num_segs; + + p_item = cl_qlist_tail(p_recv_ctx->p_rbuf); + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + p_list_mad = cl_qlist_obj(p_obj); + + /* mad data sz */ + num_segs = cl_qlist_count(p_recv_ctx->p_rbuf); + num_bytes = cl_ntoh32(((ib_rmpp_mad_t *) p_list_mad)->paylen_newwin); + + if (0 != num_bytes) { + if (p_recv_ctx->is_sa_mad) { + /* sa mad hdr sz */ + num_bytes += MAD_RMPP_HDR_SIZE; + num_bytes += (num_segs - 1) * IB_SA_DATA_SIZE; + } else { + /* mad hdr sz */ + num_bytes += MAD_RMPP_HDR_SIZE; + num_bytes += (num_segs - 1) * MAD_RMPP_DATA_SIZE; + } + } + + return num_bytes; +} + +/* assuming that the last rmpp pkt arrived so that data member: total_bytes has the right value */ +ib_api_status_t +osmv_rmpp_recv_ctx_reassemble_arbt_mad(IN osmv_rmpp_recv_ctx_t * p_recv_ctx, + IN uint32_t size, IN void *p_arbt_mad) +{ + ib_api_status_t st = IB_SUCCESS; + + CL_ASSERT(p_recv_ctx); + + st = osmv_rmpp_sar_init(&p_recv_ctx->sar, p_arbt_mad, size, + p_recv_ctx->is_sa_mad); + if (st != IB_SUCCESS) { + return st; + } + + st = osmv_rmpp_sar_reassemble_arbt_mad(&p_recv_ctx->sar, + p_recv_ctx->p_rbuf); + + osmv_rmpp_sar_done(&p_recv_ctx->sar); + + return st; +} diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sa.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sa.c new file mode 100644 index 000000000000..0257f3274d37 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sa.c @@ -0,0 +1,834 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +/***************************************************************************** + *****************************************************************************/ + +/* this struct is the internal rep of the bind handle */ +typedef struct _osmv_sa_bind_info { + osm_bind_handle_t h_bind; + osm_log_t *p_log; + osm_vendor_t *p_vendor; + osm_mad_pool_t *p_mad_pool; + uint64_t port_guid; + cl_event_t sync_event; + uint64_t last_lids_update_sec; + uint16_t lid; + uint16_t sm_lid; +} osmv_sa_bind_info_t; + +/***************************************************************************** + *****************************************************************************/ + +/* + Call back on new mad received: + + We basically only need to set the context of the query. + Or report an error. + + A pointer to the actual context of the request (a copy of the oriignal + request structure) is attached as the p_madw->context.ni_context.node_guid +*/ +void +__osmv_sa_mad_rcv_cb(IN osm_madw_t * p_madw, + IN void *bind_context, IN osm_madw_t * p_req_madw) +{ + osmv_sa_bind_info_t *p_bind = (osmv_sa_bind_info_t *) bind_context; + osmv_query_req_t *p_query_req_copy = NULL; + osmv_query_res_t query_res; + ib_sa_mad_t *p_sa_mad; + ib_net16_t mad_status; + + OSM_LOG_ENTER(p_bind->p_log); + + if (!p_req_madw) { + osm_log(p_bind->p_log, OSM_LOG_DEBUG, + "__osmv_sa_mad_rcv_cb: " + "Ignoring a non-response mad\n"); + osm_mad_pool_put(p_bind->p_mad_pool, p_madw); + goto Exit; + } + + /* obtain the sent context */ + p_query_req_copy = + (osmv_query_req_t *) (p_req_madw->context.arb_context.context1); + + /* provide the context of the original request in the result */ + query_res.query_context = p_query_req_copy->query_context; + + /* provide the resulting madw */ + query_res.p_result_madw = p_madw; + + /* update the req fields */ + p_sa_mad = (ib_sa_mad_t *) p_madw->p_mad; + + /* if we got a remote error track it in the status */ + mad_status = (ib_net16_t) (p_sa_mad->status & IB_SMP_STATUS_MASK); + if (mad_status != IB_SUCCESS) { + osm_log(p_bind->p_log, OSM_LOG_ERROR, + "__osmv_sa_mad_rcv_cb: ERR 0501: " + "Remote error:0x%04X .\n", mad_status); + query_res.status = IB_REMOTE_ERROR; + } else { + query_res.status = IB_SUCCESS; + } + + /* what if we have got back an empty mad ? */ + if (!p_madw->mad_size) { + osm_log(p_bind->p_log, OSM_LOG_ERROR, + "__osmv_sa_mad_rcv_cb: ERR 0502: " + "Got an empty mad.\n"); + query_res.status = IB_ERROR; + } + + if (IB_SUCCESS == mad_status) { + + /* if we are in not in a method response of an rmpp nature we must get only 1 */ + /* HACK: in the future we might need to be smarter for other methods... */ + if (p_sa_mad->method != IB_MAD_METHOD_GETTABLE_RESP) { + query_res.result_cnt = 1; + } else { +#ifndef VENDOR_RMPP_SUPPORT + if (mad_status != IB_SUCCESS) + query_res.result_cnt = 0; + else + query_res.result_cnt = 1; +#else + /* we used the offset value to calculate the number of + records in here */ + if (ib_get_attr_size(p_sa_mad->attr_offset) == 0) { + query_res.result_cnt = 0; + osm_log(p_bind->p_log, OSM_LOG_DEBUG, + "__osmv_sa_mad_rcv_cb: Count = 0\n"); + } + else { + query_res.result_cnt = (uintn_t) + ((p_madw->mad_size - IB_SA_MAD_HDR_SIZE) / + ib_get_attr_size(p_sa_mad->attr_offset)); + osm_log(p_bind->p_log, OSM_LOG_DEBUG, + "__osmv_sa_mad_rcv_cb: " + "Count = %u = %zu / %u (%zu)\n", + query_res.result_cnt, + p_madw->mad_size - IB_SA_MAD_HDR_SIZE, + ib_get_attr_size(p_sa_mad->attr_offset), + (p_madw->mad_size - IB_SA_MAD_HDR_SIZE) % + ib_get_attr_size(p_sa_mad->attr_offset)); + } +#endif + } + } + + query_res.query_type = p_query_req_copy->query_type; + + p_query_req_copy->pfn_query_cb(&query_res); + + if ((p_query_req_copy->flags & OSM_SA_FLAGS_SYNC) == OSM_SA_FLAGS_SYNC) + cl_event_signal(&p_bind->sync_event); + +Exit: + + /* free the copied query request if found */ + if (p_query_req_copy) + free(p_query_req_copy); + + /* put back the request madw */ + if (p_req_madw) + osm_mad_pool_put(p_bind->p_mad_pool, p_req_madw); + + OSM_LOG_EXIT(p_bind->p_log); +} + +/***************************************************************************** + ****************************************************************************/ +/* + Send Error Callback: + + Only report the error and get rid of the mad wrapper +*/ +void __osmv_sa_mad_err_cb(IN void *bind_context, IN osm_madw_t * p_madw) +{ + osmv_sa_bind_info_t *p_bind = (osmv_sa_bind_info_t *) bind_context; + osmv_query_req_t *p_query_req_copy = NULL; + osmv_query_res_t query_res; + + OSM_LOG_ENTER(p_bind->p_log); + + /* Obtain the sent context etc */ + p_query_req_copy = + (osmv_query_req_t *) (p_madw->context.arb_context.context1); + + /* provide the context of the original request in the result */ + query_res.query_context = p_query_req_copy->query_context; + + query_res.p_result_madw = p_madw; + + query_res.status = IB_TIMEOUT; + query_res.result_cnt = 0; + query_res.p_result_madw->status = IB_TIMEOUT; + p_madw->status = IB_TIMEOUT; + query_res.query_type = p_query_req_copy->query_type; + + p_query_req_copy->pfn_query_cb(&query_res); + + if ((p_query_req_copy->flags & OSM_SA_FLAGS_SYNC) == OSM_SA_FLAGS_SYNC) + cl_event_signal(&p_bind->sync_event); + + if (p_query_req_copy) + free(p_query_req_copy); + OSM_LOG_EXIT(p_bind->p_log); +} + +/***************************************************************************** + This routine needs to be invoked on every send - since the SM LID and Local + lid might change. To do that without any major perfoermance impact we cache + the results and time they were obtained. Refresh only twice a minute. + To avoid the need to use statics and risk a race - we require the refresh time + to be stored in the context of the results. Also this coveres cases were + we query for multiple guids. + *****************************************************************************/ +ib_api_status_t +__osmv_get_lid_and_sm_lid_by_port_guid(IN osm_vendor_t * const p_vend, + IN ib_net64_t port_guid, + IN OUT uint64_t * p_lids_update_time_sec, + OUT uint16_t * lid, + OUT uint16_t * sm_lid) +{ + + ib_api_status_t status; + ib_port_attr_t *p_attr_array; + uint32_t num_ports; + uint32_t port_num; + + OSM_LOG_ENTER(p_vend->p_log); + + /* use prevous values if current time is close enough to previous query */ + if (cl_get_time_stamp_sec() <= *p_lids_update_time_sec + 30) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osmv_get_lid_and_sm_lid_by_port_guid: " + "Using previously stored lid:0x%04x sm_lid:0x%04x\n", + *lid, *sm_lid); + status = IB_SUCCESS; + goto Exit; + } + + /* obtain the number of available ports */ + num_ports = 0; + status = osm_vendor_get_all_port_attr(p_vend, NULL, &num_ports); + if (status != IB_INSUFFICIENT_MEMORY) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osmv_get_lid_and_sm_lid_by_port_guid: ERR 0503: " + "expected to get the IB_INSUFFICIENT_MEMORY but got: %s\n", + ib_get_err_str(status) + ); + status = IB_ERROR; + goto Exit; + } + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osmv_get_lid_and_sm_lid_by_port_guid: " + "Found total of %u ports. Looking for guid:0x%016" PRIx64 "\n", + num_ports, cl_ntoh64(port_guid) + ); + + /* allocate the attributes */ + p_attr_array = + (ib_port_attr_t *) malloc(sizeof(ib_port_attr_t) * num_ports); + + /* obtain the attributes */ + status = osm_vendor_get_all_port_attr(p_vend, p_attr_array, &num_ports); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osmv_get_lid_and_sm_lid_by_port_guid: ERR 0504: " + "Fail to get port attributes (error: %s)\n", + ib_get_err_str(status) + ); + free(p_attr_array); + goto Exit; + } + + status = IB_ERROR; + /* find the port requested in the list */ + for (port_num = 0; (port_num < num_ports) && (status == IB_ERROR); + port_num++) { + if (p_attr_array[port_num].port_guid == port_guid) { + *lid = p_attr_array[port_num].lid; + *sm_lid = p_attr_array[port_num].sm_lid; + *p_lids_update_time_sec = cl_get_time_stamp_sec(); + status = IB_SUCCESS; + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osmv_get_lid_and_sm_lid_by_port_guid: " + "Found guid:0x%016" PRIx64 " with idx:%d\n", + cl_ntoh64(port_guid), port_num); + } + } + + free(p_attr_array); + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/***************************************************************************** + *****************************************************************************/ +osm_bind_handle_t +osmv_bind_sa(IN osm_vendor_t * const p_vend, + IN osm_mad_pool_t * const p_mad_pool, IN ib_net64_t port_guid) +{ + osm_bind_info_t bind_info; + osm_log_t *p_log = p_vend->p_log; + ib_api_status_t status = IB_SUCCESS; + osmv_sa_bind_info_t *p_sa_bind_info; + cl_status_t cl_status; + + OSM_LOG_ENTER(p_log); + + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_bind_sa: " + "Binding to port 0x%" PRIx64 ".\n", cl_ntoh64(port_guid)); + + bind_info.port_guid = port_guid; + bind_info.mad_class = IB_MCLASS_SUBN_ADM; + bind_info.class_version = 2; + bind_info.is_responder = TRUE; + bind_info.is_trap_processor = FALSE; + bind_info.is_report_processor = TRUE; + bind_info.send_q_size = 256; + bind_info.recv_q_size = 256; + + /* allocate the new sa bind info */ + p_sa_bind_info = + (osmv_sa_bind_info_t *) malloc(sizeof(osmv_sa_bind_info_t)); + if (!p_sa_bind_info) { + osm_log(p_log, OSM_LOG_ERROR, + "osmv_bind_sa: ERR 0505: " + "Fail to allocate new bidn structure\n"); + p_sa_bind_info = OSM_BIND_INVALID_HANDLE; + goto Exit; + } + + /* store some important context */ + p_sa_bind_info->p_log = p_log; + p_sa_bind_info->port_guid = port_guid; + p_sa_bind_info->p_mad_pool = p_mad_pool; + p_sa_bind_info->p_vendor = p_vend; + p_sa_bind_info->last_lids_update_sec = 0; + + /* Bind to the lower level */ + p_sa_bind_info->h_bind = osm_vendor_bind(p_vend, &bind_info, p_mad_pool, __osmv_sa_mad_rcv_cb, __osmv_sa_mad_err_cb, p_sa_bind_info); /* context provided to CBs */ + + if (p_sa_bind_info->h_bind == OSM_BIND_INVALID_HANDLE) { + free(p_sa_bind_info); + p_sa_bind_info = OSM_BIND_INVALID_HANDLE; + osm_log(p_log, OSM_LOG_ERROR, + "osmv_bind_sa: ERR 0506: " + "Fail to bind to vendor SMI.\n"); + goto Exit; + } + + /* obtain the sm_lid from the vendor */ + status = + __osmv_get_lid_and_sm_lid_by_port_guid(p_vend, port_guid, + &p_sa_bind_info-> + last_lids_update_sec, + &p_sa_bind_info->lid, + &p_sa_bind_info->sm_lid); + if (status != IB_SUCCESS) { + free(p_sa_bind_info); + p_sa_bind_info = OSM_BIND_INVALID_HANDLE; + osm_log(p_log, OSM_LOG_ERROR, + "osmv_bind_sa: ERR 0507: " + "Fail to obtain the sm lid.\n"); + goto Exit; + } + + /* initialize the sync_event */ + cl_event_construct(&p_sa_bind_info->sync_event); + cl_status = cl_event_init(&p_sa_bind_info->sync_event, TRUE); + if (cl_status != CL_SUCCESS) { + osm_log(p_log, OSM_LOG_ERROR, + "osmv_bind_sa: ERR 0508: " + "cl_init_event failed: %s\n", ib_get_err_str(cl_status) + ); + free(p_sa_bind_info); + p_sa_bind_info = OSM_BIND_INVALID_HANDLE; + } + +Exit: + OSM_LOG_EXIT(p_log); + return (p_sa_bind_info); +} + +/***************************************************************************** + *****************************************************************************/ + +/****t* OSM Vendor SA Client/osmv_sa_mad_data + * NAME + * osmv_sa_mad_data + * + * DESCRIPTION + * Extra fields required to perform a mad query + * This struct is passed to the actual send method + * + * SYNOPSIS + */ +typedef struct _osmv_sa_mad_data { + /* MAD data. */ + uint8_t method; + ib_net16_t attr_id; + ib_net16_t attr_offset; + ib_net32_t attr_mod; + ib_net64_t comp_mask; + void *p_attr; +} osmv_sa_mad_data_t; +/* + * method + * The method of the mad to be sent + * + * attr_id + * Attribute ID + * + * attr_offset + * Offset as defined by RMPP + * + * attr_mod + * Attribute modifier + * + * comp_mask + * The component mask of the query + * + * p_attr + * A pointer to the record of the attribute to be sent. + * + *****/ + +/***************************************************************************** + *****************************************************************************/ +/* Send a MAD out on the GSI interface */ +ib_api_status_t +__osmv_send_sa_req(IN osmv_sa_bind_info_t * p_bind, + IN const osmv_sa_mad_data_t * const p_sa_mad_data, + IN const osmv_query_req_t * const p_query_req) +{ + ib_api_status_t status; + ib_mad_t *p_mad_hdr; + ib_sa_mad_t *p_sa_mad; + osm_madw_t *p_madw; + osm_log_t *p_log = p_bind->p_log; + static atomic32_t trans_id; + boolean_t sync; + osmv_query_req_t *p_query_req_copy; + + OSM_LOG_ENTER(p_log); + + /* + since the sm_lid might change we obtain it every send + (actually it is cached in the bind object and refreshed + every 30sec by this proc ) + */ + status = + __osmv_get_lid_and_sm_lid_by_port_guid(p_bind->p_vendor, + p_bind->port_guid, + &p_bind-> + last_lids_update_sec, + &p_bind->lid, + &p_bind->sm_lid); + if (status != IB_SUCCESS) { + osm_log(p_log, OSM_LOG_ERROR, + "__osmv_send_sa_req: ERR 0509: " + "Fail to obtain the sm lid.\n"); + goto Exit; + } + + /* Get a MAD wrapper for the send */ + p_madw = osm_mad_pool_get(p_bind->p_mad_pool, + p_bind->h_bind, MAD_BLOCK_SIZE, NULL); + + if (p_madw == NULL) { + osm_log(p_log, OSM_LOG_ERROR, + "__osmv_send_sa_req: ERR 0510: " + "Unable to acquire MAD.\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* Initialize the Sent MAD: */ + + /* Initialize the MAD buffer for the send operation. */ + p_mad_hdr = osm_madw_get_mad_ptr(p_madw); + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + + /* Get a new transaction Id */ + cl_atomic_inc(&trans_id); + + /* Cleanup the MAD from any residue */ + memset(p_sa_mad, 0, MAD_BLOCK_SIZE); + + /* Initialize the standard MAD header. */ + ib_mad_init_new(p_mad_hdr, /* mad pointer */ + IB_MCLASS_SUBN_ADM, /* class */ + (uint8_t) 2, /* version */ + p_sa_mad_data->method, /* method */ + cl_hton64((uint64_t) trans_id), /* tid */ + p_sa_mad_data->attr_id, /* attr id */ + p_sa_mad_data->attr_mod /* attr mod */ + ); + + /* Set the query information. */ + p_sa_mad->sm_key = p_query_req->sm_key; + p_sa_mad->attr_offset = 0; + p_sa_mad->comp_mask = p_sa_mad_data->comp_mask; + if (p_sa_mad->comp_mask) { + memcpy(p_sa_mad->data, p_sa_mad_data->p_attr, + ib_get_attr_size(p_sa_mad_data->attr_offset)); + } + + /* + Provide the address to send to + */ + /* Patch to handle IBAL - host order , where it should take destination lid in network order */ +#ifdef OSM_VENDOR_INTF_AL + p_madw->mad_addr.dest_lid = p_bind->sm_lid; +#else + p_madw->mad_addr.dest_lid = cl_hton16(p_bind->sm_lid); +#endif + p_madw->mad_addr.addr_type.smi.source_lid = cl_hton16(p_bind->lid); + p_madw->mad_addr.addr_type.gsi.remote_qp = CL_HTON32(1); + p_madw->mad_addr.addr_type.gsi.remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + p_madw->mad_addr.addr_type.gsi.pkey_ix = 0; + p_madw->resp_expected = TRUE; + p_madw->fail_msg = CL_DISP_MSGID_NONE; + + /* + Provide MAD context such that the call back will know what to do. + We have to keep the entire request structure so we know the CB. + Since we can not rely on the client to keep it arroud until + the response - we duplicate it and will later dispose it (in CB). + To store on the MADW we cast it into what opensm has: + p_madw->context.arb_context.context1 + */ + p_query_req_copy = malloc(sizeof(*p_query_req_copy)); + *p_query_req_copy = *p_query_req; + p_madw->context.arb_context.context1 = p_query_req_copy; + + /* we can support async as well as sync calls */ + sync = ((p_query_req->flags & OSM_SA_FLAGS_SYNC) == OSM_SA_FLAGS_SYNC); + + /* send the mad asynchronously */ + status = osm_vendor_send(osm_madw_get_bind_handle(p_madw), + p_madw, p_madw->resp_expected); + + /* if synchronous - wait on the event */ + if (sync) { + osm_log(p_log, OSM_LOG_DEBUG, + "__osmv_send_sa_req: " "Waiting for async event.\n"); + cl_event_wait_on(&p_bind->sync_event, EVENT_NO_TIMEOUT, FALSE); + cl_event_reset(&p_bind->sync_event); + status = p_madw->status; + } + +Exit: + OSM_LOG_EXIT(p_log); + return status; +} + +/***************************************************************************** + *****************************************************************************/ +/* + * Query the SA based on the user's request. + */ +ib_api_status_t +osmv_query_sa(IN osm_bind_handle_t h_bind, + IN const osmv_query_req_t * const p_query_req) +{ + osmv_sa_bind_info_t *p_bind = (osmv_sa_bind_info_t *) h_bind; + osmv_sa_mad_data_t sa_mad_data; + osmv_user_query_t *p_user_query; + ib_service_record_t svc_rec; + ib_node_record_t node_rec; + ib_portinfo_record_t port_info; + ib_path_rec_t path_rec; + ib_class_port_info_t class_port_info; + osm_log_t *p_log = p_bind->p_log; + ib_api_status_t status; + + OSM_LOG_ENTER(p_log); + + /* Set the request information. */ + sa_mad_data.method = IB_MAD_METHOD_GETTABLE; + sa_mad_data.attr_mod = 0; + + /* Set the MAD attributes and component mask correctly. */ + switch (p_query_req->query_type) { + + case OSMV_QUERY_USER_DEFINED: + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", "USER_DEFINED\n"); + p_user_query = (osmv_user_query_t *) p_query_req->p_query_input; + if (p_user_query->method) + sa_mad_data.method = p_user_query->method; + sa_mad_data.attr_offset = p_user_query->attr_offset; + sa_mad_data.attr_id = p_user_query->attr_id; + sa_mad_data.attr_mod = p_user_query->attr_mod; + sa_mad_data.comp_mask = p_user_query->comp_mask; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + case OSMV_QUERY_ALL_SVC_RECS: + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", "SVC_REC_BY_NAME\n"); + sa_mad_data.method = IB_MAD_METHOD_GETTABLE; + sa_mad_data.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_service_record_t)); + sa_mad_data.comp_mask = 0; + sa_mad_data.p_attr = &svc_rec; + break; + + case OSMV_QUERY_SVC_REC_BY_NAME: + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", "SVC_REC_BY_NAME\n"); + sa_mad_data.method = IB_MAD_METHOD_GET; + sa_mad_data.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + sa_mad_data.comp_mask = IB_SR_COMPMASK_SNAME; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_service_record_t)); + sa_mad_data.p_attr = &svc_rec; + memcpy(svc_rec.service_name, p_query_req->p_query_input, + sizeof(ib_svc_name_t)); + break; + + case OSMV_QUERY_SVC_REC_BY_ID: + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", "SVC_REC_BY_ID\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + sa_mad_data.comp_mask = IB_SR_COMPMASK_SID; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_service_record_t)); + sa_mad_data.p_attr = &svc_rec; + svc_rec.service_id = + *(ib_net64_t *) (p_query_req->p_query_input); + break; + + case OSMV_QUERY_CLASS_PORT_INFO: + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", "CLASS_PORT_INFO\n"); + sa_mad_data.method = IB_MAD_METHOD_GET; + sa_mad_data.attr_id = IB_MAD_ATTR_CLASS_PORT_INFO; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_class_port_info_t)); + sa_mad_data.comp_mask = 0; + sa_mad_data.p_attr = &class_port_info; + + break; + + case OSMV_QUERY_NODE_REC_BY_NODE_GUID: + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", "NODE_REC_BY_NODE_GUID\n"); + sa_mad_data.method = IB_MAD_METHOD_GETTABLE; + sa_mad_data.attr_id = IB_MAD_ATTR_NODE_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_node_record_t)); + sa_mad_data.comp_mask = IB_NR_COMPMASK_NODEGUID; + sa_mad_data.p_attr = &node_rec; + node_rec.node_info.node_guid = + *(ib_net64_t *) (p_query_req->p_query_input); + + break; + + case OSMV_QUERY_PORT_REC_BY_LID: + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", "PORT_REC_BY_LID\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_PORTINFO_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_portinfo_record_t)); + sa_mad_data.comp_mask = IB_PIR_COMPMASK_LID; + sa_mad_data.p_attr = &port_info; + port_info.lid = *(ib_net16_t *) (p_query_req->p_query_input); + break; + + case OSMV_QUERY_PORT_REC_BY_LID_AND_NUM: + sa_mad_data.method = IB_MAD_METHOD_GET; + p_user_query = (osmv_user_query_t *) p_query_req->p_query_input; + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", + "PORT_REC_BY_LID_AND_NUM\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_PORTINFO_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_portinfo_record_t)); + sa_mad_data.comp_mask = + IB_PIR_COMPMASK_LID | IB_PIR_COMPMASK_PORTNUM; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + case OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK: + sa_mad_data.method = IB_MAD_METHOD_GET; + p_user_query = (osmv_user_query_t *) p_query_req->p_query_input; + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", + "OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_VLARB_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_vl_arb_table_record_t)); + sa_mad_data.comp_mask = + IB_VLA_COMPMASK_LID | IB_VLA_COMPMASK_OUT_PORT | + IB_VLA_COMPMASK_BLOCK; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + case OSMV_QUERY_SLVL_BY_LID_AND_PORTS: + sa_mad_data.method = IB_MAD_METHOD_GET; + p_user_query = (osmv_user_query_t *) p_query_req->p_query_input; + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", + "OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_SLVL_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_slvl_table_record_t)); + sa_mad_data.comp_mask = + IB_SLVL_COMPMASK_LID | IB_SLVL_COMPMASK_OUT_PORT | + IB_SLVL_COMPMASK_IN_PORT; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + case OSMV_QUERY_PATH_REC_BY_PORT_GUIDS: + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", "PATH_REC_BY_PORT_GUIDS\n"); + memset(&path_rec, 0, sizeof(ib_path_rec_t)); + sa_mad_data.attr_id = IB_MAD_ATTR_PATH_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_path_rec_t)); + sa_mad_data.comp_mask = + (IB_PR_COMPMASK_DGID | IB_PR_COMPMASK_SGID); + sa_mad_data.p_attr = &path_rec; + ib_gid_set_default(&path_rec.dgid, + ((osmv_guid_pair_t *) (p_query_req-> + p_query_input))-> + dest_guid); + ib_gid_set_default(&path_rec.sgid, + ((osmv_guid_pair_t *) (p_query_req-> + p_query_input))-> + src_guid); + break; + + case OSMV_QUERY_PATH_REC_BY_GIDS: + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", "PATH_REC_BY_GIDS\n"); + memset(&path_rec, 0, sizeof(ib_path_rec_t)); + sa_mad_data.attr_id = IB_MAD_ATTR_PATH_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_path_rec_t)); + sa_mad_data.comp_mask = + (IB_PR_COMPMASK_DGID | IB_PR_COMPMASK_SGID); + sa_mad_data.p_attr = &path_rec; + memcpy(&path_rec.dgid, + &((osmv_gid_pair_t *) (p_query_req->p_query_input))-> + dest_gid, sizeof(ib_gid_t)); + memcpy(&path_rec.sgid, + &((osmv_gid_pair_t *) (p_query_req->p_query_input))-> + src_gid, sizeof(ib_gid_t)); + break; + + case OSMV_QUERY_PATH_REC_BY_LIDS: + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", "PATH_REC_BY_LIDS\n"); + memset(&path_rec, 0, sizeof(ib_path_rec_t)); + sa_mad_data.method = IB_MAD_METHOD_GET; + sa_mad_data.attr_id = IB_MAD_ATTR_PATH_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_path_rec_t)); + sa_mad_data.comp_mask = + (IB_PR_COMPMASK_DLID | IB_PR_COMPMASK_SLID); + sa_mad_data.p_attr = &path_rec; + path_rec.dlid = + ((osmv_lid_pair_t *) (p_query_req->p_query_input))-> + dest_lid; + path_rec.slid = + ((osmv_lid_pair_t *) (p_query_req->p_query_input))->src_lid; + break; + + case OSMV_QUERY_UD_MULTICAST_SET: + sa_mad_data.method = IB_MAD_METHOD_SET; + p_user_query = (osmv_user_query_t *) p_query_req->p_query_input; + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", + "OSMV_QUERY_UD_MULTICAST_SET\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_member_rec_t)); + sa_mad_data.comp_mask = p_user_query->comp_mask; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + case OSMV_QUERY_UD_MULTICAST_DELETE: + sa_mad_data.method = IB_MAD_METHOD_DELETE; + p_user_query = (osmv_user_query_t *) p_query_req->p_query_input; + osm_log(p_log, OSM_LOG_DEBUG, + "osmv_query_sa DBG:001 %s", + "OSMV_QUERY_UD_MULTICAST_DELETE\n"); + sa_mad_data.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + sa_mad_data.attr_offset = + ib_get_attr_offset(sizeof(ib_member_rec_t)); + sa_mad_data.comp_mask = p_user_query->comp_mask; + sa_mad_data.p_attr = p_user_query->p_attr; + break; + + default: + osm_log(p_log, OSM_LOG_ERROR, + "osmv_query_sa DBG:001 %s", "UNKNOWN\n"); + CL_ASSERT(0); + return IB_ERROR; + } + + status = __osmv_send_sa_req(h_bind, &sa_mad_data, p_query_req); + + OSM_LOG_EXIT(p_log); + return status; +} + +/***************************************************************************** + *****************************************************************************/ diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sar.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sar.c new file mode 100644 index 000000000000..55232847cb86 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sar.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +ib_api_status_t +osmv_rmpp_sar_init(osmv_rmpp_sar_t * p_sar, void *p_arbt_mad, + uint32_t mad_size, boolean_t is_sa_mad) +{ + CL_ASSERT(p_sar); + p_sar->p_arbt_mad = p_arbt_mad; + if (is_sa_mad) { + p_sar->data_len = mad_size - IB_SA_MAD_HDR_SIZE; + p_sar->hdr_sz = IB_SA_MAD_HDR_SIZE; + p_sar->data_sz = IB_SA_DATA_SIZE; + } else { + p_sar->data_len = mad_size - MAD_RMPP_HDR_SIZE; + p_sar->hdr_sz = MAD_RMPP_HDR_SIZE; + p_sar->data_sz = MAD_RMPP_DATA_SIZE; + } + return IB_SUCCESS; +} + +void osmv_rmpp_sar_done(osmv_rmpp_sar_t * p_sar) +{ + p_sar->p_arbt_mad = NULL; +} + +/* the big mad should be with mad header, rmpp header ( &sa hdr) space */ +ib_api_status_t +osmv_rmpp_sar_get_mad_seg(IN osmv_rmpp_sar_t * p_sar, + IN uint32_t seg_idx, OUT void *p_buf) +{ + void *p_seg; + uint32_t sz_left; + uint32_t num_segs; + + CL_ASSERT(p_sar); + + num_segs = p_sar->data_len / p_sar->data_sz; + if ((p_sar->data_len % p_sar->data_sz) > 0) { + num_segs++; + } + + if ((seg_idx > num_segs) && (seg_idx != 1)) { + return IB_NOT_FOUND; + } + + /* cleanup */ + memset(p_buf, 0, MAD_BLOCK_SIZE); + + /* attach header */ + memcpy(p_buf, p_sar->p_arbt_mad, p_sar->hdr_sz); + + /* fill data */ + p_seg = + (char *)p_sar->p_arbt_mad + p_sar->hdr_sz + + ((seg_idx - 1) * p_sar->data_sz); + sz_left = p_sar->data_len - ((seg_idx - 1) * p_sar->data_sz); + if (sz_left > p_sar->data_sz) + memcpy((char *)p_buf + p_sar->hdr_sz, (char *)p_seg, + p_sar->data_sz); + else + memcpy((char *)p_buf + p_sar->hdr_sz, (char *)p_seg, sz_left); + + return IB_SUCCESS; +} + +/* turns a list of mads to one big mad - including header */ +/* ALSO - deallocates the list */ +ib_api_status_t +osmv_rmpp_sar_reassemble_arbt_mad(osmv_rmpp_sar_t * p_sar, cl_qlist_t * p_bufs) +{ + void *buf_tmp, *p_mad; + cl_list_item_t *p_item; + cl_list_obj_t *p_obj; + uint32_t space_left = p_sar->data_len + p_sar->hdr_sz; + + CL_ASSERT(p_sar); + CL_ASSERT(FALSE == cl_is_qlist_empty(p_bufs)); + + /* attach header */ + p_mad = p_sar->p_arbt_mad; + p_item = cl_qlist_head(p_bufs); + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + buf_tmp = cl_qlist_obj(p_obj); + memcpy(p_mad, buf_tmp, p_sar->hdr_sz); + p_mad = (char *)p_mad + p_sar->hdr_sz; + space_left -= p_sar->hdr_sz; + + /* reassemble data */ + while (FALSE == cl_is_qlist_empty(p_bufs)) { + + p_item = cl_qlist_remove_head(p_bufs); + p_obj = PARENT_STRUCT(p_item, cl_list_obj_t, list_item); + buf_tmp = cl_qlist_obj(p_obj); + + if (FALSE == cl_is_qlist_empty(p_bufs)) { + memcpy((char *)p_mad, (char *)buf_tmp + p_sar->hdr_sz, + p_sar->data_sz); + p_mad = (char *)p_mad + p_sar->data_sz; + space_left -= p_sar->data_sz; + } else { + /* the last mad on the list */ + memcpy((char *)p_mad, (char *)buf_tmp + p_sar->hdr_sz, + space_left); + p_mad = (char *)p_mad + space_left; + } + + free(buf_tmp); + free(p_obj); + } + + return IB_SUCCESS; +} diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sender.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sender.c new file mode 100644 index 000000000000..a0bdef8b20de --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sender.c @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +static ib_api_status_t +__osmv_rmpp_send_segment(IN osm_bind_handle_t h_bind, + IN osmv_txn_ctx_t * p_txn, IN uint32_t seg_num); + +/****d* OSM Vendor/osmv_simple_send_madw + * NAME + * osmv_simple_send_madw + * + * DESCRIPTION + * Send a single MAD (256 bytes). + * + * If this MAD requires a response, set the timeout event. + * The function call returns when the MAD's send completion is received. + * + */ + +ib_api_status_t +osmv_simple_send_madw(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, + IN osmv_txn_ctx_t * p_txn, IN boolean_t is_retry) +{ + ib_api_status_t ret; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_mad_addr_t *p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw); + uint8_t mad_buf[MAD_BLOCK_SIZE]; + ib_mad_t *p_mad = (ib_mad_t *) mad_buf; + uint64_t key = 0; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + CL_ASSERT(p_madw->mad_size <= MAD_BLOCK_SIZE); + + memset(p_mad, 0, MAD_BLOCK_SIZE); + memcpy(p_mad, osm_madw_get_mad_ptr(p_madw), p_madw->mad_size); + + if (NULL != p_txn) { + /* Push a fake txn id to the MAD */ + key = osmv_txn_get_key(p_txn); + p_mad->trans_id = cl_hton64(key); + } + + /* + Add call for packet drop randomizer. + This is a testing feature. If run_randomizer flag is set to TRUE, + the randomizer will be called, and randomally will drop + a packet. This is used for simulating unstable fabric. + */ + if (p_bo->p_vendor->run_randomizer == TRUE) { + /* Try the randomizer */ + if (osm_pkt_randomizer_mad_drop(p_bo->p_vendor->p_log, + p_bo->p_vendor-> + p_pkt_randomizer, + p_mad) == TRUE) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "The MAD will not be sent. \n"); + ret = IB_SUCCESS; + } else { + ret = + osmv_transport_mad_send(h_bind, p_mad, p_mad_addr); + } + } else { + ret = osmv_transport_mad_send(h_bind, p_mad, p_mad_addr); + } + + if ((IB_SUCCESS == ret) && (NULL != p_txn) && (!is_retry)) { + /* Set the timeout for receiving the response MAD */ + ret = osmv_txn_set_timeout_ev(h_bind, key, + p_bo->p_vendor->resp_timeout); + } + + OSM_LOG_EXIT(p_bo->p_vendor->p_log); + return ret; +} + +/***** OSM Vendor/osmv_rmpp_send_madw + * NAME + * osmv_rmpp_send_madw + * + * DESCRIPTION + * Send a single message (MAD wrapper of arbitrary length). + * Follow the RMPP semantics + * (segmentation, send window, timeouts etc). + * + * The function call returns either when the whole message + * has been acknowledged, or upon error. + * + * ASSUMPTIONS + * The RMPP sender context is set up + */ + +ib_api_status_t +osmv_rmpp_send_madw(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, + IN osmv_txn_ctx_t * p_txn, IN boolean_t is_rmpp_ds) +{ + ib_api_status_t ret = IB_SUCCESS; + uint32_t i, total_segs; + + osmv_rmpp_send_ctx_t *p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + total_segs = osmv_rmpp_send_ctx_get_num_segs(p_send_ctx); + CL_ASSERT(total_segs >= 1); + + /* In the double-sided transfer, wait for ACK 0 */ + + for (;;) { + + if (p_send_ctx->window_first > total_segs) { + + /* Every segment is acknowledged */ + break; + } + + /* Send the next burst. */ + for (i = p_send_ctx->window_first; i <= p_send_ctx->window_last; + i++) { + + /* Send a segment and setup a timeout timer */ + ret = __osmv_rmpp_send_segment(h_bind, p_txn, i); + if (IB_SUCCESS != ret) { + goto send_done; + } + } + + /* Set the Response Timeout for the ACK on the last DATA segment */ + ret = osmv_txn_set_timeout_ev(h_bind, osmv_txn_get_key(p_txn), + p_bo->p_vendor->resp_timeout); + if (IB_SUCCESS != ret) { + goto send_done; + } + + /* Going to sleep. Let the others access the transaction DB */ + osmv_txn_unlock(p_bo); + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "RMPP Sender thread (madw=%p) going to sleep ...\n", + p_madw); + + /* Await the next event to happen */ + cl_event_wait_on(&p_send_ctx->event, + EVENT_NO_TIMEOUT, TRUE /* interruptible */ ); + + /* Got a signal from the MAD dispatcher/timeout handler */ + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "RMPP Sender thread (madw=%p) waking up on a signal ...\n", + p_madw); + + /* Let's see what changed... Make this atomic - re-acquire the lock. */ + osmv_txn_lock(p_bo); + + if (TRUE == p_bo->is_closing) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_rmpp_send_madw: ERR 6601: " + "The bind handle %p is being closed. " + "Stopping the RMPP Send of MADW %p\n", + h_bind, p_madw); + + ret = IB_TIMEOUT; + return IB_INTERRUPTED; + } + + /* STOP? ABORT? TIMEOUT? */ + if (IB_SUCCESS != p_send_ctx->status) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_rmpp_send_madw: ERR 6602: " + "An error (%s) happened during the RMPP send of %p. Bailing out.\n", + ib_get_err_str(p_send_ctx->status), p_madw); + ret = p_send_ctx->status; + goto send_done; + } + } + + if (TRUE == is_rmpp_ds) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "Double-sided RMPP - switching to be the receiver.\n"); + + ret = osmv_txn_init_rmpp_receiver(h_bind, p_txn, FALSE + /*Send was initiated by me */ + ); + + if (IB_SUCCESS == ret) { + /* Send ACK on the 0 segment */ + ret = __osmv_rmpp_send_segment(h_bind, p_txn, 0); + } + } + +send_done: + OSM_LOG_EXIT(p_bo->p_vendor->p_log); + return ret; +} + +/* + * NAME osmv_rmpp_send_ack + * + * DESCRIPTION + * + */ + +ib_api_status_t +osmv_rmpp_send_ack(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_req_mad, + IN uint32_t seg_num, + IN uint32_t nwl, IN const osm_mad_addr_t * p_mad_addr) +{ + uint8_t resp_mad[MAD_BLOCK_SIZE]; + ib_rmpp_mad_t *p_resp_mad = (ib_rmpp_mad_t *) resp_mad; + +#ifdef OSMV_RANDOM_DROP + if (TRUE == osmv_random_drop()) { + osm_log(((osmv_bind_obj_t *) h_bind)->p_vendor->p_log, + OSM_LOG_DEBUG, + "Error injection - dropping the RMPP ACK\n"); + return IB_SUCCESS; + } +#endif + + memcpy(p_resp_mad, p_req_mad, MAD_BLOCK_SIZE); + + p_resp_mad->common_hdr.method = osmv_invert_method(p_req_mad->method); + p_resp_mad->rmpp_type = IB_RMPP_TYPE_ACK; + p_resp_mad->seg_num = cl_hton32(seg_num); + p_resp_mad->paylen_newwin = cl_hton32(nwl); + p_resp_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; + + return osmv_transport_mad_send(h_bind, p_resp_mad, p_mad_addr); +} + +/* + * NAME osmv_rmpp_send_nak + * + * DESCRIPTION Send the RMPP ABORT or STOP packet + */ + +ib_api_status_t +osmv_rmpp_send_nak(IN osm_bind_handle_t h_bind, + IN const ib_mad_t * p_req_mad, + IN const osm_mad_addr_t * p_mad_addr, + IN uint8_t nak_type, IN uint8_t status) +{ + uint8_t resp_mad[MAD_BLOCK_SIZE]; + ib_rmpp_mad_t *p_resp_mad = (ib_rmpp_mad_t *) resp_mad; + + memcpy(p_resp_mad, p_req_mad, MAD_BLOCK_SIZE); + + p_resp_mad->common_hdr.method = osmv_invert_method(p_req_mad->method); + p_resp_mad->rmpp_type = nak_type; + p_resp_mad->rmpp_status = status; + + return osmv_transport_mad_send(h_bind, p_resp_mad, p_mad_addr); +} + +/* + * NAME __osmv_rmpp_send_segment + * + * DESCRIPTION Build a MAD for a specific segment and send it + */ + +static ib_api_status_t +__osmv_rmpp_send_segment(IN osm_bind_handle_t h_bind, + IN osmv_txn_ctx_t * p_txn, IN uint32_t seg_num) +{ + ib_api_status_t ret; + osmv_rmpp_send_ctx_t *p_send_ctx; + uint8_t mad_buf[MAD_BLOCK_SIZE]; + ib_mad_t *p_mad = (ib_mad_t *) mad_buf; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_mad_addr_t *p_mad_addr = + osm_madw_get_mad_addr_ptr(osmv_txn_get_madw(p_txn)); + uint32_t timeout = p_bo->p_vendor->resp_timeout; + uint64_t key; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + +#ifdef OSMV_RANDOM_DROP + if (TRUE == osmv_random_drop()) { + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "Error injection - simulating the RMPP segment drop\n"); + return IB_SUCCESS; + } +#endif + + p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); + key = osmv_txn_get_key(p_txn); + + if (0 != seg_num) { + ret = + osmv_rmpp_send_ctx_get_seg(p_send_ctx, seg_num, timeout, + p_mad); + CL_ASSERT(IB_SUCCESS == ret); + + /* Put the segment to the wire ! */ + p_mad->trans_id = cl_hton64(key); + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "Sending RMPP segment #%d, on-wire TID=0x%llX\n", + seg_num, p_mad->trans_id); + + /* + Add call for packet drop randomizer. + This is a testing feature. If run_randomizer flag is set to TRUE, + the randomizer will be called, and randomally will drop + a packet. This is used for simulating unstable fabric. + */ + if (p_bo->p_vendor->run_randomizer == TRUE) { + /* Try the randomizer */ + if (osm_pkt_randomizer_mad_drop(p_bo->p_vendor->p_log, + p_bo->p_vendor-> + p_pkt_randomizer, + p_mad) == TRUE) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "The MAD will not be sent. \n"); + ret = IB_SUCCESS; + } else { + ret = + osmv_transport_mad_send((osm_bind_handle_t) + p_bo, p_mad, + p_mad_addr); + } + } else { + ret = + osmv_transport_mad_send((osm_bind_handle_t) p_bo, + p_mad, p_mad_addr); + } + } else { + /* This is an ACK for double-sided handshake. Give it a special treatment. */ + + /* It doesn't really matter which data to put. Only the header matters. */ + ret = osmv_rmpp_send_ctx_get_seg(p_send_ctx, 1, timeout, p_mad); + CL_ASSERT(IB_SUCCESS == ret); + + p_mad->trans_id = cl_hton64(key); + ret = + osmv_rmpp_send_ack((osm_bind_handle_t) p_bo, p_mad, + 0 /* segnum */ , + OSMV_RMPP_RECV_WIN /* NWL */ , + p_mad_addr); + } + + OSM_LOG_EXIT(p_bo->p_vendor->p_log); + return ret; +} diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sim.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sim.c new file mode 100644 index 000000000000..c02c4de552eb --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sim.c @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* AUTHOR Eitan Zahavi + * + * DESCRIPTION + * The lower-level MAD transport interface implementation + * that allows sending a single MAD/receiving a callback + * when a single MAD is received. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* the simulator messages definition */ +#include + +typedef struct _osmv_ibms_transport_mgr { + ibms_conn_handle_t conHdl; /* the connection handle we talk to */ + ibms_bind_msg_t filter; /* the bind message defining the filtering */ + cl_thread_t receiver; /* the thread waiting for incomming messages */ +} osmv_ibms_transport_mgr_t; + +static void +__osmv_ibms_mad_addr_to_osm_addr(IN osm_vendor_t const *p_vend, + IN struct _ibms_mad_addr *p_ibms_addr, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_osm_addr); + +static void +__osmv_ibms_osm_addr_to_mad_addr(IN const osm_mad_addr_t * p_osm_addr, + IN uint8_t is_smi, + OUT struct _ibms_mad_addr *p_ibms_addr); + +/* this is the callback function the "server" will call on incoming + messages */ +void __osmv_ibms_receiver_callback(void *p_ctx, ibms_mad_msg_t * p_mad) +{ + osm_mad_addr_t mad_addr; + osmv_bind_obj_t *const p_bo = (osmv_bind_obj_t *) p_ctx; + ib_api_status_t status = IB_SUCCESS; + + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + { + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + /* some logging */ + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "__osmv_ibms_receiver_callback: " + "MAD QPN:%d SLID:0x%04x class:0x%02x " + "method:0x%02x attr:0x%04x status:0x%04x " + "tid:0x%016" PRIx64 "\n", + p_mad->addr.dqpn, + cl_ntoh16(p_mad->addr.slid), + p_mad->header.mgmt_class, + p_mad->header.method, + cl_ntoh16(p_mad->header.attr_id), + cl_ntoh16(p_mad->header.status), + cl_ntoh64(p_mad->header.trans_id)); + + /* first arrange an address */ + __osmv_ibms_mad_addr_to_osm_addr(p_bo->p_vendor, + &p_mad->addr, + (((ib_mad_t *) & p_mad-> + header)->mgmt_class == + IB_MCLASS_SUBN_LID) + || + (((ib_mad_t *) & p_mad-> + header)->mgmt_class == + IB_MCLASS_SUBN_DIR), + &mad_addr); + + /* call the receiver callback */ + + status = + osmv_dispatch_mad((osm_bind_handle_t) p_bo, + (void *)&p_mad->header, &mad_addr); + + OSM_LOG_EXIT(p_bo->p_vendor->p_log); + } +} + +ib_api_status_t +osm_vendor_get_guid_by_ca_and_port(IN osm_vendor_t * const p_vend, + IN char *hca_id, + IN uint32_t port_num, + OUT uint64_t * p_port_guid); + +/* + * NAME + * osmv_transport_init + * + * DESCRIPTION + * Setup the MAD transport infrastructure (filters, callbacks etc). + */ + +ib_api_status_t +osmv_transport_init(IN osm_bind_info_t * p_info, + IN char hca_id[VENDOR_HCA_MAXNAMES], + IN uint8_t hca_idx, IN osmv_bind_obj_t * p_bo) +{ + ibms_conn_handle_t conHdl; /* the connection we talk to the simulator through */ + osmv_ibms_transport_mgr_t *p_mgr = + malloc(sizeof(osmv_ibms_transport_mgr_t)); + int qpn; + int ibms_status; + uint64_t port_guid; + + if (!p_mgr) { + return IB_INSUFFICIENT_MEMORY; + } + + memset(p_mgr, 0, sizeof(osmv_ibms_transport_mgr_t)); + + /* create the client socket connected to the simulator */ + /* also perform the "connect" message - such that we + validate the target guid */ + if (osm_vendor_get_guid_by_ca_and_port + (p_bo->p_vendor, hca_id, p_bo->port_num, &port_guid)) { + return IB_INVALID_GUID; + } + + conHdl = + ibms_connect(port_guid, __osmv_ibms_receiver_callback, + (void *)p_bo); + if (!conHdl) { + printf("fail to connect to the server.\n"); + exit(1); + } + + /* + * Create the MAD filter on this file handle. + */ + + p_mgr->filter.port = p_bo->port_num; + p_mgr->filter.only_input = 1; + p_mgr->filter.mask = + IBMS_BIND_MASK_PORT | + IBMS_BIND_MASK_INPUT | IBMS_BIND_MASK_QP | IBMS_BIND_MASK_CLASS; + + switch (p_info->mad_class) { + case IB_MCLASS_SUBN_LID: + case IB_MCLASS_SUBN_DIR: + qpn = 0; + p_mgr->filter.qpn = qpn; + p_mgr->filter.mgt_class = IB_MCLASS_SUBN_LID; + ibms_status = ibms_bind(conHdl, &p_mgr->filter); + if (ibms_status) { + return IB_ERROR; + } + + p_mgr->filter.mgt_class = IB_MCLASS_SUBN_DIR; + ibms_status = ibms_bind(conHdl, &p_mgr->filter); + if (ibms_status) { + return IB_ERROR; + } + + break; + + case IB_MCLASS_SUBN_ADM: + default: + qpn = 1; + p_mgr->filter.qpn = qpn; + p_mgr->filter.mgt_class = p_info->mad_class; + ibms_status = ibms_bind(conHdl, &p_mgr->filter); + if (ibms_status) { + return IB_ERROR; + } + break; + } + + p_mgr->conHdl = conHdl; + + p_bo->p_transp_mgr = p_mgr; + + /* Initialize the magic_ptr to the pointer of the p_bo info. + This will be used to signal when the object is being destroyed, so no + real action will be done then. */ + p_bo->magic_ptr = p_bo; + + return IB_SUCCESS; +} + +/* + * NAME + * osmv_transport_send_mad + * + * DESCRIPTION + * Send a single MAD (256 byte) + */ + +ib_api_status_t +osmv_transport_mad_send(IN const osm_bind_handle_t h_bind, + IN void *p_mad, IN const osm_mad_addr_t * p_mad_addr) +{ + + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + int ret; + ibms_mad_msg_t mad_msg; + ib_api_status_t status; + + const ib_mad_t *p_mad_hdr = p_mad; + + OSM_LOG_ENTER(p_vend->p_log); + + memset(&mad_msg, 0, sizeof(mad_msg)); + + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return IB_INVALID_CALLBACK; + + /* + * Copy the MAD over to the sent mad + */ + memcpy(&mad_msg.header, p_mad_hdr, MAD_BLOCK_SIZE); + + /* + * For all sends other than directed route SM MADs, + * acquire an address vector for the destination. + */ + if (p_mad_hdr->mgmt_class != IB_MCLASS_SUBN_DIR) { + + __osmv_ibms_osm_addr_to_mad_addr(p_mad_addr, + p_mad_hdr->mgmt_class == + IB_MCLASS_SUBN_LID, + &mad_msg.addr); + } else { + /* is a directed route - we need to construct a permissive address */ + /* we do not need port number since it is part of the mad_hndl */ + mad_msg.addr.dlid = IB_LID_PERMISSIVE; + mad_msg.addr.slid = IB_LID_PERMISSIVE; + mad_msg.addr.sqpn = 0; + mad_msg.addr.dqpn = 0; + } + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_mad_send: " + "Sending QPN:%d DLID:0x%04x class:0x%02x " + "method:0x%02x attr:0x%04x status:0x%04x " + "tid:0x%016" PRIx64 "\n", + mad_msg.addr.dqpn, + cl_ntoh16(mad_msg.addr.dlid), + mad_msg.header.mgmt_class, + mad_msg.header.method, + cl_ntoh16(mad_msg.header.attr_id), + cl_ntoh16(mad_msg.header.status), + cl_ntoh64(mad_msg.header.trans_id) + ); + + /* send it */ + ret = + ibms_send(((osmv_ibms_transport_mgr_t *) (p_bo->p_transp_mgr))-> + conHdl, &mad_msg); + if (ret) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osmv_transport_mad_send: ERR 5304: " + "Error sending mad (%d).\n", ret); + status = IB_ERROR; + goto Exit; + } + + status = IB_SUCCESS; + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +void osmv_transport_done(IN const osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osmv_ibms_transport_mgr_t *p_tpot_mgr = + (osmv_ibms_transport_mgr_t *) (p_bo->p_transp_mgr); + + CL_ASSERT(p_bo); + + /* First of all - zero out the magic_ptr, so if a callback is called - + it'll know that we are currently closing down, and will not handle the + mad. */ + p_bo->magic_ptr = 0; + /* usleep(3000000); */ + + ibms_disconnect(p_tpot_mgr->conHdl); + + /* seems the only way to abort a blocking read is to make it read something */ + free(p_tpot_mgr); +} + +static void +__osmv_ibms_osm_addr_to_mad_addr(IN const osm_mad_addr_t * p_osm_addr, + IN uint8_t is_smi, + OUT struct _ibms_mad_addr *p_ibms_addr) +{ + + /* For global destination or Multicast address: */ + p_ibms_addr->dlid = cl_ntoh16(p_osm_addr->dest_lid); + p_ibms_addr->sl = p_osm_addr->addr_type.gsi.service_level; + if (is_smi) { + p_ibms_addr->sqpn = 0; + p_ibms_addr->dqpn = 0; + } else { + p_ibms_addr->sqpn = 1; + p_ibms_addr->dqpn = + cl_ntoh32(p_osm_addr->addr_type.gsi.remote_qp); + } + /* + HACK we limit to the first PKey Index assuming it will + always be the default PKey + */ + p_ibms_addr->pkey_index = 0; +} + +static void +__osmv_ibms_mad_addr_to_osm_addr(IN osm_vendor_t const *p_vend, + IN struct _ibms_mad_addr *p_ibms_addr, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_osm_addr) +{ + memset(p_osm_addr, 0, sizeof(osm_mad_addr_t)); + p_osm_addr->dest_lid = cl_hton16(p_ibms_addr->slid); + p_osm_addr->static_rate = 0; + p_osm_addr->path_bits = 0; + if (is_smi) { + /* SMI */ + p_osm_addr->addr_type.smi.source_lid = + cl_hton16(p_ibms_addr->slid); + p_osm_addr->addr_type.smi.port_num = 1; /* TODO add if required p_ibms_addr->port; */ + } else { + /* GSI */ + p_osm_addr->addr_type.gsi.remote_qp = + cl_ntoh32(p_ibms_addr->sqpn); + p_osm_addr->addr_type.gsi.remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + p_osm_addr->addr_type.gsi.pkey_ix = p_ibms_addr->pkey_index; + p_osm_addr->addr_type.gsi.service_level = p_ibms_addr->sl; + + p_osm_addr->addr_type.gsi.global_route = FALSE; + /* copy the GRH data if relevant - TopSpin imp doesnt relate to GRH!!! */ + /* + if (p_osm_addr->addr_type.gsi.global_route) + { + p_osm_addr->addr_type.gsi.grh_info.ver_class_flow = + ib_grh_set_ver_class_flow(p_rcv_desc->grh.IP_version, + p_rcv_desc->grh.traffic_class, + p_rcv_desc->grh.flow_label); + p_osm_addr->addr_type.gsi.grh_info.hop_limit = p_rcv_desc->grh.hop_limit; + memcpy(&p_osm_addr->addr_type.gsi.grh_info.src_gid.raw, + &p_rcv_desc->grh.sgid, sizeof(ib_net64_t)); + memcpy(&p_osm_addr->addr_type.gsi.grh_info.dest_gid.raw, + p_rcv_desc->grh.dgid, sizeof(ib_net64_t)); + } + */ + } +} + +/* + * NAME osm_vendor_set_sm + * + * DESCRIPTION Modifies the port info for the bound port to set the "IS_SM" bit + * according to the value given (TRUE or FALSE). + */ + +void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + int ret; + ibms_cap_msg_t cap_msg; + + OSM_LOG_ENTER(p_vend->p_log); + + cap_msg.mask = IB_PORT_CAP_IS_SM; + if (is_sm_val) + cap_msg.capabilities = IB_PORT_CAP_IS_SM; + else + cap_msg.capabilities = 0; + + ret = ibms_set_cap(((osmv_ibms_transport_mgr_t *) (p_bo-> + p_transp_mgr))-> + conHdl, &cap_msg); + + if (ret) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_set_sm: ERR 5312: " + "Unable set 'IS_SM' bit to:%u in port attributes.\n", + is_sm_val); + } + OSM_LOG_EXIT(p_vend->p_log); +} diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_ts.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_ts.c new file mode 100644 index 000000000000..d7ab3b3a7666 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_ts.c @@ -0,0 +1,505 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* AUTHOR Edward Bortnikov + * + * DESCRIPTION + * The lower-level MAD transport interface implementation + * that allows sending a single MAD/receiving a callback + * when a single MAD is received. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +typedef struct _osmv_TOPSPIN_transport_mgr_ { + int device_fd; + osm_ts_user_mad_filter filter; + cl_thread_t receiver; +} osmv_TOPSPIN_transport_mgr_t; + +static void +__osmv_TOPSPIN_mad_addr_to_osm_addr(IN osm_vendor_t const *p_vend, + IN struct ib_mad *p_mad, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_mad_addr); + +static void +__osmv_TOPSPIN_osm_addr_to_mad_addr(IN const osm_mad_addr_t * p_mad_addr, + IN uint8_t is_smi, + OUT struct ib_mad *p_mad); + +void __osmv_TOPSPIN_receiver_thr(void *p_ctx) +{ + int ts_ret_code; + struct ib_mad mad; + osm_mad_addr_t mad_addr; + osmv_bind_obj_t *const p_bo = (osmv_bind_obj_t *) p_ctx; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + /* we set the type of cancelation for this thread */ + /* pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); */ + + while (1) { + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + /* we read one mad at a time and pass it to the read callback function */ + ts_ret_code = + read(((osmv_TOPSPIN_transport_mgr_t *) (p_bo-> + p_transp_mgr))-> + device_fd, &mad, sizeof(mad)); + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + if (ts_ret_code != sizeof(mad)) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_TOPSPIN_receiver_thr: ERR 6803: " + "error with read, bytes = %d, errno = %d\n", + ts_ret_code, errno); + break; + } else { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "__osmv_TOPSPIN_receiver_thr: " + "MAD QPN:%d SLID:0x%04x class:0x%02x " + "method:0x%02x attr:0x%04x status:0x%04x " + "tid:0x%016" PRIx64 "\n", + mad.dqpn, + cl_ntoh16(mad.slid), + mad.mgmt_class, + mad.r_method, + cl_ntoh16(mad.attribute_id), + cl_ntoh16(mad.status), + cl_ntoh64(mad.transaction_id)); + + /* first arrange an address */ + __osmv_TOPSPIN_mad_addr_to_osm_addr(p_bo->p_vendor, + &mad, + (((ib_mad_t *) & + mad)-> + mgmt_class == + IB_MCLASS_SUBN_LID) + || + (((ib_mad_t *) & + mad)-> + mgmt_class == + IB_MCLASS_SUBN_DIR), + &mad_addr); + + /* call the receiver callback */ + + status = + osmv_dispatch_mad((osm_bind_handle_t) p_bo, + (void *)&mad, &mad_addr); + + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + if (IB_INTERRUPTED == status) { + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "__osmv_TOPSPIN_receiver_thr: " + "The bind handle %p is being closed. " + "Breaking the loop.\n", p_bo); + break; + } + } + } + + OSM_LOG_EXIT(p_bo->p_vendor->p_log); +} + +/* + * NAME + * osmv_transport_init + * + * DESCRIPTION + * Setup the MAD transport infrastructure (filters, callbacks etc). + */ + +ib_api_status_t +osmv_transport_init(IN osm_bind_info_t * p_info, + IN char hca_id[VENDOR_HCA_MAXNAMES], + IN uint8_t hca_idx, IN osmv_bind_obj_t * p_bo) +{ + cl_status_t cl_st; + char device_file[16]; + int device_fd; + int ts_ioctl_ret; + osmv_TOPSPIN_transport_mgr_t *p_mgr = + malloc(sizeof(osmv_TOPSPIN_transport_mgr_t)); + int qpn; + + if (!p_mgr) { + return IB_INSUFFICIENT_MEMORY; + } + + memset(p_mgr, 0, sizeof(osmv_TOPSPIN_transport_mgr_t)); + + /* open TopSpin file device */ + /* HACK: assume last char in hostid is the HCA index */ + sprintf(device_file, "/dev/ts_ua%u", hca_idx); + device_fd = open(device_file, O_RDWR); + if (device_fd < 0) { + fprintf(stderr, "Fatal: Fail to open the file:%s err:%d\n", + device_file, errno); + return IB_ERROR; + } + + /* + * Create the MAD filter on this file handle. + */ + + p_mgr->filter.port = p_bo->port_num; + p_mgr->filter.direction = TS_IB_MAD_DIRECTION_IN; + p_mgr->filter.mask = + TS_IB_MAD_FILTER_DIRECTION | + TS_IB_MAD_FILTER_PORT | + TS_IB_MAD_FILTER_QPN | TS_IB_MAD_FILTER_MGMT_CLASS; + + switch (p_info->mad_class) { + case IB_MCLASS_SUBN_LID: + case IB_MCLASS_SUBN_DIR: + qpn = 0; + p_mgr->filter.qpn = qpn; + p_mgr->filter.mgmt_class = IB_MCLASS_SUBN_LID; + ts_ioctl_ret = + ioctl(device_fd, TS_IB_IOCSMADFILTADD, &p_mgr->filter); + if (ts_ioctl_ret < 0) { + return IB_ERROR; + } + + p_mgr->filter.mgmt_class = IB_MCLASS_SUBN_DIR; + ts_ioctl_ret = + ioctl(device_fd, TS_IB_IOCSMADFILTADD, &p_mgr->filter); + if (ts_ioctl_ret < 0) { + return IB_ERROR; + } + + break; + + case IB_MCLASS_SUBN_ADM: + default: + qpn = 1; + p_mgr->filter.qpn = qpn; + p_mgr->filter.mgmt_class = p_info->mad_class; + ts_ioctl_ret = + ioctl(device_fd, TS_IB_IOCSMADFILTADD, &p_mgr->filter); + if (ts_ioctl_ret < 0) { + return IB_ERROR; + } + break; + } + + p_mgr->device_fd = device_fd; + + p_bo->p_transp_mgr = p_mgr; + + /* Initialize the magic_ptr to the pointer of the p_bo info. + This will be used to signal when the object is being destroyed, so no + real action will be done then. */ + p_bo->magic_ptr = p_bo; + + /* init receiver thread */ + cl_st = + cl_thread_init(&p_mgr->receiver, __osmv_TOPSPIN_receiver_thr, + (void *)p_bo, "osmv TOPSPIN rcv thr"); + + return (ib_api_status_t) cl_st; +} + +/* + * NAME + * osmv_transport_send_mad + * + * DESCRIPTION + * Send a single MAD (256 byte) + */ + +ib_api_status_t +osmv_transport_mad_send(IN const osm_bind_handle_t h_bind, + IN void *p_mad, IN const osm_mad_addr_t * p_mad_addr) +{ + + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + struct ib_mad ts_mad; + int ret; + ib_api_status_t status; + + const ib_mad_t *p_mad_hdr = p_mad; + + OSM_LOG_ENTER(p_vend->p_log); + + memset(&ts_mad, 0, sizeof(ts_mad)); + + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return IB_INVALID_CALLBACK; + + /* + * Copy the MAD over to the sent mad + */ + memcpy(&ts_mad, p_mad_hdr, MAD_BLOCK_SIZE); + + /* + * For all sends other than directed route SM MADs, + * acquire an address vector for the destination. + */ + if (p_mad_hdr->mgmt_class != IB_MCLASS_SUBN_DIR) { + + __osmv_TOPSPIN_osm_addr_to_mad_addr(p_mad_addr, + p_mad_hdr->mgmt_class == + IB_MCLASS_SUBN_LID, + &ts_mad); + } else { + /* is a directed route - we need to construct a permissive address */ + /* we do not need port number since it is part of the mad_hndl */ + ts_mad.dlid = IB_LID_PERMISSIVE; + ts_mad.slid = IB_LID_PERMISSIVE; + ts_mad.sqpn = 0; + ts_mad.dqpn = 0; + } + + ts_mad.port = p_bo->port_num; + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "osmv_transport_mad_send: " + "Sending QPN:%d DLID:0x%04x class:0x%02x " + "method:0x%02x attr:0x%04x status:0x%04x " + "tid:0x%016" PRIx64 "\n", + ts_mad.dqpn, + cl_ntoh16(ts_mad.dlid), + ts_mad.mgmt_class, + ts_mad.r_method, + cl_ntoh16(ts_mad.attribute_id), + cl_ntoh16(ts_mad.status), cl_ntoh64(ts_mad.transaction_id) + ); + + /* send it */ + ret = + write(((osmv_TOPSPIN_transport_mgr_t *) (p_bo->p_transp_mgr))-> + device_fd, &ts_mad, sizeof(ts_mad)); + + if (ret != sizeof(ts_mad)) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osmv_transport_mad_send: ERR 6804: " + "Error sending mad (%d).\n", ret); + status = IB_ERROR; + goto Exit; + } + + status = IB_SUCCESS; + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/* + register a new mad type to the opened device file + and send a mad through - the main idea is to make + the filter catch it such that the read unblocks +*/ +void __osm_transport_gen_dummy_mad(osmv_bind_obj_t * p_bo) +{ + struct ib_mad ts_mad; + osmv_TOPSPIN_transport_mgr_t *p_mgr = + (osmv_TOPSPIN_transport_mgr_t *) (p_bo->p_transp_mgr); + struct ib_get_port_info_ioctl port_data; + int ts_ioctl_ret; + + /* prepare the mad fields following the stored filter on the bind */ + memset(&ts_mad, 0, sizeof(ts_mad)); + ts_mad.format_version = 1; + ts_mad.mgmt_class = p_mgr->filter.mgmt_class; + ts_mad.attribute_id = 0x2; + ts_mad.class_version = 1; + ts_mad.r_method = cl_ntoh16(0x2); + ts_mad.port = p_bo->port_num; + ts_mad.sqpn = p_mgr->filter.qpn; + ts_mad.dqpn = p_mgr->filter.qpn; + ts_mad.slid = 0xffff; + /* we must send to our local lid ... */ + port_data.port = p_bo->port_num; + ts_ioctl_ret = ioctl(p_mgr->device_fd, TS_IB_IOCGPORTINFO, &port_data); + ts_mad.dlid = port_data.port_info.lid; + ts_mad.transaction_id = 0x9999; + write(p_mgr->device_fd, &ts_mad, sizeof(ts_mad)); +} + +void osmv_transport_done(IN const osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osmv_TOPSPIN_transport_mgr_t *p_tpot_mgr = + (osmv_TOPSPIN_transport_mgr_t *) (p_bo->p_transp_mgr); + + CL_ASSERT(p_bo); + + /* First of all - zero out the magic_ptr, so if a callback is called - + it'll know that we are currently closing down, and will not handle the + mad. */ + p_bo->magic_ptr = 0; + /* usleep(3000000); */ + + /* seems the only way to abort a blocking read is to make it read something */ + __osm_transport_gen_dummy_mad(p_bo); + cl_thread_destroy(&(p_tpot_mgr->receiver)); + free(p_tpot_mgr); +} + +static void +__osmv_TOPSPIN_osm_addr_to_mad_addr(IN const osm_mad_addr_t * p_mad_addr, + IN uint8_t is_smi, OUT struct ib_mad *p_mad) +{ + + /* For global destination or Multicast address: */ + p_mad->dlid = cl_ntoh16(p_mad_addr->dest_lid); + p_mad->sl = p_mad_addr->addr_type.gsi.service_level; + if (is_smi) { + p_mad->sqpn = 0; + p_mad->dqpn = 0; + } else { + p_mad->sqpn = 1; + p_mad->dqpn = cl_ntoh32(p_mad_addr->addr_type.gsi.remote_qp); + } + /* + HACK we limit to the first PKey Index assuming it will + always be the default PKey + */ + p_mad->pkey_index = 0; +} + +static void +__osmv_TOPSPIN_mad_addr_to_osm_addr(IN osm_vendor_t const *p_vend, + IN struct ib_mad *p_mad, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_mad_addr) +{ + p_mad_addr->dest_lid = cl_hton16(p_mad->slid); + p_mad_addr->static_rate = 0; + p_mad_addr->path_bits = 0; + if (is_smi) { + /* SMI */ + p_mad_addr->addr_type.smi.source_lid = cl_hton16(p_mad->slid); + p_mad_addr->addr_type.smi.port_num = p_mad->port; + } else { + /* GSI */ + p_mad_addr->addr_type.gsi.remote_qp = cl_ntoh32(p_mad->sqpn); + p_mad_addr->addr_type.gsi.remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + /* There is a TAVOR limitation that only one P_KEY is supported per */ + /* QP - so QP1 must use IB_DEFAULT_PKEY */ + p_mad_addr->addr_type.gsi.pkey_ix = p_mad->pkey_index; + p_mad_addr->addr_type.gsi.service_level = p_mad->sl; + + p_mad_addr->addr_type.gsi.global_route = FALSE; + /* copy the GRH data if relevant - TopSpin imp doesnt relate to GRH!!! */ + /* + if (p_mad_addr->addr_type.gsi.global_route) + { + p_mad_addr->addr_type.gsi.grh_info.ver_class_flow = + ib_grh_set_ver_class_flow(p_rcv_desc->grh.IP_version, + p_rcv_desc->grh.traffic_class, + p_rcv_desc->grh.flow_label); + p_mad_addr->addr_type.gsi.grh_info.hop_limit = p_rcv_desc->grh.hop_limit; + memcpy(&p_mad_addr->addr_type.gsi.grh_info.src_gid.raw, + &p_rcv_desc->grh.sgid, sizeof(ib_net64_t)); + memcpy(&p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw, + p_rcv_desc->grh.dgid, sizeof(ib_net64_t)); + } + */ + } +} + +/* + * NAME osm_vendor_set_sm + * + * DESCRIPTION Modifies the port info for the bound port to set the "IS_SM" bit + * according to the value given (TRUE or FALSE). + */ +#if (defined(OSM_VENDOR_INTF_TS_NO_VAPI) || defined(OSM_VENDOR_INTF_TS)) + +void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + int ts_ioctl_ret; + int device_fd = + ((osmv_TOPSPIN_transport_mgr_t *) (p_bo->p_transp_mgr))->device_fd; + struct ib_set_port_info_ioctl set_port_data; + + OSM_LOG_ENTER(p_vend->p_log); + + memset(&set_port_data, 0, sizeof(set_port_data)); + + set_port_data.port = p_bo->port_num; + set_port_data.port_info.valid_fields = IB_PORT_IS_SM; + set_port_data.port_info.is_sm = is_sm_val; + ts_ioctl_ret = ioctl(device_fd, TS_IB_IOCSPORTINFO, &set_port_data); + if (ts_ioctl_ret < 0) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_set_sm: ERR 6805: " + "Unable set 'IS_SM' bit to:%u in port attributes (%d).\n", + is_sm_val, ts_ioctl_ret); + } + + OSM_LOG_EXIT(p_vend->p_log); +} + +#endif diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_ts_anafa.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_ts_anafa.c new file mode 100644 index 000000000000..b88ac646241a --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_ts_anafa.c @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* AUTHOR Edward Bortnikov + * + * DESCRIPTION + * The lower-level MAD transport interface implementation + * that allows sending a single MAD/receiving a callback + * when a single MAD is received. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static void +__osmv_TOPSPIN_ANAFA_mad_addr_to_osm_addr(IN osm_vendor_t const *p_vend, + IN struct ib_mad *p_mad, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_mad_addr); + +static void +__osmv_TOPSPIN_ANAFA_osm_addr_to_mad_addr(IN const osm_mad_addr_t * + p_mad_addr, IN uint8_t is_smi, + OUT struct ib_mad *p_mad); + +void __osmv_TOPSPIN_ANAFA_receiver_thr(void *p_ctx) +{ + int ts_ret_code; + struct ib_mad mad; + osm_mad_addr_t mad_addr; + osmv_bind_obj_t *const p_bo = (osmv_bind_obj_t *) p_ctx; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + /* we set the type of cancelation for this thread */ + /* pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); */ + + while (1) { + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + /* we read one mad at a time and pass it to the read callback function */ + ts_ret_code = + read(((osmv_TOPSPIN_ANAFA_transport_mgr_t *) (p_bo-> + p_transp_mgr))-> + device_fd, &mad, sizeof(mad)); + + /* Make sure the p_bo object is still relevant */ + if ((p_bo->magic_ptr != p_bo) || p_bo->is_closing) + return; + + if (ts_ret_code != sizeof(mad)) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_TOPSPIN_ANAFA_receiver_thr: ERR 6903: " + "error with read, bytes = %d\n", ts_ret_code); + break; + } else { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "__osmv_TOPSPIN_ANAFA_receiver_thr: " + "MAD QPN:%d SLID:0x%04x class:0x%02x " + "method:0x%02x attr:0x%04x status:0x%04x " + "tid:0x%016" PRIx64 "\n", + mad.dqpn, + cl_ntoh16(mad.slid), + mad.mgmt_class, + mad.r_method, + cl_ntoh16(mad.attribute_id), + cl_ntoh16(mad.status), + cl_ntoh64(mad.transaction_id)); + + /* first arrange an address */ + __osmv_TOPSPIN_ANAFA_mad_addr_to_osm_addr + (p_bo->p_vendor, &mad, + (((ib_mad_t *) & mad)->mgmt_class == + IB_MCLASS_SUBN_LID) + || (((ib_mad_t *) & mad)->mgmt_class == + IB_MCLASS_SUBN_DIR), &mad_addr); + + /* call the receiver callback */ + + status = + osmv_dispatch_mad((osm_bind_handle_t) p_bo, + (void *)&mad, &mad_addr); + + /* Make sure the p_bo object is still relevant */ + if (p_bo->magic_ptr != p_bo) + return; + + if (IB_INTERRUPTED == status) { + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "__osmv_TOPSPIN_ANAFA_receiver_thr: " + "The bind handle %p is being closed. " + "Breaking the loop.\n", p_bo); + break; + } + } + } + + OSM_LOG_EXIT(p_bo->p_vendor->p_log); +} + +/* + * NAME + * osmv_transport_init + * + * DESCRIPTION + * Setup the MAD transport infrastructure (filters, callbacks etc). + */ + +ib_api_status_t +osmv_transport_init(IN osm_bind_info_t * p_info, + IN char hca_id[VENDOR_HCA_MAXNAMES], + IN uint8_t hca_idx, IN osmv_bind_obj_t * p_bo) +{ + cl_status_t cl_st; + + int ts_ioctl_ret; + int device_fd; + char *device_file = "/dev/ts_ua0"; + osm_ts_user_mad_filter filter; + osmv_TOPSPIN_ANAFA_transport_mgr_t *p_mgr; + osmv_TOPSPIN_ANAFA_transport_info_t *p_tpot_info; + p_tpot_info = + (osmv_TOPSPIN_ANAFA_transport_info_t *) p_bo->p_vendor-> + p_transport_info; + + p_mgr = malloc(sizeof(osmv_TOPSPIN_ANAFA_transport_mgr_t)); + if (!p_mgr) { + return IB_INSUFFICIENT_MEMORY; + } + + memset(p_mgr, 0, sizeof(osmv_TOPSPIN_ANAFA_transport_mgr_t)); + + /* open TopSpin file device */ + device_fd = open(device_file, O_RDWR); + if (device_fd < 0) { + fprintf(stderr, "Fatal: Fail to open the file:%s err:%d\n", + device_file, errno); + return IB_ERROR; + } + p_mgr->device_fd = device_fd; + + /* + * Create the MAD filter on this file handle. + */ + + filter.port = 0; /* Victor */ + filter.direction = TS_IB_MAD_DIRECTION_IN; + filter.mask = + TS_IB_MAD_FILTER_DIRECTION | + TS_IB_MAD_FILTER_PORT | + TS_IB_MAD_FILTER_QPN | TS_IB_MAD_FILTER_MGMT_CLASS; + + switch (p_info->mad_class) { + case IB_MCLASS_SUBN_LID: + case IB_MCLASS_SUBN_DIR: + filter.qpn = 0; + filter.mgmt_class = IB_MCLASS_SUBN_LID; + ts_ioctl_ret = ioctl(device_fd, TS_IB_IOCSMADFILTADD, &filter); + if (ts_ioctl_ret < 0) { + return IB_ERROR; + } + + filter.mgmt_class = IB_MCLASS_SUBN_DIR; + ts_ioctl_ret = ioctl(device_fd, TS_IB_IOCSMADFILTADD, &filter); + if (ts_ioctl_ret < 0) { + return IB_ERROR; + } + + break; + + case IB_MCLASS_SUBN_ADM: + default: + filter.qpn = 1; + filter.mgmt_class = p_info->mad_class; + ts_ioctl_ret = ioctl(device_fd, TS_IB_IOCSMADFILTADD, &filter); + if (ts_ioctl_ret < 0) { + return IB_ERROR; + } + break; + } + + p_bo->p_transp_mgr = p_mgr; + + /* Initialize the magic_ptr to the pointer of the p_bo info. + This will be used to signal when the object is being destroyed, so no + real action will be done then. */ + p_bo->magic_ptr = p_bo; + + /* init receiver thread */ + cl_st = + cl_thread_init(&p_mgr->receiver, __osmv_TOPSPIN_ANAFA_receiver_thr, + (void *)p_bo, "osmv TOPSPIN_ANAFA rcv thr"); + + return (ib_api_status_t) cl_st; +} + +/* + * NAME + * osmv_transport_send_mad + * + * DESCRIPTION + * Send a single MAD (256 byte) + */ + +ib_api_status_t +osmv_transport_mad_send(IN const osm_bind_handle_t h_bind, + IN void *p_mad, IN const osm_mad_addr_t * p_mad_addr) +{ + + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osm_vendor_t const *p_vend = p_bo->p_vendor; + struct ib_mad ts_mad = { 0 }; + int ret; + ib_api_status_t status; + + const ib_mad_t *p_mad_hdr = p_mad; + + OSM_LOG_ENTER(p_vend->p_log); + + /* Make sure the p_bo object is still relevant */ + if (p_bo->magic_ptr != p_bo) + return IB_INVALID_CALLBACK; + + /* + * Copy the MAD over to the sent mad + */ + memcpy(&ts_mad, p_mad_hdr, MAD_BLOCK_SIZE); + + /* + * For all sends other than directed route SM MADs, + * acquire an address vector for the destination. + */ + if (p_mad_hdr->mgmt_class != IB_MCLASS_SUBN_DIR) { + + __osmv_TOPSPIN_ANAFA_osm_addr_to_mad_addr(p_mad_addr, + p_mad_hdr-> + mgmt_class == + IB_MCLASS_SUBN_LID, + &ts_mad); + } else { + /* is a directed route - we need to construct a permissive address */ + /* we do not need port number since it is part of the mad_hndl */ + ts_mad.dlid = IB_LID_PERMISSIVE; + ts_mad.slid = IB_LID_PERMISSIVE; + } + if ((p_mad_hdr->mgmt_class == IB_MCLASS_SUBN_DIR) || + (p_mad_hdr->mgmt_class == IB_MCLASS_SUBN_LID)) { + ts_mad.sqpn = 0; + ts_mad.dqpn = 0; + } else { + ts_mad.sqpn = 1; + ts_mad.dqpn = 1; + } + + /* ts_mad.port = p_bo->port_num; */ + ts_mad.port = 0; /* Victor */ + + /* send it */ + ret = + write(((osmv_TOPSPIN_ANAFA_transport_mgr_t *) (p_bo-> + p_transp_mgr))-> + device_fd, &ts_mad, sizeof(ts_mad)); + + if (ret != sizeof(ts_mad)) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osmv_transport_mad_send: ERR 6904: " + "Error sending mad (%d).\n", ret); + status = IB_ERROR; + goto Exit; + } + + status = IB_SUCCESS; + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +void osmv_transport_done(IN const osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + osmv_TOPSPIN_ANAFA_transport_mgr_t *p_tpot_mgr = + (osmv_TOPSPIN_ANAFA_transport_mgr_t *) (p_bo->p_transp_mgr); + + CL_ASSERT(p_bo); + + /* First of all - zero out the magic_ptr, so if a callback is called - + it'll know that we are currently closing down, and will not handle the + mad. */ + p_bo->magic_ptr = 0; + + /* usleep(3000000); */ + + /* pthread_cancel (p_tpot_mgr->receiver.osd.id); */ + cl_thread_destroy(&(p_tpot_mgr->receiver)); + free(p_tpot_mgr); +} + +static void +__osmv_TOPSPIN_ANAFA_osm_addr_to_mad_addr(IN const osm_mad_addr_t * p_mad_addr, + IN uint8_t is_smi, + OUT struct ib_mad *p_mad) +{ + + /* For global destination or Multicast address: */ + p_mad->dlid = cl_ntoh16(p_mad_addr->dest_lid); + p_mad->sl = p_mad_addr->addr_type.gsi.service_level; + if (is_smi) { + p_mad->sqpn = 0; + p_mad->dqpn = 0; + } else { + p_mad->sqpn = 1; + p_mad->dqpn = p_mad_addr->addr_type.gsi.remote_qp; + } + /* + HACK we limit to the first PKey Index assuming it will + always be the default PKey + */ + p_mad->pkey_index = 0; +} + +static void +__osmv_TOPSPIN_ANAFA_mad_addr_to_osm_addr(IN osm_vendor_t const *p_vend, + IN struct ib_mad *p_mad, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_mad_addr) +{ + p_mad_addr->dest_lid = cl_hton16(p_mad->slid); + p_mad_addr->static_rate = 0; + p_mad_addr->path_bits = 0; + if (is_smi) { + /* SMI */ + p_mad_addr->addr_type.smi.source_lid = cl_hton16(p_mad->slid); + p_mad_addr->addr_type.smi.port_num = p_mad->port; + } else { + /* GSI */ + p_mad_addr->addr_type.gsi.remote_qp = p_mad->sqpn; + p_mad_addr->addr_type.gsi.remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + p_mad_addr->addr_type.gsi.pkey_ix = p_mad->pkey_index; + p_mad_addr->addr_type.gsi.service_level = p_mad->sl; + + p_mad_addr->addr_type.gsi.global_route = FALSE; + /* copy the GRH data if relevant - TopSpin imp doesnt relate to GRH!!! */ + /* + if (p_mad_addr->addr_type.gsi.global_route) + { + p_mad_addr->addr_type.gsi.grh_info.ver_class_flow = + ib_grh_set_ver_class_flow(p_rcv_desc->grh.IP_version, + p_rcv_desc->grh.traffic_class, + p_rcv_desc->grh.flow_label); + p_mad_addr->addr_type.gsi.grh_info.hop_limit = p_rcv_desc->grh.hop_limit; + memcpy(&p_mad_addr->addr_type.gsi.grh_info.src_gid.raw, + &p_rcv_desc->grh.sgid, sizeof(ib_net64_t)); + memcpy(&p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw, + p_rcv_desc->grh.dgid, sizeof(ib_net64_t)); + } + */ + } +} diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_txn.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_txn.c new file mode 100644 index 000000000000..a2da75ac6b9a --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_txn.c @@ -0,0 +1,675 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#include +#include +#include +#include +#include + +static ib_api_status_t +__osmv_txnmgr_lookup(IN osmv_txn_mgr_t * p_tx_mgr, + IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn); + +static ib_api_status_t +__osmv_txnmgr_insert_txn(IN osmv_txn_mgr_t * p_tx_mgr, + IN osmv_txn_ctx_t * p_txn, IN uint64_t key); + +static ib_api_status_t +__osmv_txnmgr_remove_txn(IN osmv_txn_mgr_t * p_tx_mgr, + IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn); + +static void __osmv_txn_all_done(osm_bind_handle_t h_bind); + +static uint64_t +__osmv_txn_timeout_cb(IN uint64_t key, + IN uint32_t num_regs, IN void *cb_context); + +ib_api_status_t +osmv_txn_init(IN osm_bind_handle_t h_bind, + IN uint64_t tid, IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn) +{ + ib_api_status_t st; + osmv_txn_ctx_t *p_txn; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + CL_ASSERT(NULL != h_bind && NULL != pp_txn); + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "Starting transaction 0x%llX (key=0x%llX)\n", tid, key); + + p_txn = malloc(sizeof(osmv_txn_ctx_t)); + if (!p_txn) { + return IB_INSUFFICIENT_MEMORY; + } + + memset(p_txn, 0, sizeof(osmv_txn_ctx_t)); + p_txn->p_log = p_bo->txn_mgr.p_log; + p_txn->tid = tid; + p_txn->key = key; + p_txn->p_madw = NULL; + p_txn->rmpp_txfr.rmpp_state = OSMV_TXN_RMPP_NONE; + + /* insert into transaction manager DB */ + st = __osmv_txnmgr_insert_txn(&p_bo->txn_mgr, p_txn, key); + if (IB_SUCCESS != st) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "osmv_txn_init: ERR 6703: " + "Failed to insert to transaction 0x%llX (key=0x%llX) to manager DB\n", + tid, key); + goto insert_txn_failed; + } + + *pp_txn = p_txn; + OSM_LOG_EXIT(p_bo->p_vendor->p_log); + return IB_SUCCESS; + +insert_txn_failed: + free(p_txn); + + OSM_LOG_EXIT(p_bo->p_vendor->p_log); + return st; +} + +ib_api_status_t +osmv_txn_init_rmpp_sender(IN osm_bind_handle_t h_bind, + IN osmv_txn_ctx_t * p_txn, IN osm_madw_t * p_madw) +{ + ib_api_status_t st; + + CL_ASSERT(p_txn); + + /* Double-Sided RMPP Direction Switch */ + osmv_txn_remove_timeout_ev(h_bind, osmv_txn_get_key(p_txn)); + + p_txn->rmpp_txfr.rmpp_state = OSMV_TXN_RMPP_SENDER; + p_txn->rmpp_txfr.p_rmpp_send_ctx = malloc(sizeof(osmv_rmpp_send_ctx_t)); + + if (!p_txn->rmpp_txfr.p_rmpp_send_ctx) { + return IB_INSUFFICIENT_MEMORY; + } + + memset(p_txn->rmpp_txfr.p_rmpp_send_ctx, 0, + sizeof(osmv_rmpp_send_ctx_t)); + + st = osmv_rmpp_send_ctx_init(p_txn->rmpp_txfr.p_rmpp_send_ctx, + (void *)p_madw->p_mad, + p_madw->mad_size, p_txn->p_log); + return st; +} + +ib_api_status_t +osmv_txn_init_rmpp_receiver(IN osm_bind_handle_t h_bind, + IN osmv_txn_ctx_t * p_txn, + IN boolean_t is_init_by_peer) +{ + ib_api_status_t st; + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + uint64_t key = osmv_txn_get_key(p_txn); + + CL_ASSERT(p_txn); + + /* Double-Sided RMPP Direction Switch */ + osmv_txn_remove_timeout_ev(h_bind, key); + + /* Set the Transaction Timeout value */ + st = osmv_txn_set_timeout_ev(h_bind, key, + p_bo->p_vendor->ttime_timeout); + if (IB_SUCCESS != st) { + + return st; + } + + p_txn->rmpp_txfr.rmpp_state = OSMV_TXN_RMPP_RECEIVER; + p_txn->rmpp_txfr.is_rmpp_init_by_peer = is_init_by_peer; + + p_txn->rmpp_txfr.p_rmpp_recv_ctx = malloc(sizeof(osmv_rmpp_recv_ctx_t)); + + if (!p_txn->rmpp_txfr.p_rmpp_recv_ctx) { + + osmv_txn_remove_timeout_ev(h_bind, key); + return IB_INSUFFICIENT_MEMORY; + } + + memset(p_txn->rmpp_txfr.p_rmpp_recv_ctx, 0, + sizeof(osmv_rmpp_recv_ctx_t)); + + st = osmv_rmpp_recv_ctx_init(p_txn->rmpp_txfr.p_rmpp_recv_ctx, + p_txn->p_log); + + return st; +} + +/* + * NAME + * osmv_txn_set_timeout_ev + * + * DESCRIPTION + * + * SEE ALSO + * + */ +ib_api_status_t +osmv_txn_set_timeout_ev(IN osm_bind_handle_t h_bind, + IN uint64_t key, IN uint64_t msec) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + cl_event_wheel_t *p_event_wheel = p_bo->txn_mgr.p_event_wheel; + cl_status_t status; + + status = cl_event_wheel_reg(p_event_wheel, key, cl_get_time_stamp() + 1000 * msec, /* TTL */ + __osmv_txn_timeout_cb, + p_bo /* The context */ ); + + return (ib_api_status_t) status; +} + +/* + * NAME + * osmv_txn_remove_timeout_ev + * + * DESCRIPTION + + * SEE ALSO + * + */ +void osmv_txn_remove_timeout_ev(IN osm_bind_handle_t h_bind, IN uint64_t key) +{ + cl_event_wheel_t *p_event_wheel = + ((osmv_bind_obj_t *) h_bind)->txn_mgr.p_event_wheel; + cl_event_wheel_unreg(p_event_wheel, key); +} + +void +osmv_txn_done(IN osm_bind_handle_t h_bind, + IN uint64_t key, IN boolean_t is_in_cb) +{ + osmv_txn_ctx_t *p_ctx; + osmv_bind_obj_t *const p_bo = (osmv_bind_obj_t *) h_bind; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + CL_ASSERT(h_bind); + + /* Cancel the (single) timeout possibly outstanding for this txn + * Don't do this if you are in the callback context, for 2 reasons: + * (1) The event wheel will remove the context itself. + * (2) If we try to, there is a deadlock in the event wheel + */ + if (FALSE == is_in_cb) { + osmv_txn_remove_timeout_ev(h_bind, key); + } + + /* Remove from DB */ + if (IB_NOT_FOUND == + __osmv_txnmgr_remove_txn(&p_bo->txn_mgr, key, &p_ctx)) { + return; + } + + /* Destroy the transaction's RMPP contexts + * (can be more than one in the case of double sided transfer) + */ + + if (p_ctx->rmpp_txfr.p_rmpp_send_ctx) { + osmv_rmpp_send_ctx_done(p_ctx->rmpp_txfr.p_rmpp_send_ctx); + } + + if (p_ctx->rmpp_txfr.p_rmpp_recv_ctx) { + osmv_rmpp_recv_ctx_done(p_ctx->rmpp_txfr.p_rmpp_recv_ctx); + } + + free(p_ctx); + + OSM_LOG_EXIT(p_bo->p_vendor->p_log); +} + +ib_api_status_t +osmv_txn_lookup(IN osm_bind_handle_t h_bind, + IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn) +{ + return __osmv_txnmgr_lookup(&(((osmv_bind_obj_t *) h_bind)->txn_mgr), + key, pp_txn); +} + +void osmv_txn_abort_rmpp_txns(osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + cl_map_item_t *p_item; + cl_map_obj_t *p_obj; + osmv_txn_ctx_t *p_txn; + osmv_rmpp_send_ctx_t *p_send_ctx; + cl_qmap_t *p_map = p_bo->txn_mgr.p_txn_map; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + while (FALSE == cl_is_qmap_empty(p_map)) { + + p_item = cl_qmap_head(p_map); + p_obj = PARENT_STRUCT(p_item, cl_map_obj_t, item); + p_txn = (osmv_txn_ctx_t *) cl_qmap_obj(p_obj); + p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); + + if (NULL != p_send_ctx) { + + p_send_ctx->status = IB_INTERRUPTED; + + /* Wake up the sender thread to let it break out */ + cl_event_signal(&p_send_ctx->event); + } + + cl_qmap_remove_item(p_map, p_item); + } + + OSM_LOG_EXIT(p_bo->p_vendor->p_log); +} + +ib_api_status_t +osmv_txnmgr_init(IN osmv_txn_mgr_t * p_tx_mgr, + IN osm_log_t * p_log, IN cl_spinlock_t * p_lock) +{ + cl_status_t cl_st = CL_SUCCESS; + + p_tx_mgr->p_event_wheel = malloc(sizeof(cl_event_wheel_t)); + if (!p_tx_mgr->p_event_wheel) { + return IB_INSUFFICIENT_MEMORY; + } + + memset(p_tx_mgr->p_event_wheel, 0, sizeof(cl_event_wheel_t)); + + cl_event_wheel_construct(p_tx_mgr->p_event_wheel); + + /* NOTE! We are using an extended constructor. + * We tell the Event Wheel run in a non-protected manner in the reg/unreg calls, + * and acquire an external lock in the asynchronous callback. + */ + cl_st = cl_event_wheel_init_ex(p_tx_mgr->p_event_wheel, p_lock); + if (cl_st != CL_SUCCESS) { + free(p_tx_mgr->p_event_wheel); + return (ib_api_status_t) cl_st; + } + + p_tx_mgr->p_txn_map = malloc(sizeof(cl_qmap_t)); + if (!p_tx_mgr->p_txn_map) { + cl_event_wheel_destroy(p_tx_mgr->p_event_wheel); + free(p_tx_mgr->p_event_wheel); + return IB_INSUFFICIENT_MEMORY; + } + + memset(p_tx_mgr->p_txn_map, 0, sizeof(cl_qmap_t)); + + cl_qmap_init(p_tx_mgr->p_txn_map); + p_tx_mgr->p_log = p_log; + + return cl_st; +} + +void osmv_txnmgr_done(IN osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + + __osmv_txn_all_done(h_bind); + free(p_bo->txn_mgr.p_txn_map); + + cl_event_wheel_destroy(p_bo->txn_mgr.p_event_wheel); + free(p_bo->txn_mgr.p_event_wheel); +} + +ib_api_status_t +__osmv_txnmgr_lookup(IN osmv_txn_mgr_t * p_tx_mgr, + IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn) +{ + ib_api_status_t status = IB_SUCCESS; + cl_map_item_t *p_item; + cl_map_obj_t *p_obj; + + uint64_t tmp_key; + + OSM_LOG_ENTER(p_tx_mgr->p_log); + + CL_ASSERT(p_tx_mgr); + CL_ASSERT(pp_txn); + + osm_log(p_tx_mgr->p_log, OSM_LOG_DEBUG, + "__osmv_txnmgr_lookup: " + "Looking for key: 0x%llX in map ptr:%p\n", key, + p_tx_mgr->p_txn_map); + + p_item = cl_qmap_head(p_tx_mgr->p_txn_map); + while (p_item != cl_qmap_end(p_tx_mgr->p_txn_map)) { + tmp_key = cl_qmap_key(p_item); + osm_log(p_tx_mgr->p_log, OSM_LOG_DEBUG, + "__osmv_txnmgr_lookup: " + "Found key 0x%llX \n", tmp_key); + p_item = cl_qmap_next(p_item); + } + + p_item = cl_qmap_get(p_tx_mgr->p_txn_map, key); + if (cl_qmap_end(p_tx_mgr->p_txn_map) == p_item) { + status = IB_NOT_FOUND; + } else { + p_obj = PARENT_STRUCT(p_item, cl_map_obj_t, item); + *pp_txn = cl_qmap_obj(p_obj); + } + + OSM_LOG_EXIT(p_tx_mgr->p_log); + return status; +} + +ib_api_status_t +__osmv_txnmgr_insert_txn(IN osmv_txn_mgr_t * p_tx_mgr, + IN osmv_txn_ctx_t * p_txn, IN uint64_t key) +{ + cl_map_obj_t *p_obj = NULL; + cl_map_item_t *p_item; + uint64_t tmp_key; + + CL_ASSERT(p_tx_mgr); + CL_ASSERT(p_txn); + + key = osmv_txn_get_key(p_txn); + p_obj = malloc(sizeof(cl_map_obj_t)); + if (NULL == p_obj) + return IB_INSUFFICIENT_MEMORY; + + osm_log(p_tx_mgr->p_log, OSM_LOG_DEBUG, + "__osmv_txnmgr_insert_txn: " + "Inserting key: 0x%llX to map ptr:%p\n", key, + p_tx_mgr->p_txn_map); + + memset(p_obj, 0, sizeof(cl_map_obj_t)); + + cl_qmap_set_obj(p_obj, p_txn); + /* assuming lookup with this key was made and the result was IB_NOT_FOUND */ + cl_qmap_insert(p_tx_mgr->p_txn_map, key, &p_obj->item); + + p_item = cl_qmap_head(p_tx_mgr->p_txn_map); + while (p_item != cl_qmap_end(p_tx_mgr->p_txn_map)) { + tmp_key = cl_qmap_key(p_item); + osm_log(p_tx_mgr->p_log, OSM_LOG_DEBUG, + "__osmv_txnmgr_insert_txn: " + "Found key 0x%llX \n", tmp_key); + p_item = cl_qmap_next(p_item); + } + + return IB_SUCCESS; +} + +ib_api_status_t +__osmv_txnmgr_remove_txn(IN osmv_txn_mgr_t * p_tx_mgr, + IN uint64_t key, OUT osmv_txn_ctx_t ** pp_txn) +{ + cl_map_obj_t *p_obj; + cl_map_item_t *p_item; + + OSM_LOG_ENTER(p_tx_mgr->p_log); + + CL_ASSERT(p_tx_mgr); + CL_ASSERT(pp_txn); + + p_item = cl_qmap_remove(p_tx_mgr->p_txn_map, key); + + if (p_item == cl_qmap_end(p_tx_mgr->p_txn_map)) { + + osm_log(p_tx_mgr->p_log, OSM_LOG_ERROR, + "__osmv_txnmgr_remove_txn: ERR 6701: " + "Could not remove the transaction 0x%llX - " + "something is really wrong!\n", key); + OSM_LOG_EXIT(p_tx_mgr->p_log); + return IB_NOT_FOUND; + } + + p_obj = PARENT_STRUCT(p_item, cl_map_obj_t, item); + *pp_txn = cl_qmap_obj(p_obj); + + free(p_obj); + + OSM_LOG_EXIT(p_tx_mgr->p_log); + return IB_SUCCESS; +} + +void __osmv_txn_all_done(osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + cl_map_item_t *p_item; + cl_map_obj_t *p_obj; + osmv_txn_ctx_t *p_txn; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + p_item = cl_qmap_head(p_bo->txn_mgr.p_txn_map); + while (p_item != cl_qmap_end(p_bo->txn_mgr.p_txn_map)) { + + p_obj = PARENT_STRUCT(p_item, cl_map_obj_t, item); + p_txn = (osmv_txn_ctx_t *) cl_qmap_obj(p_obj); + osmv_txn_done(h_bind, osmv_txn_get_key(p_txn), FALSE); + free(p_obj); + /* assuming osmv_txn_done has removed the txn from the map */ + p_item = cl_qmap_head(p_bo->txn_mgr.p_txn_map); + } + + OSM_LOG_EXIT(p_bo->p_vendor->p_log); +} + +/******************************************************************************/ + +void osmv_txn_lock(IN osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "--> Acquiring lock %p on bind handle %p\n", &p_bo->lock, p_bo); + + cl_spinlock_acquire(&p_bo->lock); + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "--> Acquired lock %p on bind handle %p\n", &p_bo->lock, p_bo); +} + +void osmv_txn_unlock(IN osm_bind_handle_t h_bind) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) h_bind; + cl_spinlock_t *p_lock = &p_bo->lock; + osm_log_t *p_log = p_bo->p_vendor->p_log; + + osm_log(p_log, OSM_LOG_DEBUG, + "<-- Releasing lock %p on bind handle %p\n", p_lock, p_bo); + + cl_spinlock_release(&p_bo->lock); + + /* We'll use the saved ptrs, since now the p_bo can be destroyed already */ + osm_log(p_log, OSM_LOG_DEBUG, + "<-- Released lock %p on bind handle %p\n", p_lock, p_bo); + +} + +static uint64_t +__osmv_txn_timeout_cb(IN uint64_t key, + IN uint32_t num_regs, IN void *cb_context) +{ + osmv_bind_obj_t *p_bo = (osmv_bind_obj_t *) cb_context; + uint64_t ret = 0; + osmv_txn_ctx_t *p_txn; + osmv_rmpp_send_ctx_t *p_send_ctx; + osm_madw_t *p_madw = NULL; + ib_mad_t *p_mad; + osm_mad_addr_t *p_mad_addr; + boolean_t invoke_err_cb = FALSE; + + OSM_LOG_ENTER(p_bo->p_vendor->p_log); + + /* Don't try to acquire a lock on the Bind Object - + * it's taken by the mechanism that drives the timeout based events! + * (Recall the special constructor that the Event Wheel is applied with) + */ + if (p_bo->is_closing) { + goto txn_done; + } + + ret = osmv_txn_lookup(p_bo, key, &p_txn); + if (IB_NOT_FOUND == ret) { + /* Prevent a race - the transaction is already destroyed */ + goto txn_done; + } + + p_madw = p_txn->p_madw; + + switch (osmv_txn_get_rmpp_state(p_txn)) { + + case OSMV_TXN_RMPP_NONE: + if (num_regs <= OSMV_MAX_RETRANSMIT) { + /* We still did not exceed the limit of retransmissions. + * Set the next timeout's value. + */ + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "__osmv_txn_timeout_cb: " + "The transaction request (tid=0x%llX) timed out %d times. " + "Retrying the send.\n", + osmv_txn_get_tid(p_txn), num_regs); + + /* resend this mad */ + ret = osmv_simple_send_madw((osm_bind_handle_t *) p_bo, + p_madw, p_txn, TRUE); + if (ret != IB_SUCCESS) { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_txn_timeout_cb: " + "Fail to send retry for transaction request (tid=0x%llX).\n", + osmv_txn_get_tid(p_txn)); + + osmv_txn_done((osm_bind_handle_t) p_bo, key, + TRUE /*in timeout callback */ ); + + /* This is a requester. Always apply the callback */ + invoke_err_cb = TRUE; + } else { + uint64_t next_timeout_ms; + next_timeout_ms = + p_bo->p_vendor->resp_timeout * (num_regs + + 1) * + (num_regs + 1); + /* when do we need to timeout again */ + ret = + cl_get_time_stamp() + + (uint64_t) (1000 * next_timeout_ms); + + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "__osmv_txn_timeout_cb: " + "Retry request timout in : %lu [msec].\n", + next_timeout_ms); + } + } else { + osm_log(p_bo->p_vendor->p_log, OSM_LOG_ERROR, + "__osmv_txn_timeout_cb: ERR 6702: " + "The transaction request (tid=0x%llX) timed out (after %d retries). " + "Invoking the error callback.\n", + osmv_txn_get_tid(p_txn), num_regs); + + osmv_txn_done((osm_bind_handle_t) p_bo, key, + TRUE /*in timeout callback */ ); + + /* This is a requester. Always apply the callback */ + invoke_err_cb = TRUE; + } + break; + + case OSMV_TXN_RMPP_SENDER: + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "RMPP sender (tid=0x%llX) did not receive ACK " + "on every segment in the current send window.\n", + osmv_txn_get_tid(p_txn)); + + p_send_ctx = osmv_txn_get_rmpp_send_ctx(p_txn); + if (num_regs <= OSMV_MAX_RETRANSMIT) { + /* We still did not exceed the limit of retransmissions. + * Set the next timeout's value. + */ + ret = + cl_get_time_stamp() + + 1000 * p_bo->p_vendor->resp_timeout; + } else { + p_send_ctx->status = IB_TIMEOUT; + + p_mad = osm_madw_get_mad_ptr(p_madw); + p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw); + + /* Send an ABORT to the other side */ + osmv_rmpp_send_nak((osm_bind_handle_t) p_bo, p_mad, + p_mad_addr, IB_RMPP_TYPE_ABORT, + IB_RMPP_STATUS_T2L); + } + + /* Wake the RMPP sender thread up */ + cl_event_signal(&p_send_ctx->event); + break; + + case OSMV_TXN_RMPP_RECEIVER: + osm_log(p_bo->p_vendor->p_log, OSM_LOG_DEBUG, + "Transaction timeout on an RMPP receiver (tid=0x%llX). " + "Dropping the transaction.\n", osmv_txn_get_tid(p_txn)); + + osmv_txn_done((osm_bind_handle_t) p_bo, key, + TRUE /*in timeout callback */ ); + + if (FALSE == osmv_txn_is_rmpp_init_by_peer(p_txn)) { + /* This is a requester, still waiting for the reply. Apply the callback */ + invoke_err_cb = TRUE; + } + + break; + + default: + CL_ASSERT(FALSE); + } + + if (TRUE == invoke_err_cb) { + CL_ASSERT(NULL != p_madw); + /* update the status in the p_madw */ + p_madw->status = IB_TIMEOUT; + p_bo->send_err_cb(p_bo->cb_context, p_madw); + /* no re-registration */ + ret = 0; + } + +txn_done: + OSM_LOG_EXIT(p_bo->p_vendor->p_log); + return ret; +} diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mtl.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mtl.c new file mode 100644 index 000000000000..5fb05ef2f978 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mtl.c @@ -0,0 +1,1105 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef OSM_VENDOR_INTF_MTL + +#include +#include +#include +#include +/* HACK - I do not know how to prevent complib from loading kernel H files */ +#undef __init +#include +#include +#include +#include +#include +#include + +/* + Since a race can accure on requests. Meaning - a response is received before + the send_callback is called - we will save both the madw_p and the fact + whether or not it is a response. A race can occure only on requests that did + not fail, and then the madw_p will be put back in the pool before the callback. +*/ +uint64_t __osm_set_wrid_by_p_madw(IN osm_madw_t * p_madw) +{ + uint64_t wrid = 0; + + CL_ASSERT(p_madw->p_mad); + + memcpy(&wrid, &p_madw, sizeof(osm_madw_t *)); + wrid = (wrid << 1) | + ib_mad_is_response(p_madw->p_mad) | + (p_madw->p_mad->method == IB_MAD_METHOD_TRAP_REPRESS); + return wrid; +} + +void +__osm_set_p_madw_and_resp_by_wrid(IN uint64_t wrid, + OUT uint8_t * is_resp, + OUT osm_madw_t ** pp_madw) +{ + *is_resp = wrid & 0x0000000000000001; + wrid = wrid >> 1; + memcpy(pp_madw, &wrid, sizeof(osm_madw_t *)); +} + +/********************************************************************** + * IB_MGT to OSM ADDRESS VECTOR + **********************************************************************/ +void +__osm_mtl_conv_ibmgt_rcv_desc_to_osm_addr(IN osm_vendor_t * const p_vend, + IN IB_MGT_mad_rcv_desc_t * p_rcv_desc, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_mad_addr) +{ + /* p_mad_addr->dest_lid = p_osm->subn.sm_base_lid; - for resp we use the dest lid ... */ + p_mad_addr->dest_lid = cl_hton16(p_rcv_desc->remote_lid); + p_mad_addr->static_rate = 0; /* HACK - we do not know the rate ! */ + p_mad_addr->path_bits = p_rcv_desc->local_path_bits; + if (is_smi) { + /* SMI */ + p_mad_addr->addr_type.smi.source_lid = + cl_hton16(p_rcv_desc->remote_lid); + p_mad_addr->addr_type.smi.port_num = 99; /* HACK - if used - should fail */ + } else { + /* GSI */ + /* seems to me there is a IBMGT bug reversing the QPN ... */ + /* Does IBMGT supposed to provide the QPN is network or HOST ? */ + p_mad_addr->addr_type.gsi.remote_qp = cl_hton32(p_rcv_desc->qp); + + p_mad_addr->addr_type.gsi.remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + /* we do have the p_mad_addr->pkey_ix but how to get the PKey by index ? */ + /* the only way seems to be to use VAPI_query_hca_pkey_tbl and obtain */ + /* the full PKey table - than go by the index. */ + /* since this does not seem reasonable to me I simply use the default */ + /* There is a TAVOR limitation that only one P_KEY is supported per */ + /* QP - so QP1 must use IB_DEFAULT_PKEY */ + p_mad_addr->addr_type.gsi.pkey_ix = 0; + p_mad_addr->addr_type.gsi.service_level = p_rcv_desc->sl; + + p_mad_addr->addr_type.gsi.global_route = p_rcv_desc->grh_flag; + /* copy the GRH data if relevant */ + if (p_mad_addr->addr_type.gsi.global_route) { + p_mad_addr->addr_type.gsi.grh_info.ver_class_flow = + ib_grh_set_ver_class_flow(p_rcv_desc->grh. + IP_version, + p_rcv_desc->grh. + traffic_class, + p_rcv_desc->grh. + flow_label); + p_mad_addr->addr_type.gsi.grh_info.hop_limit = + p_rcv_desc->grh.hop_limit; + memcpy(&p_mad_addr->addr_type.gsi.grh_info.src_gid.raw, + &p_rcv_desc->grh.sgid, sizeof(ib_net64_t)); + memcpy(&p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw, + p_rcv_desc->grh.dgid, sizeof(ib_net64_t)); + } + } +} + +/********************************************************************** + * OSM ADDR VECTOR TO IB_MGT + **********************************************************************/ +void +__osm_mtl_conv_osm_addr_to_ibmgt_addr(IN osm_mad_addr_t * p_mad_addr, + IN uint8_t is_smi, OUT IB_ud_av_t * p_av) +{ + + /* For global destination or Multicast address: */ + u_int8_t ver; + + memset(p_av, 0, sizeof(IB_ud_av_t)); + + p_av->src_path_bits = p_mad_addr->path_bits; + p_av->static_rate = p_mad_addr->static_rate; + p_av->dlid = cl_ntoh16(p_mad_addr->dest_lid); + + if (is_smi) { + p_av->sl = 0; /* Just to note we use 0 here. */ + } else { + p_av->sl = p_mad_addr->addr_type.gsi.service_level; + p_av->grh_flag = p_mad_addr->addr_type.gsi.global_route; + + if (p_mad_addr->addr_type.gsi.global_route) { + ib_grh_get_ver_class_flow(p_mad_addr->addr_type.gsi. + grh_info.ver_class_flow, &ver, + &p_av->traffic_class, + &p_av->flow_label); + p_av->hop_limit = + p_mad_addr->addr_type.gsi.grh_info.hop_limit; + p_av->sgid_index = 0; /* we always use source GID 0 */ + memcpy(&p_av->dgid, + &p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw, + sizeof(ib_net64_t)); + + } + } +} + +/********************************************************************** + **********************************************************************/ +void __osm_vendor_clear_sm(IN osm_bind_handle_t h_bind) +{ + osm_mtl_bind_info_t *p_bind = (osm_mtl_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + VAPI_ret_t status; + VAPI_hca_attr_t attr_mod; + VAPI_hca_attr_mask_t attr_mask; + + OSM_LOG_ENTER(p_vend->p_log); + + memset(&attr_mod, 0, sizeof(attr_mod)); + memset(&attr_mask, 0, sizeof(attr_mask)); + + attr_mod.is_sm = FALSE; + attr_mask = HCA_ATTR_IS_SM; + + status = + VAPI_modify_hca_attr(p_bind->hca_hndl, p_bind->port_num, &attr_mod, + &attr_mask); + if (status != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_clear_sm: ERR 3C21: " + "Unable set 'IS_SM' bit in port attributes (%d).\n", + status); + } + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + * ANY CONSTRUCTION OF THE osm_vendor_t OBJECT + **********************************************************************/ +void osm_vendor_construct(IN osm_vendor_t * const p_vend) +{ + memset(p_vend, 0, sizeof(*p_vend)); +} + +/********************************************************************** + * DEALOCATE osm_vendor_t + **********************************************************************/ +void osm_vendor_destroy(IN osm_vendor_t * const p_vend) +{ + osm_vendor_mgt_bind_t *vendor_mgt_bind_p; + IB_MGT_ret_t mgt_ret; + OSM_LOG_ENTER(p_vend->p_log); + + if (p_vend->h_al != NULL) { + vendor_mgt_bind_p = (osm_vendor_mgt_bind_t *) p_vend->h_al; + if (vendor_mgt_bind_p->gsi_init) { + + /* un register the class */ + /* HACK WE ASSUME WE ONLY GOT SA CLASS REGISTERD ON GSI !!! */ + mgt_ret = + IB_MGT_unbind_gsi_class(vendor_mgt_bind_p-> + gsi_mads_hdl, + IB_MCLASS_SUBN_ADM); + if (mgt_ret != IB_MGT_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_destroy: ERR 3C03: " + "Fail to unbind the SA class.\n"); + } + + /* un bind the handle */ + if (IB_MGT_release_handle + (vendor_mgt_bind_p->gsi_mads_hdl) != IB_MGT_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_destroy: ERR 3C02: " + "Fail to unbind the SA GSI handle.\n"); + } + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_destroy: DBG 1002: " + "Unbind the GSI handles.\n"); + } + if (vendor_mgt_bind_p->smi_init) { + /* first - clear the IS_SM in the capability mask */ + __osm_vendor_clear_sm((osm_bind_handle_t) + (vendor_mgt_bind_p->smi_p_bind)); + + /* un register the class */ + mgt_ret = + IB_MGT_unbind_sm(vendor_mgt_bind_p->smi_mads_hdl); + if (mgt_ret != IB_MGT_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_destroy: ERR 3C04: " + "Fail to unbind the SM class.\n"); + } + + /* un bind the handle */ + if (IB_MGT_release_handle + (vendor_mgt_bind_p->smi_mads_hdl) != IB_MGT_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_destroy: ERR 3C05: " + "Fail to unbind the SMI handle.\n"); + } + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_destroy: DBG 1003: " + "Unbind the SMI handles.\n"); + + } + } + osm_transaction_mgr_destroy(p_vend); + /* __osm_mtl_destroy_tid_mad_map( p_vend ); */ + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** +DEALLOCATE A POINTER TO osm_vendor_t +**********************************************************************/ +void osm_vendor_delete(IN osm_vendor_t ** const pp_vend) +{ + CL_ASSERT(pp_vend); + + osm_vendor_destroy(*pp_vend); + free(*pp_vend); + *pp_vend = NULL; +} + +/********************************************************************** + * This proc actuall binds the handle to the lower level. + * + * We might have here as a result a casting of our struct to the ib_al_handle_t + * + * Q: Do we need 2 of those - one for MSI and one for GSI ? + * A: Yes! We should be able to do the SA too. So we need a struct! + * + **********************************************************************/ + +ib_api_status_t +osm_vendor_init(IN osm_vendor_t * const p_vend, + IN osm_log_t * const p_log, IN const uint32_t timeout) +{ + osm_vendor_mgt_bind_t *ib_mgt_hdl_p; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + p_vend->p_log = p_log; + + /* + * HACK: We need no handle. Assuming the driver is up. + */ + ib_mgt_hdl_p = (osm_vendor_mgt_bind_t *) + malloc(sizeof(osm_vendor_mgt_bind_t)); + if (ib_mgt_hdl_p == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_init: ERR 3C06: " + "Fail to allocate vendor mgt handle.\n"); + goto Exit; + } + + ib_mgt_hdl_p->smi_init = FALSE; + ib_mgt_hdl_p->gsi_init = FALSE; + /* cast it into the ib_al_handle_t h_al */ + p_vend->h_al = (ib_al_handle_t) ib_mgt_hdl_p; + p_vend->p_transaction_mgr = NULL; + osm_transaction_mgr_init(p_vend); + /* p_vend->madw_by_tid_map_p = NULL; */ + /* __osm_mtl_init_tid_mad_map( p_vend ); */ + p_vend->timeout = timeout; + +Exit: + OSM_LOG_EXIT(p_log); + return (status); +} + +/********************************************************************** + * Create and Initialize osm_vendor_t Object + **********************************************************************/ +osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log, + IN const uint32_t timeout) +{ + ib_api_status_t status; + osm_vendor_t *p_vend; + + OSM_LOG_ENTER(p_log); + + CL_ASSERT(p_log); + + p_vend = malloc(sizeof(*p_vend)); + if (p_vend != NULL) { + memset(p_vend, 0, sizeof(*p_vend)); + status = osm_vendor_init(p_vend, p_log, timeout); + if (status != IB_SUCCESS) { + osm_vendor_delete(&p_vend); + } + } else { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_new: ERR 3C07: " + "Fail to allocate vendor object.\n"); + } + + OSM_LOG_EXIT(p_log); + return (p_vend); +} + +/********************************************************************** + * IB_MGT RCV callback + * + **********************************************************************/ +void +__osm_mtl_rcv_callback(IN IB_MGT_mad_hndl_t mad_hndl, + IN void *private_ctx_p, + IN void *payload_p, + IN IB_MGT_mad_rcv_desc_t * rcv_remote_info_p) +{ + IB_MGT_ret_t status; + osm_mtl_bind_info_t *bind_info_p = private_ctx_p; + osm_madw_t *req_madw_p = NULL; + osm_madw_t *madw_p; + osm_vend_wrap_t *p_new_vw; + osm_mad_addr_t mad_addr; + ib_mad_t *mad_buf_p; + osm_log_t *const p_log = bind_info_p->p_vend->p_log; + + OSM_LOG_ENTER(p_log); + + /* if it is a response MAD we mustbe able to get the request */ + if (ib_mad_is_response((ib_mad_t *) payload_p)) { + /* can we find a matching madw by this payload TID */ + status = + osm_transaction_mgr_get_madw_for_tid(bind_info_p->p_vend, + (ib_mad_t *) payload_p, + &req_madw_p); + if (status != IB_MGT_OK) { + osm_log(p_log, OSM_LOG_ERROR, + "__osm_mtl_rcv_callback: ERR 3C08: " + "Error obtaining request madw by TID (%d).\n", + status); + req_madw_p = NULL; + } + + if (req_madw_p == NULL) { + osm_log(p_log, OSM_LOG_ERROR, + "__osm_mtl_rcv_callback: ERR 3C09: " + "Fail to obtain request madw for received MAD.(method=%X attr=%X) Aborting CB.\n", + ((ib_mad_t *) payload_p)->method, + cl_ntoh16(((ib_mad_t *) payload_p)->attr_id) + + ); + goto Exit; + } + } + + /* do we have a request ??? */ + if (req_madw_p == NULL) { + + /* first arrange an address */ + __osm_mtl_conv_ibmgt_rcv_desc_to_osm_addr(bind_info_p->p_vend, + rcv_remote_info_p, + (((ib_mad_t *) + payload_p)-> + mgmt_class == + IB_MCLASS_SUBN_LID) + || (((ib_mad_t *) + payload_p)-> + mgmt_class == + IB_MCLASS_SUBN_DIR), + &mad_addr); + + osm_log(p_log, OSM_LOG_ERROR, + "__osm_mtl_rcv_callback: : " + "Received MAD from QP:%X.\n", + cl_ntoh32(mad_addr.addr_type.gsi.remote_qp) + ); + + /* if not - get new osm_madw and arrange it. */ + /* create the new madw in the pool */ + madw_p = osm_mad_pool_get(bind_info_p->p_osm_pool, + (osm_bind_handle_t) bind_info_p, + MAD_BLOCK_SIZE, &mad_addr); + if (madw_p == NULL) { + osm_log(p_log, OSM_LOG_ERROR, + "__osm_mtl_rcv_callback: ERR 3C10: " + "Error request for a new madw.\n"); + goto Exit; + } + /* HACK: we cust to avoid the const ??? */ + mad_buf_p = (void *)madw_p->p_mad; + } else { + /* we have the madw defined during the send and stored in the vend_wrap */ + /* we need to make sure the wrapper is correctly init there */ + CL_ASSERT(req_madw_p->vend_wrap.p_resp_madw != 0); + madw_p = req_madw_p->vend_wrap.p_resp_madw; + + /* HACK: we do not Support RMPP */ + CL_ASSERT(madw_p->h_bind); + mad_buf_p = + osm_vendor_get(madw_p->h_bind, MAD_BLOCK_SIZE, + &madw_p->vend_wrap); + + if (mad_buf_p == NULL) { + osm_log(p_log, OSM_LOG_ERROR, + "__osm_mtl_rcv_callback: ERR 3C11: " + "Unable to acquire wire MAD.\n"); + + goto Exit; + } + + /* + Finally, attach the wire MAD to this wrapper. + */ + osm_madw_set_mad(madw_p, mad_buf_p); + + /* also we need to handle the size of the mad since we did not init ... */ + madw_p->mad_size = MAD_BLOCK_SIZE; + } + + /* init some fields of the vendor wrapper */ + p_new_vw = osm_madw_get_vend_ptr(madw_p); + p_new_vw->h_bind = bind_info_p; + p_new_vw->size = MAD_BLOCK_SIZE; + p_new_vw->p_resp_madw = NULL; + p_new_vw->mad_buf_p = mad_buf_p; + + /* HACK: We do not support RMPP in receiving MADS */ + memcpy(p_new_vw->mad_buf_p, payload_p, MAD_BLOCK_SIZE); + + /* attach the buffer to the wrapper */ + madw_p->p_mad = mad_buf_p; + + /* we can also make sure we marked the size and bind on the returned madw */ + madw_p->h_bind = p_new_vw->h_bind; + + /* call the CB */ + (*bind_info_p->rcv_callback) (madw_p, bind_info_p->client_context, + req_madw_p); + +Exit: + OSM_LOG_EXIT(p_log); +} + +/********************************************************************** + * IB_MGT Send callback : invoked after each send + * + **********************************************************************/ +void +__osm_mtl_send_callback(IN IB_MGT_mad_hndl_t mad_hndl, + IN u_int64_t wrid, + IN IB_comp_status_t status, IN void *private_ctx_p) +{ + osm_madw_t *madw_p; + osm_mtl_bind_info_t *bind_info_p = + (osm_mtl_bind_info_t *) private_ctx_p; + osm_log_t *const p_log = bind_info_p->p_vend->p_log; + osm_vend_wrap_t *p_vw; + uint8_t is_resp; + + OSM_LOG_ENTER(p_log); + + /* obtain the madp from the wrid */ + __osm_set_p_madw_and_resp_by_wrid(wrid, &is_resp, &madw_p); + + osm_log(p_log, OSM_LOG_DEBUG, + "__osm_mtl_send_callback: INFO 1008: " + "Handling Send of MADW:%p Is Resp:%d.\n", madw_p, is_resp); + + /* we need to handle requests and responses differently */ + if (is_resp) { + if (status != IB_COMP_SUCCESS) { + osm_log(p_log, OSM_LOG_ERROR, + "__osm_mtl_send_callback: ERR 3C12: " + "Error Sending Response MADW:%p.\n", madw_p); + } else { + osm_log(p_log, OSM_LOG_DEBUG, + "__osm_mtl_send_callback: DBG 1008: " + "Completed Sending Response MADW:%p.\n", + madw_p); + } + + /* if we are a response - we need to clean it up */ + osm_mad_pool_put(bind_info_p->p_osm_pool, madw_p); + } else { + + /* this call back is invoked on completion of send - error or not */ + if (status != IB_COMP_SUCCESS) { + + osm_log(p_log, OSM_LOG_ERROR, + "__osm_mtl_send_callback: ERR 3C13: " + "Received an Error from IB_MGT Send (%d).\n", + status); + + p_vw = osm_madw_get_vend_ptr(madw_p); + CL_ASSERT(p_vw); + + /* + Return any wrappers to the pool that may have been + pre-emptively allocated to handle a receive. + */ + if (p_vw->p_resp_madw) { + osm_mad_pool_put(bind_info_p->p_osm_pool, + p_vw->p_resp_madw); + p_vw->p_resp_madw = NULL; + } + + /* invoke the CB */ + (*bind_info_p->send_err_callback) (bind_info_p-> + client_context, + madw_p); + } else { + /* successful request send - do nothing - the response will need the + out mad */ + osm_log(p_log, OSM_LOG_DEBUG, + "__osm_mtl_send_callback: DBG 1008: " + "Completed Sending Request MADW:%p.\n", madw_p); + } + } + + OSM_LOG_EXIT(p_log); +} + +/********************************************************************** + * BINDs a callback (rcv and send error) for a given class and method + * defined by the given: osm_bind_info_t + **********************************************************************/ +osm_bind_handle_t +osm_vendor_bind(IN osm_vendor_t * const p_vend, + IN osm_bind_info_t * const p_user_bind, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vend_mad_recv_callback_t mad_recv_callback, + IN osm_vend_mad_send_err_callback_t send_err_callback, + IN void *context) +{ + ib_net64_t port_guid; + osm_mtl_bind_info_t *p_bind = NULL; + VAPI_hca_hndl_t hca_hndl; + VAPI_hca_id_t hca_id; + IB_MGT_mad_type_t mad_type; + uint32_t port_num; + osm_vendor_mgt_bind_t *ib_mgt_hdl_p; + IB_MGT_ret_t mgt_ret; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_user_bind); + CL_ASSERT(p_mad_pool); + CL_ASSERT(mad_recv_callback); + CL_ASSERT(send_err_callback); + + /* cast back the AL handle to vendor mgt bind */ + ib_mgt_hdl_p = (osm_vendor_mgt_bind_t *) p_vend->h_al; + + port_guid = p_user_bind->port_guid; + + osm_log(p_vend->p_log, OSM_LOG_INFO, + "osm_vendor_bind: " + "Binding to port 0x%" PRIx64 ".\n", cl_ntoh64(port_guid)); + + /* obtain the hca name and port num from the guid */ + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_bind: " + "Finding CA and Port that owns port guid 0x%" PRIx64 ".\n", + port_guid); + + mgt_ret = + osm_vendor_get_guid_ca_and_port(p_vend, port_guid, &hca_hndl, + &hca_id, &port_num); + if (mgt_ret != IB_MGT_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 3C14: " + "Unable to obtain CA and port (%d).\n"); + goto Exit; + } + + /* create the bind object tracking this binding */ + p_bind = (osm_mtl_bind_info_t *) malloc(sizeof(osm_mtl_bind_info_t)); + memset(p_bind, 0, sizeof(osm_mtl_bind_info_t)); + if (p_bind == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 3C15: " + "Unable to allocate internal bind object.\n"); + goto Exit; + } + + /* track this bind request info */ + memcpy(p_bind->hca_id, hca_id, sizeof(VAPI_hca_id_t)); + p_bind->port_num = port_num; + p_bind->p_vend = p_vend; + p_bind->client_context = context; + p_bind->rcv_callback = mad_recv_callback; + p_bind->send_err_callback = send_err_callback; + p_bind->p_osm_pool = p_mad_pool; + + CL_ASSERT(p_bind->port_num); + + /* + * Get the proper CLASS + */ + + switch (p_user_bind->mad_class) { + case IB_MCLASS_SUBN_LID: + case IB_MCLASS_SUBN_DIR: + mad_type = IB_MGT_SMI; + break; + + case IB_MCLASS_SUBN_ADM: + default: + mad_type = IB_MGT_GSI; + break; + } + + /* we split here - based on the type of MADS GSI / SMI */ + /* HACK: we only support one class registration per SMI/GSI !!! */ + if (mad_type == IB_MGT_SMI) { + /* + * SMI CASE + */ + + /* we do not need to bind the handle if already available */ + if (ib_mgt_hdl_p->smi_init == FALSE) { + + /* First we have to reg and get the handle for the mad */ + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: " + "Binding to IB_MGT SMI of %s port %u\n", hca_id, + port_num); + + mgt_ret = + IB_MGT_get_handle(hca_id, port_num, IB_MGT_SMI, + &(ib_mgt_hdl_p->smi_mads_hdl)); + if (IB_MGT_OK != mgt_ret) { + free(p_bind); + p_bind = NULL; + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 3C16: " + "Error obtaining IB_MGT handle to SMI.\n"); + goto Exit; + } + + /* bind it */ + mgt_ret = IB_MGT_bind_sm(ib_mgt_hdl_p->smi_mads_hdl); + if (IB_MGT_OK != mgt_ret) { + free(p_bind); + p_bind = NULL; + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 3C17: " + "Error binding IB_MGT handle to SM.\n"); + goto Exit; + } + + ib_mgt_hdl_p->smi_init = TRUE; + + } + + /* attach to this bind info */ + p_bind->mad_hndl = ib_mgt_hdl_p->smi_mads_hdl; + ib_mgt_hdl_p->smi_p_bind = p_bind; + + /* now register the callback */ + mgt_ret = IB_MGT_reg_cb(p_bind->mad_hndl, + &__osm_mtl_rcv_callback, + p_bind, + &__osm_mtl_send_callback, + p_bind, + IB_MGT_RCV_CB_MASK | + IB_MGT_SEND_CB_MASK); + + } else { + /* + * GSI CASE + */ + + if (ib_mgt_hdl_p->gsi_init == FALSE) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: " "Binding to IB_MGT GSI\n"); + + /* First we have to reg and get the handle for the mad */ + mgt_ret = + IB_MGT_get_handle(hca_id, port_num, IB_MGT_GSI, + &(ib_mgt_hdl_p->gsi_mads_hdl)); + if (IB_MGT_OK != mgt_ret) { + free(p_bind); + p_bind = NULL; + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 3C20: " + "Error obtaining IB_MGT handle to GSI.\n"); + goto Exit; + } + + /* bind it */ + mgt_ret = + IB_MGT_bind_gsi_class(ib_mgt_hdl_p->gsi_mads_hdl, + p_user_bind->mad_class); + if (IB_MGT_OK != mgt_ret) { + free(p_bind); + p_bind = NULL; + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 3C22: " + "Error binding IB_MGT handle to GSI.\n"); + goto Exit; + } + + ib_mgt_hdl_p->gsi_init = TRUE; + + /* attach to this bind info */ + p_bind->mad_hndl = ib_mgt_hdl_p->gsi_mads_hdl; + + /* now register the callback */ + mgt_ret = IB_MGT_reg_cb(p_bind->mad_hndl, + &__osm_mtl_rcv_callback, + p_bind, + &__osm_mtl_send_callback, + p_bind, + IB_MGT_RCV_CB_MASK | + IB_MGT_SEND_CB_MASK); + + } else { + /* we can use the existing handle */ + p_bind->mad_hndl = ib_mgt_hdl_p->gsi_mads_hdl; + mgt_ret = IB_MGT_OK; + } + + } + + if (IB_MGT_OK != mgt_ret) { + free(p_bind); + p_bind = NULL; + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 3C23: " + "Error binding IB_MGT CB (%d).\n", mgt_ret); + goto Exit; + } + + /* HACK: Do we need to initialize an address vector ???? */ + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return ((osm_bind_handle_t) p_bind); +} + +/********************************************************************** +Get a mad from the lower level. +The osm_vend_wrap_t is a wrapper used to connect the mad to the response. +**********************************************************************/ +ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind, + IN const uint32_t mad_size, + IN osm_vend_wrap_t * const p_vw) +{ + ib_mad_t *mad_p; + osm_mtl_bind_info_t *p_bind = (osm_mtl_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vw); + /* HACK: We know we can not send through IB_MGT */ + CL_ASSERT(mad_size <= MAD_BLOCK_SIZE); + + /* IB_MGT assumes it is 256 - we must follow */ + p_vw->size = MAD_BLOCK_SIZE; + + /* allocate it */ + mad_p = (ib_mad_t *) malloc(p_vw->size); + if (mad_p == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get: ERR 3C24: " + "Error Obtaining MAD buffer.\n"); + goto Exit; + } + + memset(mad_p, 0, p_vw->size); + + /* track locally */ + p_vw->mad_buf_p = mad_p; + p_vw->h_bind = h_bind; + p_vw->p_resp_madw = NULL; + + if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get: " + "Acquired MAD %p, size = %u.\n", mad_p, p_vw->size); + } + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (mad_p); +} + +/********************************************************************** + * Return a MAD by providing it's wrapper object. + **********************************************************************/ +void +osm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw) +{ + osm_mtl_bind_info_t *p_bind = (osm_mtl_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + osm_madw_t *p_madw; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vw); + CL_ASSERT(p_vw->mad_buf_p); + + if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_put: " "Retiring MAD %p.\n", + p_vw->mad_buf_p); + } + + /* + * We moved the removal of the transaction to immediatly after + * it was looked up. + */ + + /* free the mad but the wrapper is part of the madw object */ + free(p_vw->mad_buf_p); + p_vw->mad_buf_p = NULL; + p_madw = PARENT_STRUCT(p_vw, osm_madw_t, vend_wrap); + p_madw->p_mad = NULL; + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** +Actually Send a MAD + +This is for internal use by osm_vendor_send and the transaction mgr +retry too. +**********************************************************************/ +ib_api_status_t +osm_mtl_send_mad(IN osm_mtl_bind_info_t * p_bind, IN osm_madw_t * const p_madw) +{ + osm_vendor_t *const p_vend = p_bind->p_vend; + osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw); + osm_mad_addr_t *const p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw); + ib_mad_t *const p_mad = osm_madw_get_mad_ptr(p_madw); + ib_api_status_t status; + IB_MGT_ret_t mgt_res; + IB_ud_av_t av; + uint64_t wrid; + uint32_t qpn; + + OSM_LOG_ENTER(p_vend->p_log); + + /* + * For all sends other than directed route SM MADs, + * acquire an address vector for the destination. + */ + if (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) { + __osm_mtl_conv_osm_addr_to_ibmgt_addr(p_mad_addr, + p_mad->mgmt_class == + IB_MCLASS_SUBN_LID, &av); + } else { + /* is a directed route - we need to construct a permissive address */ + memset(&av, 0, sizeof(av)); + /* we do not need port number since it is part of the mad_hndl */ + av.dlid = IB_LID_PERMISSIVE; + } + + wrid = __osm_set_wrid_by_p_madw(p_madw); + + /* send it */ + if ((p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) || + (p_mad->mgmt_class == IB_MCLASS_SUBN_LID)) { + + /* SMI CASE */ + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_mtl_send_mad: " + "av.dlid 0x%X, " + "av.static_rate %d, " + "av.path_bits %d.\n", + cl_ntoh16(av.dlid), av.static_rate, + av.src_path_bits); + } + + mgt_res = IB_MGT_send_mad(p_bind->mad_hndl, p_mad, /* actual payload */ + &av, /* address vector */ + wrid, /* casting the mad wrapper pointer for err cb */ + p_vend->timeout); + + } else { + /* GSI CASE - Support Remote QP */ + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_mtl_send_mad: " + "av.dlid 0x%X, av.static_rate %d, " + "av.path_bits %d, remote qp: 0x%06X \n", + av.dlid, + av.static_rate, + av.src_path_bits, + cl_ntoh32(p_mad_addr->addr_type.gsi.remote_qp) + ); + } + + /* IBMGT have a bug sending to a QP not 1 - + the QPN must be in network order except when it qpn 1 ... */ + qpn = cl_ntoh32(p_mad_addr->addr_type.gsi.remote_qp); + + mgt_res = IB_MGT_send_mad_to_qp(p_bind->mad_hndl, p_mad, /* actual payload */ + &av, /* address vector */ + wrid, /* casting the mad wrapper pointer for err cb */ + p_vend->timeout, qpn); + } + + if (mgt_res != IB_MGT_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_mtl_send_mad: ERR 3C26: " + "Error sending mad (%d).\n", mgt_res); + if (p_vw->p_resp_madw) + osm_mad_pool_put(p_bind->p_osm_pool, p_vw->p_resp_madw); + status = IB_ERROR; + goto Exit; + } + + status = IB_SUCCESS; + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** +Send a MAD through. + +What is unclear to me is the need for the setting of all the MAD Wrapper +fields. Seems like the OSM uses these values during it's processing... +**********************************************************************/ +ib_api_status_t +osm_vendor_send(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, IN boolean_t const resp_expected) +{ + osm_mtl_bind_info_t *const p_bind = (osm_mtl_bind_info_t *) h_bind; + osm_vendor_t *const p_vend = p_bind->p_vend; + osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw); + ib_api_status_t status; + + OSM_LOG_ENTER(p_vend->p_log); + + /* + * If a response is expected to this MAD, then preallocate + * a mad wrapper to contain the wire MAD received in the + * response. Allocating a wrapper here allows for easier + * failure paths than after we already received the wire mad. + */ + if (resp_expected == TRUE) { + /* we track it in the vendor wrapper */ + p_vw->p_resp_madw = + osm_mad_pool_get_wrapper_raw(p_bind->p_osm_pool); + if (p_vw->p_resp_madw == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_send: ERR 3C27: " + "Unable to allocate MAD wrapper.\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* put some minimal info on that wrapper */ + ((osm_madw_t *) (p_vw->p_resp_madw))->h_bind = h_bind; + + /* we also want to track it in the TID based map */ + status = osm_transaction_mgr_insert_madw((osm_bind_handle_t) + p_bind, p_madw); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_send: ERR 3C25: " + "Error inserting request madw by TID (%d).\n", + status); + } + + } else + p_vw->p_resp_madw = NULL; + + /* do the actual send */ + status = osm_mtl_send_mad(p_bind, p_madw); + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + * the idea here is to change the content of the bind such that it + * will hold the local address used for sending directed route by the SMA. + **********************************************************************/ +ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind) +{ + osm_vendor_t *p_vend = ((osm_mtl_bind_info_t *) h_bind)->p_vend; + + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_local_lid_change: DEBUG 2202: " "Change of LID.\n"); + + OSM_LOG_EXIT(p_vend->p_log); + + return (IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val) +{ + osm_mtl_bind_info_t *p_bind = (osm_mtl_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + VAPI_ret_t status; + VAPI_hca_attr_t attr_mod; + VAPI_hca_attr_mask_t attr_mask; + + OSM_LOG_ENTER(p_vend->p_log); + + memset(&attr_mod, 0, sizeof(attr_mod)); + memset(&attr_mask, 0, sizeof(attr_mask)); + + attr_mod.is_sm = is_sm_val; + attr_mask = HCA_ATTR_IS_SM; + + status = + VAPI_modify_hca_attr(p_bind->hca_hndl, p_bind->port_num, &attr_mod, + &attr_mask); + if (status != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_set_sm: ERR 3C28: " + "Unable set 'IS_SM' bit to:%u in port attributes (%d).\n", + is_sm_val, status); + } + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level) +{ + +} + +#endif /* OSM_VENDOR_INTF_TEST */ diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mtl_hca_guid.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mtl_hca_guid.c new file mode 100644 index 000000000000..d78af3191002 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mtl_hca_guid.c @@ -0,0 +1,635 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#if defined(OSM_VENDOR_INTF_MTL) | defined(OSM_VENDOR_INTF_TS) +#undef IN +#undef OUT +#include +#include +#include +#include +#include +#include + +/******************************************************************************** + * + * Provide the functionality for selecting an HCA Port and Obtaining it's guid. + * + ********************************************************************************/ + +/********************************************************************** + * Convert the given GID to GUID by copy of it's upper 8 bytes + * + * + **********************************************************************/ + +ib_api_status_t +__osm_vendor_gid_to_guid(IN u_int8_t * gid, OUT VAPI_gid_t * guid) +{ + memcpy(guid, gid + 8, 8); + return (IB_SUCCESS); +} + +/****f* OpenSM: CA Info/osm_ca_info_get_pi_ptr + * NAME + * osm_ca_info_get_pi_ptr + * + * DESCRIPTION + * Returns a pointer to the port attribute of the specified port + * owned by this CA. + * + * SYNOPSIS + */ +static ib_port_attr_t *__osm_ca_info_get_port_attr_ptr(IN const osm_ca_info_t * + const p_ca_info, + IN const uint8_t index) +{ + return (&p_ca_info->p_attr->p_port_attr[index]); +} + +/* + * PARAMETERS + * p_ca_info + * [in] Pointer to a CA Info object. + * + * index + * [in] Port "index" for which to retrieve the port attribute. + * The index is the offset into the ca's internal array + * of port attributes. + * + * RETURN VALUE + * Returns a pointer to the port attribute of the specified port + * owned by this CA. + * + * NOTES + * + * SEE ALSO + *********/ + +/******************************************************************************** + * get the CA names ava`ilable on the system + * NOTE: user of this function needs to deallocate p_hca_ids after usage. + ********************************************************************************/ +static ib_api_status_t +__osm_vendor_get_ca_ids(IN osm_vendor_t * const p_vend, + IN VAPI_hca_id_t ** const p_hca_ids, + IN uint32_t * const p_num_guids) +{ + ib_api_status_t status; + VAPI_ret_t vapi_res; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_hca_ids); + CL_ASSERT(p_num_guids); + + /* first call is just to get the number */ + vapi_res = EVAPI_list_hcas(0, p_num_guids, NULL); + + /* fail ? */ + if (vapi_res == VAPI_EINVAL_PARAM) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_ids: ERR 7101: " + "Bad parameter in calling: EVAPI_list_hcas. (%d)\n", + vapi_res); + status = IB_ERROR; + goto Exit; + } + + /* NO HCA ? */ + if (*p_num_guids == 0) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_ids: ERR 7102: " + "No available channel adapters.\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* allocate and really call - user of this function needs to deallocate it */ + *p_hca_ids = + (VAPI_hca_id_t *) malloc(*p_num_guids * sizeof(VAPI_hca_id_t)); + + /* now call it really */ + vapi_res = EVAPI_list_hcas(*p_num_guids, p_num_guids, *p_hca_ids); + + /* too many ? */ + if (vapi_res == VAPI_EAGAIN) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_ids: ERR 7103: " + "More CA GUIDs than allocated array (%d).\n", + *p_num_guids); + status = IB_ERROR; + goto Exit; + } + + /* fail ? */ + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_get_ca_ids: ERR 7104: " + "Bad parameter in calling: EVAPI_list_hcas.\n"); + status = IB_ERROR; + goto Exit; + } + + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_vendor_get_ca_ids: " + "Detected %u local channel adapters.\n", *p_num_guids); + } + + status = IB_SUCCESS; + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + * Initialize an Info Struct for the Given HCA by its Id + **********************************************************************/ +static ib_api_status_t +__osm_ca_info_init(IN osm_vendor_t * const p_vend, + IN VAPI_hca_id_t ca_id, OUT osm_ca_info_t * const p_ca_info) +{ + ib_api_status_t status = IB_ERROR; + VAPI_ret_t vapi_res; + VAPI_hca_hndl_t hca_hndl; + VAPI_hca_vendor_t hca_vendor; + VAPI_hca_cap_t hca_cap; + VAPI_hca_port_t hca_port; + uint8_t port_num; + IB_gid_t *p_port_gid; + uint16_t maxNumGids; + + OSM_LOG_ENTER(p_vend->p_log); + + /* get the HCA handle */ + vapi_res = EVAPI_get_hca_hndl(ca_id, &hca_hndl); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 7105: " + "Fail to get HCA handle (%u).\n", vapi_res); + goto Exit; + } + + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_ca_info_init: " "Querying CA %s.\n", ca_id); + } + + /* query and get the HCA capability */ + vapi_res = VAPI_query_hca_cap(hca_hndl, &hca_vendor, &hca_cap); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 7106: " + "Fail to get HCA Capabilities (%u).\n", vapi_res); + goto Exit; + } + + /* get the guid of the HCA */ + memcpy(&(p_ca_info->guid), hca_cap.node_guid, 8 * sizeof(u_int8_t)); + p_ca_info->attr_size = 1; + p_ca_info->p_attr = (ib_ca_attr_t *) malloc(sizeof(ib_ca_attr_t)); + memcpy(&(p_ca_info->p_attr->ca_guid), hca_cap.node_guid, + 8 * sizeof(u_int8_t)); + + /* now obtain the attributes of the ports */ + p_ca_info->p_attr->num_ports = hca_cap.phys_port_num; + p_ca_info->p_attr->p_port_attr = + (ib_port_attr_t *) malloc(hca_cap.phys_port_num * + sizeof(ib_port_attr_t)); + + for (port_num = 0; port_num < p_ca_info->p_attr->num_ports; port_num++) { + + /* query the port attributes */ + vapi_res = + VAPI_query_hca_port_prop(hca_hndl, port_num + 1, &hca_port); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 7107: " + "Fail to get HCA Port Attributes (%d).\n", + vapi_res); + goto Exit; + } + + /* first call to know the size of the gid table */ + vapi_res = + VAPI_query_hca_gid_tbl(hca_hndl, port_num + 1, 0, + &maxNumGids, NULL); + p_port_gid = (IB_gid_t *) malloc(maxNumGids * sizeof(IB_gid_t)); + + vapi_res = + VAPI_query_hca_gid_tbl(hca_hndl, port_num + 1, maxNumGids, + &maxNumGids, p_port_gid); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_ca_info_init: ERR 7108: " + "Fail to get HCA Port GID (%d).\n", vapi_res); + goto Exit; + } + + __osm_vendor_gid_to_guid(p_port_gid[0], + (IB_gid_t *) & p_ca_info->p_attr-> + p_port_attr[port_num].port_guid); + p_ca_info->p_attr->p_port_attr[port_num].lid = hca_port.lid; + p_ca_info->p_attr->p_port_attr[port_num].link_state = + hca_port.state; + p_ca_info->p_attr->p_port_attr[port_num].sm_lid = + hca_port.sm_lid; + + free(p_port_gid); + } + + status = IB_SUCCESS; +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +void +osm_ca_info_destroy(IN osm_vendor_t * const p_vend, + IN osm_ca_info_t * const p_ca_info) +{ + OSM_LOG_ENTER(p_vend->p_log); + + if (p_ca_info->p_attr) { + if (p_ca_info->p_attr->num_ports) { + free(p_ca_info->p_attr->p_port_attr); + } + free(p_ca_info->p_attr); + } + + free(p_ca_info); + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + * Fill in the array of port_attr with all available ports on ALL the + * avilable CAs on this machine. + * ALSO - + * UPDATE THE VENDOR OBJECT LIST OF CA_INFO STRUCTS + **********************************************************************/ +ib_api_status_t +osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend, + IN ib_port_attr_t * const p_attr_array, + IN uint32_t * const p_num_ports) +{ + ib_api_status_t status; + + uint32_t ca; + uint32_t ca_count; + uint32_t port_count = 0; + uint8_t port_num; + uint32_t total_ports = 0; + VAPI_hca_id_t *p_ca_ids = NULL; + osm_ca_info_t *p_ca_info; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + + /* + * 1) Determine the number of CA's + * 2) Allocate an array big enough to hold the ca info objects. + * 3) Call again to retrieve the guids. + */ + status = __osm_vendor_get_ca_ids(p_vend, &p_ca_ids, &ca_count); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 7109: " + "Fail to get CA Ids.\n"); + goto Exit; + } + + /* we keep track of all the CAs in this info array */ + p_vend->p_ca_info = malloc(ca_count * sizeof(*p_vend->p_ca_info)); + if (p_vend->p_ca_info == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 7110: " + "Unable to allocate CA information array.\n"); + goto Exit; + } + + memset(p_vend->p_ca_info, 0, ca_count * sizeof(*p_vend->p_ca_info)); + p_vend->ca_count = ca_count; + + /* + * For each CA, retrieve the CA info attributes + */ + for (ca = 0; ca < ca_count; ca++) { + p_ca_info = &p_vend->p_ca_info[ca]; + + status = __osm_ca_info_init(p_vend, p_ca_ids[ca], p_ca_info); + + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_all_port_attr: ERR 7111: " + "Unable to initialize CA Info object (%s).\n", + ib_get_err_str(status)); + } + + total_ports += osm_ca_info_get_num_ports(p_ca_info); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get_all_port_attr: " + "osm_vendor_get_all_port_attr: %u got %u ports total:%u\n", + ca, osm_ca_info_get_num_ports(p_ca_info), total_ports); + + } + + /* + * If the user supplied enough storage, return the port guids, + * otherwise, return the appropriate error. + */ + if (*p_num_ports >= total_ports) { + for (ca = 0; ca < ca_count; ca++) { + uint32_t num_ports; + + p_ca_info = &p_vend->p_ca_info[ca]; + + num_ports = osm_ca_info_get_num_ports(p_ca_info); + + for (port_num = 0; port_num < num_ports; port_num++) { + p_attr_array[port_count] = + *__osm_ca_info_get_port_attr_ptr(p_ca_info, + port_num); + port_count++; + } + } + } else { + status = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + + status = IB_SUCCESS; + +Exit: + *p_num_ports = total_ports; + + if (p_ca_ids) + free(p_ca_ids); + + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + * Given the vendor obj and a guid + * return the ca id and port number that have that guid + **********************************************************************/ + +ib_api_status_t +osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend, + IN ib_net64_t const guid, + OUT VAPI_hca_hndl_t * p_hca_hndl, + OUT VAPI_hca_id_t * p_hca_id, + OUT uint32_t * p_port_num) +{ + + ib_api_status_t status; + VAPI_hca_id_t *p_ca_ids = NULL; + VAPI_ret_t vapi_res; + VAPI_hca_hndl_t hca_hndl; + VAPI_hca_vendor_t hca_vendor; + VAPI_hca_cap_t hca_cap; + IB_gid_t *p_port_gid = NULL; + uint16_t maxNumGids; + ib_net64_t port_guid; + uint32_t ca, portIdx, ca_count; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + + /* + * 1) Determine the number of CA's + * 2) Allocate an array big enough to hold the ca info objects. + * 3) Call again to retrieve the guids. + */ + status = __osm_vendor_get_ca_ids(p_vend, &p_ca_ids, &ca_count); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 7112: " + "Fail to get CA Ids.\n"); + goto Exit; + } + + /* + * For each CA, retrieve the CA info attributes + */ + for (ca = 0; ca < ca_count; ca++) { + /* get the HCA handle */ + vapi_res = EVAPI_get_hca_hndl(p_ca_ids[ca], &hca_hndl); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 7113: " + "Fail to get HCA handle (%u).\n", vapi_res); + goto Exit; + } + + /* get the CA attributes - to know how many ports it has: */ + if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get_guid_ca_and_port: " + "Querying CA %s.\n", p_ca_ids[ca]); + } + + /* query and get the HCA capability */ + vapi_res = VAPI_query_hca_cap(hca_hndl, &hca_vendor, &hca_cap); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 7114: " + "Fail to get HCA Capabilities (%u).\n", + vapi_res); + goto Exit; + } + + /* go over all ports - to obtail their guids */ + for (portIdx = 0; portIdx < hca_cap.phys_port_num; portIdx++) { + vapi_res = + VAPI_query_hca_gid_tbl(hca_hndl, portIdx + 1, 0, + &maxNumGids, NULL); + p_port_gid = + (IB_gid_t *) malloc(maxNumGids * sizeof(IB_gid_t)); + + /* get the port guid */ + vapi_res = + VAPI_query_hca_gid_tbl(hca_hndl, portIdx + 1, + maxNumGids, &maxNumGids, + p_port_gid); + if (vapi_res != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 7115: " + "Fail to get HCA Port GID (%d).\n", + vapi_res); + goto Exit; + } + + /* convert to SF style */ + __osm_vendor_gid_to_guid(p_port_gid[0], + (VAPI_gid_t *) & port_guid); + + /* finally did we find it ? */ + if (port_guid == guid) { + *p_hca_hndl = hca_hndl; + memcpy(p_hca_id, p_ca_ids[ca], + sizeof(VAPI_hca_id_t)); + *p_port_num = portIdx + 1; + status = IB_SUCCESS; + goto Exit; + } + + free(p_port_gid); + p_port_gid = NULL; + } /* ALL PORTS */ + } /* all HCAs */ + + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get_guid_ca_and_port: ERR 7116: " + "Fail to find HCA and Port for Port Guid 0x%" PRIx64 "\n", + cl_ntoh64(guid)); + status = IB_INVALID_GUID; + +Exit: + if (p_ca_ids != NULL) + free(p_ca_ids); + if (p_port_gid != NULL) + free(p_port_gid); + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +#ifdef __TEST_HCA_GUID__ + +#define GUID_ARRAY_SIZE 64 + +#include + +/********************************************************************** + **********************************************************************/ +ib_net64_t get_port_guid() +{ + uint32_t i; + uint32_t choice = 0; + boolean_t done_flag = FALSE; + ib_api_status_t status; + uint32_t num_ports = GUID_ARRAY_SIZE; + ib_port_attr_t attr_array[GUID_ARRAY_SIZE]; + VAPI_hca_id_t ca_id; + uint32_t portNum; + osm_vendor_t vend; + osm_vendor_t *p_vend; + osm_log_t *p_osm_log, tlog; + + p_osm_log = &tlog; + + status = osm_log_init(p_osm_log, FALSE); + if (status != IB_SUCCESS) + return (status); + + osm_log(p_osm_log, OSM_LOG_FUNCS, "get_port_guid: [\n"); + + p_vend = &vend; + p_vend->p_log = p_osm_log; + + /* + * Call the transport layer for a list of local port + * GUID values. + */ + status = osm_vendor_get_all_port_attr(p_vend, attr_array, &num_ports); + if (status != IB_SUCCESS) { + printf("\nError from osm_opensm_init (%x)\n", status); + return (0); + } + + if (num_ports == 0) { + printf("\nNo local ports detected!\n"); + return (0); + } + + while (done_flag == FALSE) { + printf("\nChoose a local port number with which to bind:\n\n"); + for (i = 0; i < num_ports; i++) { + /* + * Print the index + 1 since by convention, port numbers + * start with 1 on host channel adapters. + */ + + printf("\t%u: GUID = 0x%8" PRIx64 + ", lid = 0x%04X, state = %s\n", i + 1, + cl_ntoh64(attr_array[i].port_guid), + cl_ntoh16(attr_array[i].lid), + ib_get_port_state_str(attr_array[i].link_state)); + } + + printf("\nEnter choice (1-%u): ", i); + fflush(stdout); + scanf("%u", &choice); + if (choice > num_ports) + printf("\nError: Lame choice!\n"); + else + done_flag = TRUE; + } + + status = + osm_vendor_get_guid_ca_and_port(p_vend, + attr_array[choice - 1].port_guid, + &ca_id, &portNum); + if (status != IB_SUCCESS) { + printf("Error obtaining back the HCA and Port\n"); + return (0); + } + + printf("Selected: CA:%s Port:%d\n", ca_id, portNum); + + return (attr_array[choice - 1].port_guid); +} + +int main(int argc, char **argv) +{ + get_port_guid(); + return (0); +} + +#endif + +#endif diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_mtl_transaction_mgr.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_mtl_transaction_mgr.c new file mode 100644 index 000000000000..6e8afb04a81f --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_mtl_transaction_mgr.c @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(OSM_VENDOR_INTF_MTL) | defined(OSM_VENDOR_INTF_TS) + +#include +#ifdef OSM_VENDOR_INTF_MTL +#include +#endif + +/* this is the callback function of the timer */ +void __osm_transaction_mgr_callback(IN void *context) +{ + osm_transaction_mgr_t *trans_mgr_p; + osm_vendor_t *p_vend = (osm_vendor_t *) context; + cl_list_item_t *p_list_item; + cl_list_item_t *p_list_next_item; + osm_madw_req_t *osm_madw_req_p; + uint64_t current_time; /* [usec] */ + uint32_t new_timeout; /* [msec] */ + cl_status_t cl_status; + ib_mad_t *p_mad; +#ifdef OSM_VENDOR_INTF_MTL + osm_mtl_bind_info_t *p_bind; +#else + osm_ts_bind_info_t *p_bind; +#endif + cl_list_t tmp_madw_p_list; /* this list will include all the madw_p that should be removed. */ + cl_list_t retry_madw_p_list; /* this list will include all the madw_p that were retried and need to be removed. */ + osm_madw_t *madw_p; + + OSM_LOG_ENTER(p_vend->p_log); + + trans_mgr_p = (osm_transaction_mgr_t *) p_vend->p_transaction_mgr; + + /* initialize the tmp_madw_p_list */ + cl_list_construct(&tmp_madw_p_list); + cl_status = cl_list_init(&tmp_madw_p_list, 50); + if (cl_status != CL_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_transaction_mgr_callback : ERROR 1000: " + "Failed to create tmp_madw_p_list\n"); + } + + cl_list_construct(&retry_madw_p_list); + cl_status = cl_list_init(&retry_madw_p_list, 50); + if (cl_status != CL_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_transaction_mgr_callback : ERROR 1000: " + "Failed to create retry_madw_p_list\n"); + } + + current_time = cl_get_time_stamp(); + cl_spinlock_acquire(&(trans_mgr_p->transaction_mgr_lock)); + p_list_item = cl_qlist_head(trans_mgr_p->madw_reqs_list_p); + if (p_list_item == cl_qlist_end(trans_mgr_p->madw_reqs_list_p)) { + /* the list is empty - nothing to do */ + cl_spinlock_release(&trans_mgr_p->transaction_mgr_lock); + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_transaction_mgr_callback : Nothing to do\n"); + goto Exit; + } + + /* non empty list: */ + + /* get the osm_madw_req_p */ + osm_madw_req_p = PARENT_STRUCT(p_list_item, osm_madw_req_t, list_item); + + while (osm_madw_req_p->waking_time <= current_time) { + /* this object was supposed to have gotten a response */ + /* we need to decide if we need to retry or done with it. */ + if (osm_madw_req_p->retry_cnt > 0) { + /* add to the list of the retrys : */ + cl_list_insert_tail(&retry_madw_p_list, osm_madw_req_p); + + /* update wakeup time and retry count */ + osm_madw_req_p->waking_time = + p_vend->timeout * 1000 + cl_get_time_stamp(); + osm_madw_req_p->retry_cnt--; + + /* make sure we will get some timer call if not earlier */ + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_transaction_mgr_callback : Timer restart:%u\n", + p_vend->timeout); + + cl_status = + cl_timer_start(&trans_mgr_p->madw_list_timer, + p_vend->timeout); + + /* go to the next object and check if it also needs to be removed - didn't receive response */ + /* we need to do it before we move current item to the end of the list */ + p_list_next_item = cl_qlist_next(p_list_item); + + /* remove from the head */ + cl_qlist_remove_item(trans_mgr_p->madw_reqs_list_p, + &(osm_madw_req_p->list_item)); + + /* insert the object to the qlist and the qmap */ + cl_qlist_insert_tail(trans_mgr_p->madw_reqs_list_p, + &(osm_madw_req_p->list_item)); + + } else { + /* go to the next object and check if it also needs to be removed - didn't receive response */ + p_list_next_item = cl_qlist_next(p_list_item); + + /* remove from the head */ + cl_qlist_remove_item(trans_mgr_p->madw_reqs_list_p, + &(osm_madw_req_p->list_item)); + + /* add it to the tmp_madw_p_list to be removed */ + cl_list_insert_tail(&tmp_madw_p_list, + osm_madw_req_p->p_madw); + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_transaction_mgr_callback : Found failed transaction madw: %p\n", + osm_madw_req_p->p_madw); + } + + /* Advance */ + p_list_item = p_list_next_item; + if (p_list_item == cl_qlist_end(trans_mgr_p->madw_reqs_list_p)) { + /* the list is empty - nothing to do */ + break; + } + + /* get the osm_madw_req_p */ + osm_madw_req_p = + PARENT_STRUCT(p_list_item, osm_madw_req_t, list_item); + } + + /* look at the current p_list_item. If it is not the end item - then we need to */ + /* re-start the timer */ + if (p_list_item != cl_qlist_end(trans_mgr_p->madw_reqs_list_p)) { + /* get the osm_madw_req_p */ + osm_madw_req_p = + PARENT_STRUCT(p_list_item, osm_madw_req_t, list_item); + + /* we have the object that still didn't get response - re-start the timer */ + /* start the timer to the timeout (in miliseconds) */ + new_timeout = + (osm_madw_req_p->waking_time - cl_get_time_stamp()) / 1000 + + 1; + cl_status = + cl_timer_start(&trans_mgr_p->madw_list_timer, new_timeout); + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_transaction_mgr_callback : Timer restart:%u\n", + new_timeout); + + if (cl_status != CL_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_transaction_mgr_callback : ERROR 1000: " + "Failed to start timer\n"); + } + } + /* if not empty - retry on retry list: */ + if (!cl_is_list_empty(&retry_madw_p_list)) { + + /* remove all elements that were retried: */ + osm_madw_req_p = + (osm_madw_req_t + *) (cl_list_remove_head(&retry_madw_p_list)); + while (osm_madw_req_p != NULL) { + + /* resend: */ + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "__osm_transaction_mgr_callback : " + "Retry %d of madw %p\n", + OSM_DEFAULT_RETRY_COUNT - + osm_madw_req_p->retry_cnt, + osm_madw_req_p->p_madw); + + /* actually send it */ +#ifdef OSM_VENDOR_INTF_MTL + osm_mtl_send_mad((osm_mtl_bind_info_t *) + osm_madw_req_p->p_bind, + osm_madw_req_p->p_madw); +#else + ib_api_status_t + osm_ts_send_mad(osm_ts_bind_info_t * p_bind, + osm_madw_t * const p_madw); + osm_ts_send_mad((osm_ts_bind_info_t *) osm_madw_req_p-> + p_bind, osm_madw_req_p->p_madw); +#endif + /* next one */ + osm_madw_req_p = + (osm_madw_req_t + *) (cl_list_remove_head(&retry_madw_p_list)); + } + } + + /* if the tmp_madw_p_list has elements - need to call the send_err_callback */ + madw_p = (osm_madw_t *) (cl_list_remove_head(&tmp_madw_p_list)); + while (madw_p != NULL) { + /* need to remove it from pool */ + + /* obtain the madw_p stored as the wrid in the send call */ + p_mad = osm_madw_get_mad_ptr(madw_p); + p_bind = madw_p->h_bind; + /* + Return any wrappers to the pool that may have been + pre-emptively allocated to handle a receive. + */ + if (madw_p->vend_wrap.p_resp_madw) { +#ifdef OSM_VENDOR_INTF_MTL + osm_mad_pool_put(p_bind->p_osm_pool, + madw_p->vend_wrap.p_resp_madw); +#else + osm_mad_pool_put(p_bind->p_osm_pool, + madw_p->vend_wrap.p_resp_madw); +#endif + madw_p->vend_wrap.p_resp_madw = NULL; + } + + /* invoke the CB */ + (*(osm_vend_mad_send_err_callback_t) + (p_bind->send_err_callback)) (p_bind->client_context, madw_p); + madw_p = (osm_madw_t *) (cl_list_remove_head(&tmp_madw_p_list)); + } + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + +} + +/* + * Construct and Initialize + */ + +void osm_transaction_mgr_init(IN osm_vendor_t * const p_vend) +{ + cl_status_t cl_status; + osm_transaction_mgr_t *trans_mgr_p; + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend->p_transaction_mgr == NULL); + + (osm_transaction_mgr_t *) p_vend->p_transaction_mgr = + (osm_transaction_mgr_t *) malloc(sizeof(osm_transaction_mgr_t)); + + trans_mgr_p = (osm_transaction_mgr_t *) p_vend->p_transaction_mgr; + + /* construct lock object */ + cl_spinlock_construct(&(trans_mgr_p->transaction_mgr_lock)); + CL_ASSERT(cl_spinlock_init(&(trans_mgr_p->transaction_mgr_lock)) == + CL_SUCCESS); + + /* initialize the qlist */ + trans_mgr_p->madw_reqs_list_p = + (cl_qlist_t *) malloc(sizeof(cl_qlist_t)); + cl_qlist_init(trans_mgr_p->madw_reqs_list_p); + + /* initialize the qmap */ + trans_mgr_p->madw_by_tid_map_p = + (cl_qmap_t *) malloc(sizeof(cl_qmap_t)); + cl_qmap_init(trans_mgr_p->madw_by_tid_map_p); + + /* create the timer used by the madw_req_list */ + cl_timer_construct(&(trans_mgr_p->madw_list_timer)); + + /* init the timer with timeout. */ + cl_status = cl_timer_init(&trans_mgr_p->madw_list_timer, + __osm_transaction_mgr_callback, p_vend); + + if (cl_status != CL_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_transaction_mgr_init : ERROR 1000: " + "Failed to initialize madw_reqs_list timer\n"); + } + OSM_LOG_EXIT(p_vend->p_log); +} + +void osm_transaction_mgr_destroy(IN osm_vendor_t * const p_vend) +{ + osm_transaction_mgr_t *trans_mgr_p; + cl_list_item_t *p_list_item; + cl_map_item_t *p_map_item; + osm_madw_req_t *osm_madw_req_p; + + OSM_LOG_ENTER(p_vend->p_log); + + trans_mgr_p = (osm_transaction_mgr_t *) p_vend->p_transaction_mgr; + + if (p_vend->p_transaction_mgr != NULL) { + /* we need to get a lock */ + cl_spinlock_acquire(&trans_mgr_p->transaction_mgr_lock); + + /* go over all the items in the list and remove them */ + p_list_item = + cl_qlist_remove_head(trans_mgr_p->madw_reqs_list_p); + while (p_list_item != + cl_qlist_end(trans_mgr_p->madw_reqs_list_p)) { + osm_madw_req_p = (osm_madw_req_t *) p_list_item; + + if (osm_madw_req_p->p_madw->p_mad) + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_transaction_mgr_destroy: " + "Found outstanding MADW:%p TID:<0x%" + PRIx64 ">.\n", osm_madw_req_p->p_madw, + osm_madw_req_p->p_madw->p_mad-> + trans_id); + else + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_transaction_mgr_destroy: " + "Found outstanding MADW:%p TID:UNDEFINED.\n", + osm_madw_req_p->p_madw); + + /* each item - remove it from the map */ + p_map_item = &(osm_madw_req_p->map_item); + cl_qmap_remove_item(trans_mgr_p->madw_by_tid_map_p, + p_map_item); + /* free the item */ + free(osm_madw_req_p); + p_list_item = + cl_qlist_remove_head(trans_mgr_p->madw_reqs_list_p); + } + /* free the qlist and qmap */ + free(trans_mgr_p->madw_reqs_list_p); + free(trans_mgr_p->madw_by_tid_map_p); + /* reliease and destroy the lock */ + cl_spinlock_release(&trans_mgr_p->transaction_mgr_lock); + cl_spinlock_destroy(&(trans_mgr_p->transaction_mgr_lock)); + /* destroy the timer */ + cl_timer_trim(&trans_mgr_p->madw_list_timer, 1); + cl_timer_destroy(&trans_mgr_p->madw_list_timer); + /* free the transaction_manager object */ + free(trans_mgr_p); + trans_mgr_p = NULL; + } + + OSM_LOG_EXIT(p_vend->p_log); +} + +ib_api_status_t +osm_transaction_mgr_insert_madw(IN osm_bind_handle_t * const p_bind, + IN osm_madw_t * p_madw) +{ +#ifdef OSM_VENDOR_INTF_MTL + osm_vendor_t *const p_vend = ((osm_mtl_bind_info_t *) p_bind)->p_vend; +#else + osm_vendor_t *const p_vend = ((osm_ts_bind_info_t *) p_bind)->p_vend; +#endif + osm_transaction_mgr_t *trans_mgr_p; + osm_madw_req_t *osm_madw_req_p; + uint64_t timeout; + uint64_t waking_time; + cl_status_t cl_status; + uint64_t key; + const ib_mad_t *mad_p = p_madw->p_mad; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(mad_p); + + trans_mgr_p = (osm_transaction_mgr_t *) p_vend->p_transaction_mgr; + + timeout = (uint64_t) (p_vend->timeout) * 1000; /* change the miliseconds value of timeout to microseconds. */ + waking_time = timeout + cl_get_time_stamp(); + + osm_madw_req_p = (osm_madw_req_t *) malloc(sizeof(osm_madw_req_t)); + + osm_madw_req_p->p_madw = p_madw; + osm_madw_req_p->waking_time = waking_time; + osm_madw_req_p->retry_cnt = OSM_DEFAULT_RETRY_COUNT; + osm_madw_req_p->p_bind = p_bind; + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_transaction_mgr_insert_madw: " + "Inserting MADW:%p with waking_time: <0x%" PRIx64 "> TID:<0x%" + PRIx64 ">.\n", p_madw, waking_time, p_madw->p_mad->trans_id); + + /* Get the lock on the manager */ + cl_spinlock_acquire(&(trans_mgr_p->transaction_mgr_lock)); + /* If the list is empty - need to start the timer with timer of timeout (in miliseconds) */ + if (cl_is_qlist_empty(trans_mgr_p->madw_reqs_list_p)) { + /* stop the timer if it is running */ + cl_timer_stop(&trans_mgr_p->madw_list_timer); + + /* start the timer to the timeout (in miliseconds) */ + cl_status = cl_timer_start(&trans_mgr_p->madw_list_timer, + p_vend->timeout); + if (cl_status != CL_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_transaction_mgr_insert_madw : ERROR 1000: " + "Failed to start timer\n"); + } + } + + /* insert the object to the qlist and the qmap */ + cl_qlist_insert_tail(trans_mgr_p->madw_reqs_list_p, + &(osm_madw_req_p->list_item)); + /* get the key */ + key = (uint64_t) mad_p->trans_id; + cl_qmap_insert(trans_mgr_p->madw_by_tid_map_p, key, + &(osm_madw_req_p->map_item)); + cl_spinlock_release(&trans_mgr_p->transaction_mgr_lock); + + OSM_LOG_EXIT(p_vend->p_log); + + return (IB_SUCCESS); +} + +ib_api_status_t +osm_transaction_mgr_erase_madw(IN osm_vendor_t * const p_vend, + IN ib_mad_t * p_mad) +{ + osm_transaction_mgr_t *trans_mgr_p; + osm_madw_req_t *osm_madw_req_p; + uint64_t key; + cl_map_item_t *p_map_item; + OSM_LOG_ENTER(p_vend->p_log); + + trans_mgr_p = (osm_transaction_mgr_t *) p_vend->p_transaction_mgr; + + key = (uint64_t) p_mad->trans_id; + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_transaction_mgr_erase_madw: " + "Removing TID:<0x%" PRIx64 ">.\n", p_mad->trans_id); + + cl_spinlock_acquire(&trans_mgr_p->transaction_mgr_lock); + p_map_item = cl_qmap_get(trans_mgr_p->madw_by_tid_map_p, key); + if (p_map_item != cl_qmap_end(trans_mgr_p->madw_by_tid_map_p)) { + /* we found such an item. */ + /* get the osm_madw_req_p */ + osm_madw_req_p = + PARENT_STRUCT(p_map_item, osm_madw_req_t, map_item); + + /* remove the item from the qlist */ + cl_qlist_remove_item(trans_mgr_p->madw_reqs_list_p, + &(osm_madw_req_p->list_item)); + /* remove the item from the qmap */ + cl_qmap_remove_item(trans_mgr_p->madw_by_tid_map_p, + &(osm_madw_req_p->map_item)); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_transaction_mgr_erase_madw: " + "Removed TID:<0x%" PRIx64 ">.\n", p_mad->trans_id); + + /* free the item */ + free(osm_madw_req_p); + } else { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_transaction_mgr_erase_madw: " + "osm_transaction_mgr_erase_madw:<0x%" PRIx64 + "> NOT FOUND.\n", p_mad->trans_id); + } + cl_spinlock_release(&trans_mgr_p->transaction_mgr_lock); + OSM_LOG_EXIT(p_vend->p_log); + + return (IB_SUCCESS); +} + +ib_api_status_t +osm_transaction_mgr_get_madw_for_tid(IN osm_vendor_t * const p_vend, + IN ib_mad_t * const p_mad, + OUT osm_madw_t ** req_madw_p) +{ + osm_transaction_mgr_t *trans_mgr_p; + osm_madw_req_t *osm_madw_req_p; + cl_map_item_t *p_map_item; + uint64_t key; + OSM_LOG_ENTER(p_vend->p_log); + + trans_mgr_p = (osm_transaction_mgr_t *) p_vend->p_transaction_mgr; + + *req_madw_p = NULL; + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_transaction_mgr_get_madw_for_tid: " + "Looking for TID:<0x%" PRIx64 ">.\n", p_mad->trans_id); + + key = (uint64_t) p_mad->trans_id; + cl_spinlock_acquire(&(trans_mgr_p->transaction_mgr_lock)); + p_map_item = cl_qmap_get(trans_mgr_p->madw_by_tid_map_p, key); + if (p_map_item != cl_qmap_end(trans_mgr_p->madw_by_tid_map_p)) { + /* we found such an item. */ + /* get the osm_madw_req_p */ + osm_madw_req_p = + PARENT_STRUCT(p_map_item, osm_madw_req_t, map_item); + + /* Since the Transaction was looked up and provided for */ + /* processing we retire it */ + cl_qlist_remove_item(trans_mgr_p->madw_reqs_list_p, + &(osm_madw_req_p->list_item)); + /* remove the item from the qmap */ + cl_qmap_remove_item(trans_mgr_p->madw_by_tid_map_p, + &(osm_madw_req_p->map_item)); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_transaction_mgr_get_madw_for_tid: " + "Removed TID:<0x%" PRIx64 ">.\n", p_mad->trans_id); + + *req_madw_p = osm_madw_req_p->p_madw; + } + + cl_spinlock_release(&(trans_mgr_p->transaction_mgr_lock)); + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_transaction_mgr_get_madw_for_tid: " + "Got MADW:%p.\n", *req_madw_p); + OSM_LOG_EXIT(p_vend->p_log); + return (IB_SUCCESS); +} + +#endif diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_test.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_test.c new file mode 100644 index 000000000000..67fc0e2a6f9c --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_test.c @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of vendor specific transport interface. + * This is the "Test" vendor which allows compilation and some + * testing without a real vendor interface. + * These objects are part of the opensm family of objects. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef OSM_VENDOR_INTF_TEST + +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void osm_vendor_construct(IN osm_vendor_t * const p_vend) +{ + memset(p_vend, 0, sizeof(*p_vend)); +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_destroy(IN osm_vendor_t * const p_vend) +{ + UNUSED_PARAM(p_vend); +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_delete(IN osm_vendor_t ** const pp_vend) +{ + CL_ASSERT(pp_vend); + + osm_vendor_destroy(*pp_vend); + free(*pp_vend); + *pp_vend = NULL; +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vendor_init(IN osm_vendor_t * const p_vend, + IN osm_log_t * const p_log, IN const uint32_t timeout) +{ + OSM_LOG_ENTER(p_log); + + CL_ASSERT(p_vend); + CL_ASSERT(p_log); + + p_vend->p_log = p_log; + p_vend->timeout = timeout; + OSM_LOG_EXIT(p_log); + return (IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log, + IN const uint32_t timeout) +{ + ib_api_status_t status; + osm_vendor_t *p_vend; + OSM_LOG_ENTER(p_log); + + CL_ASSERT(p_log); + + p_vend = malloc(sizeof(*p_vend)); + if (p_vend != NULL) { + memset(p_vend, 0, sizeof(*p_vend)); + + status = osm_vendor_init(p_vend, p_log, timeout); + if (status != IB_SUCCESS) { + osm_vendor_delete(&p_vend); + } + } + + OSM_LOG_EXIT(p_log); + return (p_vend); +} + +/********************************************************************** + **********************************************************************/ +ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind, + IN const uint32_t size, + IN osm_vend_wrap_t * const p_vend_wrap) +{ + osm_vendor_t *p_vend; + ib_mad_t *p_mad; + OSM_LOG_ENTER(h_bind->p_vend->p_log); + + UNUSED_PARAM(p_vend_wrap); + + p_vend = h_bind->p_vend; + + /* + Simply malloc the MAD off the heap. + */ + p_mad = (ib_mad_t *) malloc(size); + + osm_log(p_vend->p_log, OSM_LOG_VERBOSE, + "osm_vendor_get: " "MAD %p.\n", p_mad); + + if (p_mad) + memset(p_mad, 0, size); + + OSM_LOG_EXIT(p_vend->p_log); + return (p_mad); +} + +/********************************************************************** + **********************************************************************/ +void +osm_vendor_put(IN osm_bind_handle_t h_bind, + IN osm_vend_wrap_t * const p_vend_wrap, + IN ib_mad_t * const p_mad) +{ + osm_vendor_t *p_vend; + + OSM_LOG_ENTER(h_bind->p_vend->p_log); + + UNUSED_PARAM(p_vend_wrap); + + p_vend = h_bind->p_vend; + + osm_log(p_vend->p_log, OSM_LOG_VERBOSE, + "osm_vendor_put: " "MAD %p.\n", p_mad); + + /* + Return the MAD to the heap. + */ + free(p_mad); + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vendor_send(IN osm_bind_handle_t h_bind, + IN osm_vend_wrap_t * const p_vend_wrap, + IN osm_mad_addr_t * const p_mad_addr, + IN ib_mad_t * const p_mad, + IN void *transaction_context, IN boolean_t const resp_expected) +{ + osm_vendor_t *p_vend = h_bind->p_vend; + + OSM_LOG_ENTER(p_vend->p_log); + + UNUSED_PARAM(p_vend_wrap); + UNUSED_PARAM(p_mad_addr); + UNUSED_PARAM(transaction_context); + UNUSED_PARAM(resp_expected); + + osm_log(p_vend->p_log, OSM_LOG_VERBOSE, + "osm_vendor_send: " "MAD %p.\n", p_mad); + + OSM_LOG_EXIT(p_vend->p_log); + return (IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +osm_bind_handle_t +osm_vendor_bind(IN osm_vendor_t * const p_vend, + IN osm_bind_info_t * const p_bind_info, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vend_mad_recv_callback_t mad_recv_callback, + IN void *context) +{ + osm_bind_handle_t h_bind; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vend); + CL_ASSERT(p_bind_info); + CL_ASSERT(p_mad_pool); + CL_ASSERT(mad_recv_callback); + CL_ASSERT(context); + + UNUSED_PARAM(p_vend); + UNUSED_PARAM(p_mad_pool); + UNUSED_PARAM(mad_recv_callback); + UNUSED_PARAM(context); + + h_bind = (osm_bind_handle_t) malloc(sizeof(*h_bind)); + if (h_bind != NULL) { + memset(h_bind, 0, sizeof(*h_bind)); + h_bind->p_vend = p_vend; + h_bind->port_guid = p_bind_info->port_guid; + h_bind->mad_class = p_bind_info->mad_class; + h_bind->class_version = p_bind_info->class_version; + h_bind->is_responder = p_bind_info->is_responder; + h_bind->is_trap_processor = p_bind_info->is_trap_processor; + h_bind->is_report_processor = p_bind_info->is_report_processor; + h_bind->send_q_size = p_bind_info->send_q_size; + h_bind->recv_q_size = p_bind_info->recv_q_size; + } + + OSM_LOG_EXIT(p_vend->p_log); + return (h_bind); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vendor_get_ports(IN osm_vendor_t * const p_vend, + IN ib_net64_t * const p_guids, + IN uint32_t * const num_guids) +{ + OSM_LOG_ENTER(p_vend->p_log); + + *p_guids = CL_NTOH64(0x0000000000001234); + *num_guids = 1; + + OSM_LOG_EXIT(p_vend->p_log); + return (IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind) +{ + osm_vendor_t *p_vend = h_bind->p_vend; + + OSM_LOG_ENTER(p_vend->p_log); + + OSM_LOG_EXIT(p_vend->p_log); + + return (IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level) +{ + +} + +#endif /* OSM_VENDOR_INTF_TEST */ diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_ts.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_ts.c new file mode 100644 index 000000000000..710d06f0324f --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_ts.c @@ -0,0 +1,904 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#undef __init +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +/* + Since a race can accure on requests. Meaning - a response is received before + the send_callback is called - we will save both the madw_p and the fact + whether or not it is a response. A race can occure only on requests that did + not fail, and then the madw_p will be put back in the pool before the + callback. +*/ +uint64_t __osm_set_wrid_by_p_madw(IN osm_madw_t * p_madw) +{ + uint64_t wrid = 0; + + CL_ASSERT(p_madw->p_mad); + + memcpy(&wrid, &p_madw, sizeof(osm_madw_t *)); + wrid = (wrid << 1) | + ib_mad_is_response(p_madw->p_mad) | + (p_madw->p_mad->method == IB_MAD_METHOD_TRAP_REPRESS); + return wrid; +} + +void +__osm_set_p_madw_and_resp_by_wrid(IN uint64_t wrid, + OUT uint8_t * is_resp, + OUT osm_madw_t ** pp_madw) +{ + *is_resp = wrid & 0x0000000000000001; + wrid = wrid >> 1; + memcpy(pp_madw, &wrid, sizeof(osm_madw_t *)); +} + +/********************************************************************** + * TS MAD to OSM ADDRESS VECTOR + **********************************************************************/ +void +__osm_ts_conv_mad_rcv_desc_to_osm_addr(IN osm_vendor_t * const p_vend, + IN struct ib_mad *p_mad, + IN uint8_t is_smi, + OUT osm_mad_addr_t * p_mad_addr) +{ + p_mad_addr->dest_lid = cl_hton16(p_mad->slid); + p_mad_addr->static_rate = 0; /* HACK - we do not know the rate ! */ + p_mad_addr->path_bits = 0; /* HACK - no way to know in TS */ + if (is_smi) { + /* SMI */ + p_mad_addr->addr_type.smi.source_lid = cl_hton16(p_mad->slid); + p_mad_addr->addr_type.smi.port_num = p_mad->port; + } else { + /* GSI */ + p_mad_addr->addr_type.gsi.remote_qp = p_mad->sqpn; + p_mad_addr->addr_type.gsi.remote_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + p_mad_addr->addr_type.gsi.pkey_ix = p_mad->pkey_index; + p_mad_addr->addr_type.gsi.service_level = 0; /* HACK no way to know */ + + p_mad_addr->addr_type.gsi.global_route = FALSE; /* HACK no way to know */ + /* copy the GRH data if relevant */ + /* + if (p_mad_addr->addr_type.gsi.global_route) + { + p_mad_addr->addr_type.gsi.grh_info.ver_class_flow = + ib_grh_set_ver_class_flow(p_rcv_desc->grh.IP_version, + p_rcv_desc->grh.traffic_class, + p_rcv_desc->grh.flow_label); + p_mad_addr->addr_type.gsi.grh_info.hop_limit = p_rcv_desc->grh.hop_limit; + memcpy(&p_mad_addr->addr_type.gsi.grh_info.src_gid.raw, + &p_rcv_desc->grh.sgid, sizeof(ib_net64_t)); + memcpy(&p_mad_addr->addr_type.gsi.grh_info.dest_gid.raw, + p_rcv_desc->grh.dgid, sizeof(ib_net64_t)); + } + */ + } +} + +/********************************************************************** + * OSM ADDR VECTOR TO TS MAD: + **********************************************************************/ +void +__osm_ts_conv_osm_addr_to_ts_addr(IN osm_mad_addr_t * p_mad_addr, + IN uint8_t is_smi, OUT struct ib_mad *p_mad) +{ + + /* For global destination or Multicast address: */ + p_mad->dlid = cl_ntoh16(p_mad_addr->dest_lid); + p_mad->sl = 0; + if (is_smi) { + p_mad->sqpn = 0; + p_mad->dqpn = 0; + } else { + p_mad->sqpn = 1; + p_mad->dqpn = p_mad_addr->addr_type.gsi.remote_qp; + } +} + +/********************************************************************** + **********************************************************************/ +void __osm_vendor_clear_sm(IN osm_bind_handle_t h_bind) +{ + osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + VAPI_ret_t status; + VAPI_hca_attr_t attr_mod; + VAPI_hca_attr_mask_t attr_mask; + + OSM_LOG_ENTER(p_vend->p_log); + + memset(&attr_mod, 0, sizeof(attr_mod)); + memset(&attr_mask, 0, sizeof(attr_mask)); + + attr_mod.is_sm = FALSE; + attr_mask = HCA_ATTR_IS_SM; + + status = + VAPI_modify_hca_attr(p_bind->hca_hndl, p_bind->port_num, &attr_mod, + &attr_mask); + if (status != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_clear_sm: ERR 5021: " + "Unable set 'IS_SM' bit in port attributes (%d).\n", + status); + } + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + * ANY CONSTRUCTION OF THE osm_vendor_t OBJECT + **********************************************************************/ +void osm_vendor_construct(IN osm_vendor_t * const p_vend) +{ + memset(p_vend, 0, sizeof(*p_vend)); + cl_thread_construct(&(p_vend->smi_bind.poller)); + cl_thread_construct(&(p_vend->gsi_bind.poller)); +} + +/********************************************************************** + * DEALOCATE osm_vendor_t + **********************************************************************/ +void osm_vendor_destroy(IN osm_vendor_t * const p_vend) +{ + OSM_LOG_ENTER(p_vend->p_log); + osm_transaction_mgr_destroy(p_vend); + + /* Destroy the poller threads */ + /* HACK: can you destroy an un-initialized thread ? */ + pthread_cancel(p_vend->smi_bind.poller.osd.id); + pthread_cancel(p_vend->gsi_bind.poller.osd.id); + cl_thread_destroy(&(p_vend->smi_bind.poller)); + cl_thread_destroy(&(p_vend->gsi_bind.poller)); + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** +DEALLOCATE A POINTER TO osm_vendor_t +**********************************************************************/ +void osm_vendor_delete(IN osm_vendor_t ** const pp_vend) +{ + CL_ASSERT(pp_vend); + + osm_vendor_destroy(*pp_vend); + free(*pp_vend); + *pp_vend = NULL; +} + +/********************************************************************** + Initializes the vendor: +**********************************************************************/ + +ib_api_status_t +osm_vendor_init(IN osm_vendor_t * const p_vend, + IN osm_log_t * const p_log, IN const uint32_t timeout) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + p_vend->p_log = p_log; + p_vend->p_transaction_mgr = NULL; + osm_transaction_mgr_init(p_vend); + p_vend->timeout = timeout; + + /* we use the file handle to track the binding */ + p_vend->smi_bind.ul_dev_fd = -1; + p_vend->gsi_bind.ul_dev_fd = -1; + + OSM_LOG_EXIT(p_log); + return (status); +} + +/********************************************************************** + * Create and Initialize osm_vendor_t Object + **********************************************************************/ +osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log, + IN const uint32_t timeout) +{ + ib_api_status_t status; + osm_vendor_t *p_vend; + + OSM_LOG_ENTER(p_log); + + CL_ASSERT(p_log); + + p_vend = malloc(sizeof(*p_vend)); + if (p_vend != NULL) { + memset(p_vend, 0, sizeof(*p_vend)); + + status = osm_vendor_init(p_vend, p_log, timeout); + if (status != IB_SUCCESS) { + osm_vendor_delete(&p_vend); + } + } else { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_new: ERR 5007: " + "Fail to allocate vendor object.\n"); + } + + OSM_LOG_EXIT(p_log); + return (p_vend); +} + +/********************************************************************** + * TS RCV Thread callback + * HACK: - we need to make this support arbitrary size mads. + **********************************************************************/ +void +__osm_ts_rcv_callback(IN osm_ts_bind_info_t * p_bind, + IN osm_mad_addr_t * p_mad_addr, + IN uint32_t mad_size, IN void *p_mad) +{ + ib_api_status_t status; + osm_madw_t *p_req_madw = NULL; + osm_madw_t *p_madw; + osm_vend_wrap_t *p_new_vw; + ib_mad_t *p_mad_buf; + osm_log_t *const p_log = p_bind->p_vend->p_log; + + OSM_LOG_ENTER(p_log); + + /* if it is a response MAD we mustbe able to get the request */ + if (ib_mad_is_response((ib_mad_t *) p_mad)) { + /* can we find a matching madw by this payload TID */ + status = + osm_transaction_mgr_get_madw_for_tid(p_bind->p_vend, + (ib_mad_t *) p_mad, + &p_req_madw); + if (status != IB_SUCCESS) { + osm_log(p_log, OSM_LOG_ERROR, + "__osm_ts_rcv_callback: ERR 5008: " + "Error obtaining request madw by TID (%d).\n", + status); + p_req_madw = NULL; + } + + if (p_req_madw == NULL) { + osm_log(p_log, OSM_LOG_ERROR, + "__osm_ts_rcv_callback: ERR 5009: " + "Fail to obtain request madw for receined MAD. Aborting CB.\n"); + goto Exit; + } + } + + /* do we have a request ??? */ + if (p_req_madw == NULL) { + + /* if not - get new osm_madw and arrange it. */ + /* create the new madw in the pool */ + p_madw = osm_mad_pool_get(p_bind->p_osm_pool, + (osm_bind_handle_t) p_bind, + mad_size, p_mad_addr); + if (p_madw == NULL) { + osm_log(p_log, OSM_LOG_ERROR, + "__osm_ts_rcv_callback: ERR 5010: " + "Error request for a new madw.\n"); + goto Exit; + } + /* HACK: we cust to avoid the const ??? */ + p_mad_buf = (void *)p_madw->p_mad; + } else { + /* we have the madw defined during the send and stored in the vend_wrap */ + /* we need to make sure the wrapper is correctly init there */ + CL_ASSERT(p_req_madw->vend_wrap.p_resp_madw != 0); + p_madw = p_req_madw->vend_wrap.p_resp_madw; + + CL_ASSERT(p_madw->h_bind); + p_mad_buf = + osm_vendor_get(p_madw->h_bind, mad_size, + &p_madw->vend_wrap); + + if (p_mad_buf == NULL) { + osm_log(p_log, OSM_LOG_ERROR, + "__osm_ts_rcv_callback: ERR 5011: " + "Unable to acquire wire MAD.\n"); + + goto Exit; + } + + /* + Finally, attach the wire MAD to this wrapper. + */ + osm_madw_set_mad(p_madw, p_mad_buf); + } + + /* init some fields of the vendor wrapper */ + p_new_vw = osm_madw_get_vend_ptr(p_madw); + p_new_vw->h_bind = p_bind; + p_new_vw->size = mad_size; + p_new_vw->p_resp_madw = NULL; + p_new_vw->p_mad_buf = p_mad_buf; + + memcpy(p_new_vw->p_mad_buf, p_mad, mad_size); + + /* attach the buffer to the wrapper */ + p_madw->p_mad = p_mad_buf; + + /* we can also make sure we marked the size and bind on the returned madw */ + p_madw->h_bind = p_new_vw->h_bind; + + /* call the CB */ + (*(osm_vend_mad_recv_callback_t) p_bind->rcv_callback) + (p_madw, p_bind->client_context, p_req_madw); + +Exit: + OSM_LOG_EXIT(p_log); +} + +/********************************************************************** + * TS Send callback : invoked after each send + * + **********************************************************************/ +void +__osm_ts_send_callback(IN osm_ts_bind_info_t * bind_info_p, + IN boolean_t is_resp, + IN osm_madw_t * madw_p, IN IB_comp_status_t status) +{ + osm_log_t *const p_log = bind_info_p->p_vend->p_log; + osm_vend_wrap_t *p_vw; + + OSM_LOG_ENTER(p_log); + + osm_log(p_log, OSM_LOG_DEBUG, + "__osm_ts_send_callback: INFO 1008: " + "Handling Send of MADW:%p Is Resp:%d.\n", madw_p, is_resp); + + /* we need to handle requests and responses differently */ + if (is_resp) { + if (status != IB_COMP_SUCCESS) { + osm_log(p_log, OSM_LOG_ERROR, + "__osm_ts_send_callback: ERR 5012: " + "Error Sending Response MADW:%p.\n", madw_p); + } else { + osm_log(p_log, OSM_LOG_DEBUG, + "__osm_ts_send_callback: DBG 1008: " + "Completed Sending Response MADW:%p.\n", + madw_p); + } + + /* if we are a response - we need to clean it up */ + osm_mad_pool_put(bind_info_p->p_osm_pool, madw_p); + } else { + + /* this call back is invoked on completion of send - error or not */ + if (status != IB_COMP_SUCCESS) { + + osm_log(p_log, OSM_LOG_ERROR, + "__osm_ts_send_callback: ERR 5013: " + "Received an Error from IB_MGT Send (%d).\n", + status); + + p_vw = osm_madw_get_vend_ptr(madw_p); + CL_ASSERT(p_vw); + + /* + Return any wrappers to the pool that may have been + pre-emptively allocated to handle a receive. + */ + if (p_vw->p_resp_madw) { + osm_mad_pool_put(bind_info_p->p_osm_pool, + p_vw->p_resp_madw); + p_vw->p_resp_madw = NULL; + } + + /* invoke the CB */ + (*(osm_vend_mad_send_err_callback_t) bind_info_p-> + send_err_callback) + (bind_info_p->client_context, madw_p); + } else { + /* successful request send - do nothing - the response will need the + out mad */ + osm_log(p_log, OSM_LOG_DEBUG, + "__osm_ts_send_callback: DBG 1008: " + "Completed Sending Request MADW:%p.\n", madw_p); + } + } + + OSM_LOG_EXIT(p_log); +} + +/********************************************************************** + * Poller thread: + * Always receive 256byte mads from the devcie file + **********************************************************************/ +void __osm_vendor_ts_poller(IN void *p_ptr) +{ + int ts_ret_code; + struct ib_mad mad; + osm_mad_addr_t mad_addr; + osm_ts_bind_info_t *const p_bind = (osm_ts_bind_info_t *) p_ptr; + + OSM_LOG_ENTER(p_bind->p_vend->p_log); + /* we set the type of cancelation for this thread */ + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + while (1) { + /* we read one mad at a time and pass it to the read callback function */ + ts_ret_code = read(p_bind->ul_dev_fd, &mad, sizeof(mad)); + if (ts_ret_code != sizeof(mad)) { + osm_log(p_bind->p_vend->p_log, OSM_LOG_ERROR, + "__osm_vendor_ts_poller: ERR 5003: " + "error with read, bytes = %d, errno = %d\n", + ts_ret_code, errno); + } else { + osm_log(p_bind->p_vend->p_log, OSM_LOG_DEBUG, + "__osm_vendor_ts_poller: " + "MAD QPN:%d SLID:0x%04x class:0x%02x " + "__osm_vendor_ts_poller:0x%02x attr:0x%04x status:0x%04x " + "__osm_vendor_ts_poller:0x%016" PRIx64 "\n", + cl_ntoh32(mad.dqpn), + cl_ntoh16(mad.slid), + mad.mgmt_class, + mad.r_method, + cl_ntoh16(mad.attribute_id), + cl_ntoh16(mad.status), + cl_ntoh64(mad.transaction_id)); + + /* first arrange an address */ + __osm_ts_conv_mad_rcv_desc_to_osm_addr(p_bind->p_vend, + &mad, + (((ib_mad_t *) & + mad)-> + mgmt_class == + IB_MCLASS_SUBN_LID) + || + (((ib_mad_t *) & + mad)-> + mgmt_class == + IB_MCLASS_SUBN_DIR), + &mad_addr); + + /* call the receiver callback */ + /* HACK: this should be replaced with a call to the RMPP Assembly ... */ + __osm_ts_rcv_callback(p_bind, &mad_addr, 256, &mad); + } + } + + OSM_LOG_EXIT(p_bind->p_vend->p_log); +} + +/********************************************************************** + * BINDs a callback (rcv and send error) for a given class and method + * defined by the given: osm_bind_info_t + **********************************************************************/ +osm_bind_handle_t +osm_vendor_bind(IN osm_vendor_t * const p_vend, + IN osm_bind_info_t * const p_user_bind, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vend_mad_recv_callback_t mad_recv_callback, + IN osm_vend_mad_send_err_callback_t send_err_callback, + IN void *context) +{ + ib_net64_t port_guid; + osm_ts_bind_info_t *p_bind = NULL; + VAPI_hca_hndl_t hca_hndl; + VAPI_hca_id_t hca_id; + uint32_t port_num; + ib_api_status_t status; + int device_fd; + char device_file[16]; + osm_ts_user_mad_filter filter; + int ts_ioctl_ret; + int qpn; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_mad_pool); + + port_guid = p_user_bind->port_guid; + + osm_log(p_vend->p_log, OSM_LOG_INFO, + "osm_vendor_bind: " + "Binding to port 0x%" PRIx64 ".\n", cl_ntoh64(port_guid)); + + switch (p_user_bind->mad_class) { + case IB_MCLASS_SUBN_LID: + case IB_MCLASS_SUBN_DIR: + p_bind = &(p_vend->smi_bind); + qpn = 0; + break; + + case IB_MCLASS_SUBN_ADM: + default: + p_bind = &(p_vend->gsi_bind); + qpn = 1; + break; + } + + /* Make sure we did not previously opened the file */ + if (p_bind->ul_dev_fd >= 0) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 5004: " + "Already binded to port %u\n", p_bind->port_num); + goto Exit; + } + + /* + We need to figure out what is the TS file name to attach to. + I guess it is following the index of the port in the table of + ports. + */ + + /* obtain the hca name and port num from the guid */ + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_bind: " + "Finding CA and Port that owns port guid 0x%" PRIx64 ".\n", + cl_ntoh64(port_guid)); + status = + osm_vendor_get_guid_ca_and_port(p_vend, port_guid, &hca_hndl, + &hca_id, &port_num); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 5005: " + "Fail to find port number of port guid:0x%016" PRIx64 + "\n", port_guid); + goto Exit; + } + + /* the file name is just /dev/ts_ua0: */ + strcpy(device_file, "/dev/ts_ua0"); + + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: " "Opening TS UL dev file:%s\n", device_file); + + /* Open the file ... */ + device_fd = open(device_file, O_RDWR); + if (device_fd < 0) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 5006: " + "Fail to open TS UL dev file:%s\n", device_file); + goto Exit; + } + + /* track this bind request info */ + p_bind->ul_dev_fd = device_fd; + p_bind->port_num = port_num; + p_bind->p_vend = p_vend; + p_bind->client_context = context; + p_bind->rcv_callback = mad_recv_callback; + p_bind->send_err_callback = send_err_callback; + p_bind->p_osm_pool = p_mad_pool; + p_bind->hca_hndl = hca_hndl; + + /* + * Create the MAD filter on this file handle. + */ + filter.port = port_num; + + filter.qpn = qpn; + filter.mgmt_class = p_user_bind->mad_class; + filter.direction = TS_IB_MAD_DIRECTION_IN; + filter.mask = + TS_IB_MAD_FILTER_DIRECTION | + TS_IB_MAD_FILTER_PORT | + TS_IB_MAD_FILTER_QPN | TS_IB_MAD_FILTER_MGMT_CLASS; + + ts_ioctl_ret = ioctl(device_fd, TS_IB_IOCSMADFILTADD, &filter); + if (ts_ioctl_ret < 0) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_bind: ERR 5014: " + "Fail to register MAD filter with err:%u\n", + ts_ioctl_ret); + goto Exit; + } + + /* Initialize the listener thread for this port */ + status = cl_thread_init(&p_bind->poller, + __osm_vendor_ts_poller, p_bind, + "osm ts poller"); + if (status != IB_SUCCESS) + goto Exit; + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return ((osm_bind_handle_t) p_bind); +} + +/********************************************************************** +Get a mad from the lower level. +The osm_vend_wrap_t is a wrapper used to connect the mad to the response. +**********************************************************************/ +ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind, + IN const uint32_t mad_size, + IN osm_vend_wrap_t * const p_vw) +{ + ib_mad_t *p_mad; + osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vw); + + p_vw->size = mad_size; + + /* allocate it */ + p_mad = (ib_mad_t *) malloc(p_vw->size); + if (p_mad == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_get: ERR 5022: " + "Error Obtaining MAD buffer.\n"); + goto Exit; + } + + memset(p_mad, 0, p_vw->size); + + /* track locally */ + p_vw->p_mad_buf = p_mad; + p_vw->h_bind = h_bind; + p_vw->p_resp_madw = NULL; + + if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_get: " + "Acquired MAD %p, size = %u.\n", p_mad, p_vw->size); + } + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (p_mad); +} + +/********************************************************************** + * Return a MAD by providing it's wrapper object. + **********************************************************************/ +void +osm_vendor_put(IN osm_bind_handle_t h_bind, IN osm_vend_wrap_t * const p_vw) +{ + osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + osm_madw_t *p_madw; + + OSM_LOG_ENTER(p_vend->p_log); + + CL_ASSERT(p_vw); + CL_ASSERT(p_vw->p_mad_buf); + + if (osm_log_get_level(p_vend->p_log) >= OSM_LOG_DEBUG) { + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_put: " "Retiring MAD %p.\n", + p_vw->p_mad_buf); + } + + /* + * We moved the removal of the transaction to immediatly after + * it was looked up. + */ + + /* free the mad but the wrapper is part of the madw object */ + free(p_vw->p_mad_buf); + p_vw->p_mad_buf = NULL; + p_madw = PARENT_STRUCT(p_vw, osm_madw_t, vend_wrap); + p_madw->p_mad = NULL; + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** +Actually Send a MAD + +MADs are buffers of type: struct ib_mad - so they are limited by size. +This is for internal use by osm_vendor_send and the transaction mgr +retry too. +**********************************************************************/ +ib_api_status_t +osm_ts_send_mad(IN osm_ts_bind_info_t * p_bind, IN osm_madw_t * const p_madw) +{ + osm_vendor_t *const p_vend = p_bind->p_vend; + osm_mad_addr_t *const p_mad_addr = osm_madw_get_mad_addr_ptr(p_madw); + ib_mad_t *const p_mad = osm_madw_get_mad_ptr(p_madw); + struct ib_mad ts_mad; + int ret; + ib_api_status_t status; + + OSM_LOG_ENTER(p_vend->p_log); + + /* + * Copy the MAD over to the sent mad + */ + memcpy(&ts_mad, p_mad, 256); + + /* + * For all sends other than directed route SM MADs, + * acquire an address vector for the destination. + */ + if (p_mad->mgmt_class != IB_MCLASS_SUBN_DIR) { + __osm_ts_conv_osm_addr_to_ts_addr(p_mad_addr, + p_mad->mgmt_class == + IB_MCLASS_SUBN_LID, &ts_mad); + } else { + /* is a directed route - we need to construct a permissive address */ + /* we do not need port number since it is part of the mad_hndl */ + ts_mad.dlid = IB_LID_PERMISSIVE; + ts_mad.slid = IB_LID_PERMISSIVE; + } + if ((p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) || + (p_mad->mgmt_class == IB_MCLASS_SUBN_LID)) { + ts_mad.sqpn = 0; + ts_mad.dqpn = 0; + } else { + ts_mad.sqpn = 1; + ts_mad.dqpn = 1; + } + ts_mad.port = p_bind->port_num; + + /* send it */ + ret = write(p_bind->ul_dev_fd, &ts_mad, sizeof(ts_mad)); + + if (ret != sizeof(ts_mad)) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_ts_send_mad: ERR 5026: " + "Error sending mad (%d).\n", ret); + status = IB_ERROR; + goto Exit; + } + + status = IB_SUCCESS; + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** +Send a MAD through. + +What is unclear to me is the need for the setting of all the MAD Wrapper +fields. Seems like the OSM uses these values during it's processing... +**********************************************************************/ +ib_api_status_t +osm_vendor_send(IN osm_bind_handle_t h_bind, + IN osm_madw_t * const p_madw, IN boolean_t const resp_expected) +{ + osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind; + osm_vendor_t *const p_vend = p_bind->p_vend; + osm_vend_wrap_t *const p_vw = osm_madw_get_vend_ptr(p_madw); + ib_api_status_t status; + + OSM_LOG_ENTER(p_vend->p_log); + + /* + * If a response is expected to this MAD, then preallocate + * a mad wrapper to contain the wire MAD received in the + * response. Allocating a wrapper here allows for easier + * failure paths than after we already received the wire mad. + */ + if (resp_expected == TRUE) { + /* we track it in the vendor wrapper */ + p_vw->p_resp_madw = + osm_mad_pool_get_wrapper_raw(p_bind->p_osm_pool); + if (p_vw->p_resp_madw == NULL) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_send: ERR 5024: " + "Unable to allocate MAD wrapper.\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* put some minimal info on that wrapper */ + ((osm_madw_t *) (p_vw->p_resp_madw))->h_bind = h_bind; + + /* we also want to track it in the TID based map */ + status = osm_transaction_mgr_insert_madw((osm_bind_handle_t *) + p_bind, p_madw); + if (status != IB_SUCCESS) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_send: ERR 5025: " + "Error inserting request madw by TID (%d).\n", + status); + } + } else + p_vw->p_resp_madw = NULL; + + /* do the actual send */ + /* HACK: to be replaced by call to RMPP Segmentation */ + status = osm_ts_send_mad(p_bind, p_madw); + + /* we do not get an asycn callback so call it ourselves */ + /* this will handle all cleanup if neccessary */ + __osm_ts_send_callback(p_bind, !resp_expected, p_madw, status); + +Exit: + OSM_LOG_EXIT(p_vend->p_log); + return (status); +} + +/********************************************************************** + * the idea here is to change the content of the bind such that it + * will hold the local address used for sending directed route by the SMA. + **********************************************************************/ +ib_api_status_t osm_vendor_local_lid_change(IN osm_bind_handle_t h_bind) +{ + osm_vendor_t *p_vend = ((osm_ts_bind_info_t *) h_bind)->p_vend; + + OSM_LOG_ENTER(p_vend->p_log); + + osm_log(p_vend->p_log, OSM_LOG_DEBUG, + "osm_vendor_local_lid_change: DEBUG 2202: " "Change of LID.\n"); + + OSM_LOG_EXIT(p_vend->p_log); + + return (IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_set_sm(IN osm_bind_handle_t h_bind, IN boolean_t is_sm_val) +{ + osm_ts_bind_info_t *p_bind = (osm_ts_bind_info_t *) h_bind; + osm_vendor_t *p_vend = p_bind->p_vend; + VAPI_ret_t status; + VAPI_hca_attr_t attr_mod; + VAPI_hca_attr_mask_t attr_mask; + + OSM_LOG_ENTER(p_vend->p_log); + + memset(&attr_mod, 0, sizeof(attr_mod)); + memset(&attr_mask, 0, sizeof(attr_mask)); + + attr_mod.is_sm = is_sm_val; + attr_mask = HCA_ATTR_IS_SM; + + status = + VAPI_modify_hca_attr(p_bind->hca_hndl, p_bind->port_num, &attr_mod, + &attr_mask); + if (status != VAPI_OK) { + osm_log(p_vend->p_log, OSM_LOG_ERROR, + "osm_vendor_set_sm: ERR 5027: " + "Unable set 'IS_SM' bit to:%u in port attributes (%d).\n", + is_sm_val, status); + } + + OSM_LOG_EXIT(p_vend->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_set_debug(IN osm_vendor_t * const p_vend, IN int32_t level) +{ + +} diff --git a/contrib/ofed/management/opensm/libvendor/osm_vendor_umadt.c b/contrib/ofed/management/opensm/libvendor/osm_vendor_umadt.c new file mode 100644 index 000000000000..82932dd1bb25 --- /dev/null +++ b/contrib/ofed/management/opensm/libvendor/osm_vendor_umadt.c @@ -0,0 +1,1117 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_req_t. + * This object represents the generic attribute requester. + * This object is part of the opensm family of objects. + * + */ + +/* + Next available error code: 0x300 +*/ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef OSM_VENDOR_INTF_UMADT + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* GEN1 includes */ +#include "umadt_so.h" +#include "ibt.h" +#include "statustext.h" + +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* */ +/* VENDOR_MAD_INTF */ +/* */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ +/* //////////////////////////////////////////////////////////////////////// */ + +/* //////////////////// */ +/* Globals // */ +/* //////////////////// */ +typedef struct _ib_sa_mad_vM3 { + uint8_t base_ver; + uint8_t mgmt_class; + uint8_t class_ver; + uint8_t method; + ib_net16_t status; + ib_net16_t resv; + ib_net64_t trans_id; + ib_net16_t attr_id; + ib_net16_t resv1; + ib_net32_t attr_mod; + ib_net64_t resv2; + ib_net64_t sm_key; + + ib_net32_t seg_num; + ib_net32_t payload_len; + uint8_t frag_flag; + uint8_t edit_mod; + ib_net16_t window; + ib_net16_t attr_offset; + ib_net16_t resv3; + + ib_net64_t comp_mask; + + uint8_t data[IB_SA_DATA_SIZE]; +} ib_sa_mad_t_vM3; +#define DEFAULT_TIMER_INTERVAL_MSEC 500 /* 500msec timer interval */ + +void __mad_recv_processor(void *context); + +boolean_t __valid_mad_handle(IN mad_bind_info_t * p_mad_bind_info); + +cl_status_t +__match_tid_context(const cl_list_item_t * const p_list_item, void *context); +void __osm_vendor_timer_callback(IN void *context); + +osm_vendor_t *osm_vendor_new(IN osm_log_t * const p_log, + IN const uint32_t timeout) +{ + ib_api_status_t status; + umadt_obj_t *p_umadt_obj; + + OSM_LOG_ENTER(p_log); + + p_umadt_obj = malloc(sizeof(umadt_obj_t)); + if (p_umadt_obj) { + memset(p_umadt_obj, 0, sizeof(umadt_obj_t)); + + status = osm_vendor_init((osm_vendor_t *) p_umadt_obj, p_log, + timeout); + if (status != IB_SUCCESS) { + osm_vendor_delete((osm_vendor_t **) & p_umadt_obj); + } + } else { + printf + ("osm_vendor_construct: ERROR! Unable to create Umadt object!\n"); + } + + OSM_LOG_EXIT(p_log); + + return ((osm_vendor_t *) p_umadt_obj); +} + +void osm_vendor_delete(IN osm_vendor_t ** const pp_vend) +{ + umadt_obj_t *p_umadt_obj = (umadt_obj_t *) * pp_vend; + cl_list_item_t *p_list_item; + uint32_t count, i; + mad_bind_info_t *p_mad_bind_info; + + OSM_LOG_ENTER(p_umadt_obj->p_log); + + cl_spinlock_acquire(&p_umadt_obj->register_lock); + p_mad_bind_info = + (mad_bind_info_t *) cl_qlist_head(&p_umadt_obj->register_list); + count = cl_qlist_count(&p_umadt_obj->register_list); + cl_spinlock_release(&p_umadt_obj->register_lock); + for (i = 0; i < count; i++) { + cl_spinlock_acquire(&p_umadt_obj->register_lock); + p_list_item = cl_qlist_next(&p_mad_bind_info->list_item); + cl_spinlock_release(&p_umadt_obj->register_lock); + /* Unbind this handle */ + /* osm_vendor_ubind also removesd the item from the list */ + /* osm_vendor_unbind takes the list lock so release it here */ + osm_vendor_unbind((osm_bind_handle_t) p_mad_bind_info); + p_mad_bind_info = (mad_bind_info_t *) p_list_item; + } + dlclose(p_umadt_obj->umadt_handle); + free(p_umadt_obj); + *pp_vend = NULL; + + OSM_LOG_EXIT(p_umadt_obj->p_log); +} + +/* //////////////////////////////////////////////////////////////////////// */ +/* See VendorAbstractMadIntf.h for info */ +/* //////////////////////////////////////////////////////////////////////// */ +/* */ +ib_api_status_t +osm_vendor_init(IN osm_vendor_t * const p_vend, + IN osm_log_t * const p_log, IN const uint32_t timeout) +{ + FSTATUS Status; + PUMADT_GET_INTERFACE uMadtGetInterface; + char *error; + umadt_obj_t *p_umadt_obj = (umadt_obj_t *) p_vend; + + OSM_LOG_ENTER(p_log); + + p_umadt_obj->p_log = p_log; + p_umadt_obj->timeout = timeout; + + p_umadt_obj->umadt_handle = dlopen("libibt.so", RTLD_NOW); + + if (!p_umadt_obj->umadt_handle) { + printf("Could not load libibt.so <%s>\n", dlerror()); + return IB_ERROR; + } + uMadtGetInterface = + dlsym(p_umadt_obj->umadt_handle, "uMadtGetInterface"); + if ((error = dlerror()) != NULL) { + printf("Could not resolve symbol uMadtGetInterface ERROR<%s>\n", + error); + return IB_ERROR; + } + + Status = (*uMadtGetInterface) (&p_umadt_obj->uMadtInterface); + if (Status != FSUCCESS) { + printf(" Error in getting uMADT interface ERROR<%d>\n", Status); + return IB_ERROR; + } + + /* Initialize the register list and register list lock */ + cl_qlist_init(&p_umadt_obj->register_list); + + cl_spinlock_construct(&p_umadt_obj->register_lock); + CL_ASSERT(cl_spinlock_init(&p_umadt_obj->register_lock) == CL_SUCCESS); + p_umadt_obj->init_done = TRUE; + printf("*****SUCCESS*****\n"); + + OSM_LOG_EXIT(p_log); + return IB_SUCCESS; + +} + +/* //////////////////////////////////////////////////////////////////////// */ +/* See VendorAbstractMadIntf.h for info */ +/* //////////////////////////////////////////////////////////////////////// */ +ib_api_status_t +osm_vendor_get_ports(IN osm_vendor_t * const p_vend, + IN ib_net64_t * const p_guids, + IN uint32_t * const p_num_guids) +{ + char *error = NULL; + PIBT_GET_INTERFACE pfnIbtGetInterface; + PIBT_INIT pfnIbtInitFunc; + + FSTATUS Status; + uint32_t caCount, caGuidCount; + IB_CA_ATTRIBUTES caAttributes; + IB_HANDLE caHandle; + uint32_t i; + IB_PORT_ATTRIBUTES *pPortAttributesList; + EUI64 CaGuidArray[8]; + void *context; + uint64_t *p_port_guid; + uint32_t free_guids; + + umadt_obj_t *p_umadt_obj = (umadt_obj_t *) p_vend; + + OSM_LOG_ENTER(p_umadt_obj->p_log); + + CL_ASSERT(p_guids); + CL_ASSERT(p_num_guids); + + pfnIbtInitFunc = + (PIBT_INIT) dlsym(p_umadt_obj->umadt_handle, "IbtInit"); + + if (!pfnIbtInitFunc) { + printf("Error getting IbtInit function address.\n"); + return IB_ERROR; + } + + (*pfnIbtInitFunc) (); + + pfnIbtGetInterface = + (PIBT_GET_INTERFACE) dlsym(p_umadt_obj->umadt_handle, + "IbtGetInterface"); + + if (!pfnIbtGetInterface || (error = dlerror()) != NULL) { + printf("Error getting IbtGetInterface function address.<%s>\n", + error); + return FALSE; + } + (*pfnIbtGetInterface) (&p_umadt_obj->IbtInterface); + + caGuidCount = 8; + Status = + p_umadt_obj->IbtInterface.GetCaGuidArray(&caGuidCount, + &CaGuidArray[0]); + + if ((Status != FSUCCESS) || (caGuidCount == 0)) { + return FALSE; + } + + free_guids = *p_num_guids; + p_port_guid = p_guids; + + /* query each ca & copy its info into callers buffer */ + for (caCount = 0; caCount < caGuidCount; caCount++) { + memset(&caAttributes, 0, sizeof(IB_CA_ATTRIBUTES)); + + /* Open the CA */ + Status = p_umadt_obj->IbtInterface.Vpi.OpenCA(CaGuidArray[caCount], NULL, /* CACompletionCallback */ + NULL, /* AsyncEventCallback */ + NULL, &caHandle); + if (Status != FSUCCESS) { + return IB_ERROR; + } + + Status = p_umadt_obj->IbtInterface.Vpi.QueryCA(caHandle, + &caAttributes, + &context); + + if (Status != FSUCCESS) { + p_umadt_obj->IbtInterface.Vpi.CloseCA(caHandle); + return IB_ERROR; + } + + if (caAttributes.Ports > free_guids) { + *p_num_guids = 0; + memset(p_guids, 0, (*p_num_guids) * sizeof(uint64_t)); + return IB_INSUFFICIENT_MEMORY; + } + + pPortAttributesList = + (IB_PORT_ATTRIBUTES *) malloc(caAttributes. + PortAttributesListSize); + + if (pPortAttributesList == NULL) { + p_umadt_obj->IbtInterface.Vpi.CloseCA(caHandle); + *p_num_guids = 0; + memset(p_guids, 0, (*p_num_guids) * sizeof(uint64_t)); + return IB_INSUFFICIENT_MEMORY; + } + + memset(pPortAttributesList, 0, + caAttributes.PortAttributesListSize); + + caAttributes.PortAttributesList = pPortAttributesList; + + Status = p_umadt_obj->IbtInterface.Vpi.QueryCA(caHandle, + &caAttributes, + &context); + + if (Status != FSUCCESS) { + p_umadt_obj->IbtInterface.Vpi.CloseCA(caHandle); + *p_num_guids = 0; + memset(p_guids, 0, (*p_num_guids) * sizeof(uint64_t)); + return IB_ERROR; + } + + pPortAttributesList = caAttributes.PortAttributesList; + + for (i = 0; i < caAttributes.Ports; i++) { + *(p_port_guid) = + cl_hton64((uint64_t) pPortAttributesList->GUID); + pPortAttributesList = pPortAttributesList->Next; + p_port_guid++; + } + free(caAttributes.PortAttributesList); + p_umadt_obj->IbtInterface.Vpi.CloseCA(caHandle); + + free_guids = free_guids - caAttributes.Ports; + + } + *p_num_guids = *p_num_guids - free_guids; + return IB_SUCCESS; +} + +/* //////////////////////////////////////////////////////////////////////// */ +/* See VendorAbstractMadIntf.h for info */ +/* //////////////////////////////////////////////////////////////////////// */ +ib_mad_t *osm_vendor_get(IN osm_bind_handle_t h_bind, + IN const uint32_t mad_size, + IN osm_vend_wrap_t * p_vend_wrap) +{ + /* FSTATUS Status; */ + /* uint32_t mad_count = 0; */ + /* MadtStruct *p_madt_struct; */ + mad_bind_info_t *p_mad_bind_info = (mad_bind_info_t *) h_bind; + umadt_obj_t *p_umadt_obj = p_mad_bind_info->p_umadt_obj; + ib_mad_t *p_mad; + OSM_LOG_ENTER(p_umadt_obj->p_log); + + CL_ASSERT(h_bind); + + p_umadt_obj = p_mad_bind_info->p_umadt_obj; + + /* Sanity check */ + CL_ASSERT(p_umadt_obj->init_done); + CL_ASSERT(p_vend_wrap); + CL_ASSERT(__valid_mad_handle(p_mad_bind_info)); + +#if 0 + mad_count = 1; + Status = + p_umadt_obj->uMadtInterface.uMadtGetSendMad(p_mad_bind_info-> + umadt_handle, + &mad_count, + &p_madt_struct); + + if (Status != FSUCCESS || p_madt_struct == NULL) { + p_vend_wrap->p_madt_struct = NULL; + return NULL; + } + p_vend_wrap->p_madt_struct = p_madt_struct; + p_vend_wrap->direction = SEND; + return ((ib_mad_t *) & p_madt_struct->IBMad); +#endif /* 0 */ + p_mad = (ib_mad_t *) malloc(mad_size); + if (!p_mad) { + p_vend_wrap->p_madt_struct = NULL; + return NULL; + } + + memset(p_mad, 0, mad_size); + + p_vend_wrap->p_madt_struct = NULL; + p_vend_wrap->direction = SEND; + p_vend_wrap->size = mad_size; + return (p_mad); + +} + +/* //////////////////////////////////////////////////////////////////////// */ +/* See VendorAbstractMadIntf.h for info */ +/* //////////////////////////////////////////////////////////////////////// */ +void +osm_vendor_put(IN osm_bind_handle_t h_bind, + IN osm_vend_wrap_t * const p_vend_wrap, + IN ib_mad_t * const p_mad) +{ + + FSTATUS Status; + + mad_bind_info_t *p_mad_bind_info; + umadt_obj_t *p_umadt_obj; + + /* */ + /* Validate the vendor mad transport handle */ + /* */ + CL_ASSERT(h_bind); + p_mad_bind_info = (mad_bind_info_t *) h_bind; + p_umadt_obj = p_mad_bind_info->p_umadt_obj; + + /* sanity check */ + CL_ASSERT(p_umadt_obj->init_done); + CL_ASSERT(h_bind); + CL_ASSERT(__valid_mad_handle(p_mad_bind_info)); + CL_ASSERT(p_vend_wrap); + /* CL_ASSERT( (ib_mad_t*)&p_vend_wrap->p_madt_struct->IBMad == p_mad ); */ + + /* Release the MAD based on the direction of the MAD */ + if (p_vend_wrap->direction == SEND) { + /* */ + /* For a send the PostSend released the MAD with Umadt. Simply dealloacte the */ + /* local memory that was allocated on the osm_vendor_get() call. */ + /* */ + free(p_mad); +#if 0 + Status = + p_umadt_obj->uMadtInterface. + uMadtReleaseSendMad(p_mad_bind_info->umadt_handle, + p_vend_wrap->p_madt_struct); + if (Status != FSUCCESS) { + /* printf("uMadtReleaseSendMad: Status = <%d>\n", Status); */ + return; + } +#endif + } else if (p_vend_wrap->direction == RECEIVE) { + CL_ASSERT((ib_mad_t *) & p_vend_wrap->p_madt_struct->IBMad == + p_mad); + Status = + p_umadt_obj->uMadtInterface. + uMadtReleaseRecvMad(p_mad_bind_info->umadt_handle, + p_vend_wrap->p_madt_struct); + if (Status != FSUCCESS) { + /* printf("uMadtReleaseRecvMad Status=<%d>\n", Status); */ + return; + } + } else { + return; + } + return; +} + +/* //////////////////////////////////////////////////////////////////////// */ +/* See VendorAbstractMadIntf.h for info */ +/* //////////////////////////////////////////////////////////////////////// */ +ib_api_status_t +osm_vendor_send(IN osm_bind_handle_t h_bind, + IN osm_vend_wrap_t * const p_vend_wrap, + IN osm_mad_addr_t * const p_mad_addr, + IN ib_mad_t * const p_mad, + IN void *transaction_context, IN boolean_t const resp_expected) +{ + FSTATUS Status; + + MadAddrStruct destAddr = { 0 }; + + mad_bind_info_t *p_mad_bind_info; + trans_context_t *p_trans_context; + + umadt_obj_t *p_umadt_obj = NULL; + + uint32_t mad_count = 0; + MadtStruct *p_madt_struct = NULL; + uint32_t i; + uint32_t num_mads = 0; + uint32_t seg_num = 0; + uint8_t *p_frag_data = NULL; + ib_sa_mad_t_vM3 *p_sa_mad = NULL; + + CL_ASSERT(h_bind); + p_mad_bind_info = (mad_bind_info_t *) h_bind; + p_umadt_obj = p_mad_bind_info->p_umadt_obj; + + /* sanity check */ + CL_ASSERT(p_umadt_obj); + CL_ASSERT(p_umadt_obj->init_done); + CL_ASSERT(__valid_mad_handle(p_mad_bind_info)); + CL_ASSERT(p_vend_wrap); + CL_ASSERT(p_mad_addr); + CL_ASSERT(p_mad); + /* CL_ASSERT( (ib_mad_t*)&p_vend_wrap->p_madt_struct->IBMad == p_mad ); */ + + /* */ + /* based on the class, fill out the address info */ + /* */ + destAddr.DestLid = p_mad_addr->dest_lid; + destAddr.PathBits = p_mad_addr->path_bits; + destAddr.StaticRate = p_mad_addr->static_rate; + + if (p_mad_bind_info->umadt_reg_class.ClassId == IB_MCLASS_SUBN_LID || + p_mad_bind_info->umadt_reg_class.ClassId == IB_MCLASS_SUBN_DIR) { + CL_ASSERT(p_mad_addr->addr_type.smi.source_lid); + destAddr.AddrType.Smi.SourceLid = + p_mad_addr->addr_type.smi.source_lid; + } else { + destAddr.AddrType.Gsi.RemoteQpNumber = + p_mad_addr->addr_type.gsi.remote_qp; + destAddr.AddrType.Gsi.RemoteQkey = + p_mad_addr->addr_type.gsi.remote_qkey; + destAddr.AddrType.Gsi.PKey = OSM_DEFAULT_PKEY; + destAddr.AddrType.Gsi.ServiceLevel = + p_mad_addr->addr_type.gsi.service_level; + destAddr.AddrType.Gsi.GlobalRoute = + p_mad_addr->addr_type.gsi.global_route; + /* destAddr.AddrType.Gsi.GRHInfo = p_mad_addr->addr_type.gsi.grh_info; */ + } + p_mad->trans_id = cl_ntoh64(p_mad->trans_id) << 24; + + /* */ + /* Create a transaction context for this send and save the TID and client context. */ + /* */ + + if (resp_expected) { + p_trans_context = malloc(sizeof(trans_context_t)); + CL_ASSERT(p_trans_context); + + memset(p_trans_context, 0, sizeof(trans_context_t)); + p_trans_context->trans_id = p_mad->trans_id; + p_trans_context->context = transaction_context; + p_trans_context->sent_time = cl_get_time_stamp(); + + cl_spinlock_acquire(&p_mad_bind_info->trans_ctxt_lock); + cl_qlist_insert_tail(&p_mad_bind_info->trans_ctxt_list, + &p_trans_context->list_item); + cl_spinlock_release(&p_mad_bind_info->trans_ctxt_lock); + } + + if (p_mad_bind_info->umadt_reg_class.ClassId == IB_MCLASS_SUBN_LID || + p_mad_bind_info->umadt_reg_class.ClassId == IB_MCLASS_SUBN_DIR) { + /* Get one mad from uMadt */ + mad_count = 1; + Status = + p_umadt_obj->uMadtInterface. + uMadtGetSendMad(p_mad_bind_info->umadt_handle, &mad_count, + &p_madt_struct); + + if (Status != FSUCCESS || p_madt_struct == NULL) { + return IB_ERROR; + } + + /* No Segmentation required */ + memcpy(&p_madt_struct->IBMad, p_mad, MAD_BLOCK_SIZE); + + /* Post the MAD */ + + Status = + p_umadt_obj->uMadtInterface.uMadtPostSend(p_mad_bind_info-> + umadt_handle, + p_madt_struct, + &destAddr); + if (Status != FSUCCESS) { + printf("uMadtPostSendMad: Status = <%d>\n", Status); + return IB_ERROR; + } + + /* Release send MAD */ + Status = + p_umadt_obj->uMadtInterface. + uMadtReleaseSendMad(p_mad_bind_info->umadt_handle, + p_madt_struct); + if (Status != FSUCCESS) { + printf("uMadtReleaseSendMad: Status = <%d>\n", Status); + return IB_ERROR; + } + } else { + + /* */ + /* Segment the MAD, get the required send mads from uMadt and post the MADs. */ + /* */ + uint32_t payload_len; + + payload_len = + cl_ntoh32(((ib_sa_mad_t_vM3 *) p_mad)->payload_len); + num_mads = payload_len / IB_SA_DATA_SIZE; + if (payload_len % IB_SA_DATA_SIZE != 0) { + num_mads++; /* Get one additional mad for the remainder */ + } + for (i = 0; i < num_mads; i++) { + /* Get one mad from uMadt */ + mad_count = 1; + Status = + p_umadt_obj->uMadtInterface. + uMadtGetSendMad(p_mad_bind_info->umadt_handle, + &mad_count, &p_madt_struct); + + if (Status != FSUCCESS || p_madt_struct == NULL) { + return IB_ERROR; + } + /* Copy client MAD into uMadt's MAD. */ + if (i == 0) { /* First Packet */ + /* Since this is the first MAD, copy the entire MAD_SIZE */ + memcpy(&p_madt_struct->IBMad, p_mad, + MAD_BLOCK_SIZE); + + p_frag_data = + (uint8_t *) p_mad + MAD_BLOCK_SIZE; + + p_sa_mad = + (ib_sa_mad_t_vM3 *) & p_madt_struct->IBMad; + if (num_mads == 1) { /* Only one Packet */ + p_sa_mad->seg_num = 0; + p_sa_mad->frag_flag = 5; /* Set bit 0 for first pkt and b4 for last pkt */ + /* the payload length gets copied with the mad header above */ + } else { /* More than one packet in this response */ + + seg_num = 1; + p_sa_mad->seg_num = + cl_ntoh32(seg_num++); + p_sa_mad->frag_flag = 1; /* Set bit 0 for first pkt */ + /* the payload length gets copied with the mad header above */ + } + + } else if (i < num_mads - 1) { /* Not last packet */ + /* First copy only the header */ + memcpy(&p_madt_struct->IBMad, p_mad, + IB_SA_MAD_HDR_SIZE); + /* Set the relevant fields in the SA_MAD_HEADER */ + p_sa_mad = + (ib_sa_mad_t_vM3 *) & p_madt_struct->IBMad; + p_sa_mad->payload_len = + cl_ntoh32(IB_SA_DATA_SIZE); + p_sa_mad->seg_num = cl_ntoh32(seg_num++); + p_sa_mad->frag_flag = 0; + /* Now copy the fragmented data */ + memcpy(((uint8_t *) & p_madt_struct->IBMad) + + IB_SA_MAD_HDR_SIZE, p_frag_data, + IB_SA_DATA_SIZE); + p_frag_data = p_frag_data + IB_SA_DATA_SIZE; + + } else if (i == num_mads - 1) { /* Last packet */ + /* First copy only the header */ + memcpy(&p_madt_struct->IBMad, p_mad, + IB_SA_MAD_HDR_SIZE); + /* Set the relevant fields in the SA_MAD_HEADER */ + p_sa_mad = + (ib_sa_mad_t_vM3 *) & p_madt_struct->IBMad; + p_sa_mad->seg_num = cl_ntoh32(seg_num++); + p_sa_mad->frag_flag = 4; /* Set Bit 2 for last pkt */ + p_sa_mad->payload_len = + cl_ntoh32(cl_ntoh32 + (((ib_sa_mad_t_vM3 *) p_mad)-> + payload_len) % IB_SA_DATA_SIZE); + /* Now copy the fragmented data */ + memcpy((((uint8_t *) & p_madt_struct->IBMad)) + + IB_SA_MAD_HDR_SIZE, p_frag_data, + cl_ntoh32(p_sa_mad->payload_len)); + p_frag_data = p_frag_data + IB_SA_DATA_SIZE; + + } + /* Post the MAD */ + Status = + p_umadt_obj->uMadtInterface. + uMadtPostSend(p_mad_bind_info->umadt_handle, + p_madt_struct, &destAddr); + if (Status != FSUCCESS) { + printf("uMadtPostSendMad: Status = <%d>\n", + Status); + return IB_ERROR; + } + + /* Release send MAD */ + Status = + p_umadt_obj->uMadtInterface. + uMadtReleaseSendMad(p_mad_bind_info->umadt_handle, + p_madt_struct); + if (Status != FSUCCESS) { + printf("uMadtReleaseSendMad: Status = <%d>\n", + Status); + return IB_ERROR; + } + } + } + return (IB_SUCCESS); +} + +/* //////////////////////////////////////////////////////////////////////// */ +/* See VendorAbstractMadIntf.h for info */ +/* //////////////////////////////////////////////////////////////////////// */ + +osm_bind_handle_t +osm_vendor_bind(IN osm_vendor_t * const p_vend, + IN osm_bind_info_t * const p_osm_bind_info, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vend_mad_recv_callback_t mad_recv_callback, + IN void *context) +{ + cl_status_t cl_status; + FSTATUS Status; /* GEN1 Status for Umadt */ + + mad_bind_info_t *p_mad_bind_info; + RegisterClassStruct *p_umadt_reg_class; + + umadt_obj_t *p_umadt_obj; + OSM_LOG_ENTER(((umadt_obj_t *) p_vend)->p_log); + + CL_ASSERT(p_vend); + + p_umadt_obj = (umadt_obj_t *) p_vend; + + /* Sanity check */ + CL_ASSERT(p_umadt_obj->init_done); + CL_ASSERT(p_osm_bind_info); + CL_ASSERT(p_mad_pool); + CL_ASSERT(mad_recv_callback); + + /* Allocate memory for registering the handle. */ + p_mad_bind_info = (mad_bind_info_t *) malloc(sizeof(*p_mad_bind_info)); + if (p_mad_bind_info) { + memset(p_mad_bind_info, 0, sizeof(*p_mad_bind_info)); + p_umadt_reg_class = &p_mad_bind_info->umadt_reg_class; + } + p_umadt_reg_class->PortGuid = cl_ntoh64(p_osm_bind_info->port_guid); + p_umadt_reg_class->ClassId = p_osm_bind_info->mad_class; + p_umadt_reg_class->ClassVersion = p_osm_bind_info->class_version; + p_umadt_reg_class->isResponder = p_osm_bind_info->is_responder; + p_umadt_reg_class->isTrapProcessor = p_osm_bind_info->is_trap_processor; + p_umadt_reg_class->isReportProcessor = + p_osm_bind_info->is_report_processor; + p_umadt_reg_class->SendQueueSize = p_osm_bind_info->send_q_size; + p_umadt_reg_class->RecvQueueSize = p_osm_bind_info->recv_q_size; + p_umadt_reg_class->NotifySendCompletion = TRUE; + + p_mad_bind_info->p_umadt_obj = p_umadt_obj; + p_mad_bind_info->p_mad_pool = p_mad_pool; + p_mad_bind_info->mad_recv_callback = mad_recv_callback; + p_mad_bind_info->client_context = context; + + /* register with Umadt for MAD interface */ + Status = p_umadt_obj->uMadtInterface.uMadtRegister(p_umadt_reg_class, + &p_mad_bind_info-> + umadt_handle); + if (Status != FSUCCESS) { + free(p_mad_bind_info); + OSM_LOG_EXIT(p_umadt_obj->p_log); + return (OSM_BIND_INVALID_HANDLE); + } + CL_ASSERT(p_mad_bind_info->umadt_handle); + /* */ + /* Start a worker thread to process receives. */ + /* */ + cl_thread_construct(&p_mad_bind_info->recv_processor_thread); + cl_status = cl_thread_init(&p_mad_bind_info->recv_processor_thread, + __mad_recv_processor, + (void *)p_mad_bind_info, "mad_recv_worker"); + CL_ASSERT(cl_status == CL_SUCCESS); + + cl_qlist_init(&p_mad_bind_info->trans_ctxt_list); + cl_spinlock_construct(&p_mad_bind_info->trans_ctxt_lock); + cl_spinlock_init(&p_mad_bind_info->trans_ctxt_lock); + cl_spinlock_construct(&p_mad_bind_info->timeout_list_lock); + cl_spinlock_init(&p_mad_bind_info->timeout_list_lock); + + cl_status = cl_timer_init(&p_mad_bind_info->timeout_timer, + __osm_vendor_timer_callback, + (void *)p_mad_bind_info); + CL_ASSERT(cl_status == CL_SUCCESS); + cl_qlist_init(&p_mad_bind_info->timeout_list); + /* */ + /* Insert the mad_reg_struct in list and return pointer to it as the handle */ + /* */ + cl_spinlock_acquire(&p_umadt_obj->register_lock); + + cl_qlist_insert_head(&p_umadt_obj->register_list, + &p_mad_bind_info->list_item); + + cl_spinlock_release(&p_umadt_obj->register_lock); + + /* + A timeout value of 0 means disable timeouts. + */ + if (p_umadt_obj->timeout) { + cl_timer_start(&p_mad_bind_info->timeout_timer, + DEFAULT_TIMER_INTERVAL_MSEC); + } + + OSM_LOG_EXIT(p_umadt_obj->p_log); + return ((osm_bind_handle_t) p_mad_bind_info); +} + +/********************************************************************** + **********************************************************************/ +void osm_vendor_unbind(IN osm_bind_handle_t h_bind) +{ + mad_bind_info_t *p_mad_bind_info; + umadt_obj_t *p_umadt_obj; + cl_list_item_t *p_list_item, *p_next_list_item; + + CL_ASSERT(h_bind); + p_mad_bind_info = (mad_bind_info_t *) h_bind; + p_umadt_obj = p_mad_bind_info->p_umadt_obj; + + /* sanity check */ + CL_ASSERT(p_umadt_obj); + CL_ASSERT(p_umadt_obj->init_done); + CL_ASSERT(__valid_mad_handle(p_mad_bind_info)); + + p_umadt_obj->uMadtInterface.uMadtDestroy(&p_mad_bind_info-> + umadt_handle); + cl_timer_destroy(&p_mad_bind_info->timeout_timer); + cl_thread_destroy(&p_mad_bind_info->recv_processor_thread); + + cl_spinlock_acquire(&p_mad_bind_info->trans_ctxt_lock); + p_list_item = cl_qlist_head(&p_mad_bind_info->trans_ctxt_list); + while (p_list_item != cl_qlist_end(&p_mad_bind_info->trans_ctxt_list)) { + p_next_list_item = cl_qlist_next(p_list_item); + cl_qlist_remove_item(&p_mad_bind_info->trans_ctxt_list, + p_list_item); + free(p_list_item); + p_list_item = p_next_list_item; + } + cl_spinlock_release(&p_mad_bind_info->trans_ctxt_lock); + + cl_spinlock_acquire(&p_mad_bind_info->timeout_list_lock); + p_list_item = cl_qlist_head(&p_mad_bind_info->timeout_list); + while (p_list_item != cl_qlist_end(&p_mad_bind_info->timeout_list)) { + p_next_list_item = cl_qlist_next(p_list_item); + cl_qlist_remove_item(&p_mad_bind_info->timeout_list, + p_list_item); + free(p_list_item); + p_list_item = p_next_list_item; + } + cl_spinlock_release(&p_mad_bind_info->timeout_list_lock); + + free(p_mad_bind_info); +} + +/********************************************************************** + **********************************************************************/ +void __mad_recv_processor(IN void *context) +{ + mad_bind_info_t *p_mad_bind_info = (mad_bind_info_t *) context; + umadt_obj_t *p_umadt_obj; + osm_madw_t *p_osm_madw = NULL; + osm_vend_wrap_t *p_vend_wrap = NULL; + osm_mad_addr_t osm_mad_addr = { 0 }; + cl_list_item_t *p_list_item; + void *transaction_context; + + FSTATUS Status; + MadtStruct *pRecvMad = NULL; + MadWorkCompletion *pRecvCmp = NULL; + + CL_ASSERT(context); + + p_mad_bind_info = (mad_bind_info_t *) context; + p_umadt_obj = p_mad_bind_info->p_umadt_obj; + /* PollFor a completion */ + /* if FNOTFOND, then wait for a completion then again poll and return the MAD */ + while (1) { + Status = + p_umadt_obj->uMadtInterface. + uMadtPollForRecvCompletion(p_mad_bind_info->umadt_handle, + &pRecvMad, &pRecvCmp); + if (Status != FSUCCESS) { + if (Status == FNOT_FOUND) { + /* Wait for a completion */ + Status = p_umadt_obj->uMadtInterface.uMadtWaitForAnyCompletion(p_mad_bind_info->umadt_handle, RECV_COMPLETION, 0x5000); /* 5 sec timeout */ + + if (Status == FTIMEOUT) { + continue; + } + CL_ASSERT(Status == FSUCCESS); + + Status = + p_umadt_obj->uMadtInterface. + uMadtPollForRecvCompletion(p_mad_bind_info-> + umadt_handle, + &pRecvMad, + &pRecvCmp); + if (Status != FSUCCESS) { + printf + (" mad_recv_worker: Error in PollForRecv returning <%x>\n", + Status); + CL_ASSERT(0); + } + } else { + printf + ("uMadtPollForRecvCompletion Status=<%x>\n", + Status); + CL_ASSERT(0); + } + } + CL_ASSERT(pRecvMad); + CL_ASSERT(pRecvCmp); + + if (((ib_sa_mad_t_vM3 *) (&pRecvMad->IBMad))->frag_flag & 0x20) { + /* Ignore the ACK packet */ + Status = + p_umadt_obj->uMadtInterface. + uMadtReleaseRecvMad(p_mad_bind_info->umadt_handle, + pRecvMad); + continue; + } + /* */ + /* Extract the return address to pass it on to the client */ + /* */ + osm_mad_addr.dest_lid = pRecvCmp->AddressInfo.DestLid; + osm_mad_addr.path_bits = pRecvCmp->AddressInfo.PathBits; + osm_mad_addr.static_rate = pRecvCmp->AddressInfo.StaticRate; + + if (p_mad_bind_info->umadt_reg_class.ClassId == + IB_MCLASS_SUBN_LID + || p_mad_bind_info->umadt_reg_class.ClassId == + IB_MCLASS_SUBN_DIR) { + osm_mad_addr.addr_type.smi.source_lid = + pRecvCmp->AddressInfo.AddrType.Smi.SourceLid; + /* osm_mad_addr.addr_type.smi.port_num = pRecvCmp->AddressInfo.AddrType.Smi.PortNumber; */ + } else { + osm_mad_addr.addr_type.gsi.remote_qp = + pRecvCmp->AddressInfo.AddrType.Gsi.RemoteQpNumber; + osm_mad_addr.addr_type.gsi.remote_qkey = + pRecvCmp->AddressInfo.AddrType.Gsi.RemoteQkey; + osm_mad_addr.addr_type.gsi.pkey_ix = 0; + osm_mad_addr.addr_type.gsi.service_level = + pRecvCmp->AddressInfo.AddrType.Gsi.ServiceLevel; + osm_mad_addr.addr_type.gsi.global_route = + pRecvCmp->AddressInfo.AddrType.Gsi.GlobalRoute; + /* osm_mad_addr.addr_type.gsi.grh_info = pRecvCmp->AddressInfo.AddrType.Gsi.GRHInfo; */ + } + p_osm_madw = + osm_mad_pool_get_wrapper(p_mad_bind_info->p_mad_pool, + p_mad_bind_info, MAD_BLOCK_SIZE, + (ib_mad_t *) & pRecvMad->IBMad, + &osm_mad_addr); + CL_ASSERT(p_osm_madw); + p_vend_wrap = osm_madw_get_vend_ptr(p_osm_madw); + CL_ASSERT(p_vend_wrap); + p_vend_wrap->p_madt_struct = pRecvMad; + p_vend_wrap->direction = RECEIVE; + + osm_log(p_mad_bind_info->p_umadt_obj->p_log, OSM_LOG_DEBUG, + "__mad_recv_processor: " + "Received data p_osm_madw[0x%p].\n", p_osm_madw); + + /* */ + /* Do TID Processing. */ + /* */ + /* If R bit is set swap the TID */ + + cl_spinlock_acquire(&p_mad_bind_info->trans_ctxt_lock); + p_list_item = + cl_qlist_find_from_head(&p_mad_bind_info->trans_ctxt_list, + __match_tid_context, + &p_osm_madw->p_mad->trans_id); + + if (p_list_item == + cl_qlist_end(&p_mad_bind_info->trans_ctxt_list)) { + transaction_context = NULL; + } else { + transaction_context = + ((trans_context_t *) p_list_item)->context; + cl_qlist_remove_item(&p_mad_bind_info->trans_ctxt_list, + p_list_item); + free(p_list_item); + } + cl_spinlock_release(&p_mad_bind_info->trans_ctxt_lock); + ((ib_mad_t *) p_osm_madw->p_mad)->trans_id = + cl_ntoh64(p_osm_madw->p_mad->trans_id >> 24); + osm_log(p_mad_bind_info->p_umadt_obj->p_log, OSM_LOG_DEBUG, + "__mad_recv_processor: " + "Received data p_osm_madw [0x%p]" "\n\t\t\t\tTID[0x%" + PRIx64 ", context[%p]. \n", p_osm_madw, + ((ib_mad_t *) p_osm_madw->p_mad)->trans_id, + transaction_context); + + (*(p_mad_bind_info->mad_recv_callback)) (p_osm_madw, + p_mad_bind_info-> + client_context, + transaction_context); + + } +} + +/********************************************************************** + **********************************************************************/ + +cl_status_t +__match_tid_context(const cl_list_item_t * const p_list_item, void *context) +{ + if (((trans_context_t *) p_list_item)->trans_id == + *((uint64_t *) context)) + return CL_SUCCESS; + return CL_NOT_FOUND; +} + +/********************************************************************** + **********************************************************************/ + +boolean_t __valid_mad_handle(IN mad_bind_info_t * p_mad_bind_info) +{ + + umadt_obj_t *p_umadt_obj; + + p_umadt_obj = p_mad_bind_info->p_umadt_obj; + + cl_spinlock_acquire(&p_umadt_obj->register_lock); + if (!cl_is_item_in_qlist(&p_umadt_obj->register_list, + &p_mad_bind_info->list_item)) { + cl_spinlock_release(&p_umadt_obj->register_lock); + return FALSE; + } + cl_spinlock_release(&p_umadt_obj->register_lock); + return TRUE; +} + +void __osm_vendor_timer_callback(IN void *context) +{ + uint64_t current_time; + mad_bind_info_t *p_mad_bind_info; + umadt_obj_t *p_umadt_obj; + uint32_t timeout; + + cl_list_item_t *p_list_item, *p_next_list_item; + + CL_ASSERT(context); + + p_mad_bind_info = (mad_bind_info_t *) context; + p_umadt_obj = p_mad_bind_info->p_umadt_obj; + timeout = p_umadt_obj->timeout * 1000; + + current_time = cl_get_time_stamp(); + + cl_spinlock_acquire(&p_mad_bind_info->trans_ctxt_lock); + + p_list_item = cl_qlist_head(&p_mad_bind_info->trans_ctxt_list); + while (p_list_item != cl_qlist_end(&p_mad_bind_info->trans_ctxt_list)) { + + p_next_list_item = cl_qlist_next(p_list_item); + + /* DEFAULT_PKT_TIMEOUT is in milli seconds */ + if (current_time - ((trans_context_t *) p_list_item)->sent_time + > timeout) { + /* Add this transaction to the timeout_list */ + cl_qlist_remove_item(&p_mad_bind_info->trans_ctxt_list, + p_list_item); + cl_qlist_insert_tail(&p_mad_bind_info->timeout_list, + p_list_item); + } + + p_list_item = p_next_list_item; + } + + cl_spinlock_release(&p_mad_bind_info->trans_ctxt_lock); + + p_list_item = cl_qlist_head(&p_mad_bind_info->timeout_list); + while (p_list_item != cl_qlist_end(&p_mad_bind_info->timeout_list)) { + osm_log(p_mad_bind_info->p_umadt_obj->p_log, OSM_LOG_DEBUG, + "__osm_vendor_timer_callback: " + "Timing out transaction context [0x%p].\n", + ((trans_context_t *) p_list_item)->context); + + (*(p_mad_bind_info->mad_recv_callback)) (NULL, + p_mad_bind_info-> + client_context, + ((trans_context_t *) + p_list_item)-> + context); + + p_next_list_item = cl_qlist_next(p_list_item); + cl_qlist_remove_item(&p_mad_bind_info->timeout_list, + p_list_item); + free(p_list_item); + p_list_item = p_next_list_item; + } + + cl_timer_start(&p_mad_bind_info->timeout_timer, + DEFAULT_TIMER_INTERVAL_MSEC); + +} + +#endif /* OSM_VENDOR_INTF_UMADT */ diff --git a/contrib/ofed/management/opensm/man/opensm.8 b/contrib/ofed/management/opensm/man/opensm.8 new file mode 100644 index 000000000000..3000eaffd3cf --- /dev/null +++ b/contrib/ofed/management/opensm/man/opensm.8 @@ -0,0 +1,1012 @@ +.TH OPENSM 8 "June 13, 2008" "OpenIB" "OpenIB Management" + +.SH NAME +opensm \- InfiniBand subnet manager and administration (SM/SA) + +.SH SYNOPSIS +.B opensm +[\-\-version]] +[\-F | \-\-config ] +[\-c(reate-config) ] +[\-g(uid) ] +[\-l(mc) ] +[\-p(riority) ] +[\-smkey ] +[\-r(eassign_lids)] +[\-R | \-\-routing_engine ] +[\-A | \-\-ucast_cache] +[\-z | \-\-connect_roots] +[\-M | \-\-lid_matrix_file ] +[\-U | \-\-lfts_file ] +[\-S | \-\-sadb_file ] +[\-a | \-\-root_guid_file ] +[\-u | \-\-cn_guid_file ] +[\-X | \-\-guid_routing_order_file ] +[\-m | \-\-ids_guid_file ] +[\-o(nce)] +[\-s(weep) ] +[\-t(imeout) ] +[\-maxsmps ] +[\-console [off | local | socket | loopback]] +[\-console-port ] +[\-i(gnore-guids) ] +[\-f | \-\-log_file ] +[\-L | \-\-log_limit ] [\-e(rase_log_file)] +[\-P(config) ] +[\-N | \-\-no_part_enforce] +[\-Q | \-\-qos [\-Y | \-\-qos_policy_file ]] +[\-y | \-\-stay_on_fatal] +[\-B | \-\-daemon] +[\-I | \-\-inactive] +[\-\-perfmgr] +[\-\-perfmgr_sweep_time_s ] +[\-\-prefix_routes_file ] +[\-\-consolidate_ipv6_snm_req] +[\-v(erbose)] [\-V] [\-D ] [\-d(ebug) ] +[\-h(elp)] [\-?] + +.SH DESCRIPTION +.PP +opensm is an InfiniBand compliant Subnet Manager and Administration, +and runs on top of OpenIB. + +opensm provides an implementation of an InfiniBand Subnet Manager and +Administration. Such a software entity is required to run for in order +to initialize the InfiniBand hardware (at least one per each +InfiniBand subnet). + +opensm also now contains an experimental version of a performance +manager as well. + +opensm defaults were designed to meet the common case usage on clusters with up to a few hundred nodes. Thus, in this default mode, opensm will scan the IB +fabric, initialize it, and sweep occasionally for changes. + +opensm attaches to a specific IB port on the local machine and configures only +the fabric connected to it. (If the local machine has other IB ports, +opensm will ignore the fabrics connected to those other ports). If no port is +specified, it will select the first "best" available port. + +opensm can present the available ports and prompt for a port number to +attach to. + +By default, the run is logged to two files: /var/log/messages and /var/log/opensm.log. +The first file will register only general major events, whereas the second +will include details of reported errors. All errors reported in this second +file should be treated as indicators of IB fabric health issues. +(Note that when a fatal and non-recoverable error occurs, opensm will exit.) +Both log files should include the message "SUBNET UP" if opensm was able to +setup the subnet correctly. + +.SH OPTIONS + +.PP +.TP +\fB\-\-version\fR +Prints OpenSM version and exits. +.TP +\fB\-F\fR, \fB\-\-config\fR +The name of the OpenSM config file. When not specified +\fB\% @OPENSM_CONFIG_DIR@/@OPENSM_CONFIG_FILE@\fP will be used (if exists). +.TP +\fB\-c\fR, \fB\-\-create-config\fR +OpenSM will dump its configuration to the specified file and exit. +This is a way to generate OpenSM configuration file template. +.TP +\fB\-g\fR, \fB\-\-guid\fR +This option specifies the local port GUID value +with which OpenSM should bind. OpenSM may be +bound to 1 port at a time. +If GUID given is 0, OpenSM displays a list +of possible port GUIDs and waits for user input. +Without -g, OpenSM tries to use the default port. +.TP +\fB\-l\fR, \fB\-\-lmc\fR +This option specifies the subnet's LMC value. +The number of LIDs assigned to each port is 2^LMC. +The LMC value must be in the range 0-7. +LMC values > 0 allow multiple paths between ports. +LMC values > 0 should only be used if the subnet +topology actually provides multiple paths between +ports, i.e. multiple interconnects between switches. +Without -l, OpenSM defaults to LMC = 0, which allows +one path between any two ports. +.TP +\fB\-p\fR, \fB\-\-priority\fR +This option specifies the SM\'s PRIORITY. +This will effect the handover cases, where master +is chosen by priority and GUID. Range goes from 0 +(default and lowest priority) to 15 (highest). +.TP +\fB\-smkey\fR +This option specifies the SM\'s SM_Key (64 bits). +This will effect SM authentication. +Note that OpenSM version 3.2.1 and below used the default value '1' +in a host byte order, it is fixed now but you may need this option to +interoperate with old OpenSM running on a little endian machine. +.TP +\fB\-r\fR, \fB\-\-reassign_lids\fR +This option causes OpenSM to reassign LIDs to all +end nodes. Specifying -r on a running subnet +may disrupt subnet traffic. +Without -r, OpenSM attempts to preserve existing +LID assignments resolving multiple use of same LID. +.TP +\fB\-R\fR, \fB\-\-routing_engine\fR +This option chooses routing engine(s) to use instead of Min Hop +algorithm (default). Multiple routing engines can be specified +separated by commas so that specific ordering of routing algorithms +will be tried if earlier routing engines fail. +Supported engines: minhop, updn, file, ftree, lash, dor +.TP +\fB\-A\fR, \fB\-\-ucast_cache\fR +This option enables unicast routing cache and prevents routing +recalculation (which is a heavy task in a large cluster) when +there was no topology change detected during the heavy sweep, or +when the topology change does not require new routing calculation, +e.g. when one or more CAs/RTRs/leaf switches going down, or one or +more of these nodes coming back after being down. +A very common case that is handled by the unicast routing cache +is host reboot, which otherwise would cause two full routing +recalculations: one when the host goes down, and the other when +the host comes back online. +.TP +\fB\-z\fR, \fB\-\-connect_roots\fR +This option enforces a routing engine (currently up/down +only) to make connectivity between root switches and in +this way to be fully IBA complaint. In many cases this can +violate "pure" deadlock free algorithm, so use it carefully. +.TP +\fB\-M\fR, \fB\-\-lid_matrix_file\fR +This option specifies the name of the lid matrix dump file +from where switch lid matrices (min hops tables will be +loaded. +.TP +\fB\-U\fR, \fB\-\-lfts_file\fR +This option specifies the name of the LFTs file +from where switch forwarding tables will be loaded. +.TP +\fB\-S\fR, \fB\-\-sadb_file\fR +This option specifies the name of the SA DB dump file +from where SA database will be loaded. +.TP +\fB\-a\fR, \fB\-\-root_guid_file\fR +Set the root nodes for the Up/Down or Fat-Tree routing +algorithm to the guids provided in the given file (one to a line). +.TP +\fB\-u\fR, \fB\-\-cn_guid_file\fR +Set the compute nodes for the Fat-Tree routing algorithm +to the guids provided in the given file (one to a line). +.TP +\fB\-m\fR, \fB\-\-ids_guid_file\fR +Name of the map file with set of the IDs which will be used +by Up/Down routing algorithm instead of node GUIDs +(format: per line). +.TP +\fB\-X\fR, \fB\-\-guid_routing_order_file\fR +Set the order port guids will be routed for the MinHop +and Up/Down routing algorithms to the guids provided in the +given file (one to a line). +.TP +\fB\-o\fR, \fB\-\-once\fR +This option causes OpenSM to configure the subnet +once, then exit. Ports remain in the ACTIVE state. +.TP +\fB\-s\fR, \fB\-\-sweep\fR +This option specifies the number of seconds between +subnet sweeps. Specifying -s 0 disables sweeping. +Without -s, OpenSM defaults to a sweep interval of +10 seconds. +.TP +\fB\-t\fR, \fB\-\-timeout\fR +This option specifies the time in milliseconds +used for transaction timeouts. +Specifying -t 0 disables timeouts. +Without -t, OpenSM defaults to a timeout value of +200 milliseconds. +.TP +\fB\-maxsmps\fR +This option specifies the number of VL15 SMP MADs +allowed on the wire at any one time. +Specifying -maxsmps 0 allows unlimited outstanding +SMPs. +Without -maxsmps, OpenSM defaults to a maximum of +4 outstanding SMPs. +.TP +\fB\-console [off | local | socket | loopback]\fR +This option brings up the OpenSM console (default off). +Note that the socket and loopback options will only be available +if OpenSM was built with --enable-console-socket. +.TP +\fB\-console-port\fR +Specify an alternate telnet port for the socket console (default 10000). +Note that this option only appears if OpenSM was built with +--enable-console-socket. +.TP +\fB\-i\fR, \fB\-ignore-guids\fR +This option provides the means to define a set of ports +(by node guid and port number) that will be ignored by the link load +equalization algorithm. +.TP +\fB\-x\fR, \fB\-\-honor_guid2lid\fR +This option forces OpenSM to honor the guid2lid file, +when it comes out of Standby state, if such file exists +under OSM_CACHE_DIR, and is valid. +By default, this is FALSE. +.TP +\fB\-f\fR, \fB\-\-log_file\fR +This option defines the log to be the given file. +By default, the log goes to /var/log/opensm.log. +For the log to go to standard output use -f stdout. +.TP +\fB\-L\fR, \fB\-\-log_limit\fR +This option defines maximal log file size in MB. When +specified the log file will be truncated upon reaching +this limit. +.TP +\fB\-e\fR, \fB\-\-erase_log_file\fR +This option will cause deletion of the log file +(if it previously exists). By default, the log file +is accumulative. +.TP +\fB\-P\fR, \fB\-\-Pconfig\fR +This option defines the optional partition configuration file. +The default name is \fB\%@OPENSM_CONFIG_DIR@/@PARTITION_CONFIG_FILE@\fP. +.TP +\fB\-\-prefix_routes_file\fR +Prefix routes control how the SA responds to path record queries for +off-subnet DGIDs. By default, the SA fails such queries. The +.B PREFIX ROUTES +section below describes the format of the configuration file. +The default path is \fB\%@OPENSM_CONFIG_DIR@/prefix\-routes.conf\fP. +.TP +\fB\-Q\fR, \fB\-\-qos\fR +This option enables QoS setup. It is disabled by default. +.TP +\fB\-Y\fR, \fB\-\-qos_policy_file\fR +This option defines the optional QoS policy file. The default +name is \fB\%@OPENSM_CONFIG_DIR@/@QOS_POLICY_FILE@\fP. +.TP +\fB\-N\fR, \fB\-\-no_part_enforce\fR +This option disables partition enforcement on switch external ports. +.TP +\fB\-y\fR, \fB\-\-stay_on_fatal\fR +This option will cause SM not to exit on fatal initialization +issues: if SM discovers duplicated guids or a 12x link with +lane reversal badly configured. +By default, the SM will exit on these errors. +.TP +\fB\-B\fR, \fB\-\-daemon\fR +Run in daemon mode - OpenSM will run in the background. +.TP +\fB\-I\fR, \fB\-\-inactive\fR +Start SM in inactive rather than init SM state. This +option can be used in conjunction with the perfmgr so as to +run a standalone performance manager without SM/SA. However, +this is NOT currently implemented in the performance manager. +.TP +\fB\-perfmgr\fR +Enable the perfmgr. Only takes effect if --enable-perfmgr was specified at +configure time. +.TP +\fB\-perfmgr_sweep_time_s\fR +Specify the sweep time for the performance manager in seconds +(default is 180 seconds). Only takes +effect if --enable-perfmgr was specified at configure time. +.TP +.BI --consolidate_ipv6_snm_req +Consolidate IPv6 Solicited Node Multicast group join requests into one +multicast group per MGID PKey. +.TP +\fB\-v\fR, \fB\-\-verbose\fR +This option increases the log verbosity level. +The -v option may be specified multiple times +to further increase the verbosity level. +See the -D option for more information about +log verbosity. +.TP +\fB\-V\fR +This option sets the maximum verbosity level and +forces log flushing. +The -V option is equivalent to \'-D 0xFF -d 2\'. +See the -D option for more information about +log verbosity. +.TP +\fB\-D\fR +This option sets the log verbosity level. +A flags field must follow the -D option. +A bit set/clear in the flags enables/disables a +specific log level as follows: + + BIT LOG LEVEL ENABLED + ---- ----------------- + 0x01 - ERROR (error messages) + 0x02 - INFO (basic messages, low volume) + 0x04 - VERBOSE (interesting stuff, moderate volume) + 0x08 - DEBUG (diagnostic, high volume) + 0x10 - FUNCS (function entry/exit, very high volume) + 0x20 - FRAMES (dumps all SMP and GMP frames) + 0x40 - ROUTING (dump FDB routing information) + 0x80 - currently unused. + +Without -D, OpenSM defaults to ERROR + INFO (0x3). +Specifying -D 0 disables all messages. +Specifying -D 0xFF enables all messages (see -V). +High verbosity levels may require increasing +the transaction timeout with the -t option. +.TP +\fB\-d\fR, \fB\-\-debug\fR +This option specifies a debug option. +These options are not normally needed. +The number following -d selects the debug +option to enable as follows: + + OPT Description + --- ----------------- + -d0 - Ignore other SM nodes + -d1 - Force single threaded dispatching + -d2 - Force log flushing after each log message + -d3 - Disable multicast support +.TP +\fB\-h\fR, \fB\-\-help\fR +Display this usage info then exit. +.TP +\fB\-?\fR +Display this usage info then exit. + +.SH ENVIRONMENT VARIABLES +.PP +The following environment variables control opensm behavior: + +OSM_TMP_DIR - controls the directory in which the temporary files generated by +opensm are created. These files are: opensm-subnet.lst, opensm.fdbs, and +opensm.mcfdbs. By default, this directory is /var/log. + +OSM_CACHE_DIR - opensm stores certain data to the disk such that subsequent +runs are consistent. The default directory used is /var/cache/opensm. +The following file is included in it: + + guid2lid - stores the LID range assigned to each GUID + +.SH NOTES +.PP +When opensm receives a HUP signal, it starts a new heavy sweep as if a trap was received or a topology change was found. +.PP +Also, SIGUSR1 can be used to trigger a reopen of /var/log/opensm.log for +logrotate purposes. + +.SH PARTITION CONFIGURATION +.PP +The default name of OpenSM partitions configuration file is +\fB\%@OPENSM_CONFIG_DIR@/@PARTITION_CONFIG_FILE@\fP. The default may be changed by using +--Pconfig (-P) option with OpenSM. + +The default partition will be created by OpenSM unconditionally even +when partition configuration file does not exist or cannot be accessed. + +The default partition has P_Key value 0x7fff. OpenSM\'s port will have +full membership in default partition. All other end ports will have +partial membership. + +File Format + +Comments: + +Line content followed after \'#\' character is comment and ignored by +parser. + +General file format: + +: ; + +Partition Definition: + +[PartitionName][=PKey][,flag[=value]][,defmember=full|limited] + + PartitionName - string, will be used with logging. When omitted + empty string will be used. + PKey - P_Key value for this partition. Only low 15 bits will + be used. When omitted will be autogenerated. + flag - used to indicate IPoIB capability of this partition. + defmember=full|limited - specifies default membership for port guid + list. Default is limited. + +Currently recognized flags are: + + ipoib - indicates that this partition may be used for IPoIB, as + result IPoIB capable MC group will be created. + rate= - specifies rate for this IPoIB MC group + (default is 3 (10GBps)) + mtu= - specifies MTU for this IPoIB MC group + (default is 4 (2048)) + sl= - specifies SL for this IPoIB MC group + (default is 0) + scope= - specifies scope for this IPoIB MC group + (default is 2 (link local)). Multiple scope settings + are permitted for a partition. + +Note that values for rate, mtu, and scope should be specified as +defined in the IBTA specification (for example, mtu=4 for 2048). + +PortGUIDs list: + + PortGUID - GUID of partition member EndPort. Hexadecimal + numbers should start from 0x, decimal numbers + are accepted too. + full or limited - indicates full or limited membership for this + port. When omitted (or unrecognized) limited + membership is assumed. + +There are two useful keywords for PortGUID definition: + + - 'ALL' means all end ports in this subnet. + - 'SELF' means subnet manager's port. + +Empty list means no ports in this partition. + +Notes: + +White space is permitted between delimiters ('=', ',',':',';'). + +The line can be wrapped after ':' followed after Partition Definition and +between. + +PartitionName does not need to be unique, PKey does need to be unique. +If PKey is repeated then those partition configurations will be merged +and first PartitionName will be used (see also next note). + +It is possible to split partition configuration in more than one +definition, but then PKey should be explicitly specified (otherwise +different PKey values will be generated for those definitions). + +Examples: + + Default=0x7fff : ALL, SELF=full ; + + NewPartition , ipoib : 0x123456=full, 0x3456789034=limi, 0x2134af2306 ; + + YetAnotherOne = 0x300 : SELF=full ; + YetAnotherOne = 0x300 : ALL=limited ; + + ShareIO = 0x80 , defmember=full : 0x123451, 0x123452; + # 0x123453, 0x123454 will be limited + ShareIO = 0x80 : 0x123453, 0x123454, 0x123455=full; + # 0x123456, 0x123457 will be limited + ShareIO = 0x80 : defmember=limited : 0x123456, 0x123457, 0x123458=full; + ShareIO = 0x80 , defmember=full : 0x123459, 0x12345a; + ShareIO = 0x80 , defmember=full : 0x12345b, 0x12345c=limited, 0x12345d; + + +Note: + +The following rule is equivalent to how OpenSM used to run prior to the +partition manager: + + Default=0x7fff,ipoib:ALL=full; + +.SH QOS CONFIGURATION +.PP +There are a set of QoS related low-level configuration parameters. +All these parameter names are prefixed by "qos_" string. Here is a full +list of these parameters: + + qos_max_vls - The maximum number of VLs that will be on the subnet + qos_high_limit - The limit of High Priority component of VL + Arbitration table (IBA 7.6.9) + qos_vlarb_low - Low priority VL Arbitration table (IBA 7.6.9) + template + qos_vlarb_high - High priority VL Arbitration table (IBA 7.6.9) + template + Both VL arbitration templates are pairs of + VL and weight + qos_sl2vl - SL2VL Mapping table (IBA 7.6.6) template. It is + a list of VLs corresponding to SLs 0-15 (Note + that VL15 used here means drop this SL) + +Typical default values (hard-coded in OpenSM initialization) are: + + qos_max_vls 15 + qos_high_limit 0 + qos_vlarb_low 0:0,1:4,2:4,3:4,4:4,5:4,6:4,7:4,8:4,9:4,10:4,11:4,12:4,13:4,14:4 + qos_vlarb_high 0:4,1:0,2:0,3:0,4:0,5:0,6:0,7:0,8:0,9:0,10:0,11:0,12:0,13:0,14:0 + qos_sl2vl 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7 + +The syntax is compatible with rest of OpenSM configuration options and +values may be stored in OpenSM config file (cached options file). + +In addition to the above, we may define separate QoS configuration +parameters sets for various target types. As targets, we currently support +CAs, routers, switch external ports, and switch's enhanced port 0. The +names of such specialized parameters are prefixed by "qos__" +string. Here is a full list of the currently supported sets: + + qos_ca_ - QoS configuration parameters set for CAs. + qos_rtr_ - parameters set for routers. + qos_sw0_ - parameters set for switches' port 0. + qos_swe_ - parameters set for switches' external ports. + +Examples: + qos_sw0_max_vls=2 + qos_ca_sl2vl=0,1,2,3,5,5,5,12,12,0, + qos_swe_high_limit=0 + +.SH PREFIX ROUTES +.PP +Prefix routes control how the SA responds to path record queries for +off-subnet DGIDs. By default, the SA fails such queries. +Note that IBA does not specify how the SA should obtain off-subnet path +record information. +The prefix routes configuration is meant as a stop-gap until the +specification is completed. +.PP +Each line in the configuration file is a 64-bit prefix followed by a +64-bit GUID, separated by white space. +The GUID specifies the router port on the local subnet that will +handle the prefix. +Blank lines are ignored, as is anything between a \fB#\fP character +and the end of the line. +The prefix and GUID are both in hex, the leading 0x is optional. +Either, or both, can be wild-carded by specifying an +asterisk instead of an explicit prefix or GUID. +.PP +When responding to a path record query for an off-subnet DGID, +opensm searches for the first prefix match in the configuration file. +Therefore, the order of the lines in the configuration file is important: +a wild-carded prefix at the beginning of the configuration file renders +all subsequent lines useless. +If there is no match, then opensm fails the query. +It is legal to repeat prefixes in the configuration file, +opensm will return the path to the first available matching router. +A configuration file with a single line where both prefix and GUID +are wild-carded means that a path record query specifying any +off-subnet DGID should return a path to the first available router. +This configuration yields the same behaviour formerly achieved by +compiling opensm with -DROUTER_EXP. + +.SH ROUTING +.PP +OpenSM now offers five routing engines: + +1. Min Hop Algorithm - based on the minimum hops to each node where the +path length is optimized. + +2. UPDN Unicast routing algorithm - also based on the minimum hops to each +node, but it is constrained to ranking rules. This algorithm should be chosen +if the subnet is not a pure Fat Tree, and deadlock may occur due to a +loop in the subnet. + +3. Fat Tree Unicast routing algorithm - this algorithm optimizes routing +for congestion-free "shift" communication pattern. +It should be chosen if a subnet is a symmetrical or almost symmetrical +fat-tree of various types, not just K-ary-N-Trees: non-constant K, not +fully staffed, any Constant Bisectional Bandwidth (CBB) ratio. +Similar to UPDN, Fat Tree routing is constrained to ranking rules. + +4. LASH unicast routing algorithm - uses Infiniband virtual layers +(SL) to provide deadlock-free shortest-path routing while also +distributing the paths between layers. LASH is an alternative +deadlock-free topology-agnostic routing algorithm to the non-minimal +UPDN algorithm avoiding the use of a potentially congested root node. + +5. DOR Unicast routing algorithm - based on the Min Hop algorithm, but +avoids port equalization except for redundant links between the same +two switches. This provides deadlock free routes for hypercubes when +the fabric is cabled as a hypercube and for meshes when cabled as a +mesh (see details below). + +OpenSM also supports a file method which +can load routes from a table. See \'Modular Routing Engine\' for more +information on this. + +The basic routing algorithm is comprised of two stages: + +1. MinHop matrix calculation + How many hops are required to get from each port to each LID ? + The algorithm to fill these tables is different if you run standard +(min hop) or Up/Down. + For standard routing, a "relaxation" algorithm is used to propagate +min hop from every destination LID through neighbor switches + For Up/Down routing, a BFS from every target is used. The BFS tracks link +direction (up or down) and avoid steps that will perform up after a down +step was used. + +2. Once MinHop matrices exist, each switch is visited and for each target LID a +decision is made as to what port should be used to get to that LID. + This step is common to standard and Up/Down routing. Each port has a +counter counting the number of target LIDs going through it. + When there are multiple alternative ports with same MinHop to a LID, +the one with less previously assigned ports is selected. + If LMC > 0, more checks are added: Within each group of LIDs assigned to +same target port, + a. use only ports which have same MinHop + b. first prefer the ones that go to different systemImageGuid (then +the previous LID of the same LMC group) + c. if none - prefer those which go through another NodeGuid + d. fall back to the number of paths method (if all go to same node). + +Effect of Topology Changes + +OpenSM will preserve existing routing in any case where there is no change in +the fabric switches unless the -r (--reassign_lids) option is specified. + +-r +.br +--reassign_lids + This option causes OpenSM to reassign LIDs to all + end nodes. Specifying -r on a running subnet + may disrupt subnet traffic. + Without -r, OpenSM attempts to preserve existing + LID assignments resolving multiple use of same LID. + +If a link is added or removed, OpenSM does not recalculate +the routes that do not have to change. A route has to change +if the port is no longer UP or no longer the MinHop. When routing changes +are performed, the same algorithm for balancing the routes is invoked. + +In the case of using the file based routing, any topology changes are +currently ignored The 'file' routing engine just loads the LFTs from the file +specified, with no reaction to real topology. Obviously, this will not be able +to recheck LIDs (by GUID) for disconnected nodes, and LFTs for non-existent +switches will be skipped. Multicast is not affected by 'file' routing engine +(this uses min hop tables). + + +Min Hop Algorithm + +The Min Hop algorithm is invoked by default if no routing algorithm is +specified. It can also be invoked by specifying '-R minhop'. + +The Min Hop algorithm is divided into two stages: computation of +min-hop tables on every switch and LFT output port assignment. Link +subscription is also equalized with the ability to override based on +port GUID. The latter is supplied by: + +-i +.br +-ignore-guids + This option provides the means to define a set of ports + (by guid) that will be ignored by the link load + equalization algorithm. Note that only endports (CA, + switch port 0, and router ports) and not switch external + ports are supported. + +LMC awareness routes based on (remote) system or switch basis. + + +Purpose of UPDN Algorithm + +The UPDN algorithm is designed to prevent deadlocks from occurring in loops +of the subnet. A loop-deadlock is a situation in which it is no longer +possible to send data between any two hosts connected through the loop. As +such, the UPDN routing algorithm should be used if the subnet is not a pure +Fat Tree, and one of its loops may experience a deadlock (due, for example, +to high pressure). + +The UPDN algorithm is based on the following main stages: + +1. Auto-detect root nodes - based on the CA hop length from any switch in +the subnet, a statistical histogram is built for each switch (hop num vs +number of occurrences). If the histogram reflects a specific column (higher +than others) for a certain node, then it is marked as a root node. Since +the algorithm is statistical, it may not find any root nodes. The list of +the root nodes found by this auto-detect stage is used by the ranking +process stage. + + Note 1: The user can override the node list manually. + Note 2: If this stage cannot find any root nodes, and the user did + not specify a guid list file, OpenSM defaults back to the + Min Hop routing algorithm. + +2. Ranking process - All root switch nodes (found in stage 1) are assigned +a rank of 0. Using the BFS algorithm, the rest of the switch nodes in the +subnet are ranked incrementally. This ranking aids in the process of enforcing +rules that ensure loop-free paths. + +3. Min Hop Table setting - after ranking is done, a BFS algorithm is run from +each (CA or switch) node in the subnet. During the BFS process, the FDB table +of each switch node traversed by BFS is updated, in reference to the starting +node, based on the ranking rules and guid values. + +At the end of the process, the updated FDB tables ensure loop-free paths +through the subnet. + +Note: Up/Down routing does not allow LID routing communication between +switches that are located inside spine "switch systems". +The reason is that there is no way to allow a LID route between them +that does not break the Up/Down rule. +One ramification of this is that you cannot run SM on switches other +than the leaf switches of the fabric. + + +UPDN Algorithm Usage + +Activation through OpenSM + +Use '-R updn' option (instead of old '-u') to activate the UPDN algorithm. +Use '-a ' for adding an UPDN guid file that contains the +root nodes for ranking. +If the `-a' option is not used, OpenSM uses its auto-detect root nodes +algorithm. + +Notes on the guid list file: + +1. A valid guid file specifies one guid in each line. Lines with an invalid +format will be discarded. +.br +2. The user should specify the root switch guids. However, it is also +possible to specify CA guids; OpenSM will use the guid of the switch (if +it exists) that connects the CA to the subnet as a root node. + + +Fat-tree Routing Algorithm + +The fat-tree algorithm optimizes routing for "shift" communication pattern. +It should be chosen if a subnet is a symmetrical or almost symmetrical +fat-tree of various types. +It supports not just K-ary-N-Trees, by handling for non-constant K, +cases where not all leafs (CAs) are present, any CBB ratio. +As in UPDN, fat-tree also prevents credit-loop-deadlocks. + +If the root guid file is not provided ('-a' or '--root_guid_file' options), +the topology has to be pure fat-tree that complies with the following rules: + - Tree rank should be between two and eight (inclusively) + - Switches of the same rank should have the same number + of UP-going port groups*, unless they are root switches, + in which case the shouldn't have UP-going ports at all. + - Switches of the same rank should have the same number + of DOWN-going port groups, unless they are leaf switches. + - Switches of the same rank should have the same number + of ports in each UP-going port group. + - Switches of the same rank should have the same number + of ports in each DOWN-going port group. + - All the CAs have to be at the same tree level (rank). + +If the root guid file is provided, the topology doesn't have to be pure +fat-tree, and it should only comply with the following rules: + - Tree rank should be between two and eight (inclusively) + - All the Compute Nodes** have to be at the same tree level (rank). + Note that non-compute node CAs are allowed here to be at different + tree ranks. + +* ports that are connected to the same remote switch are referenced as +\'port group\'. + +** list of compute nodes (CNs) can be specified by \'-u\' or \'--cn_guid_file\' +OpenSM options. + +Topologies that do not comply cause a fallback to min hop routing. +Note that this can also occur on link failures which cause the topology +to no longer be "pure" fat-tree. + +Note that although fat-tree algorithm supports trees with non-integer CBB +ratio, the routing will not be as balanced as in case of integer CBB ratio. +In addition to this, although the algorithm allows leaf switches to have any +number of CAs, the closer the tree is to be fully populated, the more +effective the "shift" communication pattern will be. +In general, even if the root list is provided, the closer the topology to a +pure and symmetrical fat-tree, the more optimal the routing will be. + +The algorithm also dumps compute node ordering file (opensm-ftree-ca-order.dump) +in the same directory where the OpenSM log resides. This ordering file provides +the CN order that may be used to create efficient communication pattern, that +will match the routing tables. + +Activation through OpenSM + +Use '-R ftree' option to activate the fat-tree algorithm. +Use '-a ' to provide root nodes for ranking. If the `-a' option +is not used, routing algorithm will detect roots automatically. +Use '-u ' to provide the list of compute nodes. If the `-u' option +is not used, all the CAs are considered as compute nodes. + +Note: LMC > 0 is not supported by fat-tree routing. If this is +specified, the default routing algorithm is invoked instead. + + +LASH Routing Algorithm + +LASH is an acronym for LAyered SHortest Path Routing. It is a +deterministic shortest path routing algorithm that enables topology +agnostic deadlock-free routing within communication networks. + +When computing the routing function, LASH analyzes the network +topology for the shortest-path routes between all pairs of sources / +destinations and groups these paths into virtual layers in such a way +as to avoid deadlock. + +Note LASH analyzes routes and ensures deadlock freedom between switch +pairs. The link from HCA between and switch does not need virtual +layers as deadlock will not arise between switch and HCA. + +In more detail, the algorithm works as follows: + +1) LASH determines the shortest-path between all pairs of source / +destination switches. Note, LASH ensures the same SL is used for all +SRC/DST - DST/SRC pairs and there is no guarantee that the return +path for a given DST/SRC will be the reverse of the route SRC/DST. + +2) LASH then begins an SL assignment process where a route is assigned +to a layer (SL) if the addition of that route does not cause deadlock +within that layer. This is achieved by maintaining and analysing a +channel dependency graph for each layer. Once the potential addition +of a path could lead to deadlock, LASH opens a new layer and continues +the process. + +3) Once this stage has been completed, it is highly likely that the +first layers processed will contain more paths than the latter ones. +To better balance the use of layers, LASH moves paths from one layer +to another so that the number of paths in each layer averages out. + +Note, the implementation of LASH in opensm attempts to use as few layers +as possible. This number can be less than the number of actual layers +available. + +In general LASH is a very flexible algorithm. It can, for example, +reduce to Dimension Order Routing in certain topologies, it is topology +agnostic and fares well in the face of faults. + +It has been shown that for both regular and irregular topologies, LASH +outperforms Up/Down. The reason for this is that LASH distributes the +traffic more evenly through a network, avoiding the bottleneck issues +related to a root node and always routes shortest-path. + +The algorithm was developed by Simula Research Laboratory. + + +Use '-R lash -Q ' option to activate the LASH algorithm. + +Note: QoS support has to be turned on in order that SL/VL mappings are +used. + +Note: LMC > 0 is not supported by the LASH routing. If this is +specified, the default routing algorithm is invoked instead. + + +DOR Routing Algorithm + +The Dimension Order Routing algorithm is based on the Min Hop +algorithm and so uses shortest paths. Instead of spreading traffic +out across different paths with the same shortest distance, it chooses +among the available shortest paths based on an ordering of dimensions. +Each port must be consistently cabled to represent a hypercube +dimension or a mesh dimension. Paths are grown from a destination +back to a source using the lowest dimension (port) of available paths +at each step. This provides the ordering necessary to avoid deadlock. +When there are multiple links between any two switches, they still +represent only one dimension and traffic is balanced across them +unless port equalization is turned off. In the case of hypercubes, +the same port must be used throughout the fabric to represent the +hypercube dimension and match on both ends of the cable. In the case +of meshes, the dimension should consistently use the same pair of +ports, one port on one end of the cable, and the other port on the +other end, continuing along the mesh dimension. + +Use '-R dor' option to activate the DOR algorithm. + + +Routing References + +To learn more about deadlock-free routing, see the article +"Deadlock Free Message Routing in Multiprocessor Interconnection Networks" +by William J Dally and Charles L Seitz (1985). + +To learn more about the up/down algorithm, see the article +"Effective Strategy to Compute Forwarding Tables for InfiniBand Networks" +by Jose Carlos Sancho, Antonio Robles, and Jose Duato at the +Universidad Politecnica de Valencia. + +To learn more about LASH and the flexibility behind it, the requirement +for layers, performance comparisons to other algorithms, see the +following articles: + +"Layered Routing in Irregular Networks", Lysne et al, IEEE +Transactions on Parallel and Distributed Systems, VOL.16, No12, +December 2005. + +"Routing for the ASI Fabric Manager", Solheim et al. IEEE +Communications Magazine, Vol.44, No.7, July 2006. + +"Layered Shortest Path (LASH) Routing in Irregular System Area +Networks", Skeie et al. IEEE Computer Society Communication +Architecture for Clusters 2002. + + +Modular Routine Engine + +Modular routing engine structure allows for the ease of +"plugging" new routing modules. + +Currently, only unicast callbacks are supported. Multicast +can be added later. + +One existing routing module is up-down "updn", which may be +activated with '-R updn' option (instead of old '-u'). + +General usage is: +$ opensm -R 'module-name' + +There is also a trivial routing module which is able +to load LFT tables from a file. + +Main features: + + - this will load switch LFTs and/or LID matrices (min hops tables) + - this will load switch LFTs according to the path entries introduced + in the file + - no additional checks will be performed (such as "is port connected", + etc.) + - in case when fabric LIDs were changed this will try to reconstruct + LFTs correctly if endport GUIDs are represented in the file + (in order to disable this, GUIDs may be removed from the file + or zeroed) + +The file format is compatible with output of 'ibroute' util and for +whole fabric can be generated with dump_lfts.sh script. + +To activate file based routing module, use: + + opensm -R file -U /path/to/lfts_file + +If the lfts_file is not found or is in error, the default routing +algorithm is utilized. + +The ability to dump switch lid matrices (aka min hops tables) to file and +later to load these is also supported. + +The usage is similar to unicast forwarding tables loading from a lfts +file (introduced by 'file' routing engine), but new lid matrix file +name should be specified by -M or --lid_matrix_file option. For example: + + opensm -R file -M ./opensm-lid-matrix.dump + +The dump file is named \'opensm-lid-matrix.dump\' and will be generated +in standard opensm dump directory (/var/log by default) when +OSM_LOG_ROUTING logging flag is set. + +When routing engine 'file' is activated, but the lfts file is not specified +or not cannot be open default lid matrix algorithm will be used. + +There is also a switch forwarding tables dumper which generates +a file compatible with dump_lfts.sh output. This file can be used +as input for forwarding tables loading by 'file' routing engine. +Both or one of options -U and -M can be specified together with \'-R file\'. + +.SH FILES +.TP +.B @OPENSM_CONFIG_DIR@/@OPENSM_CONFIG_FILE@ +default OpenSM config file. + +.TP +.B @OPENSM_CONFIG_DIR@/@NODENAMEMAPFILE@ +default node name map file. See ibnetdiscover for more information on format. + +.TP +.B @OPENSM_CONFIG_DIR@/@PARTITION_CONFIG_FILE@ +default partition config file + +.TP +.B @OPENSM_CONFIG_DIR@/@QOS_POLICY_FILE@ +default QOS policy config file + +.TP +.B @OPENSM_CONFIG_DIR@/@PREFIX_ROUTES_FILE@ +default prefix routes file. + +.SH AUTHORS +.TP +Hal Rosenstock +.RI < hal.rosenstock@gmail.com > +.TP +Sasha Khapyorsky +.RI < sashak@voltaire.com > +.TP +Eitan Zahavi +.RI < eitan@mellanox.co.il > +.TP +Yevgeny Kliteynik +.RI < kliteyn@mellanox.co.il > +.TP +Thomas Sodring +.RI < tsodring@simula.no > +.TP +Ira Weiny +.RI < weiny2@llnl.gov > diff --git a/contrib/ofed/management/opensm/man/opensm.8.in b/contrib/ofed/management/opensm/man/opensm.8.in new file mode 100644 index 000000000000..3000eaffd3cf --- /dev/null +++ b/contrib/ofed/management/opensm/man/opensm.8.in @@ -0,0 +1,1012 @@ +.TH OPENSM 8 "June 13, 2008" "OpenIB" "OpenIB Management" + +.SH NAME +opensm \- InfiniBand subnet manager and administration (SM/SA) + +.SH SYNOPSIS +.B opensm +[\-\-version]] +[\-F | \-\-config ] +[\-c(reate-config) ] +[\-g(uid) ] +[\-l(mc) ] +[\-p(riority) ] +[\-smkey ] +[\-r(eassign_lids)] +[\-R | \-\-routing_engine ] +[\-A | \-\-ucast_cache] +[\-z | \-\-connect_roots] +[\-M | \-\-lid_matrix_file ] +[\-U | \-\-lfts_file ] +[\-S | \-\-sadb_file ] +[\-a | \-\-root_guid_file ] +[\-u | \-\-cn_guid_file ] +[\-X | \-\-guid_routing_order_file ] +[\-m | \-\-ids_guid_file ] +[\-o(nce)] +[\-s(weep) ] +[\-t(imeout) ] +[\-maxsmps ] +[\-console [off | local | socket | loopback]] +[\-console-port ] +[\-i(gnore-guids) ] +[\-f | \-\-log_file ] +[\-L | \-\-log_limit ] [\-e(rase_log_file)] +[\-P(config) ] +[\-N | \-\-no_part_enforce] +[\-Q | \-\-qos [\-Y | \-\-qos_policy_file ]] +[\-y | \-\-stay_on_fatal] +[\-B | \-\-daemon] +[\-I | \-\-inactive] +[\-\-perfmgr] +[\-\-perfmgr_sweep_time_s ] +[\-\-prefix_routes_file ] +[\-\-consolidate_ipv6_snm_req] +[\-v(erbose)] [\-V] [\-D ] [\-d(ebug) ] +[\-h(elp)] [\-?] + +.SH DESCRIPTION +.PP +opensm is an InfiniBand compliant Subnet Manager and Administration, +and runs on top of OpenIB. + +opensm provides an implementation of an InfiniBand Subnet Manager and +Administration. Such a software entity is required to run for in order +to initialize the InfiniBand hardware (at least one per each +InfiniBand subnet). + +opensm also now contains an experimental version of a performance +manager as well. + +opensm defaults were designed to meet the common case usage on clusters with up to a few hundred nodes. Thus, in this default mode, opensm will scan the IB +fabric, initialize it, and sweep occasionally for changes. + +opensm attaches to a specific IB port on the local machine and configures only +the fabric connected to it. (If the local machine has other IB ports, +opensm will ignore the fabrics connected to those other ports). If no port is +specified, it will select the first "best" available port. + +opensm can present the available ports and prompt for a port number to +attach to. + +By default, the run is logged to two files: /var/log/messages and /var/log/opensm.log. +The first file will register only general major events, whereas the second +will include details of reported errors. All errors reported in this second +file should be treated as indicators of IB fabric health issues. +(Note that when a fatal and non-recoverable error occurs, opensm will exit.) +Both log files should include the message "SUBNET UP" if opensm was able to +setup the subnet correctly. + +.SH OPTIONS + +.PP +.TP +\fB\-\-version\fR +Prints OpenSM version and exits. +.TP +\fB\-F\fR, \fB\-\-config\fR +The name of the OpenSM config file. When not specified +\fB\% @OPENSM_CONFIG_DIR@/@OPENSM_CONFIG_FILE@\fP will be used (if exists). +.TP +\fB\-c\fR, \fB\-\-create-config\fR +OpenSM will dump its configuration to the specified file and exit. +This is a way to generate OpenSM configuration file template. +.TP +\fB\-g\fR, \fB\-\-guid\fR +This option specifies the local port GUID value +with which OpenSM should bind. OpenSM may be +bound to 1 port at a time. +If GUID given is 0, OpenSM displays a list +of possible port GUIDs and waits for user input. +Without -g, OpenSM tries to use the default port. +.TP +\fB\-l\fR, \fB\-\-lmc\fR +This option specifies the subnet's LMC value. +The number of LIDs assigned to each port is 2^LMC. +The LMC value must be in the range 0-7. +LMC values > 0 allow multiple paths between ports. +LMC values > 0 should only be used if the subnet +topology actually provides multiple paths between +ports, i.e. multiple interconnects between switches. +Without -l, OpenSM defaults to LMC = 0, which allows +one path between any two ports. +.TP +\fB\-p\fR, \fB\-\-priority\fR +This option specifies the SM\'s PRIORITY. +This will effect the handover cases, where master +is chosen by priority and GUID. Range goes from 0 +(default and lowest priority) to 15 (highest). +.TP +\fB\-smkey\fR +This option specifies the SM\'s SM_Key (64 bits). +This will effect SM authentication. +Note that OpenSM version 3.2.1 and below used the default value '1' +in a host byte order, it is fixed now but you may need this option to +interoperate with old OpenSM running on a little endian machine. +.TP +\fB\-r\fR, \fB\-\-reassign_lids\fR +This option causes OpenSM to reassign LIDs to all +end nodes. Specifying -r on a running subnet +may disrupt subnet traffic. +Without -r, OpenSM attempts to preserve existing +LID assignments resolving multiple use of same LID. +.TP +\fB\-R\fR, \fB\-\-routing_engine\fR +This option chooses routing engine(s) to use instead of Min Hop +algorithm (default). Multiple routing engines can be specified +separated by commas so that specific ordering of routing algorithms +will be tried if earlier routing engines fail. +Supported engines: minhop, updn, file, ftree, lash, dor +.TP +\fB\-A\fR, \fB\-\-ucast_cache\fR +This option enables unicast routing cache and prevents routing +recalculation (which is a heavy task in a large cluster) when +there was no topology change detected during the heavy sweep, or +when the topology change does not require new routing calculation, +e.g. when one or more CAs/RTRs/leaf switches going down, or one or +more of these nodes coming back after being down. +A very common case that is handled by the unicast routing cache +is host reboot, which otherwise would cause two full routing +recalculations: one when the host goes down, and the other when +the host comes back online. +.TP +\fB\-z\fR, \fB\-\-connect_roots\fR +This option enforces a routing engine (currently up/down +only) to make connectivity between root switches and in +this way to be fully IBA complaint. In many cases this can +violate "pure" deadlock free algorithm, so use it carefully. +.TP +\fB\-M\fR, \fB\-\-lid_matrix_file\fR +This option specifies the name of the lid matrix dump file +from where switch lid matrices (min hops tables will be +loaded. +.TP +\fB\-U\fR, \fB\-\-lfts_file\fR +This option specifies the name of the LFTs file +from where switch forwarding tables will be loaded. +.TP +\fB\-S\fR, \fB\-\-sadb_file\fR +This option specifies the name of the SA DB dump file +from where SA database will be loaded. +.TP +\fB\-a\fR, \fB\-\-root_guid_file\fR +Set the root nodes for the Up/Down or Fat-Tree routing +algorithm to the guids provided in the given file (one to a line). +.TP +\fB\-u\fR, \fB\-\-cn_guid_file\fR +Set the compute nodes for the Fat-Tree routing algorithm +to the guids provided in the given file (one to a line). +.TP +\fB\-m\fR, \fB\-\-ids_guid_file\fR +Name of the map file with set of the IDs which will be used +by Up/Down routing algorithm instead of node GUIDs +(format: per line). +.TP +\fB\-X\fR, \fB\-\-guid_routing_order_file\fR +Set the order port guids will be routed for the MinHop +and Up/Down routing algorithms to the guids provided in the +given file (one to a line). +.TP +\fB\-o\fR, \fB\-\-once\fR +This option causes OpenSM to configure the subnet +once, then exit. Ports remain in the ACTIVE state. +.TP +\fB\-s\fR, \fB\-\-sweep\fR +This option specifies the number of seconds between +subnet sweeps. Specifying -s 0 disables sweeping. +Without -s, OpenSM defaults to a sweep interval of +10 seconds. +.TP +\fB\-t\fR, \fB\-\-timeout\fR +This option specifies the time in milliseconds +used for transaction timeouts. +Specifying -t 0 disables timeouts. +Without -t, OpenSM defaults to a timeout value of +200 milliseconds. +.TP +\fB\-maxsmps\fR +This option specifies the number of VL15 SMP MADs +allowed on the wire at any one time. +Specifying -maxsmps 0 allows unlimited outstanding +SMPs. +Without -maxsmps, OpenSM defaults to a maximum of +4 outstanding SMPs. +.TP +\fB\-console [off | local | socket | loopback]\fR +This option brings up the OpenSM console (default off). +Note that the socket and loopback options will only be available +if OpenSM was built with --enable-console-socket. +.TP +\fB\-console-port\fR +Specify an alternate telnet port for the socket console (default 10000). +Note that this option only appears if OpenSM was built with +--enable-console-socket. +.TP +\fB\-i\fR, \fB\-ignore-guids\fR +This option provides the means to define a set of ports +(by node guid and port number) that will be ignored by the link load +equalization algorithm. +.TP +\fB\-x\fR, \fB\-\-honor_guid2lid\fR +This option forces OpenSM to honor the guid2lid file, +when it comes out of Standby state, if such file exists +under OSM_CACHE_DIR, and is valid. +By default, this is FALSE. +.TP +\fB\-f\fR, \fB\-\-log_file\fR +This option defines the log to be the given file. +By default, the log goes to /var/log/opensm.log. +For the log to go to standard output use -f stdout. +.TP +\fB\-L\fR, \fB\-\-log_limit\fR +This option defines maximal log file size in MB. When +specified the log file will be truncated upon reaching +this limit. +.TP +\fB\-e\fR, \fB\-\-erase_log_file\fR +This option will cause deletion of the log file +(if it previously exists). By default, the log file +is accumulative. +.TP +\fB\-P\fR, \fB\-\-Pconfig\fR +This option defines the optional partition configuration file. +The default name is \fB\%@OPENSM_CONFIG_DIR@/@PARTITION_CONFIG_FILE@\fP. +.TP +\fB\-\-prefix_routes_file\fR +Prefix routes control how the SA responds to path record queries for +off-subnet DGIDs. By default, the SA fails such queries. The +.B PREFIX ROUTES +section below describes the format of the configuration file. +The default path is \fB\%@OPENSM_CONFIG_DIR@/prefix\-routes.conf\fP. +.TP +\fB\-Q\fR, \fB\-\-qos\fR +This option enables QoS setup. It is disabled by default. +.TP +\fB\-Y\fR, \fB\-\-qos_policy_file\fR +This option defines the optional QoS policy file. The default +name is \fB\%@OPENSM_CONFIG_DIR@/@QOS_POLICY_FILE@\fP. +.TP +\fB\-N\fR, \fB\-\-no_part_enforce\fR +This option disables partition enforcement on switch external ports. +.TP +\fB\-y\fR, \fB\-\-stay_on_fatal\fR +This option will cause SM not to exit on fatal initialization +issues: if SM discovers duplicated guids or a 12x link with +lane reversal badly configured. +By default, the SM will exit on these errors. +.TP +\fB\-B\fR, \fB\-\-daemon\fR +Run in daemon mode - OpenSM will run in the background. +.TP +\fB\-I\fR, \fB\-\-inactive\fR +Start SM in inactive rather than init SM state. This +option can be used in conjunction with the perfmgr so as to +run a standalone performance manager without SM/SA. However, +this is NOT currently implemented in the performance manager. +.TP +\fB\-perfmgr\fR +Enable the perfmgr. Only takes effect if --enable-perfmgr was specified at +configure time. +.TP +\fB\-perfmgr_sweep_time_s\fR +Specify the sweep time for the performance manager in seconds +(default is 180 seconds). Only takes +effect if --enable-perfmgr was specified at configure time. +.TP +.BI --consolidate_ipv6_snm_req +Consolidate IPv6 Solicited Node Multicast group join requests into one +multicast group per MGID PKey. +.TP +\fB\-v\fR, \fB\-\-verbose\fR +This option increases the log verbosity level. +The -v option may be specified multiple times +to further increase the verbosity level. +See the -D option for more information about +log verbosity. +.TP +\fB\-V\fR +This option sets the maximum verbosity level and +forces log flushing. +The -V option is equivalent to \'-D 0xFF -d 2\'. +See the -D option for more information about +log verbosity. +.TP +\fB\-D\fR +This option sets the log verbosity level. +A flags field must follow the -D option. +A bit set/clear in the flags enables/disables a +specific log level as follows: + + BIT LOG LEVEL ENABLED + ---- ----------------- + 0x01 - ERROR (error messages) + 0x02 - INFO (basic messages, low volume) + 0x04 - VERBOSE (interesting stuff, moderate volume) + 0x08 - DEBUG (diagnostic, high volume) + 0x10 - FUNCS (function entry/exit, very high volume) + 0x20 - FRAMES (dumps all SMP and GMP frames) + 0x40 - ROUTING (dump FDB routing information) + 0x80 - currently unused. + +Without -D, OpenSM defaults to ERROR + INFO (0x3). +Specifying -D 0 disables all messages. +Specifying -D 0xFF enables all messages (see -V). +High verbosity levels may require increasing +the transaction timeout with the -t option. +.TP +\fB\-d\fR, \fB\-\-debug\fR +This option specifies a debug option. +These options are not normally needed. +The number following -d selects the debug +option to enable as follows: + + OPT Description + --- ----------------- + -d0 - Ignore other SM nodes + -d1 - Force single threaded dispatching + -d2 - Force log flushing after each log message + -d3 - Disable multicast support +.TP +\fB\-h\fR, \fB\-\-help\fR +Display this usage info then exit. +.TP +\fB\-?\fR +Display this usage info then exit. + +.SH ENVIRONMENT VARIABLES +.PP +The following environment variables control opensm behavior: + +OSM_TMP_DIR - controls the directory in which the temporary files generated by +opensm are created. These files are: opensm-subnet.lst, opensm.fdbs, and +opensm.mcfdbs. By default, this directory is /var/log. + +OSM_CACHE_DIR - opensm stores certain data to the disk such that subsequent +runs are consistent. The default directory used is /var/cache/opensm. +The following file is included in it: + + guid2lid - stores the LID range assigned to each GUID + +.SH NOTES +.PP +When opensm receives a HUP signal, it starts a new heavy sweep as if a trap was received or a topology change was found. +.PP +Also, SIGUSR1 can be used to trigger a reopen of /var/log/opensm.log for +logrotate purposes. + +.SH PARTITION CONFIGURATION +.PP +The default name of OpenSM partitions configuration file is +\fB\%@OPENSM_CONFIG_DIR@/@PARTITION_CONFIG_FILE@\fP. The default may be changed by using +--Pconfig (-P) option with OpenSM. + +The default partition will be created by OpenSM unconditionally even +when partition configuration file does not exist or cannot be accessed. + +The default partition has P_Key value 0x7fff. OpenSM\'s port will have +full membership in default partition. All other end ports will have +partial membership. + +File Format + +Comments: + +Line content followed after \'#\' character is comment and ignored by +parser. + +General file format: + +: ; + +Partition Definition: + +[PartitionName][=PKey][,flag[=value]][,defmember=full|limited] + + PartitionName - string, will be used with logging. When omitted + empty string will be used. + PKey - P_Key value for this partition. Only low 15 bits will + be used. When omitted will be autogenerated. + flag - used to indicate IPoIB capability of this partition. + defmember=full|limited - specifies default membership for port guid + list. Default is limited. + +Currently recognized flags are: + + ipoib - indicates that this partition may be used for IPoIB, as + result IPoIB capable MC group will be created. + rate= - specifies rate for this IPoIB MC group + (default is 3 (10GBps)) + mtu= - specifies MTU for this IPoIB MC group + (default is 4 (2048)) + sl= - specifies SL for this IPoIB MC group + (default is 0) + scope= - specifies scope for this IPoIB MC group + (default is 2 (link local)). Multiple scope settings + are permitted for a partition. + +Note that values for rate, mtu, and scope should be specified as +defined in the IBTA specification (for example, mtu=4 for 2048). + +PortGUIDs list: + + PortGUID - GUID of partition member EndPort. Hexadecimal + numbers should start from 0x, decimal numbers + are accepted too. + full or limited - indicates full or limited membership for this + port. When omitted (or unrecognized) limited + membership is assumed. + +There are two useful keywords for PortGUID definition: + + - 'ALL' means all end ports in this subnet. + - 'SELF' means subnet manager's port. + +Empty list means no ports in this partition. + +Notes: + +White space is permitted between delimiters ('=', ',',':',';'). + +The line can be wrapped after ':' followed after Partition Definition and +between. + +PartitionName does not need to be unique, PKey does need to be unique. +If PKey is repeated then those partition configurations will be merged +and first PartitionName will be used (see also next note). + +It is possible to split partition configuration in more than one +definition, but then PKey should be explicitly specified (otherwise +different PKey values will be generated for those definitions). + +Examples: + + Default=0x7fff : ALL, SELF=full ; + + NewPartition , ipoib : 0x123456=full, 0x3456789034=limi, 0x2134af2306 ; + + YetAnotherOne = 0x300 : SELF=full ; + YetAnotherOne = 0x300 : ALL=limited ; + + ShareIO = 0x80 , defmember=full : 0x123451, 0x123452; + # 0x123453, 0x123454 will be limited + ShareIO = 0x80 : 0x123453, 0x123454, 0x123455=full; + # 0x123456, 0x123457 will be limited + ShareIO = 0x80 : defmember=limited : 0x123456, 0x123457, 0x123458=full; + ShareIO = 0x80 , defmember=full : 0x123459, 0x12345a; + ShareIO = 0x80 , defmember=full : 0x12345b, 0x12345c=limited, 0x12345d; + + +Note: + +The following rule is equivalent to how OpenSM used to run prior to the +partition manager: + + Default=0x7fff,ipoib:ALL=full; + +.SH QOS CONFIGURATION +.PP +There are a set of QoS related low-level configuration parameters. +All these parameter names are prefixed by "qos_" string. Here is a full +list of these parameters: + + qos_max_vls - The maximum number of VLs that will be on the subnet + qos_high_limit - The limit of High Priority component of VL + Arbitration table (IBA 7.6.9) + qos_vlarb_low - Low priority VL Arbitration table (IBA 7.6.9) + template + qos_vlarb_high - High priority VL Arbitration table (IBA 7.6.9) + template + Both VL arbitration templates are pairs of + VL and weight + qos_sl2vl - SL2VL Mapping table (IBA 7.6.6) template. It is + a list of VLs corresponding to SLs 0-15 (Note + that VL15 used here means drop this SL) + +Typical default values (hard-coded in OpenSM initialization) are: + + qos_max_vls 15 + qos_high_limit 0 + qos_vlarb_low 0:0,1:4,2:4,3:4,4:4,5:4,6:4,7:4,8:4,9:4,10:4,11:4,12:4,13:4,14:4 + qos_vlarb_high 0:4,1:0,2:0,3:0,4:0,5:0,6:0,7:0,8:0,9:0,10:0,11:0,12:0,13:0,14:0 + qos_sl2vl 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7 + +The syntax is compatible with rest of OpenSM configuration options and +values may be stored in OpenSM config file (cached options file). + +In addition to the above, we may define separate QoS configuration +parameters sets for various target types. As targets, we currently support +CAs, routers, switch external ports, and switch's enhanced port 0. The +names of such specialized parameters are prefixed by "qos__" +string. Here is a full list of the currently supported sets: + + qos_ca_ - QoS configuration parameters set for CAs. + qos_rtr_ - parameters set for routers. + qos_sw0_ - parameters set for switches' port 0. + qos_swe_ - parameters set for switches' external ports. + +Examples: + qos_sw0_max_vls=2 + qos_ca_sl2vl=0,1,2,3,5,5,5,12,12,0, + qos_swe_high_limit=0 + +.SH PREFIX ROUTES +.PP +Prefix routes control how the SA responds to path record queries for +off-subnet DGIDs. By default, the SA fails such queries. +Note that IBA does not specify how the SA should obtain off-subnet path +record information. +The prefix routes configuration is meant as a stop-gap until the +specification is completed. +.PP +Each line in the configuration file is a 64-bit prefix followed by a +64-bit GUID, separated by white space. +The GUID specifies the router port on the local subnet that will +handle the prefix. +Blank lines are ignored, as is anything between a \fB#\fP character +and the end of the line. +The prefix and GUID are both in hex, the leading 0x is optional. +Either, or both, can be wild-carded by specifying an +asterisk instead of an explicit prefix or GUID. +.PP +When responding to a path record query for an off-subnet DGID, +opensm searches for the first prefix match in the configuration file. +Therefore, the order of the lines in the configuration file is important: +a wild-carded prefix at the beginning of the configuration file renders +all subsequent lines useless. +If there is no match, then opensm fails the query. +It is legal to repeat prefixes in the configuration file, +opensm will return the path to the first available matching router. +A configuration file with a single line where both prefix and GUID +are wild-carded means that a path record query specifying any +off-subnet DGID should return a path to the first available router. +This configuration yields the same behaviour formerly achieved by +compiling opensm with -DROUTER_EXP. + +.SH ROUTING +.PP +OpenSM now offers five routing engines: + +1. Min Hop Algorithm - based on the minimum hops to each node where the +path length is optimized. + +2. UPDN Unicast routing algorithm - also based on the minimum hops to each +node, but it is constrained to ranking rules. This algorithm should be chosen +if the subnet is not a pure Fat Tree, and deadlock may occur due to a +loop in the subnet. + +3. Fat Tree Unicast routing algorithm - this algorithm optimizes routing +for congestion-free "shift" communication pattern. +It should be chosen if a subnet is a symmetrical or almost symmetrical +fat-tree of various types, not just K-ary-N-Trees: non-constant K, not +fully staffed, any Constant Bisectional Bandwidth (CBB) ratio. +Similar to UPDN, Fat Tree routing is constrained to ranking rules. + +4. LASH unicast routing algorithm - uses Infiniband virtual layers +(SL) to provide deadlock-free shortest-path routing while also +distributing the paths between layers. LASH is an alternative +deadlock-free topology-agnostic routing algorithm to the non-minimal +UPDN algorithm avoiding the use of a potentially congested root node. + +5. DOR Unicast routing algorithm - based on the Min Hop algorithm, but +avoids port equalization except for redundant links between the same +two switches. This provides deadlock free routes for hypercubes when +the fabric is cabled as a hypercube and for meshes when cabled as a +mesh (see details below). + +OpenSM also supports a file method which +can load routes from a table. See \'Modular Routing Engine\' for more +information on this. + +The basic routing algorithm is comprised of two stages: + +1. MinHop matrix calculation + How many hops are required to get from each port to each LID ? + The algorithm to fill these tables is different if you run standard +(min hop) or Up/Down. + For standard routing, a "relaxation" algorithm is used to propagate +min hop from every destination LID through neighbor switches + For Up/Down routing, a BFS from every target is used. The BFS tracks link +direction (up or down) and avoid steps that will perform up after a down +step was used. + +2. Once MinHop matrices exist, each switch is visited and for each target LID a +decision is made as to what port should be used to get to that LID. + This step is common to standard and Up/Down routing. Each port has a +counter counting the number of target LIDs going through it. + When there are multiple alternative ports with same MinHop to a LID, +the one with less previously assigned ports is selected. + If LMC > 0, more checks are added: Within each group of LIDs assigned to +same target port, + a. use only ports which have same MinHop + b. first prefer the ones that go to different systemImageGuid (then +the previous LID of the same LMC group) + c. if none - prefer those which go through another NodeGuid + d. fall back to the number of paths method (if all go to same node). + +Effect of Topology Changes + +OpenSM will preserve existing routing in any case where there is no change in +the fabric switches unless the -r (--reassign_lids) option is specified. + +-r +.br +--reassign_lids + This option causes OpenSM to reassign LIDs to all + end nodes. Specifying -r on a running subnet + may disrupt subnet traffic. + Without -r, OpenSM attempts to preserve existing + LID assignments resolving multiple use of same LID. + +If a link is added or removed, OpenSM does not recalculate +the routes that do not have to change. A route has to change +if the port is no longer UP or no longer the MinHop. When routing changes +are performed, the same algorithm for balancing the routes is invoked. + +In the case of using the file based routing, any topology changes are +currently ignored The 'file' routing engine just loads the LFTs from the file +specified, with no reaction to real topology. Obviously, this will not be able +to recheck LIDs (by GUID) for disconnected nodes, and LFTs for non-existent +switches will be skipped. Multicast is not affected by 'file' routing engine +(this uses min hop tables). + + +Min Hop Algorithm + +The Min Hop algorithm is invoked by default if no routing algorithm is +specified. It can also be invoked by specifying '-R minhop'. + +The Min Hop algorithm is divided into two stages: computation of +min-hop tables on every switch and LFT output port assignment. Link +subscription is also equalized with the ability to override based on +port GUID. The latter is supplied by: + +-i +.br +-ignore-guids + This option provides the means to define a set of ports + (by guid) that will be ignored by the link load + equalization algorithm. Note that only endports (CA, + switch port 0, and router ports) and not switch external + ports are supported. + +LMC awareness routes based on (remote) system or switch basis. + + +Purpose of UPDN Algorithm + +The UPDN algorithm is designed to prevent deadlocks from occurring in loops +of the subnet. A loop-deadlock is a situation in which it is no longer +possible to send data between any two hosts connected through the loop. As +such, the UPDN routing algorithm should be used if the subnet is not a pure +Fat Tree, and one of its loops may experience a deadlock (due, for example, +to high pressure). + +The UPDN algorithm is based on the following main stages: + +1. Auto-detect root nodes - based on the CA hop length from any switch in +the subnet, a statistical histogram is built for each switch (hop num vs +number of occurrences). If the histogram reflects a specific column (higher +than others) for a certain node, then it is marked as a root node. Since +the algorithm is statistical, it may not find any root nodes. The list of +the root nodes found by this auto-detect stage is used by the ranking +process stage. + + Note 1: The user can override the node list manually. + Note 2: If this stage cannot find any root nodes, and the user did + not specify a guid list file, OpenSM defaults back to the + Min Hop routing algorithm. + +2. Ranking process - All root switch nodes (found in stage 1) are assigned +a rank of 0. Using the BFS algorithm, the rest of the switch nodes in the +subnet are ranked incrementally. This ranking aids in the process of enforcing +rules that ensure loop-free paths. + +3. Min Hop Table setting - after ranking is done, a BFS algorithm is run from +each (CA or switch) node in the subnet. During the BFS process, the FDB table +of each switch node traversed by BFS is updated, in reference to the starting +node, based on the ranking rules and guid values. + +At the end of the process, the updated FDB tables ensure loop-free paths +through the subnet. + +Note: Up/Down routing does not allow LID routing communication between +switches that are located inside spine "switch systems". +The reason is that there is no way to allow a LID route between them +that does not break the Up/Down rule. +One ramification of this is that you cannot run SM on switches other +than the leaf switches of the fabric. + + +UPDN Algorithm Usage + +Activation through OpenSM + +Use '-R updn' option (instead of old '-u') to activate the UPDN algorithm. +Use '-a ' for adding an UPDN guid file that contains the +root nodes for ranking. +If the `-a' option is not used, OpenSM uses its auto-detect root nodes +algorithm. + +Notes on the guid list file: + +1. A valid guid file specifies one guid in each line. Lines with an invalid +format will be discarded. +.br +2. The user should specify the root switch guids. However, it is also +possible to specify CA guids; OpenSM will use the guid of the switch (if +it exists) that connects the CA to the subnet as a root node. + + +Fat-tree Routing Algorithm + +The fat-tree algorithm optimizes routing for "shift" communication pattern. +It should be chosen if a subnet is a symmetrical or almost symmetrical +fat-tree of various types. +It supports not just K-ary-N-Trees, by handling for non-constant K, +cases where not all leafs (CAs) are present, any CBB ratio. +As in UPDN, fat-tree also prevents credit-loop-deadlocks. + +If the root guid file is not provided ('-a' or '--root_guid_file' options), +the topology has to be pure fat-tree that complies with the following rules: + - Tree rank should be between two and eight (inclusively) + - Switches of the same rank should have the same number + of UP-going port groups*, unless they are root switches, + in which case the shouldn't have UP-going ports at all. + - Switches of the same rank should have the same number + of DOWN-going port groups, unless they are leaf switches. + - Switches of the same rank should have the same number + of ports in each UP-going port group. + - Switches of the same rank should have the same number + of ports in each DOWN-going port group. + - All the CAs have to be at the same tree level (rank). + +If the root guid file is provided, the topology doesn't have to be pure +fat-tree, and it should only comply with the following rules: + - Tree rank should be between two and eight (inclusively) + - All the Compute Nodes** have to be at the same tree level (rank). + Note that non-compute node CAs are allowed here to be at different + tree ranks. + +* ports that are connected to the same remote switch are referenced as +\'port group\'. + +** list of compute nodes (CNs) can be specified by \'-u\' or \'--cn_guid_file\' +OpenSM options. + +Topologies that do not comply cause a fallback to min hop routing. +Note that this can also occur on link failures which cause the topology +to no longer be "pure" fat-tree. + +Note that although fat-tree algorithm supports trees with non-integer CBB +ratio, the routing will not be as balanced as in case of integer CBB ratio. +In addition to this, although the algorithm allows leaf switches to have any +number of CAs, the closer the tree is to be fully populated, the more +effective the "shift" communication pattern will be. +In general, even if the root list is provided, the closer the topology to a +pure and symmetrical fat-tree, the more optimal the routing will be. + +The algorithm also dumps compute node ordering file (opensm-ftree-ca-order.dump) +in the same directory where the OpenSM log resides. This ordering file provides +the CN order that may be used to create efficient communication pattern, that +will match the routing tables. + +Activation through OpenSM + +Use '-R ftree' option to activate the fat-tree algorithm. +Use '-a ' to provide root nodes for ranking. If the `-a' option +is not used, routing algorithm will detect roots automatically. +Use '-u ' to provide the list of compute nodes. If the `-u' option +is not used, all the CAs are considered as compute nodes. + +Note: LMC > 0 is not supported by fat-tree routing. If this is +specified, the default routing algorithm is invoked instead. + + +LASH Routing Algorithm + +LASH is an acronym for LAyered SHortest Path Routing. It is a +deterministic shortest path routing algorithm that enables topology +agnostic deadlock-free routing within communication networks. + +When computing the routing function, LASH analyzes the network +topology for the shortest-path routes between all pairs of sources / +destinations and groups these paths into virtual layers in such a way +as to avoid deadlock. + +Note LASH analyzes routes and ensures deadlock freedom between switch +pairs. The link from HCA between and switch does not need virtual +layers as deadlock will not arise between switch and HCA. + +In more detail, the algorithm works as follows: + +1) LASH determines the shortest-path between all pairs of source / +destination switches. Note, LASH ensures the same SL is used for all +SRC/DST - DST/SRC pairs and there is no guarantee that the return +path for a given DST/SRC will be the reverse of the route SRC/DST. + +2) LASH then begins an SL assignment process where a route is assigned +to a layer (SL) if the addition of that route does not cause deadlock +within that layer. This is achieved by maintaining and analysing a +channel dependency graph for each layer. Once the potential addition +of a path could lead to deadlock, LASH opens a new layer and continues +the process. + +3) Once this stage has been completed, it is highly likely that the +first layers processed will contain more paths than the latter ones. +To better balance the use of layers, LASH moves paths from one layer +to another so that the number of paths in each layer averages out. + +Note, the implementation of LASH in opensm attempts to use as few layers +as possible. This number can be less than the number of actual layers +available. + +In general LASH is a very flexible algorithm. It can, for example, +reduce to Dimension Order Routing in certain topologies, it is topology +agnostic and fares well in the face of faults. + +It has been shown that for both regular and irregular topologies, LASH +outperforms Up/Down. The reason for this is that LASH distributes the +traffic more evenly through a network, avoiding the bottleneck issues +related to a root node and always routes shortest-path. + +The algorithm was developed by Simula Research Laboratory. + + +Use '-R lash -Q ' option to activate the LASH algorithm. + +Note: QoS support has to be turned on in order that SL/VL mappings are +used. + +Note: LMC > 0 is not supported by the LASH routing. If this is +specified, the default routing algorithm is invoked instead. + + +DOR Routing Algorithm + +The Dimension Order Routing algorithm is based on the Min Hop +algorithm and so uses shortest paths. Instead of spreading traffic +out across different paths with the same shortest distance, it chooses +among the available shortest paths based on an ordering of dimensions. +Each port must be consistently cabled to represent a hypercube +dimension or a mesh dimension. Paths are grown from a destination +back to a source using the lowest dimension (port) of available paths +at each step. This provides the ordering necessary to avoid deadlock. +When there are multiple links between any two switches, they still +represent only one dimension and traffic is balanced across them +unless port equalization is turned off. In the case of hypercubes, +the same port must be used throughout the fabric to represent the +hypercube dimension and match on both ends of the cable. In the case +of meshes, the dimension should consistently use the same pair of +ports, one port on one end of the cable, and the other port on the +other end, continuing along the mesh dimension. + +Use '-R dor' option to activate the DOR algorithm. + + +Routing References + +To learn more about deadlock-free routing, see the article +"Deadlock Free Message Routing in Multiprocessor Interconnection Networks" +by William J Dally and Charles L Seitz (1985). + +To learn more about the up/down algorithm, see the article +"Effective Strategy to Compute Forwarding Tables for InfiniBand Networks" +by Jose Carlos Sancho, Antonio Robles, and Jose Duato at the +Universidad Politecnica de Valencia. + +To learn more about LASH and the flexibility behind it, the requirement +for layers, performance comparisons to other algorithms, see the +following articles: + +"Layered Routing in Irregular Networks", Lysne et al, IEEE +Transactions on Parallel and Distributed Systems, VOL.16, No12, +December 2005. + +"Routing for the ASI Fabric Manager", Solheim et al. IEEE +Communications Magazine, Vol.44, No.7, July 2006. + +"Layered Shortest Path (LASH) Routing in Irregular System Area +Networks", Skeie et al. IEEE Computer Society Communication +Architecture for Clusters 2002. + + +Modular Routine Engine + +Modular routing engine structure allows for the ease of +"plugging" new routing modules. + +Currently, only unicast callbacks are supported. Multicast +can be added later. + +One existing routing module is up-down "updn", which may be +activated with '-R updn' option (instead of old '-u'). + +General usage is: +$ opensm -R 'module-name' + +There is also a trivial routing module which is able +to load LFT tables from a file. + +Main features: + + - this will load switch LFTs and/or LID matrices (min hops tables) + - this will load switch LFTs according to the path entries introduced + in the file + - no additional checks will be performed (such as "is port connected", + etc.) + - in case when fabric LIDs were changed this will try to reconstruct + LFTs correctly if endport GUIDs are represented in the file + (in order to disable this, GUIDs may be removed from the file + or zeroed) + +The file format is compatible with output of 'ibroute' util and for +whole fabric can be generated with dump_lfts.sh script. + +To activate file based routing module, use: + + opensm -R file -U /path/to/lfts_file + +If the lfts_file is not found or is in error, the default routing +algorithm is utilized. + +The ability to dump switch lid matrices (aka min hops tables) to file and +later to load these is also supported. + +The usage is similar to unicast forwarding tables loading from a lfts +file (introduced by 'file' routing engine), but new lid matrix file +name should be specified by -M or --lid_matrix_file option. For example: + + opensm -R file -M ./opensm-lid-matrix.dump + +The dump file is named \'opensm-lid-matrix.dump\' and will be generated +in standard opensm dump directory (/var/log by default) when +OSM_LOG_ROUTING logging flag is set. + +When routing engine 'file' is activated, but the lfts file is not specified +or not cannot be open default lid matrix algorithm will be used. + +There is also a switch forwarding tables dumper which generates +a file compatible with dump_lfts.sh output. This file can be used +as input for forwarding tables loading by 'file' routing engine. +Both or one of options -U and -M can be specified together with \'-R file\'. + +.SH FILES +.TP +.B @OPENSM_CONFIG_DIR@/@OPENSM_CONFIG_FILE@ +default OpenSM config file. + +.TP +.B @OPENSM_CONFIG_DIR@/@NODENAMEMAPFILE@ +default node name map file. See ibnetdiscover for more information on format. + +.TP +.B @OPENSM_CONFIG_DIR@/@PARTITION_CONFIG_FILE@ +default partition config file + +.TP +.B @OPENSM_CONFIG_DIR@/@QOS_POLICY_FILE@ +default QOS policy config file + +.TP +.B @OPENSM_CONFIG_DIR@/@PREFIX_ROUTES_FILE@ +default prefix routes file. + +.SH AUTHORS +.TP +Hal Rosenstock +.RI < hal.rosenstock@gmail.com > +.TP +Sasha Khapyorsky +.RI < sashak@voltaire.com > +.TP +Eitan Zahavi +.RI < eitan@mellanox.co.il > +.TP +Yevgeny Kliteynik +.RI < kliteyn@mellanox.co.il > +.TP +Thomas Sodring +.RI < tsodring@simula.no > +.TP +Ira Weiny +.RI < weiny2@llnl.gov > diff --git a/contrib/ofed/management/opensm/man/osmtest.8 b/contrib/ofed/management/opensm/man/osmtest.8 new file mode 100644 index 000000000000..c814b496a784 --- /dev/null +++ b/contrib/ofed/management/opensm/man/osmtest.8 @@ -0,0 +1,190 @@ +.TH OSMTEST 8 "August 11, 2008" "OpenIB" "OpenIB Management" + +.SH NAME +osmtest \- InfiniBand subnet manager and administration (SM/SA) test program + +.SH SYNOPSIS +.B osmtest +[\-f(low) ] [\-w(ait) ] [\-d(ebug) ] +[\-m(ax_lid) ] [\-g(uid)[=]] [-p(ort)] +[\-i(nventory) ] [\-s(tress)] [\-M(ulticast_Mode)] +[\-t(imeout) ] [\-l | \-\-log_file] [\-v] [\-vf ] +[\-h(elp)] + +.SH DESCRIPTION +.PP +osmtest is a test program to validate InfiniBand subnet manager and +administration (SM/SA). + +Default is to run all flows with the exception of the QoS flow. + +osmtest provides a test suite for opensm. + +osmtest has the following capabilities and testing flows: + +It creates an inventory file of all available Nodes, Ports, and PathRecords, +including all their fields. +It verifies the existing inventory, with all the object fields, and matches it +to a pre-saved one. +A Multicast Compliancy test. +An Event Forwarding test. +A Service Record registration test. +An RMPP stress test. +A Small SA Queries stress test. + +It is recommended that after installing opensm, the user should run +"osmtest -f c" to generate the inventory file, and +immediately afterwards run "osmtest -f a" to test OpenSM. + +Another recommendation for osmtest usage is to create the inventory when the +IB fabric is stable, and occasionally +run "osmtest -v" to verify that nothing has changed. + +.SH OPTIONS + +.PP +.TP +\fB\-f\fR, \fB\-\-flow\fR +This option directs osmtest to run a specific flow: + FLOW DESCRIPTION + c = create an inventory file with all nodes, ports and paths + a = run all validation tests (expecting an input inventory) + v = only validate the given inventory file + s = run service registration, deregistration, and lease test + e = run event forwarding test + f = flood the SA with queries according to the stress mode + m = multicast flow + q = QoS info: dump VLArb and SLtoVL tables + t = run trap 64/65 flow (this flow requires running of external tool) + (default is all flows except QoS) +.TP +\fB\-w\fR, \fB\-\-wait\fR +This option specifies the wait time for trap 64/65 in seconds +It is used only when running -f t - the trap 64/65 flow +(default to 10 sec) +.TP +\fB\-d\fR, \fB\-\-debug\fR +This option specifies a debug option. +These options are not normally needed. +The number following -d selects the debug +option to enable as follows: + + OPT Description + --- ----------------- + -d0 - Ignore other SM nodes + -d1 - Force single threaded dispatching + -d2 - Force log flushing after each log message + -d3 - Disable multicast support +.TP +\fB\-m\fR, \fB\-\-max_lid\fR +This option specifies the maximal LID number to be searched +for during inventory file build (default to 100) +.TP +\fB\-g\fR, \fB\-\-guid\fR +This option specifies the local port GUID value +with which OpenSM should bind. OpenSM may be +bound to 1 port at a time. +If GUID given is 0, OpenSM displays a list +of possible port GUIDs and waits for user input. +Without -g, OpenSM trys to use the default port. +.TP +\fB\-p\fR, \fB\-\-port\fR +This option displays a menu of possible local port GUID values +with which osmtest could bind +.TP +\fB\-i\fR, \fB\-\-inventory\fR +This option specifies the name of the inventory file +Normally, osmtest expects to find an inventory file, +which osmtest uses to validate real-time information +received from the SA during testing +If -i is not specified, osmtest defaults to the file +\'osmtest.dat\' +See -c option for related information +.TP +\fB\-s\fR, \fB\-\-stress\fR +This option runs the specified stress test instead +of the normal test suite +Stress test options are as follows: + + OPT Description + --- ----------------- + -s1 - Single-MAD response SA queries + -s2 - Multi-MAD (RMPP) response SA queries + -s3 - Multi-MAD (RMPP) Path Record SA queries + +Without -s, stress testing is not performed +.TP +\fB\-M\fR, \fB\-\-Multicast_Mode\fR +This option specify length of Multicast test: + + OPT Description + --- ----------------- + -M1 - Short Multicast Flow (default) - single mode + -M2 - Short Multicast Flow - multiple mode + -M3 - Long Multicast Flow - single mode + -M4 - Long Multicast Flow - multiple mode + +Single mode - Osmtest is tested alone, with no other +apps that interact with OpenSM MC + +Multiple mode - Could be run with other apps using MC with +OpenSM. Without -M, default flow testing is performed +.TP +\fB\-t\fR, \fB\-\-timeout\fR +This option specifies the time in milliseconds +used for transaction timeouts. +Specifying -t 0 disables timeouts. +Without -t, OpenSM defaults to a timeout value of +200 milliseconds. +.TP +\fB\-l\fR, \fB\-\-log_file\fR +This option defines the log to be the given file. +By default the log goes to stdout. +.TP +\fB\-v\fR, \fB\-\-verbose\fR +This option increases the log verbosity level. +The -v option may be specified multiple times +to further increase the verbosity level. +See the -vf option for more information about. +log verbosity. +.TP +\fB\-V\fR +This option sets the maximum verbosity level and +forces log flushing. +The -V is equivalent to '-vf 0xFF -d 2'. +See the -vf option for more information about. +log verbosity. +.TP +\fB\-vf\fR +This option sets the log verbosity level. +A flags field must follow the -D option. +A bit set/clear in the flags enables/disables a +specific log level as follows: + + BIT LOG LEVEL ENABLED + ---- ----------------- + 0x01 - ERROR (error messages) + 0x02 - INFO (basic messages, low volume) + 0x04 - VERBOSE (interesting stuff, moderate volume) + 0x08 - DEBUG (diagnostic, high volume) + 0x10 - FUNCS (function entry/exit, very high volume) + 0x20 - FRAMES (dumps all SMP and GMP frames) + 0x40 - ROUTING (dump FDB routing information) + 0x80 - currently unused. + +Without -vf, osmtest defaults to ERROR + INFO (0x3) +Specifying -vf 0 disables all messages +Specifying -vf 0xFF enables all messages (see -V) +High verbosity levels may require increasing +the transaction timeout with the -t option +.TP +\fB\-h\fR, \fB\-\-help\fR +Display this usage info then exit. + +.SH AUTHORS +.TP +Hal Rosenstock +.RI < hal@xsigo.com > +.TP +Eitan Zahavi +.RI < eitan@mellanox.co.il > diff --git a/contrib/ofed/management/opensm/opensm.spec.in b/contrib/ofed/management/opensm/opensm.spec.in new file mode 100644 index 000000000000..9c23f47429a5 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm.spec.in @@ -0,0 +1,146 @@ +%define RELEASE @RELEASE@ +%define rel %{?CUSTOM_RELEASE} %{!?CUSTOM_RELEASE:%RELEASE} +%if %{?_with_console_socket:1}%{!?_with_console_socket:0} +%define _enable_console_socket --enable-console-socket +%endif +%if %{?_without_console_socket:1}%{!?_without_console_socket:0} +%define _disable_console_socket --disable-console-socket +%endif + +%if %{?_with_perf_mgr:1}%{!?_with_perf_mgr:0} +%define _enable_perf_mgr --enable-perf-mgr +%endif +%if %{?_without_perf_mgr:1}%{!?_without_perf_mgr:0} +%define _disable_perf_mgr --disable-perf-mgr +%endif + +%if %{?_with_event_plugin:1}%{!?_with_event_plugin:0} +%define _enable_event_plugin --enable-event-plugin +%endif +%if %{?_without_event_plugin:1}%{!?_without_event_plugin:0} +%define _disable_event_plugin --disable-event-plugin +%endif + +Summary: InfiniBand subnet manager and administration +Name: opensm +Version: @VERSION@ +Release: %rel%{?dist} +License: GPLv2 or BSD +Group: System Environment/Daemons +URL: http://openfabrics.org/ +Source: http://www.openfabrics.org/downloads/management/@TARBALL@ +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +BuildRequires: libibumad-devel, libtool +Requires: %{name}-libs = %{version}-%{release}, logrotate +Requires(post): /sbin/service, /sbin/chkconfig +Requires(preun): /sbin/chkconfig, /sbin/service + +%description +OpenSM provides an implementation of an InfiniBand Subnet Manager and +Administration. Such a software entity is required to run for in order +to initialize the InfiniBand hardware (at least one per each +InfiniBand subnet). + +%package libs +Summary: Libraries from the opensm package +Group: System Environment/Libraries +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig +Obsoletes: libopensm, libosmcomp, libosmvendor + +%description libs +Shared libraries that are part of the opensm package but are also used by +other applications. If you don't need opensm itself installed, these +libraries can be installed to satisfy dependencies of other applications. + +%package devel +Summary: Development files for OpenSM +Group: System Environment/Libraries +Requires: %{name}-libs = %{version}-%{release} libibumad-devel +Obsoletes: libopensm-devel, libosmcomp-devel, libosmvendor-devel + +%description devel +Header files for OpenSM. + +%package static +Summary: Static version of the opensm libraries +Group: System Environment/Libraries +Requires: %{name}-libs = %{version}-%{release} libibumad-devel + +%description static +Static version of the opensm libraries + +%prep +%setup -q + +%build +%configure \ + %{?_enable_console_socket} \ + %{?_disable_console_socket} \ + %{?_enable_perf_mgr} \ + %{?_disable_perf_mgr} \ + %{?_enable_event_plugin} \ + %{?_disable_event_plugin} +make %{?_smp_mflags} + +%install +rm -rf $RPM_BUILD_ROOT +make DESTDIR=$RPM_BUILD_ROOT install +rm -f $RPM_BUILD_ROOT%{_libdir}/*.la +etc=$RPM_BUILD_ROOT%{_sysconfdir} +mkdir -p ${RPM_BUILD_ROOT}/var/cache/opensm +if [ -f /etc/redhat-release -o -s /etc/redhat-release ]; then + REDHAT="redhat-" +else + REDHAT="" +fi +mkdir -p $etc/{init.d,logrotate.d} $etc/@OPENSM_CONFIG_SUB_DIR@ +install -m 755 scripts/${REDHAT}opensm.init $etc/init.d/opensmd +install -D -m 644 scripts/opensm.logrotate $etc/logrotate.d/opensm +install -m 755 scripts/sldd.sh $RPM_BUILD_ROOT%{_sbindir}/sldd.sh + +%clean +rm -rf $RPM_BUILD_ROOT + +%post +if [ $1 = 1 ]; then + /sbin/chkconfig --add opensmd +else + /sbin/service opensmd condrestart +fi + +%preun +if [ $1 = 0 ]; then + /sbin/service opensmd stop + /sbin/chkconfig --del opensmd + rm -f /var/cache/opensm/* +fi + +%post libs -p /sbin/ldconfig +%postun libs -p /sbin/ldconfig + +%files +%defattr(-,root,root,-) +%{_sbindir}/opensm +%{_sbindir}/osmtest +%{_mandir}/man8/* +%doc AUTHORS COPYING README doc/performance-manager-HOWTO.txt doc/QoS_management_in_OpenSM.txt doc/opensm_release_notes-3.2.txt +%{_sysconfdir}/init.d/opensmd +%{_sbindir}/sldd.sh +%config(noreplace) %{_sysconfdir}/logrotate.d/opensm +%dir /var/cache/opensm +%dir %{_sysconfdir}/@OPENSM_CONFIG_SUB_DIR@ + +%files libs +%defattr(-,root,root,-) +%{_libdir}/*.so.* + +%files devel +%defattr(-,root,root,-) +%{_includedir}/infiniband/* +%{_libdir}/*.so + +%files static +%defattr(-,root,root,-) +%{_libdir}/*.a + diff --git a/contrib/ofed/management/opensm/opensm/ChangeLog b/contrib/ofed/management/opensm/opensm/ChangeLog new file mode 100644 index 000000000000..97eb67ab0bb3 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/ChangeLog @@ -0,0 +1,115 @@ +2007-07-11 Hal Rosenstock + + * configure.in: Bump to version 2.2.1 + +2007-06-20 Hal Rosenstock + + * osm_helper.c: Add 3LeafNetworks and Xsigo to osm_get_manufacturer_str + +2007-06-15 Sasha Khapyorsky + + * osm_helper.c: Fix PortInfo:CapMask printing when CapMask is 0 + +2007-06-11 Sasha Khapyorsky + + * osm_helper.c: Remove OSM_SM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED + from __osm_sm_mgr_signal_str + +2007-06-06 Sasha Khapyorsky + + * osm_helper.c: More optimally deal with manufacturer strings + +2007-06-06 Hal Rosenstock + + * osm_helper.c: Add Sun to osm_get_manufacturer_str + +2007-06-04 Hal Rosenstock + + * osm_helper.c: Add 8x to __osm_lwa_str_fixed_width + +2007-05-07 Sasha Khapyorsky + + * osm_helper.c: Remove repeated strlen() calls + +2007-04-27 Ira K. Weiny + + * osm_helper.c: In osm_dump_notice, use ib_get_producer_type_str + for printing producer type + +2007-04-26 Hal Rosenstock + + * osm_helper.c: Clarify the proper usage of + osm_get_node_type_str_fixed_width to take uint8_t rather + than uint32_t for node_type argument + +2007-04-25 Yevgeny Kliteynik + + * osm_helper.c: Fix problematic usage of sprintf() when + source and destination strings overlap. + +2007-04-24 Albert L. Chu + + * osm_helper.c: In osm_get_node_type_str_fixed_width, fix + both range limit and endian of node type check + +2007-03-29 Hal Rosenstock + + * configure.in: Bump version to 2.2.0 + +2007-03-21 Sasha Khapyorsky + + * osm_log.c: Changed to support daemon mode + +2007-03-01 Hal Rosenstock + + * configure.in: Bump version to 2.1.2 + + * osm_helper.c: Eliminate extraneous comma in __osm_disp_msg_ string + for OSM_MSG_MAD_PORT_INFO + +2007-02-26 Sasha Khapyorsky + + * osm_log.c: Minor optimization to previous change to osm_log + for also flushing on OSM_LOG_SYS + +2007-02-26 Yevgeny Kliteynik + + * osm_log.c: In osm_log, flush log on OSM_LOG_SYS (as well + as OSM_LOG_ERROR) + +2007-02-20 Hal Rosenstock + + * configure.in: Bump version to 2.1.1 + + * osm_helper.c: In osm_dbg_get_capabilities_str, only display + Capability Mask if there are capabilities present + +2007-01-22 Hal Rosenstock + + * osm_helper.c: Change DR path format from [%X] to %d, + +2007-01-08 Sasha Khapyorsky + + * osm_log.c: Add osm_log_reopen_file API + +2006-12-22 Hal Rosenstock + + * osm_helper.c: Add osm_dump_switch_info_record API + +2006-11-03 Sasha Khapyorsky + + * osm_log.c: Add osm_log_printf API + +2006-10-30 Sasha Khapyorsky + + * osm_helper.c: Fix seg fault with strings which + might not be null terminated + +2006-10-18 Yevgeny Kliteynik + + * osm_log.c: Windows porting changes + +2006-09-19 Yevgeny Kliteynik + + * osm_log.c: Windows porting changes + diff --git a/contrib/ofed/management/opensm/opensm/Makefile.am b/contrib/ofed/management/opensm/opensm/Makefile.am new file mode 100644 index 000000000000..66fbccca03c4 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/Makefile.am @@ -0,0 +1,131 @@ + +INCLUDES = $(OSMV_INCLUDES) + +AM_CFLAGS = -Wall $(DBGFLAGS) -D_XOPEN_SOURCE=600 -D_BSD_SOURCE=1 + +lib_LTLIBRARIES = libopensm.la + +if DEBUG +DBGFLAGS = -ggdb -D_DEBUG_ +else +DBGFLAGS = -g +endif + +if HAVE_LD_VERSION_SCRIPT +libopensm_version_script = -Wl,--version-script=$(srcdir)/libopensm.map +else +libopensm_version_script = +endif + +opensm_api_version=$(shell grep LIBVERSION= $(srcdir)/libopensm.ver | sed 's/LIBVERSION=//') + +libopensm_la_SOURCES = osm_log.c osm_mad_pool.c osm_helper.c +libopensm_la_LDFLAGS = -version-info $(opensm_api_version) \ + -export-dynamic $(libopensm_version_script) +libopensm_la_DEPENDENCIES = $(srcdir)/libopensm.map + +sbin_PROGRAMS = opensm +opensm_DEPENDENCIES = libopensm.la +opensm_SOURCES = main.c osm_console_io.c osm_console.c osm_db_files.c \ + osm_db_pack.c osm_drop_mgr.c \ + osm_inform.c osm_lid_mgr.c osm_lin_fwd_rcv.c \ + osm_link_mgr.c osm_mcast_fwd_rcv.c \ + osm_mcast_mgr.c osm_mcast_tbl.c osm_mcm_info.c \ + osm_mcm_port.c osm_mtree.c osm_multicast.c osm_node.c \ + osm_node_desc_rcv.c osm_node_info_rcv.c \ + osm_opensm.c osm_pkey.c osm_pkey_mgr.c osm_pkey_rcv.c \ + osm_port.c osm_port_info_rcv.c \ + osm_remote_sm.c osm_req.c \ + osm_resp.c osm_sa.c osm_sa_class_port_info.c \ + osm_sa_informinfo.c osm_sa_lft_record.c osm_sa_mft_record.c \ + osm_sa_link_record.c osm_sa_mad_ctrl.c \ + osm_sa_mcmember_record.c osm_sa_node_record.c \ + osm_sa_path_record.c osm_sa_pkey_record.c \ + osm_sa_portinfo_record.c osm_sa_guidinfo_record.c \ + osm_sa_multipath_record.c \ + osm_sa_service_record.c osm_sa_slvl_record.c \ + osm_sa_sminfo_record.c osm_sa_vlarb_record.c \ + osm_sa_sw_info_record.c osm_service.c \ + osm_slvl_map_rcv.c osm_sm.c osm_sminfo_rcv.c \ + osm_sm_mad_ctrl.c osm_sm_state_mgr.c osm_state_mgr.c \ + osm_subnet.c osm_sw_info_rcv.c osm_switch.c \ + osm_prtn.c osm_prtn_config.c osm_qos.c osm_router.c \ + osm_trap_rcv.c osm_ucast_mgr.c osm_ucast_updn.c \ + osm_ucast_lash.c osm_ucast_file.c osm_ucast_ftree.c \ + osm_vl15intf.c osm_vl_arb_rcv.c \ + st.c osm_perfmgr.c osm_perfmgr_db.c \ + osm_event_plugin.c osm_dump.c osm_ucast_cache.c \ + osm_qos_parser_y.y osm_qos_parser_l.l osm_qos_policy.c + +AM_YFLAGS:= -d + +# we need to be able to load libraries from local build subtree before make install +# we always give precedence to local tree libs and then use the pre-installed ones. +opensm_LDADD = -L../complib -losmcomp -L../libvendor -losmvendor -L. -lopensm $(OSMV_LDADD) + +opensmincludedir = $(includedir)/infiniband/opensm + +opensminclude_HEADERS = \ + $(srcdir)/../include/opensm/osm_attrib_req.h \ + $(srcdir)/../include/opensm/osm_base.h \ + $(srcdir)/../include/opensm/osm_console.h \ + $(srcdir)/../include/opensm/osm_console_io.h \ + $(srcdir)/../include/opensm/osm_db.h \ + $(srcdir)/../include/opensm/osm_db_pack.h \ + $(srcdir)/../include/opensm/osm_event_plugin.h \ + $(srcdir)/../include/opensm/osm_errors.h \ + $(srcdir)/../include/opensm/osm_helper.h \ + $(srcdir)/../include/opensm/osm_inform.h \ + $(srcdir)/../include/opensm/osm_lid_mgr.h \ + $(srcdir)/../include/opensm/osm_log.h \ + $(srcdir)/../include/opensm/osm_mad_pool.h \ + $(srcdir)/../include/opensm/osm_madw.h \ + $(srcdir)/../include/opensm/osm_mcast_tbl.h \ + $(srcdir)/../include/opensm/osm_mcm_info.h \ + $(srcdir)/../include/opensm/osm_mcm_port.h \ + $(srcdir)/../include/opensm/osm_mtree.h \ + $(srcdir)/../include/opensm/osm_multicast.h \ + $(srcdir)/../include/opensm/osm_msgdef.h \ + $(srcdir)/../include/opensm/osm_node.h \ + $(srcdir)/../include/opensm/osm_opensm.h \ + $(srcdir)/../include/opensm/osm_partition.h \ + $(srcdir)/../include/opensm/osm_path.h \ + $(srcdir)/../include/opensm/osm_perfmgr.h \ + $(srcdir)/../include/opensm/osm_perfmgr_db.h \ + $(srcdir)/../include/opensm/osm_pkey.h \ + $(srcdir)/../include/opensm/osm_port.h \ + $(srcdir)/../include/opensm/osm_port_profile.h \ + $(srcdir)/../include/opensm/osm_prefix_route.h \ + $(srcdir)/../include/opensm/osm_qos_policy.h \ + $(srcdir)/../include/opensm/osm_remote_sm.h \ + $(srcdir)/../include/opensm/osm_router.h \ + $(srcdir)/../include/opensm/osm_sa.h \ + $(srcdir)/../include/opensm/osm_sa_mad_ctrl.h \ + $(srcdir)/../include/opensm/osm_service.h \ + $(srcdir)/../include/opensm/osm_sm.h \ + $(srcdir)/../include/opensm/osm_sm_mad_ctrl.h \ + $(srcdir)/../include/opensm/st.h \ + $(srcdir)/../include/opensm/osm_stats.h \ + $(srcdir)/../include/opensm/osm_subnet.h \ + $(srcdir)/../include/opensm/osm_switch.h \ + $(srcdir)/../include/opensm/osm_ucast_mgr.h \ + $(srcdir)/../include/opensm/osm_ucast_cache.h \ + $(srcdir)/../include/opensm/osm_vl15intf.h \ + $(top_builddir)/include/opensm/osm_version.h \ + $(top_builddir)/include/opensm/osm_config.h + +BUILT_SOURCES = osm_version osm_qos_parser_y.h +osm_version: + if [ -x $(top_srcdir)/../gen_ver.sh ] ; then \ + ver_file=$(top_builddir)/include/opensm/osm_version.h ; \ + osm_ver=`cat $$ver_file | sed -ne '/#define OSM_VERSION /s/^.*\"OpenSM \(.*\)\"$$/\1/p'` ; \ + ver=`$(top_srcdir)/../gen_ver.sh $(PACKAGE)` ; \ + if [ $$ver != $$osm_ver ] ; then \ + cat $$ver_file | sed -e '/#define OSM_VERSION /s/\"OpenSM .*\"/\"OpenSM '$$ver'\"/' > tmp_new_version ; \ + cat tmp_new_version > $$ver_file && rm -f tmp_new_version ; \ + fi ; \ + fi + +# files distributed as part of the srcdir +EXTRA_DIST = $(srcdir)/libopensm.map $(srcdir)/libopensm.ver \ + $(srcdir)/ChangeLog diff --git a/contrib/ofed/management/opensm/opensm/libopensm.map b/contrib/ofed/management/opensm/opensm/libopensm.map new file mode 100644 index 000000000000..7cd2abacce93 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/libopensm.map @@ -0,0 +1,59 @@ +OPENSM_1.5 { + global: + osm_log; + osm_log_msg_box; + osm_is_debug; + osm_log_init; + osm_log_init_v2; + osm_log_reopen_file; + osm_mad_pool_construct; + osm_mad_pool_destroy; + osm_mad_pool_init; + osm_mad_pool_get; + osm_mad_pool_put; + osm_mad_pool_get_wrapper; + osm_mad_pool_get_wrapper_raw; + ib_get_sa_method_str; + ib_get_sm_method_str; + ib_get_sm_attr_str; + ib_get_sa_attr_str; + ib_get_trap_str; + osm_dump_port_info; + osm_dump_portinfo_record; + osm_dump_guidinfo_record; + osm_dump_node_info; + osm_dump_node_record; + osm_dump_path_record; + osm_dump_multipath_record; + osm_dump_mc_record; + osm_dump_service_record; + osm_dump_inform_info; + osm_dump_inform_info_record; + osm_dump_link_record; + osm_dump_switch_info; + osm_dump_switch_info_record; + osm_dump_pkey_table; + osm_dump_slvl_map_table; + osm_dump_vl_arb_table; + osm_dump_sm_info; + osm_dump_sm_info_record; + osm_dump_notice; + osm_dump_dr_smp; + osm_dump_sa_mad; + osm_dump_dr_path; + osm_dump_smp_dr_path; + osm_dump_pkey_block; + osm_log_raw; + osm_get_sm_state_str; + osm_get_sm_signal_str; + osm_get_disp_msg_str; + osm_get_port_state_str_fixed_width; + osm_get_node_type_str_fixed_width; + osm_get_manufacturer_str; + osm_get_mtu_str; + osm_get_lwa_str; + osm_get_lsa_str; + osm_get_sm_mgr_signal_str; + osm_get_sm_mgr_state_str; + local: *; +}; diff --git a/contrib/ofed/management/opensm/opensm/libopensm.ver b/contrib/ofed/management/opensm/opensm/libopensm.ver new file mode 100644 index 000000000000..f552dd05169d --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/libopensm.ver @@ -0,0 +1,9 @@ +# In this file we track the current API version +# of the opensm common interface (and libraries) +# The version is built of the following +# tree numbers: +# API_REV:RUNNING_REV:AGE +# API_REV - advance on any added API +# RUNNING_REV - advance any change to the vendor files +# AGE - number of backward versions the API still supports +LIBVERSION=3:3:1 diff --git a/contrib/ofed/management/opensm/opensm/main.c b/contrib/ofed/management/opensm/opensm/main.c new file mode 100644 index 000000000000..999e92f19459 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/main.c @@ -0,0 +1,1027 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Command line interface for opensm. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +volatile unsigned int osm_exit_flag = 0; + +static volatile unsigned int osm_hup_flag = 0; +static volatile unsigned int osm_usr1_flag = 0; + +#define GUID_ARRAY_SIZE 64 +#define INVALID_GUID (0xFFFFFFFFFFFFFFFFULL) + +static void mark_exit_flag(int signum) +{ + if (!osm_exit_flag) + printf("OpenSM: Got signal %d - exiting...\n", signum); + osm_exit_flag = 1; +} + +static void mark_hup_flag(int signum) +{ + osm_hup_flag = 1; +} + +static void mark_usr1_flag(int signum) +{ + osm_usr1_flag = 1; +} + +static sigset_t saved_sigset; + +static void block_signals() +{ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGHUP); +#ifndef HAVE_OLD_LINUX_THREADS + sigaddset(&set, SIGUSR1); +#endif + pthread_sigmask(SIG_SETMASK, &set, &saved_sigset); +} + +static void setup_signals() +{ + struct sigaction act; + + sigemptyset(&act.sa_mask); + act.sa_handler = mark_exit_flag; + act.sa_flags = 0; + sigaction(SIGINT, &act, NULL); + sigaction(SIGTERM, &act, NULL); + act.sa_handler = mark_hup_flag; + sigaction(SIGHUP, &act, NULL); + sigaction(SIGCONT, &act, NULL); +#ifndef HAVE_OLD_LINUX_THREADS + act.sa_handler = mark_usr1_flag; + sigaction(SIGUSR1, &act, NULL); +#endif + pthread_sigmask(SIG_SETMASK, &saved_sigset, NULL); +} + +/********************************************************************** + **********************************************************************/ + +static void show_usage(void) +{ + printf("\n------- OpenSM - Usage and options ----------------------\n"); + printf("Usage: opensm [options]\n"); + printf("Options:\n"); + printf("--version\n Prints OpenSM version and exits.\n\n"); + printf("--config, -F \n" + " The name of the OpenSM config file. When not specified\n" + " " OSM_DEFAULT_CONFIG_FILE " will be used (if exists).\n\n"); + printf("--create-config, -c \n" + " OpenSM will dump its configuration to the specified file and exit.\n" + " This is a way to generate OpenSM configuration file template.\n\n"); + printf("--guid, -g \n" + " This option specifies the local port GUID value\n" + " with which OpenSM should bind. OpenSM may be\n" + " bound to 1 port at a time.\n" + " If GUID given is 0, OpenSM displays a list\n" + " of possible port GUIDs and waits for user input.\n" + " Without -g, OpenSM tries to use the default port.\n\n"); + printf("--lmc, -l \n" + " This option specifies the subnet's LMC value.\n" + " The number of LIDs assigned to each port is 2^LMC.\n" + " The LMC value must be in the range 0-7.\n" + " LMC values > 0 allow multiple paths between ports.\n" + " LMC values > 0 should only be used if the subnet\n" + " topology actually provides multiple paths between\n" + " ports, i.e. multiple interconnects between switches.\n" + " Without -l, OpenSM defaults to LMC = 0, which allows\n" + " one path between any two ports.\n\n"); + printf("--priority, -p \n" + " This option specifies the SM's PRIORITY.\n" + " This will effect the handover cases, where master\n" + " is chosen by priority and GUID. Range goes\n" + " from 0 (lowest priority) to 15 (highest).\n\n"); + printf("--smkey, -k \n" + " This option specifies the SM's SM_Key (64 bits).\n" + " This will effect SM authentication.\n" + " Note that OpenSM version 3.2.1 and below used the\n" + " default value '1' in a host byte order, it is fixed\n" + " now but you may need this option to interoperate\n" + " with old OpenSM running on a little endian machine.\n\n"); + printf("--reassign_lids, -r\n" + " This option causes OpenSM to reassign LIDs to all\n" + " end nodes. Specifying -r on a running subnet\n" + " may disrupt subnet traffic.\n" + " Without -r, OpenSM attempts to preserve existing\n" + " LID assignments resolving multiple use of same LID.\n\n"); + printf("--routing_engine, -R \n" + " This option chooses routing engine(s) to use instead of default\n" + " Min Hop algorithm. Multiple routing engines can be specified\n" + " separated by commas so that specific ordering of routing\n" + " algorithms will be tried if earlier routing engines fail.\n" + " Supported engines: updn, file, ftree, lash, dor\n\n"); + printf("--connect_roots, -z\n" + " This option enforces a routing engine (currently\n" + " up/down only) to make connectivity between root switches\n" + " and in this way be IBA compliant. In many cases,\n" + " this can violate \"pure\" deadlock free algorithm, so\n" + " use it carefully.\n\n"); + printf("--ucast_cache, -A\n" + " This option enables unicast routing cache to prevent\n" + " routing recalculation (which is a heavy task in a\n" + " large cluster) when there was no topology change\n" + " detected during the heavy sweep, or when the topology\n" + " change does not require new routing calculation,\n" + " e.g. in case of host reboot.\n" + " This option becomes very handy when the cluster size\n" + " is thousands of nodes.\n\n"); + printf("--lid_matrix_file, -M \n" + " This option specifies the name of the lid matrix dump file\n" + " from where switch lid matrices (min hops tables will be\n" + " loaded.\n\n"); + printf("--lfts_file, -U \n" + " This option specifies the name of the LFTs file\n" + " from where switch forwarding tables will be loaded.\n\n"); + printf("--sadb_file, -S \n" + " This option specifies the name of the SA DB dump file\n" + " from where SA database will be loaded.\n\n"); + printf("--root_guid_file, -a \n" + " Set the root nodes for the Up/Down or Fat-Tree routing\n" + " algorithm to the guids provided in the given file (one\n" + " to a line)\n" "\n"); + printf("--cn_guid_file, -u \n" + " Set the compute nodes for the Fat-Tree routing algorithm\n" + " to the guids provided in the given file (one to a line)\n\n"); + printf("--ids_guid_file, -m \n" + " Name of the map file with set of the IDs which will be used\n" + " by Up/Down routing algorithm instead of node GUIDs\n" + " (format: per line)\n\n"); + printf("--guid_routing_order_file, -X \n" + " Set the order port guids will be routed for the MinHop\n" + " and Up/Down routing algorithms to the guids provided in the\n" + " given file (one to a line)\n\n"); + printf("--once, -o\n" + " This option causes OpenSM to configure the subnet\n" + " once, then exit. Ports remain in the ACTIVE state.\n\n"); + printf("--sweep, -s \n" + " This option specifies the number of seconds between\n" + " subnet sweeps. Specifying -s 0 disables sweeping.\n" + " Without -s, OpenSM defaults to a sweep interval of\n" + " 10 seconds.\n\n"); + printf("--timeout, -t \n" + " This option specifies the time in milliseconds\n" + " used for transaction timeouts.\n" + " Specifying -t 0 disables timeouts.\n" + " Without -t, OpenSM defaults to a timeout value of\n" + " 200 milliseconds.\n\n"); + printf("--maxsmps, -n \n" + " This option specifies the number of VL15 SMP MADs\n" + " allowed on the wire at any one time.\n" + " Specifying --maxsmps 0 allows unlimited outstanding\n" + " SMPs.\n" + " Without --maxsmps, OpenSM defaults to a maximum of\n" + " 4 outstanding SMPs.\n\n"); + printf("--console, -q [off|local" +#ifdef ENABLE_OSM_CONSOLE_SOCKET + "|socket|loopback" +#endif + "]\n This option activates the OpenSM console (default off).\n\n"); +#ifdef ENABLE_OSM_CONSOLE_SOCKET + printf("--console-port, -C \n" + " Specify an alternate telnet port for the console (default %d).\n\n", + OSM_DEFAULT_CONSOLE_PORT); +#endif + printf("--ignore-guids, -i \n" + " This option provides the means to define a set of ports\n" + " (by guid) that will be ignored by the link load\n" + " equalization algorithm.\n\n"); + printf("--honor_guid2lid, -x\n" + " This option forces OpenSM to honor the guid2lid file,\n" + " when it comes out of Standby state, if such file exists\n" + " under OSM_CACHE_DIR, and is valid. By default, this is FALSE.\n\n"); + printf("--log_file, -f \n" + " This option defines the log to be the given file.\n" + " By default, the log goes to /var/log/opensm.log.\n" + " For the log to go to standard output use -f stdout.\n\n"); + printf("--log_limit, -L \n" + " This option defines maximal log file size in MB. When\n" + " specified the log file will be truncated upon reaching\n" + " this limit.\n\n"); + printf("--erase_log_file, -e\n" + " This option will cause deletion of the log file\n" + " (if it previously exists). By default, the log file\n" + " is accumulative.\n\n"); + printf("--Pconfig, -P \n" + " This option defines the optional partition configuration file.\n" + " The default name is \'" + OSM_DEFAULT_PARTITION_CONFIG_FILE "\'.\n\n"); + printf("--no_part_enforce, -N\n" + " This option disables partition enforcement on switch external ports.\n\n"); + printf("--qos, -Q\n" " This option enables QoS setup.\n\n"); + printf("--qos_policy_file, -Y \n" + " This option defines the optional QoS policy file.\n" + " The default name is \'" OSM_DEFAULT_QOS_POLICY_FILE + "\'.\n\n"); + printf("--stay_on_fatal, -y\n" + " This option will cause SM not to exit on fatal initialization\n" + " issues: if SM discovers duplicated guids or 12x link with\n" + " lane reversal badly configured.\n" + " By default, the SM will exit on these errors.\n\n"); + printf("--daemon, -B\n" + " Run in daemon mode - OpenSM will run in the background.\n\n"); + printf("--inactive, -I\n" + " Start SM in inactive rather than normal init SM state.\n\n"); +#ifdef ENABLE_OSM_PERF_MGR + printf("--perfmgr\n" " Start with PerfMgr enabled.\n\n"); + printf("--perfmgr_sweep_time_s \n" + " PerfMgr sweep interval in seconds.\n\n"); +#endif + printf("--prefix_routes_file \n" + " This option specifies the prefix routes file.\n" + " Prefix routes control how the SA responds to path record\n" + " queries for off-subnet DGIDs. Default file is:\n" + " " OSM_DEFAULT_PREFIX_ROUTES_FILE "\n\n"); + printf("--consolidate_ipv6_snm_req\n" + " Consolidate IPv6 Solicited Node Multicast group joins\n" + " into 1 IB multicast group.\n\n"); + printf("--verbose, -v\n" + " This option increases the log verbosity level.\n" + " The -v option may be specified multiple times\n" + " to further increase the verbosity level.\n" + " See the -D option for more information about\n" + " log verbosity.\n\n"); + printf("--V, -V\n" + " This option sets the maximum verbosity level and\n" + " forces log flushing.\n" + " The -V is equivalent to '-D 0xFF -d 2'.\n" + " See the -D option for more information about\n" + " log verbosity.\n\n"); + printf("--D, -D \n" + " This option sets the log verbosity level.\n" + " A flags field must follow the -D option.\n" + " A bit set/clear in the flags enables/disables a\n" + " specific log level as follows:\n" + " BIT LOG LEVEL ENABLED\n" + " ---- -----------------\n" + " 0x01 - ERROR (error messages)\n" + " 0x02 - INFO (basic messages, low volume)\n" + " 0x04 - VERBOSE (interesting stuff, moderate volume)\n" + " 0x08 - DEBUG (diagnostic, high volume)\n" + " 0x10 - FUNCS (function entry/exit, very high volume)\n" + " 0x20 - FRAMES (dumps all SMP and GMP frames)\n" + " 0x40 - ROUTING (dump FDB routing information)\n" + " 0x80 - currently unused.\n" + " Without -D, OpenSM defaults to ERROR + INFO (0x3).\n" + " Specifying -D 0 disables all messages.\n" + " Specifying -D 0xFF enables all messages (see -V).\n" + " High verbosity levels may require increasing\n" + " the transaction timeout with the -t option.\n\n"); + printf("--debug, -d \n" + " This option specifies a debug option.\n" + " These options are not normally needed.\n" + " The number following -d selects the debug\n" + " option to enable as follows:\n" + " OPT Description\n" + " --- -----------------\n" + " -d0 - Ignore other SM nodes\n" + " -d1 - Force single threaded dispatching\n" + " -d2 - Force log flushing after each log message\n" + " -d3 - Disable multicast support\n" + " -d10 - Put OpenSM in testability mode\n" + " Without -d, no debug options are enabled\n\n"); + printf("--help, -h, -?\n" + " Display this usage info then exit.\n\n"); + fflush(stdout); + exit(2); +} + +/********************************************************************** + **********************************************************************/ +static ib_net64_t get_port_guid(IN osm_opensm_t * p_osm, uint64_t port_guid) +{ + ib_port_attr_t attr_array[GUID_ARRAY_SIZE]; + uint32_t num_ports = GUID_ARRAY_SIZE; + char junk[128]; + uint32_t i, choice = 0; + boolean_t done_flag = FALSE; + ib_api_status_t status; + + /* + Call the transport layer for a list of local port + GUID values. + */ + status = + osm_vendor_get_all_port_attr(p_osm->p_vendor, attr_array, + &num_ports); + if (status != IB_SUCCESS) { + printf("\nError from osm_vendor_get_all_port_attr (%x)\n", + status); + return (0); + } + + /* if num_ports is 0 - return 0 */ + if (num_ports == 0) { + printf("\nNo local ports detected!\n"); + return (0); + } + /* If num_ports is 1, then there is only one possible port to use. + * Use it. */ + if (num_ports == 1) { + printf("Using default GUID 0x%" PRIx64 "\n", + cl_hton64(attr_array[0].port_guid)); + return (attr_array[0].port_guid); + } + /* If port_guid is 0 - use the first connected port */ + if (port_guid == 0) { + for (i = 0; i < num_ports; i++) + if (attr_array[i].link_state > IB_LINK_DOWN) + break; + if (i == num_ports) + i = 0; + printf("Using default GUID 0x%" PRIx64 "\n", + cl_hton64(attr_array[i].port_guid)); + return (attr_array[i].port_guid); + } + + if (p_osm->subn.opt.daemon) + return 0; + + /* More than one possible port - list all ports and let the user + * to choose. */ + while (done_flag == FALSE) { + printf("\nChoose a local port number with which to bind:\n\n"); + for (i = 0; i < num_ports; i++) + /* Print the index + 1 since by convention, port + * numbers start with 1 on host channel adapters. */ + printf("\t%u: GUID 0x%" PRIx64 + ", lid %u, state %s\n", i + 1, + cl_ntoh64(attr_array[i].port_guid), + attr_array[i].lid, + ib_get_port_state_str(attr_array[i].link_state)); + printf("\nEnter choice (1-%u): ", i); + fflush(stdout); + if (scanf("%u", &choice)) { + if (choice > num_ports || choice < 1) { + printf("\nError: Lame choice!\n"); + fflush(stdin); + } else { + choice--; + done_flag = TRUE; + } + } else { + /* get rid of the junk in the selection line */ + scanf("%s", junk); + printf("\nError: Lame choice!\n"); + fflush(stdin); + } + } + printf("Choice guid=0x%" PRIx64 "\n", + cl_ntoh64(attr_array[choice].port_guid)); + return (attr_array[choice].port_guid); +} + +/********************************************************************** + **********************************************************************/ + +static int daemonize(osm_opensm_t * osm) +{ + pid_t pid; + int fd; + + fd = open("/dev/null", O_WRONLY); + if (fd < 0) { + perror("open"); + return -1; + } + + if ((pid = fork()) < 0) { + perror("fork"); + exit(-1); + } else if (pid > 0) + exit(0); + + setsid(); + + if ((pid = fork()) < 0) { + perror("fork"); + exit(-1); + } else if (pid > 0) + exit(0); + + close(0); + close(1); + close(2); + + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + + return 0; +} + +/********************************************************************** + **********************************************************************/ +int osm_manager_loop(osm_subn_opt_t * p_opt, osm_opensm_t * p_osm) +{ + int console_init_flag = 0; + + if (is_console_enabled(p_opt)) { + if (!osm_console_init(p_opt, &p_osm->console, &p_osm->log)) + console_init_flag = 1; + } + + /* + Sit here forever - dwell or do console i/o & cmds + */ + while (!osm_exit_flag) { + if (console_init_flag) + osm_console(p_osm); + else + cl_thread_suspend(10000); + + if (osm_usr1_flag) { + osm_usr1_flag = 0; + osm_log_reopen_file(&(p_osm->log)); + } + if (osm_hup_flag) { + osm_hup_flag = 0; + /* a HUP signal should only start a new heavy sweep */ + p_osm->subn.force_heavy_sweep = TRUE; + osm_opensm_sweep(p_osm); + } + } + if (is_console_enabled(p_opt)) + osm_console_exit(&p_osm->console, &p_osm->log); + return 0; +} + +/********************************************************************** + **********************************************************************/ +int main(int argc, char *argv[]) +{ + osm_opensm_t osm; + osm_subn_opt_t opt; + ib_net64_t sm_key = 0; + ib_api_status_t status; + uint32_t temp, dbg_lvl; + boolean_t run_once_flag = FALSE; + int32_t vendor_debug = 0; + uint32_t next_option; + char *conf_template = NULL; + uint32_t val; + unsigned config_file_done = 0; + const char *const short_option = + "F:c:i:f:ed:D:g:l:L:s:t:a:u:m:X:R:zM:U:S:P:Y:ANBIQvVhoryxp:n:q:k:C:"; + + /* + In the array below, the 2nd parameter specifies the number + of arguments as follows: + 0: no arguments + 1: argument + 2: optional + */ + const struct option long_option[] = { + {"version", 0, NULL, 12}, + {"config", 1, NULL, 'F'}, + {"create-config", 1, NULL, 'c'}, + {"debug", 1, NULL, 'd'}, + {"guid", 1, NULL, 'g'}, + {"ignore_guids", 1, NULL, 'i'}, + {"lmc", 1, NULL, 'l'}, + {"sweep", 1, NULL, 's'}, + {"timeout", 1, NULL, 't'}, + {"verbose", 0, NULL, 'v'}, + {"D", 1, NULL, 'D'}, + {"log_file", 1, NULL, 'f'}, + {"log_limit", 1, NULL, 'L'}, + {"erase_log_file", 0, NULL, 'e'}, + {"Pconfig", 1, NULL, 'P'}, + {"no_part_enforce", 0, NULL, 'N'}, + {"qos", 0, NULL, 'Q'}, + {"qos_policy_file", 1, NULL, 'Y'}, + {"maxsmps", 1, NULL, 'n'}, + {"console", 1, NULL, 'q'}, + {"V", 0, NULL, 'V'}, + {"help", 0, NULL, 'h'}, + {"once", 0, NULL, 'o'}, + {"reassign_lids", 0, NULL, 'r'}, + {"priority", 1, NULL, 'p'}, + {"smkey", 1, NULL, 'k'}, + {"routing_engine", 1, NULL, 'R'}, + {"ucast_cache", 0, NULL, 'A'}, + {"connect_roots", 0, NULL, 'z'}, + {"lid_matrix_file", 1, NULL, 'M'}, + {"lfts_file", 1, NULL, 'U'}, + {"sadb_file", 1, NULL, 'S'}, + {"root_guid_file", 1, NULL, 'a'}, + {"cn_guid_file", 1, NULL, 'u'}, + {"ids_guid_file", 1, NULL, 'm'}, + {"guid_routing_order_file", 1, NULL, 'X'}, + {"stay_on_fatal", 0, NULL, 'y'}, + {"honor_guid2lid", 0, NULL, 'x'}, +#ifdef ENABLE_OSM_CONSOLE_SOCKET + {"console-port", 1, NULL, 'C'}, +#endif + {"daemon", 0, NULL, 'B'}, + {"inactive", 0, NULL, 'I'}, +#ifdef ENABLE_OSM_PERF_MGR + {"perfmgr", 0, NULL, 1}, + {"perfmgr_sweep_time_s", 1, NULL, 2}, +#endif + {"prefix_routes_file", 1, NULL, 3}, + {"consolidate_ipv6_snm_req", 0, NULL, 4}, + {NULL, 0, NULL, 0} /* Required at the end of the array */ + }; + + /* Make sure that the opensm and complib were compiled using + same modes (debug/free) */ + if (osm_is_debug() != cl_is_debug()) { + fprintf(stderr, + "ERROR: OpenSM and Complib were compiled using different modes\n"); + fprintf(stderr, "ERROR: OpenSM debug:%d Complib debug:%d \n", + osm_is_debug(), cl_is_debug()); + exit(1); + } +#if defined (_DEBUG_) && defined (OSM_VENDOR_INTF_OPENIB) + enable_stack_dump(1); +#endif + + printf("-------------------------------------------------\n"); + printf("%s\n", OSM_VERSION); + + osm_subn_set_default_opt(&opt); + + if (osm_subn_parse_conf_file(OSM_DEFAULT_CONFIG_FILE, &opt) < 0) + printf("\nosm_subn_parse_conf_file failed!\n"); + + printf("Command Line Arguments:\n"); + do { + next_option = getopt_long_only(argc, argv, short_option, + long_option, NULL); + switch (next_option) { + case 12: /* --version - already printed above */ + exit(0); + break; + case 'F': + if (config_file_done) + break; + printf("Reloading config from `%s`:\n", optarg); + if (osm_subn_parse_conf_file(optarg, &opt)) { + printf("cannot parse config file.\n"); + exit(1); + } + printf("Rescaning command line:\n"); + config_file_done = 1; + optind = 0; + break; + case 'c': + conf_template = optarg; + printf(" Creating config file template \'%s\'.\n", + conf_template); + break; + case 'o': + /* + Run once option. + */ + run_once_flag = TRUE; + printf(" Run Once\n"); + break; + + case 'r': + /* + Reassign LIDs subnet option. + */ + opt.reassign_lids = TRUE; + printf(" Reassign LIDs\n"); + break; + + case 'i': + /* + Specifies ignore guids file. + */ + opt.port_prof_ignore_file = optarg; + printf(" Ignore Guids File = %s\n", + opt.port_prof_ignore_file); + break; + + case 'g': + /* + Specifies port guid with which to bind. + */ + opt.guid = cl_hton64(strtoull(optarg, NULL, 16)); + if (!opt.guid) + /* If guid is 0 - need to display the + * guid list */ + opt.guid = INVALID_GUID; + else + printf(" Guid <0x%" PRIx64 ">\n", + cl_hton64(opt.guid)); + break; + + case 's': + val = strtol(optarg, NULL, 0); + /* Check that the number is not too large */ + if (((uint32_t) (val * 1000000)) / 1000000 != val) + fprintf(stderr, + "ERROR: sweep interval given is too large. Ignoring it.\n"); + else { + opt.sweep_interval = val; + printf(" sweep interval = %d\n", + opt.sweep_interval); + } + break; + + case 't': + opt.transaction_timeout = strtol(optarg, NULL, 0); + printf(" Transaction timeout = %d\n", + opt.transaction_timeout); + break; + + case 'n': + opt.max_wire_smps = strtol(optarg, NULL, 0); + if (opt.max_wire_smps <= 0) + opt.max_wire_smps = 0x7FFFFFFF; + printf(" Max wire smp's = %d\n", opt.max_wire_smps); + break; + + case 'q': + /* + * OpenSM interactive console + */ + if (strcmp(optarg, OSM_DISABLE_CONSOLE) == 0 + || strcmp(optarg, OSM_LOCAL_CONSOLE) == 0 +#ifdef ENABLE_OSM_CONSOLE_SOCKET + || strcmp(optarg, OSM_REMOTE_CONSOLE) == 0 + || strcmp(optarg, OSM_LOOPBACK_CONSOLE) == 0 +#endif + ) + opt.console = optarg; + else + printf("-console %s option not understood\n", + optarg); + break; + +#ifdef ENABLE_OSM_CONSOLE_SOCKET + case 'C': + opt.console_port = strtol(optarg, NULL, 0); + break; +#endif + + case 'd': + dbg_lvl = strtol(optarg, NULL, 0); + printf(" d level = 0x%x\n", dbg_lvl); + if (dbg_lvl == 0) { + printf(" Debug mode: Ignore Other SMs\n"); + opt.ignore_other_sm = TRUE; + } else if (dbg_lvl == 1) { + printf(" Debug mode: Forcing Single Thread\n"); + opt.single_thread = TRUE; + } else if (dbg_lvl == 2) { + printf(" Debug mode: Force Log Flush\n"); + opt.force_log_flush = TRUE; + } else if (dbg_lvl == 3) { + printf + (" Debug mode: Disable multicast support\n"); + opt.disable_multicast = TRUE; + } + /* + * NOTE: Debug level 4 used to be used for memory + * tracking but this is now deprecated + */ + else if (dbg_lvl == 5) + vendor_debug++; + else + printf(" OpenSM: Unknown debug option %d" + " ignored\n", dbg_lvl); + break; + + case 'l': + temp = strtol(optarg, NULL, 0); + if (temp > 7) { + fprintf(stderr, + "ERROR: LMC must be 7 or less.\n"); + return (-1); + } + opt.lmc = (uint8_t) temp; + printf(" LMC = %d\n", temp); + break; + + case 'D': + opt.log_flags = strtol(optarg, NULL, 0); + printf(" verbose option -D = 0x%x\n", opt.log_flags); + break; + + case 'f': + opt.log_file = optarg; + break; + + case 'L': + opt.log_max_size = + strtoul(optarg, NULL, 0) * (1024 * 1024); + printf(" Log file max size is %lu bytes\n", + opt.log_max_size); + break; + + case 'e': + opt.accum_log_file = FALSE; + printf(" Creating new log file\n"); + break; + + case 'P': + opt.partition_config_file = optarg; + break; + + case 'N': + opt.no_partition_enforcement = TRUE; + break; + + case 'Q': + opt.qos = TRUE; + break; + + case 'Y': + opt.qos_policy_file = optarg; + printf(" QoS policy file \'%s\'\n", optarg); + break; + + case 'y': + opt.exit_on_fatal = FALSE; + printf(" Staying on fatal initialization errors\n"); + break; + + case 'v': + opt.log_flags = (opt.log_flags << 1) | 1; + printf(" Verbose option -v (log flags = 0x%X)\n", + opt.log_flags); + break; + + case 'V': + opt.log_flags = 0xFF; + opt.force_log_flush = TRUE; + printf(" Big V selected\n"); + break; + + case 'p': + temp = strtol(optarg, NULL, 0); + if (0 > temp || 15 < temp) { + fprintf(stderr, + "ERROR: priority must be between 0 and 15\n"); + return (-1); + } + opt.sm_priority = (uint8_t) temp; + printf(" Priority = %d\n", temp); + break; + + case 'k': + sm_key = cl_hton64(strtoull(optarg, NULL, 16)); + printf(" SM Key <0x%" PRIx64 ">\n", cl_hton64(sm_key)); + opt.sm_key = sm_key; + break; + + case 'R': + opt.routing_engine_names = optarg; + printf(" Activate \'%s\' routing engine(s)\n", optarg); + break; + + case 'z': + opt.connect_roots = TRUE; + printf(" Connect roots option is on\n"); + break; + + case 'A': + opt.use_ucast_cache = TRUE; + printf(" Unicast routing cache option is on\n"); + break; + + case 'M': + opt.lid_matrix_dump_file = optarg; + printf(" Lid matrix dump file is \'%s\'\n", optarg); + break; + + case 'U': + opt.lfts_file = optarg; + printf(" LFTs file is \'%s\'\n", optarg); + break; + + case 'S': + opt.sa_db_file = optarg; + printf(" SA DB file is \'%s\'\n", optarg); + break; + + case 'a': + /* + Specifies root guids file + */ + opt.root_guid_file = optarg; + printf(" Root Guid File: %s\n", opt.root_guid_file); + break; + + case 'u': + /* + Specifies compute node guids file + */ + opt.cn_guid_file = optarg; + printf(" Compute Node Guid File: %s\n", + opt.cn_guid_file); + break; + + case 'm': + /* Specifies ids guid file */ + opt.ids_guid_file = optarg; + printf(" IDs Guid File: %s\n", opt.ids_guid_file); + break; + + case 'X': + /* Specifies guid routing order file */ + opt.guid_routing_order_file = optarg; + printf(" GUID Routing Order File: %s\n", opt.guid_routing_order_file); + break; + + case 'x': + opt.honor_guid2lid_file = TRUE; + printf(" Honor guid2lid file, if possible\n"); + break; + + case 'B': + opt.daemon = TRUE; + printf(" Daemon mode\n"); + break; + + case 'I': + opt.sm_inactive = TRUE; + printf(" SM started in inactive state\n"); + break; + +#ifdef ENABLE_OSM_PERF_MGR + case 1: + opt.perfmgr = TRUE; + break; + case 2: + opt.perfmgr_sweep_time_s = atoi(optarg); + break; +#endif /* ENABLE_OSM_PERF_MGR */ + + case 3: + opt.prefix_routes_file = optarg; + break; + case 4: + opt.consolidate_ipv6_snm_req = TRUE; + break; + case 'h': + case '?': + case ':': + show_usage(); + break; + + case -1: + break; /* done with option */ + default: /* something wrong */ + abort(); + } + } + while (next_option != -1); + + if (opt.log_file != NULL) + printf(" Log File: %s\n", opt.log_file); + /* Done with options description */ + printf("-------------------------------------------------\n"); + + if (conf_template) { + status = osm_subn_write_conf_file(conf_template, &opt); + if (status) + printf("\nosm_subn_write_conf_file failed!\n"); + exit(status); + } + + osm_subn_verify_config(&opt); + + if (vendor_debug) + osm_vendor_set_debug(osm.p_vendor, vendor_debug); + + block_signals(); + + if (opt.daemon) + daemonize(&osm); + + complib_init(); + + status = osm_opensm_init(&osm, &opt); + if (status != IB_SUCCESS) { + const char *err_str = ib_get_err_str(status); + if (err_str == NULL) + err_str = "Unknown Error Type"; + printf("\nError from osm_opensm_init: %s.\n", err_str); + /* We will just exit, and not go to Exit, since we don't + want the destroy to be called. */ + complib_exit(); + return (status); + } + + /* + If the user didn't specify a GUID on the command line, + then get a port GUID value with which to bind. + */ + if (opt.guid == 0 || cl_hton64(opt.guid) == CL_HTON64(INVALID_GUID)) + opt.guid = get_port_guid(&osm, opt.guid); + + status = osm_opensm_bind(&osm, opt.guid); + if (status != IB_SUCCESS) { + printf("\nError from osm_opensm_bind (0x%X)\n", status); + printf + ("Perhaps another instance of OpenSM is already running\n"); + goto Exit; + } + + setup_signals(); + + osm_opensm_sweep(&osm); + + if (run_once_flag == TRUE) { + while (!osm_exit_flag) { + status = + osm_opensm_wait_for_subnet_up(&osm, + osm.subn.opt. + sweep_interval * + 1000000, TRUE); + if (!status) + osm_exit_flag = 1; + } + } else { + /* + * Sit here until signaled to exit + */ + osm_manager_loop(&opt, &osm); + } + + if (osm.mad_pool.mads_out) { + fprintf(stdout, + "There are still %u MADs out. Forcing the exit of the OpenSM application...\n", + osm.mad_pool.mads_out); +#ifdef HAVE_LIBPTHREAD + pthread_cond_signal(&osm.stats.cond); +#else + cl_event_signal(&osm.stats.event); +#endif + } + +Exit: + osm_opensm_destroy(&osm); + complib_exit(); + + exit(0); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_check b/contrib/ofed/management/opensm/opensm/osm_check new file mode 100755 index 000000000000..3f30c3c10e99 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_check @@ -0,0 +1,282 @@ +#!/usr/bin/perl -W +#!/usr/bin/perl -W +# +# +# Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. +# Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. +# Copyright (c) 1996-2003 Intel Corporation. All rights reserved. +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# +# +# Abstract: +# Perl script for simple source code error checking. +# +# Environment: +# Linux User Mode +# +# $Revision: 1.4 $ +# +# +# +# DESCRIPTION: +# +# This script performs some simple conformance checks on the +# OpenSM source code. It does NOT attempt to act like a full +# blown 'C' language parser, so it can be fooled. Something +# is better than nothing. Running the 'osm_indent' script before +# running this script will increase your chances of catching +# problems. +# +# +# The following checks are performed: +# 1) Verify that the function name provided in a log statement +# matches the name of the current function. +# +# 2) Verify that log statements are in the form that this script +# can readily parse. Improvements to the regular expressions +# might make this unnecessary. +# +# 3) Verify that lower two digits of the error codes used in log +# statements are unique within that file. +# +# 4) Verify that upper two digits of the error codes used in log +# statements are not used by any other module. +# +# USAGE: +# +# In the OpenSM source directory, type: +# osm_check.pl *.c +# + +# Do necessary upfront initialization +$verbose = 0; +$in_c_comment = 0; + +if( !exists $ARGV[0] ) +{ + print "ERROR: You must specify the files on which to operate, such as '*.c'\n"; + osm_check_usage(); + exit; +} + +# loop through all the command line options +do +{ + $doing_params = 0; + + # First, look for command line options. + if( $ARGV[0] =~ /-[v|V]/ ) + { + $verbose += 1; + shift; + print "Verbose mode on, level = $verbose.\n"; + $doing_params = 1; + } + + if( !exists $ARGV[0] ) + { + print "ERROR: You must specify the files on which to operate, such as '*.c'\n"; + osm_check_usage(); + exit; + } +}while( $doing_params == 1 ); + +LINE: while( <> ) +{ + # Skip C single line C style comments + # This line must come before the multi-line C comment check! + if( /\/\*.*\*\// ) + { + $in_c_comment = 0; + next LINE; + } + + # skip multi-line C style comments + if( /\/\*/ ) + { + $in_c_comment = 1; + next LINE; + } + + # end skipping of multi-line C style comments + if( /\*\// ) + { + $in_c_comment = 0; + next LINE; + } + + # We're still in a C comment, so ignore input + if( $in_c_comment == 1 ) + { + next LINE; + } + + + # skip C++ style comment lines + if( /^\s*\/\// ) + { + next LINE; + } + + # check for bad PRIx64 usage + # It's a common mistake to forget the % before the PRIx64 + if( /[^%]\"\s*PRIx64/ ) + { + print "No % sign before PRx64!!: $ARGV $.\n"; + } + + # This simple script doesn't handle checking PRIx64 usage + # when PRIx64 starts the line. Just give a warning. + if( /^\s*PRIx64/ ) + { + print "Warning: PRIx64 at start of line. $ARGV $.\n"; + } + + # Attempt to locate function names. + # Function names must start on the beginning of the line. + if( /^(\w+)\s*\(/ ) + { + $current_func = $1; + if( $verbose == 1 ) + { + print "Processing $ARGV: $current_func\n"; + } + } + + # Attempt to find OSM_LOG_ENTER entries. + # When found, verify that the function name provided matches + # the actual function. + if( /OSM_LOG_ENTER\s*\(\s*([\-\.\>\w]+)\s*,\s*(\w+)\s*\)/ ) + { + $log_func = $2; + if( $current_func ne $log_func ) + { + printf "MISMATCH!! $ARGV $.: $current_func != $log_func\n"; + } + } + + # Check for non-conforming log statements. + # Log statements must not start the log string on the same line + # as the osm_log function itself. + # Watch out for the #include "osm_log.h" statement as a false positive. + if( /osm_log\s*\(.*\"/ ) + { + print "NON-CONFORMING LOG STATEMENT!! $ARGV $.\n"; + } + + # Attempt to find osm_log entries. + if( /^\s*\"(\w+):/ ) + { + $log_func = $1; + if( $current_func ne $log_func ) + { + print "MISMATCHED LOG FUNCTION!! $ARGV $.: $current_func != $log_func\n"; + } + } + + # Error logging must look like 'ERR 1234:' + # The upper two digits are error range assigned to that module. + # The lower two digits are the error code itself. + # Error codes are in hexadecimal. + if( /ERR(\s+)([0-9a-fA-F]{2})([0-9a-fA-F]{2})(..)/ ) + { + # Check if we already established the error prefix for this module + $err_prefix = $module_err_prefixes{$ARGV}; + if( $err_prefix ) + { + if( $err_prefix ne $2 ) + { + print "BAD ERR RANGE IN LOG ENTRY!! $ARGV $.: $current_func\n"; + print "\tExpected $err_prefix but found $2\n"; + } + } + else + { + # Create a new prefix for this module. + $module_err_prefixes{$ARGV} = $2; + } + + $err_base = $module_err_bases{$3}; + if( $err_base ) + { + print "DUPLICATE ERR NUMBER IN LOG ENTRY!! $ARGV $.: $current_func: $3\n"; + print "\tPrevious use on line $err_base.\n"; + } + else + { + # Add this error code to the list used by this module + # The data stored in the line number on which it is used. + $module_err_bases{$3} = $.; + if( $verbose > 1 ) + { + print "Adding new error: $1$2 in $ARGV.\n"; + } + } + + if( $4 ne ": " ) + { + print "MALFORMED LOG STATEMENT!! NEEDS ': ' $ARGV $.\n"; + } + + if( $1 ne " " ) + { + print "USE ONLY 1 SPACE AFTER ERR!! $ARGV $.\n"; + } + } + + # verify expected use of sizeof() with pointers + if( /sizeof\s*\(\s*[h|p]_/ ) + { + print "SUSPICIOUS USE OF SIZEOF(), DO YOU NEED AN '*' $ARGV $.\n"; + } + + +} +continue +{ + # reset the module base error index when we finished out + # each source file. + if( eof ) + { + # reset the base error value, since each module can + # repeat this range. + %module_err_bases = (); + # closing the file here resets the line number with each new file + close ARGV; + } +} + +sub osm_check_usage +{ + print "Usage:\n"; + print "osm_check.pl [-v|V] \n"; + print "[-v|V] - enable verbose mode.\n\n"; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_check_n_fix b/contrib/ofed/management/opensm/opensm/osm_check_n_fix new file mode 100755 index 000000000000..3a87cfdf3fd0 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_check_n_fix @@ -0,0 +1,517 @@ +eval '(exit $?0)' && + eval 'exec perl -S $0 ${1+"$@"}' && + eval 'exec perl -S $0 $argv:q' + if 0; + +#!/usr/bin/perl -W +# +# Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. +# Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. +# Copyright (c) 1996-2003 Intel Corporation. All rights reserved. +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +######################################################################### +# +# Abstract: +# Perl script for simple source code error checking and fixing +# +# Environment: +# Linux User Mode +# +# Author: +# Eitan Zahavi, Mellanox Technologies LTD Yokneam Israel. +# +# $Revision: 1.4 $ +# +# +# +# DESCRIPTION: +# +# This script performs some simple conformance checks on the +# OpenSM source code. It does NOT attempt to act like a full +# blown 'C' language parser, so it can be fooled. Something +# is better than nothing. +# +# The script starts by running the 'osm_indent' script on teh given files. +# +# We use an extra file for tracking error codes used by each file. +# The name is osm_errors_codes. +# +# The following checks are performed: +# 1) Verify that the function name provided in a log statement +# matches the name of the current function. +# +# 2) Verify that log statements are in the form that this script +# can readily parse. Improvements to the regular expressions +# might make this unnecessary. +# +# 3) Verify that lower two digits of the error codes used in log +# statements are unique within that file. +# +# 4) Verify that upper two digits of the error codes used in log +# statements are not used by any other module. +# +# 5) Verify the lines do not have extra spaces. +# +# USAGE: +# +# In the OpenSM source directory, type: +# osm_check_n_fix -f *.c +# +######################################################################### + +# Do necessary upfront initialization +$verbose = 0; +$in_c_comment = 0; +$fix_mode = 0; +$confirm_mode = 0; +$re_assign_err_prefix = 0; + +if( !scalar(@ARGV) ) +{ + print "ERROR: You must specify the files on which to operate, such as '*.c'\n"; + osm_check_usage(); + exit; +} + +# loop through all the command line options +do +{ + $doing_params = 0; + + # First, look for command line options. + if( $ARGV[0] =~ /-[v|V]/ ) + { + $verbose += 1; + shift; + print "Verbose mode on, level = $verbose.\n"; + $doing_params = 1; + } + + if( $ARGV[0] =~ /(-f|--fix)/ ) + { + $fix_mode += 1; + shift; + print "Fix mode on.\n"; + $doing_params = 1; + } + + if( $ARGV[0] =~ /(-c|--confirm)/ ) + { + $confirm_mode += 1; + shift; + print "Confirm mode on.\n"; + $doing_params = 1; + } + + if( $ARGV[0] =~ /(-r|--re-assign-mod-err-prefix)/ ) + { + $re_assign_err_prefix += 1; + shift; + print "Allow Re-Assignment of Module Err Prefixes.\n"; + $doing_params = 1; + } + + if( !scalar(@ARGV)) + { + print "ERROR: You must specify the files on which to operate, such as '*.c'\n"; + osm_check_usage(); + exit; + } +} while( $doing_params == 1 ); + +# parse the osm_error_codes file and define: +# module_by_prefix +# module_err_prefixes +# module_last_err_used +if (open(ERRS, "; + close(ERRS); + foreach $errDef (@ERR_DEFS) { + # the format should be + if ($errDef =~ m/^(\S+)\s+(\S+)\s+([0-9]+)$/) { + ($file_name,$mod_prefix,$last_err) = ($1,$2,$3); + if (defined($module_by_prefix{$mod_prefix})) { + print "ERROR: Double module prefix:$mod_prefix on:$module_by_prefix($mod_prefix) and $file_name\n"; + exit 3; + } + $module_by_prefix{$mod_prefix} = $file_name; + $module_err_prefixes{$file_name} = $mod_prefix; + $module_last_err_used{$file_name} = $last_err; + } else { + print "ERROR: Fail to parse sm_error_codes: $errDef\n"; + exit 3; + } + } +} + +# do a file by file read into memory so we can tweek it: +foreach $file_name (@ARGV) { + print "- $file_name ----------------------------------------------------\n"; + # first step is to run indent + $res=`osm_indent $file_name`; + + open(INFILE, "<$file_name") || die("Fail to open $file_name"); + @LINES = ; + close(INFILE); + $any_fix = 0; + $needed_fixing = 0; + $need_indentation = 0; + + LINE: for ($line_num = 0; $line_num \w]+)\s*,\s*(\w+)\s*\)/ ) { + $log_func = $2; + if( $current_func ne $log_func ) { + printf "MISMATCH!! $file_name $line_num: $current_func != $log_func\n"; + $needed_fixing++; + if ($fix_mode) { + $line =~ + s/OSM_LOG_ENTER\s*\(\s*([\-\.\>\w]+)\s*,\s*(\w+)\s*\)/OSM_LOG_ENTER( $1, $current_func )/; + if (confirm_change($line, $LINES[$line_num])) { + $LINES[$line_num] = $line; + $any_fix++; + } + } + } + } + + # Check for non-conforming log statements. + # Log statements must not start the log string on the same line + # as the osm_log function itself. + # Watch out for the #include "osm_log.h" statement as a false positive. + if (/osm_log\s*\(.*OSM_.*\"/ ) { + if (/Format Waved/) { + print "Skipping log format waiver at $file_name $line_num\n"; + } else { + print "NON-CONFORMING LOG STATEMENT!! $file_name $line_num\n"; + $needed_fixing++; + if ($fix_mode) { + print "Fatal: can not auto fix\n"; + exit 1; + } + } + } + + # Attempt to find osm_log entries. + if( /^\s*\"(\w+):/ ) + { + $log_func = $1; + if( $current_func ne $log_func ) + { + print "MISMATCHED LOG FUNCTION!! $file_name $line_num: $current_func != $log_func\n"; + $needed_fixing++; + if ($fix_mode) { + $line =~ + s/^(\s*)\"(\w+):/$1\"$current_func:/; + if (confirm_change($line, $LINES[$line_num])) { + $LINES[$line_num] = $line; + $any_fix++; + } + } + } + } + + # Error logging must look like 'ERR 1234:' + # The upper two digits are error range assigned to that module. + # The lower two digits are the error code itself. + # Error codes are in hexadecimal. + if( /ERR(\s+)([0-9a-fA-F]{2})([0-9a-fA-F]{2})(..)/ ) + { + # track any error for this exp: + $exp_err = 0; + + # the parsed prefix and err code: + ($found_prefix,$found_code) = ($2,$3); + + # Check if we already established the error prefix for this module + $err_prefix = $module_err_prefixes{$file_name}; + + # err prefix is not available for this file + if ( ! $err_prefix ) { + # make sure no other file uses this prefix: + if ($module_by_prefix{$found_prefix}) { + # some other file uses that prefix: + + # two modes: either use a new one or abort + if ($re_assign_err_prefix) { + # scan the available module prefixes for an empty one: + $found = 0; + for ($new_prefix_idx = 1; $found == 0; $new_prefix_idx++) { + $prefix = sprintf("%02X", $new_prefix_idx); + if (!defined($module_by_prefix{$prefix})) { + $module_err_prefixes{$file_name} = $prefix; + $module_by_prefix{$prefix} = $file_name; + $found = 1; + } + $exp_err = 1; + } + } else { + print "Fatal: File $module_by_prefix{$2} already uses same prefix:$2 used by: $file_name (line=$line_num)\n"; + exit 1; + } + } else { + # the prefix found is unused: + + # Create a new prefix for this module. + $module_err_prefixes{$file_name} = $found_prefix; + $module_by_prefix{$found_prefix} = $file_name; + $err_prefix = $found_prefix; + } + } else { + # we already have a prefix for this file + + if( $err_prefix ne $found_prefix ) + { + $needed_fixing++; + print "BAD ERR RANGE IN LOG ENTRY!! $file_name $line_num: $current_func\n"; + print "\tExpected $err_prefix but found $found_prefix\n"; + $exp_err = 1; + } + } + + # now check for code duplicates + $err_base = $module_err_bases{$found_code}; + if( $err_base ) { + $needed_fixing++; + print "DUPLICATE ERR NUMBER IN LOG ENTRY!! $file_name $line_num: $current_func: $3\n"; + print "\tPrevious use on line $err_base.\n"; + + # use the last error code for this module: + $module_last_err_used{$file_name}++; + $err_code = sprintf("%02X", $module_last_err_used{$file_name}); + print "\tUsing new err code:0x$err_code ($module_last_err_used{$file_name})\n"; + $module_err_bases{$err_code} = $line_num; + $exp_err = 1; + } else { + # Add this error code to the list used by this module + # The data stored in the line number on which it is used. + $module_err_bases{$found_code} = $line_num; + # track the last code used + $err_code_num = eval("0x$found_code"); + if ($module_last_err_used{$file_name} < $err_code_num) { + $module_last_err_used{$file_name} = $err_code_num; + } + $err_code = $found_code; + + if( $verbose > 1 ) { + print "Adding new error: $err_prefix$found_code in $file_name.\n"; + } + } + + if( $4 ne ": " ) { + $needed_fixing++; + print "MALFORMED LOG STATEMENT!! NEEDS ': ' $file_name $line_num\n"; + $exp_err = 1; + } + + if( $1 ne " " ) + { + $needed_fixing++; + print "USE ONLY 1 SPACE AFTER ERR!! $file_name $line_num\n"; + $exp_err = 1; + } + + if ($exp_err && $fix_mode) { + $line =~ + s/ERR(\s+)([0-9a-fA-F]{2})([0-9a-fA-F]{2})([^\"]*\")/ERR ${err_prefix}$err_code: \" /; + if (confirm_change($line, $LINES[$line_num])) { + $LINES[$line_num] = $line; + $any_fix++; + } + } + } + + # verify expected use of sizeof() with pointers + if( /sizeof\s*\(\s*[h|p]_[^-]+\)/ ) + { + print "SUSPICIOUS USE OF SIZEOF(), DO YOU NEED AN '*' $file_name $line_num\n"; + $needed_fixing++; + if ($fix_mode) { + $line =~ + s/sizeof\s*\(\s*([h|p])_/sizeof \(*$1_/; + if (confirm_change($line, $LINES[$line_num])) { + $LINES[$line_num] = $line; + $any_fix++; + } + } + } + } + + # reset the base error value, since each module can + # repeat this range. + %module_err_bases = (); + + # if any fix write out the fixed file: + if ($any_fix) { + open(OF,">$file_name.fix"); + print OF @LINES; + close(OF); + } elsif ($needed_fixing) { + print "Found $needed_fixing Errors on file: $file_name\n"; + } +} + +# write out the error codes. +# module_by_prefix +# module_err_prefixes +# module_last_err_used +open(ERRS,">osm_error_codes"); +foreach $fn (sort(keys(%module_err_prefixes))) { + print ERRS "$fn $module_err_prefixes{$fn} $module_last_err_used{$fn}\n"; +} +close(ERRS); + +sub osm_check_usage +{ + print "Usage:\n"; + print "osm_check.pl [-v|V] [-f|--fix] [-c|--confirm] [-r|--re-assign-mod-err-prefix] \n"; + print "[-v|V] - enable verbose mode.\n"; + print "[-f|--fix] - enable auto fix mode.\n"; + print "[-c|--confirm] - enable manual confirmation mode.\n"; + print "[-r|--re-assign-mod-err-prefix] - enables re-assign error prefixes if the file does not have one.\n"; +} + +sub confirm_change { + local ($line, $orig_line) = @_; + if ($confirm_mode) { + print "In Line:".($line_num + 1)."\n"; + print "From: ${orig_line}To: ${line}Ok [y] ?"; + $| = 1; + $ans = ; + chomp $ans; + + if ($ans && $ans ne "y") { + return 0; + } + } else { + print "From: ${orig_line}To: ${line}"; + } + return 1; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_console.c b/contrib/ofed/management/opensm/opensm/osm_console.c new file mode 100644 index 000000000000..c6e8e597be0e --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_console.c @@ -0,0 +1,1327 @@ +/* + * Copyright (c) 2005-2008 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE /* for getline */ +#include +#include +#include +#include +#include +#include +#ifdef ENABLE_OSM_CONSOLE_SOCKET +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +struct command { + char *name; + void (*help_function) (FILE * out, int detail); + void (*parse_function) (char **p_last, osm_opensm_t * p_osm, + FILE * out); +}; + +static struct { + int on; + int delay_s; + time_t previous; + void (*loop_function) (osm_opensm_t * p_osm, FILE * out); +} loop_command = { +on: 0, delay_s: 2, loop_function:NULL}; + +static const struct command console_cmds[]; + +static inline char *next_token(char **p_last) +{ + return strtok_r(NULL, " \t\n\r", p_last); +} + +static void help_command(FILE * out, int detail) +{ + int i; + + fprintf(out, "Supported commands and syntax:\n"); + fprintf(out, "help []\n"); + /* skip help command */ + for (i = 1; console_cmds[i].name; i++) + console_cmds[i].help_function(out, 0); +} + +static void help_quit(FILE * out, int detail) +{ + fprintf(out, "quit (not valid in local mode; use ctl-c)\n"); +} + +static void help_loglevel(FILE * out, int detail) +{ + fprintf(out, "loglevel []\n"); + if (detail) { + fprintf(out, " log-level is OR'ed from the following\n"); + fprintf(out, " OSM_LOG_NONE 0x%02X\n", + OSM_LOG_NONE); + fprintf(out, " OSM_LOG_ERROR 0x%02X\n", + OSM_LOG_ERROR); + fprintf(out, " OSM_LOG_INFO 0x%02X\n", + OSM_LOG_INFO); + fprintf(out, " OSM_LOG_VERBOSE 0x%02X\n", + OSM_LOG_VERBOSE); + fprintf(out, " OSM_LOG_DEBUG 0x%02X\n", + OSM_LOG_DEBUG); + fprintf(out, " OSM_LOG_FUNCS 0x%02X\n", + OSM_LOG_FUNCS); + fprintf(out, " OSM_LOG_FRAMES 0x%02X\n", + OSM_LOG_FRAMES); + fprintf(out, " OSM_LOG_ROUTING 0x%02X\n", + OSM_LOG_ROUTING); + fprintf(out, " OSM_LOG_SYS 0x%02X\n", + OSM_LOG_SYS); + fprintf(out, "\n"); + fprintf(out, " OSM_LOG_DEFAULT_LEVEL 0x%02X\n", + OSM_LOG_DEFAULT_LEVEL); + } +} + +static void help_priority(FILE * out, int detail) +{ + fprintf(out, "priority []\n"); +} + +static void help_resweep(FILE * out, int detail) +{ + fprintf(out, "resweep [heavy|light]\n"); +} + +static void help_reroute(FILE * out, int detail) +{ + fprintf(out, "reroute\n"); + if (detail) { + fprintf(out, "reroute the fabric\n"); + } +} + +static void help_status(FILE * out, int detail) +{ + fprintf(out, "status [loop]\n"); + if (detail) { + fprintf(out, " loop -- type \"q\" to quit\n"); + } +} + +static void help_logflush(FILE * out, int detail) +{ + fprintf(out, "logflush -- flush the opensm.log file\n"); +} + +static void help_querylid(FILE * out, int detail) +{ + fprintf(out, + "querylid lid -- print internal information about the lid specified\n"); +} + +static void help_portstatus(FILE * out, int detail) +{ + fprintf(out, "portstatus [ca|switch|router]\n"); + if (detail) { + fprintf(out, "summarize port status\n"); + fprintf(out, + " [ca|switch|router] -- limit the results to the node type specified\n"); + } + +} + +static void help_switchbalance(FILE * out, int detail) +{ + fprintf(out, "switchbalance [verbose] [guid]\n"); + if (detail) { + fprintf(out, "output switch balancing information\n"); + fprintf(out, + " [verbose] -- verbose output\n" + " [guid] -- limit results to specified guid\n"); + } +} + +static void help_lidbalance(FILE * out, int detail) +{ + fprintf(out, "lidbalance [switchguid]\n"); + if (detail) { + fprintf(out, "output lid balanced forwarding information\n"); + fprintf(out, + " [switchguid] -- limit results to specified switch guid\n"); + } +} + +static void help_dump_conf(FILE *out, int detail) +{ + fprintf(out, "dump_conf\n"); + if (detail) { + fprintf(out, "dump current opensm configuration\n"); + } +} + +#ifdef ENABLE_OSM_PERF_MGR +static void help_perfmgr(FILE * out, int detail) +{ + fprintf(out, + "perfmgr [enable|disable|clear_counters|dump_counters|sweep_time[seconds]]\n"); + if (detail) { + fprintf(out, + "perfmgr -- print the performance manager state\n"); + fprintf(out, + " [enable|disable] -- change the perfmgr state\n"); + fprintf(out, + " [sweep_time] -- change the perfmgr sweep time (requires [seconds] option)\n"); + fprintf(out, + " [clear_counters] -- clear the counters stored\n"); + fprintf(out, + " [dump_counters [mach]] -- dump the counters (optionally in [mach]ine readable format)\n"); + fprintf(out, + " [print_counters ] -- print the counters for the specified node\n"); + } +} +#endif /* ENABLE_OSM_PERF_MGR */ + +/* more help routines go here */ + +static void help_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + char *p_cmd; + int i, found = 0; + + p_cmd = next_token(p_last); + if (!p_cmd) + help_command(out, 0); + else { + for (i = 1; console_cmds[i].name; i++) { + if (!strcmp(p_cmd, console_cmds[i].name)) { + found = 1; + console_cmds[i].help_function(out, 1); + break; + } + } + if (!found) { + fprintf(out, "%s : Command not found\n\n", p_cmd); + help_command(out, 0); + } + } +} + +static void loglevel_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + char *p_cmd; + int level; + + p_cmd = next_token(p_last); + if (!p_cmd) + fprintf(out, "Current log level is 0x%x\n", + osm_log_get_level(&p_osm->log)); + else { + /* Handle x, 0x, and decimal specification of log level */ + if (!strncmp(p_cmd, "x", 1)) { + p_cmd++; + level = strtoul(p_cmd, NULL, 16); + } else { + if (!strncmp(p_cmd, "0x", 2)) { + p_cmd += 2; + level = strtoul(p_cmd, NULL, 16); + } else + level = strtol(p_cmd, NULL, 10); + } + if ((level >= 0) && (level < 256)) { + fprintf(out, "Setting log level to 0x%x\n", level); + osm_log_set_level(&p_osm->log, level); + } else + fprintf(out, "Invalid log level 0x%x\n", level); + } +} + +static void priority_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + char *p_cmd; + int priority; + + p_cmd = next_token(p_last); + if (!p_cmd) + fprintf(out, "Current sm-priority is %d\n", + p_osm->subn.opt.sm_priority); + else { + priority = strtol(p_cmd, NULL, 0); + if (0 > priority || 15 < priority) + fprintf(out, + "Invalid sm-priority %d; must be between 0 and 15\n", + priority); + else { + fprintf(out, "Setting sm-priority to %d\n", priority); + osm_set_sm_priority(&p_osm->sm, (uint8_t)priority); + } + } +} + +static char *sm_state_str(int state) +{ + switch (state) { + case IB_SMINFO_STATE_DISCOVERING: + return ("Discovering"); + case IB_SMINFO_STATE_STANDBY: + return ("Standby"); + case IB_SMINFO_STATE_NOTACTIVE: + return ("Not Active"); + case IB_SMINFO_STATE_MASTER: + return ("Master"); + } + return ("UNKNOWN"); +} + +static char *sa_state_str(osm_sa_state_t state) +{ + switch (state) { + case OSM_SA_STATE_INIT: + return ("Init"); + case OSM_SA_STATE_READY: + return ("Ready"); + } + return ("UNKNOWN"); +} + +static void print_status(osm_opensm_t * p_osm, FILE * out) +{ + cl_list_item_t *item; + + if (out) { + cl_plock_acquire(&p_osm->lock); + fprintf(out, " OpenSM Version : %s\n", p_osm->osm_version); + fprintf(out, " SM State : %s\n", + sm_state_str(p_osm->subn.sm_state)); + fprintf(out, " SA State : %s\n", + sa_state_str(p_osm->sa.state)); + fprintf(out, " Routing Engine : %s\n", + osm_routing_engine_type_str(p_osm-> + routing_engine_used)); + + fprintf(out, " Loaded event plugins :"); + if (cl_qlist_head(&p_osm->plugin_list) == + cl_qlist_end(&p_osm->plugin_list)) { + fprintf(out, " "); + } + for (item = cl_qlist_head(&p_osm->plugin_list); + item != cl_qlist_end(&p_osm->plugin_list); + item = cl_qlist_next(item)) + fprintf(out, " %s", + ((osm_epi_plugin_t *)item)->plugin_name); + fprintf(out, "\n"); + +#ifdef ENABLE_OSM_PERF_MGR + fprintf(out, "\n PerfMgr state/sweep state : %s/%s\n", + osm_perfmgr_get_state_str(&(p_osm->perfmgr)), + osm_perfmgr_get_sweep_state_str(&(p_osm->perfmgr))); +#endif + fprintf(out, "\n MAD stats\n" + " ---------\n" + " QP0 MADs outstanding : %d\n" + " QP0 MADs outstanding (on wire) : %d\n" + " QP0 MADs rcvd : %d\n" + " QP0 MADs sent : %d\n" + " QP0 unicasts sent : %d\n" + " QP0 unknown MADs rcvd : %d\n" + " SA MADs outstanding : %d\n" + " SA MADs rcvd : %d\n" + " SA MADs sent : %d\n" + " SA unknown MADs rcvd : %d\n" + " SA MADs ignored : %d\n", + p_osm->stats.qp0_mads_outstanding, + p_osm->stats.qp0_mads_outstanding_on_wire, + p_osm->stats.qp0_mads_rcvd, + p_osm->stats.qp0_mads_sent, + p_osm->stats.qp0_unicasts_sent, + p_osm->stats.qp0_mads_rcvd_unknown, + p_osm->stats.sa_mads_outstanding, + p_osm->stats.sa_mads_rcvd, + p_osm->stats.sa_mads_sent, + p_osm->stats.sa_mads_rcvd_unknown, + p_osm->stats.sa_mads_ignored); + fprintf(out, "\n Subnet flags\n" + " ------------\n" + " Ignore existing lfts : %d\n" + " Subnet Init errors : %d\n" + " In sweep hop 0 : %d\n" + " First time master sweep : %d\n" + " Coming out of standby : %d\n", + p_osm->subn.ignore_existing_lfts, + p_osm->subn.subnet_initialization_error, + p_osm->subn.in_sweep_hop_0, + p_osm->subn.first_time_master_sweep, + p_osm->subn.coming_out_of_standby); + fprintf(out, "\n"); + cl_plock_release(&p_osm->lock); + } +} + +static int loop_command_check_time(void) +{ + time_t cur = time(NULL); + if ((loop_command.previous + loop_command.delay_s) < cur) { + loop_command.previous = cur; + return (1); + } + return (0); +} + +static void status_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + char *p_cmd; + + p_cmd = next_token(p_last); + if (p_cmd) { + if (strcmp(p_cmd, "loop") == 0) { + fprintf(out, "Looping on status command...\n"); + fflush(out); + loop_command.on = 1; + loop_command.previous = time(NULL); + loop_command.loop_function = print_status; + } else { + help_status(out, 1); + return; + } + } + print_status(p_osm, out); +} + +static void resweep_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + char *p_cmd; + + p_cmd = next_token(p_last); + if (!p_cmd || + (strcmp(p_cmd, "heavy") != 0 && strcmp(p_cmd, "light") != 0)) { + fprintf(out, "Invalid resweep command\n"); + help_resweep(out, 1); + } else { + if (strcmp(p_cmd, "heavy") == 0) + p_osm->subn.force_heavy_sweep = TRUE; + osm_opensm_sweep(p_osm); + } +} + +static void reroute_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + p_osm->subn.force_reroute = TRUE; + osm_opensm_sweep(p_osm); +} + +static void logflush_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + fflush(p_osm->log.out_port); +} + +static void querylid_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + int p = 0; + uint16_t lid = 0; + osm_port_t *p_port = NULL; + char *p_cmd = next_token(p_last); + + if (!p_cmd) { + fprintf(out, "no LID specified\n"); + help_querylid(out, 1); + return; + } + + lid = (uint16_t) strtoul(p_cmd, NULL, 0); + cl_plock_acquire(&p_osm->lock); + if (lid > cl_ptr_vector_get_capacity(&(p_osm->subn.port_lid_tbl))) + goto invalid_lid; + p_port = cl_ptr_vector_get(&(p_osm->subn.port_lid_tbl), lid); + if (!p_port) + goto invalid_lid; + + fprintf(out, "Query results for LID %u\n", lid); + fprintf(out, + " GUID : 0x%016" PRIx64 "\n" + " Node Desc : %s\n" + " Node Type : %s\n" + " Num Ports : %d\n", + cl_ntoh64(p_port->guid), + p_port->p_node->print_desc, + ib_get_node_type_str(osm_node_get_type(p_port->p_node)), + p_port->p_node->node_info.num_ports); + + if (p_port->p_node->sw) + p = 0; + else + p = 1; + for ( /* see above */ ; p < p_port->p_node->physp_tbl_size; p++) { + fprintf(out, + " Port %d health : %s\n", + p, + p_port->p_node->physp_table[p]. + healthy ? "OK" : "ERROR"); + } + + cl_plock_release(&p_osm->lock); + return; + +invalid_lid: + cl_plock_release(&p_osm->lock); + fprintf(out, "Invalid lid %d\n", lid); + return; +} + +/** + * Data structures for the portstatus command + */ +typedef struct _port_report { + struct _port_report *next; + uint64_t node_guid; + uint8_t port_num; + char print_desc[IB_NODE_DESCRIPTION_SIZE + 1]; +} port_report_t; + +static void +__tag_port_report(port_report_t ** head, uint64_t node_guid, + uint8_t port_num, char *print_desc) +{ + port_report_t *rep = malloc(sizeof(*rep)); + if (!rep) + return; + + rep->node_guid = node_guid; + rep->port_num = port_num; + memcpy(rep->print_desc, print_desc, IB_NODE_DESCRIPTION_SIZE + 1); + rep->next = NULL; + if (*head) { + rep->next = *head; + *head = rep; + } else + *head = rep; +} + +static void __print_port_report(FILE * out, port_report_t * head) +{ + port_report_t *item = head; + while (item != NULL) { + fprintf(out, " 0x%016" PRIx64 " %d (%s)\n", + item->node_guid, item->port_num, item->print_desc); + port_report_t *next = item->next; + free(item); + item = next; + } +} + +typedef struct { + uint8_t node_type_lim; /* limit the results; 0 == ALL */ + uint64_t total_nodes; + uint64_t total_ports; + uint64_t ports_down; + uint64_t ports_active; + uint64_t ports_disabled; + port_report_t *disabled_ports; + uint64_t ports_1X; + uint64_t ports_4X; + uint64_t ports_8X; + uint64_t ports_12X; + uint64_t ports_unknown_width; + uint64_t ports_reduced_width; + port_report_t *reduced_width_ports; + uint64_t ports_sdr; + uint64_t ports_ddr; + uint64_t ports_qdr; + uint64_t ports_unknown_speed; + uint64_t ports_reduced_speed; + port_report_t *reduced_speed_ports; +} fabric_stats_t; + +/** + * iterator function to get portstatus on each node + */ +static void __get_stats(cl_map_item_t * const p_map_item, void *context) +{ + fabric_stats_t *fs = (fabric_stats_t *) context; + osm_node_t *node = (osm_node_t *) p_map_item; + uint8_t num_ports = osm_node_get_num_physp(node); + uint8_t port = 0; + + /* Skip nodes we are not interested in */ + if (fs->node_type_lim != 0 + && fs->node_type_lim != node->node_info.node_type) + return; + + fs->total_nodes++; + + for (port = 1; port < num_ports; port++) { + osm_physp_t *phys = osm_node_get_physp_ptr(node, port); + ib_port_info_t *pi = NULL; + uint8_t active_speed = 0; + uint8_t enabled_speed = 0; + uint8_t active_width = 0; + uint8_t enabled_width = 0; + uint8_t port_state = 0; + uint8_t port_phys_state = 0; + + if (!phys) + continue; + + pi = &(phys->port_info); + active_speed = ib_port_info_get_link_speed_active(pi); + enabled_speed = ib_port_info_get_link_speed_enabled(pi); + active_width = pi->link_width_active; + enabled_width = pi->link_width_enabled; + port_state = ib_port_info_get_port_state(pi); + port_phys_state = ib_port_info_get_port_phys_state(pi); + + if ((enabled_width ^ active_width) > active_width) { + __tag_port_report(&(fs->reduced_width_ports), + cl_ntoh64(node->node_info.node_guid), + port, node->print_desc); + fs->ports_reduced_width++; + } + + if ((enabled_speed ^ active_speed) > active_speed) { + __tag_port_report(&(fs->reduced_speed_ports), + cl_ntoh64(node->node_info.node_guid), + port, node->print_desc); + fs->ports_reduced_speed++; + } + + switch (active_speed) { + case IB_LINK_SPEED_ACTIVE_2_5: + fs->ports_sdr++; + break; + case IB_LINK_SPEED_ACTIVE_5: + fs->ports_ddr++; + break; + case IB_LINK_SPEED_ACTIVE_10: + fs->ports_qdr++; + break; + default: + fs->ports_unknown_speed++; + break; + } + switch (active_width) { + case IB_LINK_WIDTH_ACTIVE_1X: + fs->ports_1X++; + break; + case IB_LINK_WIDTH_ACTIVE_4X: + fs->ports_4X++; + break; + case IB_LINK_WIDTH_ACTIVE_8X: + fs->ports_8X++; + break; + case IB_LINK_WIDTH_ACTIVE_12X: + fs->ports_12X++; + break; + default: + fs->ports_unknown_width++; + break; + } + if (port_state == IB_LINK_DOWN) + fs->ports_down++; + else if (port_state == IB_LINK_ACTIVE) + fs->ports_active++; + if (port_phys_state == IB_PORT_PHYS_STATE_DISABLED) { + __tag_port_report(&(fs->disabled_ports), + cl_ntoh64(node->node_info.node_guid), + port, node->print_desc); + fs->ports_disabled++; + } + + fs->total_ports++; + } +} + +static void portstatus_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + fabric_stats_t fs; + struct timeval before, after; + char *p_cmd; + + memset(&fs, 0, sizeof(fs)); + + p_cmd = next_token(p_last); + if (p_cmd) { + if (strcmp(p_cmd, "ca") == 0) { + fs.node_type_lim = IB_NODE_TYPE_CA; + } else if (strcmp(p_cmd, "switch") == 0) { + fs.node_type_lim = IB_NODE_TYPE_SWITCH; + } else if (strcmp(p_cmd, "router") == 0) { + fs.node_type_lim = IB_NODE_TYPE_ROUTER; + } else { + fprintf(out, "Node type not understood\n"); + help_portstatus(out, 1); + return; + } + } + + gettimeofday(&before, NULL); + + /* for each node in the system gather the stats */ + cl_plock_acquire(&p_osm->lock); + cl_qmap_apply_func(&(p_osm->subn.node_guid_tbl), __get_stats, + (void *)&fs); + cl_plock_release(&p_osm->lock); + + gettimeofday(&after, NULL); + + /* report the stats */ + fprintf(out, "\"%s\" port status:\n", + fs.node_type_lim ? ib_get_node_type_str(fs. + node_type_lim) : "ALL"); + fprintf(out, + " %" PRIu64 " port(s) scanned on %" PRIu64 + " nodes in %lu us\n", fs.total_ports, fs.total_nodes, + after.tv_usec - before.tv_usec); + + if (fs.ports_down) + fprintf(out, " %" PRIu64 " down\n", fs.ports_down); + if (fs.ports_active) + fprintf(out, " %" PRIu64 " active\n", fs.ports_active); + if (fs.ports_1X) + fprintf(out, " %" PRIu64 " at 1X\n", fs.ports_1X); + if (fs.ports_4X) + fprintf(out, " %" PRIu64 " at 4X\n", fs.ports_4X); + if (fs.ports_8X) + fprintf(out, " %" PRIu64 " at 8X\n", fs.ports_8X); + if (fs.ports_12X) + fprintf(out, " %" PRIu64 " at 12X\n", fs.ports_12X); + + if (fs.ports_sdr) + fprintf(out, " %" PRIu64 " at 2.5 Gbps\n", fs.ports_sdr); + if (fs.ports_ddr) + fprintf(out, " %" PRIu64 " at 5.0 Gbps\n", fs.ports_ddr); + if (fs.ports_qdr) + fprintf(out, " %" PRIu64 " at 10.0 Gbps\n", fs.ports_qdr); + + if (fs.ports_disabled + fs.ports_reduced_speed + fs.ports_reduced_width + > 0) { + fprintf(out, "\nPossible issues:\n"); + } + if (fs.ports_disabled) { + fprintf(out, " %" PRIu64 " disabled\n", fs.ports_disabled); + __print_port_report(out, fs.disabled_ports); + } + if (fs.ports_reduced_speed) { + fprintf(out, " %" PRIu64 " with reduced speed\n", + fs.ports_reduced_speed); + __print_port_report(out, fs.reduced_speed_ports); + } + if (fs.ports_reduced_width) { + fprintf(out, " %" PRIu64 " with reduced width\n", + fs.ports_reduced_width); + __print_port_report(out, fs.reduced_width_ports); + } + fprintf(out, "\n"); +} + +static void switchbalance_check(osm_opensm_t * p_osm, + osm_switch_t * p_sw, FILE * out, int verbose) +{ + uint8_t port_num; + uint8_t num_ports; + const cl_qmap_t *p_port_tbl; + osm_port_t *p_port; + osm_physp_t *p_physp; + osm_physp_t *p_rem_physp; + osm_node_t *p_rem_node; + uint32_t count[255]; /* max ports is a uint8_t */ + uint8_t output_ports[255]; + uint8_t output_ports_count = 0; + uint32_t min_count = 0xFFFFFFFF; + uint32_t max_count = 0; + unsigned int i; + + memset(count, '\0', sizeof(uint32_t) * 255); + + /* Count port usage */ + p_port_tbl = &p_osm->subn.port_guid_tbl; + for (p_port = (osm_port_t *) cl_qmap_head(p_port_tbl); + p_port != (osm_port_t *) cl_qmap_end(p_port_tbl); + p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) { + uint16_t min_lid_ho; + uint16_t max_lid_ho; + uint16_t lid_ho; + + /* Don't count switches in port usage */ + if (osm_node_get_type(p_port->p_node) == IB_NODE_TYPE_SWITCH) + continue; + + osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); + + if (min_lid_ho == 0 || max_lid_ho == 0) + continue; + + for (lid_ho = min_lid_ho; lid_ho <= max_lid_ho; lid_ho++) { + port_num = osm_switch_get_port_by_lid(p_sw, lid_ho); + if (port_num == OSM_NO_PATH) + continue; + + count[port_num]++; + } + } + + num_ports = p_sw->num_ports; + for (port_num = 1; port_num < num_ports; port_num++) { + p_physp = osm_node_get_physp_ptr(p_sw->p_node, port_num); + + /* if port is down/unhealthy, don't consider it in + * min/max calculations + */ + if (!p_physp || !osm_physp_is_healthy(p_physp) + || !osm_physp_get_remote(p_physp)) + continue; + + p_rem_physp = osm_physp_get_remote(p_physp); + p_rem_node = osm_physp_get_node_ptr(p_rem_physp); + + /* If we are directly connected to a CA/router, its not really + * up for balancing consideration. + */ + if (osm_node_get_type(p_rem_node) != IB_NODE_TYPE_SWITCH) + continue; + + output_ports[output_ports_count] = port_num; + output_ports_count++; + + if (count[port_num] < min_count) + min_count = count[port_num]; + if (count[port_num] > max_count) + max_count = count[port_num]; + } + + if (verbose || ((max_count - min_count) > 1)) { + if ((max_count - min_count) > 1) + fprintf(out, + "Unbalanced Switch: 0x%016" PRIx64 " (%s)\n", + cl_ntoh64(p_sw->p_node->node_info.node_guid), + p_sw->p_node->print_desc); + else + fprintf(out, + "Switch: 0x%016" PRIx64 " (%s)\n", + cl_ntoh64(p_sw->p_node->node_info.node_guid), + p_sw->p_node->print_desc); + + for (i = 0; i < output_ports_count; i++) { + fprintf(out, + "Port %d: %d\n", + output_ports[i], count[output_ports[i]]); + } + } +} + +static void switchbalance_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + char *p_cmd; + uint64_t guid = 0; + osm_switch_t *p_sw; + int verbose = 0; + + p_cmd = next_token(p_last); + if (p_cmd) { + char *p_end; + + if (strcmp(p_cmd, "verbose") == 0) { + verbose++; + p_cmd = next_token(p_last); + } + + if (p_cmd) { + guid = strtoull(p_cmd, &p_end, 0); + if (!guid || *p_end != '\0') { + fprintf(out, "Invalid guid specified\n"); + help_switchbalance(out, 1); + return; + } + } + } + + cl_plock_acquire(&p_osm->lock); + if (guid) { + p_sw = osm_get_switch_by_guid(&p_osm->subn, cl_hton64(guid)); + if (!p_sw) { + fprintf(out, "guid not found\n"); + goto lock_exit; + } + + switchbalance_check(p_osm, p_sw, out, verbose); + } else { + cl_qmap_t *p_sw_guid_tbl = &p_osm->subn.sw_guid_tbl; + for (p_sw = (osm_switch_t *) cl_qmap_head(p_sw_guid_tbl); + p_sw != (osm_switch_t *) cl_qmap_end(p_sw_guid_tbl); + p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) + switchbalance_check(p_osm, p_sw, out, verbose); + } +lock_exit: + cl_plock_release(&p_osm->lock); + return; +} + +static void lidbalance_check(osm_opensm_t * p_osm, + osm_switch_t * p_sw, FILE * out) +{ + uint8_t port_num; + const cl_qmap_t *p_port_tbl; + osm_port_t *p_port; + + p_port_tbl = &p_osm->subn.port_guid_tbl; + for (p_port = (osm_port_t *) cl_qmap_head(p_port_tbl); + p_port != (osm_port_t *) cl_qmap_end(p_port_tbl); + p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) { + uint32_t port_count[255]; /* max ports is a uint8_t */ + osm_node_t *rem_node[255]; + uint32_t rem_node_count; + uint32_t rem_count[255]; + osm_physp_t *p_physp; + osm_physp_t *p_rem_physp; + osm_node_t *p_rem_node; + uint32_t port_min_count = 0xFFFFFFFF; + uint32_t port_max_count = 0; + uint32_t rem_min_count = 0xFFFFFFFF; + uint32_t rem_max_count = 0; + uint16_t min_lid_ho; + uint16_t max_lid_ho; + uint16_t lid_ho; + uint8_t num_ports; + unsigned int i; + + /* we only care about non-switches */ + if (osm_node_get_type(p_port->p_node) == IB_NODE_TYPE_SWITCH) + continue; + + osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); + + if (min_lid_ho == 0 || max_lid_ho == 0) + continue; + + memset(port_count, '\0', sizeof(uint32_t) * 255); + memset(rem_node, '\0', sizeof(osm_node_t *) * 255); + rem_node_count = 0; + memset(rem_count, '\0', sizeof(uint32_t) * 255); + + for (lid_ho = min_lid_ho; lid_ho <= max_lid_ho; lid_ho++) { + boolean_t rem_node_found = FALSE; + unsigned int indx = 0; + + port_num = osm_switch_get_port_by_lid(p_sw, lid_ho); + if (port_num == OSM_NO_PATH) + continue; + + p_physp = + osm_node_get_physp_ptr(p_sw->p_node, port_num); + + /* if port is down/unhealthy, can't calculate */ + if (!p_physp || !osm_physp_is_healthy(p_physp) + || !osm_physp_get_remote(p_physp)) + continue; + + p_rem_physp = osm_physp_get_remote(p_physp); + p_rem_node = osm_physp_get_node_ptr(p_rem_physp); + + /* determine if we've seen this remote node before. + * If not, store it. If yes, update the counter + */ + for (i = 0; i < rem_node_count; i++) { + if (rem_node[i] == p_rem_node) { + rem_node_found = TRUE; + indx = i; + break; + } + } + + if (!rem_node_found) { + rem_node[rem_node_count] = p_rem_node; + rem_count[rem_node_count]++; + indx = rem_node_count; + rem_node_count++; + } else + rem_count[indx]++; + + port_count[port_num]++; + } + + if (!rem_node_count) + continue; + + for (i = 0; i < rem_node_count; i++) { + if (rem_count[i] < rem_min_count) + rem_min_count = rem_count[i]; + if (rem_count[i] > rem_max_count) + rem_max_count = rem_count[i]; + } + + num_ports = p_sw->num_ports; + for (i = 0; i < num_ports; i++) { + if (!port_count[i]) + continue; + if (port_count[i] < port_min_count) + port_min_count = port_count[i]; + if (port_count[i] > port_max_count) + port_max_count = port_count[i]; + } + + /* Output if this CA/router is being forwarded an unbalanced number of + * times to a destination. + */ + if ((rem_max_count - rem_min_count) > 1) { + fprintf(out, + "Unbalanced Remote Forwarding: Switch 0x%016" + PRIx64 " (%s): ", + cl_ntoh64(p_sw->p_node->node_info.node_guid), + p_sw->p_node->print_desc); + if (osm_node_get_type(p_port->p_node) == + IB_NODE_TYPE_CA) + fprintf(out, "CA"); + else if (osm_node_get_type(p_port->p_node) == + IB_NODE_TYPE_ROUTER) + fprintf(out, "Router"); + fprintf(out, " 0x%016" PRIx64 " (%s): ", + cl_ntoh64(p_port->p_node->node_info.node_guid), + p_port->p_node->print_desc); + for (i = 0; i < rem_node_count; i++) { + fprintf(out, + "Dest 0x%016" PRIx64 "(%s) - %u ", + cl_ntoh64(rem_node[i]->node_info. + node_guid), + rem_node[i]->print_desc, rem_count[i]); + } + fprintf(out, "\n"); + } + + /* Output if this CA/router is being forwarded through a port + * an unbalanced number of times. + */ + if ((port_max_count - port_min_count) > 1) { + fprintf(out, + "Unbalanced Port Forwarding: Switch 0x%016" + PRIx64 " (%s): ", + cl_ntoh64(p_sw->p_node->node_info.node_guid), + p_sw->p_node->print_desc); + if (osm_node_get_type(p_port->p_node) == + IB_NODE_TYPE_CA) + fprintf(out, "CA"); + else if (osm_node_get_type(p_port->p_node) == + IB_NODE_TYPE_ROUTER) + fprintf(out, "Router"); + fprintf(out, " 0x%016" PRIx64 " (%s): ", + cl_ntoh64(p_port->p_node->node_info.node_guid), + p_port->p_node->print_desc); + for (i = 0; i < num_ports; i++) { + if (!port_count[i]) + continue; + fprintf(out, "Port %u - %u: ", i, + port_count[i]); + } + fprintf(out, "\n"); + } + } +} + +static void lidbalance_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + char *p_cmd; + uint64_t guid = 0; + osm_switch_t *p_sw; + + p_cmd = next_token(p_last); + if (p_cmd) { + char *p_end; + + guid = strtoull(p_cmd, &p_end, 0); + if (!guid || *p_end != '\0') { + fprintf(out, "Invalid switchguid specified\n"); + help_lidbalance(out, 1); + return; + } + } + + cl_plock_acquire(&p_osm->lock); + if (guid) { + p_sw = osm_get_switch_by_guid(&p_osm->subn, cl_hton64(guid)); + if (!p_sw) { + fprintf(out, "switchguid not found\n"); + goto lock_exit; + } + lidbalance_check(p_osm, p_sw, out); + } else { + cl_qmap_t *p_sw_guid_tbl = &p_osm->subn.sw_guid_tbl; + for (p_sw = (osm_switch_t *) cl_qmap_head(p_sw_guid_tbl); + p_sw != (osm_switch_t *) cl_qmap_end(p_sw_guid_tbl); + p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) + lidbalance_check(p_osm, p_sw, out); + } + +lock_exit: + cl_plock_release(&p_osm->lock); + return; +} + +static void dump_conf_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + osm_subn_output_conf(out, &p_osm->subn.opt); +} + +#ifdef ENABLE_OSM_PERF_MGR +static void perfmgr_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + char *p_cmd; + + p_cmd = next_token(p_last); + if (p_cmd) { + if (strcmp(p_cmd, "enable") == 0) { + osm_perfmgr_set_state(&(p_osm->perfmgr), + PERFMGR_STATE_ENABLED); + } else if (strcmp(p_cmd, "disable") == 0) { + osm_perfmgr_set_state(&(p_osm->perfmgr), + PERFMGR_STATE_DISABLE); + } else if (strcmp(p_cmd, "clear_counters") == 0) { + osm_perfmgr_clear_counters(&(p_osm->perfmgr)); + } else if (strcmp(p_cmd, "dump_counters") == 0) { + p_cmd = next_token(p_last); + if (p_cmd && (strcmp(p_cmd, "mach") == 0)) { + osm_perfmgr_dump_counters(&(p_osm->perfmgr), + PERFMGR_EVENT_DB_DUMP_MR); + } else { + osm_perfmgr_dump_counters(&(p_osm->perfmgr), + PERFMGR_EVENT_DB_DUMP_HR); + } + } else if (strcmp(p_cmd, "print_counters") == 0) { + p_cmd = next_token(p_last); + if (p_cmd) { + osm_perfmgr_print_counters(&(p_osm->perfmgr), + p_cmd, out); + } else { + fprintf(out, + "print_counters requires a node name to be specified\n"); + } + } else if (strcmp(p_cmd, "sweep_time") == 0) { + p_cmd = next_token(p_last); + if (p_cmd) { + uint16_t time_s = atoi(p_cmd); + osm_perfmgr_set_sweep_time_s(&(p_osm->perfmgr), + time_s); + } else { + fprintf(out, + "sweep_time requires a time period (in seconds) to be specified\n"); + } + } else { + fprintf(out, "\"%s\" option not found\n", p_cmd); + } + } else { + fprintf(out, "Performance Manager status:\n" + "state : %s\n" + "sweep state : %s\n" + "sweep time : %us\n" + "outstanding queries/max : %d/%u\n", + osm_perfmgr_get_state_str(&(p_osm->perfmgr)), + osm_perfmgr_get_sweep_state_str(&(p_osm->perfmgr)), + osm_perfmgr_get_sweep_time_s(&(p_osm->perfmgr)), + p_osm->perfmgr.outstanding_queries, + p_osm->perfmgr.max_outstanding_queries); + } +} +#endif /* ENABLE_OSM_PERF_MGR */ + +static void quit_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + osm_console_exit(&p_osm->console, &p_osm->log); +} + +static void help_version(FILE * out, int detail) +{ + fprintf(out, "version -- print the OSM version\n"); +} + +static void version_parse(char **p_last, osm_opensm_t * p_osm, FILE * out) +{ + fprintf(out, "%s build %s %s\n", p_osm->osm_version, __DATE__, __TIME__); +} + +/* more parse routines go here */ + +static const struct command console_cmds[] = { + {"help", &help_command, &help_parse}, + {"quit", &help_quit, &quit_parse}, + {"loglevel", &help_loglevel, &loglevel_parse}, + {"priority", &help_priority, &priority_parse}, + {"resweep", &help_resweep, &resweep_parse}, + {"reroute", &help_reroute, &reroute_parse}, + {"status", &help_status, &status_parse}, + {"logflush", &help_logflush, &logflush_parse}, + {"querylid", &help_querylid, &querylid_parse}, + {"portstatus", &help_portstatus, &portstatus_parse}, + {"switchbalance", &help_switchbalance, &switchbalance_parse}, + {"lidbalance", &help_lidbalance, &lidbalance_parse}, + {"dump_conf", &help_dump_conf, &dump_conf_parse}, + {"version", &help_version, &version_parse}, +#ifdef ENABLE_OSM_PERF_MGR + {"perfmgr", &help_perfmgr, &perfmgr_parse}, +#endif /* ENABLE_OSM_PERF_MGR */ + {NULL, NULL, NULL} /* end of array */ +}; + +static void parse_cmd_line(char *line, osm_opensm_t * p_osm) +{ + char *p_cmd, *p_last; + int i, found = 0; + FILE *out = p_osm->console.out; + + while (isspace(*line)) + line++; + if (!*line) + return; + + /* find first token which is the command */ + p_cmd = strtok_r(line, " \t\n\r", &p_last); + if (p_cmd) { + for (i = 0; console_cmds[i].name; i++) { + if (loop_command.on) { + if (!strcmp(p_cmd, "q")) { + loop_command.on = 0; + } + found = 1; + break; + } + if (!strcmp(p_cmd, console_cmds[i].name)) { + found = 1; + console_cmds[i].parse_function(&p_last, p_osm, + out); + break; + } + } + if (!found) { + fprintf(out, "%s : Command not found\n\n", p_cmd); + help_command(out, 0); + } + } else { + fprintf(out, "Error parsing command line: `%s'\n", line); + } + if (loop_command.on) { + fprintf(out, "use \"q\" to quit loop\n"); + fflush(out); + } +} + +void osm_console(osm_opensm_t * p_osm) +{ + struct pollfd pollfd[2]; + char *p_line; + size_t len; + ssize_t n; + struct pollfd *fds; + nfds_t nfds; + osm_console_t *p_oct = &p_osm->console; + osm_log_t *p_log = &p_osm->log; + + pollfd[0].fd = p_oct->socket; + pollfd[0].events = POLLIN; + pollfd[0].revents = 0; + + pollfd[1].fd = p_oct->in_fd; + pollfd[1].events = POLLIN; + pollfd[1].revents = 0; + + fds = p_oct->socket < 0 ? &pollfd[1] : pollfd; + nfds = p_oct->socket < 0 || pollfd[1].fd < 0 ? 1 : 2; + + if (loop_command.on && loop_command_check_time() && + loop_command.loop_function) { + if (p_oct->out) { + loop_command.loop_function(p_osm, p_oct->out); + fflush(p_oct->out); + } else { + loop_command.on = 0; + } + } + + if (poll(fds, nfds, 1000) <= 0) + return; + +#ifdef ENABLE_OSM_CONSOLE_SOCKET + if (pollfd[0].revents & POLLIN) { + int new_fd = 0; + struct sockaddr_in sin; + socklen_t len = sizeof(sin); + struct hostent *hent; + if ((new_fd = accept(p_oct->socket, &sin, &len)) < 0) { + OSM_LOG(p_log, OSM_LOG_ERROR, + "ERR 4B04: Failed to accept console socket: %s\n", + strerror(errno)); + p_oct->in_fd = -1; + return; + } + if (inet_ntop + (AF_INET, &sin.sin_addr, p_oct->client_ip, + sizeof(p_oct->client_ip)) == NULL) { + snprintf(p_oct->client_ip, 64, "STRING_UNKNOWN"); + } + if ((hent = gethostbyaddr((const char *)&sin.sin_addr, + sizeof(struct in_addr), + AF_INET)) == NULL) { + snprintf(p_oct->client_hn, 128, "STRING_UNKNOWN"); + } else { + snprintf(p_oct->client_hn, 128, "%s", hent->h_name); + } + if (is_authorized(p_oct)) { + cio_open(p_oct, new_fd, p_log); + } else { + OSM_LOG(p_log, OSM_LOG_ERROR, + "ERR 4B05: Console connection denied: %s (%s)\n", + p_oct->client_hn, p_oct->client_ip); + close(new_fd); + } + return; + } +#endif + + if (pollfd[1].revents & POLLIN) { + p_line = NULL; + /* Get input line */ + n = getline(&p_line, &len, p_oct->in); + if (n > 0) { + /* Parse and act on input */ + parse_cmd_line(p_line, p_osm); + if (!loop_command.on) { + osm_console_prompt(p_oct->out); + } + } else + osm_console_exit(p_oct, p_log); + if (p_line) + free(p_line); + } +} diff --git a/contrib/ofed/management/opensm/opensm/osm_console_io.c b/contrib/ofed/management/opensm/opensm/osm_console_io.c new file mode 100644 index 000000000000..3d3ece461ed1 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_console_io.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2005-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2008 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Provide a framework for the Console which decouples the connection + * or I/O from the functionality, or commands. + * + * Extensible - allows a variety of connection methods independent of + * the console commands. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE /* for getline */ +#ifdef ENABLE_OSM_CONSOLE_SOCKET +#include +#include +#include +#include +#endif +#include +#include +#include +#include + +static int is_local(char *str) +{ + // convenience - checks if just stdin/stdout + if (str) + return (strcmp(str, OSM_LOCAL_CONSOLE) == 0); + return 0; +} + +static int is_loopback(char *str) +{ + // convenience - checks if socket based connection + if (str) + return (strcmp(str, OSM_LOOPBACK_CONSOLE) == 0); + return 0; +} + +static int is_remote(char *str) +{ + // convenience - checks if socket based connection + if (str) + return (strcmp(str, OSM_REMOTE_CONSOLE) == 0) + || is_loopback(str); + return 0; +} + +int is_console_enabled(osm_subn_opt_t * p_opt) +{ + // checks for a variety of types of consoles - default is off or 0 + if (p_opt) + return (is_local(p_opt->console) + || is_loopback(p_opt->console) + || is_remote(p_opt->console)); + return 0; +} + + +#ifdef ENABLE_OSM_CONSOLE_SOCKET +static int cio_close(osm_console_t * p_oct) +{ + int rtnval = -1; + if (p_oct && (p_oct->in_fd > 0)) { + rtnval = close(p_oct->in_fd); + p_oct->in_fd = -1; + p_oct->out_fd = -1; + p_oct->in = NULL; + p_oct->out = NULL; + } + return rtnval; +} +#endif + +/* close the connection */ +static void osm_console_close(osm_console_t * p_oct, osm_log_t * p_log) +{ +#ifdef ENABLE_OSM_CONSOLE_SOCKET + if ((p_oct->socket > 0) && (p_oct->in_fd != -1)) { + OSM_LOG(p_log, OSM_LOG_INFO, + "Console connection closed: %s (%s)\n", + p_oct->client_hn, p_oct->client_ip); + cio_close(p_oct); + } + if (p_oct->socket > 0) { + close(p_oct->socket); + p_oct->socket = -1; + } +#endif +} + + +/********************************************************************** + * Do authentication & authorization check + **********************************************************************/ +#ifdef ENABLE_OSM_CONSOLE_SOCKET +int is_authorized(osm_console_t * p_oct) +{ + /* allowed to use the console? */ + p_oct->authorized = !is_remote(p_oct->client_type) || + hosts_ctl(OSM_DAEMON_NAME, p_oct->client_hn, p_oct->client_ip, + "STRING_UNKNOWN"); + return p_oct->authorized; +} +#endif + +void osm_console_prompt(FILE * out) +{ + if (out) { + fprintf(out, "OpenSM %s", OSM_COMMAND_PROMPT); + fflush(out); + } +} + +int osm_console_init(osm_subn_opt_t * opt, osm_console_t * p_oct, osm_log_t * p_log) +{ + p_oct->socket = -1; + strncpy(p_oct->client_type, opt->console, sizeof(p_oct->client_type)); + + /* set up the file descriptors for the console */ + if (strcmp(opt->console, OSM_LOCAL_CONSOLE) == 0) { + p_oct->in = stdin; + p_oct->out = stdout; + p_oct->in_fd = fileno(stdin); + p_oct->out_fd = fileno(stdout); + + osm_console_prompt(p_oct->out); +#ifdef ENABLE_OSM_CONSOLE_SOCKET + } else if (strcmp(opt->console, OSM_REMOTE_CONSOLE) == 0 + || strcmp(opt->console, OSM_LOOPBACK_CONSOLE) == 0) { + struct sockaddr_in sin; + int optval = 1; + + if ((p_oct->socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + OSM_LOG(p_log, OSM_LOG_ERROR, + "ERR 4B01: Failed to open console socket: %s\n", + strerror(errno)); + return -1; + } + setsockopt(p_oct->socket, SOL_SOCKET, SO_REUSEADDR, + &optval, sizeof(optval)); + sin.sin_family = AF_INET; + sin.sin_port = htons(opt->console_port); + if (strcmp(opt->console, OSM_REMOTE_CONSOLE) == 0) + sin.sin_addr.s_addr = htonl(INADDR_ANY); + else + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + if (bind(p_oct->socket, &sin, sizeof(sin)) < 0) { + OSM_LOG(p_log, OSM_LOG_ERROR, + "ERR 4B02: Failed to bind console socket: %s\n", + strerror(errno)); + return -1; + } + if (listen(p_oct->socket, 1) < 0) { + OSM_LOG(p_log, OSM_LOG_ERROR, + "ERR 4B03: Failed to listen on socket: %s\n", + strerror(errno)); + return -1; + } + + signal(SIGPIPE, SIG_IGN); /* protect ourselves from closed pipes */ + p_oct->in = NULL; + p_oct->out = NULL; + p_oct->in_fd = -1; + p_oct->out_fd = -1; + OSM_LOG(p_log, OSM_LOG_INFO, + "Console listening on port %d\n", opt->console_port); +#endif + } + + return 0; +} + +/* clean up and release resources */ +void osm_console_exit(osm_console_t * p_oct, osm_log_t * p_log) +{ + // clean up and release resources, currently just close the socket + osm_console_close(p_oct, p_log); +} + +#ifdef ENABLE_OSM_CONSOLE_SOCKET +int cio_open(osm_console_t * p_oct, int new_fd, osm_log_t * p_log) +{ + // returns zero if opened fine, -1 otherwise + char *p_line; + size_t len; + ssize_t n; + + if (p_oct->in_fd >= 0) { + FILE *file = fdopen(new_fd, "w+"); + + fprintf(file, "OpenSM Console connection already in use\n" + " kill other session (y/n)? "); + fflush(file); + p_line = NULL; + n = getline(&p_line, &len, file); + if (n > 0 && (p_line[0] == 'y' || p_line[0] == 'Y')) { + osm_console_close(p_oct, p_log); + } else { + OSM_LOG(p_log, OSM_LOG_INFO, + "Console connection aborted: %s (%s)\n", + p_oct->client_hn, p_oct->client_ip); + close(new_fd); + return -1; + } + } + p_oct->in_fd = new_fd; + p_oct->out_fd = p_oct->in_fd; + p_oct->in = fdopen(p_oct->in_fd, "w+"); + p_oct->out = p_oct->in; + osm_console_prompt(p_oct->out); + OSM_LOG(p_log, OSM_LOG_INFO, + "Console connection accepted: %s (%s)\n", + p_oct->client_hn, p_oct->client_ip); + + return (p_oct->in == NULL) ? -1 : 0; +} +#endif diff --git a/contrib/ofed/management/opensm/opensm/osm_db_files.c b/contrib/ofed/management/opensm/opensm/osm_db_files.c new file mode 100644 index 000000000000..907b7c77aceb --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_db_files.c @@ -0,0 +1,723 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of the osm_db interface using simple text files + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +/****d* Database/OSM_DB_MAX_LINE_LEN + * NAME + * OSM_DB_MAX_LINE_LEN + * + * DESCRIPTION + * The Maximal line length allowed for the file + * + * SYNOPSIS + */ +#define OSM_DB_MAX_LINE_LEN 1024 +/**********/ + +/****d* Database/OSM_DB_MAX_GUID_LEN + * NAME + * OSM_DB_MAX_GUID_LEN + * + * DESCRIPTION + * The Maximal word length allowed for the file (guid or lid) + * + * SYNOPSIS + */ +#define OSM_DB_MAX_GUID_LEN 32 +/**********/ + +/****s* OpenSM: Database/osm_db_domain_imp + * NAME + * osm_db_domain_imp + * + * DESCRIPTION + * An implementation for domain of the database based on text files and + * hash tables. + * + * SYNOPSIS + */ +typedef struct osm_db_domain_imp { + char *file_name; + st_table *p_hash; + cl_spinlock_t lock; +} osm_db_domain_imp_t; +/* + * FIELDS + * + * SEE ALSO + * osm_db_domain_t + *********/ + +/****s* OpenSM: Database/osm_db_imp_t + * NAME + * osm_db_imp_t + * + * DESCRIPTION + * An implementation for file based database + * + * SYNOPSIS + */ +typedef struct osm_db_imp { + char *db_dir_name; +} osm_db_imp_t; +/* + * FIELDS + * + * db_dir_name + * The directory holding the database + * + * SEE ALSO + * osm_db_t + *********/ + +/*************************************************************************** + ***************************************************************************/ +void osm_db_construct(IN osm_db_t * const p_db) +{ + memset(p_db, 0, sizeof(osm_db_t)); + cl_list_construct(&p_db->domains); +} + +/*************************************************************************** + ***************************************************************************/ +void osm_db_domain_destroy(IN osm_db_domain_t * const p_db_domain) +{ + osm_db_domain_imp_t *p_domain_imp; + p_domain_imp = (osm_db_domain_imp_t *) p_db_domain->p_domain_imp; + + osm_db_clear(p_db_domain); + + cl_spinlock_destroy(&p_domain_imp->lock); + + st_free_table(p_domain_imp->p_hash); + free(p_domain_imp->file_name); + free(p_domain_imp); +} + +/*************************************************************************** + ***************************************************************************/ +void osm_db_destroy(IN osm_db_t * const p_db) +{ + osm_db_domain_t *p_domain; + + while ((p_domain = cl_list_remove_head(&p_db->domains)) != NULL) { + osm_db_domain_destroy(p_domain); + free(p_domain); + } + cl_list_destroy(&p_db->domains); + free(p_db->p_db_imp); +} + +/*************************************************************************** + ***************************************************************************/ +int osm_db_init(IN osm_db_t * const p_db, IN osm_log_t * p_log) +{ + osm_db_imp_t *p_db_imp; + struct stat dstat; + + OSM_LOG_ENTER(p_log); + + p_db_imp = (osm_db_imp_t *) malloc(sizeof(osm_db_imp_t)); + CL_ASSERT(p_db_imp != NULL); + + p_db_imp->db_dir_name = getenv("OSM_CACHE_DIR"); + if (!p_db_imp->db_dir_name || !(*p_db_imp->db_dir_name)) + p_db_imp->db_dir_name = OSM_DEFAULT_CACHE_DIR; + + /* Create the directory if it doesn't exist */ + /* There is a difference in creating directory between windows and linux */ +#ifdef __WIN__ + /* Check if the directory exists. If not - create it. */ + CreateDirectory(p_db_imp->db_dir_name, NULL); +#else /* __WIN__ */ + /* make sure the directory exists */ + if (lstat(p_db_imp->db_dir_name, &dstat)) { + if (mkdir(p_db_imp->db_dir_name, 0755)) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6101: " + "Failed to create the db directory:%s\n", + p_db_imp->db_dir_name); + OSM_LOG_EXIT(p_log); + return 1; + } + } +#endif + + p_db->p_log = p_log; + p_db->p_db_imp = (void *)p_db_imp; + + cl_list_init(&p_db->domains, 5); + + OSM_LOG_EXIT(p_log); + + return 0; +} + +/*************************************************************************** + ***************************************************************************/ +osm_db_domain_t *osm_db_domain_init(IN osm_db_t * const p_db, + IN char *domain_name) +{ + osm_db_domain_t *p_domain; + osm_db_domain_imp_t *p_domain_imp; + int dir_name_len; + osm_log_t *p_log = p_db->p_log; + FILE *p_file; + + OSM_LOG_ENTER(p_log); + + /* allocate a new domain object */ + p_domain = (osm_db_domain_t *) malloc(sizeof(osm_db_domain_t)); + CL_ASSERT(p_domain != NULL); + + p_domain_imp = + (osm_db_domain_imp_t *) malloc(sizeof(osm_db_domain_imp_t)); + CL_ASSERT(p_domain_imp != NULL); + + dir_name_len = strlen(((osm_db_imp_t *) p_db->p_db_imp)->db_dir_name); + + /* set the domain file name */ + p_domain_imp->file_name = + (char *)malloc(sizeof(char) * (dir_name_len) + strlen(domain_name) + + 2); + CL_ASSERT(p_domain_imp->file_name != NULL); + strcpy(p_domain_imp->file_name, + ((osm_db_imp_t *) p_db->p_db_imp)->db_dir_name); + strcat(p_domain_imp->file_name, domain_name); + + /* make sure the file exists - or exit if not writable */ + p_file = fopen(p_domain_imp->file_name, "a+"); + if (!p_file) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6102: " + "Failed to open the db file:%s\n", + p_domain_imp->file_name); + free(p_domain_imp); + free(p_domain); + p_domain = NULL; + goto Exit; + } + fclose(p_file); + + /* initialize the hash table object */ + p_domain_imp->p_hash = st_init_strtable(); + CL_ASSERT(p_domain_imp->p_hash != NULL); + + p_domain->p_db = p_db; + cl_list_insert_tail(&p_db->domains, p_domain); + p_domain->p_domain_imp = p_domain_imp; + cl_spinlock_construct(&p_domain_imp->lock); + cl_spinlock_init(&p_domain_imp->lock); + +Exit: + OSM_LOG_EXIT(p_log); + return p_domain; +} + +/*************************************************************************** + ***************************************************************************/ +int osm_db_restore(IN osm_db_domain_t * p_domain) +{ + + osm_log_t *p_log = p_domain->p_db->p_log; + osm_db_domain_imp_t *p_domain_imp = + (osm_db_domain_imp_t *) p_domain->p_domain_imp; + FILE *p_file; + int status; + char sLine[OSM_DB_MAX_LINE_LEN]; + boolean_t before_key; + char *p_first_word, *p_rest_of_line, *p_last; + char *p_key = NULL; + char *p_prev_val, *p_accum_val = NULL; + char *endptr = NULL; + unsigned int line_num; + + OSM_LOG_ENTER(p_log); + + /* take the lock on the domain */ + cl_spinlock_acquire(&p_domain_imp->lock); + + /* open the file - read mode */ + p_file = fopen(p_domain_imp->file_name, "r"); + + if (!p_file) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6103: " + "Failed to open the db file:%s\n", + p_domain_imp->file_name); + status = 1; + goto Exit; + } + + /* parse the file allocating new hash tables as required */ + /* + states: + before_key (0) -> in_key (1) + + before_key: if a word on the first byte - it is the key. state=in_key + the rest of the line is start of the value. + in_key: unless the line is empty - add it (with newlines) to the value. + if empty: state=before_key + */ + status = 0; + before_key = TRUE; + line_num = 0; + /* if we got to EOF in the middle of a key we add a last newline */ + while ((fgets(sLine, OSM_DB_MAX_LINE_LEN, p_file) != NULL) || + ((before_key == FALSE) && strcpy(sLine, "\n")) + ) { + line_num++; + if (before_key) { + if ((sLine[0] != ' ') && (sLine[0] != '\t') + && (sLine[0] != '\n')) { + /* we got a new key */ + before_key = FALSE; + + /* handle the key */ + p_first_word = + strtok_r(sLine, " \t\n", &p_last); + if (!p_first_word) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6104: " + "Failed to get key from line:%u : %s (file:%s)\n", + line_num, sLine, + p_domain_imp->file_name); + status = 1; + goto EndParsing; + } + if (strlen(p_first_word) > OSM_DB_MAX_GUID_LEN) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 610A: " + "Illegal key from line:%u : %s (file:%s)\n", + line_num, sLine, + p_domain_imp->file_name); + status = 1; + goto EndParsing; + } + + p_key = + (char *)malloc(sizeof(char) * + (strlen(p_first_word) + 1)); + strcpy(p_key, p_first_word); + + p_rest_of_line = strtok_r(NULL, "\n", &p_last); + if (p_rest_of_line != NULL) { + p_accum_val = + (char *)malloc(sizeof(char) * + (strlen + (p_rest_of_line) + + 1)); + strcpy(p_accum_val, p_rest_of_line); + } else { + p_accum_val = (char *)malloc(2); + strcpy(p_accum_val, "\0"); + } + } else if (sLine[0] != '\n') { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6105: " + "How did we get here? line:%u : %s (file:%s)\n", + line_num, sLine, + p_domain_imp->file_name); + status = 1; + goto EndParsing; + } + } /* before key */ + else { + /* we already have a key */ + + if (sLine[0] == '\n') { + /* got an end of key */ + before_key = TRUE; + + /* make sure the key was not previously used */ + if (st_lookup(p_domain_imp->p_hash, + (st_data_t) p_key, + (void *) & p_prev_val)) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6106: " + "Key:%s already exists in:%s with value:%s." + " Removing it\n", + p_key, + p_domain_imp->file_name, + p_prev_val); + } else { + p_prev_val = NULL; + } + + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Got key:%s value:%s\n", p_key, + p_accum_val); + + /* check that the key is a number */ + if (!strtouq(p_key, &endptr, 0) + && *endptr != '\0') { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 610B: " + "Key:%s is invalid\n", p_key); + } else { + /* store our key and value */ + st_insert(p_domain_imp->p_hash, + (st_data_t) p_key, + (st_data_t) p_accum_val); + } + } else { + /* accumulate into the value */ + p_prev_val = p_accum_val; + p_accum_val = + (char *)malloc(strlen(p_prev_val) + + strlen(sLine) + 1); + strcpy(p_accum_val, p_prev_val); + free(p_prev_val); + strcat(p_accum_val, sLine); + } + } /* in key */ + } /* while lines or last line */ + +EndParsing: + fclose(p_file); + +Exit: + cl_spinlock_release(&p_domain_imp->lock); + OSM_LOG_EXIT(p_log); + return status; +} + +/*************************************************************************** + ***************************************************************************/ +static int __osm_dump_tbl_entry(st_data_t key, st_data_t val, st_data_t arg) +{ + FILE *p_file = (FILE *) arg; + char *p_key = (char *)key; + char *p_val = (char *)val; + + fprintf(p_file, "%s %s\n\n", p_key, p_val); + return ST_CONTINUE; +} + +int osm_db_store(IN osm_db_domain_t * p_domain) +{ + osm_log_t *p_log = p_domain->p_db->p_log; + osm_db_domain_imp_t *p_domain_imp; + FILE *p_file; + int status = 0; + char *p_tmp_file_name; + + OSM_LOG_ENTER(p_log); + + p_domain_imp = (osm_db_domain_imp_t *) p_domain->p_domain_imp; + p_tmp_file_name = + (char *)malloc(sizeof(char) * + (strlen(p_domain_imp->file_name) + 8)); + strcpy(p_tmp_file_name, p_domain_imp->file_name); + strcat(p_tmp_file_name, ".tmp"); + + cl_spinlock_acquire(&p_domain_imp->lock); + + /* open up the output file */ + p_file = fopen(p_tmp_file_name, "w"); + if (!p_file) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6107: " + "Failed to open the db file:%s for writing\n", + p_domain_imp->file_name); + status = 1; + goto Exit; + } + + st_foreach(p_domain_imp->p_hash, __osm_dump_tbl_entry, + (st_data_t) p_file); + fclose(p_file); + + /* move the domain file */ + status = remove(p_domain_imp->file_name); + if (status) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6109: " + "Failed to remove file:%s (err:%u)\n", + p_domain_imp->file_name, status); + } + + status = rename(p_tmp_file_name, p_domain_imp->file_name); + if (status) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6108: " + "Failed to rename the db file to:%s (err:%u)\n", + p_domain_imp->file_name, status); + } +Exit: + cl_spinlock_release(&p_domain_imp->lock); + free(p_tmp_file_name); + OSM_LOG_EXIT(p_log); + return status; +} + +/*************************************************************************** + ***************************************************************************/ +/* simply de-allocate the key and the value and return the code + that makes the st_foreach delete the entry */ +static int __osm_clear_tbl_entry(st_data_t key, st_data_t val, st_data_t arg) +{ + free((char *)key); + free((char *)val); + return ST_DELETE; +} + +int osm_db_clear(IN osm_db_domain_t * p_domain) +{ + osm_db_domain_imp_t *p_domain_imp = + (osm_db_domain_imp_t *) p_domain->p_domain_imp; + + cl_spinlock_acquire(&p_domain_imp->lock); + st_foreach(p_domain_imp->p_hash, __osm_clear_tbl_entry, + (st_data_t) NULL); + cl_spinlock_release(&p_domain_imp->lock); + + return 0; +} + +/*************************************************************************** + ***************************************************************************/ +static int __osm_get_key_of_tbl_entry(st_data_t key, st_data_t val, + st_data_t arg) +{ + cl_list_t *p_list = (cl_list_t *) arg; + cl_list_insert_tail(p_list, (void *)key); + return ST_CONTINUE; +} + +int osm_db_keys(IN osm_db_domain_t * p_domain, OUT cl_list_t * p_key_list) +{ + osm_db_domain_imp_t *p_domain_imp = + (osm_db_domain_imp_t *) p_domain->p_domain_imp; + + cl_spinlock_acquire(&p_domain_imp->lock); + + st_foreach(p_domain_imp->p_hash, + __osm_get_key_of_tbl_entry, (st_data_t) p_key_list); + + cl_spinlock_release(&p_domain_imp->lock); + + return 0; +} + +/*************************************************************************** + ***************************************************************************/ +char *osm_db_lookup(IN osm_db_domain_t * p_domain, IN char *const p_key) +{ + osm_db_domain_imp_t *p_domain_imp = + (osm_db_domain_imp_t *) p_domain->p_domain_imp; + char *p_val = NULL; + + cl_spinlock_acquire(&p_domain_imp->lock); + + if (!st_lookup + (p_domain_imp->p_hash, (st_data_t) p_key, (void *) & p_val)) + p_val = NULL; + + cl_spinlock_release(&p_domain_imp->lock); + + return p_val; +} + +/*************************************************************************** + ***************************************************************************/ +int +osm_db_update(IN osm_db_domain_t * p_domain, + IN char *const p_key, IN char *const p_val) +{ + osm_log_t *p_log = p_domain->p_db->p_log; + osm_db_domain_imp_t *p_domain_imp = + (osm_db_domain_imp_t *) p_domain->p_domain_imp; + char *p_prev_val = NULL; + char *p_new_key; + char *p_new_val; + + cl_spinlock_acquire(&p_domain_imp->lock); + + if (st_lookup(p_domain_imp->p_hash, + (st_data_t) p_key, (void *) & p_prev_val)) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Key:%s previously exists in:%s with value:%s\n", + p_key, p_domain_imp->file_name, p_prev_val); + p_new_key = p_key; + } else { + /* need to allocate the key */ + p_new_key = malloc(sizeof(char) * (strlen(p_key) + 1)); + strcpy(p_new_key, p_key); + } + + /* need to arange a new copy of the value */ + p_new_val = malloc(sizeof(char) * (strlen(p_val) + 1)); + strcpy(p_new_val, p_val); + + st_insert(p_domain_imp->p_hash, (st_data_t) p_new_key, + (st_data_t) p_new_val); + + if (p_prev_val) + free(p_prev_val); + + cl_spinlock_release(&p_domain_imp->lock); + + return 0; +} + +/*************************************************************************** + ***************************************************************************/ +int osm_db_delete(IN osm_db_domain_t * p_domain, IN char *const p_key) +{ + osm_log_t *p_log = p_domain->p_db->p_log; + osm_db_domain_imp_t *p_domain_imp = + (osm_db_domain_imp_t *) p_domain->p_domain_imp; + char *p_prev_val = NULL; + int res; + + OSM_LOG_ENTER(p_log); + + cl_spinlock_acquire(&p_domain_imp->lock); + if (st_delete(p_domain_imp->p_hash, + (void *) & p_key, (void *) & p_prev_val)) { + if (st_lookup(p_domain_imp->p_hash, + (st_data_t) p_key, (void *) & p_prev_val)) { + OSM_LOG(p_log, OSM_LOG_ERROR, + "key:%s still exists in:%s with value:%s\n", + p_key, p_domain_imp->file_name, p_prev_val); + res = 1; + } else { + free(p_key); + free(p_prev_val); + res = 0; + } + } else { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "fail to find key:%s. delete failed\n", p_key); + res = 1; + } + cl_spinlock_release(&p_domain_imp->lock); + + OSM_LOG_EXIT(p_log); + return res; +} + +#ifdef TEST_OSMDB +#include +#include + +int main(int argc, char **argv) +{ + osm_db_t db; + osm_log_t log; + osm_db_domain_t *p_dbd; + cl_list_t keys; + cl_list_iterator_t kI; + char *p_key; + char *p_val; + int i; + + cl_list_construct(&keys); + cl_list_init(&keys, 10); + + osm_log_init_v2(&log, TRUE, 0xff, "/var/log/osm_db_test.log", 0, FALSE); + + osm_db_construct(&db); + if (osm_db_init(&db, &log)) { + printf("db init failed\n"); + exit(1); + } + + p_dbd = osm_db_domain_init(&db, "lid_by_guid"); + + if (osm_db_restore(p_dbd)) { + printf("failed to restore\n"); + } + + if (osm_db_keys(p_dbd, &keys)) { + printf("failed to get keys\n"); + } else { + kI = cl_list_head(&keys); + while (kI != cl_list_end(&keys)) { + p_key = cl_list_obj(kI); + kI = cl_list_next(kI); + + p_val = osm_db_lookup(p_dbd, p_key); + printf("key = %s val = %s\n", p_key, p_val); + } + } + + cl_list_remove_all(&keys); + + /* randomly add and remove numbers */ + for (i = 0; i < 10; i++) { + int k; + float v; + int is_add; + char val_buf[16]; + char key_buf[16]; + + k = floor(1.0 * rand() / RAND_MAX * 100); + v = rand(); + sprintf(key_buf, "%u", k); + sprintf(val_buf, "%u", v); + + is_add = (rand() < RAND_MAX / 2); + + if (is_add) { + osm_db_update(p_dbd, key_buf, val_buf); + } else { + osm_db_delete(p_dbd, key_buf); + } + } + if (osm_db_keys(p_dbd, &keys)) { + printf("failed to get keys\n"); + } else { + kI = cl_list_head(&keys); + while (kI != cl_list_end(&keys)) { + p_key = cl_list_obj(kI); + kI = cl_list_next(kI); + + p_val = osm_db_lookup(p_dbd, p_key); + printf("key = %s val = %s\n", p_key, p_val); + } + } + if (osm_db_store(p_dbd)) + printf("failed to store\n"); + + osm_db_destroy(&db); + cl_list_destroy(&keys); +} +#endif diff --git a/contrib/ofed/management/opensm/opensm/osm_db_pack.c b/contrib/ofed/management/opensm/opensm/osm_db_pack.c new file mode 100644 index 000000000000..bf56169776d7 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_db_pack.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +static inline void __osm_pack_guid(uint64_t guid, char *p_guid_str) +{ + sprintf(p_guid_str, "0x%016" PRIx64, guid); +} + +static inline uint64_t __osm_unpack_guid(char *p_guid_str) +{ + return strtoull(p_guid_str, NULL, 0); +} + +static inline void +__osm_pack_lids(uint16_t min_lid, uint16_t max_lid, char *p_lid_str) +{ + sprintf(p_lid_str, "0x%04x 0x%04x", min_lid, max_lid); +} + +static inline int +__osm_unpack_lids(IN char *p_lid_str, + OUT uint16_t * p_min_lid, OUT uint16_t * p_max_lid) +{ + unsigned long tmp; + char *p_next; + char *p_num; + char lids_str[24]; + + strncpy(lids_str, p_lid_str, 23); + lids_str[23] = '\0'; + p_num = strtok_r(lids_str, " \t", &p_next); + if (!p_num) + return 1; + tmp = strtoul(p_num, NULL, 0); + CL_ASSERT(tmp < 0x10000); + *p_min_lid = (uint16_t) tmp; + + p_num = strtok_r(NULL, " \t", &p_next); + if (!p_num) + return 1; + tmp = strtoul(p_num, NULL, 0); + CL_ASSERT(tmp < 0x10000); + *p_max_lid = (uint16_t) tmp; + + return 0; +} + +int +osm_db_guid2lid_guids(IN osm_db_domain_t * const p_g2l, + OUT cl_qlist_t * p_guid_list) +{ + char *p_key; + cl_list_t keys; + osm_db_guid_elem_t *p_guid_elem; + + cl_list_construct(&keys); + cl_list_init(&keys, 10); + + if (osm_db_keys(p_g2l, &keys)) + return 1; + + while ((p_key = cl_list_remove_head(&keys)) != NULL) { + p_guid_elem = + (osm_db_guid_elem_t *) malloc(sizeof(osm_db_guid_elem_t)); + CL_ASSERT(p_guid_elem != NULL); + + p_guid_elem->guid = __osm_unpack_guid(p_key); + cl_qlist_insert_head(p_guid_list, &p_guid_elem->item); + } + + cl_list_destroy(&keys); + return 0; +} + +int +osm_db_guid2lid_get(IN osm_db_domain_t * const p_g2l, + IN uint64_t guid, + OUT uint16_t * p_min_lid, OUT uint16_t * p_max_lid) +{ + char guid_str[20]; + char *p_lid_str; + uint16_t min_lid, max_lid; + + __osm_pack_guid(guid, guid_str); + p_lid_str = osm_db_lookup(p_g2l, guid_str); + if (!p_lid_str) + return 1; + if (__osm_unpack_lids(p_lid_str, &min_lid, &max_lid)) + return 1; + + if (p_min_lid) + *p_min_lid = min_lid; + if (p_max_lid) + *p_max_lid = max_lid; + + return 0; +} + +int +osm_db_guid2lid_set(IN osm_db_domain_t * const p_g2l, + IN uint64_t guid, IN uint16_t min_lid, IN uint16_t max_lid) +{ + char guid_str[20]; + char lid_str[16]; + + __osm_pack_guid(guid, guid_str); + __osm_pack_lids(min_lid, max_lid, lid_str); + + return (osm_db_update(p_g2l, guid_str, lid_str)); +} + +int osm_db_guid2lid_delete(IN osm_db_domain_t * const p_g2l, IN uint64_t guid) +{ + char guid_str[20]; + __osm_pack_guid(guid, guid_str); + return (osm_db_delete(p_g2l, guid_str)); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_drop_mgr.c b/contrib/ofed/management/opensm/opensm/osm_drop_mgr.c new file mode 100644 index 000000000000..215a15558f40 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_drop_mgr.c @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_drop_mgr_t. + * This object represents the Drop Manager object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +static void +__osm_drop_mgr_remove_router(osm_sm_t * sm, IN const ib_net64_t portguid) +{ + osm_router_t *p_rtr; + cl_qmap_t *p_rtr_guid_tbl; + + p_rtr_guid_tbl = &sm->p_subn->rtr_guid_tbl; + p_rtr = (osm_router_t *) cl_qmap_remove(p_rtr_guid_tbl, portguid); + if (p_rtr != (osm_router_t *) cl_qmap_end(p_rtr_guid_tbl)) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Cleaned router for port guid 0x%016" PRIx64 "\n", + cl_ntoh64(portguid)); + osm_router_delete(&p_rtr); + } +} + +/********************************************************************** + **********************************************************************/ +static void drop_mgr_clean_physp(osm_sm_t * sm, IN osm_physp_t * p_physp) +{ + osm_physp_t *p_remote_physp; + osm_port_t *p_remote_port; + + p_remote_physp = osm_physp_get_remote(p_physp); + if (p_remote_physp) { + p_remote_port = osm_get_port_by_guid(sm->p_subn, + p_remote_physp->port_guid); + + if (p_remote_port) { + /* Let's check if this is a case of link that is lost (both ports + weren't recognized), or a "hiccup" in the subnet - in which case + the remote port was recognized, and its state is ACTIVE. + If this is just a "hiccup" - force a heavy sweep in the next sweep. + We don't want to lose that part of the subnet. */ + if (p_remote_port->discovery_count && + osm_physp_get_port_state(p_remote_physp) == + IB_LINK_ACTIVE) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Forcing new heavy sweep. Remote " + "port 0x%016" PRIx64 " port num: %u " + "was recognized in ACTIVE state\n", + cl_ntoh64(p_remote_physp->port_guid), + p_remote_physp->port_num); + sm->p_subn->force_heavy_sweep = TRUE; + } + + /* If the remote node is ca or router - need to remove the remote port, + since it is no longer reachable. This can be done if we reset the + discovery count of the remote port. */ + if (!p_remote_physp->p_node->sw) { + p_remote_port->discovery_count = 0; + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Resetting discovery count of node: " + "0x%016" PRIx64 " port num:%u\n", + cl_ntoh64(osm_node_get_node_guid + (p_remote_physp->p_node)), + p_remote_physp->port_num); + } + } + + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Unlinking local node 0x%016" PRIx64 ", port %u" + "\n\t\t\t\tand remote node 0x%016" PRIx64 + ", port %u\n", + cl_ntoh64(osm_node_get_node_guid(p_physp->p_node)), + p_physp->port_num, + cl_ntoh64(osm_node_get_node_guid + (p_remote_physp->p_node)), + p_remote_physp->port_num); + + if (sm->ucast_mgr.cache_valid) + osm_ucast_cache_add_link(&sm->ucast_mgr, + p_physp, p_remote_physp); + + osm_physp_unlink(p_physp, p_remote_physp); + + } + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Clearing node 0x%016" PRIx64 " physical port number %u\n", + cl_ntoh64(osm_node_get_node_guid(p_physp->p_node)), + p_physp->port_num); + + osm_physp_destroy(p_physp); +} + +/********************************************************************** + **********************************************************************/ +static void __osm_drop_mgr_remove_port(osm_sm_t * sm, IN osm_port_t * p_port) +{ + ib_net64_t port_guid; + osm_port_t *p_port_check; + cl_qmap_t *p_sm_guid_tbl; + osm_mcm_info_t *p_mcm; + osm_mgrp_t *p_mgrp; + cl_ptr_vector_t *p_port_lid_tbl; + uint16_t min_lid_ho; + uint16_t max_lid_ho; + uint16_t lid_ho; + osm_node_t *p_node; + osm_remote_sm_t *p_sm; + ib_gid_t port_gid; + ib_mad_notice_attr_t notice; + ib_api_status_t status; + + OSM_LOG_ENTER(sm->p_log); + + port_guid = osm_port_get_guid(p_port); + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Unreachable port 0x%016" PRIx64 "\n", cl_ntoh64(port_guid)); + + p_port_check = + (osm_port_t *) cl_qmap_remove(&sm->p_subn->port_guid_tbl, + port_guid); + if (p_port_check != p_port) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0101: " + "Port 0x%016" PRIx64 " not in guid table\n", + cl_ntoh64(port_guid)); + goto Exit; + } + + p_sm_guid_tbl = &sm->p_subn->sm_guid_tbl; + p_sm = (osm_remote_sm_t *) cl_qmap_remove(p_sm_guid_tbl, port_guid); + if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_guid_tbl)) { + /* need to remove this item */ + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Cleaned SM for port guid 0x%016" PRIx64 "\n", + cl_ntoh64(port_guid)); + + free(p_sm); + } + + __osm_drop_mgr_remove_router(sm, port_guid); + + osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); + + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Clearing abandoned LID range [%u,%u]\n", + min_lid_ho, max_lid_ho); + + p_port_lid_tbl = &sm->p_subn->port_lid_tbl; + for (lid_ho = min_lid_ho; lid_ho <= max_lid_ho; lid_ho++) + cl_ptr_vector_set(p_port_lid_tbl, lid_ho, NULL); + + drop_mgr_clean_physp(sm, p_port->p_physp); + + p_mcm = (osm_mcm_info_t *) cl_qlist_remove_head(&p_port->mcm_list); + while (p_mcm != (osm_mcm_info_t *) cl_qlist_end(&p_port->mcm_list)) { + p_mgrp = osm_get_mgrp_by_mlid(sm->p_subn, p_mcm->mlid); + if (p_mgrp) { + osm_mgrp_delete_port(sm->p_subn, sm->p_log, + p_mgrp, p_port->guid); + osm_mcm_info_delete((osm_mcm_info_t *) p_mcm); + } + p_mcm = + (osm_mcm_info_t *) cl_qlist_remove_head(&p_port->mcm_list); + } + + /* initialize the p_node - may need to get node_desc later */ + p_node = p_port->p_node; + + osm_port_delete(&p_port); + + /* issue a notice - trap 65 */ + + /* details of the notice */ + notice.generic_type = 0x83; /* is generic subn mgt type */ + ib_notice_set_prod_type_ho(¬ice, 4); /* A class manager generator */ + /* endport ceases to be reachable */ + notice.g_or_v.generic.trap_num = CL_HTON16(65); + /* The sm_base_lid is saved in network order already. */ + notice.issuer_lid = sm->p_subn->sm_base_lid; + /* following C14-72.1.2 and table 119 p725 */ + /* we need to provide the GID */ + port_gid.unicast.prefix = sm->p_subn->opt.subnet_prefix; + port_gid.unicast.interface_id = port_guid; + memcpy(&(notice.data_details.ntc_64_67.gid), + &(port_gid), sizeof(ib_gid_t)); + + /* According to page 653 - the issuer gid in this case of trap + is the SM gid, since the SM is the initiator of this trap. */ + notice.issuer_gid.unicast.prefix = sm->p_subn->opt.subnet_prefix; + notice.issuer_gid.unicast.interface_id = sm->p_subn->sm_port_guid; + + status = osm_report_notice(sm->p_log, sm->p_subn, ¬ice); + if (status != IB_SUCCESS) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0103: " + "Error sending trap reports (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + OSM_LOG(sm->p_log, OSM_LOG_INFO, + "Removed port with GUID:0x%016" PRIx64 + " LID range [%u, %u] of node:%s\n", + cl_ntoh64(port_gid.unicast.interface_id), + min_lid_ho, max_lid_ho, + p_node ? p_node->print_desc : "UNKNOWN"); + +Exit: + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void __osm_drop_mgr_remove_switch(osm_sm_t * sm, IN osm_node_t * p_node) +{ + osm_switch_t *p_sw; + cl_qmap_t *p_sw_guid_tbl; + ib_net64_t node_guid; + + OSM_LOG_ENTER(sm->p_log); + + node_guid = osm_node_get_node_guid(p_node); + p_sw_guid_tbl = &sm->p_subn->sw_guid_tbl; + + p_sw = (osm_switch_t *) cl_qmap_remove(p_sw_guid_tbl, node_guid); + if (p_sw == (osm_switch_t *) cl_qmap_end(p_sw_guid_tbl)) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0102: " + "Node 0x%016" PRIx64 " not in switch table\n", + cl_ntoh64(osm_node_get_node_guid(p_node))); + } else { + p_node->sw = NULL; + osm_switch_delete(&p_sw); + } + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +__osm_drop_mgr_process_node(osm_sm_t * sm, IN osm_node_t * p_node) +{ + osm_physp_t *p_physp; + osm_port_t *p_port; + osm_node_t *p_node_check; + uint32_t port_num; + uint32_t max_ports; + ib_net64_t port_guid; + boolean_t return_val = FALSE; + + OSM_LOG_ENTER(sm->p_log); + + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Unreachable node 0x%016" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(p_node))); + + if (sm->ucast_mgr.cache_valid) + osm_ucast_cache_add_node(&sm->ucast_mgr, p_node); + + /* + Delete all the logical and physical port objects + associated with this node. + */ + max_ports = osm_node_get_num_physp(p_node); + for (port_num = 0; port_num < max_ports; port_num++) { + p_physp = osm_node_get_physp_ptr(p_node, port_num); + if (p_physp) { + port_guid = osm_physp_get_port_guid(p_physp); + + p_port = osm_get_port_by_guid(sm->p_subn, port_guid); + + if (p_port) + __osm_drop_mgr_remove_port(sm, p_port); + else + drop_mgr_clean_physp(sm, p_physp); + } + } + + return_val = TRUE; + + if (p_node->sw) + __osm_drop_mgr_remove_switch(sm, p_node); + + p_node_check = + (osm_node_t *) cl_qmap_remove(&sm->p_subn->node_guid_tbl, + osm_node_get_node_guid(p_node)); + if (p_node_check != p_node) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0105: " + "Node 0x%016" PRIx64 " not in guid table\n", + cl_ntoh64(osm_node_get_node_guid(p_node))); + } + + /* free memory allocated to node */ + osm_node_delete(&p_node); + + OSM_LOG_EXIT(sm->p_log); + return (return_val); +} + +/********************************************************************** + **********************************************************************/ +static void __osm_drop_mgr_check_node(osm_sm_t * sm, IN osm_node_t * p_node) +{ + ib_net64_t node_guid; + osm_physp_t *p_physp; + osm_port_t *p_port; + ib_net64_t port_guid; + + OSM_LOG_ENTER(sm->p_log); + + node_guid = osm_node_get_node_guid(p_node); + + if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0107: " + "Node 0x%016" PRIx64 " is not a switch node\n", + cl_ntoh64(node_guid)); + goto Exit; + } + + /* Make sure we have a switch object for this node */ + if (!p_node->sw) { + /* We do not have switch info for this node */ + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Node 0x%016" PRIx64 " no switch in table\n", + cl_ntoh64(node_guid)); + + __osm_drop_mgr_process_node(sm, p_node); + goto Exit; + } + + /* Make sure we have a port object for port zero */ + p_physp = osm_node_get_physp_ptr(p_node, 0); + if (!p_physp) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Node 0x%016" PRIx64 " no valid physical port 0\n", + cl_ntoh64(node_guid)); + + __osm_drop_mgr_process_node(sm, p_node); + goto Exit; + } + + port_guid = osm_physp_get_port_guid(p_physp); + + p_port = osm_get_port_by_guid(sm->p_subn, port_guid); + + if (!p_port) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Node 0x%016" PRIx64 " has no port object\n", + cl_ntoh64(node_guid)); + + __osm_drop_mgr_process_node(sm, p_node); + goto Exit; + } + + if (p_port->discovery_count == 0) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Node 0x%016" PRIx64 " port has discovery count zero\n", + cl_ntoh64(node_guid)); + + __osm_drop_mgr_process_node(sm, p_node); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(sm->p_log); + return; +} + +/********************************************************************** + **********************************************************************/ +void osm_drop_mgr_process(osm_sm_t * sm) +{ + cl_qmap_t *p_node_guid_tbl; + cl_qmap_t *p_port_guid_tbl; + osm_port_t *p_port; + osm_port_t *p_next_port; + osm_node_t *p_node; + osm_node_t *p_next_node; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + p_node_guid_tbl = &sm->p_subn->node_guid_tbl; + p_port_guid_tbl = &sm->p_subn->port_guid_tbl; + + CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); + + p_next_node = (osm_node_t *) cl_qmap_head(p_node_guid_tbl); + while (p_next_node != (osm_node_t *) cl_qmap_end(p_node_guid_tbl)) { + p_node = p_next_node; + p_next_node = + (osm_node_t *) cl_qmap_next(&p_next_node->map_item); + + CL_ASSERT(cl_qmap_key(&p_node->map_item) == + osm_node_get_node_guid(p_node)); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Checking node 0x%016" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(p_node))); + + /* + Check if this node was discovered during the last sweep. + If not, it is unreachable in the current subnet, and + should therefore be removed from the subnet object. + */ + if (p_node->discovery_count == 0) + __osm_drop_mgr_process_node(sm, p_node); + } + + /* + Go over all the nodes. If the node is a switch - make sure + there is also a switch record for it, and a portInfo record for + port zero of of the node. + If not - this means that there was some error in getting the data + of this node. Drop the node. + */ + p_next_node = (osm_node_t *) cl_qmap_head(p_node_guid_tbl); + while (p_next_node != (osm_node_t *) cl_qmap_end(p_node_guid_tbl)) { + p_node = p_next_node; + p_next_node = + (osm_node_t *) cl_qmap_next(&p_next_node->map_item); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Checking full discovery of node 0x%016" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(p_node))); + + if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH) + continue; + + /* We are handling a switch node */ + __osm_drop_mgr_check_node(sm, p_node); + } + + p_next_port = (osm_port_t *) cl_qmap_head(p_port_guid_tbl); + while (p_next_port != (osm_port_t *) cl_qmap_end(p_port_guid_tbl)) { + p_port = p_next_port; + p_next_port = + (osm_port_t *) cl_qmap_next(&p_next_port->map_item); + + CL_ASSERT(cl_qmap_key(&p_port->map_item) == + osm_port_get_guid(p_port)); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Checking port 0x%016" PRIx64 "\n", + cl_ntoh64(osm_port_get_guid(p_port))); + + /* + If the port is unreachable, remove it from the guid table. + */ + if (p_port->discovery_count == 0) + __osm_drop_mgr_remove_port(sm, p_port); + } + + CL_PLOCK_RELEASE(sm->p_lock); + OSM_LOG_EXIT(sm->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_dump.c b/contrib/ofed/management/opensm/opensm/osm_dump.c new file mode 100644 index 000000000000..7e0ba4790c38 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_dump.c @@ -0,0 +1,642 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Various OpenSM dumpers + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void dump_ucast_path_distribution(cl_map_item_t * p_map_item, + FILE *file, void *cxt) +{ + osm_node_t *p_node; + osm_node_t *p_remote_node; + uint8_t i; + uint8_t num_ports; + uint32_t num_paths; + ib_net64_t remote_guid_ho; + osm_switch_t *p_sw = (osm_switch_t *) p_map_item; + + p_node = p_sw->p_node; + num_ports = p_sw->num_ports; + + fprintf(file, "dump_ucast_path_distribution: Switch 0x%" PRIx64 "\n" + "Port : Path Count Through Port", + cl_ntoh64(osm_node_get_node_guid(p_node))); + + for (i = 0; i < num_ports; i++) { + num_paths = osm_switch_path_count_get(p_sw, i); + fprintf(file, "\n %03u : %u", i, num_paths); + if (i == 0) { + fprintf(file, " (switch management port)"); + continue; + } + + p_remote_node = osm_node_get_remote_node(p_node, i, NULL); + if (p_remote_node == NULL) + continue; + + remote_guid_ho = + cl_ntoh64(osm_node_get_node_guid(p_remote_node)); + + switch (osm_node_get_type(p_remote_node)) { + case IB_NODE_TYPE_SWITCH: + fprintf(file, " (link to switch"); + break; + case IB_NODE_TYPE_ROUTER: + fprintf(file, " (link to router"); + break; + case IB_NODE_TYPE_CA: + fprintf(file, " (link to CA"); + break; + default: + fprintf(file, " (link to unknown node type"); + break; + } + + fprintf(file, " 0x%" PRIx64 ")", remote_guid_ho); + } + + fprintf(file, "\n"); +} + +static void dump_ucast_routes(cl_map_item_t *p_map_item, FILE *file, void *cxt) +{ + const osm_node_t *p_node; + osm_port_t *p_port; + uint8_t port_num; + uint8_t num_hops; + uint8_t best_hops; + uint8_t best_port; + uint16_t max_lid_ho; + uint16_t lid_ho, base_lid; + boolean_t direct_route_exists = FALSE; + boolean_t dor; + osm_switch_t *p_sw = (osm_switch_t *) p_map_item; + osm_opensm_t *p_osm = cxt; + + p_node = p_sw->p_node; + + max_lid_ho = p_sw->max_lid_ho; + + fprintf(file, "__osm_ucast_mgr_dump_ucast_routes: " + "Switch 0x%016" PRIx64 "\nLID : Port : Hops : Optimal\n", + cl_ntoh64(osm_node_get_node_guid(p_node))); + + dor = (p_osm->routing_engine_used == OSM_ROUTING_ENGINE_TYPE_DOR); + + for (lid_ho = 1; lid_ho <= max_lid_ho; lid_ho++) { + fprintf(file, "0x%04X : ", lid_ho); + + p_port = cl_ptr_vector_get(&p_osm->subn.port_lid_tbl, lid_ho); + if (!p_port) { + fprintf(file, "UNREACHABLE\n"); + continue; + } + + port_num = osm_switch_get_port_by_lid(p_sw, lid_ho); + if (port_num == OSM_NO_PATH) { + /* + This may occur if there are 'holes' in the existing + LID assignments. Running SM with --reassign_lids + will reassign and compress the LID range. The + subnet should work fine either way. + */ + fprintf(file, "UNREACHABLE\n"); + continue; + } + /* + Switches can lie about which port routes a given + lid due to a recent reconfiguration of the subnet. + Therefore, ensure that the hop count is better than + OSM_NO_PATH. + */ + if (p_port->p_node->sw) { + /* Target LID is switch. + Get its base lid and check hop count for this base LID only. */ + base_lid = osm_node_get_base_lid(p_port->p_node, 0); + base_lid = cl_ntoh16(base_lid); + num_hops = + osm_switch_get_hop_count(p_sw, base_lid, port_num); + } else { + /* Target LID is not switch (CA or router). + Check if we have route to this target from current switch. */ + num_hops = + osm_switch_get_hop_count(p_sw, lid_ho, port_num); + if (num_hops != OSM_NO_PATH) { + direct_route_exists = TRUE; + base_lid = lid_ho; + } else { + osm_physp_t *p_physp = p_port->p_physp; + + if (!p_physp || !p_physp->p_remote_physp || + !p_physp->p_remote_physp->p_node->sw) + num_hops = OSM_NO_PATH; + else { + base_lid = + osm_node_get_base_lid(p_physp-> + p_remote_physp-> + p_node, 0); + base_lid = cl_ntoh16(base_lid); + num_hops = + p_physp->p_remote_physp->p_node-> + sw == + p_sw ? 0 : + osm_switch_get_hop_count(p_sw, + base_lid, + port_num); + } + } + } + + if (num_hops == OSM_NO_PATH) { + fprintf(file, "UNREACHABLE\n"); + continue; + } + + best_hops = osm_switch_get_least_hops(p_sw, base_lid); + if (!p_port->p_node->sw && !direct_route_exists) { + best_hops++; + num_hops++; + } + + fprintf(file, "%03u : %02u : ", port_num, num_hops); + + if (best_hops == num_hops) + fprintf(file, "yes"); + else { + /* No LMC Optimization */ + best_port = osm_switch_recommend_path(p_sw, p_port, + lid_ho, 1, TRUE, + dor); + fprintf(file, "No %u hop path possible via port %u!", + best_hops, best_port); + } + + fprintf(file, "\n"); + } +} + +static void dump_mcast_routes(cl_map_item_t *p_map_item, FILE *file, void *cxt) +{ + osm_switch_t *p_sw = (osm_switch_t *) p_map_item; + osm_mcast_tbl_t *p_tbl; + int16_t mlid_ho = 0; + int16_t mlid_start_ho; + uint8_t position = 0; + int16_t block_num = 0; + boolean_t first_mlid; + boolean_t first_port; + const osm_node_t *p_node; + uint16_t i, j; + uint16_t mask_entry; + char sw_hdr[256]; + char mlid_hdr[32]; + + p_node = p_sw->p_node; + + p_tbl = osm_switch_get_mcast_tbl_ptr(p_sw); + + sprintf(sw_hdr, "\nSwitch 0x%016" PRIx64 "\nLID : Out Port(s)\n", + cl_ntoh64(osm_node_get_node_guid(p_node))); + first_mlid = TRUE; + while (block_num <= p_tbl->max_block_in_use) { + mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE); + for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++) { + mlid_ho = mlid_start_ho + i; + position = 0; + first_port = TRUE; + sprintf(mlid_hdr, "0x%04X :", + mlid_ho + IB_LID_MCAST_START_HO); + while (position <= p_tbl->max_position) { + mask_entry = + cl_ntoh16((*p_tbl-> + p_mask_tbl)[mlid_ho][position]); + if (mask_entry == 0) { + position++; + continue; + } + for (j = 0; j < 16; j++) { + if ((1 << j) & mask_entry) { + if (first_mlid) { + fprintf(file, "%s", + sw_hdr); + first_mlid = FALSE; + } + if (first_port) { + fprintf(file, "%s", + mlid_hdr); + first_port = FALSE; + } + fprintf(file, " 0x%03X ", + j + (position * 16)); + } + } + position++; + } + if (first_port == FALSE) + fprintf(file, "\n"); + } + block_num++; + } +} + +static void dump_lid_matrix(cl_map_item_t *p_map_item, FILE *file, void *cxt) +{ + osm_switch_t *p_sw = (osm_switch_t *) p_map_item; + osm_opensm_t *p_osm = cxt; + osm_node_t *p_node = p_sw->p_node; + unsigned max_lid = p_sw->max_lid_ho; + unsigned max_port = p_sw->num_ports; + uint16_t lid; + uint8_t port; + + fprintf(file, "Switch: guid 0x%016" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(p_node))); + for (lid = 1; lid <= max_lid; lid++) { + osm_port_t *p_port; + if (osm_switch_get_least_hops(p_sw, lid) == OSM_NO_PATH) + continue; + fprintf(file, "0x%04x:", lid); + for (port = 0; port < max_port; port++) + fprintf(file, " %02x", + osm_switch_get_hop_count(p_sw, lid, port)); + p_port = cl_ptr_vector_get(&p_osm->subn.port_lid_tbl, lid); + if (p_port) + fprintf(file, " # portguid 0x016%" PRIx64, + cl_ntoh64(osm_port_get_guid(p_port))); + fprintf(file, "\n"); + } +} + +static void dump_ucast_lfts(cl_map_item_t *p_map_item, FILE *file, void *cxt) +{ + osm_switch_t *p_sw = (osm_switch_t *) p_map_item; + osm_opensm_t *p_osm = cxt; + osm_node_t *p_node = p_sw->p_node; + unsigned max_lid = p_sw->max_lid_ho; + unsigned max_port = p_sw->num_ports; + uint16_t lid; + uint8_t port; + + fprintf(file, "Unicast lids [0-%u] of switch Lid %u guid 0x%016" + PRIx64 " (\'%s\'):\n", + max_lid, cl_ntoh16(osm_node_get_base_lid(p_node, 0)), + cl_ntoh64(osm_node_get_node_guid(p_node)), p_node->print_desc); + for (lid = 0; lid <= max_lid; lid++) { + osm_port_t *p_port; + port = osm_switch_get_port_by_lid(p_sw, lid); + + if (port >= max_port) + continue; + + fprintf(file, "0x%04x %03u # ", lid, port); + + p_port = cl_ptr_vector_get(&p_osm->subn.port_lid_tbl, lid); + if (p_port) { + p_node = p_port->p_node; + fprintf(file, "%s portguid 0x%016" PRIx64 ": \'%s\'", + ib_get_node_type_str(osm_node_get_type(p_node)), + cl_ntoh64(osm_port_get_guid(p_port)), + p_node->print_desc); + } else + fprintf(file, "unknown node and type"); + fprintf(file, "\n"); + } + fprintf(file, "%u lids dumped\n", max_lid); +} + +static void dump_topology_node(cl_map_item_t *p_map_item, FILE *file, void *cxt) +{ + osm_node_t *p_node = (osm_node_t *) p_map_item; + uint32_t cPort; + osm_node_t *p_nbnode; + osm_physp_t *p_physp, *p_default_physp, *p_rphysp; + uint8_t link_speed_act; + + if (!p_node->node_info.num_ports) + return; + + for (cPort = 1; cPort < osm_node_get_num_physp(p_node); cPort++) { + uint8_t port_state; + + p_physp = osm_node_get_physp_ptr(p_node, cPort); + if (!p_physp) + continue; + + p_rphysp = p_physp->p_remote_physp; + if (!p_rphysp) + continue; + + CL_ASSERT(cPort == p_physp->port_num); + + if (p_node->node_info.node_type == IB_NODE_TYPE_SWITCH) + p_default_physp = osm_node_get_physp_ptr(p_node, 0); + else + p_default_physp = p_physp; + + fprintf(file, "{ %s%s Ports:%02X SystemGUID:%016" PRIx64 + " NodeGUID:%016" PRIx64 " PortGUID:%016" PRIx64 + " VenID:%06X DevID:%04X Rev:%08X {%s} LID:%04X PN:%02X } ", + p_node->node_info.node_type == IB_NODE_TYPE_SWITCH ? + "SW" : p_node->node_info.node_type == + IB_NODE_TYPE_CA ? "CA" : p_node->node_info.node_type == + IB_NODE_TYPE_ROUTER ? "Rt" : "**", + p_default_physp->port_info.base_lid == + p_default_physp->port_info. + master_sm_base_lid ? "-SM" : "", + p_node->node_info.num_ports, + cl_ntoh64(p_node->node_info.sys_guid), + cl_ntoh64(p_node->node_info.node_guid), + cl_ntoh64(p_physp->port_guid), + cl_ntoh32(ib_node_info_get_vendor_id + (&p_node->node_info)), + cl_ntoh16(p_node->node_info.device_id), + cl_ntoh32(p_node->node_info.revision), + p_node->print_desc, + cl_ntoh16(p_default_physp->port_info.base_lid), cPort); + + p_nbnode = p_rphysp->p_node; + + if (p_nbnode->node_info.node_type == IB_NODE_TYPE_SWITCH) + p_default_physp = osm_node_get_physp_ptr(p_nbnode, 0); + else + p_default_physp = p_rphysp; + + fprintf(file, "{ %s%s Ports:%02X SystemGUID:%016" PRIx64 + " NodeGUID:%016" PRIx64 " PortGUID:%016" PRIx64 + " VenID:%08X DevID:%04X Rev:%08X {%s} LID:%04X PN:%02X } ", + p_nbnode->node_info.node_type == IB_NODE_TYPE_SWITCH ? + "SW" : p_nbnode->node_info.node_type == + IB_NODE_TYPE_CA ? "CA" : + p_nbnode->node_info.node_type == IB_NODE_TYPE_ROUTER ? + "Rt" : "**", + p_default_physp->port_info.base_lid == + p_default_physp->port_info. + master_sm_base_lid ? "-SM" : "", + p_nbnode->node_info.num_ports, + cl_ntoh64(p_nbnode->node_info.sys_guid), + cl_ntoh64(p_nbnode->node_info.node_guid), + cl_ntoh64(p_rphysp->port_guid), + cl_ntoh32(ib_node_info_get_vendor_id + (&p_nbnode->node_info)), + cl_ntoh32(p_nbnode->node_info.device_id), + cl_ntoh32(p_nbnode->node_info.revision), + p_nbnode->print_desc, + cl_ntoh16(p_default_physp->port_info.base_lid), + p_rphysp->port_num); + + port_state = ib_port_info_get_port_state(&p_physp->port_info); + link_speed_act = + ib_port_info_get_link_speed_active(&p_physp->port_info); + + fprintf(file, "PHY=%s LOG=%s SPD=%s\n", + p_physp->port_info.link_width_active == 1 ? "1x" : + p_physp->port_info.link_width_active == 2 ? "4x" : + p_physp->port_info.link_width_active == 8 ? "12x" : + "??", + port_state == IB_LINK_ACTIVE ? "ACT" : + port_state == IB_LINK_ARMED ? "ARM" : + port_state == IB_LINK_INIT ? "INI" : "DWN", + link_speed_act == 1 ? "2.5" : + link_speed_act == 2 ? "5" : + link_speed_act == 4 ? "10" : "??"); + } +} + +static void print_node_report(cl_map_item_t *p_map_item, FILE *file, void *cxt) +{ + osm_node_t *p_node = (osm_node_t *) p_map_item; + osm_opensm_t *osm = cxt; + const osm_physp_t *p_physp, *p_remote_physp; + const ib_port_info_t *p_pi; + uint8_t port_num; + uint32_t num_ports; + uint8_t node_type; + + node_type = osm_node_get_type(p_node); + + num_ports = osm_node_get_num_physp(p_node); + port_num = node_type == IB_NODE_TYPE_SWITCH ? 0 : 1; + for (; port_num < num_ports; port_num++) { + p_physp = osm_node_get_physp_ptr(p_node, port_num); + if (!p_physp) + continue; + + fprintf(file, "%-11s : %s : %02X :", + osm_get_manufacturer_str(cl_ntoh64 + (osm_node_get_node_guid + (p_node))), + osm_get_node_type_str_fixed_width(node_type), port_num); + + p_pi = &p_physp->port_info; + + /* + * Port state is not defined for switch port 0 + */ + if (port_num == 0) + fprintf(file, " :"); + else + fprintf(file, " %s :", + osm_get_port_state_str_fixed_width + (ib_port_info_get_port_state(p_pi))); + + /* + * LID values are only meaningful in select cases. + */ + if (ib_port_info_get_port_state(p_pi) != IB_LINK_DOWN + && ((node_type == IB_NODE_TYPE_SWITCH && port_num == 0) + || node_type != IB_NODE_TYPE_SWITCH)) + fprintf(file, " %04X : %01X :", + cl_ntoh16(p_pi->base_lid), + ib_port_info_get_lmc(p_pi)); + else + fprintf(file, " : :"); + + if (port_num != 0) + fprintf(file, " %s : %s : %s ", + osm_get_mtu_str + (ib_port_info_get_neighbor_mtu(p_pi)), + osm_get_lwa_str(p_pi->link_width_active), + osm_get_lsa_str + (ib_port_info_get_link_speed_active(p_pi))); + else + fprintf(file, " : : "); + + if (osm_physp_get_port_guid(p_physp) == osm->subn.sm_port_guid) + fprintf(file, "* %016" PRIx64 " *", + cl_ntoh64(osm_physp_get_port_guid(p_physp))); + else + fprintf(file, ": %016" PRIx64 " :", + cl_ntoh64(osm_physp_get_port_guid(p_physp))); + + if (port_num + && (ib_port_info_get_port_state(p_pi) != IB_LINK_DOWN)) { + p_remote_physp = osm_physp_get_remote(p_physp); + if (p_remote_physp) + fprintf(file, " %016" PRIx64 " (%02X)", + cl_ntoh64(osm_physp_get_port_guid + (p_remote_physp)), + osm_physp_get_port_num(p_remote_physp)); + else + fprintf(file, " UNKNOWN"); + } + + fprintf(file, "\n"); + } + + fprintf(file, "------------------------------------------------------" + "------------------------------------------------\n"); +} + +/********************************************************************** + **********************************************************************/ +struct dump_context { + osm_opensm_t *p_osm; + FILE *file; + void (*func) (cl_map_item_t *, FILE *, void *); + void *cxt; +}; + +static void dump_item(cl_map_item_t *item, void *cxt) +{ + ((struct dump_context *)cxt)->func(item, + ((struct dump_context *)cxt)->file, + ((struct dump_context *)cxt)->cxt); +} + +static void dump_qmap(FILE *file, cl_qmap_t *map, + void (*func)(cl_map_item_t *, FILE *, void *), void *cxt) +{ + struct dump_context dump_context; + + dump_context.file = file; + dump_context.func = func; + dump_context.cxt = cxt; + + cl_qmap_apply_func(map, dump_item, &dump_context); +} + +void osm_dump_qmap_to_file(osm_opensm_t * p_osm, const char *file_name, + cl_qmap_t * map, + void (*func) (cl_map_item_t *, FILE *, void *), + void *cxt) +{ + char path[1024]; + FILE *file; + + snprintf(path, sizeof(path), "%s/%s", + p_osm->subn.opt.dump_files_dir, file_name); + + file = fopen(path, "w"); + if (!file) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, + "cannot create file \'%s\': %s\n", + path, strerror(errno)); + return; + } + + dump_qmap(file, map, func, cxt); + + fclose(file); +} + +/********************************************************************** + **********************************************************************/ + +static void print_report(osm_opensm_t *osm, FILE *file) +{ + fprintf(file, "\n===================================================" + "====================================================\n" + "Vendor : Ty : # : Sta : LID : LMC : MTU : LWA :" + " LSA : Port GUID : Neighbor Port (Port #)\n"); + dump_qmap(stdout, &osm->subn.node_guid_tbl, print_node_report, osm); +} + +void osm_dump_mcast_routes(osm_opensm_t * osm) +{ + if (osm_log_is_active(&osm->log, OSM_LOG_ROUTING)) + /* multicast routes */ + osm_dump_qmap_to_file(osm, "opensm.mcfdbs", + &osm->subn.sw_guid_tbl, + dump_mcast_routes, osm); +} + +void osm_dump_all(osm_opensm_t * osm) +{ + if (osm_log_is_active(&osm->log, OSM_LOG_ROUTING)) { + /* unicast routes */ + osm_dump_qmap_to_file(osm, "opensm-lid-matrix.dump", + &osm->subn.sw_guid_tbl, dump_lid_matrix, + osm); + osm_dump_qmap_to_file(osm, "opensm-lfts.dump", + &osm->subn.sw_guid_tbl, dump_ucast_lfts, + osm); + if (osm_log_is_active(&osm->log, OSM_LOG_DEBUG)) + dump_qmap(stdout, &osm->subn.sw_guid_tbl, + dump_ucast_path_distribution, osm); + osm_dump_qmap_to_file(osm, "opensm.fdbs", + &osm->subn.sw_guid_tbl, + dump_ucast_routes, osm); + /* multicast routes */ + osm_dump_qmap_to_file(osm, "opensm.mcfdbs", + &osm->subn.sw_guid_tbl, + dump_mcast_routes, osm); + } + osm_dump_qmap_to_file(osm, "opensm-subnet.lst", + &osm->subn.node_guid_tbl, dump_topology_node, + osm); + if (osm_log_is_active(&osm->log, OSM_LOG_VERBOSE)) + print_report(osm, stdout); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_event_plugin.c b/contrib/ofed/management/opensm/opensm/osm_event_plugin.c new file mode 100644 index 000000000000..b0dc549cc54c --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_event_plugin.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2007 The Regents of the University of California. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/****h* OpenSM Event plugin interface +* DESCRIPTION +* Database interface to record subnet events +* +* Implementations of this object _MUST_ be thread safe. +* +* AUTHOR +* Ira Weiny, LLNL +* +*********/ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +#if defined(PATH_MAX) +#define OSM_PATH_MAX (PATH_MAX + 1) +#elif defined (_POSIX_PATH_MAX) +#define OSM_PATH_MAX (_POSIX_PATH_MAX + 1) +#else +#define OSM_PATH_MAX 256 +#endif + +/** + * functions + */ +osm_epi_plugin_t *osm_epi_construct(osm_opensm_t *osm, char *plugin_name) +{ + char lib_name[OSM_PATH_MAX]; + struct old_if { unsigned ver; } *old_impl; + osm_epi_plugin_t *rc = NULL; + + if (!plugin_name || !*plugin_name) + return (NULL); + + /* find the plugin */ + snprintf(lib_name, OSM_PATH_MAX, "lib%s.so", plugin_name); + + rc = malloc(sizeof(*rc)); + if (!rc) + return (NULL); + + rc->handle = dlopen(lib_name, RTLD_LAZY); + if (!rc->handle) { + OSM_LOG(&osm->log, OSM_LOG_ERROR, + "Failed to open event plugin \"%s\" : \"%s\"\n", + lib_name, dlerror()); + goto DLOPENFAIL; + } + + rc->impl = + (osm_event_plugin_t *) dlsym(rc->handle, + OSM_EVENT_PLUGIN_IMPL_NAME); + if (!rc->impl) { + OSM_LOG(&osm->log, OSM_LOG_ERROR, + "Failed to find \"%s\" symbol in \"%s\" : \"%s\"\n", + OSM_EVENT_PLUGIN_IMPL_NAME, lib_name, dlerror()); + goto Exit; + } + + /* check for old interface */ + old_impl = (struct old_if *) rc->impl; + if (old_impl->ver == OSM_ORIG_EVENT_PLUGIN_INTERFACE_VER) { + OSM_LOG(&osm->log, OSM_LOG_ERROR, "Error loading plugin: " + "\'%s\' contains a depricated interface version %d\n" + " Please recompile with the new interface.\n", + plugin_name, old_impl->ver); + goto Exit; + } + + /* Check the version to make sure this module will work with us */ + if (strcmp(rc->impl->osm_version, osm->osm_version)) { + OSM_LOG(&osm->log, OSM_LOG_ERROR, "Error loading plugin" + " \'%s\': OpenSM version mismatch - plugin was built" + " against %s version of OpenSM. Skip loading.\n", + plugin_name, rc->impl->osm_version); + goto Exit; + } + + if (!rc->impl->create) { + OSM_LOG(&osm->log, OSM_LOG_ERROR, + "Error loading plugin \'%s\': no create() method.\n", + plugin_name); + goto Exit; + } + + rc->plugin_data = rc->impl->create(osm); + + if (!rc->plugin_data) + goto Exit; + + rc->plugin_name = strdup(plugin_name); + return (rc); + +Exit: + dlclose(rc->handle); +DLOPENFAIL: + free(rc); + return (NULL); +} + +void osm_epi_destroy(osm_epi_plugin_t * plugin) +{ + if (plugin) { + if (plugin->impl->delete) + plugin->impl->delete(plugin->plugin_data); + dlclose(plugin->handle); + free(plugin->plugin_name); + free(plugin); + } +} diff --git a/contrib/ofed/management/opensm/opensm/osm_helper.c b/contrib/ofed/management/opensm/opensm/osm_helper.c new file mode 100644 index 000000000000..51fb894a4a3f --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_helper.c @@ -0,0 +1,2334 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of opensm helper functions. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LINE_LENGTH 256 + +#define ARR_SIZE(a) (sizeof(a)/sizeof((a)[0])) + +/* we use two tables - one for queries and one for responses */ +static const char *const __ib_sa_method_str[] = { + "RESERVED", /* 0 */ + "SubnAdmGet", /* 1 */ + "SubnAdmSet", /* 2 */ + "RESERVED", /* 3 */ + "RESERVED", /* 4 */ + "RESERVED", /* 5 */ + "SubnAdmReport", /* 6 */ + "RESERVED", /* 7 */ + "RESERVED", /* 8 */ + "RESERVED", /* 9 */ + "RESERVED", /* A */ + "RESERVED", /* B */ + "RESERVED", /* C */ + "RESERVED", /* D */ + "RESERVED", /* E */ + "RESERVED", /* F */ + "RESERVED", /* 10 */ + "RESERVED", /* 11 */ + "SubnAdmGetTable", /* 12 */ + "SubnAdmGetTraceTable", /* 13 */ + "SubnAdmGetMulti", /* 14 */ + "SubnAdmDelete", /* 15 */ + "UNKNOWN" /* 16 */ +}; + +static const char *const __ib_sa_resp_method_str[] = { + "RESERVED", /* 80 */ + "SubnAdmGetResp", /* 81 */ + "RESERVED (SetResp?)", /* 82 */ + "RESERVED", /* 83 */ + "RESERVED", /* 84 */ + "RESERVED", /* 85 */ + "SubnAdmReportResp", /* 86 */ + "RESERVED", /* 87 */ + "RESERVED", /* 88 */ + "RESERVED", /* 89 */ + "RESERVED", /* 8A */ + "RESERVED", /* 8B */ + "RESERVED", /* 8C */ + "RESERVED", /* 8D */ + "RESERVED", /* 8E */ + "RESERVED", /* 8F */ + "RESERVED", /* 90 */ + "RESERVED", /* 91 */ + "SubnAdmGetTableResp", /* 92 */ + "RESERVED", /* 93 */ + "SubnAdmGetMultiResp", /* 94 */ + "SubnAdmDeleteResp", /* 95 */ + "UNKNOWN" +}; + +#define OSM_SA_METHOD_STR_UNKNOWN_VAL 0x16 + +static const char *const __ib_sm_method_str[] = { + "RESERVED0", /* 0 */ + "SubnGet", /* 1 */ + "SubnSet", /* 2 */ + "RESERVED3", /* 3 */ + "RESERVED4", /* 4 */ + "SubnTrap", /* 5 */ + "RESERVED6", /* 6 */ + "SubnTrapRepress", /* 7 */ + "RESERVED8", /* 8 */ + "RESERVED9", /* 9 */ + "RESERVEDA", /* A */ + "RESERVEDB", /* B */ + "RESERVEDC", /* C */ + "RESERVEDD", /* D */ + "RESERVEDE", /* E */ + "RESERVEDF", /* F */ + "RESERVED10", /* 10 */ + "SubnGetResp", /* 11 */ + "RESERVED12", /* 12 */ + "RESERVED13", /* 13 */ + "RESERVED14", /* 14 */ + "RESERVED15", /* 15 */ + "RESERVED16", /* 16 */ + "RESERVED17", /* 17 */ + "RESERVED18", /* 18 */ + "RESERVED19", /* 19 */ + "RESERVED1A", /* 1A */ + "RESERVED1B", /* 1B */ + "RESERVED1C", /* 1C */ + "RESERVED1D", /* 1D */ + "RESERVED1E", /* 1E */ + "RESERVED1F", /* 1F */ + "UNKNOWN" /* 20 */ +}; + +#define OSM_SM_METHOD_STR_UNKNOWN_VAL 0x21 + +static const char *const __ib_sm_attr_str[] = { + "RESERVED", /* 0 */ + "ClassPortInfo", /* 1 */ + "Notice", /* 2 */ + "InformInfo", /* 3 */ + "RESERVED", /* 4 */ + "RESERVED", /* 5 */ + "RESERVED", /* 6 */ + "RESERVED", /* 7 */ + "RESERVED", /* 8 */ + "RESERVED", /* 9 */ + "RESERVED", /* A */ + "RESERVED", /* B */ + "RESERVED", /* C */ + "RESERVED", /* D */ + "RESERVED", /* E */ + "RESERVED", /* F */ + "NodeDescription", /* 10 */ + "NodeInfo", /* 11 */ + "SwitchInfo", /* 12 */ + "UNKNOWN", /* 13 */ + "GUIDInfo", /* 14 */ + "PortInfo", /* 15 */ + "P_KeyTable", /* 16 */ + "SLtoVLMappingTable", /* 17 */ + "VLArbitrationTable", /* 18 */ + "LinearForwardingTable", /* 19 */ + "RandomForwardingTable", /* 1A */ + "MulticastForwardingTable", /* 1B */ + "UNKNOWN", /* 1C */ + "UNKNOWN", /* 1D */ + "UNKNOWN", /* 1E */ + "UNKNOWN", /* 1F */ + "SMInfo", /* 20 */ + "UNKNOWN" /* 21 - always highest value */ +}; + +#define OSM_SM_ATTR_STR_UNKNOWN_VAL 0x21 + +static const char *const __ib_sa_attr_str[] = { + "RESERVED", /* 0 */ + "ClassPortInfo", /* 1 */ + "Notice", /* 2 */ + "InformInfo", /* 3 */ + "RESERVED", /* 4 */ + "RESERVED", /* 5 */ + "RESERVED", /* 6 */ + "RESERVED", /* 7 */ + "RESERVED", /* 8 */ + "RESERVED", /* 9 */ + "RESERVED", /* A */ + "RESERVED", /* B */ + "RESERVED", /* C */ + "RESERVED", /* D */ + "RESERVED", /* E */ + "RESERVED", /* F */ + "RESERVED", /* 10 */ + "NodeRecord", /* 11 */ + "PortInfoRecord", /* 12 */ + "SLtoVLMappingTableRecord", /* 13 */ + "SwitchInfoRecord", /* 14 */ + "LinearForwardingTableRecord", /* 15 */ + "RandomForwardingTableRecord", /* 16 */ + "MulticastForwardingTableRecord", /* 17 */ + "SMInfoRecord", /* 18 */ + "RESERVED", /* 19 */ + "RandomForwardingTable", /* 1A */ + "MulticastForwardingTable", /* 1B */ + "UNKNOWN", /* 1C */ + "UNKNOWN", /* 1D */ + "UNKNOWN", /* 1E */ + "UNKNOWN", /* 1F */ + "LinkRecord", /* 20 */ + "UNKNOWN", /* 21 */ + "UNKNOWN", /* 22 */ + "UNKNOWN", /* 23 */ + "UNKNOWN", /* 24 */ + "UNKNOWN", /* 25 */ + "UNKNOWN", /* 26 */ + "UNKNOWN", /* 27 */ + "UNKNOWN", /* 28 */ + "UNKNOWN", /* 29 */ + "UNKNOWN", /* 2A */ + "UNKNOWN", /* 2B */ + "UNKNOWN", /* 2C */ + "UNKNOWN", /* 2D */ + "UNKNOWN", /* 2E */ + "UNKNOWN", /* 2F */ + "GuidInfoRecord", /* 30 */ + "ServiceRecord", /* 31 */ + "UNKNOWN", /* 32 */ + "P_KeyTableRecord", /* 33 */ + "UNKNOWN", /* 34 */ + "PathRecord", /* 35 */ + "VLArbitrationTableRecord", /* 36 */ + "UNKNOWN", /* 37 */ + "MCMemberRecord", /* 38 */ + "TraceRecord", /* 39 */ + "MultiPathRecord", /* 3A */ + "ServiceAssociationRecord", /* 3B */ + "UNKNOWN", /* 3C */ + "UNKNOWN", /* 3D */ + "UNKNOWN", /* 3E */ + "UNKNOWN", /* 3F */ + "UNKNOWN", /* 40 */ + "UNKNOWN", /* 41 */ + "UNKNOWN", /* 42 */ + "UNKNOWN", /* 43 */ + "UNKNOWN", /* 44 */ + "UNKNOWN", /* 45 */ + "UNKNOWN", /* 46 */ + "UNKNOWN", /* 47 */ + "UNKNOWN", /* 48 */ + "UNKNOWN", /* 49 */ + "UNKNOWN", /* 4A */ + "UNKNOWN", /* 4B */ + "UNKNOWN", /* 4C */ + "UNKNOWN", /* 4D */ + "UNKNOWN", /* 4E */ + "UNKNOWN", /* 4F */ + "UNKNOWN", /* 50 */ + "UNKNOWN", /* 51 */ + "UNKNOWN", /* 52 */ + "UNKNOWN", /* 53 */ + "UNKNOWN", /* 54 */ + "UNKNOWN", /* 55 */ + "UNKNOWN", /* 56 */ + "UNKNOWN", /* 57 */ + "UNKNOWN", /* 58 */ + "UNKNOWN", /* 59 */ + "UNKNOWN", /* 5A */ + "UNKNOWN", /* 5B */ + "UNKNOWN", /* 5C */ + "UNKNOWN", /* 5D */ + "UNKNOWN", /* 5E */ + "UNKNOWN", /* 5F */ + "UNKNOWN", /* 60 */ + "UNKNOWN", /* 61 */ + "UNKNOWN", /* 62 */ + "UNKNOWN", /* 63 */ + "UNKNOWN", /* 64 */ + "UNKNOWN", /* 65 */ + "UNKNOWN", /* 66 */ + "UNKNOWN", /* 67 */ + "UNKNOWN", /* 68 */ + "UNKNOWN", /* 69 */ + "UNKNOWN", /* 6A */ + "UNKNOWN", /* 6B */ + "UNKNOWN", /* 6C */ + "UNKNOWN", /* 6D */ + "UNKNOWN", /* 6E */ + "UNKNOWN", /* 6F */ + "UNKNOWN", /* 70 */ + "UNKNOWN", /* 71 */ + "UNKNOWN", /* 72 */ + "UNKNOWN", /* 73 */ + "UNKNOWN", /* 74 */ + "UNKNOWN", /* 75 */ + "UNKNOWN", /* 76 */ + "UNKNOWN", /* 77 */ + "UNKNOWN", /* 78 */ + "UNKNOWN", /* 79 */ + "UNKNOWN", /* 7A */ + "UNKNOWN", /* 7B */ + "UNKNOWN", /* 7C */ + "UNKNOWN", /* 7D */ + "UNKNOWN", /* 7E */ + "UNKNOWN", /* 7F */ + "UNKNOWN", /* 80 */ + "UNKNOWN", /* 81 */ + "UNKNOWN", /* 82 */ + "UNKNOWN", /* 83 */ + "UNKNOWN", /* 84 */ + "UNKNOWN", /* 85 */ + "UNKNOWN", /* 86 */ + "UNKNOWN", /* 87 */ + "UNKNOWN", /* 88 */ + "UNKNOWN", /* 89 */ + "UNKNOWN", /* 8A */ + "UNKNOWN", /* 8B */ + "UNKNOWN", /* 8C */ + "UNKNOWN", /* 8D */ + "UNKNOWN", /* 8E */ + "UNKNOWN", /* 8F */ + "UNKNOWN", /* 90 */ + "UNKNOWN", /* 91 */ + "UNKNOWN", /* 92 */ + "UNKNOWN", /* 93 */ + "UNKNOWN", /* 94 */ + "UNKNOWN", /* 95 */ + "UNKNOWN", /* 96 */ + "UNKNOWN", /* 97 */ + "UNKNOWN", /* 98 */ + "UNKNOWN", /* 99 */ + "UNKNOWN", /* 9A */ + "UNKNOWN", /* 9B */ + "UNKNOWN", /* 9C */ + "UNKNOWN", /* 9D */ + "UNKNOWN", /* 9E */ + "UNKNOWN", /* 9F */ + "UNKNOWN", /* A0 */ + "UNKNOWN", /* A1 */ + "UNKNOWN", /* A2 */ + "UNKNOWN", /* A3 */ + "UNKNOWN", /* A4 */ + "UNKNOWN", /* A5 */ + "UNKNOWN", /* A6 */ + "UNKNOWN", /* A7 */ + "UNKNOWN", /* A8 */ + "UNKNOWN", /* A9 */ + "UNKNOWN", /* AA */ + "UNKNOWN", /* AB */ + "UNKNOWN", /* AC */ + "UNKNOWN", /* AD */ + "UNKNOWN", /* AE */ + "UNKNOWN", /* AF */ + "UNKNOWN", /* B0 */ + "UNKNOWN", /* B1 */ + "UNKNOWN", /* B2 */ + "UNKNOWN", /* B3 */ + "UNKNOWN", /* B4 */ + "UNKNOWN", /* B5 */ + "UNKNOWN", /* B6 */ + "UNKNOWN", /* B7 */ + "UNKNOWN", /* B8 */ + "UNKNOWN", /* B9 */ + "UNKNOWN", /* BA */ + "UNKNOWN", /* BB */ + "UNKNOWN", /* BC */ + "UNKNOWN", /* BD */ + "UNKNOWN", /* BE */ + "UNKNOWN", /* BF */ + "UNKNOWN", /* C0 */ + "UNKNOWN", /* C1 */ + "UNKNOWN", /* C2 */ + "UNKNOWN", /* C3 */ + "UNKNOWN", /* C4 */ + "UNKNOWN", /* C5 */ + "UNKNOWN", /* C6 */ + "UNKNOWN", /* C7 */ + "UNKNOWN", /* C8 */ + "UNKNOWN", /* C9 */ + "UNKNOWN", /* CA */ + "UNKNOWN", /* CB */ + "UNKNOWN", /* CC */ + "UNKNOWN", /* CD */ + "UNKNOWN", /* CE */ + "UNKNOWN", /* CF */ + "UNKNOWN", /* D0 */ + "UNKNOWN", /* D1 */ + "UNKNOWN", /* D2 */ + "UNKNOWN", /* D3 */ + "UNKNOWN", /* D4 */ + "UNKNOWN", /* D5 */ + "UNKNOWN", /* D6 */ + "UNKNOWN", /* D7 */ + "UNKNOWN", /* D8 */ + "UNKNOWN", /* D9 */ + "UNKNOWN", /* DA */ + "UNKNOWN", /* DB */ + "UNKNOWN", /* DC */ + "UNKNOWN", /* DD */ + "UNKNOWN", /* DE */ + "UNKNOWN", /* DF */ + "UNKNOWN", /* E0 */ + "UNKNOWN", /* E1 */ + "UNKNOWN", /* E2 */ + "UNKNOWN", /* E3 */ + "UNKNOWN", /* E4 */ + "UNKNOWN", /* E5 */ + "UNKNOWN", /* E6 */ + "UNKNOWN", /* E7 */ + "UNKNOWN", /* E8 */ + "UNKNOWN", /* E9 */ + "UNKNOWN", /* EA */ + "UNKNOWN", /* EB */ + "UNKNOWN", /* EC */ + "UNKNOWN", /* ED */ + "UNKNOWN", /* EE */ + "UNKNOWN", /* EF */ + "UNKNOWN", /* F0 */ + "UNKNOWN", /* F1 */ + "UNKNOWN", /* F2 */ + "InformInfoRecord", /* F3 */ + "UNKNOWN" /* F4 - always highest value */ +}; + +#define OSM_SA_ATTR_STR_UNKNOWN_VAL 0xF4 + +/********************************************************************** + **********************************************************************/ +const char *ib_get_sa_method_str(IN uint8_t method) +{ + if (method & 0x80) { + method = method & 0x7f; + if (method >= OSM_SA_METHOD_STR_UNKNOWN_VAL) + method = OSM_SA_METHOD_STR_UNKNOWN_VAL; + /* it is a response - use the response table */ + return (__ib_sa_resp_method_str[method]); + } else { + if (method >= OSM_SA_METHOD_STR_UNKNOWN_VAL) + method = OSM_SA_METHOD_STR_UNKNOWN_VAL; + return (__ib_sa_method_str[method]); + } +} + +/********************************************************************** + **********************************************************************/ +const char *ib_get_sm_method_str(IN uint8_t method) +{ + if (method & 0x80) + method = (method & 0x0F) | 0x10; + if (method >= OSM_SM_METHOD_STR_UNKNOWN_VAL) + method = OSM_SM_METHOD_STR_UNKNOWN_VAL; + return (__ib_sm_method_str[method]); +} + +/********************************************************************** + **********************************************************************/ +const char *ib_get_sm_attr_str(IN ib_net16_t attr) +{ + uint16_t host_attr; + host_attr = cl_ntoh16(attr); + + if (host_attr >= OSM_SM_ATTR_STR_UNKNOWN_VAL) + host_attr = OSM_SM_ATTR_STR_UNKNOWN_VAL; + + return (__ib_sm_attr_str[host_attr]); +} + +/********************************************************************** + **********************************************************************/ +const char *ib_get_sa_attr_str(IN ib_net16_t attr) +{ + uint16_t host_attr; + host_attr = cl_ntoh16(attr); + + if (host_attr >= OSM_SA_ATTR_STR_UNKNOWN_VAL) + host_attr = OSM_SA_ATTR_STR_UNKNOWN_VAL; + + return (__ib_sa_attr_str[host_attr]); +} + +/********************************************************************** + **********************************************************************/ +const char *ib_get_trap_str(ib_net16_t trap_num) +{ + switch(cl_ntoh16(trap_num)) + { + case 64: + return "GID in service"; + case 65: + return "GID out of service"; + case 66: + return "New mcast group created"; + case 67: + return "Mcast group deleted"; + case 68: + return "UnPath, Path no longer valid"; + case 69: + return "RePath, Path recomputed"; + case 128: + return "Link state change"; + case 129: + return "Local Link integrity threshold reached"; + case 130: + return "Excessive Buffer Overrun Threshold reached"; + case 131: + return "Flow Control Update watchdog timer expired"; + case 144: + return "CapabilityMask, NodeDescription, Link [Width|Speed] Enabled changed"; + case 145: + return "System Image GUID changed"; + case 256: + return "Bad M_Key"; + case 257: + return "Bad P_Key"; + case 258: + return "Bad Q_Key"; + case 259: + return "Bad P_Key (switch external port)"; + default: + break; + } + return "Unknown"; +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +dbg_do_line(IN char **pp_local, + IN const uint32_t buf_size, + IN const char *const p_prefix_str, + IN const char *const p_new_str, IN uint32_t * const p_total_len) +{ + char line[LINE_LENGTH]; + uint32_t len; + + sprintf(line, "%s%s", p_prefix_str, p_new_str); + len = (uint32_t) strlen(line); + *p_total_len += len; + if (*p_total_len + sizeof('\0') > buf_size) + return (IB_INSUFFICIENT_MEMORY); + + strcpy(*pp_local, line); + *pp_local += len; + return (IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +static void +dbg_get_capabilities_str(IN char *p_buf, + IN const uint32_t buf_size, + IN const char *const p_prefix_str, + IN const ib_port_info_t * const p_pi) +{ + uint32_t total_len = 0; + char *p_local = p_buf; + + strcpy(p_local, "Capability Mask:\n"); + p_local += strlen(p_local); + + if (p_pi->capability_mask & IB_PORT_CAP_RESV0) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_RESV0\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_IS_SM) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_IS_SM\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_NOTICE) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_NOTICE\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_TRAP) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_TRAP\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_IPD) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_IPD\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_AUTO_MIG) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_AUTO_MIG\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_SL_MAP) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_SL_MAP\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_NV_MKEY) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_NV_MKEY\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_NV_PKEY) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_NV_PKEY\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_LED_INFO) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_LED_INFO\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_SM_DISAB) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_SM_DISAB\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_SYS_IMG_GUID) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_SYS_IMG_GUID\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_PKEY_SW_EXT_PORT_TRAP) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_PKEY_SW_EXT_PORT_TRAP\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_RESV13) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_RESV13\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_RESV14) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_RESV14\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_RESV15) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_RESV15\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_COM_MGT) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_COM_MGT\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_SNMP) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_SNMP\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_REINIT) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_REINIT\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_DEV_MGT) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_DEV_MGT\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_VEND_CLS) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_VEND_CLS\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_DR_NTC) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_DR_NTC\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_CAP_NTC) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_CAP_NTC\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_BM) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_BM\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_LINK_RT_LATENCY) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_LINK_RT_LATENCY\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_CLIENT_REREG) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_CLIENT_REREG\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_OTHER_LOCAL_CHANGES_NTC) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_OTHER_LOCAL_CHANGES_NTC\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_HAS_LINK_SPEED_WIDTH_PAIRS_TBL) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_HAS_LINK_SPEED_WIDTH_PAIRS_TBL\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_RESV28) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_RESV28\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_RESV29) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_RESV29\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_RESV30) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_RESV30\n", + &total_len) != IB_SUCCESS) + return; + } + if (p_pi->capability_mask & IB_PORT_CAP_RESV31) { + if (dbg_do_line(&p_local, buf_size, p_prefix_str, + "IB_PORT_CAP_RESV31\n", + &total_len) != IB_SUCCESS) + return; + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_port_info(IN osm_log_t * const p_log, + IN const ib_net64_t node_guid, + IN const ib_net64_t port_guid, + IN const uint8_t port_num, + IN const ib_port_info_t * const p_pi, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char buf[BUF_SIZE]; + + osm_log(p_log, log_level, + "PortInfo dump:\n" + "\t\t\t\tport number.............%u\n" + "\t\t\t\tnode_guid...............0x%016" PRIx64 "\n" + "\t\t\t\tport_guid...............0x%016" PRIx64 "\n" + "\t\t\t\tm_key...................0x%016" PRIx64 "\n" + "\t\t\t\tsubnet_prefix...........0x%016" PRIx64 "\n" + "\t\t\t\tbase_lid................%u\n" + "\t\t\t\tmaster_sm_base_lid......%u\n" + "\t\t\t\tcapability_mask.........0x%X\n" + "\t\t\t\tdiag_code...............0x%X\n" + "\t\t\t\tm_key_lease_period......0x%X\n" + "\t\t\t\tlocal_port_num..........%u\n" + "\t\t\t\tlink_width_enabled......0x%X\n" + "\t\t\t\tlink_width_supported....0x%X\n" + "\t\t\t\tlink_width_active.......0x%X\n" + "\t\t\t\tlink_speed_supported....0x%X\n" + "\t\t\t\tport_state..............%s\n" + "\t\t\t\tstate_info2.............0x%X\n" + "\t\t\t\tm_key_protect_bits......0x%X\n" + "\t\t\t\tlmc.....................0x%X\n" + "\t\t\t\tlink_speed..............0x%X\n" + "\t\t\t\tmtu_smsl................0x%X\n" + "\t\t\t\tvl_cap_init_type........0x%X\n" + "\t\t\t\tvl_high_limit...........0x%X\n" + "\t\t\t\tvl_arb_high_cap.........0x%X\n" + "\t\t\t\tvl_arb_low_cap..........0x%X\n" + "\t\t\t\tinit_rep_mtu_cap........0x%X\n" + "\t\t\t\tvl_stall_life...........0x%X\n" + "\t\t\t\tvl_enforce..............0x%X\n" + "\t\t\t\tm_key_violations........0x%X\n" + "\t\t\t\tp_key_violations........0x%X\n" + "\t\t\t\tq_key_violations........0x%X\n" + "\t\t\t\tguid_cap................0x%X\n" + "\t\t\t\tclient_reregister.......0x%X\n" + "\t\t\t\tsubnet_timeout..........0x%X\n" + "\t\t\t\tresp_time_value.........0x%X\n" + "\t\t\t\terror_threshold.........0x%X\n", + port_num, + cl_ntoh64(node_guid), + cl_ntoh64(port_guid), + cl_ntoh64(p_pi->m_key), + cl_ntoh64(p_pi->subnet_prefix), + cl_ntoh16(p_pi->base_lid), + cl_ntoh16(p_pi->master_sm_base_lid), + cl_ntoh32(p_pi->capability_mask), + cl_ntoh16(p_pi->diag_code), + cl_ntoh16(p_pi->m_key_lease_period), + p_pi->local_port_num, + p_pi->link_width_enabled, + p_pi->link_width_supported, + p_pi->link_width_active, + ib_port_info_get_link_speed_sup(p_pi), + ib_get_port_state_str(ib_port_info_get_port_state + (p_pi)), p_pi->state_info2, + ib_port_info_get_mpb(p_pi), ib_port_info_get_lmc(p_pi), + p_pi->link_speed, p_pi->mtu_smsl, p_pi->vl_cap, + p_pi->vl_high_limit, p_pi->vl_arb_high_cap, + p_pi->vl_arb_low_cap, p_pi->mtu_cap, + p_pi->vl_stall_life, p_pi->vl_enforce, + cl_ntoh16(p_pi->m_key_violations), + cl_ntoh16(p_pi->p_key_violations), + cl_ntoh16(p_pi->q_key_violations), p_pi->guid_cap, + ib_port_info_get_client_rereg(p_pi), + ib_port_info_get_timeout(p_pi), p_pi->resp_time_value, + p_pi->error_threshold); + + /* show the capabilities mask */ + if (p_pi->capability_mask) { + dbg_get_capabilities_str(buf, BUF_SIZE, "\t\t\t\t", + p_pi); + osm_log(p_log, log_level, "%s", buf); + } + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_portinfo_record(IN osm_log_t * const p_log, + IN const ib_portinfo_record_t * const p_pir, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char buf[BUF_SIZE]; + const ib_port_info_t *const p_pi = &p_pir->port_info; + + osm_log(p_log, log_level, + "PortInfo Record dump:\n" + "\t\t\t\tRID\n" + "\t\t\t\tEndPortLid..............%u\n" + "\t\t\t\tPortNum.................0x%X\n" + "\t\t\t\tReserved................0x%X\n" + "\t\t\t\tPortInfo dump:\n" + "\t\t\t\tm_key...................0x%016" PRIx64 "\n" + "\t\t\t\tsubnet_prefix...........0x%016" PRIx64 "\n" + "\t\t\t\tbase_lid................%u\n" + "\t\t\t\tmaster_sm_base_lid......%u\n" + "\t\t\t\tcapability_mask.........0x%X\n" + "\t\t\t\tdiag_code...............0x%X\n" + "\t\t\t\tm_key_lease_period......0x%X\n" + "\t\t\t\tlocal_port_num..........%u\n" + "\t\t\t\tlink_width_enabled......0x%X\n" + "\t\t\t\tlink_width_supported....0x%X\n" + "\t\t\t\tlink_width_active.......0x%X\n" + "\t\t\t\tlink_speed_supported....0x%X\n" + "\t\t\t\tport_state..............%s\n" + "\t\t\t\tstate_info2.............0x%X\n" + "\t\t\t\tm_key_protect_bits......0x%X\n" + "\t\t\t\tlmc.....................0x%X\n" + "\t\t\t\tlink_speed..............0x%X\n" + "\t\t\t\tmtu_smsl................0x%X\n" + "\t\t\t\tvl_cap_init_type........0x%X\n" + "\t\t\t\tvl_high_limit...........0x%X\n" + "\t\t\t\tvl_arb_high_cap.........0x%X\n" + "\t\t\t\tvl_arb_low_cap..........0x%X\n" + "\t\t\t\tinit_rep_mtu_cap........0x%X\n" + "\t\t\t\tvl_stall_life...........0x%X\n" + "\t\t\t\tvl_enforce..............0x%X\n" + "\t\t\t\tm_key_violations........0x%X\n" + "\t\t\t\tp_key_violations........0x%X\n" + "\t\t\t\tq_key_violations........0x%X\n" + "\t\t\t\tguid_cap................0x%X\n" + "\t\t\t\tsubnet_timeout..........0x%X\n" + "\t\t\t\tresp_time_value.........0x%X\n" + "\t\t\t\terror_threshold.........0x%X\n", + cl_ntoh16(p_pir->lid), + p_pir->port_num, + p_pir->resv, + cl_ntoh64(p_pi->m_key), + cl_ntoh64(p_pi->subnet_prefix), + cl_ntoh16(p_pi->base_lid), + cl_ntoh16(p_pi->master_sm_base_lid), + cl_ntoh32(p_pi->capability_mask), + cl_ntoh16(p_pi->diag_code), + cl_ntoh16(p_pi->m_key_lease_period), + p_pi->local_port_num, + p_pi->link_width_enabled, + p_pi->link_width_supported, + p_pi->link_width_active, + ib_port_info_get_link_speed_sup(p_pi), + ib_get_port_state_str(ib_port_info_get_port_state + (p_pi)), p_pi->state_info2, + ib_port_info_get_mpb(p_pi), ib_port_info_get_lmc(p_pi), + p_pi->link_speed, p_pi->mtu_smsl, p_pi->vl_cap, + p_pi->vl_high_limit, p_pi->vl_arb_high_cap, + p_pi->vl_arb_low_cap, p_pi->mtu_cap, + p_pi->vl_stall_life, p_pi->vl_enforce, + cl_ntoh16(p_pi->m_key_violations), + cl_ntoh16(p_pi->p_key_violations), + cl_ntoh16(p_pi->q_key_violations), p_pi->guid_cap, + ib_port_info_get_timeout(p_pi), p_pi->resp_time_value, + p_pi->error_threshold); + + /* show the capabilities mask */ + if (p_pi->capability_mask) { + dbg_get_capabilities_str(buf, BUF_SIZE, "\t\t\t\t", + p_pi); + osm_log(p_log, log_level, "%s", buf); + } + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_guidinfo_record(IN osm_log_t * const p_log, + IN const ib_guidinfo_record_t * const p_gir, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + const ib_guid_info_t *const p_gi = &p_gir->guid_info; + + osm_log(p_log, log_level, + "GUIDInfo Record dump:\n" + "\t\t\t\tRID\n" + "\t\t\t\tLid.....................%u\n" + "\t\t\t\tBlockNum................0x%X\n" + "\t\t\t\tReserved................0x%X\n" + "\t\t\t\tGUIDInfo dump:\n" + "\t\t\t\tReserved................0x%X\n" + "\t\t\t\tGUID 0..................0x%016" PRIx64 "\n" + "\t\t\t\tGUID 1..................0x%016" PRIx64 "\n" + "\t\t\t\tGUID 2..................0x%016" PRIx64 "\n" + "\t\t\t\tGUID 3..................0x%016" PRIx64 "\n" + "\t\t\t\tGUID 4..................0x%016" PRIx64 "\n" + "\t\t\t\tGUID 5..................0x%016" PRIx64 "\n" + "\t\t\t\tGUID 6..................0x%016" PRIx64 "\n" + "\t\t\t\tGUID 7..................0x%016" PRIx64 "\n", + cl_ntoh16(p_gir->lid), + p_gir->block_num, + p_gir->resv, + cl_ntoh32(p_gir->reserved), + cl_ntoh64(p_gi->guid[0]), + cl_ntoh64(p_gi->guid[1]), + cl_ntoh64(p_gi->guid[2]), + cl_ntoh64(p_gi->guid[3]), + cl_ntoh64(p_gi->guid[4]), + cl_ntoh64(p_gi->guid[5]), + cl_ntoh64(p_gi->guid[6]), cl_ntoh64(p_gi->guid[7])); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_node_info(IN osm_log_t * const p_log, + IN const ib_node_info_t * const p_ni, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + osm_log(p_log, log_level, + "NodeInfo dump:\n" + "\t\t\t\tbase_version............0x%X\n" + "\t\t\t\tclass_version...........0x%X\n" + "\t\t\t\tnode_type...............%s\n" + "\t\t\t\tnum_ports...............%u\n" + "\t\t\t\tsys_guid................0x%016" PRIx64 "\n" + "\t\t\t\tnode_guid...............0x%016" PRIx64 "\n" + "\t\t\t\tport_guid...............0x%016" PRIx64 "\n" + "\t\t\t\tpartition_cap...........0x%X\n" + "\t\t\t\tdevice_id...............0x%X\n" + "\t\t\t\trevision................0x%X\n" + "\t\t\t\tport_num................%u\n" + "\t\t\t\tvendor_id...............0x%X\n", + p_ni->base_version, + p_ni->class_version, + ib_get_node_type_str(p_ni->node_type), + p_ni->num_ports, + cl_ntoh64(p_ni->sys_guid), + cl_ntoh64(p_ni->node_guid), + cl_ntoh64(p_ni->port_guid), + cl_ntoh16(p_ni->partition_cap), + cl_ntoh16(p_ni->device_id), + cl_ntoh32(p_ni->revision), + ib_node_info_get_local_port_num(p_ni), + cl_ntoh32(ib_node_info_get_vendor_id(p_ni))); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_node_record(IN osm_log_t * const p_log, + IN const ib_node_record_t * const p_nr, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char desc[sizeof(p_nr->node_desc.description) + 1]; + const ib_node_info_t *const p_ni = &p_nr->node_info; + + memcpy(desc, p_nr->node_desc.description, + sizeof(p_nr->node_desc.description)); + desc[sizeof(desc) - 1] = '\0'; + osm_log(p_log, log_level, + "Node Record dump:\n" + "\t\t\t\tRID\n" + "\t\t\t\tLid.....................%u\n" + "\t\t\t\tReserved................0x%X\n" + "\t\t\t\tNodeInfo dump:\n" + "\t\t\t\tbase_version............0x%X\n" + "\t\t\t\tclass_version...........0x%X\n" + "\t\t\t\tnode_type...............%s\n" + "\t\t\t\tnum_ports...............%u\n" + "\t\t\t\tsys_guid................0x%016" PRIx64 "\n" + "\t\t\t\tnode_guid...............0x%016" PRIx64 "\n" + "\t\t\t\tport_guid...............0x%016" PRIx64 "\n" + "\t\t\t\tpartition_cap...........0x%X\n" + "\t\t\t\tdevice_id...............0x%X\n" + "\t\t\t\trevision................0x%X\n" + "\t\t\t\tport_num................%u\n" + "\t\t\t\tvendor_id...............0x%X\n" + "\t\t\t\tNodeDescription\n" + "\t\t\t\t%s\n", + cl_ntoh16(p_nr->lid), + cl_ntoh16(p_nr->resv), + p_ni->base_version, + p_ni->class_version, + ib_get_node_type_str(p_ni->node_type), + p_ni->num_ports, + cl_ntoh64(p_ni->sys_guid), + cl_ntoh64(p_ni->node_guid), + cl_ntoh64(p_ni->port_guid), + cl_ntoh16(p_ni->partition_cap), + cl_ntoh16(p_ni->device_id), + cl_ntoh32(p_ni->revision), + ib_node_info_get_local_port_num(p_ni), + cl_ntoh32(ib_node_info_get_vendor_id(p_ni)), desc); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_path_record(IN osm_log_t * const p_log, + IN const ib_path_rec_t * const p_pr, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + osm_log(p_log, log_level, + "PathRecord dump:\n" + "\t\t\t\tservice_id..............0x%016" PRIx64 "\n" + "\t\t\t\tdgid....................0x%016" PRIx64 " : " + "0x%016" PRIx64 "\n" + "\t\t\t\tsgid....................0x%016" PRIx64 " : " + "0x%016" PRIx64 "\n" + "\t\t\t\tdlid....................%u\n" + "\t\t\t\tslid....................%u\n" + "\t\t\t\thop_flow_raw............0x%X\n" + "\t\t\t\ttclass..................0x%X\n" + "\t\t\t\tnum_path_revers.........0x%X\n" + "\t\t\t\tpkey....................0x%X\n" + "\t\t\t\tqos_class...............0x%X\n" + "\t\t\t\tsl......................0x%X\n" + "\t\t\t\tmtu.....................0x%X\n" + "\t\t\t\trate....................0x%X\n" + "\t\t\t\tpkt_life................0x%X\n" + "\t\t\t\tpreference..............0x%X\n" + "\t\t\t\tresv2...................0x%X\n" + "\t\t\t\tresv3...................0x%X\n", + cl_ntoh64(p_pr->service_id), + cl_ntoh64(p_pr->dgid.unicast.prefix), + cl_ntoh64(p_pr->dgid.unicast.interface_id), + cl_ntoh64(p_pr->sgid.unicast.prefix), + cl_ntoh64(p_pr->sgid.unicast.interface_id), + cl_ntoh16(p_pr->dlid), + cl_ntoh16(p_pr->slid), + cl_ntoh32(p_pr->hop_flow_raw), + p_pr->tclass, + p_pr->num_path, + cl_ntoh16(p_pr->pkey), + ib_path_rec_qos_class(p_pr), + ib_path_rec_sl(p_pr), + p_pr->mtu, + p_pr->rate, + p_pr->pkt_life, + p_pr->preference, + *(uint32_t *) & p_pr->resv2, + *((uint16_t *) & p_pr->resv2 + 2)); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_multipath_record(IN osm_log_t * const p_log, + IN const ib_multipath_rec_t * const p_mpr, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char buf_line[1024]; + ib_gid_t const *p_gid = p_mpr->gids; + int i, n = 0; + + if (p_mpr->sgid_count) { + for (i = 0; i < p_mpr->sgid_count; i++) { + n += sprintf(buf_line + n, + "\t\t\t\tsgid%02d.................." + "0x%016" PRIx64 " : 0x%016" PRIx64 + "\n", i + 1, + cl_ntoh64(p_gid->unicast.prefix), + cl_ntoh64(p_gid->unicast. + interface_id)); + p_gid++; + } + } + if (p_mpr->dgid_count) { + for (i = 0; i < p_mpr->dgid_count; i++) { + n += sprintf(buf_line + n, + "\t\t\t\tdgid%02d.................." + "0x%016" PRIx64 " : 0x%016" PRIx64 + "\n", i + 1, + cl_ntoh64(p_gid->unicast.prefix), + cl_ntoh64(p_gid->unicast. + interface_id)); + p_gid++; + } + } + osm_log(p_log, log_level, + "MultiPath Record dump:\n" + "\t\t\t\thop_flow_raw............0x%X\n" + "\t\t\t\ttclass..................0x%X\n" + "\t\t\t\tnum_path_revers.........0x%X\n" + "\t\t\t\tpkey....................0x%X\n" + "\t\t\t\tqos_class...............0x%X\n" + "\t\t\t\tsl......................0x%X\n" + "\t\t\t\tmtu.....................0x%X\n" + "\t\t\t\trate....................0x%X\n" + "\t\t\t\tpkt_life................0x%X\n" + "\t\t\t\tindependence............0x%X\n" + "\t\t\t\tsgid_count..............0x%X\n" + "\t\t\t\tdgid_count..............0x%X\n" + "\t\t\t\tservice_id..............0x%016" PRIx64 "\n" + "%s\n", + cl_ntoh32(p_mpr->hop_flow_raw), + p_mpr->tclass, + p_mpr->num_path, + cl_ntoh16(p_mpr->pkey), + ib_multipath_rec_qos_class(p_mpr), + ib_multipath_rec_sl(p_mpr), + p_mpr->mtu, + p_mpr->rate, + p_mpr->pkt_life, + p_mpr->independence, + p_mpr->sgid_count, p_mpr->dgid_count, + cl_ntoh64(ib_multipath_rec_service_id(p_mpr)), + buf_line); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_mc_record(IN osm_log_t * const p_log, + IN const ib_member_rec_t * const p_mcmr, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + osm_log(p_log, log_level, + "MCMember Record dump:\n" + "\t\t\t\tMGID....................%s\n" + "\t\t\t\tPortGid.................%s\n" + "\t\t\t\tqkey....................0x%X\n" + "\t\t\t\tmlid....................0x%X\n" + "\t\t\t\tmtu.....................0x%X\n" + "\t\t\t\tTClass..................0x%X\n" + "\t\t\t\tpkey....................0x%X\n" + "\t\t\t\trate....................0x%X\n" + "\t\t\t\tpkt_life................0x%X\n" + "\t\t\t\tSLFlowLabelHopLimit.....0x%X\n" + "\t\t\t\tScopeState..............0x%X\n" + "\t\t\t\tProxyJoin...............0x%X\n", + inet_ntop(AF_INET6, p_mcmr->mgid.raw, gid_str, + sizeof gid_str), + inet_ntop(AF_INET6, p_mcmr->port_gid.raw, gid_str2, + sizeof gid_str2), + cl_ntoh32(p_mcmr->qkey), + cl_ntoh16(p_mcmr->mlid), + p_mcmr->mtu, + p_mcmr->tclass, + cl_ntoh16(p_mcmr->pkey), + p_mcmr->rate, + p_mcmr->pkt_life, + cl_ntoh32(p_mcmr->sl_flow_hop), + p_mcmr->scope_state, p_mcmr->proxy_join); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_service_record(IN osm_log_t * const p_log, + IN const ib_service_record_t * const p_sr, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char gid_str[INET6_ADDRSTRLEN]; + char buf_service_key[35]; + char buf_service_name[65]; + + sprintf(buf_service_key, + "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + p_sr->service_key[0], + p_sr->service_key[1], + p_sr->service_key[2], + p_sr->service_key[3], + p_sr->service_key[4], + p_sr->service_key[5], + p_sr->service_key[6], + p_sr->service_key[7], + p_sr->service_key[8], + p_sr->service_key[9], + p_sr->service_key[10], + p_sr->service_key[11], + p_sr->service_key[12], + p_sr->service_key[13], + p_sr->service_key[14], p_sr->service_key[15]); + strncpy(buf_service_name, (char *)p_sr->service_name, 64); + buf_service_name[64] = '\0'; + + osm_log(p_log, log_level, + "Service Record dump:\n" + "\t\t\t\tServiceID...............0x%016" PRIx64 "\n" + "\t\t\t\tServiceGID..............%s\n" + "\t\t\t\tServiceP_Key............0x%X\n" + "\t\t\t\tServiceLease............0x%X\n" + "\t\t\t\tServiceKey..............%s\n" + "\t\t\t\tServiceName.............%s\n" + "\t\t\t\tServiceData8.1..........0x%X\n" + "\t\t\t\tServiceData8.2..........0x%X\n" + "\t\t\t\tServiceData8.3..........0x%X\n" + "\t\t\t\tServiceData8.4..........0x%X\n" + "\t\t\t\tServiceData8.5..........0x%X\n" + "\t\t\t\tServiceData8.6..........0x%X\n" + "\t\t\t\tServiceData8.7..........0x%X\n" + "\t\t\t\tServiceData8.8..........0x%X\n" + "\t\t\t\tServiceData8.9..........0x%X\n" + "\t\t\t\tServiceData8.10.........0x%X\n" + "\t\t\t\tServiceData8.11.........0x%X\n" + "\t\t\t\tServiceData8.12.........0x%X\n" + "\t\t\t\tServiceData8.13.........0x%X\n" + "\t\t\t\tServiceData8.14.........0x%X\n" + "\t\t\t\tServiceData8.15.........0x%X\n" + "\t\t\t\tServiceData8.16.........0x%X\n" + "\t\t\t\tServiceData16.1.........0x%X\n" + "\t\t\t\tServiceData16.2.........0x%X\n" + "\t\t\t\tServiceData16.3.........0x%X\n" + "\t\t\t\tServiceData16.4.........0x%X\n" + "\t\t\t\tServiceData16.5.........0x%X\n" + "\t\t\t\tServiceData16.6.........0x%X\n" + "\t\t\t\tServiceData16.7.........0x%X\n" + "\t\t\t\tServiceData16.8.........0x%X\n" + "\t\t\t\tServiceData32.1.........0x%X\n" + "\t\t\t\tServiceData32.2.........0x%X\n" + "\t\t\t\tServiceData32.3.........0x%X\n" + "\t\t\t\tServiceData32.4.........0x%X\n" + "\t\t\t\tServiceData64.1.........0x%016" PRIx64 "\n" + "\t\t\t\tServiceData64.2.........0x%016" PRIx64 "\n", + cl_ntoh64(p_sr->service_id), + inet_ntop(AF_INET6, p_sr->service_gid.raw, gid_str, + sizeof gid_str), + cl_ntoh16(p_sr->service_pkey), + cl_ntoh32(p_sr->service_lease), + buf_service_key, + buf_service_name, + p_sr->service_data8[0], p_sr->service_data8[1], + p_sr->service_data8[2], p_sr->service_data8[3], + p_sr->service_data8[4], p_sr->service_data8[5], + p_sr->service_data8[6], p_sr->service_data8[7], + p_sr->service_data8[8], p_sr->service_data8[9], + p_sr->service_data8[10], p_sr->service_data8[11], + p_sr->service_data8[12], p_sr->service_data8[13], + p_sr->service_data8[14], p_sr->service_data8[15], + cl_ntoh16(p_sr->service_data16[0]), + cl_ntoh16(p_sr->service_data16[1]), + cl_ntoh16(p_sr->service_data16[2]), + cl_ntoh16(p_sr->service_data16[3]), + cl_ntoh16(p_sr->service_data16[4]), + cl_ntoh16(p_sr->service_data16[5]), + cl_ntoh16(p_sr->service_data16[6]), + cl_ntoh16(p_sr->service_data16[7]), + cl_ntoh32(p_sr->service_data32[0]), + cl_ntoh32(p_sr->service_data32[1]), + cl_ntoh32(p_sr->service_data32[2]), + cl_ntoh32(p_sr->service_data32[3]), + cl_ntoh64(p_sr->service_data64[0]), + cl_ntoh64(p_sr->service_data64[1])); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_inform_info(IN osm_log_t * const p_log, + IN const ib_inform_info_t * const p_ii, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + uint32_t qpn; + uint8_t resp_time_val; + + ib_inform_info_get_qpn_resp_time(p_ii->g_or_v.generic. + qpn_resp_time_val, &qpn, + &resp_time_val); + if (p_ii->is_generic) { + osm_log(p_log, log_level, + "InformInfo dump:\n" + "\t\t\t\tgid.....................0x%016" PRIx64 + " : 0x%016" PRIx64 "\n" + "\t\t\t\tlid_range_begin.........%u\n" + "\t\t\t\tlid_range_end...........%u\n" + "\t\t\t\tis_generic..............0x%X\n" + "\t\t\t\tsubscribe...............0x%X\n" + "\t\t\t\ttrap_type...............0x%X\n" + "\t\t\t\ttrap_num................%u\n" + "\t\t\t\tqpn.....................0x%06X\n" + "\t\t\t\tresp_time_val...........0x%X\n" + "\t\t\t\tnode_type...............0x%06X\n" "", + cl_ntoh64(p_ii->gid.unicast.prefix), + cl_ntoh64(p_ii->gid.unicast.interface_id), + cl_ntoh16(p_ii->lid_range_begin), + cl_ntoh16(p_ii->lid_range_end), + p_ii->is_generic, p_ii->subscribe, + cl_ntoh16(p_ii->trap_type), + cl_ntoh16(p_ii->g_or_v.generic.trap_num), + cl_ntoh32(qpn), resp_time_val, + cl_ntoh32(ib_inform_info_get_prod_type(p_ii))); + } else { + osm_log(p_log, log_level, + "InformInfo dump:\n" + "\t\t\t\tgid.....................0x%016" PRIx64 + " : 0x%016" PRIx64 "\n" + "\t\t\t\tlid_range_begin.........%u\n" + "\t\t\t\tlid_range_end...........%u\n" + "\t\t\t\tis_generic..............0x%X\n" + "\t\t\t\tsubscribe...............0x%X\n" + "\t\t\t\ttrap_type...............0x%X\n" + "\t\t\t\tdev_id..................0x%X\n" + "\t\t\t\tqpn.....................0x%06X\n" + "\t\t\t\tresp_time_val...........0x%X\n" + "\t\t\t\tvendor_id...............0x%06X\n" "", + cl_ntoh64(p_ii->gid.unicast.prefix), + cl_ntoh64(p_ii->gid.unicast.interface_id), + cl_ntoh16(p_ii->lid_range_begin), + cl_ntoh16(p_ii->lid_range_end), + p_ii->is_generic, p_ii->subscribe, + cl_ntoh16(p_ii->trap_type), + cl_ntoh16(p_ii->g_or_v.vend.dev_id), + cl_ntoh32(qpn), resp_time_val, + cl_ntoh32(ib_inform_info_get_prod_type(p_ii))); + } + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_inform_info_record(IN osm_log_t * const p_log, + IN const ib_inform_info_record_t * const p_iir, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + uint32_t qpn; + uint8_t resp_time_val; + + ib_inform_info_get_qpn_resp_time(p_iir->inform_info.g_or_v. + generic.qpn_resp_time_val, + &qpn, &resp_time_val); + if (p_iir->inform_info.is_generic) { + osm_log(p_log, log_level, + "InformInfo Record dump:\n" + "\t\t\t\tRID\n" + "\t\t\t\tSubscriberGID...........%s\n" + "\t\t\t\tSubscriberEnum..........0x%X\n" + "\t\t\t\tInformInfo dump:\n" + "\t\t\t\tgid.....................%s\n" + "\t\t\t\tlid_range_begin.........%u\n" + "\t\t\t\tlid_range_end...........%u\n" + "\t\t\t\tis_generic..............0x%X\n" + "\t\t\t\tsubscribe...............0x%X\n" + "\t\t\t\ttrap_type...............0x%X\n" + "\t\t\t\ttrap_num................%u\n" + "\t\t\t\tqpn.....................0x%06X\n" + "\t\t\t\tresp_time_val...........0x%X\n" + "\t\t\t\tnode_type...............0x%06X\n" "", + inet_ntop(AF_INET6, p_iir->subscriber_gid.raw, + gid_str, sizeof gid_str), + cl_ntoh16(p_iir->subscriber_enum), + inet_ntop(AF_INET6, p_iir->inform_info.gid.raw, + gid_str2, sizeof gid_str2), + cl_ntoh16(p_iir->inform_info.lid_range_begin), + cl_ntoh16(p_iir->inform_info.lid_range_end), + p_iir->inform_info.is_generic, + p_iir->inform_info.subscribe, + cl_ntoh16(p_iir->inform_info.trap_type), + cl_ntoh16(p_iir->inform_info.g_or_v.generic. + trap_num), cl_ntoh32(qpn), + resp_time_val, + cl_ntoh32(ib_inform_info_get_prod_type + (&p_iir->inform_info))); + } else { + osm_log(p_log, log_level, + "InformInfo Record dump:\n" + "\t\t\t\tRID\n" + "\t\t\t\tSubscriberGID...........%s\n" + "\t\t\t\tSubscriberEnum..........0x%X\n" + "\t\t\t\tInformInfo dump:\n" + "\t\t\t\tgid.....................%s\n" + "\t\t\t\tlid_range_begin.........%u\n" + "\t\t\t\tlid_range_end...........%u\n" + "\t\t\t\tis_generic..............0x%X\n" + "\t\t\t\tsubscribe...............0x%X\n" + "\t\t\t\ttrap_type...............0x%X\n" + "\t\t\t\tdev_id..................0x%X\n" + "\t\t\t\tqpn.....................0x%06X\n" + "\t\t\t\tresp_time_val...........0x%X\n" + "\t\t\t\tvendor_id...............0x%06X\n" "", + inet_ntop(AF_INET6, p_iir->subscriber_gid.raw, + gid_str, sizeof gid_str), + cl_ntoh16(p_iir->subscriber_enum), + inet_ntop(AF_INET6, p_iir->inform_info.gid.raw, + gid_str2, sizeof gid_str2), + cl_ntoh16(p_iir->inform_info.lid_range_begin), + cl_ntoh16(p_iir->inform_info.lid_range_end), + p_iir->inform_info.is_generic, + p_iir->inform_info.subscribe, + cl_ntoh16(p_iir->inform_info.trap_type), + cl_ntoh16(p_iir->inform_info.g_or_v.vend. + dev_id), cl_ntoh32(qpn), + resp_time_val, + cl_ntoh32(ib_inform_info_get_prod_type + (&p_iir->inform_info))); + } + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_link_record(IN osm_log_t * const p_log, + IN const ib_link_record_t * const p_lr, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + osm_log(p_log, log_level, + "Link Record dump:\n" + "\t\t\t\tfrom_lid................%u\n" + "\t\t\t\tfrom_port_num...........%u\n" + "\t\t\t\tto_port_num.............%u\n" + "\t\t\t\tto_lid..................%u\n", + cl_ntoh16(p_lr->from_lid), + p_lr->from_port_num, + p_lr->to_port_num, cl_ntoh16(p_lr->to_lid)); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_switch_info(IN osm_log_t * const p_log, + IN const ib_switch_info_t * const p_si, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + osm_log(p_log, OSM_LOG_VERBOSE, + "SwitchInfo dump:\n" + "\t\t\t\tlin_cap.................0x%X\n" + "\t\t\t\trand_cap................0x%X\n" + "\t\t\t\tmcast_cap...............0x%X\n" + "\t\t\t\tlin_top.................0x%X\n" + "\t\t\t\tdef_port................%u\n" + "\t\t\t\tdef_mcast_pri_port......%u\n" + "\t\t\t\tdef_mcast_not_port......%u\n" + "\t\t\t\tlife_state..............0x%X\n" + "\t\t\t\tlids_per_port...........%u\n" + "\t\t\t\tpartition_enf_cap.......0x%X\n" + "\t\t\t\tflags...................0x%X\n", + cl_ntoh16(p_si->lin_cap), + cl_ntoh16(p_si->rand_cap), + cl_ntoh16(p_si->mcast_cap), + cl_ntoh16(p_si->lin_top), + p_si->def_port, + p_si->def_mcast_pri_port, + p_si->def_mcast_not_port, + p_si->life_state, + cl_ntoh16(p_si->lids_per_port), + cl_ntoh16(p_si->enforce_cap), p_si->flags); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_switch_info_record(IN osm_log_t * const p_log, + IN const ib_switch_info_record_t * const p_sir, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + osm_log(p_log, log_level, + "SwitchInfo Record dump:\n" + "\t\t\t\tRID\n" + "\t\t\t\tlid.....................%u\n" + "\t\t\t\tSwitchInfo dump:\n" + "\t\t\t\tlin_cap.................0x%X\n" + "\t\t\t\trand_cap................0x%X\n" + "\t\t\t\tmcast_cap...............0x%X\n" + "\t\t\t\tlin_top.................0x%X\n" + "\t\t\t\tdef_port................%u\n" + "\t\t\t\tdef_mcast_pri_port......%u\n" + "\t\t\t\tdef_mcast_not_port......%u\n" + "\t\t\t\tlife_state..............0x%X\n" + "\t\t\t\tlids_per_port...........%u\n" + "\t\t\t\tpartition_enf_cap.......0x%X\n" + "\t\t\t\tflags...................0x%X\n", + cl_ntoh16(p_sir->lid), + cl_ntoh16(p_sir->switch_info.lin_cap), + cl_ntoh16(p_sir->switch_info.rand_cap), + cl_ntoh16(p_sir->switch_info.mcast_cap), + cl_ntoh16(p_sir->switch_info.lin_top), + p_sir->switch_info.def_port, + p_sir->switch_info.def_mcast_pri_port, + p_sir->switch_info.def_mcast_not_port, + p_sir->switch_info.life_state, + cl_ntoh16(p_sir->switch_info.lids_per_port), + cl_ntoh16(p_sir->switch_info.enforce_cap), + p_sir->switch_info.flags); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_pkey_block(IN osm_log_t * const p_log, + IN uint64_t port_guid, + IN uint16_t block_num, + IN uint8_t port_num, + IN const ib_pkey_table_t * const p_pkey_tbl, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char buf_line[1024]; + int i, n; + + for (i = 0, n = 0; i < 32; i++) + n += sprintf(buf_line + n, " 0x%04x |", + cl_ntoh16(p_pkey_tbl->pkey_entry[i])); + + osm_log(p_log, log_level, + "P_Key table dump:\n" + "\t\t\tport_guid...........0x%016" PRIx64 "\n" + "\t\t\tblock_num...........0x%X\n" + "\t\t\tport_num............%u\n\tP_Key Table: %s\n", + cl_ntoh64(port_guid), block_num, port_num, buf_line); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_slvl_map_table(IN osm_log_t * const p_log, + IN uint64_t port_guid, + IN uint8_t in_port_num, + IN uint8_t out_port_num, + IN const ib_slvl_table_t * const p_slvl_tbl, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char buf_line1[1024], buf_line2[1024]; + int n; + uint8_t i; + + for (i = 0, n = 0; i < 16; i++) + n += sprintf(buf_line1 + n, " %-2u |", i); + for (i = 0, n = 0; i < 16; i++) + n += sprintf(buf_line2 + n, "0x%01X |", + ib_slvl_table_get(p_slvl_tbl, i)); + osm_log(p_log, log_level, + "SLtoVL dump:\n" + "\t\t\tport_guid............0x%016" PRIx64 "\n" + "\t\t\tin_port_num..........%u\n" + "\t\t\tout_port_num.........%u\n\tSL: | %s\n\tVL: | %s\n", + cl_ntoh64(port_guid), + in_port_num, out_port_num, buf_line1, buf_line2); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_vl_arb_table(IN osm_log_t * const p_log, + IN uint64_t port_guid, + IN uint8_t block_num, + IN uint8_t port_num, + IN const ib_vl_arb_table_t * const p_vla_tbl, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char buf_line1[1024], buf_line2[1024]; + int i, n; + + for (i = 0, n = 0; i < 32; i++) + n += sprintf(buf_line1 + n, " 0x%01X |", + p_vla_tbl->vl_entry[i].vl); + for (i = 0, n = 0; i < 32; i++) + n += sprintf(buf_line2 + n, " 0x%01X |", + p_vla_tbl->vl_entry[i].weight); + osm_log(p_log, log_level, + "VLArb dump:\n" "\t\t\tport_guid...........0x%016" + PRIx64 "\n" "\t\t\tblock_num...........0x%X\n" + "\t\t\tport_num............%u\n\tVL : | %s\n\tWEIGHT:| %s\n", + cl_ntoh64(port_guid), block_num, port_num, buf_line1, + buf_line2); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_sm_info(IN osm_log_t * const p_log, + IN const ib_sm_info_t * const p_smi, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + osm_log(p_log, OSM_LOG_DEBUG, + "SMInfo dump:\n" + "\t\t\t\tguid....................0x%016" PRIx64 "\n" + "\t\t\t\tsm_key..................0x%016" PRIx64 "\n" + "\t\t\t\tact_count...............%u\n" + "\t\t\t\tpriority................%u\n" + "\t\t\t\tsm_state................%u\n", + cl_ntoh64(p_smi->guid), + cl_ntoh64(p_smi->sm_key), + cl_ntoh32(p_smi->act_count), + ib_sminfo_get_priority(p_smi), + ib_sminfo_get_state(p_smi)); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_sm_info_record(IN osm_log_t * const p_log, + IN const ib_sminfo_record_t * const p_smir, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + osm_log(p_log, OSM_LOG_DEBUG, + "SMInfo Record dump:\n" + "\t\t\t\tRID\n" + "\t\t\t\tLid.....................%u\n" + "\t\t\t\tReserved................0x%X\n" + "\t\t\t\tSMInfo dump:\n" + "\t\t\t\tguid....................0x%016" PRIx64 "\n" + "\t\t\t\tsm_key..................0x%016" PRIx64 "\n" + "\t\t\t\tact_count...............%u\n" + "\t\t\t\tpriority................%u\n" + "\t\t\t\tsm_state................%u\n", + cl_ntoh16(p_smir->lid), + cl_ntoh16(p_smir->resv0), + cl_ntoh64(p_smir->sm_info.guid), + cl_ntoh64(p_smir->sm_info.sm_key), + cl_ntoh32(p_smir->sm_info.act_count), + ib_sminfo_get_priority(&p_smir->sm_info), + ib_sminfo_get_state(&p_smir->sm_info)); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_notice(IN osm_log_t * const p_log, + IN const ib_mad_notice_attr_t * p_ntci, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + if (ib_notice_is_generic(p_ntci)) { + char buff[1024]; + buff[0] = '\0'; + + /* immediate data based on the trap */ + switch (cl_ntoh16(p_ntci->g_or_v.generic.trap_num)) { + case 64: + case 65: + case 66: + case 67: + sprintf(buff, + "\t\t\t\tsrc_gid..................0x%016" + PRIx64 ":0x%016" PRIx64 "\n", + cl_ntoh64(p_ntci->data_details. + ntc_64_67.gid.unicast.prefix), + cl_ntoh64(p_ntci->data_details. + ntc_64_67.gid.unicast. + interface_id)); + break; + case 128: + sprintf(buff, + "\t\t\t\tsw_lid...................%u\n", + cl_ntoh16(p_ntci->data_details.ntc_128. + sw_lid)); + break; + case 129: + case 130: + case 131: + sprintf(buff, + "\t\t\t\tlid......................%u\n" + "\t\t\t\tport_num.................%u\n", + cl_ntoh16(p_ntci->data_details. + ntc_129_131.lid), + p_ntci->data_details.ntc_129_131. + port_num); + break; + case 144: + sprintf(buff, + "\t\t\t\tlid......................%u\n" + "\t\t\t\tnew_cap_mask.............0x%08x\n", + cl_ntoh16(p_ntci->data_details.ntc_144. + lid), + cl_ntoh32(p_ntci->data_details.ntc_144. + new_cap_mask)); + break; + case 145: + sprintf(buff, + "\t\t\t\tlid......................%u\n" + "\t\t\t\tnew_sys_guid.............0x%016" + PRIx64 "\n", + cl_ntoh16(p_ntci->data_details.ntc_145. + lid), + cl_ntoh64(p_ntci->data_details.ntc_145. + new_sys_guid)); + break; + } + + osm_log(p_log, log_level, + "Generic Notice dump:\n" + "\t\t\t\ttype.....................%u\n" + "\t\t\t\tprod_type................%u (%s)\n" + "\t\t\t\ttrap_num.................%u\n%s", + ib_notice_get_type(p_ntci), + cl_ntoh32(ib_notice_get_prod_type(p_ntci)), + ib_get_producer_type_str(ib_notice_get_prod_type + (p_ntci)), + cl_ntoh16(p_ntci->g_or_v.generic.trap_num), + buff); + } else { + osm_log(p_log, log_level, + "Vendor Notice dump:\n" + "\t\t\t\ttype.....................%u\n" + "\t\t\t\tvendor...................%u\n" + "\t\t\t\tdevice_id................%u\n", + cl_ntoh16(ib_notice_get_type(p_ntci)), + cl_ntoh32(ib_notice_get_vend_id(p_ntci)), + cl_ntoh16(p_ntci->g_or_v.vend.dev_id)); + } + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_dr_smp(IN osm_log_t * const p_log, + IN const ib_smp_t * const p_smp, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char buf[BUF_SIZE], line[BUF_SIZE]; + uint32_t i; + + sprintf(buf, + "SMP dump:\n" + "\t\t\t\tbase_ver................0x%X\n" + "\t\t\t\tmgmt_class..............0x%X\n" + "\t\t\t\tclass_ver...............0x%X\n" + "\t\t\t\tmethod..................0x%X (%s)\n", + p_smp->base_ver, + p_smp->mgmt_class, + p_smp->class_ver, + p_smp->method, ib_get_sm_method_str(p_smp->method)); + + if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR) { + sprintf(line, + "\t\t\t\tD bit...................0x%X\n" + "\t\t\t\tstatus..................0x%X\n", + ib_smp_is_d(p_smp), ib_smp_get_status(p_smp)); + } else { + sprintf(line, + "\t\t\t\tstatus..................0x%X\n", + cl_ntoh16(p_smp->status)); + } + strcat(buf, line); + + sprintf(line, + "\t\t\t\thop_ptr.................0x%X\n" + "\t\t\t\thop_count...............0x%X\n" + "\t\t\t\ttrans_id................0x%" PRIx64 "\n" + "\t\t\t\tattr_id.................0x%X (%s)\n" + "\t\t\t\tresv....................0x%X\n" + "\t\t\t\tattr_mod................0x%X\n" + "\t\t\t\tm_key...................0x%016" PRIx64 "\n", + p_smp->hop_ptr, + p_smp->hop_count, + cl_ntoh64(p_smp->trans_id), + cl_ntoh16(p_smp->attr_id), + ib_get_sm_attr_str(p_smp->attr_id), + cl_ntoh16(p_smp->resv), + cl_ntoh32(p_smp->attr_mod), cl_ntoh64(p_smp->m_key)); + strcat(buf, line); + + if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR) { + sprintf(line, + "\t\t\t\tdr_slid.................%u\n" + "\t\t\t\tdr_dlid.................%u\n", + cl_ntoh16(p_smp->dr_slid), + cl_ntoh16(p_smp->dr_dlid)); + strcat(buf, line); + + strcat(buf, "\n\t\t\t\tInitial path: "); + + for (i = 0; i <= p_smp->hop_count; i++) { + if (i == 0) + sprintf(line, "%d", + p_smp->initial_path[i]); + else + sprintf(line, ",%d", + p_smp->initial_path[i]); + strcat(buf, line); + } + + strcat(buf, "\n\t\t\t\tReturn path: "); + + for (i = 0; i <= p_smp->hop_count; i++) { + if (i == 0) + sprintf(line, "%d", + p_smp->return_path[i]); + else + sprintf(line, ",%d", + p_smp->return_path[i]); + strcat(buf, line); + } + + strcat(buf, "\n\t\t\t\tReserved: "); + + for (i = 0; i < 7; i++) { + sprintf(line, "[%0X]", p_smp->resv1[i]); + strcat(buf, line); + } + + strcat(buf, "\n"); + + for (i = 0; i < 64; i += 16) { + sprintf(line, "\n\t\t\t\t%02X %02X %02X %02X " + "%02X %02X %02X %02X" + " %02X %02X %02X %02X %02X %02X %02X %02X\n", + p_smp->data[i], + p_smp->data[i + 1], + p_smp->data[i + 2], + p_smp->data[i + 3], + p_smp->data[i + 4], + p_smp->data[i + 5], + p_smp->data[i + 6], + p_smp->data[i + 7], + p_smp->data[i + 8], + p_smp->data[i + 9], + p_smp->data[i + 10], + p_smp->data[i + 11], + p_smp->data[i + 12], + p_smp->data[i + 13], + p_smp->data[i + 14], + p_smp->data[i + 15]); + + strcat(buf, line); + } + } else { + /* not a Direct Route so provide source and destination lids */ + strcat(buf, "\t\t\t\tMAD IS LID ROUTED\n"); + } + + osm_log(p_log, log_level, "%s\n", buf); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_sa_mad(IN osm_log_t * const p_log, + IN const ib_sa_mad_t * const p_mad, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char buf[BUF_SIZE]; + + /* make sure the mad is valid */ + if (p_mad == NULL) { + OSM_LOG(p_log, log_level, "NULL MAD POINTER\n"); + return; + } + + sprintf(buf, + "SA MAD dump:\n" + "\t\t\t\tbase_ver................0x%X\n" + "\t\t\t\tmgmt_class..............0x%X\n" + "\t\t\t\tclass_ver...............0x%X\n" + "\t\t\t\tmethod..................0x%X (%s)\n" + "\t\t\t\tstatus..................0x%X\n" + "\t\t\t\tresv....................0x%X\n" + "\t\t\t\ttrans_id................0x%" PRIx64 "\n" + "\t\t\t\tattr_id.................0x%X (%s)\n" + "\t\t\t\tresv1...................0x%X\n" + "\t\t\t\tattr_mod................0x%X\n" + "\t\t\t\trmpp_version............0x%X\n" + "\t\t\t\trmpp_type...............0x%X\n" + "\t\t\t\trmpp_flags..............0x%X\n" + "\t\t\t\trmpp_status.............0x%X\n" + "\t\t\t\tseg_num.................0x%X\n" + "\t\t\t\tpayload_len/new_win.....0x%X\n" + "\t\t\t\tsm_key..................0x%016" PRIx64 "\n" + "\t\t\t\tattr_offset.............0x%X\n" + "\t\t\t\tresv2...................0x%X\n" + "\t\t\t\tcomp_mask...............0x%016" PRIx64 "\n", + p_mad->base_ver, + p_mad->mgmt_class, + p_mad->class_ver, + p_mad->method, ib_get_sa_method_str(p_mad->method), + cl_ntoh16(p_mad->status), + cl_ntoh16(p_mad->resv), + cl_ntoh64(p_mad->trans_id), + cl_ntoh16(p_mad->attr_id), + ib_get_sa_attr_str(p_mad->attr_id), + cl_ntoh16(p_mad->resv1), + cl_ntoh32(p_mad->attr_mod), + p_mad->rmpp_version, + p_mad->rmpp_type, + p_mad->rmpp_flags, + p_mad->rmpp_status, + cl_ntoh32(p_mad->seg_num), + cl_ntoh32(p_mad->paylen_newwin), + cl_ntoh64(p_mad->sm_key), + cl_ntoh16(p_mad->attr_offset), + cl_ntoh16(p_mad->resv3), cl_ntoh64(p_mad->comp_mask)); + + strcat(buf, "\n"); + + osm_log(p_log, log_level, "%s\n", buf); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_dr_path(IN osm_log_t * const p_log, + IN const osm_dr_path_t * const p_path, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char buf[BUF_SIZE], line[BUF_SIZE]; + uint32_t i; + + sprintf(buf, "Directed Path Dump of %u hop path:" + "\n\t\t\t\tPath = ", p_path->hop_count); + + for (i = 0; i <= p_path->hop_count; i++) { + if (i == 0) + sprintf(line, "%d", p_path->path[i]); + else + sprintf(line, ",%d", p_path->path[i]); + strcat(buf, line); + } + osm_log(p_log, log_level, "%s\n", buf); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_dump_smp_dr_path(IN osm_log_t * const p_log, + IN const ib_smp_t * const p_smp, + IN const osm_log_level_t log_level) +{ + if (osm_log_is_active(p_log, log_level)) { + char buf[BUF_SIZE], line[BUF_SIZE]; + uint32_t i; + + sprintf(buf, "Received SMP on a %u hop path:" + "\n\t\t\t\tInitial path = ", p_smp->hop_count); + + for (i = 0; i <= p_smp->hop_count; i++) { + if (i == 0) + sprintf(line, "%d", p_smp->initial_path[i]); + else + sprintf(line, ",%d", p_smp->initial_path[i]); + strcat(buf, line); + } + + strcat(buf, "\n\t\t\t\tReturn path = "); + + for (i = 0; i <= p_smp->hop_count; i++) { + if (i == 0) + sprintf(line, "%d", p_smp->return_path[i]); + else + sprintf(line, ",%d", p_smp->return_path[i]); + strcat(buf, line); + } + + osm_log(p_log, log_level, "%s\n", buf); + } +} + +static const char *const __osm_sm_signal_str[] = { + "OSM_SIGNAL_NONE", /* 0 */ + "OSM_SIGNAL_SWEEP", /* 1 */ + "OSM_SIGNAL_IDLE_TIME_PROCESS_REQUEST", /* 2 */ + "OSM_SIGNAL_EXIT_STBY", /* 3 */ + "OSM_SIGNAL_PERFMGR_SWEEP", /* 4 */ + "UNKNOWN SIGNAL!!" /* 5 */ +}; + +/********************************************************************** + **********************************************************************/ +const char *osm_get_sm_signal_str(IN osm_signal_t signal) +{ + if (signal > OSM_SIGNAL_MAX) + signal = OSM_SIGNAL_MAX; + return (__osm_sm_signal_str[signal]); +} + +/********************************************************************** + **********************************************************************/ + +static const char *const __osm_disp_msg_str[] = { + "OSM_MSG_NONE", + "OSM_MSG_MAD_NODE_INFO", + "OSM_MSG_MAD_PORT_INFO", + "OSM_MSG_MAD_SWITCH_INFO", + "OSM_MSG_MAD_NODE_DESC", + "OSM_MSG_MAD_NODE_RECORD", + "OSM_MSG_MAD_PORTINFO_RECORD", + "OSM_MSG_MAD_SERVICE_RECORD", + "OSM_MSG_MAD_PATH_RECORD", + "OSM_MSG_MAD_MCMEMBER_RECORD", + "OSM_MSG_MAD_LINK_RECORD", + "OSM_MSG_MAD_SMINFO_RECORD", + "OSM_MSG_MAD_CLASS_PORT_INFO", + "OSM_MSG_MAD_INFORM_INFO", + "OSM_MSG_MAD_LFT_RECORD", + "OSM_MSG_MAD_LFT", + "OSM_MSG_MAD_SM_INFO", + "OSM_MSG_MAD_NOTICE", + "OSM_MSG_LIGHT_SWEEP_FAIL", + "OSM_MSG_MAD_MFT", + "OSM_MSG_MAD_PKEY_TBL_RECORD", + "OSM_MSG_MAD_VL_ARB_RECORD", + "OSM_MSG_MAD_SLVL_TBL_RECORD", + "OSM_MSG_MAD_PKEY", + "OSM_MSG_MAD_VL_ARB", + "OSM_MSG_MAD_SLVL", + "OSM_MSG_MAD_GUIDINFO_RECORD", + "OSM_MSG_MAD_INFORM_INFO_RECORD", +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + "OSM_MSG_MAD_MULTIPATH_RECORD", +#endif + "UNKNOWN!!" +}; + +/********************************************************************** + **********************************************************************/ +const char *osm_get_disp_msg_str(IN cl_disp_msgid_t msg) +{ + if (msg > OSM_MSG_MAX) + msg = OSM_MSG_MAX; + return (__osm_disp_msg_str[msg]); +} + +static const char *const __osm_port_state_str_fixed_width[] = { + "NOC", + "DWN", + "INI", + "ARM", + "ACT", + "???" +}; + +/********************************************************************** + **********************************************************************/ +const char *osm_get_port_state_str_fixed_width(IN uint8_t port_state) +{ + if (port_state > IB_LINK_ACTIVE) + port_state = IB_LINK_ACTIVE + 1; + return (__osm_port_state_str_fixed_width[port_state]); +} + +static const char *const __osm_node_type_str_fixed_width[] = { + "??", + "CA", + "SW", + "RT", +}; + +/********************************************************************** + **********************************************************************/ +const char *osm_get_node_type_str_fixed_width(IN uint8_t node_type) +{ + if (node_type > IB_NODE_TYPE_ROUTER) + node_type = 0; + return (__osm_node_type_str_fixed_width[node_type]); +} + +/********************************************************************** + **********************************************************************/ +const char *osm_get_manufacturer_str(IN uint64_t const guid_ho) +{ + /* note that the max vendor string length is 11 */ + static const char *intel_str = "Intel"; + static const char *mellanox_str = "Mellanox"; + static const char *redswitch_str = "Redswitch"; + static const char *silverstorm_str = "SilverStorm"; + static const char *topspin_str = "Topspin"; + static const char *fujitsu_str = "Fujitsu"; + static const char *voltaire_str = "Voltaire"; + static const char *yotta_str = "YottaYotta"; + static const char *pathscale_str = "PathScale"; + static const char *ibm_str = "IBM"; + static const char *divergenet_str = "DivergeNet"; + static const char *flextronics_str = "Flextronics"; + static const char *agilent_str = "Agilent"; + static const char *obsidian_str = "Obsidian"; + static const char *baymicro_str = "BayMicro"; + static const char *lsilogic_str = "LSILogic"; + static const char *ddn_str = "DataDirect"; + static const char *panta_str = "Panta"; + static const char *hp_str = "HP"; + static const char *rioworks_str = "Rioworks"; + static const char *sun_str = "Sun"; + static const char *leafntwks_str = "3LeafNtwks"; + static const char *xsigo_str = "Xsigo"; + static const char *unknown_str = "Unknown"; + + switch ((uint32_t) (guid_ho >> (5 * 8))) { + case OSM_VENDOR_ID_INTEL: + return (intel_str); + case OSM_VENDOR_ID_MELLANOX: + return (mellanox_str); + case OSM_VENDOR_ID_REDSWITCH: + return (redswitch_str); + case OSM_VENDOR_ID_SILVERSTORM: + return (silverstorm_str); + case OSM_VENDOR_ID_TOPSPIN: + return (topspin_str); + case OSM_VENDOR_ID_FUJITSU: + case OSM_VENDOR_ID_FUJITSU2: + return (fujitsu_str); + case OSM_VENDOR_ID_VOLTAIRE: + return (voltaire_str); + case OSM_VENDOR_ID_YOTTAYOTTA: + return (yotta_str); + case OSM_VENDOR_ID_PATHSCALE: + return (pathscale_str); + case OSM_VENDOR_ID_IBM: + return (ibm_str); + case OSM_VENDOR_ID_DIVERGENET: + return (divergenet_str); + case OSM_VENDOR_ID_FLEXTRONICS: + return (flextronics_str); + case OSM_VENDOR_ID_AGILENT: + return (agilent_str); + case OSM_VENDOR_ID_OBSIDIAN: + return (obsidian_str); + case OSM_VENDOR_ID_BAYMICRO: + return (baymicro_str); + case OSM_VENDOR_ID_LSILOGIC: + return (lsilogic_str); + case OSM_VENDOR_ID_DDN: + return (ddn_str); + case OSM_VENDOR_ID_PANTA: + return (panta_str); + case OSM_VENDOR_ID_HP: + case OSM_VENDOR_ID_HP2: + return (hp_str); + case OSM_VENDOR_ID_RIOWORKS: + return (rioworks_str); + case OSM_VENDOR_ID_SUN: + return (sun_str); + case OSM_VENDOR_ID_3LEAFNTWKS: + return (leafntwks_str); + case OSM_VENDOR_ID_XSIGO: + return (xsigo_str); + default: + return (unknown_str); + } +} + +static const char *const __osm_mtu_str_fixed_width[] = { + "??? ", + "256 ", + "512 ", + "1024", + "2048", + "4096" +}; + +/********************************************************************** + **********************************************************************/ +const char *osm_get_mtu_str(IN uint8_t const mtu) +{ + if (mtu > IB_MTU_LEN_4096) + return (__osm_mtu_str_fixed_width[0]); + else + return (__osm_mtu_str_fixed_width[mtu]); +} + +static const char *const __osm_lwa_str_fixed_width[] = { + "???", + "1x ", + "4x ", + "???", + "8x ", + "???", + "???", + "???", + "12x" +}; + +/********************************************************************** + **********************************************************************/ +const char *osm_get_lwa_str(IN uint8_t const lwa) +{ + if (lwa > 8) + return (__osm_lwa_str_fixed_width[0]); + else + return (__osm_lwa_str_fixed_width[lwa]); +} + +/********************************************************************** + **********************************************************************/ +static const char *const __osm_lsa_str_fixed_width[] = { + "???", + "2.5", + "5 ", + "???", + "10 " +}; + +const char *osm_get_lsa_str(IN uint8_t const lsa) +{ + if (lsa > 4) + return (__osm_lsa_str_fixed_width[0]); + else + return (__osm_lsa_str_fixed_width[lsa]); +} + +/********************************************************************** + **********************************************************************/ + +static const char *const __osm_sm_mgr_signal_str[] = { + "OSM_SM_SIGNAL_NONE", /* 0 */ + "OSM_SM_SIGNAL_DISCOVERY_COMPLETED", /* 2 */ + "OSM_SM_SIGNAL_POLLING_TIMEOUT", /* 3 */ + "OSM_SM_SIGNAL_DISCOVER", /* 4 */ + "OSM_SM_SIGNAL_DISABLE", /* 5 */ + "OSM_SM_SIGNAL_HANDOVER", /* 6 */ + "OSM_SM_SIGNAL_HANDOVER_SENT", /* 7 */ + "OSM_SM_SIGNAL_ACKNOWLEDGE", /* 8 */ + "OSM_SM_SIGNAL_STANDBY", /* 9 */ + "OSM_SM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED", /* 10 */ + "OSM_SM_SIGNAL_WAIT_FOR_HANDOVER", /* 11 */ + "UNKNOWN STATE!!" /* 12 */ +}; + +/********************************************************************** + **********************************************************************/ +const char *osm_get_sm_mgr_signal_str(IN osm_sm_signal_t signal) +{ + if (signal > OSM_SM_SIGNAL_MAX) + signal = OSM_SM_SIGNAL_MAX; + return (__osm_sm_mgr_signal_str[signal]); +} + +static const char *const __osm_sm_mgr_state_str[] = { + "NOTACTIVE", /* 0 */ + "DISCOVERING", /* 1 */ + "STANDBY", /* 2 */ + "MASTER", /* 3 */ + "UNKNOWN STATE!!" /* 4 */ +}; + +const char *osm_get_sm_mgr_state_str(IN uint16_t state) +{ + return state < ARR_SIZE(__osm_sm_mgr_state_str) ? + __osm_sm_mgr_state_str[state] : + __osm_sm_mgr_state_str[ARR_SIZE(__osm_sm_mgr_state_str) - 1]; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_indent b/contrib/ofed/management/opensm/opensm/osm_indent new file mode 100755 index 000000000000..4da000f285d2 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_indent @@ -0,0 +1,56 @@ +#!/bin/bash +# +# Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. +# Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. +# Copyright (c) 1996-2003 Intel Corporation. All rights reserved. +# +# This software is available to you under a choice of one of two +# licenses. You may choose to be licensed under the terms of the GNU +# General Public License (GPL) Version 2, available from the file +# COPYING in the main directory of this source tree, or the +# OpenIB.org BSD license below: +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +######################################################################### +# +# Abstract: +# Indent script for source code formatting. +# +# Environment: +# Linux User Mode +# +# This is the indent format used for OpenSM (similar to one used in +# linux/scripts/Lindent). + +indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs "$@" + +# indent doesn't have an option for label indentation, so do it with sed +for f in $@ ; do + test -f $f || continue + temp=`mktemp -t osm_indent.XXXXXXXX` + cat $f \ + | sed -e 's/^ \([A-Za-z_]\+[A-Za-z_0-9]*:\)$/\1/' > $temp + diff $f $temp > /dev/null || cat $temp > $f + rm -f $temp +done diff --git a/contrib/ofed/management/opensm/opensm/osm_inform.c b/contrib/ofed/management/opensm/opensm/osm_inform.c new file mode 100644 index 000000000000..1331d752d274 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_inform.c @@ -0,0 +1,616 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of inform record functions. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_infr_match_ctxt { + cl_list_t *p_remove_infr_list; + ib_mad_notice_attr_t *p_ntc; +} osm_infr_match_ctxt_t; + +/********************************************************************** + **********************************************************************/ +void osm_infr_delete(IN osm_infr_t * const p_infr) +{ + free(p_infr); +} + +/********************************************************************** + **********************************************************************/ +osm_infr_t *osm_infr_new(IN const osm_infr_t * p_infr_rec) +{ + osm_infr_t *p_infr; + + CL_ASSERT(p_infr_rec); + + p_infr = (osm_infr_t *) malloc(sizeof(osm_infr_t)); + if (p_infr) + memcpy(p_infr, p_infr_rec, sizeof(osm_infr_t)); + + return (p_infr); +} + +/********************************************************************** + **********************************************************************/ +static void dump_all_informs(IN osm_subn_t const *p_subn, IN osm_log_t * p_log) +{ + cl_list_item_t *p_list_item; + + if (!osm_log_is_active(p_log, OSM_LOG_DEBUG)) + return; + + p_list_item = cl_qlist_head(&p_subn->sa_infr_list); + while (p_list_item != cl_qlist_end(&p_subn->sa_infr_list)) { + osm_dump_inform_info(p_log, + &((osm_infr_t *) p_list_item)-> + inform_record.inform_info, OSM_LOG_DEBUG); + p_list_item = cl_qlist_next(p_list_item); + } +} + +/********************************************************************** + * Match an infr by the InformInfo and Address vector + **********************************************************************/ +static cl_status_t +__match_inf_rec(IN const cl_list_item_t * const p_list_item, IN void *context) +{ + osm_infr_t *p_infr_rec = (osm_infr_t *) context; + osm_infr_t *p_infr = (osm_infr_t *) p_list_item; + osm_log_t *p_log = p_infr_rec->sa->p_log; + cl_status_t status = CL_NOT_FOUND; + ib_gid_t all_zero_gid; + + OSM_LOG_ENTER(p_log); + + if (memcmp(&p_infr->report_addr, &p_infr_rec->report_addr, + sizeof(p_infr_rec->report_addr))) { + OSM_LOG(p_log, OSM_LOG_DEBUG, "Differ by Address\n"); + goto Exit; + } + + memset(&all_zero_gid, 0, sizeof(ib_gid_t)); + + /* if inform_info.gid is not zero, ignore lid range */ + if (!memcmp(&p_infr_rec->inform_record.inform_info.gid, &all_zero_gid, + sizeof(p_infr_rec->inform_record.inform_info.gid))) { + if (memcmp(&p_infr->inform_record.inform_info.gid, + &p_infr_rec->inform_record.inform_info.gid, + sizeof(p_infr->inform_record.inform_info.gid))) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Differ by InformInfo.gid\n"); + goto Exit; + } + } else { + if ((p_infr->inform_record.inform_info.lid_range_begin != + p_infr_rec->inform_record.inform_info.lid_range_begin) || + (p_infr->inform_record.inform_info.lid_range_end != + p_infr_rec->inform_record.inform_info.lid_range_end)) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Differ by InformInfo.LIDRange\n"); + goto Exit; + } + } + + if (p_infr->inform_record.inform_info.trap_type != + p_infr_rec->inform_record.inform_info.trap_type) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Differ by InformInfo.TrapType\n"); + goto Exit; + } + + if (p_infr->inform_record.inform_info.is_generic != + p_infr_rec->inform_record.inform_info.is_generic) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Differ by InformInfo.IsGeneric\n"); + goto Exit; + } + + if (p_infr->inform_record.inform_info.is_generic) { + if (p_infr->inform_record.inform_info.g_or_v.generic.trap_num != + p_infr_rec->inform_record.inform_info.g_or_v.generic. + trap_num) + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Differ by InformInfo.Generic.TrapNumber\n"); + else if (p_infr->inform_record.inform_info.g_or_v.generic. + qpn_resp_time_val != + p_infr_rec->inform_record.inform_info.g_or_v.generic. + qpn_resp_time_val) + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Differ by InformInfo.Generic.QPNRespTimeVal\n"); + else if (p_infr->inform_record.inform_info.g_or_v.generic. + node_type_msb != + p_infr_rec->inform_record.inform_info.g_or_v.generic. + node_type_msb) + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Differ by InformInfo.Generic.NodeTypeMSB\n"); + else if (p_infr->inform_record.inform_info.g_or_v.generic. + node_type_lsb != + p_infr_rec->inform_record.inform_info.g_or_v.generic. + node_type_lsb) + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Differ by InformInfo.Generic.NodeTypeLSB\n"); + else + status = CL_SUCCESS; + } else { + if (p_infr->inform_record.inform_info.g_or_v.vend.dev_id != + p_infr_rec->inform_record.inform_info.g_or_v.vend.dev_id) + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Differ by InformInfo.Vendor.DeviceID\n"); + else if (p_infr->inform_record.inform_info.g_or_v.vend. + qpn_resp_time_val != + p_infr_rec->inform_record.inform_info.g_or_v.vend. + qpn_resp_time_val) + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Differ by InformInfo.Vendor.QPNRespTimeVal\n"); + else if (p_infr->inform_record.inform_info.g_or_v.vend. + vendor_id_msb != + p_infr_rec->inform_record.inform_info.g_or_v.vend. + vendor_id_msb) + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Differ by InformInfo.Vendor.VendorIdMSB\n"); + else if (p_infr->inform_record.inform_info.g_or_v.vend. + vendor_id_lsb != + p_infr_rec->inform_record.inform_info.g_or_v.vend. + vendor_id_lsb) + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Differ by InformInfo.Vendor.VendorIdLSB\n"); + else + status = CL_SUCCESS; + } + +Exit: + OSM_LOG_EXIT(p_log); + return status; +} + +/********************************************************************** + **********************************************************************/ +osm_infr_t *osm_infr_get_by_rec(IN osm_subn_t const *p_subn, + IN osm_log_t * p_log, + IN osm_infr_t * const p_infr_rec) +{ + cl_list_item_t *p_list_item; + + OSM_LOG_ENTER(p_log); + + dump_all_informs(p_subn, p_log); + + OSM_LOG(p_log, OSM_LOG_DEBUG, "Looking for Inform Record\n"); + osm_dump_inform_info(p_log, &(p_infr_rec->inform_record.inform_info), + OSM_LOG_DEBUG); + OSM_LOG(p_log, OSM_LOG_DEBUG, "InformInfo list size %d\n", + cl_qlist_count(&p_subn->sa_infr_list)); + + p_list_item = cl_qlist_find_from_head(&p_subn->sa_infr_list, + __match_inf_rec, p_infr_rec); + + if (p_list_item == cl_qlist_end(&p_subn->sa_infr_list)) + p_list_item = NULL; + + OSM_LOG_EXIT(p_log); + return (osm_infr_t *) p_list_item; +} + +/********************************************************************** + **********************************************************************/ +void +osm_infr_insert_to_db(IN osm_subn_t * p_subn, + IN osm_log_t * p_log, IN osm_infr_t * p_infr) +{ + OSM_LOG_ENTER(p_log); + + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Inserting new InformInfo Record into Database\n"); + OSM_LOG(p_log, OSM_LOG_DEBUG, "Dump before insertion (size %d)\n", + cl_qlist_count(&p_subn->sa_infr_list)); + dump_all_informs(p_subn, p_log); + +#if 0 + osm_dump_inform_info(p_log, + &(p_infr->inform_record.inform_info), + OSM_LOG_DEBUG); +#endif + + cl_qlist_insert_head(&p_subn->sa_infr_list, &p_infr->list_item); + + OSM_LOG(p_log, OSM_LOG_DEBUG, "Dump after insertion (size %d)\n", + cl_qlist_count(&p_subn->sa_infr_list)); + dump_all_informs(p_subn, p_log); + OSM_LOG_EXIT(p_log); +} + +/********************************************************************** + **********************************************************************/ +void +osm_infr_remove_from_db(IN osm_subn_t * p_subn, + IN osm_log_t * p_log, IN osm_infr_t * p_infr) +{ + char gid_str[INET6_ADDRSTRLEN]; + OSM_LOG_ENTER(p_log); + + OSM_LOG(p_log, OSM_LOG_DEBUG, "Removing InformInfo Subscribing GID:%s" + " Enum:0x%X from Database\n", + inet_ntop(AF_INET6, p_infr->inform_record.subscriber_gid.raw, + gid_str, sizeof gid_str), + p_infr->inform_record.subscriber_enum); + + osm_dump_inform_info(p_log, &(p_infr->inform_record.inform_info), + OSM_LOG_DEBUG); + + cl_qlist_remove_item(&p_subn->sa_infr_list, &p_infr->list_item); + + osm_infr_delete(p_infr); + + OSM_LOG_EXIT(p_log); +} + +/********************************************************************** + * Send a report: + * Given a target address to send to and the notice. + * We need to send SubnAdmReport + **********************************************************************/ +static ib_api_status_t __osm_send_report(IN osm_infr_t * p_infr_rec, /* the informinfo */ + IN ib_mad_notice_attr_t * p_ntc /* notice to send */ + ) +{ + osm_madw_t *p_report_madw; + ib_mad_notice_attr_t *p_report_ntc; + ib_mad_t *p_mad; + ib_sa_mad_t *p_sa_mad; + static atomic32_t trap_fwd_trans_id = 0x02DAB000; + ib_api_status_t status = IB_SUCCESS; + osm_log_t *p_log = p_infr_rec->sa->p_log; + + OSM_LOG_ENTER(p_log); + + /* HACK: who switches or uses the src and dest GIDs in the grh_info ?? */ + + /* it is better to use LIDs since the GIDs might not be there for SMI traps */ + OSM_LOG(p_log, OSM_LOG_DEBUG, "Forwarding Notice Event from LID:%u" + " to InformInfo LID: %u TID:0x%X\n", + cl_ntoh16(p_ntc->issuer_lid), + cl_ntoh16(p_infr_rec->report_addr.dest_lid), trap_fwd_trans_id); + + /* get the MAD to send */ + p_report_madw = osm_mad_pool_get(p_infr_rec->sa->p_mad_pool, + p_infr_rec->h_bind, MAD_BLOCK_SIZE, + &(p_infr_rec->report_addr)); + + p_report_madw->resp_expected = TRUE; + + if (!p_report_madw) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0203" + "osm_mad_pool_get failed\n"); + status = IB_ERROR; + goto Exit; + } + + /* advance trap trans id (cant simply ++ on some systems inside ntoh) */ + p_mad = osm_madw_get_mad_ptr(p_report_madw); + ib_mad_init_new(p_mad, IB_MCLASS_SUBN_ADM, 2, IB_MAD_METHOD_REPORT, + cl_hton64((uint64_t) cl_atomic_inc(&trap_fwd_trans_id)), + IB_MAD_ATTR_NOTICE, 0); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_report_madw); + + p_report_ntc = (ib_mad_notice_attr_t *) & (p_sa_mad->data); + + /* copy the notice */ + *p_report_ntc = *p_ntc; + + /* The TRUE is for: response is expected */ + osm_sa_send(p_infr_rec->sa, p_report_madw, TRUE); + +Exit: + OSM_LOG_EXIT(p_log); + return (status); +} + +/********************************************************************** + * This routine compares a given Notice and a ListItem of InformInfo type. + * PREREQUISITE: + * The Notice.GID should be pre-filled with the trap generator GID + **********************************************************************/ +static void +__match_notice_to_inf_rec(IN cl_list_item_t * const p_list_item, + IN void *context) +{ + osm_infr_match_ctxt_t *p_infr_match = (osm_infr_match_ctxt_t *) context; + ib_mad_notice_attr_t *p_ntc = p_infr_match->p_ntc; + cl_list_t *p_infr_to_remove_list = p_infr_match->p_remove_infr_list; + osm_infr_t *p_infr_rec = (osm_infr_t *) p_list_item; + ib_inform_info_t *p_ii = &(p_infr_rec->inform_record.inform_info); + cl_status_t status = CL_NOT_FOUND; + osm_log_t *p_log = p_infr_rec->sa->p_log; + osm_subn_t *p_subn = p_infr_rec->sa->p_subn; + ib_gid_t source_gid; + osm_port_t *p_src_port; + osm_port_t *p_dest_port; + + OSM_LOG_ENTER(p_log); + + /* matching rules + * InformInfo Notice + * GID IssuerGID if non zero must match the trap + * LIDRange IssuerLID apply only if GID=0 + * IsGeneric IsGeneric is compulsory and must match the trap + * Type Type if not 0xFFFF must match + * TrapNumber TrapNumber if not 0xFFFF must match + * DeviceId DeviceID if not 0xFFFF must match + * QPN dont care + * ProducerType ProducerType match or 0xFFFFFF // EZ: actually my interpretation + * VendorID VendorID match or 0xFFFFFF + */ + + /* GID IssuerGID if non zero must match the trap */ + if (p_ii->gid.unicast.prefix != 0 + || p_ii->gid.unicast.interface_id != 0) { + /* match by GID */ + if (memcmp(&(p_ii->gid), &(p_ntc->issuer_gid), + sizeof(ib_gid_t))) { + OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by GID\n"); + goto Exit; + } + } else { + /* LIDRange IssuerLID apply only if GID=0 */ + /* If lid_range_begin of the informInfo is 0xFFFF - then it should be ignored. */ + if (p_ii->lid_range_begin != 0xFFFF) { + /* a real lid range is given - check it */ + if ((cl_hton16(p_ii->lid_range_begin) > + cl_hton16(p_ntc->issuer_lid)) + || (cl_hton16(p_ntc->issuer_lid) > + cl_hton16(p_ii->lid_range_end))) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Mismatch by LID Range. Needed: %u <= %u <= %u\n", + cl_hton16(p_ii->lid_range_begin), + cl_hton16(p_ntc->issuer_lid), + cl_hton16(p_ii->lid_range_end)); + goto Exit; + } + } + } + + /* IsGeneric IsGeneric is compulsory and must match the trap */ + if ((p_ii->is_generic && !ib_notice_is_generic(p_ntc)) || + (!p_ii->is_generic && ib_notice_is_generic(p_ntc))) { + OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Generic/Vendor\n"); + goto Exit; + } + + /* Type Type if not 0xFFFF must match */ + if ((p_ii->trap_type != 0xFFFF) && + (cl_ntoh16(p_ii->trap_type) != ib_notice_get_type(p_ntc))) { + OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Type\n"); + goto Exit; + } + + /* based on generic type */ + if (p_ii->is_generic) { + /* TrapNumber TrapNumber if not 0xFFFF must match */ + if ((p_ii->g_or_v.generic.trap_num != 0xFFFF) && + (p_ii->g_or_v.generic.trap_num != + p_ntc->g_or_v.generic.trap_num)) { + OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Trap Num\n"); + goto Exit; + } + + /* ProducerType ProducerType match or 0xFFFFFF */ + if ((cl_ntoh32(ib_inform_info_get_prod_type(p_ii)) != 0xFFFFFF) + && (ib_inform_info_get_prod_type(p_ii) != + ib_notice_get_prod_type(p_ntc))) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Mismatch by Node Type: II=0x%06X (%s) Trap=0x%06X (%s)\n", + cl_ntoh32(ib_inform_info_get_prod_type(p_ii)), + ib_get_producer_type_str + (ib_inform_info_get_prod_type(p_ii)), + cl_ntoh32(ib_notice_get_prod_type(p_ntc)), + ib_get_producer_type_str(ib_notice_get_prod_type + (p_ntc))); + goto Exit; + } + } else { + /* DeviceId DeviceID if not 0xFFFF must match */ + if ((p_ii->g_or_v.vend.dev_id != 0xFFFF) && + (p_ii->g_or_v.vend.dev_id != p_ntc->g_or_v.vend.dev_id)) { + OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Dev Id\n"); + goto Exit; + } + + /* VendorID VendorID match or 0xFFFFFF */ + if ((ib_inform_info_get_vend_id(p_ii) != CL_HTON32(0xFFFFFF)) && + (ib_inform_info_get_vend_id(p_ii) != + ib_notice_get_vend_id(p_ntc))) { + OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Vendor ID\n"); + goto Exit; + } + } + + /* Check if there is a pkey match. o13-17.1.1 */ + /* Check if the issuer of the trap is the SM. If it is, then the gid + comparison should be done on the trap source (saved as the gid in the + data details field). + If the issuer gid is not the SM - then it is the guid of the trap + source */ + if ((cl_ntoh64(p_ntc->issuer_gid.unicast.prefix) == + p_subn->opt.subnet_prefix) + && (cl_ntoh64(p_ntc->issuer_gid.unicast.interface_id) == + p_subn->sm_port_guid)) + /* The issuer is the SM then this is trap 64-67 - compare the gid + with the gid saved on the data details */ + source_gid = p_ntc->data_details.ntc_64_67.gid; + else + source_gid = p_ntc->issuer_gid; + + p_src_port = + osm_get_port_by_guid(p_subn, source_gid.unicast.interface_id); + if (!p_src_port) { + OSM_LOG(p_log, OSM_LOG_INFO, + "Cannot find source port with GUID:0x%016" PRIx64 "\n", + cl_ntoh64(source_gid.unicast.interface_id)); + goto Exit; + } + + p_dest_port = + cl_ptr_vector_get(&p_subn->port_lid_tbl, + cl_ntoh16(p_infr_rec->report_addr.dest_lid)); + if (!p_dest_port) { + OSM_LOG(p_log, OSM_LOG_INFO, + "Cannot find destination port with LID:%u\n", + cl_ntoh16(p_infr_rec->report_addr.dest_lid)); + goto Exit; + } + + if (osm_port_share_pkey(p_log, p_src_port, p_dest_port) == FALSE) { + OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Pkey\n"); + /* According to o13-17.1.2 - If this informInfo does not have + lid_range_begin of 0xFFFF, then this informInfo request + should be removed from database */ + if (p_ii->lid_range_begin != 0xFFFF) { + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "Pkey mismatch on lid_range_begin != 0xFFFF. " + "Need to remove this informInfo from db\n"); + /* add the informInfo record to the remove_infr list */ + cl_list_insert_tail(p_infr_to_remove_list, p_infr_rec); + } + goto Exit; + } + + /* send the report to the address provided in the inform record */ + OSM_LOG(p_log, OSM_LOG_DEBUG, "MATCH! Sending Report...\n"); + __osm_send_report(p_infr_rec, p_ntc); + status = CL_SUCCESS; + +Exit: + OSM_LOG_EXIT(p_log); +} + +/********************************************************************** + * Once a Trap was received by osm_trap_rcv, or a Trap sourced by + * the SM was sent (Traps 64-67), this routine is called with a copy of + * the notice data. + * Given a notice attribute - compare and see if it matches the InformInfo + * element and if it does - call the Report(Notice) for the + * target QP registered by the address stored in the InformInfo element + **********************************************************************/ +ib_api_status_t +osm_report_notice(IN osm_log_t * const p_log, + IN osm_subn_t * p_subn, IN ib_mad_notice_attr_t * p_ntc) +{ + char gid_str[INET6_ADDRSTRLEN]; + osm_infr_match_ctxt_t context; + cl_list_t infr_to_remove_list; + osm_infr_t *p_infr_rec; + osm_infr_t *p_next_infr_rec; + + OSM_LOG_ENTER(p_log); + + /* + * we must make sure we are ready for this... + * note that the trap receivers might be initialized before + * the osm_infr_init call is performed. + */ + if (p_subn->sa_infr_list.state != CL_INITIALIZED) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Ignoring Notice Reports since Inform List is not initialized yet!\n"); + return (IB_ERROR); + } + + /* an official Event information log */ + if (ib_notice_is_generic(p_ntc)) + OSM_LOG(p_log, OSM_LOG_INFO, + "Reporting Generic Notice type:%u num:%u (%s)" + " from LID:%u GID:%s\n", + ib_notice_get_type(p_ntc), + cl_ntoh16(p_ntc->g_or_v.generic.trap_num), + ib_get_trap_str(p_ntc->g_or_v.generic.trap_num), + cl_ntoh16(p_ntc->issuer_lid), + inet_ntop(AF_INET6, p_ntc->issuer_gid.raw, gid_str, + sizeof gid_str)); + else + OSM_LOG(p_log, OSM_LOG_INFO, + "Reporting Vendor Notice type:%u vend:%u dev:%u" + " from LID:%u GID:%s\n", + ib_notice_get_type(p_ntc), + cl_ntoh32(ib_notice_get_vend_id(p_ntc)), + cl_ntoh16(p_ntc->g_or_v.vend.dev_id), + cl_ntoh16(p_ntc->issuer_lid), + inet_ntop(AF_INET6, p_ntc->issuer_gid.raw, gid_str, + sizeof gid_str)); + + /* Create a list that will hold all the infr records that should + be removed due to violation. o13-17.1.2 */ + cl_list_construct(&infr_to_remove_list); + cl_list_init(&infr_to_remove_list, 5); + context.p_remove_infr_list = &infr_to_remove_list; + context.p_ntc = p_ntc; + + /* go over all inform info available at the subnet */ + /* try match to the given notice and send if match */ + cl_qlist_apply_func(&(p_subn->sa_infr_list), + __match_notice_to_inf_rec, &context); + + /* If we inserted items into the infr_to_remove_list - we need to + remove them */ + p_infr_rec = (osm_infr_t *) cl_list_remove_head(&infr_to_remove_list); + while (p_infr_rec != NULL) { + p_next_infr_rec = + (osm_infr_t *) cl_list_remove_head(&infr_to_remove_list); + osm_infr_remove_from_db(p_subn, p_log, p_infr_rec); + p_infr_rec = p_next_infr_rec; + } + cl_list_destroy(&infr_to_remove_list); + + OSM_LOG_EXIT(p_log); + + return (IB_SUCCESS); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_lid_mgr.c b/contrib/ofed/management/opensm/opensm/osm_lid_mgr.c new file mode 100644 index 000000000000..b74aba51d46e --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_lid_mgr.c @@ -0,0 +1,1321 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_lid_mgr_t. + * This file implements the LID Manager object which is responsible for + * assigning LIDs to all ports on the subnet. + * + * DATA STRUCTURES: + * p_subn->port_lid_tbl : a vector pointing from lid to its port. + * osm db guid2lid domain : a hash from guid to lid (min lid). + * p_subn->port_guid_tbl : a map from guid to discovered port obj. + * + * ALGORITHM: + * + * 0. we define a function to obtain the correct port lid: + * __osm_lid_mgr_get_port_lid( p_mgr, port, &min_lid ): + * 0.1 if the port info lid matches the guid2lid return 0 + * 0.2 if the port info has a lid and that range is empty in + * port_lid_tbl, return 0 and update the port_lid_tbl and + * guid2lid + * 0.3 else find an empty space in port_lid_tbl, update the + * port_lid_tbl and guid2lid, return 1 to flag a change required. + * + * 1. During initialization: + * 1.1 initialize the guid2lid database domain. + * 1.2 if reassign_lid is not set: + * 1.2.1 read the persistent data for the domain. + * 1.2.2 validate no duplicate use of lids and lids are 2^(lmc-1) + * + * 2. During SM port lid assignment: + * 2.1 if reassign_lids is set, make it 2^lmc + * 2.2 cleanup all port_lid_tbl and re-fill it according to guid2lid + * 2.3 call __osm_lid_mgr_get_port_lid the SM port + * 2.4 set the port info + * + * 3. During all other ports lid assignment: + * 3.1 go through all ports in the subnet + * 3.1.1 call __osm_lid_mgr_get_port_min_lid + * 3.1.2 if a change required send the port info + * 3.2 if any change send the signal PENDING... + * + * 4. Store the guid2lid + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + lid range item of qlist + **********************************************************************/ +typedef struct osm_lid_mgr_range { + cl_list_item_t item; + uint16_t min_lid; + uint16_t max_lid; +} osm_lid_mgr_range_t; + +/********************************************************************** + **********************************************************************/ +void osm_lid_mgr_construct(IN osm_lid_mgr_t * const p_mgr) +{ + memset(p_mgr, 0, sizeof(*p_mgr)); + cl_ptr_vector_construct(&p_mgr->used_lids); +} + +/********************************************************************** + **********************************************************************/ +void osm_lid_mgr_destroy(IN osm_lid_mgr_t * const p_mgr) +{ + cl_list_item_t *p_item; + + OSM_LOG_ENTER(p_mgr->p_log); + + cl_ptr_vector_destroy(&p_mgr->used_lids); + p_item = cl_qlist_remove_head(&p_mgr->free_ranges); + while (p_item != cl_qlist_end(&p_mgr->free_ranges)) { + free((osm_lid_mgr_range_t *) p_item); + p_item = cl_qlist_remove_head(&p_mgr->free_ranges); + } + OSM_LOG_EXIT(p_mgr->p_log); +} + +/********************************************************************** +Validate the guid to lid data by making sure that under the current +LMC we did not get duplicates. If we do flag them as errors and remove +the entry. +**********************************************************************/ +static void __osm_lid_mgr_validate_db(IN osm_lid_mgr_t * p_mgr) +{ + cl_qlist_t guids; + osm_db_guid_elem_t *p_item; + uint16_t lid; + uint16_t min_lid; + uint16_t max_lid; + uint16_t lmc_mask; + boolean_t lids_ok; + + OSM_LOG_ENTER(p_mgr->p_log); + + if (p_mgr->p_subn->opt.lmc) + lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1); + else + lmc_mask = 0xffff; + + cl_qlist_init(&guids); + + if (osm_db_guid2lid_guids(p_mgr->p_g2l, &guids)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0310: " + "could not get guid list\n"); + goto Exit; + } + + p_item = (osm_db_guid_elem_t *) cl_qlist_remove_head(&guids); + while ((cl_list_item_t *) p_item != cl_qlist_end(&guids)) { + if (osm_db_guid2lid_get + (p_mgr->p_g2l, p_item->guid, &min_lid, &max_lid)) + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0311: " + "could not get lid for guid:0x%016" PRIx64 "\n", + p_item->guid); + else { + lids_ok = TRUE; + + if ((min_lid > max_lid) || (min_lid == 0) + || (p_item->guid == 0) + || (max_lid > p_mgr->p_subn->max_ucast_lid_ho)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0312: " + "Illegal LID range [%u:%u] for " + "guid:0x%016" PRIx64 "\n", min_lid, + max_lid, p_item->guid); + lids_ok = FALSE; + } else if ((min_lid != max_lid) + && ((min_lid & lmc_mask) != min_lid)) { + /* check that if the lids define a range that is valid + for the current LMC mask */ + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0313: " + "LID range [%u:%u] for guid:0x%016" + PRIx64 + " is not aligned according to mask:0x%04x\n", + min_lid, max_lid, p_item->guid, + lmc_mask); + lids_ok = FALSE; + } else { + /* check if the lids were not previously assigned */ + for (lid = min_lid; lid <= max_lid; lid++) { + if ((cl_ptr_vector_get_size + (&p_mgr->used_lids) > lid) + && + (cl_ptr_vector_get + (&p_mgr->used_lids, lid))) { + OSM_LOG(p_mgr->p_log, + OSM_LOG_ERROR, "ERR 0314: " + "0x%04x for guid:0x%016" + PRIx64 + " was previously used\n", + lid, p_item->guid); + lids_ok = FALSE; + } + } + } + + if (!lids_ok) { + if (osm_db_guid2lid_delete + (p_mgr->p_g2l, p_item->guid)) + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, + "ERR 0315: " + "failed to delete entry for " + "guid:0x%016" PRIx64 "\n", + p_item->guid); + } else { + /* mark it was visited */ + for (lid = min_lid; lid <= max_lid; lid++) + cl_ptr_vector_set(&p_mgr->used_lids, + lid, (void *)1); + } + } /* got a lid */ + free(p_item); + p_item = (osm_db_guid_elem_t *) cl_qlist_remove_head(&guids); + } /* all guids */ +Exit: + OSM_LOG_EXIT(p_mgr->p_log); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_lid_mgr_init(IN osm_lid_mgr_t * const p_mgr, IN osm_sm_t *sm) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sm->p_log); + + osm_lid_mgr_construct(p_mgr); + + p_mgr->sm = sm; + p_mgr->p_log = sm->p_log; + p_mgr->p_subn = sm->p_subn; + p_mgr->p_db = sm->p_db; + p_mgr->p_lock = sm->p_lock; + + /* we initialize and restore the db domain of guid to lid map */ + p_mgr->p_g2l = osm_db_domain_init(p_mgr->p_db, "/guid2lid"); + if (!p_mgr->p_g2l) { + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0316: " + "Error initializing Guid-to-Lid persistent database\n"); + status = IB_ERROR; + goto Exit; + } + + cl_ptr_vector_init(&p_mgr->used_lids, 100, 40); + cl_qlist_init(&p_mgr->free_ranges); + + /* we use the stored guid to lid table if not forced to reassign */ + if (!p_mgr->p_subn->opt.reassign_lids) { + if (osm_db_restore(p_mgr->p_g2l)) { +#ifndef __WIN__ + /* + * When Windows is BSODing, it might corrupt files that + * were previously opened for writing, even if the files + * are closed, so we might see corrupted guid2lid file. + */ + if (p_mgr->p_subn->opt.exit_on_fatal) { + osm_log(p_mgr->p_log, OSM_LOG_SYS, + "FATAL: Error restoring Guid-to-Lid " + "persistent database\n"); + status = IB_ERROR; + goto Exit; + } else +#endif + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, + "ERR 0317: Error restoring Guid-to-Lid " + "persistent database\n"); + } + + /* we need to make sure we did not get duplicates with + current lmc */ + __osm_lid_mgr_validate_db(p_mgr); + } + +Exit: + OSM_LOG_EXIT(p_mgr->p_log); + return (status); +} + +static uint16_t __osm_trim_lid(IN uint16_t lid) +{ + if ((lid > IB_LID_UCAST_END_HO) || (lid < IB_LID_UCAST_START_HO)) + return 0; + return lid; +} + +/********************************************************************** + initialize the manager for a new sweep: + scans the known persistent assignment and port_lid_tbl + re-calculate all empty ranges. + cleanup invalid port_lid_tbl entries +**********************************************************************/ +static int __osm_lid_mgr_init_sweep(IN osm_lid_mgr_t * const p_mgr) +{ + cl_ptr_vector_t *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl; + cl_ptr_vector_t *p_persistent_vec = &p_mgr->used_lids; + uint16_t max_defined_lid; + uint16_t max_persistent_lid; + uint16_t max_discovered_lid; + uint16_t lid; + uint16_t disc_min_lid; + uint16_t disc_max_lid; + uint16_t db_min_lid; + uint16_t db_max_lid; + int status = 0; + cl_list_item_t *p_item; + boolean_t is_free; + osm_lid_mgr_range_t *p_range = NULL; + osm_port_t *p_port; + cl_qmap_t *p_port_guid_tbl; + uint8_t lmc_num_lids = (uint8_t) (1 << p_mgr->p_subn->opt.lmc); + uint16_t lmc_mask; + uint16_t req_lid, num_lids; + + OSM_LOG_ENTER(p_mgr->p_log); + + if (p_mgr->p_subn->opt.lmc) + lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1); + else + lmc_mask = 0xffff; + + /* if we came out of standby we need to discard any previous guid2lid + info we might have. + Do this only if the honor_guid2lid_file option is FALSE. If not, then + need to honor this file. */ + if (p_mgr->p_subn->coming_out_of_standby == TRUE) { + if (p_mgr->p_subn->opt.honor_guid2lid_file == FALSE) { + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Ignore guid2lid file when coming out of standby\n"); + osm_db_clear(p_mgr->p_g2l); + for (lid = 0; + lid < cl_ptr_vector_get_size(&p_mgr->used_lids); + lid++) + cl_ptr_vector_set(p_persistent_vec, lid, NULL); + } else { + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Honor current guid2lid file when coming out " + "of standby\n"); + osm_db_clear(p_mgr->p_g2l); + if (osm_db_restore(p_mgr->p_g2l)) + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0306: " + "Error restoring Guid-to-Lid " + "persistent database. Ignoring it\n"); + } + } + + /* we need to cleanup the empty ranges list */ + p_item = cl_qlist_remove_head(&p_mgr->free_ranges); + while (p_item != cl_qlist_end(&p_mgr->free_ranges)) { + free((osm_lid_mgr_range_t *) p_item); + p_item = cl_qlist_remove_head(&p_mgr->free_ranges); + } + + /* first clean up the port_by_lid_tbl */ + for (lid = 0; lid < cl_ptr_vector_get_size(p_discovered_vec); lid++) + cl_ptr_vector_set(p_discovered_vec, lid, NULL); + + /* we if are in the first sweep and in reassign lids mode + we should ignore all the available info and simply define one + huge empty range */ + if ((p_mgr->p_subn->first_time_master_sweep == TRUE) && + (p_mgr->p_subn->opt.reassign_lids == TRUE)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Skipping all lids as we are reassigning them\n"); + p_range = + (osm_lid_mgr_range_t *) malloc(sizeof(osm_lid_mgr_range_t)); + if (p_range) + p_range->min_lid = 1; + goto AfterScanningLids; + } + + /* go over all discovered ports and mark their entries */ + p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl; + + for (p_port = (osm_port_t *) cl_qmap_head(p_port_guid_tbl); + p_port != (osm_port_t *) cl_qmap_end(p_port_guid_tbl); + p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) { + osm_port_get_lid_range_ho(p_port, &disc_min_lid, &disc_max_lid); + disc_min_lid = __osm_trim_lid(disc_min_lid); + disc_max_lid = __osm_trim_lid(disc_max_lid); + for (lid = disc_min_lid; lid <= disc_max_lid; lid++) + cl_ptr_vector_set(p_discovered_vec, lid, p_port); + /* make sure the guid2lid entry is valid. If not, clean it. */ + if (!osm_db_guid2lid_get(p_mgr->p_g2l, + cl_ntoh64(osm_port_get_guid(p_port)), + &db_min_lid, &db_max_lid)) { + if (!p_port->p_node->sw || + osm_switch_sp0_is_lmc_capable(p_port->p_node->sw, + p_mgr->p_subn)) + num_lids = lmc_num_lids; + else + num_lids = 1; + + if ((num_lids != 1) && + (((db_min_lid & lmc_mask) != db_min_lid) || + (db_max_lid - db_min_lid + 1 < num_lids))) { + /* Not aligned, or not wide enough, then remove the entry */ + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Cleaning persistent entry for guid:" + "0x%016" PRIx64 " illegal range:" + "[0x%x:0x%x]\n", + cl_ntoh64(osm_port_get_guid(p_port)), + db_min_lid, db_max_lid); + osm_db_guid2lid_delete(p_mgr->p_g2l, + cl_ntoh64 + (osm_port_get_guid + (p_port))); + for (lid = db_min_lid; lid <= db_max_lid; lid++) + cl_ptr_vector_set(p_persistent_vec, lid, + NULL); + } + } + } + + /* + Our task is to find free lid ranges. + A lid can be used if + 1. a persistent assignment exists + 2. the lid is used by a discovered port that does not have a persistent + assignment. + + scan through all lid values of both the persistent table and + discovered table. + If the lid has an assigned port in the discovered table: + * make sure the lid matches the persistent table, or + * there is no other persistent assignment for that lid. + * else cleanup the port_by_lid_tbl, mark this as empty range. + Else if the lid does not have an entry in the persistent table + mark it as free. + */ + + /* find the range of lids to scan */ + max_discovered_lid = + (uint16_t) cl_ptr_vector_get_size(p_discovered_vec); + max_persistent_lid = + (uint16_t) cl_ptr_vector_get_size(p_persistent_vec); + + /* but the vectors have one extra entry for lid=0 */ + if (max_discovered_lid) + max_discovered_lid--; + if (max_persistent_lid) + max_persistent_lid--; + + if (max_persistent_lid > max_discovered_lid) + max_defined_lid = max_persistent_lid; + else + max_defined_lid = max_discovered_lid; + + for (lid = 1; lid <= max_defined_lid; lid++) { + is_free = TRUE; + /* first check to see if the lid is used by a persistent assignment */ + if ((lid <= max_persistent_lid) + && cl_ptr_vector_get(p_persistent_vec, lid)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "0x%04x is not free as its mapped by the " + "persistent db\n", lid); + is_free = FALSE; + } else { + /* check this is a discovered port */ + if (lid <= max_discovered_lid + && (p_port = (osm_port_t *) + cl_ptr_vector_get(p_discovered_vec, lid))) { + /* we have a port. Now lets see if we can preserve its lid range. */ + /* For that, we need to make sure: + 1. The port has a (legal) persistency entry. Then the local lid + is free (we will use the persistency value). + 2. Can the port keep its local assignment? + a. Make sure the lid a aligned. + b. Make sure all needed lids (for the lmc) are free according + to persistency table. + */ + /* qualify the guid of the port is not persistently mapped to + another range */ + if (!osm_db_guid2lid_get(p_mgr->p_g2l, + cl_ntoh64 + (osm_port_get_guid + (p_port)), + &db_min_lid, + &db_max_lid)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "0x%04x is free as it was " + "discovered but mapped by the " + "persistent db to [0x%04x:0x%04x]\n", + lid, db_min_lid, db_max_lid); + } else { + /* can the port keep its assignment ? */ + /* get the lid range of that port, and the required number + of lids we are about to assign to it */ + osm_port_get_lid_range_ho(p_port, + &disc_min_lid, + &disc_max_lid); + if (!p_port->p_node->sw + || + osm_switch_sp0_is_lmc_capable + (p_port->p_node->sw, + p_mgr->p_subn)) { + disc_max_lid = + disc_min_lid + + lmc_num_lids - 1; + num_lids = lmc_num_lids; + } else + num_lids = 1; + + /* Make sure the lid is aligned */ + if ((num_lids != 1) + && ((disc_min_lid & lmc_mask) != + disc_min_lid)) { + /* The lid cannot be used */ + OSM_LOG(p_mgr->p_log, + OSM_LOG_DEBUG, + "0x%04x is free as it was " + "discovered but not aligned\n", + lid); + } else { + /* check that all needed lids are not persistently mapped */ + is_free = FALSE; + for (req_lid = disc_min_lid + 1; + req_lid <= disc_max_lid; + req_lid++) { + if ((req_lid <= + max_persistent_lid) + && + cl_ptr_vector_get + (p_persistent_vec, + req_lid)) { + OSM_LOG(p_mgr-> + p_log, + OSM_LOG_DEBUG, + "0x%04x is free as it was discovered " + "but mapped\n", + lid); + is_free = TRUE; + break; + } + } + + if (is_free == FALSE) { + /* This port will use its local lid, and consume the entire required lid range. + Thus we can skip that range. */ + /* If the disc_max_lid is greater then lid, we can skip right to it, + since we've done all neccessary checks on the lids in between. */ + if (disc_max_lid > lid) + lid = + disc_max_lid; + } + } + } + } + } + + if (is_free) { + if (p_range) + p_range->max_lid = lid; + else { + p_range = (osm_lid_mgr_range_t *) + malloc(sizeof(osm_lid_mgr_range_t)); + if (p_range) { + p_range->min_lid = lid; + p_range->max_lid = lid; + } + } + } else { + /* this lid is used so we need to finalize the previous free range */ + if (p_range) { + cl_qlist_insert_tail(&p_mgr->free_ranges, + &p_range->item); + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "new free lid range [%u:%u]\n", + p_range->min_lid, p_range->max_lid); + p_range = NULL; + } + } + } + +AfterScanningLids: + /* after scanning all known lids we need to extend the last range + to the max allowed lid */ + if (!p_range) { + p_range = + (osm_lid_mgr_range_t *) malloc(sizeof(osm_lid_mgr_range_t)); + /* + The p_range can be NULL in one of 2 cases: + 1. If max_defined_lid == 0. In this case, we want the + entire range. + 2. If all lids discovered in the loop where mapped. In this + case, no free range exists and we want to define it after the + last mapped lid. + */ + if (p_range) + p_range->min_lid = lid; + } + if (p_range) { + p_range->max_lid = p_mgr->p_subn->max_ucast_lid_ho; + cl_qlist_insert_tail(&p_mgr->free_ranges, &p_range->item); + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "final free lid range [%u:%u]\n", + p_range->min_lid, p_range->max_lid); + } + + OSM_LOG_EXIT(p_mgr->p_log); + return status; +} + +/********************************************************************** + check if the given range of lids is free +**********************************************************************/ +static boolean_t +__osm_lid_mgr_is_range_not_persistent(IN osm_lid_mgr_t * const p_mgr, + IN const uint16_t lid, + IN const uint16_t num_lids) +{ + uint16_t i; + cl_status_t status; + osm_port_t *p_port; + const uint8_t start_lid = (uint8_t) (1 << p_mgr->p_subn->opt.lmc); + const cl_ptr_vector_t *const p_tbl = &p_mgr->used_lids; + + if (lid < start_lid) + return (FALSE); + + for (i = lid; i < lid + num_lids; i++) { + status = cl_ptr_vector_at(p_tbl, i, (void *)&p_port); + if (status == CL_SUCCESS) { + if (p_port != NULL) + return (FALSE); + } else + /* + We are out of range in the array. + Consider all further entries "free". + */ + return (TRUE); + } + + return (TRUE); +} + +/********************************************************************** +find a free lid range +**********************************************************************/ +static void +__osm_lid_mgr_find_free_lid_range(IN osm_lid_mgr_t * const p_mgr, + IN const uint8_t num_lids, + OUT uint16_t * const p_min_lid, + OUT uint16_t * const p_max_lid) +{ + uint16_t lid; + cl_list_item_t *p_item; + cl_list_item_t *p_next_item; + osm_lid_mgr_range_t *p_range = NULL; + uint8_t lmc_num_lids; + uint16_t lmc_mask; + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "LMC = %u, number LIDs = %u\n", + p_mgr->p_subn->opt.lmc, num_lids); + + lmc_num_lids = (1 << p_mgr->p_subn->opt.lmc); + if (p_mgr->p_subn->opt.lmc) + lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1); + else + lmc_mask = 0xffff; + + /* + Search the list of free lid ranges for a range which is big enough + */ + p_item = cl_qlist_head(&p_mgr->free_ranges); + while (p_item != cl_qlist_end(&p_mgr->free_ranges)) { + p_next_item = cl_qlist_next(p_item); + p_range = (osm_lid_mgr_range_t *) p_item; + + lid = p_range->min_lid; + + /* if we require more then one lid we must align to LMC */ + if (num_lids > 1) { + if ((lid & lmc_mask) != lid) + lid = (lid + lmc_num_lids) & lmc_mask; + } + + /* but we can be out of the range */ + if (lid + num_lids - 1 <= p_range->max_lid) { + /* ok let us use that range */ + if (lid + num_lids - 1 == p_range->max_lid) + /* we consumed the entire range */ + cl_qlist_remove_item(&p_mgr->free_ranges, + p_item); + else + /* only update the available range */ + p_range->min_lid = lid + num_lids; + + *p_min_lid = lid; + *p_max_lid = (uint16_t) (lid + num_lids - 1); + return; + } + p_item = p_next_item; + } + + /* + Couldn't find a free range of lids. + */ + *p_min_lid = *p_max_lid = 0; + /* if we run out of lids, give an error and abort! */ + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0307: " + "OPENSM RAN OUT OF LIDS!!!\n"); + CL_ASSERT(0); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_lid_mgr_cleanup_discovered_port_lid_range(IN osm_lid_mgr_t * p_mgr, + IN osm_port_t * p_port) +{ + cl_ptr_vector_t *p_discovered_vec = &p_mgr->p_subn->port_lid_tbl; + uint16_t lid, min_lid, max_lid; + uint16_t max_tbl_lid = + (uint16_t) (cl_ptr_vector_get_size(p_discovered_vec)); + + osm_port_get_lid_range_ho(p_port, &min_lid, &max_lid); + min_lid = __osm_trim_lid(min_lid); + max_lid = __osm_trim_lid(max_lid); + for (lid = min_lid; lid <= max_lid; lid++) { + if ((lid < max_tbl_lid) && + (p_port == + (osm_port_t *) cl_ptr_vector_get(p_discovered_vec, lid))) + cl_ptr_vector_set(p_discovered_vec, lid, NULL); + } +} + +/********************************************************************** + 0.1 if the port info lid matches the guid2lid return 0 + 0.2 if the port info has a lid and that range is empty in + port_lid_tbl, return 0 and update the port_lid_tbl and + guid2lid + 0.3 else find an empty space in port_lid_tbl, update the + port_lid_tbl and guid2lid, return 1 to flag a change required. +**********************************************************************/ +static int +__osm_lid_mgr_get_port_lid(IN osm_lid_mgr_t * const p_mgr, + IN osm_port_t * const p_port, + OUT uint16_t * const p_min_lid, + OUT uint16_t * const p_max_lid) +{ + uint16_t lid, min_lid, max_lid; + uint64_t guid; + uint8_t num_lids = (1 << p_mgr->p_subn->opt.lmc); + int lid_changed = 0; + uint16_t lmc_mask; + + OSM_LOG_ENTER(p_mgr->p_log); + + if (p_mgr->p_subn->opt.lmc) + lmc_mask = ~((1 << p_mgr->p_subn->opt.lmc) - 1); + else + lmc_mask = 0xffff; + + /* get the lid from the guid2lid */ + guid = cl_ntoh64(osm_port_get_guid(p_port)); + + /* if the port is a base switch port 0 then we only need one lid */ + if (p_port->p_node->sw && + !osm_switch_sp0_is_lmc_capable(p_port->p_node->sw, p_mgr->p_subn)) + num_lids = 1; + + /* if the port matches the guid2lid */ + if (!osm_db_guid2lid_get(p_mgr->p_g2l, guid, &min_lid, &max_lid)) { + *p_min_lid = min_lid; + *p_max_lid = min_lid + num_lids - 1; + if (min_lid == cl_ntoh16(osm_port_get_base_lid(p_port))) { + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "0x%016" PRIx64 + " matches its known lid:%u\n", guid, min_lid); + goto Exit; + } else { + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "0x%016" PRIx64 " with lid:%u " + "does not match its known lid:%u\n", + guid, cl_ntoh16(osm_port_get_base_lid(p_port)), + min_lid); + __osm_lid_mgr_cleanup_discovered_port_lid_range(p_mgr, + p_port); + /* we still need to send the setting to the target port */ + lid_changed = 1; + goto Exit; + } + } else + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "0x%016" PRIx64 " has no persistent lid assigned\n", + guid); + + /* if the port info carries a lid it must be lmc aligned and not mapped + by the pesistent storage */ + min_lid = cl_ntoh16(osm_port_get_base_lid(p_port)); + + /* we want to ignore the discovered lid if we are also on first sweep of + reassign lids flow */ + if (min_lid && + !((p_mgr->p_subn->first_time_master_sweep == TRUE) && + (p_mgr->p_subn->opt.reassign_lids == TRUE))) { + /* make sure lid is valid */ + if ((num_lids == 1) || ((min_lid & lmc_mask) == min_lid)) { + /* is it free */ + if (__osm_lid_mgr_is_range_not_persistent + (p_mgr, min_lid, num_lids)) { + *p_min_lid = min_lid; + *p_max_lid = min_lid + num_lids - 1; + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "0x%016" PRIx64 + " lid range:[%u-%u] is free\n", + guid, *p_min_lid, *p_max_lid); + goto NewLidSet; + } else + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "0x%016" PRIx64 " existing lid " + "range:[%u:%u] is not free\n", + guid, min_lid, min_lid + num_lids - 1); + } else + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "0x%016" PRIx64 " existing lid range:" + "[%u:%u] is not lmc aligned\n", + guid, min_lid, min_lid + num_lids - 1); + } + + /* first cleanup the existing discovered lid range */ + __osm_lid_mgr_cleanup_discovered_port_lid_range(p_mgr, p_port); + + /* find an empty space */ + __osm_lid_mgr_find_free_lid_range(p_mgr, num_lids, p_min_lid, + p_max_lid); + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "0x%016" PRIx64 " assigned a new lid range:[%u-%u]\n", + guid, *p_min_lid, *p_max_lid); + lid_changed = 1; + +NewLidSet: + /* update the guid2lid db and used_lids */ + osm_db_guid2lid_set(p_mgr->p_g2l, guid, *p_min_lid, *p_max_lid); + for (lid = *p_min_lid; lid <= *p_max_lid; lid++) + cl_ptr_vector_set(&p_mgr->used_lids, lid, (void *)1); + +Exit: + /* make sure the assigned lids are marked in port_lid_tbl */ + for (lid = *p_min_lid; lid <= *p_max_lid; lid++) + cl_ptr_vector_set(&p_mgr->p_subn->port_lid_tbl, lid, p_port); + + OSM_LOG_EXIT(p_mgr->p_log); + return lid_changed; +} + +/********************************************************************** + Set to INIT the remote port of the given physical port + **********************************************************************/ +static void +__osm_lid_mgr_set_remote_pi_state_to_init(IN osm_lid_mgr_t * const p_mgr, + IN osm_physp_t * const p_physp) +{ + osm_physp_t *p_rem_physp = osm_physp_get_remote(p_physp); + + if (p_rem_physp == NULL) + return; + + /* but in some rare cases the remote side might be non responsive */ + ib_port_info_set_port_state(&p_rem_physp->port_info, IB_LINK_INIT); +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +__osm_lid_mgr_set_physp_pi(IN osm_lid_mgr_t * const p_mgr, + IN osm_port_t * const p_port, + IN osm_physp_t * const p_physp, + IN ib_net16_t const lid) +{ + uint8_t payload[IB_SMP_DATA_SIZE]; + ib_port_info_t *p_pi = (ib_port_info_t *) payload; + const ib_port_info_t *p_old_pi; + osm_madw_context_t context; + osm_node_t *p_node; + ib_api_status_t status; + uint8_t mtu; + uint8_t op_vls; + uint8_t port_num; + boolean_t send_set = FALSE; + + OSM_LOG_ENTER(p_mgr->p_log); + + /* + Don't bother doing anything if this Physical Port is not valid. + This allows simplified code in the caller. + */ + if (!p_physp) + goto Exit; + + port_num = osm_physp_get_port_num(p_physp); + p_node = osm_physp_get_node_ptr(p_physp); + + if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH && port_num != 0) { + /* + Switch ports that are not numbered 0 should not be set + with the following attributes as they are set later + (during NO_CHANGE state in link mgr). + */ + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Skipping switch port %u, GUID 0x%016" PRIx64 "\n", + port_num, cl_ntoh64(osm_physp_get_port_guid(p_physp))); + goto Exit; + } + + p_old_pi = &p_physp->port_info; + + /* + First, copy existing parameters from the PortInfo attribute we + already have for this node. + + Second, update with default values that we know must be set for + every Physical Port and the LID and set the neighbor MTU field + appropriately. + + Third, send the SMP to this physical port. + */ + + memset(payload, 0, IB_SMP_DATA_SIZE); + memcpy(payload, p_old_pi, sizeof(ib_port_info_t)); + + /* + Should never write back a value that is bigger then 3 in + the PortPhysicalState field, so cannot simply copy! + + Actually we want to write there: + port physical state - no change + link down default state = polling + port state - no change + */ + p_pi->state_info2 = 0x02; + ib_port_info_set_port_state(p_pi, IB_LINK_NO_CHANGE); + + if (ib_port_info_get_link_down_def_state(p_pi) != + ib_port_info_get_link_down_def_state(p_old_pi)) + send_set = TRUE; + + /* didn't get PortInfo before */ + if (!ib_port_info_get_port_state(p_old_pi)) + send_set = TRUE; + + p_pi->m_key = p_mgr->p_subn->opt.m_key; + if (memcmp(&p_pi->m_key, &p_old_pi->m_key, sizeof(p_pi->m_key))) + send_set = TRUE; + + p_pi->subnet_prefix = p_mgr->p_subn->opt.subnet_prefix; + if (memcmp(&p_pi->subnet_prefix, &p_old_pi->subnet_prefix, + sizeof(p_pi->subnet_prefix))) + send_set = TRUE; + + p_pi->base_lid = lid; + if (memcmp(&p_pi->base_lid, &p_old_pi->base_lid, + sizeof(p_pi->base_lid))) + send_set = TRUE; + + /* we are updating the ports with our local sm_base_lid */ + p_pi->master_sm_base_lid = p_mgr->p_subn->sm_base_lid; + if (memcmp(&p_pi->master_sm_base_lid, &p_old_pi->master_sm_base_lid, + sizeof(p_pi->master_sm_base_lid))) + send_set = TRUE; + + p_pi->m_key_lease_period = p_mgr->p_subn->opt.m_key_lease_period; + if (memcmp(&p_pi->m_key_lease_period, &p_old_pi->m_key_lease_period, + sizeof(p_pi->m_key_lease_period))) + send_set = TRUE; + + /* + we want to set the timeout for both the switch port 0 + and the CA ports + */ + ib_port_info_set_timeout(p_pi, p_mgr->p_subn->opt.subnet_timeout); + if (ib_port_info_get_timeout(p_pi) != + ib_port_info_get_timeout(p_old_pi)) + send_set = TRUE; + + if (port_num != 0) { + /* + CAs don't have a port 0, and for switch port 0, + the state bits are ignored. + This is not the switch management port + */ + p_pi->link_width_enabled = p_old_pi->link_width_supported; + if (memcmp(&p_pi->link_width_enabled, + &p_old_pi->link_width_enabled, + sizeof(p_pi->link_width_enabled))) + send_set = TRUE; + + /* M_KeyProtectBits are always zero */ + p_pi->mkey_lmc = p_mgr->p_subn->opt.lmc; + if (memcmp(&p_pi->mkey_lmc, &p_old_pi->mkey_lmc, + sizeof(p_pi->mkey_lmc))) + send_set = TRUE; + + /* calc new op_vls and mtu */ + op_vls = + osm_physp_calc_link_op_vls(p_mgr->p_log, p_mgr->p_subn, + p_physp); + mtu = osm_physp_calc_link_mtu(p_mgr->p_log, p_physp); + + ib_port_info_set_neighbor_mtu(p_pi, mtu); + + if (ib_port_info_get_neighbor_mtu(p_pi) != + ib_port_info_get_neighbor_mtu(p_old_pi)) + send_set = TRUE; + + ib_port_info_set_op_vls(p_pi, op_vls); + if (ib_port_info_get_op_vls(p_pi) != + ib_port_info_get_op_vls(p_old_pi)) + send_set = TRUE; + + /* + Several timeout mechanisms: + */ + ib_port_info_set_phy_and_overrun_err_thd(p_pi, + p_mgr->p_subn->opt. + local_phy_errors_threshold, + p_mgr->p_subn->opt. + overrun_errors_threshold); + + if (memcmp(&p_pi->error_threshold, &p_old_pi->error_threshold, + sizeof(p_pi->error_threshold))) + send_set = TRUE; + + /* + To reset the port state machine we can send + PortInfo.State = DOWN. (see: 7.2.7 p171 lines:10-19) + */ + if ((mtu != ib_port_info_get_neighbor_mtu(p_old_pi)) || + (op_vls != ib_port_info_get_op_vls(p_old_pi))) { + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Sending Link Down to GUID 0x%016" + PRIx64 " port %d due to op_vls or " + "mtu change. MTU:%u,%u VL_CAP:%u,%u\n", + cl_ntoh64(osm_physp_get_port_guid(p_physp)), + port_num, mtu, + ib_port_info_get_neighbor_mtu(p_old_pi), + op_vls, ib_port_info_get_op_vls(p_old_pi)); + + /* + we need to make sure the internal DB will follow the + fact that the remote port is also going through + "down" state into "init"... + */ + __osm_lid_mgr_set_remote_pi_state_to_init(p_mgr, + p_physp); + + ib_port_info_set_port_state(p_pi, IB_LINK_DOWN); + if (ib_port_info_get_port_state(p_pi) != + ib_port_info_get_port_state(p_old_pi)) + send_set = TRUE; + } + } else { + /* + For Port 0, NeighborMTU is relevant only for Enh. SP0. + In this case, we'll set the MTU according to the mtu_cap + */ + ib_port_info_set_neighbor_mtu(p_pi, + ib_port_info_get_mtu_cap + (p_old_pi)); + if (ib_port_info_get_neighbor_mtu(p_pi) != + ib_port_info_get_neighbor_mtu(p_old_pi)) + send_set = TRUE; + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Updating neighbor_mtu on switch GUID 0x%016" PRIx64 + " port 0 to:%u\n", + cl_ntoh64(osm_physp_get_port_guid(p_physp)), + ib_port_info_get_neighbor_mtu(p_pi)); + + /* Determine if enhanced switch port 0 and if so set LMC */ + if (osm_switch_sp0_is_lmc_capable(p_node->sw, p_mgr->p_subn)) { + /* M_KeyProtectBits are always zero */ + p_pi->mkey_lmc = p_mgr->p_subn->opt.lmc; + if (memcmp(&p_pi->mkey_lmc, &p_old_pi->mkey_lmc, + sizeof(p_pi->mkey_lmc))) + send_set = TRUE; + } + } + + context.pi_context.node_guid = osm_node_get_node_guid(p_node); + context.pi_context.port_guid = osm_physp_get_port_guid(p_physp); + context.pi_context.set_method = TRUE; + context.pi_context.light_sweep = FALSE; + context.pi_context.active_transition = FALSE; + + /* + We need to set the cli_rereg bit when we are in first_time_master_sweep + for ports supporting the ClientReregistration Vol1 (v1.2) p811 14.4.11 + Also, if this port was just now discovered, then we should also set + the cli_rereg bit. We know that the port was just discovered if its + is_new field is set. + */ + if ((p_mgr->p_subn->first_time_master_sweep == TRUE || p_port->is_new) + && !p_mgr->p_subn->opt.no_clients_rereg + && (p_old_pi->capability_mask & IB_PORT_CAP_HAS_CLIENT_REREG)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Seting client rereg on %s, port %d\n", + p_port->p_node->print_desc, p_port->p_physp->port_num); + ib_port_info_set_client_rereg(p_pi, 1); + send_set = TRUE; + } else + ib_port_info_set_client_rereg(p_pi, 0); + + /* We need to send the PortInfo Set request with the new sm_lid + in the following cases: + 1. There is a change in the values (send_set == TRUE) + 2. first_time_master_sweep flag on the subnet is TRUE. This means the + SM just became master, and it then needs to send a PortInfo Set to + every port. + */ + if (p_mgr->p_subn->first_time_master_sweep == TRUE) + send_set = TRUE; + + if (send_set) { + p_mgr->send_set_reqs = TRUE; + status = osm_req_set(p_mgr->sm, + osm_physp_get_dr_path_ptr(p_physp), + payload, + sizeof(payload), + IB_MAD_ATTR_PORT_INFO, + cl_hton32(osm_physp_get_port_num(p_physp)), + CL_DISP_MSGID_NONE, &context); + } + +Exit: + OSM_LOG_EXIT(p_mgr->p_log); + return send_set; +} + +/********************************************************************** + Processes our own node + Lock must already be held. +**********************************************************************/ +static boolean_t +__osm_lid_mgr_process_our_sm_node(IN osm_lid_mgr_t * const p_mgr) +{ + osm_port_t *p_port; + uint16_t min_lid_ho; + uint16_t max_lid_ho; + boolean_t res = TRUE; + + OSM_LOG_ENTER(p_mgr->p_log); + + /* + Acquire our own port object. + */ + p_port = + osm_get_port_by_guid(p_mgr->p_subn, p_mgr->p_subn->sm_port_guid); + if (!p_port) { + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 0308: " + "Can't acquire SM's port object, GUID 0x%016" PRIx64 + "\n", cl_ntoh64(p_mgr->p_subn->sm_port_guid)); + res = FALSE; + goto Exit; + } + + /* + Determine the LID this SM will use for its own port. + Be careful. With an LMC > 0, the bottom of the LID range becomes + unusable, since port hardware will mask off least significant bits, + leaving a LID of 0 (invalid). Therefore, make sure that we always + configure the SM with a LID that has non-zero bits, even after + LMC masking by hardware. + */ + __osm_lid_mgr_get_port_lid(p_mgr, p_port, &min_lid_ho, &max_lid_ho); + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Current base LID is %u\n", min_lid_ho); + /* + Update subnet object. + */ + p_mgr->p_subn->master_sm_base_lid = cl_hton16(min_lid_ho); + p_mgr->p_subn->sm_base_lid = cl_hton16(min_lid_ho); + + OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE, + "Assigning SM's port 0x%016" PRIx64 + "\n\t\t\t\tto LID range [%u,%u]\n", + cl_ntoh64(osm_port_get_guid(p_port)), min_lid_ho, max_lid_ho); + + /* + Set the PortInfo the Physical Port associated with this Port. + */ + __osm_lid_mgr_set_physp_pi(p_mgr, p_port, p_port->p_physp, + cl_hton16(min_lid_ho)); + +Exit: + OSM_LOG_EXIT(p_mgr->p_log); + return res; +} + +/********************************************************************** + **********************************************************************/ +osm_signal_t osm_lid_mgr_process_sm(IN osm_lid_mgr_t * const p_mgr) +{ + osm_signal_t signal = OSM_SIGNAL_DONE_PENDING; + + OSM_LOG_ENTER(p_mgr->p_log); + + CL_ASSERT(p_mgr->p_subn->sm_port_guid); + + CL_PLOCK_EXCL_ACQUIRE(p_mgr->p_lock); + + /* initialize the port_lid_tbl and empty ranges list following the + persistent db */ + __osm_lid_mgr_init_sweep(p_mgr); + + /* Set the send_set_reqs of the p_mgr to FALSE, and + we'll see if any set requests were sent. If not - + can signal OSM_SIGNAL_DONE */ + p_mgr->send_set_reqs = FALSE; + if (__osm_lid_mgr_process_our_sm_node(p_mgr) == FALSE) + /* The initialization failed */ + signal = OSM_SIGNAL_DONE; + + if (p_mgr->send_set_reqs == FALSE) + signal = OSM_SIGNAL_DONE; + + CL_PLOCK_RELEASE(p_mgr->p_lock); + + OSM_LOG_EXIT(p_mgr->p_log); + return (signal); +} + +/********************************************************************** + 1 go through all ports in the subnet. + 1.1 call __osm_lid_mgr_get_port_min_lid + 1.2 if a change is required send the port info + 2 if any change send the signal PENDING... +**********************************************************************/ +osm_signal_t osm_lid_mgr_process_subnet(IN osm_lid_mgr_t * const p_mgr) +{ + osm_signal_t signal; + cl_qmap_t *p_port_guid_tbl; + osm_port_t *p_port; + ib_net64_t port_guid; + uint16_t min_lid_ho, max_lid_ho; + int lid_changed; + + CL_ASSERT(p_mgr); + + OSM_LOG_ENTER(p_mgr->p_log); + + CL_PLOCK_EXCL_ACQUIRE(p_mgr->p_lock); + + CL_ASSERT(p_mgr->p_subn->sm_port_guid); + + /* Set the send_set_reqs of the p_mgr to FALSE, and + we'll see if any set requests were sent. If not - + can signal OSM_SIGNAL_DONE */ + p_mgr->send_set_reqs = FALSE; + + p_port_guid_tbl = &p_mgr->p_subn->port_guid_tbl; + + for (p_port = (osm_port_t *) cl_qmap_head(p_port_guid_tbl); + p_port != (osm_port_t *) cl_qmap_end(p_port_guid_tbl); + p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item)) { + port_guid = osm_port_get_guid(p_port); + + /* + Our own port is a special case in that we want to + assign a LID to ourselves first, since we have to + advertise that LID value to the other ports. + + For that reason, our node is treated separately and + we will not add it to any of these lists. + */ + if (port_guid == p_mgr->p_subn->sm_port_guid) { + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Skipping our own port 0x%016" PRIx64 "\n", + cl_ntoh64(port_guid)); + continue; + } + + /* + get the port lid range - we need to send it on first active + sweep or if there was a change (the result of + __osm_lid_mgr_get_port_lid) + */ + lid_changed = + __osm_lid_mgr_get_port_lid(p_mgr, p_port, &min_lid_ho, + &max_lid_ho); + + /* we can call the function to update the port info as it known + to look for any field change and will only send an updated + if required */ + OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE, + "Assigned port 0x%016" PRIx64 + ", LID [%u,%u]\n", cl_ntoh64(port_guid), + min_lid_ho, max_lid_ho); + + /* the proc returns the fact it sent a set port info */ + if (__osm_lid_mgr_set_physp_pi + (p_mgr, p_port, p_port->p_physp, cl_hton16(min_lid_ho))) + p_mgr->send_set_reqs = TRUE; + } /* all ports */ + + /* store the guid to lid table in persistent db */ + osm_db_store(p_mgr->p_g2l); + + if (p_mgr->send_set_reqs == FALSE) + signal = OSM_SIGNAL_DONE; + else + signal = OSM_SIGNAL_DONE_PENDING; + + CL_PLOCK_RELEASE(p_mgr->p_lock); + + OSM_LOG_EXIT(p_mgr->p_log); + return (signal); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_lin_fwd_rcv.c b/contrib/ofed/management/opensm/opensm/osm_lin_fwd_rcv.c new file mode 100644 index 000000000000..c3d863305051 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_lin_fwd_rcv.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_lft_rcv_t. + * This object represents the NodeDescription Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void osm_lft_rcv_process(IN void *context, IN void *data) +{ + osm_sm_t *sm = context; + osm_madw_t *p_madw = data; + ib_smp_t *p_smp; + uint32_t block_num; + osm_switch_t *p_sw; + osm_lft_context_t *p_lft_context; + uint8_t *p_block; + ib_net64_t node_guid; + ib_api_status_t status; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_block = (uint8_t *) ib_smp_get_payload_ptr(p_smp); + block_num = cl_ntoh32(p_smp->attr_mod); + + /* + Acquire the switch object for this switch. + */ + p_lft_context = osm_madw_get_lft_context_ptr(p_madw); + node_guid = p_lft_context->node_guid; + + CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); + p_sw = osm_get_switch_by_guid(sm->p_subn, node_guid); + + if (!p_sw) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0401: " + "LFT received for nonexistent node " + "0x%" PRIx64 "\n", cl_ntoh64(node_guid)); + } else { + status = osm_switch_set_lft_block(p_sw, p_block, block_num); + if (status != IB_SUCCESS) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0402: " + "Setting forwarding table block failed (%s)" + "\n\t\t\t\tSwitch 0x%" PRIx64 "\n", + ib_get_err_str(status), cl_ntoh64(node_guid)); + } + } + + CL_PLOCK_RELEASE(sm->p_lock); + OSM_LOG_EXIT(sm->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_link_mgr.c b/contrib/ofed/management/opensm/opensm/osm_link_mgr.c new file mode 100644 index 000000000000..37e3e1b8483b --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_link_mgr.c @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_link_mgr_t. + * This file implements the Link Manager object. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +static boolean_t +__osm_link_mgr_set_physp_pi(osm_sm_t * sm, + IN osm_physp_t * const p_physp, + IN uint8_t const port_state) +{ + uint8_t payload[IB_SMP_DATA_SIZE]; + ib_port_info_t *const p_pi = (ib_port_info_t *) payload; + const ib_port_info_t *p_old_pi; + osm_madw_context_t context; + osm_node_t *p_node; + ib_api_status_t status; + uint8_t port_num; + uint8_t mtu; + uint8_t op_vls; + boolean_t esp0 = FALSE; + boolean_t send_set = FALSE; + osm_physp_t *p_remote_physp; + + OSM_LOG_ENTER(sm->p_log); + + p_node = osm_physp_get_node_ptr(p_physp); + + port_num = osm_physp_get_port_num(p_physp); + + if (port_num == 0) { + /* + CAs don't have a port 0, and for switch port 0, + we need to check if this is enhanced or base port 0. + For base port 0 the following parameters are not valid (p822, table 145). + */ + if (!p_node->sw) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 4201: " + "Cannot find switch by guid: 0x%" PRIx64 "\n", + cl_ntoh64(p_node->node_info.node_guid)); + goto Exit; + } + + if (ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info) + == FALSE) { + /* This means the switch doesn't support enhanced port 0. + Can skip it. */ + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Skipping port 0, GUID 0x%016" PRIx64 "\n", + cl_ntoh64(osm_physp_get_port_guid(p_physp))); + goto Exit; + } + esp0 = TRUE; + } + + /* + PAST THIS POINT WE ARE HANDLING EITHER A NON PORT 0 OR ENHANCED PORT 0 + */ + + p_old_pi = &p_physp->port_info; + + memset(payload, 0, IB_SMP_DATA_SIZE); + memcpy(payload, p_old_pi, sizeof(ib_port_info_t)); + + /* + Should never write back a value that is bigger then 3 in + the PortPhysicalState field - so can not simply copy! + + Actually we want to write there: + port physical state - no change, + link down default state = polling + port state - as requested. + */ + p_pi->state_info2 = 0x02; + ib_port_info_set_port_state(p_pi, port_state); + + if (ib_port_info_get_link_down_def_state(p_pi) != + ib_port_info_get_link_down_def_state(p_old_pi)) + send_set = TRUE; + + /* didn't get PortInfo before */ + if (!ib_port_info_get_port_state(p_old_pi)) + send_set = TRUE; + + /* we only change port fields if we do not change state */ + if (port_state == IB_LINK_NO_CHANGE) { + /* The following fields are relevant only for CA port, router, or Enh. SP0 */ + if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH || + port_num == 0) { + p_pi->m_key = sm->p_subn->opt.m_key; + if (memcmp(&p_pi->m_key, &p_old_pi->m_key, + sizeof(p_pi->m_key))) + send_set = TRUE; + + p_pi->subnet_prefix = sm->p_subn->opt.subnet_prefix; + if (memcmp(&p_pi->subnet_prefix, + &p_old_pi->subnet_prefix, + sizeof(p_pi->subnet_prefix))) + send_set = TRUE; + + p_pi->base_lid = osm_physp_get_base_lid(p_physp); + if (memcmp(&p_pi->base_lid, &p_old_pi->base_lid, + sizeof(p_pi->base_lid))) + send_set = TRUE; + + /* we are initializing the ports with our local sm_base_lid */ + p_pi->master_sm_base_lid = sm->p_subn->sm_base_lid; + if (memcmp(&p_pi->master_sm_base_lid, + &p_old_pi->master_sm_base_lid, + sizeof(p_pi->master_sm_base_lid))) + send_set = TRUE; + + p_pi->m_key_lease_period = + sm->p_subn->opt.m_key_lease_period; + if (memcmp(&p_pi->m_key_lease_period, + &p_old_pi->m_key_lease_period, + sizeof(p_pi->m_key_lease_period))) + send_set = TRUE; + + if (esp0 == FALSE) + p_pi->mkey_lmc = sm->p_subn->opt.lmc; + else { + if (sm->p_subn->opt.lmc_esp0) + p_pi->mkey_lmc = sm->p_subn->opt.lmc; + else + p_pi->mkey_lmc = 0; + } + if (memcmp(&p_pi->mkey_lmc, &p_old_pi->mkey_lmc, + sizeof(p_pi->mkey_lmc))) + send_set = TRUE; + + ib_port_info_set_timeout(p_pi, + sm->p_subn->opt. + subnet_timeout); + if (ib_port_info_get_timeout(p_pi) != + ib_port_info_get_timeout(p_old_pi)) + send_set = TRUE; + } + + /* + Several timeout mechanisms: + */ + p_remote_physp = osm_physp_get_remote(p_physp); + if (port_num != 0 && p_remote_physp) { + if (osm_node_get_type(osm_physp_get_node_ptr(p_physp)) + == IB_NODE_TYPE_ROUTER) { + ib_port_info_set_hoq_lifetime(p_pi, + sm->p_subn-> + opt. + leaf_head_of_queue_lifetime); + } else + if (osm_node_get_type + (osm_physp_get_node_ptr(p_physp)) == + IB_NODE_TYPE_SWITCH) { + /* Is remote end CA or router (a leaf port) ? */ + if (osm_node_get_type + (osm_physp_get_node_ptr(p_remote_physp)) != + IB_NODE_TYPE_SWITCH) { + ib_port_info_set_hoq_lifetime(p_pi, + sm-> + p_subn-> + opt. + leaf_head_of_queue_lifetime); + ib_port_info_set_vl_stall_count(p_pi, + sm-> + p_subn-> + opt. + leaf_vl_stall_count); + } else { + ib_port_info_set_hoq_lifetime(p_pi, + sm-> + p_subn-> + opt. + head_of_queue_lifetime); + ib_port_info_set_vl_stall_count(p_pi, + sm-> + p_subn-> + opt. + vl_stall_count); + } + } + if (ib_port_info_get_hoq_lifetime(p_pi) != + ib_port_info_get_hoq_lifetime(p_old_pi) || + ib_port_info_get_vl_stall_count(p_pi) != + ib_port_info_get_vl_stall_count(p_old_pi)) + send_set = TRUE; + } + + ib_port_info_set_phy_and_overrun_err_thd(p_pi, + sm->p_subn->opt. + local_phy_errors_threshold, + sm->p_subn->opt. + overrun_errors_threshold); + if (memcmp(&p_pi->error_threshold, &p_old_pi->error_threshold, + sizeof(p_pi->error_threshold))) + send_set = TRUE; + + /* + Set the easy common parameters for all port types, + then determine the neighbor MTU. + */ + p_pi->link_width_enabled = p_old_pi->link_width_supported; + if (memcmp(&p_pi->link_width_enabled, + &p_old_pi->link_width_enabled, + sizeof(p_pi->link_width_enabled))) + send_set = TRUE; + + if (sm->p_subn->opt.force_link_speed && + (sm->p_subn->opt.force_link_speed != 15 || + ib_port_info_get_link_speed_enabled(p_pi) != + ib_port_info_get_link_speed_sup(p_pi))) { + ib_port_info_set_link_speed_enabled(p_pi, + sm->p_subn->opt. + force_link_speed); + if (memcmp(&p_pi->link_speed, &p_old_pi->link_speed, + sizeof(p_pi->link_speed))) + send_set = TRUE; + } + + /* calc new op_vls and mtu */ + op_vls = + osm_physp_calc_link_op_vls(sm->p_log, sm->p_subn, p_physp); + mtu = osm_physp_calc_link_mtu(sm->p_log, p_physp); + + ib_port_info_set_neighbor_mtu(p_pi, mtu); + if (ib_port_info_get_neighbor_mtu(p_pi) != + ib_port_info_get_neighbor_mtu(p_old_pi)) + send_set = TRUE; + + ib_port_info_set_op_vls(p_pi, op_vls); + if (ib_port_info_get_op_vls(p_pi) != + ib_port_info_get_op_vls(p_old_pi)) + send_set = TRUE; + + /* provide the vl_high_limit from the qos mgr */ + if (sm->p_subn->opt.qos && + p_physp->vl_high_limit != p_old_pi->vl_high_limit) { + send_set = TRUE; + p_pi->vl_high_limit = p_physp->vl_high_limit; + } + } + + if (port_state != IB_LINK_NO_CHANGE && + port_state != ib_port_info_get_port_state(p_old_pi)) { + send_set = TRUE; + if (port_state == IB_LINK_ACTIVE) + context.pi_context.active_transition = TRUE; + else + context.pi_context.active_transition = FALSE; + } + + context.pi_context.node_guid = osm_node_get_node_guid(p_node); + context.pi_context.port_guid = osm_physp_get_port_guid(p_physp); + context.pi_context.set_method = TRUE; + context.pi_context.light_sweep = FALSE; + + /* We need to send the PortInfoSet request with the new sm_lid + in the following cases: + 1. There is a change in the values (send_set == TRUE) + 2. This is a switch external port (so it wasn't handled yet by + osm_lid_mgr) and first_time_master_sweep flag on the subnet is TRUE, + which means the SM just became master, and it then needs to send at + PortInfoSet to every port. + */ + if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH && port_num + && sm->p_subn->first_time_master_sweep == TRUE) + send_set = TRUE; + + if (send_set) + status = osm_req_set(sm, osm_physp_get_dr_path_ptr(p_physp), + payload, sizeof(payload), + IB_MAD_ATTR_PORT_INFO, + cl_hton32(port_num), + CL_DISP_MSGID_NONE, &context); + +Exit: + OSM_LOG_EXIT(sm->p_log); + return send_set; +} + +/********************************************************************** + **********************************************************************/ +static osm_signal_t +__osm_link_mgr_process_node(osm_sm_t * sm, + IN osm_node_t * const p_node, + IN const uint8_t link_state) +{ + uint32_t i; + uint32_t num_physp; + osm_physp_t *p_physp; + uint8_t current_state; + osm_signal_t signal = OSM_SIGNAL_DONE; + + OSM_LOG_ENTER(sm->p_log); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Node 0x%" PRIx64 " going to %s\n", + cl_ntoh64(osm_node_get_node_guid(p_node)), + ib_get_port_state_str(link_state)); + + /* + Set the PortInfo for every Physical Port associated + with this Port. Start iterating with port 1, since the linkstate + is not applicable to the management port on switches. + */ + num_physp = osm_node_get_num_physp(p_node); + for (i = 0; i < num_physp; i++) { + /* + Don't bother doing anything if this Physical Port is not valid. + or if the state of the port is already better then the + specified state. + */ + p_physp = osm_node_get_physp_ptr(p_node, (uint8_t) i); + if (!p_physp) + continue; + + current_state = osm_physp_get_port_state(p_physp); + if (current_state == IB_LINK_DOWN) + continue; + + /* + Normally we only send state update if state is lower + then required state. However, we need to send update if + no state change required. + */ + if (link_state != IB_LINK_NO_CHANGE && + link_state <= current_state) + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Physical port %u already %s. Skipping\n", + p_physp->port_num, + ib_get_port_state_str(current_state)); + else if (__osm_link_mgr_set_physp_pi(sm, p_physp, link_state)) + signal = OSM_SIGNAL_DONE_PENDING; + } + + OSM_LOG_EXIT(sm->p_log); + return (signal); +} + +/********************************************************************** + **********************************************************************/ +osm_signal_t osm_link_mgr_process(osm_sm_t * sm, IN const uint8_t link_state) +{ + cl_qmap_t *p_node_guid_tbl; + osm_node_t *p_node; + osm_signal_t signal = OSM_SIGNAL_DONE; + + OSM_LOG_ENTER(sm->p_log); + + p_node_guid_tbl = &sm->p_subn->node_guid_tbl; + + CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); + + for (p_node = (osm_node_t *) cl_qmap_head(p_node_guid_tbl); + p_node != (osm_node_t *) cl_qmap_end(p_node_guid_tbl); + p_node = (osm_node_t *) cl_qmap_next(&p_node->map_item)) { + if (__osm_link_mgr_process_node(sm, p_node, link_state) == + OSM_SIGNAL_DONE_PENDING) + signal = OSM_SIGNAL_DONE_PENDING; + } + + CL_PLOCK_RELEASE(sm->p_lock); + + OSM_LOG_EXIT(sm->p_log); + return (signal); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_log.c b/contrib/ofed/management/opensm/opensm/osm_log.c new file mode 100644 index 000000000000..88633ab5fec5 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_log.c @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_log_t. + * This object represents the log file. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static int log_exit_count = 0; + +#ifndef WIN32 +#include +#include +#include + +static char *month_str[] = { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" +}; +#else +void OsmReportState(IN const char *p_str); +#endif /* ndef WIN32 */ + +#ifndef WIN32 + +static void truncate_log_file(osm_log_t * const p_log) +{ + int fd = fileno(p_log->out_port); + if (ftruncate(fd, 0) < 0) + fprintf(stderr, "truncate_log_file: cannot truncate: %s\n", + strerror(errno)); + if (lseek(fd, 0, SEEK_SET) < 0) + fprintf(stderr, "truncate_log_file: cannot rewind: %s\n", + strerror(errno)); + p_log->count = 0; +} + +#else /* Windows */ + +static void truncate_log_file(osm_log_t * const p_log) +{ + fprintf(stderr, + "truncate_log_file: cannot truncate on windows system (yet)\n"); +} +#endif /* ndef WIN32 */ + +void osm_log(IN osm_log_t * const p_log, + IN const osm_log_level_t verbosity, IN const char *p_str, ...) +{ + char buffer[LOG_ENTRY_SIZE_MAX]; + va_list args; + int ret; +#ifdef WIN32 + SYSTEMTIME st; + uint32_t pid = GetCurrentThreadId(); +#else + pid_t pid = 0; + time_t tim; + struct tm result; + uint64_t time_usecs; + uint32_t usecs; +#endif /* WIN32 */ + + /* If this is a call to syslog - always print it */ + if (!(verbosity & (OSM_LOG_SYS | p_log->level))) + return; + + va_start(args, p_str); + vsprintf(buffer, p_str, args); + va_end(args); + + /* this is a call to the syslog */ + if (verbosity & OSM_LOG_SYS) { + syslog(LOG_INFO, "%s\n", buffer); + + /* SYSLOG should go to stdout too */ + if (p_log->out_port != stdout) { + printf("%s\n", buffer); + fflush(stdout); + } +#ifdef WIN32 + OsmReportState(buffer); +#endif /* WIN32 */ + } + + /* regular log to default out_port */ + cl_spinlock_acquire(&p_log->lock); + + if (p_log->max_size && p_log->count > p_log->max_size) { + /* truncate here */ + fprintf(stderr, + "osm_log: log file exceeds the limit %lu. Truncating.\n", + p_log->max_size); + truncate_log_file(p_log); + } +#ifdef WIN32 + GetLocalTime(&st); +_retry: + ret = + fprintf(p_log->out_port, + "[%02d:%02d:%02d:%03d][%04X] 0x%02x -> %s", + st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, + pid, verbosity, buffer); +#else + time_usecs = cl_get_time_stamp(); + tim = time_usecs / 1000000; + usecs = time_usecs % 1000000; + localtime_r(&tim, &result); + pid = pthread_self(); +_retry: + ret = + fprintf(p_log->out_port, + "%s %02d %02d:%02d:%02d %06d [%04X] 0x%02x -> %s", + (result.tm_mon < + 12 ? month_str[result.tm_mon] : "???"), + result.tm_mday, result.tm_hour, result.tm_min, + result.tm_sec, usecs, pid, verbosity, buffer); +#endif + + /* flush log */ + if (ret > 0 && + (p_log->flush || (verbosity & (OSM_LOG_ERROR | OSM_LOG_SYS))) + && fflush(p_log->out_port) < 0) + ret = -1; + + if (ret >= 0) { + log_exit_count = 0; + p_log->count += ret; + } else if (log_exit_count < 3) { + log_exit_count++; + if (errno == ENOSPC && p_log->max_size) { + fprintf(stderr, + "osm_log: write failed: %s. Truncating log file.\n", + strerror(errno)); + truncate_log_file(p_log); + goto _retry; + } + fprintf(stderr, "osm_log: write failed: %s\n", strerror(errno)); + } + + cl_spinlock_release(&p_log->lock); +} + +void osm_log_raw(IN osm_log_t * const p_log, + IN const osm_log_level_t verbosity, IN const char *p_buf) +{ + if (p_log->level & verbosity) { + cl_spinlock_acquire(&p_log->lock); + printf("%s", p_buf); + cl_spinlock_release(&p_log->lock); + + /* + Flush log on errors too. + */ + if (p_log->flush || (verbosity & OSM_LOG_ERROR)) + fflush(stdout); + } +} + +void osm_log_msg_box(IN osm_log_t * log, osm_log_level_t level, + const char *func_name, const char *msg) +{ +#define MSG_BOX_LENGTH 66 + char buf[MSG_BOX_LENGTH + 1]; + int i, n; + + if (!osm_log_is_active(log, level)) + return; + + n = (MSG_BOX_LENGTH - strlen(msg)) / 2 - 1; + if (n < 0) + n = 0; + for (i = 0; i < n; i++) + sprintf(buf + i, "*"); + n += snprintf(buf + n, sizeof(buf) - n, " %s ", msg); + for (i = n; i < MSG_BOX_LENGTH; i++) + buf[i] = '*'; + buf[i] = '\0'; + + osm_log(log, level, "%s:\n\n\n" + "*********************************************" + "*********************\n%s\n" + "*********************************************" + "*********************\n\n\n", func_name, buf); +} + +boolean_t osm_is_debug(void) +{ +#if defined( _DEBUG_ ) + return TRUE; +#else + return FALSE; +#endif /* defined( _DEBUG_ ) */ +} + +static int open_out_port(IN osm_log_t * p_log) +{ + struct stat st; + + if (p_log->accum_log_file) + p_log->out_port = fopen(p_log->log_file_name, "a+"); + else + p_log->out_port = fopen(p_log->log_file_name, "w+"); + + if (!p_log->out_port) { + syslog(LOG_CRIT, "Cannot open file \'%s\' for %s: %s\n", + p_log->log_file_name, + p_log->accum_log_file ? "appending" : "writing", + strerror(errno)); + fprintf(stderr, "Cannot open file \'%s\': %s\n", + p_log->log_file_name, strerror(errno)); + return -1; + } + + if (fstat(fileno(p_log->out_port), &st) == 0) + p_log->count = st.st_size; + + syslog(LOG_NOTICE, "%s log file opened\n", p_log->log_file_name); + + if (p_log->daemon) { + dup2(fileno(p_log->out_port), 0); + dup2(fileno(p_log->out_port), 1); + dup2(fileno(p_log->out_port), 2); + } + + return 0; +} + +int osm_log_reopen_file(osm_log_t * p_log) +{ + int ret; + + if (p_log->out_port == stdout || p_log->out_port == stderr) + return 0; + cl_spinlock_acquire(&p_log->lock); + fclose(p_log->out_port); + ret = open_out_port(p_log); + cl_spinlock_release(&p_log->lock); + return ret; +} + +ib_api_status_t osm_log_init_v2(IN osm_log_t * const p_log, + IN const boolean_t flush, + IN const uint8_t log_flags, + IN const char *log_file, + IN const unsigned long max_size, + IN const boolean_t accum_log_file) +{ + p_log->level = log_flags; + p_log->flush = flush; + p_log->count = 0; + p_log->max_size = max_size; + p_log->accum_log_file = accum_log_file; + p_log->log_file_name = (char *)log_file; + + openlog("OpenSM", LOG_CONS | LOG_PID, LOG_USER); + + if (log_file == NULL || !strcmp(log_file, "-") || + !strcmp(log_file, "stdout")) + p_log->out_port = stdout; + else if (!strcmp(log_file, "stderr")) + p_log->out_port = stderr; + else if (open_out_port(p_log)) + return IB_ERROR; + + if (cl_spinlock_init(&p_log->lock) == CL_SUCCESS) + return IB_SUCCESS; + else + return IB_ERROR; +} + +ib_api_status_t osm_log_init(IN osm_log_t * const p_log, + IN const boolean_t flush, + IN const uint8_t log_flags, + IN const char *log_file, + IN const boolean_t accum_log_file) +{ + return osm_log_init_v2(p_log, flush, log_flags, log_file, 0, + accum_log_file); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_mad_pool.c b/contrib/ofed/management/opensm/opensm/osm_mad_pool.c new file mode 100644 index 000000000000..56a2a6dd1718 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_mad_pool.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mad_pool_t. + * This object represents a pool of management datagram (MAD) objects. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void osm_mad_pool_construct(IN osm_mad_pool_t * const p_pool) +{ + CL_ASSERT(p_pool); + + memset(p_pool, 0, sizeof(*p_pool)); +} + +/********************************************************************** + **********************************************************************/ +void osm_mad_pool_destroy(IN osm_mad_pool_t * const p_pool) +{ + CL_ASSERT(p_pool); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t osm_mad_pool_init(IN osm_mad_pool_t * const p_pool) +{ + p_pool->mads_out = 0; + + return IB_SUCCESS; +} + +/********************************************************************** + **********************************************************************/ +osm_madw_t *osm_mad_pool_get(IN osm_mad_pool_t * const p_pool, + IN osm_bind_handle_t h_bind, + IN const uint32_t total_size, + IN const osm_mad_addr_t * const p_mad_addr) +{ + osm_madw_t *p_madw; + ib_mad_t *p_mad; + + CL_ASSERT(h_bind != OSM_BIND_INVALID_HANDLE); + CL_ASSERT(total_size); + + /* + First, acquire a mad wrapper from the mad wrapper pool. + */ + p_madw = malloc(sizeof(*p_madw)); + if (p_madw == NULL) + goto Exit; + + osm_madw_init(p_madw, h_bind, total_size, p_mad_addr); + + /* + Next, acquire a wire mad of the specified size. + */ + p_mad = osm_vendor_get(h_bind, total_size, &p_madw->vend_wrap); + if (p_mad == NULL) { + /* Don't leak wrappers! */ + free(p_madw); + p_madw = NULL; + goto Exit; + } + + cl_atomic_inc(&p_pool->mads_out); + /* + Finally, attach the wire MAD to this wrapper. + */ + osm_madw_set_mad(p_madw, p_mad); + +Exit: + return p_madw; +} + +/********************************************************************** + **********************************************************************/ +osm_madw_t *osm_mad_pool_get_wrapper(IN osm_mad_pool_t * const p_pool, + IN osm_bind_handle_t h_bind, + IN const uint32_t total_size, + IN const ib_mad_t * const p_mad, + IN const osm_mad_addr_t * const p_mad_addr) +{ + osm_madw_t *p_madw; + + CL_ASSERT(h_bind != OSM_BIND_INVALID_HANDLE); + CL_ASSERT(total_size); + CL_ASSERT(p_mad); + + /* + First, acquire a mad wrapper from the mad wrapper pool. + */ + p_madw = malloc(sizeof(*p_madw)); + if (p_madw == NULL) + goto Exit; + + /* + Finally, initialize the wrapper object. + */ + cl_atomic_inc(&p_pool->mads_out); + osm_madw_init(p_madw, h_bind, total_size, p_mad_addr); + osm_madw_set_mad(p_madw, p_mad); + +Exit: + return (p_madw); +} + +/********************************************************************** + **********************************************************************/ +osm_madw_t *osm_mad_pool_get_wrapper_raw(IN osm_mad_pool_t * const p_pool) +{ + osm_madw_t *p_madw; + + p_madw = malloc(sizeof(*p_madw)); + if (!p_madw) + return NULL; + + osm_madw_init(p_madw, 0, 0, 0); + osm_madw_set_mad(p_madw, 0); + cl_atomic_inc(&p_pool->mads_out); + + return (p_madw); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mad_pool_put(IN osm_mad_pool_t * const p_pool, IN osm_madw_t * const p_madw) +{ + CL_ASSERT(p_madw); + + /* + First, return the wire mad to the pool + */ + if (p_madw->p_mad) + osm_vendor_put(p_madw->h_bind, &p_madw->vend_wrap); + + /* + Return the mad wrapper to the wrapper pool + */ + free(p_madw); + cl_atomic_dec(&p_pool->mads_out); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_mcast_fwd_rcv.c b/contrib/ofed/management/opensm/opensm/osm_mcast_fwd_rcv.c new file mode 100644 index 000000000000..635c7dabbbba --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_mcast_fwd_rcv.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mft_rcv_t. + * This object represents the Multicast Forwarding Table Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void osm_mft_rcv_process(IN void *context, IN void *data) +{ + osm_sm_t *sm = context; + osm_madw_t *p_madw = data; + ib_smp_t *p_smp; + uint32_t block_num; + uint8_t position; + osm_switch_t *p_sw; + osm_mft_context_t *p_mft_context; + uint16_t *p_block; + ib_net64_t node_guid; + ib_api_status_t status; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_block = (uint16_t *) ib_smp_get_payload_ptr(p_smp); + block_num = cl_ntoh32(p_smp->attr_mod) & IB_MCAST_BLOCK_ID_MASK_HO; + position = (uint8_t) ((cl_ntoh32(p_smp->attr_mod) & + IB_MCAST_POSITION_MASK_HO) >> + IB_MCAST_POSITION_SHIFT); + + /* + Acquire the switch object for this switch. + */ + p_mft_context = osm_madw_get_mft_context_ptr(p_madw); + node_guid = p_mft_context->node_guid; + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Setting MFT block %u, position %u, " + "Switch 0x%016" PRIx64 ", TID 0x%" PRIx64 "\n", + block_num, position, cl_ntoh64(node_guid), + cl_ntoh64(p_smp->trans_id)); + + CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); + p_sw = osm_get_switch_by_guid(sm->p_subn, node_guid); + + if (!p_sw) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0801: " + "MFT received for nonexistent node " + "0x%016" PRIx64 "\n", cl_ntoh64(node_guid)); + } else { + status = osm_switch_set_mft_block(p_sw, p_block, + (uint16_t) block_num, + position); + if (status != IB_SUCCESS) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0802: " + "Setting MFT block failed (%s)" + "\n\t\t\t\tSwitch 0x%016" PRIx64 + ", block %u, position %u\n", + ib_get_err_str(status), + cl_ntoh64(node_guid), block_num, position); + } + } + + CL_PLOCK_RELEASE(sm->p_lock); + OSM_LOG_EXIT(sm->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_mcast_mgr.c b/contrib/ofed/management/opensm/opensm/osm_mcast_mgr.c new file mode 100644 index 000000000000..2f9cb5e37e0d --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_mcast_mgr.c @@ -0,0 +1,1267 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mcast_mgr_t. + * This file implements the Multicast Manager object. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +typedef struct osm_mcast_work_obj { + cl_list_item_t list_item; + osm_port_t *p_port; +} osm_mcast_work_obj_t; + +/********************************************************************** + **********************************************************************/ +static osm_mcast_work_obj_t *__osm_mcast_work_obj_new(IN const osm_port_t * + const p_port) +{ + /* + TO DO - get these objects from a lockpool. + */ + osm_mcast_work_obj_t *p_obj; + + /* + clean allocated memory to avoid assertion when trying to insert to + qlist. + see cl_qlist_insert_tail(): CL_ASSERT(p_list_item->p_list != p_list) + */ + p_obj = malloc(sizeof(*p_obj)); + if (p_obj) { + memset(p_obj, 0, sizeof(*p_obj)); + p_obj->p_port = (osm_port_t *) p_port; + } + + return (p_obj); +} + +/********************************************************************** + **********************************************************************/ +static void __osm_mcast_work_obj_delete(IN osm_mcast_work_obj_t * p_wobj) +{ + free(p_wobj); +} + +/********************************************************************** + Recursively remove nodes from the tree + *********************************************************************/ +static void __osm_mcast_mgr_purge_tree_node(IN osm_mtree_node_t * p_mtn) +{ + uint8_t i; + + for (i = 0; i < p_mtn->max_children; i++) { + if (p_mtn->child_array[i] && + (p_mtn->child_array[i] != OSM_MTREE_LEAF)) + __osm_mcast_mgr_purge_tree_node(p_mtn->child_array[i]); + + p_mtn->child_array[i] = NULL; + + } + + free(p_mtn); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_mcast_mgr_purge_tree(osm_sm_t * sm, IN osm_mgrp_t * const p_mgrp) +{ + OSM_LOG_ENTER(sm->p_log); + + if (p_mgrp->p_root) + __osm_mcast_mgr_purge_tree_node(p_mgrp->p_root); + + p_mgrp->p_root = NULL; + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +static float +osm_mcast_mgr_compute_avg_hops(osm_sm_t * sm, + const osm_mgrp_t * const p_mgrp, + const osm_switch_t * const p_sw) +{ + float avg_hops = 0; + uint32_t hops = 0; + uint32_t num_ports = 0; + const osm_port_t *p_port; + const osm_mcm_port_t *p_mcm_port; + const cl_qmap_t *p_mcm_tbl; + + OSM_LOG_ENTER(sm->p_log); + + p_mcm_tbl = &p_mgrp->mcm_port_tbl; + + /* + For each member of the multicast group, compute the + number of hops to its base LID. + */ + for (p_mcm_port = (osm_mcm_port_t *) cl_qmap_head(p_mcm_tbl); + p_mcm_port != (osm_mcm_port_t *) cl_qmap_end(p_mcm_tbl); + p_mcm_port = + (osm_mcm_port_t *) cl_qmap_next(&p_mcm_port->map_item)) { + /* + Acquire the port object for this port guid, then create + the new worker object to build the list. + */ + p_port = osm_get_port_by_guid(sm->p_subn, + ib_gid_get_guid(&p_mcm_port-> + port_gid)); + + if (!p_port) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A18: " + "No port object for port 0x%016" PRIx64 "\n", + cl_ntoh64(ib_gid_get_guid + (&p_mcm_port->port_gid))); + continue; + } + + hops += osm_switch_get_port_least_hops(p_sw, p_port); + num_ports++; + } + + /* + We should be here if there aren't any ports in the group. + */ + CL_ASSERT(num_ports); + + if (num_ports != 0) + avg_hops = (float)(hops / num_ports); + + OSM_LOG_EXIT(sm->p_log); + return (avg_hops); +} + +/********************************************************************** + Calculate the maximal "min hops" from the given switch to any + of the group HCAs + **********************************************************************/ +static float +osm_mcast_mgr_compute_max_hops(osm_sm_t * sm, + const osm_mgrp_t * const p_mgrp, + const osm_switch_t * const p_sw) +{ + uint32_t max_hops = 0; + uint32_t hops = 0; + const osm_port_t *p_port; + const osm_mcm_port_t *p_mcm_port; + const cl_qmap_t *p_mcm_tbl; + + OSM_LOG_ENTER(sm->p_log); + + p_mcm_tbl = &p_mgrp->mcm_port_tbl; + + /* + For each member of the multicast group, compute the + number of hops to its base LID. + */ + for (p_mcm_port = (osm_mcm_port_t *) cl_qmap_head(p_mcm_tbl); + p_mcm_port != (osm_mcm_port_t *) cl_qmap_end(p_mcm_tbl); + p_mcm_port = + (osm_mcm_port_t *) cl_qmap_next(&p_mcm_port->map_item)) { + /* + Acquire the port object for this port guid, then create + the new worker object to build the list. + */ + p_port = osm_get_port_by_guid(sm->p_subn, + ib_gid_get_guid(&p_mcm_port-> + port_gid)); + + if (!p_port) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A1A: " + "No port object for port 0x%016" PRIx64 "\n", + cl_ntoh64(ib_gid_get_guid + (&p_mcm_port->port_gid))); + continue; + } + + hops = osm_switch_get_port_least_hops(p_sw, p_port); + if (hops > max_hops) + max_hops = hops; + } + + if (max_hops == 0) { + /* + We should be here if there aren't any ports in the group. + */ + max_hops = 10001; /* see later - we use it to realize no hops */ + } + + OSM_LOG_EXIT(sm->p_log); + return (float)(max_hops); +} + +/********************************************************************** + This function attempts to locate the optimal switch for the + center of the spanning tree. The current algorithm chooses + a switch with the lowest average hop count to the members + of the multicast group. +**********************************************************************/ +static osm_switch_t *__osm_mcast_mgr_find_optimal_switch(osm_sm_t * sm, + const osm_mgrp_t * + const p_mgrp) +{ + cl_qmap_t *p_sw_tbl; + const osm_switch_t *p_sw; + const osm_switch_t *p_best_sw = NULL; + float hops = 0; + float best_hops = 10000; /* any big # will do */ +#ifdef OSM_VENDOR_INTF_ANAFA + boolean_t use_avg_hops = TRUE; /* anafa2 - bug hca on switch *//* use max hops for root */ +#else + boolean_t use_avg_hops = FALSE; /* use max hops for root */ +#endif + + OSM_LOG_ENTER(sm->p_log); + + p_sw_tbl = &sm->p_subn->sw_guid_tbl; + + CL_ASSERT(!osm_mgrp_is_empty(p_mgrp)); + + for (p_sw = (osm_switch_t *) cl_qmap_head(p_sw_tbl); + p_sw != (osm_switch_t *) cl_qmap_end(p_sw_tbl); + p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) { + if (!osm_switch_supports_mcast(p_sw)) + continue; + + if (use_avg_hops) + hops = osm_mcast_mgr_compute_avg_hops(sm, p_mgrp, p_sw); + else + hops = osm_mcast_mgr_compute_max_hops(sm, p_mgrp, p_sw); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Switch 0x%016" PRIx64 ", hops = %f\n", + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)), hops); + + if (hops < best_hops) { + p_best_sw = p_sw; + best_hops = hops; + } + } + + if (p_best_sw) + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Best switch is 0x%" PRIx64 ", hops = %f\n", + cl_ntoh64(osm_node_get_node_guid(p_best_sw->p_node)), + best_hops); + else + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "No multicast capable switches detected\n"); + + OSM_LOG_EXIT(sm->p_log); + return ((osm_switch_t *) p_best_sw); +} + +/********************************************************************** + This function returns the existing or optimal root swtich for the tree. +**********************************************************************/ +static osm_switch_t *__osm_mcast_mgr_find_root_switch(osm_sm_t * sm, + const osm_mgrp_t * + const p_mgrp) +{ + const osm_switch_t *p_sw = NULL; + + OSM_LOG_ENTER(sm->p_log); + + /* + We always look for the best multicast tree root switch. + Otherwise since we always start with a a single join + the root will be always on the first switch attached to it. + - Very bad ... + */ + p_sw = __osm_mcast_mgr_find_optimal_switch(sm, p_mgrp); + + OSM_LOG_EXIT(sm->p_log); + return ((osm_switch_t *) p_sw); +} + +/********************************************************************** + **********************************************************************/ +static osm_signal_t +__osm_mcast_mgr_set_tbl(osm_sm_t * sm, IN osm_switch_t * const p_sw) +{ + osm_node_t *p_node; + osm_dr_path_t *p_path; + osm_madw_context_t mad_context; + ib_api_status_t status; + uint32_t block_id_ho = 0; + int16_t block_num = 0; + uint32_t position = 0; + uint32_t max_position; + osm_mcast_tbl_t *p_tbl; + ib_net16_t block[IB_MCAST_BLOCK_SIZE]; + osm_signal_t signal = OSM_SIGNAL_DONE; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_sw); + + p_node = p_sw->p_node; + + CL_ASSERT(p_node); + + p_path = osm_physp_get_dr_path_ptr(osm_node_get_physp_ptr(p_node, 0)); + + /* + Send multicast forwarding table blocks to the switch + as long as the switch indicates it has blocks needing + configuration. + */ + + mad_context.mft_context.node_guid = osm_node_get_node_guid(p_node); + mad_context.mft_context.set_method = TRUE; + + p_tbl = osm_switch_get_mcast_tbl_ptr(p_sw); + max_position = p_tbl->max_position; + + while (osm_mcast_tbl_get_block(p_tbl, block_num, + (uint8_t) position, block)) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Writing MFT block 0x%X\n", block_id_ho); + + block_id_ho = block_num + (position << 28); + + status = osm_req_set(sm, p_path, (void *)block, sizeof(block), + IB_MAD_ATTR_MCAST_FWD_TBL, + cl_hton32(block_id_ho), + CL_DISP_MSGID_NONE, &mad_context); + + if (status != IB_SUCCESS) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A02: " + "Sending multicast fwd. tbl. block failed (%s)\n", + ib_get_err_str(status)); + } + + signal = OSM_SIGNAL_DONE_PENDING; + + if (++position > max_position) { + position = 0; + block_num++; + } + } + + OSM_LOG_EXIT(sm->p_log); + return (signal); +} + +/********************************************************************** + This is part of the recursive function to compute the paths in the + spanning tree that eminate from this switch. On input, the p_list + contains the group members that must be routed from this switch. +**********************************************************************/ +static void +__osm_mcast_mgr_subdivide(osm_sm_t * sm, + osm_mgrp_t * const p_mgrp, + osm_switch_t * const p_sw, + cl_qlist_t * const p_list, + cl_qlist_t * const list_array, + uint8_t const array_size) +{ + uint8_t port_num; + uint16_t mlid_ho; + boolean_t ignore_existing; + osm_mcast_work_obj_t *p_wobj; + + OSM_LOG_ENTER(sm->p_log); + + mlid_ho = cl_ntoh16(osm_mgrp_get_mlid(p_mgrp)); + + /* + For Multicast Groups, we want not to count on previous + configurations - since we can easily generate a storm + by loops. + */ + ignore_existing = TRUE; + + /* + Subdivide the set of ports into non-overlapping subsets + that will be routed to other switches. + */ + while ((p_wobj = + (osm_mcast_work_obj_t *) cl_qlist_remove_head(p_list)) != + (osm_mcast_work_obj_t *) cl_qlist_end(p_list)) { + port_num = + osm_switch_recommend_mcast_path(p_sw, p_wobj->p_port, + mlid_ho, ignore_existing); + + if (port_num == OSM_NO_PATH) { + /* + This typically occurs if the switch does not support + multicast and the multicast tree must branch at this + switch. + */ + uint64_t node_guid_ho = + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)); + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A03: " + "Error routing MLID 0x%X through switch 0x%" + PRIx64 "\n" + "\t\t\t\tNo multicast paths from this switch for port " + "with LID %u\n", mlid_ho, node_guid_ho, + cl_ntoh16(osm_port_get_base_lid + (p_wobj->p_port))); + + __osm_mcast_work_obj_delete(p_wobj); + continue; + } + + if (port_num > array_size) { + uint64_t node_guid_ho = + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)); + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A04: " + "Error routing MLID 0x%X through switch 0x%" + PRIx64 "\n" + "\t\t\t\tNo multicast paths from this switch to port " + "with LID %u\n", mlid_ho, node_guid_ho, + cl_ntoh16(osm_port_get_base_lid + (p_wobj->p_port))); + + __osm_mcast_work_obj_delete(p_wobj); + + /* This is means OpenSM has a bug. */ + CL_ASSERT(FALSE); + continue; + } + + cl_qlist_insert_tail(&list_array[port_num], &p_wobj->list_item); + } + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void __osm_mcast_mgr_purge_list(osm_sm_t * sm, cl_qlist_t * const p_list) +{ + osm_mcast_work_obj_t *p_wobj; + + OSM_LOG_ENTER(sm->p_log); + + while ((p_wobj = (osm_mcast_work_obj_t *) cl_qlist_remove_head(p_list)) + != (osm_mcast_work_obj_t *) cl_qlist_end(p_list)) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A06: " + "Unable to route for port 0x%" PRIx64 "\n", + osm_port_get_guid(p_wobj->p_port)); + __osm_mcast_work_obj_delete(p_wobj); + } + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + This is the recursive function to compute the paths in the spanning + tree that emanate from this switch. On input, the p_list contains + the group members that must be routed from this switch. + + The function returns the newly created mtree node element. +**********************************************************************/ +static osm_mtree_node_t *__osm_mcast_mgr_branch(osm_sm_t * sm, + osm_mgrp_t * const p_mgrp, + osm_switch_t * const p_sw, + cl_qlist_t * const p_list, + uint8_t depth, + uint8_t const upstream_port, + uint8_t * const p_max_depth) +{ + uint8_t max_children; + osm_mtree_node_t *p_mtn = NULL; + cl_qlist_t *list_array = NULL; + uint8_t i; + ib_net64_t node_guid; + uint64_t node_guid_ho; + osm_mcast_work_obj_t *p_wobj; + cl_qlist_t *p_port_list; + size_t count; + uint16_t mlid_ho; + osm_mcast_tbl_t *p_tbl; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_sw); + CL_ASSERT(p_list); + CL_ASSERT(p_max_depth); + + node_guid = osm_node_get_node_guid(p_sw->p_node); + node_guid_ho = cl_ntoh64(node_guid); + mlid_ho = cl_ntoh16(osm_mgrp_get_mlid(p_mgrp)); + + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Routing MLID 0x%X through switch 0x%" PRIx64 + ", %u nodes at depth %u\n", + mlid_ho, node_guid_ho, cl_qlist_count(p_list), depth); + + CL_ASSERT(cl_qlist_count(p_list) > 0); + + depth++; + + if (depth >= 64) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "Maximal hops number is reached for MLID 0x%x." + " Break processing.", mlid_ho); + __osm_mcast_mgr_purge_list(sm, p_list); + goto Exit; + } + + if (depth > *p_max_depth) { + CL_ASSERT(depth == *p_max_depth + 1); + *p_max_depth = depth; + } + + if (osm_switch_supports_mcast(p_sw) == FALSE) { + /* + This switch doesn't do multicast. Clean-up. + */ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A14: " + "Switch 0x%" PRIx64 " does not support multicast\n", + node_guid_ho); + + /* + Deallocate all the work objects on this branch of the tree. + */ + __osm_mcast_mgr_purge_list(sm, p_list); + goto Exit; + } + + p_mtn = osm_mtree_node_new(p_sw); + if (p_mtn == NULL) { + /* + We are unable to continue routing down this + leg of the tree. Clean-up. + */ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A15: " + "Insufficient memory to build multicast tree\n"); + + /* + Deallocate all the work objects on this branch of the tree. + */ + __osm_mcast_mgr_purge_list(sm, p_list); + goto Exit; + } + + max_children = osm_mtree_node_get_max_children(p_mtn); + + CL_ASSERT(max_children > 1); + + /* + Prepare an empty list for each port in the switch. + TO DO - this list array could probably be moved + inside the switch element to save on malloc thrashing. + */ + list_array = malloc(sizeof(cl_qlist_t) * max_children); + if (list_array == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A16: " + "Unable to allocate list array\n"); + __osm_mcast_mgr_purge_list(sm, p_list); + goto Exit; + } + + memset(list_array, 0, sizeof(cl_qlist_t) * max_children); + + for (i = 0; i < max_children; i++) + cl_qlist_init(&list_array[i]); + + __osm_mcast_mgr_subdivide(sm, p_mgrp, p_sw, p_list, list_array, + max_children); + + p_tbl = osm_switch_get_mcast_tbl_ptr(p_sw); + + /* + Add the upstream port to the forwarding table unless + we're at the root of the spanning tree. + */ + if (depth > 1) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Adding upstream port %u\n", upstream_port); + + CL_ASSERT(upstream_port); + osm_mcast_tbl_set(p_tbl, mlid_ho, upstream_port); + } + + /* + For each port that was allocated some routes, + recurse into this function to continue building the tree + if the node on the other end of that port is another switch. + Otherwise, the node is an endpoint, and we've found a leaf + of the tree. Mark leaves with our special pointer value. + */ + + for (i = 0; i < max_children; i++) { + const osm_physp_t *p_physp; + const osm_physp_t *p_remote_physp; + osm_node_t *p_node; + const osm_node_t *p_remote_node; + + p_port_list = &list_array[i]; + + count = cl_qlist_count(p_port_list); + + /* + There should be no children routed through the upstream port! + */ + CL_ASSERT((upstream_port == 0) || (i != upstream_port) || + ((i == upstream_port) && (count == 0))); + + if (count == 0) + continue; /* No routes down this port. */ + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Routing %zu destinations via switch port %u\n", + count, i); + + /* + This port routes frames for this mcast group. Therefore, + set the appropriate bit in the multicast forwarding + table for this switch. + */ + osm_mcast_tbl_set(p_tbl, mlid_ho, i); + if (i == 0) { + /* This means we are adding the switch to the MC group. + We do not need to continue looking at the remote port, just + needed to add the port to the table */ + CL_ASSERT(count == 1); + + p_wobj = (osm_mcast_work_obj_t *) + cl_qlist_remove_head(p_port_list); + __osm_mcast_work_obj_delete(p_wobj); + continue; + } + + p_node = p_sw->p_node; + p_remote_node = osm_node_get_remote_node(p_node, i, NULL); + if (!p_remote_node) + continue; + + if (osm_node_get_type(p_remote_node) == IB_NODE_TYPE_SWITCH) { + /* + Acquire a pointer to the remote switch then recurse. + */ + CL_ASSERT(p_remote_node->sw); + + p_physp = osm_node_get_physp_ptr(p_node, i); + CL_ASSERT(p_physp); + + p_remote_physp = osm_physp_get_remote(p_physp); + CL_ASSERT(p_remote_physp); + + p_mtn->child_array[i] = + __osm_mcast_mgr_branch(sm, p_mgrp, + p_remote_node->sw, + p_port_list, depth, + osm_physp_get_port_num + (p_remote_physp), + p_max_depth); + } else { + /* + The neighbor node is not a switch, so this + must be a leaf. + */ + CL_ASSERT(count == 1); + + p_mtn->child_array[i] = OSM_MTREE_LEAF; + p_wobj = (osm_mcast_work_obj_t *) + cl_qlist_remove_head(p_port_list); + + CL_ASSERT(cl_is_qlist_empty(p_port_list)); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Found leaf for port 0x%016" PRIx64 + " on switch port %u\n", + cl_ntoh64(osm_port_get_guid(p_wobj->p_port)), + i); + + __osm_mcast_work_obj_delete(p_wobj); + } + } + + free(list_array); +Exit: + OSM_LOG_EXIT(sm->p_log); + return (p_mtn); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_mcast_mgr_build_spanning_tree(osm_sm_t * sm, osm_mgrp_t * const p_mgrp) +{ + const cl_qmap_t *p_mcm_tbl; + const osm_port_t *p_port; + const osm_mcm_port_t *p_mcm_port; + uint32_t num_ports; + cl_qlist_t port_list; + osm_switch_t *p_sw; + osm_mcast_work_obj_t *p_wobj; + ib_api_status_t status = IB_SUCCESS; + uint8_t max_depth = 0; + uint32_t count; + + OSM_LOG_ENTER(sm->p_log); + + cl_qlist_init(&port_list); + + /* + TO DO - for now, just blow away the old tree. + In the future we'll need to construct the tree based + on multicast forwarding table information if the user wants to + preserve existing multicast routes. + */ + __osm_mcast_mgr_purge_tree(sm, p_mgrp); + + p_mcm_tbl = &p_mgrp->mcm_port_tbl; + num_ports = cl_qmap_count(p_mcm_tbl); + if (num_ports == 0) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "MLID 0x%X has no members - nothing to do\n", + cl_ntoh16(osm_mgrp_get_mlid(p_mgrp))); + goto Exit; + } + + /* + This function builds the single spanning tree recursively. + At each stage, the ports to be reached are divided into + non-overlapping subsets of member ports that can be reached through + a given switch port. Construction then moves down each + branch, and the process starts again with each branch computing + for its own subset of the member ports. + + The maximum recursion depth is at worst the maximum hop count in the + subnet, which is spec limited to 64. + */ + + /* + Locate the switch around which to create the spanning + tree for this multicast group. + */ + p_sw = __osm_mcast_mgr_find_root_switch(sm, p_mgrp); + if (p_sw == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A08: " + "Unable to locate a suitable switch for group 0x%X\n", + cl_ntoh16(osm_mgrp_get_mlid(p_mgrp))); + status = IB_ERROR; + goto Exit; + } + + /* + Build the first "subset" containing all member ports. + */ + for (p_mcm_port = (osm_mcm_port_t *) cl_qmap_head(p_mcm_tbl); + p_mcm_port != (osm_mcm_port_t *) cl_qmap_end(p_mcm_tbl); + p_mcm_port = + (osm_mcm_port_t *) cl_qmap_next(&p_mcm_port->map_item)) { + /* + Acquire the port object for this port guid, then create + the new worker object to build the list. + */ + p_port = osm_get_port_by_guid(sm->p_subn, + ib_gid_get_guid(&p_mcm_port-> + port_gid)); + if (!p_port) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A09: " + "No port object for port 0x%016" PRIx64 "\n", + cl_ntoh64(ib_gid_get_guid + (&p_mcm_port->port_gid))); + continue; + } + + p_wobj = __osm_mcast_work_obj_new(p_port); + if (p_wobj == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A10: " + "Insufficient memory to route port 0x%016" + PRIx64 "\n", + cl_ntoh64(osm_port_get_guid(p_port))); + continue; + } + + cl_qlist_insert_tail(&port_list, &p_wobj->list_item); + } + + count = cl_qlist_count(&port_list); + p_mgrp->p_root = __osm_mcast_mgr_branch(sm, p_mgrp, p_sw, + &port_list, 0, 0, &max_depth); + + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Configured MLID 0x%X for %u ports, max tree depth = %u\n", + cl_ntoh16(osm_mgrp_get_mlid(p_mgrp)), count, max_depth); + +Exit: + OSM_LOG_EXIT(sm->p_log); + return (status); +} + +#if 0 +/* unused */ +/********************************************************************** + **********************************************************************/ +void +osm_mcast_mgr_set_table(osm_sm_t * sm, + IN const osm_mgrp_t * const p_mgrp, + IN const osm_mtree_node_t * const p_mtn) +{ + uint8_t i; + uint8_t max_children; + osm_mtree_node_t *p_child_mtn; + uint16_t mlid_ho; + osm_mcast_tbl_t *p_tbl; + osm_switch_t *p_sw; + + OSM_LOG_ENTER(sm->p_log); + + mlid_ho = cl_ntoh16(osm_mgrp_get_mlid(p_mgrp)); + p_sw = osm_mtree_node_get_switch_ptr(p_mtn); + + CL_ASSERT(p_sw); + + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Configuring MLID 0x%X on switch 0x%" PRIx64 "\n", + mlid_ho, osm_node_get_node_guid(p_sw->p_node)); + + /* + For every child of this tree node, set the corresponding + bit in the switch's mcast table. + */ + p_tbl = osm_switch_get_mcast_tbl_ptr(p_sw); + max_children = osm_mtree_node_get_max_children(p_mtn); + + CL_ASSERT(max_children <= osm_switch_get_num_ports(p_sw)); + + osm_mcast_tbl_clear_mlid(p_tbl, mlid_ho); + + for (i = 0; i < max_children; i++) { + p_child_mtn = osm_mtree_node_get_child(p_mtn, i); + if (p_child_mtn == NULL) + continue; + + osm_mcast_tbl_set(p_tbl, mlid_ho, i); + } + + OSM_LOG_EXIT(sm->p_log); +} +#endif + +/********************************************************************** + **********************************************************************/ +static void __osm_mcast_mgr_clear(osm_sm_t * sm, IN osm_mgrp_t * const p_mgrp) +{ + osm_switch_t *p_sw; + cl_qmap_t *p_sw_tbl; + osm_mcast_tbl_t *p_mcast_tbl; + + OSM_LOG_ENTER(sm->p_log); + + /* + Walk the switches and clear the routing entries for + this MLID. + */ + p_sw_tbl = &sm->p_subn->sw_guid_tbl; + p_sw = (osm_switch_t *) cl_qmap_head(p_sw_tbl); + while (p_sw != (osm_switch_t *) cl_qmap_end(p_sw_tbl)) { + p_mcast_tbl = osm_switch_get_mcast_tbl_ptr(p_sw); + osm_mcast_tbl_clear_mlid(p_mcast_tbl, cl_ntoh16(p_mgrp->mlid)); + p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); + } + + OSM_LOG_EXIT(sm->p_log); +} + +#if 0 +/* TO DO - make this real -- at least update spanning tree */ +/********************************************************************** + Lock must be held on entry. +**********************************************************************/ +ib_api_status_t +osm_mcast_mgr_process_single(osm_sm_t * sm, + IN ib_net16_t const mlid, + IN ib_net64_t const port_guid, + IN uint8_t const join_state) +{ + uint8_t port_num; + uint16_t mlid_ho; + ib_net64_t sw_guid; + osm_port_t *p_port; + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + osm_node_t *p_remote_node; + osm_mcast_tbl_t *p_mcast_tbl; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(mlid); + CL_ASSERT(port_guid); + + mlid_ho = cl_ntoh16(mlid); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Attempting to add port 0x%" PRIx64 " to MLID 0x%X, " + "\n\t\t\t\tjoin state = 0x%X\n", + cl_ntoh64(port_guid), mlid_ho, join_state); + + /* + Acquire the Port object. + */ + p_port = osm_get_port_by_guid(sm->p_subn, port_guid); + if (!p_port) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A01: " + "Unable to acquire port object for 0x%" PRIx64 "\n", + cl_ntoh64(port_guid)); + status = IB_ERROR; + goto Exit; + } + + p_physp = p_port->p_physp; + if (p_physp == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A05: " + "Unable to acquire phsyical port object for 0x%" PRIx64 + "\n", cl_ntoh64(port_guid)); + status = IB_ERROR; + goto Exit; + } + + p_remote_physp = osm_physp_get_remote(p_physp); + if (p_remote_physp == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A11: " + "Unable to acquire remote phsyical port object " + "for 0x%" PRIx64 "\n", cl_ntoh64(port_guid)); + status = IB_ERROR; + goto Exit; + } + + p_remote_node = osm_physp_get_node_ptr(p_remote_physp); + + CL_ASSERT(p_remote_node); + + sw_guid = osm_node_get_node_guid(p_remote_node); + + if (osm_node_get_type(p_remote_node) != IB_NODE_TYPE_SWITCH) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A22: " + "Remote node not a switch node 0x%" PRIx64 "\n", + cl_ntoh64(sw_guid)); + status = IB_ERROR; + goto Exit; + } + + if (!p_remote_node->sw) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A12: " + "No switch object 0x%" PRIx64 "\n", cl_ntoh64(sw_guid)); + status = IB_ERROR; + goto Exit; + } + + if (osm_switch_is_in_mcast_tree(p_remote_node->sw, mlid_ho)) { + /* + We're in luck. The switch attached to this port + is already in the multicast group, so we can just + add the specified port as a new leaf of the tree. + */ + if (join_state & (IB_JOIN_STATE_FULL | IB_JOIN_STATE_NON)) { + /* + This node wants to receive multicast frames. + Get the switch port number to which the new member port + is attached, then configure this single mcast table. + */ + port_num = osm_physp_get_port_num(p_remote_physp); + CL_ASSERT(port_num); + + p_mcast_tbl = + osm_switch_get_mcast_tbl_ptr(p_remote_node->sw); + osm_mcast_tbl_set(p_mcast_tbl, mlid_ho, port_num); + } else { + if (join_state & IB_JOIN_STATE_SEND_ONLY) + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Success. Nothing to do for send" + "only member\n"); + else { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A13: " + "Unknown join state 0x%X\n", + join_state); + status = IB_ERROR; + goto Exit; + } + } + } else + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Unable to add port\n"); + +Exit: + OSM_LOG_EXIT(sm->p_log); + return (status); +} +#endif + +/********************************************************************** + lock must already be held on entry +**********************************************************************/ +static ib_api_status_t +osm_mcast_mgr_process_tree(osm_sm_t * sm, + IN osm_mgrp_t * const p_mgrp, + IN osm_mcast_req_type_t req_type, + ib_net64_t port_guid) +{ + ib_api_status_t status = IB_SUCCESS; + ib_net16_t mlid; + + OSM_LOG_ENTER(sm->p_log); + + mlid = osm_mgrp_get_mlid(p_mgrp); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Processing multicast group 0x%X\n", cl_ntoh16(mlid)); + + /* + If there are no switches in the subnet, then we have nothing to do. + */ + if (cl_qmap_count(&sm->p_subn->sw_guid_tbl) == 0) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "No switches in subnet. Nothing to do\n"); + goto Exit; + } + + /* + Clear the multicast tables to start clean, then build + the spanning tree which sets the mcast table bits for each + port in the group. + */ + __osm_mcast_mgr_clear(sm, p_mgrp); + + if (!p_mgrp->full_members) + goto Exit; + + status = __osm_mcast_mgr_build_spanning_tree(sm, p_mgrp); + if (status != IB_SUCCESS) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A17: " + "Unable to create spanning tree (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(sm->p_log); + return (status); +} + +/********************************************************************** + Process the entire group. + NOTE : The lock should be held externally! + **********************************************************************/ +static ib_api_status_t +mcast_mgr_process_mgrp(osm_sm_t * sm, + IN osm_mgrp_t * const p_mgrp, + IN osm_mcast_req_type_t req_type, + IN ib_net64_t port_guid) +{ + ib_api_status_t status; + + OSM_LOG_ENTER(sm->p_log); + + status = osm_mcast_mgr_process_tree(sm, p_mgrp, req_type, port_guid); + if (status != IB_SUCCESS) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0A19: " + "Unable to create spanning tree (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + p_mgrp->last_tree_id = p_mgrp->last_change_id; + + /* remove MCGRP if it is marked for deletion */ + if (p_mgrp->to_be_deleted) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Destroying mgrp with lid:0x%x\n", + cl_ntoh16(p_mgrp->mlid)); + sm->p_subn->mgroups[cl_ntoh16(p_mgrp->mlid) - IB_LID_MCAST_START_HO] = NULL; + osm_mgrp_delete(p_mgrp); + } + +Exit: + OSM_LOG_EXIT(sm->p_log); + return status; +} + +/********************************************************************** + **********************************************************************/ +osm_signal_t osm_mcast_mgr_process(osm_sm_t * sm) +{ + osm_signal_t signal; + osm_switch_t *p_sw; + cl_qmap_t *p_sw_tbl; + cl_qlist_t *p_list = &sm->mgrp_list; + osm_mgrp_t *p_mgrp; + boolean_t pending_transactions = FALSE; + int i; + + OSM_LOG_ENTER(sm->p_log); + + p_sw_tbl = &sm->p_subn->sw_guid_tbl; + /* + While holding the lock, iterate over all the established + multicast groups, servicing each in turn. + + Then, download the multicast tables to the switches. + */ + CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); + + for (i = 0; i <= sm->p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO; + i++) { + /* + We reached here due to some change that caused a heavy sweep + of the subnet. Not due to a specific multicast request. + So the request type is subnet_change and the port guid is 0. + */ + p_mgrp = sm->p_subn->mgroups[i]; + if (p_mgrp) + mcast_mgr_process_mgrp(sm, p_mgrp, + OSM_MCAST_REQ_TYPE_SUBNET_CHANGE, + 0); + } + + /* + Walk the switches and download the tables for each. + */ + p_sw = (osm_switch_t *) cl_qmap_head(p_sw_tbl); + while (p_sw != (osm_switch_t *) cl_qmap_end(p_sw_tbl)) { + signal = __osm_mcast_mgr_set_tbl(sm, p_sw); + if (signal == OSM_SIGNAL_DONE_PENDING) + pending_transactions = TRUE; + p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); + } + + while (!cl_is_qlist_empty(p_list)) { + cl_list_item_t *p = cl_qlist_remove_head(p_list); + free(p); + } + + CL_PLOCK_RELEASE(sm->p_lock); + + OSM_LOG_EXIT(sm->p_log); + + if (pending_transactions == TRUE) + return (OSM_SIGNAL_DONE_PENDING); + else + return (OSM_SIGNAL_DONE); +} + +/********************************************************************** + This is the function that is invoked during idle time to handle the + process request for mcast groups where join/leave/delete was required. + **********************************************************************/ +osm_signal_t osm_mcast_mgr_process_mgroups(osm_sm_t * sm) +{ + cl_qlist_t *p_list = &sm->mgrp_list; + osm_switch_t *p_sw; + cl_qmap_t *p_sw_tbl; + osm_mgrp_t *p_mgrp; + ib_net16_t mlid; + osm_signal_t ret, signal = OSM_SIGNAL_DONE; + osm_mcast_mgr_ctxt_t *ctx; + osm_mcast_req_type_t req_type; + ib_net64_t port_guid; + + OSM_LOG_ENTER(sm->p_log); + + /* we need a lock to make sure the p_mgrp is not change other ways */ + CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); + + while (!cl_is_qlist_empty(p_list)) { + ctx = (osm_mcast_mgr_ctxt_t *) cl_qlist_remove_head(p_list); + req_type = ctx->req_type; + port_guid = ctx->port_guid; + + /* nice copy no warning on size diff */ + memcpy(&mlid, &ctx->mlid, sizeof(mlid)); + + /* we can destroy the context now */ + free(ctx); + + /* since we delayed the execution we prefer to pass the + mlid as the mgrp identifier and then find it or abort */ + p_mgrp = osm_get_mgrp_by_mlid(sm->p_subn, mlid); + if (!p_mgrp) + continue; + + /* if there was no change from the last time + * we processed the group we can skip doing anything + */ + if (p_mgrp->last_change_id == p_mgrp->last_tree_id) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Skip processing mgrp with lid:0x%X change id:%u\n", + cl_ntoh16(mlid), p_mgrp->last_change_id); + continue; + } + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Processing mgrp with lid:0x%X change id:%u\n", + cl_ntoh16(mlid), p_mgrp->last_change_id); + mcast_mgr_process_mgrp(sm, p_mgrp, req_type, port_guid); + } + + /* + Walk the switches and download the tables for each. + */ + p_sw_tbl = &sm->p_subn->sw_guid_tbl; + p_sw = (osm_switch_t *) cl_qmap_head(p_sw_tbl); + while (p_sw != (osm_switch_t *) cl_qmap_end(p_sw_tbl)) { + ret = __osm_mcast_mgr_set_tbl(sm, p_sw); + if (ret == OSM_SIGNAL_DONE_PENDING) + signal = ret; + p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); + } + + osm_dump_mcast_routes(sm->p_subn->p_osm); + + CL_PLOCK_RELEASE(sm->p_lock); + OSM_LOG_EXIT(sm->p_log); + return signal; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_mcast_tbl.c b/contrib/ofed/management/opensm/opensm/osm_mcast_tbl.c new file mode 100644 index 000000000000..17fb69c4cb0c --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_mcast_tbl.c @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mcast_tbl_t. + * This object represents an multicast forwarding table. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_mcast_tbl_init(IN osm_mcast_tbl_t * const p_tbl, + IN uint8_t const num_ports, IN uint16_t const capacity) +{ + CL_ASSERT(p_tbl); + CL_ASSERT(num_ports); + + memset(p_tbl, 0, sizeof(*p_tbl)); + + p_tbl->max_block_in_use = -1; + + if (capacity == 0) { + /* + This switch apparently doesn't support multicast. + Everything is initialized to zero already, so return. + */ + return (IB_SUCCESS); + } + + p_tbl->num_entries = capacity; + p_tbl->num_ports = num_ports; + p_tbl->max_position = + (uint8_t) ((ROUNDUP(num_ports, IB_MCAST_MASK_SIZE) / + IB_MCAST_MASK_SIZE) - 1); + + p_tbl->max_block = (uint16_t) ((ROUNDUP(p_tbl->num_entries, + IB_MCAST_BLOCK_SIZE) / + IB_MCAST_BLOCK_SIZE) - 1); + + p_tbl->max_mlid_ho = (uint16_t) (IB_LID_MCAST_START_HO + capacity - 1); + + /* + The number of bytes needed in the mask table is: + The (maximum bit mask 'position' + 1) times the + number of bytes in each bit mask times the + number of MLIDs supported by the table. + + We must always allocate the array with the maximum position + since it is (and must be) defined that way the table structure + in order to create a pointer to a two dimensional array. + */ + p_tbl->p_mask_tbl = malloc(p_tbl->num_entries * + (IB_MCAST_POSITION_MAX + + 1) * IB_MCAST_MASK_SIZE / 8); + + if (p_tbl->p_mask_tbl == NULL) + return (IB_INSUFFICIENT_MEMORY); + + memset(p_tbl->p_mask_tbl, 0, + p_tbl->num_entries * (IB_MCAST_POSITION_MAX + + 1) * IB_MCAST_MASK_SIZE / 8); + return (IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +void osm_mcast_tbl_destroy(IN osm_mcast_tbl_t * const p_tbl) +{ + free(p_tbl->p_mask_tbl); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcast_tbl_set(IN osm_mcast_tbl_t * const p_tbl, + IN const uint16_t mlid_ho, IN const uint8_t port) +{ + uintn_t mlid_offset; + uintn_t mask_offset; + uintn_t bit_mask; + int16_t block_num; + + CL_ASSERT(p_tbl); + CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO); + CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho); + CL_ASSERT(p_tbl->p_mask_tbl); + + mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; + mask_offset = port / IB_MCAST_MASK_SIZE; + bit_mask = cl_ntoh16((uint16_t) (1 << (port % IB_MCAST_MASK_SIZE))); + (*p_tbl->p_mask_tbl)[mlid_offset][mask_offset] |= bit_mask; + + block_num = (int16_t) (mlid_offset / IB_MCAST_BLOCK_SIZE); + + if (block_num > p_tbl->max_block_in_use) + p_tbl->max_block_in_use = (uint16_t) block_num; +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_mcast_tbl_is_port(IN const osm_mcast_tbl_t * const p_tbl, + IN const uint16_t mlid_ho, IN const uint8_t port_num) +{ + uintn_t mlid_offset; + uintn_t mask_offset; + uintn_t bit_mask; + + CL_ASSERT(p_tbl); + + if (p_tbl->p_mask_tbl) { + CL_ASSERT(port_num <= + (p_tbl->max_position + 1) * IB_MCAST_MASK_SIZE); + CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO); + CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho); + + mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; + mask_offset = port_num / IB_MCAST_MASK_SIZE; + bit_mask = cl_ntoh16((uint16_t) + (1 << (port_num % IB_MCAST_MASK_SIZE))); + return (((*p_tbl-> + p_mask_tbl)[mlid_offset][mask_offset] & bit_mask) == + bit_mask); + } + + return (FALSE); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_mcast_tbl_is_any_port(IN const osm_mcast_tbl_t * const p_tbl, + IN const uint16_t mlid_ho) +{ + uintn_t mlid_offset; + uint8_t position; + uint16_t result = 0; + + CL_ASSERT(p_tbl); + + if (p_tbl->p_mask_tbl) { + CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO); + CL_ASSERT(mlid_ho <= p_tbl->max_mlid_ho); + + mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; + + for (position = 0; position <= p_tbl->max_position; position++) + result |= (*p_tbl->p_mask_tbl)[mlid_offset][position]; + } + + return (result != 0); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_mcast_tbl_set_block(IN osm_mcast_tbl_t * const p_tbl, + IN const ib_net16_t * const p_block, + IN const int16_t block_num, IN const uint8_t position) +{ + uint32_t i; + uint16_t mlid_start_ho; + + CL_ASSERT(p_tbl); + CL_ASSERT(p_block); + + if (block_num > p_tbl->max_block) + return (IB_INVALID_PARAMETER); + + if (position > p_tbl->max_position) + return (IB_INVALID_PARAMETER); + + mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE); + + if (mlid_start_ho + IB_MCAST_BLOCK_SIZE - 1 > p_tbl->max_mlid_ho) + return (IB_INVALID_PARAMETER); + + for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++) + (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position] = p_block[i]; + + if (block_num > p_tbl->max_block_in_use) + p_tbl->max_block_in_use = (uint16_t) block_num; + + return (IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +void +osm_mcast_tbl_clear_mlid(IN osm_mcast_tbl_t * const p_tbl, + IN const uint16_t mlid_ho) +{ + uint8_t i; + uintn_t mlid_offset; + + CL_ASSERT(p_tbl); + CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO); + + if (p_tbl->p_mask_tbl && (mlid_ho <= p_tbl->max_mlid_ho)) { + mlid_offset = mlid_ho - IB_LID_MCAST_START_HO; + for (i = 0; i <= p_tbl->max_position; i++) + (*p_tbl->p_mask_tbl)[mlid_offset][i] = 0; + } +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_mcast_tbl_get_block(IN osm_mcast_tbl_t * const p_tbl, + IN int16_t const block_num, + IN uint8_t const position, + OUT ib_net16_t * const p_block) +{ + uint32_t i; + uint16_t mlid_start_ho; + + CL_ASSERT(p_tbl); + CL_ASSERT(p_block); + + if (block_num > p_tbl->max_block_in_use) + return (FALSE); + + if (position > p_tbl->max_position) { + /* + Caller shouldn't do this for efficiency's sake... + */ + memset(p_block, 0, IB_SMP_DATA_SIZE); + return (TRUE); + } + + mlid_start_ho = (uint16_t) (block_num * IB_MCAST_BLOCK_SIZE); + + if (mlid_start_ho + IB_MCAST_BLOCK_SIZE - 1 > p_tbl->max_mlid_ho) + return (IB_INVALID_PARAMETER); + + for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++) + p_block[i] = (*p_tbl->p_mask_tbl)[mlid_start_ho + i][position]; + + return (TRUE); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_mcm_info.c b/contrib/ofed/management/opensm/opensm/osm_mcm_info.c new file mode 100644 index 000000000000..0325a34b7cd2 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_mcm_info.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osm_mcm_info_t. + * This object represents a Multicast Forwarding Information object. + * This object is part of the OpenSM family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +/********************************************************************** + **********************************************************************/ +osm_mcm_info_t *osm_mcm_info_new(IN const ib_net16_t mlid) +{ + osm_mcm_info_t *p_mcm; + + p_mcm = (osm_mcm_info_t *) malloc(sizeof(*p_mcm)); + if (p_mcm) { + memset(p_mcm, 0, sizeof(*p_mcm)); + p_mcm->mlid = mlid; + } + + return (p_mcm); +} + +/********************************************************************** + **********************************************************************/ +void osm_mcm_info_delete(IN osm_mcm_info_t * const p_mcm) +{ + free(p_mcm); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_mcm_port.c b/contrib/ofed/management/opensm/opensm/osm_mcm_port.c new file mode 100644 index 000000000000..b6b61495f994 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_mcm_port.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mcm_port_t. + * This object represents the membership of a port in a multicast group. + * This object is part of the OpenSM family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +osm_mcm_port_t *osm_mcm_port_new(IN const ib_gid_t * const p_port_gid, + IN const uint8_t scope_state, + IN const boolean_t proxy_join) +{ + osm_mcm_port_t *p_mcm; + + p_mcm = malloc(sizeof(*p_mcm)); + if (p_mcm) { + memset(p_mcm, 0, sizeof(*p_mcm)); + p_mcm->port_gid = *p_port_gid; + p_mcm->scope_state = scope_state; + p_mcm->proxy_join = proxy_join; + } + + return (p_mcm); +} + +/********************************************************************** + **********************************************************************/ +void osm_mcm_port_delete(IN osm_mcm_port_t * const p_mcm) +{ + CL_ASSERT(p_mcm); + free(p_mcm); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_mtree.c b/contrib/ofed/management/opensm/opensm/osm_mtree.c new file mode 100644 index 000000000000..3832e7dda7b4 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_mtree.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mtree_node_t. + * This file implements the Multicast Tree object. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +static void +osm_mtree_node_init(IN osm_mtree_node_t * const p_mtn, + IN const osm_switch_t * const p_sw) +{ + uint32_t i; + + CL_ASSERT(p_mtn); + CL_ASSERT(p_sw); + + memset(p_mtn, 0, sizeof(*p_mtn)); + + p_mtn->p_sw = (osm_switch_t *) p_sw; + p_mtn->max_children = p_sw->num_ports; + + for (i = 0; i < p_mtn->max_children; i++) + p_mtn->child_array[i] = NULL; +} + +/********************************************************************** + **********************************************************************/ +osm_mtree_node_t *osm_mtree_node_new(IN const osm_switch_t * const p_sw) +{ + osm_mtree_node_t *p_mtn; + + p_mtn = malloc(sizeof(osm_mtree_node_t) + + sizeof(void *) * (p_sw->num_ports - 1)); + + if (p_mtn != NULL) + osm_mtree_node_init(p_mtn, p_sw); + + return (p_mtn); +} + +/********************************************************************** + **********************************************************************/ +void osm_mtree_destroy(IN osm_mtree_node_t * p_mtn) +{ + uint32_t i; + + if (p_mtn == NULL) + return; + + if (p_mtn->child_array != NULL) + for (i = 0; i < p_mtn->max_children; i++) + if ((p_mtn->child_array[i] != NULL) && + (p_mtn->child_array[i] != OSM_MTREE_LEAF)) + osm_mtree_destroy(p_mtn->child_array[i]); + + free(p_mtn); +} + +/********************************************************************** + **********************************************************************/ +#if 0 +static void __osm_mtree_dump(IN osm_mtree_node_t * p_mtn) +{ + uint32_t i; + + if (p_mtn == NULL) + return; + + printf("GUID:0x%016" PRIx64 " max_children:%u\n", + cl_ntoh64(p_mtn->p_sw->p_node->node_info.node_guid), + p_mtn->max_children); + if (p_mtn->child_array != NULL) { + for (i = 0; i < p_mtn->max_children; i++) { + printf("i=%d\n", i); + if ((p_mtn->child_array[i] != NULL) + && (p_mtn->child_array[i] != OSM_MTREE_LEAF)) + __osm_mtree_dump(p_mtn->child_array[i]); + } + } +} +#endif diff --git a/contrib/ofed/management/opensm/opensm/osm_multicast.c b/contrib/ofed/management/opensm/opensm/osm_multicast.c new file mode 100644 index 000000000000..350fd22ea18c --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_multicast.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of multicast functions. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void osm_mgrp_delete(IN osm_mgrp_t * const p_mgrp) +{ + osm_mcm_port_t *p_mcm_port; + osm_mcm_port_t *p_next_mcm_port; + + CL_ASSERT(p_mgrp); + + p_next_mcm_port = + (osm_mcm_port_t *) cl_qmap_head(&p_mgrp->mcm_port_tbl); + while (p_next_mcm_port != + (osm_mcm_port_t *) cl_qmap_end(&p_mgrp->mcm_port_tbl)) { + p_mcm_port = p_next_mcm_port; + p_next_mcm_port = + (osm_mcm_port_t *) cl_qmap_next(&p_mcm_port->map_item); + osm_mcm_port_delete(p_mcm_port); + } + /* destroy the mtree_node structure */ + osm_mtree_destroy(p_mgrp->p_root); + + free(p_mgrp); +} + +/********************************************************************** + **********************************************************************/ +osm_mgrp_t *osm_mgrp_new(IN const ib_net16_t mlid) +{ + osm_mgrp_t *p_mgrp; + + p_mgrp = (osm_mgrp_t *) malloc(sizeof(*p_mgrp)); + if (!p_mgrp) + return NULL; + + memset(p_mgrp, 0, sizeof(*p_mgrp)); + cl_qmap_init(&p_mgrp->mcm_port_tbl); + p_mgrp->mlid = mlid; + p_mgrp->last_change_id = 0; + p_mgrp->last_tree_id = 0; + p_mgrp->to_be_deleted = FALSE; + + return p_mgrp; +} + +/********************************************************************** + **********************************************************************/ +static void mgrp_send_notice(osm_subn_t *subn, osm_log_t *log, + osm_mgrp_t *mgrp, unsigned num) +{ + ib_mad_notice_attr_t notice; + ib_api_status_t status; + + notice.generic_type = 0x83; /* generic SubnMgt type */ + ib_notice_set_prod_type_ho(¬ice, 4); /* A Class Manager generator */ + notice.g_or_v.generic.trap_num = CL_HTON16(num); + /* The sm_base_lid is saved in network order already. */ + notice.issuer_lid = subn->sm_base_lid; + /* following o14-12.1.11 and table 120 p726 */ + /* we need to provide the MGID */ + memcpy(¬ice.data_details.ntc_64_67.gid, + &mgrp->mcmember_rec.mgid, sizeof(ib_gid_t)); + + /* According to page 653 - the issuer gid in this case of trap + is the SM gid, since the SM is the initiator of this trap. */ + notice.issuer_gid.unicast.prefix = subn->opt.subnet_prefix; + notice.issuer_gid.unicast.interface_id = subn->sm_port_guid; + + if ((status = osm_report_notice(log, subn, ¬ice))) + OSM_LOG(log, OSM_LOG_ERROR, "ERR 7601: " + "Error sending trap reports (%s)\n", + ib_get_err_str(status)); +} + +/********************************************************************** + **********************************************************************/ +osm_mcm_port_t *osm_mgrp_add_port(IN osm_subn_t *subn, osm_log_t *log, + IN osm_mgrp_t * const p_mgrp, + IN const ib_gid_t * const p_port_gid, + IN const uint8_t join_state, + IN boolean_t proxy_join) +{ + ib_net64_t port_guid; + osm_mcm_port_t *p_mcm_port; + cl_map_item_t *prev_item; + uint8_t prev_join_state = 0; + uint8_t prev_scope; + + p_mcm_port = osm_mcm_port_new(p_port_gid, join_state, proxy_join); + if (!p_mcm_port) + return NULL; + + port_guid = p_port_gid->unicast.interface_id; + + /* + prev_item = cl_qmap_insert(...) + Pointer to the item in the map with the specified key. If insertion + was successful, this is the pointer to the item. If an item with the + specified key already exists in the map, the pointer to that item is + returned. + */ + prev_item = cl_qmap_insert(&p_mgrp->mcm_port_tbl, + port_guid, &p_mcm_port->map_item); + + /* if already exists - revert the insertion and only update join state */ + if (prev_item != &p_mcm_port->map_item) { + osm_mcm_port_delete(p_mcm_port); + p_mcm_port = (osm_mcm_port_t *) prev_item; + + /* + o15.0.1.11 + Join state of the end port should be the or of the + previous setting with the current one + */ + ib_member_get_scope_state(p_mcm_port->scope_state, &prev_scope, + &prev_join_state); + p_mcm_port->scope_state = + ib_member_set_scope_state(prev_scope, + prev_join_state | join_state); + } else { + /* track the fact we modified the group ports */ + p_mgrp->last_change_id++; + } + + if ((join_state & IB_JOIN_STATE_FULL) && + !(prev_join_state & IB_JOIN_STATE_FULL) && + (++p_mgrp->full_members == 1)) { + mgrp_send_notice(subn, log, p_mgrp, 66); + p_mgrp->to_be_deleted = 0; + } + + return (p_mcm_port); +} + +/********************************************************************** + **********************************************************************/ +int osm_mgrp_remove_port(osm_subn_t *subn, osm_log_t *log, osm_mgrp_t *mgrp, + osm_mcm_port_t *mcm, uint8_t join_state) +{ + int ret; + uint8_t port_join_state; + uint8_t new_join_state; + + /* + * according to the same o15-0.1.14 we get the stored + * JoinState and the request JoinState and they must be + * opposite to leave - otherwise just update it + */ + port_join_state = mcm->scope_state & 0x0F; + new_join_state = port_join_state & ~join_state; + + if (new_join_state) { + mcm->scope_state = new_join_state | (mcm->scope_state & 0xf0); + OSM_LOG(log, OSM_LOG_DEBUG, + "updating port 0x%" PRIx64 " JoinState 0x%x -> 0x%x\n", + cl_ntoh64(mcm->port_gid.unicast.interface_id), + port_join_state, new_join_state); + ret = 0; + } else { + cl_qmap_remove_item(&mgrp->mcm_port_tbl, &mcm->map_item); + OSM_LOG(log, OSM_LOG_DEBUG, "removing port 0x%" PRIx64 "\n", + cl_ntoh64(mcm->port_gid.unicast.interface_id)); + osm_mcm_port_delete(mcm); + /* track the fact we modified the group */ + mgrp->last_change_id++; + ret = 1; + } + + /* no more full members so the group will be deleted after re-route + but only if it is not a well known group */ + if ((port_join_state & IB_JOIN_STATE_FULL) && + !(new_join_state & IB_JOIN_STATE_FULL) && + (--mgrp->full_members == 0)) { + mgrp_send_notice(subn, log, mgrp, 67); + if (!mgrp->well_known) + mgrp->to_be_deleted = 1; + } + + return ret; +} + +void osm_mgrp_delete_port(osm_subn_t *subn, osm_log_t *log, osm_mgrp_t *mgrp, + ib_net64_t port_guid) +{ + cl_map_item_t *item = cl_qmap_get(&mgrp->mcm_port_tbl, port_guid); + + if (item != cl_qmap_end(&mgrp->mcm_port_tbl)) + osm_mgrp_remove_port(subn, log, mgrp, (osm_mcm_port_t *)item, 0xf); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_mgrp_is_port_present(IN const osm_mgrp_t * const p_mgrp, + IN const ib_net64_t port_guid, + OUT osm_mcm_port_t ** const pp_mcm_port) +{ + cl_map_item_t *p_map_item; + + CL_ASSERT(p_mgrp); + + p_map_item = cl_qmap_get(&p_mgrp->mcm_port_tbl, port_guid); + + if (p_map_item != cl_qmap_end(&p_mgrp->mcm_port_tbl)) { + if (pp_mcm_port) + *pp_mcm_port = (osm_mcm_port_t *) p_map_item; + return TRUE; + } + if (pp_mcm_port) + *pp_mcm_port = NULL; + return FALSE; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_mgrp_apply_func_sub(const osm_mgrp_t * const p_mgrp, + const osm_mtree_node_t * const p_mtn, + osm_mgrp_func_t p_func, void *context) +{ + uint8_t i = 0; + uint8_t max_children; + osm_mtree_node_t *p_child_mtn; + + /* Call the user, then recurse. */ + p_func(p_mgrp, p_mtn, context); + + max_children = osm_mtree_node_get_max_children(p_mtn); + for (i = 0; i < max_children; i++) { + p_child_mtn = osm_mtree_node_get_child(p_mtn, i); + if (p_child_mtn) + __osm_mgrp_apply_func_sub(p_mgrp, p_child_mtn, p_func, + context); + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_mgrp_apply_func(const osm_mgrp_t * const p_mgrp, + osm_mgrp_func_t p_func, void *context) +{ + osm_mtree_node_t *p_mtn; + + CL_ASSERT(p_mgrp); + CL_ASSERT(p_func); + + p_mtn = p_mgrp->p_root; + + if (p_mtn) + __osm_mgrp_apply_func_sub(p_mgrp, p_mtn, p_func, context); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_node.c b/contrib/ofed/management/opensm/opensm/osm_node.c new file mode 100644 index 000000000000..07371a2f799a --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_node.c @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_node_t. + * This object represents an Infiniband Node. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void +osm_node_init_physp(IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw) +{ + ib_net64_t port_guid; + ib_smp_t *p_smp; + ib_node_info_t *p_ni; + uint8_t port_num; + + p_smp = osm_madw_get_smp_ptr(p_madw); + + p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp); + port_guid = p_ni->port_guid; + port_num = ib_node_info_get_local_port_num(p_ni); + + CL_ASSERT(port_num < p_node->physp_tbl_size); + + osm_physp_init(&p_node->physp_table[port_num], + port_guid, port_num, p_node, + osm_madw_get_bind_handle(p_madw), + p_smp->hop_count, p_smp->initial_path); +} + +/********************************************************************** + **********************************************************************/ +static void node_init_physp0(IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw) +{ + ib_smp_t *p_smp; + ib_node_info_t *p_ni; + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp); + + osm_physp_init(&p_node->physp_table[0], + p_ni->port_guid, 0, p_node, + osm_madw_get_bind_handle(p_madw), + p_smp->hop_count, p_smp->initial_path); +} + +/********************************************************************** + **********************************************************************/ +osm_node_t *osm_node_new(IN const osm_madw_t * const p_madw) +{ + osm_node_t *p_node; + ib_smp_t *p_smp; + ib_node_info_t *p_ni; + uint8_t i; + uint32_t size; + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp); + + /* + The node object already contains one physical port object. + Therefore, subtract 1 from the number of physical ports + used by the switch. This is not done for CA's since they + need to occupy 1 more physp than they physically have since + we still reserve room for a "port 0". + */ + size = p_ni->num_ports; + + p_node = malloc(sizeof(*p_node) + sizeof(osm_physp_t) * size); + if (!p_node) + return NULL; + + memset(p_node, 0, sizeof(*p_node) + sizeof(osm_physp_t) * size); + p_node->node_info = *p_ni; + p_node->physp_tbl_size = size + 1; + + /* + Construct Physical Port objects owned by this Node. + Then, initialize the Physical Port through with we + discovered this port. + For switches, all ports have the same GUID. + For CAs and routers, each port has a different GUID, so we only + know the GUID for the port that responded to our + Get(NodeInfo). + */ + for (i = 0; i < p_node->physp_tbl_size; i++) + osm_physp_construct(&p_node->physp_table[i]); + + osm_node_init_physp(p_node, p_madw); + if (p_ni->node_type == IB_NODE_TYPE_SWITCH) + node_init_physp0(p_node, p_madw); + p_node->print_desc = strdup(OSM_NODE_DESC_UNKNOWN); + + return (p_node); +} + +/********************************************************************** + **********************************************************************/ +static void osm_node_destroy(IN osm_node_t * p_node) +{ + uint16_t i; + + /* + Cleanup all physports + */ + for (i = 0; i < p_node->physp_tbl_size; i++) + osm_physp_destroy(&p_node->physp_table[i]); + + /* cleanup printable node_desc field */ + if (p_node->print_desc) { + free(p_node->print_desc); + } +} + +/********************************************************************** + **********************************************************************/ +void osm_node_delete(IN OUT osm_node_t ** const p_node) +{ + CL_ASSERT(p_node && *p_node); + osm_node_destroy(*p_node); + free(*p_node); + *p_node = NULL; +} + +/********************************************************************** + **********************************************************************/ +void +osm_node_link(IN osm_node_t * const p_node, + IN const uint8_t port_num, + IN osm_node_t * const p_remote_node, + IN const uint8_t remote_port_num) +{ + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + + CL_ASSERT(port_num < p_node->physp_tbl_size); + CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size); + + p_physp = osm_node_get_physp_ptr(p_node, port_num); + p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num); + + if (p_physp->p_remote_physp) + p_physp->p_remote_physp->p_remote_physp = NULL; + if (p_remote_physp->p_remote_physp) + p_remote_physp->p_remote_physp->p_remote_physp = NULL; + + osm_physp_link(p_physp, p_remote_physp); +} + +/********************************************************************** + **********************************************************************/ +void +osm_node_unlink(IN osm_node_t * const p_node, + IN const uint8_t port_num, + IN osm_node_t * const p_remote_node, + IN const uint8_t remote_port_num) +{ + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + + CL_ASSERT(port_num < p_node->physp_tbl_size); + CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size); + + if (osm_node_link_exists(p_node, port_num, + p_remote_node, remote_port_num)) { + + p_physp = osm_node_get_physp_ptr(p_node, port_num); + p_remote_physp = + osm_node_get_physp_ptr(p_remote_node, remote_port_num); + + osm_physp_unlink(p_physp, p_remote_physp); + } +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_node_link_exists(IN osm_node_t * const p_node, + IN const uint8_t port_num, + IN osm_node_t * const p_remote_node, + IN const uint8_t remote_port_num) +{ + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + + CL_ASSERT(port_num < p_node->physp_tbl_size); + CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size); + + p_physp = osm_node_get_physp_ptr(p_node, port_num); + p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num); + + return (osm_physp_link_exists(p_physp, p_remote_physp)); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_node_link_has_valid_ports(IN osm_node_t * const p_node, + IN const uint8_t port_num, + IN osm_node_t * const p_remote_node, + IN const uint8_t remote_port_num) +{ + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + + CL_ASSERT(port_num < p_node->physp_tbl_size); + CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size); + + p_physp = osm_node_get_physp_ptr(p_node, port_num); + p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num); + + return (p_physp && p_remote_physp); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_node_has_any_link(IN osm_node_t * const p_node, IN const uint8_t port_num) +{ + osm_physp_t *p_physp; + CL_ASSERT(port_num < p_node->physp_tbl_size); + p_physp = osm_node_get_physp_ptr(p_node, port_num); + return (osm_physp_has_any_link(p_physp)); +} + +/********************************************************************** + **********************************************************************/ +osm_node_t *osm_node_get_remote_node(IN osm_node_t * const p_node, + IN const uint8_t port_num, + OUT uint8_t * p_remote_port_num) +{ + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + + p_physp = osm_node_get_physp_ptr(p_node, port_num); + + if (!p_physp || !osm_physp_has_any_link(p_physp)) + return (NULL); + + p_remote_physp = osm_physp_get_remote(p_physp); + if (p_remote_port_num) + *p_remote_port_num = osm_physp_get_port_num(p_remote_physp); + + return (osm_physp_get_node_ptr(p_remote_physp)); +} + +/********************************************************************** + The lock must be held before calling this function. +**********************************************************************/ +ib_net16_t +osm_node_get_remote_base_lid(IN osm_node_t * const p_node, + IN const uint32_t port_num) +{ + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + CL_ASSERT(port_num < p_node->physp_tbl_size); + + p_physp = osm_node_get_physp_ptr(p_node, port_num); + if (p_physp) { + p_remote_physp = osm_physp_get_remote(p_physp); + return (osm_physp_get_base_lid(p_remote_physp)); + } + + return (0); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_node_desc_rcv.c b/contrib/ofed/management/opensm/opensm/osm_node_desc_rcv.c new file mode 100644 index 000000000000..f6178b972fe1 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_node_desc_rcv.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_nd_rcv_t. + * This object represents the NodeDescription Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +static void +__osm_nd_rcv_process_nd(IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN const ib_node_desc_t * const p_nd) +{ + char *tmp_desc; + char print_desc[IB_NODE_DESCRIPTION_SIZE + 1]; + + OSM_LOG_ENTER(sm->p_log); + + memcpy(&p_node->node_desc.description, p_nd, sizeof(*p_nd)); + + /* also set up a printable version */ + memcpy(print_desc, p_nd, sizeof(*p_nd)); + print_desc[IB_NODE_DESCRIPTION_SIZE] = '\0'; + tmp_desc = remap_node_name(sm->p_subn->p_osm->node_name_map, + cl_ntoh64(osm_node_get_node_guid(p_node)), + print_desc); + + /* make a copy for this node to "own" */ + if (p_node->print_desc) + free(p_node->print_desc); + p_node->print_desc = tmp_desc; + + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Node 0x%" PRIx64 "\n\t\t\t\tDescription = %s\n", + cl_ntoh64(osm_node_get_node_guid(p_node)), p_node->print_desc); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_nd_rcv_process(IN void *context, IN void *data) +{ + osm_sm_t *sm = context; + osm_madw_t *p_madw = data; + ib_node_desc_t *p_nd; + ib_smp_t *p_smp; + osm_node_t *p_node; + ib_net64_t node_guid; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_nd = (ib_node_desc_t *) ib_smp_get_payload_ptr(p_smp); + + /* + Acquire the node object and add the node description. + */ + + node_guid = osm_madw_get_nd_context_ptr(p_madw)->node_guid; + CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); + p_node = osm_get_node_by_guid(sm->p_subn, node_guid); + if (!p_node) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0B01: " + "NodeDescription received for nonexistent node " + "0x%" PRIx64 "\n", cl_ntoh64(node_guid)); + } else { + __osm_nd_rcv_process_nd(sm, p_node, p_nd); + } + + CL_PLOCK_RELEASE(sm->p_lock); + OSM_LOG_EXIT(sm->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_node_info_rcv.c b/contrib/ofed/management/opensm/opensm/osm_node_info_rcv.c new file mode 100644 index 000000000000..c52c0d5343f7 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_node_info_rcv.c @@ -0,0 +1,849 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_ni_rcv_t. + * This object represents the NodeInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +report_duplicated_guid(IN osm_sm_t * sm, + osm_physp_t * p_physp, + osm_node_t * p_neighbor_node, const uint8_t port_num) +{ + osm_physp_t *p_old, *p_new; + osm_dr_path_t path; + + p_old = p_physp->p_remote_physp; + p_new = osm_node_get_physp_ptr(p_neighbor_node, port_num); + + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D01: " + "Found duplicated node.\n" + "Node 0x%" PRIx64 " port %u is reachable from remote node " + "0x%" PRIx64 " port %u and remote node 0x%" PRIx64 " port %u.\n" + "Paths are:\n", + cl_ntoh64(p_physp->p_node->node_info.node_guid), + p_physp->port_num, + cl_ntoh64(p_old->p_node->node_info.node_guid), p_old->port_num, + cl_ntoh64(p_new->p_node->node_info.node_guid), p_new->port_num); + + osm_dump_dr_path(sm->p_log, osm_physp_get_dr_path_ptr(p_physp), + OSM_LOG_ERROR); + + path = *osm_physp_get_dr_path_ptr(p_new); + osm_dr_path_extend(&path, port_num); + osm_dump_dr_path(sm->p_log, &path, OSM_LOG_ERROR); + + osm_log(sm->p_log, OSM_LOG_SYS, + "FATAL: duplicated guids or 12x lane reversal\n"); +} + +static void requery_dup_node_info(IN osm_sm_t * sm, + osm_physp_t * p_physp, unsigned count) +{ + osm_madw_context_t context; + osm_dr_path_t path; + cl_status_t status; + + path = *osm_physp_get_dr_path_ptr(p_physp->p_remote_physp); + osm_dr_path_extend(&path, p_physp->p_remote_physp->port_num); + + context.ni_context.node_guid = + p_physp->p_remote_physp->p_node->node_info.port_guid; + context.ni_context.port_num = p_physp->p_remote_physp->port_num; + context.ni_context.dup_node_guid = p_physp->p_node->node_info.node_guid; + context.ni_context.dup_port_num = p_physp->port_num; + context.ni_context.dup_count = count; + + status = osm_req_get(sm, &path, IB_MAD_ATTR_NODE_INFO, + 0, CL_DISP_MSGID_NONE, &context); + + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D02: " + "Failure initiating NodeInfo request (%s)\n", + ib_get_err_str(status)); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_set_links(IN osm_sm_t * sm, + osm_node_t * p_node, + const uint8_t port_num, + const osm_ni_context_t * const p_ni_context) +{ + osm_node_t *p_neighbor_node; + osm_physp_t *p_physp; + + OSM_LOG_ENTER(sm->p_log); + + /* + A special case exists in which the node we're trying to + link is our own node. In this case, the guid value in + the ni_context will be zero. + */ + if (p_ni_context->node_guid == 0) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Nothing to link for our own node 0x%" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(p_node))); + goto _exit; + } + + p_neighbor_node = osm_get_node_by_guid(sm->p_subn, + p_ni_context->node_guid); + if (!p_neighbor_node) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D10: " + "Unexpected removal of neighbor node " + "0x%" PRIx64 "\n", cl_ntoh64(p_ni_context->node_guid)); + goto _exit; + } + + /* + We have seen this neighbor node before, but we might + not have seen this port on the neighbor node before. + We should not set links to an uninitialized port on the + neighbor, so check validity up front. If it's not + valid, do nothing, since we'll see this link again + when we probe the neighbor. + */ + if (!osm_node_link_has_valid_ports(p_node, port_num, + p_neighbor_node, + p_ni_context->port_num)) + goto _exit; + + if (osm_node_link_exists(p_node, port_num, + p_neighbor_node, p_ni_context->port_num)) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Link already exists\n"); + goto _exit; + } + + if (osm_node_has_any_link(p_node, port_num) && + sm->p_subn->force_heavy_sweep == FALSE && + (!p_ni_context->dup_count || + (p_ni_context->dup_node_guid == osm_node_get_node_guid(p_node) && + p_ni_context->dup_port_num == port_num))) { + /* + Uh oh... + This could be reconnected ports, but also duplicated GUID + (2 nodes have the same guid) or a 12x link with lane reversal + that is not configured correctly. + We will try to recover by querying NodeInfo again. + In order to catch even fast port moving to new location(s) and + back we will count up to 5. + Some crazy reconnections (newly created switch loop right before + targeted CA) will not be catched this way. So in worst case - + report GUID duplication and request new discovery. + When switch node is targeted NodeInfo querying will be done in + opposite order, this is much stronger check, unfortunately it is + impossible with CAs. + */ + p_physp = osm_node_get_physp_ptr(p_node, port_num); + if (p_ni_context->dup_count > 5) { + report_duplicated_guid(sm, p_physp, + p_neighbor_node, + p_ni_context->port_num); + sm->p_subn->force_heavy_sweep = TRUE; + } else if (p_node->sw) + requery_dup_node_info(sm, p_physp->p_remote_physp, + p_ni_context->dup_count + 1); + else + requery_dup_node_info(sm, p_physp, + p_ni_context->dup_count + 1); + } + + /* + When there are only two nodes with exact same guids (connected back + to back) - the previous check for duplicated guid will not catch + them. But the link will be from the port to itself... + Enhanced Port 0 is an exception to this + */ + if ((osm_node_get_node_guid(p_node) == p_ni_context->node_guid) && + (port_num == p_ni_context->port_num) && + port_num != 0 && cl_qmap_count(&sm->p_subn->sw_guid_tbl) == 0) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Duplicate GUID found by link from a port to itself:" + "node 0x%" PRIx64 ", port number %u\n", + cl_ntoh64(osm_node_get_node_guid(p_node)), port_num); + p_physp = osm_node_get_physp_ptr(p_node, port_num); + osm_dump_dr_path(sm->p_log, + osm_physp_get_dr_path_ptr(p_physp), + OSM_LOG_VERBOSE); + + if (sm->p_subn->opt.exit_on_fatal == TRUE) { + osm_log(sm->p_log, OSM_LOG_SYS, + "Errors on subnet. Duplicate GUID found " + "by link from a port to itself. " + "See verbose opensm.log for more details\n"); + exit(1); + } + } + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Creating new link between:\n\t\t\t\tnode 0x%" PRIx64 + ", port number %u and\n\t\t\t\tnode 0x%" PRIx64 + ", port number %u\n", + cl_ntoh64(osm_node_get_node_guid(p_node)), port_num, + cl_ntoh64(p_ni_context->node_guid), p_ni_context->port_num); + + if (sm->ucast_mgr.cache_valid) + osm_ucast_cache_check_new_link(&sm->ucast_mgr, + p_node, port_num, + p_neighbor_node, + p_ni_context->port_num); + + osm_node_link(p_node, port_num, p_neighbor_node, + p_ni_context->port_num); + +_exit: + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_process_new_node(IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw) +{ + ib_api_status_t status = IB_SUCCESS; + osm_madw_context_t context; + osm_physp_t *p_physp; + ib_node_info_t *p_ni; + ib_smp_t *p_smp; + uint8_t port_num; + + OSM_LOG_ENTER(sm->p_log); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp); + port_num = ib_node_info_get_local_port_num(p_ni); + + /* + Request PortInfo & NodeDescription attributes for the port + that responded to the NodeInfo attribute. + Because this is a channel adapter or router, we are + not allowed to request PortInfo for the other ports. + Set the context union properly, so the recipient + knows which node & port are relevant. + */ + p_physp = osm_node_get_physp_ptr(p_node, port_num); + + context.pi_context.node_guid = p_ni->node_guid; + context.pi_context.port_guid = p_ni->port_guid; + context.pi_context.set_method = FALSE; + context.pi_context.light_sweep = FALSE; + context.pi_context.active_transition = FALSE; + + status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp), + IB_MAD_ATTR_PORT_INFO, + cl_hton32(port_num), CL_DISP_MSGID_NONE, &context); + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D02: " + "Failure initiating PortInfo request (%s)\n", + ib_get_err_str(status)); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +void +osm_req_get_node_desc(IN osm_sm_t * sm, + osm_physp_t *p_physp) +{ + ib_api_status_t status = IB_SUCCESS; + osm_madw_context_t context; + + OSM_LOG_ENTER(sm->p_log); + + context.nd_context.node_guid = + osm_node_get_node_guid(osm_physp_get_node_ptr(p_physp)); + + status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp), + IB_MAD_ATTR_NODE_DESC, + 0, CL_DISP_MSGID_NONE, &context); + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D03: " + "Failure initiating NodeDescription request (%s)\n", + ib_get_err_str(status)); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_get_node_desc(IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw) +{ + ib_node_info_t *p_ni; + ib_smp_t *p_smp; + uint8_t port_num; + osm_physp_t *p_physp = NULL; + + OSM_LOG_ENTER(sm->p_log); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp); + port_num = ib_node_info_get_local_port_num(p_ni); + + /* + Request PortInfo & NodeDescription attributes for the port + that responded to the NodeInfo attribute. + Because this is a channel adapter or router, we are + not allowed to request PortInfo for the other ports. + Set the context union properly, so the recipient + knows which node & port are relevant. + */ + p_physp = osm_node_get_physp_ptr(p_node, port_num); + + osm_req_get_node_desc(sm, p_physp); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_process_new_ca_or_router(IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw) +{ + OSM_LOG_ENTER(sm->p_log); + + __osm_ni_rcv_process_new_node(sm, p_node, p_madw); + + /* + A node guid of 0 is the corner case that indicates + we discovered our own node. Initialize the subnet + object with the SM's own port guid. + */ + if (osm_madw_get_ni_context_ptr(p_madw)->node_guid == 0) + sm->p_subn->sm_port_guid = p_node->node_info.port_guid; + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_process_existing_ca_or_router(IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw) +{ + ib_node_info_t *p_ni; + ib_smp_t *p_smp; + osm_port_t *p_port; + osm_port_t *p_port_check; + osm_madw_context_t context; + uint8_t port_num; + osm_physp_t *p_physp; + ib_api_status_t status; + osm_dr_path_t *p_dr_path; + osm_bind_handle_t h_bind; + + OSM_LOG_ENTER(sm->p_log); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp); + port_num = ib_node_info_get_local_port_num(p_ni); + h_bind = osm_madw_get_bind_handle(p_madw); + + /* + Determine if we have encountered this node through a + previously undiscovered port. If so, build the new + port object. + */ + p_port = osm_get_port_by_guid(sm->p_subn, p_ni->port_guid); + if (!p_port) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Creating new port object with GUID 0x%" PRIx64 "\n", + cl_ntoh64(p_ni->port_guid)); + + osm_node_init_physp(p_node, p_madw); + + p_port = osm_port_new(p_ni, p_node); + if (p_port == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D04: " + "Unable to create new port object\n"); + goto Exit; + } + + /* + Add the new port object to the database. + */ + p_port_check = + (osm_port_t *) cl_qmap_insert(&sm->p_subn->port_guid_tbl, + p_ni->port_guid, + &p_port->map_item); + if (p_port_check != p_port) { + /* + We should never be here! + Somehow, this port GUID already exists in the table. + */ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D12: " + "Port 0x%" PRIx64 " already in the database!\n", + cl_ntoh64(p_ni->port_guid)); + + osm_port_delete(&p_port); + goto Exit; + } + + /* If we are a master, then this means the port is new on the subnet. + Mark it as new - need to send trap 64 on these ports. + The condition that we are master is true, since if we are in discovering + state (meaning we woke up from standby or we are just initializing), + then these ports may be new to us, but are not new on the subnet. + If we are master, then the subnet as we know it is the updated one, + and any new ports we encounter should cause trap 64. C14-72.1.1 */ + if (sm->p_subn->sm_state == IB_SMINFO_STATE_MASTER) + p_port->is_new = 1; + + p_physp = osm_node_get_physp_ptr(p_node, port_num); + } else { + p_physp = osm_node_get_physp_ptr(p_node, port_num); + /* + Update the DR Path to the port, + in case the old one is no longer available. + */ + p_dr_path = osm_physp_get_dr_path_ptr(p_physp); + + osm_dr_path_init(p_dr_path, h_bind, p_smp->hop_count, + p_smp->initial_path); + } + + context.pi_context.node_guid = p_ni->node_guid; + context.pi_context.port_guid = p_ni->port_guid; + context.pi_context.set_method = FALSE; + context.pi_context.light_sweep = FALSE; + + status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp), + IB_MAD_ATTR_PORT_INFO, + cl_hton32(port_num), CL_DISP_MSGID_NONE, &context); + + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D13: " + "Failure initiating PortInfo request (%s)\n", + ib_get_err_str(status)); + +Exit: + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_ni_rcv_process_switch(IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw) +{ + ib_api_status_t status = IB_SUCCESS; + osm_madw_context_t context; + osm_dr_path_t *path; + ib_smp_t *p_smp; + + OSM_LOG_ENTER(sm->p_log); + + p_smp = osm_madw_get_smp_ptr(p_madw); + + /* update DR path of already initialized switch port 0 */ + path = osm_physp_get_dr_path_ptr(osm_node_get_physp_ptr(p_node, 0)); + osm_dr_path_init(path, osm_madw_get_bind_handle(p_madw), + p_smp->hop_count, p_smp->initial_path); + + context.si_context.node_guid = osm_node_get_node_guid(p_node); + context.si_context.set_method = FALSE; + context.si_context.light_sweep = FALSE; + + /* Request a SwitchInfo attribute */ + status = osm_req_get(sm, path, IB_MAD_ATTR_SWITCH_INFO, + 0, CL_DISP_MSGID_NONE, &context); + if (status != IB_SUCCESS) + /* continue despite error */ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D06: " + "Failure initiating SwitchInfo request (%s)\n", + ib_get_err_str(status)); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_process_existing_switch(IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw) +{ + OSM_LOG_ENTER(sm->p_log); + + /* + If this switch has already been probed during this sweep, + then don't bother reprobing it. + There is one exception - if the node has been visited, but + for some reason we don't have the switch object (this can happen + if the SwitchInfo mad didn't reach the SM) then we want + to retry to probe the switch. + */ + if (p_node->discovery_count == 1) + __osm_ni_rcv_process_switch(sm, p_node, p_madw); + else if (!p_node->sw || p_node->sw->discovery_count == 0) { + /* we don't have the SwitchInfo - retry to get it */ + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Retry to get SwitchInfo on node GUID:0x%" + PRIx64 "\n", cl_ntoh64(osm_node_get_node_guid(p_node))); + __osm_ni_rcv_process_switch(sm, p_node, p_madw); + } + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_process_new_switch(IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw) +{ + OSM_LOG_ENTER(sm->p_log); + + __osm_ni_rcv_process_switch(sm, p_node, p_madw); + + /* + A node guid of 0 is the corner case that indicates + we discovered our own node. Initialize the subnet + object with the SM's own port guid. + */ + if (osm_madw_get_ni_context_ptr(p_madw)->node_guid == 0) + sm->p_subn->sm_port_guid = p_node->node_info.port_guid; + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + The plock must NOT be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_process_new(IN osm_sm_t * sm, + IN const osm_madw_t * const p_madw) +{ + osm_node_t *p_node; + osm_node_t *p_node_check; + osm_port_t *p_port; + osm_port_t *p_port_check; + osm_router_t *p_rtr = NULL; + osm_router_t *p_rtr_check; + cl_qmap_t *p_rtr_guid_tbl; + ib_node_info_t *p_ni; + ib_smp_t *p_smp; + osm_ni_context_t *p_ni_context; + uint8_t port_num; + + OSM_LOG_ENTER(sm->p_log); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp); + p_ni_context = osm_madw_get_ni_context_ptr(p_madw); + port_num = ib_node_info_get_local_port_num(p_ni); + + osm_dump_smp_dr_path(sm->p_log, p_smp, OSM_LOG_VERBOSE); + + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Discovered new %s node," + "\n\t\t\t\tGUID 0x%" PRIx64 ", TID 0x%" PRIx64 "\n", + ib_get_node_type_str(p_ni->node_type), + cl_ntoh64(p_ni->node_guid), cl_ntoh64(p_smp->trans_id)); + + p_node = osm_node_new(p_madw); + if (p_node == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D07: " + "Unable to create new node object\n"); + goto Exit; + } + + /* + Create a new port object to represent this node's physical + ports in the port table. + */ + p_port = osm_port_new(p_ni, p_node); + if (p_port == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D14: " + "Unable to create new port object\n"); + osm_node_delete(&p_node); + goto Exit; + } + + /* + Add the new port object to the database. + */ + p_port_check = + (osm_port_t *) cl_qmap_insert(&sm->p_subn->port_guid_tbl, + p_ni->port_guid, &p_port->map_item); + if (p_port_check != p_port) { + /* + We should never be here! + Somehow, this port GUID already exists in the table. + */ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D15: " + "Duplicate Port GUID 0x%" PRIx64 + "! Found by the two directed routes:\n", + cl_ntoh64(p_ni->port_guid)); + osm_dump_dr_path(sm->p_log, + osm_physp_get_dr_path_ptr(p_port->p_physp), + OSM_LOG_ERROR); + osm_dump_dr_path(sm->p_log, + osm_physp_get_dr_path_ptr(p_port_check-> + p_physp), + OSM_LOG_ERROR); + osm_port_delete(&p_port); + osm_node_delete(&p_node); + goto Exit; + } + + /* If we are a master, then this means the port is new on the subnet. + Mark it as new - need to send trap 64 on these ports. + The condition that we are master is true, since if we are in discovering + state (meaning we woke up from standby or we are just initializing), + then these ports may be new to us, but are not new on the subnet. + If we are master, then the subnet as we know it is the updated one, + and any new ports we encounter should cause trap 64. C14-72.1.1 */ + if (sm->p_subn->sm_state == IB_SMINFO_STATE_MASTER) + p_port->is_new = 1; + + /* If there were RouterInfo or other router attribute, + this would be elsewhere */ + if (p_ni->node_type == IB_NODE_TYPE_ROUTER) { + if ((p_rtr = osm_router_new(p_port)) == NULL) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D1A: " + "Unable to create new router object\n"); + else { + p_rtr_guid_tbl = &sm->p_subn->rtr_guid_tbl; + p_rtr_check = + (osm_router_t *) cl_qmap_insert(p_rtr_guid_tbl, + p_ni->port_guid, + &p_rtr->map_item); + if (p_rtr_check != p_rtr) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D1B: " + "Unable to add port GUID:0x%016" PRIx64 + " to router table\n", + cl_ntoh64(p_ni->port_guid)); + } + } + + p_node_check = + (osm_node_t *) cl_qmap_insert(&sm->p_subn->node_guid_tbl, + p_ni->node_guid, &p_node->map_item); + if (p_node_check != p_node) { + /* + This node must have been inserted by another thread. + This is unexpected, but is not an error. + We can simply clean-up, since the other thread will + see this processing through to completion. + */ + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Discovery race detected at node 0x%" PRIx64 "\n", + cl_ntoh64(p_ni->node_guid)); + osm_node_delete(&p_node); + p_node = p_node_check; + __osm_ni_rcv_set_links(sm, p_node, port_num, p_ni_context); + goto Exit; + } else + __osm_ni_rcv_set_links(sm, p_node, port_num, p_ni_context); + + p_node->discovery_count++; + __osm_ni_rcv_get_node_desc(sm, p_node, p_madw); + + switch (p_ni->node_type) { + case IB_NODE_TYPE_CA: + case IB_NODE_TYPE_ROUTER: + __osm_ni_rcv_process_new_ca_or_router(sm, p_node, p_madw); + break; + case IB_NODE_TYPE_SWITCH: + __osm_ni_rcv_process_new_switch(sm, p_node, p_madw); + break; + default: + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D16: " + "Unknown node type %u with GUID 0x%" PRIx64 "\n", + p_ni->node_type, cl_ntoh64(p_ni->node_guid)); + break; + } + +Exit: + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_ni_rcv_process_existing(IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw) +{ + ib_node_info_t *p_ni; + ib_smp_t *p_smp; + osm_ni_context_t *p_ni_context; + uint8_t port_num; + + OSM_LOG_ENTER(sm->p_log); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp); + p_ni_context = osm_madw_get_ni_context_ptr(p_madw); + port_num = ib_node_info_get_local_port_num(p_ni); + + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Rediscovered %s node 0x%" PRIx64 " TID 0x%" PRIx64 + ", discovered %u times already\n", + ib_get_node_type_str(p_ni->node_type), + cl_ntoh64(p_ni->node_guid), + cl_ntoh64(p_smp->trans_id), p_node->discovery_count); + + /* + If we haven't already encountered this existing node + on this particular sweep, then process further. + */ + p_node->discovery_count++; + + switch (p_ni->node_type) { + case IB_NODE_TYPE_CA: + case IB_NODE_TYPE_ROUTER: + __osm_ni_rcv_process_existing_ca_or_router(sm, p_node, + p_madw); + break; + + case IB_NODE_TYPE_SWITCH: + __osm_ni_rcv_process_existing_switch(sm, p_node, p_madw); + break; + + default: + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D09: " + "Unknown node type %u with GUID 0x%" PRIx64 "\n", + p_ni->node_type, cl_ntoh64(p_ni->node_guid)); + break; + } + + __osm_ni_rcv_set_links(sm, p_node, port_num, p_ni_context); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_ni_rcv_process(IN void *context, IN void *data) +{ + osm_sm_t *sm = context; + osm_madw_t *p_madw = data; + ib_node_info_t *p_ni; + ib_smp_t *p_smp; + osm_node_t *p_node; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp); + + CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_NODE_INFO); + + if (p_ni->node_guid == 0) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D16: " + "Got Zero Node GUID! Found on the directed route:\n"); + osm_dump_smp_dr_path(sm->p_log, p_smp, OSM_LOG_ERROR); + goto Exit; + } + + if (p_ni->port_guid == 0) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0D17: " + "Got Zero Port GUID! Found on the directed route:\n"); + osm_dump_smp_dr_path(sm->p_log, p_smp, OSM_LOG_ERROR); + goto Exit; + } + + /* + Determine if this node has already been discovered, + and process accordingly. + During processing of this node, hold the shared lock. + */ + + CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); + p_node = osm_get_node_by_guid(sm->p_subn, p_ni->node_guid); + + osm_dump_node_info(sm->p_log, p_ni, OSM_LOG_DEBUG); + + if (!p_node) + __osm_ni_rcv_process_new(sm, p_madw); + else + __osm_ni_rcv_process_existing(sm, p_node, p_madw); + + CL_PLOCK_RELEASE(sm->p_lock); + +Exit: + OSM_LOG_EXIT(sm->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_opensm.c b/contrib/ofed/management/opensm/opensm/osm_opensm.c new file mode 100644 index 000000000000..7de2e5bdcba0 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_opensm.c @@ -0,0 +1,497 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_opensm_t. + * This object represents the opensm super object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct routing_engine_module { + const char *name; + int (*setup) (struct osm_routing_engine *, osm_opensm_t *); +}; + +extern int osm_ucast_minhop_setup(struct osm_routing_engine *, osm_opensm_t *); +extern int osm_ucast_updn_setup(struct osm_routing_engine *, osm_opensm_t *); +extern int osm_ucast_file_setup(struct osm_routing_engine *, osm_opensm_t *); +extern int osm_ucast_ftree_setup(struct osm_routing_engine *, osm_opensm_t *); +extern int osm_ucast_lash_setup(struct osm_routing_engine *, osm_opensm_t *); +extern int osm_ucast_dor_setup(struct osm_routing_engine *, osm_opensm_t *); + +const static struct routing_engine_module routing_modules[] = { + {"minhop", osm_ucast_minhop_setup}, + {"updn", osm_ucast_updn_setup}, + {"file", osm_ucast_file_setup}, + {"ftree", osm_ucast_ftree_setup}, + {"lash", osm_ucast_lash_setup}, + {"dor", osm_ucast_dor_setup}, + {NULL, NULL} +}; + +/********************************************************************** + **********************************************************************/ +const char *osm_routing_engine_type_str(IN osm_routing_engine_type_t type) +{ + switch (type) { + case OSM_ROUTING_ENGINE_TYPE_NONE: + return "none"; + case OSM_ROUTING_ENGINE_TYPE_MINHOP: + return "minhop"; + case OSM_ROUTING_ENGINE_TYPE_UPDN: + return "updn"; + case OSM_ROUTING_ENGINE_TYPE_FILE: + return "file"; + case OSM_ROUTING_ENGINE_TYPE_FTREE: + return "ftree"; + case OSM_ROUTING_ENGINE_TYPE_LASH: + return "lash"; + case OSM_ROUTING_ENGINE_TYPE_DOR: + return "dor"; + default: + break; + } + return "unknown"; +} + +/********************************************************************** + **********************************************************************/ +osm_routing_engine_type_t osm_routing_engine_type(IN const char *str) +{ + /* For legacy reasons, consider a NULL pointer and the string + * "null" as the minhop routing engine. + */ + if (!str || !strcasecmp(str, "null") + || !strcasecmp(str, "minhop")) + return OSM_ROUTING_ENGINE_TYPE_MINHOP; + else if (!strcasecmp(str, "none")) + return OSM_ROUTING_ENGINE_TYPE_NONE; + else if (!strcasecmp(str, "updn")) + return OSM_ROUTING_ENGINE_TYPE_UPDN; + else if (!strcasecmp(str, "file")) + return OSM_ROUTING_ENGINE_TYPE_FILE; + else if (!strcasecmp(str, "ftree")) + return OSM_ROUTING_ENGINE_TYPE_FTREE; + else if (!strcasecmp(str, "lash")) + return OSM_ROUTING_ENGINE_TYPE_LASH; + else if (!strcasecmp(str, "dor")) + return OSM_ROUTING_ENGINE_TYPE_DOR; + else + return OSM_ROUTING_ENGINE_TYPE_UNKNOWN; +} + +/********************************************************************** + **********************************************************************/ +static void append_routing_engine(osm_opensm_t *osm, + struct osm_routing_engine *routing_engine) +{ + struct osm_routing_engine *r; + + routing_engine->next = NULL; + + if (!osm->routing_engine_list) { + osm->routing_engine_list = routing_engine; + return; + } + + r = osm->routing_engine_list; + while (r->next) + r = r->next; + + r->next = routing_engine; +} + +static void setup_routing_engine(osm_opensm_t *osm, const char *name) +{ + struct osm_routing_engine *re; + const struct routing_engine_module *m; + + for (m = routing_modules; m->name && *m->name; m++) { + if (!strcmp(m->name, name)) { + re = malloc(sizeof(struct osm_routing_engine)); + if (!re) { + OSM_LOG(&osm->log, OSM_LOG_VERBOSE, + "memory allocation failed\n"); + return; + } + memset(re, 0, sizeof(struct osm_routing_engine)); + + re->name = m->name; + if (m->setup(re, osm)) { + OSM_LOG(&osm->log, OSM_LOG_VERBOSE, + "setup of routing" + " engine \'%s\' failed\n", name); + return; + } + OSM_LOG(&osm->log, OSM_LOG_DEBUG, + "\'%s\' routing engine set up\n", re->name); + append_routing_engine(osm, re); + return; + } + } + + OSM_LOG(&osm->log, OSM_LOG_ERROR, + "cannot find or setup routing engine \'%s\'", name); +} + +static void setup_routing_engines(osm_opensm_t *osm, const char *engine_names) +{ + char *name, *str, *p; + + if (!engine_names || !*engine_names) { + setup_routing_engine(osm, "minhop"); + return; + } + + str = strdup(engine_names); + name = strtok_r(str, ", \t\n", &p); + while (name && *name) { + setup_routing_engine(osm, name); + name = strtok_r(NULL, ", \t\n", &p); + } + free(str); + + if (!osm->routing_engine_list) + setup_routing_engine(osm, "minhop"); +} + +/********************************************************************** + **********************************************************************/ +void osm_opensm_construct(IN osm_opensm_t * const p_osm) +{ + memset(p_osm, 0, sizeof(*p_osm)); + p_osm->osm_version = OSM_VERSION; + osm_subn_construct(&p_osm->subn); + osm_sm_construct(&p_osm->sm); + osm_sa_construct(&p_osm->sa); + osm_db_construct(&p_osm->db); + osm_mad_pool_construct(&p_osm->mad_pool); + osm_vl15_construct(&p_osm->vl15); + osm_log_construct(&p_osm->log); +} + +/********************************************************************** + **********************************************************************/ +static void destroy_routing_engines(osm_opensm_t *osm) +{ + struct osm_routing_engine *r, *next; + + next = osm->routing_engine_list; + while (next) { + r = next; + next = r->next; + if (r->delete) + r->delete(r->context); + free(r); + } +} + +/********************************************************************** + **********************************************************************/ +static void destroy_plugins(osm_opensm_t *osm) +{ + osm_epi_plugin_t *p; + /* remove from the list, and destroy it */ + while (!cl_is_qlist_empty(&osm->plugin_list)){ + p = (osm_epi_plugin_t *)cl_qlist_remove_head(&osm->plugin_list); + /* plugin is responsible for freeing its own resources */ + osm_epi_destroy(p); + } +} + +void osm_opensm_destroy(IN osm_opensm_t * const p_osm) +{ + /* in case of shutdown through exit proc - no ^C */ + osm_exit_flag = TRUE; + + /* + * First of all, clear the is_sm bit. + */ + if (p_osm->sm.mad_ctrl.h_bind) + osm_vendor_set_sm(p_osm->sm.mad_ctrl.h_bind, FALSE); + +#ifdef ENABLE_OSM_PERF_MGR + /* Shutdown the PerfMgr */ + osm_perfmgr_shutdown(&p_osm->perfmgr); +#endif /* ENABLE_OSM_PERF_MGR */ + + /* shut down the SA + * - unbind from QP1 messages + */ + osm_sa_shutdown(&p_osm->sa); + + /* shut down the SM + * - make sure the SM sweeper thread exited + * - unbind from QP0 messages + */ + osm_sm_shutdown(&p_osm->sm); + + /* cleanup all messages on VL15 fifo that were not sent yet */ + osm_vl15_shutdown(&p_osm->vl15, &p_osm->mad_pool); + + /* shut down the dispatcher - so no new messages cross */ + cl_disp_shutdown(&p_osm->disp); + + /* dump SA DB */ + osm_sa_db_file_dump(p_osm); + + /* do the destruction in reverse order as init */ + destroy_plugins(p_osm); + destroy_routing_engines(p_osm); + osm_sa_destroy(&p_osm->sa); + osm_sm_destroy(&p_osm->sm); +#ifdef ENABLE_OSM_PERF_MGR + osm_perfmgr_destroy(&p_osm->perfmgr); +#endif /* ENABLE_OSM_PERF_MGR */ + osm_db_destroy(&p_osm->db); + osm_vl15_destroy(&p_osm->vl15, &p_osm->mad_pool); + osm_mad_pool_destroy(&p_osm->mad_pool); + osm_vendor_delete(&p_osm->p_vendor); + osm_subn_destroy(&p_osm->subn); + cl_disp_destroy(&p_osm->disp); +#ifdef HAVE_LIBPTHREAD + pthread_cond_destroy(&p_osm->stats.cond); + pthread_mutex_destroy(&p_osm->stats.mutex); +#else + cl_event_destroy(&p_osm->stats.event); +#endif + close_node_name_map(p_osm->node_name_map); + + cl_plock_destroy(&p_osm->lock); + + osm_log_destroy(&p_osm->log); +} + +static void load_plugins(osm_opensm_t *osm, const char *plugin_names) +{ + osm_epi_plugin_t *epi; + char *p_names, *name, *p; + + p_names = strdup(plugin_names); + name = strtok_r(p_names, " \t\n", &p); + while (name && *name) { + epi = osm_epi_construct(osm, name); + if (!epi) + osm_log(&osm->log, OSM_LOG_ERROR, + "cannot load plugin \'%s\'\n", name); + else + cl_qlist_insert_tail(&osm->plugin_list, &epi->list); + name = strtok_r(NULL, " \t\n", &p); + } + free(p_names); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_opensm_init(IN osm_opensm_t * const p_osm, + IN const osm_subn_opt_t * const p_opt) +{ + ib_api_status_t status; + + /* Can't use log macros here, since we're initializing the log */ + osm_opensm_construct(p_osm); + + if (p_opt->daemon) + p_osm->log.daemon = 1; + + status = osm_log_init_v2(&p_osm->log, p_opt->force_log_flush, + p_opt->log_flags, p_opt->log_file, + p_opt->log_max_size, p_opt->accum_log_file); + if (status != IB_SUCCESS) + return (status); + + /* If there is a log level defined - add the OSM_VERSION to it */ + osm_log(&p_osm->log, + osm_log_get_level(&p_osm->log) & (OSM_LOG_SYS ^ 0xFF), "%s\n", + p_osm->osm_version); + /* Write the OSM_VERSION to the SYS_LOG */ + osm_log(&p_osm->log, OSM_LOG_SYS, "%s\n", p_osm->osm_version); /* Format Waived */ + + OSM_LOG(&p_osm->log, OSM_LOG_FUNCS, "[\n"); /* Format Waived */ + + status = cl_plock_init(&p_osm->lock); + if (status != IB_SUCCESS) + goto Exit; + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_init(&p_osm->stats.mutex, NULL); + pthread_cond_init(&p_osm->stats.cond, NULL); +#else + status = cl_event_init(&p_osm->stats.event, FALSE); + if (status != IB_SUCCESS) + goto Exit; +#endif + + if (p_opt->single_thread) { + OSM_LOG(&p_osm->log, OSM_LOG_INFO, + "Forcing single threaded dispatcher\n"); + status = cl_disp_init(&p_osm->disp, 1, "opensm"); + } else { + /* + * Normal behavior is to initialize the dispatcher with + * one thread per CPU, as specified by a thread count of '0'. + */ + status = cl_disp_init(&p_osm->disp, 0, "opensm"); + } + if (status != IB_SUCCESS) + goto Exit; + + status = osm_subn_init(&p_osm->subn, p_osm, p_opt); + if (status != IB_SUCCESS) + goto Exit; + + p_osm->p_vendor = + osm_vendor_new(&p_osm->log, p_opt->transaction_timeout); + if (p_osm->p_vendor == NULL) { + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + status = osm_mad_pool_init(&p_osm->mad_pool); + if (status != IB_SUCCESS) + goto Exit; + + status = osm_vl15_init(&p_osm->vl15, p_osm->p_vendor, + &p_osm->log, &p_osm->stats, + p_opt->max_wire_smps); + if (status != IB_SUCCESS) + goto Exit; + + /* the DB is in use by the SM and SA so init before */ + status = osm_db_init(&p_osm->db, &p_osm->log); + if (status != IB_SUCCESS) + goto Exit; + + status = osm_sm_init(&p_osm->sm, &p_osm->subn, &p_osm->db, + p_osm->p_vendor, &p_osm->mad_pool, &p_osm->vl15, + &p_osm->log, &p_osm->stats, &p_osm->disp, + &p_osm->lock); + + if (status != IB_SUCCESS) + goto Exit; + + status = osm_sa_init(&p_osm->sm, &p_osm->sa, &p_osm->subn, + p_osm->p_vendor, &p_osm->mad_pool, &p_osm->log, + &p_osm->stats, &p_osm->disp, &p_osm->lock); + + if (status != IB_SUCCESS) + goto Exit; + + cl_qlist_init(&p_osm->plugin_list); + + if (p_opt->event_plugin_name) + load_plugins(p_osm, p_opt->event_plugin_name); + +#ifdef ENABLE_OSM_PERF_MGR + status = osm_perfmgr_init(&p_osm->perfmgr, p_osm, p_opt); + if (status != IB_SUCCESS) + goto Exit; +#endif /* ENABLE_OSM_PERF_MGR */ + + setup_routing_engines(p_osm, p_opt->routing_engine_names); + + p_osm->routing_engine_used = OSM_ROUTING_ENGINE_TYPE_NONE; + + p_osm->node_name_map = open_node_name_map(p_opt->node_name_map_name); + +Exit: + OSM_LOG(&p_osm->log, OSM_LOG_FUNCS, "]\n"); /* Format Waived */ + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_opensm_bind(IN osm_opensm_t * const p_osm, IN const ib_net64_t guid) +{ + ib_api_status_t status; + + OSM_LOG_ENTER(&p_osm->log); + + status = osm_sm_bind(&p_osm->sm, guid); + if (status != IB_SUCCESS) + goto Exit; + + status = osm_sa_bind(&p_osm->sa, guid); + if (status != IB_SUCCESS) + goto Exit; + +#ifdef ENABLE_OSM_PERF_MGR + status = osm_perfmgr_bind(&p_osm->perfmgr, guid); + if (status != IB_SUCCESS) + goto Exit; +#endif /* ENABLE_OSM_PERF_MGR */ + +Exit: + OSM_LOG_EXIT(&p_osm->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +void osm_opensm_report_event(osm_opensm_t *osm, osm_epi_event_id_t event_id, + void *event_data) +{ + cl_list_item_t *item; + + for (item = cl_qlist_head(&osm->plugin_list); + item != cl_qlist_end(&osm->plugin_list); + item = cl_qlist_next(item)) { + osm_epi_plugin_t *p = (osm_epi_plugin_t *)item; + if (p->impl->report) + p->impl->report(p->plugin_data, event_id, event_data); + } +} diff --git a/contrib/ofed/management/opensm/opensm/osm_perfmgr.c b/contrib/ofed/management/opensm/opensm/osm_perfmgr.c new file mode 100644 index 000000000000..f7da2dc5edd1 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_perfmgr.c @@ -0,0 +1,1311 @@ +/* + * Copyright (c) 2007 The Regents of the University of California. + * Copyright (c) 2007-2008 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_perfmgr_t. + * This object implements an IBA performance manager. + * + * Author: + * Ira Weiny, LLNL + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef ENABLE_OSM_PERF_MGR + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_PERFMGR_INITIAL_TID_VALUE 0xcafe + +#if ENABLE_OSM_PERF_MGR_PROFILE +struct { + double fastest_us; + double slowest_us; + double avg_us; + uint64_t num; +} perfmgr_mad_stats = { + fastest_us: DBL_MAX, + slowest_us: DBL_MIN, + avg_us: 0, + num: 0 +}; + +/* diff must be something which can fit in a susecond_t */ +static inline void update_mad_stats(struct timeval *diff) +{ + double new = (diff->tv_sec * 1000000) + diff->tv_usec; + if (new < perfmgr_mad_stats.fastest_us) + perfmgr_mad_stats.fastest_us = new; + if (new > perfmgr_mad_stats.slowest_us) + perfmgr_mad_stats.slowest_us = new; + + perfmgr_mad_stats.avg_us = + ((perfmgr_mad_stats.avg_us * perfmgr_mad_stats.num) + new) + / (perfmgr_mad_stats.num + 1); + perfmgr_mad_stats.num++; +} + +static inline void perfmgr_clear_mad_stats(void) +{ + perfmgr_mad_stats.fastest_us = DBL_MAX; + perfmgr_mad_stats.slowest_us = DBL_MIN; + perfmgr_mad_stats.avg_us = 0; + perfmgr_mad_stats.num = 0; +} + +/* after and diff can be the same struct */ +static inline void diff_time(struct timeval *before, + struct timeval *after, struct timeval *diff) +{ + struct timeval tmp = *after; + if (tmp.tv_usec < before->tv_usec) { + tmp.tv_sec--; + tmp.tv_usec += 1000000; + } + diff->tv_sec = tmp.tv_sec - before->tv_sec; + diff->tv_usec = tmp.tv_usec - before->tv_usec; +} + +#endif + +extern int wait_for_pending_transactions(osm_stats_t * stats); + +/********************************************************************** + * Internal helper functions. + **********************************************************************/ +static inline void __init_monitored_nodes(osm_perfmgr_t * pm) +{ + cl_qmap_init(&pm->monitored_map); + pm->remove_list = NULL; + cl_event_construct(&pm->sig_query); + cl_event_init(&pm->sig_query, FALSE); +} + +static inline void +__mark_for_removal(osm_perfmgr_t * pm, __monitored_node_t * node) +{ + if (pm->remove_list) { + node->next = pm->remove_list; + pm->remove_list = node; + } else { + node->next = NULL; + pm->remove_list = node; + } +} + +static inline void __remove_marked_nodes(osm_perfmgr_t * pm) +{ + while (pm->remove_list) { + __monitored_node_t *next = pm->remove_list->next; + + cl_qmap_remove_item(&(pm->monitored_map), + (cl_map_item_t *) (pm->remove_list)); + + if (pm->remove_list->name) + free(pm->remove_list->name); + free(pm->remove_list); + pm->remove_list = next; + } +} + +static inline void __decrement_outstanding_queries(osm_perfmgr_t * pm) +{ + cl_atomic_dec(&(pm->outstanding_queries)); + cl_event_signal(&(pm->sig_query)); +} + +/********************************************************************** + * Receive the MAD from the vendor layer and post it for processing by + * the dispatcher. + **********************************************************************/ +static void +osm_perfmgr_mad_recv_callback(osm_madw_t * p_madw, void *bind_context, + osm_madw_t * p_req_madw) +{ + osm_perfmgr_t *pm = (osm_perfmgr_t *) bind_context; + + OSM_LOG_ENTER(pm->log); + + osm_madw_copy_context(p_madw, p_req_madw); + osm_mad_pool_put(pm->mad_pool, p_req_madw); + + __decrement_outstanding_queries(pm); + + /* post this message for later processing. */ + if (cl_disp_post(pm->pc_disp_h, OSM_MSG_MAD_PORT_COUNTERS, + (void *)p_madw, NULL, NULL) != CL_SUCCESS) { + OSM_LOG(pm->log, OSM_LOG_ERROR, "ERR 4C01: " + "PerfMgr Dispatcher post failed\n"); + osm_mad_pool_put(pm->mad_pool, p_madw); + } + OSM_LOG_EXIT(pm->log); +} + +/********************************************************************** + * Process MAD send errors. + **********************************************************************/ +static void +osm_perfmgr_mad_send_err_callback(void *bind_context, osm_madw_t * p_madw) +{ + osm_perfmgr_t *pm = (osm_perfmgr_t *) bind_context; + osm_madw_context_t *context = &(p_madw->context); + uint64_t node_guid = context->perfmgr_context.node_guid; + uint8_t port = context->perfmgr_context.port; + cl_map_item_t *p_node; + __monitored_node_t *p_mon_node; + + OSM_LOG_ENTER(pm->log); + + /* go ahead and get the monitored node struct to have the printable + * name if needed in messages + */ + if ((p_node = cl_qmap_get(&(pm->monitored_map), node_guid)) == + cl_qmap_end(&(pm->monitored_map))) { + OSM_LOG(pm->log, OSM_LOG_ERROR, "ERR 4C15: GUID 0x%016" + PRIx64 " not found in monitored map\n", + node_guid); + goto Exit; + } + p_mon_node = (__monitored_node_t *) p_node; + + OSM_LOG(pm->log, OSM_LOG_ERROR, "ERR 4C02: %s (0x%" PRIx64 + ") port %u\n", p_mon_node->name, p_mon_node->guid, port); + + if (pm->subn->opt.perfmgr_redir && p_madw->status == IB_TIMEOUT) { + /* First, find the node in the monitored map */ + cl_plock_acquire(pm->lock); + /* Now, validate port number */ + if (port > p_mon_node->redir_tbl_size) { + cl_plock_release(pm->lock); + OSM_LOG(pm->log, OSM_LOG_ERROR, "ERR 4C16: " + "Invalid port num %u for %s (GUID 0x%016" + PRIx64 ") num ports %u\n", port, p_mon_node->name, + p_mon_node->guid, p_mon_node->redir_tbl_size); + goto Exit; + } + /* Clear redirection info */ + p_mon_node->redir_port[port].redir_lid = 0; + p_mon_node->redir_port[port].redir_qp = 0; + cl_plock_release(pm->lock); + } + +Exit: + osm_mad_pool_put(pm->mad_pool, p_madw); + + __decrement_outstanding_queries(pm); + + OSM_LOG_EXIT(pm->log); +} + +/********************************************************************** + * Bind the PerfMgr to the vendor layer for MAD sends/receives + **********************************************************************/ +ib_api_status_t +osm_perfmgr_bind(osm_perfmgr_t * const pm, const ib_net64_t port_guid) +{ + osm_bind_info_t bind_info; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(pm->log); + + if (pm->bind_handle != OSM_BIND_INVALID_HANDLE) { + OSM_LOG(pm->log, OSM_LOG_ERROR, + "ERR 4C03: Multiple binds not allowed\n"); + status = IB_ERROR; + goto Exit; + } + + bind_info.port_guid = port_guid; + bind_info.mad_class = IB_MCLASS_PERF; + bind_info.class_version = 1; + bind_info.is_responder = FALSE; + bind_info.is_report_processor = FALSE; + bind_info.is_trap_processor = FALSE; + bind_info.recv_q_size = OSM_PM_DEFAULT_QP1_RCV_SIZE; + bind_info.send_q_size = OSM_PM_DEFAULT_QP1_SEND_SIZE; + + OSM_LOG(pm->log, OSM_LOG_VERBOSE, + "Binding to port GUID 0x%" PRIx64 "\n", cl_ntoh64(port_guid)); + + pm->bind_handle = osm_vendor_bind(pm->vendor, + &bind_info, + pm->mad_pool, + osm_perfmgr_mad_recv_callback, + osm_perfmgr_mad_send_err_callback, + pm); + + if (pm->bind_handle == OSM_BIND_INVALID_HANDLE) { + status = IB_ERROR; + OSM_LOG(pm->log, OSM_LOG_ERROR, + "ERR 4C04: Vendor specific bind failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(pm->log); + return (status); +} + +/********************************************************************** + * Unbind the PerfMgr from the vendor layer for MAD sends/receives + **********************************************************************/ +static void osm_perfmgr_mad_unbind(osm_perfmgr_t * const pm) +{ + OSM_LOG_ENTER(pm->log); + if (pm->bind_handle == OSM_BIND_INVALID_HANDLE) { + OSM_LOG(pm->log, OSM_LOG_ERROR, "ERR 4C05: No previous bind\n"); + goto Exit; + } + osm_vendor_unbind(pm->bind_handle); +Exit: + OSM_LOG_EXIT(pm->log); +} + +/********************************************************************** + * Given a monitored node and a port, return the qp + **********************************************************************/ +static ib_net32_t get_qp(__monitored_node_t * mon_node, uint8_t port) +{ + ib_net32_t qp = cl_ntoh32(1); + + if (mon_node && mon_node->redir_tbl_size && + port < mon_node->redir_tbl_size && + mon_node->redir_port[port].redir_lid && + mon_node->redir_port[port].redir_qp) + qp = mon_node->redir_port[port].redir_qp; + + return qp; +} + +/********************************************************************** + * Given a node, a port, and an optional monitored node, + * return the appropriate lid to query that port + **********************************************************************/ +static ib_net16_t +get_lid(osm_node_t * p_node, uint8_t port, __monitored_node_t * mon_node) +{ + if (mon_node && mon_node->redir_tbl_size && + port < mon_node->redir_tbl_size && + mon_node->redir_port[port].redir_lid) + return mon_node->redir_port[port].redir_lid; + + switch (p_node->node_info.node_type) { + case IB_NODE_TYPE_CA: + case IB_NODE_TYPE_ROUTER: + return osm_node_get_base_lid(p_node, port); + case IB_NODE_TYPE_SWITCH: + return osm_node_get_base_lid(p_node, 0); + default: + return 0; + } +} + +/********************************************************************** + * Form and send the Port Counters MAD for a single port. + **********************************************************************/ +static ib_api_status_t +osm_perfmgr_send_pc_mad(osm_perfmgr_t * perfmgr, ib_net16_t dest_lid, + ib_net32_t dest_qp, uint8_t port, uint8_t mad_method, + osm_madw_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + ib_port_counters_t *port_counter = NULL; + ib_perfmgt_mad_t *pm_mad = NULL; + osm_madw_t *p_madw = NULL; + + OSM_LOG_ENTER(perfmgr->log); + + p_madw = + osm_mad_pool_get(perfmgr->mad_pool, perfmgr->bind_handle, + MAD_BLOCK_SIZE, NULL); + if (p_madw == NULL) + return (IB_INSUFFICIENT_MEMORY); + + pm_mad = osm_madw_get_perfmgt_mad_ptr(p_madw); + + /* build the mad */ + pm_mad->header.base_ver = 1; + pm_mad->header.mgmt_class = IB_MCLASS_PERF; + pm_mad->header.class_ver = 1; + pm_mad->header.method = mad_method; + pm_mad->header.status = 0; + pm_mad->header.class_spec = 0; + pm_mad->header.trans_id = + cl_hton64((uint64_t) cl_atomic_inc(&(perfmgr->trans_id))); + pm_mad->header.attr_id = IB_MAD_ATTR_PORT_CNTRS; + pm_mad->header.resv = 0; + pm_mad->header.attr_mod = 0; + + port_counter = (ib_port_counters_t *) & (pm_mad->data); + memset(port_counter, 0, sizeof(*port_counter)); + port_counter->port_select = port; + port_counter->counter_select = 0xFFFF; + + p_madw->mad_addr.dest_lid = dest_lid; + p_madw->mad_addr.addr_type.gsi.remote_qp = dest_qp; + p_madw->mad_addr.addr_type.gsi.remote_qkey = + cl_hton32(IB_QP1_WELL_KNOWN_Q_KEY); + /* FIXME what about other partitions */ + p_madw->mad_addr.addr_type.gsi.pkey_ix = 0; + p_madw->mad_addr.addr_type.gsi.service_level = 0; + p_madw->mad_addr.addr_type.gsi.global_route = FALSE; + p_madw->resp_expected = TRUE; + + if (p_context) + p_madw->context = *p_context; + + status = osm_vendor_send(perfmgr->bind_handle, p_madw, TRUE); + + if (status == IB_SUCCESS) { + /* pause this thread if we have too many outstanding requests */ + cl_atomic_inc(&(perfmgr->outstanding_queries)); + if (perfmgr->outstanding_queries > + perfmgr->max_outstanding_queries) { + perfmgr->sweep_state = PERFMGR_SWEEP_SUSPENDED; + cl_event_wait_on(&perfmgr->sig_query, EVENT_NO_TIMEOUT, + TRUE); + perfmgr->sweep_state = PERFMGR_SWEEP_ACTIVE; + } + } + + OSM_LOG_EXIT(perfmgr->log); + return (status); +} + +/********************************************************************** + * sweep the node_guid_tbl and collect the node guids to be tracked + **********************************************************************/ +static void __collect_guids(cl_map_item_t * const p_map_item, void *context) +{ + osm_node_t *node = (osm_node_t *) p_map_item; + uint64_t node_guid = cl_ntoh64(node->node_info.node_guid); + osm_perfmgr_t *pm = (osm_perfmgr_t *) context; + __monitored_node_t *mon_node = NULL; + uint32_t size; + + OSM_LOG_ENTER(pm->log); + + if (cl_qmap_get(&(pm->monitored_map), node_guid) + == cl_qmap_end(&(pm->monitored_map))) { + /* if not already in our map add it */ + size = node->node_info.num_ports; + mon_node = malloc(sizeof(*mon_node) + sizeof(redir_t) * size); + if (!mon_node) { + OSM_LOG(pm->log, OSM_LOG_ERROR, "PerfMgr: ERR 4C06: " + "malloc failed: not handling node %s" + "(GUID 0x%" PRIx64 ")\n", node->print_desc, node_guid); + goto Exit; + } + memset(mon_node, 0, sizeof(*mon_node) + sizeof(redir_t) * size); + mon_node->guid = node_guid; + mon_node->name = strdup(node->print_desc); + mon_node->redir_tbl_size = size + 1; + cl_qmap_insert(&(pm->monitored_map), node_guid, + (cl_map_item_t *) mon_node); + } + +Exit: + OSM_LOG_EXIT(pm->log); +} + +/********************************************************************** + * query the Port Counters of all the nodes in the subnet. + **********************************************************************/ +static void +__osm_perfmgr_query_counters(cl_map_item_t * const p_map_item, void *context) +{ + ib_api_status_t status = IB_SUCCESS; + uint8_t port = 0, startport = 1; + osm_perfmgr_t *pm = (osm_perfmgr_t *) context; + osm_node_t *node = NULL; + __monitored_node_t *mon_node = (__monitored_node_t *) p_map_item; + osm_madw_context_t mad_context; + uint8_t num_ports = 0; + uint64_t node_guid = 0; + ib_net32_t remote_qp; + + OSM_LOG_ENTER(pm->log); + + cl_plock_acquire(pm->lock); + node = osm_get_node_by_guid(pm->subn, cl_hton64(mon_node->guid)); + if (!node) { + OSM_LOG(pm->log, OSM_LOG_ERROR, + "ERR 4C07: Node \"%s\" (guid 0x%" PRIx64 + ") no longer exists so removing from PerfMgr monitoring\n", + mon_node->name, mon_node->guid); + __mark_for_removal(pm, mon_node); + goto Exit; + } + + num_ports = osm_node_get_num_physp(node); + node_guid = cl_ntoh64(node->node_info.node_guid); + + /* make sure we have a database object ready to store this information */ + if (perfmgr_db_create_entry(pm->db, node_guid, num_ports, + node->print_desc) != + PERFMGR_EVENT_DB_SUCCESS) { + OSM_LOG(pm->log, OSM_LOG_ERROR, + "ERR 4C08: DB create entry failed for 0x%" + PRIx64 " (%s) : %s\n", node_guid, node->print_desc, + strerror(errno)); + goto Exit; + } + + /* if switch, check for enhanced port 0 */ + if (osm_node_get_type(node) == IB_NODE_TYPE_SWITCH && + node->sw && + ib_switch_info_is_enhanced_port0(&node->sw->switch_info)) + startport = 0; + + /* issue the query for each port */ + for (port = startport; port < num_ports; port++) { + ib_net16_t lid; + + if (!osm_node_get_physp_ptr(node, port)) + continue; + + lid = get_lid(node, port, mon_node); + if (lid == 0) { + OSM_LOG(pm->log, OSM_LOG_DEBUG, "WARN: node 0x%" PRIx64 + " port %d (%s): port out of range, skipping\n", + cl_ntoh64(node->node_info.node_guid), port, + node->print_desc); + continue; + } + + remote_qp = get_qp(mon_node, port); + + mad_context.perfmgr_context.node_guid = node_guid; + mad_context.perfmgr_context.port = port; + mad_context.perfmgr_context.mad_method = IB_MAD_METHOD_GET; +#if ENABLE_OSM_PERF_MGR_PROFILE + gettimeofday(&(mad_context.perfmgr_context.query_start), NULL); +#endif + OSM_LOG(pm->log, OSM_LOG_VERBOSE, "Getting stats for node 0x%" + PRIx64 " port %d (lid %u) (%s)\n", node_guid, port, + cl_ntoh16(lid), node->print_desc); + status = + osm_perfmgr_send_pc_mad(pm, lid, remote_qp, port, + IB_MAD_METHOD_GET, &mad_context); + if (status != IB_SUCCESS) + OSM_LOG(pm->log, OSM_LOG_ERROR, "ERR 4C09: " + "Failed to issue port counter query for node 0x%" + PRIx64 " port %d (%s)\n", + node->node_info.node_guid, port, + node->print_desc); + } +Exit: + cl_plock_release(pm->lock); + OSM_LOG_EXIT(pm->log); +} + +/********************************************************************** + * Discovery stuff. + * Basically this code should not be here, but merged with main OpenSM + **********************************************************************/ +extern void osm_drop_mgr_process(IN osm_sm_t *sm); + +static int sweep_hop_1(osm_sm_t * sm) +{ + ib_api_status_t status = IB_SUCCESS; + osm_bind_handle_t h_bind; + osm_madw_context_t context; + osm_node_t *p_node; + osm_port_t *p_port; + osm_physp_t *p_physp; + osm_dr_path_t *p_dr_path; + osm_dr_path_t hop_1_path; + ib_net64_t port_guid; + uint8_t port_num; + uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX]; + uint8_t num_ports; + osm_physp_t *p_ext_physp; + + port_guid = sm->p_subn->sm_port_guid; + + p_port = osm_get_port_by_guid(sm->p_subn, port_guid); + if (!p_port) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 4C81: No SM port object\n"); + return -1; + } + + p_node = p_port->p_node; + port_num = ib_node_info_get_local_port_num(&p_node->node_info); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Probing hop 1 on local port %u\n", port_num); + + p_physp = osm_node_get_physp_ptr(p_node, port_num); + + CL_ASSERT(p_physp); + + p_dr_path = osm_physp_get_dr_path_ptr(p_physp); + h_bind = osm_dr_path_get_bind_handle(p_dr_path); + + CL_ASSERT(h_bind != OSM_BIND_INVALID_HANDLE); + + memset(path_array, 0, sizeof(path_array)); + /* the hop_1 operations depend on the type of our node. + * Currently - legal nodes that can host SM are SW and CA */ + switch (osm_node_get_type(p_node)) { + case IB_NODE_TYPE_CA: + case IB_NODE_TYPE_ROUTER: + memset(&context, 0, sizeof(context)); + context.ni_context.node_guid = osm_node_get_node_guid(p_node); + context.ni_context.port_num = port_num; + + path_array[1] = port_num; + + osm_dr_path_init(&hop_1_path, h_bind, 1, path_array); + status = osm_req_get(sm, &hop_1_path, + IB_MAD_ATTR_NODE_INFO, 0, + CL_DISP_MSGID_NONE, &context); + + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 4C82: " + "Request for NodeInfo failed\n"); + break; + + case IB_NODE_TYPE_SWITCH: + /* Need to go over all the ports of the switch, and send a node_info + * from them. This doesn't include the port 0 of the switch, which + * hosts the SM. + * Note: We'll send another switchInfo on port 0, since if no ports + * are connected, we still want to get some response, and have the + * subnet come up. + */ + num_ports = osm_node_get_num_physp(p_node); + for (port_num = 0; port_num < num_ports; port_num++) { + /* go through the port only if the port is not DOWN */ + p_ext_physp = osm_node_get_physp_ptr(p_node, port_num); + if (!p_ext_physp || ib_port_info_get_port_state + (&p_ext_physp->port_info) <= IB_LINK_DOWN) + continue; + + memset(&context, 0, sizeof(context)); + context.ni_context.node_guid = + osm_node_get_node_guid(p_node); + context.ni_context.port_num = port_num; + + path_array[1] = port_num; + + osm_dr_path_init(&hop_1_path, h_bind, 1, path_array); + status = osm_req_get(sm, &hop_1_path, + IB_MAD_ATTR_NODE_INFO, 0, + CL_DISP_MSGID_NONE, &context); + + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 4C82: " + "Request for NodeInfo failed\n"); + } + break; + + default: + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 4C83: Unknown node type %d\n", + osm_node_get_type(p_node)); + } + + return (status); +} + +static unsigned is_sm_port_down(osm_sm_t * const sm) +{ + ib_net64_t port_guid; + osm_port_t *p_port; + + port_guid = sm->p_subn->sm_port_guid; + if (port_guid == 0) + return 1; + + CL_PLOCK_ACQUIRE(sm->p_lock); + p_port = osm_get_port_by_guid(sm->p_subn, port_guid); + if (!p_port) { + CL_PLOCK_RELEASE(sm->p_lock); + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 4C85: " + "SM port with GUID:%016" PRIx64 " is unknown\n", + cl_ntoh64(port_guid)); + return 1; + } + CL_PLOCK_RELEASE(sm->p_lock); + + return osm_physp_get_port_state(p_port->p_physp) == IB_LINK_DOWN; +} + +static int sweep_hop_0(osm_sm_t * const sm) +{ + ib_api_status_t status; + osm_dr_path_t dr_path; + osm_bind_handle_t h_bind; + uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX]; + + memset(path_array, 0, sizeof(path_array)); + + h_bind = osm_sm_mad_ctrl_get_bind_handle(&sm->mad_ctrl); + if (h_bind == OSM_BIND_INVALID_HANDLE) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "No bound ports.\n"); + return -1; + } + + osm_dr_path_init(&dr_path, h_bind, 0, path_array); + status = osm_req_get(sm, &dr_path, IB_MAD_ATTR_NODE_INFO, 0, + CL_DISP_MSGID_NONE, NULL); + + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 4C86: Request for NodeInfo failed\n"); + + return (status); +} + +static void reset_node_count(cl_map_item_t * const p_map_item, void *cxt) +{ + osm_node_t *p_node = (osm_node_t *) p_map_item; + p_node->discovery_count = 0; +} + +static void reset_port_count(cl_map_item_t * const p_map_item, void *cxt) +{ + osm_port_t *p_port = (osm_port_t *) p_map_item; + p_port->discovery_count = 0; +} + +static void reset_switch_count(cl_map_item_t * const p_map_item, void *cxt) +{ + osm_switch_t *p_sw = (osm_switch_t *) p_map_item; + p_sw->discovery_count = 0; + p_sw->need_update = 0; +} + +static int perfmgr_discovery(osm_opensm_t * osm) +{ + int ret; + + CL_PLOCK_ACQUIRE(&osm->lock); + cl_qmap_apply_func(&osm->subn.node_guid_tbl, reset_node_count, NULL); + cl_qmap_apply_func(&osm->subn.port_guid_tbl, reset_port_count, NULL); + cl_qmap_apply_func(&osm->subn.sw_guid_tbl, reset_switch_count, NULL); + CL_PLOCK_RELEASE(&osm->lock); + + osm->subn.in_sweep_hop_0 = TRUE; + + ret = sweep_hop_0(&osm->sm); + if (ret) + goto _exit; + + if (wait_for_pending_transactions(&osm->stats)) + goto _exit; + + if (is_sm_port_down(&osm->sm)) { + OSM_LOG(&osm->log, OSM_LOG_VERBOSE, "SM port is down\n"); + goto _drop; + } + + osm->subn.in_sweep_hop_0 = FALSE; + + ret = sweep_hop_1(&osm->sm); + if (ret) + goto _exit; + + if (wait_for_pending_transactions(&osm->stats)) + goto _exit; + +_drop: + osm_drop_mgr_process(&osm->sm); + +_exit: + return ret; +} + +/********************************************************************** + * Main PerfMgr processor - query the performance counters. + **********************************************************************/ +void osm_perfmgr_process(osm_perfmgr_t * pm) +{ +#if ENABLE_OSM_PERF_MGR_PROFILE + struct timeval before, after; +#endif + + if (pm->state != PERFMGR_STATE_ENABLED) + return; + + if (pm->subn->sm_state == IB_SMINFO_STATE_STANDBY || + pm->subn->sm_state == IB_SMINFO_STATE_NOTACTIVE) + perfmgr_discovery(pm->subn->p_osm); + +#if ENABLE_OSM_PERF_MGR_PROFILE + gettimeofday(&before, NULL); +#endif + pm->sweep_state = PERFMGR_SWEEP_ACTIVE; + /* With the global lock held collect the node guids */ + /* FIXME we should be able to track SA notices + * and not have to sweep the node_guid_tbl each pass + */ + OSM_LOG(pm->log, OSM_LOG_VERBOSE, "Gathering PerfMgr stats\n"); + cl_plock_acquire(pm->lock); + cl_qmap_apply_func(&(pm->subn->node_guid_tbl), + __collect_guids, (void *)pm); + cl_plock_release(pm->lock); + + /* then for each node query their counters */ + cl_qmap_apply_func(&(pm->monitored_map), + __osm_perfmgr_query_counters, (void *)pm); + + /* Clean out any nodes found to be removed during the + * sweep + */ + __remove_marked_nodes(pm); + +#if ENABLE_OSM_PERF_MGR_PROFILE + /* spin on outstanding queries */ + while (pm->outstanding_queries > 0) + cl_event_wait_on(&pm->sig_sweep, 1000, TRUE); + + gettimeofday(&after, NULL); + diff_time(&before, &after, &after); + osm_log(pm->log, OSM_LOG_INFO, + "PerfMgr total sweep time : %ld.%06ld s\n" + " fastest mad : %g us\n" + " slowest mad : %g us\n" + " average mad : %g us\n", + after.tv_sec, after.tv_usec, + perfmgr_mad_stats.fastest_us, + perfmgr_mad_stats.slowest_us, perfmgr_mad_stats.avg_us); + perfmgr_clear_mad_stats(); +#endif + + pm->sweep_state = PERFMGR_SWEEP_SLEEP; +} + +/********************************************************************** + * PerfMgr timer - loop continuously and signal SM to run PerfMgr + * processor. + **********************************************************************/ +static void perfmgr_sweep(void *arg) +{ + osm_perfmgr_t *pm = arg; + + if (pm->state == PERFMGR_STATE_ENABLED) + osm_sm_signal(pm->sm, OSM_SIGNAL_PERFMGR_SWEEP); + cl_timer_start(&pm->sweep_timer, pm->sweep_time_s * 1000); +} + +/********************************************************************** + **********************************************************************/ +void osm_perfmgr_shutdown(osm_perfmgr_t * const pm) +{ + OSM_LOG_ENTER(pm->log); + cl_timer_stop(&pm->sweep_timer); + osm_perfmgr_mad_unbind(pm); + OSM_LOG_EXIT(pm->log); +} + +/********************************************************************** + **********************************************************************/ +void osm_perfmgr_destroy(osm_perfmgr_t * const pm) +{ + OSM_LOG_ENTER(pm->log); + perfmgr_db_destroy(pm->db); + cl_timer_destroy(&pm->sweep_timer); + OSM_LOG_EXIT(pm->log); +} + +/********************************************************************** + * Detect if someone else on the network could have cleared the counters + * without us knowing. This is easy to detect because the counters never wrap + * but are "sticky" + * + * The one time this will not work is if the port is getting errors fast enough + * to have the reading overtake the previous reading. In this case counters + * will be missed. + **********************************************************************/ +static void +osm_perfmgr_check_oob_clear(osm_perfmgr_t * pm, __monitored_node_t *mon_node, + uint8_t port, perfmgr_db_err_reading_t * cr, + perfmgr_db_data_cnt_reading_t * dc) +{ + perfmgr_db_err_reading_t prev_err; + perfmgr_db_data_cnt_reading_t prev_dc; + + if (perfmgr_db_get_prev_err(pm->db, mon_node->guid, port, &prev_err) + != PERFMGR_EVENT_DB_SUCCESS) { + OSM_LOG(pm->log, OSM_LOG_VERBOSE, "Failed to find previous " + "error reading for %s (guid 0x%" PRIx64 ") port %u\n", + mon_node->name, mon_node->guid, port); + return; + } + + if (cr->symbol_err_cnt < prev_err.symbol_err_cnt || + cr->link_err_recover < prev_err.link_err_recover || + cr->link_downed < prev_err.link_downed || + cr->rcv_err < prev_err.rcv_err || + cr->rcv_rem_phys_err < prev_err.rcv_rem_phys_err || + cr->rcv_switch_relay_err < prev_err.rcv_switch_relay_err || + cr->xmit_discards < prev_err.xmit_discards || + cr->xmit_constraint_err < prev_err.xmit_constraint_err || + cr->rcv_constraint_err < prev_err.rcv_constraint_err || + cr->link_integrity < prev_err.link_integrity || + cr->buffer_overrun < prev_err.buffer_overrun || + cr->vl15_dropped < prev_err.vl15_dropped) { + OSM_LOG(pm->log, OSM_LOG_ERROR, "PerfMgr: ERR 4C0A: " + "Detected an out of band error clear " + "on %s (0x%" PRIx64 ") port %u\n", + mon_node->name, mon_node->guid, port); + perfmgr_db_clear_prev_err(pm->db, mon_node->guid, port); + } + + /* FIXME handle extended counters */ + if (perfmgr_db_get_prev_dc(pm->db, mon_node->guid, port, &prev_dc) + != PERFMGR_EVENT_DB_SUCCESS) { + OSM_LOG(pm->log, OSM_LOG_VERBOSE, + "Failed to find previous data count " + "reading for %s (0x%" PRIx64 ") port %u\n", + mon_node->name, mon_node->guid, port); + return; + } + + if (dc->xmit_data < prev_dc.xmit_data || + dc->rcv_data < prev_dc.rcv_data || + dc->xmit_pkts < prev_dc.xmit_pkts || + dc->rcv_pkts < prev_dc.rcv_pkts) { + OSM_LOG(pm->log, OSM_LOG_ERROR, + "PerfMgr: ERR 4C0B: Detected an out of band data counter " + "clear on node %s (0x%" PRIx64 ") port %u\n", + mon_node->name, mon_node->guid, port); + perfmgr_db_clear_prev_dc(pm->db, mon_node->guid, port); + } +} + +/********************************************************************** + * Return 1 if the value is "close" to overflowing + **********************************************************************/ +static int counter_overflow_4(uint8_t val) +{ + return (val >= 10); +} + +static int counter_overflow_8(uint8_t val) +{ + return (val >= (UINT8_MAX - (UINT8_MAX / 4))); +} + +static int counter_overflow_16(ib_net16_t val) +{ + return (cl_ntoh16(val) >= (UINT16_MAX - (UINT16_MAX / 4))); +} + +static int counter_overflow_32(ib_net32_t val) +{ + return (cl_ntoh32(val) >= (UINT32_MAX - (UINT32_MAX / 4))); +} + +/********************************************************************** + * Check if the port counters have overflowed and if so issue a clear + * MAD to the port. + **********************************************************************/ +static void +osm_perfmgr_check_overflow(osm_perfmgr_t * pm, __monitored_node_t *mon_node, + uint8_t port, ib_port_counters_t * pc) +{ + osm_madw_context_t mad_context; + ib_api_status_t status; + ib_net32_t remote_qp; + + OSM_LOG_ENTER(pm->log); + + if (counter_overflow_16(pc->symbol_err_cnt) || + counter_overflow_8(pc->link_err_recover) || + counter_overflow_8(pc->link_downed) || + counter_overflow_16(pc->rcv_err) || + counter_overflow_16(pc->rcv_rem_phys_err) || + counter_overflow_16(pc->rcv_switch_relay_err) || + counter_overflow_16(pc->xmit_discards) || + counter_overflow_8(pc->xmit_constraint_err) || + counter_overflow_8(pc->rcv_constraint_err) || + counter_overflow_4(PC_LINK_INT(pc->link_int_buffer_overrun)) || + counter_overflow_4(PC_BUF_OVERRUN(pc->link_int_buffer_overrun)) || + counter_overflow_16(pc->vl15_dropped) || + counter_overflow_32(pc->xmit_data) || + counter_overflow_32(pc->rcv_data) || + counter_overflow_32(pc->xmit_pkts) || + counter_overflow_32(pc->rcv_pkts)) { + osm_node_t *p_node = NULL; + ib_net16_t lid = 0; + + osm_log(pm->log, OSM_LOG_VERBOSE, + "PerfMgr: Counter overflow: %s (0x%" PRIx64 + ") port %d; clearing counters\n", + mon_node->name, mon_node->guid, port); + + cl_plock_acquire(pm->lock); + p_node = osm_get_node_by_guid(pm->subn, cl_hton64(mon_node->guid)); + lid = get_lid(p_node, port, mon_node); + cl_plock_release(pm->lock); + if (lid == 0) { + OSM_LOG(pm->log, OSM_LOG_ERROR, "PerfMgr: ERR 4C0C: " + "Failed to clear counters for %s (0x%" + PRIx64 ") port %d; failed to get lid\n", + mon_node->name, mon_node->guid, port); + goto Exit; + } + + remote_qp = get_qp(NULL, port); + + mad_context.perfmgr_context.node_guid = mon_node->guid; + mad_context.perfmgr_context.port = port; + mad_context.perfmgr_context.mad_method = IB_MAD_METHOD_SET; + /* clear port counters */ + status = + osm_perfmgr_send_pc_mad(pm, lid, remote_qp, port, + IB_MAD_METHOD_SET, &mad_context); + if (status != IB_SUCCESS) + OSM_LOG(pm->log, OSM_LOG_ERROR, "PerfMgr: ERR 4C11: " + "Failed to send clear counters MAD for %s (0x%" + PRIx64 ") port %d\n", + mon_node->name, mon_node->guid, port); + + perfmgr_db_clear_prev_dc(pm->db, mon_node->guid, port); + } + +Exit: + OSM_LOG_EXIT(pm->log); +} + +/********************************************************************** + * Check values for logging of errors + **********************************************************************/ +static void +osm_perfmgr_log_events(osm_perfmgr_t * pm, __monitored_node_t *mon_node, uint8_t port, + perfmgr_db_err_reading_t * reading) +{ + perfmgr_db_err_reading_t prev_read; + time_t time_diff = 0; + perfmgr_db_err_t err = + perfmgr_db_get_prev_err(pm->db, mon_node->guid, port, &prev_read); + + if (err != PERFMGR_EVENT_DB_SUCCESS) { + OSM_LOG(pm->log, OSM_LOG_VERBOSE, "Failed to find previous " + "reading for %s (0x%" PRIx64 ") port %u\n", + mon_node->name, mon_node->guid, port); + return; + } + time_diff = (reading->time - prev_read.time); + + /* FIXME these events should be defineable by the user in a config + * file somewhere. */ + if (reading->symbol_err_cnt > prev_read.symbol_err_cnt) + OSM_LOG(pm->log, OSM_LOG_ERROR, "ERR 4C0D: " + "Found %" PRIu64 " Symbol errors in %lu sec on %s (0x%" + PRIx64 ") port %u\n", + (reading->symbol_err_cnt - prev_read.symbol_err_cnt), + time_diff, mon_node->name, mon_node->guid, port); + + if (reading->rcv_err > prev_read.rcv_err) + OSM_LOG(pm->log, OSM_LOG_ERROR, "ERR 4C0E: " + "Found %" PRIu64 + " Receive errors in %lu sec on %s (0x%" PRIx64 + ") port %u\n", (reading->rcv_err - prev_read.rcv_err), + time_diff, mon_node->name, mon_node->guid, port); + + if (reading->xmit_discards > prev_read.xmit_discards) + OSM_LOG(pm->log, OSM_LOG_ERROR, "ERR 4C0F: " + "Found %" PRIu64 " Xmit Discards in %lu sec on %s (0x%" + PRIx64 ") port %u\n", + (reading->xmit_discards - prev_read.xmit_discards), + time_diff, mon_node->name, mon_node->guid, port); +} + +/********************************************************************** + * The dispatcher uses a thread pool which will call this function when + * we have a thread available to process our mad received from the wire. + **********************************************************************/ +static void osm_pc_rcv_process(void *context, void *data) +{ + osm_perfmgr_t *const pm = (osm_perfmgr_t *) context; + osm_madw_t *p_madw = (osm_madw_t *) data; + osm_madw_context_t *mad_context = &(p_madw->context); + ib_port_counters_t *wire_read = + (ib_port_counters_t *) & (osm_madw_get_perfmgt_mad_ptr(p_madw)-> + data); + ib_mad_t *p_mad = osm_madw_get_mad_ptr(p_madw); + uint64_t node_guid = mad_context->perfmgr_context.node_guid; + uint8_t port = mad_context->perfmgr_context.port; + perfmgr_db_err_reading_t err_reading; + perfmgr_db_data_cnt_reading_t data_reading; + cl_map_item_t *p_node; + __monitored_node_t *p_mon_node; + + OSM_LOG_ENTER(pm->log); + + /* go ahead and get the monitored node struct to have the printable + * name if needed in messages + */ + if ((p_node = cl_qmap_get(&(pm->monitored_map), node_guid)) == + cl_qmap_end(&(pm->monitored_map))) { + OSM_LOG(pm->log, OSM_LOG_ERROR, "ERR 4C12: GUID 0x%016" + PRIx64 " not found in monitored map\n", + node_guid); + goto Exit; + } + p_mon_node = (__monitored_node_t *) p_node; + + OSM_LOG(pm->log, OSM_LOG_VERBOSE, + "Processing received MAD status 0x%x context 0x%" + PRIx64 " port %u\n", p_mad->status, node_guid, port); + + /* Response could also be redirection (IBM eHCA PMA does this) */ + if (p_mad->attr_id == IB_MAD_ATTR_CLASS_PORT_INFO) { + char gid_str[INET6_ADDRSTRLEN]; + ib_class_port_info_t *cpi = + (ib_class_port_info_t *) & + (osm_madw_get_perfmgt_mad_ptr(p_madw)->data); + ib_api_status_t status; + + OSM_LOG(pm->log, OSM_LOG_VERBOSE, + "Redirection to LID %u GID %s QP 0x%x received\n", + cl_ntoh16(cpi->redir_lid), + inet_ntop(AF_INET6, cpi->redir_gid.raw, gid_str, + sizeof gid_str), + cl_ntoh32(cpi->redir_qp)); + + /* LID or GID redirection ? */ + /* For GID redirection, need to get PathRecord from SA */ + if (cpi->redir_lid == 0) { + OSM_LOG(pm->log, OSM_LOG_VERBOSE, + "GID redirection not currently implemented!\n"); + goto Exit; + } + + if (!pm->subn->opt.perfmgr_redir) { + OSM_LOG(pm->log, OSM_LOG_ERROR, "ERR 4C16: " + "redirection requested but disabled\n"); + goto Exit; + } + + /* LID redirection support (easier than GID redirection) */ + cl_plock_acquire(pm->lock); + /* Now, validate port number */ + if (port > p_mon_node->redir_tbl_size) { + cl_plock_release(pm->lock); + OSM_LOG(pm->log, OSM_LOG_ERROR, "ERR 4C13: " + "Invalid port num %d for GUID 0x%016" + PRIx64 " num ports %d\n", port, node_guid, + p_mon_node->redir_tbl_size); + goto Exit; + } + p_mon_node->redir_port[port].redir_lid = cpi->redir_lid; + p_mon_node->redir_port[port].redir_qp = cpi->redir_qp; + cl_plock_release(pm->lock); + + /* Finally, reissue the query to the redirected location */ + status = + osm_perfmgr_send_pc_mad(pm, cpi->redir_lid, cpi->redir_qp, + port, + mad_context->perfmgr_context. + mad_method, mad_context); + if (status != IB_SUCCESS) + OSM_LOG(pm->log, OSM_LOG_ERROR, "ERR 4C14: " + "Failed to send redirected MAD with method 0x%x for node 0x%" + PRIx64 " port %d\n", + mad_context->perfmgr_context.mad_method, + node_guid, port); + goto Exit; + } + + CL_ASSERT(p_mad->attr_id == IB_MAD_ATTR_PORT_CNTRS); + + perfmgr_db_fill_err_read(wire_read, &err_reading); + /* FIXME separate query for extended counters if they are supported + * on the port. + */ + perfmgr_db_fill_data_cnt_read_pc(wire_read, &data_reading); + + /* detect an out of band clear on the port */ + if (mad_context->perfmgr_context.mad_method != IB_MAD_METHOD_SET) + osm_perfmgr_check_oob_clear(pm, p_mon_node, port, + &err_reading, &data_reading); + + /* log any critical events from this reading */ + osm_perfmgr_log_events(pm, p_mon_node, port, &err_reading); + + if (mad_context->perfmgr_context.mad_method == IB_MAD_METHOD_GET) { + perfmgr_db_add_err_reading(pm->db, node_guid, port, + &err_reading); + perfmgr_db_add_dc_reading(pm->db, node_guid, port, + &data_reading); + } else { + perfmgr_db_clear_prev_err(pm->db, node_guid, port); + perfmgr_db_clear_prev_dc(pm->db, node_guid, port); + } + + osm_perfmgr_check_overflow(pm, p_mon_node, port, wire_read); + +#if ENABLE_OSM_PERF_MGR_PROFILE + do { + struct timeval proc_time; + gettimeofday(&proc_time, NULL); + diff_time(&(p_madw->context.perfmgr_context.query_start), + &proc_time, &proc_time); + update_mad_stats(&proc_time); + } while (0); +#endif + +Exit: + osm_mad_pool_put(pm->mad_pool, p_madw); + + OSM_LOG_EXIT(pm->log); +} + +/********************************************************************** + * Initialize the PerfMgr object + **********************************************************************/ +ib_api_status_t +osm_perfmgr_init(osm_perfmgr_t * const pm, osm_opensm_t *osm, + const osm_subn_opt_t * const p_opt) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&osm->log); + + OSM_LOG(&osm->log, OSM_LOG_VERBOSE, "Initializing PerfMgr\n"); + + memset(pm, 0, sizeof(*pm)); + + cl_event_construct(&pm->sig_sweep); + cl_event_init(&pm->sig_sweep, FALSE); + pm->subn = &osm->subn; + pm->sm = &osm->sm; + pm->log = &osm->log; + pm->mad_pool = &osm->mad_pool; + pm->vendor = osm->p_vendor; + pm->trans_id = OSM_PERFMGR_INITIAL_TID_VALUE; + pm->lock = &osm->lock; + pm->state = + p_opt->perfmgr ? PERFMGR_STATE_ENABLED : PERFMGR_STATE_DISABLE; + pm->sweep_time_s = p_opt->perfmgr_sweep_time_s; + pm->max_outstanding_queries = p_opt->perfmgr_max_outstanding_queries; + pm->osm = osm; + + status = cl_timer_init(&pm->sweep_timer, perfmgr_sweep, pm); + if (status != IB_SUCCESS) + goto Exit; + + pm->db = perfmgr_db_construct(pm); + if (!pm->db) { + pm->state = PERFMGR_STATE_NO_DB; + goto Exit; + } + + pm->pc_disp_h = cl_disp_register(&osm->disp, OSM_MSG_MAD_PORT_COUNTERS, + osm_pc_rcv_process, pm); + if (pm->pc_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + __init_monitored_nodes(pm); + + cl_timer_start(&pm->sweep_timer, pm->sweep_time_s * 1000); + +Exit: + OSM_LOG_EXIT(pm->log); + return (status); +} + +/********************************************************************** + * Clear the counters from the db + **********************************************************************/ +void osm_perfmgr_clear_counters(osm_perfmgr_t * pm) +{ + /** + * FIXME todo issue clear on the fabric? + */ + perfmgr_db_clear_counters(pm->db); + osm_log(pm->log, OSM_LOG_INFO, "PerfMgr counters cleared\n"); +} + +/******************************************************************* + * Have the DB dump its information to the file specified + *******************************************************************/ +void osm_perfmgr_dump_counters(osm_perfmgr_t * pm, perfmgr_db_dump_t dump_type) +{ + char path[256]; + char *file_name; + if (pm->subn->opt.event_db_dump_file) + file_name = pm->subn->opt.event_db_dump_file; + else { + snprintf(path, sizeof(path), "%s/%s", + pm->subn->opt.dump_files_dir, + OSM_PERFMGR_DEFAULT_DUMP_FILE); + file_name = path; + } + if (perfmgr_db_dump(pm->db, file_name, dump_type) != 0) + OSM_LOG(pm->log, OSM_LOG_ERROR, "Failed to dump file %s : %s", + file_name, strerror(errno)); +} + +/******************************************************************* + * Have the DB print its information to the fp specified + *******************************************************************/ +void +osm_perfmgr_print_counters(osm_perfmgr_t *pm, char *nodename, FILE *fp) +{ + uint64_t guid = strtoull(nodename, NULL, 0); + if (guid == 0 && errno == EINVAL) { + perfmgr_db_print_by_name(pm->db, nodename, fp); + } else { + perfmgr_db_print_by_guid(pm->db, guid, fp); + } +} + +#endif /* ENABLE_OSM_PERF_MGR */ diff --git a/contrib/ofed/management/opensm/opensm/osm_perfmgr_db.c b/contrib/ofed/management/opensm/opensm/osm_perfmgr_db.c new file mode 100644 index 000000000000..934be7770cf0 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_perfmgr_db.c @@ -0,0 +1,807 @@ +/* + * Copyright (c) 2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2007 The Regents of the University of California. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#ifdef ENABLE_OSM_PERF_MGR + +#include +#include +#include +#include +#include + +#include +#include +#include + +/** ========================================================================= + */ +perfmgr_db_t *perfmgr_db_construct(osm_perfmgr_t *perfmgr) +{ + perfmgr_db_t *db = malloc(sizeof(*db)); + if (!db) + return (NULL); + + cl_qmap_init(&(db->pc_data)); + cl_plock_construct(&(db->lock)); + cl_plock_init(&(db->lock)); + db->perfmgr = perfmgr; + return ((void *)db); +} + +/** ========================================================================= + */ +void perfmgr_db_destroy(perfmgr_db_t * db) +{ + if (db) { + cl_plock_destroy(&(db->lock)); + free(db); + } +} + +/********************************************************************** + * Internal call db->lock should be held when calling + **********************************************************************/ +static inline _db_node_t *_get(perfmgr_db_t * db, uint64_t guid) +{ + cl_map_item_t *rc = cl_qmap_get(&(db->pc_data), guid); + const cl_map_item_t *end = cl_qmap_end(&(db->pc_data)); + + if (rc == end) + return (NULL); + return ((_db_node_t *) rc); +} + +static inline perfmgr_db_err_t bad_node_port(_db_node_t * node, uint8_t port) +{ + if (!node) + return (PERFMGR_EVENT_DB_GUIDNOTFOUND); + if (port == 0 || port >= node->num_ports) + return (PERFMGR_EVENT_DB_PORTNOTFOUND); + return (PERFMGR_EVENT_DB_SUCCESS); +} + +/** ========================================================================= + */ +static _db_node_t *__malloc_node(uint64_t guid, uint8_t num_ports, char *name) +{ + int i = 0; + time_t cur_time = 0; + _db_node_t *rc = malloc(sizeof(*rc)); + if (!rc) + return (NULL); + + rc->ports = calloc(num_ports, sizeof(_db_port_t)); + if (!rc->ports) + goto free_rc; + rc->num_ports = num_ports; + rc->node_guid = guid; + + cur_time = time(NULL); + for (i = 0; i < num_ports; i++) { + rc->ports[i].last_reset = cur_time; + rc->ports[i].err_previous.time = cur_time; + rc->ports[i].dc_previous.time = cur_time; + } + snprintf(rc->node_name, NODE_NAME_SIZE, "%s", name); + + return (rc); + +free_rc: + free(rc); + return (NULL); +} + +/** ========================================================================= + */ +static void __free_node(_db_node_t * node) +{ + if (!node) + return; + if (node->ports) + free(node->ports); + free(node); +} + +/* insert nodes to the database */ +static perfmgr_db_err_t __insert(perfmgr_db_t * db, _db_node_t * node) +{ + cl_map_item_t *rc = cl_qmap_insert(&(db->pc_data), node->node_guid, + (cl_map_item_t *) node); + + if ((void *)rc != (void *)node) + return (PERFMGR_EVENT_DB_FAIL); + return (PERFMGR_EVENT_DB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +perfmgr_db_err_t +perfmgr_db_create_entry(perfmgr_db_t * db, uint64_t guid, + uint8_t num_ports, char *name) +{ + perfmgr_db_err_t rc = PERFMGR_EVENT_DB_SUCCESS; + + cl_plock_excl_acquire(&(db->lock)); + if (!_get(db, guid)) { + _db_node_t *pc_node = __malloc_node(guid, num_ports, name); + if (!pc_node) { + rc = PERFMGR_EVENT_DB_NOMEM; + goto Exit; + } + if (__insert(db, pc_node)) { + __free_node(pc_node); + rc = PERFMGR_EVENT_DB_FAIL; + goto Exit; + } + } +Exit: + cl_plock_release(&(db->lock)); + return (rc); +} + +/********************************************************************** + * Dump a reading vs the previous reading to stdout + **********************************************************************/ +static inline void +debug_dump_err_reading(perfmgr_db_t * db, uint64_t guid, uint8_t port_num, + _db_port_t * port, perfmgr_db_err_reading_t * cur) +{ + osm_log_t *log = db->perfmgr->log; + + if (!osm_log_is_active(log, OSM_LOG_DEBUG)) + return; /* optimize this a bit */ + + osm_log(log, OSM_LOG_DEBUG, + "GUID 0x%" PRIx64 " Port %u:\n", guid, port_num); + osm_log(log, OSM_LOG_DEBUG, + "sym %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", + cur->symbol_err_cnt, port->err_previous.symbol_err_cnt, + port->err_total.symbol_err_cnt); + osm_log(log, OSM_LOG_DEBUG, + "ler %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", + cur->link_err_recover, port->err_previous.link_err_recover, + port->err_total.link_err_recover); + osm_log(log, OSM_LOG_DEBUG, + "ld %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", + cur->link_downed, port->err_previous.link_downed, + port->err_total.link_downed); + osm_log(log, OSM_LOG_DEBUG, + "re %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", cur->rcv_err, + port->err_previous.rcv_err, port->err_total.rcv_err); + osm_log(log, OSM_LOG_DEBUG, + "rrp %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", + cur->rcv_rem_phys_err, port->err_previous.rcv_rem_phys_err, + port->err_total.rcv_rem_phys_err); + osm_log(log, OSM_LOG_DEBUG, + "rsr %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", + cur->rcv_switch_relay_err, + port->err_previous.rcv_switch_relay_err, + port->err_total.rcv_switch_relay_err); + osm_log(log, OSM_LOG_DEBUG, + "xd %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", + cur->xmit_discards, port->err_previous.xmit_discards, + port->err_total.xmit_discards); + osm_log(log, OSM_LOG_DEBUG, + "xce %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", + cur->xmit_constraint_err, + port->err_previous.xmit_constraint_err, + port->err_total.xmit_constraint_err); + osm_log(log, OSM_LOG_DEBUG, + "rce %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", + cur->rcv_constraint_err, port->err_previous.rcv_constraint_err, + port->err_total.rcv_constraint_err); + osm_log(log, OSM_LOG_DEBUG, + "li %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", + cur->link_integrity, port->err_previous.link_integrity, + port->err_total.link_integrity); + osm_log(log, OSM_LOG_DEBUG, + "bo %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", + cur->buffer_overrun, port->err_previous.buffer_overrun, + port->err_total.buffer_overrun); + osm_log(log, OSM_LOG_DEBUG, + "vld %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", + cur->vl15_dropped, port->err_previous.vl15_dropped, + port->err_total.vl15_dropped); +} + +/********************************************************************** + * perfmgr_db_err_reading_t functions + **********************************************************************/ +perfmgr_db_err_t +perfmgr_db_add_err_reading(perfmgr_db_t * db, uint64_t guid, + uint8_t port, perfmgr_db_err_reading_t * reading) +{ + _db_port_t *p_port = NULL; + _db_node_t *node = NULL; + perfmgr_db_err_reading_t *previous = NULL; + perfmgr_db_err_t rc = PERFMGR_EVENT_DB_SUCCESS; + osm_epi_pe_event_t epi_pe_data; + + cl_plock_excl_acquire(&(db->lock)); + node = _get(db, guid); + if ((rc = bad_node_port(node, port)) != PERFMGR_EVENT_DB_SUCCESS) + goto Exit; + + p_port = &(node->ports[port]); + previous = &(node->ports[port].err_previous); + + debug_dump_err_reading(db, guid, port, p_port, reading); + + epi_pe_data.time_diff_s = (reading->time - previous->time); + osm_epi_create_port_id(&(epi_pe_data.port_id), guid, port, + node->node_name); + + /* calculate changes from previous reading */ + epi_pe_data.symbol_err_cnt = + (reading->symbol_err_cnt - previous->symbol_err_cnt); + p_port->err_total.symbol_err_cnt += epi_pe_data.symbol_err_cnt; + epi_pe_data.link_err_recover = + (reading->link_err_recover - previous->link_err_recover); + p_port->err_total.link_err_recover += epi_pe_data.link_err_recover; + epi_pe_data.link_downed = + (reading->link_downed - previous->link_downed); + p_port->err_total.link_downed += epi_pe_data.link_downed; + epi_pe_data.rcv_err = (reading->rcv_err - previous->rcv_err); + p_port->err_total.rcv_err += epi_pe_data.rcv_err; + epi_pe_data.rcv_rem_phys_err = + (reading->rcv_rem_phys_err - previous->rcv_rem_phys_err); + p_port->err_total.rcv_rem_phys_err += epi_pe_data.rcv_rem_phys_err; + epi_pe_data.rcv_switch_relay_err = + (reading->rcv_switch_relay_err - previous->rcv_switch_relay_err); + p_port->err_total.rcv_switch_relay_err += + epi_pe_data.rcv_switch_relay_err; + epi_pe_data.xmit_discards = + (reading->xmit_discards - previous->xmit_discards); + p_port->err_total.xmit_discards += epi_pe_data.xmit_discards; + epi_pe_data.xmit_constraint_err = + (reading->xmit_constraint_err - previous->xmit_constraint_err); + p_port->err_total.xmit_constraint_err += + epi_pe_data.xmit_constraint_err; + epi_pe_data.rcv_constraint_err = + (reading->rcv_constraint_err - previous->rcv_constraint_err); + p_port->err_total.rcv_constraint_err += epi_pe_data.rcv_constraint_err; + epi_pe_data.link_integrity = + (reading->link_integrity - previous->link_integrity); + p_port->err_total.link_integrity += epi_pe_data.link_integrity; + epi_pe_data.buffer_overrun = + (reading->buffer_overrun - previous->buffer_overrun); + p_port->err_total.buffer_overrun += epi_pe_data.buffer_overrun; + epi_pe_data.vl15_dropped = + (reading->vl15_dropped - previous->vl15_dropped); + p_port->err_total.vl15_dropped += epi_pe_data.vl15_dropped; + + p_port->err_previous = *reading; + + osm_opensm_report_event(db->perfmgr->osm, OSM_EVENT_ID_PORT_ERRORS, + &epi_pe_data); + +Exit: + cl_plock_release(&(db->lock)); + return (rc); +} + +perfmgr_db_err_t perfmgr_db_get_prev_err(perfmgr_db_t * db, uint64_t guid, + uint8_t port, + perfmgr_db_err_reading_t * reading) +{ + _db_node_t *node = NULL; + perfmgr_db_err_t rc = PERFMGR_EVENT_DB_SUCCESS; + + cl_plock_acquire(&(db->lock)); + + node = _get(db, guid); + if ((rc = bad_node_port(node, port)) != PERFMGR_EVENT_DB_SUCCESS) + goto Exit; + + *reading = node->ports[port].err_previous; + +Exit: + cl_plock_release(&(db->lock)); + return (rc); +} + +perfmgr_db_err_t +perfmgr_db_clear_prev_err(perfmgr_db_t * db, uint64_t guid, uint8_t port) +{ + _db_node_t *node = NULL; + perfmgr_db_err_reading_t *previous = NULL; + perfmgr_db_err_t rc = PERFMGR_EVENT_DB_SUCCESS; + + cl_plock_excl_acquire(&(db->lock)); + node = _get(db, guid); + if ((rc = bad_node_port(node, port)) != PERFMGR_EVENT_DB_SUCCESS) + goto Exit; + + previous = &(node->ports[port].err_previous); + + memset(previous, 0, sizeof(*previous)); + node->ports[port].err_previous.time = time(NULL); + +Exit: + cl_plock_release(&(db->lock)); + return (rc); +} + +static inline void +debug_dump_dc_reading(perfmgr_db_t * db, uint64_t guid, uint8_t port_num, + _db_port_t * port, perfmgr_db_data_cnt_reading_t * cur) +{ + osm_log_t *log = db->perfmgr->log; + if (!osm_log_is_active(log, OSM_LOG_DEBUG)) + return; /* optimize this a big */ + + osm_log(log, OSM_LOG_DEBUG, + "xd %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", + cur->xmit_data, port->dc_previous.xmit_data, + port->dc_total.xmit_data); + osm_log(log, OSM_LOG_DEBUG, + "rd %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", cur->rcv_data, + port->dc_previous.rcv_data, port->dc_total.rcv_data); + osm_log(log, OSM_LOG_DEBUG, + "xp %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", + cur->xmit_pkts, port->dc_previous.xmit_pkts, + port->dc_total.xmit_pkts); + osm_log(log, OSM_LOG_DEBUG, + "rp %" PRIu64 " <-- %" PRIu64 " (%" PRIu64 ")\n", cur->rcv_pkts, + port->dc_previous.rcv_pkts, port->dc_total.rcv_pkts); +} + +/********************************************************************** + * perfmgr_db_data_cnt_reading_t functions + **********************************************************************/ +perfmgr_db_err_t +perfmgr_db_add_dc_reading(perfmgr_db_t * db, uint64_t guid, + uint8_t port, perfmgr_db_data_cnt_reading_t * reading) +{ + _db_port_t *p_port = NULL; + _db_node_t *node = NULL; + perfmgr_db_data_cnt_reading_t *previous = NULL; + perfmgr_db_err_t rc = PERFMGR_EVENT_DB_SUCCESS; + osm_epi_dc_event_t epi_dc_data; + + cl_plock_excl_acquire(&(db->lock)); + node = _get(db, guid); + if ((rc = bad_node_port(node, port)) != PERFMGR_EVENT_DB_SUCCESS) + goto Exit; + + p_port = &(node->ports[port]); + previous = &(node->ports[port].dc_previous); + + debug_dump_dc_reading(db, guid, port, p_port, reading); + + epi_dc_data.time_diff_s = (reading->time - previous->time); + osm_epi_create_port_id(&(epi_dc_data.port_id), guid, port, + node->node_name); + + /* calculate changes from previous reading */ + epi_dc_data.xmit_data = (reading->xmit_data - previous->xmit_data); + p_port->dc_total.xmit_data += epi_dc_data.xmit_data; + epi_dc_data.rcv_data = (reading->rcv_data - previous->rcv_data); + p_port->dc_total.rcv_data += epi_dc_data.rcv_data; + epi_dc_data.xmit_pkts = (reading->xmit_pkts - previous->xmit_pkts); + p_port->dc_total.xmit_pkts += epi_dc_data.xmit_pkts; + epi_dc_data.rcv_pkts = (reading->rcv_pkts - previous->rcv_pkts); + p_port->dc_total.rcv_pkts += epi_dc_data.rcv_pkts; + epi_dc_data.unicast_xmit_pkts = + (reading->unicast_xmit_pkts - previous->unicast_xmit_pkts); + p_port->dc_total.unicast_xmit_pkts += epi_dc_data.unicast_xmit_pkts; + epi_dc_data.unicast_rcv_pkts = + (reading->unicast_rcv_pkts - previous->unicast_rcv_pkts); + p_port->dc_total.unicast_rcv_pkts += epi_dc_data.unicast_rcv_pkts; + epi_dc_data.multicast_xmit_pkts = + (reading->multicast_xmit_pkts - previous->multicast_xmit_pkts); + p_port->dc_total.multicast_xmit_pkts += epi_dc_data.multicast_xmit_pkts; + epi_dc_data.multicast_rcv_pkts = + (reading->multicast_rcv_pkts - previous->multicast_rcv_pkts); + p_port->dc_total.multicast_rcv_pkts += epi_dc_data.multicast_rcv_pkts; + + p_port->dc_previous = *reading; + + osm_opensm_report_event(db->perfmgr->osm, + OSM_EVENT_ID_PORT_DATA_COUNTERS, &epi_dc_data); + +Exit: + cl_plock_release(&(db->lock)); + return (rc); +} + +perfmgr_db_err_t perfmgr_db_get_prev_dc(perfmgr_db_t * db, uint64_t guid, + uint8_t port, + perfmgr_db_data_cnt_reading_t * reading) +{ + _db_node_t *node = NULL; + perfmgr_db_err_t rc = PERFMGR_EVENT_DB_SUCCESS; + + cl_plock_acquire(&(db->lock)); + + node = _get(db, guid); + if ((rc = bad_node_port(node, port)) != PERFMGR_EVENT_DB_SUCCESS) + goto Exit; + + *reading = node->ports[port].dc_previous; + +Exit: + cl_plock_release(&(db->lock)); + return (rc); +} + +perfmgr_db_err_t +perfmgr_db_clear_prev_dc(perfmgr_db_t * db, uint64_t guid, uint8_t port) +{ + _db_node_t *node = NULL; + perfmgr_db_data_cnt_reading_t *previous = NULL; + perfmgr_db_err_t rc = PERFMGR_EVENT_DB_SUCCESS; + + cl_plock_excl_acquire(&(db->lock)); + node = _get(db, guid); + if ((rc = bad_node_port(node, port)) != PERFMGR_EVENT_DB_SUCCESS) + goto Exit; + + previous = &(node->ports[port].dc_previous); + + memset(previous, 0, sizeof(*previous)); + node->ports[port].dc_previous.time = time(NULL); + +Exit: + cl_plock_release(&(db->lock)); + return (rc); +} + +static void __clear_counters(cl_map_item_t * const p_map_item, void *context) +{ + _db_node_t *node = (_db_node_t *) p_map_item; + int i = 0; + time_t ts = time(NULL); + + for (i = 0; i < node->num_ports; i++) { + node->ports[i].err_total.symbol_err_cnt = 0; + node->ports[i].err_total.link_err_recover = 0; + node->ports[i].err_total.link_downed = 0; + node->ports[i].err_total.rcv_err = 0; + node->ports[i].err_total.rcv_rem_phys_err = 0; + node->ports[i].err_total.rcv_switch_relay_err = 0; + node->ports[i].err_total.xmit_discards = 0; + node->ports[i].err_total.xmit_constraint_err = 0; + node->ports[i].err_total.rcv_constraint_err = 0; + node->ports[i].err_total.link_integrity = 0; + node->ports[i].err_total.buffer_overrun = 0; + node->ports[i].err_total.vl15_dropped = 0; + node->ports[i].err_total.time = ts; + + node->ports[i].dc_total.xmit_data = 0; + node->ports[i].dc_total.rcv_data = 0; + node->ports[i].dc_total.xmit_pkts = 0; + node->ports[i].dc_total.rcv_pkts = 0; + node->ports[i].dc_total.unicast_xmit_pkts = 0; + node->ports[i].dc_total.unicast_rcv_pkts = 0; + node->ports[i].dc_total.multicast_xmit_pkts = 0; + node->ports[i].dc_total.multicast_rcv_pkts = 0; + node->ports[i].dc_total.time = ts; + + node->ports[i].last_reset = ts; + } +} + +/********************************************************************** + * Clear all the counters from the db + **********************************************************************/ +void perfmgr_db_clear_counters(perfmgr_db_t * db) +{ + cl_plock_excl_acquire(&(db->lock)); + cl_qmap_apply_func(&(db->pc_data), __clear_counters, (void *)db); + cl_plock_release(&(db->lock)); +#if 0 + if (db->db_impl->clear_counters) + db->db_impl->clear_counters(db->db_data); +#endif +} + +/********************************************************************** + * Output a tab delimited output of the port counters + **********************************************************************/ +static void __dump_node_mr(_db_node_t * node, FILE * fp) +{ + int i = 0; + + fprintf(fp, "\nName\tGUID\tPort\tLast Reset\t" + "%s\t%s\t" + "%s\t%s\t%s\t%s\t%s\t%s\t%s\t" + "%s\t%s\t%s\t%s\t%s\t%s\t%s\t" + "%s\t%s\t%s\t%s\n", + "symbol_err_cnt", + "link_err_recover", + "link_downed", + "rcv_err", + "rcv_rem_phys_err", + "rcv_switch_relay_err", + "xmit_discards", + "xmit_constraint_err", + "rcv_constraint_err", + "link_int_err", + "buf_overrun_err", + "vl15_dropped", + "xmit_data", + "rcv_data", + "xmit_pkts", + "rcv_pkts", + "unicast_xmit_pkts", + "unicast_rcv_pkts", + "multicast_xmit_pkts", "multicast_rcv_pkts"); + for (i = 1; i < node->num_ports; i++) { + char *since = ctime(&(node->ports[i].last_reset)); + since[strlen(since) - 1] = '\0'; /* remove \n */ + + fprintf(fp, + "%s\t0x%" PRIx64 "\t%d\t%s\t%" PRIu64 "\t%" PRIu64 "\t" + "%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t" + "%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t" "%" PRIu64 + "\t%" PRIu64 "\t%" PRIu64 "\t" "%" PRIu64 "\t%" PRIu64 + "\t%" PRIu64 "\t%" PRIu64 "\t" "%" PRIu64 "\t%" PRIu64 + "\t%" PRIu64 "\t%" PRIu64 "\n", node->node_name, + node->node_guid, i, since, + node->ports[i].err_total.symbol_err_cnt, + node->ports[i].err_total.link_err_recover, + node->ports[i].err_total.link_downed, + node->ports[i].err_total.rcv_err, + node->ports[i].err_total.rcv_rem_phys_err, + node->ports[i].err_total.rcv_switch_relay_err, + node->ports[i].err_total.xmit_discards, + node->ports[i].err_total.xmit_constraint_err, + node->ports[i].err_total.rcv_constraint_err, + node->ports[i].err_total.link_integrity, + node->ports[i].err_total.buffer_overrun, + node->ports[i].err_total.vl15_dropped, + node->ports[i].dc_total.xmit_data, + node->ports[i].dc_total.rcv_data, + node->ports[i].dc_total.xmit_pkts, + node->ports[i].dc_total.rcv_pkts, + node->ports[i].dc_total.unicast_xmit_pkts, + node->ports[i].dc_total.unicast_rcv_pkts, + node->ports[i].dc_total.multicast_xmit_pkts, + node->ports[i].dc_total.multicast_rcv_pkts); + } +} + +/********************************************************************** + * Output a human readable output of the port counters + **********************************************************************/ +static void __dump_node_hr(_db_node_t * node, FILE * fp) +{ + int i = 0; + + fprintf(fp, "\n"); + for (i = 1; i < node->num_ports; i++) { + char *since = ctime(&(node->ports[i].last_reset)); + since[strlen(since) - 1] = '\0'; /* remove \n */ + + fprintf(fp, "\"%s\" 0x%" PRIx64 " port %d (Since %s)\n" + " symbol_err_cnt : %" PRIu64 "\n" + " link_err_recover : %" PRIu64 "\n" + " link_downed : %" PRIu64 "\n" + " rcv_err : %" PRIu64 "\n" + " rcv_rem_phys_err : %" PRIu64 "\n" + " rcv_switch_relay_err : %" PRIu64 "\n" + " xmit_discards : %" PRIu64 "\n" + " xmit_constraint_err : %" PRIu64 "\n" + " rcv_constraint_err : %" PRIu64 "\n" + " link_integrity_err : %" PRIu64 "\n" + " buf_overrun_err : %" PRIu64 "\n" + " vl15_dropped : %" PRIu64 "\n" + " xmit_data : %" PRIu64 "\n" + " rcv_data : %" PRIu64 "\n" + " xmit_pkts : %" PRIu64 "\n" + " rcv_pkts : %" PRIu64 "\n" + " unicast_xmit_pkts : %" PRIu64 "\n" + " unicast_rcv_pkts : %" PRIu64 "\n" + " multicast_xmit_pkts : %" PRIu64 "\n" + " multicast_rcv_pkts : %" PRIu64 "\n", + node->node_name, + node->node_guid, + i, + since, + node->ports[i].err_total.symbol_err_cnt, + node->ports[i].err_total.link_err_recover, + node->ports[i].err_total.link_downed, + node->ports[i].err_total.rcv_err, + node->ports[i].err_total.rcv_rem_phys_err, + node->ports[i].err_total.rcv_switch_relay_err, + node->ports[i].err_total.xmit_discards, + node->ports[i].err_total.xmit_constraint_err, + node->ports[i].err_total.rcv_constraint_err, + node->ports[i].err_total.link_integrity, + node->ports[i].err_total.buffer_overrun, + node->ports[i].err_total.vl15_dropped, + node->ports[i].dc_total.xmit_data, + node->ports[i].dc_total.rcv_data, + node->ports[i].dc_total.xmit_pkts, + node->ports[i].dc_total.rcv_pkts, + node->ports[i].dc_total.unicast_xmit_pkts, + node->ports[i].dc_total.unicast_rcv_pkts, + node->ports[i].dc_total.multicast_xmit_pkts, + node->ports[i].dc_total.multicast_rcv_pkts); + } +} + +/* Define a context for the __db_dump callback */ +typedef struct { + FILE *fp; + perfmgr_db_dump_t dump_type; +} dump_context_t; + +/********************************************************************** + **********************************************************************/ +static void __db_dump(cl_map_item_t * const p_map_item, void *context) +{ + _db_node_t *node = (_db_node_t *) p_map_item; + dump_context_t *c = (dump_context_t *) context; + FILE *fp = c->fp; + + switch (c->dump_type) { + case PERFMGR_EVENT_DB_DUMP_MR: + __dump_node_mr(node, fp); + break; + case PERFMGR_EVENT_DB_DUMP_HR: + default: + __dump_node_hr(node, fp); + break; + } +} + +/********************************************************************** + * print node data to fp + **********************************************************************/ +void +perfmgr_db_print_by_name(perfmgr_db_t * db, char *nodename, FILE *fp) +{ + cl_map_item_t *item = NULL; + _db_node_t *node = NULL; + + cl_plock_acquire(&(db->lock)); + + /* find the node */ + item = cl_qmap_head(&(db->pc_data)); + while (item != cl_qmap_end(&(db->pc_data))) { + node = (_db_node_t *)item; + if (strcmp(node->node_name, nodename) == 0) { + __dump_node_hr(node, fp); + goto done; + } + item = cl_qmap_next(item); + } + + fprintf(fp, "Node %s not found...\n", nodename); +done: + cl_plock_release(&(db->lock)); +} + +/********************************************************************** + * print node data to fp + **********************************************************************/ +void +perfmgr_db_print_by_guid(perfmgr_db_t * db, uint64_t nodeguid, FILE *fp) +{ + cl_map_item_t *node = NULL; + + cl_plock_acquire(&(db->lock)); + + node = cl_qmap_get(&(db->pc_data), nodeguid); + if (node != cl_qmap_end(&(db->pc_data))) + __dump_node_hr((_db_node_t *)node, fp); + else + fprintf(fp, "Node %"PRIx64" not found...\n", nodeguid); + + cl_plock_release(&(db->lock)); +} + +/********************************************************************** + * dump the data to the file "file" + **********************************************************************/ +perfmgr_db_err_t +perfmgr_db_dump(perfmgr_db_t * db, char *file, perfmgr_db_dump_t dump_type) +{ + dump_context_t context; + + context.fp = fopen(file, "w+"); + if (!context.fp) + return (PERFMGR_EVENT_DB_FAIL); + context.dump_type = dump_type; + + cl_plock_acquire(&(db->lock)); + cl_qmap_apply_func(&(db->pc_data), __db_dump, (void *)&context); + cl_plock_release(&(db->lock)); + fclose(context.fp); + return (PERFMGR_EVENT_DB_SUCCESS); +} + +/********************************************************************** + * Fill in the various DB objects from their wire counter parts + **********************************************************************/ +void +perfmgr_db_fill_err_read(ib_port_counters_t * wire_read, + perfmgr_db_err_reading_t * reading) +{ + reading->symbol_err_cnt = cl_ntoh16(wire_read->symbol_err_cnt); + reading->link_err_recover = cl_ntoh16(wire_read->link_err_recover); + reading->link_downed = wire_read->link_downed; + reading->rcv_err = wire_read->rcv_err; + reading->rcv_rem_phys_err = cl_ntoh16(wire_read->rcv_rem_phys_err); + reading->rcv_switch_relay_err = + cl_ntoh16(wire_read->rcv_switch_relay_err); + reading->xmit_discards = cl_ntoh16(wire_read->xmit_discards); + reading->xmit_constraint_err = + cl_ntoh16(wire_read->xmit_constraint_err); + reading->rcv_constraint_err = wire_read->rcv_constraint_err; + reading->link_integrity = + PC_LINK_INT(wire_read->link_int_buffer_overrun); + reading->buffer_overrun = + PC_BUF_OVERRUN(wire_read->link_int_buffer_overrun); + reading->vl15_dropped = cl_ntoh16(wire_read->vl15_dropped); + reading->time = time(NULL); +} + +void +perfmgr_db_fill_data_cnt_read_pc(ib_port_counters_t * wire_read, + perfmgr_db_data_cnt_reading_t * reading) +{ + reading->xmit_data = cl_ntoh32(wire_read->xmit_data); + reading->rcv_data = cl_ntoh32(wire_read->rcv_data); + reading->xmit_pkts = cl_ntoh32(wire_read->xmit_pkts); + reading->rcv_pkts = cl_ntoh32(wire_read->rcv_pkts); + reading->unicast_xmit_pkts = 0; + reading->unicast_rcv_pkts = 0; + reading->multicast_xmit_pkts = 0; + reading->multicast_rcv_pkts = 0; + reading->time = time(NULL); +} + +void +perfmgr_db_fill_data_cnt_read_epc(ib_port_counters_ext_t * wire_read, + perfmgr_db_data_cnt_reading_t * reading) +{ + reading->xmit_data = cl_ntoh64(wire_read->xmit_data); + reading->rcv_data = cl_ntoh64(wire_read->rcv_data); + reading->xmit_pkts = cl_ntoh64(wire_read->xmit_pkts); + reading->rcv_pkts = cl_ntoh64(wire_read->rcv_pkts); + reading->unicast_xmit_pkts = cl_ntoh64(wire_read->unicast_xmit_pkts); + reading->unicast_rcv_pkts = cl_ntoh64(wire_read->unicast_rcv_pkts); + reading->multicast_xmit_pkts = + cl_ntoh64(wire_read->multicast_xmit_pkts); + reading->multicast_rcv_pkts = cl_ntoh64(wire_read->multicast_rcv_pkts); + reading->time = time(NULL); +} +#endif /* ENABLE_OSM_PERF_MGR */ diff --git a/contrib/ofed/management/opensm/opensm/osm_pkey.c b/contrib/ofed/management/opensm/opensm/osm_pkey.c new file mode 100644 index 000000000000..466618644c1e --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_pkey.c @@ -0,0 +1,467 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of opensm pkey manipulation functions. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void osm_pkey_tbl_construct(IN osm_pkey_tbl_t * p_pkey_tbl) +{ + cl_ptr_vector_construct(&p_pkey_tbl->blocks); + cl_ptr_vector_construct(&p_pkey_tbl->new_blocks); + cl_map_construct(&p_pkey_tbl->keys); +} + +/********************************************************************** + **********************************************************************/ +void osm_pkey_tbl_destroy(IN osm_pkey_tbl_t * p_pkey_tbl) +{ + ib_pkey_table_t *p_block; + uint16_t num_blocks, i; + + num_blocks = (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->blocks)); + for (i = 0; i < num_blocks; i++) + if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, i))) + free(p_block); + cl_ptr_vector_destroy(&p_pkey_tbl->blocks); + + num_blocks = + (uint16_t) (cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks)); + for (i = 0; i < num_blocks; i++) + if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, i))) + free(p_block); + cl_ptr_vector_destroy(&p_pkey_tbl->new_blocks); + + cl_map_remove_all(&p_pkey_tbl->keys); + cl_map_destroy(&p_pkey_tbl->keys); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t osm_pkey_tbl_init(IN osm_pkey_tbl_t * p_pkey_tbl) +{ + cl_ptr_vector_init(&p_pkey_tbl->blocks, 0, 1); + cl_ptr_vector_init(&p_pkey_tbl->new_blocks, 0, 1); + cl_map_init(&p_pkey_tbl->keys, 1); + cl_qlist_init(&p_pkey_tbl->pending); + p_pkey_tbl->used_blocks = 0; + p_pkey_tbl->max_blocks = 0; + return (IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +void osm_pkey_tbl_init_new_blocks(IN const osm_pkey_tbl_t * p_pkey_tbl) +{ + ib_pkey_table_t *p_block; + size_t b, num_blocks = cl_ptr_vector_get_size(&p_pkey_tbl->new_blocks); + + for (b = 0; b < num_blocks; b++) + if ((p_block = cl_ptr_vector_get(&p_pkey_tbl->new_blocks, b))) + memset(p_block, 0, sizeof(*p_block)); +} + +/********************************************************************** + **********************************************************************/ +void osm_pkey_tbl_cleanup_pending(IN osm_pkey_tbl_t * p_pkey_tbl) +{ + cl_list_item_t *p_item; + + p_item = cl_qlist_remove_head(&p_pkey_tbl->pending); + while (p_item != cl_qlist_end(&p_pkey_tbl->pending)) { + free((osm_pending_pkey_t *) p_item); + } +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_pkey_tbl_set(IN osm_pkey_tbl_t * p_pkey_tbl, + IN uint16_t block, IN ib_pkey_table_t * p_tbl) +{ + uint16_t b, i; + ib_pkey_table_t *p_pkey_block; + uint16_t *p_prev_pkey; + ib_net16_t pkey; + + /* make sure the block is allocated */ + if (cl_ptr_vector_get_size(&p_pkey_tbl->blocks) > block) + p_pkey_block = + (ib_pkey_table_t *) cl_ptr_vector_get(&p_pkey_tbl->blocks, + block); + else + p_pkey_block = NULL; + + if (!p_pkey_block) { + p_pkey_block = + (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t)); + if (!p_pkey_block) + return (IB_ERROR); + memset(p_pkey_block, 0, sizeof(ib_pkey_table_t)); + cl_ptr_vector_set(&p_pkey_tbl->blocks, block, p_pkey_block); + } + + /* sets the block values */ + memcpy(p_pkey_block, p_tbl, sizeof(ib_pkey_table_t)); + + /* + NOTE: as the spec does not require uniqueness of PKeys in + tables there is no other way but to refresh the entire keys map. + + Moreover, if the same key exists but with full membership it should + have precedence on the key with limited membership ! + */ + cl_map_remove_all(&p_pkey_tbl->keys); + + for (b = 0; b < cl_ptr_vector_get_size(&p_pkey_tbl->blocks); b++) { + + p_pkey_block = cl_ptr_vector_get(&p_pkey_tbl->blocks, b); + if (!p_pkey_block) + continue; + + for (i = 0; i < IB_NUM_PKEY_ELEMENTS_IN_BLOCK; i++) { + pkey = p_pkey_block->pkey_entry[i]; + if (ib_pkey_is_invalid(pkey)) + continue; + + /* + ignore the PKey Full Member bit in the key but store + the pointer to the table element as the map value + */ + p_prev_pkey = + cl_map_get(&p_pkey_tbl->keys, + ib_pkey_get_base(pkey)); + + /* we only insert if no previous or it is not full member */ + if ((p_prev_pkey == NULL) || + (cl_ntoh16(*p_prev_pkey) < cl_ntoh16(pkey))) + cl_map_insert(&p_pkey_tbl->keys, + ib_pkey_get_base(pkey), + &(p_pkey_block->pkey_entry[i]) + ); + } + } + return (IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +/* + Store the given pkey in the "new" blocks array. + Also, make sure the regular block exists. +*/ +ib_api_status_t +osm_pkey_tbl_set_new_entry(IN osm_pkey_tbl_t * p_pkey_tbl, + IN uint16_t block_idx, + IN uint8_t pkey_idx, IN uint16_t pkey) +{ + ib_pkey_table_t *p_block; + + if (!(p_block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_idx))) { + p_block = (ib_pkey_table_t *) malloc(sizeof(ib_pkey_table_t)); + if (!p_block) + return (IB_ERROR); + memset(p_block, 0, sizeof(ib_pkey_table_t)); + cl_ptr_vector_set(&p_pkey_tbl->new_blocks, block_idx, p_block); + } + + p_block->pkey_entry[pkey_idx] = pkey; + if (p_pkey_tbl->used_blocks <= block_idx) + p_pkey_tbl->used_blocks = block_idx + 1; + + return (IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_pkey_find_next_free_entry(IN osm_pkey_tbl_t * p_pkey_tbl, + OUT uint16_t * p_block_idx, + OUT uint8_t * p_pkey_idx) +{ + ib_pkey_table_t *p_new_block; + + CL_ASSERT(p_block_idx); + CL_ASSERT(p_pkey_idx); + + while (*p_block_idx < p_pkey_tbl->max_blocks) { + if (*p_pkey_idx > IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) { + *p_pkey_idx = 0; + (*p_block_idx)++; + if (*p_block_idx >= p_pkey_tbl->max_blocks) + return FALSE; + } + + p_new_block = + osm_pkey_tbl_new_block_get(p_pkey_tbl, *p_block_idx); + + if (!p_new_block || + ib_pkey_is_invalid(p_new_block->pkey_entry[*p_pkey_idx])) + return TRUE; + else + (*p_pkey_idx)++; + } + return FALSE; +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_pkey_tbl_get_block_and_idx(IN osm_pkey_tbl_t * p_pkey_tbl, + IN uint16_t * p_pkey, + OUT uint16_t * p_block_idx, + OUT uint8_t * p_pkey_idx) +{ + uint16_t num_of_blocks; + uint16_t block_index; + ib_pkey_table_t *block; + + CL_ASSERT(p_block_idx != NULL); + CL_ASSERT(p_pkey_idx != NULL); + + num_of_blocks = (uint16_t) cl_ptr_vector_get_size(&p_pkey_tbl->blocks); + for (block_index = 0; block_index < num_of_blocks; block_index++) { + block = osm_pkey_tbl_block_get(p_pkey_tbl, block_index); + if ((block->pkey_entry <= p_pkey) && + (p_pkey < + block->pkey_entry + IB_NUM_PKEY_ELEMENTS_IN_BLOCK)) { + *p_block_idx = block_index; + *p_pkey_idx = (uint8_t) (p_pkey - block->pkey_entry); + return (IB_SUCCESS); + } + } + return (IB_NOT_FOUND); +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +__osm_match_pkey(IN const ib_net16_t * pkey1, IN const ib_net16_t * pkey2) +{ + + /* if both pkeys are not full member - this is not a match */ + if (!(ib_pkey_is_full_member(*pkey1) || ib_pkey_is_full_member(*pkey2))) + return (FALSE); + + /* compare if the bases are the same. if they are - then + this is a match */ + if (ib_pkey_get_base(*pkey1) != ib_pkey_get_base(*pkey2)) + return (FALSE); + + return (TRUE); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_physp_share_this_pkey(IN const osm_physp_t * const p_physp1, + IN const osm_physp_t * const p_physp2, + IN const ib_net16_t pkey) +{ + ib_net16_t *pkey1, *pkey2; + + pkey1 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp1))->keys, + ib_pkey_get_base(pkey)); + pkey2 = cl_map_get(&(osm_physp_get_pkey_tbl(p_physp2))->keys, + ib_pkey_get_base(pkey)); + return (pkey1 && pkey2 && __osm_match_pkey(pkey1, pkey2)); +} + +/********************************************************************** + **********************************************************************/ +ib_net16_t +osm_physp_find_common_pkey(IN const osm_physp_t * const p_physp1, + IN const osm_physp_t * const p_physp2) +{ + ib_net16_t *pkey1, *pkey2; + uint64_t pkey1_base, pkey2_base; + const osm_pkey_tbl_t *pkey_tbl1, *pkey_tbl2; + cl_map_iterator_t map_iter1, map_iter2; + + pkey_tbl1 = osm_physp_get_pkey_tbl(p_physp1); + pkey_tbl2 = osm_physp_get_pkey_tbl(p_physp2); + + map_iter1 = cl_map_head(&pkey_tbl1->keys); + map_iter2 = cl_map_head(&pkey_tbl2->keys); + + /* we rely on the fact the map are sorted by pkey */ + while ((map_iter1 != cl_map_end(&pkey_tbl1->keys)) && + (map_iter2 != cl_map_end(&pkey_tbl2->keys))) { + pkey1 = (ib_net16_t *) cl_map_obj(map_iter1); + pkey2 = (ib_net16_t *) cl_map_obj(map_iter2); + + if (__osm_match_pkey(pkey1, pkey2)) + return *pkey1; + + /* advance the lower value if they are not equal */ + pkey1_base = cl_map_key(map_iter1); + pkey2_base = cl_map_key(map_iter2); + if (pkey2_base == pkey1_base) { + map_iter1 = cl_map_next(map_iter1); + map_iter2 = cl_map_next(map_iter2); + } else if (pkey2_base < pkey1_base) + map_iter2 = cl_map_next(map_iter2); + else + map_iter1 = cl_map_next(map_iter1); + } + + return 0; +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_physp_share_pkey(IN osm_log_t * p_log, + IN const osm_physp_t * const p_physp_1, + IN const osm_physp_t * const p_physp_2) +{ + const osm_pkey_tbl_t *pkey_tbl1, *pkey_tbl2; + + if (p_physp_1 == p_physp_2) + return TRUE; + + pkey_tbl1 = osm_physp_get_pkey_tbl(p_physp_1); + pkey_tbl2 = osm_physp_get_pkey_tbl(p_physp_2); + + /* + The spec: 10.9.2 does not require each phys port to have PKey Table. + So actually if it does not, we need to use the default port instead. + + HACK: meanwhile we will ignore the check + */ + if (cl_is_map_empty(&pkey_tbl1->keys) + || cl_is_map_empty(&pkey_tbl2->keys)) + return TRUE; + + return + !ib_pkey_is_invalid(osm_physp_find_common_pkey + (p_physp_1, p_physp_2)); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_port_share_pkey(IN osm_log_t * p_log, + IN const osm_port_t * const p_port_1, + IN const osm_port_t * const p_port_2) +{ + + osm_physp_t *p_physp1, *p_physp2; + boolean_t ret; + + OSM_LOG_ENTER(p_log); + + if (!p_port_1 || !p_port_2) { + ret = FALSE; + goto Exit; + } + + p_physp1 = p_port_1->p_physp; + p_physp2 = p_port_2->p_physp; + + if (!p_physp1 || !p_physp2) { + ret = FALSE; + goto Exit; + } + + ret = osm_physp_share_pkey(p_log, p_physp1, p_physp2); + +Exit: + OSM_LOG_EXIT(p_log); + return ret; +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_physp_has_pkey(IN osm_log_t * p_log, + IN const ib_net16_t pkey, + IN const osm_physp_t * const p_physp) +{ + + ib_net16_t *p_pkey, pkey_base; + const osm_pkey_tbl_t *pkey_tbl; + boolean_t res = FALSE; + + OSM_LOG_ENTER(p_log); + + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Search for PKey: 0x%04x\n", cl_ntoh16(pkey)); + + /* if the pkey given is an invalid pkey - return TRUE. */ + if (ib_pkey_is_invalid(pkey)) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Given invalid PKey - we treat it loosely and allow it\n"); + res = TRUE; + goto Exit; + } + + pkey_base = ib_pkey_get_base(pkey); + + pkey_tbl = osm_physp_get_pkey_tbl(p_physp); + + p_pkey = cl_map_get(&pkey_tbl->keys, pkey_base); + if (p_pkey) { + res = TRUE; + OSM_LOG(p_log, OSM_LOG_DEBUG, + "PKey 0x%04x was found\n", cl_ntoh16(pkey)); + } else { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "PKey 0x%04x was not found\n", cl_ntoh16(pkey)); + } + +Exit: + OSM_LOG_EXIT(p_log); + return res; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_pkey_mgr.c b/contrib/ofed/management/opensm/opensm/osm_pkey_mgr.c new file mode 100644 index 000000000000..ae16eb66b9b2 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_pkey_mgr.c @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of the P_Key Manager (Partititon Manager). + * This is part of the OpenSM. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +/* + The max number of pkey blocks for a physical port is located in + a different place for switch external ports (SwitchInfo) and the + rest of the ports (NodeInfo). +*/ +static uint16_t +pkey_mgr_get_physp_max_blocks(IN const osm_subn_t * p_subn, + IN const osm_physp_t * p_physp) +{ + osm_node_t *p_node = osm_physp_get_node_ptr(p_physp); + uint16_t num_pkeys = 0; + + if (!p_node->sw || (osm_physp_get_port_num(p_physp) == 0)) + num_pkeys = cl_ntoh16(p_node->node_info.partition_cap); + else + num_pkeys = cl_ntoh16(p_node->sw->switch_info.enforce_cap); + return ((num_pkeys + 31) / 32); +} + +/********************************************************************** + **********************************************************************/ +/* + * Insert new pending pkey entry to the specific port pkey table + * pending pkeys. New entries are inserted at the back. + */ +static void +pkey_mgr_process_physical_port(IN osm_log_t * p_log, + IN osm_sm_t * sm, + IN const ib_net16_t pkey, + IN osm_physp_t * p_physp) +{ + osm_node_t *p_node = osm_physp_get_node_ptr(p_physp); + osm_pkey_tbl_t *p_pkey_tbl; + ib_net16_t *p_orig_pkey; + char *stat = NULL; + osm_pending_pkey_t *p_pending; + + p_pkey_tbl = &p_physp->pkeys; + p_pending = (osm_pending_pkey_t *) malloc(sizeof(osm_pending_pkey_t)); + if (!p_pending) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0502: " + "Failed to allocate new pending pkey entry for node " + "0x%016" PRIx64 " port %u\n", + cl_ntoh64(osm_node_get_node_guid(p_node)), + osm_physp_get_port_num(p_physp)); + return; + } + p_pending->pkey = pkey; + p_orig_pkey = cl_map_get(&p_pkey_tbl->keys, ib_pkey_get_base(pkey)); + if (!p_orig_pkey) { + p_pending->is_new = TRUE; + cl_qlist_insert_tail(&p_pkey_tbl->pending, + (cl_list_item_t *) p_pending); + stat = "inserted"; + } else { + CL_ASSERT(ib_pkey_get_base(*p_orig_pkey) == + ib_pkey_get_base(pkey)); + p_pending->is_new = FALSE; + if (osm_pkey_tbl_get_block_and_idx(p_pkey_tbl, p_orig_pkey, + &p_pending->block, + &p_pending->index) != + IB_SUCCESS) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0503: " + "Failed to obtain P_Key 0x%04x block and index for node " + "0x%016" PRIx64 " port %u\n", + ib_pkey_get_base(pkey), + cl_ntoh64(osm_node_get_node_guid(p_node)), + osm_physp_get_port_num(p_physp)); + return; + } + cl_qlist_insert_head(&p_pkey_tbl->pending, + (cl_list_item_t *) p_pending); + stat = "updated"; + } + + OSM_LOG(p_log, OSM_LOG_DEBUG, + "pkey 0x%04x was %s for node 0x%016" PRIx64 " port %u\n", + cl_ntoh16(pkey), stat, + cl_ntoh64(osm_node_get_node_guid(p_node)), + osm_physp_get_port_num(p_physp)); +} + +/********************************************************************** + **********************************************************************/ +static void +pkey_mgr_process_partition_table(osm_log_t * p_log, osm_sm_t * sm, + const osm_prtn_t * p_prtn, + const boolean_t full) +{ + const cl_map_t *p_tbl = + full ? &p_prtn->full_guid_tbl : &p_prtn->part_guid_tbl; + cl_map_iterator_t i, i_next; + ib_net16_t pkey = p_prtn->pkey; + osm_physp_t *p_physp; + + if (full) + pkey |= cl_hton16(0x8000); + + i_next = cl_map_head(p_tbl); + while (i_next != cl_map_end(p_tbl)) { + i = i_next; + i_next = cl_map_next(i); + p_physp = cl_map_obj(i); + if (p_physp) + pkey_mgr_process_physical_port(p_log, sm, pkey, + p_physp); + } +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +pkey_mgr_update_pkey_entry(IN osm_sm_t * sm, + IN const osm_physp_t * p_physp, + IN const ib_pkey_table_t * block, + IN const uint16_t block_index) +{ + osm_madw_context_t context; + osm_node_t *p_node = osm_physp_get_node_ptr(p_physp); + uint32_t attr_mod; + + context.pkey_context.node_guid = osm_node_get_node_guid(p_node); + context.pkey_context.port_guid = osm_physp_get_port_guid(p_physp); + context.pkey_context.set_method = TRUE; + attr_mod = block_index; + if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) + attr_mod |= osm_physp_get_port_num(p_physp) << 16; + return osm_req_set(sm, osm_physp_get_dr_path_ptr(p_physp), + (uint8_t *) block, sizeof(*block), + IB_MAD_ATTR_P_KEY_TABLE, + cl_hton32(attr_mod), CL_DISP_MSGID_NONE, &context); +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +pkey_mgr_enforce_partition(IN osm_log_t * p_log, osm_sm_t * sm, + IN osm_physp_t * p_physp, IN const boolean_t enforce) +{ + osm_madw_context_t context; + uint8_t payload[IB_SMP_DATA_SIZE]; + ib_port_info_t *p_pi; + ib_api_status_t status; + + p_pi = &p_physp->port_info; + + if ((p_pi->vl_enforce & 0xc) == (0xc) * (enforce == TRUE)) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "No need to update PortInfo for " + "node 0x%016" PRIx64 " port %u\n", + cl_ntoh64(osm_node_get_node_guid + (osm_physp_get_node_ptr(p_physp))), + osm_physp_get_port_num(p_physp)); + return FALSE; + } + + memset(payload, 0, IB_SMP_DATA_SIZE); + memcpy(payload, p_pi, sizeof(ib_port_info_t)); + + p_pi = (ib_port_info_t *) payload; + if (enforce == TRUE) + p_pi->vl_enforce |= 0xc; + else + p_pi->vl_enforce &= ~0xc; + p_pi->state_info2 = 0; + ib_port_info_set_port_state(p_pi, IB_LINK_NO_CHANGE); + + context.pi_context.node_guid = + osm_node_get_node_guid(osm_physp_get_node_ptr(p_physp)); + context.pi_context.port_guid = osm_physp_get_port_guid(p_physp); + context.pi_context.set_method = TRUE; + context.pi_context.light_sweep = FALSE; + context.pi_context.active_transition = FALSE; + + status = osm_req_set(sm, osm_physp_get_dr_path_ptr(p_physp), + payload, sizeof(payload), + IB_MAD_ATTR_PORT_INFO, + cl_hton32(osm_physp_get_port_num(p_physp)), + CL_DISP_MSGID_NONE, &context); + if (status != IB_SUCCESS) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0511: " + "Failed to set PortInfo for " + "node 0x%016" PRIx64 " port %u\n", + cl_ntoh64(osm_node_get_node_guid + (osm_physp_get_node_ptr(p_physp))), + osm_physp_get_port_num(p_physp)); + return FALSE; + } else { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Set PortInfo for node 0x%016" PRIx64 " port %u\n", + cl_ntoh64(osm_node_get_node_guid + (osm_physp_get_node_ptr(p_physp))), + osm_physp_get_port_num(p_physp)); + return TRUE; + } +} + +/********************************************************************** + **********************************************************************/ +static boolean_t pkey_mgr_update_port(osm_log_t * p_log, osm_sm_t * sm, + const osm_port_t * const p_port) +{ + osm_physp_t *p_physp; + osm_node_t *p_node; + ib_pkey_table_t *block, *new_block; + osm_pkey_tbl_t *p_pkey_tbl; + uint16_t block_index; + uint8_t pkey_index; + uint16_t last_free_block_index = 0; + uint8_t last_free_pkey_index = 0; + uint16_t num_of_blocks; + uint16_t max_num_of_blocks; + ib_api_status_t status; + boolean_t ret_val = FALSE; + osm_pending_pkey_t *p_pending; + boolean_t found; + ib_pkey_table_t empty_block; + + memset(&empty_block, 0, sizeof(ib_pkey_table_t)); + + p_physp = p_port->p_physp; + if (!p_physp) + return FALSE; + + p_node = osm_physp_get_node_ptr(p_physp); + p_pkey_tbl = &p_physp->pkeys; + num_of_blocks = osm_pkey_tbl_get_num_blocks(p_pkey_tbl); + max_num_of_blocks = + pkey_mgr_get_physp_max_blocks(sm->p_subn, p_physp); + if (p_pkey_tbl->max_blocks > max_num_of_blocks) { + OSM_LOG(p_log, OSM_LOG_INFO, + "Max number of blocks reduced from %u to %u " + "for node 0x%016" PRIx64 " port %u\n", + p_pkey_tbl->max_blocks, max_num_of_blocks, + cl_ntoh64(osm_node_get_node_guid(p_node)), + osm_physp_get_port_num(p_physp)); + } + p_pkey_tbl->max_blocks = max_num_of_blocks; + + osm_pkey_tbl_init_new_blocks(p_pkey_tbl); + p_pkey_tbl->used_blocks = 0; + + /* + process every pending pkey in order - + first must be "updated" last are "new" + */ + p_pending = + (osm_pending_pkey_t *) cl_qlist_remove_head(&p_pkey_tbl->pending); + while (p_pending != + (osm_pending_pkey_t *) cl_qlist_end(&p_pkey_tbl->pending)) { + if (p_pending->is_new == FALSE) { + block_index = p_pending->block; + pkey_index = p_pending->index; + found = TRUE; + } else { + found = osm_pkey_find_next_free_entry(p_pkey_tbl, + &last_free_block_index, + &last_free_pkey_index); + if (!found) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0504: " + "Failed to find empty space for new pkey 0x%04x " + "for node 0x%016" PRIx64 " port %u\n", + cl_ntoh16(p_pending->pkey), + cl_ntoh64(osm_node_get_node_guid + (p_node)), + osm_physp_get_port_num(p_physp)); + } else { + block_index = last_free_block_index; + pkey_index = last_free_pkey_index++; + } + } + + if (found) { + if (IB_SUCCESS != + osm_pkey_tbl_set_new_entry(p_pkey_tbl, block_index, + pkey_index, + p_pending->pkey)) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0505: " + "Failed to set PKey 0x%04x in block %u idx %u " + "for node 0x%016" PRIx64 " port %u\n", + cl_ntoh16(p_pending->pkey), block_index, + pkey_index, + cl_ntoh64(osm_node_get_node_guid + (p_node)), + osm_physp_get_port_num(p_physp)); + } + } + + free(p_pending); + p_pending = + (osm_pending_pkey_t *) cl_qlist_remove_head(&p_pkey_tbl-> + pending); + } + + /* now look for changes and store */ + for (block_index = 0; block_index < num_of_blocks; block_index++) { + block = osm_pkey_tbl_block_get(p_pkey_tbl, block_index); + new_block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_index); + if (!new_block) + new_block = &empty_block; + if (block && !memcmp(new_block, block, sizeof(*block))) + continue; + + status = + pkey_mgr_update_pkey_entry(sm, p_physp, new_block, + block_index); + if (status == IB_SUCCESS) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Updated pkey table block %d for node 0x%016" + PRIx64 " port %u\n", block_index, + cl_ntoh64(osm_node_get_node_guid(p_node)), + osm_physp_get_port_num(p_physp)); + ret_val = TRUE; + } else { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0506: " + "pkey_mgr_update_pkey_entry() failed to update " + "pkey table block %d for node 0x%016" PRIx64 + " port %u\n", block_index, + cl_ntoh64(osm_node_get_node_guid(p_node)), + osm_physp_get_port_num(p_physp)); + } + } + + return ret_val; +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +pkey_mgr_update_peer_port(osm_log_t * p_log, osm_sm_t * sm, + const osm_subn_t * p_subn, + const osm_port_t * const p_port, boolean_t enforce) +{ + osm_physp_t *p_physp, *peer; + osm_node_t *p_node; + ib_pkey_table_t *block, *peer_block; + const osm_pkey_tbl_t *p_pkey_tbl; + osm_pkey_tbl_t *p_peer_pkey_tbl; + uint16_t block_index; + uint16_t num_of_blocks; + uint16_t peer_max_blocks; + ib_api_status_t status = IB_SUCCESS; + boolean_t ret_val = FALSE; + boolean_t port_info_set = FALSE; + ib_pkey_table_t empty_block; + + memset(&empty_block, 0, sizeof(ib_pkey_table_t)); + + p_physp = p_port->p_physp; + if (!p_physp) + return FALSE; + peer = osm_physp_get_remote(p_physp); + if (!peer) + return FALSE; + p_node = osm_physp_get_node_ptr(peer); + if (!p_node->sw || !p_node->sw->switch_info.enforce_cap) + return FALSE; + + p_pkey_tbl = osm_physp_get_pkey_tbl(p_physp); + p_peer_pkey_tbl = &peer->pkeys; + num_of_blocks = osm_pkey_tbl_get_num_blocks(p_pkey_tbl); + peer_max_blocks = pkey_mgr_get_physp_max_blocks(p_subn, peer); + if (peer_max_blocks < p_pkey_tbl->used_blocks) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0508: " + "Not enough pkey entries (%u < %u) on switch 0x%016" + PRIx64 " port %u. Clearing Enforcement bit\n", + peer_max_blocks, num_of_blocks, + cl_ntoh64(osm_node_get_node_guid(p_node)), + osm_physp_get_port_num(peer)); + enforce = FALSE; + } + + if (pkey_mgr_enforce_partition(p_log, sm, peer, enforce)) + port_info_set = TRUE; + + if (enforce == FALSE) + return port_info_set; + + p_peer_pkey_tbl->used_blocks = p_pkey_tbl->used_blocks; + for (block_index = 0; block_index < p_pkey_tbl->used_blocks; + block_index++) { + block = osm_pkey_tbl_new_block_get(p_pkey_tbl, block_index); + if (!block) + block = &empty_block; + + peer_block = + osm_pkey_tbl_block_get(p_peer_pkey_tbl, block_index); + if (!peer_block + || memcmp(peer_block, block, sizeof(*peer_block))) { + status = + pkey_mgr_update_pkey_entry(sm, peer, block, + block_index); + if (status == IB_SUCCESS) + ret_val = TRUE; + else + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0509: " + "pkey_mgr_update_pkey_entry() failed to update " + "pkey table block %d for node 0x%016" + PRIx64 " port %u\n", block_index, + cl_ntoh64(osm_node_get_node_guid + (p_node)), + osm_physp_get_port_num(peer)); + } + } + + if (ret_val) + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Pkey table was updated for node 0x%016" PRIx64 + " port %u\n", + cl_ntoh64(osm_node_get_node_guid(p_node)), + osm_physp_get_port_num(peer)); + + if (port_info_set) + return TRUE; + return ret_val; +} + +/********************************************************************** + **********************************************************************/ +osm_signal_t osm_pkey_mgr_process(IN osm_opensm_t * p_osm) +{ + cl_qmap_t *p_tbl; + cl_map_item_t *p_next; + osm_prtn_t *p_prtn; + osm_port_t *p_port; + osm_signal_t signal = OSM_SIGNAL_DONE; + + CL_ASSERT(p_osm); + + OSM_LOG_ENTER(&p_osm->log); + + CL_PLOCK_EXCL_ACQUIRE(&p_osm->lock); + + if (osm_prtn_make_partitions(&p_osm->log, &p_osm->subn) != IB_SUCCESS) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 0510: " + "osm_prtn_make_partitions() failed\n"); + goto _err; + } + + /* populate the pending pkey entries by scanning all partitions */ + p_tbl = &p_osm->subn.prtn_pkey_tbl; + p_next = cl_qmap_head(p_tbl); + while (p_next != cl_qmap_end(p_tbl)) { + p_prtn = (osm_prtn_t *) p_next; + p_next = cl_qmap_next(p_next); + pkey_mgr_process_partition_table(&p_osm->log, &p_osm->sm, + p_prtn, FALSE); + pkey_mgr_process_partition_table(&p_osm->log, &p_osm->sm, + p_prtn, TRUE); + } + + /* calculate and set new pkey tables */ + p_tbl = &p_osm->subn.port_guid_tbl; + p_next = cl_qmap_head(p_tbl); + while (p_next != cl_qmap_end(p_tbl)) { + p_port = (osm_port_t *) p_next; + p_next = cl_qmap_next(p_next); + if (pkey_mgr_update_port(&p_osm->log, &p_osm->sm, p_port)) + signal = OSM_SIGNAL_DONE_PENDING; + if ((osm_node_get_type(p_port->p_node) != IB_NODE_TYPE_SWITCH) + && pkey_mgr_update_peer_port(&p_osm->log, &p_osm->sm, + &p_osm->subn, p_port, + !p_osm->subn.opt. + no_partition_enforcement)) + signal = OSM_SIGNAL_DONE_PENDING; + } + +_err: + CL_PLOCK_RELEASE(&p_osm->lock); + OSM_LOG_EXIT(&p_osm->log); + return (signal); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_pkey_rcv.c b/contrib/ofed/management/opensm/opensm/osm_pkey_rcv.c new file mode 100644 index 000000000000..706194183435 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_pkey_rcv.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +/* + * WE MIGHT ONLY RECEIVE GET or SET responses + */ +void osm_pkey_rcv_process(IN void *context, IN void *data) +{ + osm_sm_t *sm = context; + osm_madw_t *p_madw = data; + ib_pkey_table_t *p_pkey_tbl; + ib_smp_t *p_smp; + osm_port_t *p_port; + osm_physp_t *p_physp; + osm_node_t *p_node; + osm_pkey_context_t *p_context; + ib_net64_t port_guid; + ib_net64_t node_guid; + uint8_t port_num; + uint16_t block_num; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + + p_context = osm_madw_get_pkey_context_ptr(p_madw); + p_pkey_tbl = (ib_pkey_table_t *) ib_smp_get_payload_ptr(p_smp); + + port_guid = p_context->port_guid; + node_guid = p_context->node_guid; + + CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_P_KEY_TABLE); + + cl_plock_excl_acquire(sm->p_lock); + p_port = osm_get_port_by_guid(sm->p_subn, port_guid); + if (!p_port) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 4806: " + "No port object for port with GUID 0x%" PRIx64 + "\n\t\t\t\tfor parent node GUID 0x%" PRIx64 + ", TID 0x%" PRIx64 "\n", + cl_ntoh64(port_guid), + cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); + goto Exit; + } + + p_node = p_port->p_node; + CL_ASSERT(p_node); + + block_num = (uint16_t) ((cl_ntoh32(p_smp->attr_mod)) & 0x0000FFFF); + /* in case of a non switch node the attr modifier should be ignored */ + if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) { + port_num = + (uint8_t) (((cl_ntoh32(p_smp->attr_mod)) & 0x00FF0000) >> + 16); + p_physp = osm_node_get_physp_ptr(p_node, port_num); + } else { + p_physp = p_port->p_physp; + port_num = p_physp->port_num; + } + + /* + We do not mind if this is a result of a set or get - all we want is to + update the subnet. + */ + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Got GetResp(PKey) block:%u port_num %u with GUID 0x%" + PRIx64 " for parent node GUID 0x%" PRIx64 ", TID 0x%" + PRIx64 "\n", block_num, port_num, cl_ntoh64(port_guid), + cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); + + /* + Determine if we encountered a new Physical Port. + If so, ignore it. + */ + if (!p_physp) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 4807: " + "Got invalid port number %u\n", port_num); + goto Exit; + } + + osm_dump_pkey_block(sm->p_log, + port_guid, block_num, + port_num, p_pkey_tbl, OSM_LOG_DEBUG); + + osm_physp_set_pkey_tbl(sm->p_log, sm->p_subn, + p_physp, p_pkey_tbl, block_num); + +Exit: + cl_plock_release(sm->p_lock); + + OSM_LOG_EXIT(sm->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_port.c b/contrib/ofed/management/opensm/opensm/osm_port.c new file mode 100644 index 000000000000..4b4d4b8d28ea --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_port.c @@ -0,0 +1,780 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_physp_t. + * This object represents an Infiniband Port. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void osm_physp_construct(IN osm_physp_t * const p_physp) +{ + memset(p_physp, 0, sizeof(*p_physp)); + osm_dr_path_construct(&p_physp->dr_path); + cl_ptr_vector_construct(&p_physp->slvl_by_port); + osm_pkey_tbl_construct(&p_physp->pkeys); +} + +/********************************************************************** + **********************************************************************/ +void osm_physp_destroy(IN osm_physp_t * const p_physp) +{ + size_t num_slvl, i; + + /* the physp might be uninitialized */ + if (p_physp->port_guid) { + /* free the SL2VL Tables */ + num_slvl = cl_ptr_vector_get_size(&p_physp->slvl_by_port); + for (i = 0; i < num_slvl; i++) + free(cl_ptr_vector_get(&p_physp->slvl_by_port, i)); + cl_ptr_vector_destroy(&p_physp->slvl_by_port); + + /* free the P_Key Tables */ + osm_pkey_tbl_destroy(&p_physp->pkeys); + + memset(p_physp, 0, sizeof(*p_physp)); + osm_dr_path_construct(&p_physp->dr_path); /* clear dr_path */ + } +} + +/********************************************************************** + **********************************************************************/ +void +osm_physp_init(IN osm_physp_t * const p_physp, + IN const ib_net64_t port_guid, + IN const uint8_t port_num, + IN const struct osm_node *const p_node, + IN const osm_bind_handle_t h_bind, + IN const uint8_t hop_count, + IN const uint8_t * const p_initial_path) +{ + uint16_t num_slvl, i; + ib_slvl_table_t *p_slvl; + + CL_ASSERT(p_node); + + osm_physp_construct(p_physp); + p_physp->port_guid = port_guid; + p_physp->port_num = port_num; + p_physp->healthy = TRUE; + p_physp->need_update = 2; + p_physp->p_node = (struct osm_node *)p_node; + + osm_dr_path_init(&p_physp->dr_path, h_bind, hop_count, p_initial_path); + + /* allocate enough SL2VL tables */ + if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) + /* we need node num ports + 1 SL2VL tables */ + num_slvl = osm_node_get_num_physp(p_node) + 1; + else + /* An end node - we need only one SL2VL */ + num_slvl = 1; + + cl_ptr_vector_init(&p_physp->slvl_by_port, num_slvl, 1); + for (i = 0; i < num_slvl; i++) { + p_slvl = (ib_slvl_table_t *) malloc(sizeof(ib_slvl_table_t)); + if (!p_slvl) + break; + memset(p_slvl, 0, sizeof(ib_slvl_table_t)); + cl_ptr_vector_set(&p_physp->slvl_by_port, i, p_slvl); + } + + /* initialize the pkey table */ + osm_pkey_tbl_init(&p_physp->pkeys); +} + +/********************************************************************** + **********************************************************************/ +void osm_port_delete(IN OUT osm_port_t ** const pp_port) +{ + /* cleanup all mcm recs attached */ + osm_port_remove_all_mgrp(*pp_port); + free(*pp_port); + *pp_port = NULL; +} + +/********************************************************************** + **********************************************************************/ +static void +osm_port_init(IN osm_port_t * const p_port, + IN const ib_node_info_t * p_ni, + IN osm_node_t * const p_parent_node) +{ + ib_net64_t port_guid; + osm_physp_t *p_physp; + uint8_t port_num; + + CL_ASSERT(p_port); + CL_ASSERT(p_ni); + CL_ASSERT(p_parent_node); + + memset(p_port, 0, sizeof(*p_port)); + cl_qlist_init(&p_port->mcm_list); + p_port->p_node = (struct osm_node *)p_parent_node; + port_guid = p_ni->port_guid; + p_port->guid = port_guid; + port_num = p_ni->node_type == IB_NODE_TYPE_SWITCH ? + 0 : ib_node_info_get_local_port_num(p_ni); + + /* + Get the pointers to the physical node objects "owned" by this + logical port GUID. + For switches, port '0' is owned; for HCA's and routers, + only the singular part that has this GUID is owned. + */ + p_physp = osm_node_get_physp_ptr(p_parent_node, port_num); + CL_ASSERT(port_guid == osm_physp_get_port_guid(p_physp)); + p_port->p_physp = p_physp; +} + +/********************************************************************** + **********************************************************************/ +osm_port_t *osm_port_new(IN const ib_node_info_t * p_ni, + IN osm_node_t * const p_parent_node) +{ + osm_port_t *p_port; + + p_port = malloc(sizeof(*p_port)); + if (p_port != NULL) { + memset(p_port, 0, sizeof(*p_port)); + osm_port_init(p_port, p_ni, p_parent_node); + } + + return (p_port); +} + +/********************************************************************** + **********************************************************************/ +void +osm_port_get_lid_range_ho(IN const osm_port_t * const p_port, + IN uint16_t * const p_min_lid, + IN uint16_t * const p_max_lid) +{ + uint8_t lmc; + + *p_min_lid = cl_ntoh16(osm_port_get_base_lid(p_port)); + lmc = osm_port_get_lmc(p_port); + *p_max_lid = (uint16_t) (*p_min_lid + (1 << lmc) - 1); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_get_port_by_base_lid(IN const osm_subn_t * const p_subn, + IN const ib_net16_t lid, + IN OUT const osm_port_t ** const pp_port) +{ + ib_api_status_t status; + uint16_t base_lid; + uint8_t lmc; + + *pp_port = NULL; + + /* Loop on lmc from 0 up through max LMC possible */ + for (lmc = 0; lmc <= IB_PORT_LMC_MAX; lmc++) { + /* Calculate a base LID assuming this is the real LMC */ + base_lid = cl_ntoh16(lid) & ~((1 << lmc) - 1); + + /* Look for a match */ + status = cl_ptr_vector_at(&p_subn->port_lid_tbl, + base_lid, (void **)pp_port); + if ((status == CL_SUCCESS) && (*pp_port != NULL)) { + /* Determine if base LID "tested" is the real base LID */ + /* This is true if the LMC "tested" is the port's actual LMC */ + if (lmc == osm_port_get_lmc(*pp_port)) { + status = IB_SUCCESS; + goto Found; + } + } + } + *pp_port = NULL; + status = IB_NOT_FOUND; + +Found: + return status; +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_port_add_mgrp(IN osm_port_t * const p_port, IN const ib_net16_t mlid) +{ + ib_api_status_t status = IB_SUCCESS; + osm_mcm_info_t *p_mcm; + + p_mcm = osm_mcm_info_new(mlid); + if (p_mcm) + cl_qlist_insert_tail(&p_port->mcm_list, + (cl_list_item_t *) p_mcm); + else + status = IB_INSUFFICIENT_MEMORY; + + return (status); +} + +/********************************************************************** + **********************************************************************/ +static cl_status_t +__osm_port_mgrp_find_func(IN const cl_list_item_t * const p_list_item, + IN void *context) +{ + if (*((ib_net16_t *) context) == ((osm_mcm_info_t *) p_list_item)->mlid) + return (CL_SUCCESS); + else + return (CL_NOT_FOUND); +} + +/********************************************************************** + **********************************************************************/ +void +osm_port_remove_mgrp(IN osm_port_t * const p_port, IN const ib_net16_t mlid) +{ + cl_list_item_t *p_mcm; + + p_mcm = cl_qlist_find_from_head(&p_port->mcm_list, + __osm_port_mgrp_find_func, &mlid); + + if (p_mcm != cl_qlist_end(&p_port->mcm_list)) { + cl_qlist_remove_item(&p_port->mcm_list, p_mcm); + osm_mcm_info_delete((osm_mcm_info_t *) p_mcm); + } +} + +/********************************************************************** + **********************************************************************/ +void osm_port_remove_all_mgrp(IN osm_port_t * const p_port) +{ + cl_list_item_t *p_mcm; + + p_mcm = cl_qlist_remove_head(&p_port->mcm_list); + while (p_mcm != cl_qlist_end(&p_port->mcm_list)) { + osm_mcm_info_delete((osm_mcm_info_t *) p_mcm); + p_mcm = cl_qlist_remove_head(&p_port->mcm_list); + } +} + +/********************************************************************** + **********************************************************************/ +uint8_t +osm_physp_calc_link_mtu(IN osm_log_t * p_log, IN const osm_physp_t * p_physp) +{ + const osm_physp_t *p_remote_physp; + uint8_t mtu; + uint8_t remote_mtu; + + OSM_LOG_ENTER(p_log); + + p_remote_physp = osm_physp_get_remote(p_physp); + if (p_remote_physp) { + /* use the available MTU */ + mtu = ib_port_info_get_mtu_cap(&p_physp->port_info); + + remote_mtu = + ib_port_info_get_mtu_cap(&p_remote_physp->port_info); + + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Remote port 0x%016" PRIx64 " port = %u : " + "MTU = %u. This Port MTU: %u\n", + cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)), + osm_physp_get_port_num(p_remote_physp), + remote_mtu, mtu); + + if (mtu != remote_mtu) { + if (mtu > remote_mtu) + mtu = remote_mtu; + + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "MTU mismatch between ports." + "\n\t\t\t\tPort 0x%016" PRIx64 ", port %u" + " and port 0x%016" PRIx64 ", port %u." + "\n\t\t\t\tUsing lower MTU of %u\n", + cl_ntoh64(osm_physp_get_port_guid(p_physp)), + osm_physp_get_port_num(p_physp), + cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)), + osm_physp_get_port_num(p_remote_physp),mtu); + } + } else + mtu = ib_port_info_get_neighbor_mtu(&p_physp->port_info); + + if (mtu == 0) { + OSM_LOG(p_log, OSM_LOG_DEBUG, "ERR 4101: " + "Invalid MTU = 0. Forcing correction to 256\n"); + mtu = 1; + } + + OSM_LOG_EXIT(p_log); + return (mtu); +} + +/********************************************************************** + **********************************************************************/ +uint8_t +osm_physp_calc_link_op_vls(IN osm_log_t * p_log, + IN const osm_subn_t * p_subn, + IN const osm_physp_t * p_physp) +{ + const osm_physp_t *p_remote_physp; + uint8_t op_vls; + uint8_t remote_op_vls; + + OSM_LOG_ENTER(p_log); + + p_remote_physp = osm_physp_get_remote(p_physp); + if (p_remote_physp) { + /* use the available VLCap */ + op_vls = ib_port_info_get_vl_cap(&p_physp->port_info); + + remote_op_vls = + ib_port_info_get_vl_cap(&p_remote_physp->port_info); + + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Remote port 0x%016" PRIx64 " port = 0x%X : " + "VL_CAP = %u. This port VL_CAP = %u\n", + cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)), + osm_physp_get_port_num(p_remote_physp), + remote_op_vls, op_vls); + + if (op_vls != remote_op_vls) { + if (op_vls > remote_op_vls) + op_vls = remote_op_vls; + + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "OP_VLS mismatch between ports." + "\n\t\t\t\tPort 0x%016" PRIx64 ", port 0x%X" + " and port 0x%016" PRIx64 ", port 0x%X." + "\n\t\t\t\tUsing lower OP_VLS of %u\n", + cl_ntoh64(osm_physp_get_port_guid(p_physp)), + osm_physp_get_port_num(p_physp), + cl_ntoh64(osm_physp_get_port_guid(p_remote_physp)), + osm_physp_get_port_num(p_remote_physp), op_vls); + } + } else + op_vls = ib_port_info_get_op_vls(&p_physp->port_info); + + /* support user limitation of max_op_vls */ + if (op_vls > p_subn->opt.max_op_vls) + op_vls = p_subn->opt.max_op_vls; + + if (op_vls == 0) { + OSM_LOG(p_log, OSM_LOG_DEBUG, "ERR 4102: " + "Invalid OP_VLS = 0. Forcing correction to 1 (VL0)\n"); + op_vls = 1; + } + + OSM_LOG_EXIT(p_log); + return (op_vls); +} + +static inline uint64_t __osm_ptr_to_key(void const *p) +{ + uint64_t k = 0; + + memcpy(&k, p, sizeof(void *)); + return k; +} + +static inline void *__osm_key_to_ptr(uint64_t k) +{ + void *p = 0; + + memcpy(&p, &k, sizeof(void *)); + return p; +} + +/********************************************************************** + Traverse the fabric from the SM node following the DR path given and + add every phys port traversed to the map. Avoid tracking the first and + last phys ports (going into the first switch and into the target port). + **********************************************************************/ +static cl_status_t +__osm_physp_get_dr_physp_set(IN osm_log_t * p_log, + IN osm_subn_t const *p_subn, + IN osm_dr_path_t const *p_path, + OUT cl_map_t * p_physp_map) +{ + osm_port_t *p_port; + osm_physp_t *p_physp; + osm_node_t *p_node; + uint8_t hop; + cl_status_t status = CL_SUCCESS; + + OSM_LOG_ENTER(p_log); + + /* find the OSM node */ + p_port = osm_get_port_by_guid(p_subn, p_subn->sm_port_guid); + if (!p_port) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4103: " + "Failed to find the SM own port by guid\n"); + status = CL_ERROR; + goto Exit; + } + + /* get the node of the SM */ + p_node = p_port->p_node; + + /* + traverse the path adding the nodes to the table + start after the first dummy hop and stop just before the + last one + */ + for (hop = 1; hop < p_path->hop_count - 1; hop++) { + /* go out using the phys port of the path */ + p_physp = osm_node_get_physp_ptr(p_node, p_path->path[hop]); + + /* make sure we got a valid port and it has a remote port */ + if (!p_physp) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4104: " + "DR Traversal stopped on invalid port at hop:%u\n", + hop); + status = CL_ERROR; + goto Exit; + } + + /* we track the ports we go out along the path */ + if (hop > 1) + cl_map_insert(p_physp_map, __osm_ptr_to_key(p_physp), + NULL); + + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Traversed through node: 0x%016" PRIx64 + " port:%u\n", + cl_ntoh64(p_node->node_info.node_guid), + p_path->path[hop]); + + if (!(p_physp = osm_physp_get_remote(p_physp))) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4106: " + "DR Traversal stopped on missing remote physp at hop:%u\n", + hop); + status = CL_ERROR; + goto Exit; + } + + p_node = osm_physp_get_node_ptr(p_physp); + } + +Exit: + OSM_LOG_EXIT(p_log); + return status; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_physp_update_new_dr_path(IN osm_physp_t const *p_dest_physp, + IN cl_map_t * p_visited_map, + IN osm_bind_handle_t * h_bind) +{ + cl_list_t tmpPortsList; + osm_physp_t *p_physp, *p_src_physp = NULL; + uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX]; + uint8_t i = 0; + osm_dr_path_t *p_dr_path; + + cl_list_construct(&tmpPortsList); + cl_list_init(&tmpPortsList, 10); + + cl_list_insert_head(&tmpPortsList, p_dest_physp); + /* get the output port where we need to come from */ + p_physp = (osm_physp_t *) cl_map_get(p_visited_map, + __osm_ptr_to_key(p_dest_physp)); + while (p_physp != NULL) { + cl_list_insert_head(&tmpPortsList, p_physp); + /* get the input port through where we reached the output port */ + p_src_physp = p_physp; + p_physp = (osm_physp_t *) cl_map_get(p_visited_map, + __osm_ptr_to_key(p_physp)); + /* if we reached a null p_physp - this means we are at the begining + of the path. Break. */ + if (p_physp == NULL) + break; + /* get the output port */ + p_physp = (osm_physp_t *) cl_map_get(p_visited_map, + __osm_ptr_to_key(p_physp)); + } + + memset(path_array, 0, sizeof(path_array)); + p_physp = (osm_physp_t *) cl_list_remove_head(&tmpPortsList); + while (p_physp != NULL) { + i++; + path_array[i] = p_physp->port_num; + p_physp = (osm_physp_t *) cl_list_remove_head(&tmpPortsList); + } + if (p_src_physp) { + p_dr_path = osm_physp_get_dr_path_ptr(p_src_physp); + osm_dr_path_init(p_dr_path, h_bind, i, path_array); + } + + cl_list_destroy(&tmpPortsList); +} + +/********************************************************************** + **********************************************************************/ +void +osm_physp_replace_dr_path_with_alternate_dr_path(IN osm_log_t * p_log, + IN osm_subn_t const *p_subn, + IN osm_physp_t const + *p_dest_physp, + IN osm_bind_handle_t * h_bind) +{ + cl_map_t physp_map; + cl_map_t visited_map; + osm_dr_path_t *p_dr_path; + cl_list_t *p_currPortsList; + cl_list_t *p_nextPortsList; + osm_port_t *p_port; + osm_physp_t *p_physp, *p_remote_physp; + ib_net64_t port_guid; + boolean_t next_list_is_full = TRUE, reached_dest = FALSE; + uint8_t num_ports, port_num; + + p_nextPortsList = (cl_list_t *) malloc(sizeof(cl_list_t)); + if (!p_nextPortsList) + return; + + /* + initialize the map of all port participating in current dr path + not including first and last switches + */ + cl_map_construct(&physp_map); + cl_map_init(&physp_map, 4); + cl_map_construct(&visited_map); + cl_map_init(&visited_map, 4); + p_dr_path = osm_physp_get_dr_path_ptr(p_dest_physp); + __osm_physp_get_dr_physp_set(p_log, p_subn, p_dr_path, &physp_map); + + /* + BFS from OSM port until we find the target physp but avoid + going through mapped ports + */ + cl_list_construct(p_nextPortsList); + cl_list_init(p_nextPortsList, 10); + + port_guid = p_subn->sm_port_guid; + + CL_ASSERT(port_guid); + + p_port = osm_get_port_by_guid(p_subn, port_guid); + if (!p_port) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4105: No SM port object\n"); + goto Exit; + } + + /* + HACK: We are assuming SM is running on HCA, so when getting the default + port we'll get the port connected to the rest of the subnet. If SM is + running on SWITCH - we should try to get a dr path from all switch ports. + */ + p_physp = p_port->p_physp; + + CL_ASSERT(p_physp); + + cl_list_insert_tail(p_nextPortsList, p_physp); + + while (next_list_is_full == TRUE) { + next_list_is_full = FALSE; + p_currPortsList = p_nextPortsList; + p_nextPortsList = (cl_list_t *) malloc(sizeof(cl_list_t)); + if (!p_nextPortsList) { + p_nextPortsList = p_currPortsList; + goto Exit; + } + cl_list_construct(p_nextPortsList); + cl_list_init(p_nextPortsList, 10); + p_physp = (osm_physp_t *) cl_list_remove_head(p_currPortsList); + while (p_physp != NULL) { + /* If we are in a switch - need to go out through all + the other physical ports of the switch */ + num_ports = osm_node_get_num_physp(p_physp->p_node); + + for (port_num = 1; port_num < num_ports; port_num++) { + if (osm_node_get_type(p_physp->p_node) == + IB_NODE_TYPE_SWITCH) + p_remote_physp = + osm_node_get_physp_ptr(p_physp-> + p_node, + port_num); + else + /* this is HCA or router - the remote port is just the port connected + on the other side */ + p_remote_physp = + p_physp->p_remote_physp; + + /* + make sure that all of the following occurred: + 1. The port isn't NULL + 2. This is not the port we came from + 3. The port is not in the physp_map + 4. This port haven't been visited before + */ + if (p_remote_physp && + p_remote_physp != p_physp && + cl_map_get(&physp_map, + __osm_ptr_to_key(p_remote_physp)) + == NULL + && cl_map_get(&visited_map, + __osm_ptr_to_key + (p_remote_physp)) == NULL) { + /* Insert the port into the visited_map, and save its source port */ + cl_map_insert(&visited_map, + __osm_ptr_to_key + (p_remote_physp), + p_physp); + + /* Is this the p_dest_physp? */ + if (p_remote_physp == p_dest_physp) { + /* update the new dr path */ + __osm_physp_update_new_dr_path + (p_dest_physp, &visited_map, + h_bind); + reached_dest = TRUE; + break; + } + + /* add the p_remote_physp to the nextPortsList */ + cl_list_insert_tail(p_nextPortsList, + p_remote_physp); + next_list_is_full = TRUE; + } + } + + p_physp = (osm_physp_t *) + cl_list_remove_head(p_currPortsList); + if (reached_dest == TRUE) { + /* free the rest of the currPortsList */ + while (p_physp != NULL) + p_physp = (osm_physp_t *) + cl_list_remove_head + (p_currPortsList); + /* free the nextPortsList, if items were added to it */ + p_physp = (osm_physp_t *) + cl_list_remove_head(p_nextPortsList); + while (p_physp != NULL) + p_physp = (osm_physp_t *) + cl_list_remove_head + (p_nextPortsList); + next_list_is_full = FALSE; + } + } + cl_list_destroy(p_currPortsList); + free(p_currPortsList); + } + + /* cleanup */ +Exit: + cl_list_destroy(p_nextPortsList); + free(p_nextPortsList); + cl_map_destroy(&physp_map); + cl_map_destroy(&visited_map); +} + +/********************************************************************** + **********************************************************************/ +boolean_t osm_link_is_healthy(IN const osm_physp_t * const p_physp) +{ + osm_physp_t *p_remote_physp; + + CL_ASSERT(p_physp); + p_remote_physp = p_physp->p_remote_physp; + if (p_remote_physp != NULL) + return ((p_physp->healthy) & (p_remote_physp->healthy)); + /* the other side is not known - consider the link as healthy */ + return (TRUE); +} + +/********************************************************************** + **********************************************************************/ +void +osm_physp_set_pkey_tbl(IN osm_log_t * p_log, + IN const osm_subn_t * p_subn, + IN osm_physp_t * const p_physp, + IN ib_pkey_table_t * p_pkey_tbl, IN uint16_t block_num) +{ + uint16_t max_blocks; + + CL_ASSERT(p_pkey_tbl); + /* + (14.2.5.7) - the block number valid values are 0-2047, and are + further limited by the size of the P_Key table specified by + the PartitionCap on the node. + */ + if (!p_physp->p_node->sw || p_physp->port_num == 0) + /* + The maximum blocks is defined in the node info: partition cap + for CA, router, and switch management ports. + */ + max_blocks = + (cl_ntoh16(p_physp->p_node->node_info.partition_cap) + + IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) + / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; + else + /* + This is a switch, and not a management port. The maximum + blocks is defined in the switch info: partition enforcement + cap. + */ + max_blocks = + (cl_ntoh16(p_physp->p_node->sw->switch_info.enforce_cap) + + IB_NUM_PKEY_ELEMENTS_IN_BLOCK - + 1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; + + if (block_num >= max_blocks) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4108: " + "Got illegal set for block number:%u " + "For GUID: %" PRIx64 " port number:%u\n", + block_num, + cl_ntoh64(p_physp->p_node->node_info.node_guid), + p_physp->port_num); + return; + } + + osm_pkey_tbl_set(&p_physp->pkeys, block_num, p_pkey_tbl); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_port_info_rcv.c b/contrib/ofed/management/opensm/opensm/osm_port_info_rcv.c new file mode 100644 index 000000000000..8763b8785678 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_port_info_rcv.c @@ -0,0 +1,687 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_pi_rcv_t. + * This object represents the PortInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +static void +__osm_pi_rcv_set_sm(IN osm_sm_t * sm, + IN osm_physp_t * const p_physp) +{ + osm_bind_handle_t h_bind; + osm_dr_path_t *p_dr_path; + + OSM_LOG_ENTER(sm->p_log); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Setting IS_SM bit in port attributes\n"); + + p_dr_path = osm_physp_get_dr_path_ptr(p_physp); + h_bind = osm_dr_path_get_bind_handle(p_dr_path); + + /* + The 'IS_SM' bit isn't already set, so set it. + */ + osm_vendor_set_sm(h_bind, TRUE); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void pi_rcv_check_and_fix_lid(osm_log_t *log, ib_port_info_t * const pi, + osm_physp_t * p) +{ + if (cl_ntoh16(pi->base_lid) > IB_LID_UCAST_END_HO) { + OSM_LOG(log, OSM_LOG_ERROR, "ERR 0F04: " + "Got invalid base LID %u from the network. " + "Corrected to %u.\n", cl_ntoh16(pi->base_lid), + cl_ntoh16(p->port_info.base_lid)); + pi->base_lid = p->port_info.base_lid; + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pi_rcv_process_endport(IN osm_sm_t * sm, + IN osm_physp_t * const p_physp, + IN const ib_port_info_t * const p_pi) +{ + osm_madw_context_t context; + ib_api_status_t status; + ib_net64_t port_guid; + uint8_t rate, mtu; + cl_qmap_t *p_sm_tbl; + osm_remote_sm_t *p_sm; + + OSM_LOG_ENTER(sm->p_log); + + port_guid = osm_physp_get_port_guid(p_physp); + + /* HACK extended port 0 should be handled too! */ + if (osm_physp_get_port_num(p_physp) != 0) { + /* track the minimal endport MTU and rate */ + mtu = ib_port_info_get_mtu_cap(p_pi); + if (mtu < sm->p_subn->min_ca_mtu) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Setting endport minimal MTU to:%u defined by port:0x%" + PRIx64 "\n", mtu, cl_ntoh64(port_guid)); + sm->p_subn->min_ca_mtu = mtu; + } + + rate = ib_port_info_compute_rate(p_pi); + if (rate < sm->p_subn->min_ca_rate) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Setting endport minimal rate to:%u defined by port:0x%" + PRIx64 "\n", rate, cl_ntoh64(port_guid)); + sm->p_subn->min_ca_rate = rate; + } + } + + if (port_guid == sm->p_subn->sm_port_guid) { + /* + We received the PortInfo for our own port. + */ + if (!(p_pi->capability_mask & IB_PORT_CAP_IS_SM)) + /* + Set the IS_SM bit to indicate our port hosts an SM. + */ + __osm_pi_rcv_set_sm(sm, p_physp); + } else { + p_sm_tbl = &sm->p_subn->sm_guid_tbl; + if (p_pi->capability_mask & IB_PORT_CAP_IS_SM) { + /* + * Before querying the SM - we want to make sure we + * clean its state, so if the querying fails we + * recognize that this SM is not active. + */ + p_sm = (osm_remote_sm_t *) cl_qmap_get(p_sm_tbl, port_guid); + if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) + /* clean it up */ + p_sm->smi.pri_state = 0xF0 & p_sm->smi.pri_state; + if (sm->p_subn->opt.ignore_other_sm) + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Ignoring SM on port 0x%" PRIx64 "\n", + cl_ntoh64(port_guid)); + else { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Detected another SM. Requesting SMInfo" + "\n\t\t\t\tPort 0x%" PRIx64 "\n", + cl_ntoh64(port_guid)); + + /* + This port indicates it's an SM and + it's not our own port. + Acquire the SMInfo Attribute. + */ + memset(&context, 0, sizeof(context)); + context.smi_context.set_method = FALSE; + context.smi_context.port_guid = port_guid; + status = osm_req_get(sm, + osm_physp_get_dr_path_ptr + (p_physp), + IB_MAD_ATTR_SM_INFO, 0, + CL_DISP_MSGID_NONE, + &context); + + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 0F05: " + "Failure requesting SMInfo (%s)\n", + ib_get_err_str(status)); + } + } else { + p_sm = (osm_remote_sm_t *) cl_qmap_remove(p_sm_tbl, port_guid); + if (p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) + free(p_sm); + } + } + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_pi_rcv_process_switch_port(IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN osm_physp_t * const p_physp, + IN ib_port_info_t * const p_pi) +{ + ib_api_status_t status = IB_SUCCESS; + osm_madw_context_t context; + osm_physp_t *p_remote_physp; + osm_node_t *p_remote_node; + uint8_t port_num; + uint8_t remote_port_num; + osm_dr_path_t path; + + OSM_LOG_ENTER(sm->p_log); + + /* + Check the state of the physical port. + If there appears to be something on the other end of the wire, + then ask for NodeInfo. Ignore the switch management port. + */ + port_num = osm_physp_get_port_num(p_physp); + /* if in_sweep_hop_0 is TRUE, then this means the SM is on the switch, + and we got switchInfo of our local switch. Do not continue + probing through the switch. */ + if (port_num != 0 && sm->p_subn->in_sweep_hop_0 == FALSE) { + switch (ib_port_info_get_port_state(p_pi)) { + case IB_LINK_DOWN: + p_remote_physp = osm_physp_get_remote(p_physp); + if (p_remote_physp) { + p_remote_node = + osm_physp_get_node_ptr(p_remote_physp); + remote_port_num = + osm_physp_get_port_num(p_remote_physp); + + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Unlinking local node 0x%" PRIx64 + ", port %u" + "\n\t\t\t\tand remote node 0x%" PRIx64 + ", port %u\n", + cl_ntoh64(osm_node_get_node_guid + (p_node)), port_num, + cl_ntoh64(osm_node_get_node_guid + (p_remote_node)), + remote_port_num); + + if (sm->ucast_mgr.cache_valid) + osm_ucast_cache_add_link(&sm->ucast_mgr, + p_physp, + p_remote_physp); + + osm_node_unlink(p_node, (uint8_t) port_num, + p_remote_node, + (uint8_t) remote_port_num); + + } + break; + + case IB_LINK_INIT: + case IB_LINK_ARMED: + case IB_LINK_ACTIVE: + /* + To avoid looping forever, only probe the port if it + is NOT the port that responded to the SMP. + + Request node info from the other end of this link: + 1) Copy the current path from the parent node. + 2) Extend the path to the next hop thru this port. + 3) Request node info with the new path + + */ + if (p_pi->local_port_num != + osm_physp_get_port_num(p_physp)) { + path = *osm_physp_get_dr_path_ptr(p_physp); + + osm_dr_path_extend(&path, + osm_physp_get_port_num + (p_physp)); + + memset(&context, 0, sizeof(context)); + context.ni_context.node_guid = + osm_node_get_node_guid(p_node); + context.ni_context.port_num = + osm_physp_get_port_num(p_physp); + + status = osm_req_get(sm, + &path, + IB_MAD_ATTR_NODE_INFO, + 0, + CL_DISP_MSGID_NONE, + &context); + + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 0F02: " + "Failure initiating NodeInfo request (%s)\n", + ib_get_err_str(status)); + } else + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Skipping SMP responder port %u\n", + p_pi->local_port_num); + break; + + default: + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F03: " + "Unknown link state = %u, port = %u\n", + ib_port_info_get_port_state(p_pi), + p_pi->local_port_num); + break; + } + } + + if (ib_port_info_get_port_state(p_pi) > IB_LINK_INIT && p_node->sw && + p_node->sw->need_update == 1) + p_node->sw->need_update = 0; + + if (p_physp->need_update) + sm->p_subn->ignore_existing_lfts = TRUE; + + if (port_num == 0) + pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp); + + /* + Update the PortInfo attribute. + */ + osm_physp_set_port_info(p_physp, p_pi); + + if (port_num == 0) { + /* Determine if base switch port 0 */ + if (p_node->sw && + !ib_switch_info_is_enhanced_port0(&p_node->sw->switch_info)) + /* PortState is not used on BSP0 but just in case it is DOWN */ + p_physp->port_info = *p_pi; + __osm_pi_rcv_process_endport(sm, p_physp, p_pi); + } + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pi_rcv_process_ca_or_router_port(IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN osm_physp_t * const p_physp, + IN ib_port_info_t * const p_pi) +{ + OSM_LOG_ENTER(sm->p_log); + + UNUSED_PARAM(p_node); + + pi_rcv_check_and_fix_lid(sm->p_log, p_pi, p_physp); + + osm_physp_set_port_info(p_physp, p_pi); + + __osm_pi_rcv_process_endport(sm, p_physp, p_pi); + + OSM_LOG_EXIT(sm->p_log); +} + +#define IBM_VENDOR_ID (0x5076) +/********************************************************************** + **********************************************************************/ +static void get_pkey_table(IN osm_log_t * p_log, + IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN osm_physp_t * const p_physp) +{ + + osm_madw_context_t context; + ib_api_status_t status; + osm_dr_path_t path; + uint8_t port_num; + uint16_t block_num, max_blocks; + uint32_t attr_mod_ho; + + OSM_LOG_ENTER(p_log); + + path = *osm_physp_get_dr_path_ptr(p_physp); + + context.pkey_context.node_guid = osm_node_get_node_guid(p_node); + context.pkey_context.port_guid = osm_physp_get_port_guid(p_physp); + context.pkey_context.set_method = FALSE; + + port_num = p_physp->port_num; + + if (!p_node->sw || port_num == 0) + /* The maximum blocks is defined by the node info partition cap for CA, + router, and switch management ports. */ + max_blocks = + (cl_ntoh16(p_node->node_info.partition_cap) + + IB_NUM_PKEY_ELEMENTS_IN_BLOCK - 1) + / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; + else { + /* This is a switch, and not a management port. The maximum blocks + is defined in the switch info partition enforcement cap. */ + + /* Check for IBM eHCA firmware defect in reporting partition enforcement cap */ + if (cl_ntoh32(ib_node_info_get_vendor_id(&p_node->node_info)) == + IBM_VENDOR_ID) + p_node->sw->switch_info.enforce_cap = 0; + + /* Bail out if this is a switch with no partition enforcement capability */ + if (cl_ntoh16(p_node->sw->switch_info.enforce_cap) == 0) + goto Exit; + + max_blocks = (cl_ntoh16(p_node->sw->switch_info.enforce_cap) + + IB_NUM_PKEY_ELEMENTS_IN_BLOCK - + 1) / IB_NUM_PKEY_ELEMENTS_IN_BLOCK; + } + + for (block_num = 0; block_num < max_blocks; block_num++) { + if (osm_node_get_type(p_node) != IB_NODE_TYPE_SWITCH) + attr_mod_ho = block_num; + else + attr_mod_ho = block_num | (port_num << 16); + status = osm_req_get(sm, &path, IB_MAD_ATTR_P_KEY_TABLE, + cl_hton32(attr_mod_ho), + CL_DISP_MSGID_NONE, &context); + + if (status != IB_SUCCESS) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0F12: " + "Failure initiating PKeyTable request (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + } + +Exit: + OSM_LOG_EXIT(p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pi_rcv_get_pkey_slvl_vla_tables(IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN osm_physp_t * const p_physp) +{ + OSM_LOG_ENTER(sm->p_log); + + get_pkey_table(sm->p_log, sm, p_node, p_physp); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +osm_pi_rcv_process_set(IN osm_sm_t * sm, IN osm_node_t * const p_node, + IN const uint8_t port_num, IN osm_madw_t * const p_madw) +{ + osm_physp_t *p_physp; + ib_net64_t port_guid; + ib_smp_t *p_smp; + ib_port_info_t *p_pi; + osm_pi_context_t *p_context; + osm_log_level_t level; + + OSM_LOG_ENTER(sm->p_log); + + p_context = osm_madw_get_pi_context_ptr(p_madw); + + CL_ASSERT(p_node); + + p_physp = osm_node_get_physp_ptr(p_node, port_num); + CL_ASSERT(p_physp); + + port_guid = osm_physp_get_port_guid(p_physp); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_pi = (ib_port_info_t *) ib_smp_get_payload_ptr(p_smp); + + /* check for error */ + if (cl_ntoh16(p_smp->status) & 0x7fff) { + /* If port already ACTIVE, don't treat status 7 as error */ + if (p_context->active_transition && + (cl_ntoh16(p_smp->status) & 0x7fff) == 0x1c) { + level = OSM_LOG_INFO; + OSM_LOG(sm->p_log, OSM_LOG_INFO, + "Received error status 0x%x for SetResp() during ACTIVE transition\n", + cl_ntoh16(p_smp->status) & 0x7fff); + /* Should there be a subsequent Get to validate that port is ACTIVE ? */ + } else { + level = OSM_LOG_ERROR; + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F10: " + "Received error status for SetResp()\n"); + } + osm_dump_port_info(sm->p_log, + osm_node_get_node_guid(p_node), + port_guid, port_num, p_pi, level); + } + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Received logical SetResp() for GUID 0x%" PRIx64 + ", port num %u" + "\n\t\t\t\tfor parent node GUID 0x%" PRIx64 + " TID 0x%" PRIx64 "\n", + cl_ntoh64(port_guid), port_num, + cl_ntoh64(osm_node_get_node_guid(p_node)), + cl_ntoh64(p_smp->trans_id)); + + osm_physp_set_port_info(p_physp, p_pi); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_pi_rcv_process(IN void *context, IN void *data) +{ + osm_sm_t *sm = context; + osm_madw_t *p_madw = data; + ib_port_info_t *p_pi; + ib_smp_t *p_smp; + osm_port_t *p_port; + osm_physp_t *p_physp; + osm_dr_path_t *p_dr_path; + osm_node_t *p_node; + osm_pi_context_t *p_context; + ib_net64_t port_guid; + ib_net64_t node_guid; + uint8_t port_num; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(sm); + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_context = osm_madw_get_pi_context_ptr(p_madw); + p_pi = (ib_port_info_t *) ib_smp_get_payload_ptr(p_smp); + + CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_PORT_INFO); + + port_num = (uint8_t) cl_ntoh32(p_smp->attr_mod); + + port_guid = p_context->port_guid; + node_guid = p_context->node_guid; + + osm_dump_port_info(sm->p_log, + node_guid, port_guid, port_num, p_pi, OSM_LOG_DEBUG); + + /* On receipt of client reregister, clear the reregister bit so + reregistering won't be sent again and again */ + if (ib_port_info_get_client_rereg(p_pi)) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Client reregister received on response\n"); + ib_port_info_set_client_rereg(p_pi, 0); + } + + /* + we might get a response during a light sweep looking for a change in + the status of a remote port that did not respond in earlier sweeps. + So if the context of the Get was light_sweep - we do not need to + do anything with the response - just flag that we need a heavy sweep + */ + if (p_context->light_sweep == TRUE) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Got light sweep response from remote port of parent node " + "GUID 0x%" PRIx64 " port 0x%016" PRIx64 + ", Commencing heavy sweep\n", + cl_ntoh64(node_guid), cl_ntoh64(port_guid)); + sm->p_subn->force_heavy_sweep = TRUE; + sm->p_subn->ignore_existing_lfts = TRUE; + goto Exit; + } + + CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); + p_port = osm_get_port_by_guid(sm->p_subn, port_guid); + if (!p_port) { + CL_PLOCK_RELEASE(sm->p_lock); + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F06: " + "No port object for port with GUID 0x%" PRIx64 + "\n\t\t\t\tfor parent node GUID 0x%" PRIx64 + ", TID 0x%" PRIx64 "\n", + cl_ntoh64(port_guid), + cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); + goto Exit; + } + + p_node = p_port->p_node; + CL_ASSERT(p_node); + + /* + If we were setting the PortInfo, then receiving + this attribute was not part of sweeping the subnet. + In this case, just update the PortInfo attribute. + + In an unfortunate blunder, the IB spec defines the + return method for Set() as a GetResp(). Thus, we can't + use the method (what would have been SetResp()) to determine + our course of action. So, we have to carry this extra + boolean around to determine if we were doing Get() or Set(). + */ + if (p_context->set_method) + osm_pi_rcv_process_set(sm, p_node, port_num, p_madw); + else { + p_port->discovery_count++; + + /* + This PortInfo arrived because we did a Get() method, + most likely due to a subnet sweep in progress. + */ + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Discovered port num %u with GUID 0x%" PRIx64 + " for parent node GUID 0x%" PRIx64 + ", TID 0x%" PRIx64 "\n", + port_num, cl_ntoh64(port_guid), + cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); + + p_physp = osm_node_get_physp_ptr(p_node, port_num); + + /* + Determine if we encountered a new Physical Port. + If so, initialize the new Physical Port then + continue processing as normal. + */ + if (!p_physp) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Initializing port number %u\n", port_num); + p_physp = &p_node->physp_table[port_num]; + osm_physp_init(p_physp, + port_guid, + port_num, + p_node, + osm_madw_get_bind_handle(p_madw), + p_smp->hop_count, p_smp->initial_path); + } else { + /* + Update the directed route path to this port + in case the old path is no longer usable. + */ + p_dr_path = osm_physp_get_dr_path_ptr(p_physp); + osm_dr_path_init(p_dr_path, + osm_madw_get_bind_handle(p_madw), + p_smp->hop_count, p_smp->initial_path); + } + + /* if port just inited or reached INIT state (external reset) + request update for port related tables */ + p_physp->need_update = + (ib_port_info_get_port_state(p_pi) == IB_LINK_INIT || + p_physp->need_update > 1) ? 1 : 0; + + switch (osm_node_get_type(p_node)) { + case IB_NODE_TYPE_CA: + case IB_NODE_TYPE_ROUTER: + __osm_pi_rcv_process_ca_or_router_port(sm, + p_node, p_physp, + p_pi); + break; + case IB_NODE_TYPE_SWITCH: + __osm_pi_rcv_process_switch_port(sm, + p_node, p_physp, p_pi); + break; + default: + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 0F07: " + "Unknown node type %u with GUID 0x%" PRIx64 + "\n", osm_node_get_type(p_node), + cl_ntoh64(node_guid)); + break; + } + + /* + Get the tables on the physp. + */ + if (p_physp->need_update || sm->p_subn->need_update) + __osm_pi_rcv_get_pkey_slvl_vla_tables(sm, p_node, + p_physp); + + } + + CL_PLOCK_RELEASE(sm->p_lock); + +Exit: + /* + Release the lock before jumping here!! + */ + OSM_LOG_EXIT(sm->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_prtn.c b/contrib/ofed/management/opensm/opensm/osm_prtn.c new file mode 100644 index 000000000000..be51410b1a57 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_prtn.c @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_prtn_t. + * This object represents an IBA partition. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int osm_prtn_config_parse_file(osm_log_t * const p_log, + osm_subn_t * const p_subn, + const char *file_name); + +static uint16_t global_pkey_counter; + +osm_prtn_t *osm_prtn_new(IN const char *name, IN const uint16_t pkey) +{ + osm_prtn_t *p = malloc(sizeof(*p)); + if (!p) + return NULL; + + memset(p, 0, sizeof(*p)); + p->pkey = pkey; + p->sl = OSM_DEFAULT_SL; + cl_map_construct(&p->full_guid_tbl); + cl_map_init(&p->full_guid_tbl, 32); + cl_map_construct(&p->part_guid_tbl); + cl_map_init(&p->part_guid_tbl, 32); + + if (name && *name) + strncpy(p->name, name, sizeof(p->name)); + else + snprintf(p->name, sizeof(p->name), "%04x", cl_ntoh16(pkey)); + + return p; +} + +void osm_prtn_delete(IN OUT osm_prtn_t ** const pp_prtn) +{ + osm_prtn_t *p = *pp_prtn; + + cl_map_remove_all(&p->full_guid_tbl); + cl_map_destroy(&p->full_guid_tbl); + cl_map_remove_all(&p->part_guid_tbl); + cl_map_destroy(&p->part_guid_tbl); + free(p); + *pp_prtn = NULL; +} + +ib_api_status_t osm_prtn_add_port(osm_log_t * p_log, osm_subn_t * p_subn, + osm_prtn_t * p, ib_net64_t guid, + boolean_t full) +{ + ib_api_status_t status = IB_SUCCESS; + cl_map_t *p_tbl; + osm_port_t *p_port; + osm_physp_t *p_physp; + + p_port = osm_get_port_by_guid(p_subn, guid); + if (!p_port) { + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "port 0x%" PRIx64 " not found\n", cl_ntoh64(guid)); + return status; + } + + p_physp = p_port->p_physp; + if (!p_physp) { + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "no physical for port 0x%" PRIx64 "\n", + cl_ntoh64(guid)); + return status; + } + + if (cl_map_remove(&p->part_guid_tbl, guid) || + cl_map_remove(&p->full_guid_tbl, guid)) { + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "port 0x%" PRIx64 " already in " + "partition \'%s\' (0x%04x). Will overwrite\n", + cl_ntoh64(guid), p->name, cl_ntoh16(p->pkey)); + } + + p_tbl = (full == TRUE) ? &p->full_guid_tbl : &p->part_guid_tbl; + + if (cl_map_insert(p_tbl, guid, p_physp) == NULL) + return IB_INSUFFICIENT_MEMORY; + + return status; +} + +ib_api_status_t osm_prtn_add_all(osm_log_t * p_log, osm_subn_t * p_subn, + osm_prtn_t * p, boolean_t full) +{ + cl_qmap_t *p_port_tbl = &p_subn->port_guid_tbl; + cl_map_item_t *p_item; + osm_port_t *p_port; + ib_api_status_t status = IB_SUCCESS; + + p_item = cl_qmap_head(p_port_tbl); + while (p_item != cl_qmap_end(p_port_tbl)) { + p_port = (osm_port_t *) p_item; + p_item = cl_qmap_next(p_item); + status = osm_prtn_add_port(p_log, p_subn, p, + osm_port_get_guid(p_port), full); + if (status != IB_SUCCESS) + goto _err; + } + +_err: + return status; +} + +static const ib_gid_t osm_ipoib_mgid = { + { + 0xff, /* multicast field */ + 0x12, /* non-permanent bit, link local scope */ + 0x40, 0x1b, /* IPv4 signature */ + 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */ + 0xff, 0xff, 0xff, 0xff, /* 32 bit IPv4 broadcast address */ + }, +}; + +/* + * HACK: Until TS resolves their noncompliant join compmask, + * we have to pre-define the MGID + */ +static const ib_gid_t osm_ts_ipoib_mgid = { + { + 0xff, /* multicast field */ + 0x12, /* non-permanent bit, link local scope */ + 0x40, 0x1b, /* IPv4 signature */ + 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */ + 0x00, 0x00, 0x00, 0x01, /* 32 bit IPv4 broadcast address */ + }, +}; + +ib_api_status_t osm_prtn_add_mcgroup(osm_log_t * p_log, + osm_subn_t * p_subn, osm_prtn_t * p, + uint8_t rate, + uint8_t mtu, uint8_t scope) +{ + ib_member_rec_t mc_rec; + ib_net64_t comp_mask; + ib_net16_t pkey; + osm_mgrp_t *p_mgrp = NULL; + osm_sa_t *p_sa = &p_subn->p_osm->sa; + ib_api_status_t status = IB_SUCCESS; + uint8_t hop_limit; + + pkey = p->pkey | cl_hton16(0x8000); + if (!scope) + scope = OSM_DEFAULT_MGRP_SCOPE; + hop_limit = (scope == IB_MC_SCOPE_LINK_LOCAL) ? 0 : IB_HOPLIMIT_MAX; + + memset(&mc_rec, 0, sizeof(mc_rec)); + + mc_rec.mgid = osm_ipoib_mgid; /* ipv4 broadcast group */ + memcpy(&mc_rec.mgid.raw[4], &pkey, sizeof(pkey)); + + mc_rec.qkey = CL_HTON32(0x0b1b); + mc_rec.mtu = (mtu ? mtu : OSM_DEFAULT_MGRP_MTU) | (2 << 6); /* 2048 Bytes */ + mc_rec.tclass = 0; + mc_rec.pkey = pkey; + mc_rec.rate = (rate ? rate : OSM_DEFAULT_MGRP_RATE) | (2 << 6); /* 10Gb/sec */ + mc_rec.pkt_life = p_subn->opt.subnet_timeout; + mc_rec.sl_flow_hop = ib_member_set_sl_flow_hop(p->sl, 0, hop_limit); + /* Scope in MCMemberRecord (if present) needs to be consistent with MGID */ + mc_rec.scope_state = ib_member_set_scope_state(scope, IB_MC_REC_STATE_FULL_MEMBER); + ib_mgid_set_scope(&mc_rec.mgid, scope); + + /* don't update rate, mtu */ + comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_MTU_SEL | + IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_RATE_SEL; + status = osm_mcmr_rcv_find_or_create_new_mgrp(p_sa, comp_mask, &mc_rec, + &p_mgrp); + if (!p_mgrp || status != IB_SUCCESS) + OSM_LOG(p_log, OSM_LOG_ERROR, + "Failed to create MC group with pkey 0x%04x\n", + cl_ntoh16(pkey)); + if (p_mgrp) { + p_mgrp->well_known = TRUE; + p->mlid = p_mgrp->mlid; + } + + /* workaround for TS */ + /* FIXME: remove this upon TS fixes */ + mc_rec.mgid = osm_ts_ipoib_mgid; + memcpy(&mc_rec.mgid.raw[4], &pkey, sizeof(pkey)); + /* Scope in MCMemberRecord (if present) needs to be consistent with MGID */ + mc_rec.scope_state = ib_member_set_scope_state(scope, IB_MC_REC_STATE_FULL_MEMBER); + ib_mgid_set_scope(&mc_rec.mgid, scope); + + status = osm_mcmr_rcv_find_or_create_new_mgrp(p_sa, comp_mask, &mc_rec, + &p_mgrp); + if (p_mgrp) { + p_mgrp->well_known = TRUE; + if (!p->mlid) + p->mlid = p_mgrp->mlid; + } + + return status; +} + +static uint16_t __generate_pkey(osm_subn_t * p_subn) +{ + uint16_t pkey; + + cl_qmap_t *m = &p_subn->prtn_pkey_tbl; + while (global_pkey_counter < cl_ntoh16(IB_DEFAULT_PARTIAL_PKEY) - 1) { + pkey = ++global_pkey_counter; + pkey = cl_hton16(pkey); + if (cl_qmap_get(m, pkey) == cl_qmap_end(m)) + return pkey; + } + return 0; +} + +osm_prtn_t *osm_prtn_find_by_name(osm_subn_t * p_subn, const char *name) +{ + cl_map_item_t *p_next; + osm_prtn_t *p; + + p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl); + while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) { + p = (osm_prtn_t *) p_next; + p_next = cl_qmap_next(&p->map_item); + if (!strncmp(p->name, name, sizeof(p->name))) + return p; + } + + return NULL; +} + +osm_prtn_t *osm_prtn_make_new(osm_log_t * p_log, osm_subn_t * p_subn, + const char *name, uint16_t pkey) +{ + osm_prtn_t *p = NULL, *p_check; + + pkey &= cl_hton16((uint16_t) ~ 0x8000); + + if (!pkey) { + if (name && (p = osm_prtn_find_by_name(p_subn, name))) + return p; + if (!(pkey = __generate_pkey(p_subn))) + return NULL; + } + + p = osm_prtn_new(name, pkey); + if (!p) { + OSM_LOG(p_log, OSM_LOG_ERROR, "Unable to create" + " partition \'%s\' (0x%04x)\n", name, cl_ntoh16(pkey)); + return NULL; + } + + p_check = (osm_prtn_t *) cl_qmap_insert(&p_subn->prtn_pkey_tbl, + p->pkey, &p->map_item); + if (p != p_check) { + OSM_LOG(p_log, OSM_LOG_VERBOSE, "Duplicated partition" + " definition: \'%s\' (0x%04x) prev name \'%s\'" + ". Will use it\n", + name, cl_ntoh16(pkey), p_check->name); + osm_prtn_delete(&p); + p = p_check; + } + + return p; +} + +static ib_api_status_t osm_prtn_make_default(osm_log_t * const p_log, + osm_subn_t * const p_subn, + boolean_t no_config) +{ + ib_api_status_t status = IB_UNKNOWN_ERROR; + osm_prtn_t *p; + + p = osm_prtn_make_new(p_log, p_subn, "Default", + IB_DEFAULT_PARTIAL_PKEY); + if (!p) + goto _err; + status = osm_prtn_add_all(p_log, p_subn, p, no_config); + if (status != IB_SUCCESS) + goto _err; + cl_map_remove(&p->part_guid_tbl, p_subn->sm_port_guid); + status = + osm_prtn_add_port(p_log, p_subn, p, p_subn->sm_port_guid, TRUE); + + if (no_config) + osm_prtn_add_mcgroup(p_log, p_subn, p, 0, 0, 0); + +_err: + return status; +} + +ib_api_status_t osm_prtn_make_partitions(osm_log_t * const p_log, + osm_subn_t * const p_subn) +{ + struct stat statbuf; + const char *file_name; + boolean_t is_config = TRUE; + ib_api_status_t status = IB_SUCCESS; + cl_map_item_t *p_next; + osm_prtn_t *p; + + file_name = p_subn->opt.partition_config_file ? + p_subn->opt.partition_config_file : OSM_DEFAULT_PARTITION_CONFIG_FILE; + if (stat(file_name, &statbuf)) + is_config = FALSE; + + /* clean up current port maps */ + p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl); + while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) { + p = (osm_prtn_t *) p_next; + p_next = cl_qmap_next(&p->map_item); + cl_map_remove_all(&p->part_guid_tbl); + cl_map_remove_all(&p->full_guid_tbl); + } + + global_pkey_counter = 0; + + status = osm_prtn_make_default(p_log, p_subn, !is_config); + if (status != IB_SUCCESS) + goto _err; + + if (is_config && osm_prtn_config_parse_file(p_log, p_subn, file_name)) { + OSM_LOG(p_log, OSM_LOG_VERBOSE, "Partition configuration " + "was not fully processed\n"); + } + + /* and now clean up empty partitions */ + p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl); + while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) { + p = (osm_prtn_t *) p_next; + p_next = cl_qmap_next(&p->map_item); + if (cl_map_count(&p->part_guid_tbl) == 0 && + cl_map_count(&p->full_guid_tbl) == 0) { + cl_qmap_remove_item(&p_subn->prtn_pkey_tbl, + (cl_map_item_t *) p); + osm_prtn_delete(&p); + } + } + +_err: + return status; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_prtn_config.c b/contrib/ofed/management/opensm/opensm/osm_prtn_config.c new file mode 100644 index 000000000000..d663fad79eeb --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_prtn_config.c @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2006-2007 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of opensm partition management configuration + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +struct part_conf { + osm_log_t *p_log; + osm_subn_t *p_subn; + osm_prtn_t *p_prtn; + unsigned is_ipoib, mtu, rate, sl, scope_mask; + boolean_t full; +}; + +extern osm_prtn_t *osm_prtn_make_new(osm_log_t * p_log, osm_subn_t * p_subn, + const char *name, uint16_t pkey); +extern ib_api_status_t osm_prtn_add_all(osm_log_t * p_log, + osm_subn_t * p_subn, + osm_prtn_t * p, boolean_t full); +extern ib_api_status_t osm_prtn_add_port(osm_log_t * p_log, + osm_subn_t * p_subn, osm_prtn_t * p, + ib_net64_t guid, boolean_t full); +extern ib_api_status_t osm_prtn_add_mcgroup(osm_log_t * p_log, + osm_subn_t * p_subn, osm_prtn_t * p, + uint8_t rate, + uint8_t mtu, uint8_t scope); + +static int partition_create(unsigned lineno, struct part_conf *conf, + char *name, char *id, char *flag, char *flag_val) +{ + uint16_t pkey; + unsigned int scope; + + if (!id && name && isdigit(*name)) { + id = name; + name = NULL; + } + + if (id) { + char *end; + + pkey = (uint16_t) strtoul(id, &end, 0); + if (end == id || *end) + return -1; + } else + pkey = 0; + + conf->p_prtn = osm_prtn_make_new(conf->p_log, conf->p_subn, + name, cl_hton16(pkey)); + if (!conf->p_prtn) + return -1; + + if (!conf->p_subn->opt.qos && conf->sl != OSM_DEFAULT_SL) { + OSM_LOG(conf->p_log, OSM_LOG_DEBUG, "Overriding SL %d" + " to default SL %d on partition %s" + " as QoS is not enabled.\n", + conf->sl, OSM_DEFAULT_SL, name); + conf->sl = OSM_DEFAULT_SL; + } + conf->p_prtn->sl = (uint8_t) conf->sl; + + if (!conf->is_ipoib) + return 0; + + if (!conf->scope_mask) { + osm_prtn_add_mcgroup(conf->p_log, conf->p_subn, conf->p_prtn, + (uint8_t) conf->rate, + (uint8_t) conf->mtu, + 0); + return 0; + } + + for (scope = 0; scope < 16; scope++) { + if (((1<scope_mask) == 0) + continue; + + osm_prtn_add_mcgroup(conf->p_log, conf->p_subn, conf->p_prtn, + (uint8_t) conf->rate, + (uint8_t) conf->mtu, + (uint8_t) scope); + } + return 0; +} + +static int partition_add_flag(unsigned lineno, struct part_conf *conf, + char *flag, char *val) +{ + int len = strlen(flag); + if (!strncmp(flag, "ipoib", len)) { + conf->is_ipoib = 1; + } else if (!strncmp(flag, "mtu", len)) { + if (!val || (conf->mtu = strtoul(val, NULL, 0)) == 0) + OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "flag \'mtu\' requires valid value" + " - skipped\n", lineno); + } else if (!strncmp(flag, "rate", len)) { + if (!val || (conf->rate = strtoul(val, NULL, 0)) == 0) + OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "flag \'rate\' requires valid value" + " - skipped\n", lineno); + } else if (!strncmp(flag, "scope", len)) { + unsigned int scope; + if (!val || (scope = strtoul(val, NULL, 0)) == 0 || scope > 0xF) + OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "flag \'scope\' requires valid value" + " - skipped\n", lineno); + else + conf->scope_mask |= (1< 15 || + (*end && !isspace(*end))) + OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "flag \'sl\' requires valid value" + " - skipped\n", lineno); + else + conf->sl = sl; + } else if (!strncmp(flag, "defmember", len)) { + if (!val || (strncmp(val, "limited", strlen(val)) + && strncmp(val, "full", strlen(val)))) + OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "flag \'defmember\' requires valid value (limited or full)" + " - skipped\n", lineno); + else + conf->full = strncmp(val, "full", strlen(val)) == 0; + } else { + OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "unrecognized partition flag \'%s\'" + " - ignored\n", lineno, flag); + } + return 0; +} + +static int partition_add_port(unsigned lineno, struct part_conf *conf, + char *name, char *flag) +{ + osm_prtn_t *p = conf->p_prtn; + ib_net64_t guid; + boolean_t full = conf->full; + + if (!name || !*name || !strncmp(name, "NONE", strlen(name))) + return 0; + + if (flag) { + /* reset default membership to limited */ + full = FALSE; + if (!strncmp(flag, "full", strlen(flag))) + full = TRUE; + else if (strncmp(flag, "limited", strlen(flag))) { + OSM_LOG(conf->p_log, OSM_LOG_VERBOSE, + "PARSE WARN: line %d: " + "unrecognized port flag \'%s\'." + " Assume \'limited\'\n", lineno, flag); + } + } + + if (!strncmp(name, "ALL", strlen(name))) { + return osm_prtn_add_all(conf->p_log, conf->p_subn, p, + full) == IB_SUCCESS ? 0 : -1; + } else if (!strncmp(name, "SELF", strlen(name))) { + guid = cl_ntoh64(conf->p_subn->sm_port_guid); + } else { + char *end; + guid = strtoull(name, &end, 0); + if (!guid || *end) + return -1; + } + + if (osm_prtn_add_port(conf->p_log, conf->p_subn, p, + cl_hton64(guid), full) != IB_SUCCESS) + return -1; + + return 0; +} + +/* conf file parser */ + +#define STRIP_HEAD_SPACES(p) while (*(p) == ' ' || *(p) == '\t' || \ + *(p) == '\n') { (p)++; } +#define STRIP_TAIL_SPACES(p) { char *q = (p) + strlen(p); \ + while ( q != (p) && ( *q == '\0' || \ + *q == ' ' || *q == '\t' || \ + *q == '\n')) { *q-- = '\0'; }; } + +static int parse_name_token(char *str, char **name, char **val) +{ + int len = 0; + char *p, *q; + + *name = *val = NULL; + + p = str; + + while (*p == ' ' || *p == '\t' || *p == '\n') + p++; + + q = strchr(p, '='); + if (q) + *q++ = '\0'; + + len = strlen(str) + 1; + str = q; + + q = p + strlen(p); + while (q != p && (*q == '\0' || *q == ' ' || *q == '\t' || *q == '\n')) + *q-- = '\0'; + + *name = p; + + p = str; + if (!p) + return len; + + while (*p == ' ' || *p == '\t' || *p == '\n') + p++; + + q = p + strlen(p); + len += (int)(q - str) + 1; + while (q != p && (*q == '\0' || *q == ' ' || *q == '\t' || *q == '\n')) + *q-- = '\0'; + *val = p; + + return len; +} + +static struct part_conf *new_part_conf(osm_log_t * p_log, osm_subn_t * p_subn) +{ + static struct part_conf part; + struct part_conf *conf = ∂ + + memset(conf, 0, sizeof(*conf)); + conf->p_log = p_log; + conf->p_subn = p_subn; + conf->p_prtn = NULL; + conf->is_ipoib = 0; + conf->sl = OSM_DEFAULT_SL; + conf->full = FALSE; + return conf; +} + +static int flush_part_conf(struct part_conf *conf) +{ + memset(conf, 0, sizeof(*conf)); + return 0; +} + +static int parse_part_conf(struct part_conf *conf, char *str, int lineno) +{ + int ret, len = 0; + char *name, *id, *flag, *flval; + char *q, *p; + + p = str; + if (*p == '\t' || *p == '\0' || *p == '\n') + p++; + + len += (int)(p - str); + str = p; + + if (conf->p_prtn) + goto skip_header; + + q = strchr(p, ':'); + if (!q) { + OSM_LOG(conf->p_log, OSM_LOG_ERROR, "PARSE ERROR: line %d: " + "no partition definition found\n", lineno); + fprintf(stderr, "\nPARSE ERROR: line %d: " + "no partition definition found\n", lineno); + return -1; + } + + *q++ = '\0'; + str = q; + + name = id = flag = flval = NULL; + + q = strchr(p, ','); + if (q) + *q = '\0'; + + ret = parse_name_token(p, &name, &id); + p += ret; + len += ret; + + while (q) { + flag = flval = NULL; + q = strchr(p, ','); + if (q) + *q++ = '\0'; + ret = parse_name_token(p, &flag, &flval); + if (!flag) { + OSM_LOG(conf->p_log, OSM_LOG_ERROR, + "PARSE ERROR: line %d: " + "bad partition flags\n", lineno); + fprintf(stderr, "\nPARSE ERROR: line %d: " + "bad partition flags\n", lineno); + return -1; + } + p += ret; + len += ret; + partition_add_flag(lineno, conf, flag, flval); + } + + if (p != str || (partition_create(lineno, conf, + name, id, flag, flval) < 0)) { + OSM_LOG(conf->p_log, OSM_LOG_ERROR, "PARSE ERROR: line %d: " + "bad partition definition\n", lineno); + fprintf(stderr, "\nPARSE ERROR: line %d: " + "bad partition definition\n", lineno); + return -1; + } + +skip_header: + do { + name = flag = NULL; + q = strchr(p, ','); + if (q) + *q++ = '\0'; + ret = parse_name_token(p, &name, &flag); + if (partition_add_port(lineno, conf, name, flag) < 0) { + OSM_LOG(conf->p_log, OSM_LOG_ERROR, + "PARSE ERROR: line %d: " + "bad PortGUID\n", lineno); + fprintf(stderr, "PARSE ERROR: line %d: " + "bad PortGUID\n", lineno); + return -1; + } + p += ret; + len += ret; + } while (q); + + return len; +} + +int osm_prtn_config_parse_file(osm_log_t * p_log, osm_subn_t * p_subn, + const char *file_name) +{ + char line[1024]; + struct part_conf *conf = NULL; + FILE *file; + int lineno; + + file = fopen(file_name, "r"); + if (!file) { + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "Cannot open config file \'%s\': %s\n", + file_name, strerror(errno)); + return -1; + } + + lineno = 0; + + while (fgets(line, sizeof(line) - 1, file) != NULL) { + char *q, *p = line; + + lineno++; + + p = line; + + q = strchr(p, '#'); + if (q) + *q = '\0'; + + do { + int len; + while (*p == ' ' || *p == '\t' || *p == '\n') + p++; + if (*p == '\0') + break; + + if (!conf && !(conf = new_part_conf(p_log, p_subn))) { + OSM_LOG(conf->p_log, OSM_LOG_ERROR, + "PARSE ERROR: line %d: " + "internal: cannot create config\n", + lineno); + fprintf(stderr, + "PARSE ERROR: line %d: " + "internal: cannot create config\n", + lineno); + break; + } + + q = strchr(p, ';'); + if (q) + *q = '\0'; + + len = parse_part_conf(conf, p, lineno); + if (len < 0) { + break; + } + + p += len; + + if (q) { + flush_part_conf(conf); + conf = NULL; + } + } while (q); + } + + fclose(file); + + return 0; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_qos.c b/contrib/ofed/management/opensm/opensm/osm_qos.c new file mode 100644 index 000000000000..b451c25ab513 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_qos.c @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of OpenSM QoS infrastructure primitives + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +struct qos_config { + uint8_t max_vls; + uint8_t vl_high_limit; + ib_vl_arb_table_t vlarb_high[2]; + ib_vl_arb_table_t vlarb_low[2]; + ib_slvl_table_t sl2vl; +}; + +static void qos_build_config(struct qos_config *cfg, + osm_qos_options_t * opt, osm_qos_options_t * dflt); + +/* + * QoS primitives + */ +static ib_api_status_t vlarb_update_table_block(osm_sm_t * sm, + osm_physp_t * p, + uint8_t port_num, + unsigned force_update, + const ib_vl_arb_table_t * + table_block, + unsigned block_length, + unsigned block_num) +{ + ib_vl_arb_table_t block; + osm_madw_context_t context; + uint32_t attr_mod; + unsigned vl_mask, i; + + vl_mask = (1 << (ib_port_info_get_op_vls(&p->port_info) - 1)) - 1; + + memset(&block, 0, sizeof(block)); + memcpy(&block, table_block, block_length * sizeof(block.vl_entry[0])); + for (i = 0; i < block_length; i++) + block.vl_entry[i].vl &= vl_mask; + + if (!force_update && + !memcmp(&p->vl_arb[block_num], &block, + block_length * sizeof(block.vl_entry[0]))) + return IB_SUCCESS; + + context.vla_context.node_guid = + osm_node_get_node_guid(osm_physp_get_node_ptr(p)); + context.vla_context.port_guid = osm_physp_get_port_guid(p); + context.vla_context.set_method = TRUE; + attr_mod = ((block_num + 1) << 16) | port_num; + + return osm_req_set(sm, osm_physp_get_dr_path_ptr(p), + (uint8_t *) & block, sizeof(block), + IB_MAD_ATTR_VL_ARBITRATION, + cl_hton32(attr_mod), CL_DISP_MSGID_NONE, &context); +} + +static ib_api_status_t vlarb_update(osm_sm_t * sm, + osm_physp_t * p, uint8_t port_num, + unsigned force_update, + const struct qos_config *qcfg) +{ + ib_api_status_t status = IB_SUCCESS; + ib_port_info_t *p_pi = &p->port_info; + unsigned len; + + if (p_pi->vl_arb_low_cap > 0) { + len = p_pi->vl_arb_low_cap < IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK ? + p_pi->vl_arb_low_cap : IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK; + if ((status = vlarb_update_table_block(sm, p, port_num, + force_update, + &qcfg->vlarb_low[0], + len, 0)) != IB_SUCCESS) + return status; + } + if (p_pi->vl_arb_low_cap > IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK) { + len = p_pi->vl_arb_low_cap % IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK; + if ((status = vlarb_update_table_block(sm, p, port_num, + force_update, + &qcfg->vlarb_low[1], + len, 1)) != IB_SUCCESS) + return status; + } + if (p_pi->vl_arb_high_cap > 0) { + len = p_pi->vl_arb_high_cap < IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK ? + p_pi->vl_arb_high_cap : IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK; + if ((status = vlarb_update_table_block(sm, p, port_num, + force_update, + &qcfg->vlarb_high[0], + len, 2)) != IB_SUCCESS) + return status; + } + if (p_pi->vl_arb_high_cap > IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK) { + len = p_pi->vl_arb_high_cap % IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK; + if ((status = vlarb_update_table_block(sm, p, port_num, + force_update, + &qcfg->vlarb_high[1], + len, 3)) != IB_SUCCESS) + return status; + } + + return status; +} + +static ib_api_status_t sl2vl_update_table(osm_sm_t * sm, + osm_physp_t * p, uint8_t in_port, + uint8_t out_port, + unsigned force_update, + const ib_slvl_table_t * sl2vl_table) +{ + osm_madw_context_t context; + ib_slvl_table_t tbl, *p_tbl; + osm_node_t *p_node = osm_physp_get_node_ptr(p); + uint32_t attr_mod; + unsigned vl_mask; + uint8_t vl1, vl2; + int i; + + vl_mask = (1 << (ib_port_info_get_op_vls(&p->port_info) - 1)) - 1; + + for (i = 0; i < IB_MAX_NUM_VLS / 2; i++) { + vl1 = sl2vl_table->raw_vl_by_sl[i] >> 4; + vl2 = sl2vl_table->raw_vl_by_sl[i] & 0xf; + if (vl1 != 15) + vl1 &= vl_mask; + if (vl2 != 15) + vl2 &= vl_mask; + tbl.raw_vl_by_sl[i] = (vl1 << 4) | vl2; + } + + if (!force_update && (p_tbl = osm_physp_get_slvl_tbl(p, in_port)) && + !memcmp(p_tbl, &tbl, sizeof(tbl))) + return IB_SUCCESS; + + context.slvl_context.node_guid = osm_node_get_node_guid(p_node); + context.slvl_context.port_guid = osm_physp_get_port_guid(p); + context.slvl_context.set_method = TRUE; + attr_mod = in_port << 8 | out_port; + return osm_req_set(sm, osm_physp_get_dr_path_ptr(p), + (uint8_t *) & tbl, sizeof(tbl), + IB_MAD_ATTR_SLVL_TABLE, + cl_hton32(attr_mod), CL_DISP_MSGID_NONE, &context); +} + +static ib_api_status_t sl2vl_update(osm_sm_t * sm, osm_port_t * p_port, + osm_physp_t * p, uint8_t port_num, + unsigned force_update, + const struct qos_config *qcfg) +{ + ib_api_status_t status; + uint8_t i, num_ports; + osm_physp_t *p_physp; + + if (osm_node_get_type(osm_physp_get_node_ptr(p)) == IB_NODE_TYPE_SWITCH) { + if (ib_port_info_get_vl_cap(&p->port_info) == 1) { + /* Check port 0's capability mask */ + p_physp = p_port->p_physp; + if (! + (p_physp->port_info. + capability_mask & IB_PORT_CAP_HAS_SL_MAP)) + return IB_SUCCESS; + } + num_ports = osm_node_get_num_physp(osm_physp_get_node_ptr(p)); + } else { + if (!(p->port_info.capability_mask & IB_PORT_CAP_HAS_SL_MAP)) + return IB_SUCCESS; + num_ports = 1; + } + + for (i = 0; i < num_ports; i++) { + status = + sl2vl_update_table(sm, p, i, port_num, + force_update, &qcfg->sl2vl); + if (status != IB_SUCCESS) + return status; + } + + return IB_SUCCESS; +} + +static ib_api_status_t qos_physp_setup(osm_log_t * p_log, osm_sm_t * sm, + osm_port_t * p_port, osm_physp_t * p, + uint8_t port_num, + unsigned force_update, + const struct qos_config *qcfg) +{ + ib_api_status_t status; + + /* OpVLs should be ok at this moment - just use it */ + + /* setup VL high limit on the physp later to be updated by link mgr */ + p->vl_high_limit = qcfg->vl_high_limit; + + /* setup VLArbitration */ + status = vlarb_update(sm, p, port_num, force_update, qcfg); + if (status != IB_SUCCESS) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6202 : " + "failed to update VLArbitration tables " + "for port %" PRIx64 " #%d\n", + cl_ntoh64(p->port_guid), port_num); + return status; + } + + /* setup SL2VL tables */ + status = sl2vl_update(sm, p_port, p, port_num, force_update, qcfg); + if (status != IB_SUCCESS) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6203 : " + "failed to update SL2VLMapping tables " + "for port %" PRIx64 " #%d\n", + cl_ntoh64(p->port_guid), port_num); + return status; + } + + return IB_SUCCESS; +} + +osm_signal_t osm_qos_setup(osm_opensm_t * p_osm) +{ + struct qos_config ca_config, sw0_config, swe_config, rtr_config; + struct qos_config *cfg; + cl_qmap_t *p_tbl; + cl_map_item_t *p_next; + osm_port_t *p_port; + uint32_t num_physp; + osm_physp_t *p_physp; + osm_node_t *p_node; + ib_api_status_t status; + unsigned force_update; + uint8_t i; + + if (!p_osm->subn.opt.qos) + return OSM_SIGNAL_DONE; + + OSM_LOG_ENTER(&p_osm->log); + + qos_build_config(&ca_config, &p_osm->subn.opt.qos_ca_options, + &p_osm->subn.opt.qos_options); + qos_build_config(&sw0_config, &p_osm->subn.opt.qos_sw0_options, + &p_osm->subn.opt.qos_options); + qos_build_config(&swe_config, &p_osm->subn.opt.qos_swe_options, + &p_osm->subn.opt.qos_options); + qos_build_config(&rtr_config, &p_osm->subn.opt.qos_rtr_options, + &p_osm->subn.opt.qos_options); + + cl_plock_excl_acquire(&p_osm->lock); + + /* read QoS policy config file */ + osm_qos_parse_policy_file(&p_osm->subn); + + p_tbl = &p_osm->subn.port_guid_tbl; + p_next = cl_qmap_head(p_tbl); + while (p_next != cl_qmap_end(p_tbl)) { + p_port = (osm_port_t *) p_next; + p_next = cl_qmap_next(p_next); + + p_node = p_port->p_node; + if (p_node->sw) { + num_physp = osm_node_get_num_physp(p_node); + for (i = 1; i < num_physp; i++) { + p_physp = osm_node_get_physp_ptr(p_node, i); + if (!p_physp) + continue; + force_update = p_physp->need_update || + p_osm->subn.need_update; + status = + qos_physp_setup(&p_osm->log, &p_osm->sm, + p_port, p_physp, i, + force_update, &swe_config); + } + /* skip base port 0 */ + if (!ib_switch_info_is_enhanced_port0 + (&p_node->sw->switch_info)) + continue; + + cfg = &sw0_config; + } else if (osm_node_get_type(p_node) == IB_NODE_TYPE_ROUTER) + cfg = &rtr_config; + else + cfg = &ca_config; + + p_physp = p_port->p_physp; + if (!p_physp) + continue; + + force_update = p_physp->need_update || p_osm->subn.need_update; + status = qos_physp_setup(&p_osm->log, &p_osm->sm, + p_port, p_physp, 0, force_update, cfg); + } + + cl_plock_release(&p_osm->lock); + OSM_LOG_EXIT(&p_osm->log); + + return OSM_SIGNAL_DONE; +} + +/* + * QoS config stuff + */ +static int parse_one_unsigned(char *str, char delim, unsigned *val) +{ + char *end; + *val = strtoul(str, &end, 0); + if (*end) + end++; + return (int)(end - str); +} + +static int parse_vlarb_entry(char *str, ib_vl_arb_element_t * e) +{ + unsigned val; + char *p = str; + p += parse_one_unsigned(p, ':', &val); + e->vl = val % 15; + p += parse_one_unsigned(p, ',', &val); + e->weight = (uint8_t) val; + return (int)(p - str); +} + +static int parse_sl2vl_entry(char *str, uint8_t * raw) +{ + unsigned val1, val2; + char *p = str; + p += parse_one_unsigned(p, ',', &val1); + p += parse_one_unsigned(p, ',', &val2); + *raw = (val1 << 4) | (val2 & 0xf); + return (int)(p - str); +} + +static void qos_build_config(struct qos_config *cfg, + osm_qos_options_t * opt, osm_qos_options_t * dflt) +{ + int i; + char *p; + + memset(cfg, 0, sizeof(*cfg)); + + cfg->max_vls = opt->max_vls > 0 ? opt->max_vls : dflt->max_vls; + + if (opt->high_limit >= 0) + cfg->vl_high_limit = (uint8_t) opt->high_limit; + else + cfg->vl_high_limit = (uint8_t) dflt->high_limit; + + p = opt->vlarb_high ? opt->vlarb_high : dflt->vlarb_high; + for (i = 0; i < 2 * IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK; i++) { + p += parse_vlarb_entry(p, + &cfg->vlarb_high[i / + IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK]. + vl_entry[i % + IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK]); + } + + p = opt->vlarb_low ? opt->vlarb_low : dflt->vlarb_low; + for (i = 0; i < 2 * IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK; i++) { + p += parse_vlarb_entry(p, + &cfg->vlarb_low[i / + IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK]. + vl_entry[i % + IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK]); + } + + p = opt->sl2vl ? opt->sl2vl : dflt->sl2vl; + for (i = 0; i < IB_MAX_NUM_VLS / 2; i++) + p += parse_sl2vl_entry(p, &cfg->sl2vl.raw_vl_by_sl[i]); + +} diff --git a/contrib/ofed/management/opensm/opensm/osm_qos_parser_l.l b/contrib/ofed/management/opensm/opensm/osm_qos_parser_l.l new file mode 100644 index 000000000000..ecdee8a0b085 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_qos_parser_l.l @@ -0,0 +1,394 @@ +%{ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Lexer of OSM QoS parser. + * + * Environment: + * Linux User Mode + * + * Author: + * Yevgeny Kliteynik, Mellanox + */ + +#include +#include "osm_qos_parser_y.h" + +#define HANDLE_IF_IN_DESCRIPTION if (in_description) { yylval = strdup(yytext); return TK_TEXT; } + +#define SAVE_POS save_pos() +static void save_pos(); + +extern int column_num; +extern int line_num; +extern FILE * yyin; +extern YYSTYPE yylval; + +boolean_t in_description = FALSE; +boolean_t in_list_of_hex_num_ranges = FALSE; +boolean_t in_node_type = FALSE; +boolean_t in_list_of_numbers = FALSE; +boolean_t in_list_of_strings = FALSE; +boolean_t in_list_of_num_pairs = FALSE; +boolean_t in_asterisk_or_list_of_numbers = FALSE; +boolean_t in_list_of_num_ranges = FALSE; +boolean_t in_single_string = FALSE; +boolean_t in_single_number = FALSE; + +static void reset_new_line_flags(); +#define RESET_NEW_LINE_FLAGS reset_new_line_flags() + +#define START_USE {in_description = TRUE;} /* list of strings including whitespace (description) */ +#define START_PORT_GUID {in_list_of_hex_num_ranges = TRUE;} /* comma-separated list of hex num ranges */ +#define START_PORT_NAME {in_list_of_strings = TRUE;} /* comma-separated list of following strings: ../../.. */ +#define START_PARTITION {in_single_string = TRUE;} /* single string w/o whitespaces (partition name) */ +#define START_NAME {in_single_string = TRUE;} /* single string w/o whitespaces (port group name) */ +#define START_QOS_LEVEL_NAME {in_single_string = TRUE;} /* single string w/o whitespaces (qos level name in match rule) */ + +#define START_NODE_TYPE {in_node_type = TRUE;} /* comma-separated list of node types (ROUTER,CA,...) */ +#define START_SL2VL_TABLE {in_list_of_numbers = TRUE;} /* comma-separated list of hex or dec numbers */ + +#define START_GROUP {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_ACROSS {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_ACROSS_TO {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_ACROSS_FROM {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_SOURCE {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ +#define START_DESTINATION {in_list_of_strings = TRUE;} /* list of strings w/o whitespaces (group names) */ + +#define START_VLARB_HIGH {in_list_of_num_pairs = TRUE;} /* comma-separated list of hex or dec num pairs: "num1:num2" */ +#define START_VLARB_LOW {in_list_of_num_pairs = TRUE;} /* comma-separated list of hex or dec num pairs: "num1:num2" */ + +#define START_TO {in_asterisk_or_list_of_numbers = TRUE;} /* (asterisk) or (comma-separated list of hex or dec numbers) */ +#define START_FROM {in_asterisk_or_list_of_numbers = TRUE;} /* (asterisk) or (comma-separated list of hex or dec numbers) */ + +#define START_PATH_BITS {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_QOS_CLASS {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_SERVICE_ID {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_PKEY {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ + +#define START_SL {in_single_number = TRUE;} /* single number */ +#define START_VLARB_HIGH_LIMIT {in_single_number = TRUE;} /* single number */ +#define START_MTU_LIMIT {in_single_number = TRUE;} /* single number */ +#define START_RATE_LIMIT {in_single_number = TRUE;} /* single number */ +#define START_PACKET_LIFE {in_single_number = TRUE;} /* single number */ + +#define START_ULP_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_ANY {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_SDP_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_SDP_PORT {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_RDS_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_RDS_PORT {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_ISER_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_ISER_PORT {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_SRP_GUID {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ +#define START_ULP_IPOIB_DEFAULT {in_single_number = TRUE;} /* single number */ +#define START_ULP_IPOIB_PKEY {in_list_of_num_ranges = TRUE;} /* comma-separated list of hex or dec num ranges */ + + +%} + +%option nounput noinput + +QOS_ULPS_START qos\-ulps +QOS_ULPS_END end\-qos\-ulps +PORT_GROUPS_START port\-groups +PORT_GROUPS_END end\-port\-groups +PORT_GROUP_START port\-group +PORT_GROUP_END end\-port\-group +PORT_NUM port\-num +NAME name +USE use +PORT_GUID port\-guid +TARGET_PORT_GUID target\-port\-guid +PORT_NAME port\-name +PARTITION partition +NODE_TYPE node\-type +QOS_SETUP_START qos\-setup +QOS_SETUP_END end\-qos\-setup +VLARB_TABLES_START vlarb\-tables +VLARB_TABLES_END end\-vlarb\-tables +VLARB_SCOPE_START vlarb\-scope +VLARB_SCOPE_END end\-vlarb\-scope +GROUP group +ACROSS across +VLARB_HIGH vlarb\-high +VLARB_LOW vlarb\-low +VLARB_HIGH_LIMIT vl\-high\-limit +SL2VL_TABLES_START sl2vl\-tables +SL2VL_TABLES_END end\-sl2vl\-tables +SL2VL_SCOPE_START sl2vl\-scope +SL2VL_SCOPE_END end\-sl2vl\-scope +TO to +FROM from +ACROSS_TO across\-to +ACROSS_FROM across\-from +SL2VL_TABLE sl2vl\-table +QOS_LEVELS_START qos\-levels +QOS_LEVELS_END end\-qos\-levels +QOS_LEVEL_START qos\-level +QOS_LEVEL_END end\-qos\-level +SL sl +MTU_LIMIT mtu\-limit +RATE_LIMIT rate\-limit +PACKET_LIFE packet\-life +PATH_BITS path\-bits +QOS_MATCH_RULES_START qos\-match\-rules +QOS_MATCH_RULES_END end\-qos\-match\-rules +QOS_MATCH_RULE_START qos\-match\-rule +QOS_MATCH_RULE_END end\-qos\-match\-rule +QOS_CLASS qos\-class +SOURCE source +DESTINATION destination +SERVICE_ID service\-id +PKEY pkey +QOS_LEVEL_NAME qos\-level\-name + +ROUTER [Rr][Oo][Uu][Tt][Ee][Rr] +CA [Cc][Aa] +SWITCH [Ss][Ww][Ii][Tt][Cc][Hh] +SELF [Ss][Ee][Ll][Ff] +ALL [Aa][Ll][Ll] + +ULP_SDP [Ss][Dd][Pp] +ULP_SRP [Ss][Rr][Pp] +ULP_RDS [Rr][Dd][Ss] +ULP_IPOIB [Ii][Pp][Oo][Ii][Bb] +ULP_ISER [Ii][Ss][Ee][Rr] +ULP_ANY [Aa][Nn][Yy] +ULP_DEFAULT [Dd][Ee][Ff][Aa][Uu][Ll][Tt] + +WHITE [ \t]+ +NEW_LINE \n +COMMENT \#.*\n +WHITE_DOTDOT_WHITE [ \t]*:[ \t]* +WHITE_COMMA_WHITE [ \t]*,[ \t]* +QUOTED_TEXT \"[^\"]*\" + +%% + + +{COMMENT} { SAVE_POS; RESET_NEW_LINE_FLAGS; } /* swallow comment */ +{WHITE}{NEW_LINE} { SAVE_POS; RESET_NEW_LINE_FLAGS; } /* trailing blanks with new line */ +{WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; } +{NEW_LINE} { SAVE_POS; RESET_NEW_LINE_FLAGS; } + +{QOS_ULPS_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_ULPS_START; } +{QOS_ULPS_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_ULPS_END; } + +{PORT_GROUPS_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_PORT_GROUPS_START; } +{PORT_GROUPS_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_PORT_GROUPS_END; } +{PORT_GROUP_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_PORT_GROUP_START; } +{PORT_GROUP_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_PORT_GROUP_END; } + +{QOS_SETUP_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_SETUP_START; } +{QOS_SETUP_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_SETUP_END; } +{VLARB_TABLES_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_VLARB_TABLES_START; } +{VLARB_TABLES_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_VLARB_TABLES_END; } +{VLARB_SCOPE_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_VLARB_SCOPE_START; } +{VLARB_SCOPE_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_VLARB_SCOPE_END; } + +{SL2VL_TABLES_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_SL2VL_TABLES_START; } +{SL2VL_TABLES_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_SL2VL_TABLES_END; } +{SL2VL_SCOPE_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_SL2VL_SCOPE_START; } +{SL2VL_SCOPE_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_SL2VL_SCOPE_END; } + +{QOS_LEVELS_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_LEVELS_START; } +{QOS_LEVELS_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_LEVELS_END; } +{QOS_LEVEL_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_LEVEL_START; } +{QOS_LEVEL_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_LEVEL_END; } + +{QOS_MATCH_RULES_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_MATCH_RULES_START; } +{QOS_MATCH_RULES_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_MATCH_RULES_END; } +{QOS_MATCH_RULE_START} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_MATCH_RULE_START; } +{QOS_MATCH_RULE_END} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; return TK_QOS_MATCH_RULE_END; } + +{PORT_GUID}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PORT_GUID; return TK_PORT_GUID; } +{PORT_NAME}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PORT_NAME; return TK_PORT_NAME; } +{PARTITION}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PARTITION; return TK_PARTITION; } +{NODE_TYPE}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_NODE_TYPE; return TK_NODE_TYPE; } +{NAME}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_NAME; return TK_NAME; } +{USE}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_USE; return TK_USE; } +{GROUP}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_GROUP; return TK_GROUP; } +{VLARB_HIGH}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_VLARB_HIGH; return TK_VLARB_HIGH; } +{VLARB_LOW}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_VLARB_LOW; return TK_VLARB_LOW; } +{VLARB_HIGH_LIMIT}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_VLARB_HIGH_LIMIT; return TK_VLARB_HIGH_LIMIT;} +{TO}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_TO; return TK_TO; } +{FROM}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_FROM; return TK_FROM; } +{ACROSS_TO}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ACROSS_TO; return TK_ACROSS_TO; } +{ACROSS_FROM}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ACROSS_FROM; return TK_ACROSS_FROM;} +{ACROSS}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ACROSS; return TK_ACROSS; } +{SL2VL_TABLE}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_SL2VL_TABLE; return TK_SL2VL_TABLE;} +{SL}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_SL; return TK_SL; } +{MTU_LIMIT}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_MTU_LIMIT; return TK_MTU_LIMIT; } +{RATE_LIMIT}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_RATE_LIMIT; return TK_RATE_LIMIT; } +{PACKET_LIFE}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PACKET_LIFE; return TK_PACKET_LIFE;} +{PATH_BITS}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PATH_BITS; return TK_PATH_BITS; } +{QOS_CLASS}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_QOS_CLASS; return TK_QOS_CLASS; } +{SOURCE}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_SOURCE; return TK_SOURCE; } +{DESTINATION}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_DESTINATION; return TK_DESTINATION;} +{SERVICE_ID}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_SERVICE_ID; return TK_SERVICE_ID; } +{PKEY}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_PKEY; return TK_PKEY; } +{QOS_LEVEL_NAME}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_QOS_LEVEL_NAME; return TK_QOS_LEVEL_NAME;} + +{ROUTER} { SAVE_POS; if (in_node_type) return TK_NODE_TYPE_ROUTER; yylval = strdup(yytext); return TK_TEXT; } +{CA} { SAVE_POS; if (in_node_type) return TK_NODE_TYPE_CA; yylval = strdup(yytext); return TK_TEXT; } +{SWITCH} { SAVE_POS; if (in_node_type) return TK_NODE_TYPE_SWITCH; yylval = strdup(yytext); return TK_TEXT; } +{SELF} { SAVE_POS; if (in_node_type) return TK_NODE_TYPE_SELF; yylval = strdup(yytext); return TK_TEXT; } +{ALL} { SAVE_POS; if (in_node_type) return TK_NODE_TYPE_ALL; yylval = strdup(yytext); return TK_TEXT; } + +{ULP_DEFAULT}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_DEFAULT; return TK_ULP_DEFAULT; } +{ULP_ANY}{WHITE_COMMA_WHITE}{SERVICE_ID} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_ANY; return TK_ULP_ANY_SERVICE_ID; } +{ULP_ANY}{WHITE_COMMA_WHITE}{PKEY} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_ANY; return TK_ULP_ANY_PKEY; } +{ULP_ANY}{WHITE_COMMA_WHITE}{TARGET_PORT_GUID} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_ANY; return TK_ULP_ANY_TARGET_PORT_GUID; } + +{ULP_SDP}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SDP_DEFAULT; return TK_ULP_SDP_DEFAULT; } +{ULP_SDP}{WHITE_COMMA_WHITE}{PORT_NUM} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SDP_PORT; return TK_ULP_SDP_PORT; } + +{ULP_RDS}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_RDS_DEFAULT; return TK_ULP_RDS_DEFAULT; } +{ULP_RDS}{WHITE_COMMA_WHITE}{PORT_NUM} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_RDS_PORT; return TK_ULP_RDS_PORT; } + +{ULP_ISER}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SDP_DEFAULT; return TK_ULP_ISER_DEFAULT; } +{ULP_ISER}{WHITE_COMMA_WHITE}{PORT_NUM} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SDP_PORT; return TK_ULP_ISER_PORT; } + +{ULP_SRP}{WHITE_COMMA_WHITE}{TARGET_PORT_GUID} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_SRP_GUID; return TK_ULP_SRP_GUID; } + +{ULP_IPOIB}{WHITE_DOTDOT_WHITE} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_IPOIB_DEFAULT; return TK_ULP_IPOIB_DEFAULT; } +{ULP_IPOIB}{WHITE_COMMA_WHITE}{PKEY} { SAVE_POS; HANDLE_IF_IN_DESCRIPTION; START_ULP_IPOIB_PKEY; return TK_ULP_IPOIB_PKEY; } + +0[xX][0-9a-fA-F]+ { + SAVE_POS; + yylval = strdup(yytext); + if (in_description || in_list_of_strings || in_single_string) + return TK_TEXT; + return TK_NUMBER; + } + +[0-9]+ { + SAVE_POS; + yylval = strdup(yytext); + if (in_description || in_list_of_strings || in_single_string) + return TK_TEXT; + return TK_NUMBER; + } + + +- { + SAVE_POS; + if (in_description || in_list_of_strings || in_single_string) + { + yylval = strdup(yytext); + return TK_TEXT; + } + return TK_DASH; + } + +: { + SAVE_POS; + if (in_description || in_list_of_strings || in_single_string) + { + yylval = strdup(yytext); + return TK_TEXT; + } + return TK_DOTDOT; + } + +, { + SAVE_POS; + if (in_description) + { + yylval = strdup(yytext); + return TK_TEXT; + } + return TK_COMMA; + } + +\* { + SAVE_POS; + if (in_description || in_list_of_strings || in_single_string) + { + yylval = strdup(yytext); + return TK_TEXT; + } + return TK_ASTERISK; + } + +{QUOTED_TEXT} { + SAVE_POS; + yylval = strdup(&yytext[1]); + yylval[strlen(yylval)-1] = '\0'; + return TK_TEXT; + } + +. { SAVE_POS; yylval = strdup(yytext); return TK_TEXT;} + +%% + + +/********************************************* + *********************************************/ + +static void save_pos() +{ + int i; + for (i = 0; i < yyleng; i++) + { + if (yytext[i] == '\n') + { + line_num ++; + column_num = 1; + } + else + column_num ++; + } +} + +/********************************************* + *********************************************/ + +static void reset_new_line_flags() +{ + in_description = FALSE; + in_list_of_hex_num_ranges = FALSE; + in_node_type = FALSE; + in_list_of_numbers = FALSE; + in_list_of_strings = FALSE; + in_list_of_num_pairs = FALSE; + in_asterisk_or_list_of_numbers = FALSE; + in_list_of_num_ranges = FALSE; + in_single_string = FALSE; + in_single_number = FALSE; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_qos_parser_y.y b/contrib/ofed/management/opensm/opensm/osm_qos_parser_y.y new file mode 100644 index 000000000000..6b5a9b124b4f --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_qos_parser_y.y @@ -0,0 +1,3063 @@ +%{ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Grammar of OSM QoS parser. + * + * Environment: + * Linux User Mode + * + * Author: + * Yevgeny Kliteynik, Mellanox + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_QOS_POLICY_MAX_LINE_LEN 1024*10 +#define OSM_QOS_POLICY_SL2VL_TABLE_LEN IB_MAX_NUM_VLS +#define OSM_QOS_POLICY_MAX_VL_NUM IB_MAX_NUM_VLS + +typedef struct tmp_parser_struct_t_ { + char str[OSM_QOS_POLICY_MAX_LINE_LEN]; + uint64_t num_pair[2]; + cl_list_t str_list; + cl_list_t num_list; + cl_list_t num_pair_list; +} tmp_parser_struct_t; + +static void __parser_tmp_struct_init(); +static void __parser_tmp_struct_reset(); +static void __parser_tmp_struct_destroy(); + +static char * __parser_strip_white(char * str); + +static void __parser_str2uint64(uint64_t * p_val, char * str); + +static void __parser_port_group_start(); +static int __parser_port_group_end(); + +static void __parser_sl2vl_scope_start(); +static int __parser_sl2vl_scope_end(); + +static void __parser_vlarb_scope_start(); +static int __parser_vlarb_scope_end(); + +static void __parser_qos_level_start(); +static int __parser_qos_level_end(); + +static void __parser_match_rule_start(); +static int __parser_match_rule_end(); + +static void __parser_ulp_match_rule_start(); +static int __parser_ulp_match_rule_end(); + +static void __pkey_rangelist2rangearr( + cl_list_t * p_list, + uint64_t ** * p_arr, + unsigned * p_arr_len); + +static void __rangelist2rangearr( + cl_list_t * p_list, + uint64_t ** * p_arr, + unsigned * p_arr_len); + +static void __merge_rangearr( + uint64_t ** range_arr_1, + unsigned range_len_1, + uint64_t ** range_arr_2, + unsigned range_len_2, + uint64_t ** * p_arr, + unsigned * p_arr_len ); + +static void __parser_add_port_to_port_map( + cl_qmap_t * p_map, + osm_physp_t * p_physp); + +static void __parser_add_guid_range_to_port_map( + cl_qmap_t * p_map, + uint64_t ** range_arr, + unsigned range_len); + +static void __parser_add_pkey_range_to_port_map( + cl_qmap_t * p_map, + uint64_t ** range_arr, + unsigned range_len); + +static void __parser_add_partition_list_to_port_map( + cl_qmap_t * p_map, + cl_list_t * p_list); + +static void __parser_add_map_to_port_map( + cl_qmap_t * p_dmap, + cl_map_t * p_smap); + +static int __validate_pkeys( + uint64_t ** range_arr, + unsigned range_len, + boolean_t is_ipoib); + +static void __setup_simple_qos_levels(); +static void __clear_simple_qos_levels(); +static void __setup_ulp_match_rules(); +static void __process_ulp_match_rules(); +static void yyerror(const char *format, ...); + +extern char * yytext; +extern int yylex (void); +extern FILE * yyin; +extern int errno; +int yyparse(); + +#define RESET_BUFFER __parser_tmp_struct_reset() + +tmp_parser_struct_t tmp_parser_struct; + +int column_num; +int line_num; + +osm_qos_policy_t * p_qos_policy = NULL; +osm_qos_port_group_t * p_current_port_group = NULL; +osm_qos_sl2vl_scope_t * p_current_sl2vl_scope = NULL; +osm_qos_vlarb_scope_t * p_current_vlarb_scope = NULL; +osm_qos_level_t * p_current_qos_level = NULL; +osm_qos_match_rule_t * p_current_qos_match_rule = NULL; +osm_log_t * p_qos_parser_osm_log; + +/* 16 Simple QoS Levels - one for each SL */ +static osm_qos_level_t osm_qos_policy_simple_qos_levels[16]; + +/* Default Simple QoS Level */ +osm_qos_level_t __default_simple_qos_level; + +/* + * List of match rules that will be generated by the + * qos-ulp section. These rules are concatenated to + * the end of the usual matching rules list at the + * end of parsing. + */ +static cl_list_t __ulp_match_rules; + +/***************************************************/ + +%} + +%token TK_NUMBER +%token TK_DASH +%token TK_DOTDOT +%token TK_COMMA +%token TK_ASTERISK +%token TK_TEXT + +%token TK_QOS_ULPS_START +%token TK_QOS_ULPS_END + +%token TK_PORT_GROUPS_START +%token TK_PORT_GROUPS_END +%token TK_PORT_GROUP_START +%token TK_PORT_GROUP_END + +%token TK_QOS_SETUP_START +%token TK_QOS_SETUP_END +%token TK_VLARB_TABLES_START +%token TK_VLARB_TABLES_END +%token TK_VLARB_SCOPE_START +%token TK_VLARB_SCOPE_END + +%token TK_SL2VL_TABLES_START +%token TK_SL2VL_TABLES_END +%token TK_SL2VL_SCOPE_START +%token TK_SL2VL_SCOPE_END + +%token TK_QOS_LEVELS_START +%token TK_QOS_LEVELS_END +%token TK_QOS_LEVEL_START +%token TK_QOS_LEVEL_END + +%token TK_QOS_MATCH_RULES_START +%token TK_QOS_MATCH_RULES_END +%token TK_QOS_MATCH_RULE_START +%token TK_QOS_MATCH_RULE_END + +%token TK_NAME +%token TK_USE +%token TK_PORT_GUID +%token TK_PORT_NAME +%token TK_PARTITION +%token TK_NODE_TYPE +%token TK_GROUP +%token TK_ACROSS +%token TK_VLARB_HIGH +%token TK_VLARB_LOW +%token TK_VLARB_HIGH_LIMIT +%token TK_TO +%token TK_FROM +%token TK_ACROSS_TO +%token TK_ACROSS_FROM +%token TK_SL2VL_TABLE +%token TK_SL +%token TK_MTU_LIMIT +%token TK_RATE_LIMIT +%token TK_PACKET_LIFE +%token TK_PATH_BITS +%token TK_QOS_CLASS +%token TK_SOURCE +%token TK_DESTINATION +%token TK_SERVICE_ID +%token TK_QOS_LEVEL_NAME +%token TK_PKEY + +%token TK_NODE_TYPE_ROUTER +%token TK_NODE_TYPE_CA +%token TK_NODE_TYPE_SWITCH +%token TK_NODE_TYPE_SELF +%token TK_NODE_TYPE_ALL + +%token TK_ULP_DEFAULT +%token TK_ULP_ANY_SERVICE_ID +%token TK_ULP_ANY_PKEY +%token TK_ULP_ANY_TARGET_PORT_GUID +%token TK_ULP_SDP_DEFAULT +%token TK_ULP_SDP_PORT +%token TK_ULP_RDS_DEFAULT +%token TK_ULP_RDS_PORT +%token TK_ULP_ISER_DEFAULT +%token TK_ULP_ISER_PORT +%token TK_ULP_SRP_GUID +%token TK_ULP_IPOIB_DEFAULT +%token TK_ULP_IPOIB_PKEY + +%start head + +%% + +head: qos_policy_entries + ; + +qos_policy_entries: /* empty */ + | qos_policy_entries qos_policy_entry + ; + +qos_policy_entry: qos_ulps_section + | port_groups_section + | qos_setup_section + | qos_levels_section + | qos_match_rules_section + ; + + /* + * Parsing qos-ulps: + * ------------------- + * qos-ulps + * default : 0 #default SL + * sdp, port-num 30000 : 1 #SL for SDP when destination port is 30000 + * sdp, port-num 10000-20000 : 2 + * sdp : 0 #default SL for SDP + * srp, target-port-guid 0x1234 : 2 + * rds, port-num 25000 : 2 #SL for RDS when destination port is 25000 + * rds, : 0 #default SL for RDS + * iser, port-num 900 : 5 #SL for iSER where target port is 900 + * iser : 4 #default SL for iSER + * ipoib, pkey 0x0001 : 5 #SL for IPoIB on partition with pkey 0x0001 + * ipoib : 6 #default IPoIB partition - pkey=0x7FFF + * any, service-id 0x6234 : 2 + * any, pkey 0x0ABC : 3 + * any, target-port-guid 0x0ABC-0xFFFFF : 6 + * end-qos-ulps + */ + +qos_ulps_section: TK_QOS_ULPS_START qos_ulps TK_QOS_ULPS_END + ; + +qos_ulps: qos_ulp + | qos_ulps qos_ulp + ; + + /* + * Parsing port groups: + * ------------------- + * port-groups + * port-group + * name: Storage + * use: our SRP storage targets + * port-guid: 0x1000000000000001,0x1000000000000002 + * ... + * port-name: vs1 HCA-1/P1 + * port-name: node_description/P2 + * ... + * pkey: 0x00FF-0x0FFF + * ... + * partition: Part1 + * ... + * node-type: ROUTER,CA,SWITCH,SELF,ALL + * ... + * end-port-group + * port-group + * ... + * end-port-group + * end-port-groups + */ + + +port_groups_section: TK_PORT_GROUPS_START port_groups TK_PORT_GROUPS_END + ; + +port_groups: port_group + | port_groups port_group + ; + +port_group: port_group_start port_group_entries port_group_end + ; + +port_group_start: TK_PORT_GROUP_START { + __parser_port_group_start(); + } + ; + +port_group_end: TK_PORT_GROUP_END { + if ( __parser_port_group_end() ) + return 1; + } + ; + +port_group_entries: /* empty */ + | port_group_entries port_group_entry + ; + +port_group_entry: port_group_name + | port_group_use + | port_group_port_guid + | port_group_port_name + | port_group_pkey + | port_group_partition + | port_group_node_type + ; + + + /* + * Parsing qos setup: + * ----------------- + * qos-setup + * vlarb-tables + * vlarb-scope + * ... + * end-vlarb-scope + * vlarb-scope + * ... + * end-vlarb-scope + * end-vlarb-tables + * sl2vl-tables + * sl2vl-scope + * ... + * end-sl2vl-scope + * sl2vl-scope + * ... + * end-sl2vl-scope + * end-sl2vl-tables + * end-qos-setup + */ + +qos_setup_section: TK_QOS_SETUP_START qos_setup_items TK_QOS_SETUP_END + ; + +qos_setup_items: /* empty */ + | qos_setup_items vlarb_tables + | qos_setup_items sl2vl_tables + ; + + /* Parsing vlarb-tables */ + +vlarb_tables: TK_VLARB_TABLES_START vlarb_scope_items TK_VLARB_TABLES_END + ; + +vlarb_scope_items: /* empty */ + | vlarb_scope_items vlarb_scope + ; + +vlarb_scope: vlarb_scope_start vlarb_scope_entries vlarb_scope_end + ; + +vlarb_scope_start: TK_VLARB_SCOPE_START { + __parser_vlarb_scope_start(); + } + ; + +vlarb_scope_end: TK_VLARB_SCOPE_END { + if ( __parser_vlarb_scope_end() ) + return 1; + } + ; + +vlarb_scope_entries:/* empty */ + | vlarb_scope_entries vlarb_scope_entry + ; + + /* + * vlarb-scope + * group: Storage + * ... + * across: Storage + * ... + * vlarb-high: 0:255,1:127,2:63,3:31,4:15,5:7,6:3,7:1 + * vlarb-low: 8:255,9:127,10:63,11:31,12:15,13:7,14:3 + * vl-high-limit: 10 + * end-vlarb-scope + */ + +vlarb_scope_entry: vlarb_scope_group + | vlarb_scope_across + | vlarb_scope_vlarb_high + | vlarb_scope_vlarb_low + | vlarb_scope_vlarb_high_limit + ; + + /* Parsing sl2vl-tables */ + +sl2vl_tables: TK_SL2VL_TABLES_START sl2vl_scope_items TK_SL2VL_TABLES_END + ; + +sl2vl_scope_items: /* empty */ + | sl2vl_scope_items sl2vl_scope + ; + +sl2vl_scope: sl2vl_scope_start sl2vl_scope_entries sl2vl_scope_end + ; + +sl2vl_scope_start: TK_SL2VL_SCOPE_START { + __parser_sl2vl_scope_start(); + } + ; + +sl2vl_scope_end: TK_SL2VL_SCOPE_END { + if ( __parser_sl2vl_scope_end() ) + return 1; + } + ; + +sl2vl_scope_entries:/* empty */ + | sl2vl_scope_entries sl2vl_scope_entry + ; + + /* + * sl2vl-scope + * group: Part1 + * ... + * from: * + * ... + * to: * + * ... + * across-to: Storage2 + * ... + * across-from: Storage1 + * ... + * sl2vl-table: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7 + * end-sl2vl-scope + */ + +sl2vl_scope_entry: sl2vl_scope_group + | sl2vl_scope_across + | sl2vl_scope_across_from + | sl2vl_scope_across_to + | sl2vl_scope_from + | sl2vl_scope_to + | sl2vl_scope_sl2vl_table + ; + + /* + * Parsing qos-levels: + * ------------------ + * qos-levels + * qos-level + * name: qos_level_1 + * use: for the lowest priority communication + * sl: 15 + * mtu-limit: 1 + * rate-limit: 1 + * packet-life: 12 + * path-bits: 2,4,8-32 + * pkey: 0x00FF-0x0FFF + * end-qos-level + * ... + * qos-level + * end-qos-level + * end-qos-levels + */ + + +qos_levels_section: TK_QOS_LEVELS_START qos_levels TK_QOS_LEVELS_END + ; + +qos_levels: /* empty */ + | qos_levels qos_level + ; + +qos_level: qos_level_start qos_level_entries qos_level_end + ; + +qos_level_start: TK_QOS_LEVEL_START { + __parser_qos_level_start(); + } + ; + +qos_level_end: TK_QOS_LEVEL_END { + if ( __parser_qos_level_end() ) + return 1; + } + ; + +qos_level_entries: /* empty */ + | qos_level_entries qos_level_entry + ; + +qos_level_entry: qos_level_name + | qos_level_use + | qos_level_sl + | qos_level_mtu_limit + | qos_level_rate_limit + | qos_level_packet_life + | qos_level_path_bits + | qos_level_pkey + ; + + /* + * Parsing qos-match-rules: + * ----------------------- + * qos-match-rules + * qos-match-rule + * use: low latency by class 7-9 or 11 and bla bla + * qos-class: 7-9,11 + * qos-level-name: default + * source: Storage + * destination: Storage + * service-id: 22,4719-5000 + * pkey: 0x00FF-0x0FFF + * end-qos-match-rule + * qos-match-rule + * ... + * end-qos-match-rule + * end-qos-match-rules + */ + +qos_match_rules_section: TK_QOS_MATCH_RULES_START qos_match_rules TK_QOS_MATCH_RULES_END + ; + +qos_match_rules: /* empty */ + | qos_match_rules qos_match_rule + ; + +qos_match_rule: qos_match_rule_start qos_match_rule_entries qos_match_rule_end + ; + +qos_match_rule_start: TK_QOS_MATCH_RULE_START { + __parser_match_rule_start(); + } + ; + +qos_match_rule_end: TK_QOS_MATCH_RULE_END { + if ( __parser_match_rule_end() ) + return 1; + } + ; + +qos_match_rule_entries: /* empty */ + | qos_match_rule_entries qos_match_rule_entry + ; + +qos_match_rule_entry: qos_match_rule_use + | qos_match_rule_qos_class + | qos_match_rule_qos_level_name + | qos_match_rule_source + | qos_match_rule_destination + | qos_match_rule_service_id + | qos_match_rule_pkey + ; + + + /* + * Parsing qos-ulps: + * ----------------- + * default + * sdp + * sdp with port-num + * rds + * rds with port-num + * srp with port-guid + * iser + * iser with port-num + * ipoib + * ipoib with pkey + * any with service-id + * any with pkey + * any with target-port-guid + */ + +qos_ulp: TK_ULP_DEFAULT single_number { + /* parsing default ulp rule: "default: num" */ + cl_list_iterator_t list_iterator; + uint64_t * p_tmp_num; + + list_iterator = cl_list_head(&tmp_parser_struct.num_list); + p_tmp_num = (uint64_t*)cl_list_obj(list_iterator); + if (*p_tmp_num > 15) + { + yyerror("illegal SL value"); + return 1; + } + __default_simple_qos_level.sl = (uint8_t)(*p_tmp_num); + __default_simple_qos_level.sl_set = TRUE; + free(p_tmp_num); + cl_list_remove_all(&tmp_parser_struct.num_list); + } + + | qos_ulp_type_any_service list_of_ranges TK_DOTDOT { + /* "any, service-id ... : sl" - one instance of list of ranges */ + uint64_t ** range_arr; + unsigned range_len; + + if (!cl_list_count(&tmp_parser_struct.num_pair_list)) + { + yyerror("ULP rule doesn't have service ids"); + return 1; + } + + /* get all the service id ranges */ + __rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + + p_current_qos_match_rule->service_id_range_arr = range_arr; + p_current_qos_match_rule->service_id_range_len = range_len; + + } qos_ulp_sl + + | qos_ulp_type_any_pkey list_of_ranges TK_DOTDOT { + /* "any, pkey ... : sl" - one instance of list of ranges */ + uint64_t ** range_arr; + unsigned range_len; + + if (!cl_list_count(&tmp_parser_struct.num_pair_list)) + { + yyerror("ULP rule doesn't have pkeys"); + return 1; + } + + /* get all the pkey ranges */ + __pkey_rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + + p_current_qos_match_rule->pkey_range_arr = range_arr; + p_current_qos_match_rule->pkey_range_len = range_len; + + } qos_ulp_sl + + | qos_ulp_type_any_target_port_guid list_of_ranges TK_DOTDOT { + /* any, target-port-guid ... : sl */ + uint64_t ** range_arr; + unsigned range_len; + + if (!cl_list_count(&tmp_parser_struct.num_pair_list)) + { + yyerror("ULP rule doesn't have port guids"); + return 1; + } + + /* create a new port group with these ports */ + __parser_port_group_start(); + + p_current_port_group->name = strdup("_ULP_Targets_"); + p_current_port_group->use = strdup("Generated from ULP rules"); + + __rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + + __parser_add_guid_range_to_port_map( + &p_current_port_group->port_map, + range_arr, + range_len); + + /* add this port group to the destination + groups of the current match rule */ + cl_list_insert_tail(&p_current_qos_match_rule->destination_group_list, + p_current_port_group); + + __parser_port_group_end(); + + } qos_ulp_sl + + | qos_ulp_type_sdp_default { + /* "sdp : sl" - default SL for SDP */ + uint64_t ** range_arr = + (uint64_t **)malloc(sizeof(uint64_t *)); + range_arr[0] = (uint64_t *)malloc(2*sizeof(uint64_t)); + range_arr[0][0] = OSM_QOS_POLICY_ULP_SDP_SERVICE_ID; + range_arr[0][1] = OSM_QOS_POLICY_ULP_SDP_SERVICE_ID + 0xFFFF; + + p_current_qos_match_rule->service_id_range_arr = range_arr; + p_current_qos_match_rule->service_id_range_len = 1; + + } qos_ulp_sl + + | qos_ulp_type_sdp_port list_of_ranges TK_DOTDOT { + /* sdp with port numbers */ + uint64_t ** range_arr; + unsigned range_len; + unsigned i; + + if (!cl_list_count(&tmp_parser_struct.num_pair_list)) + { + yyerror("SDP ULP rule doesn't have port numbers"); + return 1; + } + + /* get all the port ranges */ + __rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + /* now translate these port numbers into service ids */ + for (i = 0; i < range_len; i++) + { + if (range_arr[i][0] > 0xFFFF || range_arr[i][1] > 0xFFFF) + { + yyerror("SDP port number out of range"); + return 1; + } + range_arr[i][0] += OSM_QOS_POLICY_ULP_SDP_SERVICE_ID; + range_arr[i][1] += OSM_QOS_POLICY_ULP_SDP_SERVICE_ID; + } + + p_current_qos_match_rule->service_id_range_arr = range_arr; + p_current_qos_match_rule->service_id_range_len = range_len; + + } qos_ulp_sl + + | qos_ulp_type_rds_default { + /* "rds : sl" - default SL for RDS */ + uint64_t ** range_arr = + (uint64_t **)malloc(sizeof(uint64_t *)); + range_arr[0] = (uint64_t *)malloc(2*sizeof(uint64_t)); + range_arr[0][0] = range_arr[0][1] = + OSM_QOS_POLICY_ULP_RDS_SERVICE_ID + OSM_QOS_POLICY_ULP_RDS_PORT; + + p_current_qos_match_rule->service_id_range_arr = range_arr; + p_current_qos_match_rule->service_id_range_len = 1; + + } qos_ulp_sl + + | qos_ulp_type_rds_port list_of_ranges TK_DOTDOT { + /* rds with port numbers */ + uint64_t ** range_arr; + unsigned range_len; + unsigned i; + + if (!cl_list_count(&tmp_parser_struct.num_pair_list)) + { + yyerror("RDS ULP rule doesn't have port numbers"); + return 1; + } + + /* get all the port ranges */ + __rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + /* now translate these port numbers into service ids */ + for (i = 0; i < range_len; i++) + { + if (range_arr[i][0] > 0xFFFF || range_arr[i][1] > 0xFFFF) + { + yyerror("SDP port number out of range"); + return 1; + } + range_arr[i][0] += OSM_QOS_POLICY_ULP_RDS_SERVICE_ID; + range_arr[i][1] += OSM_QOS_POLICY_ULP_RDS_SERVICE_ID; + } + + p_current_qos_match_rule->service_id_range_arr = range_arr; + p_current_qos_match_rule->service_id_range_len = range_len; + + } qos_ulp_sl + + | qos_ulp_type_iser_default { + /* "iSER : sl" - default SL for iSER */ + uint64_t ** range_arr = + (uint64_t **)malloc(sizeof(uint64_t *)); + range_arr[0] = (uint64_t *)malloc(2*sizeof(uint64_t)); + range_arr[0][0] = range_arr[0][1] = + OSM_QOS_POLICY_ULP_ISER_SERVICE_ID + OSM_QOS_POLICY_ULP_ISER_PORT; + + p_current_qos_match_rule->service_id_range_arr = range_arr; + p_current_qos_match_rule->service_id_range_len = 1; + + } qos_ulp_sl + + | qos_ulp_type_iser_port list_of_ranges TK_DOTDOT { + /* iser with port numbers */ + uint64_t ** range_arr; + unsigned range_len; + unsigned i; + + if (!cl_list_count(&tmp_parser_struct.num_pair_list)) + { + yyerror("iSER ULP rule doesn't have port numbers"); + return 1; + } + + /* get all the port ranges */ + __rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + /* now translate these port numbers into service ids */ + for (i = 0; i < range_len; i++) + { + if (range_arr[i][0] > 0xFFFF || range_arr[i][1] > 0xFFFF) + { + yyerror("SDP port number out of range"); + return 1; + } + range_arr[i][0] += OSM_QOS_POLICY_ULP_ISER_SERVICE_ID; + range_arr[i][1] += OSM_QOS_POLICY_ULP_ISER_SERVICE_ID; + } + + p_current_qos_match_rule->service_id_range_arr = range_arr; + p_current_qos_match_rule->service_id_range_len = range_len; + + } qos_ulp_sl + + | qos_ulp_type_srp_guid list_of_ranges TK_DOTDOT { + /* srp with target guids - this rule is similar + to writing 'any' ulp with target port guids */ + uint64_t ** range_arr; + unsigned range_len; + + if (!cl_list_count(&tmp_parser_struct.num_pair_list)) + { + yyerror("SRP ULP rule doesn't have port guids"); + return 1; + } + + /* create a new port group with these ports */ + __parser_port_group_start(); + + p_current_port_group->name = strdup("_SRP_Targets_"); + p_current_port_group->use = strdup("Generated from ULP rules"); + + __rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + + __parser_add_guid_range_to_port_map( + &p_current_port_group->port_map, + range_arr, + range_len); + + /* add this port group to the destination + groups of the current match rule */ + cl_list_insert_tail(&p_current_qos_match_rule->destination_group_list, + p_current_port_group); + + __parser_port_group_end(); + + } qos_ulp_sl + + | qos_ulp_type_ipoib_default { + /* ipoib w/o any pkeys (default pkey) */ + uint64_t ** range_arr = + (uint64_t **)malloc(sizeof(uint64_t *)); + range_arr[0] = (uint64_t *)malloc(2*sizeof(uint64_t)); + range_arr[0][0] = range_arr[0][1] = 0x7fff; + + /* + * Although we know that the default partition exists, + * we still need to validate it by checking that it has + * at least two full members. Otherwise IPoIB won't work. + */ + if (__validate_pkeys(range_arr, 1, TRUE)) + return 1; + + p_current_qos_match_rule->pkey_range_arr = range_arr; + p_current_qos_match_rule->pkey_range_len = 1; + + } qos_ulp_sl + + | qos_ulp_type_ipoib_pkey list_of_ranges TK_DOTDOT { + /* ipoib with pkeys */ + uint64_t ** range_arr; + unsigned range_len; + + if (!cl_list_count(&tmp_parser_struct.num_pair_list)) + { + yyerror("IPoIB ULP rule doesn't have pkeys"); + return 1; + } + + /* get all the pkey ranges */ + __pkey_rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + + /* + * Validate pkeys. + * For IPoIB pkeys the validation is strict. + * If some problem would be found, parsing will + * be aborted with a proper error messages. + */ + if (__validate_pkeys(range_arr, range_len, TRUE)) + return 1; + + p_current_qos_match_rule->pkey_range_arr = range_arr; + p_current_qos_match_rule->pkey_range_len = range_len; + + } qos_ulp_sl + ; + +qos_ulp_type_any_service: TK_ULP_ANY_SERVICE_ID + { __parser_ulp_match_rule_start(); }; + +qos_ulp_type_any_pkey: TK_ULP_ANY_PKEY + { __parser_ulp_match_rule_start(); }; + +qos_ulp_type_any_target_port_guid: TK_ULP_ANY_TARGET_PORT_GUID + { __parser_ulp_match_rule_start(); }; + +qos_ulp_type_sdp_default: TK_ULP_SDP_DEFAULT + { __parser_ulp_match_rule_start(); }; + +qos_ulp_type_sdp_port: TK_ULP_SDP_PORT + { __parser_ulp_match_rule_start(); }; + +qos_ulp_type_rds_default: TK_ULP_RDS_DEFAULT + { __parser_ulp_match_rule_start(); }; + +qos_ulp_type_rds_port: TK_ULP_RDS_PORT + { __parser_ulp_match_rule_start(); }; + +qos_ulp_type_iser_default: TK_ULP_ISER_DEFAULT + { __parser_ulp_match_rule_start(); }; + +qos_ulp_type_iser_port: TK_ULP_ISER_PORT + { __parser_ulp_match_rule_start(); }; + +qos_ulp_type_srp_guid: TK_ULP_SRP_GUID + { __parser_ulp_match_rule_start(); }; + +qos_ulp_type_ipoib_default: TK_ULP_IPOIB_DEFAULT + { __parser_ulp_match_rule_start(); }; + +qos_ulp_type_ipoib_pkey: TK_ULP_IPOIB_PKEY + { __parser_ulp_match_rule_start(); }; + + +qos_ulp_sl: single_number { + /* get the SL for ULP rules */ + cl_list_iterator_t list_iterator; + uint64_t * p_tmp_num; + uint8_t sl; + + list_iterator = cl_list_head(&tmp_parser_struct.num_list); + p_tmp_num = (uint64_t*)cl_list_obj(list_iterator); + if (*p_tmp_num > 15) + { + yyerror("illegal SL value"); + return 1; + } + + sl = (uint8_t)(*p_tmp_num); + free(p_tmp_num); + cl_list_remove_all(&tmp_parser_struct.num_list); + + p_current_qos_match_rule->p_qos_level = + &osm_qos_policy_simple_qos_levels[sl]; + p_current_qos_match_rule->qos_level_name = + strdup(osm_qos_policy_simple_qos_levels[sl].name); + + if (__parser_ulp_match_rule_end()) + return 1; + } + ; + + /* + * port_group_entry values: + * port_group_name + * port_group_use + * port_group_port_guid + * port_group_port_name + * port_group_pkey + * port_group_partition + * port_group_node_type + */ + +port_group_name: port_group_name_start single_string { + /* 'name' of 'port-group' - one instance */ + cl_list_iterator_t list_iterator; + char * tmp_str; + + if (p_current_port_group->name) + { + yyerror("port-group has multiple 'name' tags"); + cl_list_remove_all(&tmp_parser_struct.str_list); + return 1; + } + + list_iterator = cl_list_head(&tmp_parser_struct.str_list); + if ( list_iterator != cl_list_end(&tmp_parser_struct.str_list) ) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) + p_current_port_group->name = tmp_str; + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +port_group_name_start: TK_NAME { + RESET_BUFFER; + } + ; + +port_group_use: port_group_use_start single_string { + /* 'use' of 'port-group' - one instance */ + cl_list_iterator_t list_iterator; + char * tmp_str; + + if (p_current_port_group->use) + { + yyerror("port-group has multiple 'use' tags"); + cl_list_remove_all(&tmp_parser_struct.str_list); + return 1; + } + + list_iterator = cl_list_head(&tmp_parser_struct.str_list); + if ( list_iterator != cl_list_end(&tmp_parser_struct.str_list) ) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) + p_current_port_group->use = tmp_str; + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +port_group_use_start: TK_USE { + RESET_BUFFER; + } + ; + +port_group_port_name: port_group_port_name_start string_list { + /* 'port-name' in 'port-group' - any num of instances */ + cl_list_iterator_t list_iterator; + osm_node_t * p_node; + osm_physp_t * p_physp; + unsigned port_num; + char * tmp_str; + char * port_str; + + /* parsing port name strings */ + for (list_iterator = cl_list_head(&tmp_parser_struct.str_list); + list_iterator != cl_list_end(&tmp_parser_struct.str_list); + list_iterator = cl_list_next(list_iterator)) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) + { + /* last slash in port name string is a separator + between node name and port number */ + port_str = strrchr(tmp_str, '/'); + if (!port_str || (strlen(port_str) < 3) || + (port_str[1] != 'p' && port_str[1] != 'P')) { + yyerror("'%s' - illegal port name", + tmp_str); + free(tmp_str); + cl_list_remove_all(&tmp_parser_struct.str_list); + return 1; + } + + if (!(port_num = strtoul(&port_str[2],NULL,0))) { + yyerror( + "'%s' - illegal port number in port name", + tmp_str); + free(tmp_str); + cl_list_remove_all(&tmp_parser_struct.str_list); + return 1; + } + + /* separate node name from port number */ + port_str[0] = '\0'; + + if (st_lookup(p_qos_policy->p_node_hash, + (st_data_t)tmp_str, + (void *)&p_node)) + { + /* we found the node, now get the right port */ + p_physp = osm_node_get_physp_ptr(p_node, port_num); + if (!p_physp) { + yyerror( + "'%s' - port number out of range in port name", + tmp_str); + free(tmp_str); + cl_list_remove_all(&tmp_parser_struct.str_list); + return 1; + } + /* we found the port, now add it to guid table */ + __parser_add_port_to_port_map(&p_current_port_group->port_map, + p_physp); + } + free(tmp_str); + } + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +port_group_port_name_start: TK_PORT_NAME { + RESET_BUFFER; + } + ; + +port_group_port_guid: port_group_port_guid_start list_of_ranges { + /* 'port-guid' in 'port-group' - any num of instances */ + /* list of guid ranges */ + if (cl_list_count(&tmp_parser_struct.num_pair_list)) + { + uint64_t ** range_arr; + unsigned range_len; + + __rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + + __parser_add_guid_range_to_port_map( + &p_current_port_group->port_map, + range_arr, + range_len); + } + } + ; + +port_group_port_guid_start: TK_PORT_GUID { + RESET_BUFFER; + } + ; + +port_group_pkey: port_group_pkey_start list_of_ranges { + /* 'pkey' in 'port-group' - any num of instances */ + /* list of pkey ranges */ + if (cl_list_count(&tmp_parser_struct.num_pair_list)) + { + uint64_t ** range_arr; + unsigned range_len; + + __pkey_rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + + __parser_add_pkey_range_to_port_map( + &p_current_port_group->port_map, + range_arr, + range_len); + } + } + ; + +port_group_pkey_start: TK_PKEY { + RESET_BUFFER; + } + ; + +port_group_partition: port_group_partition_start string_list { + /* 'partition' in 'port-group' - any num of instances */ + __parser_add_partition_list_to_port_map( + &p_current_port_group->port_map, + &tmp_parser_struct.str_list); + } + ; + +port_group_partition_start: TK_PARTITION { + RESET_BUFFER; + } + ; + +port_group_node_type: port_group_node_type_start port_group_node_type_list { + /* 'node-type' in 'port-group' - any num of instances */ + } + ; + +port_group_node_type_start: TK_NODE_TYPE { + RESET_BUFFER; + } + ; + +port_group_node_type_list: node_type_item + | port_group_node_type_list TK_COMMA node_type_item + ; + +node_type_item: node_type_ca + | node_type_switch + | node_type_router + | node_type_all + | node_type_self + ; + +node_type_ca: TK_NODE_TYPE_CA { + p_current_port_group->node_types |= + OSM_QOS_POLICY_NODE_TYPE_CA; + } + ; + +node_type_switch: TK_NODE_TYPE_SWITCH { + p_current_port_group->node_types |= + OSM_QOS_POLICY_NODE_TYPE_SWITCH; + } + ; + +node_type_router: TK_NODE_TYPE_ROUTER { + p_current_port_group->node_types |= + OSM_QOS_POLICY_NODE_TYPE_ROUTER; + } + ; + +node_type_all: TK_NODE_TYPE_ALL { + p_current_port_group->node_types |= + (OSM_QOS_POLICY_NODE_TYPE_CA | + OSM_QOS_POLICY_NODE_TYPE_SWITCH | + OSM_QOS_POLICY_NODE_TYPE_ROUTER); + } + ; + +node_type_self: TK_NODE_TYPE_SELF { + osm_port_t * p_osm_port = + osm_get_port_by_guid(p_qos_policy->p_subn, + p_qos_policy->p_subn->sm_port_guid); + if (p_osm_port) + __parser_add_port_to_port_map( + &p_current_port_group->port_map, + p_osm_port->p_physp); + } + ; + + /* + * vlarb_scope_entry values: + * vlarb_scope_group + * vlarb_scope_across + * vlarb_scope_vlarb_high + * vlarb_scope_vlarb_low + * vlarb_scope_vlarb_high_limit + */ + + + +vlarb_scope_group: vlarb_scope_group_start string_list { + /* 'group' in 'vlarb-scope' - any num of instances */ + cl_list_iterator_t list_iterator; + char * tmp_str; + + list_iterator = cl_list_head(&tmp_parser_struct.str_list); + while( list_iterator != cl_list_end(&tmp_parser_struct.str_list) ) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) + cl_list_insert_tail(&p_current_vlarb_scope->group_list,tmp_str); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +vlarb_scope_group_start: TK_GROUP { + RESET_BUFFER; + } + ; + +vlarb_scope_across: vlarb_scope_across_start string_list { + /* 'across' in 'vlarb-scope' - any num of instances */ + cl_list_iterator_t list_iterator; + char * tmp_str; + + list_iterator = cl_list_head(&tmp_parser_struct.str_list); + while( list_iterator != cl_list_end(&tmp_parser_struct.str_list) ) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) + cl_list_insert_tail(&p_current_vlarb_scope->across_list,tmp_str); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +vlarb_scope_across_start: TK_ACROSS { + RESET_BUFFER; + } + ; + +vlarb_scope_vlarb_high_limit: vlarb_scope_vlarb_high_limit_start single_number { + /* 'vl-high-limit' in 'vlarb-scope' - one instance of one number */ + cl_list_iterator_t list_iterator; + uint64_t * p_tmp_num; + + list_iterator = cl_list_head(&tmp_parser_struct.num_list); + p_tmp_num = (uint64_t*)cl_list_obj(list_iterator); + if (p_tmp_num) + { + p_current_vlarb_scope->vl_high_limit = (uint32_t)(*p_tmp_num); + p_current_vlarb_scope->vl_high_limit_set = TRUE; + free(p_tmp_num); + } + + cl_list_remove_all(&tmp_parser_struct.num_list); + } + ; + +vlarb_scope_vlarb_high_limit_start: TK_VLARB_HIGH_LIMIT { + RESET_BUFFER; + } + ; + +vlarb_scope_vlarb_high: vlarb_scope_vlarb_high_start num_list_with_dotdot { + /* 'vlarb-high' in 'vlarb-scope' - list of pairs of numbers with ':' and ',' */ + cl_list_iterator_t list_iterator; + uint64_t * num_pair; + + list_iterator = cl_list_head(&tmp_parser_struct.num_pair_list); + while( list_iterator != cl_list_end(&tmp_parser_struct.num_pair_list) ) + { + num_pair = (uint64_t*)cl_list_obj(list_iterator); + if (num_pair) + cl_list_insert_tail(&p_current_vlarb_scope->vlarb_high_list,num_pair); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&tmp_parser_struct.num_pair_list); + } + ; + +vlarb_scope_vlarb_high_start: TK_VLARB_HIGH { + RESET_BUFFER; + } + ; + +vlarb_scope_vlarb_low: vlarb_scope_vlarb_low_start num_list_with_dotdot { + /* 'vlarb-low' in 'vlarb-scope' - list of pairs of numbers with ':' and ',' */ + cl_list_iterator_t list_iterator; + uint64_t * num_pair; + + list_iterator = cl_list_head(&tmp_parser_struct.num_pair_list); + while( list_iterator != cl_list_end(&tmp_parser_struct.num_pair_list) ) + { + num_pair = (uint64_t*)cl_list_obj(list_iterator); + if (num_pair) + cl_list_insert_tail(&p_current_vlarb_scope->vlarb_low_list,num_pair); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&tmp_parser_struct.num_pair_list); + } + ; + +vlarb_scope_vlarb_low_start: TK_VLARB_LOW { + RESET_BUFFER; + } + ; + + /* + * sl2vl_scope_entry values: + * sl2vl_scope_group + * sl2vl_scope_across + * sl2vl_scope_across_from + * sl2vl_scope_across_to + * sl2vl_scope_from + * sl2vl_scope_to + * sl2vl_scope_sl2vl_table + */ + +sl2vl_scope_group: sl2vl_scope_group_start string_list { + /* 'group' in 'sl2vl-scope' - any num of instances */ + cl_list_iterator_t list_iterator; + char * tmp_str; + + list_iterator = cl_list_head(&tmp_parser_struct.str_list); + while( list_iterator != cl_list_end(&tmp_parser_struct.str_list) ) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) + cl_list_insert_tail(&p_current_sl2vl_scope->group_list,tmp_str); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +sl2vl_scope_group_start: TK_GROUP { + RESET_BUFFER; + } + ; + +sl2vl_scope_across: sl2vl_scope_across_start string_list { + /* 'across' in 'sl2vl-scope' - any num of instances */ + cl_list_iterator_t list_iterator; + char * tmp_str; + + list_iterator = cl_list_head(&tmp_parser_struct.str_list); + while( list_iterator != cl_list_end(&tmp_parser_struct.str_list) ) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) { + cl_list_insert_tail(&p_current_sl2vl_scope->across_from_list,tmp_str); + cl_list_insert_tail(&p_current_sl2vl_scope->across_to_list,strdup(tmp_str)); + } + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +sl2vl_scope_across_start: TK_ACROSS { + RESET_BUFFER; + } + ; + +sl2vl_scope_across_from: sl2vl_scope_across_from_start string_list { + /* 'across-from' in 'sl2vl-scope' - any num of instances */ + cl_list_iterator_t list_iterator; + char * tmp_str; + + list_iterator = cl_list_head(&tmp_parser_struct.str_list); + while( list_iterator != cl_list_end(&tmp_parser_struct.str_list) ) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) + cl_list_insert_tail(&p_current_sl2vl_scope->across_from_list,tmp_str); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +sl2vl_scope_across_from_start: TK_ACROSS_FROM { + RESET_BUFFER; + } + ; + +sl2vl_scope_across_to: sl2vl_scope_across_to_start string_list { + /* 'across-to' in 'sl2vl-scope' - any num of instances */ + cl_list_iterator_t list_iterator; + char * tmp_str; + + list_iterator = cl_list_head(&tmp_parser_struct.str_list); + while( list_iterator != cl_list_end(&tmp_parser_struct.str_list) ) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) { + cl_list_insert_tail(&p_current_sl2vl_scope->across_to_list,tmp_str); + } + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +sl2vl_scope_across_to_start: TK_ACROSS_TO { + RESET_BUFFER; + } + ; + +sl2vl_scope_from: sl2vl_scope_from_start sl2vl_scope_from_list_or_asterisk { + /* 'from' in 'sl2vl-scope' - any num of instances */ + } + ; + +sl2vl_scope_from_start: TK_FROM { + RESET_BUFFER; + } + ; + +sl2vl_scope_to: sl2vl_scope_to_start sl2vl_scope_to_list_or_asterisk { + /* 'to' in 'sl2vl-scope' - any num of instances */ + } + ; + +sl2vl_scope_to_start: TK_TO { + RESET_BUFFER; + } + ; + +sl2vl_scope_from_list_or_asterisk: sl2vl_scope_from_asterisk + | sl2vl_scope_from_list_of_ranges + ; + +sl2vl_scope_from_asterisk: TK_ASTERISK { + int i; + for (i = 0; i < OSM_QOS_POLICY_MAX_PORTS_ON_SWITCH; i++) + p_current_sl2vl_scope->from[i] = TRUE; + } + ; + +sl2vl_scope_to_list_or_asterisk: sl2vl_scope_to_asterisk + | sl2vl_scope_to_list_of_ranges + ; + +sl2vl_scope_to_asterisk: TK_ASTERISK { + int i; + for (i = 0; i < OSM_QOS_POLICY_MAX_PORTS_ON_SWITCH; i++) + p_current_sl2vl_scope->to[i] = TRUE; + } + ; + +sl2vl_scope_from_list_of_ranges: list_of_ranges { + int i; + cl_list_iterator_t list_iterator; + uint64_t * num_pair; + uint8_t num1, num2; + + list_iterator = cl_list_head(&tmp_parser_struct.num_pair_list); + while( list_iterator != cl_list_end(&tmp_parser_struct.num_pair_list) ) + { + num_pair = (uint64_t*)cl_list_obj(list_iterator); + if (num_pair) + { + if ( num_pair[0] < 0 || + num_pair[1] >= OSM_QOS_POLICY_MAX_PORTS_ON_SWITCH ) + { + yyerror("port number out of range 'from' list"); + free(num_pair); + cl_list_remove_all(&tmp_parser_struct.num_pair_list); + return 1; + } + num1 = (uint8_t)num_pair[0]; + num2 = (uint8_t)num_pair[1]; + free(num_pair); + for (i = num1; i <= num2; i++) + p_current_sl2vl_scope->from[i] = TRUE; + } + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&tmp_parser_struct.num_pair_list); + } + ; + +sl2vl_scope_to_list_of_ranges: list_of_ranges { + int i; + cl_list_iterator_t list_iterator; + uint64_t * num_pair; + uint8_t num1, num2; + + list_iterator = cl_list_head(&tmp_parser_struct.num_pair_list); + while( list_iterator != cl_list_end(&tmp_parser_struct.num_pair_list) ) + { + num_pair = (uint64_t*)cl_list_obj(list_iterator); + if (num_pair) + { + if ( num_pair[0] < 0 || + num_pair[1] >= OSM_QOS_POLICY_MAX_PORTS_ON_SWITCH ) + { + yyerror("port number out of range 'to' list"); + free(num_pair); + cl_list_remove_all(&tmp_parser_struct.num_pair_list); + return 1; + } + num1 = (uint8_t)num_pair[0]; + num2 = (uint8_t)num_pair[1]; + free(num_pair); + for (i = num1; i <= num2; i++) + p_current_sl2vl_scope->to[i] = TRUE; + } + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&tmp_parser_struct.num_pair_list); + } + ; + + +sl2vl_scope_sl2vl_table: sl2vl_scope_sl2vl_table_start num_list { + /* 'sl2vl-table' - one instance of exactly + OSM_QOS_POLICY_SL2VL_TABLE_LEN numbers */ + cl_list_iterator_t list_iterator; + uint64_t num; + uint64_t * p_num; + int i = 0; + + if (p_current_sl2vl_scope->sl2vl_table_set) + { + yyerror("sl2vl-scope has more than one sl2vl-table"); + cl_list_remove_all(&tmp_parser_struct.num_list); + return 1; + } + + if (cl_list_count(&tmp_parser_struct.num_list) != OSM_QOS_POLICY_SL2VL_TABLE_LEN) + { + yyerror("wrong number of values in 'sl2vl-table' (should be 16)"); + cl_list_remove_all(&tmp_parser_struct.num_list); + return 1; + } + + list_iterator = cl_list_head(&tmp_parser_struct.num_list); + while( list_iterator != cl_list_end(&tmp_parser_struct.num_list) ) + { + p_num = (uint64_t*)cl_list_obj(list_iterator); + num = *p_num; + free(p_num); + if (num >= OSM_QOS_POLICY_MAX_VL_NUM) + { + yyerror("wrong VL value in 'sl2vl-table' (should be 0 to 15)"); + cl_list_remove_all(&tmp_parser_struct.num_list); + return 1; + } + + p_current_sl2vl_scope->sl2vl_table[i++] = (uint8_t)num; + list_iterator = cl_list_next(list_iterator); + } + p_current_sl2vl_scope->sl2vl_table_set = TRUE; + cl_list_remove_all(&tmp_parser_struct.num_list); + } + ; + +sl2vl_scope_sl2vl_table_start: TK_SL2VL_TABLE { + RESET_BUFFER; + } + ; + + /* + * qos_level_entry values: + * qos_level_name + * qos_level_use + * qos_level_sl + * qos_level_mtu_limit + * qos_level_rate_limit + * qos_level_packet_life + * qos_level_path_bits + * qos_level_pkey + */ + +qos_level_name: qos_level_name_start single_string { + /* 'name' of 'qos-level' - one instance */ + cl_list_iterator_t list_iterator; + char * tmp_str; + + if (p_current_qos_level->name) + { + yyerror("qos-level has multiple 'name' tags"); + cl_list_remove_all(&tmp_parser_struct.str_list); + return 1; + } + + list_iterator = cl_list_head(&tmp_parser_struct.str_list); + if ( list_iterator != cl_list_end(&tmp_parser_struct.str_list) ) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) + p_current_qos_level->name = tmp_str; + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +qos_level_name_start: TK_NAME { + RESET_BUFFER; + } + ; + +qos_level_use: qos_level_use_start single_string { + /* 'use' of 'qos-level' - one instance */ + cl_list_iterator_t list_iterator; + char * tmp_str; + + if (p_current_qos_level->use) + { + yyerror("qos-level has multiple 'use' tags"); + cl_list_remove_all(&tmp_parser_struct.str_list); + return 1; + } + + list_iterator = cl_list_head(&tmp_parser_struct.str_list); + if ( list_iterator != cl_list_end(&tmp_parser_struct.str_list) ) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) + p_current_qos_level->use = tmp_str; + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +qos_level_use_start: TK_USE { + RESET_BUFFER; + } + ; + +qos_level_sl: qos_level_sl_start single_number { + /* 'sl' in 'qos-level' - one instance */ + cl_list_iterator_t list_iterator; + uint64_t * p_num; + + if (p_current_qos_level->sl_set) + { + yyerror("'qos-level' has multiple 'sl' tags"); + cl_list_remove_all(&tmp_parser_struct.num_list); + return 1; + } + list_iterator = cl_list_head(&tmp_parser_struct.num_list); + p_num = (uint64_t*)cl_list_obj(list_iterator); + p_current_qos_level->sl = (uint8_t)(*p_num); + free(p_num); + p_current_qos_level->sl_set = TRUE; + cl_list_remove_all(&tmp_parser_struct.num_list); + } + ; + +qos_level_sl_start: TK_SL { + RESET_BUFFER; + } + ; + +qos_level_mtu_limit: qos_level_mtu_limit_start single_number { + /* 'mtu-limit' in 'qos-level' - one instance */ + cl_list_iterator_t list_iterator; + uint64_t * p_num; + + if (p_current_qos_level->mtu_limit_set) + { + yyerror("'qos-level' has multiple 'mtu-limit' tags"); + cl_list_remove_all(&tmp_parser_struct.num_list); + return 1; + } + list_iterator = cl_list_head(&tmp_parser_struct.num_list); + p_num = (uint64_t*)cl_list_obj(list_iterator); + p_current_qos_level->mtu_limit = (uint8_t)(*p_num); + free(p_num); + p_current_qos_level->mtu_limit_set = TRUE; + cl_list_remove_all(&tmp_parser_struct.num_list); + } + ; + +qos_level_mtu_limit_start: TK_MTU_LIMIT { + /* 'mtu-limit' in 'qos-level' - one instance */ + RESET_BUFFER; + } + ; + +qos_level_rate_limit: qos_level_rate_limit_start single_number { + /* 'rate-limit' in 'qos-level' - one instance */ + cl_list_iterator_t list_iterator; + uint64_t * p_num; + + if (p_current_qos_level->rate_limit_set) + { + yyerror("'qos-level' has multiple 'rate-limit' tags"); + cl_list_remove_all(&tmp_parser_struct.num_list); + return 1; + } + list_iterator = cl_list_head(&tmp_parser_struct.num_list); + p_num = (uint64_t*)cl_list_obj(list_iterator); + p_current_qos_level->rate_limit = (uint8_t)(*p_num); + free(p_num); + p_current_qos_level->rate_limit_set = TRUE; + cl_list_remove_all(&tmp_parser_struct.num_list); + } + ; + +qos_level_rate_limit_start: TK_RATE_LIMIT { + /* 'rate-limit' in 'qos-level' - one instance */ + RESET_BUFFER; + } + ; + +qos_level_packet_life: qos_level_packet_life_start single_number { + /* 'packet-life' in 'qos-level' - one instance */ + cl_list_iterator_t list_iterator; + uint64_t * p_num; + + if (p_current_qos_level->pkt_life_set) + { + yyerror("'qos-level' has multiple 'packet-life' tags"); + cl_list_remove_all(&tmp_parser_struct.num_list); + return 1; + } + list_iterator = cl_list_head(&tmp_parser_struct.num_list); + p_num = (uint64_t*)cl_list_obj(list_iterator); + p_current_qos_level->pkt_life = (uint8_t)(*p_num); + free(p_num); + p_current_qos_level->pkt_life_set= TRUE; + cl_list_remove_all(&tmp_parser_struct.num_list); + } + ; + +qos_level_packet_life_start: TK_PACKET_LIFE { + /* 'packet-life' in 'qos-level' - one instance */ + RESET_BUFFER; + } + ; + +qos_level_path_bits: qos_level_path_bits_start list_of_ranges { + /* 'path-bits' in 'qos-level' - any num of instances */ + /* list of path bit ranges */ + + if (cl_list_count(&tmp_parser_struct.num_pair_list)) + { + uint64_t ** range_arr; + unsigned range_len; + + __rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + + if ( !p_current_qos_level->path_bits_range_len ) + { + p_current_qos_level->path_bits_range_arr = range_arr; + p_current_qos_level->path_bits_range_len = range_len; + } + else + { + uint64_t ** new_range_arr; + unsigned new_range_len; + __merge_rangearr( p_current_qos_level->path_bits_range_arr, + p_current_qos_level->path_bits_range_len, + range_arr, + range_len, + &new_range_arr, + &new_range_len ); + p_current_qos_level->path_bits_range_arr = new_range_arr; + p_current_qos_level->path_bits_range_len = new_range_len; + } + } + } + ; + +qos_level_path_bits_start: TK_PATH_BITS { + RESET_BUFFER; + } + ; + +qos_level_pkey: qos_level_pkey_start list_of_ranges { + /* 'pkey' in 'qos-level' - num of instances of list of ranges */ + if (cl_list_count(&tmp_parser_struct.num_pair_list)) + { + uint64_t ** range_arr; + unsigned range_len; + + __pkey_rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + + if ( !p_current_qos_level->pkey_range_len ) + { + p_current_qos_level->pkey_range_arr = range_arr; + p_current_qos_level->pkey_range_len = range_len; + } + else + { + uint64_t ** new_range_arr; + unsigned new_range_len; + __merge_rangearr( p_current_qos_level->pkey_range_arr, + p_current_qos_level->pkey_range_len, + range_arr, + range_len, + &new_range_arr, + &new_range_len ); + p_current_qos_level->pkey_range_arr = new_range_arr; + p_current_qos_level->pkey_range_len = new_range_len; + } + } + } + ; + +qos_level_pkey_start: TK_PKEY { + RESET_BUFFER; + } + ; + + /* + * qos_match_rule_entry values: + * qos_match_rule_use + * qos_match_rule_qos_class + * qos_match_rule_qos_level_name + * qos_match_rule_source + * qos_match_rule_destination + * qos_match_rule_service_id + * qos_match_rule_pkey + */ + + +qos_match_rule_use: qos_match_rule_use_start single_string { + /* 'use' of 'qos-match-rule' - one instance */ + cl_list_iterator_t list_iterator; + char * tmp_str; + + if (p_current_qos_match_rule->use) + { + yyerror("'qos-match-rule' has multiple 'use' tags"); + cl_list_remove_all(&tmp_parser_struct.str_list); + return 1; + } + + list_iterator = cl_list_head(&tmp_parser_struct.str_list); + if ( list_iterator != cl_list_end(&tmp_parser_struct.str_list) ) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) + p_current_qos_match_rule->use = tmp_str; + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +qos_match_rule_use_start: TK_USE { + RESET_BUFFER; + } + ; + +qos_match_rule_qos_class: qos_match_rule_qos_class_start list_of_ranges { + /* 'qos-class' in 'qos-match-rule' - num of instances of list of ranges */ + /* list of class ranges (QoS Class is 12-bit value) */ + if (cl_list_count(&tmp_parser_struct.num_pair_list)) + { + uint64_t ** range_arr; + unsigned range_len; + + __rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + + if ( !p_current_qos_match_rule->qos_class_range_len ) + { + p_current_qos_match_rule->qos_class_range_arr = range_arr; + p_current_qos_match_rule->qos_class_range_len = range_len; + } + else + { + uint64_t ** new_range_arr; + unsigned new_range_len; + __merge_rangearr( p_current_qos_match_rule->qos_class_range_arr, + p_current_qos_match_rule->qos_class_range_len, + range_arr, + range_len, + &new_range_arr, + &new_range_len ); + p_current_qos_match_rule->qos_class_range_arr = new_range_arr; + p_current_qos_match_rule->qos_class_range_len = new_range_len; + } + } + } + ; + +qos_match_rule_qos_class_start: TK_QOS_CLASS { + RESET_BUFFER; + } + ; + +qos_match_rule_source: qos_match_rule_source_start string_list { + /* 'source' in 'qos-match-rule' - text */ + cl_list_iterator_t list_iterator; + char * tmp_str; + + list_iterator = cl_list_head(&tmp_parser_struct.str_list); + while( list_iterator != cl_list_end(&tmp_parser_struct.str_list) ) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) + cl_list_insert_tail(&p_current_qos_match_rule->source_list,tmp_str); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +qos_match_rule_source_start: TK_SOURCE { + RESET_BUFFER; + } + ; + +qos_match_rule_destination: qos_match_rule_destination_start string_list { + /* 'destination' in 'qos-match-rule' - text */ + cl_list_iterator_t list_iterator; + char * tmp_str; + + list_iterator = cl_list_head(&tmp_parser_struct.str_list); + while( list_iterator != cl_list_end(&tmp_parser_struct.str_list) ) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) + cl_list_insert_tail(&p_current_qos_match_rule->destination_list,tmp_str); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +qos_match_rule_destination_start: TK_DESTINATION { + RESET_BUFFER; + } + ; + +qos_match_rule_qos_level_name: qos_match_rule_qos_level_name_start single_string { + /* 'qos-level-name' in 'qos-match-rule' - single string */ + cl_list_iterator_t list_iterator; + char * tmp_str; + + if (p_current_qos_match_rule->qos_level_name) + { + yyerror("qos-match-rule has multiple 'qos-level-name' tags"); + cl_list_remove_all(&tmp_parser_struct.num_list); + return 1; + } + + list_iterator = cl_list_head(&tmp_parser_struct.str_list); + if ( list_iterator != cl_list_end(&tmp_parser_struct.str_list) ) + { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) + p_current_qos_match_rule->qos_level_name = tmp_str; + } + cl_list_remove_all(&tmp_parser_struct.str_list); + } + ; + +qos_match_rule_qos_level_name_start: TK_QOS_LEVEL_NAME { + RESET_BUFFER; + } + ; + +qos_match_rule_service_id: qos_match_rule_service_id_start list_of_ranges { + /* 'service-id' in 'qos-match-rule' - num of instances of list of ranges */ + if (cl_list_count(&tmp_parser_struct.num_pair_list)) + { + uint64_t ** range_arr; + unsigned range_len; + + __rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + + if ( !p_current_qos_match_rule->service_id_range_len ) + { + p_current_qos_match_rule->service_id_range_arr = range_arr; + p_current_qos_match_rule->service_id_range_len = range_len; + } + else + { + uint64_t ** new_range_arr; + unsigned new_range_len; + __merge_rangearr( p_current_qos_match_rule->service_id_range_arr, + p_current_qos_match_rule->service_id_range_len, + range_arr, + range_len, + &new_range_arr, + &new_range_len ); + p_current_qos_match_rule->service_id_range_arr = new_range_arr; + p_current_qos_match_rule->service_id_range_len = new_range_len; + } + } + } + ; + +qos_match_rule_service_id_start: TK_SERVICE_ID { + RESET_BUFFER; + } + ; + +qos_match_rule_pkey: qos_match_rule_pkey_start list_of_ranges { + /* 'pkey' in 'qos-match-rule' - num of instances of list of ranges */ + if (cl_list_count(&tmp_parser_struct.num_pair_list)) + { + uint64_t ** range_arr; + unsigned range_len; + + __pkey_rangelist2rangearr( &tmp_parser_struct.num_pair_list, + &range_arr, + &range_len ); + + if ( !p_current_qos_match_rule->pkey_range_len ) + { + p_current_qos_match_rule->pkey_range_arr = range_arr; + p_current_qos_match_rule->pkey_range_len = range_len; + } + else + { + uint64_t ** new_range_arr; + unsigned new_range_len; + __merge_rangearr( p_current_qos_match_rule->pkey_range_arr, + p_current_qos_match_rule->pkey_range_len, + range_arr, + range_len, + &new_range_arr, + &new_range_len ); + p_current_qos_match_rule->pkey_range_arr = new_range_arr; + p_current_qos_match_rule->pkey_range_len = new_range_len; + } + } + } + ; + +qos_match_rule_pkey_start: TK_PKEY { + RESET_BUFFER; + } + ; + + + /* + * Common part + */ + + +single_string: single_string_elems { + cl_list_insert_tail(&tmp_parser_struct.str_list, + strdup(__parser_strip_white(tmp_parser_struct.str))); + tmp_parser_struct.str[0] = '\0'; + } + ; + +single_string_elems: single_string_element + | single_string_elems single_string_element + ; + +single_string_element: TK_TEXT { + strcat(tmp_parser_struct.str,$1); + free($1); + } + ; + + +string_list: single_string + | string_list TK_COMMA single_string + ; + + + +single_number: number + ; + +num_list: number + | num_list TK_COMMA number + ; + +number: TK_NUMBER { + uint64_t * p_num = (uint64_t*)malloc(sizeof(uint64_t)); + __parser_str2uint64(p_num,$1); + free($1); + cl_list_insert_tail(&tmp_parser_struct.num_list, p_num); + } + ; + +num_list_with_dotdot: number_from_pair_1 TK_DOTDOT number_from_pair_2 { + uint64_t * num_pair = (uint64_t*)malloc(sizeof(uint64_t)*2); + num_pair[0] = tmp_parser_struct.num_pair[0]; + num_pair[1] = tmp_parser_struct.num_pair[1]; + cl_list_insert_tail(&tmp_parser_struct.num_pair_list, num_pair); + } + | num_list_with_dotdot TK_COMMA number_from_pair_1 TK_DOTDOT number_from_pair_2 { + uint64_t * num_pair = (uint64_t*)malloc(sizeof(uint64_t)*2); + num_pair[0] = tmp_parser_struct.num_pair[0]; + num_pair[1] = tmp_parser_struct.num_pair[1]; + cl_list_insert_tail(&tmp_parser_struct.num_pair_list, num_pair); + } + ; + +number_from_pair_1: TK_NUMBER { + __parser_str2uint64(&tmp_parser_struct.num_pair[0],$1); + free($1); + } + ; + +number_from_pair_2: TK_NUMBER { + __parser_str2uint64(&tmp_parser_struct.num_pair[1],$1); + free($1); + } + ; + +list_of_ranges: num_list_with_dash + ; + +num_list_with_dash: single_number_from_range { + uint64_t * num_pair = (uint64_t*)malloc(sizeof(uint64_t)*2); + num_pair[0] = tmp_parser_struct.num_pair[0]; + num_pair[1] = tmp_parser_struct.num_pair[1]; + cl_list_insert_tail(&tmp_parser_struct.num_pair_list, num_pair); + } + | number_from_range_1 TK_DASH number_from_range_2 { + uint64_t * num_pair = (uint64_t*)malloc(sizeof(uint64_t)*2); + if (tmp_parser_struct.num_pair[0] <= tmp_parser_struct.num_pair[1]) { + num_pair[0] = tmp_parser_struct.num_pair[0]; + num_pair[1] = tmp_parser_struct.num_pair[1]; + } + else { + num_pair[1] = tmp_parser_struct.num_pair[0]; + num_pair[0] = tmp_parser_struct.num_pair[1]; + } + cl_list_insert_tail(&tmp_parser_struct.num_pair_list, num_pair); + } + | num_list_with_dash TK_COMMA number_from_range_1 TK_DASH number_from_range_2 { + uint64_t * num_pair = (uint64_t*)malloc(sizeof(uint64_t)*2); + if (tmp_parser_struct.num_pair[0] <= tmp_parser_struct.num_pair[1]) { + num_pair[0] = tmp_parser_struct.num_pair[0]; + num_pair[1] = tmp_parser_struct.num_pair[1]; + } + else { + num_pair[1] = tmp_parser_struct.num_pair[0]; + num_pair[0] = tmp_parser_struct.num_pair[1]; + } + cl_list_insert_tail(&tmp_parser_struct.num_pair_list, num_pair); + } + | num_list_with_dash TK_COMMA single_number_from_range { + uint64_t * num_pair = (uint64_t*)malloc(sizeof(uint64_t)*2); + num_pair[0] = tmp_parser_struct.num_pair[0]; + num_pair[1] = tmp_parser_struct.num_pair[1]; + cl_list_insert_tail(&tmp_parser_struct.num_pair_list, num_pair); + } + ; + +single_number_from_range: TK_NUMBER { + __parser_str2uint64(&tmp_parser_struct.num_pair[0],$1); + __parser_str2uint64(&tmp_parser_struct.num_pair[1],$1); + free($1); + } + ; + +number_from_range_1: TK_NUMBER { + __parser_str2uint64(&tmp_parser_struct.num_pair[0],$1); + free($1); + } + ; + +number_from_range_2: TK_NUMBER { + __parser_str2uint64(&tmp_parser_struct.num_pair[1],$1); + free($1); + } + ; + +%% + +/*************************************************** + ***************************************************/ + +int osm_qos_parse_policy_file(IN osm_subn_t * const p_subn) +{ + int res = 0; + static boolean_t first_time = TRUE; + p_qos_parser_osm_log = &p_subn->p_osm->log; + + OSM_LOG_ENTER(p_qos_parser_osm_log); + + osm_qos_policy_destroy(p_subn->p_qos_policy); + p_subn->p_qos_policy = NULL; + + yyin = fopen (p_subn->opt.qos_policy_file, "r"); + if (!yyin) + { + if (strcmp(p_subn->opt.qos_policy_file,OSM_DEFAULT_QOS_POLICY_FILE)) { + OSM_LOG(p_qos_parser_osm_log, OSM_LOG_ERROR, "ERR AC01: " + "Failed opening QoS policy file %s - %s\n", + p_subn->opt.qos_policy_file, strerror(errno)); + res = 1; + } + else + OSM_LOG(p_qos_parser_osm_log, OSM_LOG_VERBOSE, + "QoS policy file not found (%s)\n", + p_subn->opt.qos_policy_file); + + goto Exit; + } + + if (first_time) + { + first_time = FALSE; + __setup_simple_qos_levels(); + __setup_ulp_match_rules(); + OSM_LOG(p_qos_parser_osm_log, OSM_LOG_INFO, + "Loading QoS policy file (%s)\n", + p_subn->opt.qos_policy_file); + } + else + /* + * ULP match rules list was emptied at the end of + * previous parsing iteration. + * What's left is to clear simple QoS levels. + */ + __clear_simple_qos_levels(); + + column_num = 1; + line_num = 1; + + p_subn->p_qos_policy = osm_qos_policy_create(p_subn); + + __parser_tmp_struct_init(); + p_qos_policy = p_subn->p_qos_policy; + + res = yyparse(); + + __parser_tmp_struct_destroy(); + + if (res != 0) + { + OSM_LOG(p_qos_parser_osm_log, OSM_LOG_ERROR, "ERR AC03: " + "Failed parsing QoS policy file (%s)\n", + p_subn->opt.qos_policy_file); + osm_qos_policy_destroy(p_subn->p_qos_policy); + p_subn->p_qos_policy = NULL; + res = 1; + goto Exit; + } + + /* add generated ULP match rules to the usual match rules */ + __process_ulp_match_rules(); + + if (osm_qos_policy_validate(p_subn->p_qos_policy,p_qos_parser_osm_log)) + { + OSM_LOG(p_qos_parser_osm_log, OSM_LOG_ERROR, "ERR AC04: " + "Error(s) in QoS policy file (%s)\n", + p_subn->opt.qos_policy_file); + fprintf(stderr, "Error(s) in QoS policy file (%s)\n", + p_subn->opt.qos_policy_file); + osm_qos_policy_destroy(p_subn->p_qos_policy); + p_subn->p_qos_policy = NULL; + res = 1; + goto Exit; + } + + Exit: + if (yyin) + fclose(yyin); + OSM_LOG_EXIT(p_qos_parser_osm_log); + return res; +} + +/*************************************************** + ***************************************************/ + +int yywrap() +{ + return(1); +} + +/*************************************************** + ***************************************************/ + +static void yyerror(const char *format, ...) +{ + char s[256]; + va_list pvar; + + OSM_LOG_ENTER(p_qos_parser_osm_log); + + va_start(pvar, format); + vsnprintf(s, sizeof(s), format, pvar); + va_end(pvar); + + OSM_LOG(p_qos_parser_osm_log, OSM_LOG_ERROR, "ERR AC05: " + "Syntax error (line %d:%d): %s\n", + line_num, column_num, s); + fprintf(stderr, "Error in QoS Policy File (line %d:%d): %s.\n", + line_num, column_num, s); + OSM_LOG_EXIT(p_qos_parser_osm_log); +} + +/*************************************************** + ***************************************************/ + +static char * __parser_strip_white(char * str) +{ + int i; + for (i = (strlen(str)-1); i >= 0; i--) + { + if (isspace(str[i])) + str[i] = '\0'; + else + break; + } + for (i = 0; i < strlen(str); i++) + { + if (!isspace(str[i])) + break; + } + return &(str[i]); +} + +/*************************************************** + ***************************************************/ + +static void __parser_str2uint64(uint64_t * p_val, char * str) +{ + *p_val = strtoull(str, NULL, 0); +} + +/*************************************************** + ***************************************************/ + +static void __parser_port_group_start() +{ + p_current_port_group = osm_qos_policy_port_group_create(); +} + +/*************************************************** + ***************************************************/ + +static int __parser_port_group_end() +{ + if(!p_current_port_group->name) + { + yyerror("port-group validation failed - no port group name specified"); + return -1; + } + + cl_list_insert_tail(&p_qos_policy->port_groups, + p_current_port_group); + p_current_port_group = NULL; + return 0; +} + +/*************************************************** + ***************************************************/ + +static void __parser_vlarb_scope_start() +{ + p_current_vlarb_scope = osm_qos_policy_vlarb_scope_create(); +} + +/*************************************************** + ***************************************************/ + +static int __parser_vlarb_scope_end() +{ + if ( !cl_list_count(&p_current_vlarb_scope->group_list) && + !cl_list_count(&p_current_vlarb_scope->across_list) ) + { + yyerror("vlarb-scope validation failed - no port groups specified by 'group' or by 'across'"); + return -1; + } + + cl_list_insert_tail(&p_qos_policy->vlarb_tables, + p_current_vlarb_scope); + p_current_vlarb_scope = NULL; + return 0; +} + +/*************************************************** + ***************************************************/ + +static void __parser_sl2vl_scope_start() +{ + p_current_sl2vl_scope = osm_qos_policy_sl2vl_scope_create(); +} + +/*************************************************** + ***************************************************/ + +static int __parser_sl2vl_scope_end() +{ + if (!p_current_sl2vl_scope->sl2vl_table_set) + { + yyerror("sl2vl-scope validation failed - no sl2vl table specified"); + return -1; + } + if ( !cl_list_count(&p_current_sl2vl_scope->group_list) && + !cl_list_count(&p_current_sl2vl_scope->across_to_list) && + !cl_list_count(&p_current_sl2vl_scope->across_from_list) ) + { + yyerror("sl2vl-scope validation failed - no port groups specified by 'group', 'across-to' or 'across-from'"); + return -1; + } + + cl_list_insert_tail(&p_qos_policy->sl2vl_tables, + p_current_sl2vl_scope); + p_current_sl2vl_scope = NULL; + return 0; +} + +/*************************************************** + ***************************************************/ + +static void __parser_qos_level_start() +{ + p_current_qos_level = osm_qos_policy_qos_level_create(); +} + +/*************************************************** + ***************************************************/ + +static int __parser_qos_level_end() +{ + if (!p_current_qos_level->sl_set) + { + yyerror("qos-level validation failed - no 'sl' specified"); + return -1; + } + if (!p_current_qos_level->name) + { + yyerror("qos-level validation failed - no 'name' specified"); + return -1; + } + + cl_list_insert_tail(&p_qos_policy->qos_levels, + p_current_qos_level); + p_current_qos_level = NULL; + return 0; +} + +/*************************************************** + ***************************************************/ + +static void __parser_match_rule_start() +{ + p_current_qos_match_rule = osm_qos_policy_match_rule_create(); +} + +/*************************************************** + ***************************************************/ + +static int __parser_match_rule_end() +{ + if (!p_current_qos_match_rule->qos_level_name) + { + yyerror("match-rule validation failed - no 'qos-level-name' specified"); + return -1; + } + + cl_list_insert_tail(&p_qos_policy->qos_match_rules, + p_current_qos_match_rule); + p_current_qos_match_rule = NULL; + return 0; +} + +/*************************************************** + ***************************************************/ + +static void __parser_ulp_match_rule_start() +{ + p_current_qos_match_rule = osm_qos_policy_match_rule_create(); +} + +/*************************************************** + ***************************************************/ + +static int __parser_ulp_match_rule_end() +{ + CL_ASSERT(p_current_qos_match_rule->p_qos_level); + cl_list_insert_tail(&__ulp_match_rules, + p_current_qos_match_rule); + p_current_qos_match_rule = NULL; + return 0; +} + +/*************************************************** + ***************************************************/ + +static void __parser_tmp_struct_init() +{ + tmp_parser_struct.str[0] = '\0'; + cl_list_construct(&tmp_parser_struct.str_list); + cl_list_init(&tmp_parser_struct.str_list, 10); + cl_list_construct(&tmp_parser_struct.num_list); + cl_list_init(&tmp_parser_struct.num_list, 10); + cl_list_construct(&tmp_parser_struct.num_pair_list); + cl_list_init(&tmp_parser_struct.num_pair_list, 10); +} + +/*************************************************** + ***************************************************/ + +/* + * Do NOT free objects from the temp struct. + * Either they are inserted into the parse tree data + * structure, or they are already freed when copying + * their values to the parse tree data structure. + */ +static void __parser_tmp_struct_reset() +{ + tmp_parser_struct.str[0] = '\0'; + cl_list_remove_all(&tmp_parser_struct.str_list); + cl_list_remove_all(&tmp_parser_struct.num_list); + cl_list_remove_all(&tmp_parser_struct.num_pair_list); +} + +/*************************************************** + ***************************************************/ + +static void __parser_tmp_struct_destroy() +{ + __parser_tmp_struct_reset(); + cl_list_destroy(&tmp_parser_struct.str_list); + cl_list_destroy(&tmp_parser_struct.num_list); + cl_list_destroy(&tmp_parser_struct.num_pair_list); +} + +/*************************************************** + ***************************************************/ + +#define __SIMPLE_QOS_LEVEL_NAME "SimpleQoSLevel_SL" +#define __SIMPLE_QOS_LEVEL_DEFAULT_NAME "SimpleQoSLevel_DEFAULT" + +static void __setup_simple_qos_levels() +{ + uint8_t i; + char tmp_buf[30]; + memset(osm_qos_policy_simple_qos_levels, 0, + sizeof(osm_qos_policy_simple_qos_levels)); + for (i = 0; i < 16; i++) + { + osm_qos_policy_simple_qos_levels[i].sl = i; + osm_qos_policy_simple_qos_levels[i].sl_set = TRUE; + sprintf(tmp_buf, "%s%u", __SIMPLE_QOS_LEVEL_NAME, i); + osm_qos_policy_simple_qos_levels[i].name = strdup(tmp_buf); + } + + memset(&__default_simple_qos_level, 0, + sizeof(__default_simple_qos_level)); + __default_simple_qos_level.name = + strdup(__SIMPLE_QOS_LEVEL_DEFAULT_NAME); +} + +/*************************************************** + ***************************************************/ + +static void __clear_simple_qos_levels() +{ + /* + * Simple QoS levels are static. + * What's left is to invalidate default simple QoS level. + */ + __default_simple_qos_level.sl_set = FALSE; +} + +/*************************************************** + ***************************************************/ + +static void __setup_ulp_match_rules() +{ + cl_list_construct(&__ulp_match_rules); + cl_list_init(&__ulp_match_rules, 10); +} + +/*************************************************** + ***************************************************/ + +static void __process_ulp_match_rules() +{ + cl_list_iterator_t list_iterator; + osm_qos_match_rule_t *p_qos_match_rule = NULL; + + list_iterator = cl_list_head(&__ulp_match_rules); + while (list_iterator != cl_list_end(&__ulp_match_rules)) + { + p_qos_match_rule = (osm_qos_match_rule_t *) cl_list_obj(list_iterator); + if (p_qos_match_rule) + cl_list_insert_tail(&p_qos_policy->qos_match_rules, + p_qos_match_rule); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&__ulp_match_rules); +} + +/*************************************************** + ***************************************************/ + +static int OSM_CDECL +__cmp_num_range( + const void * p1, + const void * p2) +{ + uint64_t * pair1 = *((uint64_t **)p1); + uint64_t * pair2 = *((uint64_t **)p2); + + if (pair1[0] < pair2[0]) + return -1; + if (pair1[0] > pair2[0]) + return 1; + + if (pair1[1] < pair2[1]) + return -1; + if (pair1[1] > pair2[1]) + return 1; + + return 0; +} + +/*************************************************** + ***************************************************/ + +static void __sort_reduce_rangearr( + uint64_t ** arr, + unsigned arr_len, + uint64_t ** * p_res_arr, + unsigned * p_res_arr_len ) +{ + unsigned i = 0; + unsigned j = 0; + unsigned last_valid_ind = 0; + unsigned valid_cnt = 0; + uint64_t ** res_arr; + boolean_t * is_valid_arr; + + *p_res_arr = NULL; + *p_res_arr_len = 0; + + qsort(arr, arr_len, sizeof(uint64_t*), __cmp_num_range); + + is_valid_arr = (boolean_t *)malloc(arr_len * sizeof(boolean_t)); + is_valid_arr[last_valid_ind] = TRUE; + valid_cnt++; + for (i = 1; i < arr_len; i++) + { + if (arr[i][0] <= arr[last_valid_ind][1]) + { + if (arr[i][1] > arr[last_valid_ind][1]) + arr[last_valid_ind][1] = arr[i][1]; + free(arr[i]); + arr[i] = NULL; + is_valid_arr[i] = FALSE; + } + else if ((arr[i][0] - 1) == arr[last_valid_ind][1]) + { + arr[last_valid_ind][1] = arr[i][1]; + free(arr[i]); + arr[i] = NULL; + is_valid_arr[i] = FALSE; + } + else + { + is_valid_arr[i] = TRUE; + last_valid_ind = i; + valid_cnt++; + } + } + + res_arr = (uint64_t **)malloc(valid_cnt * sizeof(uint64_t *)); + for (i = 0; i < arr_len; i++) + { + if (is_valid_arr[i]) + res_arr[j++] = arr[i]; + } + free(is_valid_arr); + free(arr); + + *p_res_arr = res_arr; + *p_res_arr_len = valid_cnt; +} + +/*************************************************** + ***************************************************/ + +static void __pkey_rangelist2rangearr( + cl_list_t * p_list, + uint64_t ** * p_arr, + unsigned * p_arr_len) +{ + uint64_t tmp_pkey; + uint64_t * p_pkeys; + cl_list_iterator_t list_iterator; + + list_iterator= cl_list_head(p_list); + while( list_iterator != cl_list_end(p_list) ) + { + p_pkeys = (uint64_t *)cl_list_obj(list_iterator); + p_pkeys[0] &= 0x7fff; + p_pkeys[1] &= 0x7fff; + if (p_pkeys[0] > p_pkeys[1]) + { + tmp_pkey = p_pkeys[1]; + p_pkeys[1] = p_pkeys[0]; + p_pkeys[0] = tmp_pkey; + } + list_iterator = cl_list_next(list_iterator); + } + + __rangelist2rangearr(p_list, p_arr, p_arr_len); +} + +/*************************************************** + ***************************************************/ + +static void __rangelist2rangearr( + cl_list_t * p_list, + uint64_t ** * p_arr, + unsigned * p_arr_len) +{ + cl_list_iterator_t list_iterator; + unsigned len = cl_list_count(p_list); + unsigned i = 0; + uint64_t ** tmp_arr; + uint64_t ** res_arr = NULL; + unsigned res_arr_len = 0; + + tmp_arr = (uint64_t **)malloc(len * sizeof(uint64_t *)); + + list_iterator = cl_list_head(p_list); + while( list_iterator != cl_list_end(p_list) ) + { + tmp_arr[i++] = (uint64_t *)cl_list_obj(list_iterator); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(p_list); + + __sort_reduce_rangearr( tmp_arr, + len, + &res_arr, + &res_arr_len ); + *p_arr = res_arr; + *p_arr_len = res_arr_len; +} + +/*************************************************** + ***************************************************/ + +static void __merge_rangearr( + uint64_t ** range_arr_1, + unsigned range_len_1, + uint64_t ** range_arr_2, + unsigned range_len_2, + uint64_t ** * p_arr, + unsigned * p_arr_len ) +{ + unsigned i = 0; + unsigned j = 0; + unsigned len = range_len_1 + range_len_2; + uint64_t ** tmp_arr; + uint64_t ** res_arr = NULL; + unsigned res_arr_len = 0; + + *p_arr = NULL; + *p_arr_len = 0; + + tmp_arr = (uint64_t **)malloc(len * sizeof(uint64_t *)); + + for (i = 0; i < range_len_1; i++) + tmp_arr[j++] = range_arr_1[i]; + for (i = 0; i < range_len_2; i++) + tmp_arr[j++] = range_arr_2[i]; + free(range_arr_1); + free(range_arr_2); + + __sort_reduce_rangearr( tmp_arr, + len, + &res_arr, + &res_arr_len ); + *p_arr = res_arr; + *p_arr_len = res_arr_len; +} + +/*************************************************** + ***************************************************/ + +static void __parser_add_port_to_port_map( + cl_qmap_t * p_map, + osm_physp_t * p_physp) +{ + if (cl_qmap_get(p_map, cl_ntoh64(osm_physp_get_port_guid(p_physp))) == + cl_qmap_end(p_map)) + { + osm_qos_port_t * p_port = osm_qos_policy_port_create(p_physp); + if (p_port) + cl_qmap_insert(p_map, + cl_ntoh64(osm_physp_get_port_guid(p_physp)), + &p_port->map_item); + } +} + +/*************************************************** + ***************************************************/ + +static void __parser_add_guid_range_to_port_map( + cl_qmap_t * p_map, + uint64_t ** range_arr, + unsigned range_len) +{ + unsigned i; + uint64_t guid_ho; + osm_port_t * p_osm_port; + + if (!range_arr || !range_len) + return; + + for (i = 0; i < range_len; i++) { + for (guid_ho = range_arr[i][0]; guid_ho <= range_arr[i][1]; guid_ho++) { + p_osm_port = + osm_get_port_by_guid(p_qos_policy->p_subn, cl_hton64(guid_ho)); + if (p_osm_port) + __parser_add_port_to_port_map(p_map, p_osm_port->p_physp); + } + free(range_arr[i]); + } + free(range_arr); +} + +/*************************************************** + ***************************************************/ + +static void __parser_add_pkey_range_to_port_map( + cl_qmap_t * p_map, + uint64_t ** range_arr, + unsigned range_len) +{ + unsigned i; + uint64_t pkey_64; + ib_net16_t pkey; + osm_prtn_t * p_prtn; + + if (!range_arr || !range_len) + return; + + for (i = 0; i < range_len; i++) { + for (pkey_64 = range_arr[i][0]; pkey_64 <= range_arr[i][1]; pkey_64++) { + pkey = cl_hton16((uint16_t)(pkey_64 & 0x7fff)); + p_prtn = (osm_prtn_t *) + cl_qmap_get(&p_qos_policy->p_subn->prtn_pkey_tbl, pkey); + if (p_prtn != (osm_prtn_t *)cl_qmap_end( + &p_qos_policy->p_subn->prtn_pkey_tbl)) { + __parser_add_map_to_port_map(p_map, &p_prtn->part_guid_tbl); + __parser_add_map_to_port_map(p_map, &p_prtn->full_guid_tbl); + } + } + free(range_arr[i]); + } + free(range_arr); +} + +/*************************************************** + ***************************************************/ + +static void __parser_add_partition_list_to_port_map( + cl_qmap_t * p_map, + cl_list_t * p_list) +{ + cl_list_iterator_t list_iterator; + char * tmp_str; + osm_prtn_t * p_prtn; + + /* extract all the ports from the partition + to the port map of this port group */ + list_iterator = cl_list_head(p_list); + while(list_iterator != cl_list_end(p_list)) { + tmp_str = (char*)cl_list_obj(list_iterator); + if (tmp_str) { + p_prtn = osm_prtn_find_by_name(p_qos_policy->p_subn, tmp_str); + if (p_prtn) { + __parser_add_map_to_port_map(p_map, &p_prtn->part_guid_tbl); + __parser_add_map_to_port_map(p_map, &p_prtn->full_guid_tbl); + } + free(tmp_str); + } + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(p_list); +} + +/*************************************************** + ***************************************************/ + +static void __parser_add_map_to_port_map( + cl_qmap_t * p_dmap, + cl_map_t * p_smap) +{ + cl_map_iterator_t map_iterator; + osm_physp_t * p_physp; + + if (!p_dmap || !p_smap) + return; + + map_iterator = cl_map_head(p_smap); + while (map_iterator != cl_map_end(p_smap)) { + p_physp = (osm_physp_t*)cl_map_obj(map_iterator); + __parser_add_port_to_port_map(p_dmap, p_physp); + map_iterator = cl_map_next(map_iterator); + } +} + +/*************************************************** + ***************************************************/ + +static int __validate_pkeys( uint64_t ** range_arr, + unsigned range_len, + boolean_t is_ipoib) +{ + unsigned i; + uint64_t pkey_64; + ib_net16_t pkey; + osm_prtn_t * p_prtn; + + if (!range_arr || !range_len) + return 0; + + for (i = 0; i < range_len; i++) { + for (pkey_64 = range_arr[i][0]; pkey_64 <= range_arr[i][1]; pkey_64++) { + pkey = cl_hton16((uint16_t)(pkey_64 & 0x7fff)); + p_prtn = (osm_prtn_t *) + cl_qmap_get(&p_qos_policy->p_subn->prtn_pkey_tbl, pkey); + + if (p_prtn == (osm_prtn_t *)cl_qmap_end( + &p_qos_policy->p_subn->prtn_pkey_tbl)) + p_prtn = NULL; + + if (is_ipoib) { + /* + * Be very strict for IPoIB partition: + * - the partition for the pkey have to exist + * - it has to have at least 2 full members + */ + if (!p_prtn) { + yyerror("IPoIB partition, pkey 0x%04X - " + "partition doesn't exist", + cl_ntoh16(pkey)); + return 1; + } + else if (cl_map_count(&p_prtn->full_guid_tbl) < 2) { + yyerror("IPoIB partition, pkey 0x%04X - " + "partition has less than two full members", + cl_ntoh16(pkey)); + return 1; + } + } + else if (!p_prtn) { + /* + * For non-IPoIB pkey we just want to check that + * the relevant partition exists. + * And even if it doesn't, don't exit - just print + * error message and continue. + */ + OSM_LOG(p_qos_parser_osm_log, OSM_LOG_ERROR, "ERR AC02: " + "pkey 0x%04X - partition doesn't exist", + cl_ntoh16(pkey)); + } + } + } + return 0; +} + +/*************************************************** + ***************************************************/ diff --git a/contrib/ofed/management/opensm/opensm/osm_qos_policy.c b/contrib/ofed/management/opensm/opensm/osm_qos_policy.c new file mode 100644 index 000000000000..094fef25804d --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_qos_policy.c @@ -0,0 +1,1091 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * OSM QoS Policy functions. + * + * Author: + * Yevgeny Kliteynik, Mellanox + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern osm_qos_level_t __default_simple_qos_level; + +/*************************************************** + ***************************************************/ + +static void +__build_nodebyname_hash(osm_qos_policy_t * p_qos_policy) +{ + osm_node_t * p_node; + cl_qmap_t * p_node_guid_tbl = &p_qos_policy->p_subn->node_guid_tbl; + + p_qos_policy->p_node_hash = st_init_strtable(); + CL_ASSERT(p_qos_policy->p_node_hash); + + if (!p_node_guid_tbl || !cl_qmap_count(p_node_guid_tbl)) + return; + + for (p_node = (osm_node_t *) cl_qmap_head(p_node_guid_tbl); + p_node != (osm_node_t *) cl_qmap_end(p_node_guid_tbl); + p_node = (osm_node_t *) cl_qmap_next(&p_node->map_item)) { + if (!st_lookup(p_qos_policy->p_node_hash, + (st_data_t)p_node->print_desc, NULL)) + st_insert(p_qos_policy->p_node_hash, + (st_data_t)p_node->print_desc, + (st_data_t)p_node); + } +} + +/*************************************************** + ***************************************************/ + +static boolean_t +__is_num_in_range_arr(uint64_t ** range_arr, + unsigned range_arr_len, uint64_t num) +{ + unsigned ind_1 = 0; + unsigned ind_2 = range_arr_len - 1; + unsigned ind_mid; + + if (!range_arr || !range_arr_len) + return FALSE; + + while (ind_1 <= ind_2) { + if (num < range_arr[ind_1][0] || num > range_arr[ind_2][1]) + return FALSE; + else if (num <= range_arr[ind_1][1] || num >= range_arr[ind_2][0]) + return TRUE; + + ind_mid = ind_1 + (ind_2 - ind_1 + 1)/2; + + if (num < range_arr[ind_mid][0]) + ind_2 = ind_mid; + else if (num > range_arr[ind_mid][1]) + ind_1 = ind_mid; + else + return TRUE; + + ind_1++; + ind_2--; + } + + return FALSE; +} + +/*************************************************** + ***************************************************/ + +static void __free_single_element(void *p_element, void *context) +{ + if (p_element) + free(p_element); +} + +/*************************************************** + ***************************************************/ + +osm_qos_port_t *osm_qos_policy_port_create(osm_physp_t *p_physp) +{ + osm_qos_port_t *p = + (osm_qos_port_t *) malloc(sizeof(osm_qos_port_t)); + if (!p) + return NULL; + memset(p, 0, sizeof(osm_qos_port_t)); + + p->p_physp = p_physp; + return p; +} + +/*************************************************** + ***************************************************/ + +osm_qos_port_group_t *osm_qos_policy_port_group_create() +{ + osm_qos_port_group_t *p = + (osm_qos_port_group_t *) malloc(sizeof(osm_qos_port_group_t)); + if (!p) + return NULL; + + memset(p, 0, sizeof(osm_qos_port_group_t)); + cl_qmap_init(&p->port_map); + + return p; +} + +/*************************************************** + ***************************************************/ + +void osm_qos_policy_port_group_destroy(osm_qos_port_group_t * p) +{ + osm_qos_port_t * p_port; + osm_qos_port_t * p_old_port; + + if (!p) + return; + + if (p->name) + free(p->name); + if (p->use) + free(p->use); + + p_port = (osm_qos_port_t *) cl_qmap_head(&p->port_map); + while (p_port != (osm_qos_port_t *) cl_qmap_end(&p->port_map)) + { + p_old_port = p_port; + p_port = (osm_qos_port_t *) cl_qmap_next(&p_port->map_item); + free(p_old_port); + } + cl_qmap_remove_all(&p->port_map); + + free(p); +} + +/*************************************************** + ***************************************************/ + +osm_qos_vlarb_scope_t *osm_qos_policy_vlarb_scope_create() +{ + osm_qos_vlarb_scope_t *p = + (osm_qos_vlarb_scope_t *) malloc(sizeof(osm_qos_sl2vl_scope_t)); + if (!p) + return NULL; + + memset(p, 0, sizeof(osm_qos_vlarb_scope_t)); + + cl_list_init(&p->group_list, 10); + cl_list_init(&p->across_list, 10); + cl_list_init(&p->vlarb_high_list, 10); + cl_list_init(&p->vlarb_low_list, 10); + + return p; +} + +/*************************************************** + ***************************************************/ + +void osm_qos_policy_vlarb_scope_destroy(osm_qos_vlarb_scope_t * p) +{ + if (!p) + return; + + cl_list_apply_func(&p->group_list, __free_single_element, NULL); + cl_list_apply_func(&p->across_list, __free_single_element, NULL); + cl_list_apply_func(&p->vlarb_high_list, __free_single_element, NULL); + cl_list_apply_func(&p->vlarb_low_list, __free_single_element, NULL); + + cl_list_remove_all(&p->group_list); + cl_list_remove_all(&p->across_list); + cl_list_remove_all(&p->vlarb_high_list); + cl_list_remove_all(&p->vlarb_low_list); + + cl_list_destroy(&p->group_list); + cl_list_destroy(&p->across_list); + cl_list_destroy(&p->vlarb_high_list); + cl_list_destroy(&p->vlarb_low_list); + + free(p); +} + +/*************************************************** + ***************************************************/ + +osm_qos_sl2vl_scope_t *osm_qos_policy_sl2vl_scope_create() +{ + osm_qos_sl2vl_scope_t *p = + (osm_qos_sl2vl_scope_t *) malloc(sizeof(osm_qos_sl2vl_scope_t)); + if (!p) + return NULL; + + memset(p, 0, sizeof(osm_qos_sl2vl_scope_t)); + + cl_list_init(&p->group_list, 10); + cl_list_init(&p->across_from_list, 10); + cl_list_init(&p->across_to_list, 10); + + return p; +} + +/*************************************************** + ***************************************************/ + +void osm_qos_policy_sl2vl_scope_destroy(osm_qos_sl2vl_scope_t * p) +{ + if (!p) + return; + + cl_list_apply_func(&p->group_list, __free_single_element, NULL); + cl_list_apply_func(&p->across_from_list, __free_single_element, NULL); + cl_list_apply_func(&p->across_to_list, __free_single_element, NULL); + + cl_list_remove_all(&p->group_list); + cl_list_remove_all(&p->across_from_list); + cl_list_remove_all(&p->across_to_list); + + cl_list_destroy(&p->group_list); + cl_list_destroy(&p->across_from_list); + cl_list_destroy(&p->across_to_list); + + free(p); +} + +/*************************************************** + ***************************************************/ + +osm_qos_level_t *osm_qos_policy_qos_level_create() +{ + osm_qos_level_t *p = + (osm_qos_level_t *) malloc(sizeof(osm_qos_level_t)); + if (!p) + return NULL; + memset(p, 0, sizeof(osm_qos_level_t)); + return p; +} + +/*************************************************** + ***************************************************/ + +void osm_qos_policy_qos_level_destroy(osm_qos_level_t * p) +{ + unsigned i; + + if (!p) + return; + + if (p->name) + free(p->name); + if (p->use) + free(p->use); + + for (i = 0; i < p->path_bits_range_len; i++) + free(p->path_bits_range_arr[i]); + if (p->path_bits_range_arr) + free(p->path_bits_range_arr); + + free(p); +} + +/*************************************************** + ***************************************************/ + +boolean_t osm_qos_level_has_pkey(IN const osm_qos_level_t * p_qos_level, + IN ib_net16_t pkey) +{ + if (!p_qos_level || !p_qos_level->pkey_range_len) + return FALSE; + return __is_num_in_range_arr(p_qos_level->pkey_range_arr, + p_qos_level->pkey_range_len, + cl_ntoh16(pkey)); +} + +/*************************************************** + ***************************************************/ + +ib_net16_t osm_qos_level_get_shared_pkey(IN const osm_qos_level_t * p_qos_level, + IN const osm_physp_t * p_src_physp, + IN const osm_physp_t * p_dest_physp) +{ + unsigned i; + uint16_t pkey_ho = 0; + + if (!p_qos_level || !p_qos_level->pkey_range_len) + return 0; + + /* + * ToDo: This approach is not optimal. + * Think how to find shared pkey that also exists + * in QoS level in less runtime. + */ + + for (i = 0; i < p_qos_level->pkey_range_len; i++) { + for (pkey_ho = p_qos_level->pkey_range_arr[i][0]; + pkey_ho <= p_qos_level->pkey_range_arr[i][1]; pkey_ho++) { + if (osm_physp_share_this_pkey + (p_src_physp, p_dest_physp, cl_hton16(pkey_ho))) + return cl_hton16(pkey_ho); + } + } + + return 0; +} + +/*************************************************** + ***************************************************/ + +osm_qos_match_rule_t *osm_qos_policy_match_rule_create() +{ + osm_qos_match_rule_t *p = + (osm_qos_match_rule_t *) malloc(sizeof(osm_qos_match_rule_t)); + if (!p) + return NULL; + + memset(p, 0, sizeof(osm_qos_match_rule_t)); + + cl_list_init(&p->source_list, 10); + cl_list_init(&p->source_group_list, 10); + cl_list_init(&p->destination_list, 10); + cl_list_init(&p->destination_group_list, 10); + + return p; +} + +/*************************************************** + ***************************************************/ + +void osm_qos_policy_match_rule_destroy(osm_qos_match_rule_t * p) +{ + unsigned i; + + if (!p) + return; + + if (p->qos_level_name) + free(p->qos_level_name); + if (p->use) + free(p->use); + + for (i = 0; i < p->service_id_range_len; i++) + free(p->service_id_range_arr[i]); + if (p->service_id_range_arr) + free(p->service_id_range_arr); + + for (i = 0; i < p->qos_class_range_len; i++) + free(p->qos_class_range_arr[i]); + if (p->qos_class_range_arr) + free(p->qos_class_range_arr); + + for (i = 0; i < p->pkey_range_len; i++) + free(p->pkey_range_arr[i]); + if (p->pkey_range_arr) + free(p->pkey_range_arr); + + cl_list_apply_func(&p->source_list, __free_single_element, NULL); + cl_list_remove_all(&p->source_list); + cl_list_destroy(&p->source_list); + + cl_list_remove_all(&p->source_group_list); + cl_list_destroy(&p->source_group_list); + + cl_list_apply_func(&p->destination_list, __free_single_element, NULL); + cl_list_remove_all(&p->destination_list); + cl_list_destroy(&p->destination_list); + + cl_list_remove_all(&p->destination_group_list); + cl_list_destroy(&p->destination_group_list); + + free(p); +} + +/*************************************************** + ***************************************************/ + +osm_qos_policy_t * osm_qos_policy_create(osm_subn_t * p_subn) +{ + osm_qos_policy_t * p_qos_policy = (osm_qos_policy_t *)malloc(sizeof(osm_qos_policy_t)); + if (!p_qos_policy) + return NULL; + + memset(p_qos_policy, 0, sizeof(osm_qos_policy_t)); + + cl_list_construct(&p_qos_policy->port_groups); + cl_list_init(&p_qos_policy->port_groups, 10); + + cl_list_construct(&p_qos_policy->vlarb_tables); + cl_list_init(&p_qos_policy->vlarb_tables, 10); + + cl_list_construct(&p_qos_policy->sl2vl_tables); + cl_list_init(&p_qos_policy->sl2vl_tables, 10); + + cl_list_construct(&p_qos_policy->qos_levels); + cl_list_init(&p_qos_policy->qos_levels, 10); + + cl_list_construct(&p_qos_policy->qos_match_rules); + cl_list_init(&p_qos_policy->qos_match_rules, 10); + + p_qos_policy->p_subn = p_subn; + __build_nodebyname_hash(p_qos_policy); + + return p_qos_policy; +} + +/*************************************************** + ***************************************************/ + +void osm_qos_policy_destroy(osm_qos_policy_t * p_qos_policy) +{ + cl_list_iterator_t list_iterator; + osm_qos_port_group_t *p_port_group = NULL; + osm_qos_vlarb_scope_t *p_vlarb_scope = NULL; + osm_qos_sl2vl_scope_t *p_sl2vl_scope = NULL; + osm_qos_level_t *p_qos_level = NULL; + osm_qos_match_rule_t *p_qos_match_rule = NULL; + + if (!p_qos_policy) + return; + + list_iterator = cl_list_head(&p_qos_policy->port_groups); + while (list_iterator != cl_list_end(&p_qos_policy->port_groups)) { + p_port_group = + (osm_qos_port_group_t *) cl_list_obj(list_iterator); + if (p_port_group) + osm_qos_policy_port_group_destroy(p_port_group); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&p_qos_policy->port_groups); + cl_list_destroy(&p_qos_policy->port_groups); + + list_iterator = cl_list_head(&p_qos_policy->vlarb_tables); + while (list_iterator != cl_list_end(&p_qos_policy->vlarb_tables)) { + p_vlarb_scope = + (osm_qos_vlarb_scope_t *) cl_list_obj(list_iterator); + if (p_vlarb_scope) + osm_qos_policy_vlarb_scope_destroy(p_vlarb_scope); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&p_qos_policy->vlarb_tables); + cl_list_destroy(&p_qos_policy->vlarb_tables); + + list_iterator = cl_list_head(&p_qos_policy->sl2vl_tables); + while (list_iterator != cl_list_end(&p_qos_policy->sl2vl_tables)) { + p_sl2vl_scope = + (osm_qos_sl2vl_scope_t *) cl_list_obj(list_iterator); + if (p_sl2vl_scope) + osm_qos_policy_sl2vl_scope_destroy(p_sl2vl_scope); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&p_qos_policy->sl2vl_tables); + cl_list_destroy(&p_qos_policy->sl2vl_tables); + + list_iterator = cl_list_head(&p_qos_policy->qos_levels); + while (list_iterator != cl_list_end(&p_qos_policy->qos_levels)) { + p_qos_level = (osm_qos_level_t *) cl_list_obj(list_iterator); + if (p_qos_level) + osm_qos_policy_qos_level_destroy(p_qos_level); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&p_qos_policy->qos_levels); + cl_list_destroy(&p_qos_policy->qos_levels); + + list_iterator = cl_list_head(&p_qos_policy->qos_match_rules); + while (list_iterator != cl_list_end(&p_qos_policy->qos_match_rules)) { + p_qos_match_rule = + (osm_qos_match_rule_t *) cl_list_obj(list_iterator); + if (p_qos_match_rule) + osm_qos_policy_match_rule_destroy(p_qos_match_rule); + list_iterator = cl_list_next(list_iterator); + } + cl_list_remove_all(&p_qos_policy->qos_match_rules); + cl_list_destroy(&p_qos_policy->qos_match_rules); + + if (p_qos_policy->p_node_hash) + st_free_table(p_qos_policy->p_node_hash); + + free(p_qos_policy); + + p_qos_policy = NULL; +} + +/*************************************************** + ***************************************************/ + +static boolean_t +__qos_policy_is_port_in_group(osm_subn_t * p_subn, + const osm_physp_t * p_physp, + osm_qos_port_group_t * p_port_group) +{ + osm_node_t *p_node = osm_physp_get_node_ptr(p_physp); + ib_net64_t port_guid = osm_physp_get_port_guid(p_physp); + uint64_t port_guid_ho = cl_ntoh64(port_guid); + + /* check whether this port's type matches any of group's types */ + + if ( p_port_group->node_types & + (((uint8_t)1)<port_map, port_guid_ho) != + cl_qmap_end(&p_port_group->port_map)) + return TRUE; + + return FALSE; +} /* __qos_policy_is_port_in_group() */ + +/*************************************************** + ***************************************************/ + +static boolean_t +__qos_policy_is_port_in_group_list(const osm_qos_policy_t * p_qos_policy, + const osm_physp_t * p_physp, + cl_list_t * p_port_group_list) +{ + osm_qos_port_group_t *p_port_group; + cl_list_iterator_t list_iterator; + + list_iterator = cl_list_head(p_port_group_list); + while (list_iterator != cl_list_end(p_port_group_list)) { + p_port_group = + (osm_qos_port_group_t *) cl_list_obj(list_iterator); + if (p_port_group) { + if (__qos_policy_is_port_in_group + (p_qos_policy->p_subn, p_physp, p_port_group)) + return TRUE; + } + list_iterator = cl_list_next(list_iterator); + } + return FALSE; +} + +/*************************************************** + ***************************************************/ + +static osm_qos_match_rule_t *__qos_policy_get_match_rule_by_params( + const osm_qos_policy_t * p_qos_policy, + uint64_t service_id, + uint16_t qos_class, + uint16_t pkey, + const osm_physp_t * p_src_physp, + const osm_physp_t * p_dest_physp, + ib_net64_t comp_mask) +{ + osm_qos_match_rule_t *p_qos_match_rule = NULL; + cl_list_iterator_t list_iterator; + osm_log_t * p_log = &p_qos_policy->p_subn->p_osm->log; + + boolean_t matched_by_sguid = FALSE, + matched_by_dguid = FALSE, + matched_by_class = FALSE, + matched_by_sid = FALSE, + matched_by_pkey = FALSE; + + if (!cl_list_count(&p_qos_policy->qos_match_rules)) + return NULL; + + OSM_LOG_ENTER(p_log); + + /* Go over all QoS match rules and find the one that matches the request */ + + list_iterator = cl_list_head(&p_qos_policy->qos_match_rules); + while (list_iterator != cl_list_end(&p_qos_policy->qos_match_rules)) { + p_qos_match_rule = + (osm_qos_match_rule_t *) cl_list_obj(list_iterator); + if (!p_qos_match_rule) { + list_iterator = cl_list_next(list_iterator); + continue; + } + + /* If a match rule has Source groups, PR request source has to be in this list */ + + if (cl_list_count(&p_qos_match_rule->source_group_list)) { + if (!__qos_policy_is_port_in_group_list(p_qos_policy, + p_src_physp, + &p_qos_match_rule-> + source_group_list)) + { + list_iterator = cl_list_next(list_iterator); + continue; + } + matched_by_sguid = TRUE; + } + + /* If a match rule has Destination groups, PR request dest. has to be in this list */ + + if (cl_list_count(&p_qos_match_rule->destination_group_list)) { + if (!__qos_policy_is_port_in_group_list(p_qos_policy, + p_dest_physp, + &p_qos_match_rule-> + destination_group_list)) + { + list_iterator = cl_list_next(list_iterator); + continue; + } + matched_by_dguid = TRUE; + } + + /* If a match rule has QoS classes, PR request HAS + to have a matching QoS class to match the rule */ + + if (p_qos_match_rule->qos_class_range_len) { + if (!(comp_mask & IB_PR_COMPMASK_QOS_CLASS)) { + list_iterator = cl_list_next(list_iterator); + continue; + } + + if (!__is_num_in_range_arr + (p_qos_match_rule->qos_class_range_arr, + p_qos_match_rule->qos_class_range_len, + qos_class)) { + list_iterator = cl_list_next(list_iterator); + continue; + } + matched_by_class = TRUE; + } + + /* If a match rule has Service IDs, PR request HAS + to have a matching Service ID to match the rule */ + + if (p_qos_match_rule->service_id_range_len) { + if (!(comp_mask & IB_PR_COMPMASK_SERVICEID_MSB) || + !(comp_mask & IB_PR_COMPMASK_SERVICEID_LSB)) { + list_iterator = cl_list_next(list_iterator); + continue; + } + + if (!__is_num_in_range_arr + (p_qos_match_rule->service_id_range_arr, + p_qos_match_rule->service_id_range_len, + service_id)) { + list_iterator = cl_list_next(list_iterator); + continue; + } + matched_by_sid = TRUE; + } + + /* If a match rule has PKeys, PR request HAS + to have a matching PKey to match the rule */ + + if (p_qos_match_rule->pkey_range_len) { + if (!(comp_mask & IB_PR_COMPMASK_PKEY)) { + list_iterator = cl_list_next(list_iterator); + continue; + } + + if (!__is_num_in_range_arr + (p_qos_match_rule->pkey_range_arr, + p_qos_match_rule->pkey_range_len, + pkey & 0x7FFF)) { + list_iterator = cl_list_next(list_iterator); + continue; + } + matched_by_pkey = TRUE; + } + + /* if we got here, then this match-rule matched this PR request */ + break; + } + + if (list_iterator == cl_list_end(&p_qos_policy->qos_match_rules)) + p_qos_match_rule = NULL; + + if (p_qos_match_rule) + OSM_LOG(p_log, OSM_LOG_DEBUG, + "request matched rule (%s) by:%s%s%s%s%s\n", + (p_qos_match_rule->use) ? + p_qos_match_rule->use : "no description", + (matched_by_sguid) ? " SGUID" : "", + (matched_by_dguid) ? " DGUID" : "", + (matched_by_class) ? " QoS_Class" : "", + (matched_by_sid) ? " ServiceID" : "", + (matched_by_pkey) ? " PKey" : ""); + else + OSM_LOG(p_log, OSM_LOG_DEBUG, + "request not matched any rule\n"); + + OSM_LOG_EXIT(p_log); + return p_qos_match_rule; +} /* __qos_policy_get_match_rule_by_params() */ + +/*************************************************** + ***************************************************/ + +static osm_qos_level_t *__qos_policy_get_qos_level_by_name( + const osm_qos_policy_t * p_qos_policy, + char *name) +{ + osm_qos_level_t *p_qos_level = NULL; + cl_list_iterator_t list_iterator; + + list_iterator = cl_list_head(&p_qos_policy->qos_levels); + while (list_iterator != cl_list_end(&p_qos_policy->qos_levels)) { + p_qos_level = (osm_qos_level_t *) cl_list_obj(list_iterator); + if (!p_qos_level) + continue; + + /* names are case INsensitive */ + if (strcasecmp(name, p_qos_level->name) == 0) + return p_qos_level; + + list_iterator = cl_list_next(list_iterator); + } + + return NULL; +} + +/*************************************************** + ***************************************************/ + +static osm_qos_port_group_t *__qos_policy_get_port_group_by_name( + const osm_qos_policy_t * p_qos_policy, + const char *const name) +{ + osm_qos_port_group_t *p_port_group = NULL; + cl_list_iterator_t list_iterator; + + list_iterator = cl_list_head(&p_qos_policy->port_groups); + while (list_iterator != cl_list_end(&p_qos_policy->port_groups)) { + p_port_group = + (osm_qos_port_group_t *) cl_list_obj(list_iterator); + if (!p_port_group) + continue; + + /* names are case INsensitive */ + if (strcasecmp(name, p_port_group->name) == 0) + return p_port_group; + + list_iterator = cl_list_next(list_iterator); + } + + return NULL; +} + +/*************************************************** + ***************************************************/ + +static void __qos_policy_validate_pkey( + osm_qos_policy_t * p_qos_policy, + osm_qos_match_rule_t * p_qos_match_rule, + osm_prtn_t * p_prtn) +{ + uint8_t sl; + uint32_t flow; + uint8_t hop; + osm_mgrp_t * p_mgrp; + + if (!p_qos_policy || !p_qos_match_rule || !p_prtn) + return; + + if (!p_qos_match_rule->p_qos_level->sl_set || + p_prtn->sl == p_qos_match_rule->p_qos_level->sl) + return; + + /* overriding partition's SL */ + OSM_LOG(&p_qos_policy->p_subn->p_osm->log, OSM_LOG_ERROR, + "ERR AC15: pkey 0x%04X in match rule - " + "overriding partition SL (%u) with QoS Level SL (%u)\n", + cl_ntoh16(p_prtn->pkey), p_prtn->sl, + p_qos_match_rule->p_qos_level->sl); + p_prtn->sl = p_qos_match_rule->p_qos_level->sl; + + + /* If this partition is an IPoIB partition, there should + be a matching MCast group. Fix this group's SL too */ + + if (!p_prtn->mlid) + return; + + p_mgrp = osm_get_mgrp_by_mlid(p_qos_policy->p_subn, p_prtn->mlid); + if (!p_mgrp) { + OSM_LOG(&p_qos_policy->p_subn->p_osm->log, OSM_LOG_ERROR, + "ERR AC16: MCast group for partition with " + "pkey 0x%04X not found\n", + cl_ntoh16(p_prtn->pkey)); + return; + } + + CL_ASSERT((cl_ntoh16(p_mgrp->mcmember_rec.pkey) & 0x7fff) == + (cl_ntoh16(p_prtn->pkey) & 0x7fff)); + + ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop, + &sl, &flow, &hop); + if (sl != p_prtn->sl) { + OSM_LOG(&p_qos_policy->p_subn->p_osm->log, OSM_LOG_DEBUG, + "Updating MCGroup (MLID 0x%04x) SL to " + "match partition SL (%u)\n", + cl_hton16(p_mgrp->mcmember_rec.mlid), + p_prtn->sl); + p_mgrp->mcmember_rec.sl_flow_hop = + ib_member_set_sl_flow_hop(p_prtn->sl, flow, hop); + } +} + +/*************************************************** + ***************************************************/ + +int osm_qos_policy_validate(osm_qos_policy_t * p_qos_policy, + osm_log_t *p_log) +{ + cl_list_iterator_t match_rules_list_iterator; + cl_list_iterator_t list_iterator; + osm_qos_port_group_t *p_port_group = NULL; + osm_qos_match_rule_t *p_qos_match_rule = NULL; + char *str; + unsigned i, j; + int res = 0; + uint64_t pkey_64; + ib_net16_t pkey; + osm_prtn_t * p_prtn; + + OSM_LOG_ENTER(p_log); + + /* set default qos level */ + + p_qos_policy->p_default_qos_level = + __qos_policy_get_qos_level_by_name(p_qos_policy, OSM_QOS_POLICY_DEFAULT_LEVEL_NAME); + if (!p_qos_policy->p_default_qos_level) { + /* There's no default QoS level in the usual qos-level section. + Check whether the 'simple' default QoS level that can be + defined in the qos-ulp section exists */ + if (__default_simple_qos_level.sl_set) { + p_qos_policy->p_default_qos_level = &__default_simple_qos_level; + } + else { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AC10: " + "Default qos-level (%s) not defined.\n", + OSM_QOS_POLICY_DEFAULT_LEVEL_NAME); + res = 1; + goto Exit; + } + } + + /* scan all the match rules, and fill the lists of pointers to + relevant qos levels and port groups to speed up PR matching */ + + i = 1; + match_rules_list_iterator = + cl_list_head(&p_qos_policy->qos_match_rules); + while (match_rules_list_iterator != + cl_list_end(&p_qos_policy->qos_match_rules)) { + p_qos_match_rule = + (osm_qos_match_rule_t *) + cl_list_obj(match_rules_list_iterator); + CL_ASSERT(p_qos_match_rule); + + /* find the matching qos-level for each match-rule */ + + if (!p_qos_match_rule->p_qos_level) + p_qos_match_rule->p_qos_level = + __qos_policy_get_qos_level_by_name(p_qos_policy, + p_qos_match_rule->qos_level_name); + + if (!p_qos_match_rule->p_qos_level) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AC11: " + "qos-match-rule num %u: qos-level '%s' not found\n", + i, p_qos_match_rule->qos_level_name); + res = 1; + goto Exit; + } + + /* find the matching port-group for element of source_list */ + + if (cl_list_count(&p_qos_match_rule->source_list)) { + list_iterator = + cl_list_head(&p_qos_match_rule->source_list); + while (list_iterator != + cl_list_end(&p_qos_match_rule->source_list)) { + str = (char *)cl_list_obj(list_iterator); + CL_ASSERT(str); + + p_port_group = + __qos_policy_get_port_group_by_name(p_qos_policy, str); + if (!p_port_group) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AC12: " + "qos-match-rule num %u: source port-group '%s' not found\n", + i, str); + res = 1; + goto Exit; + } + + cl_list_insert_tail(&p_qos_match_rule-> + source_group_list, + p_port_group); + + list_iterator = cl_list_next(list_iterator); + } + } + + /* find the matching port-group for element of destination_list */ + + if (cl_list_count(&p_qos_match_rule->destination_list)) { + list_iterator = + cl_list_head(&p_qos_match_rule->destination_list); + while (list_iterator != + cl_list_end(&p_qos_match_rule-> + destination_list)) { + str = (char *)cl_list_obj(list_iterator); + CL_ASSERT(str); + + p_port_group = + __qos_policy_get_port_group_by_name(p_qos_policy,str); + if (!p_port_group) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AC13: " + "qos-match-rule num %u: destination port-group '%s' not found\n", + i, str); + res = 1; + goto Exit; + } + + cl_list_insert_tail(&p_qos_match_rule-> + destination_group_list, + p_port_group); + + list_iterator = cl_list_next(list_iterator); + } + } + + /* + * Scan all the pkeys in matching rule, and if the + * partition for these pkeys exists, set the SL + * according to the QoS Level. + * Warn if there's mismatch between QoS level SL + * and Partition SL. + */ + + for (j = 0; j < p_qos_match_rule->pkey_range_len; j++) { + for ( pkey_64 = p_qos_match_rule->pkey_range_arr[j][0]; + pkey_64 <= p_qos_match_rule->pkey_range_arr[j][1]; + pkey_64++) { + pkey = cl_hton16((uint16_t)(pkey_64 & 0x7fff)); + p_prtn = (osm_prtn_t *)cl_qmap_get( + &p_qos_policy->p_subn->prtn_pkey_tbl, pkey); + + if (p_prtn == (osm_prtn_t *)cl_qmap_end( + &p_qos_policy->p_subn->prtn_pkey_tbl)) + /* partition for this pkey not found */ + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AC14: " + "pkey 0x%04X in match rule - " + "partition doesn't exist\n", + cl_ntoh16(pkey)); + else + __qos_policy_validate_pkey(p_qos_policy, + p_qos_match_rule, + p_prtn); + } + } + + /* done with the current match-rule */ + + match_rules_list_iterator = + cl_list_next(match_rules_list_iterator); + i++; + } + +Exit: + OSM_LOG_EXIT(p_log); + return res; +} /* osm_qos_policy_validate() */ + +/*************************************************** + ***************************************************/ + +static osm_qos_level_t * __qos_policy_get_qos_level_by_params( + IN const osm_qos_policy_t * p_qos_policy, + IN const osm_physp_t * p_src_physp, + IN const osm_physp_t * p_dest_physp, + IN uint64_t service_id, + IN uint16_t qos_class, + IN uint16_t pkey, + IN ib_net64_t comp_mask) +{ + osm_qos_match_rule_t *p_qos_match_rule = NULL; + + if (!p_qos_policy) + return NULL; + + p_qos_match_rule = __qos_policy_get_match_rule_by_params( + p_qos_policy, service_id, qos_class, pkey, + p_src_physp, p_dest_physp, comp_mask); + + return p_qos_match_rule ? p_qos_match_rule->p_qos_level : + p_qos_policy->p_default_qos_level; +} /* __qos_policy_get_qos_level_by_params() */ + +/*************************************************** + ***************************************************/ + +osm_qos_level_t * osm_qos_policy_get_qos_level_by_pr( + IN const osm_qos_policy_t * p_qos_policy, + IN const ib_path_rec_t * p_pr, + IN const osm_physp_t * p_src_physp, + IN const osm_physp_t * p_dest_physp, + IN ib_net64_t comp_mask) +{ + return __qos_policy_get_qos_level_by_params( + p_qos_policy, p_src_physp, p_dest_physp, + cl_ntoh64(p_pr->service_id), ib_path_rec_qos_class(p_pr), + cl_ntoh16(p_pr->pkey), comp_mask); +} + +/*************************************************** + ***************************************************/ + +osm_qos_level_t * osm_qos_policy_get_qos_level_by_mpr( + IN const osm_qos_policy_t * p_qos_policy, + IN const ib_multipath_rec_t * p_mpr, + IN const osm_physp_t * p_src_physp, + IN const osm_physp_t * p_dest_physp, + IN ib_net64_t comp_mask) +{ + ib_net64_t pr_comp_mask = 0; + + if (!p_qos_policy) + return NULL; + + /* + * Converting MultiPathRecord compmask to the PathRecord + * compmask. Note that only relevant bits are set. + */ + pr_comp_mask = + ((comp_mask & IB_MPR_COMPMASK_QOS_CLASS) ? + IB_PR_COMPMASK_QOS_CLASS : 0) | + ((comp_mask & IB_MPR_COMPMASK_PKEY) ? + IB_PR_COMPMASK_PKEY : 0) | + ((comp_mask & IB_MPR_COMPMASK_SERVICEID_MSB) ? + IB_PR_COMPMASK_SERVICEID_MSB : 0) | + ((comp_mask & IB_MPR_COMPMASK_SERVICEID_LSB) ? + IB_PR_COMPMASK_SERVICEID_LSB : 0); + + return __qos_policy_get_qos_level_by_params( + p_qos_policy, p_src_physp, p_dest_physp, + cl_ntoh64(ib_multipath_rec_service_id(p_mpr)), + ib_multipath_rec_qos_class(p_mpr), + cl_ntoh16(p_mpr->pkey), pr_comp_mask); +} + +/*************************************************** + ***************************************************/ diff --git a/contrib/ofed/management/opensm/opensm/osm_remote_sm.c b/contrib/ofed/management/opensm/opensm/osm_remote_sm.c new file mode 100644 index 000000000000..96bfd7829e9a --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_remote_sm.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sm_t. + * This object represents the remote SM object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +/********************************************************************** + **********************************************************************/ +void osm_remote_sm_construct(IN osm_remote_sm_t * const p_sm) +{ + memset(p_sm, 0, sizeof(*p_sm)); +} + +/********************************************************************** + **********************************************************************/ +void osm_remote_sm_destroy(IN osm_remote_sm_t * const p_sm) +{ + memset(p_sm, 0, sizeof(*p_sm)); +} + +/********************************************************************** + **********************************************************************/ +void +osm_remote_sm_init(IN osm_remote_sm_t * const p_sm, + IN const osm_port_t * const p_port, + IN const ib_sm_info_t * const p_smi) +{ + CL_ASSERT(p_sm); + CL_ASSERT(p_port); + + osm_remote_sm_construct(p_sm); + + p_sm->p_port = p_port; + p_sm->smi = *p_smi; + return; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_req.c b/contrib/ofed/management/opensm/opensm/osm_req.c new file mode 100644 index 000000000000..0865ce5d04ea --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_req.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_req_t. + * This object represents the generic attribute requester. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + The plock MAY or MAY NOT be held before calling this function. +**********************************************************************/ +ib_api_status_t +osm_req_get(IN osm_sm_t * sm, + IN const osm_dr_path_t * const p_path, + IN const uint16_t attr_id, + IN const uint32_t attr_mod, + IN const cl_disp_msgid_t err_msg, + IN const osm_madw_context_t * const p_context) +{ + osm_madw_t *p_madw; + ib_api_status_t status = IB_SUCCESS; + ib_net64_t tid; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_path); + CL_ASSERT(attr_id); + + /* do nothing if we are exiting ... */ + if (osm_exit_flag) + goto Exit; + + /* p_context may be NULL. */ + + p_madw = osm_mad_pool_get(sm->p_mad_pool, + p_path->h_bind, MAD_BLOCK_SIZE, NULL); + + if (p_madw == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 1101: Unable to acquire MAD\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + tid = cl_hton64((uint64_t) cl_atomic_inc(&sm->sm_trans_id)); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Getting %s (0x%X), modifier 0x%X, TID 0x%" PRIx64 "\n", + ib_get_sm_attr_str(attr_id), cl_ntoh16(attr_id), + cl_ntoh32(attr_mod), cl_ntoh64(tid)); + + ib_smp_init_new(osm_madw_get_smp_ptr(p_madw), + IB_MAD_METHOD_GET, + tid, + attr_id, + attr_mod, + p_path->hop_count, + sm->p_subn->opt.m_key, + p_path->path, IB_LID_PERMISSIVE, IB_LID_PERMISSIVE); + + p_madw->mad_addr.dest_lid = IB_LID_PERMISSIVE; + p_madw->mad_addr.addr_type.smi.source_lid = IB_LID_PERMISSIVE; + p_madw->resp_expected = TRUE; + p_madw->fail_msg = err_msg; + + /* + Fill in the mad wrapper context for the recipient. + In this case, the only thing the recipient needs is the + guid value. + */ + + if (p_context) + p_madw->context = *p_context; + + osm_vl15_post(sm->p_vl15, p_madw); + +Exit: + OSM_LOG_EXIT(sm->p_log); + return (status); +} + +/********************************************************************** + The plock MAY or MAY NOT be held before calling this function. +**********************************************************************/ +ib_api_status_t +osm_req_set(IN osm_sm_t * sm, + IN const osm_dr_path_t * const p_path, + IN const uint8_t * const p_payload, + IN const size_t payload_size, + IN const uint16_t attr_id, + IN const uint32_t attr_mod, + IN const cl_disp_msgid_t err_msg, + IN const osm_madw_context_t * const p_context) +{ + osm_madw_t *p_madw; + ib_api_status_t status = IB_SUCCESS; + ib_net64_t tid; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_path); + CL_ASSERT(attr_id); + CL_ASSERT(p_payload); + + /* do nothing if we are exiting ... */ + if (osm_exit_flag) + goto Exit; + + /* p_context may be NULL. */ + + p_madw = osm_mad_pool_get(sm->p_mad_pool, + p_path->h_bind, MAD_BLOCK_SIZE, NULL); + + if (p_madw == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 1102: Unable to acquire MAD\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + tid = cl_hton64((uint64_t) cl_atomic_inc(&sm->sm_trans_id)); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Setting %s (0x%X), modifier 0x%X, TID 0x%" PRIx64 "\n", + ib_get_sm_attr_str(attr_id), cl_ntoh16(attr_id), + cl_ntoh32(attr_mod), cl_ntoh64(tid)); + + ib_smp_init_new(osm_madw_get_smp_ptr(p_madw), + IB_MAD_METHOD_SET, + tid, + attr_id, + attr_mod, + p_path->hop_count, + sm->p_subn->opt.m_key, + p_path->path, IB_LID_PERMISSIVE, IB_LID_PERMISSIVE); + + p_madw->mad_addr.dest_lid = IB_LID_PERMISSIVE; + p_madw->mad_addr.addr_type.smi.source_lid = IB_LID_PERMISSIVE; + p_madw->resp_expected = TRUE; + p_madw->fail_msg = err_msg; + + /* + Fill in the mad wrapper context for the recipient. + In this case, the only thing the recipient needs is the + guid value. + */ + + if (p_context) + p_madw->context = *p_context; + + memcpy(osm_madw_get_smp_ptr(p_madw)->data, p_payload, payload_size); + + osm_vl15_post(sm->p_vl15, p_madw); + +Exit: + OSM_LOG_EXIT(sm->p_log); + return (status); +} + +int osm_send_trap144(osm_sm_t *sm, ib_net16_t local) +{ + osm_madw_t *madw; + ib_smp_t *smp; + ib_mad_notice_attr_t *ntc; + osm_port_t *port; + ib_port_info_t *pi; + + port = osm_get_port_by_guid(sm->p_subn, sm->p_subn->sm_port_guid); + if (!port) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 1104: cannot find SM port by guid 0x%" PRIx64 "\n", + cl_ntoh64(sm->p_subn->sm_port_guid)); + return -1; + } + + pi = &port->p_physp->port_info; + + /* don't bother with sending trap when SMA supports this */ + if (!local && + pi->capability_mask&(IB_PORT_CAP_HAS_TRAP|IB_PORT_CAP_HAS_CAP_NTC)) + return 0; + + madw = osm_mad_pool_get(sm->p_mad_pool, + osm_sm_mad_ctrl_get_bind_handle(&sm->mad_ctrl), + MAD_BLOCK_SIZE, NULL); + if (madw == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 1105: Unable to acquire MAD\n"); + return -1; + } + + madw->mad_addr.dest_lid = pi->master_sm_base_lid; + madw->mad_addr.addr_type.smi.source_lid = pi->base_lid; + madw->fail_msg = CL_DISP_MSGID_NONE; + + smp = osm_madw_get_smp_ptr(madw); + memset(smp, 0, sizeof(*smp)); + + smp->base_ver = 1; + smp->mgmt_class = IB_MCLASS_SUBN_LID; + smp->class_ver = 1; + smp->method = IB_MAD_METHOD_TRAP; + smp->trans_id = cl_hton64((uint64_t)cl_atomic_inc(&sm->sm_trans_id)); + smp->attr_id = IB_MAD_ATTR_NOTICE; + smp->m_key = sm->p_subn->opt.m_key; + + ntc = (ib_mad_notice_attr_t *)smp->data; + + ntc->generic_type = 0x80 | IB_NOTICE_TYPE_INFO; + ib_notice_set_prod_type_ho(ntc, IB_NODE_TYPE_CA); + ntc->g_or_v.generic.trap_num = cl_hton16(144); + ntc->issuer_lid = pi->base_lid; + ntc->data_details.ntc_144.lid = pi->base_lid; + ntc->data_details.ntc_144.local_changes = local ? + TRAP_144_MASK_OTHER_LOCAL_CHANGES : 0; + ntc->data_details.ntc_144.new_cap_mask = pi->capability_mask; + ntc->data_details.ntc_144.change_flgs = local; + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Sending Trap 144, TID 0x%" PRIx64 " to SM lid %u\n", + cl_ntoh64(smp->trans_id), cl_ntoh16(pi->master_sm_base_lid)); + + osm_vl15_post(sm->p_vl15, madw); + + return 0; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_resp.c b/contrib/ofed/management/opensm/opensm/osm_resp.c new file mode 100644 index 000000000000..9cd44f5e7a96 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_resp.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_resp_t. + * This object represents the generic attribute responder. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +static void +osm_resp_make_resp_smp(IN osm_sm_t * sm, + IN const ib_smp_t * const p_src_smp, + IN const ib_net16_t status, + IN const uint8_t * const p_payload, + OUT ib_smp_t * const p_dest_smp) +{ + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_dest_smp); + CL_ASSERT(p_src_smp); + CL_ASSERT(!ib_smp_is_response(p_src_smp)); + + *p_dest_smp = *p_src_smp; + if (p_src_smp->method == IB_MAD_METHOD_GET || + p_src_smp->method == IB_MAD_METHOD_SET) { + p_dest_smp->method = IB_MAD_METHOD_GET_RESP; + p_dest_smp->status = status; + } else if (p_src_smp->method == IB_MAD_METHOD_TRAP) { + p_dest_smp->method = IB_MAD_METHOD_TRAP_REPRESS; + p_dest_smp->status = 0; + } else { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 1302: " + "src smp method unsupported 0x%X\n", p_src_smp->method); + goto Exit; + } + + if (p_src_smp->mgmt_class == IB_MCLASS_SUBN_DIR) + p_dest_smp->status |= IB_SMP_DIRECTION; + + p_dest_smp->dr_dlid = p_dest_smp->dr_slid; + p_dest_smp->dr_slid = p_dest_smp->dr_dlid; + memcpy(&p_dest_smp->data, p_payload, IB_SMP_DATA_SIZE); + +Exit: + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_resp_send(IN osm_sm_t * sm, + IN const osm_madw_t * const p_req_madw, + IN const ib_net16_t mad_status, + IN const uint8_t * const p_payload) +{ + const ib_smp_t *p_req_smp; + ib_smp_t *p_smp; + osm_madw_t *p_madw; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_req_madw); + CL_ASSERT(p_payload); + + /* do nothing if we are exiting ... */ + if (osm_exit_flag) + goto Exit; + + p_madw = osm_mad_pool_get(sm->p_mad_pool, + osm_madw_get_bind_handle(p_req_madw), + MAD_BLOCK_SIZE, NULL); + + if (p_madw == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 1301: Unable to acquire MAD\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + /* + Copy the request smp to the response smp, then just + update the necessary fields. + */ + p_smp = osm_madw_get_smp_ptr(p_madw); + p_req_smp = osm_madw_get_smp_ptr(p_req_madw); + osm_resp_make_resp_smp(sm, p_req_smp, mad_status, p_payload, p_smp); + p_madw->mad_addr.dest_lid = + p_req_madw->mad_addr.addr_type.smi.source_lid; + p_madw->mad_addr.addr_type.smi.source_lid = + p_req_madw->mad_addr.dest_lid; + + p_madw->resp_expected = FALSE; + p_madw->fail_msg = CL_DISP_MSGID_NONE; + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "Responding to %s (0x%X)" + "\n\t\t\t\tattribute modifier 0x%X, TID 0x%" PRIx64 "\n", + ib_get_sm_attr_str(p_smp->attr_id), cl_ntoh16(p_smp->attr_id), + cl_ntoh32(p_smp->attr_mod), cl_ntoh64(p_smp->trans_id)); + + osm_vl15_post(sm->p_vl15, p_madw); + +Exit: + OSM_LOG_EXIT(sm->p_log); + return (status); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_router.c b/contrib/ofed/management/opensm/opensm/osm_router.c new file mode 100644 index 000000000000..cb5a23681d16 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_router.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_router_t. + * This object represents an Infiniband router. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void osm_router_delete(IN OUT osm_router_t ** const pp_rtr) +{ + free(*pp_rtr); + *pp_rtr = NULL; +} + +/********************************************************************** + **********************************************************************/ +osm_router_t *osm_router_new(IN osm_port_t * const p_port) +{ + osm_router_t *p_rtr; + + CL_ASSERT(p_port); + + p_rtr = (osm_router_t *) malloc(sizeof(*p_rtr)); + if (p_rtr) { + memset(p_rtr, 0, sizeof(*p_rtr)); + p_rtr->p_port = p_port; + } + + return (p_rtr); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa.c b/contrib/ofed/management/opensm/opensm/osm_sa.c new file mode 100644 index 000000000000..185557fa44fb --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa.c @@ -0,0 +1,1123 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sa_t. + * This object represents the Subnet Administration object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_SA_INITIAL_TID_VALUE 0xabc + +extern void osm_cpi_rcv_process(IN void *context, IN void *data); +extern void osm_gir_rcv_process(IN void *context, IN void *data); +extern void osm_infr_rcv_process(IN void *context, IN void *data); +extern void osm_infir_rcv_process(IN void *context, IN void *data); +extern void osm_lftr_rcv_process(IN void *context, IN void *data); +extern void osm_lr_rcv_process(IN void *context, IN void *data); +extern void osm_mcmr_rcv_process(IN void *context, IN void *data); +extern void osm_mftr_rcv_process(IN void *context, IN void *data); +extern void osm_mpr_rcv_process(IN void *context, IN void *data); +extern void osm_nr_rcv_process(IN void *context, IN void *data); +extern void osm_pr_rcv_process(IN void *context, IN void *data); +extern void osm_pkey_rec_rcv_process(IN void *context, IN void *data); +extern void osm_pir_rcv_process(IN void *context, IN void *data); +extern void osm_sr_rcv_process(IN void *context, IN void *data); +extern void osm_slvl_rec_rcv_process(IN void *context, IN void *data); +extern void osm_smir_rcv_process(IN void *context, IN void *data); +extern void osm_sir_rcv_process(IN void *context, IN void *data); +extern void osm_vlarb_rec_rcv_process(IN void *context, IN void *data); +extern void osm_sr_rcv_lease_cb(IN void *context); + +/********************************************************************** + **********************************************************************/ +void osm_sa_construct(IN osm_sa_t * const p_sa) +{ + memset(p_sa, 0, sizeof(*p_sa)); + p_sa->state = OSM_SA_STATE_INIT; + p_sa->sa_trans_id = OSM_SA_INITIAL_TID_VALUE; + + cl_timer_construct(&p_sa->sr_timer); +} + +/********************************************************************** + **********************************************************************/ +void osm_sa_shutdown(IN osm_sa_t * const p_sa) +{ + ib_api_status_t status; + OSM_LOG_ENTER(p_sa->p_log); + + cl_timer_stop(&p_sa->sr_timer); + + /* unbind from the mad service */ + status = osm_sa_mad_ctrl_unbind(&p_sa->mad_ctrl); + + /* remove any registered dispatcher message */ + cl_disp_unregister(p_sa->nr_disp_h); + cl_disp_unregister(p_sa->pir_disp_h); + cl_disp_unregister(p_sa->gir_disp_h); + cl_disp_unregister(p_sa->lr_disp_h); + cl_disp_unregister(p_sa->pr_disp_h); +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + cl_disp_unregister(p_sa->mpr_disp_h); +#endif + cl_disp_unregister(p_sa->smir_disp_h); + cl_disp_unregister(p_sa->mcmr_disp_h); + cl_disp_unregister(p_sa->sr_disp_h); + cl_disp_unregister(p_sa->infr_disp_h); + cl_disp_unregister(p_sa->infir_disp_h); + cl_disp_unregister(p_sa->vlarb_disp_h); + cl_disp_unregister(p_sa->slvl_disp_h); + cl_disp_unregister(p_sa->pkey_disp_h); + cl_disp_unregister(p_sa->lft_disp_h); + cl_disp_unregister(p_sa->sir_disp_h); + cl_disp_unregister(p_sa->mft_disp_h); + osm_sa_mad_ctrl_destroy(&p_sa->mad_ctrl); + + OSM_LOG_EXIT(p_sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_sa_destroy(IN osm_sa_t * const p_sa) +{ + OSM_LOG_ENTER(p_sa->p_log); + + p_sa->state = OSM_SA_STATE_INIT; + + cl_timer_destroy(&p_sa->sr_timer); + + OSM_LOG_EXIT(p_sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sa_init(IN osm_sm_t * const p_sm, + IN osm_sa_t * const p_sa, + IN osm_subn_t * const p_subn, + IN osm_vendor_t * const p_vendor, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_log_t * const p_log, + IN osm_stats_t * const p_stats, + IN cl_dispatcher_t * const p_disp, IN cl_plock_t * const p_lock) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + p_sa->sm = p_sm; + p_sa->p_subn = p_subn; + p_sa->p_vendor = p_vendor; + p_sa->p_mad_pool = p_mad_pool; + p_sa->p_log = p_log; + p_sa->p_disp = p_disp; + p_sa->p_lock = p_lock; + + p_sa->state = OSM_SA_STATE_READY; + + status = osm_sa_mad_ctrl_init(&p_sa->mad_ctrl, + p_sa, + p_sa->p_mad_pool, + p_sa->p_vendor, + p_subn, p_log, p_stats, p_disp); + if (status != IB_SUCCESS) + goto Exit; + + status = cl_timer_init(&p_sa->sr_timer, osm_sr_rcv_lease_cb, p_sa); + if (status != IB_SUCCESS) + goto Exit; + + p_sa->cpi_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_CLASS_PORT_INFO, + osm_cpi_rcv_process, p_sa); + if (p_sa->cpi_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->nr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NODE_RECORD, + osm_nr_rcv_process, p_sa); + if (p_sa->nr_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->pir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PORTINFO_RECORD, + osm_pir_rcv_process, p_sa); + if (p_sa->pir_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->gir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_GUIDINFO_RECORD, + osm_gir_rcv_process, p_sa); + if (p_sa->gir_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->lr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LINK_RECORD, + osm_lr_rcv_process, p_sa); + if (p_sa->lr_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->pr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PATH_RECORD, + osm_pr_rcv_process, p_sa); + if (p_sa->pr_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + p_sa->mpr_disp_h = + cl_disp_register(p_disp, OSM_MSG_MAD_MULTIPATH_RECORD, + osm_mpr_rcv_process, p_sa); + if (p_sa->mpr_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; +#endif + + p_sa->smir_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SMINFO_RECORD, + osm_smir_rcv_process, p_sa); + if (p_sa->smir_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->mcmr_disp_h = + cl_disp_register(p_disp, OSM_MSG_MAD_MCMEMBER_RECORD, + osm_mcmr_rcv_process, p_sa); + if (p_sa->mcmr_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->sr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SERVICE_RECORD, + osm_sr_rcv_process, p_sa); + if (p_sa->sr_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->infr_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_INFORM_INFO, + osm_infr_rcv_process, p_sa); + if (p_sa->infr_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->infir_disp_h = + cl_disp_register(p_disp, OSM_MSG_MAD_INFORM_INFO_RECORD, + osm_infir_rcv_process, p_sa); + if (p_sa->infir_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->vlarb_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_VL_ARB_RECORD, + osm_vlarb_rec_rcv_process, p_sa); + if (p_sa->vlarb_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->slvl_disp_h = + cl_disp_register(p_disp, OSM_MSG_MAD_SLVL_TBL_RECORD, + osm_slvl_rec_rcv_process, p_sa); + if (p_sa->slvl_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->pkey_disp_h = + cl_disp_register(p_disp, OSM_MSG_MAD_PKEY_TBL_RECORD, + osm_pkey_rec_rcv_process, p_sa); + if (p_sa->pkey_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->lft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LFT_RECORD, + osm_lftr_rcv_process, p_sa); + if (p_sa->lft_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->sir_disp_h = + cl_disp_register(p_disp, OSM_MSG_MAD_SWITCH_INFO_RECORD, + osm_sir_rcv_process, p_sa); + if (p_sa->sir_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sa->mft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_MFT_RECORD, + osm_mftr_rcv_process, p_sa); + if (p_sa->mft_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + +Exit: + OSM_LOG_EXIT(p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sa_bind(IN osm_sa_t * const p_sa, IN const ib_net64_t port_guid) +{ + ib_api_status_t status; + + OSM_LOG_ENTER(p_sa->p_log); + + status = osm_sa_mad_ctrl_bind(&p_sa->mad_ctrl, port_guid); + + if (status != IB_SUCCESS) { + OSM_LOG(p_sa->p_log, OSM_LOG_ERROR, "ERR 4C03: " + "SA MAD Controller bind failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_sa->p_log); + return (status); +} + +ib_api_status_t osm_sa_send(osm_sa_t *sa, + IN osm_madw_t * const p_madw, + IN boolean_t const resp_expected) +{ + ib_api_status_t status; + + cl_atomic_inc(&sa->p_subn->p_osm->stats.sa_mads_sent); + status = osm_vendor_send(p_madw->h_bind, p_madw, resp_expected); + if (status != IB_SUCCESS) { + cl_atomic_dec(&sa->p_subn->p_osm->stats.sa_mads_sent); + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C04: " + "osm_vendor_send failed, status = %s\n", + ib_get_err_str(status)); + } + return status; +} + +void +osm_sa_send_error(IN osm_sa_t * sa, + IN const osm_madw_t * const p_madw, + IN const ib_net16_t sa_status) +{ + osm_madw_t *p_resp_madw; + ib_sa_mad_t *p_resp_sa_mad; + ib_sa_mad_t *p_sa_mad; + + OSM_LOG_ENTER(sa->p_log); + + /* avoid races - if we are exiting - exit */ + if (osm_exit_flag) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Ignoring requested send after exit\n"); + goto Exit; + } + + p_resp_madw = osm_mad_pool_get(sa->p_mad_pool, + p_madw->h_bind, MAD_BLOCK_SIZE, + &p_madw->mad_addr); + + if (p_resp_madw == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C07: " + "Unable to acquire response MAD\n"); + goto Exit; + } + + p_resp_sa_mad = osm_madw_get_sa_mad_ptr(p_resp_madw); + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + + /* Copy the MAD header back into the response mad */ + *p_resp_sa_mad = *p_sa_mad; + p_resp_sa_mad->status = sa_status; + + if (p_resp_sa_mad->method == IB_MAD_METHOD_SET) + p_resp_sa_mad->method = IB_MAD_METHOD_GET; + else if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE) + p_resp_sa_mad->attr_offset = 0; + + p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK; + + /* + * C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) + */ + p_resp_sa_mad->sm_key = 0; + + /* + * o15-0.2.7 - The PathRecord Attribute ID shall be used in + * the response (to a SubnAdmGetMulti(MultiPathRecord) + */ + if (p_resp_sa_mad->attr_id == IB_MAD_ATTR_MULTIPATH_RECORD) + p_resp_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD; + + if (osm_log_is_active(sa->p_log, OSM_LOG_FRAMES)) + osm_dump_sa_mad(sa->p_log, p_resp_sa_mad, OSM_LOG_FRAMES); + + osm_sa_send(sa, p_resp_madw, FALSE); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +void osm_sa_respond(osm_sa_t *sa, osm_madw_t *madw, size_t attr_size, + cl_qlist_t *list) +{ + struct item_data { + cl_list_item_t list; + char data[0]; + }; + cl_list_item_t *item; + osm_madw_t *resp_madw; + ib_sa_mad_t *sa_mad, *resp_sa_mad; + unsigned num_rec, i; +#ifndef VENDOR_RMPP_SUPPORT + unsigned trim_num_rec; +#endif + void *p; + + sa_mad = osm_madw_get_sa_mad_ptr(madw); + num_rec = cl_qlist_count(list); + + /* + * C15-0.1.30: + * If we do a SubnAdmGet and got more than one record it is an error! + */ + if (sa_mad->method == IB_MAD_METHOD_GET && num_rec > 1) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C05: " + "Got more than one record for SubnAdmGet (%u)\n", + num_rec); + osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_TOO_MANY_RECORDS); + goto Exit; + } + +#ifndef VENDOR_RMPP_SUPPORT + trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / attr_size; + if (trim_num_rec < num_rec) { + OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, + "Number of records:%u trimmed to:%u to fit in one MAD\n", + num_rec, trim_num_rec); + num_rec = trim_num_rec; + } +#endif + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Returning %u records\n", num_rec); + + if (sa_mad->method == IB_MAD_METHOD_GET && num_rec == 0) { + osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_NO_RECORDS); + goto Exit; + } + + /* + * Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + resp_madw = osm_mad_pool_get(sa->p_mad_pool, madw->h_bind, + num_rec * attr_size + IB_SA_MAD_HDR_SIZE, + &madw->mad_addr); + if (!resp_madw) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4C06: " + "osm_mad_pool_get failed\n"); + osm_sa_send_error(sa, madw, IB_SA_MAD_STATUS_NO_RESOURCES); + goto Exit; + } + + resp_sa_mad = osm_madw_get_sa_mad_ptr(resp_madw); + + /* + Copy the MAD header back into the response mad. + Set the 'R' bit and the payload length, + Then copy all records from the list into the response payload. + */ + + memcpy(resp_sa_mad, sa_mad, IB_SA_MAD_HDR_SIZE); + if (resp_sa_mad->method == IB_MAD_METHOD_SET) + resp_sa_mad->method = IB_MAD_METHOD_GET; + resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK; + /* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */ + resp_sa_mad->sm_key = 0; + + /* Fill in the offset (paylen will be done by the rmpp SAR) */ + resp_sa_mad->attr_offset = num_rec ? ib_get_attr_offset(attr_size) : 0; + + p = ib_sa_mad_get_payload_ptr(resp_sa_mad); + +#ifndef VENDOR_RMPP_SUPPORT + /* we support only one packet RMPP - so we will set the first and + last flags for gettable */ + if (resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) { + resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA; + resp_sa_mad->rmpp_flags = + IB_RMPP_FLAG_FIRST | IB_RMPP_FLAG_LAST | + IB_RMPP_FLAG_ACTIVE; + } +#else + /* forcefully define the packet as RMPP one */ + if (resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP) + resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE; +#endif + + for (i = 0; i < num_rec; i++) { + item = cl_qlist_remove_head(list); + memcpy(p, ((struct item_data *)item)->data, attr_size); + p += attr_size; + free(item); + } + + osm_sa_send(sa, resp_madw, FALSE); + + osm_dump_sa_mad(sa->p_log, resp_sa_mad, OSM_LOG_FRAMES); +Exit: + /* need to set the mem free ... */ + item = cl_qlist_remove_head(list); + while (item != cl_qlist_end(list)) { + free(item); + item = cl_qlist_remove_head(list); + } +} + +/********************************************************************** + **********************************************************************/ +/* + * SA DB Dumper + * + */ + +struct opensm_dump_context { + osm_opensm_t *p_osm; + FILE *file; +}; + +static int +opensm_dump_to_file(osm_opensm_t * p_osm, const char *file_name, + void (*dump_func) (osm_opensm_t * p_osm, FILE * file)) +{ + char path[1024]; + FILE *file; + + snprintf(path, sizeof(path), "%s/%s", + p_osm->subn.opt.dump_files_dir, file_name); + + file = fopen(path, "w"); + if (!file) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR 4C01: " + "cannot open file \'%s\': %s\n", + file_name, strerror(errno)); + return -1; + } + + chmod(path, S_IRUSR | S_IWUSR); + + dump_func(p_osm, file); + + fclose(file); + return 0; +} + +static void mcast_mgr_dump_one_port(cl_map_item_t * p_map_item, void *cxt) +{ + FILE *file = ((struct opensm_dump_context *)cxt)->file; + osm_mcm_port_t *p_mcm_port = (osm_mcm_port_t *) p_map_item; + + fprintf(file, "mcm_port: " + "port_gid=0x%016" PRIx64 ":0x%016" PRIx64 " " + "scope_state=0x%02x proxy_join=0x%x" "\n\n", + cl_ntoh64(p_mcm_port->port_gid.unicast.prefix), + cl_ntoh64(p_mcm_port->port_gid.unicast.interface_id), + p_mcm_port->scope_state, p_mcm_port->proxy_join); +} + +static void sa_dump_one_mgrp(osm_mgrp_t *p_mgrp, void *cxt) +{ + struct opensm_dump_context dump_context; + osm_opensm_t *p_osm = ((struct opensm_dump_context *)cxt)->p_osm; + FILE *file = ((struct opensm_dump_context *)cxt)->file; + + fprintf(file, "MC Group 0x%04x %s:" + " mgid=0x%016" PRIx64 ":0x%016" PRIx64 + " port_gid=0x%016" PRIx64 ":0x%016" PRIx64 + " qkey=0x%08x mlid=0x%04x mtu=0x%02x tclass=0x%02x" + " pkey=0x%04x rate=0x%02x pkt_life=0x%02x sl_flow_hop=0x%08x" + " scope_state=0x%02x proxy_join=0x%x" "\n\n", + cl_ntoh16(p_mgrp->mlid), + p_mgrp->well_known ? " (well known)" : "", + cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.prefix), + cl_ntoh64(p_mgrp->mcmember_rec.mgid.unicast.interface_id), + cl_ntoh64(p_mgrp->mcmember_rec.port_gid.unicast.prefix), + cl_ntoh64(p_mgrp->mcmember_rec.port_gid.unicast.interface_id), + cl_ntoh32(p_mgrp->mcmember_rec.qkey), + cl_ntoh16(p_mgrp->mcmember_rec.mlid), + p_mgrp->mcmember_rec.mtu, + p_mgrp->mcmember_rec.tclass, + cl_ntoh16(p_mgrp->mcmember_rec.pkey), + p_mgrp->mcmember_rec.rate, + p_mgrp->mcmember_rec.pkt_life, + cl_ntoh32(p_mgrp->mcmember_rec.sl_flow_hop), + p_mgrp->mcmember_rec.scope_state, + p_mgrp->mcmember_rec.proxy_join); + + dump_context.p_osm = p_osm; + dump_context.file = file; + + cl_qmap_apply_func(&p_mgrp->mcm_port_tbl, + mcast_mgr_dump_one_port, &dump_context); +} + +static void sa_dump_one_inform(cl_list_item_t * p_list_item, void *cxt) +{ + FILE *file = ((struct opensm_dump_context *)cxt)->file; + osm_infr_t *p_infr = (osm_infr_t *) p_list_item; + ib_inform_info_record_t *p_iir = &p_infr->inform_record; + + fprintf(file, "InformInfo Record:" + " subscriber_gid=0x%016" PRIx64 ":0x%016" PRIx64 + " subscriber_enum=0x%x" + " InformInfo:" + " gid=0x%016" PRIx64 ":0x%016" PRIx64 + " lid_range_begin=0x%x" + " lid_range_end=0x%x" + " is_generic=0x%x" + " subscribe=0x%x" + " trap_type=0x%x" + " trap_num=0x%x" + " qpn_resp_time_val=0x%x" + " node_type=0x%06x" + " rep_addr: lid=0x%04x path_bits=0x%02x static_rate=0x%02x" + " remote_qp=0x%08x remote_qkey=0x%08x pkey_ix=0x%04x sl=0x%02x" + "\n\n", + cl_ntoh64(p_iir->subscriber_gid.unicast.prefix), + cl_ntoh64(p_iir->subscriber_gid.unicast.interface_id), + cl_ntoh16(p_iir->subscriber_enum), + cl_ntoh64(p_iir->inform_info.gid.unicast.prefix), + cl_ntoh64(p_iir->inform_info.gid.unicast.interface_id), + cl_ntoh16(p_iir->inform_info.lid_range_begin), + cl_ntoh16(p_iir->inform_info.lid_range_end), + p_iir->inform_info.is_generic, + p_iir->inform_info.subscribe, + cl_ntoh16(p_iir->inform_info.trap_type), + cl_ntoh16(p_iir->inform_info.g_or_v.generic.trap_num), + cl_ntoh32(p_iir->inform_info.g_or_v.generic.qpn_resp_time_val), + cl_ntoh32(ib_inform_info_get_prod_type(&p_iir->inform_info)), + cl_ntoh16(p_infr->report_addr.dest_lid), + p_infr->report_addr.path_bits, + p_infr->report_addr.static_rate, + cl_ntoh32(p_infr->report_addr.addr_type.gsi.remote_qp), + cl_ntoh32(p_infr->report_addr.addr_type.gsi.remote_qkey), + p_infr->report_addr.addr_type.gsi.pkey_ix, + p_infr->report_addr.addr_type.gsi.service_level); +} + +static void sa_dump_one_service(cl_list_item_t * p_list_item, void *cxt) +{ + FILE *file = ((struct opensm_dump_context *)cxt)->file; + osm_svcr_t *p_svcr = (osm_svcr_t *) p_list_item; + ib_service_record_t *p_sr = &p_svcr->service_record; + + fprintf(file, "Service Record: id=0x%016" PRIx64 + " gid=0x%016" PRIx64 ":0x%016" PRIx64 + " pkey=0x%x" + " lease=0x%x" + " key=0x%02x%02x%02x%02x%02x%02x%02x%02x" + ":0x%02x%02x%02x%02x%02x%02x%02x%02x" + " name=\'%s\'" + " data8=0x%02x%02x%02x%02x%02x%02x%02x%02x" + ":0x%02x%02x%02x%02x%02x%02x%02x%02x" + " data16=0x%04x%04x%04x%04x:0x%04x%04x%04x%04x" + " data32=0x%08x%08x:0x%08x%08x" + " data64=0x%016" PRIx64 ":0x%016" PRIx64 + " modified_time=0x%x lease_period=0x%x\n\n", + cl_ntoh64(p_sr->service_id), + cl_ntoh64(p_sr->service_gid.unicast.prefix), + cl_ntoh64(p_sr->service_gid.unicast.interface_id), + cl_ntoh16(p_sr->service_pkey), + cl_ntoh32(p_sr->service_lease), + p_sr->service_key[0], p_sr->service_key[1], + p_sr->service_key[2], p_sr->service_key[3], + p_sr->service_key[4], p_sr->service_key[5], + p_sr->service_key[6], p_sr->service_key[7], + p_sr->service_key[8], p_sr->service_key[9], + p_sr->service_key[10], p_sr->service_key[11], + p_sr->service_key[12], p_sr->service_key[13], + p_sr->service_key[14], p_sr->service_key[15], + p_sr->service_name, + p_sr->service_data8[0], p_sr->service_data8[1], + p_sr->service_data8[2], p_sr->service_data8[3], + p_sr->service_data8[4], p_sr->service_data8[5], + p_sr->service_data8[6], p_sr->service_data8[7], + p_sr->service_data8[8], p_sr->service_data8[9], + p_sr->service_data8[10], p_sr->service_data8[11], + p_sr->service_data8[12], p_sr->service_data8[13], + p_sr->service_data8[14], p_sr->service_data8[15], + cl_ntoh16(p_sr->service_data16[0]), + cl_ntoh16(p_sr->service_data16[1]), + cl_ntoh16(p_sr->service_data16[2]), + cl_ntoh16(p_sr->service_data16[3]), + cl_ntoh16(p_sr->service_data16[4]), + cl_ntoh16(p_sr->service_data16[5]), + cl_ntoh16(p_sr->service_data16[6]), + cl_ntoh16(p_sr->service_data16[7]), + cl_ntoh32(p_sr->service_data32[0]), + cl_ntoh32(p_sr->service_data32[1]), + cl_ntoh32(p_sr->service_data32[2]), + cl_ntoh32(p_sr->service_data32[3]), + cl_ntoh64(p_sr->service_data64[0]), + cl_ntoh64(p_sr->service_data64[1]), + p_svcr->modified_time, p_svcr->lease_period); +} + +static void sa_dump_all_sa(osm_opensm_t * p_osm, FILE * file) +{ + struct opensm_dump_context dump_context; + osm_mgrp_t *p_mgrp; + int i; + + dump_context.p_osm = p_osm; + dump_context.file = file; + OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump multicast:\n"); + cl_plock_acquire(&p_osm->lock); + for (i = 0; i <= p_osm->subn.max_mcast_lid_ho - IB_LID_MCAST_START_HO; + i++) { + p_mgrp = p_osm->subn.mgroups[i]; + if (p_mgrp) + sa_dump_one_mgrp(p_mgrp, &dump_context); + } + OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump inform:\n"); + cl_qlist_apply_func(&p_osm->subn.sa_infr_list, + sa_dump_one_inform, &dump_context); + OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "Dump services:\n"); + cl_qlist_apply_func(&p_osm->subn.sa_sr_list, + sa_dump_one_service, &dump_context); + cl_plock_release(&p_osm->lock); +} + +int osm_sa_db_file_dump(osm_opensm_t * p_osm) +{ + return opensm_dump_to_file(p_osm, "opensm-sa.dump", sa_dump_all_sa); +} + +/* + * SA DB Loader + */ +static osm_mgrp_t *load_mcgroup(osm_opensm_t * p_osm, ib_net16_t mlid, + ib_member_rec_t * p_mcm_rec, + unsigned well_known) +{ + ib_net64_t comp_mask; + osm_mgrp_t *p_mgrp; + + cl_plock_excl_acquire(&p_osm->lock); + + p_mgrp = osm_get_mgrp_by_mlid(&p_osm->subn, mlid); + if (p_mgrp) { + if (!memcmp(&p_mgrp->mcmember_rec.mgid, &p_mcm_rec->mgid, + sizeof(ib_gid_t))) { + OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, + "mgrp %04x is already here.", cl_ntoh16(mlid)); + goto _out; + } + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "mlid %04x is already used by another MC group. Will " + "request clients reregistration.\n", cl_ntoh16(mlid)); + p_mgrp = NULL; + goto _out; + } + + comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_MTU_SEL + | IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_RATE_SEL; + if (osm_mcmr_rcv_find_or_create_new_mgrp(&p_osm->sa, + comp_mask, p_mcm_rec, + &p_mgrp) != IB_SUCCESS || + !p_mgrp || p_mgrp->mlid != mlid) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, + "cannot create MC group with mlid 0x%04x and mgid " + "0x%016" PRIx64 ":0x%016" PRIx64 "\n", cl_ntoh16(mlid), + cl_ntoh64(p_mcm_rec->mgid.unicast.prefix), + cl_ntoh64(p_mcm_rec->mgid.unicast.interface_id)); + p_mgrp = NULL; + } else if (well_known) + p_mgrp->well_known = TRUE; + +_out: + cl_plock_release(&p_osm->lock); + + return p_mgrp; +} + +static int load_svcr(osm_opensm_t * p_osm, ib_service_record_t * sr, + uint32_t modified_time, uint32_t lease_period) +{ + osm_svcr_t *p_svcr; + int ret = 0; + + cl_plock_excl_acquire(&p_osm->lock); + + if (osm_svcr_get_by_rid(&p_osm->subn, &p_osm->log, sr)) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "ServiceRecord already exists\n"); + goto _out; + } + + if (!(p_svcr = osm_svcr_new(sr))) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, + "cannot allocate new service struct\n"); + ret = -1; + goto _out; + } + + p_svcr->modified_time = modified_time; + p_svcr->lease_period = lease_period; + + OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "adding ServiceRecord...\n"); + + osm_svcr_insert_to_db(&p_osm->subn, &p_osm->log, p_svcr); + + if (lease_period != 0xffffffff) + cl_timer_trim(&p_osm->sa.sr_timer, 1000); + +_out: + cl_plock_release(&p_osm->lock); + + return ret; +} + +static int load_infr(osm_opensm_t * p_osm, ib_inform_info_record_t * iir, + osm_mad_addr_t * addr) +{ + osm_infr_t infr, *p_infr; + int ret = 0; + + infr.h_bind = p_osm->sa.mad_ctrl.h_bind; + infr.sa = &p_osm->sa; + /* other possible way to restore mad_addr partially is + to extract qpn from InformInfo and to find lid by gid */ + infr.report_addr = *addr; + infr.inform_record = *iir; + + cl_plock_excl_acquire(&p_osm->lock); + if (osm_infr_get_by_rec(&p_osm->subn, &p_osm->log, &infr)) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "InformInfo Record already exists\n"); + goto _out; + } + + if (!(p_infr = osm_infr_new(&infr))) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, + "cannot allocate new infr struct\n"); + ret = -1; + goto _out; + } + + OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, "adding InformInfo Record...\n"); + + osm_infr_insert_to_db(&p_osm->subn, &p_osm->log, p_infr); + +_out: + cl_plock_release(&p_osm->lock); + + return ret; +} + +#define UNPACK_FUNC(name,x) \ +static int unpack_##name##x(char *p, uint##x##_t *val_ptr) \ +{ \ + char *q; \ + unsigned long long num; \ + num = strtoull(p, &q, 16); \ + if (num > ~((uint##x##_t)0x0) \ + || q == p || (!isspace(*q) && *q != ':')) { \ + *val_ptr = 0; \ + return -1; \ + } \ + *val_ptr = cl_hton##x((uint##x##_t)num); \ + return (int)(q - p); \ +} + +#define cl_hton8(x) (x) + +UNPACK_FUNC(net, 8); +UNPACK_FUNC(net, 16); +UNPACK_FUNC(net, 32); +UNPACK_FUNC(net, 64); + +static int unpack_string(char *p, uint8_t * buf, unsigned len) +{ + char *q = p; + char delim = ' '; + + if (*q == '\'' || *q == '\"') + delim = *q++; + while (--len && *q && *q != delim) + *buf++ = *q++; + *buf = '\0'; + if (*q == delim && delim != ' ') + q++; + return (int)(q - p); +} + +static int unpack_string64(char *p, uint8_t * buf) +{ + return unpack_string(p, buf, 64); +} + +#define PARSE_AHEAD(p, x, name, val_ptr) { int _ret; \ + p = strstr(p, name); \ + if (!p) { \ + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, \ + "PARSE ERROR: %s:%u: cannot find \"%s\" string\n", \ + file_name, lineno, (name)); \ + ret = -2; \ + goto _error; \ + } \ + p += strlen(name); \ + _ret = unpack_##x(p, (val_ptr)); \ + if (_ret < 0) { \ + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, \ + "PARSE ERROR: %s:%u: cannot parse "#x" value " \ + "after \"%s\"\n", file_name, lineno, (name)); \ + ret = _ret; \ + goto _error; \ + } \ + p += _ret; \ +} + +int osm_sa_db_file_load(osm_opensm_t * p_osm) +{ + char line[1024]; + char *file_name; + FILE *file; + int ret = 0; + osm_mgrp_t *p_mgrp = NULL; + unsigned rereg_clients = 0; + unsigned lineno; + + file_name = p_osm->subn.opt.sa_db_file; + if (!file_name) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "sa db file name is not specifed. Skip restore\n"); + return 0; + } + + file = fopen(file_name, "r"); + if (!file) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 4C02: " + "cannot open sa db file \'%s\'. Skip restoring\n", + file_name); + return -1; + } + + lineno = 0; + + while (fgets(line, sizeof(line) - 1, file) != NULL) { + char *p; + uint8_t val; + + lineno++; + + p = line; + while (isspace(*p)) + p++; + + if (*p == '#') + continue; + + if (!strncmp(p, "MC Group", 8)) { + ib_member_rec_t mcm_rec; + ib_net16_t mlid; + unsigned well_known = 0; + + p_mgrp = NULL; + memset(&mcm_rec, 0, sizeof(mcm_rec)); + + PARSE_AHEAD(p, net16, " 0x", &mlid); + if (strstr(p, "well known")) + well_known = 1; + PARSE_AHEAD(p, net64, " mgid=0x", + &mcm_rec.mgid.unicast.prefix); + PARSE_AHEAD(p, net64, ":0x", + &mcm_rec.mgid.unicast.interface_id); + PARSE_AHEAD(p, net64, " port_gid=0x", + &mcm_rec.port_gid.unicast.prefix); + PARSE_AHEAD(p, net64, ":0x", + &mcm_rec.port_gid.unicast.interface_id); + PARSE_AHEAD(p, net32, " qkey=0x", &mcm_rec.qkey); + PARSE_AHEAD(p, net16, " mlid=0x", &mcm_rec.mlid); + PARSE_AHEAD(p, net8, " mtu=0x", &mcm_rec.mtu); + PARSE_AHEAD(p, net8, " tclass=0x", &mcm_rec.tclass); + PARSE_AHEAD(p, net16, " pkey=0x", &mcm_rec.pkey); + PARSE_AHEAD(p, net8, " rate=0x", &mcm_rec.rate); + PARSE_AHEAD(p, net8, " pkt_life=0x", &mcm_rec.pkt_life); + PARSE_AHEAD(p, net32, " sl_flow_hop=0x", + &mcm_rec.sl_flow_hop); + PARSE_AHEAD(p, net8, " scope_state=0x", + &mcm_rec.scope_state); + PARSE_AHEAD(p, net8, " proxy_join=0x", &val); + mcm_rec.proxy_join = val; + + p_mgrp = load_mcgroup(p_osm, mlid, &mcm_rec, + well_known); + if (!p_mgrp) + rereg_clients = 1; + } else if (p_mgrp && !strncmp(p, "mcm_port", 8)) { + ib_gid_t port_gid; + ib_net64_t guid; + uint8_t scope_state; + boolean_t proxy_join; + + PARSE_AHEAD(p, net64, " port_gid=0x", + &port_gid.unicast.prefix); + PARSE_AHEAD(p, net64, ":0x", + &port_gid.unicast.interface_id); + PARSE_AHEAD(p, net8, " scope_state=0x", &scope_state); + PARSE_AHEAD(p, net8, " proxy_join=0x", &val); + proxy_join = val; + + guid = port_gid.unicast.interface_id; + if (cl_qmap_get(&p_mgrp->mcm_port_tbl, + port_gid.unicast.interface_id) == + cl_qmap_end(&p_mgrp->mcm_port_tbl)) + osm_mgrp_add_port(&p_osm->subn, &p_osm->log, + p_mgrp, &port_gid, + scope_state, proxy_join); + } else if (!strncmp(p, "Service Record:", 15)) { + ib_service_record_t s_rec; + uint32_t modified_time, lease_period; + + p_mgrp = NULL; + memset(&s_rec, 0, sizeof(s_rec)); + + PARSE_AHEAD(p, net64, " id=0x", &s_rec.service_id); + PARSE_AHEAD(p, net64, " gid=0x", + &s_rec.service_gid.unicast.prefix); + PARSE_AHEAD(p, net64, ":0x", + &s_rec.service_gid.unicast.interface_id); + PARSE_AHEAD(p, net16, " pkey=0x", &s_rec.service_pkey); + PARSE_AHEAD(p, net32, " lease=0x", + &s_rec.service_lease); + PARSE_AHEAD(p, net64, " key=0x", + (ib_net64_t *) (&s_rec.service_key[0])); + PARSE_AHEAD(p, net64, ":0x", + (ib_net64_t *) (&s_rec.service_key[8])); + PARSE_AHEAD(p, string64, " name=", s_rec.service_name); + PARSE_AHEAD(p, net64, " data8=0x", + (ib_net64_t *) (&s_rec.service_data8[0])); + PARSE_AHEAD(p, net64, ":0x", + (ib_net64_t *) (&s_rec.service_data8[8])); + PARSE_AHEAD(p, net64, " data16=0x", + (ib_net64_t *) (&s_rec.service_data16[0])); + PARSE_AHEAD(p, net64, ":0x", + (ib_net64_t *) (&s_rec.service_data16[4])); + PARSE_AHEAD(p, net64, " data32=0x", + (ib_net64_t *) (&s_rec.service_data32[0])); + PARSE_AHEAD(p, net64, ":0x", + (ib_net64_t *) (&s_rec.service_data32[2])); + PARSE_AHEAD(p, net64, " data64=0x", + &s_rec.service_data64[0]); + PARSE_AHEAD(p, net64, ":0x", &s_rec.service_data64[1]); + PARSE_AHEAD(p, net32, " modified_time=0x", + &modified_time); + PARSE_AHEAD(p, net32, " lease_period=0x", + &lease_period); + + if (load_svcr(p_osm, &s_rec, cl_ntoh32(modified_time), + cl_ntoh32(lease_period))) + rereg_clients = 1; + } else if (!strncmp(p, "InformInfo Record:", 18)) { + ib_inform_info_record_t i_rec; + osm_mad_addr_t rep_addr; + ib_net16_t val16; + + p_mgrp = NULL; + memset(&i_rec, 0, sizeof(i_rec)); + memset(&rep_addr, 0, sizeof(rep_addr)); + + PARSE_AHEAD(p, net64, " subscriber_gid=0x", + &i_rec.subscriber_gid.unicast.prefix); + PARSE_AHEAD(p, net64, ":0x", + &i_rec.subscriber_gid.unicast.interface_id); + PARSE_AHEAD(p, net16, " subscriber_enum=0x", + &i_rec.subscriber_enum); + PARSE_AHEAD(p, net64, " gid=0x", + &i_rec.inform_info.gid.unicast.prefix); + PARSE_AHEAD(p, net64, ":0x", + &i_rec.inform_info.gid.unicast. + interface_id); + PARSE_AHEAD(p, net16, " lid_range_begin=0x", + &i_rec.inform_info.lid_range_begin); + PARSE_AHEAD(p, net16, " lid_range_end=0x", + &i_rec.inform_info.lid_range_end); + PARSE_AHEAD(p, net8, " is_generic=0x", + &i_rec.inform_info.is_generic); + PARSE_AHEAD(p, net8, " subscribe=0x", + &i_rec.inform_info.subscribe); + PARSE_AHEAD(p, net16, " trap_type=0x", + &i_rec.inform_info.trap_type); + PARSE_AHEAD(p, net16, " trap_num=0x", + &i_rec.inform_info.g_or_v.generic.trap_num); + PARSE_AHEAD(p, net32, " qpn_resp_time_val=0x", + &i_rec.inform_info.g_or_v.generic. + qpn_resp_time_val); + PARSE_AHEAD(p, net32, " node_type=0x", + (uint32_t *) & i_rec.inform_info.g_or_v. + generic.reserved2); + + PARSE_AHEAD(p, net16, " rep_addr: lid=0x", + &rep_addr.dest_lid); + PARSE_AHEAD(p, net8, " path_bits=0x", + &rep_addr.path_bits); + PARSE_AHEAD(p, net8, " static_rate=0x", + &rep_addr.static_rate); + PARSE_AHEAD(p, net32, " remote_qp=0x", + &rep_addr.addr_type.gsi.remote_qp); + PARSE_AHEAD(p, net32, " remote_qkey=0x", + &rep_addr.addr_type.gsi.remote_qkey); + PARSE_AHEAD(p, net16, " pkey_ix=0x", &val16); + rep_addr.addr_type.gsi.pkey_ix = cl_ntoh16(val16); + PARSE_AHEAD(p, net8, " sl=0x", + &rep_addr.addr_type.gsi.service_level); + + if (load_infr(p_osm, &i_rec, &rep_addr)) + rereg_clients = 1; + } + } + + if (!rereg_clients) + p_osm->subn.opt.no_clients_rereg = TRUE; + +_error: + fclose(file); + return ret; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_class_port_info.c b/contrib/ofed/management/opensm/opensm/osm_sa_class_port_info.c new file mode 100644 index 000000000000..a3a27825f8e1 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_class_port_info.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_cpi_rcv_t. + * This object represents the ClassPortInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_MSECS_TO_RTV 24 +/* Precalculated table in msec (index is related to encoded value) */ +/* 4.096 usec * 2 ** n (where n = 8 - 31) */ +const static uint32_t __msecs_to_rtv_table[MAX_MSECS_TO_RTV] = { + 1, 2, 4, 8, + 16, 33, 67, 134, + 268, 536, 1073, 2147, + 4294, 8589, 17179, 34359, + 68719, 137438, 274877, 549755, + 1099511, 2199023, 4398046, 8796093 +}; + +/********************************************************************** + **********************************************************************/ +static void +__osm_cpi_rcv_respond(IN osm_sa_t * sa, + IN const osm_madw_t * const p_madw) +{ + osm_madw_t *p_resp_madw; + const ib_sa_mad_t *p_sa_mad; + ib_sa_mad_t *p_resp_sa_mad; + ib_class_port_info_t *p_resp_cpi; + ib_gid_t zero_gid; + uint8_t rtv; + + OSM_LOG_ENTER(sa->p_log); + + memset(&zero_gid, 0, sizeof(ib_gid_t)); + + /* + Get a MAD to reply. Address of Mad is in the received mad_wrapper + */ + p_resp_madw = osm_mad_pool_get(sa->p_mad_pool, p_madw->h_bind, + MAD_BLOCK_SIZE, &p_madw->mad_addr); + if (!p_resp_madw) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1408: " + "Unable to allocate MAD\n"); + goto Exit; + } + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_resp_sa_mad = osm_madw_get_sa_mad_ptr(p_resp_madw); + + memcpy(p_resp_sa_mad, p_sa_mad, IB_SA_MAD_HDR_SIZE); + p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK; + /* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */ + p_resp_sa_mad->sm_key = 0; + + p_resp_cpi = + (ib_class_port_info_t *) ib_sa_mad_get_payload_ptr(p_resp_sa_mad); + + /* finally do it (the job) man ! */ + p_resp_cpi->base_ver = 1; + p_resp_cpi->class_ver = 2; + /* Calculate encoded response time value */ + /* transaction timeout is in msec */ + if (sa->p_subn->opt.transaction_timeout > + __msecs_to_rtv_table[MAX_MSECS_TO_RTV - 1]) + rtv = MAX_MSECS_TO_RTV - 1; + else { + for (rtv = 0; rtv < MAX_MSECS_TO_RTV; rtv++) { + if (sa->p_subn->opt.transaction_timeout <= + __msecs_to_rtv_table[rtv]) + break; + } + } + rtv += 8; + ib_class_set_resp_time_val(p_resp_cpi, rtv); + p_resp_cpi->redir_gid = zero_gid; + p_resp_cpi->redir_tc_sl_fl = 0; + p_resp_cpi->redir_lid = 0; + p_resp_cpi->redir_pkey = 0; + p_resp_cpi->redir_qp = CL_NTOH32(1); + p_resp_cpi->redir_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + p_resp_cpi->trap_gid = zero_gid; + p_resp_cpi->trap_tc_sl_fl = 0; + p_resp_cpi->trap_lid = 0; + p_resp_cpi->trap_pkey = 0; + p_resp_cpi->trap_hop_qp = 0; + p_resp_cpi->trap_qkey = IB_QP1_WELL_KNOWN_Q_KEY; + + /* set specific capability mask bits */ + /* we do not support the following options/optional records: + OSM_CAP_IS_SUBN_OPT_RECS_SUP : + RandomForwardingTableRecord, + ServiceAssociationRecord + other optional records supported "under the table" + + OSM_CAP_IS_MULTIPATH_SUP: + TraceRecord + + OSM_CAP_IS_REINIT_SUP: + For reinitialization functionality. + + So not sending traps, but supporting Get(Notice) and Set(Notice). + */ + + /* Note host notation replaced later */ +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + p_resp_cpi->cap_mask = OSM_CAP_IS_SUBN_GET_SET_NOTICE_SUP | + OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED | + OSM_CAP_IS_MULTIPATH_SUP; +#else + p_resp_cpi->cap_mask = OSM_CAP_IS_SUBN_GET_SET_NOTICE_SUP | + OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED; +#endif + if (sa->p_subn->opt.qos) + ib_class_set_cap_mask2(p_resp_cpi, OSM_CAP2_IS_QOS_SUPPORTED); + + if (!sa->p_subn->opt.disable_multicast) + p_resp_cpi->cap_mask |= OSM_CAP_IS_UD_MCAST_SUP; + p_resp_cpi->cap_mask = cl_hton16(p_resp_cpi->cap_mask); + + if (osm_log_is_active(sa->p_log, OSM_LOG_FRAMES)) + osm_dump_sa_mad(sa->p_log, p_resp_sa_mad, OSM_LOG_FRAMES); + + osm_sa_send(sa, p_resp_madw, FALSE); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + * This code actually handles the call + **********************************************************************/ +void osm_cpi_rcv_process(IN void *context, IN void *data) +{ + osm_sa_t *sa = context; + osm_madw_t *p_madw = data; + const ib_sa_mad_t *p_sa_mad; + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + + /* we only support GET */ + if (p_sa_mad->method != IB_MAD_METHOD_GET) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1403: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_sa_mad->method)); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_CLASS_PORT_INFO); + + /* + CLASS PORT INFO does not really look on the SMDB - no lock required. + */ + + __osm_cpi_rcv_respond(sa, p_madw); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_guidinfo_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_guidinfo_record.c new file mode 100644 index 000000000000..39dae7288643 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_guidinfo_record.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_gir_rcv_t. + * This object represents the GUIDInfoRecord Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_gir_item { + cl_list_item_t list_item; + ib_guidinfo_record_t rec; +} osm_gir_item_t; + +typedef struct osm_gir_search_ctxt { + const ib_guidinfo_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_gir_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_gir_rcv_new_gir(IN osm_sa_t * sa, + IN const osm_node_t * const p_node, + IN cl_qlist_t * const p_list, + IN ib_net64_t const match_port_guid, + IN ib_net16_t const match_lid, + IN const osm_physp_t * const p_req_physp, + IN uint8_t const block_num) +{ + osm_gir_item_t *p_rec_item; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sa->p_log); + + p_rec_item = malloc(sizeof(*p_rec_item)); + if (p_rec_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5102: " + "rec_item alloc failed\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "New GUIDInfoRecord: lid %u, block num %d\n", + cl_ntoh16(match_lid), block_num); + + memset(p_rec_item, 0, sizeof(*p_rec_item)); + + p_rec_item->rec.lid = match_lid; + p_rec_item->rec.block_num = block_num; + if (!block_num) + p_rec_item->rec.guid_info.guid[0] = + osm_physp_get_port_guid(p_req_physp); + + cl_qlist_insert_tail(p_list, &p_rec_item->list_item); + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_gir_create_gir(IN osm_sa_t * sa, + IN osm_node_t * const p_node, + IN cl_qlist_t * const p_list, + IN ib_net64_t const match_port_guid, + IN ib_net16_t const match_lid, + IN const osm_physp_t * const p_req_physp, + IN uint8_t const match_block_num) +{ + const osm_physp_t *p_physp; + uint8_t port_num; + uint8_t num_ports; + uint16_t match_lid_ho; + ib_net16_t base_lid_ho; + ib_net16_t max_lid_ho; + uint8_t lmc; + ib_net64_t port_guid; + uint8_t block_num, start_block_num, end_block_num, num_blocks; + + OSM_LOG_ENTER(sa->p_log); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Looking for GUIDRecord with LID: %u GUID:0x%016" + PRIx64 "\n", cl_ntoh16(match_lid), cl_ntoh64(match_port_guid)); + + /* + For switches, do not return the GUIDInfo record(s) + for each port on the switch, just for port 0. + */ + if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) + num_ports = 1; + else + num_ports = osm_node_get_num_physp(p_node); + + for (port_num = 0; port_num < num_ports; port_num++) { + p_physp = osm_node_get_physp_ptr(p_node, port_num); + if (!p_physp) + continue; + + /* Check to see if the found p_physp and the requester physp + share a pkey. If not, continue */ + if (!osm_physp_share_pkey(sa->p_log, p_physp, p_req_physp)) + continue; + + port_guid = osm_physp_get_port_guid(p_physp); + + if (match_port_guid && (port_guid != match_port_guid)) + continue; + + /* + Note: the following check is a temporary workaround + Since 1. GUIDCap should never be 0 on ports where this applies + and 2. GUIDCap should not be used on ports where it doesn't apply + So this should really be a check for whether the port is a + switch external port or not! + */ + if (p_physp->port_info.guid_cap == 0) + continue; + + num_blocks = p_physp->port_info.guid_cap / 8; + if (p_physp->port_info.guid_cap % 8) + num_blocks++; + if (match_block_num == 255) { + start_block_num = 0; + end_block_num = num_blocks - 1; + } else { + if (match_block_num >= num_blocks) + continue; + end_block_num = start_block_num = match_block_num; + } + + base_lid_ho = cl_ntoh16(osm_physp_get_base_lid(p_physp)); + match_lid_ho = cl_ntoh16(match_lid); + if (match_lid_ho) { + lmc = osm_physp_get_lmc(p_physp); + max_lid_ho = (uint16_t) (base_lid_ho + (1 << lmc) - 1); + + /* + We validate that the lid belongs to this node. + */ + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Comparing LID: %u <= %u <= %u\n", + base_lid_ho, match_lid_ho, max_lid_ho); + + if (match_lid_ho < base_lid_ho + || match_lid_ho > max_lid_ho) + continue; + } + + for (block_num = start_block_num; block_num <= end_block_num; + block_num++) + __osm_gir_rcv_new_gir(sa, p_node, p_list, port_guid, + cl_ntoh16(base_lid_ho), p_physp, + block_num); + + } + + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_gir_by_comp_mask_cb(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + const osm_gir_search_ctxt_t *const p_ctxt = + (osm_gir_search_ctxt_t *) context; + osm_node_t *const p_node = (osm_node_t *) p_map_item; + const ib_guidinfo_record_t *const p_rcvd_rec = p_ctxt->p_rcvd_rec; + const osm_physp_t *const p_req_physp = p_ctxt->p_req_physp; + osm_sa_t *sa = p_ctxt->sa; + const ib_guid_info_t *p_comp_gi; + ib_net64_t const comp_mask = p_ctxt->comp_mask; + ib_net64_t match_port_guid = 0; + ib_net16_t match_lid = 0; + uint8_t match_block_num = 255; + + OSM_LOG_ENTER(p_ctxt->sa->p_log); + + if (comp_mask & IB_GIR_COMPMASK_LID) + match_lid = p_rcvd_rec->lid; + + if (comp_mask & IB_GIR_COMPMASK_BLOCKNUM) + match_block_num = p_rcvd_rec->block_num; + + p_comp_gi = &p_rcvd_rec->guid_info; + /* Different rule for block 0 v. other blocks */ + if (comp_mask & IB_GIR_COMPMASK_GID0) { + if (!p_rcvd_rec->block_num) + match_port_guid = osm_physp_get_port_guid(p_req_physp); + if (p_comp_gi->guid[0] != match_port_guid) + goto Exit; + } + + if (comp_mask & IB_GIR_COMPMASK_GID1) { + if (p_comp_gi->guid[1] != 0) + goto Exit; + } + + if (comp_mask & IB_GIR_COMPMASK_GID2) { + if (p_comp_gi->guid[2] != 0) + goto Exit; + } + + if (comp_mask & IB_GIR_COMPMASK_GID3) { + if (p_comp_gi->guid[3] != 0) + goto Exit; + } + + if (comp_mask & IB_GIR_COMPMASK_GID4) { + if (p_comp_gi->guid[4] != 0) + goto Exit; + } + + if (comp_mask & IB_GIR_COMPMASK_GID5) { + if (p_comp_gi->guid[5] != 0) + goto Exit; + } + + if (comp_mask & IB_GIR_COMPMASK_GID6) { + if (p_comp_gi->guid[6] != 0) + goto Exit; + } + + if (comp_mask & IB_GIR_COMPMASK_GID7) { + if (p_comp_gi->guid[7] != 0) + goto Exit; + } + + __osm_sa_gir_create_gir(sa, p_node, p_ctxt->p_list, + match_port_guid, match_lid, p_req_physp, + match_block_num); + +Exit: + OSM_LOG_EXIT(p_ctxt->sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_gir_rcv_process(IN void *ctx, IN void *data) +{ + osm_sa_t *sa = ctx; + osm_madw_t *p_madw = data; + const ib_sa_mad_t *p_rcvd_mad; + const ib_guidinfo_record_t *p_rcvd_rec; + cl_qlist_t rec_list; + osm_gir_search_ctxt_t context; + osm_physp_t *p_req_physp; + + CL_ASSERT(sa); + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_rcvd_rec = + (ib_guidinfo_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); + + CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_GUIDINFO_RECORD); + + /* we only support SubnAdmGet and SubnAdmGetTable methods */ + if (p_rcvd_mad->method != IB_MAD_METHOD_GET && + p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5105: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_rcvd_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5104: " + "Cannot find requester physical port\n"); + goto Exit; + } + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_guidinfo_record(sa->p_log, p_rcvd_rec, OSM_LOG_DEBUG); + + cl_qlist_init(&rec_list); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = p_rcvd_mad->comp_mask; + context.sa = sa; + context.p_req_physp = p_req_physp; + + cl_plock_acquire(sa->p_lock); + + cl_qmap_apply_func(&sa->p_subn->node_guid_tbl, + __osm_sa_gir_by_comp_mask_cb, &context); + + cl_plock_release(sa->p_lock); + + osm_sa_respond(sa, p_madw, sizeof(ib_guidinfo_record_t), &rec_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_informinfo.c b/contrib/ofed/management/opensm/opensm/osm_sa_informinfo.c new file mode 100644 index 000000000000..a48b5466188d --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_informinfo.c @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_infr_rcv_t. + * This object represents the InformInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef struct osm_iir_item { + cl_list_item_t list_item; + ib_inform_info_record_t rec; +} osm_iir_item_t; + +typedef struct osm_iir_search_ctxt { + const ib_inform_info_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + ib_gid_t subscriber_gid; + ib_net16_t subscriber_enum; + osm_sa_t *sa; + osm_physp_t *p_req_physp; +} osm_iir_search_ctxt_t; + +/********************************************************************** +o13-14.1.1: Except for Set(InformInfo) requests with Inform- +Info:LIDRangeBegin=0xFFFF, managers that support event forwarding +shall, upon receiving a Set(InformInfo), verify that the requester +originating the Set(InformInfo) and a Trap() source identified by Inform- +can access each other - can use path record to verify that. +**********************************************************************/ +static boolean_t +__validate_ports_access_rights(IN osm_sa_t * sa, + IN osm_infr_t * p_infr_rec) +{ + boolean_t valid = TRUE; + osm_physp_t *p_requester_physp; + osm_port_t *p_port; + osm_physp_t *p_physp; + ib_net64_t portguid; + ib_net16_t lid_range_begin; + ib_net16_t lid_range_end; + ib_net16_t lid; + const cl_ptr_vector_t *p_tbl; + ib_gid_t zero_gid; + + OSM_LOG_ENTER(sa->p_log); + + /* get the requester physp from the request address */ + p_requester_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, + &p_infr_rec->report_addr); + + memset(&zero_gid, 0, sizeof(zero_gid)); + if (memcmp(&(p_infr_rec->inform_record.inform_info.gid), + &zero_gid, sizeof(ib_gid_t))) { + /* a gid is defined */ + portguid = + p_infr_rec->inform_record.inform_info.gid.unicast. + interface_id; + + p_port = osm_get_port_by_guid(sa->p_subn, portguid); + + if (p_port == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4301: " + "Invalid port guid: 0x%016" PRIx64 "\n", + cl_ntoh64(portguid)); + valid = FALSE; + goto Exit; + } + + /* get the destination InformInfo physical port */ + p_physp = p_port->p_physp; + + /* make sure that the requester and destination port can access each other + according to the current partitioning. */ + if (!osm_physp_share_pkey + (sa->p_log, p_physp, p_requester_physp)) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "port and requester don't share pkey\n"); + valid = FALSE; + goto Exit; + } + } else { + /* gid is zero - check if LID range is defined */ + lid_range_begin = + cl_ntoh16(p_infr_rec->inform_record.inform_info. + lid_range_begin); + /* if lid is 0xFFFF - meaning all endports managed by the manager */ + if (lid_range_begin == 0xFFFF) + goto Exit; + + lid_range_end = + cl_ntoh16(p_infr_rec->inform_record.inform_info. + lid_range_end); + + /* lid_range_end is set to zero if no range desired. In this case - + just make it equal to the lid_range_begin. */ + if (lid_range_end == 0) + lid_range_end = lid_range_begin; + + /* go over all defined lids within the range and make sure that the + requester port can access them according to current partitioning. */ + for (lid = lid_range_begin; lid <= lid_range_end; lid++) { + p_tbl = &sa->p_subn->port_lid_tbl; + if (cl_ptr_vector_get_size(p_tbl) > lid) + p_port = cl_ptr_vector_get(p_tbl, lid); + else { + /* lid requested is out of range */ + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4302: " + "Given LID (%u) is out of range:%u\n", + lid, cl_ptr_vector_get_size(p_tbl)); + valid = FALSE; + goto Exit; + } + if (p_port == NULL) + continue; + + p_physp = p_port->p_physp; + /* make sure that the requester and destination port can access + each other according to the current partitioning. */ + if (!osm_physp_share_pkey + (sa->p_log, p_physp, p_requester_physp)) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "port and requester don't share pkey\n"); + valid = FALSE; + goto Exit; + } + } + } + +Exit: + OSM_LOG_EXIT(sa->p_log); + return valid; +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +__validate_infr(IN osm_sa_t * sa, IN osm_infr_t * p_infr_rec) +{ + boolean_t valid = TRUE; + + OSM_LOG_ENTER(sa->p_log); + + valid = __validate_ports_access_rights(sa, p_infr_rec); + if (!valid) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Invalid Access for InformInfo\n"); + valid = FALSE; + } + + OSM_LOG_EXIT(sa->p_log); + return valid; +} + +/********************************************************************** +o13-12.1.1: Confirm a valid request for event subscription by responding +with an InformInfo attribute that is a copy of the data in the +Set(InformInfo) request. +**********************************************************************/ +static void +__osm_infr_rcv_respond(IN osm_sa_t * sa, + IN osm_madw_t * const p_madw) +{ + cl_qlist_t rec_list; + osm_iir_item_t *item; + + OSM_LOG_ENTER(sa->p_log); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Generating successful InformInfo response\n"); + + item = malloc(sizeof(*item)); + if (!item) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4303: " + "rec_item alloc failed\n"); + goto Exit; + } + + memcpy(&item->rec, + ib_sa_mad_get_payload_ptr(osm_madw_get_sa_mad_ptr(p_madw)), + sizeof(item->rec)); + + cl_qlist_init(&rec_list); + cl_qlist_insert_tail(&rec_list, &item->list_item); + + osm_sa_respond(sa, p_madw, sizeof(ib_inform_info_t), &rec_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_inform_info_rec_by_comp_mask(IN osm_sa_t * sa, + IN const osm_infr_t * const p_infr, + osm_iir_search_ctxt_t * const p_ctxt) +{ + const ib_inform_info_record_t *p_rcvd_rec = NULL; + ib_net64_t comp_mask; + ib_net64_t portguid; + osm_port_t *p_subscriber_port; + osm_physp_t *p_subscriber_physp; + const osm_physp_t *p_req_physp; + osm_iir_item_t *p_rec_item; + + OSM_LOG_ENTER(sa->p_log); + + p_rcvd_rec = p_ctxt->p_rcvd_rec; + comp_mask = p_ctxt->comp_mask; + p_req_physp = p_ctxt->p_req_physp; + + if (comp_mask & IB_IIR_COMPMASK_SUBSCRIBERGID && + memcmp(&p_infr->inform_record.subscriber_gid, + &p_ctxt->subscriber_gid, + sizeof(p_infr->inform_record.subscriber_gid))) + goto Exit; + + if (comp_mask & IB_IIR_COMPMASK_ENUM && + p_infr->inform_record.subscriber_enum != p_ctxt->subscriber_enum) + goto Exit; + + /* Implement any other needed search cases */ + + /* Ensure pkey is shared before returning any records */ + portguid = p_infr->inform_record.subscriber_gid.unicast.interface_id; + p_subscriber_port = osm_get_port_by_guid(sa->p_subn, portguid); + if (p_subscriber_port == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 430D: " + "Invalid subscriber port guid: 0x%016" PRIx64 "\n", + cl_ntoh64(portguid)); + goto Exit; + } + + /* get the subscriber InformInfo physical port */ + p_subscriber_physp = p_subscriber_port->p_physp; + /* make sure that the requester and subscriber port can access each other + according to the current partitioning. */ + if (!osm_physp_share_pkey + (sa->p_log, p_req_physp, p_subscriber_physp)) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "requester and subscriber ports don't share pkey\n"); + goto Exit; + } + + p_rec_item = malloc(sizeof(*p_rec_item)); + if (p_rec_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 430E: " + "rec_item alloc failed\n"); + goto Exit; + } + + memcpy((void *)&p_rec_item->rec, (void *)&p_infr->inform_record, + sizeof(ib_inform_info_record_t)); + cl_qlist_insert_tail(p_ctxt->p_list, &p_rec_item->list_item); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_inform_info_rec_by_comp_mask_cb(IN cl_list_item_t * const p_list_item, + IN void *context) +{ + const osm_infr_t *const p_infr = (osm_infr_t *) p_list_item; + osm_iir_search_ctxt_t *const p_ctxt = (osm_iir_search_ctxt_t *) context; + + __osm_sa_inform_info_rec_by_comp_mask(p_ctxt->sa, p_infr, p_ctxt); +} + +/********************************************************************** +Received a Get(InformInfoRecord) or GetTable(InformInfoRecord) MAD +**********************************************************************/ +static void +osm_infr_rcv_process_get_method(IN osm_sa_t * sa, + IN osm_madw_t * const p_madw) +{ + char gid_str[INET6_ADDRSTRLEN]; + ib_sa_mad_t *p_rcvd_mad; + const ib_inform_info_record_t *p_rcvd_rec; + cl_qlist_t rec_list; + osm_iir_search_ctxt_t context; + osm_physp_t *p_req_physp; + osm_iir_item_t *item; + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_rcvd_rec = + (ib_inform_info_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4309: " + "Cannot find requester physical port\n"); + goto Exit; + } + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_inform_info_record(sa->p_log, p_rcvd_rec, + OSM_LOG_DEBUG); + + cl_qlist_init(&rec_list); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = p_rcvd_mad->comp_mask; + context.subscriber_gid = p_rcvd_rec->subscriber_gid; + context.subscriber_enum = p_rcvd_rec->subscriber_enum; + context.sa = sa; + context.p_req_physp = p_req_physp; + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Query Subscriber GID:%s(%02X) Enum:0x%X(%02X)\n", + inet_ntop(AF_INET6, p_rcvd_rec->subscriber_gid.raw, + gid_str, sizeof gid_str), + (p_rcvd_mad->comp_mask & IB_IIR_COMPMASK_SUBSCRIBERGID) != 0, + cl_ntoh16(p_rcvd_rec->subscriber_enum), + (p_rcvd_mad->comp_mask & IB_IIR_COMPMASK_ENUM) != 0); + + cl_plock_acquire(sa->p_lock); + + cl_qlist_apply_func(&sa->p_subn->sa_infr_list, + __osm_sa_inform_info_rec_by_comp_mask_cb, &context); + + cl_plock_release(sa->p_lock); + + /* clear reserved and pad fields in InformInfoRecord */ + for (item = (osm_iir_item_t *) cl_qlist_head(&rec_list); + item != (osm_iir_item_t *) cl_qlist_end(&rec_list); + item = (osm_iir_item_t *)cl_qlist_next(&item->list_item)) { + memset(item->rec.reserved, 0, sizeof(item->rec.reserved)); + memset(item->rec.pad, 0, sizeof(item->rec.pad)); + } + + osm_sa_respond(sa, p_madw, sizeof(ib_inform_info_record_t), &rec_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************* +Received a Set(InformInfo) MAD +**********************************************************************/ +static void +osm_infr_rcv_process_set_method(IN osm_sa_t * sa, + IN osm_madw_t * const p_madw) +{ + ib_sa_mad_t *p_sa_mad; + ib_inform_info_t *p_recvd_inform_info; + osm_infr_t inform_info_rec; /* actual inform record to be stored for reports */ + osm_infr_t *p_infr; + ib_net32_t qpn; + uint8_t resp_time_val; + ib_api_status_t res; + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_recvd_inform_info = + (ib_inform_info_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + +#if 0 + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_inform_info(sa->p_log, p_recvd_inform_info, + OSM_LOG_DEBUG); +#endif + + /* Grab the lock */ + cl_plock_excl_acquire(sa->p_lock); + + /* define the inform record */ + inform_info_rec.inform_record.inform_info = *p_recvd_inform_info; + + /* following C13-32.1.2 Tbl 120: we only copy the source address vector */ + inform_info_rec.report_addr = p_madw->mad_addr; + + /* we will need to know the mad srvc to send back through */ + inform_info_rec.h_bind = p_madw->h_bind; + inform_info_rec.sa = sa; + + /* update the subscriber GID according to mad address */ + res = osm_get_gid_by_mad_addr(sa->p_log, sa->p_subn, &p_madw->mad_addr, + &inform_info_rec.inform_record. + subscriber_gid); + if (res != IB_SUCCESS) { + cl_plock_release(sa->p_lock); + + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4308 " + "Subscribe Request from unknown LID: %u\n", + cl_ntoh16(p_madw->mad_addr.dest_lid)); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + /* HACK: enum is always 0 (currently) */ + inform_info_rec.inform_record.subscriber_enum = 0; + + /* Subscribe values above 1 are undefined */ + if (p_recvd_inform_info->subscribe > 1) { + cl_plock_release(sa->p_lock); + + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4308 " + "Invalid subscribe: %d\n", + p_recvd_inform_info->subscribe); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + /* + * MODIFICATIONS DONE ON INCOMING REQUEST: + * + * QPN: + * Internally we keep the QPN field of the InformInfo updated + * so we can simply compare it in the record - when finding such. + */ + if (p_recvd_inform_info->subscribe) { + ib_inform_info_set_qpn(&inform_info_rec.inform_record. + inform_info, + inform_info_rec.report_addr.addr_type. + gsi.remote_qp); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Subscribe Request with QPN: 0x%06X\n", + cl_ntoh32(inform_info_rec.report_addr.addr_type.gsi. + remote_qp)); + } else { + ib_inform_info_get_qpn_resp_time(p_recvd_inform_info->g_or_v. + generic.qpn_resp_time_val, + &qpn, &resp_time_val); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "UnSubscribe Request with QPN: 0x%06X\n", + cl_ntoh32(qpn)); + } + + /* If record exists with matching InformInfo */ + p_infr = + osm_infr_get_by_rec(sa->p_subn, sa->p_log, &inform_info_rec); + + /* check to see if the request was for subscribe */ + if (p_recvd_inform_info->subscribe) { + /* validate the request for a new or update InformInfo */ + if (__validate_infr(sa, &inform_info_rec) != TRUE) { + cl_plock_release(sa->p_lock); + + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4305: " + "Failed to validate a new inform object\n"); + + /* o13-13.1.1: we need to set the subscribe bit to 0 */ + p_recvd_inform_info->subscribe = 0; + osm_sa_send_error(sa, p_madw, + IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + /* ok - we can try and create a new entry */ + if (p_infr == NULL) { + /* Create the instance of the osm_infr_t object */ + p_infr = osm_infr_new(&inform_info_rec); + if (p_infr == NULL) { + cl_plock_release(sa->p_lock); + + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4306: " + "Failed to create a new inform object\n"); + + /* o13-13.1.1: we need to set the subscribe bit to 0 */ + p_recvd_inform_info->subscribe = 0; + osm_sa_send_error(sa, p_madw, + IB_SA_MAD_STATUS_NO_RESOURCES); + goto Exit; + } + + /* Add this new osm_infr_t object to subnet object */ + osm_infr_insert_to_db(sa->p_subn, sa->p_log, p_infr); + } else + /* Update the old instance of the osm_infr_t object */ + p_infr->inform_record = inform_info_rec.inform_record; + /* We got an UnSubscribe request */ + } else if (p_infr == NULL) { + cl_plock_release(sa->p_lock); + + /* No Such Item - So Error */ + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4307: " + "Failed to UnSubscribe to non existing inform object\n"); + + /* o13-13.1.1: we need to set the subscribe bit to 0 */ + p_recvd_inform_info->subscribe = 0; + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } else + /* Delete this object from the subnet list of informs */ + osm_infr_remove_from_db(sa->p_subn, sa->p_log, p_infr); + + cl_plock_release(sa->p_lock); + + /* send the success response */ + __osm_infr_rcv_respond(sa, p_madw); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************* +**********************************************************************/ +void osm_infr_rcv_process(IN void *context, IN void *data) +{ + osm_sa_t *sa = context; + osm_madw_t *p_madw = data; + ib_sa_mad_t *p_sa_mad; + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + + CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_INFORM_INFO); + + if (p_sa_mad->method != IB_MAD_METHOD_SET) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_sa_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + osm_infr_rcv_process_set_method(sa, p_madw); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************* +**********************************************************************/ +void osm_infir_rcv_process(IN void *context, IN void *data) +{ + osm_sa_t *sa = context; + osm_madw_t *p_madw = data; + ib_sa_mad_t *p_sa_mad; + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + + CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_INFORM_INFO_RECORD); + + if (p_sa_mad->method != IB_MAD_METHOD_GET && + p_sa_mad->method != IB_MAD_METHOD_GETTABLE) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_sa_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + osm_infr_rcv_process_get_method(sa, p_madw); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_lft_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_lft_record.c new file mode 100644 index 000000000000..d84a6a5b8fe3 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_lft_record.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_lftr_rcv_t. + * This object represents the LinearForwardingTable Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_lftr_item { + cl_list_item_t list_item; + ib_lft_record_t rec; +} osm_lftr_item_t; + +typedef struct osm_lftr_search_ctxt { + const ib_lft_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_lftr_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_lftr_rcv_new_lftr(IN osm_sa_t * sa, + IN const osm_switch_t * const p_sw, + IN cl_qlist_t * const p_list, + IN ib_net16_t const lid, IN uint16_t const block) +{ + osm_lftr_item_t *p_rec_item; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sa->p_log); + + p_rec_item = malloc(sizeof(*p_rec_item)); + if (p_rec_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4402: " + "rec_item alloc failed\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "New LinearForwardingTable: sw 0x%016" PRIx64 + "\n\t\t\t\tblock 0x%02X lid %u\n", + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)), + block, cl_ntoh16(lid)); + + memset(p_rec_item, 0, sizeof(*p_rec_item)); + + p_rec_item->rec.lid = lid; + p_rec_item->rec.block_num = cl_hton16(block); + + /* copy the lft block */ + osm_switch_get_lft_block(p_sw, block, p_rec_item->rec.lft); + + cl_qlist_insert_tail(p_list, &p_rec_item->list_item); + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_lftr_rcv_by_comp_mask(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + const osm_lftr_search_ctxt_t *const p_ctxt = + (osm_lftr_search_ctxt_t *) context; + const osm_switch_t *const p_sw = (osm_switch_t *) p_map_item; + const ib_lft_record_t *const p_rcvd_rec = p_ctxt->p_rcvd_rec; + osm_sa_t *sa = p_ctxt->sa; + ib_net64_t const comp_mask = p_ctxt->comp_mask; + const osm_physp_t *const p_req_physp = p_ctxt->p_req_physp; + osm_port_t *p_port; + uint16_t min_lid_ho, max_lid_ho; + uint16_t min_block, max_block, block; + const osm_physp_t *p_physp; + + /* In switches, the port guid is the node guid. */ + p_port = osm_get_port_by_guid(sa->p_subn, + p_sw->p_node->node_info.port_guid); + if (!p_port) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4405: " + "Failed to find Port by Node Guid:0x%016" PRIx64 + "\n", cl_ntoh64(p_sw->p_node->node_info.node_guid)); + return; + } + + /* check that the requester physp and the current physp are under + the same partition. */ + p_physp = p_port->p_physp; + if (!p_physp) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4406: " + "Failed to find default physical Port by Node Guid:0x%016" + PRIx64 "\n", + cl_ntoh64(p_sw->p_node->node_info.node_guid)); + return; + } + if (!osm_physp_share_pkey(sa->p_log, p_req_physp, p_physp)) + return; + + /* get the port 0 of the switch */ + osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); + + /* compare the lids - if required */ + if (comp_mask & IB_LFTR_COMPMASK_LID) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Comparing lid:%u to port lid range: %u .. %u\n", + cl_ntoh16(p_rcvd_rec->lid), min_lid_ho, max_lid_ho); + /* ok we are ready for range check */ + if (min_lid_ho > cl_ntoh16(p_rcvd_rec->lid) || + max_lid_ho < cl_ntoh16(p_rcvd_rec->lid)) + return; + } + + /* now we need to decide which blocks to output */ + max_block = osm_switch_get_max_block_id_in_use(p_sw); + if (comp_mask & IB_LFTR_COMPMASK_BLOCK) { + min_block = cl_ntoh16(p_rcvd_rec->block_num); + if (min_block > max_block) + return; + max_block = min_block; + } else /* use as many blocks as "in use" */ + min_block = 0; + + /* so we can add these blocks one by one ... */ + for (block = min_block; block <= max_block; block++) + __osm_lftr_rcv_new_lftr(sa, p_sw, p_ctxt->p_list, + osm_port_get_base_lid(p_port), block); +} + +/********************************************************************** + **********************************************************************/ +void osm_lftr_rcv_process(IN void *ctx, IN void *data) +{ + osm_sa_t *sa = ctx; + osm_madw_t *p_madw = data; + const ib_sa_mad_t *p_rcvd_mad; + const ib_lft_record_t *p_rcvd_rec; + cl_qlist_t rec_list; + osm_lftr_search_ctxt_t context; + osm_physp_t *p_req_physp; + + CL_ASSERT(sa); + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_rcvd_rec = (ib_lft_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); + + CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_LFT_RECORD); + + /* we only support SubnAdmGet and SubnAdmGetTable methods */ + if (p_rcvd_mad->method != IB_MAD_METHOD_GET && + p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4408: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_rcvd_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4407: " + "Cannot find requester physical port\n"); + goto Exit; + } + + cl_qlist_init(&rec_list); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = p_rcvd_mad->comp_mask; + context.sa = sa; + context.p_req_physp = p_req_physp; + + cl_plock_acquire(sa->p_lock); + + /* Go over all switches */ + cl_qmap_apply_func(&sa->p_subn->sw_guid_tbl, + __osm_lftr_rcv_by_comp_mask, &context); + + cl_plock_release(sa->p_lock); + + osm_sa_respond(sa, p_madw, sizeof(ib_lft_record_t), &rec_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_link_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_link_record.c new file mode 100644 index 000000000000..b92845e6675b --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_link_record.c @@ -0,0 +1,505 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_lr_rcv_t. + * This object represents the LinkRecord Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_lr_item { + cl_list_item_t list_item; + ib_link_record_t link_rec; +} osm_lr_item_t; + +/********************************************************************** + **********************************************************************/ +static void +__osm_lr_rcv_build_physp_link(IN osm_sa_t * sa, + IN const ib_net16_t from_lid, + IN const ib_net16_t to_lid, + IN const uint8_t from_port, + IN const uint8_t to_port, IN cl_qlist_t * p_list) +{ + osm_lr_item_t *p_lr_item; + + p_lr_item = malloc(sizeof(*p_lr_item)); + if (p_lr_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1801: " + "Unable to acquire link record\n" + "\t\t\t\tFrom port %u\n" + "\t\t\t\tTo port %u\n" + "\t\t\t\tFrom lid %u\n" + "\t\t\t\tTo lid %u\n", + from_port, to_port, + cl_ntoh16(from_lid), cl_ntoh16(to_lid)); + return; + } + memset(p_lr_item, 0, sizeof(*p_lr_item)); + + p_lr_item->link_rec.from_port_num = from_port; + p_lr_item->link_rec.to_port_num = to_port; + p_lr_item->link_rec.to_lid = to_lid; + p_lr_item->link_rec.from_lid = from_lid; + + cl_qlist_insert_tail(p_list, &p_lr_item->list_item); +} + +/********************************************************************** + **********************************************************************/ +static void +__get_base_lid(IN const osm_physp_t * p_physp, OUT ib_net16_t * p_base_lid) +{ + if (p_physp->p_node->node_info.node_type == IB_NODE_TYPE_SWITCH) + *p_base_lid = osm_physp_get_base_lid + (osm_node_get_physp_ptr(p_physp->p_node, 0)); + else + *p_base_lid = osm_physp_get_base_lid(p_physp); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_lr_rcv_get_physp_link(IN osm_sa_t * sa, + IN const ib_link_record_t * const p_lr, + IN const osm_physp_t * p_src_physp, + IN const osm_physp_t * p_dest_physp, + IN const ib_net64_t comp_mask, + IN cl_qlist_t * const p_list, + IN const osm_physp_t * p_req_physp) +{ + uint8_t src_port_num; + uint8_t dest_port_num; + ib_net16_t from_base_lid; + ib_net16_t to_base_lid; + ib_net16_t lmc_mask; + + OSM_LOG_ENTER(sa->p_log); + + /* + If only one end of the link is specified, determine + the other side. + */ + if (p_src_physp) { + if (p_dest_physp) { + /* + Ensure the two physp's are actually connected. + If not, bail out. + */ + if (osm_physp_get_remote(p_src_physp) != p_dest_physp) + goto Exit; + } else { + p_dest_physp = osm_physp_get_remote(p_src_physp); + if (p_dest_physp == NULL) + goto Exit; + } + } else { + if (p_dest_physp) { + p_src_physp = osm_physp_get_remote(p_dest_physp); + if (p_src_physp == NULL) + goto Exit; + } else + goto Exit; /* no physp's, so nothing to do */ + } + + /* Check that the p_src_physp, p_dest_physp and p_req_physp + all share a pkey (doesn't have to be the same p_key). */ + if (!osm_physp_share_pkey(sa->p_log, p_src_physp, p_dest_physp)) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Source and Dest PhysPorts do not share PKey\n"); + goto Exit; + } + if (!osm_physp_share_pkey(sa->p_log, p_src_physp, p_req_physp)) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Source and Requester PhysPorts do not share PKey\n"); + goto Exit; + } + if (!osm_physp_share_pkey(sa->p_log, p_req_physp, p_dest_physp)) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Requester and Dest PhysPorts do not share PKey\n"); + goto Exit; + } + + src_port_num = osm_physp_get_port_num(p_src_physp); + dest_port_num = osm_physp_get_port_num(p_dest_physp); + + if (comp_mask & IB_LR_COMPMASK_FROM_PORT) + if (src_port_num != p_lr->from_port_num) + goto Exit; + + if (comp_mask & IB_LR_COMPMASK_TO_PORT) + if (dest_port_num != p_lr->to_port_num) + goto Exit; + + __get_base_lid(p_src_physp, &from_base_lid); + __get_base_lid(p_dest_physp, &to_base_lid); + + lmc_mask = ~((1 << sa->p_subn->opt.lmc) - 1); + lmc_mask = cl_hton16(lmc_mask); + + if (comp_mask & IB_LR_COMPMASK_FROM_LID) + if (from_base_lid != (p_lr->from_lid & lmc_mask)) + goto Exit; + + if (comp_mask & IB_LR_COMPMASK_TO_LID) + if (to_base_lid != (p_lr->to_lid & lmc_mask)) + goto Exit; + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Acquiring link record\n" + "\t\t\t\tsrc port 0x%" PRIx64 " (port %u)" + ", dest port 0x%" PRIx64 " (port %u)\n", + cl_ntoh64(osm_physp_get_port_guid(p_src_physp)), src_port_num, + cl_ntoh64(osm_physp_get_port_guid(p_dest_physp)), + dest_port_num); + + + __osm_lr_rcv_build_physp_link(sa, from_base_lid, to_base_lid, + src_port_num, dest_port_num, p_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_lr_rcv_get_port_links(IN osm_sa_t * sa, + IN const ib_link_record_t * const p_lr, + IN const osm_port_t * p_src_port, + IN const osm_port_t * p_dest_port, + IN const ib_net64_t comp_mask, + IN cl_qlist_t * const p_list, + IN const osm_physp_t * p_req_physp) +{ + const osm_physp_t *p_src_physp; + const osm_physp_t *p_dest_physp; + const cl_qmap_t *p_node_tbl; + osm_node_t * p_node; + uint8_t port_num; + uint8_t num_ports; + uint8_t dest_num_ports; + uint8_t dest_port_num; + + OSM_LOG_ENTER(sa->p_log); + + if (p_src_port) { + if (p_dest_port) { + /* + Build an LR for every link connected between both ports. + The inner function will discard physp combinations + that do not actually connect. Don't bother screening + for that here. + */ + num_ports = osm_node_get_num_physp(p_src_port->p_node); + dest_num_ports = + osm_node_get_num_physp(p_dest_port->p_node); + for (port_num = 1; port_num < num_ports; port_num++) { + p_src_physp = + osm_node_get_physp_ptr(p_src_port->p_node, + port_num); + for (dest_port_num = 1; + dest_port_num < dest_num_ports; + dest_port_num++) { + p_dest_physp = + osm_node_get_physp_ptr(p_dest_port-> + p_node, + dest_port_num); + /* both physical ports should be with data */ + if (p_src_physp && p_dest_physp) + __osm_lr_rcv_get_physp_link + (sa, p_lr, p_src_physp, + p_dest_physp, comp_mask, + p_list, p_req_physp); + } + } + } else { + /* + Build an LR for every link connected from the source port. + */ + if (comp_mask & IB_LR_COMPMASK_FROM_PORT) { + port_num = p_lr->from_port_num; + /* If the port number is out of the range of the p_src_port, then + this couldn't be a relevant record. */ + if (port_num < + p_src_port->p_node->physp_tbl_size) { + p_src_physp = + osm_node_get_physp_ptr(p_src_port-> + p_node, + port_num); + if (p_src_physp) + __osm_lr_rcv_get_physp_link + (sa, p_lr, p_src_physp, + NULL, comp_mask, p_list, + p_req_physp); + } + } else { + num_ports = + osm_node_get_num_physp(p_src_port->p_node); + for (port_num = 1; port_num < num_ports; + port_num++) { + p_src_physp = + osm_node_get_physp_ptr(p_src_port-> + p_node, + port_num); + if (p_src_physp) + __osm_lr_rcv_get_physp_link + (sa, p_lr, p_src_physp, + NULL, comp_mask, p_list, + p_req_physp); + } + } + } + } else { + if (p_dest_port) { + /* + Build an LR for every link connected to the dest port. + */ + if (comp_mask & IB_LR_COMPMASK_TO_PORT) { + port_num = p_lr->to_port_num; + /* If the port number is out of the range of the p_dest_port, then + this couldn't be a relevant record. */ + if (port_num < + p_dest_port->p_node->physp_tbl_size) { + p_dest_physp = + osm_node_get_physp_ptr(p_dest_port-> + p_node, + port_num); + if (p_dest_physp) + __osm_lr_rcv_get_physp_link + (sa, p_lr, NULL, + p_dest_physp, comp_mask, + p_list, p_req_physp); + } + } else { + num_ports = + osm_node_get_num_physp(p_dest_port->p_node); + for (port_num = 1; port_num < num_ports; + port_num++) { + p_dest_physp = + osm_node_get_physp_ptr(p_dest_port-> + p_node, + port_num); + if (p_dest_physp) + __osm_lr_rcv_get_physp_link + (sa, p_lr, NULL, + p_dest_physp, comp_mask, + p_list, p_req_physp); + } + } + } else { + /* + Process the world (recurse once back into this function). + */ + p_node_tbl = &sa->p_subn->node_guid_tbl; + p_node = (osm_node_t *)cl_qmap_head(p_node_tbl); + + while (p_node != (osm_node_t *)cl_qmap_end(p_node_tbl)) { + num_ports = osm_node_get_num_physp(p_node); + for (port_num = 1; port_num < num_ports; + port_num++) { + p_src_physp = + osm_node_get_physp_ptr(p_node, + port_num); + if (p_src_physp) + __osm_lr_rcv_get_physp_link + (sa, p_lr, p_src_physp, + NULL, comp_mask, p_list, + p_req_physp); + } + p_node = (osm_node_t *) cl_qmap_next(&p_node-> + map_item); + } + } + } + + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + Returns the SA status to return to the client. + **********************************************************************/ +static ib_net16_t +__osm_lr_rcv_get_end_points(IN osm_sa_t * sa, + IN const osm_madw_t * const p_madw, + OUT const osm_port_t ** const pp_src_port, + OUT const osm_port_t ** const pp_dest_port) +{ + const ib_link_record_t *p_lr; + const ib_sa_mad_t *p_sa_mad; + ib_net64_t comp_mask; + ib_api_status_t status; + ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS; + + OSM_LOG_ENTER(sa->p_log); + + /* + Determine what fields are valid and then get a pointer + to the source and destination port objects, if possible. + */ + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_lr = (ib_link_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + comp_mask = p_sa_mad->comp_mask; + *pp_src_port = NULL; + *pp_dest_port = NULL; + + if (p_sa_mad->comp_mask & IB_LR_COMPMASK_FROM_LID) { + status = osm_get_port_by_base_lid(sa->p_subn, + p_lr->from_lid, pp_src_port); + + if ((status != IB_SUCCESS) || (*pp_src_port == NULL)) { + /* + This 'error' is the client's fault (bad lid) so + don't enter it as an error in our own log. + Return an error response to the client. + */ + OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, + "No source port with LID %u\n", + cl_ntoh16(p_lr->from_lid)); + + sa_status = IB_SA_MAD_STATUS_NO_RECORDS; + goto Exit; + } + } + + if (p_sa_mad->comp_mask & IB_LR_COMPMASK_TO_LID) { + status = osm_get_port_by_base_lid(sa->p_subn, + p_lr->to_lid, pp_dest_port); + + if ((status != IB_SUCCESS) || (*pp_dest_port == NULL)) { + /* + This 'error' is the client's fault (bad lid) so + don't enter it as an error in our own log. + Return an error response to the client. + */ + OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, + "No dest port with LID %u\n", + cl_ntoh16(p_lr->to_lid)); + + sa_status = IB_SA_MAD_STATUS_NO_RECORDS; + goto Exit; + } + } + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (sa_status); +} + +/********************************************************************** + **********************************************************************/ +void osm_lr_rcv_process(IN void *context, IN void *data) +{ + osm_sa_t *sa = context; + osm_madw_t *p_madw = data; + const ib_link_record_t *p_lr; + const ib_sa_mad_t *p_sa_mad; + const osm_port_t *p_src_port; + const osm_port_t *p_dest_port; + cl_qlist_t lr_list; + ib_net16_t sa_status; + osm_physp_t *p_req_physp; + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_lr = (ib_link_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_LINK_RECORD); + + /* we only support SubnAdmGet and SubnAdmGetTable methods */ + if (p_sa_mad->method != IB_MAD_METHOD_GET && + p_sa_mad->method != IB_MAD_METHOD_GETTABLE) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1804: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_sa_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1805: " + "Cannot find requester physical port\n"); + goto Exit; + } + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_link_record(sa->p_log, p_lr, OSM_LOG_DEBUG); + + cl_qlist_init(&lr_list); + + /* + Most SA functions (including this one) are read-only on the + subnet object, so we grab the lock non-exclusively. + */ + cl_plock_acquire(sa->p_lock); + + sa_status = __osm_lr_rcv_get_end_points(sa, p_madw, + &p_src_port, &p_dest_port); + + if (sa_status == IB_SA_MAD_STATUS_SUCCESS) + __osm_lr_rcv_get_port_links(sa, p_lr, p_src_port, + p_dest_port, p_sa_mad->comp_mask, + &lr_list, p_req_physp); + + cl_plock_release(sa->p_lock); + + osm_sa_respond(sa, p_madw, sizeof(ib_link_record_t), &lr_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_mad_ctrl.c b/contrib/ofed/management/opensm/opensm/osm_sa_mad_ctrl.c new file mode 100644 index 000000000000..49309f90ea37 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_mad_ctrl.c @@ -0,0 +1,592 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sa_mad_ctrl_t. + * This object is part of the SA object. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/****f* opensm: SA/__osm_sa_mad_ctrl_disp_done_callback + * NAME + * __osm_sa_mad_ctrl_disp_done_callback + * + * DESCRIPTION + * This function is the Dispatcher callback that indicates + * a received MAD has been processed by the recipient. + * + * SYNOPSIS + */ +static void +__osm_sa_mad_ctrl_disp_done_callback(IN void *context, IN void *p_data) +{ + osm_sa_mad_ctrl_t *const p_ctrl = (osm_sa_mad_ctrl_t *) context; + osm_madw_t *const p_madw = (osm_madw_t *) p_data; + + OSM_LOG_ENTER(p_ctrl->p_log); + + CL_ASSERT(p_madw); + /* + Return the MAD & wrapper to the pool. + */ + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + OSM_LOG_EXIT(p_ctrl->p_log); +} + +/************/ + +/****f* opensm: SA/__osm_sa_mad_ctrl_process + * NAME + * __osm_sa_mad_ctrl_process + * + * DESCRIPTION + * This function handles known methods for received MADs. + * + * SYNOPSIS + */ +static void +__osm_sa_mad_ctrl_process(IN osm_sa_mad_ctrl_t * const p_ctrl, + IN osm_madw_t * p_madw) +{ + ib_sa_mad_t *p_sa_mad; + cl_status_t status; + cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE; + uint64_t last_dispatched_msg_queue_time_msec; + uint32_t num_messages; + + OSM_LOG_ENTER(p_ctrl->p_log); + + /* + If the dispatcher is showing us that it is overloaded + there is no point in placing the request in. We should instead provide + immediate response - IB_RESOURCE_BUSY + But how do we know? + The dispatcher reports back the number of outstanding messages and the + time the last message stayed in the queue. + HACK: Actually, we cannot send a mad from within the receive callback; + thus - we will just drop it. + */ + cl_disp_get_queue_status(p_ctrl->h_disp, + &num_messages, + &last_dispatched_msg_queue_time_msec); + if ((num_messages > 1) && + (p_ctrl->p_subn->opt.max_msg_fifo_timeout) && + (last_dispatched_msg_queue_time_msec > + p_ctrl->p_subn->opt.max_msg_fifo_timeout)) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_INFO, + /* "Responding BUSY status since the dispatcher is already" */ + "Dropping MAD since the dispatcher is already" + " overloaded with %u messages and queue time of:" + "%" PRIu64 "[msec]\n", + num_messages, last_dispatched_msg_queue_time_msec); + + /* send a busy response */ + /* osm_sa_send_error(p_ctrl->p_resp, p_madw, IB_RESOURCE_BUSY); */ + + /* return the request to the pool */ + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + + goto Exit; + } + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + + /* + Note that attr_id (like the rest of the MAD) is in + network byte order. + */ + switch (p_sa_mad->attr_id) { + case IB_MAD_ATTR_CLASS_PORT_INFO: + msg_id = OSM_MSG_MAD_CLASS_PORT_INFO; + break; + + case IB_MAD_ATTR_NODE_RECORD: + msg_id = OSM_MSG_MAD_NODE_RECORD; + break; + + case IB_MAD_ATTR_PORTINFO_RECORD: + msg_id = OSM_MSG_MAD_PORTINFO_RECORD; + break; + + case IB_MAD_ATTR_LINK_RECORD: + msg_id = OSM_MSG_MAD_LINK_RECORD; + break; + + case IB_MAD_ATTR_SMINFO_RECORD: + msg_id = OSM_MSG_MAD_SMINFO_RECORD; + break; + + case IB_MAD_ATTR_SERVICE_RECORD: + msg_id = OSM_MSG_MAD_SERVICE_RECORD; + break; + + case IB_MAD_ATTR_PATH_RECORD: + msg_id = OSM_MSG_MAD_PATH_RECORD; + break; + + case IB_MAD_ATTR_MCMEMBER_RECORD: + msg_id = OSM_MSG_MAD_MCMEMBER_RECORD; + break; + + case IB_MAD_ATTR_INFORM_INFO: + msg_id = OSM_MSG_MAD_INFORM_INFO; + break; + + case IB_MAD_ATTR_VLARB_RECORD: + msg_id = OSM_MSG_MAD_VL_ARB_RECORD; + break; + + case IB_MAD_ATTR_SLVL_RECORD: + msg_id = OSM_MSG_MAD_SLVL_TBL_RECORD; + break; + + case IB_MAD_ATTR_PKEY_TBL_RECORD: + msg_id = OSM_MSG_MAD_PKEY_TBL_RECORD; + break; + + case IB_MAD_ATTR_LFT_RECORD: + msg_id = OSM_MSG_MAD_LFT_RECORD; + break; + + case IB_MAD_ATTR_GUIDINFO_RECORD: + msg_id = OSM_MSG_MAD_GUIDINFO_RECORD; + break; + + case IB_MAD_ATTR_INFORM_INFO_RECORD: + msg_id = OSM_MSG_MAD_INFORM_INFO_RECORD; + break; + + case IB_MAD_ATTR_SWITCH_INFO_RECORD: + msg_id = OSM_MSG_MAD_SWITCH_INFO_RECORD; + break; + + case IB_MAD_ATTR_MFT_RECORD: + msg_id = OSM_MSG_MAD_MFT_RECORD; + break; + +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + case IB_MAD_ATTR_MULTIPATH_RECORD: + msg_id = OSM_MSG_MAD_MULTIPATH_RECORD; + break; +#endif + + default: + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A01: " + "Unsupported attribute = 0x%X\n", + cl_ntoh16(p_sa_mad->attr_id)); + osm_dump_sa_mad(p_ctrl->p_log, p_sa_mad, OSM_LOG_ERROR); + } + + if (msg_id != CL_DISP_MSGID_NONE) { + /* + Post this MAD to the dispatcher for asynchronous + processing by the appropriate controller. + */ + + OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, + "Posting Dispatcher message %s\n", + osm_get_disp_msg_str(msg_id)); + + status = cl_disp_post(p_ctrl->h_disp, + msg_id, + p_madw, + __osm_sa_mad_ctrl_disp_done_callback, + p_ctrl); + + if (status != CL_SUCCESS) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A02: " + "Dispatcher post message failed (%s) for attribute = 0x%X\n", + CL_STATUS_MSG(status), + cl_ntoh16(p_sa_mad->attr_id)); + + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + goto Exit; + } + } else { + /* + There is an unknown MAD attribute type for which there is + no recipient. Simply retire the MAD here. + */ + cl_atomic_inc(&p_ctrl->p_stats->sa_mads_rcvd_unknown); + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + } + +Exit: + OSM_LOG_EXIT(p_ctrl->p_log); +} + +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* opensm: SA/__osm_sa_mad_ctrl_rcv_callback + * NAME + * __osm_sa_mad_ctrl_rcv_callback + * + * DESCRIPTION + * This is the callback from the transport layer for received MADs. + * + * SYNOPSIS + */ +static void +__osm_sa_mad_ctrl_rcv_callback(IN osm_madw_t * p_madw, + IN void *bind_context, + IN osm_madw_t * p_req_madw) +{ + osm_sa_mad_ctrl_t *p_ctrl = (osm_sa_mad_ctrl_t *) bind_context; + ib_sa_mad_t *p_sa_mad; + + OSM_LOG_ENTER(p_ctrl->p_log); + + CL_ASSERT(p_madw); + + /* + A MAD was received from the wire, possibly in response to a request. + */ + cl_atomic_inc(&p_ctrl->p_stats->sa_mads_rcvd); + + OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, + "%u SA MADs received\n", p_ctrl->p_stats->sa_mads_rcvd); + + /* + * C15-0.1.3 requires not responding to any MAD if the SM is + * not in active state! + * We will not respond if the sm_state is not MASTER, or if the + * first_time_master_sweep flag (of the subnet) is TRUE - this + * flag indicates that the master still didn't finish its first + * sweep, so the subnet is not up and stable yet. + */ + if (p_ctrl->p_subn->sm_state != IB_SMINFO_STATE_MASTER) { + cl_atomic_inc(&p_ctrl->p_stats->sa_mads_ignored); + OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE, + "Received SA MAD while SM not MASTER. MAD ignored\n"); + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + goto Exit; + } + if (p_ctrl->p_subn->first_time_master_sweep == TRUE) { + cl_atomic_inc(&p_ctrl->p_stats->sa_mads_ignored); + OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE, + "Received SA MAD while SM in first sweep. MAD ignored\n"); + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + goto Exit; + } + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + + if (osm_log_is_active(p_ctrl->p_log, OSM_LOG_FRAMES)) + osm_dump_sa_mad(p_ctrl->p_log, p_sa_mad, OSM_LOG_FRAMES); + + /* + * C15-0.1.5 - Table 185: SA Header - p884 + * SM_key should be either 0 or match the current SM_Key + * otherwise discard the MAD. + */ + if ((p_sa_mad->sm_key != 0) && + (p_sa_mad->sm_key != p_ctrl->p_subn->opt.sa_key)) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A04: " + "Non-Zero SA MAD SM_Key: 0x%" PRIx64 " != SM_Key: 0x%" + PRIx64 "; MAD ignored\n", cl_ntoh64(p_sa_mad->sm_key), + cl_ntoh64(p_ctrl->p_subn->opt.sa_key) + ); + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + goto Exit; + } + + switch (p_sa_mad->method) { + case IB_MAD_METHOD_REPORT_RESP: + /* we do not really do anything with report represses - + just retire the transaction */ + OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, + "Received Report Repress. Retiring the transaction\n"); + + if (p_req_madw) + osm_mad_pool_put(p_ctrl->p_mad_pool, p_req_madw); + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + + break; + + case IB_MAD_METHOD_GET: + case IB_MAD_METHOD_GETTABLE: +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + case IB_MAD_METHOD_GETMULTI: +#endif + case IB_MAD_METHOD_SET: + case IB_MAD_METHOD_DELETE: + __osm_sa_mad_ctrl_process(p_ctrl, p_madw); + break; + + default: + cl_atomic_inc(&p_ctrl->p_stats->sa_mads_rcvd_unknown); + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A05: " + "Unsupported method = 0x%X\n", p_sa_mad->method); + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_ctrl->p_log); +} + +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* opensm: SA/__osm_sa_mad_ctrl_send_err_callback + * NAME + * __osm_sa_mad_ctrl_send_err_callback + * + * DESCRIPTION + * This is the callback from the transport layer for send errors + * on MADs that were expecting a response. + * + * SYNOPSIS + */ +static void +__osm_sa_mad_ctrl_send_err_callback(IN void *bind_context, + IN osm_madw_t * p_madw) +{ + osm_sa_mad_ctrl_t *p_ctrl = (osm_sa_mad_ctrl_t *) bind_context; + cl_status_t status; + + OSM_LOG_ENTER(p_ctrl->p_log); + + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A06: " + "MAD transaction completed in error\n"); + + /* + We should never be here since the SA never originates a request. + Unless we generated a Report(Notice) + */ + + CL_ASSERT(p_madw); + + /* + An error occurred. No response was received to a request MAD. + Retire the original request MAD. + */ + + osm_dump_sa_mad(p_ctrl->p_log, osm_madw_get_sa_mad_ptr(p_madw), + OSM_LOG_ERROR); + + /* __osm_sm_mad_ctrl_update_wire_stats( p_ctrl ); */ + + if (osm_madw_get_err_msg(p_madw) != CL_DISP_MSGID_NONE) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, + "Posting Dispatcher message %s\n", + osm_get_disp_msg_str(osm_madw_get_err_msg(p_madw))); + + status = cl_disp_post(p_ctrl->h_disp, + osm_madw_get_err_msg(p_madw), + p_madw, + __osm_sa_mad_ctrl_disp_done_callback, + p_ctrl); + if (status != CL_SUCCESS) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A07: " + "Dispatcher post message failed (%s)\n", + CL_STATUS_MSG(status)); + } + } else { + /* + No error message was provided, just retire the MAD. + */ + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + } + + OSM_LOG_EXIT(p_ctrl->p_log); +} + +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/********************************************************************** + **********************************************************************/ +void osm_sa_mad_ctrl_construct(IN osm_sa_mad_ctrl_t * const p_ctrl) +{ + CL_ASSERT(p_ctrl); + memset(p_ctrl, 0, sizeof(*p_ctrl)); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void osm_sa_mad_ctrl_destroy(IN osm_sa_mad_ctrl_t * const p_ctrl) +{ + CL_ASSERT(p_ctrl); + cl_disp_unregister(p_ctrl->h_disp); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sa_mad_ctrl_init(IN osm_sa_mad_ctrl_t * const p_ctrl, + IN osm_sa_t * sa, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vendor_t * const p_vendor, + IN osm_subn_t * const p_subn, + IN osm_log_t * const p_log, + IN osm_stats_t * const p_stats, + IN cl_dispatcher_t * const p_disp) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + osm_sa_mad_ctrl_construct(p_ctrl); + + p_ctrl->sa = sa; + p_ctrl->p_log = p_log; + p_ctrl->p_disp = p_disp; + p_ctrl->p_mad_pool = p_mad_pool; + p_ctrl->p_vendor = p_vendor; + p_ctrl->p_stats = p_stats; + p_ctrl->p_subn = p_subn; + + p_ctrl->h_disp = cl_disp_register(p_disp, + CL_DISP_MSGID_NONE, NULL, p_ctrl); + + if (p_ctrl->h_disp == CL_DISP_INVALID_HANDLE) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 1A08: " + "Dispatcher registration failed\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sa_mad_ctrl_bind(IN osm_sa_mad_ctrl_t * const p_ctrl, + IN const ib_net64_t port_guid) +{ + osm_bind_info_t bind_info; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_ctrl->p_log); + + if (p_ctrl->h_bind != OSM_BIND_INVALID_HANDLE) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A09: " + "Multiple binds not allowed\n"); + status = IB_ERROR; + goto Exit; + } + + bind_info.class_version = 2; + bind_info.is_responder = TRUE; + bind_info.is_report_processor = FALSE; + bind_info.is_trap_processor = FALSE; + bind_info.mad_class = IB_MCLASS_SUBN_ADM; + bind_info.port_guid = port_guid; + bind_info.recv_q_size = OSM_SM_DEFAULT_QP1_RCV_SIZE; + bind_info.send_q_size = OSM_SM_DEFAULT_QP1_SEND_SIZE; + + OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE, + "Binding to port GUID 0x%" PRIx64 "\n", cl_ntoh64(port_guid)); + + p_ctrl->h_bind = osm_vendor_bind(p_ctrl->p_vendor, + &bind_info, + p_ctrl->p_mad_pool, + __osm_sa_mad_ctrl_rcv_callback, + __osm_sa_mad_ctrl_send_err_callback, + p_ctrl); + + if (p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE) { + status = IB_ERROR; + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A10: " + "Vendor specific bind failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_ctrl->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t osm_sa_mad_ctrl_unbind(IN osm_sa_mad_ctrl_t * const p_ctrl) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_ctrl->p_log); + + if (p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 1A11: " + "No previous bind\n"); + status = IB_ERROR; + goto Exit; + } + + osm_vendor_unbind(p_ctrl->h_bind); +Exit: + OSM_LOG_EXIT(p_ctrl->p_log); + return (status); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_mcmember_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_mcmember_record.c new file mode 100644 index 000000000000..37e78b583c6d --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_mcmember_record.c @@ -0,0 +1,1735 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mcmr_recv_t. + * This object represents the MCMemberRecord Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define JOIN_MC_COMP_MASK (IB_MCR_COMPMASK_MGID | \ + IB_MCR_COMPMASK_PORT_GID | \ + IB_MCR_COMPMASK_JOIN_STATE) + +#define REQUIRED_MC_CREATE_COMP_MASK (IB_MCR_COMPMASK_MGID | \ + IB_MCR_COMPMASK_PORT_GID | \ + IB_MCR_COMPMASK_JOIN_STATE | \ + IB_MCR_COMPMASK_QKEY | \ + IB_MCR_COMPMASK_TCLASS | \ + IB_MCR_COMPMASK_PKEY | \ + IB_MCR_COMPMASK_FLOW | \ + IB_MCR_COMPMASK_SL) + +typedef struct osm_mcmr_item { + cl_list_item_t list_item; + ib_member_rec_t rec; +} osm_mcmr_item_t; + +/********************************************************************* + Copy certain fields between two mcmember records + used during the process of join request to copy data from the mgrp + to the port record. +**********************************************************************/ +static inline void +__copy_from_create_mc_rec(IN ib_member_rec_t * const dest, + IN const ib_member_rec_t * const src) +{ + dest->qkey = src->qkey; + dest->mlid = src->mlid; + dest->tclass = src->tclass; + dest->pkey = src->pkey; + dest->sl_flow_hop = src->sl_flow_hop; + dest->mtu = src->mtu; + dest->rate = src->rate; + dest->pkt_life = src->pkt_life; +} + +/********************************************************************* + Return mlid to the pool of free mlids. + But this implementation is not a pool - it simply scans through + the MGRP database for unused mlids... +*********************************************************************/ +static void __free_mlid(IN osm_sa_t * sa, IN uint16_t mlid) +{ + UNUSED_PARAM(sa); + UNUSED_PARAM(mlid); +} + +/********************************************************************* + Get a new unused mlid by scanning all the used ones in the subnet. +**********************************************************************/ +static ib_net16_t __get_new_mlid(osm_sa_t *sa, ib_net16_t requested_mlid) +{ + osm_subn_t *p_subn = sa->p_subn; + unsigned i, max; + + if (requested_mlid && cl_ntoh16(requested_mlid) >= IB_LID_MCAST_START_HO + && cl_ntoh16(requested_mlid) <= p_subn->max_mcast_lid_ho + && !osm_get_mgrp_by_mlid(p_subn, requested_mlid)) + return requested_mlid; + + max = p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO + 1; + for (i = 0; i < max; i++) { + osm_mgrp_t *p_mgrp = sa->p_subn->mgroups[i]; + if (!p_mgrp || p_mgrp->to_be_deleted) + return cl_hton16(i + IB_LID_MCAST_START_HO); + } + + return 0; +} + +/********************************************************************* + This procedure is only invoked to cleanup an INTERMEDIATE mgrp. + If there is only one port on the mgrp it means that the current + request was the only member and the group is not really needed. So + we silently drop it. Since it was an intermediate group no need to + re-route it. +**********************************************************************/ +static void __cleanup_mgrp(IN osm_sa_t * sa, osm_mgrp_t *mgrp) +{ + /* Remove MGRP only if osm_mcm_port_t count is 0 and + not a well known group */ + if (cl_is_qmap_empty(&mgrp->mcm_port_tbl) && !mgrp->well_known) { + sa->p_subn->mgroups[cl_ntoh16(mgrp->mlid) - IB_LID_MCAST_START_HO] = NULL; + osm_mgrp_delete(mgrp); + } +} + +/********************************************************************* + Add a port to the group. Calculating its PROXY_JOIN by the Port and + requester gids. +**********************************************************************/ +static ib_api_status_t +__add_new_mgrp_port(IN osm_sa_t * sa, + IN osm_mgrp_t * p_mgrp, + IN ib_member_rec_t * p_recvd_mcmember_rec, + IN osm_mad_addr_t * p_mad_addr, + OUT osm_mcm_port_t ** pp_mcmr_port) +{ + boolean_t proxy_join; + ib_gid_t requester_gid; + ib_api_status_t res; + + /* set the proxy_join if the requester gid is not identical to the + joined gid */ + res = osm_get_gid_by_mad_addr(sa->p_log, sa->p_subn, + p_mad_addr, &requester_gid); + if (res != IB_SUCCESS) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B29: " + "Could not find GID for requester\n"); + + return IB_INVALID_PARAMETER; + } + + if (!memcmp(&p_recvd_mcmember_rec->port_gid, &requester_gid, + sizeof(ib_gid_t))) { + proxy_join = FALSE; + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Create new port with proxy_join FALSE\n"); + } else { + /* The port is not the one specified in PortGID. + The check that the requester is in the same partition as + the PortGID is done before - just need to update + the proxy_join. */ + proxy_join = TRUE; + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Create new port with proxy_join TRUE\n"); + } + + *pp_mcmr_port = osm_mgrp_add_port(sa->p_subn, sa->p_log, p_mgrp, + &p_recvd_mcmember_rec->port_gid, + p_recvd_mcmember_rec->scope_state, + proxy_join); + if (*pp_mcmr_port == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B06: " + "osm_mgrp_add_port failed\n"); + + return IB_INSUFFICIENT_MEMORY; + } + + return IB_SUCCESS; +} + +/********************************************************************** + **********************************************************************/ +static inline boolean_t __check_join_comp_mask(ib_net64_t comp_mask) +{ + return ((comp_mask & JOIN_MC_COMP_MASK) == JOIN_MC_COMP_MASK); +} + +/********************************************************************** + **********************************************************************/ +static inline boolean_t +__check_create_comp_mask(ib_net64_t comp_mask, + ib_member_rec_t * p_recvd_mcmember_rec) +{ + return ((comp_mask & REQUIRED_MC_CREATE_COMP_MASK) == + REQUIRED_MC_CREATE_COMP_MASK); +} + +/********************************************************************** + Generate the response MAD +**********************************************************************/ +static void +__osm_mcmr_rcv_respond(IN osm_sa_t * sa, + IN osm_madw_t * const p_madw, + IN ib_member_rec_t * p_mcmember_rec) +{ + cl_qlist_t rec_list; + osm_mcmr_item_t *item; + + OSM_LOG_ENTER(sa->p_log); + + item = malloc(sizeof(*item)); + if (!item) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B16: " + "rec_item alloc failed\n"); + goto Exit; + } + + item->rec = *p_mcmember_rec; + + /* Fill in the mtu, rate, and packet lifetime selectors */ + item->rec.mtu &= 0x3f; + item->rec.mtu |= 2 << 6; /* exactly */ + item->rec.rate &= 0x3f; + item->rec.rate |= 2 << 6; /* exactly */ + item->rec.pkt_life &= 0x3f; + item->rec.pkt_life |= 2 << 6; /* exactly */ + + cl_qlist_init(&rec_list); + cl_qlist_insert_tail(&rec_list, &item->list_item); + + osm_sa_respond(sa, p_madw, sizeof(ib_member_rec_t), &rec_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************* + In joining an existing group, or when querying the mc groups, + we make sure the following components provided match: MTU and RATE + HACK: Currently we ignore the PKT_LIFETIME field. +**********************************************************************/ +static boolean_t +__validate_more_comp_fields(osm_log_t * p_log, + const osm_mgrp_t * p_mgrp, + const ib_member_rec_t * p_recvd_mcmember_rec, + ib_net64_t comp_mask) +{ + uint8_t mtu_sel; + uint8_t mtu_required; + uint8_t mtu_mgrp; + uint8_t rate_sel; + uint8_t rate_required; + uint8_t rate_mgrp; + + if (comp_mask & IB_MCR_COMPMASK_MTU_SEL) { + mtu_sel = (uint8_t) (p_recvd_mcmember_rec->mtu >> 6); + /* Clearing last 2 bits */ + mtu_required = (uint8_t) (p_recvd_mcmember_rec->mtu & 0x3F); + mtu_mgrp = (uint8_t) (p_mgrp->mcmember_rec.mtu & 0x3F); + switch (mtu_sel) { + case 0: /* Greater than MTU specified */ + if (mtu_mgrp <= mtu_required) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Requested mcast group has MTU %x, " + "which is not greater than %x\n", + mtu_mgrp, mtu_required); + return FALSE; + } + break; + case 1: /* Less than MTU specified */ + if (mtu_mgrp >= mtu_required) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Requested mcast group has MTU %x, " + "which is not less than %x\n", + mtu_mgrp, mtu_required); + return FALSE; + } + break; + case 2: /* Exactly MTU specified */ + if (mtu_mgrp != mtu_required) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Requested mcast group has MTU %x, " + "which is not equal to %x\n", + mtu_mgrp, mtu_required); + return FALSE; + } + break; + default: + break; + } + } + + /* what about rate ? */ + if (comp_mask & IB_MCR_COMPMASK_RATE_SEL) { + rate_sel = (uint8_t) (p_recvd_mcmember_rec->rate >> 6); + /* Clearing last 2 bits */ + rate_required = (uint8_t) (p_recvd_mcmember_rec->rate & 0x3F); + rate_mgrp = (uint8_t) (p_mgrp->mcmember_rec.rate & 0x3F); + switch (rate_sel) { + case 0: /* Greater than RATE specified */ + if (rate_mgrp <= rate_required) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Requested mcast group has RATE %x, " + "which is not greater than %x\n", + rate_mgrp, rate_required); + return FALSE; + } + break; + case 1: /* Less than RATE specified */ + if (rate_mgrp >= rate_required) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Requested mcast group has RATE %x, " + "which is not less than %x\n", + rate_mgrp, rate_required); + return FALSE; + } + break; + case 2: /* Exactly RATE specified */ + if (rate_mgrp != rate_required) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Requested mcast group has RATE %x, " + "which is not equal to %x\n", + rate_mgrp, rate_required); + return FALSE; + } + break; + default: + break; + } + } + + return TRUE; +} + +/********************************************************************* + In joining an existing group, we make sure the following components + are physically realizable: MTU and RATE +**********************************************************************/ +static boolean_t +__validate_port_caps(osm_log_t * const p_log, + const osm_mgrp_t * p_mgrp, const osm_physp_t * p_physp) +{ + uint8_t mtu_required; + uint8_t mtu_mgrp; + uint8_t rate_required; + uint8_t rate_mgrp; + + mtu_required = ib_port_info_get_mtu_cap(&p_physp->port_info); + mtu_mgrp = (uint8_t) (p_mgrp->mcmember_rec.mtu & 0x3F); + if (mtu_required < mtu_mgrp) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Port's MTU %x is less than %x\n", + mtu_required, mtu_mgrp); + return FALSE; + } + + rate_required = ib_port_info_compute_rate(&p_physp->port_info); + rate_mgrp = (uint8_t) (p_mgrp->mcmember_rec.rate & 0x3F); + if (rate_required < rate_mgrp) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Port's RATE %x is less than %x\n", + rate_required, rate_mgrp); + return FALSE; + } + + return TRUE; +} + +/********************************************************************** + * o15-0.2.1: If SA supports UD multicast, then if SA receives a SubnAdmSet() + * or SubnAdmDelete() method that would modify an existing + * MCMemberRecord, SA shall not modify that MCMemberRecord and shall + * return an error status of ERR_REQ_INVALID in response in the + * following cases: + * 1. Saved MCMemberRecord.ProxyJoin is not set and the request is + * issued by a requester with a GID other than the Port-GID. + * 2. Saved MCMemberRecord.ProxyJoin is set and the requester is not + * part of the partition for that MCMemberRecord. + **********************************************************************/ +static boolean_t +__validate_modify(IN osm_sa_t * sa, + IN osm_mgrp_t * p_mgrp, + IN osm_mad_addr_t * p_mad_addr, + IN ib_member_rec_t * p_recvd_mcmember_rec, + OUT osm_mcm_port_t ** pp_mcm_port) +{ + ib_net64_t portguid; + ib_gid_t request_gid; + osm_physp_t *p_request_physp; + ib_api_status_t res; + + portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id; + + *pp_mcm_port = NULL; + + /* o15-0.2.1: If this is a new port being added - nothing to check */ + if (!osm_mgrp_is_port_present(p_mgrp, portguid, pp_mcm_port)) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "This is a new port in the MC group\n"); + return TRUE; + } + + /* We validate the request according the the proxy_join. + Check if the proxy_join is set or not */ + if ((*pp_mcm_port)->proxy_join == FALSE) { + /* The proxy_join is not set. Modifying can by done only + if the requester GID == PortGID */ + res = osm_get_gid_by_mad_addr(sa->p_log, + sa->p_subn, + p_mad_addr, &request_gid); + + if (res != IB_SUCCESS) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Could not find port for requested address\n"); + return FALSE; + } + + if (memcmp(&((*pp_mcm_port)->port_gid), &request_gid, + sizeof(ib_gid_t))) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "No ProxyJoin but different ports: stored:" + "0x%016" PRIx64 " request:0x%016" PRIx64 "\n", + cl_ntoh64((*pp_mcm_port)->port_gid.unicast. + interface_id), + cl_ntoh64(p_mad_addr->addr_type.gsi.grh_info. + src_gid.unicast.interface_id)); + return FALSE; + } + } else { + /* The proxy_join is set. Modification allowed only if the + requester is part of the partition for this MCMemberRecord */ + p_request_physp = osm_get_physp_by_mad_addr(sa->p_log, + sa->p_subn, + p_mad_addr); + if (p_request_physp == NULL) + return FALSE; + + if (!osm_physp_has_pkey(sa->p_log, p_mgrp->mcmember_rec.pkey, + p_request_physp)) { + /* the request port is not part of the partition for this mgrp */ + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "ProxyJoin but port not in partition. stored:" + "0x%016" PRIx64 " request:0x%016" PRIx64 "\n", + cl_ntoh64((*pp_mcm_port)->port_gid.unicast. + interface_id), + cl_ntoh64(p_mad_addr->addr_type.gsi.grh_info. + src_gid.unicast.interface_id)); + return FALSE; + } + } + return TRUE; +} + +/********************************************************************** + **********************************************************************/ +/* + * Check legality of the requested MGID DELETE + * o15-0.1.14 = VALID DELETE: + * To be a valid delete MAD needs to: + * 1 the MADs PortGID and MGID components match the PortGID and + * MGID of a stored MCMemberRecord; + * 2 the MADs JoinState component contains at least one bit set to 1 + * in the same position as that stored MCMemberRecords JoinState + * has a bit set to 1, + * i.e., the logical AND of the two JoinState components + * is not all zeros; + * 3 the MADs JoinState component does not have some bits set + * which are not set in the stored MCMemberRecords JoinState component; + * 4 either the stored MCMemberRecord:ProxyJoin is reset (0), and the + * MADs source is the stored PortGID; + * OR + * the stored MCMemberRecord:ProxyJoin is set (1), (see o15- + * 0.1.2:); and the MADs source is a member of the partition indicated + * by the stored MCMemberRecord:P_Key. + */ +static boolean_t +__validate_delete(IN osm_sa_t * sa, + IN osm_mgrp_t * p_mgrp, + IN osm_mad_addr_t * p_mad_addr, + IN ib_member_rec_t * p_recvd_mcmember_rec, + OUT osm_mcm_port_t ** pp_mcm_port) +{ + ib_net64_t portguid; + + portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id; + + *pp_mcm_port = NULL; + + /* 1 */ + if (!osm_mgrp_is_port_present(p_mgrp, portguid, pp_mcm_port)) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Failed to find the port in the MC group\n"); + return FALSE; + } + + /* 2 */ + if (!(p_recvd_mcmember_rec->scope_state & 0x0F & + (*pp_mcm_port)->scope_state)) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Could not find any matching bits in the stored " + "and requested JoinStates\n"); + return FALSE; + } + + /* 3 */ + if (((p_recvd_mcmember_rec->scope_state & 0x0F) | + (0x0F & (*pp_mcm_port)->scope_state)) != + (0x0F & (*pp_mcm_port)->scope_state)) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Some bits in the request JoinState (0x%X) are not " + "set in the stored port (0x%X)\n", + (p_recvd_mcmember_rec->scope_state & 0x0F), + (0x0F & (*pp_mcm_port)->scope_state)); + return FALSE; + } + + /* 4 */ + /* Validate according the the proxy_join (o15-0.1.2) */ + if (__validate_modify(sa, p_mgrp, p_mad_addr, p_recvd_mcmember_rec, + pp_mcm_port) == FALSE) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "proxy_join validation failure\n"); + return FALSE; + } + return TRUE; +} + +/********************************************************************** + **********************************************************************/ +/* + * Check legality of the requested MGID (note this does not hold for SA + * created MGIDs) + * + * Implementing o15-0.1.5: + * A multicast GID is considered to be invalid if: + * 1. It does not comply with the rules as specified in 4.1.1 "GID Usage and + * Properties" on page 145: + * + * 14) The multicast GID format is (bytes are comma sep): + * 0xff,,,,

,

,

,

,

,

,

,

,,,, + * Fl 4bit = Flags (b) + * Sc 4bit = Scope (c) + * Si 16bit = Signature (2) + * P 64bit = GID Prefix (should be a subnet unique ID - normally Subnet Prefix) + * Id 32bit = Unique ID in the Subnet (might be MLID or Pkey ?) + * + * a) 8-bits of 11111111 at the start of the GID identifies this as being a + * multicast GID. + * b) Flags is a set of four 1-bit flags: 000T with three flags reserved + * and defined as zero (0). The T flag is defined as follows: + * i) T = 0 indicates this is a permanently assigned (i.e. wellknown) + * multicast GID. See RFC 2373 and RFC 2375 as reference + * for these permanently assigned GIDs. + * ii) T = 1 indicates this is a non-permanently assigned (i.e. transient) + * multicast GID. + * c) Scope is a 4-bit multicast scope value used to limit the scope of + * the multicast group. The following table defines scope value and + * interpretation. + * + * Multicast Address Scope Values: + * 0x2 Link-local + * 0x5 Site-local + * 0x8 Organization-local + * 0xE Global + * + * 2. It contains the SA-specific signature of 0xA01B and has the link-local + * scope bits set. (EZ: the idea here is that SA created MGIDs are the + * only source for this signature with link-local scope) + */ +static ib_api_status_t +__validate_requested_mgid(IN osm_sa_t * sa, + IN const ib_member_rec_t * p_mcm_rec) +{ + uint16_t signature; + boolean_t valid = TRUE; + + OSM_LOG_ENTER(sa->p_log); + + /* 14-a: mcast GID must start with 0xFF */ + if (p_mcm_rec->mgid.multicast.header[0] != 0xFF) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B01: " + "Wrong MGID Prefix 0x%02X must be 0xFF\n", + cl_ntoh16(p_mcm_rec->mgid.multicast.header[0])); + valid = FALSE; + goto Exit; + } + + /* the MGID signature can mark IPoIB or SA assigned MGIDs */ + memcpy(&signature, &(p_mcm_rec->mgid.multicast.raw_group_id), + sizeof(signature)); + signature = cl_ntoh16(signature); + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "MGID Signed as 0x%04X\n", signature); + + /* + * We skip any checks for MGIDs that follow IPoIB + * GID structure as defined by the IETF ipoib-link-multicast. + * + * For IPv4 over IB, the signature will be "0x401B". + * + * | 8 | 4 | 4 | 16 bits | 16 bits | 48 bits | 32 bits | + * +--------+----+----+-----------------+---------+----------+---------+ + * |11111111|0001|scop||< P_Key >|00.......0|| + * +--------+----+----+-----------------+---------+----------+---------+ + * + * For IPv6 over IB, the signature will be "0x601B". + * + * | 8 | 4 | 4 | 16 bits | 16 bits | 80 bits | + * +--------+----+----+-----------------+---------+--------------------+ + * |11111111|0001|scop||< P_Key >|000.............0001| + * +--------+----+----+-----------------+---------+--------------------+ + * + */ + if (signature == 0x401B || signature == 0x601B) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Skipping MGID Validation for IPoIB Signed (0x%04X) MGIDs\n", + signature); + goto Exit; + } + + /* 14-b: the 3 upper bits in the "flags" should be zero: */ + if (p_mcm_rec->mgid.multicast.header[1] & 0xE0) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B28: " + "MGID uses Reserved Flags: flags=0x%X\n", + (p_mcm_rec->mgid.multicast.header[1] & 0xE0) >> 4); + valid = FALSE; + goto Exit; + } + + /* 2 - now what if the link local format 0xA01B is used - + the scope should not be link local */ + if (signature == 0xA01B && + (p_mcm_rec->mgid.multicast.header[1] & 0x0F) == + IB_MC_SCOPE_LINK_LOCAL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B24: " + "MGID uses 0xA01B signature but with link-local scope\n"); + valid = FALSE; + goto Exit; + } + + /* + * For SA assigned MGIDs (signature 0xA01B): + * There is no real way to make sure the Unique MGID Prefix is really unique. + * If we could enforce using the Subnet Prefix for that purpose it would + * have been nice. But the spec does not require it. + */ + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (valid); +} + +/********************************************************************** + Check if the requested new MC group parameters are realizable. + Also set the default MTU and Rate if not provided by the user. +**********************************************************************/ +static boolean_t +__mgrp_request_is_realizable(IN osm_sa_t * sa, + IN ib_net64_t comp_mask, + IN ib_member_rec_t * p_mcm_rec, + IN const osm_physp_t * const p_physp) +{ + uint8_t mtu_sel = 2; /* exactly */ + uint8_t mtu_required, mtu, port_mtu; + uint8_t rate_sel = 2; /* exactly */ + uint8_t rate_required, rate, port_rate; + osm_log_t *p_log = sa->p_log; + + OSM_LOG_ENTER(sa->p_log); + + /* + * End of o15-0.2.3 specifies: + * .... + * The entity may also supply the other components such as HopLimit, + * MTU, etc. during group creation time. If these components are not + * provided during group creation time, SA will provide them for the + * group. The values chosen are vendor-dependent and beyond the scope + * of the specification. + * + * so we might also need to assign RATE/MTU if they are not comp + * masked in. + */ + + port_mtu = p_physp ? ib_port_info_get_mtu_cap(&p_physp->port_info) : 0; + if (!(comp_mask & IB_MCR_COMPMASK_MTU) || + !(comp_mask & IB_MCR_COMPMASK_MTU_SEL) || + (mtu_sel = (p_mcm_rec->mtu >> 6)) == 3) + mtu = port_mtu ? port_mtu : sa->p_subn->min_ca_mtu; + else { + mtu_required = (uint8_t) (p_mcm_rec->mtu & 0x3F); + mtu = mtu_required; + switch (mtu_sel) { + case 0: /* Greater than MTU specified */ + if (port_mtu && mtu_required >= port_mtu) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Requested MTU %x >= the port\'s mtu:%x\n", + mtu_required, port_mtu); + return FALSE; + } + /* we provide the largest MTU possible if we can */ + if (port_mtu) + mtu = port_mtu; + else if (mtu_required < sa->p_subn->min_ca_mtu) + mtu = sa->p_subn->min_ca_mtu; + else + mtu++; + break; + case 1: /* Less than MTU specified */ + /* use the smaller of the two: + a. one lower then the required + b. the mtu of the requesting port (if exists) */ + if (port_mtu && mtu_required > port_mtu) + mtu = port_mtu; + else + mtu--; + break; + case 2: /* Exactly MTU specified */ + default: + break; + } + /* make sure it still be in the range */ + if (mtu < IB_MIN_MTU || mtu > IB_MAX_MTU) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Calculated MTU %x is out of range\n", mtu); + return FALSE; + } + } + p_mcm_rec->mtu = (mtu_sel << 6) | mtu; + + port_rate = + p_physp ? ib_port_info_compute_rate(&p_physp->port_info) : 0; + if (!(comp_mask & IB_MCR_COMPMASK_RATE) + || !(comp_mask & IB_MCR_COMPMASK_RATE_SEL) + || (rate_sel = (p_mcm_rec->rate >> 6)) == 3) + rate = port_rate ? port_rate : sa->p_subn->min_ca_rate; + else { + rate_required = (uint8_t) (p_mcm_rec->rate & 0x3F); + rate = rate_required; + switch (rate_sel) { + case 0: /* Greater than RATE specified */ + if (port_rate && rate_required >= port_rate) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Requested RATE %x >= the port\'s rate:%x\n", + rate_required, port_rate); + return FALSE; + } + /* we provide the largest RATE possible if we can */ + if (port_rate) + rate = port_rate; + else if (rate_required < sa->p_subn->min_ca_rate) + rate = sa->p_subn->min_ca_rate; + else + rate++; + break; + case 1: /* Less than RATE specified */ + /* use the smaller of the two: + a. one lower then the required + b. the rate of the requesting port (if exists) */ + if (port_rate && rate_required > port_rate) + rate = port_rate; + else + rate--; + break; + case 2: /* Exactly RATE specified */ + default: + break; + } + /* make sure it still is in the range */ + if (rate < IB_MIN_RATE || rate > IB_MAX_RATE) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Calculated RATE %x is out of range\n", rate); + return FALSE; + } + } + p_mcm_rec->rate = (rate_sel << 6) | rate; + + OSM_LOG_EXIT(sa->p_log); + return TRUE; +} + +/********************************************************************** + Call this function to create a new mgrp. +**********************************************************************/ +ib_api_status_t +osm_mcmr_rcv_create_new_mgrp(IN osm_sa_t * sa, + IN ib_net64_t comp_mask, + IN const ib_member_rec_t * + const p_recvd_mcmember_rec, + IN const osm_physp_t * const p_physp, + OUT osm_mgrp_t ** pp_mgrp) +{ + ib_net16_t mlid; + unsigned zero_mgid, i; + uint8_t scope; + ib_gid_t *p_mgid; + osm_mgrp_t *p_prev_mgrp; + ib_api_status_t status = IB_SUCCESS; + ib_member_rec_t mcm_rec = *p_recvd_mcmember_rec; /* copy for modifications */ + + OSM_LOG_ENTER(sa->p_log); + + /* but what if the given MGID was not 0 ? */ + zero_mgid = 1; + for (i = 0; i < sizeof(p_recvd_mcmember_rec->mgid); i++) + if (p_recvd_mcmember_rec->mgid.raw[i] != 0) { + zero_mgid = 0; + break; + } + + /* + we allocate a new mlid number before we might use it + for MGID ... + */ + mlid = __get_new_mlid(sa, mcm_rec.mlid); + if (mlid == 0) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B19: " + "__get_new_mlid failed request mlid 0x%04x\n", cl_ntoh16(mcm_rec.mlid)); + status = IB_SA_MAD_STATUS_NO_RESOURCES; + goto Exit; + } + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Obtained new mlid 0x%X\n", cl_ntoh16(mlid)); + + /* we need to create the new MGID if it was not defined */ + if (zero_mgid) { + /* create a new MGID */ + char gid_str[INET6_ADDRSTRLEN]; + + /* use the given scope state only if requested! */ + if (comp_mask & IB_MCR_COMPMASK_SCOPE) + ib_member_get_scope_state(p_recvd_mcmember_rec-> + scope_state, &scope, NULL); + else + /* to guarantee no collision with other subnets use local scope! */ + scope = IB_MC_SCOPE_LINK_LOCAL; + + p_mgid = &(mcm_rec.mgid); + p_mgid->raw[0] = 0xFF; + p_mgid->raw[1] = 0x10 | scope; + p_mgid->raw[2] = 0xA0; + p_mgid->raw[3] = 0x1B; + + /* HACK: use the SA port gid to make it globally unique */ + memcpy((&p_mgid->raw[4]), + &sa->p_subn->opt.subnet_prefix, sizeof(uint64_t)); + + /* HACK: how do we get a unique number - use the mlid twice */ + memcpy(&p_mgid->raw[10], &mlid, sizeof(uint16_t)); + memcpy(&p_mgid->raw[12], &mlid, sizeof(uint16_t)); + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Allocated new MGID:%s\n", + inet_ntop(AF_INET6, p_mgid->raw, gid_str, + sizeof gid_str)); + } else if (!__validate_requested_mgid(sa, &mcm_rec)) { + /* a specific MGID was requested so validate the resulting MGID */ + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B22: " + "Invalid requested MGID\n"); + __free_mlid(sa, mlid); + status = IB_SA_MAD_STATUS_REQ_INVALID; + goto Exit; + } + + /* check the requested parameters are realizable */ + if (__mgrp_request_is_realizable(sa, comp_mask, &mcm_rec, p_physp) == + FALSE) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B26: " + "Requested MGRP parameters are not realizable\n"); + __free_mlid(sa, mlid); + status = IB_SA_MAD_STATUS_REQ_INVALID; + goto Exit; + } + + /* create a new MC Group */ + *pp_mgrp = osm_mgrp_new(mlid); + if (*pp_mgrp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B08: " + "osm_mgrp_new failed\n"); + __free_mlid(sa, mlid); + status = IB_SA_MAD_STATUS_NO_RESOURCES; + goto Exit; + } + + /* Initialize the mgrp */ + (*pp_mgrp)->mcmember_rec = mcm_rec; + (*pp_mgrp)->mcmember_rec.mlid = mlid; + + /* the mcmember_record should have mtu_sel, rate_sel, and pkt_lifetime_sel = 2 */ + (*pp_mgrp)->mcmember_rec.mtu &= 0x3f; + (*pp_mgrp)->mcmember_rec.mtu |= 2 << 6; /* exactly */ + (*pp_mgrp)->mcmember_rec.rate &= 0x3f; + (*pp_mgrp)->mcmember_rec.rate |= 2 << 6; /* exactly */ + (*pp_mgrp)->mcmember_rec.pkt_life &= 0x3f; + (*pp_mgrp)->mcmember_rec.pkt_life |= 2 << 6; /* exactly */ + + /* Insert the new group in the data base */ + + /* since we might have an old group by that mlid + one whose deletion was delayed for an idle time + we need to deallocate it first */ + p_prev_mgrp = osm_get_mgrp_by_mlid(sa->p_subn, mlid); + if (p_prev_mgrp) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Found previous group for mlid:0x%04x - " + "Destroying it first\n", + cl_ntoh16(mlid)); + sa->p_subn->mgroups[cl_ntoh16(mlid) - IB_LID_MCAST_START_HO] = NULL; + osm_mgrp_delete(p_prev_mgrp); + } + + sa->p_subn->mgroups[cl_ntoh16(mlid) - IB_LID_MCAST_START_HO] = *pp_mgrp; + +Exit: + OSM_LOG_EXIT(sa->p_log); + return status; +} + +/********************************************************************** + *********************************************************************/ +static unsigned match_mgrp_by_mgid(IN osm_mgrp_t * const p_mgrp, ib_gid_t *mgid) +{ + /* ignore groups marked for deletion */ + if (p_mgrp->to_be_deleted || + memcmp(&p_mgrp->mcmember_rec.mgid, mgid, sizeof(ib_gid_t))) + return 0; + else + return 1; +} + +/********************************************************************** + **********************************************************************/ +#define PREFIX_MASK CL_HTON64(0xff10ffff0000ffffULL) +#define PREFIX_SIGNATURE CL_HTON64(0xff10601b00000000ULL) +#define INT_ID_MASK CL_HTON64(0xfffffff1ff000000ULL) +#define INT_ID_SIGNATURE CL_HTON64(0x00000001ff000000ULL) + +/* Special Case IPv6 Solicited Node Multicast (SNM) addresses */ +/* 0xff1Z601bXXXX0000 : 0x00000001ffYYYYYY */ +/* Where Z is the scope, XXXX is the P_Key, and + * YYYYYY is the last 24 bits of the port guid */ +static unsigned match_and_update_ipv6_snm_mgid(ib_gid_t *mgid) +{ + if ((mgid->unicast.prefix & PREFIX_MASK) == PREFIX_SIGNATURE && + (mgid->unicast.interface_id & INT_ID_MASK) == INT_ID_SIGNATURE) { + mgid->unicast.prefix &= PREFIX_MASK; + mgid->unicast.interface_id &= INT_ID_MASK; + return 1; + } + return 0; +} + +osm_mgrp_t *osm_get_mgrp_by_mgid(IN osm_sa_t *sa, IN ib_gid_t *p_mgid) +{ + int i; + + if (sa->p_subn->opt.consolidate_ipv6_snm_req && + match_and_update_ipv6_snm_mgid(p_mgid)) { + char gid_str[INET6_ADDRSTRLEN]; + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Special Case Solicited Node Mcast Join for MGID %s\n", + inet_ntop(AF_INET6, p_mgid->raw, gid_str, + sizeof gid_str)); + } + + for (i = 0; i <= sa->p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO; + i++) + if (sa->p_subn->mgroups[i] && + match_mgrp_by_mgid(sa->p_subn->mgroups[i], p_mgid)) + return sa->p_subn->mgroups[i]; + + return NULL; +} + +/********************************************************************** + Call this function to find or create a new mgrp. +**********************************************************************/ +ib_api_status_t +osm_mcmr_rcv_find_or_create_new_mgrp(IN osm_sa_t * sa, + IN ib_net64_t comp_mask, + IN ib_member_rec_t * + const p_recvd_mcmember_rec, + OUT osm_mgrp_t ** pp_mgrp) +{ + osm_mgrp_t *mgrp; + + if ((mgrp = osm_get_mgrp_by_mgid(sa, &p_recvd_mcmember_rec->mgid))) { + *pp_mgrp = mgrp; + return IB_SUCCESS; + } + return osm_mcmr_rcv_create_new_mgrp(sa, comp_mask, + p_recvd_mcmember_rec, NULL, + pp_mgrp); +} + +/********************************************************************* +Process a request for leaving the group +**********************************************************************/ +static void +__osm_mcmr_rcv_leave_mgrp(IN osm_sa_t * sa, + IN osm_madw_t * const p_madw) +{ + osm_mgrp_t *p_mgrp; + ib_sa_mad_t *p_sa_mad; + ib_member_rec_t *p_recvd_mcmember_rec; + ib_member_rec_t mcmember_rec; + ib_net16_t mlid; + ib_net64_t portguid; + osm_mcm_port_t *p_mcm_port; + int removed; + + OSM_LOG_ENTER(sa->p_log); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_recvd_mcmember_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + mcmember_rec = *p_recvd_mcmember_rec; + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Dump of record\n"); + osm_dump_mc_record(sa->p_log, &mcmember_rec, OSM_LOG_DEBUG); + } + + CL_PLOCK_EXCL_ACQUIRE(sa->p_lock); + p_mgrp = osm_get_mgrp_by_mgid(sa, &p_recvd_mcmember_rec->mgid); + if (!p_mgrp) { + char gid_str[INET6_ADDRSTRLEN]; + CL_PLOCK_RELEASE(sa->p_lock); + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Failed since multicast group %s not present\n", + inet_ntop(AF_INET6, p_recvd_mcmember_rec->mgid.raw, + gid_str, sizeof gid_str)); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + mlid = p_mgrp->mlid; + portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id; + + /* check validity of the delete request o15-0.1.14 */ + if (!__validate_delete(sa, p_mgrp, osm_madw_get_mad_addr_ptr(p_madw), + p_recvd_mcmember_rec, &p_mcm_port)) { + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + CL_PLOCK_RELEASE(sa->p_lock); + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B25: " + "Received an invalid delete request for " + "MGID: %s for PortGID: %s\n", + inet_ntop(AF_INET6, p_recvd_mcmember_rec->mgid.raw, + gid_str, sizeof gid_str), + inet_ntop(AF_INET6, p_recvd_mcmember_rec->port_gid.raw, + gid_str2, sizeof gid_str2)); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + /* store state - we'll need it if the port is removed */ + mcmember_rec.scope_state = p_mcm_port->scope_state; + + /* remove port or update join state */ + removed = osm_mgrp_remove_port(sa->p_subn, sa->p_log, p_mgrp, p_mcm_port, + p_recvd_mcmember_rec->scope_state&0x0F); + if (!removed) + mcmember_rec.scope_state = p_mcm_port->scope_state; + + CL_PLOCK_RELEASE(sa->p_lock); + + /* we can leave if port was deleted from MCG */ + if (removed && osm_sm_mcgrp_leave(sa->sm, mlid, portguid)) + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B09: " + "osm_sm_mcgrp_leave failed\n"); + + /* Send an SA response */ + __osm_mcmr_rcv_respond(sa, p_madw, &mcmember_rec); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + Handle a join (or create) request +**********************************************************************/ +static void +__osm_mcmr_rcv_join_mgrp(IN osm_sa_t * sa, IN osm_madw_t * const p_madw) +{ + osm_mgrp_t *p_mgrp = NULL; + ib_api_status_t status; + ib_sa_mad_t *p_sa_mad; + ib_member_rec_t *p_recvd_mcmember_rec; + ib_member_rec_t mcmember_rec; + ib_net16_t mlid; + osm_mcm_port_t *p_mcmr_port; + ib_net64_t portguid; + osm_port_t *p_port; + osm_physp_t *p_physp; + osm_physp_t *p_request_physp; + uint8_t is_new_group; /* TRUE = there is a need to create a group */ + osm_mcast_req_type_t req_type; + uint8_t join_state; + + OSM_LOG_ENTER(sa->p_log); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_recvd_mcmember_rec = ib_sa_mad_get_payload_ptr(p_sa_mad); + + portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id; + + mcmember_rec = *p_recvd_mcmember_rec; + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Dump of incoming record\n"); + osm_dump_mc_record(sa->p_log, &mcmember_rec, OSM_LOG_DEBUG); + } + + CL_PLOCK_EXCL_ACQUIRE(sa->p_lock); + + /* make sure the requested port guid is known to the SM */ + p_port = osm_get_port_by_guid(sa->p_subn, portguid); + if (!p_port) { + CL_PLOCK_RELEASE(sa->p_lock); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Unknown port GUID 0x%016" PRIx64 "\n", + cl_ntoh64(portguid)); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + p_physp = p_port->p_physp; + /* Check that the p_physp and the requester physp are in the same + partition. */ + p_request_physp = + osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr(p_madw)); + if (p_request_physp == NULL) { + CL_PLOCK_RELEASE(sa->p_lock); + goto Exit; + } + + if (!osm_physp_share_pkey(sa->p_log, p_physp, p_request_physp)) { + CL_PLOCK_RELEASE(sa->p_lock); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Port and requester don't share pkey\n"); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + ib_member_get_scope_state(p_recvd_mcmember_rec->scope_state, NULL, + &join_state); + + /* do we need to create a new group? */ + p_mgrp = osm_get_mgrp_by_mgid(sa, &p_recvd_mcmember_rec->mgid); + if (!p_mgrp || p_mgrp->to_be_deleted) { + /* check for JoinState.FullMember = 1 o15.0.1.9 */ + if ((join_state & 0x01) != 0x01) { + char gid_str[INET6_ADDRSTRLEN]; + CL_PLOCK_RELEASE(sa->p_lock); + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B10: " + "Provided Join State != FullMember - " + "required for create, " + "MGID: %s from port 0x%016" PRIx64 " (%s)\n", + inet_ntop(AF_INET6, + p_recvd_mcmember_rec->mgid.raw, + gid_str, sizeof gid_str), + cl_ntoh64(portguid), + p_port->p_node->print_desc); + osm_sa_send_error(sa, p_madw, + IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + /* check the comp_mask */ + if (!__check_create_comp_mask(p_sa_mad->comp_mask, + p_recvd_mcmember_rec)) { + char gid_str[INET6_ADDRSTRLEN]; + CL_PLOCK_RELEASE(sa->p_lock); + + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B11: " + "method = %s, scope_state = 0x%x, " + "component mask = 0x%016" PRIx64 ", " + "expected comp mask = 0x%016" PRIx64 ", " + "MGID: %s from port 0x%016" PRIx64 " (%s)\n", + ib_get_sa_method_str(p_sa_mad->method), + p_recvd_mcmember_rec->scope_state, + cl_ntoh64(p_sa_mad->comp_mask), + CL_NTOH64(REQUIRED_MC_CREATE_COMP_MASK), + inet_ntop(AF_INET6, + p_recvd_mcmember_rec->mgid.raw, + gid_str, sizeof gid_str), + cl_ntoh64(portguid), + p_port->p_node->print_desc); + + osm_sa_send_error(sa, p_madw, + IB_SA_MAD_STATUS_INSUF_COMPS); + goto Exit; + } + + status = osm_mcmr_rcv_create_new_mgrp(sa, p_sa_mad->comp_mask, + p_recvd_mcmember_rec, + p_physp, &p_mgrp); + if (status != IB_SUCCESS) { + CL_PLOCK_RELEASE(sa->p_lock); + osm_sa_send_error(sa, p_madw, status); + goto Exit; + } + /* copy the MGID to the result */ + mcmember_rec.mgid = p_mgrp->mcmember_rec.mgid; + is_new_group = 1; + req_type = OSM_MCAST_REQ_TYPE_CREATE; + } else { + /* no need for a new group */ + is_new_group = 0; + req_type = OSM_MCAST_REQ_TYPE_JOIN; + } + + CL_ASSERT(p_mgrp); + mlid = p_mgrp->mlid; + + /* + * o15-0.2.4: If SA supports UD multicast, then SA shall cause an + * endport to join an existing multicast group if: + * 1. It receives a SubnAdmSet() method for a MCMemberRecord, and + * - WE KNOW THAT ALREADY + * 2. The MGID is specified and matches an existing multicast + * group, and + * - WE KNOW THAT ALREADY + * 3. The MCMemberRecord:JoinState is not all 0s, and + * 4. PortGID is specified and + * - WE KNOW THAT ALREADY (as it matched a real one) + * 5. All other components match that existing group, either by + * being wildcarded or by having values identical to those specified + * by the component mask and in use by the group with the exception + * of components such as ProxyJoin and Reserved, which are ignored + * by SA. + * + * We need to check #3 and #5 here: + */ + if (!__validate_more_comp_fields(sa->p_log, p_mgrp, + p_recvd_mcmember_rec, + p_sa_mad->comp_mask) + || !__validate_port_caps(sa->p_log, p_mgrp, p_physp) + || !(join_state != 0)) { + /* since we might have created the new group we need to cleanup */ + __cleanup_mgrp(sa, p_mgrp); + + CL_PLOCK_RELEASE(sa->p_lock); + + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B12: " + "__validate_more_comp_fields, __validate_port_caps, " + "or JoinState = 0 failed from port 0x%016" PRIx64 + " (%s), " "sending IB_SA_MAD_STATUS_REQ_INVALID\n", + cl_ntoh64(portguid), p_port->p_node->print_desc); + + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + /* + * o15-0.2.1 requires validation of the requesting port + * in the case of modification: + */ + if (!is_new_group && + !__validate_modify(sa, p_mgrp, osm_madw_get_mad_addr_ptr(p_madw), + p_recvd_mcmember_rec, &p_mcmr_port)) { + CL_PLOCK_RELEASE(sa->p_lock); + + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B13: " + "__validate_modify failed from port 0x%016" PRIx64 + " (%s), sending IB_SA_MAD_STATUS_REQ_INVALID\n", + cl_ntoh64(portguid), p_port->p_node->print_desc); + + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + /* create or update existing port (join-state will be updated) */ + status = __add_new_mgrp_port(sa, p_mgrp, p_recvd_mcmember_rec, + osm_madw_get_mad_addr_ptr(p_madw), + &p_mcmr_port); + + if (status != IB_SUCCESS) { + /* we fail to add the port so we might need to delete the group */ + __cleanup_mgrp(sa, p_mgrp); + + CL_PLOCK_RELEASE(sa->p_lock); + + osm_sa_send_error(sa, p_madw, status == IB_INVALID_PARAMETER ? + IB_SA_MAD_STATUS_REQ_INVALID : + IB_SA_MAD_STATUS_NO_RESOURCES); + goto Exit; + } + + /* o15.0.1.11: copy the join state */ + mcmember_rec.scope_state = p_mcmr_port->scope_state; + + /* copy qkey mlid tclass pkey sl_flow_hop mtu rate pkt_life sl_flow_hop */ + __copy_from_create_mc_rec(&mcmember_rec, &p_mgrp->mcmember_rec); + + /* Release the lock as we don't need it. */ + CL_PLOCK_RELEASE(sa->p_lock); + + /* do the actual routing (actually schedule the update) */ + status = osm_sm_mcgrp_join(sa->sm, mlid, + p_recvd_mcmember_rec->port_gid.unicast. + interface_id, req_type); + + if (status != IB_SUCCESS) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B14: " + "osm_sm_mcgrp_join failed from port 0x%016" PRIx64 + " (%s), " "sending IB_SA_MAD_STATUS_NO_RESOURCES\n", + cl_ntoh64(portguid), p_port->p_node->print_desc); + + CL_PLOCK_EXCL_ACQUIRE(sa->p_lock); + + /* the request for routing failed so we need to remove the port */ + osm_mgrp_delete_port(sa->p_subn, sa->p_log, p_mgrp, + p_recvd_mcmember_rec->port_gid. + unicast.interface_id); + __cleanup_mgrp(sa, p_mgrp); + CL_PLOCK_RELEASE(sa->p_lock); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES); + goto Exit; + + } + /* failed to route */ + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_mc_record(sa->p_log, &mcmember_rec, OSM_LOG_DEBUG); + + __osm_mcmr_rcv_respond(sa, p_madw, &mcmember_rec); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + Add a patched multicast group to the results list +**********************************************************************/ +static ib_api_status_t +__osm_mcmr_rcv_new_mcmr(IN osm_sa_t * sa, + IN const ib_member_rec_t * p_rcvd_rec, + IN cl_qlist_t * const p_list) +{ + osm_mcmr_item_t *p_rec_item; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sa->p_log); + + p_rec_item = malloc(sizeof(*p_rec_item)); + if (p_rec_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B15: " + "rec_item alloc failed\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + memset(p_rec_item, 0, sizeof(*p_rec_item)); + + /* HACK: Untrusted requesters should result with 0 Join + State, Port Guid, and Proxy */ + p_rec_item->rec = *p_rcvd_rec; + cl_qlist_insert_tail(p_list, &p_rec_item->list_item); + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (status); +} + +/********************************************************************** + Match the given mgrp to the requested mcmr +**********************************************************************/ +static void mcmr_by_comp_mask(osm_sa_t *sa, const ib_member_rec_t *p_rcvd_rec, + ib_net64_t comp_mask, osm_mgrp_t *p_mgrp, + const osm_physp_t *p_req_physp, + boolean_t trusted_req, cl_qlist_t *list) +{ + /* since we might change scope_state */ + ib_member_rec_t match_rec; + osm_mcm_port_t *p_mcm_port; + ib_net64_t portguid = p_rcvd_rec->port_gid.unicast.interface_id; + /* will be used for group or port info */ + uint8_t scope_state; + uint8_t scope_state_mask = 0; + cl_map_item_t *p_item; + ib_gid_t port_gid; + boolean_t proxy_join = FALSE; + + OSM_LOG_ENTER(sa->p_log); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Checking mlid:0x%X\n", cl_ntoh16(p_mgrp->mlid)); + + /* the group might be marked for deletion */ + if (p_mgrp->to_be_deleted) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Group mlid:0x%X is marked to be deleted\n", + cl_ntoh16(p_mgrp->mlid)); + goto Exit; + } + + /* first try to eliminate the group by MGID, MLID, or P_Key */ + if ((IB_MCR_COMPMASK_MGID & comp_mask) && + memcmp(&p_rcvd_rec->mgid, &p_mgrp->mcmember_rec.mgid, + sizeof(ib_gid_t))) + goto Exit; + + if ((IB_MCR_COMPMASK_MLID & comp_mask) && + memcmp(&p_rcvd_rec->mlid, &p_mgrp->mcmember_rec.mlid, + sizeof(uint16_t))) + goto Exit; + + /* if the requester physical port doesn't have the pkey that is defined + for the group - exit. */ + if (!osm_physp_has_pkey(sa->p_log, p_mgrp->mcmember_rec.pkey, + p_req_physp)) + goto Exit; + + /* now do the rest of the match */ + if ((IB_MCR_COMPMASK_QKEY & comp_mask) && + p_rcvd_rec->qkey != p_mgrp->mcmember_rec.qkey) + goto Exit; + + if ((IB_MCR_COMPMASK_PKEY & comp_mask) && + p_rcvd_rec->pkey != p_mgrp->mcmember_rec.pkey) + goto Exit; + + if ((IB_MCR_COMPMASK_TCLASS & comp_mask) && + p_rcvd_rec->tclass != p_mgrp->mcmember_rec.tclass) + goto Exit; + + /* check SL, Flow, and Hop limit */ + { + uint8_t mgrp_sl, query_sl; + uint32_t mgrp_flow, query_flow; + uint8_t mgrp_hop, query_hop; + + ib_member_get_sl_flow_hop(p_rcvd_rec->sl_flow_hop, + &query_sl, &query_flow, &query_hop); + + ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop, + &mgrp_sl, &mgrp_flow, &mgrp_hop); + + if ((IB_MCR_COMPMASK_SL & comp_mask) && query_sl != mgrp_sl) + goto Exit; + + if ((IB_MCR_COMPMASK_FLOW & comp_mask) && + query_flow != mgrp_flow) + goto Exit; + + if ((IB_MCR_COMPMASK_HOP & comp_mask) && query_hop != mgrp_hop) + goto Exit; + } + + if ((IB_MCR_COMPMASK_PROXY & comp_mask) && + p_rcvd_rec->proxy_join != p_mgrp->mcmember_rec.proxy_join) + goto Exit; + + /* need to validate mtu, rate, and pkt_lifetime fields */ + if (__validate_more_comp_fields(sa->p_log, p_mgrp, p_rcvd_rec, + comp_mask) == FALSE) + goto Exit; + + /* Port specific fields */ + /* so did we get the PortGUID mask */ + if (IB_MCR_COMPMASK_PORT_GID & comp_mask) { + /* try to find this port */ + if (osm_mgrp_is_port_present(p_mgrp, portguid, &p_mcm_port)) { + scope_state = p_mcm_port->scope_state; + memcpy(&port_gid, &(p_mcm_port->port_gid), + sizeof(ib_gid_t)); + proxy_join = p_mcm_port->proxy_join; + } else { + /* port not in group */ + goto Exit; + } + } else { + /* point to the group information */ + scope_state = p_mgrp->mcmember_rec.scope_state; + } + + if (IB_MCR_COMPMASK_SCOPE & comp_mask) + scope_state_mask = 0xF0; + + if (IB_MCR_COMPMASK_JOIN_STATE & comp_mask) + scope_state_mask = scope_state_mask | 0x0F; + + /* Many MC records returned */ + if (trusted_req == TRUE + && !(IB_MCR_COMPMASK_PORT_GID & comp_mask)) { + char gid_str[INET6_ADDRSTRLEN]; + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Trusted req is TRUE and no specific port defined\n"); + + /* return all the ports that match in this MC group */ + p_item = cl_qmap_head(&(p_mgrp->mcm_port_tbl)); + while (p_item != cl_qmap_end(&(p_mgrp->mcm_port_tbl))) { + p_mcm_port = (osm_mcm_port_t *) p_item; + + if ((scope_state_mask & p_rcvd_rec->scope_state) == + (scope_state_mask & p_mcm_port->scope_state)) { + /* add to the list */ + match_rec = p_mgrp->mcmember_rec; + match_rec.scope_state = p_mcm_port->scope_state; + memcpy(&(match_rec.port_gid), + &(p_mcm_port->port_gid), + sizeof(ib_gid_t)); + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Record of port_gid: %s" + " in multicast_lid: 0x%X is returned\n", + inet_ntop(AF_INET6, match_rec.port_gid.raw, + gid_str, sizeof gid_str), + cl_ntoh16(p_mgrp->mlid)); + + match_rec.proxy_join = + (uint8_t) (p_mcm_port->proxy_join); + + __osm_mcmr_rcv_new_mcmr(sa, &match_rec, list); + } + p_item = cl_qmap_next(p_item); + } + } + /* One MC record returned */ + else { + if ((scope_state_mask & p_rcvd_rec->scope_state) != + (scope_state_mask & scope_state)) + goto Exit; + + /* add to the list */ + match_rec = p_mgrp->mcmember_rec; + match_rec.scope_state = scope_state; + memcpy(&(match_rec.port_gid), &port_gid, sizeof(ib_gid_t)); + match_rec.proxy_join = (uint8_t) proxy_join; + + __osm_mcmr_rcv_new_mcmr(sa, &match_rec, list); + } + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + Handle a query request +**********************************************************************/ +static void +__osm_mcmr_query_mgrp(IN osm_sa_t * sa, + IN osm_madw_t * const p_madw) +{ + const ib_sa_mad_t *p_rcvd_mad; + const ib_member_rec_t *p_rcvd_rec; + cl_qlist_t rec_list; + ib_net64_t comp_mask; + osm_physp_t *p_req_physp; + boolean_t trusted_req; + osm_mgrp_t *p_mgrp; + int i; + + OSM_LOG_ENTER(sa->p_log); + + p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_rcvd_rec = (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); + comp_mask = p_rcvd_mad->comp_mask; + + /* + if sm_key is not zero and does not match we never get here + see main SA receiver + */ + trusted_req = (p_rcvd_mad->sm_key != 0); + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B04: " + "Cannot find requester physical port\n"); + goto Exit; + } + + cl_qlist_init(&rec_list); + + CL_PLOCK_ACQUIRE(sa->p_lock); + + /* simply go over all MCGs and match */ + for (i = 0; i <= sa->p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO; + i++) { + p_mgrp = sa->p_subn->mgroups[i]; + if (p_mgrp) + mcmr_by_comp_mask(sa, p_rcvd_rec, comp_mask, p_mgrp, + p_req_physp, trusted_req, &rec_list); + } + + CL_PLOCK_RELEASE(sa->p_lock); + + /* + p923 - The PortGID, JoinState and ProxyJoin shall be zero, + except in the case of a trusted request. + Note: In the mad controller we check that the SM_Key received on + the mad is valid. Meaning - is either zero or equal to the local + sm_key. + */ + + if (!p_rcvd_mad->sm_key) { + osm_mcmr_item_t *item; + for (item = (osm_mcmr_item_t *) cl_qlist_head(&rec_list); + item != (osm_mcmr_item_t *) cl_qlist_end(&rec_list); + item = (osm_mcmr_item_t *)cl_qlist_next(&item->list_item)) { + memset(&item->rec.port_gid, 0, sizeof(ib_gid_t)); + ib_member_set_join_state(&item->rec, 0); + item->rec.proxy_join = 0; + } + } + + osm_sa_respond(sa, p_madw, sizeof(ib_member_rec_t), &rec_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_mcmr_rcv_process(IN void *context, IN void *data) +{ + osm_sa_t *sa = context; + osm_madw_t *p_madw = data; + ib_sa_mad_t *p_sa_mad; + ib_member_rec_t *p_recvd_mcmember_rec; + + CL_ASSERT(sa); + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_recvd_mcmember_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_MCMEMBER_RECORD); + + switch (p_sa_mad->method) { + case IB_MAD_METHOD_SET: + if (!__check_join_comp_mask(p_sa_mad->comp_mask)) { + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B18: " + "component mask = 0x%016" PRIx64 ", " + "expected comp mask = 0x%016" PRIx64 ", " + "MGID: %s for PortGID: %s\n", + cl_ntoh64(p_sa_mad->comp_mask), + CL_NTOH64(JOIN_MC_COMP_MASK), + inet_ntop(AF_INET6, + p_recvd_mcmember_rec->mgid.raw, + gid_str, sizeof gid_str), + inet_ntop(AF_INET6, + p_recvd_mcmember_rec->port_gid.raw, + gid_str2, sizeof gid_str2)); + + osm_sa_send_error(sa, p_madw, + IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + /* + * Join or Create Multicast Group + */ + __osm_mcmr_rcv_join_mgrp(sa, p_madw); + break; + case IB_MAD_METHOD_DELETE: + if (!__check_join_comp_mask(p_sa_mad->comp_mask)) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B20: " + "component mask = 0x%016" PRIx64 ", " + "expected comp mask = 0x%016" PRIx64 "\n", + cl_ntoh64(p_sa_mad->comp_mask), + CL_NTOH64(JOIN_MC_COMP_MASK)); + + osm_sa_send_error(sa, p_madw, + IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + /* + * Leave Multicast Group + */ + __osm_mcmr_rcv_leave_mgrp(sa, p_madw); + break; + case IB_MAD_METHOD_GET: + case IB_MAD_METHOD_GETTABLE: + /* + * Querying a Multicast Group + */ + __osm_mcmr_query_mgrp(sa, p_madw); + break; + default: + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B21: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_sa_mad->method)); + osm_sa_send_error(sa, p_madw, + IB_MAD_STATUS_UNSUP_METHOD_ATTR); + break; + } + +Exit: + OSM_LOG_EXIT(sa->p_log); + return; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_mft_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_mft_record.c new file mode 100644 index 000000000000..bda9aeec6272 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_mft_record.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mftr_rcv_t. + * This object represents the MulticastForwardingTable Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_mftr_item { + cl_list_item_t list_item; + ib_mft_record_t rec; +} osm_mftr_item_t; + +typedef struct osm_mftr_search_ctxt { + const ib_mft_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_mftr_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_mftr_rcv_new_mftr(IN osm_sa_t * sa, + IN osm_switch_t * const p_sw, + IN cl_qlist_t * const p_list, + IN ib_net16_t const lid, + IN uint16_t const block, IN uint8_t const position) +{ + osm_mftr_item_t *p_rec_item; + ib_api_status_t status = IB_SUCCESS; + uint16_t position_block_num; + + OSM_LOG_ENTER(sa->p_log); + + p_rec_item = malloc(sizeof(*p_rec_item)); + if (p_rec_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4A02: " + "rec_item alloc failed\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "New MulticastForwardingTable: sw 0x%016" PRIx64 + "\n\t\t\t\tblock %u position %u lid %u\n", + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)), + block, position, cl_ntoh16(lid)); + + position_block_num = ((uint16_t) position << 12) | + (block & IB_MCAST_BLOCK_ID_MASK_HO); + + memset(p_rec_item, 0, sizeof(*p_rec_item)); + + p_rec_item->rec.lid = lid; + p_rec_item->rec.position_block_num = cl_hton16(position_block_num); + + /* copy the mft block */ + osm_switch_get_mft_block(p_sw, block, position, p_rec_item->rec.mft); + + cl_qlist_insert_tail(p_list, &p_rec_item->list_item); + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_mftr_rcv_by_comp_mask(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + const osm_mftr_search_ctxt_t *const p_ctxt = + (osm_mftr_search_ctxt_t *) context; + osm_switch_t *const p_sw = (osm_switch_t *) p_map_item; + const ib_mft_record_t *const p_rcvd_rec = p_ctxt->p_rcvd_rec; + osm_sa_t *sa = p_ctxt->sa; + ib_net64_t const comp_mask = p_ctxt->comp_mask; + const osm_physp_t *const p_req_physp = p_ctxt->p_req_physp; + osm_port_t *p_port; + uint16_t min_lid_ho, max_lid_ho; + uint16_t position_block_num_ho; + uint16_t min_block, max_block, block; + const osm_physp_t *p_physp; + uint8_t min_position, max_position, position; + + /* In switches, the port guid is the node guid. */ + p_port = + osm_get_port_by_guid(sa->p_subn, p_sw->p_node->node_info.port_guid); + if (!p_port) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4A05: " + "Failed to find Port by Node Guid:0x%016" PRIx64 + "\n", cl_ntoh64(p_sw->p_node->node_info.node_guid)); + return; + } + + /* check that the requester physp and the current physp are under + the same partition. */ + p_physp = p_port->p_physp; + if (!p_physp) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4A06: " + "Failed to find default physical Port by Node Guid:0x%016" + PRIx64 "\n", + cl_ntoh64(p_sw->p_node->node_info.node_guid)); + return; + } + if (!osm_physp_share_pkey(sa->p_log, p_req_physp, p_physp)) + return; + + /* get the port 0 of the switch */ + osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); + + /* compare the lids - if required */ + if (comp_mask & IB_MFTR_COMPMASK_LID) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Comparing lid:%u to port lid range: %u .. %u\n", + cl_ntoh16(p_rcvd_rec->lid), min_lid_ho, max_lid_ho); + /* ok we are ready for range check */ + if (min_lid_ho > cl_ntoh16(p_rcvd_rec->lid) || + max_lid_ho < cl_ntoh16(p_rcvd_rec->lid)) + return; + } + + if (!osm_switch_supports_mcast(p_sw)) + return; + + /* Are there any blocks in use ? */ + if (osm_switch_get_mft_max_block_in_use(p_sw) == -1) + return; + + position_block_num_ho = cl_ntoh16(p_rcvd_rec->position_block_num); + + /* now we need to decide which blocks to output */ + if (comp_mask & IB_MFTR_COMPMASK_BLOCK) { + max_block = min_block = + position_block_num_ho & IB_MCAST_BLOCK_ID_MASK_HO; + if (max_block > osm_switch_get_mft_max_block_in_use(p_sw)) + return; + } else { + /* use as many blocks as needed */ + min_block = 0; + max_block = osm_switch_get_mft_max_block_in_use(p_sw); + } + + /* need to decide which positions to output */ + if (comp_mask & IB_MFTR_COMPMASK_POSITION) { + min_position = max_position = + (position_block_num_ho & 0xF000) >> 12; + if (max_position > osm_switch_get_mft_max_position(p_sw)) + return; + } else { + /* use as many positions as needed */ + min_position = 0; + max_position = osm_switch_get_mft_max_position(p_sw); + } + + /* so we can add these one by one ... */ + for (block = min_block; block <= max_block; block++) + for (position = min_position; position <= max_position; + position++) + __osm_mftr_rcv_new_mftr(sa, p_sw, p_ctxt->p_list, + osm_port_get_base_lid(p_port), + block, position); +} + +/********************************************************************** + **********************************************************************/ +void osm_mftr_rcv_process(IN void *ctx, IN void *data) +{ + osm_sa_t *sa = ctx; + osm_madw_t *p_madw = data; + const ib_sa_mad_t *p_rcvd_mad; + const ib_mft_record_t *p_rcvd_rec; + cl_qlist_t rec_list; + osm_mftr_search_ctxt_t context; + osm_physp_t *p_req_physp; + + CL_ASSERT(sa); + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_rcvd_rec = (ib_mft_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); + + CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_MFT_RECORD); + + /* we only support SubnAdmGet and SubnAdmGetTable methods */ + if (p_rcvd_mad->method != IB_MAD_METHOD_GET && + p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4A08: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_rcvd_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, + sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4A07: " + "Cannot find requester physical port\n"); + goto Exit; + } + + cl_qlist_init(&rec_list); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = p_rcvd_mad->comp_mask; + context.sa = sa; + context.p_req_physp = p_req_physp; + + cl_plock_acquire(sa->p_lock); + + /* Go over all switches */ + cl_qmap_apply_func(&sa->p_subn->sw_guid_tbl, + __osm_mftr_rcv_by_comp_mask, &context); + + cl_plock_release(sa->p_lock); + + osm_sa_respond(sa, p_madw, sizeof(ib_mft_record_t), &rec_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_multipath_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_multipath_record.c new file mode 100644 index 000000000000..b9164befa39a --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_multipath_record.c @@ -0,0 +1,1536 @@ +/* + * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_mpr_rcv_t. + * This object represents the MultiPath Record Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_SA_MPR_MAX_NUM_PATH 127 + +typedef struct osm_mpr_item { + cl_list_item_t list_item; + ib_path_rec_t path_rec; + const osm_port_t *p_src_port; + const osm_port_t *p_dest_port; + int hops; +} osm_mpr_item_t; + +typedef struct osm_path_parms { + ib_net16_t pkey; + uint8_t mtu; + uint8_t rate; + uint8_t sl; + uint8_t pkt_life; + boolean_t reversible; + int hops; +} osm_path_parms_t; + +/********************************************************************** + **********************************************************************/ +static inline boolean_t +__osm_sa_multipath_rec_is_tavor_port(IN const osm_port_t * const p_port) +{ + osm_node_t const *p_node; + ib_net32_t vend_id; + + p_node = p_port->p_node; + vend_id = ib_node_info_get_vendor_id(&p_node->node_info); + + return ((p_node->node_info.device_id == CL_HTON16(23108)) && + ((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) || + (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) || + (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) || + (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE)))); +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +__osm_sa_multipath_rec_apply_tavor_mtu_limit(IN const ib_multipath_rec_t * + const p_mpr, + IN const osm_port_t * + const p_src_port, + IN const osm_port_t * + const p_dest_port, + IN const ib_net64_t comp_mask) +{ + uint8_t required_mtu; + + /* only if at least one of the ports is a Tavor device */ + if (!__osm_sa_multipath_rec_is_tavor_port(p_src_port) && + !__osm_sa_multipath_rec_is_tavor_port(p_dest_port)) + return (FALSE); + + /* + we can apply the patch if either: + 1. No MTU required + 2. Required MTU < + 3. Required MTU = 1K or 512 or 256 + 4. Required MTU > 256 or 512 + */ + required_mtu = ib_multipath_rec_mtu(p_mpr); + if ((comp_mask & IB_MPR_COMPMASK_MTUSELEC) && + (comp_mask & IB_MPR_COMPMASK_MTU)) { + switch (ib_multipath_rec_mtu_sel(p_mpr)) { + case 0: /* must be greater than */ + case 2: /* exact match */ + if (IB_MTU_LEN_1024 < required_mtu) + return (FALSE); + break; + + case 1: /* must be less than */ + /* can't be disqualified by this one */ + break; + + case 3: /* largest available */ + /* the ULP intentionally requested */ + /* the largest MTU possible */ + return (FALSE); + break; + + default: + /* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */ + CL_ASSERT(FALSE); + break; + } + } + + return (TRUE); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_mpr_rcv_get_path_parms(IN osm_sa_t * sa, + IN const ib_multipath_rec_t * const p_mpr, + IN const osm_port_t * const p_src_port, + IN const osm_port_t * const p_dest_port, + IN const uint16_t dest_lid_ho, + IN const ib_net64_t comp_mask, + OUT osm_path_parms_t * const p_parms) +{ + const osm_node_t *p_node; + const osm_physp_t *p_physp; + const osm_physp_t *p_src_physp; + const osm_physp_t *p_dest_physp; + const osm_prtn_t *p_prtn = NULL; + const ib_port_info_t *p_pi; + ib_slvl_table_t *p_slvl_tbl; + ib_api_status_t status = IB_SUCCESS; + uint8_t mtu; + uint8_t rate; + uint8_t pkt_life; + uint8_t required_mtu; + uint8_t required_rate; + ib_net16_t required_pkey; + uint8_t required_sl; + uint8_t required_pkt_life; + ib_net16_t dest_lid; + int hops = 0; + int in_port_num = 0; + uint8_t i; + osm_qos_level_t *p_qos_level = NULL; + uint16_t valid_sl_mask = 0xffff; + + OSM_LOG_ENTER(sa->p_log); + + dest_lid = cl_hton16(dest_lid_ho); + + p_dest_physp = p_dest_port->p_physp; + p_physp = p_src_port->p_physp; + p_src_physp = p_physp; + p_pi = &p_physp->port_info; + + mtu = ib_port_info_get_mtu_cap(p_pi); + rate = ib_port_info_compute_rate(p_pi); + + /* + Mellanox Tavor device performance is better using 1K MTU. + If required MTU and MTU selector are such that 1K is OK + and at least one end of the path is Tavor we override the + port MTU with 1K. + */ + if (sa->p_subn->opt.enable_quirks && + __osm_sa_multipath_rec_apply_tavor_mtu_limit(p_mpr, p_src_port, + p_dest_port, + comp_mask)) + if (mtu > IB_MTU_LEN_1024) { + mtu = IB_MTU_LEN_1024; + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Optimized Path MTU to 1K for Mellanox Tavor device\n"); + } + + /* + Walk the subnet object from source to destination, + tracking the most restrictive rate and mtu values along the way... + + If source port node is a switch, then p_physp should + point to the port that routes the destination lid + */ + + p_node = osm_physp_get_node_ptr(p_physp); + + if (p_node->sw) { + /* + * Source node is a switch. + * Make sure that p_physp points to the out port of the + * switch that routes to the destination lid (dest_lid_ho) + */ + p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid); + if (p_physp == 0) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4514: " + "Can't find routing to LID %u from switch for GUID 0x%016" + PRIx64 "\n", dest_lid_ho, + cl_ntoh64(osm_node_get_node_guid(p_node))); + status = IB_NOT_FOUND; + goto Exit; + } + } + + if (sa->p_subn->opt.qos) { + + /* + * Whether this node is switch or CA, the IN port for + * the sl2vl table is 0, because this is a source node. + */ + p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, 0); + + /* update valid SLs that still exist on this route */ + for (i = 0; i < IB_MAX_NUM_VLS; i++) { + if (valid_sl_mask & (1 << i) && + ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL) + valid_sl_mask &= ~(1 << i); + } + if (!valid_sl_mask) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "All the SLs lead to VL15 on this path\n"); + status = IB_NOT_FOUND; + goto Exit; + } + } + + /* + * Same as above + */ + p_node = osm_physp_get_node_ptr(p_dest_physp); + + if (p_node->sw) { + /* + * if destination is switch, we want p_dest_physp to point to port 0 + */ + p_dest_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid); + + if (p_dest_physp == 0) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4515: " + "Can't find routing to LID %u from switch for GUID 0x%016" + PRIx64 "\n", dest_lid_ho, + cl_ntoh64(osm_node_get_node_guid(p_node))); + status = IB_NOT_FOUND; + goto Exit; + } + + } + + /* + * Now go through the path step by step + */ + + while (p_physp != p_dest_physp) { + + p_node = osm_physp_get_node_ptr(p_physp); + p_physp = osm_physp_get_remote(p_physp); + + if (p_physp == 0) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4505: " + "Can't find remote phys port when routing to LID %u from node GUID 0x%016" + PRIx64 "\n", dest_lid_ho, + cl_ntoh64(osm_node_get_node_guid(p_node))); + status = IB_ERROR; + goto Exit; + } + + hops++; + in_port_num = osm_physp_get_port_num(p_physp); + + /* + This is point to point case (no switch in between) + */ + if (p_physp == p_dest_physp) + break; + + p_node = osm_physp_get_node_ptr(p_physp); + + if (!p_node->sw) { + /* + There is some sort of problem in the subnet object! + If this isn't a switch, we should have reached + the destination by now! + */ + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4503: " + "Internal error, bad path\n"); + status = IB_ERROR; + goto Exit; + } + + /* + Check parameters for the ingress port in this switch. + */ + p_pi = &p_physp->port_info; + + if (mtu > ib_port_info_get_mtu_cap(p_pi)) + mtu = ib_port_info_get_mtu_cap(p_pi); + + if (rate > ib_port_info_compute_rate(p_pi)) + rate = ib_port_info_compute_rate(p_pi); + + /* + Continue with the egress port on this switch. + */ + p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid); + if (p_physp == 0) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4516: " + "Dead end on path to LID %u from switch for GUID 0x%016" + PRIx64 "\n", dest_lid_ho, + cl_ntoh64(osm_node_get_node_guid(p_node))); + status = IB_ERROR; + goto Exit; + } + + p_pi = &p_physp->port_info; + + if (mtu > ib_port_info_get_mtu_cap(p_pi)) + mtu = ib_port_info_get_mtu_cap(p_pi); + + if (rate > ib_port_info_compute_rate(p_pi)) + rate = ib_port_info_compute_rate(p_pi); + + if (sa->p_subn->opt.qos) { + /* + * Check SL2VL table of the switch and update valid SLs + */ + p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, in_port_num); + for (i = 0; i < IB_MAX_NUM_VLS; i++) { + if (valid_sl_mask & (1 << i) && + ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL) + valid_sl_mask &= ~(1 << i); + } + if (!valid_sl_mask) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "All the SLs lead to VL15 " + "on this path\n"); + status = IB_NOT_FOUND; + goto Exit; + } + } + } + + /* + p_physp now points to the destination + */ + p_pi = &p_physp->port_info; + + if (mtu > ib_port_info_get_mtu_cap(p_pi)) + mtu = ib_port_info_get_mtu_cap(p_pi); + + if (rate > ib_port_info_compute_rate(p_pi)) + rate = ib_port_info_compute_rate(p_pi); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Path min MTU = %u, min rate = %u\n", mtu, rate); + + /* + * Get QoS Level object according to the MultiPath request + * and adjust MultiPath parameters according to QoS settings + */ + if (sa->p_subn->opt.qos && + sa->p_subn->p_qos_policy && + (p_qos_level = + osm_qos_policy_get_qos_level_by_mpr(sa->p_subn->p_qos_policy, + p_mpr, p_src_physp, + p_dest_physp, comp_mask))) { + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "MultiPathRecord request matches QoS Level '%s' (%s)\n", + p_qos_level->name, + p_qos_level->use ? p_qos_level->use : "no description"); + + if (p_qos_level->mtu_limit_set + && (mtu > p_qos_level->mtu_limit)) + mtu = p_qos_level->mtu_limit; + + if (p_qos_level->rate_limit_set + && (rate > p_qos_level->rate_limit)) + rate = p_qos_level->rate_limit; + + if (p_qos_level->sl_set) { + required_sl = p_qos_level->sl; + if (!(valid_sl_mask & (1 << required_sl))) { + status = IB_NOT_FOUND; + goto Exit; + } + } + } + + /* + Determine if these values meet the user criteria + */ + + /* we silently ignore cases where only the MTU selector is defined */ + if ((comp_mask & IB_MPR_COMPMASK_MTUSELEC) && + (comp_mask & IB_MPR_COMPMASK_MTU)) { + required_mtu = ib_multipath_rec_mtu(p_mpr); + switch (ib_multipath_rec_mtu_sel(p_mpr)) { + case 0: /* must be greater than */ + if (mtu <= required_mtu) + status = IB_NOT_FOUND; + break; + + case 1: /* must be less than */ + if (mtu >= required_mtu) { + /* adjust to use the highest mtu + lower then the required one */ + if (required_mtu > 1) + mtu = required_mtu - 1; + else + status = IB_NOT_FOUND; + } + break; + + case 2: /* exact match */ + if (mtu < required_mtu) + status = IB_NOT_FOUND; + else + mtu = required_mtu; + break; + + case 3: /* largest available */ + /* can't be disqualified by this one */ + break; + + default: + /* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */ + CL_ASSERT(FALSE); + status = IB_ERROR; + break; + } + } + if (status != IB_SUCCESS) + goto Exit; + + /* we silently ignore cases where only the Rate selector is defined */ + if ((comp_mask & IB_MPR_COMPMASK_RATESELEC) && + (comp_mask & IB_MPR_COMPMASK_RATE)) { + required_rate = ib_multipath_rec_rate(p_mpr); + switch (ib_multipath_rec_rate_sel(p_mpr)) { + case 0: /* must be greater than */ + if (rate <= required_rate) + status = IB_NOT_FOUND; + break; + + case 1: /* must be less than */ + if (rate >= required_rate) { + /* adjust the rate to use the highest rate + lower then the required one */ + if (required_rate > 2) + rate = required_rate - 1; + else + status = IB_NOT_FOUND; + } + break; + + case 2: /* exact match */ + if (rate < required_rate) + status = IB_NOT_FOUND; + else + rate = required_rate; + break; + + case 3: /* largest available */ + /* can't be disqualified by this one */ + break; + + default: + /* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */ + CL_ASSERT(FALSE); + status = IB_ERROR; + break; + } + } + if (status != IB_SUCCESS) + goto Exit; + + /* Verify the pkt_life_time */ + /* According to spec definition IBA 1.2 Table 205 PacketLifeTime description, + for loopback paths, packetLifeTime shall be zero. */ + if (p_src_port == p_dest_port) + pkt_life = 0; /* loopback */ + else if (p_qos_level && p_qos_level->pkt_life_set) + pkt_life = p_qos_level->pkt_life; + else + pkt_life = sa->p_subn->opt.subnet_timeout; + + /* we silently ignore cases where only the PktLife selector is defined */ + if ((comp_mask & IB_MPR_COMPMASK_PKTLIFETIMESELEC) && + (comp_mask & IB_MPR_COMPMASK_PKTLIFETIME)) { + required_pkt_life = ib_multipath_rec_pkt_life(p_mpr); + switch (ib_multipath_rec_pkt_life_sel(p_mpr)) { + case 0: /* must be greater than */ + if (pkt_life <= required_pkt_life) + status = IB_NOT_FOUND; + break; + + case 1: /* must be less than */ + if (pkt_life >= required_pkt_life) { + /* adjust the lifetime to use the highest possible + lower then the required one */ + if (required_pkt_life > 1) + pkt_life = required_pkt_life - 1; + else + status = IB_NOT_FOUND; + } + break; + + case 2: /* exact match */ + if (pkt_life < required_pkt_life) + status = IB_NOT_FOUND; + else + pkt_life = required_pkt_life; + break; + + case 3: /* smallest available */ + /* can't be disqualified by this one */ + break; + + default: + /* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */ + CL_ASSERT(FALSE); + status = IB_ERROR; + break; + } + } + + if (status != IB_SUCCESS) + goto Exit; + + /* + * set Pkey for this MultiPath record request + */ + + if (comp_mask & IB_MPR_COMPMASK_RAWTRAFFIC && + cl_ntoh32(p_mpr->hop_flow_raw) & (1 << 31)) + required_pkey = + osm_physp_find_common_pkey(p_src_physp, p_dest_physp); + + else if (comp_mask & IB_MPR_COMPMASK_PKEY) { + /* + * MPR request has a specific pkey: + * Check that source and destination share this pkey. + * If QoS level has pkeys, check that this pkey exists + * in the QoS level pkeys. + * MPR returned pkey is the requested pkey. + */ + required_pkey = p_mpr->pkey; + if (!osm_physp_share_this_pkey + (p_src_physp, p_dest_physp, required_pkey)) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4518: " + "Ports do not share specified PKey 0x%04x\n" + "\t\tsrc %" PRIx64 " dst %" PRIx64 "\n", + cl_ntoh16(required_pkey), + cl_ntoh64(osm_physp_get_port_guid(p_src_physp)), + cl_ntoh64(osm_physp_get_port_guid + (p_dest_physp))); + status = IB_NOT_FOUND; + goto Exit; + } + if (p_qos_level && p_qos_level->pkey_range_len && + !osm_qos_level_has_pkey(p_qos_level, required_pkey)) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451C: " + "Ports do not share PKeys defined by QoS level\n"); + status = IB_NOT_FOUND; + goto Exit; + } + + } else if (p_qos_level && p_qos_level->pkey_range_len) { + /* + * MPR request doesn't have a specific pkey, but QoS level + * has pkeys - get shared pkey from QoS level pkeys + */ + required_pkey = osm_qos_level_get_shared_pkey(p_qos_level, + p_src_physp, + p_dest_physp); + if (!required_pkey) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451D: " + "Ports do not share PKeys defined by QoS level\n"); + status = IB_NOT_FOUND; + goto Exit; + } + + } else { + /* + * Neither MPR request nor QoS level have pkey. + * Just get any shared pkey. + */ + required_pkey = + osm_physp_find_common_pkey(p_src_physp, p_dest_physp); + if (!required_pkey) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4519: " + "Ports do not have any shared PKeys\n" + "\t\tsrc %" PRIx64 " dst %" PRIx64 "\n", + cl_ntoh64(osm_physp_get_port_guid(p_physp)), + cl_ntoh64(osm_physp_get_port_guid + (p_dest_physp))); + status = IB_NOT_FOUND; + goto Exit; + } + } + + if (required_pkey) { + p_prtn = + (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl, + required_pkey & + cl_ntoh16((uint16_t) ~ 0x8000)); + if (p_prtn == + (osm_prtn_t *) cl_qmap_end(&sa->p_subn->prtn_pkey_tbl)) + p_prtn = NULL; + } + + /* + * Set MultiPathRecord SL. + */ + + if (comp_mask & IB_MPR_COMPMASK_SL) { + /* + * Specific SL was requested + */ + required_sl = ib_multipath_rec_sl(p_mpr); + + if (p_qos_level && p_qos_level->sl_set && + p_qos_level->sl != required_sl) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451E: " + "QoS constaraints: required MultiPathRecord SL (%u) " + "doesn't match QoS policy SL (%u)\n", + required_sl, p_qos_level->sl); + status = IB_NOT_FOUND; + goto Exit; + } + + } else if (p_qos_level && p_qos_level->sl_set) { + /* + * No specific SL was requested, + * but there is an SL in QoS level. + */ + required_sl = p_qos_level->sl; + + if (required_pkey && p_prtn && p_prtn->sl != p_qos_level->sl) + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "QoS level SL (%u) overrides partition SL (%u)\n", + p_qos_level->sl, p_prtn->sl); + + } else if (required_pkey) { + /* + * No specific SL in request or in QoS level - use partition SL + */ + p_prtn = + (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl, + required_pkey & + cl_ntoh16((uint16_t) ~ 0x8000)); + if (!p_prtn) { + required_sl = OSM_DEFAULT_SL; + /* this may be possible when pkey tables are created somehow in + previous runs or things are going wrong here */ + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451A: " + "No partition found for PKey 0x%04x - using default SL %d\n", + cl_ntoh16(required_pkey), required_sl); + } else + required_sl = p_prtn->sl; + + } else if (sa->p_subn->opt.qos) { + if (valid_sl_mask & (1 << OSM_DEFAULT_SL)) + required_sl = OSM_DEFAULT_SL; + else { + for (i = 0; i < IB_MAX_NUM_VLS; i++) + if (valid_sl_mask & (1 << i)) + break; + required_sl = i; + } + } else + required_sl = OSM_DEFAULT_SL; + + if (sa->p_subn->opt.qos && !(valid_sl_mask & (1 << required_sl))) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451F: " + "Selected SL (%u) leads to VL15\n", required_sl); + status = IB_NOT_FOUND; + goto Exit; + } + + /* reset pkey when raw traffic */ + if (comp_mask & IB_MPR_COMPMASK_RAWTRAFFIC && + cl_ntoh32(p_mpr->hop_flow_raw) & (1 << 31)) + required_pkey = 0; + + p_parms->mtu = mtu; + p_parms->rate = rate; + p_parms->pkey = required_pkey; + p_parms->pkt_life = pkt_life; + p_parms->sl = required_sl; + p_parms->hops = hops; + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "MultiPath params:" + " mtu = %u, rate = %u, packet lifetime = %u," + " pkey = 0x%04X, sl = %u, hops = %u\n", mtu, rate, + pkt_life, cl_ntoh16(required_pkey), required_sl, hops); + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_mpr_rcv_build_pr(IN osm_sa_t * sa, + IN const osm_port_t * const p_src_port, + IN const osm_port_t * const p_dest_port, + IN const uint16_t src_lid_ho, + IN const uint16_t dest_lid_ho, + IN const uint8_t preference, + IN const osm_path_parms_t * const p_parms, + OUT ib_path_rec_t * const p_pr) +{ + const osm_physp_t *p_src_physp; + const osm_physp_t *p_dest_physp; + + OSM_LOG_ENTER(sa->p_log); + + p_src_physp = p_src_port->p_physp; + p_dest_physp = p_dest_port->p_physp; + + p_pr->dgid.unicast.prefix = osm_physp_get_subnet_prefix(p_dest_physp); + p_pr->dgid.unicast.interface_id = osm_physp_get_port_guid(p_dest_physp); + + p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix(p_src_physp); + p_pr->sgid.unicast.interface_id = osm_physp_get_port_guid(p_src_physp); + + p_pr->dlid = cl_hton16(dest_lid_ho); + p_pr->slid = cl_hton16(src_lid_ho); + + p_pr->hop_flow_raw &= cl_hton32(1 << 31); + + p_pr->pkey = p_parms->pkey; + ib_path_rec_set_qos_class(p_pr, 0); + ib_path_rec_set_sl(p_pr, p_parms->sl); + p_pr->mtu = (uint8_t) (p_parms->mtu | 0x80); + p_pr->rate = (uint8_t) (p_parms->rate | 0x80); + + /* According to 1.2 spec definition Table 205 PacketLifeTime description, + for loopback paths, packetLifeTime shall be zero. */ + if (p_src_port == p_dest_port) + p_pr->pkt_life = 0x80; /* loopback */ + else + p_pr->pkt_life = (uint8_t) (p_parms->pkt_life | 0x80); + + p_pr->preference = preference; + + /* always return num_path = 0 so this is only the reversible component */ + if (p_parms->reversible) + p_pr->num_path = 0x80; + + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static osm_mpr_item_t * +__osm_mpr_rcv_get_lid_pair_path(IN osm_sa_t * sa, + IN const ib_multipath_rec_t * const p_mpr, + IN const osm_port_t * const p_src_port, + IN const osm_port_t * const p_dest_port, + IN const uint16_t src_lid_ho, + IN const uint16_t dest_lid_ho, + IN const ib_net64_t comp_mask, + IN const uint8_t preference) +{ + osm_path_parms_t path_parms; + osm_path_parms_t rev_path_parms; + osm_mpr_item_t *p_pr_item; + ib_api_status_t status, rev_path_status; + + OSM_LOG_ENTER(sa->p_log); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID %u, Dest LID %u\n", + src_lid_ho, dest_lid_ho); + + p_pr_item = malloc(sizeof(*p_pr_item)); + if (p_pr_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4501: " + "Unable to allocate path record\n"); + goto Exit; + } + memset(p_pr_item, 0, sizeof(*p_pr_item)); + + status = __osm_mpr_rcv_get_path_parms(sa, p_mpr, p_src_port, + p_dest_port, dest_lid_ho, + comp_mask, &path_parms); + + if (status != IB_SUCCESS) { + free(p_pr_item); + p_pr_item = NULL; + goto Exit; + } + + /* now try the reversible path */ + rev_path_status = + __osm_mpr_rcv_get_path_parms(sa, p_mpr, p_dest_port, p_src_port, + src_lid_ho, comp_mask, + &rev_path_parms); + path_parms.reversible = (rev_path_status == IB_SUCCESS); + + /* did we get a Reversible Path compmask ? */ + /* + NOTE that if the reversible component = 0, it is a don't care + rather then requiring non-reversible paths ... + see Vol1 Ver1.2 p900 l16 + */ + if (comp_mask & IB_MPR_COMPMASK_REVERSIBLE) { + if ((!path_parms.reversible && (p_mpr->num_path & 0x80))) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Requested reversible path but failed to get one\n"); + + free(p_pr_item); + p_pr_item = NULL; + goto Exit; + } + } + + p_pr_item->p_src_port = p_src_port; + p_pr_item->p_dest_port = p_dest_port; + p_pr_item->hops = path_parms.hops; + + __osm_mpr_rcv_build_pr(sa, p_src_port, p_dest_port, src_lid_ho, + dest_lid_ho, preference, &path_parms, + &p_pr_item->path_rec); + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (p_pr_item); +} + +/********************************************************************** + **********************************************************************/ +static uint32_t +__osm_mpr_rcv_get_port_pair_paths(IN osm_sa_t * sa, + IN const ib_multipath_rec_t * const p_mpr, + IN const osm_port_t * const p_req_port, + IN const osm_port_t * const p_src_port, + IN const osm_port_t * const p_dest_port, + IN const uint32_t rem_paths, + IN const ib_net64_t comp_mask, + IN cl_qlist_t * const p_list) +{ + osm_mpr_item_t *p_pr_item; + uint16_t src_lid_min_ho; + uint16_t src_lid_max_ho; + uint16_t dest_lid_min_ho; + uint16_t dest_lid_max_ho; + uint16_t src_lid_ho; + uint16_t dest_lid_ho; + uint32_t path_num = 0; + uint8_t preference; + uintn_t src_offset; + uintn_t dest_offset; + + OSM_LOG_ENTER(sa->p_log); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Src port 0x%016" PRIx64 ", Dst port 0x%016" PRIx64 "\n", + cl_ntoh64(osm_port_get_guid(p_src_port)), + cl_ntoh64(osm_port_get_guid(p_dest_port))); + + /* Check that the req_port, src_port and dest_port all share a + pkey. The check is done on the default physical port of the ports. */ + if (osm_port_share_pkey(sa->p_log, p_req_port, p_src_port) == FALSE + || osm_port_share_pkey(sa->p_log, p_req_port, + p_dest_port) == FALSE + || osm_port_share_pkey(sa->p_log, p_src_port, + p_dest_port) == FALSE) + /* One of the pairs doesn't share a pkey so the path is disqualified. */ + goto Exit; + + /* + We shouldn't be here if the paths are disqualified in some way... + Thus, we assume every possible connection is valid. + + We desire to return high-quality paths first. + In OpenSM, higher quality mean least overlap with other paths. + This is acheived in practice by returning paths with + different LID value on each end, which means these + paths are more redundant that paths with the same LID repeated + on one side. For example, in OpenSM the paths between two + endpoints with LMC = 1 might be as follows: + + Port A, LID 1 <-> Port B, LID 3 + Port A, LID 1 <-> Port B, LID 4 + Port A, LID 2 <-> Port B, LID 3 + Port A, LID 2 <-> Port B, LID 4 + + The OpenSM unicast routing algorithms attempt to disperse each path + to as varied a physical path as is reasonable. 1<->3 and 1<->4 have + more physical overlap (hence less redundancy) than 1<->3 and 2<->4. + + OpenSM ranks paths in three preference groups: + + Preference Value Description + ---------------- ------------------------------------------- + 0 Redundant in both directions with other + pref value = 0 paths + + 1 Redundant in one direction with other + pref value = 0 and pref value = 1 paths + + 2 Not redundant in either direction with + other paths + + 3-FF Unused + + SA clients don't need to know these details, only that the lower + preference paths are preferred, as stated in the spec. The paths + may not actually be physically redundant depending on the topology + of the subnet, but the point of LMC > 0 is to offer redundancy, + so I assume the subnet is physically appropriate for the specified + LMC value. A more advanced implementation could inspect for physical + redundancy, but I'm not going to bother with that now. + */ + + osm_port_get_lid_range_ho(p_src_port, &src_lid_min_ho, &src_lid_max_ho); + osm_port_get_lid_range_ho(p_dest_port, &dest_lid_min_ho, + &dest_lid_max_ho); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID [%u-%u], Dest LID [%u-%u]\n", + src_lid_min_ho, src_lid_max_ho, + dest_lid_min_ho, dest_lid_max_ho); + + src_lid_ho = src_lid_min_ho; + dest_lid_ho = dest_lid_min_ho; + + /* + Preferred paths come first in OpenSM + */ + preference = 0; + + while (path_num < rem_paths) { + /* + These paths are "fully redundant" + */ + p_pr_item = __osm_mpr_rcv_get_lid_pair_path(sa, p_mpr, + p_src_port, + p_dest_port, + src_lid_ho, + dest_lid_ho, + comp_mask, + preference); + + if (p_pr_item) { + cl_qlist_insert_tail(p_list, &p_pr_item->list_item); + ++path_num; + } + + if (++src_lid_ho > src_lid_max_ho) + break; + + if (++dest_lid_ho > dest_lid_max_ho) + break; + } + + /* + Check if we've accumulated all the paths that the user cares to see + */ + if (path_num == rem_paths) + goto Exit; + + /* + Don't bother reporting preference 1 paths for now. + It's more trouble than it's worth and can only occur + if ports have different LMC values, which isn't supported + by OpenSM right now anyway. + */ + preference = 2; + src_lid_ho = src_lid_min_ho; + dest_lid_ho = dest_lid_min_ho; + src_offset = 0; + dest_offset = 0; + + /* + Iterate over the remaining paths + */ + while (path_num < rem_paths) { + dest_offset++; + dest_lid_ho++; + + if (dest_lid_ho > dest_lid_max_ho) { + src_offset++; + src_lid_ho++; + + if (src_lid_ho > src_lid_max_ho) + break; /* done */ + + dest_offset = 0; + dest_lid_ho = dest_lid_min_ho; + } + + /* + These paths are "fully non-redundant" with paths already + identified above and consequently not of much value. + + Don't return paths we already identified above, as indicated + by the offset values being equal. + */ + if (src_offset == dest_offset) + continue; /* already reported */ + + p_pr_item = __osm_mpr_rcv_get_lid_pair_path(sa, p_mpr, + p_src_port, + p_dest_port, + src_lid_ho, + dest_lid_ho, + comp_mask, + preference); + + if (p_pr_item) { + cl_qlist_insert_tail(p_list, &p_pr_item->list_item); + ++path_num; + } + } + +Exit: + OSM_LOG_EXIT(sa->p_log); + return path_num; +} + +#undef min +#define min(x,y) (((x) < (y)) ? (x) : (y)) + +/********************************************************************** + **********************************************************************/ +static osm_mpr_item_t * +__osm_mpr_rcv_get_apm_port_pair_paths(IN osm_sa_t * sa, + IN const ib_multipath_rec_t * const p_mpr, + IN const osm_port_t * const p_src_port, + IN const osm_port_t * const p_dest_port, + IN int base_offs, + IN const ib_net64_t comp_mask, + IN cl_qlist_t * const p_list) +{ + osm_mpr_item_t *p_pr_item = 0; + uint16_t src_lid_min_ho; + uint16_t src_lid_max_ho; + uint16_t dest_lid_min_ho; + uint16_t dest_lid_max_ho; + uint16_t src_lid_ho; + uint16_t dest_lid_ho; + uintn_t iterations; + int src_lids, dest_lids; + + OSM_LOG_ENTER(sa->p_log); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src port 0x%016" PRIx64 ", " + "Dst port 0x%016" PRIx64 ", base offs %d\n", + cl_ntoh64(osm_port_get_guid(p_src_port)), + cl_ntoh64(osm_port_get_guid(p_dest_port)), base_offs); + + osm_port_get_lid_range_ho(p_src_port, &src_lid_min_ho, &src_lid_max_ho); + osm_port_get_lid_range_ho(p_dest_port, &dest_lid_min_ho, + &dest_lid_max_ho); + + src_lid_ho = src_lid_min_ho; + dest_lid_ho = dest_lid_min_ho; + + src_lids = src_lid_max_ho - src_lid_min_ho + 1; + dest_lids = dest_lid_max_ho - dest_lid_min_ho + 1; + + src_lid_ho += base_offs % src_lids; + dest_lid_ho += base_offs % dest_lids; + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Src LIDs [%u-%u] hashed %u, " + "Dest LIDs [%u-%u] hashed %u\n", + src_lid_min_ho, src_lid_max_ho, src_lid_ho, + dest_lid_min_ho, dest_lid_max_ho, dest_lid_ho); + + iterations = min(src_lids, dest_lids); + + while (iterations--) { + /* + These paths are "fully redundant" + */ + p_pr_item = __osm_mpr_rcv_get_lid_pair_path(sa, p_mpr, + p_src_port, + p_dest_port, + src_lid_ho, + dest_lid_ho, + comp_mask, 0); + + if (p_pr_item) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Found matching path from Src LID %u to Dest LID %u with %d hops\n", + src_lid_ho, dest_lid_ho, p_pr_item->hops); + break; + } + + if (++src_lid_ho > src_lid_max_ho) + src_lid_ho = src_lid_min_ho; + + if (++dest_lid_ho > dest_lid_max_ho) + dest_lid_ho = dest_lid_min_ho; + } + + OSM_LOG_EXIT(sa->p_log); + return p_pr_item; +} + +/********************************************************************** + **********************************************************************/ +static ib_net16_t +__osm_mpr_rcv_get_gids(IN osm_sa_t * sa, + IN const ib_gid_t * gids, + IN int ngids, IN int is_sgid, OUT osm_port_t ** pp_port) +{ + osm_port_t *p_port; + ib_net16_t ib_status = IB_SUCCESS; + int i; + + OSM_LOG_ENTER(sa->p_log); + + for (i = 0; i < ngids; i++, gids++) { + if (!ib_gid_is_link_local(gids)) { + if ((is_sgid && ib_gid_is_multicast(gids)) || + (ib_gid_get_subnet_prefix(gids) != + sa->p_subn->opt.subnet_prefix)) { + /* + This 'error' is the client's fault (bad gid) + so don't enter it as an error in our own log. + Return an error response to the client. + */ + OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "ERR 451B: " + "%sGID 0x%016" PRIx64 + " is multicast or non local subnet prefix\n", + is_sgid ? "S" : "D", + cl_ntoh64(gids->unicast.prefix)); + + ib_status = IB_SA_MAD_STATUS_INVALID_GID; + goto Exit; + } + } + + p_port = + osm_get_port_by_guid(sa->p_subn, + gids->unicast.interface_id); + if (!p_port) { + /* + This 'error' is the client's fault (bad gid) so + don't enter it as an error in our own log. + Return an error response to the client. + */ + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4506: " + "No port with GUID 0x%016" PRIx64 "\n", + cl_ntoh64(gids->unicast.interface_id)); + + ib_status = IB_SA_MAD_STATUS_INVALID_GID; + goto Exit; + } + + pp_port[i] = p_port; + } + +Exit: + OSM_LOG_EXIT(sa->p_log); + + return ib_status; +} + +/********************************************************************** + **********************************************************************/ +static ib_net16_t +__osm_mpr_rcv_get_end_points(IN osm_sa_t * sa, + IN const osm_madw_t * const p_madw, + OUT osm_port_t ** pp_ports, + OUT int *nsrc, OUT int *ndest) +{ + const ib_multipath_rec_t *p_mpr; + const ib_sa_mad_t *p_sa_mad; + ib_net64_t comp_mask; + ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS; + ib_gid_t *gids; + + OSM_LOG_ENTER(sa->p_log); + + /* + Determine what fields are valid and then get a pointer + to the source and destination port objects, if possible. + */ + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_mpr = (ib_multipath_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + gids = (ib_gid_t *) p_mpr->gids; + + comp_mask = p_sa_mad->comp_mask; + + /* + Check a few easy disqualifying cases up front before getting + into the endpoints. + */ + *nsrc = *ndest = 0; + + if (comp_mask & IB_MPR_COMPMASK_SGIDCOUNT) { + *nsrc = p_mpr->sgid_count; + if (*nsrc > IB_MULTIPATH_MAX_GIDS) + *nsrc = IB_MULTIPATH_MAX_GIDS; + sa_status = + __osm_mpr_rcv_get_gids(sa, gids, *nsrc, 1, pp_ports); + if (sa_status != IB_SUCCESS) + goto Exit; + } + + if (comp_mask & IB_MPR_COMPMASK_DGIDCOUNT) { + *ndest = p_mpr->dgid_count; + if (*ndest + *nsrc > IB_MULTIPATH_MAX_GIDS) + *ndest = IB_MULTIPATH_MAX_GIDS - *nsrc; + sa_status = + __osm_mpr_rcv_get_gids(sa, gids + *nsrc, *ndest, 0, + pp_ports + *nsrc); + } + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (sa_status); +} + +#define __hash_lids(a, b, lmc) \ + (((((a) >> (lmc)) << 4) | ((b) >> (lmc))) % 103) + +/********************************************************************** + **********************************************************************/ +static void +__osm_mpr_rcv_get_apm_paths(IN osm_sa_t * sa, + IN const ib_multipath_rec_t * const p_mpr, + IN const osm_port_t * const p_req_port, + IN osm_port_t ** _pp_ports, + IN const ib_net64_t comp_mask, + IN cl_qlist_t * const p_list) +{ + osm_port_t *pp_ports[4]; + osm_mpr_item_t *matrix[2][2]; + int base_offs, src_lid_ho, dest_lid_ho; + int sumA, sumB, minA, minB; + + OSM_LOG_ENTER(sa->p_log); + + /* + * We want to: + * 1. use different lid offsets (from base) for the resultant paths + * to increase the probability of redundant paths or in case + * of Clos - to ensure it (different offset => different spine!) + * 2. keep consistent paths no matter of direction and order of ports + * 3. distibute the lid offsets to balance the load + * So, we sort the ports (within the srcs, and within the dests), + * hash the lids of S0, D0 (after the sort), and call __osm_mpr_rcv_get_apm_port_pair_paths + * with base_lid for S0, D0 and base_lid + 1 for S1, D1. This way we will get + * always the same offsets - order indepentent, and make sure different spines are used. + * Note that the diagonals on a Clos have the same number of hops, so it doesn't + * really matter which diagonal we use. + */ + if (_pp_ports[0]->guid < _pp_ports[1]->guid) { + pp_ports[0] = _pp_ports[0]; + pp_ports[1] = _pp_ports[1]; + } else { + pp_ports[0] = _pp_ports[1]; + pp_ports[1] = _pp_ports[0]; + } + if (_pp_ports[2]->guid < _pp_ports[3]->guid) { + pp_ports[2] = _pp_ports[2]; + pp_ports[3] = _pp_ports[3]; + } else { + pp_ports[2] = _pp_ports[3]; + pp_ports[3] = _pp_ports[2]; + } + + src_lid_ho = osm_port_get_base_lid(pp_ports[0]); + dest_lid_ho = osm_port_get_base_lid(pp_ports[2]); + + base_offs = src_lid_ho < dest_lid_ho ? + __hash_lids(src_lid_ho, dest_lid_ho, sa->p_subn->opt.lmc) : + __hash_lids(dest_lid_ho, src_lid_ho, sa->p_subn->opt.lmc); + + matrix[0][0] = + __osm_mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_ports[0], + pp_ports[2], base_offs, + comp_mask, p_list); + matrix[0][1] = + __osm_mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_ports[0], + pp_ports[3], base_offs, + comp_mask, p_list); + matrix[1][0] = + __osm_mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_ports[1], + pp_ports[2], base_offs + 1, + comp_mask, p_list); + matrix[1][1] = + __osm_mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_ports[1], + pp_ports[3], base_offs + 1, + comp_mask, p_list); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "APM matrix:\n" + "\t{0,0} 0x%X->0x%X (%d)\t| {0,1} 0x%X->0x%X (%d)\n" + "\t{1,0} 0x%X->0x%X (%d)\t| {1,1} 0x%X->0x%X (%d)\n", + matrix[0][0]->path_rec.slid, matrix[0][0]->path_rec.dlid, + matrix[0][0]->hops, matrix[0][1]->path_rec.slid, + matrix[0][1]->path_rec.dlid, matrix[0][1]->hops, + matrix[1][0]->path_rec.slid, matrix[1][0]->path_rec.dlid, + matrix[1][0]->hops, matrix[1][1]->path_rec.slid, + matrix[1][1]->path_rec.dlid, matrix[1][1]->hops); + + /* check diagonal A {(0,0), (1,1)} */ + sumA = matrix[0][0]->hops + matrix[1][1]->hops; + minA = min(matrix[0][0]->hops, matrix[1][1]->hops); + + /* check diagonal B {(0,1), (1,0)} */ + sumB = matrix[0][1]->hops + matrix[1][0]->hops; + minB = min(matrix[0][1]->hops, matrix[1][0]->hops); + + /* and the winner is... */ + if (minA <= minB || (minA == minB && sumA < sumB)) { + /* Diag A */ + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Diag {0,0} & {1,1} is the best:\n" + "\t{0,0} 0x%X->0x%X (%d)\t & {1,1} 0x%X->0x%X (%d)\n", + matrix[0][0]->path_rec.slid, + matrix[0][0]->path_rec.dlid, matrix[0][0]->hops, + matrix[1][1]->path_rec.slid, + matrix[1][1]->path_rec.dlid, matrix[1][1]->hops); + cl_qlist_insert_tail(p_list, &matrix[0][0]->list_item); + cl_qlist_insert_tail(p_list, &matrix[1][1]->list_item); + free(matrix[0][1]); + free(matrix[1][0]); + } else { + /* Diag B */ + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Diag {0,1} & {1,0} is the best:\n" + "\t{0,1} 0x%X->0x%X (%d)\t & {1,0} 0x%X->0x%X (%d)\n", + matrix[0][1]->path_rec.slid, + matrix[0][1]->path_rec.dlid, matrix[0][1]->hops, + matrix[1][0]->path_rec.slid, + matrix[1][0]->path_rec.dlid, matrix[1][0]->hops); + cl_qlist_insert_tail(p_list, &matrix[0][1]->list_item); + cl_qlist_insert_tail(p_list, &matrix[1][0]->list_item); + free(matrix[0][0]); + free(matrix[1][1]); + } + + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_mpr_rcv_process_pairs(IN osm_sa_t * sa, + IN const ib_multipath_rec_t * const p_mpr, + IN osm_port_t * const p_req_port, + IN osm_port_t ** pp_ports, + IN const int nsrc, + IN const int ndest, + IN const ib_net64_t comp_mask, + IN cl_qlist_t * const p_list) +{ + osm_port_t **pp_src_port, **pp_es; + osm_port_t **pp_dest_port, **pp_ed; + uint32_t max_paths, num_paths, total_paths = 0; + + OSM_LOG_ENTER(sa->p_log); + + if (comp_mask & IB_MPR_COMPMASK_NUMBPATH) + max_paths = p_mpr->num_path & 0x7F; + else + max_paths = OSM_SA_MPR_MAX_NUM_PATH; + + for (pp_src_port = pp_ports, pp_es = pp_ports + nsrc; + pp_src_port < pp_es; pp_src_port++) { + for (pp_dest_port = pp_es, pp_ed = pp_es + ndest; + pp_dest_port < pp_ed; pp_dest_port++) { + num_paths = + __osm_mpr_rcv_get_port_pair_paths(sa, p_mpr, + p_req_port, + *pp_src_port, + *pp_dest_port, + max_paths - + total_paths, + comp_mask, + p_list); + total_paths += num_paths; + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "%d paths %d total paths %d max paths\n", + num_paths, total_paths, max_paths); + /* Just take first NumbPaths found */ + if (total_paths >= max_paths) + goto Exit; + } + } + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_mpr_rcv_process(IN void *context, IN void *data) +{ + osm_sa_t *sa = context; + osm_madw_t *p_madw = data; + const ib_multipath_rec_t *p_mpr; + ib_sa_mad_t *p_sa_mad; + osm_port_t *requester_port; + osm_port_t *pp_ports[IB_MULTIPATH_MAX_GIDS]; + cl_qlist_t pr_list; + ib_net16_t sa_status; + int nsrc, ndest; + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_mpr = (ib_multipath_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_MULTIPATH_RECORD); + + if ((p_sa_mad->rmpp_flags & IB_RMPP_FLAG_ACTIVE) != IB_RMPP_FLAG_ACTIVE) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4510: " + "Invalid request since RMPP_FLAG_ACTIVE is not set\n"); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + /* we only support SubnAdmGetMulti method */ + if (p_sa_mad->method != IB_MAD_METHOD_GETMULTI) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4513: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_sa_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + /* update the requester physical port. */ + requester_port = osm_get_port_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (requester_port == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4517: " + "Cannot find requester physical port\n"); + goto Exit; + } + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_multipath_record(sa->p_log, p_mpr, OSM_LOG_DEBUG); + + cl_qlist_init(&pr_list); + + /* + Most SA functions (including this one) are read-only on the + subnet object, so we grab the lock non-exclusively. + */ + cl_plock_acquire(sa->p_lock); + + sa_status = __osm_mpr_rcv_get_end_points(sa, p_madw, pp_ports, + &nsrc, &ndest); + + if (sa_status != IB_SA_MAD_STATUS_SUCCESS || !nsrc || !ndest) { + if (sa_status == IB_SA_MAD_STATUS_SUCCESS && (!nsrc || !ndest)) + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4512: " + "__osm_mpr_rcv_get_end_points failed, not enough GIDs " + "(nsrc %d ndest %d)\n", nsrc, ndest); + cl_plock_release(sa->p_lock); + if (sa_status == IB_SA_MAD_STATUS_SUCCESS) + osm_sa_send_error(sa, p_madw, + IB_SA_MAD_STATUS_REQ_INVALID); + else + osm_sa_send_error(sa, p_madw, sa_status); + goto Exit; + } + + /* APM request */ + if (nsrc == 2 && ndest == 2 && (p_mpr->num_path & 0x7F) == 2) + __osm_mpr_rcv_get_apm_paths(sa, p_mpr, requester_port, + pp_ports, p_sa_mad->comp_mask, + &pr_list); + else + __osm_mpr_rcv_process_pairs(sa, p_mpr, requester_port, + pp_ports, nsrc, ndest, + p_sa_mad->comp_mask, &pr_list); + + cl_plock_release(sa->p_lock); + + /* o15-0.2.7: If MultiPath is supported, then SA shall respond to a + SubnAdmGetMulti() containing a valid MultiPathRecord attribute with + a set of zero or more PathRecords satisfying the constraints + indicated in the MultiPathRecord received. The PathRecord Attribute + ID shall be used in the response. + */ + p_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD; + osm_sa_respond(sa, p_madw, sizeof(ib_path_rec_t), &pr_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} +#endif diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_node_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_node_record.c new file mode 100644 index 000000000000..4df2c9154568 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_node_record.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_nr_rcv_t. + * This object represents the NodeInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_nr_item { + cl_list_item_t list_item; + ib_node_record_t rec; +} osm_nr_item_t; + +typedef struct osm_nr_search_ctxt { + const ib_node_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_nr_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_nr_rcv_new_nr(IN osm_sa_t * sa, + IN const osm_node_t * const p_node, + IN cl_qlist_t * const p_list, + IN ib_net64_t const port_guid, IN ib_net16_t const lid) +{ + osm_nr_item_t *p_rec_item; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sa->p_log); + + p_rec_item = malloc(sizeof(*p_rec_item)); + if (p_rec_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1D02: " + "rec_item alloc failed\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "New NodeRecord: node 0x%016" PRIx64 + "\n\t\t\t\tport 0x%016" PRIx64 ", lid %u\n", + cl_ntoh64(osm_node_get_node_guid(p_node)), + cl_ntoh64(port_guid), cl_ntoh16(lid)); + + memset(p_rec_item, 0, sizeof(*p_rec_item)); + + p_rec_item->rec.lid = lid; + + p_rec_item->rec.node_info = p_node->node_info; + p_rec_item->rec.node_info.port_guid = port_guid; + memcpy(&(p_rec_item->rec.node_desc), &(p_node->node_desc), + IB_NODE_DESCRIPTION_SIZE); + cl_qlist_insert_tail(p_list, &p_rec_item->list_item); + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_nr_rcv_create_nr(IN osm_sa_t * sa, + IN osm_node_t * const p_node, + IN cl_qlist_t * const p_list, + IN ib_net64_t const match_port_guid, + IN ib_net16_t const match_lid, + IN const osm_physp_t * const p_req_physp) +{ + const osm_physp_t *p_physp; + uint8_t port_num; + uint8_t num_ports; + uint16_t match_lid_ho; + ib_net16_t base_lid; + ib_net16_t base_lid_ho; + ib_net16_t max_lid_ho; + uint8_t lmc; + ib_net64_t port_guid; + + OSM_LOG_ENTER(sa->p_log); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Looking for NodeRecord with LID: %u GUID:0x%016" + PRIx64 "\n", cl_ntoh16(match_lid), + cl_ntoh64(match_port_guid)); + + /* + For switches, do not return the NodeInfo record + for each port on the switch, just for port 0. + */ + if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) + num_ports = 1; + else + num_ports = osm_node_get_num_physp(p_node); + + for (port_num = 0; port_num < num_ports; port_num++) { + p_physp = osm_node_get_physp_ptr(p_node, port_num); + if (!p_physp) + continue; + + /* Check to see if the found p_physp and the requester physp + share a pkey. If not - continue */ + if (!osm_physp_share_pkey(sa->p_log, p_physp, p_req_physp)) + continue; + + port_guid = osm_physp_get_port_guid(p_physp); + + if (match_port_guid && (port_guid != match_port_guid)) + continue; + + base_lid = osm_physp_get_base_lid(p_physp); + base_lid_ho = cl_ntoh16(base_lid); + lmc = osm_physp_get_lmc(p_physp); + max_lid_ho = (uint16_t) (base_lid_ho + (1 << lmc) - 1); + match_lid_ho = cl_ntoh16(match_lid); + + if (match_lid_ho) { + /* + We validate that the lid belongs to this node. + */ + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Comparing LID: %u <= %u <= %u\n", + base_lid_ho, match_lid_ho, max_lid_ho); + + if (match_lid_ho < base_lid_ho + || match_lid_ho > max_lid_ho) + continue; + } + + __osm_nr_rcv_new_nr(sa, p_node, p_list, port_guid, base_lid); + + } + + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_nr_rcv_by_comp_mask(IN cl_map_item_t * const p_map_item, IN void *context) +{ + const osm_nr_search_ctxt_t *const p_ctxt = + (osm_nr_search_ctxt_t *) context; + osm_node_t *const p_node = (osm_node_t *) p_map_item; + const ib_node_record_t *const p_rcvd_rec = p_ctxt->p_rcvd_rec; + const osm_physp_t *const p_req_physp = p_ctxt->p_req_physp; + osm_sa_t *sa = p_ctxt->sa; + ib_net64_t const comp_mask = p_ctxt->comp_mask; + ib_net64_t match_port_guid = 0; + ib_net16_t match_lid = 0; + + OSM_LOG_ENTER(p_ctxt->sa->p_log); + + osm_dump_node_info(p_ctxt->sa->p_log, + &p_node->node_info, OSM_LOG_VERBOSE); + + if (comp_mask & IB_NR_COMPMASK_LID) + match_lid = p_rcvd_rec->lid; + + if (comp_mask & IB_NR_COMPMASK_NODEGUID) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Looking for node 0x%016" PRIx64 + ", found 0x%016" PRIx64 "\n", + cl_ntoh64(p_rcvd_rec->node_info.node_guid), + cl_ntoh64(osm_node_get_node_guid(p_node))); + + if ((p_node->node_info.node_guid != + p_rcvd_rec->node_info.node_guid)) + goto Exit; + } + if (comp_mask & IB_NR_COMPMASK_PORTGUID) { + match_port_guid = p_rcvd_rec->node_info.port_guid; + } + if (comp_mask & IB_NR_COMPMASK_SYSIMAGEGUID) { + if ((p_node->node_info.sys_guid != + p_rcvd_rec->node_info.sys_guid)) + goto Exit; + } + if (comp_mask & IB_NR_COMPMASK_BASEVERSION) { + if ((p_node->node_info.base_version != + p_rcvd_rec->node_info.base_version)) + goto Exit; + } + if (comp_mask & IB_NR_COMPMASK_CLASSVERSION) { + if ((p_node->node_info.class_version != + p_rcvd_rec->node_info.class_version)) + goto Exit; + } + if (comp_mask & IB_NR_COMPMASK_NODETYPE) { + if ((p_node->node_info.node_type != + p_rcvd_rec->node_info.node_type)) + goto Exit; + } + if (comp_mask & IB_NR_COMPMASK_NUMPORTS) { + if ((p_node->node_info.num_ports != + p_rcvd_rec->node_info.num_ports)) + goto Exit; + } + if (comp_mask & IB_NR_COMPMASK_PARTCAP) { + if ((p_node->node_info.partition_cap != + p_rcvd_rec->node_info.partition_cap)) + goto Exit; + } + if (comp_mask & IB_NR_COMPMASK_DEVID) { + if ((p_node->node_info.device_id != + p_rcvd_rec->node_info.device_id)) + goto Exit; + } + if (comp_mask & IB_NR_COMPMASK_REV) { + if ((p_node->node_info.revision != + p_rcvd_rec->node_info.revision)) + goto Exit; + } + if (comp_mask & IB_NR_COMPMASK_PORTNUM) { + if (ib_node_info_get_local_port_num(&p_node->node_info) != + ib_node_info_get_local_port_num(&p_rcvd_rec->node_info)) + goto Exit; + } + if (comp_mask & IB_NR_COMPMASK_VENDID) { + if (ib_node_info_get_vendor_id(&p_node->node_info) != + ib_node_info_get_vendor_id(&p_rcvd_rec->node_info)) + goto Exit; + } + if (comp_mask & IB_NR_COMPMASK_NODEDESC) { + if (strncmp((char *)&p_node->node_desc, + (char *)&p_rcvd_rec->node_desc, + sizeof(ib_node_desc_t))) + goto Exit; + } + + __osm_nr_rcv_create_nr(sa, p_node, p_ctxt->p_list, + match_port_guid, match_lid, p_req_physp); + +Exit: + OSM_LOG_EXIT(p_ctxt->sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_nr_rcv_process(IN void *ctx, IN void *data) +{ + osm_sa_t *sa = ctx; + osm_madw_t *p_madw = data; + const ib_sa_mad_t *p_rcvd_mad; + const ib_node_record_t *p_rcvd_rec; + cl_qlist_t rec_list; + osm_nr_search_ctxt_t context; + osm_physp_t *p_req_physp; + + CL_ASSERT(sa); + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_rcvd_rec = (ib_node_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); + + CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_NODE_RECORD); + + /* we only support SubnAdmGet and SubnAdmGetTable methods */ + if (p_rcvd_mad->method != IB_MAD_METHOD_GET && + p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1D05: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_rcvd_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1D04: " + "Cannot find requester physical port\n"); + goto Exit; + } + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_node_record(sa->p_log, p_rcvd_rec, OSM_LOG_DEBUG); + + cl_qlist_init(&rec_list); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = p_rcvd_mad->comp_mask; + context.sa = sa; + context.p_req_physp = p_req_physp; + + cl_plock_acquire(sa->p_lock); + + cl_qmap_apply_func(&sa->p_subn->node_guid_tbl, + __osm_nr_rcv_by_comp_mask, &context); + + cl_plock_release(sa->p_lock); + + osm_sa_respond(sa, p_madw, sizeof(ib_node_record_t), &rec_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_path_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_path_record.c new file mode 100644 index 000000000000..6fdada7ae4f6 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_path_record.c @@ -0,0 +1,1813 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_pr_rcv_t. + * This object represents the PathRecord Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern uint8_t osm_get_lash_sl(osm_opensm_t * p_osm, + const osm_port_t * p_src_port, + const osm_port_t * p_dst_port); + +typedef struct osm_pr_item { + cl_list_item_t list_item; + ib_path_rec_t path_rec; +} osm_pr_item_t; + +typedef struct osm_path_parms { + ib_net16_t pkey; + uint8_t mtu; + uint8_t rate; + uint8_t sl; + uint8_t pkt_life; + boolean_t reversible; +} osm_path_parms_t; + +static const ib_gid_t zero_gid = { {0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, +}; + +/********************************************************************** + **********************************************************************/ +static inline boolean_t +__osm_sa_path_rec_is_tavor_port(IN const osm_port_t * const p_port) +{ + osm_node_t const *p_node; + ib_net32_t vend_id; + + p_node = p_port->p_node; + vend_id = ib_node_info_get_vendor_id(&p_node->node_info); + + return ((p_node->node_info.device_id == CL_HTON16(23108)) && + ((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) || + (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) || + (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) || + (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE)))); +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +__osm_sa_path_rec_apply_tavor_mtu_limit(IN const ib_path_rec_t * const p_pr, + IN const osm_port_t * const p_src_port, + IN const osm_port_t * const p_dest_port, + IN const ib_net64_t comp_mask) +{ + uint8_t required_mtu; + + /* only if at least one of the ports is a Tavor device */ + if (!__osm_sa_path_rec_is_tavor_port(p_src_port) && + !__osm_sa_path_rec_is_tavor_port(p_dest_port)) + return (FALSE); + + /* + we can apply the patch if either: + 1. No MTU required + 2. Required MTU < + 3. Required MTU = 1K or 512 or 256 + 4. Required MTU > 256 or 512 + */ + required_mtu = ib_path_rec_mtu(p_pr); + if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) && + (comp_mask & IB_PR_COMPMASK_MTU)) { + switch (ib_path_rec_mtu_sel(p_pr)) { + case 0: /* must be greater than */ + case 2: /* exact match */ + if (IB_MTU_LEN_1024 < required_mtu) + return (FALSE); + break; + + case 1: /* must be less than */ + /* can't be disqualified by this one */ + break; + + case 3: /* largest available */ + /* the ULP intentionally requested */ + /* the largest MTU possible */ + return (FALSE); + break; + + default: + /* if we're here, there's a bug in ib_path_rec_mtu_sel() */ + CL_ASSERT(FALSE); + break; + } + } + + return (TRUE); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_pr_rcv_get_path_parms(IN osm_sa_t * sa, + IN const ib_path_rec_t * const p_pr, + IN const osm_port_t * const p_src_port, + IN const osm_port_t * const p_dest_port, + IN const uint16_t dest_lid_ho, + IN const ib_net64_t comp_mask, + OUT osm_path_parms_t * const p_parms) +{ + const osm_node_t *p_node; + const osm_physp_t *p_physp; + const osm_physp_t *p_src_physp; + const osm_physp_t *p_dest_physp; + const osm_prtn_t *p_prtn = NULL; + osm_opensm_t *p_osm; + const ib_port_info_t *p_pi; + ib_api_status_t status = IB_SUCCESS; + ib_net16_t pkey; + uint8_t mtu; + uint8_t rate; + uint8_t pkt_life; + uint8_t required_mtu; + uint8_t required_rate; + uint8_t required_pkt_life; + uint8_t sl; + uint8_t in_port_num; + ib_net16_t dest_lid; + uint8_t i; + ib_slvl_table_t *p_slvl_tbl = NULL; + osm_qos_level_t *p_qos_level = NULL; + uint16_t valid_sl_mask = 0xffff; + int is_lash; + + OSM_LOG_ENTER(sa->p_log); + + dest_lid = cl_hton16(dest_lid_ho); + + p_dest_physp = p_dest_port->p_physp; + p_physp = p_src_port->p_physp; + p_src_physp = p_physp; + p_pi = &p_physp->port_info; + p_osm = sa->p_subn->p_osm; + + mtu = ib_port_info_get_mtu_cap(p_pi); + rate = ib_port_info_compute_rate(p_pi); + + /* + Mellanox Tavor device performance is better using 1K MTU. + If required MTU and MTU selector are such that 1K is OK + and at least one end of the path is Tavor we override the + port MTU with 1K. + */ + if (sa->p_subn->opt.enable_quirks && + __osm_sa_path_rec_apply_tavor_mtu_limit(p_pr, p_src_port, + p_dest_port, comp_mask)) + if (mtu > IB_MTU_LEN_1024) { + mtu = IB_MTU_LEN_1024; + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Optimized Path MTU to 1K for Mellanox Tavor device\n"); + } + + /* + Walk the subnet object from source to destination, + tracking the most restrictive rate and mtu values along the way... + + If source port node is a switch, then p_physp should + point to the port that routes the destination lid + */ + + p_node = osm_physp_get_node_ptr(p_physp); + + if (p_node->sw) { + /* + * Source node is a switch. + * Make sure that p_physp points to the out port of the + * switch that routes to the destination lid (dest_lid_ho) + */ + p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid); + if (p_physp == 0) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F02: " + "Cannot find routing to LID %u from switch for GUID 0x%016" + PRIx64 "\n", dest_lid_ho, + cl_ntoh64(osm_node_get_node_guid(p_node))); + status = IB_NOT_FOUND; + goto Exit; + } + } + + if (sa->p_subn->opt.qos) { + + /* + * Whether this node is switch or CA, the IN port for + * the sl2vl table is 0, because this is a source node. + */ + p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, 0); + + /* update valid SLs that still exist on this route */ + for (i = 0; i < IB_MAX_NUM_VLS; i++) { + if (valid_sl_mask & (1 << i) && + ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL) + valid_sl_mask &= ~(1 << i); + } + if (!valid_sl_mask) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "All the SLs lead to VL15 on this path\n"); + status = IB_NOT_FOUND; + goto Exit; + } + } + + /* + * Same as above + */ + p_node = osm_physp_get_node_ptr(p_dest_physp); + + if (p_node->sw) { + /* + * if destination is switch, we want p_dest_physp to point to port 0 + */ + p_dest_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid); + + if (p_dest_physp == 0) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F03: " + "Cannot find routing to LID %u from switch for GUID 0x%016" + PRIx64 "\n", dest_lid_ho, + cl_ntoh64(osm_node_get_node_guid(p_node))); + status = IB_NOT_FOUND; + goto Exit; + } + + } + + /* + * Now go through the path step by step + */ + + while (p_physp != p_dest_physp) { + + p_node = osm_physp_get_node_ptr(p_physp); + p_physp = osm_physp_get_remote(p_physp); + + if (p_physp == 0) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F05: " + "Cannot find remote phys port when routing to LID %u from node GUID 0x%016" + PRIx64 "\n", dest_lid_ho, + cl_ntoh64(osm_node_get_node_guid(p_node))); + status = IB_ERROR; + goto Exit; + } + + in_port_num = osm_physp_get_port_num(p_physp); + + /* + This is point to point case (no switch in between) + */ + if (p_physp == p_dest_physp) + break; + + p_node = osm_physp_get_node_ptr(p_physp); + + if (!p_node->sw) { + /* + There is some sort of problem in the subnet object! + If this isn't a switch, we should have reached + the destination by now! + */ + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F06: " + "Internal error, bad path\n"); + status = IB_ERROR; + goto Exit; + } + + /* + Check parameters for the ingress port in this switch. + */ + p_pi = &p_physp->port_info; + + if (mtu > ib_port_info_get_mtu_cap(p_pi)) + mtu = ib_port_info_get_mtu_cap(p_pi); + + if (rate > ib_port_info_compute_rate(p_pi)) + rate = ib_port_info_compute_rate(p_pi); + + /* + Continue with the egress port on this switch. + */ + p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid); + if (p_physp == 0) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F07: " + "Dead end on path to LID %u from switch for GUID 0x%016" + PRIx64 "\n", dest_lid_ho, + cl_ntoh64(osm_node_get_node_guid(p_node))); + status = IB_ERROR; + goto Exit; + } + + p_pi = &p_physp->port_info; + + if (mtu > ib_port_info_get_mtu_cap(p_pi)) + mtu = ib_port_info_get_mtu_cap(p_pi); + + if (rate > ib_port_info_compute_rate(p_pi)) + rate = ib_port_info_compute_rate(p_pi); + + if (sa->p_subn->opt.qos) { + /* + * Check SL2VL table of the switch and update valid SLs + */ + p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, in_port_num); + for (i = 0; i < IB_MAX_NUM_VLS; i++) { + if (valid_sl_mask & (1 << i) && + ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL) + valid_sl_mask &= ~(1 << i); + } + if (!valid_sl_mask) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "All the SLs " + "lead to VL15 on this path\n"); + status = IB_NOT_FOUND; + goto Exit; + } + } + } + + /* + p_physp now points to the destination + */ + p_pi = &p_physp->port_info; + + if (mtu > ib_port_info_get_mtu_cap(p_pi)) + mtu = ib_port_info_get_mtu_cap(p_pi); + + if (rate > ib_port_info_compute_rate(p_pi)) + rate = ib_port_info_compute_rate(p_pi); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Path min MTU = %u, min rate = %u\n", mtu, rate); + + /* + * Get QoS Level object according to the path request + * and adjust path parameters according to QoS settings + */ + if (sa->p_subn->opt.qos && + sa->p_subn->p_qos_policy && + (p_qos_level = + osm_qos_policy_get_qos_level_by_pr(sa->p_subn->p_qos_policy, + p_pr, p_src_physp, p_dest_physp, + comp_mask))) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "PathRecord request matches QoS Level '%s' (%s)\n", + p_qos_level->name, p_qos_level->use ? + p_qos_level->use : "no description"); + + if (p_qos_level->mtu_limit_set + && (mtu > p_qos_level->mtu_limit)) + mtu = p_qos_level->mtu_limit; + + if (p_qos_level->rate_limit_set + && (rate > p_qos_level->rate_limit)) + rate = p_qos_level->rate_limit; + + if (p_qos_level->sl_set) { + sl = p_qos_level->sl; + if (!(valid_sl_mask & (1 << sl))) { + status = IB_NOT_FOUND; + goto Exit; + } + } + } + + /* + * Set packet lifetime. + * According to spec definition IBA 1.2 Table 205 + * PacketLifeTime description, for loopback paths, + * packetLifeTime shall be zero. + */ + if (p_src_port == p_dest_port) + pkt_life = 0; + else if (p_qos_level && p_qos_level->pkt_life_set) + pkt_life = p_qos_level->pkt_life; + else + pkt_life = sa->p_subn->opt.subnet_timeout; + + /* + Determine if these values meet the user criteria + and adjust appropriately + */ + + /* we silently ignore cases where only the MTU selector is defined */ + if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) && + (comp_mask & IB_PR_COMPMASK_MTU)) { + required_mtu = ib_path_rec_mtu(p_pr); + switch (ib_path_rec_mtu_sel(p_pr)) { + case 0: /* must be greater than */ + if (mtu <= required_mtu) + status = IB_NOT_FOUND; + break; + + case 1: /* must be less than */ + if (mtu >= required_mtu) { + /* adjust to use the highest mtu + lower then the required one */ + if (required_mtu > 1) + mtu = required_mtu - 1; + else + status = IB_NOT_FOUND; + } + break; + + case 2: /* exact match */ + if (mtu < required_mtu) + status = IB_NOT_FOUND; + else + mtu = required_mtu; + break; + + case 3: /* largest available */ + /* can't be disqualified by this one */ + break; + + default: + /* if we're here, there's a bug in ib_path_rec_mtu_sel() */ + CL_ASSERT(FALSE); + status = IB_ERROR; + break; + } + } + if (status != IB_SUCCESS) + goto Exit; + + /* we silently ignore cases where only the Rate selector is defined */ + if ((comp_mask & IB_PR_COMPMASK_RATESELEC) && + (comp_mask & IB_PR_COMPMASK_RATE)) { + required_rate = ib_path_rec_rate(p_pr); + switch (ib_path_rec_rate_sel(p_pr)) { + case 0: /* must be greater than */ + if (rate <= required_rate) + status = IB_NOT_FOUND; + break; + + case 1: /* must be less than */ + if (rate >= required_rate) { + /* adjust the rate to use the highest rate + lower then the required one */ + if (required_rate > 2) + rate = required_rate - 1; + else + status = IB_NOT_FOUND; + } + break; + + case 2: /* exact match */ + if (rate < required_rate) + status = IB_NOT_FOUND; + else + rate = required_rate; + break; + + case 3: /* largest available */ + /* can't be disqualified by this one */ + break; + + default: + /* if we're here, there's a bug in ib_path_rec_mtu_sel() */ + CL_ASSERT(FALSE); + status = IB_ERROR; + break; + } + } + if (status != IB_SUCCESS) + goto Exit; + + /* we silently ignore cases where only the PktLife selector is defined */ + if ((comp_mask & IB_PR_COMPMASK_PKTLIFETIMESELEC) && + (comp_mask & IB_PR_COMPMASK_PKTLIFETIME)) { + required_pkt_life = ib_path_rec_pkt_life(p_pr); + switch (ib_path_rec_pkt_life_sel(p_pr)) { + case 0: /* must be greater than */ + if (pkt_life <= required_pkt_life) + status = IB_NOT_FOUND; + break; + + case 1: /* must be less than */ + if (pkt_life >= required_pkt_life) { + /* adjust the lifetime to use the highest possible + lower then the required one */ + if (required_pkt_life > 1) + pkt_life = required_pkt_life - 1; + else + status = IB_NOT_FOUND; + } + break; + + case 2: /* exact match */ + if (pkt_life < required_pkt_life) + status = IB_NOT_FOUND; + else + pkt_life = required_pkt_life; + break; + + case 3: /* smallest available */ + /* can't be disqualified by this one */ + break; + + default: + /* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */ + CL_ASSERT(FALSE); + status = IB_ERROR; + break; + } + } + + if (status != IB_SUCCESS) + goto Exit; + + /* + * set Pkey for this path record request + */ + + if ((comp_mask & IB_PR_COMPMASK_RAWTRAFFIC) && + (cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31))) + pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp); + + else if (comp_mask & IB_PR_COMPMASK_PKEY) { + /* + * PR request has a specific pkey: + * Check that source and destination share this pkey. + * If QoS level has pkeys, check that this pkey exists + * in the QoS level pkeys. + * PR returned pkey is the requested pkey. + */ + pkey = p_pr->pkey; + if (!osm_physp_share_this_pkey(p_src_physp, p_dest_physp, pkey)) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1A: " + "Ports 0x%016" PRIx64 " 0x%016" PRIx64 + " do not share specified PKey 0x%04x\n", + cl_ntoh64(osm_physp_get_port_guid(p_src_physp)), + cl_ntoh64(osm_physp_get_port_guid(p_dest_physp)), + cl_ntoh16(pkey)); + status = IB_NOT_FOUND; + goto Exit; + } + if (p_qos_level && p_qos_level->pkey_range_len && + !osm_qos_level_has_pkey(p_qos_level, pkey)) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1D: " + "Ports do not share PKeys defined by QoS level\n"); + status = IB_NOT_FOUND; + goto Exit; + } + + } else if (p_qos_level && p_qos_level->pkey_range_len) { + /* + * PR request doesn't have a specific pkey, but QoS level + * has pkeys - get shared pkey from QoS level pkeys + */ + pkey = osm_qos_level_get_shared_pkey(p_qos_level, + p_src_physp, p_dest_physp); + if (!pkey) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1E: " + "Ports 0x%016" PRIx64 " 0x%016" PRIx64 + " do not share PKeys defined by QoS level\n", + cl_ntoh64(osm_physp_get_port_guid(p_src_physp)), + cl_ntoh64(osm_physp_get_port_guid(p_dest_physp))); + status = IB_NOT_FOUND; + goto Exit; + } + } else { + /* + * Neither PR request nor QoS level have pkey. + * Just get any shared pkey. + */ + pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp); + if (!pkey) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1B: " + "Ports 0x%016" PRIx64 " 0x%016" PRIx64 + " do not have any shared PKeys\n", + cl_ntoh64(osm_physp_get_port_guid(p_src_physp)), + cl_ntoh64(osm_physp_get_port_guid(p_dest_physp))); + status = IB_NOT_FOUND; + goto Exit; + } + } + + if (pkey) { + p_prtn = + (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl, + pkey & cl_hton16((uint16_t) ~ + 0x8000)); + if (p_prtn == + (osm_prtn_t *) cl_qmap_end(&sa->p_subn->prtn_pkey_tbl)) + p_prtn = NULL; + } + + /* + * Set PathRecord SL. + */ + + is_lash = (p_osm->routing_engine_used == OSM_ROUTING_ENGINE_TYPE_LASH); + + if (comp_mask & IB_PR_COMPMASK_SL) { + /* + * Specific SL was requested + */ + sl = ib_path_rec_sl(p_pr); + + if (p_qos_level && p_qos_level->sl_set + && (p_qos_level->sl != sl)) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1F: " + "QoS constaraints: required PathRecord SL (%u) " + "doesn't match QoS policy SL (%u)\n", sl, + p_qos_level->sl); + status = IB_NOT_FOUND; + goto Exit; + } + + if (is_lash + && osm_get_lash_sl(p_osm, p_src_port, p_dest_port) != sl) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F23: " + "Required PathRecord SL (%u) doesn't " + "match LASH SL\n", sl); + status = IB_NOT_FOUND; + goto Exit; + } + + } else if (is_lash) { + /* + * No specific SL in PathRecord request. + * If it's LASH routing - use its SL. + * slid and dest_lid are stored in network in lash. + */ + sl = osm_get_lash_sl(p_osm, p_src_port, p_dest_port); + } else if (p_qos_level && p_qos_level->sl_set) { + /* + * No specific SL was requested, and we're not in + * LASH routing, but there is an SL in QoS level. + */ + sl = p_qos_level->sl; + + if (pkey && p_prtn && p_prtn->sl != p_qos_level->sl) + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "QoS level SL (%u) overrides partition SL (%u)\n", + p_qos_level->sl, p_prtn->sl); + + } else if (pkey) { + /* + * No specific SL in request or in QoS level - use partition SL + */ + if (!p_prtn) { + sl = OSM_DEFAULT_SL; + /* this may be possible when pkey tables are created somehow in + previous runs or things are going wrong here */ + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1C: " + "No partition found for PKey 0x%04x - using default SL %d\n", + cl_ntoh16(pkey), sl); + } else + sl = p_prtn->sl; + } else if (sa->p_subn->opt.qos) { + if (valid_sl_mask & (1 << OSM_DEFAULT_SL)) + sl = OSM_DEFAULT_SL; + else { + for (i = 0; i < IB_MAX_NUM_VLS; i++) + if (valid_sl_mask & (1 << i)) + break; + sl = i; + } + } else + sl = OSM_DEFAULT_SL; + + if (sa->p_subn->opt.qos && !(valid_sl_mask & (1 << sl))) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F24: " + "Selected SL (%u) leads to VL15\n", sl); + status = IB_NOT_FOUND; + goto Exit; + } + + /* reset pkey when raw traffic */ + if (comp_mask & IB_PR_COMPMASK_RAWTRAFFIC && + cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31)) + pkey = 0; + + p_parms->mtu = mtu; + p_parms->rate = rate; + p_parms->pkt_life = pkt_life; + p_parms->pkey = pkey; + p_parms->sl = sl; + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Path params: mtu = %u, rate = %u," + " packet lifetime = %u, pkey = 0x%04X, sl = %u\n", + mtu, rate, pkt_life, cl_ntoh16(pkey), sl); +Exit: + OSM_LOG_EXIT(sa->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pr_rcv_build_pr(IN osm_sa_t * sa, + IN const osm_port_t * const p_src_port, + IN const osm_port_t * const p_dest_port, + IN const ib_gid_t * const p_dgid, + IN const uint16_t src_lid_ho, + IN const uint16_t dest_lid_ho, + IN const uint8_t preference, + IN const osm_path_parms_t * const p_parms, + OUT ib_path_rec_t * const p_pr) +{ + const osm_physp_t *p_src_physp; + const osm_physp_t *p_dest_physp; + boolean_t is_nonzero_gid = 0; + + OSM_LOG_ENTER(sa->p_log); + + p_src_physp = p_src_port->p_physp; + + if (p_dgid) { + if (memcmp(p_dgid, &zero_gid, sizeof(*p_dgid))) + is_nonzero_gid = 1; + } + + if (is_nonzero_gid) + p_pr->dgid = *p_dgid; + else { + p_dest_physp = p_dest_port->p_physp; + + p_pr->dgid.unicast.prefix = + osm_physp_get_subnet_prefix(p_dest_physp); + p_pr->dgid.unicast.interface_id = + osm_physp_get_port_guid(p_dest_physp); + } + + p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix(p_src_physp); + p_pr->sgid.unicast.interface_id = osm_physp_get_port_guid(p_src_physp); + + p_pr->dlid = cl_hton16(dest_lid_ho); + p_pr->slid = cl_hton16(src_lid_ho); + + p_pr->hop_flow_raw &= cl_hton32(1 << 31); + + /* Only set HopLimit if going through a router */ + if (is_nonzero_gid) + p_pr->hop_flow_raw |= cl_hton32(IB_HOPLIMIT_MAX); + + p_pr->pkey = p_parms->pkey; + ib_path_rec_set_sl(p_pr, p_parms->sl); + ib_path_rec_set_qos_class(p_pr, 0); + p_pr->mtu = (uint8_t) (p_parms->mtu | 0x80); + p_pr->rate = (uint8_t) (p_parms->rate | 0x80); + + /* According to 1.2 spec definition Table 205 PacketLifeTime description, + for loopback paths, packetLifeTime shall be zero. */ + if (p_src_port == p_dest_port) + p_pr->pkt_life = 0x80; /* loopback */ + else + p_pr->pkt_life = (uint8_t) (p_parms->pkt_life | 0x80); + + p_pr->preference = preference; + + /* always return num_path = 0 so this is only the reversible component */ + if (p_parms->reversible) + p_pr->num_path = 0x80; + + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static osm_pr_item_t * +__osm_pr_rcv_get_lid_pair_path(IN osm_sa_t * sa, + IN const ib_path_rec_t * const p_pr, + IN const osm_port_t * const p_src_port, + IN const osm_port_t * const p_dest_port, + IN const ib_gid_t * const p_dgid, + IN const uint16_t src_lid_ho, + IN const uint16_t dest_lid_ho, + IN const ib_net64_t comp_mask, + IN const uint8_t preference) +{ + osm_path_parms_t path_parms; + osm_path_parms_t rev_path_parms; + osm_pr_item_t *p_pr_item; + ib_api_status_t status, rev_path_status; + + OSM_LOG_ENTER(sa->p_log); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID %u, Dest LID %u\n", + src_lid_ho, dest_lid_ho); + + p_pr_item = malloc(sizeof(*p_pr_item)); + if (p_pr_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F01: " + "Unable to allocate path record\n"); + goto Exit; + } + memset(p_pr_item, 0, sizeof(*p_pr_item)); + + status = __osm_pr_rcv_get_path_parms(sa, p_pr, p_src_port, + p_dest_port, dest_lid_ho, + comp_mask, &path_parms); + + if (status != IB_SUCCESS) { + free(p_pr_item); + p_pr_item = NULL; + goto Exit; + } + + /* now try the reversible path */ + rev_path_status = __osm_pr_rcv_get_path_parms(sa, p_pr, p_dest_port, + p_src_port, src_lid_ho, + comp_mask, + &rev_path_parms); + path_parms.reversible = (rev_path_status == IB_SUCCESS); + + /* did we get a Reversible Path compmask ? */ + /* + NOTE that if the reversible component = 0, it is a don't care + rather then requiring non-reversible paths ... + see Vol1 Ver1.2 p900 l16 + */ + if (comp_mask & IB_PR_COMPMASK_REVERSIBLE) { + if ((!path_parms.reversible && (p_pr->num_path & 0x80))) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Requested reversible path but failed to get one\n"); + + free(p_pr_item); + p_pr_item = NULL; + goto Exit; + } + } + + __osm_pr_rcv_build_pr(sa, p_src_port, p_dest_port, p_dgid, + src_lid_ho, dest_lid_ho, preference, &path_parms, + &p_pr_item->path_rec); + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (p_pr_item); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pr_rcv_get_port_pair_paths(IN osm_sa_t * sa, + IN const osm_madw_t * const p_madw, + IN const osm_port_t * const p_req_port, + IN const osm_port_t * const p_src_port, + IN const osm_port_t * const p_dest_port, + IN const ib_gid_t * const p_dgid, + IN const ib_net64_t comp_mask, + IN cl_qlist_t * const p_list) +{ + const ib_path_rec_t *p_pr; + const ib_sa_mad_t *p_sa_mad; + osm_pr_item_t *p_pr_item; + uint16_t src_lid_min_ho; + uint16_t src_lid_max_ho; + uint16_t dest_lid_min_ho; + uint16_t dest_lid_max_ho; + uint16_t src_lid_ho; + uint16_t dest_lid_ho; + uint32_t path_num; + uint8_t preference; + uintn_t iterations; + uintn_t src_offset; + uintn_t dest_offset; + + OSM_LOG_ENTER(sa->p_log); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Src port 0x%016" PRIx64 ", Dst port 0x%016" PRIx64 "\n", + cl_ntoh64(osm_port_get_guid(p_src_port)), + cl_ntoh64(osm_port_get_guid(p_dest_port))); + + /* Check that the req_port, src_port and dest_port all share a + pkey. The check is done on the default physical port of the ports. */ + if (osm_port_share_pkey(sa->p_log, p_req_port, p_src_port) == FALSE + || osm_port_share_pkey(sa->p_log, p_req_port, + p_dest_port) == FALSE + || osm_port_share_pkey(sa->p_log, p_src_port, + p_dest_port) == FALSE) + /* One of the pairs doesn't share a pkey so the path is disqualified. */ + goto Exit; + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_pr = (ib_path_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + /* + We shouldn't be here if the paths are disqualified in some way... + Thus, we assume every possible connection is valid. + + We desire to return high-quality paths first. + In OpenSM, higher quality means least overlap with other paths. + This is acheived in practice by returning paths with + different LID value on each end, which means these + paths are more redundant that paths with the same LID repeated + on one side. For example, in OpenSM the paths between two + endpoints with LMC = 1 might be as follows: + + Port A, LID 1 <-> Port B, LID 3 + Port A, LID 1 <-> Port B, LID 4 + Port A, LID 2 <-> Port B, LID 3 + Port A, LID 2 <-> Port B, LID 4 + + The OpenSM unicast routing algorithms attempt to disperse each path + to as varied a physical path as is reasonable. 1<->3 and 1<->4 have + more physical overlap (hence less redundancy) than 1<->3 and 2<->4. + + OpenSM ranks paths in three preference groups: + + Preference Value Description + ---------------- ------------------------------------------- + 0 Redundant in both directions with other + pref value = 0 paths + + 1 Redundant in one direction with other + pref value = 0 and pref value = 1 paths + + 2 Not redundant in either direction with + other paths + + 3-FF Unused + + SA clients don't need to know these details, only that the lower + preference paths are preferred, as stated in the spec. The paths + may not actually be physically redundant depending on the topology + of the subnet, but the point of LMC > 0 is to offer redundancy, + so it is assumed that the subnet is physically appropriate for the + specified LMC value. A more advanced implementation would inspect for + physical redundancy, but I'm not going to bother with that now. + */ + + /* + Refine our search if the client specified end-point LIDs + */ + if (comp_mask & IB_PR_COMPMASK_DLID) { + dest_lid_min_ho = cl_ntoh16(p_pr->dlid); + dest_lid_max_ho = cl_ntoh16(p_pr->dlid); + } else + osm_port_get_lid_range_ho(p_dest_port, &dest_lid_min_ho, + &dest_lid_max_ho); + + if (comp_mask & IB_PR_COMPMASK_SLID) { + src_lid_min_ho = cl_ntoh16(p_pr->slid); + src_lid_max_ho = cl_ntoh16(p_pr->slid); + } else + osm_port_get_lid_range_ho(p_src_port, &src_lid_min_ho, + &src_lid_max_ho); + + if (src_lid_min_ho == 0) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F20:" + "Obtained source LID of 0. No such LID possible\n"); + goto Exit; + } + + if (dest_lid_min_ho == 0) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F21:" + "Obtained destination LID of 0. No such LID possible\n"); + goto Exit; + } + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Src LIDs [%u-%u], Dest LIDs [%u-%u]\n", + src_lid_min_ho, src_lid_max_ho, + dest_lid_min_ho, dest_lid_max_ho); + + src_lid_ho = src_lid_min_ho; + dest_lid_ho = dest_lid_min_ho; + + /* + Preferred paths come first in OpenSM + */ + preference = 0; + path_num = 0; + + /* If SubnAdmGet, assume NumbPaths 1 (1.2 erratum) */ + if (p_sa_mad->method != IB_MAD_METHOD_GET) + if (comp_mask & IB_PR_COMPMASK_NUMBPATH) + iterations = ib_path_rec_num_path(p_pr); + else + iterations = (uintn_t) (-1); + else + iterations = 1; + + while (path_num < iterations) { + /* + These paths are "fully redundant" + */ + + p_pr_item = __osm_pr_rcv_get_lid_pair_path(sa, p_pr, + p_src_port, + p_dest_port, p_dgid, + src_lid_ho, + dest_lid_ho, + comp_mask, + preference); + + if (p_pr_item) { + cl_qlist_insert_tail(p_list, &p_pr_item->list_item); + ++path_num; + } + + if (++src_lid_ho > src_lid_max_ho) + break; + + if (++dest_lid_ho > dest_lid_max_ho) + break; + } + + /* + Check if we've accumulated all the paths that the user cares to see + */ + if (path_num == iterations) + goto Exit; + + /* + Don't bother reporting preference 1 paths for now. + It's more trouble than it's worth and can only occur + if ports have different LMC values, which isn't supported + by OpenSM right now anyway. + */ + preference = 2; + src_lid_ho = src_lid_min_ho; + dest_lid_ho = dest_lid_min_ho; + src_offset = 0; + dest_offset = 0; + + /* + Iterate over the remaining paths + */ + while (path_num < iterations) { + dest_offset++; + dest_lid_ho++; + + if (dest_lid_ho > dest_lid_max_ho) { + src_offset++; + src_lid_ho++; + + if (src_lid_ho > src_lid_max_ho) + break; /* done */ + + dest_offset = 0; + dest_lid_ho = dest_lid_min_ho; + } + + /* + These paths are "fully non-redundant" with paths already + identified above and consequently not of much value. + + Don't return paths we already identified above, as indicated + by the offset values being equal. + */ + if (src_offset == dest_offset) + continue; /* already reported */ + + p_pr_item = __osm_pr_rcv_get_lid_pair_path(sa, p_pr, + p_src_port, + p_dest_port, p_dgid, + src_lid_ho, + dest_lid_ho, + comp_mask, + preference); + + if (p_pr_item) { + cl_qlist_insert_tail(p_list, &p_pr_item->list_item); + ++path_num; + } + } + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static ib_net16_t +__osm_pr_rcv_get_end_points(IN osm_sa_t * sa, + IN const osm_madw_t * const p_madw, + OUT const osm_port_t ** const pp_src_port, + OUT const osm_port_t ** const pp_dest_port, + OUT ib_gid_t * const p_dgid) +{ + const ib_path_rec_t *p_pr; + const ib_sa_mad_t *p_sa_mad; + ib_net64_t comp_mask; + ib_net64_t dest_guid; + ib_api_status_t status; + ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS; + osm_router_t *p_rtr; + osm_port_t *p_rtr_port; + + OSM_LOG_ENTER(sa->p_log); + + /* + Determine what fields are valid and then get a pointer + to the source and destination port objects, if possible. + */ + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_pr = (ib_path_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + comp_mask = p_sa_mad->comp_mask; + + /* + Check a few easy disqualifying cases up front before getting + into the endpoints. + */ + + if (comp_mask & IB_PR_COMPMASK_SGID) { + if (!ib_gid_is_link_local(&p_pr->sgid)) { + if (ib_gid_get_subnet_prefix(&p_pr->sgid) != + sa->p_subn->opt.subnet_prefix) { + /* + This 'error' is the client's fault (bad gid) + so don't enter it as an error in our own log. + Return an error response to the client. + */ + OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, + "Non local SGID subnet prefix 0x%016" + PRIx64 "\n", + cl_ntoh64(p_pr->sgid.unicast.prefix)); + + sa_status = IB_SA_MAD_STATUS_INVALID_GID; + goto Exit; + } + } + + *pp_src_port = osm_get_port_by_guid(sa->p_subn, + p_pr->sgid.unicast. + interface_id); + if (!*pp_src_port) { + /* + This 'error' is the client's fault (bad gid) so + don't enter it as an error in our own log. + Return an error response to the client. + */ + OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, + "No source port with GUID 0x%016" PRIx64 "\n", + cl_ntoh64(p_pr->sgid.unicast.interface_id)); + + sa_status = IB_SA_MAD_STATUS_INVALID_GID; + goto Exit; + } + } else { + *pp_src_port = 0; + if (comp_mask & IB_PR_COMPMASK_SLID) { + status = cl_ptr_vector_at(&sa->p_subn->port_lid_tbl, + cl_ntoh16(p_pr->slid), + (void **)pp_src_port); + + if ((status != CL_SUCCESS) || (*pp_src_port == NULL)) { + /* + This 'error' is the client's fault (bad lid) so + don't enter it as an error in our own log. + Return an error response to the client. + */ + OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, + "No source port with LID %u\n", + cl_ntoh16(p_pr->slid)); + + sa_status = IB_SA_MAD_STATUS_NO_RECORDS; + goto Exit; + } + } + } + + if (p_dgid) + memset(p_dgid, 0, sizeof(*p_dgid)); + + if (comp_mask & IB_PR_COMPMASK_DGID) { + dest_guid = p_pr->dgid.unicast.interface_id; + if (!ib_gid_is_link_local(&p_pr->dgid)) { + if (!ib_gid_is_multicast(&p_pr->dgid) && + ib_gid_get_subnet_prefix(&p_pr->dgid) != + sa->p_subn->opt.subnet_prefix) { + OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, + "Non local DGID subnet prefix 0x%016" + PRIx64 "\n", + cl_ntoh64(p_pr->dgid.unicast.prefix)); + + /* Find the router port that is configured to + handle this prefix, if any */ + osm_prefix_route_t *route = NULL; + osm_prefix_route_t *r = (osm_prefix_route_t *) + cl_qlist_head(&sa->p_subn->prefix_routes_list); + + while (r != (osm_prefix_route_t *) + cl_qlist_end(&sa->p_subn->prefix_routes_list)) + { + if (r->prefix == p_pr->dgid.unicast.prefix || + r->prefix == 0) + { + route = r; + break; + } + r = (osm_prefix_route_t *) cl_qlist_next(&r->list_item); + } + + if (!route) { + /* + This 'error' is the client's fault (bad gid) so + don't enter it as an error in our own log. + Return an error response to the client. + */ + sa_status = IB_SA_MAD_STATUS_INVALID_GID; + goto Exit; + } else if (route->guid == 0) { + /* first router */ + p_rtr = (osm_router_t *) + cl_qmap_head(&sa-> + p_subn-> + rtr_guid_tbl); + } else { + p_rtr = (osm_router_t *) + cl_qmap_get(&sa-> + p_subn-> + rtr_guid_tbl, + route->guid); + } + + if (p_rtr == + (osm_router_t *) cl_qmap_end(&sa-> + p_subn-> + rtr_guid_tbl)) + { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, + "ERR 1F22: " + "Off subnet DGID but router not found\n"); + sa_status = + IB_SA_MAD_STATUS_INVALID_GID; + goto Exit; + } + + p_rtr_port = osm_router_get_port_ptr(p_rtr); + dest_guid = osm_port_get_guid(p_rtr_port); + if (p_dgid) + *p_dgid = p_pr->dgid; + } + } + + *pp_dest_port = osm_get_port_by_guid(sa->p_subn, dest_guid); + if (!*pp_dest_port) { + /* + This 'error' is the client's fault (bad gid) so + don't enter it as an error in our own log. + Return an error response to the client. + */ + OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, + "No dest port with GUID 0x%016" PRIx64 "\n", + cl_ntoh64(dest_guid)); + + sa_status = IB_SA_MAD_STATUS_INVALID_GID; + goto Exit; + } + } else { + *pp_dest_port = 0; + if (comp_mask & IB_PR_COMPMASK_DLID) { + status = cl_ptr_vector_at(&sa->p_subn->port_lid_tbl, + cl_ntoh16(p_pr->dlid), + (void **)pp_dest_port); + + if ((status != CL_SUCCESS) || (*pp_dest_port == NULL)) { + /* + This 'error' is the client's fault (bad lid) + so don't enter it as an error in our own log. + Return an error response to the client. + */ + OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, + "No dest port with LID %u\n", + cl_ntoh16(p_pr->dlid)); + + sa_status = IB_SA_MAD_STATUS_NO_RECORDS; + goto Exit; + } + } + } + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (sa_status); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pr_rcv_process_world(IN osm_sa_t * sa, + IN const osm_madw_t * const p_madw, + IN const osm_port_t * const requester_port, + IN const ib_gid_t * const p_dgid, + IN const ib_net64_t comp_mask, + IN cl_qlist_t * const p_list) +{ + const cl_qmap_t *p_tbl; + const osm_port_t *p_dest_port; + const osm_port_t *p_src_port; + + OSM_LOG_ENTER(sa->p_log); + + /* + Iterate the entire port space over itself. + A path record from a port to itself is legit, so no + need for a special case there. + + We compute both A -> B and B -> A, since we don't have + any check to determine the reversability of the paths. + */ + p_tbl = &sa->p_subn->port_guid_tbl; + + p_dest_port = (osm_port_t *) cl_qmap_head(p_tbl); + while (p_dest_port != (osm_port_t *) cl_qmap_end(p_tbl)) { + p_src_port = (osm_port_t *) cl_qmap_head(p_tbl); + while (p_src_port != (osm_port_t *) cl_qmap_end(p_tbl)) { + __osm_pr_rcv_get_port_pair_paths(sa, p_madw, + requester_port, + p_src_port, + p_dest_port, p_dgid, + comp_mask, p_list); + + p_src_port = + (osm_port_t *) cl_qmap_next(&p_src_port->map_item); + } + + p_dest_port = + (osm_port_t *) cl_qmap_next(&p_dest_port->map_item); + } + + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pr_rcv_process_half(IN osm_sa_t * sa, + IN const osm_madw_t * const p_madw, + IN const osm_port_t * const requester_port, + IN const osm_port_t * const p_src_port, + IN const osm_port_t * const p_dest_port, + IN const ib_gid_t * const p_dgid, + IN const ib_net64_t comp_mask, + IN cl_qlist_t * const p_list) +{ + const cl_qmap_t *p_tbl; + const osm_port_t *p_port; + + OSM_LOG_ENTER(sa->p_log); + + /* + Iterate over every port, looking for matches... + A path record from a port to itself is legit, so no + need to special case that one. + */ + p_tbl = &sa->p_subn->port_guid_tbl; + + if (p_src_port) { + /* + The src port if fixed, so iterate over destination ports. + */ + p_port = (osm_port_t *) cl_qmap_head(p_tbl); + while (p_port != (osm_port_t *) cl_qmap_end(p_tbl)) { + __osm_pr_rcv_get_port_pair_paths(sa, p_madw, + requester_port, + p_src_port, p_port, + p_dgid, comp_mask, + p_list); + p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item); + } + } else { + /* + The dest port if fixed, so iterate over source ports. + */ + p_port = (osm_port_t *) cl_qmap_head(p_tbl); + while (p_port != (osm_port_t *) cl_qmap_end(p_tbl)) { + __osm_pr_rcv_get_port_pair_paths(sa, p_madw, + requester_port, p_port, + p_dest_port, p_dgid, + comp_mask, p_list); + p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item); + } + } + + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_pr_rcv_process_pair(IN osm_sa_t * sa, + IN const osm_madw_t * const p_madw, + IN const osm_port_t * const requester_port, + IN const osm_port_t * const p_src_port, + IN const osm_port_t * const p_dest_port, + IN const ib_gid_t * const p_dgid, + IN const ib_net64_t comp_mask, + IN cl_qlist_t * const p_list) +{ + OSM_LOG_ENTER(sa->p_log); + + __osm_pr_rcv_get_port_pair_paths(sa, p_madw, requester_port, + p_src_port, p_dest_port, p_dgid, + comp_mask, p_list); + + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static osm_mgrp_t *pr_get_mgrp(IN osm_sa_t * sa, + IN const osm_madw_t * const p_madw) +{ + ib_path_rec_t *p_pr; + const ib_sa_mad_t *p_sa_mad; + ib_net64_t comp_mask; + osm_mgrp_t *mgrp = NULL; + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_pr = (ib_path_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + comp_mask = p_sa_mad->comp_mask; + + if ((comp_mask & IB_PR_COMPMASK_DGID) && + !(mgrp = osm_get_mgrp_by_mgid(sa, &p_pr->dgid))) { + char gid_str[INET6_ADDRSTRLEN]; + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F09: " + "No MC group found for PathRecord destination GID %s\n", + inet_ntop(AF_INET6, p_pr->dgid.raw, gid_str, + sizeof gid_str)); + goto Exit; + } + + if (comp_mask & IB_PR_COMPMASK_DLID) { + if (mgrp) { + /* check that the MLID in the MC group is */ + /* the same as the DLID in the PathRecord */ + if (mgrp->mlid != p_pr->dlid) { + /* Note: perhaps this might be better indicated as an invalid request */ + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F10: " + "MC group MLID 0x%x does not match " + "PathRecord destination LID 0x%x\n", + mgrp->mlid, p_pr->dlid); + mgrp = NULL; + goto Exit; + } + } else if (!(mgrp = osm_get_mgrp_by_mlid(sa->p_subn, p_pr->dlid))) + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F11: " + "No MC group found for PathRecord " + "destination LID 0x%x\n", p_pr->dlid); + } + +Exit: + return mgrp; +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_pr_match_mgrp_attributes(IN osm_sa_t * sa, + IN const osm_madw_t * const p_madw, + IN const osm_mgrp_t * const p_mgrp) +{ + const ib_path_rec_t *p_pr; + const ib_sa_mad_t *p_sa_mad; + ib_net64_t comp_mask; + ib_api_status_t status = IB_ERROR; + uint32_t flow_label; + uint8_t sl; + uint8_t hop_limit; + + OSM_LOG_ENTER(sa->p_log); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_pr = (ib_path_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + comp_mask = p_sa_mad->comp_mask; + + /* If SGID and/or SLID specified, should validate as member of MC group */ + /* Also, MTU, rate, packet lifetime, and raw traffic requested are not currently checked */ + if (comp_mask & IB_PR_COMPMASK_PKEY) { + if (p_pr->pkey != p_mgrp->mcmember_rec.pkey) + goto Exit; + } + + ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop, + &sl, &flow_label, &hop_limit); + + if (comp_mask & IB_PR_COMPMASK_SL) { + if (ib_path_rec_sl(p_pr) != sl) + goto Exit; + } + + /* If SubnAdmGet, assume NumbPaths of 1 (1.2 erratum) */ + if ((comp_mask & IB_PR_COMPMASK_NUMBPATH) && + (p_sa_mad->method != IB_MAD_METHOD_GET)) { + if (ib_path_rec_num_path(p_pr) == 0) + goto Exit; + } + + if (comp_mask & IB_PR_COMPMASK_FLOWLABEL) { + if (ib_path_rec_flow_lbl(p_pr) != flow_label) + goto Exit; + } + + if (comp_mask & IB_PR_COMPMASK_HOPLIMIT) { + if (ib_path_rec_hop_limit(p_pr) != hop_limit) + goto Exit; + } + + if (comp_mask & IB_PR_COMPMASK_TCLASS) { + if (p_pr->tclass != p_mgrp->mcmember_rec.tclass) + goto Exit; + } + + status = IB_SUCCESS; + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static int +__osm_pr_rcv_check_mcast_dest(IN osm_sa_t * sa, + IN const osm_madw_t * const p_madw) +{ + const ib_path_rec_t *p_pr; + const ib_sa_mad_t *p_sa_mad; + ib_net64_t comp_mask; + int is_multicast = 0; + + OSM_LOG_ENTER(sa->p_log); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_pr = (ib_path_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + comp_mask = p_sa_mad->comp_mask; + + if (comp_mask & IB_PR_COMPMASK_DGID) { + is_multicast = ib_gid_is_multicast(&p_pr->dgid); + if (!is_multicast) + goto Exit; + } + + if (comp_mask & IB_PR_COMPMASK_DLID) { + if (cl_ntoh16(p_pr->dlid) >= IB_LID_MCAST_START_HO && + cl_ntoh16(p_pr->dlid) <= IB_LID_MCAST_END_HO) + is_multicast = 1; + else if (is_multicast) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F12: " + "PathRecord request indicates MGID but not MLID\n"); + is_multicast = -1; + } + } + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (is_multicast); +} + +/********************************************************************** + **********************************************************************/ +void osm_pr_rcv_process(IN void *context, IN void *data) +{ + osm_sa_t *sa = context; + osm_madw_t *p_madw = data; + const ib_path_rec_t *p_pr; + const ib_sa_mad_t *p_sa_mad; + const osm_port_t *p_src_port; + const osm_port_t *p_dest_port; + cl_qlist_t pr_list; + ib_gid_t dgid; + ib_net16_t sa_status; + osm_port_t *requester_port; + int ret; + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_pr = (ib_path_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD); + + /* we only support SubnAdmGet and SubnAdmGetTable methods */ + if (p_sa_mad->method != IB_MAD_METHOD_GET && + p_sa_mad->method != IB_MAD_METHOD_GETTABLE) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F17: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_sa_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + /* update the requester physical port. */ + requester_port = osm_get_port_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (requester_port == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F16: " + "Cannot find requester physical port\n"); + goto Exit; + } + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_path_record(sa->p_log, p_pr, OSM_LOG_DEBUG); + + cl_qlist_init(&pr_list); + + /* + Most SA functions (including this one) are read-only on the + subnet object, so we grab the lock non-exclusively. + */ + cl_plock_acquire(sa->p_lock); + + /* Handle multicast destinations separately */ + if ((ret = __osm_pr_rcv_check_mcast_dest(sa, p_madw)) < 0) { + /* Multicast DGID with unicast DLID */ + cl_plock_release(sa->p_lock); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_INVALID_FIELD); + goto Exit; + } + + if (ret > 0) + goto McastDest; + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Unicast destination requested\n"); + + sa_status = __osm_pr_rcv_get_end_points(sa, p_madw, + &p_src_port, &p_dest_port, + &dgid); + + if (sa_status == IB_SA_MAD_STATUS_SUCCESS) { + /* + What happens next depends on the type of endpoint information + that was specified.... + */ + if (p_src_port) { + if (p_dest_port) + __osm_pr_rcv_process_pair(sa, p_madw, + requester_port, + p_src_port, + p_dest_port, &dgid, + p_sa_mad->comp_mask, + &pr_list); + else + __osm_pr_rcv_process_half(sa, p_madw, + requester_port, + p_src_port, NULL, + &dgid, + p_sa_mad->comp_mask, + &pr_list); + } else { + if (p_dest_port) + __osm_pr_rcv_process_half(sa, p_madw, + requester_port, NULL, + p_dest_port, &dgid, + p_sa_mad->comp_mask, + &pr_list); + else + /* + Katie, bar the door! + */ + __osm_pr_rcv_process_world(sa, p_madw, + requester_port, + &dgid, + p_sa_mad->comp_mask, + &pr_list); + } + } + goto Unlock; + +McastDest: + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Multicast destination requested\n"); + { + osm_mgrp_t *p_mgrp = NULL; + ib_api_status_t status; + osm_pr_item_t *p_pr_item; + uint32_t flow_label; + uint8_t sl; + uint8_t hop_limit; + + /* First, get the MC info */ + p_mgrp = pr_get_mgrp(sa, p_madw); + + if (!p_mgrp) + goto Unlock; + + /* Make sure the rest of the PathRecord matches the MC group attributes */ + status = __osm_pr_match_mgrp_attributes(sa, p_madw, p_mgrp); + if (status != IB_SUCCESS) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F19: " + "MC group attributes don't match PathRecord request\n"); + goto Unlock; + } + + p_pr_item = malloc(sizeof(*p_pr_item)); + if (p_pr_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F18: " + "Unable to allocate path record for MC group\n"); + goto Unlock; + } + memset(p_pr_item, 0, sizeof(*p_pr_item)); + + /* Copy PathRecord request into response */ + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_pr = (ib_path_rec_t *) + ib_sa_mad_get_payload_ptr(p_sa_mad); + p_pr_item->path_rec = *p_pr; + + /* Now, use the MC info to cruft up the PathRecord response */ + p_pr_item->path_rec.dgid = p_mgrp->mcmember_rec.mgid; + p_pr_item->path_rec.dlid = p_mgrp->mcmember_rec.mlid; + p_pr_item->path_rec.tclass = p_mgrp->mcmember_rec.tclass; + p_pr_item->path_rec.num_path = 1; + p_pr_item->path_rec.pkey = p_mgrp->mcmember_rec.pkey; + + /* MTU, rate, and packet lifetime should be exactly */ + p_pr_item->path_rec.mtu = (2 << 6) | p_mgrp->mcmember_rec.mtu; + p_pr_item->path_rec.rate = (2 << 6) | p_mgrp->mcmember_rec.rate; + p_pr_item->path_rec.pkt_life = + (2 << 6) | p_mgrp->mcmember_rec.pkt_life; + + /* SL, Hop Limit, and Flow Label */ + ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop, + &sl, &flow_label, &hop_limit); + ib_path_rec_set_sl(&p_pr_item->path_rec, sl); + ib_path_rec_set_qos_class(&p_pr_item->path_rec, 0); + + /* HopLimit is not yet set in non link local MC groups */ + /* If it were, this would not be needed */ + if (ib_mgid_get_scope(&p_mgrp->mcmember_rec.mgid) != IB_MC_SCOPE_LINK_LOCAL) + hop_limit = IB_HOPLIMIT_MAX; + + p_pr_item->path_rec.hop_flow_raw = + cl_hton32(hop_limit) | (flow_label << 8); + + cl_qlist_insert_tail(&pr_list, &p_pr_item->list_item); + } + +Unlock: + cl_plock_release(sa->p_lock); + + /* Now, (finally) respond to the PathRecord request */ + osm_sa_respond(sa, p_madw, sizeof(ib_path_rec_t), &pr_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_pkey_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_pkey_record.c new file mode 100644 index 000000000000..70c6047bccb3 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_pkey_record.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_pkey_item { + cl_list_item_t list_item; + ib_pkey_table_record_t rec; +} osm_pkey_item_t; + +typedef struct osm_pkey_search_ctxt { + const ib_pkey_table_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + uint16_t block_num; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_pkey_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_pkey_create(IN osm_sa_t * sa, + IN osm_physp_t * const p_physp, + IN osm_pkey_search_ctxt_t * const p_ctxt, + IN uint16_t block) +{ + osm_pkey_item_t *p_rec_item; + uint16_t lid; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sa->p_log); + + p_rec_item = malloc(sizeof(*p_rec_item)); + if (p_rec_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4602: " + "rec_item alloc failed\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + if (p_physp->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) + lid = p_physp->port_info.base_lid; + else + lid = osm_node_get_base_lid(p_physp->p_node, 0); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "New P_Key table for: port 0x%016" PRIx64 + ", lid %u, port %u Block:%u\n", + cl_ntoh64(osm_physp_get_port_guid(p_physp)), + cl_ntoh16(lid), osm_physp_get_port_num(p_physp), block); + + memset(p_rec_item, 0, sizeof(*p_rec_item)); + + p_rec_item->rec.lid = lid; + p_rec_item->rec.block_num = block; + p_rec_item->rec.port_num = osm_physp_get_port_num(p_physp); + p_rec_item->rec.pkey_tbl = + *(osm_pkey_tbl_block_get(osm_physp_get_pkey_tbl(p_physp), block)); + + cl_qlist_insert_tail(p_ctxt->p_list, &p_rec_item->list_item); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_pkey_check_physp(IN osm_sa_t * sa, + IN osm_physp_t * const p_physp, + osm_pkey_search_ctxt_t * const p_ctxt) +{ + ib_net64_t comp_mask = p_ctxt->comp_mask; + uint16_t block, num_blocks; + + OSM_LOG_ENTER(sa->p_log); + + /* we got here with the phys port - all is left is to get the right block */ + if (comp_mask & IB_PKEY_COMPMASK_BLOCK) { + __osm_sa_pkey_create(sa, p_physp, p_ctxt, p_ctxt->block_num); + } else { + num_blocks = + osm_pkey_tbl_get_num_blocks(osm_physp_get_pkey_tbl + (p_physp)); + for (block = 0; block < num_blocks; block++) { + __osm_sa_pkey_create(sa, p_physp, p_ctxt, block); + } + } + + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_pkey_by_comp_mask(IN osm_sa_t * sa, + IN const osm_port_t * const p_port, + osm_pkey_search_ctxt_t * const p_ctxt) +{ + const ib_pkey_table_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + osm_physp_t *p_physp; + uint8_t port_num; + uint8_t num_ports; + const osm_physp_t *p_req_physp; + + OSM_LOG_ENTER(sa->p_log); + + p_rcvd_rec = p_ctxt->p_rcvd_rec; + comp_mask = p_ctxt->comp_mask; + port_num = p_rcvd_rec->port_num; + p_req_physp = p_ctxt->p_req_physp; + + /* if this is a switch port we can search all ports + otherwise we must be looking on port 0 */ + if (p_port->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) { + /* we put it in the comp mask and port num */ + port_num = p_port->p_physp->port_num; + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Using Physical Default Port Number: 0x%X (for End Node)\n", + port_num); + comp_mask |= IB_PKEY_COMPMASK_PORT; + } + + if (comp_mask & IB_PKEY_COMPMASK_PORT) { + if (port_num < osm_node_get_num_physp(p_port->p_node)) { + p_physp = + osm_node_get_physp_ptr(p_port->p_node, port_num); + /* Check that the p_physp is valid, and that is shares a pkey + with the p_req_physp. */ + if (p_physp && + (osm_physp_share_pkey + (sa->p_log, p_req_physp, p_physp))) + __osm_sa_pkey_check_physp(sa, p_physp, + p_ctxt); + } else { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4603: " + "Given Physical Port Number: 0x%X is out of range should be < 0x%X\n", + port_num, + osm_node_get_num_physp(p_port->p_node)); + goto Exit; + } + } else { + num_ports = osm_node_get_num_physp(p_port->p_node); + for (port_num = 0; port_num < num_ports; port_num++) { + p_physp = + osm_node_get_physp_ptr(p_port->p_node, port_num); + if (!p_physp) + continue; + + /* if the requester and the p_physp don't share a pkey - + continue */ + if (!osm_physp_share_pkey + (sa->p_log, p_req_physp, p_physp)) + continue; + + __osm_sa_pkey_check_physp(sa, p_physp, p_ctxt); + } + } +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_pkey_by_comp_mask_cb(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + const osm_port_t *const p_port = (osm_port_t *) p_map_item; + osm_pkey_search_ctxt_t *const p_ctxt = + (osm_pkey_search_ctxt_t *) context; + + __osm_sa_pkey_by_comp_mask(p_ctxt->sa, p_port, p_ctxt); +} + +/********************************************************************** + **********************************************************************/ +void osm_pkey_rec_rcv_process(IN void *ctx, IN void *data) +{ + osm_sa_t *sa = ctx; + osm_madw_t *p_madw = data; + const ib_sa_mad_t *p_rcvd_mad; + const ib_pkey_table_record_t *p_rcvd_rec; + const osm_port_t *p_port = NULL; + const ib_pkey_table_t *p_pkey; + cl_qlist_t rec_list; + osm_pkey_search_ctxt_t context; + ib_api_status_t status = IB_SUCCESS; + ib_net64_t comp_mask; + osm_physp_t *p_req_physp; + + CL_ASSERT(sa); + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_rcvd_rec = + (ib_pkey_table_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); + comp_mask = p_rcvd_mad->comp_mask; + + CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_PKEY_TBL_RECORD); + + /* we only support SubnAdmGet and SubnAdmGetTable methods */ + if (p_rcvd_mad->method != IB_MAD_METHOD_GET && + p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4605: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_rcvd_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + /* + p922 - P_KeyTableRecords shall only be provided in response + to trusted requests. + Check that the requester is a trusted one. + */ + if (p_rcvd_mad->sm_key != sa->p_subn->opt.sa_key) { + /* This is not a trusted requester! */ + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4608: " + "Request from non-trusted requester: " + "Given SM_Key:0x%016" PRIx64 "\n", + cl_ntoh64(p_rcvd_mad->sm_key)); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4604: " + "Cannot find requester physical port\n"); + goto Exit; + } + + p_pkey = (ib_pkey_table_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); + + cl_qlist_init(&rec_list); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = p_rcvd_mad->comp_mask; + context.sa = sa; + context.block_num = p_rcvd_rec->block_num; + context.p_req_physp = p_req_physp; + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Got Query Lid:%u(%02X), Block:0x%02X(%02X), Port:0x%02X(%02X)\n", + cl_ntoh16(p_rcvd_rec->lid), + (comp_mask & IB_PKEY_COMPMASK_LID) != 0, p_rcvd_rec->port_num, + (comp_mask & IB_PKEY_COMPMASK_PORT) != 0, p_rcvd_rec->block_num, + (comp_mask & IB_PKEY_COMPMASK_BLOCK) != 0); + + cl_plock_acquire(sa->p_lock); + + /* + If the user specified a LID, it obviously narrows our + work load, since we don't have to search every port + */ + if (comp_mask & IB_PKEY_COMPMASK_LID) { + status = osm_get_port_by_base_lid(sa->p_subn, p_rcvd_rec->lid, + &p_port); + if (status != IB_SUCCESS || p_port == NULL) { + status = IB_NOT_FOUND; + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 460B: " + "No port found with LID %u\n", + cl_ntoh16(p_rcvd_rec->lid)); + } + } + + if (status == IB_SUCCESS) { + /* if we got a unique port - no need for a port search */ + if (p_port) + /* this does the loop on all the port phys ports */ + __osm_sa_pkey_by_comp_mask(sa, p_port, &context); + else + cl_qmap_apply_func(&sa->p_subn->port_guid_tbl, + __osm_sa_pkey_by_comp_mask_cb, + &context); + } + + cl_plock_release(sa->p_lock); + + osm_sa_respond(sa, p_madw, sizeof(ib_pkey_table_record_t), &rec_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_portinfo_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_portinfo_record.c new file mode 100644 index 000000000000..753c3dbd289e --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_portinfo_record.c @@ -0,0 +1,592 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_pir_rcv_t. + * This object represents the PortInfoRecord Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_pir_item { + cl_list_item_t list_item; + ib_portinfo_record_t rec; +} osm_pir_item_t; + +typedef struct osm_pir_search_ctxt { + const ib_portinfo_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; + boolean_t is_enhanced_comp_mask; +} osm_pir_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_pir_rcv_new_pir(IN osm_sa_t * sa, + IN const osm_physp_t * const p_physp, + IN cl_qlist_t * const p_list, IN ib_net16_t const lid) +{ + osm_pir_item_t *p_rec_item; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sa->p_log); + + p_rec_item = malloc(sizeof(*p_rec_item)); + if (p_rec_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2102: " + "rec_item alloc failed\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "New PortInfoRecord: port 0x%016" PRIx64 + ", lid %u, port %u\n", + cl_ntoh64(osm_physp_get_port_guid(p_physp)), + cl_ntoh16(lid), osm_physp_get_port_num(p_physp)); + + memset(p_rec_item, 0, sizeof(*p_rec_item)); + + p_rec_item->rec.lid = lid; + p_rec_item->rec.port_info = p_physp->port_info; + p_rec_item->rec.port_num = osm_physp_get_port_num(p_physp); + + cl_qlist_insert_tail(p_list, &p_rec_item->list_item); + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_pir_create(IN osm_sa_t * sa, + IN const osm_physp_t * const p_physp, + IN osm_pir_search_ctxt_t * const p_ctxt) +{ + uint8_t lmc; + uint16_t max_lid_ho; + uint16_t base_lid_ho; + uint16_t match_lid_ho; + osm_physp_t *p_node_physp; + + OSM_LOG_ENTER(sa->p_log); + + if (p_physp->p_node->sw) { + p_node_physp = osm_node_get_physp_ptr(p_physp->p_node, 0); + base_lid_ho = cl_ntoh16(osm_physp_get_base_lid(p_node_physp)); + lmc = + osm_switch_sp0_is_lmc_capable(p_physp->p_node->sw, + sa-> + p_subn) ? + osm_physp_get_lmc(p_node_physp) : 0; + } else { + lmc = osm_physp_get_lmc(p_physp); + base_lid_ho = cl_ntoh16(osm_physp_get_base_lid(p_physp)); + } + max_lid_ho = (uint16_t) (base_lid_ho + (1 << lmc) - 1); + + if (p_ctxt->comp_mask & IB_PIR_COMPMASK_LID) { + match_lid_ho = cl_ntoh16(p_ctxt->p_rcvd_rec->lid); + + /* + We validate that the lid belongs to this node. + */ + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Comparing LID: %u <= %u <= %u\n", + base_lid_ho, match_lid_ho, max_lid_ho); + + if (match_lid_ho < base_lid_ho || match_lid_ho > max_lid_ho) + goto Exit; + } + + __osm_pir_rcv_new_pir(sa, p_physp, p_ctxt->p_list, + cl_hton16(base_lid_ho)); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_pir_check_physp(IN osm_sa_t * sa, + IN const osm_physp_t * const p_physp, + osm_pir_search_ctxt_t * const p_ctxt) +{ + const ib_portinfo_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + const ib_port_info_t *p_comp_pi; + const ib_port_info_t *p_pi; + + OSM_LOG_ENTER(sa->p_log); + + p_rcvd_rec = p_ctxt->p_rcvd_rec; + comp_mask = p_ctxt->comp_mask; + p_comp_pi = &p_rcvd_rec->port_info; + p_pi = &p_physp->port_info; + + osm_dump_port_info(sa->p_log, + osm_node_get_node_guid(p_physp->p_node), + p_physp->port_guid, + p_physp->port_num, + &p_physp->port_info, OSM_LOG_DEBUG); + + /* We have to re-check the base_lid, since if the given + base_lid in p_pi is zero - we are comparing on all ports. */ + if (comp_mask & IB_PIR_COMPMASK_BASELID) { + if (p_comp_pi->base_lid != p_pi->base_lid) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_MKEY) { + if (p_comp_pi->m_key != p_pi->m_key) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_GIDPRE) { + if (p_comp_pi->subnet_prefix != p_pi->subnet_prefix) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_SMLID) { + if (p_comp_pi->master_sm_base_lid != p_pi->master_sm_base_lid) + goto Exit; + } + + /* IBTA 1.2 errata provides support for bitwise compare if the bit 31 + of the attribute modifier of the Get/GetTable is set */ + if (comp_mask & IB_PIR_COMPMASK_CAPMASK) { + if (p_ctxt->is_enhanced_comp_mask) { + if (((p_comp_pi->capability_mask & p_pi-> + capability_mask) != p_comp_pi->capability_mask)) + goto Exit; + } else { + if (p_comp_pi->capability_mask != p_pi->capability_mask) + goto Exit; + } + } + + if (comp_mask & IB_PIR_COMPMASK_DIAGCODE) { + if (p_comp_pi->diag_code != p_pi->diag_code) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_MKEYLEASEPRD) { + if (p_comp_pi->m_key_lease_period != p_pi->m_key_lease_period) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_LOCALPORTNUM) { + if (p_comp_pi->local_port_num != p_pi->local_port_num) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_LNKWIDTHSUPPORT) { + if (p_comp_pi->link_width_supported != + p_pi->link_width_supported) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_LNKWIDTHACTIVE) { + if (p_comp_pi->link_width_active != p_pi->link_width_active) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_LINKWIDTHENABLED) { + if (p_comp_pi->link_width_enabled != p_pi->link_width_enabled) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_LNKSPEEDSUPPORT) { + if (ib_port_info_get_link_speed_sup(p_comp_pi) != + ib_port_info_get_link_speed_sup(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_PORTSTATE) { + if (ib_port_info_get_port_state(p_comp_pi) != + ib_port_info_get_port_state(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_PORTPHYSTATE) { + if (ib_port_info_get_port_phys_state(p_comp_pi) != + ib_port_info_get_port_phys_state(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_LINKDWNDFLTSTATE) { + if (ib_port_info_get_link_down_def_state(p_comp_pi) != + ib_port_info_get_link_down_def_state(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_MKEYPROTBITS) { + if (ib_port_info_get_mpb(p_comp_pi) != + ib_port_info_get_mpb(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_LMC) { + if (ib_port_info_get_lmc(p_comp_pi) != + ib_port_info_get_lmc(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_LINKSPEEDACTIVE) { + if (ib_port_info_get_link_speed_active(p_comp_pi) != + ib_port_info_get_link_speed_active(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_LINKSPEEDENABLE) { + if (ib_port_info_get_link_speed_enabled(p_comp_pi) != + ib_port_info_get_link_speed_enabled(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_NEIGHBORMTU) { + if (ib_port_info_get_neighbor_mtu(p_comp_pi) != + ib_port_info_get_neighbor_mtu(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_MASTERSMSL) { + if (ib_port_info_get_master_smsl(p_comp_pi) != + ib_port_info_get_master_smsl(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_VLCAP) { + if (ib_port_info_get_vl_cap(p_comp_pi) != + ib_port_info_get_vl_cap(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_INITTYPE) { + if (ib_port_info_get_init_type(p_comp_pi) != + ib_port_info_get_init_type(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_VLHIGHLIMIT) { + if (p_comp_pi->vl_high_limit != p_pi->vl_high_limit) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_VLARBHIGHCAP) { + if (p_comp_pi->vl_arb_high_cap != p_pi->vl_arb_high_cap) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_VLARBLOWCAP) { + if (p_comp_pi->vl_arb_low_cap != p_pi->vl_arb_low_cap) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_MTUCAP) { + if (ib_port_info_get_mtu_cap(p_comp_pi) != + ib_port_info_get_mtu_cap(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_VLSTALLCNT) { + if (ib_port_info_get_vl_stall_count(p_comp_pi) != + ib_port_info_get_vl_stall_count(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_HOQLIFE) { + if ((p_comp_pi->vl_stall_life & 0x1F) != + (p_pi->vl_stall_life & 0x1F)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_OPVLS) { + if ((p_comp_pi->vl_enforce & 0xF0) != (p_pi->vl_enforce & 0xF0)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_PARENFIN) { + if ((p_comp_pi->vl_enforce & 0x08) != (p_pi->vl_enforce & 0x08)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_PARENFOUT) { + if ((p_comp_pi->vl_enforce & 0x04) != (p_pi->vl_enforce & 0x04)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_FILTERRAWIN) { + if ((p_comp_pi->vl_enforce & 0x02) != (p_pi->vl_enforce & 0x02)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_FILTERRAWOUT) { + if ((p_comp_pi->vl_enforce & 0x01) != (p_pi->vl_enforce & 0x01)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_MKEYVIO) { + if (p_comp_pi->m_key_violations != p_pi->m_key_violations) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_PKEYVIO) { + if (p_comp_pi->p_key_violations != p_pi->p_key_violations) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_QKEYVIO) { + if (p_comp_pi->q_key_violations != p_pi->q_key_violations) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_GUIDCAP) { + if (p_comp_pi->guid_cap != p_pi->guid_cap) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_SUBNTO) { + if (ib_port_info_get_timeout(p_comp_pi) != + ib_port_info_get_timeout(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_RESPTIME) { + if ((p_comp_pi->resp_time_value & 0x1F) != + (p_pi->resp_time_value & 0x1F)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_LOCALPHYERR) { + if (ib_port_info_get_local_phy_err_thd(p_comp_pi) != + ib_port_info_get_local_phy_err_thd(p_pi)) + goto Exit; + } + if (comp_mask & IB_PIR_COMPMASK_OVERRUNERR) { + if (ib_port_info_get_overrun_err_thd(p_comp_pi) != + ib_port_info_get_overrun_err_thd(p_pi)) + goto Exit; + } + + __osm_sa_pir_create(sa, p_physp, p_ctxt); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_pir_by_comp_mask(IN osm_sa_t * sa, + IN osm_node_t * const p_node, + osm_pir_search_ctxt_t * const p_ctxt) +{ + const ib_portinfo_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + const osm_physp_t *p_physp; + uint8_t port_num; + uint8_t num_ports; + const osm_physp_t *p_req_physp; + + OSM_LOG_ENTER(sa->p_log); + + p_rcvd_rec = p_ctxt->p_rcvd_rec; + comp_mask = p_ctxt->comp_mask; + p_req_physp = p_ctxt->p_req_physp; + + num_ports = osm_node_get_num_physp(p_node); + + if (comp_mask & IB_PIR_COMPMASK_PORTNUM) { + if (p_rcvd_rec->port_num < num_ports) { + p_physp = + osm_node_get_physp_ptr(p_node, + p_rcvd_rec->port_num); + /* Check that the p_physp is valid, and that the + p_physp and the p_req_physp share a pkey. */ + if (p_physp && + osm_physp_share_pkey(sa->p_log, p_req_physp, + p_physp)) + __osm_sa_pir_check_physp(sa, p_physp, + p_ctxt); + } + } else { + for (port_num = 0; port_num < num_ports; port_num++) { + p_physp = + osm_node_get_physp_ptr(p_node, port_num); + if (!p_physp) + continue; + + /* if the requester and the p_physp don't share a pkey - + continue */ + if (!osm_physp_share_pkey + (sa->p_log, p_req_physp, p_physp)) + continue; + + __osm_sa_pir_check_physp(sa, p_physp, p_ctxt); + } + } + + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_pir_by_comp_mask_cb(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + osm_node_t *const p_node = (osm_node_t *) p_map_item; + osm_pir_search_ctxt_t *const p_ctxt = (osm_pir_search_ctxt_t *) context; + + __osm_sa_pir_by_comp_mask(p_ctxt->sa, p_node, p_ctxt); +} + +/********************************************************************** + **********************************************************************/ +void osm_pir_rcv_process(IN void *ctx, IN void *data) +{ + osm_sa_t *sa = ctx; + osm_madw_t *p_madw = data; + const ib_sa_mad_t *p_rcvd_mad; + const ib_portinfo_record_t *p_rcvd_rec; + const cl_ptr_vector_t *p_tbl; + const osm_port_t *p_port = NULL; + const ib_port_info_t *p_pi; + cl_qlist_t rec_list; + osm_pir_search_ctxt_t context; + ib_api_status_t status = IB_SUCCESS; + ib_net64_t comp_mask; + osm_physp_t *p_req_physp; + + CL_ASSERT(sa); + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_rcvd_rec = + (ib_portinfo_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); + comp_mask = p_rcvd_mad->comp_mask; + + CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_PORTINFO_RECORD); + + /* we only support SubnAdmGet and SubnAdmGetTable methods */ + if (p_rcvd_mad->method != IB_MAD_METHOD_GET && + p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2105: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_rcvd_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2104: " + "Cannot find requester physical port\n"); + goto Exit; + } + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_portinfo_record(sa->p_log, p_rcvd_rec, OSM_LOG_DEBUG); + + p_tbl = &sa->p_subn->port_lid_tbl; + p_pi = &p_rcvd_rec->port_info; + + cl_qlist_init(&rec_list); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = p_rcvd_mad->comp_mask; + context.sa = sa; + context.p_req_physp = p_req_physp; + context.is_enhanced_comp_mask = + cl_ntoh32(p_rcvd_mad->attr_mod) & (1 << 31); + + cl_plock_acquire(sa->p_lock); + + CL_ASSERT(cl_ptr_vector_get_size(p_tbl) < 0x10000); + + /* + If the user specified a LID, it obviously narrows our + work load, since we don't have to search every port + */ + if (comp_mask & IB_PIR_COMPMASK_LID) { + status = + osm_get_port_by_base_lid(sa->p_subn, p_rcvd_rec->lid, + &p_port); + if ((status != IB_SUCCESS) || (p_port == NULL)) { + status = IB_NOT_FOUND; + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2109: " + "No port found with LID %u\n", + cl_ntoh16(p_rcvd_rec->lid)); + } + } else if (comp_mask & IB_PIR_COMPMASK_BASELID) { + if ((uint16_t) cl_ptr_vector_get_size(p_tbl) > + cl_ntoh16(p_pi->base_lid)) + p_port = cl_ptr_vector_get(p_tbl, + cl_ntoh16(p_pi->base_lid)); + else { + status = IB_NOT_FOUND; + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2103: " + "Given LID (%u) is out of range:%u\n", + cl_ntoh16(p_pi->base_lid), + cl_ptr_vector_get_size(p_tbl)); + } + } + + if (status == IB_SUCCESS) { + if (p_port) + __osm_sa_pir_by_comp_mask(sa, p_port->p_node, + &context); + else + cl_qmap_apply_func(&sa->p_subn->node_guid_tbl, + __osm_sa_pir_by_comp_mask_cb, + &context); + } + + cl_plock_release(sa->p_lock); + + /* + p922 - The M_Key returned shall be zero, except in the case of a + trusted request. + Note: In the mad controller we check that the SM_Key received on + the mad is valid. Meaning - is either zero or equal to the local + sm_key. + */ + if (!p_rcvd_mad->sm_key) { + osm_pir_item_t *item; + for (item = (osm_pir_item_t *) cl_qlist_head(&rec_list); + item != (osm_pir_item_t *) cl_qlist_end(&rec_list); + item = (osm_pir_item_t *)cl_qlist_next(&item->list_item)) + item->rec.port_info.m_key = 0; + } + + osm_sa_respond(sa, p_madw, sizeof(ib_portinfo_record_t), &rec_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_service_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_service_record.c new file mode 100644 index 000000000000..66b4cb7d0963 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_service_record.c @@ -0,0 +1,842 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sr_rcv_t. + * This object represents the ServiceRecord Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_sr_item { + cl_list_item_t list_item; + ib_service_record_t service_rec; +} osm_sr_item_t; + +typedef struct osm_sr_match_item { + cl_qlist_t sr_list; + ib_service_record_t *p_service_rec; + ib_net64_t comp_mask; + osm_sa_t *sa; +} osm_sr_match_item_t; + +typedef struct osm_sr_search_ctxt { + osm_sr_match_item_t *p_sr_item; + const osm_physp_t *p_req_physp; +} osm_sr_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +static boolean_t +__match_service_pkey_with_ports_pkey(IN osm_sa_t * sa, + IN const osm_madw_t * const p_madw, + ib_service_record_t * const p_service_rec, + ib_net64_t const comp_mask) +{ + boolean_t valid = TRUE; + osm_physp_t *p_req_physp; + ib_net64_t service_guid; + osm_port_t *service_port; + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, + sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2404: " + "Cannot find requester physical port\n"); + valid = FALSE; + goto Exit; + } + + if ((comp_mask & IB_SR_COMPMASK_SPKEY) == IB_SR_COMPMASK_SPKEY) { + /* We have a ServiceP_Key - check matching on requester port, and + ServiceGid port (if such exists) */ + /* Make sure it matches the p_req_physp */ + if (!osm_physp_has_pkey + (sa->p_log, p_service_rec->service_pkey, p_req_physp)) { + valid = FALSE; + goto Exit; + } + + /* Make sure it matches the port of the ServiceGid */ + if ((comp_mask & IB_SR_COMPMASK_SGID) == IB_SR_COMPMASK_SGID) { + service_guid = + p_service_rec->service_gid.unicast.interface_id; + service_port = + osm_get_port_by_guid(sa->p_subn, service_guid); + if (!service_port) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2405: " + "No port object for port 0x%016" PRIx64 + "\n", cl_ntoh64(service_guid)); + valid = FALSE; + goto Exit; + } + /* check on the table of the default physical port of the service port */ + if (!osm_physp_has_pkey(sa->p_log, + p_service_rec->service_pkey, + service_port->p_physp)) { + valid = FALSE; + goto Exit; + } + } + } + +Exit: + return valid; +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +__match_name_to_key_association(IN osm_sa_t * sa, + ib_service_record_t * p_service_rec, + ib_net64_t comp_mask) +{ + UNUSED_PARAM(p_service_rec); + UNUSED_PARAM(sa); + + if ((comp_mask & (IB_SR_COMPMASK_SKEY | IB_SR_COMPMASK_SNAME)) == + (IB_SR_COMPMASK_SKEY | IB_SR_COMPMASK_SNAME)) { + /* For now, we are not maintaining the ServiceAssociation record + * so just return TRUE + */ + return TRUE; + } + + return TRUE; +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +__validate_sr(IN osm_sa_t * sa, IN const osm_madw_t * const p_madw) +{ + boolean_t valid = TRUE; + ib_sa_mad_t *p_sa_mad; + ib_service_record_t *p_recvd_service_rec; + + OSM_LOG_ENTER(sa->p_log); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_recvd_service_rec = + (ib_service_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + valid = __match_service_pkey_with_ports_pkey(sa, + p_madw, + p_recvd_service_rec, + p_sa_mad->comp_mask); + + if (!valid) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "No Match for Service Pkey\n"); + valid = FALSE; + goto Exit; + } + + valid = __match_name_to_key_association(sa, + p_recvd_service_rec, + p_sa_mad->comp_mask); + + if (!valid) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Service Record Name to key matching failed\n"); + valid = FALSE; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(sa->p_log); + return valid; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sr_rcv_respond(IN osm_sa_t * sa, + IN osm_madw_t * const p_madw, + IN cl_qlist_t * const p_list) +{ + /* p923 - The ServiceKey shall be set to 0, except in the case of + a trusted request. + Note: In the mad controller we check that the SM_Key received on + the mad is valid. Meaning - is either zero or equal to the local + sm_key. + */ + if (!osm_madw_get_sa_mad_ptr(p_madw)->sm_key) { + osm_sr_item_t *item; + for (item = (osm_sr_item_t *) cl_qlist_head(p_list); + item != (osm_sr_item_t *) cl_qlist_end(p_list); + item = (osm_sr_item_t *)cl_qlist_next(&item->list_item)) + memset(item->service_rec.service_key, 0, + sizeof(item->service_rec.service_key)); + } + + osm_sa_respond(sa, p_madw, sizeof(ib_service_record_t), p_list); +} + +/********************************************************************** + **********************************************************************/ +static void +__get_matching_sr(IN cl_list_item_t * const p_list_item, IN void *context) +{ + osm_sr_search_ctxt_t *const p_ctxt = (osm_sr_search_ctxt_t *) context; + osm_svcr_t *p_svcr = (osm_svcr_t *) p_list_item; + osm_sr_item_t *p_sr_pool_item; + osm_sr_match_item_t *p_sr_item = p_ctxt->p_sr_item; + ib_net64_t comp_mask = p_sr_item->comp_mask; + const osm_physp_t *p_req_physp = p_ctxt->p_req_physp; + + if ((comp_mask & IB_SR_COMPMASK_SID) == IB_SR_COMPMASK_SID) { + if (p_sr_item->p_service_rec->service_id != + p_svcr->service_record.service_id) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SGID) == IB_SR_COMPMASK_SGID) { + if (memcmp(&p_sr_item->p_service_rec->service_gid, + &p_svcr->service_record.service_gid, + sizeof(p_svcr->service_record.service_gid)) != 0) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SPKEY) == IB_SR_COMPMASK_SPKEY) { + if (p_sr_item->p_service_rec->service_pkey != + p_svcr->service_record.service_pkey) + return; + } + + if ((comp_mask & IB_SR_COMPMASK_SKEY) == IB_SR_COMPMASK_SKEY) { + if (memcmp(p_sr_item->p_service_rec->service_key, + p_svcr->service_record.service_key, + 16 * sizeof(uint8_t))) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SNAME) == IB_SR_COMPMASK_SNAME) { + if (memcmp(p_sr_item->p_service_rec->service_name, + p_svcr->service_record.service_name, + sizeof(p_svcr->service_record.service_name)) != 0) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA8_0) == IB_SR_COMPMASK_SDATA8_0) { + if (p_sr_item->p_service_rec->service_data8[0] != + p_svcr->service_record.service_data8[0]) + return; + } + + if ((comp_mask & IB_SR_COMPMASK_SDATA8_1) == IB_SR_COMPMASK_SDATA8_1) { + if (p_sr_item->p_service_rec->service_data8[1] != + p_svcr->service_record.service_data8[1]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA8_2) == IB_SR_COMPMASK_SDATA8_2) { + if (p_sr_item->p_service_rec->service_data8[2] != + p_svcr->service_record.service_data8[2]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA8_3) == IB_SR_COMPMASK_SDATA8_3) { + if (p_sr_item->p_service_rec->service_data8[3] != + p_svcr->service_record.service_data8[3]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA8_4) == IB_SR_COMPMASK_SDATA8_4) { + if (p_sr_item->p_service_rec->service_data8[4] != + p_svcr->service_record.service_data8[4]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA8_5) == IB_SR_COMPMASK_SDATA8_5) { + if (p_sr_item->p_service_rec->service_data8[5] != + p_svcr->service_record.service_data8[5]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA8_6) == IB_SR_COMPMASK_SDATA8_6) { + if (p_sr_item->p_service_rec->service_data8[6] != + p_svcr->service_record.service_data8[6]) + return; + } + + if ((comp_mask & IB_SR_COMPMASK_SDATA8_7) == IB_SR_COMPMASK_SDATA8_7) { + if (p_sr_item->p_service_rec->service_data8[7] != + p_svcr->service_record.service_data8[7]) + return; + } + + if ((comp_mask & IB_SR_COMPMASK_SDATA8_8) == IB_SR_COMPMASK_SDATA8_8) { + if (p_sr_item->p_service_rec->service_data8[8] != + p_svcr->service_record.service_data8[8]) + return; + } + + if ((comp_mask & IB_SR_COMPMASK_SDATA8_9) == IB_SR_COMPMASK_SDATA8_9) { + if (p_sr_item->p_service_rec->service_data8[9] != + p_svcr->service_record.service_data8[9]) + return; + } + + if ((comp_mask & IB_SR_COMPMASK_SDATA8_10) == IB_SR_COMPMASK_SDATA8_10) { + if (p_sr_item->p_service_rec->service_data8[10] != + p_svcr->service_record.service_data8[10]) + return; + } + + if ((comp_mask & IB_SR_COMPMASK_SDATA8_11) == IB_SR_COMPMASK_SDATA8_11) { + if (p_sr_item->p_service_rec->service_data8[11] != + p_svcr->service_record.service_data8[11]) + return; + } + + if ((comp_mask & IB_SR_COMPMASK_SDATA8_12) == IB_SR_COMPMASK_SDATA8_12) { + if (p_sr_item->p_service_rec->service_data8[12] != + p_svcr->service_record.service_data8[12]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA8_13) == IB_SR_COMPMASK_SDATA8_13) { + if (p_sr_item->p_service_rec->service_data8[13] != + p_svcr->service_record.service_data8[13]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA8_14) == IB_SR_COMPMASK_SDATA8_14) { + if (p_sr_item->p_service_rec->service_data8[14] != + p_svcr->service_record.service_data8[14]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA8_15) == IB_SR_COMPMASK_SDATA8_15) { + if (p_sr_item->p_service_rec->service_data8[15] != + p_svcr->service_record.service_data8[15]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA16_0) == IB_SR_COMPMASK_SDATA16_0) { + if (p_sr_item->p_service_rec->service_data16[0] != + p_svcr->service_record.service_data16[0]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA16_1) == IB_SR_COMPMASK_SDATA16_1) { + if (p_sr_item->p_service_rec->service_data16[1] != + p_svcr->service_record.service_data16[1]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA16_2) == IB_SR_COMPMASK_SDATA16_2) { + if (p_sr_item->p_service_rec->service_data16[2] != + p_svcr->service_record.service_data16[2]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA16_3) == IB_SR_COMPMASK_SDATA16_3) { + if (p_sr_item->p_service_rec->service_data16[3] != + p_svcr->service_record.service_data16[3]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA16_4) == IB_SR_COMPMASK_SDATA16_4) { + if (p_sr_item->p_service_rec->service_data16[4] != + p_svcr->service_record.service_data16[4]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA16_5) == IB_SR_COMPMASK_SDATA16_5) { + if (p_sr_item->p_service_rec->service_data16[5] != + p_svcr->service_record.service_data16[5]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA16_6) == IB_SR_COMPMASK_SDATA16_6) { + if (p_sr_item->p_service_rec->service_data16[6] != + p_svcr->service_record.service_data16[6]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA16_7) == IB_SR_COMPMASK_SDATA16_7) { + if (p_sr_item->p_service_rec->service_data16[7] != + p_svcr->service_record.service_data16[7]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA32_0) == IB_SR_COMPMASK_SDATA32_0) { + if (p_sr_item->p_service_rec->service_data32[0] != + p_svcr->service_record.service_data32[0]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA32_1) == IB_SR_COMPMASK_SDATA32_1) { + if (p_sr_item->p_service_rec->service_data32[1] != + p_svcr->service_record.service_data32[1]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA32_2) == IB_SR_COMPMASK_SDATA32_2) { + if (p_sr_item->p_service_rec->service_data32[2] != + p_svcr->service_record.service_data32[2]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA32_3) == IB_SR_COMPMASK_SDATA32_3) { + if (p_sr_item->p_service_rec->service_data32[3] != + p_svcr->service_record.service_data32[3]) + return; + } + + if ((comp_mask & IB_SR_COMPMASK_SDATA64_0) == IB_SR_COMPMASK_SDATA64_0) { + if (p_sr_item->p_service_rec->service_data64[0] != + p_svcr->service_record.service_data64[0]) + return; + } + if ((comp_mask & IB_SR_COMPMASK_SDATA64_1) == IB_SR_COMPMASK_SDATA64_1) { + if (p_sr_item->p_service_rec->service_data64[1] != + p_svcr->service_record.service_data64[1]) + return; + } + + /* Check that the requester port has the pkey which is the service_pkey. + If not - then it cannot receive this ServiceRecord. */ + /* The check is relevant only if the service_pkey is valid */ + if (!ib_pkey_is_invalid(p_svcr->service_record.service_pkey)) { + if (!osm_physp_has_pkey(p_sr_item->sa->p_log, + p_svcr->service_record.service_pkey, + p_req_physp)) { + OSM_LOG(p_sr_item->sa->p_log, OSM_LOG_VERBOSE, + "requester port doesn't have the service_pkey: 0x%X\n", + cl_ntoh16(p_svcr->service_record.service_pkey)); + return; + } + } + + p_sr_pool_item = malloc(sizeof(*p_sr_pool_item)); + if (p_sr_pool_item == NULL) { + OSM_LOG(p_sr_item->sa->p_log, OSM_LOG_ERROR, "ERR 2408: " + "Unable to acquire Service Record from pool\n"); + goto Exit; + } + + p_sr_pool_item->service_rec = p_svcr->service_record; + + cl_qlist_insert_tail(&p_sr_item->sr_list, &p_sr_pool_item->list_item); + +Exit: + return; +} + +/********************************************************************** + **********************************************************************/ +static void +osm_sr_rcv_process_get_method(IN osm_sa_t * sa, + IN osm_madw_t * const p_madw) +{ + ib_sa_mad_t *p_sa_mad; + ib_service_record_t *p_recvd_service_rec; + osm_sr_match_item_t sr_match_item; + osm_sr_search_ctxt_t context; + osm_physp_t *p_req_physp; + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, + sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2409: " + "Cannot find requester physical port\n"); + goto Exit; + } + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_recvd_service_rec = + (ib_service_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_service_record(sa->p_log, p_recvd_service_rec, + OSM_LOG_DEBUG); + + cl_qlist_init(&sr_match_item.sr_list); + sr_match_item.p_service_rec = p_recvd_service_rec; + sr_match_item.comp_mask = p_sa_mad->comp_mask; + sr_match_item.sa = sa; + + context.p_sr_item = &sr_match_item; + context.p_req_physp = p_req_physp; + + /* Grab the lock */ + cl_plock_excl_acquire(sa->p_lock); + + cl_qlist_apply_func(&sa->p_subn->sa_sr_list, + __get_matching_sr, &context); + + cl_plock_release(sa->p_lock); + + if (p_sa_mad->method == IB_MAD_METHOD_GET && + cl_qlist_count(&sr_match_item.sr_list) == 0) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "No records matched the Service Record query\n"); + + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_NO_RECORDS); + goto Exit; + } + + __osm_sr_rcv_respond(sa, p_madw, &sr_match_item.sr_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); + return; +} + +/********************************************************************** + **********************************************************************/ +static void +osm_sr_rcv_process_set_method(IN osm_sa_t * sa, + IN osm_madw_t * const p_madw) +{ + ib_sa_mad_t *p_sa_mad; + ib_service_record_t *p_recvd_service_rec; + ib_net64_t comp_mask; + osm_svcr_t *p_svcr; + osm_sr_item_t *p_sr_item; + cl_qlist_t sr_list; + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_recvd_service_rec = + (ib_service_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + comp_mask = p_sa_mad->comp_mask; + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_service_record(sa->p_log, p_recvd_service_rec, + OSM_LOG_DEBUG); + + if ((comp_mask & (IB_SR_COMPMASK_SID | IB_SR_COMPMASK_SGID)) != + (IB_SR_COMPMASK_SID | IB_SR_COMPMASK_SGID)) { + OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, + "Component Mask RID check failed for METHOD_SET\n"); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + + /* if we were not provided with a service lease make it + infinite */ + if ((comp_mask & IB_SR_COMPMASK_SLEASE) != IB_SR_COMPMASK_SLEASE) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "ServiceLease Component Mask not set - using infinite lease\n"); + p_recvd_service_rec->service_lease = 0xFFFFFFFF; + } + + /* Grab the lock */ + cl_plock_excl_acquire(sa->p_lock); + + /* If Record exists with matching RID */ + p_svcr = osm_svcr_get_by_rid(sa->p_subn, + sa->p_log, p_recvd_service_rec); + + if (p_svcr == NULL) { + /* Create the instance of the osm_svcr_t object */ + p_svcr = osm_svcr_new(p_recvd_service_rec); + if (p_svcr == NULL) { + cl_plock_release(sa->p_lock); + + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2411: " + "osm_svcr_get_by_rid failed\n"); + + osm_sa_send_error(sa, p_madw, + IB_SA_MAD_STATUS_NO_RESOURCES); + goto Exit; + } + + /* Add this new osm_svcr_t object to subnet object */ + osm_svcr_insert_to_db(sa->p_subn, sa->p_log, p_svcr); + + } else { + /* Update the old instance of the osm_svcr_t object */ + osm_svcr_init(p_svcr, p_recvd_service_rec); + } + + cl_plock_release(sa->p_lock); + + if (p_recvd_service_rec->service_lease != 0xFFFFFFFF) { +#if 0 + cl_timer_trim(&sa->sr_timer, + p_recvd_service_rec->service_lease * 1000); +#endif + /* This was a bug since no check was made to see if too long */ + /* just make sure the timer works - get a call back within a second */ + cl_timer_trim(&sa->sr_timer, 1000); + p_svcr->modified_time = cl_get_time_stamp_sec(); + } + + p_sr_item = malloc(sizeof(*p_sr_item)); + if (p_sr_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2412: " + "Unable to acquire Service record\n"); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES); + goto Exit; + } + + if ((comp_mask & IB_SR_COMPMASK_SPKEY) != IB_SR_COMPMASK_SPKEY) { + /* Set the Default Service P_Key in the response */ + p_recvd_service_rec->service_pkey = IB_DEFAULT_PKEY; + } + + p_sr_item->service_rec = *p_recvd_service_rec; + cl_qlist_init(&sr_list); + + cl_qlist_insert_tail(&sr_list, &p_sr_item->list_item); + + __osm_sr_rcv_respond(sa, p_madw, &sr_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +osm_sr_rcv_process_delete_method(IN osm_sa_t * sa, + IN osm_madw_t * const p_madw) +{ + ib_sa_mad_t *p_sa_mad; + ib_service_record_t *p_recvd_service_rec; + ib_net64_t comp_mask; + osm_svcr_t *p_svcr; + osm_sr_item_t *p_sr_item; + cl_qlist_t sr_list; + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_recvd_service_rec = + (ib_service_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad); + + comp_mask = p_sa_mad->comp_mask; + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_service_record(sa->p_log, p_recvd_service_rec, + OSM_LOG_DEBUG); + + /* Grab the lock */ + cl_plock_excl_acquire(sa->p_lock); + + /* If Record exists with matching RID */ + p_svcr = osm_svcr_get_by_rid(sa->p_subn, + sa->p_log, p_recvd_service_rec); + + if (p_svcr == NULL) { + cl_plock_release(sa->p_lock); + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "No records matched the RID\n"); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_NO_RECORDS); + goto Exit; + } else { + osm_svcr_remove_from_db(sa->p_subn, sa->p_log, p_svcr); + } + + cl_plock_release(sa->p_lock); + + p_sr_item = malloc(sizeof(*p_sr_item)); + if (p_sr_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2413: " + "Unable to acquire Service record\n"); + osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES); + goto Exit; + } + + /* provide back the copy of the record */ + p_sr_item->service_rec = p_svcr->service_record; + cl_qlist_init(&sr_list); + + cl_qlist_insert_tail(&sr_list, &p_sr_item->list_item); + + if (p_svcr) + osm_svcr_delete(p_svcr); + + __osm_sr_rcv_respond(sa, p_madw, &sr_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); + return; +} + +/********************************************************************** + **********************************************************************/ +void osm_sr_rcv_process(IN void *context, IN void *data) +{ + osm_sa_t *sa = context; + osm_madw_t *p_madw = data; + ib_sa_mad_t *p_sa_mad; + boolean_t valid; + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw); + + CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_SERVICE_RECORD); + + switch (p_sa_mad->method) { + case IB_MAD_METHOD_SET: + valid = __validate_sr(sa, p_madw); + if (!valid) { + OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, + "Component Mask check failed for set request\n"); + osm_sa_send_error(sa, p_madw, + IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + osm_sr_rcv_process_set_method(sa, p_madw); + break; + case IB_MAD_METHOD_DELETE: + valid = __validate_sr(sa, p_madw); + if (!valid) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Component Mask check failed for delete request\n"); + osm_sa_send_error(sa, p_madw, + IB_SA_MAD_STATUS_REQ_INVALID); + goto Exit; + } + osm_sr_rcv_process_delete_method(sa, p_madw); + break; + case IB_MAD_METHOD_GET: + case IB_MAD_METHOD_GETTABLE: + osm_sr_rcv_process_get_method(sa, p_madw); + break; + default: + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_sa_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + break; + } + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_sr_rcv_lease_cb(IN void *context) +{ + osm_sa_t *sa = context; + cl_list_item_t *p_list_item; + cl_list_item_t *p_next_list_item; + osm_svcr_t *p_svcr; + uint32_t curr_time; + uint32_t elapsed_time; + uint32_t trim_time = 20; /* maxiaml timer refresh is 20 seconds */ + + OSM_LOG_ENTER(sa->p_log); + + cl_plock_excl_acquire(sa->p_lock); + + p_list_item = cl_qlist_head(&sa->p_subn->sa_sr_list); + + while (p_list_item != cl_qlist_end(&sa->p_subn->sa_sr_list)) { + p_svcr = (osm_svcr_t *) p_list_item; + + if (p_svcr->service_record.service_lease == 0xFFFFFFFF) { + p_list_item = cl_qlist_next(p_list_item); + continue; + } + + /* current time in seconds */ + curr_time = cl_get_time_stamp_sec(); + /* elapsed time from last modify */ + elapsed_time = curr_time - p_svcr->modified_time; + /* but it can not be less then 1 */ + if (elapsed_time < 1) + elapsed_time = 1; + + if (elapsed_time < p_svcr->lease_period) { + /* + Just update the service lease period + note: for simplicity we work with a uint32_t field + external to the network order lease_period of the MAD + */ + p_svcr->lease_period -= elapsed_time; + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Remaining time for Service Name:%s is:0x%X\n", + p_svcr->service_record.service_name, + p_svcr->lease_period); + + p_svcr->modified_time = curr_time; + + /* Update the trim timer */ + if (trim_time > p_svcr->lease_period) { + trim_time = p_svcr->lease_period; + if (trim_time < 1) + trim_time = 1; + } + + p_list_item = cl_qlist_next(p_list_item); + continue; + + } else { + p_next_list_item = cl_qlist_next(p_list_item); + + /* Remove the service Record */ + osm_svcr_remove_from_db(sa->p_subn, + sa->p_log, p_svcr); + + osm_svcr_delete(p_svcr); + + p_list_item = p_next_list_item; + continue; + } + } + + /* Release the Lock */ + cl_plock_release(sa->p_lock); + + if (trim_time != 0xFFFFFFFF) { + cl_timer_trim(&sa->sr_timer, trim_time * 1000); /* Convert to milli seconds */ + } + + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_slvl_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_slvl_record.c new file mode 100644 index 000000000000..0550fc16586b --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_slvl_record.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_slvl_rec_rcv_t. + * This object represents the SLtoVL Mapping Query Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_slvl_item { + cl_list_item_t list_item; + ib_slvl_table_record_t rec; +} osm_slvl_item_t; + +typedef struct osm_slvl_search_ctxt { + const ib_slvl_table_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + uint8_t in_port_num; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_slvl_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_slvl_create(IN osm_sa_t * sa, + IN const osm_physp_t * const p_physp, + IN osm_slvl_search_ctxt_t * const p_ctxt, + IN uint8_t in_port_idx) +{ + osm_slvl_item_t *p_rec_item; + uint16_t lid; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sa->p_log); + + p_rec_item = malloc(sizeof(*p_rec_item)); + if (p_rec_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2602: " + "rec_item alloc failed\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + if (p_physp->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) + lid = p_physp->port_info.base_lid; + else + lid = osm_node_get_base_lid(p_physp->p_node, 0); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "New SLtoVL Map for: OUT port 0x%016" PRIx64 + ", lid 0x%X, port %u to In Port:%u\n", + cl_ntoh64(osm_physp_get_port_guid(p_physp)), + cl_ntoh16(lid), osm_physp_get_port_num(p_physp), in_port_idx); + + memset(p_rec_item, 0, sizeof(*p_rec_item)); + + p_rec_item->rec.lid = lid; + p_rec_item->rec.out_port_num = osm_physp_get_port_num(p_physp); + p_rec_item->rec.in_port_num = in_port_idx; + p_rec_item->rec.slvl_tbl = + *(osm_physp_get_slvl_tbl(p_physp, in_port_idx)); + + cl_qlist_insert_tail(p_ctxt->p_list, &p_rec_item->list_item); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_slvl_by_comp_mask(IN osm_sa_t * sa, + IN const osm_port_t * const p_port, + osm_slvl_search_ctxt_t * const p_ctxt) +{ + const ib_slvl_table_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + const osm_physp_t *p_out_physp, *p_in_physp; + uint8_t in_port_num, out_port_num; + uint8_t num_ports; + uint8_t in_port_start, in_port_end; + uint8_t out_port_start, out_port_end; + const osm_physp_t *p_req_physp; + + OSM_LOG_ENTER(sa->p_log); + + p_rcvd_rec = p_ctxt->p_rcvd_rec; + comp_mask = p_ctxt->comp_mask; + num_ports = osm_node_get_num_physp(p_port->p_node); + in_port_start = 0; + in_port_end = num_ports - 1; + out_port_start = 0; + out_port_end = num_ports - 1; + p_req_physp = p_ctxt->p_req_physp; + + if (p_port->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) { + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Using Physical Default Port Number: 0x%X (for End Node)\n", + p_port->p_physp->port_num); + p_out_physp = p_port->p_physp; + /* check that the p_out_physp and the p_req_physp share a pkey */ + if (osm_physp_share_pkey + (sa->p_log, p_req_physp, p_out_physp)) + __osm_sa_slvl_create(sa, p_out_physp, p_ctxt, 0); + } else { + if (comp_mask & IB_SLVL_COMPMASK_OUT_PORT) + out_port_start = out_port_end = + p_rcvd_rec->out_port_num; + if (comp_mask & IB_SLVL_COMPMASK_IN_PORT) + in_port_start = in_port_end = p_rcvd_rec->in_port_num; + + for (out_port_num = out_port_start; + out_port_num <= out_port_end; out_port_num++) { + p_out_physp = + osm_node_get_physp_ptr(p_port->p_node, + out_port_num); + if (!p_out_physp) + continue; + + for (in_port_num = in_port_start; + in_port_num <= in_port_end; in_port_num++) { +#if 0 + if (out_port_num && out_port_num == in_port_num) + continue; +#endif + + p_in_physp = + osm_node_get_physp_ptr(p_port->p_node, + in_port_num); + if (!p_in_physp) + continue; + + /* if the requester and the p_out_physp don't share a pkey - + continue */ + if (!osm_physp_share_pkey + (sa->p_log, p_req_physp, p_out_physp)) + continue; + + __osm_sa_slvl_create(sa, p_out_physp, p_ctxt, + in_port_num); + } + } + } + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_slvl_by_comp_mask_cb(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + const osm_port_t *const p_port = (osm_port_t *) p_map_item; + osm_slvl_search_ctxt_t *const p_ctxt = + (osm_slvl_search_ctxt_t *) context; + + __osm_sa_slvl_by_comp_mask(p_ctxt->sa, p_port, p_ctxt); +} + +/********************************************************************** + **********************************************************************/ +void osm_slvl_rec_rcv_process(IN void *ctx, IN void *data) +{ + osm_sa_t *sa = ctx; + osm_madw_t *p_madw = data; + const ib_sa_mad_t *p_rcvd_mad; + const ib_slvl_table_record_t *p_rcvd_rec; + const osm_port_t *p_port = NULL; + cl_qlist_t rec_list; + osm_slvl_search_ctxt_t context; + ib_api_status_t status = IB_SUCCESS; + ib_net64_t comp_mask; + osm_physp_t *p_req_physp; + + CL_ASSERT(sa); + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_rcvd_rec = + (ib_slvl_table_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); + comp_mask = p_rcvd_mad->comp_mask; + + CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_SLVL_RECORD); + + /* we only support SubnAdmGet and SubnAdmGetTable methods */ + if (p_rcvd_mad->method != IB_MAD_METHOD_GET && + p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2604: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(p_rcvd_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2603: " + "Cannot find requester physical port\n"); + goto Exit; + } + + cl_qlist_init(&rec_list); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = p_rcvd_mad->comp_mask; + context.sa = sa; + context.in_port_num = p_rcvd_rec->in_port_num; + context.p_req_physp = p_req_physp; + + cl_plock_acquire(sa->p_lock); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Got Query Lid:%u(%02X), In-Port:0x%02X(%02X), Out-Port:0x%02X(%02X)\n", + cl_ntoh16(p_rcvd_rec->lid), + (comp_mask & IB_SLVL_COMPMASK_LID) != 0, + p_rcvd_rec->in_port_num, + (comp_mask & IB_SLVL_COMPMASK_IN_PORT) != 0, + p_rcvd_rec->out_port_num, + (comp_mask & IB_SLVL_COMPMASK_OUT_PORT) != 0); + + /* + If the user specified a LID, it obviously narrows our + work load, since we don't have to search every port + */ + if (comp_mask & IB_SLVL_COMPMASK_LID) { + status = + osm_get_port_by_base_lid(sa->p_subn, p_rcvd_rec->lid, + &p_port); + if ((status != IB_SUCCESS) || (p_port == NULL)) { + status = IB_NOT_FOUND; + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2608: " + "No port found with LID %u\n", + cl_ntoh16(p_rcvd_rec->lid)); + } + } + + if (status == IB_SUCCESS) { + /* if we have a unique port - no need for a port search */ + if (p_port) + /* this does the loop on all the port phys ports */ + __osm_sa_slvl_by_comp_mask(sa, p_port, &context); + else + cl_qmap_apply_func(&sa->p_subn->port_guid_tbl, + __osm_sa_slvl_by_comp_mask_cb, + &context); + } + + cl_plock_release(sa->p_lock); + + osm_sa_respond(sa, p_madw, sizeof(ib_slvl_table_record_t), &rec_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_sminfo_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_sminfo_record.c new file mode 100644 index 000000000000..de99065469b0 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_sminfo_record.c @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_smir_rcv_t. + * This object represents the SMInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_smir_item { + cl_list_item_t list_item; + ib_sminfo_record_t rec; +} osm_smir_item_t; + +typedef struct osm_smir_search_ctxt { + const ib_sminfo_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_smir_search_ctxt_t; + +static ib_api_status_t +__osm_smir_rcv_new_smir(IN osm_sa_t * sa, + IN const osm_port_t * const p_port, + IN cl_qlist_t * const p_list, + IN ib_net64_t const guid, + IN ib_net32_t const act_count, + IN uint8_t const pri_state, + IN const osm_physp_t * const p_req_physp) +{ + osm_smir_item_t *p_rec_item; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sa->p_log); + + p_rec_item = malloc(sizeof(*p_rec_item)); + if (p_rec_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2801: " + "rec_item alloc failed\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "New SMInfo: GUID 0x%016" PRIx64 "\n", cl_ntoh64(guid)); + + memset(p_rec_item, 0, sizeof(*p_rec_item)); + + p_rec_item->rec.lid = osm_port_get_base_lid(p_port); + p_rec_item->rec.sm_info.guid = guid; + p_rec_item->rec.sm_info.act_count = act_count; + p_rec_item->rec.sm_info.pri_state = pri_state; + + cl_qlist_insert_tail(p_list, &p_rec_item->list_item); + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_smir_by_comp_mask(IN osm_sa_t * sa, + IN const osm_remote_sm_t * const p_rem_sm, + osm_smir_search_ctxt_t * const p_ctxt) +{ + const ib_sminfo_record_t *const p_rcvd_rec = p_ctxt->p_rcvd_rec; + const osm_physp_t *const p_req_physp = p_ctxt->p_req_physp; + ib_net64_t const comp_mask = p_ctxt->comp_mask; + + OSM_LOG_ENTER(sa->p_log); + + if (comp_mask & IB_SMIR_COMPMASK_GUID) { + if (p_rem_sm->smi.guid != p_rcvd_rec->sm_info.guid) + goto Exit; + } + + if (comp_mask & IB_SMIR_COMPMASK_PRIORITY) { + if (ib_sminfo_get_priority(&p_rem_sm->smi) != + ib_sminfo_get_priority(&p_rcvd_rec->sm_info)) + goto Exit; + } + + if (comp_mask & IB_SMIR_COMPMASK_SMSTATE) { + if (ib_sminfo_get_state(&p_rem_sm->smi) != + ib_sminfo_get_state(&p_rcvd_rec->sm_info)) + goto Exit; + } + + /* Implement any other needed search cases */ + + __osm_smir_rcv_new_smir(sa, p_rem_sm->p_port, p_ctxt->p_list, + p_rem_sm->smi.guid, + p_rem_sm->smi.act_count, + p_rem_sm->smi.pri_state, p_req_physp); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_smir_by_comp_mask_cb(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + const osm_remote_sm_t *const p_rem_sm = (osm_remote_sm_t *) p_map_item; + osm_smir_search_ctxt_t *const p_ctxt = + (osm_smir_search_ctxt_t *) context; + + __osm_sa_smir_by_comp_mask(p_ctxt->sa, p_rem_sm, p_ctxt); +} + +/********************************************************************** + **********************************************************************/ +void osm_smir_rcv_process(IN void *ctx, IN void *data) +{ + osm_sa_t *sa = ctx; + osm_madw_t *p_madw = data; + const ib_sa_mad_t *sad_mad; + const ib_sminfo_record_t *p_rcvd_rec; + const osm_port_t *p_port = NULL; + const ib_sm_info_t *p_smi; + cl_qlist_t rec_list; + osm_smir_search_ctxt_t context; + ib_api_status_t status = IB_SUCCESS; + ib_net64_t comp_mask; + ib_net64_t port_guid; + osm_physp_t *p_req_physp; + osm_port_t *local_port; + osm_remote_sm_t *p_rem_sm; + cl_qmap_t *p_sm_guid_tbl; + uint8_t pri_state; + + CL_ASSERT(sa); + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + sad_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_rcvd_rec = + (ib_sminfo_record_t *) ib_sa_mad_get_payload_ptr(sad_mad); + comp_mask = sad_mad->comp_mask; + + CL_ASSERT(sad_mad->attr_id == IB_MAD_ATTR_SMINFO_RECORD); + + /* we only support SubnAdmGet and SubnAdmGetTable methods */ + if (sad_mad->method != IB_MAD_METHOD_GET && + sad_mad->method != IB_MAD_METHOD_GETTABLE) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2804: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(sad_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2803: " + "Cannot find requester physical port\n"); + goto Exit; + } + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_sm_info_record(sa->p_log, p_rcvd_rec, OSM_LOG_DEBUG); + + p_smi = &p_rcvd_rec->sm_info; + + cl_qlist_init(&rec_list); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = sad_mad->comp_mask; + context.sa = sa; + context.p_req_physp = p_req_physp; + + cl_plock_acquire(sa->p_lock); + + /* + If the user specified a LID, it obviously narrows our + work load, since we don't have to search every port + */ + if (comp_mask & IB_SMIR_COMPMASK_LID) { + status = + osm_get_port_by_base_lid(sa->p_subn, p_rcvd_rec->lid, + &p_port); + if ((status != IB_SUCCESS) || (p_port == NULL)) { + status = IB_NOT_FOUND; + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2806: " + "No port found with LID %u\n", + cl_ntoh16(p_rcvd_rec->lid)); + } + } + + if (status == IB_SUCCESS) { + /* Handle our own SM first */ + local_port = osm_get_port_by_guid(sa->p_subn, + sa->p_subn->sm_port_guid); + if (!local_port) { + cl_plock_release(sa->p_lock); + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2809: " + "No port found with GUID 0x%016" PRIx64 "\n", + cl_ntoh64(sa->p_subn->sm_port_guid)); + goto Exit; + } + + if (!p_port || local_port == p_port) { + if (FALSE == + osm_physp_share_pkey(sa->p_log, p_req_physp, + local_port->p_physp)) { + cl_plock_release(sa->p_lock); + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2805: " + "Cannot get SMInfo record due to pkey violation\n"); + goto Exit; + } + + /* Check that other search components specified match */ + if ((comp_mask & IB_SMIR_COMPMASK_GUID) && + sa->p_subn->sm_port_guid != p_smi->guid) + goto Remotes; + if ((comp_mask & IB_SMIR_COMPMASK_PRIORITY) && + sa->p_subn->opt.sm_priority != + ib_sminfo_get_priority(p_smi)) + goto Remotes; + if ((comp_mask & IB_SMIR_COMPMASK_SMSTATE) && + sa->p_subn->sm_state != ib_sminfo_get_state(p_smi)) + goto Remotes; + + /* Now, add local SMInfo to list */ + pri_state = sa->p_subn->sm_state & 0x0F; + pri_state |= + (sa->p_subn->opt.sm_priority & 0x0F) << 4; + __osm_smir_rcv_new_smir(sa, local_port, context.p_list, + sa->p_subn->sm_port_guid, + cl_ntoh32(sa->p_subn->p_osm->stats.qp0_mads_sent), + pri_state, p_req_physp); + } + + Remotes: + if (p_port && p_port != local_port) { + /* Find remote SM corresponding to p_port */ + port_guid = osm_port_get_guid(p_port); + p_sm_guid_tbl = &sa->p_subn->sm_guid_tbl; + p_rem_sm = + (osm_remote_sm_t *) cl_qmap_get(p_sm_guid_tbl, + port_guid); + if (p_rem_sm != + (osm_remote_sm_t *) cl_qmap_end(p_sm_guid_tbl)) + __osm_sa_smir_by_comp_mask(sa, p_rem_sm, + &context); + else + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 280A: " + "No remote SM for GUID 0x%016" PRIx64 + "\n", cl_ntoh64(port_guid)); + } else { + /* Go over all other known (remote) SMs */ + cl_qmap_apply_func(&sa->p_subn->sm_guid_tbl, + __osm_sa_smir_by_comp_mask_cb, + &context); + } + } + + cl_plock_release(sa->p_lock); + + osm_sa_respond(sa, p_madw, sizeof(ib_sminfo_record_t), &rec_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_sw_info_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_sw_info_record.c new file mode 100644 index 000000000000..649b0ac405bf --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_sw_info_record.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sir_rcv_t. + * This object represents the SwitchInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_sir_item { + cl_list_item_t list_item; + ib_switch_info_record_t rec; +} osm_sir_item_t; + +typedef struct osm_sir_search_ctxt { + const ib_switch_info_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_sir_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_sir_rcv_new_sir(IN osm_sa_t * sa, + IN const osm_switch_t * const p_sw, + IN cl_qlist_t * const p_list, IN ib_net16_t const lid) +{ + osm_sir_item_t *p_rec_item; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sa->p_log); + + p_rec_item = malloc(sizeof(*p_rec_item)); + if (p_rec_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5308: " + "rec_item alloc failed\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "New SwitchInfoRecord: lid %u\n", cl_ntoh16(lid)); + + memset(p_rec_item, 0, sizeof(*p_rec_item)); + + p_rec_item->rec.lid = lid; + p_rec_item->rec.switch_info = p_sw->switch_info; + + cl_qlist_insert_tail(p_list, &p_rec_item->list_item); + +Exit: + OSM_LOG_EXIT(sa->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sir_rcv_create_sir(IN osm_sa_t * sa, + IN const osm_switch_t * const p_sw, + IN cl_qlist_t * const p_list, + IN ib_net16_t const match_lid, + IN const osm_physp_t * const p_req_physp) +{ + osm_port_t *p_port; + const osm_physp_t *p_physp; + uint16_t match_lid_ho; + ib_net16_t min_lid_ho; + ib_net16_t max_lid_ho; + + OSM_LOG_ENTER(sa->p_log); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Looking for SwitchInfoRecord with LID: %u\n", + cl_ntoh16(match_lid)); + + /* In switches, the port guid is the node guid. */ + p_port = + osm_get_port_by_guid(sa->p_subn, p_sw->p_node->node_info.port_guid); + if (!p_port) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 530A: " + "Failed to find Port by Node Guid:0x%016" PRIx64 + "\n", cl_ntoh64(p_sw->p_node->node_info.node_guid)); + goto Exit; + } + + /* check that the requester physp and the current physp are under + the same partition. */ + p_physp = p_port->p_physp; + if (!p_physp) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 530B: " + "Failed to find default physical Port by Node Guid:0x%016" + PRIx64 "\n", + cl_ntoh64(p_sw->p_node->node_info.node_guid)); + goto Exit; + } + if (!osm_physp_share_pkey(sa->p_log, p_req_physp, p_physp)) + goto Exit; + + /* get the port 0 of the switch */ + osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); + + match_lid_ho = cl_ntoh16(match_lid); + if (match_lid_ho) { + /* + We validate that the lid belongs to this switch. + */ + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Comparing LID: %u <= %u <= %u\n", + min_lid_ho, match_lid_ho, max_lid_ho); + + if (match_lid_ho < min_lid_ho || match_lid_ho > max_lid_ho) + goto Exit; + + } + + __osm_sir_rcv_new_sir(sa, p_sw, p_list, osm_port_get_base_lid(p_port)); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sir_rcv_by_comp_mask(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + const osm_sir_search_ctxt_t *const p_ctxt = + (osm_sir_search_ctxt_t *) context; + const osm_switch_t *const p_sw = (osm_switch_t *) p_map_item; + const ib_switch_info_record_t *const p_rcvd_rec = p_ctxt->p_rcvd_rec; + const osm_physp_t *const p_req_physp = p_ctxt->p_req_physp; + osm_sa_t *sa = p_ctxt->sa; + ib_net64_t const comp_mask = p_ctxt->comp_mask; + ib_net16_t match_lid = 0; + + OSM_LOG_ENTER(p_ctxt->sa->p_log); + + osm_dump_switch_info(p_ctxt->sa->p_log, + &p_sw->switch_info, OSM_LOG_VERBOSE); + + if (comp_mask & IB_SWIR_COMPMASK_LID) { + match_lid = p_rcvd_rec->lid; + if (!match_lid) + goto Exit; + } + + __osm_sir_rcv_create_sir(sa, p_sw, p_ctxt->p_list, + match_lid, p_req_physp); + +Exit: + OSM_LOG_EXIT(p_ctxt->sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_sir_rcv_process(IN void *ctx, IN void *data) +{ + osm_sa_t *sa = ctx; + osm_madw_t *p_madw = data; + const ib_sa_mad_t *sad_mad; + const ib_switch_info_record_t *p_rcvd_rec; + cl_qlist_t rec_list; + osm_sir_search_ctxt_t context; + osm_physp_t *p_req_physp; + + CL_ASSERT(sa); + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + sad_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_rcvd_rec = + (ib_switch_info_record_t *) ib_sa_mad_get_payload_ptr(sad_mad); + + CL_ASSERT(sad_mad->attr_id == IB_MAD_ATTR_SWITCH_INFO_RECORD); + + /* we only support SubnAdmGet and SubnAdmGetTable methods */ + if (sad_mad->method != IB_MAD_METHOD_GET && + sad_mad->method != IB_MAD_METHOD_GETTABLE) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5305: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(sad_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5304: " + "Cannot find requester physical port\n"); + goto Exit; + } + + if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) + osm_dump_switch_info_record(sa->p_log, p_rcvd_rec, + OSM_LOG_DEBUG); + + cl_qlist_init(&rec_list); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = sad_mad->comp_mask; + context.sa = sa; + context.p_req_physp = p_req_physp; + + cl_plock_acquire(sa->p_lock); + + /* Go over all switches */ + cl_qmap_apply_func(&sa->p_subn->sw_guid_tbl, + __osm_sir_rcv_by_comp_mask, &context); + + cl_plock_release(sa->p_lock); + + osm_sa_respond(sa, p_madw, sizeof(ib_switch_info_record_t), &rec_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sa_vlarb_record.c b/contrib/ofed/management/opensm/opensm/osm_sa_vlarb_record.c new file mode 100644 index 000000000000..3bc9b8aa61a6 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sa_vlarb_record.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_vlarb_rec_rcv_t. + * This object represents the VLArbitrationRecord Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct osm_vl_arb_item { + cl_list_item_t list_item; + ib_vl_arb_table_record_t rec; +} osm_vl_arb_item_t; + +typedef struct osm_vl_arb_search_ctxt { + const ib_vl_arb_table_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + uint8_t block_num; + cl_qlist_t *p_list; + osm_sa_t *sa; + const osm_physp_t *p_req_physp; +} osm_vl_arb_search_ctxt_t; + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_vl_arb_create(IN osm_sa_t * sa, + IN osm_physp_t * const p_physp, + IN osm_vl_arb_search_ctxt_t * const p_ctxt, + IN uint8_t block) +{ + osm_vl_arb_item_t *p_rec_item; + uint16_t lid; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sa->p_log); + + p_rec_item = malloc(sizeof(*p_rec_item)); + if (p_rec_item == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A02: " + "rec_item alloc failed\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + + if (p_physp->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) + lid = p_physp->port_info.base_lid; + else + lid = osm_node_get_base_lid(p_physp->p_node, 0); + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "New VLArbitration for: port 0x%016" PRIx64 + ", lid %u, port %u Block:%u\n", + cl_ntoh64(osm_physp_get_port_guid(p_physp)), + cl_ntoh16(lid), osm_physp_get_port_num(p_physp), block); + + memset(p_rec_item, 0, sizeof(*p_rec_item)); + + p_rec_item->rec.lid = lid; + p_rec_item->rec.port_num = osm_physp_get_port_num(p_physp); + p_rec_item->rec.block_num = block; + p_rec_item->rec.vl_arb_tbl = *(osm_physp_get_vla_tbl(p_physp, block)); + + cl_qlist_insert_tail(p_ctxt->p_list, &p_rec_item->list_item); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_vl_arb_check_physp(IN osm_sa_t * sa, + IN osm_physp_t * const p_physp, + osm_vl_arb_search_ctxt_t * const p_ctxt) +{ + ib_net64_t comp_mask = p_ctxt->comp_mask; + uint8_t block; + + OSM_LOG_ENTER(sa->p_log); + + /* we got here with the phys port - all that's left is to get the right block */ + for (block = 1; block <= 4; block++) { + if (!(comp_mask & IB_VLA_COMPMASK_BLOCK) + || block == p_ctxt->block_num) { + __osm_sa_vl_arb_create(sa, p_physp, p_ctxt, block); + } + } + + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_vl_arb_by_comp_mask(IN osm_sa_t * sa, + IN const osm_port_t * const p_port, + osm_vl_arb_search_ctxt_t * const p_ctxt) +{ + const ib_vl_arb_table_record_t *p_rcvd_rec; + ib_net64_t comp_mask; + osm_physp_t *p_physp; + uint8_t port_num; + uint8_t num_ports; + const osm_physp_t *p_req_physp; + + OSM_LOG_ENTER(sa->p_log); + + p_rcvd_rec = p_ctxt->p_rcvd_rec; + comp_mask = p_ctxt->comp_mask; + port_num = p_rcvd_rec->port_num; + p_req_physp = p_ctxt->p_req_physp; + + /* if this is a switch port we can search all ports + otherwise we must be looking on port 0 */ + if (p_port->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) { + /* we put it in the comp mask and port num */ + port_num = p_port->p_physp->port_num; + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Using Physical Default Port Number: 0x%X (for End Node)\n", + port_num); + comp_mask |= IB_VLA_COMPMASK_OUT_PORT; + } + + if (comp_mask & IB_VLA_COMPMASK_OUT_PORT) { + if (port_num < osm_node_get_num_physp(p_port->p_node)) { + p_physp = + osm_node_get_physp_ptr(p_port->p_node, port_num); + /* check that the p_physp is valid, and that the requester + and the p_physp share a pkey. */ + if (p_physp && + osm_physp_share_pkey(sa->p_log, p_req_physp, + p_physp)) + __osm_sa_vl_arb_check_physp(sa, p_physp, + p_ctxt); + } else { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A03: " + "Given Physical Port Number: 0x%X is out of range should be < 0x%X\n", + port_num, + osm_node_get_num_physp(p_port->p_node)); + goto Exit; + } + } else { + num_ports = osm_node_get_num_physp(p_port->p_node); + for (port_num = 0; port_num < num_ports; port_num++) { + p_physp = + osm_node_get_physp_ptr(p_port->p_node, port_num); + if (!p_physp) + continue; + + /* if the requester and the p_physp don't share a pkey - + continue */ + if (!osm_physp_share_pkey + (sa->p_log, p_req_physp, p_physp)) + continue; + + __osm_sa_vl_arb_check_physp(sa, p_physp, p_ctxt); + } + } +Exit: + OSM_LOG_EXIT(sa->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sa_vl_arb_by_comp_mask_cb(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + const osm_port_t *const p_port = (osm_port_t *) p_map_item; + osm_vl_arb_search_ctxt_t *const p_ctxt = + (osm_vl_arb_search_ctxt_t *) context; + + __osm_sa_vl_arb_by_comp_mask(p_ctxt->sa, p_port, p_ctxt); +} + +/********************************************************************** + **********************************************************************/ +void osm_vlarb_rec_rcv_process(IN void *ctx, IN void *data) +{ + osm_sa_t *sa = ctx; + osm_madw_t *p_madw = data; + const ib_sa_mad_t *sad_mad; + const ib_vl_arb_table_record_t *p_rcvd_rec; + const osm_port_t *p_port = NULL; + const ib_vl_arb_table_t *p_vl_arb; + cl_qlist_t rec_list; + osm_vl_arb_search_ctxt_t context; + ib_api_status_t status = IB_SUCCESS; + ib_net64_t comp_mask; + osm_physp_t *p_req_physp; + + CL_ASSERT(sa); + + OSM_LOG_ENTER(sa->p_log); + + CL_ASSERT(p_madw); + + sad_mad = osm_madw_get_sa_mad_ptr(p_madw); + p_rcvd_rec = + (ib_vl_arb_table_record_t *) ib_sa_mad_get_payload_ptr(sad_mad); + comp_mask = sad_mad->comp_mask; + + CL_ASSERT(sad_mad->attr_id == IB_MAD_ATTR_VLARB_RECORD); + + /* we only support SubnAdmGet and SubnAdmGetTable methods */ + if (sad_mad->method != IB_MAD_METHOD_GET && + sad_mad->method != IB_MAD_METHOD_GETTABLE) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A05: " + "Unsupported Method (%s)\n", + ib_get_sa_method_str(sad_mad->method)); + osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); + goto Exit; + } + + /* update the requester physical port. */ + p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, + osm_madw_get_mad_addr_ptr + (p_madw)); + if (p_req_physp == NULL) { + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A04: " + "Cannot find requester physical port\n"); + goto Exit; + } + + p_vl_arb = (ib_vl_arb_table_t *) ib_sa_mad_get_payload_ptr(sad_mad); + + cl_qlist_init(&rec_list); + + context.p_rcvd_rec = p_rcvd_rec; + context.p_list = &rec_list; + context.comp_mask = sad_mad->comp_mask; + context.sa = sa; + context.block_num = p_rcvd_rec->block_num; + context.p_req_physp = p_req_physp; + + OSM_LOG(sa->p_log, OSM_LOG_DEBUG, + "Got Query Lid:%u(%02X), Port:0x%02X(%02X), Block:0x%02X(%02X)\n", + cl_ntoh16(p_rcvd_rec->lid), + (comp_mask & IB_VLA_COMPMASK_LID) != 0, p_rcvd_rec->port_num, + (comp_mask & IB_VLA_COMPMASK_OUT_PORT) != 0, + p_rcvd_rec->block_num, + (comp_mask & IB_VLA_COMPMASK_BLOCK) != 0); + + cl_plock_acquire(sa->p_lock); + + /* + If the user specified a LID, it obviously narrows our + work load, since we don't have to search every port + */ + if (comp_mask & IB_VLA_COMPMASK_LID) { + status = + osm_get_port_by_base_lid(sa->p_subn, p_rcvd_rec->lid, + &p_port); + if ((status != IB_SUCCESS) || (p_port == NULL)) { + status = IB_NOT_FOUND; + OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 2A09: " + "No port found with LID %u\n", + cl_ntoh16(p_rcvd_rec->lid)); + } + } + + if (status == IB_SUCCESS) { + /* if we got a unique port - no need for a port search */ + if (p_port) + /* this does the loop on all the port phys ports */ + __osm_sa_vl_arb_by_comp_mask(sa, p_port, &context); + else + cl_qmap_apply_func(&sa->p_subn->port_guid_tbl, + __osm_sa_vl_arb_by_comp_mask_cb, + &context); + } + + cl_plock_release(sa->p_lock); + + osm_sa_respond(sa, p_madw, sizeof(ib_vl_arb_table_record_t), &rec_list); + +Exit: + OSM_LOG_EXIT(sa->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_service.c b/contrib/ofed/management/opensm/opensm/osm_service.c new file mode 100644 index 000000000000..b7c1270b069e --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_service.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of service record functions. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void osm_svcr_delete(IN osm_svcr_t * const p_svcr) +{ + free(p_svcr); +} + +/********************************************************************** + **********************************************************************/ +void +osm_svcr_init(IN osm_svcr_t * const p_svcr, + IN const ib_service_record_t * p_svc_rec) +{ + CL_ASSERT(p_svcr); + + p_svcr->modified_time = cl_get_time_stamp_sec(); + + /* We track the time left for this service in + an external field to avoid extra cl_ntoh/hton + required for working with the MAD field */ + p_svcr->lease_period = cl_ntoh32(p_svc_rec->service_lease); + p_svcr->service_record = *p_svc_rec; +} + +/********************************************************************** + **********************************************************************/ +osm_svcr_t *osm_svcr_new(IN const ib_service_record_t * p_svc_rec) +{ + osm_svcr_t *p_svcr; + + CL_ASSERT(p_svc_rec); + + p_svcr = (osm_svcr_t *) malloc(sizeof(*p_svcr)); + if (p_svcr) { + memset(p_svcr, 0, sizeof(*p_svcr)); + osm_svcr_init(p_svcr, p_svc_rec); + } + + return (p_svcr); +} + +/********************************************************************** + **********************************************************************/ +static + cl_status_t +__match_rid_of_svc_rec(IN const cl_list_item_t * const p_list_item, + IN void *context) +{ + ib_service_record_t *p_svc_rec = (ib_service_record_t *) context; + osm_svcr_t *p_svcr = (osm_svcr_t *) p_list_item; + int32_t count; + + count = memcmp(&p_svcr->service_record, + p_svc_rec, + sizeof(p_svc_rec->service_id) + + sizeof(p_svc_rec->service_gid) + + sizeof(p_svc_rec->service_pkey)); + + if (count == 0) + return CL_SUCCESS; + else + return CL_NOT_FOUND; + +} + +/********************************************************************** + **********************************************************************/ +osm_svcr_t *osm_svcr_get_by_rid(IN osm_subn_t const *p_subn, + IN osm_log_t * p_log, + IN ib_service_record_t * const p_svc_rec) +{ + cl_list_item_t *p_list_item; + + OSM_LOG_ENTER(p_log); + + p_list_item = cl_qlist_find_from_head(&p_subn->sa_sr_list, + __match_rid_of_svc_rec, + p_svc_rec); + + if (p_list_item == cl_qlist_end(&p_subn->sa_sr_list)) + p_list_item = NULL; + + OSM_LOG_EXIT(p_log); + return (osm_svcr_t *) p_list_item; +} + +/********************************************************************** + **********************************************************************/ +void +osm_svcr_insert_to_db(IN osm_subn_t * p_subn, + IN osm_log_t * p_log, IN osm_svcr_t * p_svcr) +{ + OSM_LOG_ENTER(p_log); + + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Inserting new Service Record into Database\n"); + + cl_qlist_insert_head(&p_subn->sa_sr_list, &p_svcr->list_item); + + OSM_LOG_EXIT(p_log); +} + +void +osm_svcr_remove_from_db(IN osm_subn_t * p_subn, + IN osm_log_t * p_log, IN osm_svcr_t * p_svcr) +{ + OSM_LOG_ENTER(p_log); + + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Removing Service Record Name:%s ID:0x%016" PRIx64 + " from Database\n", p_svcr->service_record.service_name, + p_svcr->service_record.service_id); + + cl_qlist_remove_item(&p_subn->sa_sr_list, &p_svcr->list_item); + + OSM_LOG_EXIT(p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_slvl_map_rcv.c b/contrib/ofed/management/opensm/opensm/osm_slvl_map_rcv.c new file mode 100644 index 000000000000..e177345b67f5 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_slvl_map_rcv.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_slvl_rcv_t. + * This object represents the SLtoVL Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +/* + * WE MIGHT ONLY RECEIVE A GET or SET responses + */ +void osm_slvl_rcv_process(IN void *context, IN void *p_data) +{ + osm_sm_t *sm = context; + osm_madw_t *p_madw = p_data; + ib_slvl_table_t *p_slvl_tbl; + ib_smp_t *p_smp; + osm_port_t *p_port; + osm_physp_t *p_physp; + osm_node_t *p_node; + osm_slvl_context_t *p_context; + ib_net64_t port_guid; + ib_net64_t node_guid; + uint8_t out_port_num, in_port_num; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_context = osm_madw_get_slvl_context_ptr(p_madw); + p_slvl_tbl = (ib_slvl_table_t *) ib_smp_get_payload_ptr(p_smp); + + port_guid = p_context->port_guid; + node_guid = p_context->node_guid; + + CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_SLVL_TABLE); + + cl_plock_excl_acquire(sm->p_lock); + p_port = osm_get_port_by_guid(sm->p_subn, port_guid); + + if (!p_port) { + cl_plock_release(sm->p_lock); + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2C06: " + "No port object for port with GUID 0x%" PRIx64 + "\n\t\t\t\tfor parent node GUID 0x%" PRIx64 + ", TID 0x%" PRIx64 "\n", + cl_ntoh64(port_guid), + cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); + goto Exit; + } + + p_node = p_port->p_node; + CL_ASSERT(p_node); + + /* in case of a non switch node the attr modifier should be ignored */ + if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) { + out_port_num = + (uint8_t) cl_ntoh32(p_smp->attr_mod & 0xFF000000); + in_port_num = + (uint8_t) cl_ntoh32((p_smp->attr_mod & 0x00FF0000) << 8); + p_physp = osm_node_get_physp_ptr(p_node, out_port_num); + } else { + p_physp = p_port->p_physp; + out_port_num = p_physp->port_num; + in_port_num = 0; + } + + /* + We do not mind if this is a result of a set or get - all we want is to update + the subnet. + */ + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Got SLtoVL get response in_port_num %u out_port_num %u with " + "GUID 0x%" PRIx64 " for parent node GUID 0x%" PRIx64 ", TID 0x%" + PRIx64 "\n", in_port_num, out_port_num, cl_ntoh64(port_guid), + cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); + + /* + Determine if we encountered a new Physical Port. + If so, Ignore it. + */ + if (!p_physp) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "Got invalid port number %u\n", out_port_num); + goto Exit; + } + + osm_dump_slvl_map_table(sm->p_log, + port_guid, in_port_num, + out_port_num, p_slvl_tbl, OSM_LOG_DEBUG); + + osm_physp_set_slvl_tbl(p_physp, p_slvl_tbl, in_port_num); + +Exit: + cl_plock_release(sm->p_lock); + + OSM_LOG_EXIT(sm->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sm.c b/contrib/ofed/management/opensm/opensm/osm_sm.c new file mode 100644 index 000000000000..649ff2a56de3 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sm.c @@ -0,0 +1,655 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sm_t. + * This object represents the SM Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSM_SM_INITIAL_TID_VALUE 0x1233 + +extern void osm_lft_rcv_process(IN void *context, IN void *data); +extern void osm_mft_rcv_process(IN void *context, IN void *data); +extern void osm_nd_rcv_process(IN void *context, IN void *data); +extern void osm_ni_rcv_process(IN void *context, IN void *data); +extern void osm_pkey_rcv_process(IN void *context, IN void *data); +extern void osm_pi_rcv_process(IN void *context, IN void *data); +extern void osm_slvl_rcv_process(IN void *context, IN void *p_data); +extern void osm_sminfo_rcv_process(IN void *context, IN void *data); +extern void osm_si_rcv_process(IN void *context, IN void *data); +extern void osm_trap_rcv_process(IN void *context, IN void *data); +extern void osm_vla_rcv_process(IN void *context, IN void *data); + +extern void osm_state_mgr_process(IN osm_sm_t * sm, IN osm_signal_t signal); +extern void osm_sm_state_mgr_polling_callback(IN void *context); + +/********************************************************************** + **********************************************************************/ +static void osm_sm_process(osm_sm_t * sm, osm_signal_t signal) +{ +#ifdef ENABLE_OSM_PERF_MGR + if (signal == OSM_SIGNAL_PERFMGR_SWEEP) + osm_perfmgr_process(&sm->p_subn->p_osm->perfmgr); + else +#endif + osm_state_mgr_process(sm, signal); +} + +static void __osm_sm_sweeper(IN void *p_ptr) +{ + ib_api_status_t status; + osm_sm_t *const p_sm = (osm_sm_t *) p_ptr; + unsigned signals, i; + + OSM_LOG_ENTER(p_sm->p_log); + + while (p_sm->thread_state == OSM_THREAD_STATE_RUN) { + /* + * Wait on the event with a timeout. + * Sweeps may be initiated "off schedule" by simply + * signaling the event. + */ + status = cl_event_wait_on(&p_sm->signal_event, + EVENT_NO_TIMEOUT, TRUE); + + if (status == CL_SUCCESS) + OSM_LOG(p_sm->p_log, OSM_LOG_DEBUG, + "Off schedule sweep signalled\n"); + else if (status != CL_TIMEOUT) { + OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E01: " + "Event wait failed (%s)\n", + CL_STATUS_MSG(status)); + continue; + } + + if (osm_exit_flag) + break; + + cl_spinlock_acquire(&p_sm->signal_lock); + signals = p_sm->signal_mask; + p_sm->signal_mask = 0; + cl_spinlock_release(&p_sm->signal_lock); + + for (i = 0; signals; signals >>= 1, i++) + if (signals & 1) + osm_sm_process(p_sm, i); + } + + OSM_LOG_EXIT(p_sm->p_log); +} + +static void sm_sweep(void *arg) +{ + osm_sm_t *sm = arg; + + /* do the sweep only if we are in MASTER state */ + if (sm->p_subn->sm_state == IB_SMINFO_STATE_MASTER || + sm->p_subn->sm_state == IB_SMINFO_STATE_DISCOVERING) + osm_sm_signal(sm, OSM_SIGNAL_SWEEP); + cl_timer_start(&sm->sweep_timer, sm->p_subn->opt.sweep_interval * 1000); +} + +static void sweep_fail_process(IN void *context, IN void *p_data) +{ + osm_sm_t *sm = context; + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, "light sweep failed\n"); + sm->p_subn->force_heavy_sweep = TRUE; +} + +/********************************************************************** + **********************************************************************/ +void osm_sm_construct(IN osm_sm_t * const p_sm) +{ + memset(p_sm, 0, sizeof(*p_sm)); + p_sm->thread_state = OSM_THREAD_STATE_NONE; + p_sm->sm_trans_id = OSM_SM_INITIAL_TID_VALUE; + cl_spinlock_construct(&p_sm->signal_lock); + cl_spinlock_construct(&p_sm->state_lock); + cl_timer_construct(&p_sm->polling_timer); + cl_event_construct(&p_sm->signal_event); + cl_event_construct(&p_sm->subnet_up_event); + cl_event_wheel_construct(&p_sm->trap_aging_tracker); + cl_thread_construct(&p_sm->sweeper); + cl_spinlock_construct(&p_sm->mgrp_lock); + osm_sm_mad_ctrl_construct(&p_sm->mad_ctrl); + osm_lid_mgr_construct(&p_sm->lid_mgr); + osm_ucast_mgr_construct(&p_sm->ucast_mgr); +} + +/********************************************************************** + **********************************************************************/ +void osm_sm_shutdown(IN osm_sm_t * const p_sm) +{ + boolean_t signal_event = FALSE; + + OSM_LOG_ENTER(p_sm->p_log); + + /* + * Signal our threads that we're leaving. + */ + if (p_sm->thread_state != OSM_THREAD_STATE_NONE) + signal_event = TRUE; + + p_sm->thread_state = OSM_THREAD_STATE_EXIT; + + /* + * Don't trigger unless event has been initialized. + * Destroy the thread before we tear down the other objects. + */ + if (signal_event) + cl_event_signal(&p_sm->signal_event); + + cl_timer_stop(&p_sm->polling_timer); + cl_timer_stop(&p_sm->sweep_timer); + cl_thread_destroy(&p_sm->sweeper); + + /* + * Always destroy controllers before the corresponding + * receiver to guarantee that all callbacks from the + * dispatcher are complete. + */ + osm_sm_mad_ctrl_destroy(&p_sm->mad_ctrl); + cl_disp_unregister(p_sm->ni_disp_h); + cl_disp_unregister(p_sm->pi_disp_h); + cl_disp_unregister(p_sm->si_disp_h); + cl_disp_unregister(p_sm->nd_disp_h); + cl_disp_unregister(p_sm->lft_disp_h); + cl_disp_unregister(p_sm->mft_disp_h); + cl_disp_unregister(p_sm->sm_info_disp_h); + cl_disp_unregister(p_sm->trap_disp_h); + cl_disp_unregister(p_sm->slvl_disp_h); + cl_disp_unregister(p_sm->vla_disp_h); + cl_disp_unregister(p_sm->pkey_disp_h); + cl_disp_unregister(p_sm->sweep_fail_disp_h); + + OSM_LOG_EXIT(p_sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_sm_destroy(IN osm_sm_t * const p_sm) +{ + OSM_LOG_ENTER(p_sm->p_log); + osm_lid_mgr_destroy(&p_sm->lid_mgr); + osm_ucast_mgr_destroy(&p_sm->ucast_mgr); + cl_event_wheel_destroy(&p_sm->trap_aging_tracker); + cl_timer_destroy(&p_sm->sweep_timer); + cl_timer_destroy(&p_sm->polling_timer); + cl_event_destroy(&p_sm->signal_event); + cl_event_destroy(&p_sm->subnet_up_event); + cl_spinlock_destroy(&p_sm->signal_lock); + cl_spinlock_destroy(&p_sm->mgrp_lock); + cl_spinlock_destroy(&p_sm->state_lock); + + osm_log(p_sm->p_log, OSM_LOG_SYS, "Exiting SM\n"); /* Format Waived */ + OSM_LOG_EXIT(p_sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_init(IN osm_sm_t * const p_sm, + IN osm_subn_t * const p_subn, + IN osm_db_t * const p_db, + IN osm_vendor_t * const p_vendor, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vl15_t * const p_vl15, + IN osm_log_t * const p_log, + IN osm_stats_t * const p_stats, + IN cl_dispatcher_t * const p_disp, IN cl_plock_t * const p_lock) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + p_sm->p_subn = p_subn; + p_sm->p_db = p_db; + p_sm->p_vendor = p_vendor; + p_sm->p_mad_pool = p_mad_pool; + p_sm->p_vl15 = p_vl15; + p_sm->p_log = p_log; + p_sm->p_disp = p_disp; + p_sm->p_lock = p_lock; + + status = cl_spinlock_init(&p_sm->signal_lock); + if (status != CL_SUCCESS) + goto Exit; + + status = cl_spinlock_init(&p_sm->state_lock); + if (status != CL_SUCCESS) + goto Exit; + + status = cl_event_init(&p_sm->signal_event, FALSE); + if (status != CL_SUCCESS) + goto Exit; + + status = cl_event_init(&p_sm->subnet_up_event, FALSE); + if (status != CL_SUCCESS) + goto Exit; + + status = cl_timer_init(&p_sm->sweep_timer, sm_sweep, p_sm); + if (status != CL_SUCCESS) + goto Exit; + + status = cl_timer_init(&p_sm->polling_timer, + osm_sm_state_mgr_polling_callback, p_sm); + if (status != CL_SUCCESS) + goto Exit; + + cl_qlist_init(&p_sm->mgrp_list); + + status = cl_spinlock_init(&p_sm->mgrp_lock); + if (status != CL_SUCCESS) + goto Exit; + + status = osm_sm_mad_ctrl_init(&p_sm->mad_ctrl, + p_sm->p_subn, + p_sm->p_mad_pool, + p_sm->p_vl15, + p_sm->p_vendor, + p_log, p_stats, p_lock, p_disp); + if (status != IB_SUCCESS) + goto Exit; + + status = cl_event_wheel_init(&p_sm->trap_aging_tracker); + if (status != IB_SUCCESS) + goto Exit; + + status = osm_lid_mgr_init(&p_sm->lid_mgr, p_sm); + if (status != IB_SUCCESS) + goto Exit; + + status = osm_ucast_mgr_init(&p_sm->ucast_mgr, p_sm); + if (status != IB_SUCCESS) + goto Exit; + + p_sm->sweep_fail_disp_h = cl_disp_register(p_disp, + OSM_MSG_LIGHT_SWEEP_FAIL, + sweep_fail_process, p_sm); + if (p_sm->sweep_fail_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sm->ni_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NODE_INFO, + osm_ni_rcv_process, p_sm); + if (p_sm->ni_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sm->pi_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PORT_INFO, + osm_pi_rcv_process, p_sm); + if (p_sm->pi_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sm->si_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SWITCH_INFO, + osm_si_rcv_process, p_sm); + if (p_sm->si_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sm->nd_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NODE_DESC, + osm_nd_rcv_process, p_sm); + if (p_sm->nd_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sm->lft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_LFT, + osm_lft_rcv_process, p_sm); + if (p_sm->lft_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sm->mft_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_MFT, + osm_mft_rcv_process, p_sm); + if (p_sm->mft_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sm->sm_info_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SM_INFO, + osm_sminfo_rcv_process, p_sm); + if (p_sm->sm_info_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sm->trap_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_NOTICE, + osm_trap_rcv_process, p_sm); + if (p_sm->trap_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sm->slvl_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_SLVL, + osm_slvl_rcv_process, p_sm); + if (p_sm->slvl_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sm->vla_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_VL_ARB, + osm_vla_rcv_process, p_sm); + if (p_sm->vla_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_sm->pkey_disp_h = cl_disp_register(p_disp, OSM_MSG_MAD_PKEY, + osm_pkey_rcv_process, p_sm); + if (p_sm->pkey_disp_h == CL_DISP_INVALID_HANDLE) + goto Exit; + + p_subn->sm_state = p_subn->opt.sm_inactive ? + IB_SMINFO_STATE_NOTACTIVE : IB_SMINFO_STATE_DISCOVERING; + osm_report_sm_state(p_sm); + + /* + * Now that the component objects are initialized, start + * the sweeper thread if the user wants sweeping. + */ + p_sm->thread_state = OSM_THREAD_STATE_RUN; + status = cl_thread_init(&p_sm->sweeper, __osm_sm_sweeper, p_sm, + "opensm sweeper"); + if (status != IB_SUCCESS) + goto Exit; + + if (p_sm->p_subn->opt.sweep_interval) + cl_timer_start(&p_sm->sweep_timer, + p_sm->p_subn->opt.sweep_interval * 1000); + +Exit: + OSM_LOG_EXIT(p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +void osm_sm_signal(osm_sm_t * p_sm, osm_signal_t signal) +{ + cl_spinlock_acquire(&p_sm->signal_lock); + p_sm->signal_mask |= 1 << signal; + cl_event_signal(&p_sm->signal_event); + cl_spinlock_release(&p_sm->signal_lock); +} + +/********************************************************************** + **********************************************************************/ +void osm_sm_sweep(IN osm_sm_t * const p_sm) +{ + OSM_LOG_ENTER(p_sm->p_log); + osm_sm_signal(p_sm, OSM_SIGNAL_SWEEP); + OSM_LOG_EXIT(p_sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_bind(IN osm_sm_t * const p_sm, IN const ib_net64_t port_guid) +{ + ib_api_status_t status; + + OSM_LOG_ENTER(p_sm->p_log); + + status = osm_sm_mad_ctrl_bind(&p_sm->mad_ctrl, port_guid); + + if (status != IB_SUCCESS) { + OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E10: " + "SM MAD Controller bind failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_sm->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_sm_mgrp_process(IN osm_sm_t * const p_sm, + IN osm_mgrp_t * const p_mgrp, + IN const ib_net64_t port_guid, + IN osm_mcast_req_type_t req_type) +{ + osm_mcast_mgr_ctxt_t *ctx; + + /* + * 'Schedule' all the QP0 traffic for when the state manager + * isn't busy trying to do something else. + */ + ctx = malloc(sizeof(*ctx)); + if (!ctx) + return IB_ERROR; + memset(ctx, 0, sizeof(*ctx)); + ctx->mlid = p_mgrp->mlid; + ctx->req_type = req_type; + ctx->port_guid = port_guid; + + cl_spinlock_acquire(&p_sm->mgrp_lock); + cl_qlist_insert_tail(&p_sm->mgrp_list, &ctx->list_item); + cl_spinlock_release(&p_sm->mgrp_lock); + + osm_sm_signal(p_sm, OSM_SIGNAL_IDLE_TIME_PROCESS_REQUEST); + + return IB_SUCCESS; +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +__osm_sm_mgrp_connect(IN osm_sm_t * const p_sm, + IN osm_mgrp_t * const p_mgrp, + IN const ib_net64_t port_guid, + IN osm_mcast_req_type_t req_type) +{ + return __osm_sm_mgrp_process(p_sm, p_mgrp, port_guid, req_type); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sm_mgrp_disconnect(IN osm_sm_t * const p_sm, + IN osm_mgrp_t * const p_mgrp, + IN const ib_net64_t port_guid) +{ + __osm_sm_mgrp_process(p_sm, p_mgrp, port_guid, + OSM_MCAST_REQ_TYPE_LEAVE); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_mcgrp_join(IN osm_sm_t * const p_sm, + IN const ib_net16_t mlid, + IN const ib_net64_t port_guid, + IN osm_mcast_req_type_t req_type) +{ + osm_mgrp_t *p_mgrp; + osm_port_t *p_port; + ib_api_status_t status = IB_SUCCESS; + osm_mcm_info_t *p_mcm; + + OSM_LOG_ENTER(p_sm->p_log); + + OSM_LOG(p_sm->p_log, OSM_LOG_VERBOSE, + "Port 0x%016" PRIx64 " joining MLID 0x%X\n", + cl_ntoh64(port_guid), cl_ntoh16(mlid)); + + /* + * Acquire the port object for the port joining this group. + */ + CL_PLOCK_EXCL_ACQUIRE(p_sm->p_lock); + p_port = osm_get_port_by_guid(p_sm->p_subn, port_guid); + if (!p_port) { + CL_PLOCK_RELEASE(p_sm->p_lock); + OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E05: " + "No port object for port 0x%016" PRIx64 "\n", + cl_ntoh64(port_guid)); + status = IB_INVALID_PARAMETER; + goto Exit; + } + + /* + * If this multicast group does not already exist, create it. + */ + p_mgrp = osm_get_mgrp_by_mlid(p_sm->p_subn, mlid); + if (!p_mgrp || !osm_mgrp_is_guid(p_mgrp, port_guid)) { + /* + * The group removed or the port is not a + * member of the group, then fail immediately. + * This can happen since the spinlock is released briefly + * before the SA calls this function. + */ + CL_PLOCK_RELEASE(p_sm->p_lock); + OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E12: " + "MC group with mlid 0x%x doesn't exist or " + "port 0x%016" PRIx64 " is not in the group.\n", + cl_ntoh16(mlid), cl_ntoh64(port_guid)); + status = IB_NOT_FOUND; + goto Exit; + } + + /* + * Check if the object (according to mlid) already exists on this port. + * If it does - then no need to update it again, and no need to + * create the mc tree again. Just goto Exit. + */ + p_mcm = (osm_mcm_info_t *) cl_qlist_head(&p_port->mcm_list); + while (p_mcm != (osm_mcm_info_t *) cl_qlist_end(&p_port->mcm_list)) { + if (p_mcm->mlid == mlid) { + CL_PLOCK_RELEASE(p_sm->p_lock); + OSM_LOG(p_sm->p_log, OSM_LOG_DEBUG, + "Found mlid object for Port:" + "0x%016" PRIx64 " lid:0x%X\n", + cl_ntoh64(port_guid), cl_ntoh16(mlid)); + goto Exit; + } + p_mcm = (osm_mcm_info_t *) cl_qlist_next(&p_mcm->list_item); + } + + status = osm_port_add_mgrp(p_port, mlid); + if (status != IB_SUCCESS) { + CL_PLOCK_RELEASE(p_sm->p_lock); + OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E03: " + "Unable to associate port 0x%" PRIx64 " to mlid 0x%X\n", + cl_ntoh64(osm_port_get_guid(p_port)), + cl_ntoh16(osm_mgrp_get_mlid(p_mgrp))); + goto Exit; + } + + status = __osm_sm_mgrp_connect(p_sm, p_mgrp, port_guid, req_type); + CL_PLOCK_RELEASE(p_sm->p_lock); + +Exit: + OSM_LOG_EXIT(p_sm->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_mcgrp_leave(IN osm_sm_t * const p_sm, + IN const ib_net16_t mlid, IN const ib_net64_t port_guid) +{ + osm_mgrp_t *p_mgrp; + osm_port_t *p_port; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_sm->p_log); + + OSM_LOG(p_sm->p_log, OSM_LOG_VERBOSE, + "Port 0x%" PRIx64 " leaving MLID 0x%X\n", + cl_ntoh64(port_guid), cl_ntoh16(mlid)); + + /* + * Acquire the port object for the port leaving this group. + */ + CL_PLOCK_EXCL_ACQUIRE(p_sm->p_lock); + + p_port = osm_get_port_by_guid(p_sm->p_subn, port_guid); + if (!p_port) { + CL_PLOCK_RELEASE(p_sm->p_lock); + OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E04: " + "No port object for port 0x%" PRIx64 "\n", + cl_ntoh64(port_guid)); + status = IB_INVALID_PARAMETER; + goto Exit; + } + + /* + * Get the multicast group object for this group. + */ + p_mgrp = osm_get_mgrp_by_mlid(p_sm->p_subn, mlid); + if (!p_mgrp) { + CL_PLOCK_RELEASE(p_sm->p_lock); + OSM_LOG(p_sm->p_log, OSM_LOG_ERROR, "ERR 2E08: " + "No multicast group for MLID 0x%X\n", cl_ntoh16(mlid)); + status = IB_INVALID_PARAMETER; + goto Exit; + } + + /* + * Walk the list of ports in the group, and remove the appropriate one. + */ + osm_port_remove_mgrp(p_port, mlid); + + __osm_sm_mgrp_disconnect(p_sm, p_mgrp, port_guid); + CL_PLOCK_RELEASE(p_sm->p_lock); + +Exit: + OSM_LOG_EXIT(p_sm->p_log); + return (status); +} + +void osm_set_sm_priority(osm_sm_t *sm, uint8_t priority) +{ + uint8_t old_pri = sm->p_subn->opt.sm_priority; + + sm->p_subn->opt.sm_priority = priority; + + if (old_pri < priority && + sm->p_subn->sm_state == IB_SMINFO_STATE_STANDBY) + osm_send_trap144(sm, TRAP_144_MASK_SM_PRIORITY_CHANGE); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sm_mad_ctrl.c b/contrib/ofed/management/opensm/opensm/osm_sm_mad_ctrl.c new file mode 100644 index 000000000000..267ec8568f68 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sm_mad_ctrl.c @@ -0,0 +1,874 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sm_mad_ctrl_t. + * This object represents the SM MAD request controller object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****f* opensm: SM/__osm_sm_mad_ctrl_retire_trans_mad + * NAME + * __osm_sm_mad_ctrl_retire_trans_mad + * + * DESCRIPTION + * This function handles clean-up of MADs associated with the SM's + * outstanding transactions on the wire. + * + * SYNOPSIS + */ + +static void +__osm_sm_mad_ctrl_retire_trans_mad(IN osm_sm_mad_ctrl_t * const p_ctrl, + IN osm_madw_t * const p_madw) +{ + uint32_t outstanding; + + OSM_LOG_ENTER(p_ctrl->p_log); + + CL_ASSERT(p_madw); + /* + Return the MAD & wrapper to the pool. + */ + OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, + "Retiring MAD with TID 0x%" PRIx64 "\n", + cl_ntoh64(osm_madw_get_smp_ptr(p_madw)->trans_id)); + + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + + outstanding = osm_stats_dec_qp0_outstanding(p_ctrl->p_stats); + + OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "%u QP0 MADs outstanding%s\n", + p_ctrl->p_stats->qp0_mads_outstanding, + outstanding ? "" : ": wire is clean."); + + OSM_LOG_EXIT(p_ctrl->p_log); +} + +/************/ + +/****f* opensm: SM/__osm_sm_mad_ctrl_disp_done_callback + * NAME + * __osm_sm_mad_ctrl_disp_done_callback + * + * DESCRIPTION + * This function is the Dispatcher callback that indicates + * a received MAD has been processed by the recipient. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_disp_done_callback(IN void *context, IN void *p_data) +{ + osm_sm_mad_ctrl_t *const p_ctrl = (osm_sm_mad_ctrl_t *) context; + osm_madw_t *const p_madw = (osm_madw_t *) p_data; + ib_smp_t *p_smp; + + OSM_LOG_ENTER(p_ctrl->p_log); + + /* + If the MAD that just finished processing was a response, + then retire the transaction, since we must have generated + the request. + + Otherwise, retire the transaction if a response was expected, + as in the case of a send failure. If a response was not expected, + just put the MAD back in the pool, because the MAD was a query + from some outside agent, e.g. Get(SMInfo) from another SM. + */ + p_smp = osm_madw_get_smp_ptr(p_madw); + if (ib_smp_is_response(p_smp)) { + CL_ASSERT(p_madw->resp_expected == FALSE); + __osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw); + } else if (p_madw->resp_expected == TRUE) + __osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw); + else + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + + OSM_LOG_EXIT(p_ctrl->p_log); +} + +/************/ + +/****f* opensm: SM/__osm_sm_mad_ctrl_update_wire_stats + * NAME + * __osm_sm_mad_ctrl_update_wire_stats + * + * DESCRIPTION + * Updates wire stats for outstanding MADs and calls the VL15 poller. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_update_wire_stats(IN osm_sm_mad_ctrl_t * const p_ctrl) +{ + uint32_t mads_on_wire; + + OSM_LOG_ENTER(p_ctrl->p_log); + + mads_on_wire = + cl_atomic_dec(&p_ctrl->p_stats->qp0_mads_outstanding_on_wire); + + OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, + "%u SMPs on the wire, %u outstanding\n", mads_on_wire, + p_ctrl->p_stats->qp0_mads_outstanding); + + /* + We can signal the VL15 controller to send another MAD + if any are waiting for transmission. + */ + osm_vl15_poll(p_ctrl->p_vl15); + OSM_LOG_EXIT(p_ctrl->p_log); +} + +/****f* opensm: SM/__osm_sm_mad_ctrl_process_get_resp + * NAME + * __osm_sm_mad_ctrl_process_get_resp + * + * DESCRIPTION + * This function handles method GetResp() for received MADs. + * This is the most common path for QP0 MADs. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_process_get_resp(IN osm_sm_mad_ctrl_t * const p_ctrl, + IN osm_madw_t * p_madw, + IN void *transaction_context) +{ + ib_smp_t *p_smp; + cl_status_t status; + osm_madw_t *p_old_madw; + cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE; + + OSM_LOG_ENTER(p_ctrl->p_log); + + CL_ASSERT(p_madw); + CL_ASSERT(transaction_context); + + p_smp = osm_madw_get_smp_ptr(p_madw); + + if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR && !ib_smp_is_d(p_smp)) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3102: " + "'D' bit not set in returned SMP\n"); + osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR); + } + + p_old_madw = (osm_madw_t *) transaction_context; + + __osm_sm_mad_ctrl_update_wire_stats(p_ctrl); + + /* + Copy the MAD Wrapper context from the requesting MAD + to the new MAD. This mechanism allows the recipient + controller to recover its own context regarding this + MAD transaction. Once we've copied the context, we + can return the original MAD to the pool. + */ + osm_madw_copy_context(p_madw, p_old_madw); + osm_mad_pool_put(p_ctrl->p_mad_pool, p_old_madw); + + /* + Note that attr_id (like the rest of the MAD) is in + network byte order. + */ + switch (p_smp->attr_id) { + case IB_MAD_ATTR_NODE_DESC: + msg_id = OSM_MSG_MAD_NODE_DESC; + break; + case IB_MAD_ATTR_NODE_INFO: + msg_id = OSM_MSG_MAD_NODE_INFO; + break; + case IB_MAD_ATTR_SWITCH_INFO: + msg_id = OSM_MSG_MAD_SWITCH_INFO; + break; + case IB_MAD_ATTR_PORT_INFO: + msg_id = OSM_MSG_MAD_PORT_INFO; + break; + case IB_MAD_ATTR_LIN_FWD_TBL: + msg_id = OSM_MSG_MAD_LFT; + break; + case IB_MAD_ATTR_MCAST_FWD_TBL: + msg_id = OSM_MSG_MAD_MFT; + break; + case IB_MAD_ATTR_SM_INFO: + msg_id = OSM_MSG_MAD_SM_INFO; + break; + case IB_MAD_ATTR_SLVL_TABLE: + msg_id = OSM_MSG_MAD_SLVL; + break; + case IB_MAD_ATTR_VL_ARBITRATION: + msg_id = OSM_MSG_MAD_VL_ARB; + break; + case IB_MAD_ATTR_P_KEY_TABLE: + msg_id = OSM_MSG_MAD_PKEY; + break; + + case IB_MAD_ATTR_GUID_INFO: + case IB_MAD_ATTR_CLASS_PORT_INFO: + case IB_MAD_ATTR_NOTICE: + case IB_MAD_ATTR_INFORM_INFO: + default: + cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown); + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3103: " + "Unsupported attribute = 0x%X\n", + cl_ntoh16(p_smp->attr_id)); + osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR); + goto Exit; + } + + if (msg_id == CL_DISP_MSGID_NONE) + goto Exit; + + /* + Post this MAD to the dispatcher for asynchronous + processing by the appropriate controller. + */ + + OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n", + osm_get_disp_msg_str(msg_id)); + + status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw, + __osm_sm_mad_ctrl_disp_done_callback, p_ctrl); + + if (status != CL_SUCCESS) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3104: " + "Dispatcher post message failed (%s) for attribute = 0x%X\n", + CL_STATUS_MSG(status), cl_ntoh16(p_smp->attr_id)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_ctrl->p_log); +} + +/****f* opensm: SM/__osm_sm_mad_ctrl_process_get + * NAME + * __osm_sm_mad_ctrl_process_get + * + * DESCRIPTION + * This function handles method Get() for received MADs. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_process_get(IN osm_sm_mad_ctrl_t * const p_ctrl, + IN osm_madw_t * p_madw) +{ + ib_smp_t *p_smp; + cl_status_t status; + cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE; + + OSM_LOG_ENTER(p_ctrl->p_log); + + p_smp = osm_madw_get_smp_ptr(p_madw); + + /* + Note that attr_id (like the rest of the MAD) is in + network byte order. + */ + switch (p_smp->attr_id) { + case IB_MAD_ATTR_SM_INFO: + msg_id = OSM_MSG_MAD_SM_INFO; + break; + + default: + cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown); + OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE, + "Ignoring SubnGet MAD - unsupported attribute = 0x%X\n", + cl_ntoh16(p_smp->attr_id)); + break; + } + + if (msg_id == CL_DISP_MSGID_NONE) { + /* + There is an unknown MAD attribute type for which there is + no recipient. Simply retire the MAD here. + */ + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + goto Exit; + } + + /* + Post this MAD to the dispatcher for asynchronous + processing by the appropriate controller. + */ + + OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n", + osm_get_disp_msg_str(msg_id)); + + status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw, + __osm_sm_mad_ctrl_disp_done_callback, p_ctrl); + + if (status != CL_SUCCESS) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3106: " + "Dispatcher post message failed (%s)\n", + CL_STATUS_MSG(status)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_ctrl->p_log); +} + +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* opensm: SM/__osm_sm_mad_ctrl_process_set + * NAME + * __osm_sm_mad_ctrl_process_set + * + * DESCRIPTION + * This function handles method Set() for received MADs. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_process_set(IN osm_sm_mad_ctrl_t * const p_ctrl, + IN osm_madw_t * p_madw) +{ + ib_smp_t *p_smp; + cl_status_t status; + cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE; + + OSM_LOG_ENTER(p_ctrl->p_log); + + p_smp = osm_madw_get_smp_ptr(p_madw); + + /* + Note that attr_id (like the rest of the MAD) is in + network byte order. + */ + switch (p_smp->attr_id) { + case IB_MAD_ATTR_SM_INFO: + msg_id = OSM_MSG_MAD_SM_INFO; + break; + + default: + cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown); + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3107: " + "Unsupported attribute = 0x%X\n", + cl_ntoh16(p_smp->attr_id)); + osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR); + break; + } + + if (msg_id == CL_DISP_MSGID_NONE) { + /* + There is an unknown MAD attribute type for which there is + no recipient. Simply retire the MAD here. + */ + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + goto Exit; + } + + /* + Post this MAD to the dispatcher for asynchronous + processing by the appropriate controller. + */ + + OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n", + osm_get_disp_msg_str(msg_id)); + + status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw, + __osm_sm_mad_ctrl_disp_done_callback, p_ctrl); + + if (status != CL_SUCCESS) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3108: " + "Dispatcher post message failed (%s)\n", + CL_STATUS_MSG(status)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_ctrl->p_log); +} + +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* opensm: SM/__osm_sm_mad_ctrl_process_trap + * NAME + * __osm_sm_mad_ctrl_process_trap + * + * DESCRIPTION + * This function handles method Trap() for received MADs. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_process_trap(IN osm_sm_mad_ctrl_t * const p_ctrl, + IN osm_madw_t * p_madw) +{ + ib_smp_t *p_smp; + cl_status_t status; + cl_disp_msgid_t msg_id = CL_DISP_MSGID_NONE; + + OSM_LOG_ENTER(p_ctrl->p_log); + + p_smp = osm_madw_get_smp_ptr(p_madw); + + /* Make sure OpenSM is master. If not - then we should not process the trap */ + if (p_ctrl->p_subn->sm_state != IB_SMINFO_STATE_MASTER) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, + "Received trap but OpenSM is not in MASTER state. " + "Dropping mad\n"); + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + goto Exit; + } + + /* + Note that attr_id (like the rest of the MAD) is in + network byte order. + */ + switch (p_smp->attr_id) { + case IB_MAD_ATTR_NOTICE: + msg_id = OSM_MSG_MAD_NOTICE; + break; + + default: + cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown); + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3109: " + "Unsupported attribute = 0x%X\n", + cl_ntoh16(p_smp->attr_id)); + osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR); + break; + } + + if (msg_id == CL_DISP_MSGID_NONE) { + /* + There is an unknown MAD attribute type for which there is + no recipient. Simply retire the MAD here. + */ + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + goto Exit; + } + + /* + Post this MAD to the dispatcher for asynchronous + processing by the appropriate controller. + */ + + OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "Posting Dispatcher message %s\n", + osm_get_disp_msg_str(msg_id)); + + status = cl_disp_post(p_ctrl->h_disp, msg_id, p_madw, + __osm_sm_mad_ctrl_disp_done_callback, p_ctrl); + + if (status != CL_SUCCESS) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3110: " + "Dispatcher post message failed (%s)\n", + CL_STATUS_MSG(status)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_ctrl->p_log); +} + +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* opensm: SM/__osm_sm_mad_ctrl_rcv_callback + * NAME + * __osm_sm_mad_ctrl_rcv_callback + * + * DESCRIPTION + * This is the callback from the transport layer for received MADs. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_rcv_callback(IN osm_madw_t * p_madw, + IN void *bind_context, + IN osm_madw_t * p_req_madw) +{ + osm_sm_mad_ctrl_t *p_ctrl = (osm_sm_mad_ctrl_t *) bind_context; + ib_smp_t *p_smp; + ib_net16_t status; + + OSM_LOG_ENTER(p_ctrl->p_log); + + CL_ASSERT(p_madw); + + /* + A MAD was received from the wire, possibly in response to a request. + */ + cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd); + + OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, "%u QP0 MADs received\n", + p_ctrl->p_stats->qp0_mads_rcvd); + + p_smp = osm_madw_get_smp_ptr(p_madw); + + /* if we are closing down simply do nothing */ + if (osm_exit_flag) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, + "Ignoring received mad - since we are exiting\n"); + + osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_DEBUG); + + /* retire the mad or put it back */ + if (ib_smp_is_response(p_smp) || + (p_smp->method == IB_MAD_METHOD_TRAP_REPRESS)) { + CL_ASSERT(p_madw->resp_expected == FALSE); + __osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw); + } else if (p_madw->resp_expected == TRUE) + __osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw); + else + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + + goto Exit; + } + + if (osm_log_is_active(p_ctrl->p_log, OSM_LOG_FRAMES)) + osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_FRAMES); + + if (p_smp->mgmt_class == IB_MCLASS_SUBN_DIR) + status = ib_smp_get_status(p_smp); + else + status = p_smp->status; + + if (status != 0) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3111: " + "Error status = 0x%X\n", status); + osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR); + } + + switch (p_smp->method) { + case IB_MAD_METHOD_GET_RESP: + CL_ASSERT(p_req_madw != NULL); + __osm_sm_mad_ctrl_process_get_resp(p_ctrl, p_madw, p_req_madw); + break; + + case IB_MAD_METHOD_GET: + CL_ASSERT(p_req_madw == NULL); + __osm_sm_mad_ctrl_process_get(p_ctrl, p_madw); + break; + + case IB_MAD_METHOD_TRAP: + CL_ASSERT(p_req_madw == NULL); + __osm_sm_mad_ctrl_process_trap(p_ctrl, p_madw); + break; + + case IB_MAD_METHOD_SET: + CL_ASSERT(p_req_madw == NULL); + __osm_sm_mad_ctrl_process_set(p_ctrl, p_madw); + break; + + case IB_MAD_METHOD_SEND: + case IB_MAD_METHOD_REPORT: + case IB_MAD_METHOD_REPORT_RESP: + case IB_MAD_METHOD_TRAP_REPRESS: + default: + cl_atomic_inc(&p_ctrl->p_stats->qp0_mads_rcvd_unknown); + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3112: " + "Unsupported method = 0x%X\n", p_smp->method); + osm_dump_dr_smp(p_ctrl->p_log, p_smp, OSM_LOG_ERROR); + osm_mad_pool_put(p_ctrl->p_mad_pool, p_madw); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_ctrl->p_log); +} + +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* opensm: SM/__osm_sm_mad_ctrl_send_err_cb + * NAME + * __osm_sm_mad_ctrl_send_err_cb + * + * DESCRIPTION + * This is the callback from the transport layer for send errors + * on MADs that were expecting a response. + * + * SYNOPSIS + */ +static void +__osm_sm_mad_ctrl_send_err_cb(IN void *bind_context, IN osm_madw_t * p_madw) +{ + osm_sm_mad_ctrl_t *p_ctrl = (osm_sm_mad_ctrl_t *) bind_context; + ib_api_status_t status; + ib_smp_t *p_smp; + + OSM_LOG_ENTER(p_ctrl->p_log); + + CL_ASSERT(p_madw); + + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3113: " + "MAD completed in error (%s)\n", + ib_get_err_str(p_madw->status)); + + /* + If this was a SubnSet MAD, then this error might indicate a problem + in configuring the subnet. In this case - need to mark that there was + such a problem. The subnet will not be up, and the next sweep should + be a heavy sweep as well. + */ + p_smp = osm_madw_get_smp_ptr(p_madw); + if (p_smp->method == IB_MAD_METHOD_SET && + (p_smp->attr_id == IB_MAD_ATTR_PORT_INFO || + p_smp->attr_id == IB_MAD_ATTR_MCAST_FWD_TBL || + p_smp->attr_id == IB_MAD_ATTR_SWITCH_INFO || + p_smp->attr_id == IB_MAD_ATTR_LIN_FWD_TBL)) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3119: " + "Set method failed\n"); + p_ctrl->p_subn->subnet_initialization_error = TRUE; + } + + /* + Since we did not get any response we suspect the DR path + used for the target port. + Find it and replace it with an alternate path. + This is true only if the destination lid is not 0xFFFF, since + then we are aiming for a specific path and not specific destination + lid. + */ + /* For now - do not add the alternate dr path to the release */ +#if 0 + if (p_madw->mad_addr.dest_lid != 0xFFFF) { + osm_physp_t *p_physp = + osm_get_physp_by_mad_addr(p_ctrl->p_log, + p_ctrl->p_subn, + &(p_madw->mad_addr)); + if (!p_physp) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3114: " + "Failed to find the corresponding phys port\n"); + } else { + osm_physp_replace_dr_path_with_alternate_dr_path + (p_ctrl->p_log, p_ctrl->p_subn, p_physp, + p_madw->h_bind); + } + } +#endif + + /* + An error occurred. No response was received to a request MAD. + Retire the original request MAD. + */ + + osm_dump_dr_smp(p_ctrl->p_log, osm_madw_get_smp_ptr(p_madw), + OSM_LOG_ERROR); + + __osm_sm_mad_ctrl_update_wire_stats(p_ctrl); + + if (osm_madw_get_err_msg(p_madw) != CL_DISP_MSGID_NONE) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_DEBUG, + "Posting Dispatcher message %s\n", + osm_get_disp_msg_str(osm_madw_get_err_msg(p_madw))); + + status = cl_disp_post(p_ctrl->h_disp, + osm_madw_get_err_msg(p_madw), + p_madw, + __osm_sm_mad_ctrl_disp_done_callback, + p_ctrl); + if (status != CL_SUCCESS) + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3115: " + "Dispatcher post message failed (%s)\n", + CL_STATUS_MSG(status)); + } else + /* + No error message was provided, just retire the MAD. + */ + __osm_sm_mad_ctrl_retire_trans_mad(p_ctrl, p_madw); + + OSM_LOG_EXIT(p_ctrl->p_log); +} + +/* + * PARAMETERS + * + * RETURN VALUES + * + * NOTES + * + * SEE ALSO + *********/ + +/********************************************************************** + **********************************************************************/ +void osm_sm_mad_ctrl_construct(IN osm_sm_mad_ctrl_t * const p_ctrl) +{ + CL_ASSERT(p_ctrl); + memset(p_ctrl, 0, sizeof(*p_ctrl)); + p_ctrl->h_disp = CL_DISP_INVALID_HANDLE; +} + +/********************************************************************** + **********************************************************************/ +void osm_sm_mad_ctrl_destroy(IN osm_sm_mad_ctrl_t * const p_ctrl) +{ + CL_ASSERT(p_ctrl); + + if (p_ctrl->h_bind != CL_DISP_INVALID_HANDLE) + osm_vendor_unbind(p_ctrl->h_bind); + cl_disp_unregister(p_ctrl->h_disp); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_mad_ctrl_init(IN osm_sm_mad_ctrl_t * const p_ctrl, + IN osm_subn_t * const p_subn, + IN osm_mad_pool_t * const p_mad_pool, + IN osm_vl15_t * const p_vl15, + IN osm_vendor_t * const p_vendor, + IN osm_log_t * const p_log, + IN osm_stats_t * const p_stats, + IN cl_plock_t * const p_lock, + IN cl_dispatcher_t * const p_disp) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + osm_sm_mad_ctrl_construct(p_ctrl); + + p_ctrl->p_subn = p_subn; + p_ctrl->p_log = p_log; + p_ctrl->p_disp = p_disp; + p_ctrl->p_mad_pool = p_mad_pool; + p_ctrl->p_vendor = p_vendor; + p_ctrl->p_stats = p_stats; + p_ctrl->p_lock = p_lock; + p_ctrl->p_vl15 = p_vl15; + + p_ctrl->h_disp = cl_disp_register(p_disp, + CL_DISP_MSGID_NONE, NULL, NULL); + + if (p_ctrl->h_disp == CL_DISP_INVALID_HANDLE) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 3116: " + "Dispatcher registration failed\n"); + status = IB_INSUFFICIENT_RESOURCES; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_sm_mad_ctrl_bind(IN osm_sm_mad_ctrl_t * const p_ctrl, + IN const ib_net64_t port_guid) +{ + osm_bind_info_t bind_info; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_ctrl->p_log); + + if (p_ctrl->h_bind != OSM_BIND_INVALID_HANDLE) { + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3117: " + "Multiple binds not allowed\n"); + status = IB_ERROR; + goto Exit; + } + + bind_info.class_version = 1; + bind_info.is_report_processor = FALSE; + bind_info.is_responder = TRUE; + bind_info.is_trap_processor = TRUE; + bind_info.mad_class = IB_MCLASS_SUBN_DIR; + bind_info.port_guid = port_guid; + bind_info.recv_q_size = OSM_SM_DEFAULT_QP0_RCV_SIZE; + bind_info.send_q_size = OSM_SM_DEFAULT_QP0_SEND_SIZE; + + OSM_LOG(p_ctrl->p_log, OSM_LOG_VERBOSE, + "Binding to port 0x%" PRIx64 "\n", cl_ntoh64(port_guid)); + + p_ctrl->h_bind = osm_vendor_bind(p_ctrl->p_vendor, + &bind_info, + p_ctrl->p_mad_pool, + __osm_sm_mad_ctrl_rcv_callback, + __osm_sm_mad_ctrl_send_err_cb, p_ctrl); + + if (p_ctrl->h_bind == OSM_BIND_INVALID_HANDLE) { + status = IB_ERROR; + OSM_LOG(p_ctrl->p_log, OSM_LOG_ERROR, "ERR 3118: " + "Vendor specific bind failed\n"); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_ctrl->p_log); + return (status); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sm_state_mgr.c b/contrib/ofed/management/opensm/opensm/osm_sm_state_mgr.c new file mode 100644 index 000000000000..343a9e30423e --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sm_state_mgr.c @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sm_state_mgr_t. + * This file implements the SM State Manager object. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void osm_report_sm_state(osm_sm_t * sm) +{ + char buf[64]; + const char *state_str = osm_get_sm_mgr_state_str(sm->p_subn->sm_state); + + osm_log(sm->p_log, OSM_LOG_SYS, "Entering %s state\n", state_str); + snprintf(buf, sizeof(buf), "ENTERING SM %s STATE", state_str); + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, buf); +} + +/********************************************************************** + **********************************************************************/ +static void __osm_sm_state_mgr_send_master_sm_info_req(osm_sm_t * sm) +{ + osm_madw_context_t context; + const osm_port_t *p_port; + ib_api_status_t status; + + OSM_LOG_ENTER(sm->p_log); + + memset(&context, 0, sizeof(context)); + if (sm->p_subn->sm_state == IB_SMINFO_STATE_STANDBY) { + /* + * We are in STANDBY state - this means we need to poll on the master + * SM (according to master_guid) + * Send a query of SubnGet(SMInfo) to the subn master_sm_base_lid object. + */ + p_port = osm_get_port_by_guid(sm->p_subn, sm->master_sm_guid); + } else { + /* + * We are not in STANDBY - this means we are in MASTER state - so we need + * to poll on the SM that is saved in p_polling_sm under sm. + * Send a query of SubnGet(SMInfo) to that SM. + */ + p_port = sm->p_polling_sm->p_port; + } + if (p_port == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3203: " + "No port object for GUID 0x%016" PRIx64 "\n", + cl_ntoh64(sm->master_sm_guid)); + goto Exit; + } + + context.smi_context.port_guid = p_port->guid; + context.smi_context.set_method = FALSE; + + status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_port->p_physp), + IB_MAD_ATTR_SM_INFO, 0, CL_DISP_MSGID_NONE, + &context); + + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3204: " + "Failure requesting SMInfo (%s)\n", + ib_get_err_str(status)); + +Exit: + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void __osm_sm_state_mgr_start_polling(osm_sm_t * sm) +{ + uint32_t timeout = sm->p_subn->opt.sminfo_polling_timeout; + cl_status_t cl_status; + + OSM_LOG_ENTER(sm->p_log); + + /* + * Init the retry_number back to zero - need to restart counting + */ + sm->retry_number = 0; + + /* + * Send a SubnGet(SMInfo) query to the current (or new) master found. + */ + __osm_sm_state_mgr_send_master_sm_info_req(sm); + + /* + * Start a timer that will wake up every sminfo_polling_timeout milliseconds. + * The callback of the timer will send a SubnGet(SMInfo) to the Master SM + * and restart the timer + */ + cl_status = cl_timer_start(&sm->polling_timer, timeout); + if (cl_status != CL_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3210: " + "Failed to start timer\n"); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_sm_state_mgr_polling_callback(IN void *context) +{ + osm_sm_t *sm = context; + uint32_t timeout = sm->p_subn->opt.sminfo_polling_timeout; + cl_status_t cl_status; + + OSM_LOG_ENTER(sm->p_log); + + /* + * We can be here in one of two cases: + * 1. We are a STANDBY sm polling on the master SM. + * 2. We are a MASTER sm, waiting for a handover from a remote master sm. + * If we are not in one of these cases - don't need to restart the poller. + */ + if (!((sm->p_subn->sm_state == IB_SMINFO_STATE_MASTER && + sm->p_polling_sm != NULL) || + (sm->p_subn->sm_state == IB_SMINFO_STATE_STANDBY))) + goto Exit; + + /* + * If we are a STANDBY sm and the osm_exit_flag is set, then let's + * signal the subnet_up. This is relevant for the case of running only + * once. In that case - the program is stuck until this signal is + * received. In other cases - it is not relevant whether or not the + * signal is on - since we are currently in exit flow + */ + if (sm->p_subn->sm_state == IB_SMINFO_STATE_STANDBY && osm_exit_flag) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Signalling subnet_up_event\n"); + cl_event_signal(&sm->subnet_up_event); + goto Exit; + } + + /* + * Incr the retry number. + * If it reached the max_retry_number in the subnet opt - call + * osm_sm_state_mgr_process with signal OSM_SM_SIGNAL_POLLING_TIMEOUT + */ + sm->retry_number++; + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Retry number:%d\n", sm->retry_number); + + if (sm->retry_number >= sm->p_subn->opt.polling_retry_number) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Reached polling_retry_number value in retry_number. " + "Go to DISCOVERY state\n"); + osm_sm_state_mgr_process(sm, OSM_SM_SIGNAL_POLLING_TIMEOUT); + goto Exit; + } + + /* Send a SubnGet(SMInfo) request to the remote sm (depends on our state) */ + __osm_sm_state_mgr_send_master_sm_info_req(sm); + + /* restart the timer */ + cl_status = cl_timer_start(&sm->polling_timer, timeout); + if (cl_status != CL_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3211: " + "Failed to restart timer\n"); + +Exit: + OSM_LOG_EXIT(sm->p_log); + return; +} + +/********************************************************************** + **********************************************************************/ +static void __osm_sm_state_mgr_signal_error(osm_sm_t * sm, + IN const osm_sm_signal_t signal) +{ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3207: " + "Invalid signal %s in state %s\n", + osm_get_sm_mgr_signal_str(signal), + osm_get_sm_mgr_state_str(sm->p_subn->sm_state)); +} + +/********************************************************************** + **********************************************************************/ +void osm_sm_state_mgr_signal_master_is_alive(osm_sm_t * sm) +{ + OSM_LOG_ENTER(sm->p_log); + sm->retry_number = 0; + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t osm_sm_state_mgr_process(osm_sm_t * sm, + IN osm_sm_signal_t signal) +{ + ib_api_status_t status = IB_SUCCESS; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + /* + * The state lock prevents many race conditions from screwing + * up the state transition process. + */ + cl_spinlock_acquire(&sm->state_lock); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Received signal %s in state %s\n", + osm_get_sm_mgr_signal_str(signal), + osm_get_sm_mgr_state_str(sm->p_subn->sm_state)); + + switch (sm->p_subn->sm_state) { + case IB_SMINFO_STATE_DISCOVERING: + switch (signal) { + case OSM_SM_SIGNAL_DISCOVERY_COMPLETED: + /* + * Update the state of the SM to MASTER + */ + /* Turn on the first_time_master_sweep flag */ + sm->p_subn->first_time_master_sweep = TRUE; + sm->p_subn->sm_state = IB_SMINFO_STATE_MASTER; + osm_report_sm_state(sm); + /* + * Make sure to set the subnet master_sm_base_lid + * to the sm_base_lid value + */ + sm->p_subn->master_sm_base_lid = + sm->p_subn->sm_base_lid; + break; + case OSM_SM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED: + /* + * Finished all discovery actions - move to STANDBY + * start the polling + */ + sm->p_subn->sm_state = IB_SMINFO_STATE_STANDBY; + osm_report_sm_state(sm); + /* + * Since another SM is doing the LFT config - we should not + * ignore the results of it + */ + sm->p_subn->ignore_existing_lfts = FALSE; + + __osm_sm_state_mgr_start_polling(sm); + break; + case OSM_SM_SIGNAL_HANDOVER: + /* + * Do nothing. We will discover it later on. If we already discovered + * this SM, and got the HANDOVER - this means the remote SM is of + * lower priority. In this case we will stop polling it (since it is + * a lower priority SM in STANDBY state). + */ + break; + default: + __osm_sm_state_mgr_signal_error(sm, signal); + status = IB_INVALID_PARAMETER; + break; + } + break; + + case IB_SMINFO_STATE_STANDBY: + switch (signal) { + case OSM_SM_SIGNAL_POLLING_TIMEOUT: + case OSM_SM_SIGNAL_DISCOVER: + /* + * case 1: Polling timeout occured - this means that the Master SM + * is no longer alive. + * case 2: Got a signal to move to DISCOVERING + * Move to DISCOVERING state and start sweeping + */ + sm->p_subn->sm_state = IB_SMINFO_STATE_DISCOVERING; + osm_report_sm_state(sm); + sm->p_subn->coming_out_of_standby = TRUE; + osm_sm_signal(sm, OSM_SIGNAL_SWEEP); + break; + case OSM_SM_SIGNAL_DISABLE: + /* + * Update the state to NOT_ACTIVE + */ + sm->p_subn->sm_state = IB_SMINFO_STATE_NOTACTIVE; + osm_report_sm_state(sm); + osm_vendor_set_sm(sm->mad_ctrl.h_bind, FALSE); + break; + case OSM_SM_SIGNAL_HANDOVER: + /* + * Update the state to MASTER, and start sweeping + * OPTIONAL: send ACKNOWLEDGE + */ + /* Turn on the first_time_master_sweep flag */ + sm->p_subn->first_time_master_sweep = TRUE; + /* Turn on the force_heavy_sweep - we want a + * heavy sweep to occur on the first sweep of this SM. */ + sm->p_subn->force_heavy_sweep = TRUE; + + sm->p_subn->sm_state = IB_SMINFO_STATE_MASTER; + osm_report_sm_state(sm); + /* + * Make sure to set the subnet master_sm_base_lid + * to the sm_base_lid value + */ + sm->p_subn->master_sm_base_lid = + sm->p_subn->sm_base_lid; + sm->p_subn->coming_out_of_standby = TRUE; + osm_sm_signal(sm, OSM_SIGNAL_SWEEP); + break; + case OSM_SM_SIGNAL_ACKNOWLEDGE: + /* + * Do nothing - already moved to STANDBY + */ + break; + default: + __osm_sm_state_mgr_signal_error(sm, signal); + status = IB_INVALID_PARAMETER; + break; + } + break; + + case IB_SMINFO_STATE_NOTACTIVE: + switch (signal) { + case OSM_SM_SIGNAL_STANDBY: + /* + * Update the state to STANDBY + * start the polling + */ + sm->p_subn->sm_state = IB_SMINFO_STATE_STANDBY; + osm_report_sm_state(sm); + __osm_sm_state_mgr_start_polling(sm); + break; + default: + __osm_sm_state_mgr_signal_error(sm, signal); + status = IB_INVALID_PARAMETER; + break; + } + break; + + case IB_SMINFO_STATE_MASTER: + switch (signal) { + case OSM_SM_SIGNAL_POLLING_TIMEOUT: + /* + * we received a polling timeout - this means that we waited for + * a remote master sm to send us a handover, but didn't get it, and + * didn't get a response from that remote sm. + * We want to force a heavy sweep - hopefully this occurred because + * the remote sm died, and we'll find this out and configure the + * subnet after a heavy sweep. + * We also want to clear the p_polling_sm object - since we are + * done polling on that remote sm - we are sweeping again. + */ + case OSM_SM_SIGNAL_HANDOVER: + /* + * If we received a handover in a master state - then we want to + * force a heavy sweep. This means that either we are in a sweep + * currently - in this case - no change, or we are in idle state - + * since we recognized a master SM before - so we want to make a + * heavy sweep and reconfigure the new subnet. + * We also want to clear the p_polling_sm object - since we are + * done polling on that remote sm - we got a handover from it. + */ + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Forcing heavy sweep. " + "Received OSM_SM_SIGNAL_HANDOVER or OSM_SM_SIGNAL_POLLING_TIMEOUT\n"); + sm->p_polling_sm = NULL; + sm->p_subn->force_heavy_sweep = TRUE; + osm_sm_signal(sm, OSM_SIGNAL_SWEEP); + break; + case OSM_SM_SIGNAL_HANDOVER_SENT: + /* + * Just sent a HANDOVER signal - move to STANDBY + * start the polling + */ + sm->p_subn->sm_state = IB_SMINFO_STATE_STANDBY; + osm_report_sm_state(sm); + __osm_sm_state_mgr_start_polling(sm); + break; + case OSM_SM_SIGNAL_WAIT_FOR_HANDOVER: + /* + * We found a remote master SM, and we are waiting for it + * to handover the mastership to us. Need to start polling + * on that SM, to make sure it is alive, if it isn't - then + * we should move back to discovering, since something must + * have happened to it. + */ + __osm_sm_state_mgr_start_polling(sm); + break; + case OSM_SM_SIGNAL_DISCOVER: + sm->p_subn->sm_state = IB_SMINFO_STATE_DISCOVERING; + osm_report_sm_state(sm); + break; + default: + __osm_sm_state_mgr_signal_error(sm, signal); + status = IB_INVALID_PARAMETER; + break; + } + break; + + default: + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3208: " + "Invalid state %s\n", + osm_get_sm_mgr_state_str(sm->p_subn->sm_state)); + + } + + cl_spinlock_release(&sm->state_lock); + + OSM_LOG_EXIT(sm->p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t osm_sm_state_mgr_check_legality(osm_sm_t * sm, + IN osm_sm_signal_t signal) +{ + ib_api_status_t status = IB_SUCCESS; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + /* + * The state lock prevents many race conditions from screwing + * up the state transition process. + */ + cl_spinlock_acquire(&sm->state_lock); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Received signal %s in state %s\n", + osm_get_sm_mgr_signal_str(signal), + osm_get_sm_mgr_state_str(sm->p_subn->sm_state)); + + switch (sm->p_subn->sm_state) { + case IB_SMINFO_STATE_DISCOVERING: + switch (signal) { + case OSM_SM_SIGNAL_DISCOVERY_COMPLETED: + case OSM_SM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED: + case OSM_SM_SIGNAL_HANDOVER: + status = IB_SUCCESS; + break; + default: + __osm_sm_state_mgr_signal_error(sm, signal); + status = IB_INVALID_PARAMETER; + break; + } + break; + + case IB_SMINFO_STATE_STANDBY: + switch (signal) { + case OSM_SM_SIGNAL_POLLING_TIMEOUT: + case OSM_SM_SIGNAL_DISCOVER: + case OSM_SM_SIGNAL_DISABLE: + case OSM_SM_SIGNAL_HANDOVER: + case OSM_SM_SIGNAL_ACKNOWLEDGE: + status = IB_SUCCESS; + break; + default: + __osm_sm_state_mgr_signal_error(sm, signal); + status = IB_INVALID_PARAMETER; + break; + } + break; + + case IB_SMINFO_STATE_NOTACTIVE: + switch (signal) { + case OSM_SM_SIGNAL_STANDBY: + status = IB_SUCCESS; + break; + default: + __osm_sm_state_mgr_signal_error(sm, signal); + status = IB_INVALID_PARAMETER; + break; + } + break; + + case IB_SMINFO_STATE_MASTER: + switch (signal) { + case OSM_SM_SIGNAL_HANDOVER: + case OSM_SM_SIGNAL_HANDOVER_SENT: + status = IB_SUCCESS; + break; + default: + __osm_sm_state_mgr_signal_error(sm, signal); + status = IB_INVALID_PARAMETER; + break; + } + break; + + default: + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3209: " + "Invalid state %s\n", + osm_get_sm_mgr_state_str(sm->p_subn->sm_state)); + status = IB_INVALID_PARAMETER; + + } + + cl_spinlock_release(&sm->state_lock); + + OSM_LOG_EXIT(sm->p_log); + return (status); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sminfo_rcv.c b/contrib/ofed/management/opensm/opensm/osm_sminfo_rcv.c new file mode 100644 index 000000000000..98c19946ea00 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sminfo_rcv.c @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_sminfo_rcv_t. + * This object represents the SMInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + Return TRUE if the remote sm given (by ib_sm_info_t) is higher, + return FALSE otherwise. + By higher - we mean: SM with higher priority or with same priority + and lower GUID. +**********************************************************************/ +static inline boolean_t +__osm_sminfo_rcv_remote_sm_is_higher(IN osm_sm_t * sm, + IN const ib_sm_info_t * p_remote_smi) +{ + return (osm_sm_is_greater_than(ib_sminfo_get_priority(p_remote_smi), + p_remote_smi->guid, + sm->p_subn->opt.sm_priority, + sm->p_subn->sm_port_guid)); + +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sminfo_rcv_process_get_request(IN osm_sm_t * sm, + IN const osm_madw_t * const p_madw) +{ + uint8_t payload[IB_SMP_DATA_SIZE]; + ib_smp_t *p_smp; + ib_sm_info_t *p_smi = (ib_sm_info_t *) payload; + ib_api_status_t status; + ib_sm_info_t *p_remote_smi; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + /* No real need to grab the lock for this function. */ + memset(payload, 0, sizeof(payload)); + + p_smp = osm_madw_get_smp_ptr(p_madw); + + CL_ASSERT(p_smp->method == IB_MAD_METHOD_GET); + + p_smi->guid = sm->p_subn->sm_port_guid; + p_smi->act_count = cl_hton32(sm->p_subn->p_osm->stats.qp0_mads_sent); + p_smi->pri_state = (uint8_t) (sm->p_subn->sm_state | + sm->p_subn->opt.sm_priority << 4); + /* + p.840 line 20 - Return 0 for the SM key unless we authenticate the + requester as the master SM. + */ + p_remote_smi = ib_smp_get_payload_ptr(osm_madw_get_smp_ptr(p_madw)); + if (ib_sminfo_get_state(p_remote_smi) == IB_SMINFO_STATE_MASTER) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Responding to master SM with real sm_key\n"); + p_smi->sm_key = sm->p_subn->opt.sm_key; + } else { + /* The requester is not authenticated as master - set sm_key to zero. */ + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Responding to SM not master with zero sm_key\n"); + p_smi->sm_key = 0; + } + + status = osm_resp_send(sm, p_madw, 0, payload); + if (status != IB_SUCCESS) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F02: " + "Error sending response (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + * Check if the p_smp received is legal. + * Current checks: + * MADHeader:AttributeModifier of ACKNOWLEDGE that was not sent by a + * Standby SM. + * MADHeader:AttributeModifiers of HANDOVER/DISABLE/STANDBY/DISCOVER + * that was not sent by a Master SM. + * FUTURE - TO DO: + * Check that the SM_Key matches. + **********************************************************************/ +static ib_api_status_t +__osm_sminfo_rcv_check_set_req_legality(IN const ib_smp_t * const p_smp) +{ + ib_sm_info_t *p_smi; + + p_smi = ib_smp_get_payload_ptr(p_smp); + + if (p_smp->attr_mod == IB_SMINFO_ATTR_MOD_ACKNOWLEDGE) { + if (ib_sminfo_get_state(p_smi) == IB_SMINFO_STATE_STANDBY) + return (IB_SUCCESS); + } else if (p_smp->attr_mod == IB_SMINFO_ATTR_MOD_HANDOVER || + p_smp->attr_mod == IB_SMINFO_ATTR_MOD_DISABLE || + p_smp->attr_mod == IB_SMINFO_ATTR_MOD_STANDBY || + p_smp->attr_mod == IB_SMINFO_ATTR_MOD_DISCOVER) { + if (ib_sminfo_get_state(p_smi) == IB_SMINFO_STATE_MASTER) + return (IB_SUCCESS); + } + + return (IB_INVALID_PARAMETER); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sminfo_rcv_process_set_request(IN osm_sm_t * sm, + IN const osm_madw_t * const p_madw) +{ + uint8_t payload[IB_SMP_DATA_SIZE]; + ib_smp_t *p_smp; + ib_sm_info_t *p_smi = (ib_sm_info_t *) payload; + ib_sm_info_t *sm_smi; + ib_api_status_t status; + osm_sm_signal_t sm_signal; + ib_sm_info_t *p_remote_smi; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + memset(payload, 0, sizeof(payload)); + + p_smp = osm_madw_get_smp_ptr(p_madw); + sm_smi = ib_smp_get_payload_ptr(p_smp); + + if (p_smp->method != IB_MAD_METHOD_SET) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F03: " + "Unsupported method 0x%X\n", p_smp->method); + goto Exit; + } + + CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); + + p_smi->guid = sm->p_subn->sm_port_guid; + p_smi->act_count = cl_hton32(sm->p_subn->p_osm->stats.qp0_mads_sent); + p_smi->pri_state = (uint8_t) (sm->p_subn->sm_state | + sm->p_subn->opt.sm_priority << 4); + /* + p.840 line 20 - Return 0 for the SM key unless we authenticate the + requester as the master SM. + */ + p_remote_smi = ib_smp_get_payload_ptr(osm_madw_get_smp_ptr(p_madw)); + if (ib_sminfo_get_state(p_remote_smi) == IB_SMINFO_STATE_MASTER) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Responding to master SM with real sm_key\n"); + p_smi->sm_key = sm->p_subn->opt.sm_key; + } else { + /* The requester is not authenticated as master - set sm_key to zero. */ + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Responding to SM not master with zero sm_key\n"); + p_smi->sm_key = 0; + } + + /* Check the legality of the packet */ + status = __osm_sminfo_rcv_check_set_req_legality(p_smp); + if (status != IB_SUCCESS) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F04: " + "Check legality failed. AttributeModifier:0x%X RemoteState:%s\n", + p_smp->attr_mod, + osm_get_sm_mgr_state_str(ib_sminfo_get_state(sm_smi))); + status = osm_resp_send(sm, p_madw, 7, payload); + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F05: " + "Error sending response (%s)\n", + ib_get_err_str(status)); + CL_PLOCK_RELEASE(sm->p_lock); + goto Exit; + } + + /* translate from IB_SMINFO_ATTR to OSM_SM_SIGNAL */ + switch (p_smp->attr_mod) { + case IB_SMINFO_ATTR_MOD_HANDOVER: + sm_signal = OSM_SM_SIGNAL_HANDOVER; + break; + case IB_SMINFO_ATTR_MOD_ACKNOWLEDGE: + sm_signal = OSM_SM_SIGNAL_ACKNOWLEDGE; + break; + case IB_SMINFO_ATTR_MOD_DISABLE: + sm_signal = OSM_SM_SIGNAL_DISABLE; + break; + case IB_SMINFO_ATTR_MOD_STANDBY: + sm_signal = OSM_SM_SIGNAL_STANDBY; + break; + case IB_SMINFO_ATTR_MOD_DISCOVER: + sm_signal = OSM_SM_SIGNAL_DISCOVER; + break; + default: + /* + This code shouldn't be reached - checked in the + check legality + */ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F06: " + "THIS CODE SHOULD NOT BE REACHED!!\n"); + CL_PLOCK_RELEASE(sm->p_lock); + goto Exit; + } + + /* check legality of the needed transition in the SM state machine */ + status = osm_sm_state_mgr_check_legality(sm, sm_signal); + if (status != IB_SUCCESS) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F07: " + "Failed check of legality of needed SM transition. AttributeModifier:0x%X RemoteState:%s\n", + p_smp->attr_mod, + osm_get_sm_mgr_state_str(ib_sminfo_get_state(sm_smi))); + status = osm_resp_send(sm, p_madw, 7, payload); + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F08: " + "Error sending response (%s)\n", + ib_get_err_str(status)); + CL_PLOCK_RELEASE(sm->p_lock); + goto Exit; + } + + /* the SubnSet(SMInfo) command is ok. Send a response. */ + status = osm_resp_send(sm, p_madw, 0, payload); + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F09: " + "Error sending response (%s)\n", + ib_get_err_str(status)); + + /* it is a legal packet - act according to it */ + + /* if the AttributeModifier is STANDBY - need to save on the sm in */ + /* the master_sm_guid variable - the guid of the current master. */ + if (p_smp->attr_mod == IB_SMINFO_ATTR_MOD_STANDBY) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Received a STANDBY signal. Updating " + "sm_state_mgr master_guid: 0x%016" PRIx64 "\n", + cl_ntoh64(sm_smi->guid)); + sm->master_sm_guid = sm_smi->guid; + } + + CL_PLOCK_RELEASE(sm->p_lock); + status = osm_sm_state_mgr_process(sm, sm_signal); + + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F10: " + "Error in SM state transition (%s)\n", + ib_get_err_str(status)); + +Exit: + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +static osm_signal_t +__osm_sminfo_rcv_process_get_sm(IN osm_sm_t * sm, + IN const osm_remote_sm_t * const p_sm, + boolean_t light_sweep) +{ + const ib_sm_info_t *p_smi; + + OSM_LOG_ENTER(sm->p_log); + + p_smi = &p_sm->smi; + + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Detected SM 0x%016" PRIx64 " in state %u\n", + cl_ntoh64(p_smi->guid), ib_sminfo_get_state(p_smi)); + + /* Check the state of this SM vs. our own. */ + switch (sm->p_subn->sm_state) { + case IB_SMINFO_STATE_NOTACTIVE: + break; + + case IB_SMINFO_STATE_DISCOVERING: + switch (ib_sminfo_get_state(p_smi)) { + case IB_SMINFO_STATE_NOTACTIVE: + break; + case IB_SMINFO_STATE_MASTER: + sm->master_sm_found = 1; + /* save on the sm the guid of the current master. */ + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Found master SM. Updating sm_state_mgr master_guid: 0x%016" + PRIx64 "\n", cl_ntoh64(p_sm->p_port->guid)); + sm->master_sm_guid = p_sm->p_port->guid; + break; + case IB_SMINFO_STATE_DISCOVERING: + case IB_SMINFO_STATE_STANDBY: + if (__osm_sminfo_rcv_remote_sm_is_higher(sm, p_smi) + == TRUE) { + /* the remote is a higher sm - need to stop sweeping */ + sm->master_sm_found = 1; + /* save on the sm the guid of the higher SM we found - */ + /* we will poll it - as long as it lives - we should be in Standby. */ + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Found higher SM. Updating sm_state_mgr master_guid:" + " 0x%016" PRIx64 "\n", + cl_ntoh64(p_sm->p_port->guid)); + sm->master_sm_guid = p_sm->p_port->guid; + } + break; + default: + break; + } + break; + + case IB_SMINFO_STATE_STANDBY: + /* if the guid of the SM that sent us this response is equal to the */ + /* p_sm_mgr->master_guid - then this is a signal that the polling */ + switch (ib_sminfo_get_state(p_smi)) { + case IB_SMINFO_STATE_MASTER: + /* This means the master is alive */ + /* Signal that to the SM state mgr */ + osm_sm_state_mgr_signal_master_is_alive(sm); + break; + case IB_SMINFO_STATE_STANDBY: + /* This should be the response from the sm we are polling. */ + /* If it is - then signal master is alive */ + if (sm->master_sm_guid == p_sm->p_port->guid) { + /* Make sure that it is an SM with higher priority than us. + If we started polling it when it was master, and it moved + to standby - then it might be with a lower priority than + us - and then we don't want to continue polling it. */ + if (__osm_sminfo_rcv_remote_sm_is_higher + (sm, p_smi) == TRUE) + osm_sm_state_mgr_signal_master_is_alive(sm); + } + break; + default: + /* any other state - do nothing */ + break; + } + break; + + case IB_SMINFO_STATE_MASTER: + switch (ib_sminfo_get_state(p_smi)) { + case IB_SMINFO_STATE_MASTER: + /* If this is a response due to our polling, this means that we are + waiting for a handover from this SM, and it is still alive - + signal that. */ + if (sm->p_polling_sm) + osm_sm_state_mgr_signal_master_is_alive(sm); + else { + /* This is a response we got while sweeping the subnet. + We will handle a case of handover needed later on, when the sweep + is done and all SMs are recongnized. */ + } + break; + case IB_SMINFO_STATE_STANDBY: + if (light_sweep && + __osm_sminfo_rcv_remote_sm_is_higher(sm, p_smi)) + sm->p_subn->force_heavy_sweep = TRUE; + break; + default: + /* any other state - do nothing */ + break; + } + break; + + default: + break; + } + + OSM_LOG_EXIT(sm->p_log); + return 0; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sminfo_rcv_process_get_response(IN osm_sm_t * sm, + IN const osm_madw_t * const p_madw) +{ + const ib_smp_t *p_smp; + const ib_sm_info_t *p_smi; + cl_qmap_t *p_sm_tbl; + osm_port_t *p_port; + ib_net64_t port_guid; + osm_remote_sm_t *p_sm; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + + if (p_smp->method != IB_MAD_METHOD_GET_RESP) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F11: " + "Unsupported method 0x%X\n", p_smp->method); + goto Exit; + } + + p_smi = ib_smp_get_payload_ptr(p_smp); + p_sm_tbl = &sm->p_subn->sm_guid_tbl; + port_guid = p_smi->guid; + + osm_dump_sm_info(sm->p_log, p_smi, OSM_LOG_DEBUG); + + /* Check that the sm_key of the found SM is the same as ours, + or is zero. If not - OpenSM cannot continue with configuration!. */ + if (p_smi->sm_key != 0 && p_smi->sm_key != sm->p_subn->opt.sm_key) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F18: " + "Got SM with sm_key that doesn't match our " + "local key. Exiting\n"); + osm_log(sm->p_log, OSM_LOG_SYS, + "Found remote SM with non-matching sm_key. Exiting\n"); + osm_exit_flag = TRUE; + goto Exit; + } + + /* Determine if we already have another SM object for this SM. */ + CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); + + p_port = osm_get_port_by_guid(sm->p_subn, port_guid); + if (!p_port) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F12: " + "No port object for this SM\n"); + goto _unlock_and_exit; + } + + if (osm_port_get_guid(p_port) != p_smi->guid) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F13: " + "Bogus SM port GUID\n\t\t\t\tExpected 0x%016" PRIx64 + ", Received 0x%016" PRIx64 "\n", + cl_ntoh64(osm_port_get_guid(p_port)), + cl_ntoh64(p_smi->guid)); + goto _unlock_and_exit; + } + + if (port_guid == sm->p_subn->sm_port_guid) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Self query response received - SM port 0x%016" PRIx64 + "\n", cl_ntoh64(port_guid)); + goto _unlock_and_exit; + } + + p_sm = (osm_remote_sm_t *) cl_qmap_get(p_sm_tbl, port_guid); + if (p_sm == (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl)) { + p_sm = malloc(sizeof(*p_sm)); + if (p_sm == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F14: " + "Unable to allocate SM object\n"); + goto _unlock_and_exit; + } + + osm_remote_sm_init(p_sm, p_port, p_smi); + + cl_qmap_insert(p_sm_tbl, port_guid, &p_sm->map_item); + } else + /* We already know this SM. Update the SMInfo attribute. */ + p_sm->smi = *p_smi; + + __osm_sminfo_rcv_process_get_sm(sm, p_sm, + osm_madw_get_smi_context_ptr(p_madw)->light_sweep); + +_unlock_and_exit: + CL_PLOCK_RELEASE(sm->p_lock); + +Exit: + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_sminfo_rcv_process_set_response(IN osm_sm_t * sm, + IN const osm_madw_t * const p_madw) +{ + const ib_smp_t *p_smp; + const ib_sm_info_t *p_smi; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + + if (p_smp->method != IB_MAD_METHOD_GET_RESP) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F16: " + "Unsupported method 0x%X\n", p_smp->method); + goto Exit; + } + + p_smi = ib_smp_get_payload_ptr(p_smp); + osm_dump_sm_info(sm->p_log, p_smi, OSM_LOG_DEBUG); + + /* Check the AttributeModifier */ + if (p_smp->attr_mod != IB_SMINFO_ATTR_MOD_HANDOVER) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F17: " + "Unsupported attribute modifier 0x%X\n", + p_smp->attr_mod); + goto Exit; + } + + /* This is a response on a HANDOVER request - Nothing to do. */ + +Exit: + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_sminfo_rcv_process(IN void *context, IN void *data) +{ + osm_sm_t *sm = context; + osm_madw_t *p_madw = data; + ib_smp_t *p_smp; + osm_smi_context_t *p_smi_context; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + + /* Determine if this is a request for our own SMInfo or if + this is a response to our request for another SM's SMInfo. */ + if (ib_smp_is_response(p_smp)) { + const ib_sm_info_t *p_smi = ib_smp_get_payload_ptr(p_smp); + + /* Get the context - to see if this is a response to a Get or Set method */ + p_smi_context = osm_madw_get_smi_context_ptr(p_madw); + + /* Verify that response is from expected port and there is + no port moving issue. */ + if (p_smi_context->port_guid != p_smi->guid) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 2F19: " + "Unexpected SM port GUID in response" + "\n\t\t\t\tExpected 0x%016" PRIx64 + ", Received 0x%016" PRIx64 "\n", + cl_ntoh64(p_smi_context->port_guid), + cl_ntoh64(p_smi->guid)); + goto Exit; + } + + if (p_smi_context->set_method == FALSE) + /* this is a response to a Get method */ + __osm_sminfo_rcv_process_get_response(sm, p_madw); + else + /* this is a response to a Set method */ + __osm_sminfo_rcv_process_set_response(sm, p_madw); + } else if (p_smp->method == IB_MAD_METHOD_GET) + /* This is a SubnGet request */ + __osm_sminfo_rcv_process_get_request(sm, p_madw); + else + /* This should be a SubnSet request */ + __osm_sminfo_rcv_process_set_request(sm, p_madw); + +Exit: + OSM_LOG_EXIT(sm->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_state_mgr.c b/contrib/ofed/management/opensm/opensm/osm_state_mgr.c new file mode 100644 index 000000000000..625e026faa75 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_state_mgr.c @@ -0,0 +1,1396 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_state_mgr_t. + * This file implements the State Manager object. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void osm_drop_mgr_process(IN osm_sm_t * sm); +extern osm_signal_t osm_qos_setup(IN osm_opensm_t * p_osm); +extern osm_signal_t osm_pkey_mgr_process(IN osm_opensm_t * p_osm); +extern osm_signal_t osm_mcast_mgr_process(IN osm_sm_t * sm); +extern osm_signal_t osm_mcast_mgr_process_mgroups(IN osm_sm_t * sm); +extern osm_signal_t osm_link_mgr_process(IN osm_sm_t * sm, IN uint8_t state); + +/********************************************************************** + **********************************************************************/ +static void __osm_state_mgr_up_msg(IN const osm_sm_t * sm) +{ + /* + * This message should be written only once - when the + * SM moves to Master state and the subnet is up for + * the first time. + */ + osm_log(sm->p_log, sm->p_subn->first_time_master_sweep ? + OSM_LOG_SYS : OSM_LOG_INFO, "SUBNET UP\n"); + + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, + sm->p_subn->opt.sweep_interval ? + "SUBNET UP" : "SUBNET UP (sweep disabled)"); +} + +/********************************************************************** + **********************************************************************/ +static void __osm_state_mgr_reset_node_count(IN cl_map_item_t * + const p_map_item, IN void *context) +{ + osm_node_t *p_node = (osm_node_t *) p_map_item; + + p_node->discovery_count = 0; +} + +/********************************************************************** + **********************************************************************/ +static void __osm_state_mgr_reset_port_count(IN cl_map_item_t * + const p_map_item, IN void *context) +{ + osm_port_t *p_port = (osm_port_t *) p_map_item; + + p_port->discovery_count = 0; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_state_mgr_reset_switch_count(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + osm_switch_t *p_sw = (osm_switch_t *) p_map_item; + + p_sw->discovery_count = 0; + p_sw->need_update = 1; +} + +/********************************************************************** + **********************************************************************/ +static void __osm_state_mgr_get_sw_info(IN cl_map_item_t * const p_object, + IN void *context) +{ + osm_node_t *p_node; + osm_dr_path_t *p_dr_path; + osm_madw_context_t mad_context; + osm_switch_t *const p_sw = (osm_switch_t *) p_object; + osm_sm_t *sm = context; + ib_api_status_t status; + + OSM_LOG_ENTER(sm->p_log); + + p_node = p_sw->p_node; + p_dr_path = osm_physp_get_dr_path_ptr(osm_node_get_physp_ptr(p_node, 0)); + + memset(&mad_context, 0, sizeof(mad_context)); + + mad_context.si_context.node_guid = osm_node_get_node_guid(p_node); + mad_context.si_context.set_method = FALSE; + mad_context.si_context.light_sweep = TRUE; + + status = osm_req_get(sm, p_dr_path, IB_MAD_ATTR_SWITCH_INFO, 0, + OSM_MSG_LIGHT_SWEEP_FAIL, &mad_context); + + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3304: " + "Request for SwitchInfo failed\n"); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + Initiate a remote port info request for the given physical port + **********************************************************************/ +static void +__osm_state_mgr_get_remote_port_info(IN osm_sm_t * sm, + IN osm_physp_t * const p_physp) +{ + osm_dr_path_t *p_dr_path; + osm_dr_path_t rem_node_dr_path; + osm_madw_context_t mad_context; + ib_api_status_t status; + + OSM_LOG_ENTER(sm->p_log); + + /* generate a dr path leaving on the physp to the remote node */ + p_dr_path = osm_physp_get_dr_path_ptr(p_physp); + memcpy(&rem_node_dr_path, p_dr_path, sizeof(osm_dr_path_t)); + osm_dr_path_extend(&rem_node_dr_path, osm_physp_get_port_num(p_physp)); + + memset(&mad_context, 0, sizeof(mad_context)); + + mad_context.pi_context.node_guid = + osm_node_get_node_guid(osm_physp_get_node_ptr(p_physp)); + mad_context.pi_context.port_guid = p_physp->port_guid; + mad_context.pi_context.set_method = FALSE; + mad_context.pi_context.light_sweep = TRUE; + mad_context.pi_context.active_transition = FALSE; + + /* note that with some negative logic - if the query failed it means that + * there is no point in going to heavy sweep */ + status = osm_req_get(sm, &rem_node_dr_path, + IB_MAD_ATTR_PORT_INFO, 0, CL_DISP_MSGID_NONE, + &mad_context); + + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 332E: " + "Request for PortInfo failed\n"); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + Initiates a thorough sweep of the subnet. + Used when there is suspicion that something on the subnet has changed. +**********************************************************************/ +static ib_api_status_t __osm_state_mgr_sweep_hop_0(IN osm_sm_t * sm) +{ + ib_api_status_t status; + osm_dr_path_t dr_path; + osm_bind_handle_t h_bind; + uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX]; + + OSM_LOG_ENTER(sm->p_log); + + memset(path_array, 0, sizeof(path_array)); + + /* + * First, get the bind handle. + */ + h_bind = osm_sm_mad_ctrl_get_bind_handle(&sm->mad_ctrl); + if (h_bind != OSM_BIND_INVALID_HANDLE) { + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, + "INITIATING HEAVY SWEEP"); + /* + * Start the sweep by clearing the port counts, then + * get our own NodeInfo at 0 hops. + */ + CL_PLOCK_ACQUIRE(sm->p_lock); + + cl_qmap_apply_func(&sm->p_subn->node_guid_tbl, + __osm_state_mgr_reset_node_count, sm); + + cl_qmap_apply_func(&sm->p_subn->port_guid_tbl, + __osm_state_mgr_reset_port_count, sm); + + cl_qmap_apply_func(&sm->p_subn->sw_guid_tbl, + __osm_state_mgr_reset_switch_count, sm); + + /* Set the in_sweep_hop_0 flag in subn to be TRUE. + * This will indicate the sweeping not to continue beyond the + * the current node. + * This is relevant for the case of SM on switch, since in the + * switch info we need to signal somehow not to continue + * the sweeping. */ + sm->p_subn->in_sweep_hop_0 = TRUE; + + CL_PLOCK_RELEASE(sm->p_lock); + + osm_dr_path_init(&dr_path, h_bind, 0, path_array); + status = osm_req_get(sm, &dr_path, IB_MAD_ATTR_NODE_INFO, 0, + CL_DISP_MSGID_NONE, NULL); + + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3305: " + "Request for NodeInfo failed\n"); + } else { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "No bound ports. Deferring sweep...\n"); + status = IB_INVALID_STATE; + } + + OSM_LOG_EXIT(sm->p_log); + return (status); +} + +/********************************************************************** + Clear out all existing port lid assignments +**********************************************************************/ +static ib_api_status_t __osm_state_mgr_clean_known_lids(IN osm_sm_t * sm) +{ + ib_api_status_t status = IB_SUCCESS; + cl_ptr_vector_t *p_vec = &(sm->p_subn->port_lid_tbl); + uint32_t i; + + OSM_LOG_ENTER(sm->p_log); + + /* we need a lock here! */ + CL_PLOCK_ACQUIRE(sm->p_lock); + + for (i = 0; i < cl_ptr_vector_get_size(p_vec); i++) + cl_ptr_vector_set(p_vec, i, NULL); + + CL_PLOCK_RELEASE(sm->p_lock); + + OSM_LOG_EXIT(sm->p_log); + return (status); +} + +/********************************************************************** + Notifies the transport layer that the local LID has changed, + which give it a chance to update address vectors, etc.. +**********************************************************************/ +static ib_api_status_t __osm_state_mgr_notify_lid_change(IN osm_sm_t * sm) +{ + ib_api_status_t status; + osm_bind_handle_t h_bind; + + OSM_LOG_ENTER(sm->p_log); + + /* + * First, get the bind handle. + */ + h_bind = osm_sm_mad_ctrl_get_bind_handle(&sm->mad_ctrl); + if (h_bind == OSM_BIND_INVALID_HANDLE) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3306: " + "No bound ports\n"); + status = IB_ERROR; + goto Exit; + } + + /* + * Notify the transport layer that we changed the local LID. + */ + status = osm_vendor_local_lid_change(h_bind); + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3307: " + "Vendor LID update failed (%s)\n", + ib_get_err_str(status)); + +Exit: + OSM_LOG_EXIT(sm->p_log); + return (status); +} + +/********************************************************************** + Returns true if the SM port is down. + The SM's port object must exist in the port_guid table. +**********************************************************************/ +static boolean_t __osm_state_mgr_is_sm_port_down(IN osm_sm_t * sm) +{ + ib_net64_t port_guid; + osm_port_t *p_port; + osm_physp_t *p_physp; + uint8_t state; + + OSM_LOG_ENTER(sm->p_log); + + port_guid = sm->p_subn->sm_port_guid; + + /* + * If we don't know our own port guid yet, assume the port is down. + */ + if (port_guid == 0) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3308: " + "SM port GUID unknown\n"); + state = IB_LINK_DOWN; + goto Exit; + } + + CL_ASSERT(port_guid); + + CL_PLOCK_ACQUIRE(sm->p_lock); + p_port = osm_get_port_by_guid(sm->p_subn, port_guid); + if (!p_port) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3309: " + "SM port with GUID:%016" PRIx64 " is unknown\n", + cl_ntoh64(port_guid)); + state = IB_LINK_DOWN; + CL_PLOCK_RELEASE(sm->p_lock); + goto Exit; + } + + p_physp = p_port->p_physp; + + CL_ASSERT(p_physp); + + state = osm_physp_get_port_state(p_physp); + CL_PLOCK_RELEASE(sm->p_lock); + +Exit: + OSM_LOG_EXIT(sm->p_log); + return (state == IB_LINK_DOWN); +} + +/********************************************************************** + Sweeps the node 1 hop away. + This sets off a "chain reaction" that causes discovery of the subnet. + Used when there is suspicion that something on the subnet has changed. +**********************************************************************/ +static ib_api_status_t __osm_state_mgr_sweep_hop_1(IN osm_sm_t * sm) +{ + ib_api_status_t status = IB_SUCCESS; + osm_bind_handle_t h_bind; + osm_madw_context_t context; + osm_node_t *p_node; + osm_port_t *p_port; + osm_physp_t *p_physp; + osm_dr_path_t *p_dr_path; + osm_dr_path_t hop_1_path; + ib_net64_t port_guid; + uint8_t port_num; + uint8_t path_array[IB_SUBNET_PATH_HOPS_MAX]; + uint8_t num_ports; + osm_physp_t *p_ext_physp; + + OSM_LOG_ENTER(sm->p_log); + + /* + * First, get our own port and node objects. + */ + port_guid = sm->p_subn->sm_port_guid; + + CL_ASSERT(port_guid); + + /* Set the in_sweep_hop_0 flag in subn to be FALSE. + * This will indicate the sweeping to continue beyond the + * the current node. + * This is relevant for the case of SM on switch, since in the + * switch info we need to signal that the sweeping should + * continue through the switch. */ + sm->p_subn->in_sweep_hop_0 = FALSE; + + p_port = osm_get_port_by_guid(sm->p_subn, port_guid); + if (!p_port) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3310: " + "No SM port object\n"); + status = IB_ERROR; + goto Exit; + } + + p_node = p_port->p_node; + CL_ASSERT(p_node); + + port_num = ib_node_info_get_local_port_num(&p_node->node_info); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Probing hop 1 on local port %u\n", port_num); + + p_physp = osm_node_get_physp_ptr(p_node, port_num); + + CL_ASSERT(p_physp); + + p_dr_path = osm_physp_get_dr_path_ptr(p_physp); + h_bind = osm_dr_path_get_bind_handle(p_dr_path); + + CL_ASSERT(h_bind != OSM_BIND_INVALID_HANDLE); + + memset(path_array, 0, sizeof(path_array)); + /* the hop_1 operations depend on the type of our node. + * Currently - legal nodes that can host SM are SW and CA */ + switch (osm_node_get_type(p_node)) { + case IB_NODE_TYPE_CA: + case IB_NODE_TYPE_ROUTER: + memset(&context, 0, sizeof(context)); + context.ni_context.node_guid = osm_node_get_node_guid(p_node); + context.ni_context.port_num = port_num; + + path_array[1] = port_num; + + osm_dr_path_init(&hop_1_path, h_bind, 1, path_array); + status = osm_req_get(sm, &hop_1_path, IB_MAD_ATTR_NODE_INFO, 0, + CL_DISP_MSGID_NONE, &context); + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3311: " + "Request for NodeInfo failed\n"); + break; + + case IB_NODE_TYPE_SWITCH: + /* Need to go over all the ports of the switch, and send a node_info + * from them. This doesn't include the port 0 of the switch, which + * hosts the SM. + * Note: We'll send another switchInfo on port 0, since if no ports + * are connected, we still want to get some response, and have the + * subnet come up. + */ + num_ports = osm_node_get_num_physp(p_node); + for (port_num = 0; port_num < num_ports; port_num++) { + /* go through the port only if the port is not DOWN */ + p_ext_physp = osm_node_get_physp_ptr(p_node, port_num); + if (p_ext_physp && ib_port_info_get_port_state + (&(p_ext_physp->port_info)) > IB_LINK_DOWN) { + memset(&context, 0, sizeof(context)); + context.ni_context.node_guid = + osm_node_get_node_guid(p_node); + context.ni_context.port_num = port_num; + + path_array[1] = port_num; + osm_dr_path_init(&hop_1_path, h_bind, 1, + path_array); + status = osm_req_get(sm, &hop_1_path, + IB_MAD_ATTR_NODE_INFO, 0, + CL_DISP_MSGID_NONE, + &context); + + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3312: " + "Request for NodeInfo failed\n"); + } + } + break; + + default: + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 3313: Unknown node type %d (%s)\n", + osm_node_get_type(p_node), p_node->print_desc); + } + +Exit: + OSM_LOG_EXIT(sm->p_log); + return (status); +} + +static void query_sm_info(cl_map_item_t *item, void *cxt) +{ + osm_madw_context_t context; + osm_remote_sm_t *r_sm = cl_item_obj(item, r_sm, map_item); + osm_sm_t *sm = cxt; + ib_api_status_t ret; + + context.smi_context.port_guid = r_sm->p_port->guid; + context.smi_context.set_method = FALSE; + context.smi_context.light_sweep = TRUE; + + ret = osm_req_get(sm, osm_physp_get_dr_path_ptr(r_sm->p_port->p_physp), + IB_MAD_ATTR_SM_INFO, 0, CL_DISP_MSGID_NONE, &context); + if (ret != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3314: " + "Failure requesting SMInfo (%s)\n", + ib_get_err_str(ret)); +} + +/********************************************************************** + During a light sweep check each node to see if the node descriptor is valid + if not issue a ND query. +**********************************************************************/ +static void __osm_state_mgr_get_node_desc(IN cl_map_item_t * const p_object, + IN void *context) +{ + osm_madw_context_t mad_context; + osm_node_t *const p_node = (osm_node_t *) p_object; + osm_sm_t *sm = context; + osm_physp_t *p_physp = NULL; + unsigned i, num_ports; + ib_api_status_t status; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_node); + + if (p_node->print_desc && strcmp(p_node->print_desc, OSM_NODE_DESC_UNKNOWN)) + /* if ND is valid, do nothing */ + goto exit; + + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 3319: Unknown node description for node GUID " + "0x%016" PRIx64 ". Reissuing ND query\n", + cl_ntoh64(osm_node_get_node_guid (p_node))); + + /* get a physp to request from. */ + num_ports = osm_node_get_num_physp(p_node); + for (i = 0; i < num_ports; i++) + if ((p_physp = osm_node_get_physp_ptr(p_node, i))) + break; + + if (!p_physp) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 331C: " + "Failed to find any valid physical port object.\n"); + goto exit; + } + + mad_context.nd_context.node_guid = osm_node_get_node_guid(p_node); + + status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp), + IB_MAD_ATTR_NODE_DESC, 0, CL_DISP_MSGID_NONE, + &mad_context); + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 331B: Failure initiating NodeDescription request " + "(%s)\n", ib_get_err_str(status)); + +exit: + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + Initiates a lightweight sweep of the subnet. + Used during normal sweeps after the subnet is up. +**********************************************************************/ +static ib_api_status_t __osm_state_mgr_light_sweep_start(IN osm_sm_t * sm) +{ + ib_api_status_t status = IB_SUCCESS; + osm_bind_handle_t h_bind; + cl_qmap_t *p_sw_tbl; + cl_map_item_t *p_next; + osm_node_t *p_node; + osm_physp_t *p_physp; + uint8_t port_num; + + OSM_LOG_ENTER(sm->p_log); + + p_sw_tbl = &sm->p_subn->sw_guid_tbl; + + /* + * First, get the bind handle. + */ + h_bind = osm_sm_mad_ctrl_get_bind_handle(&sm->mad_ctrl); + if (h_bind == OSM_BIND_INVALID_HANDLE) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "No bound ports. Deferring sweep...\n"); + status = IB_INVALID_STATE; + goto _exit; + } + + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, "INITIATING LIGHT SWEEP"); + CL_PLOCK_ACQUIRE(sm->p_lock); + cl_qmap_apply_func(p_sw_tbl, __osm_state_mgr_get_sw_info, sm); + CL_PLOCK_RELEASE(sm->p_lock); + + CL_PLOCK_ACQUIRE(sm->p_lock); + cl_qmap_apply_func(&sm->p_subn->node_guid_tbl, __osm_state_mgr_get_node_desc, sm); + CL_PLOCK_RELEASE(sm->p_lock); + + /* now scan the list of physical ports that were not down but have no remote port */ + CL_PLOCK_ACQUIRE(sm->p_lock); + p_next = cl_qmap_head(&sm->p_subn->node_guid_tbl); + while (p_next != cl_qmap_end(&sm->p_subn->node_guid_tbl)) { + p_node = (osm_node_t *) p_next; + p_next = cl_qmap_next(p_next); + + for (port_num = 1; port_num < osm_node_get_num_physp(p_node); + port_num++) { + p_physp = osm_node_get_physp_ptr(p_node, port_num); + if (p_physp && (osm_physp_get_port_state(p_physp) != + IB_LINK_DOWN) + && !osm_physp_get_remote(p_physp)) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3315: " + "Unknown remote side for node 0x%016" + PRIx64 + "(%s) port %u. Adding to light sweep sampling list\n", + cl_ntoh64(osm_node_get_node_guid + (p_node)), + p_node->print_desc, port_num); + + osm_dump_dr_path(sm->p_log, + osm_physp_get_dr_path_ptr + (p_physp), OSM_LOG_ERROR); + + __osm_state_mgr_get_remote_port_info(sm, + p_physp); + } + } + } + + cl_qmap_apply_func(&sm->p_subn->sm_guid_tbl, query_sm_info, sm); + + CL_PLOCK_RELEASE(sm->p_lock); + +_exit: + OSM_LOG_EXIT(sm->p_log); + return (status); +} + +/********************************************************************** + * Go over all the remote SMs (as updated in the sm_guid_tbl). + * Find if there is a remote sm that is a master SM. + * If there is a remote master SM - return a pointer to it, + * else - return NULL. + **********************************************************************/ +static osm_remote_sm_t *__osm_state_mgr_exists_other_master_sm(IN osm_sm_t * sm) +{ + cl_qmap_t *p_sm_tbl; + osm_remote_sm_t *p_sm; + osm_remote_sm_t *p_sm_res = NULL; + + OSM_LOG_ENTER(sm->p_log); + + p_sm_tbl = &sm->p_subn->sm_guid_tbl; + + /* go over all the remote SMs */ + for (p_sm = (osm_remote_sm_t *) cl_qmap_head(p_sm_tbl); + p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl); + p_sm = (osm_remote_sm_t *) cl_qmap_next(&p_sm->map_item)) { + /* If the sm is in MASTER state - return a pointer to it */ + if (ib_sminfo_get_state(&p_sm->smi) == IB_SMINFO_STATE_MASTER) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Found remote master SM with guid:0x%016" PRIx64 + " (node %s)\n", cl_ntoh64(p_sm->smi.guid), + p_sm->p_port->p_node ? p_sm->p_port->p_node-> + print_desc : "UNKNOWN"); + p_sm_res = p_sm; + goto Exit; + } + } + +Exit: + OSM_LOG_EXIT(sm->p_log); + return (p_sm_res); +} + +/********************************************************************** + * Go over all remote SMs (as updated in the sm_guid_tbl). + * Find the one with the highest priority and lowest guid. + * Compare this SM to the local SM. If the local SM is higher - + * return NULL, if the remote SM is higher - return a pointer to it. + **********************************************************************/ +static osm_remote_sm_t *__osm_state_mgr_get_highest_sm(IN osm_sm_t * sm) +{ + cl_qmap_t *p_sm_tbl; + osm_remote_sm_t *p_sm = NULL; + osm_remote_sm_t *p_highest_sm; + uint8_t highest_sm_priority; + ib_net64_t highest_sm_guid; + + OSM_LOG_ENTER(sm->p_log); + + p_sm_tbl = &sm->p_subn->sm_guid_tbl; + + /* Start with the local sm as the standard */ + p_highest_sm = NULL; + highest_sm_priority = sm->p_subn->opt.sm_priority; + highest_sm_guid = sm->p_subn->sm_port_guid; + + /* go over all the remote SMs */ + for (p_sm = (osm_remote_sm_t *) cl_qmap_head(p_sm_tbl); + p_sm != (osm_remote_sm_t *) cl_qmap_end(p_sm_tbl); + p_sm = (osm_remote_sm_t *) cl_qmap_next(&p_sm->map_item)) { + + /* If the sm is in NOTACTIVE state - continue */ + if (ib_sminfo_get_state(&p_sm->smi) == + IB_SMINFO_STATE_NOTACTIVE) + continue; + + if (osm_sm_is_greater_than(ib_sminfo_get_priority(&p_sm->smi), + p_sm->smi.guid, highest_sm_priority, + highest_sm_guid)) { + /* the new p_sm is with higher priority - update the highest_sm */ + /* to this sm */ + p_highest_sm = p_sm; + highest_sm_priority = + ib_sminfo_get_priority(&p_sm->smi); + highest_sm_guid = p_sm->smi.guid; + } + } + + if (p_highest_sm != NULL) + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Found higher SM with guid: %016" PRIx64 " (node %s)\n", + cl_ntoh64(p_highest_sm->smi.guid), + p_highest_sm->p_port->p_node ? + p_highest_sm->p_port->p_node->print_desc : "UNKNOWN"); + + OSM_LOG_EXIT(sm->p_log); + return (p_highest_sm); +} + +/********************************************************************** + * Send SubnSet(SMInfo) SMP with HANDOVER attribute to the + * remote_sm indicated. + **********************************************************************/ +static void +__osm_state_mgr_send_handover(IN osm_sm_t * const sm, + IN osm_remote_sm_t * const p_sm) +{ + uint8_t payload[IB_SMP_DATA_SIZE]; + ib_sm_info_t *p_smi = (ib_sm_info_t *) payload; + osm_madw_context_t context; + const osm_port_t *p_port; + ib_api_status_t status; + + OSM_LOG_ENTER(sm->p_log); + + /* + * Send a query of SubnSet(SMInfo) HANDOVER to the remote sm given. + */ + + memset(&context, 0, sizeof(context)); + p_port = p_sm->p_port; + if (p_port == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3316: " + "No port object on given remote_sm object\n"); + goto Exit; + } + + /* update the master_guid in the sm_state_mgr object according to */ + /* the guid of the port where the new Master SM should reside. */ + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Handing over mastership. Updating sm_state_mgr master_guid: %016" + PRIx64 " (node %s)\n", cl_ntoh64(p_port->guid), + p_port->p_node ? p_port->p_node->print_desc : "UNKNOWN"); + sm->master_sm_guid = p_port->guid; + + context.smi_context.port_guid = p_port->guid; + context.smi_context.set_method = TRUE; + + p_smi->guid = sm->p_subn->sm_port_guid; + p_smi->act_count = cl_hton32(sm->p_subn->p_osm->stats.qp0_mads_sent); + p_smi->pri_state = (uint8_t) (sm->p_subn->sm_state | + sm->p_subn->opt.sm_priority << 4); + /* + * Return 0 for the SM key unless we authenticate the requester + * as the master SM. + */ + if (ib_sminfo_get_state(&p_sm->smi) == IB_SMINFO_STATE_MASTER) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Responding to master SM with real sm_key\n"); + p_smi->sm_key = sm->p_subn->opt.sm_key; + } else { + /* The requester is not authenticated as master - set sm_key to zero */ + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Responding to SM not master with zero sm_key\n"); + p_smi->sm_key = 0; + } + + status = osm_req_set(sm, osm_physp_get_dr_path_ptr(p_port->p_physp), + payload, sizeof(payload), IB_MAD_ATTR_SM_INFO, + IB_SMINFO_ATTR_MOD_HANDOVER, CL_DISP_MSGID_NONE, + &context); + + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3317: " + "Failure requesting SMInfo (%s)\n", + ib_get_err_str(status)); + +Exit: + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + * Send Trap 64 on all new ports. + **********************************************************************/ +static void __osm_state_mgr_report_new_ports(IN osm_sm_t * sm) +{ + ib_gid_t port_gid; + ib_mad_notice_attr_t notice; + ib_api_status_t status; + ib_net64_t port_guid; + cl_map_item_t *p_next; + osm_port_t *p_port; + uint16_t min_lid_ho; + uint16_t max_lid_ho; + + OSM_LOG_ENTER(sm->p_log); + + CL_PLOCK_ACQUIRE(sm->p_lock); + p_next = cl_qmap_head(&sm->p_subn->port_guid_tbl); + while (p_next != cl_qmap_end(&sm->p_subn->port_guid_tbl)) { + p_port = (osm_port_t *) p_next; + p_next = cl_qmap_next(p_next); + + if (!p_port->is_new) + continue; + + port_guid = osm_port_get_guid(p_port); + /* issue a notice - trap 64 */ + + /* details of the notice */ + notice.generic_type = 0x83; /* is generic subn mgt type */ + ib_notice_set_prod_type_ho(¬ice, 4); /* A Class Manager generator */ + /* endport becomes to be reachable */ + notice.g_or_v.generic.trap_num = CL_HTON16(64); + /* The sm_base_lid is saved in network order already. */ + notice.issuer_lid = sm->p_subn->sm_base_lid; + /* following C14-72.1.1 and table 119 p739 */ + /* we need to provide the GID */ + port_gid.unicast.prefix = sm->p_subn->opt.subnet_prefix; + port_gid.unicast.interface_id = port_guid; + memcpy(&(notice.data_details.ntc_64_67.gid), &(port_gid), + sizeof(ib_gid_t)); + + /* According to page 653 - the issuer gid in this case of trap + * is the SM gid, since the SM is the initiator of this trap. */ + notice.issuer_gid.unicast.prefix = + sm->p_subn->opt.subnet_prefix; + notice.issuer_gid.unicast.interface_id = + sm->p_subn->sm_port_guid; + + status = osm_report_notice(sm->p_log, sm->p_subn, ¬ice); + if (status != IB_SUCCESS) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3318: " + "Error sending trap reports on GUID:0x%016" + PRIx64 " (%s)\n", port_gid.unicast.interface_id, + ib_get_err_str(status)); + osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); + OSM_LOG(sm->p_log, OSM_LOG_INFO, + "Discovered new port with GUID:0x%016" PRIx64 + " LID range [%u,%u] of node:%s\n", + cl_ntoh64(port_gid.unicast.interface_id), + min_lid_ho, max_lid_ho, + p_port->p_node ? p_port->p_node-> + print_desc : "UNKNOWN"); + + p_port->is_new = 0; + } + CL_PLOCK_RELEASE(sm->p_lock); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + * Make sure that the lid_port_tbl of the subnet has only the ports + * that are recognized, and in the correct lid place. There could be + * errors if we wanted to assign a certain port with lid X, but that + * request didn't reach the port. In this case port_lid_tbl will have + * the port under lid X, though the port isn't updated with this lid. + * We will run a new heavy sweep (since there were errors in the + * initialization), but here we'll clean the database from incorrect + * information. + **********************************************************************/ +static void __osm_state_mgr_check_tbl_consistency(IN osm_sm_t * sm) +{ + cl_qmap_t *p_port_guid_tbl; + osm_port_t *p_port; + osm_port_t *p_next_port; + cl_ptr_vector_t *p_port_lid_tbl; + size_t max_lid, ref_size, curr_size, lid; + osm_port_t *p_port_ref, *p_port_stored; + cl_ptr_vector_t ref_port_lid_tbl; + uint16_t min_lid_ho; + uint16_t max_lid_ho; + uint16_t lid_ho; + + OSM_LOG_ENTER(sm->p_log); + + cl_ptr_vector_construct(&ref_port_lid_tbl); + cl_ptr_vector_init(&ref_port_lid_tbl, + cl_ptr_vector_get_size(&sm->p_subn->port_lid_tbl), + OSM_SUBNET_VECTOR_GROW_SIZE); + + p_port_guid_tbl = &sm->p_subn->port_guid_tbl; + + /* Let's go over all the ports according to port_guid_tbl, + * and add the port to a reference port_lid_tbl. */ + p_next_port = (osm_port_t *) cl_qmap_head(p_port_guid_tbl); + while (p_next_port != (osm_port_t *) cl_qmap_end(p_port_guid_tbl)) { + p_port = p_next_port; + p_next_port = + (osm_port_t *) cl_qmap_next(&p_next_port->map_item); + + osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); + for (lid_ho = min_lid_ho; lid_ho <= max_lid_ho; lid_ho++) + cl_ptr_vector_set(&ref_port_lid_tbl, lid_ho, p_port); + } + + p_port_lid_tbl = &sm->p_subn->port_lid_tbl; + + ref_size = cl_ptr_vector_get_size(&ref_port_lid_tbl); + curr_size = cl_ptr_vector_get_size(p_port_lid_tbl); + /* They should be the same, but compare it anyway */ + max_lid = (ref_size > curr_size) ? ref_size : curr_size; + + for (lid = 1; lid <= max_lid; lid++) { + p_port_ref = NULL; + p_port_stored = NULL; + cl_ptr_vector_at(p_port_lid_tbl, lid, (void *)&p_port_stored); + cl_ptr_vector_at(&ref_port_lid_tbl, lid, (void *)&p_port_ref); + + if (p_port_stored == p_port_ref) + /* This is the "good" case - both entries are the + * same for this lid. Nothing to do. */ + continue; + + if (p_port_ref == NULL) + /* There is an object in the subnet database for this + * lid, but no such object exists in the reference + * port_list_tbl. This can occur if we wanted to assign + * a certain port with some lid (different than the one + * pre-assigned to it), and the port didn't get the + * PortInfo Set request. Due to this, the port is + * updated with its original lid in our database, but + * with the new lid we wanted to give it in our + * port_lid_tbl. */ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3322: " + "lid %zu is wrongly assigned to port 0x%016" + PRIx64 " (\'%s\' port %u) in port_lid_tbl\n", + lid, + cl_ntoh64(osm_port_get_guid(p_port_stored)), + p_port_stored->p_node->print_desc, + p_port_stored->p_physp->port_num); + else if (p_port_stored == NULL) + /* There is an object in the new database, but no + * object in our subnet database. This is the matching + * case of the prior check - the port still has its + * original lid. */ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3323: " + "port 0x%016" PRIx64 " (\'%s\' port %u)" + " exists in new port_lid_tbl under lid %zu," + " but missing in subnet port_lid_tbl db\n", + cl_ntoh64(osm_port_get_guid(p_port_ref)), + p_port_ref->p_node->print_desc, + p_port_ref->p_physp->port_num, lid); + else + /* if we reached here then p_port_stored != p_port_ref. + * We were trying to set a lid to p_port_stored, but + * it didn't reach it, and p_port_ref also didn't get + * the lid update. */ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3324: " + "lid %zu has port 0x%016" PRIx64 + " (\'%s\' port %u) in new port_lid_tbl db, " + "and port 0x%016" PRIx64 " (\'%s\' port %u)" + " in subnet port_lid_tbl db\n", lid, + cl_ntoh64(osm_port_get_guid(p_port_ref)), + p_port_ref->p_node->print_desc, + p_port_ref->p_physp->port_num, + cl_ntoh64(osm_port_get_guid(p_port_stored)), + p_port_ref->p_node->print_desc, + p_port_ref->p_physp->port_num); + + /* In any of these cases we want to set NULL in the + * port_lid_tbl, since this entry is invalid. Also, make sure + * we'll do another heavy sweep. */ + cl_ptr_vector_set(p_port_lid_tbl, lid, NULL); + sm->p_subn->subnet_initialization_error = TRUE; + } + + cl_ptr_vector_destroy(&ref_port_lid_tbl); + OSM_LOG_EXIT(sm->p_log); +} + +static void cleanup_switch(cl_map_item_t *item, void *log) +{ + osm_switch_t *sw = (osm_switch_t *)item; + + if (!sw->new_lft) + return; + + if (memcmp(sw->lft, sw->new_lft, IB_LID_UCAST_END_HO + 1)) + osm_log(log, OSM_LOG_ERROR, "ERR 331D: " + "LFT of switch 0x%016" PRIx64 " is not up to date.\n", + cl_ntoh64(sw->p_node->node_info.node_guid)); + else { + free(sw->new_lft); + sw->new_lft = NULL; + } +} + +/********************************************************************** + **********************************************************************/ +int wait_for_pending_transactions(osm_stats_t * stats) +{ +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&stats->mutex); + while (stats->qp0_mads_outstanding && !osm_exit_flag) + pthread_cond_wait(&stats->cond, &stats->mutex); + pthread_mutex_unlock(&stats->mutex); +#else + while (1) { + unsigned count = stats->qp0_mads_outstanding; + if (!count || osm_exit_flag) + break; + cl_event_wait_on(&stats->event, EVENT_NO_TIMEOUT, TRUE); + } +#endif + return osm_exit_flag; +} + +static void do_sweep(osm_sm_t * sm) +{ + ib_api_status_t status; + osm_remote_sm_t *p_remote_sm; + + if (sm->p_subn->sm_state != IB_SMINFO_STATE_MASTER && + sm->p_subn->sm_state != IB_SMINFO_STATE_DISCOVERING) + return; + + if (sm->p_subn->coming_out_of_standby) + /* + * Need to force re-write of sm_base_lid to all ports + * to do that we want all the ports to be considered + * foreign + */ + __osm_state_mgr_clean_known_lids(sm); + + sm->master_sm_found = 0; + + /* + * If we already have switches, then try a light sweep. + * Otherwise, this is probably our first discovery pass + * or we are connected in loopback. In both cases do a + * heavy sweep. + * Note: If we are connected in loopback we want a heavy + * sweep, since we will not be getting any traps if there is + * a lost connection. + */ + /* if we are in DISCOVERING state - this means it is either in + * initializing or wake up from STANDBY - run the heavy sweep */ + if (cl_qmap_count(&sm->p_subn->sw_guid_tbl) + && sm->p_subn->sm_state != IB_SMINFO_STATE_DISCOVERING + && sm->p_subn->opt.force_heavy_sweep == FALSE + && sm->p_subn->force_heavy_sweep == FALSE + && sm->p_subn->force_reroute == FALSE + && sm->p_subn->subnet_initialization_error == FALSE + && (__osm_state_mgr_light_sweep_start(sm) == IB_SUCCESS)) { + if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats)) + return; + if (!sm->p_subn->force_heavy_sweep) { + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, + "LIGHT SWEEP COMPLETE"); + return; + } + } + + /* + * Unicast cache should be invalidated if there were errors + * during initialization or if subnet re-route is requested. + */ + if (sm->p_subn->opt.use_ucast_cache && + (sm->p_subn->subnet_initialization_error || + sm->p_subn->force_reroute)) + osm_ucast_cache_invalidate(&sm->ucast_mgr); + + /* + * If we don't need to do a heavy sweep and we want to do a reroute, + * just reroute only. + */ + if (cl_qmap_count(&sm->p_subn->sw_guid_tbl) + && sm->p_subn->sm_state != IB_SMINFO_STATE_DISCOVERING + && sm->p_subn->opt.force_heavy_sweep == FALSE + && sm->p_subn->force_heavy_sweep == FALSE + && sm->p_subn->force_reroute == TRUE + && sm->p_subn->subnet_initialization_error == FALSE) { + /* Reset flag */ + sm->p_subn->force_reroute = FALSE; + + /* Re-program the switches fully */ + sm->p_subn->ignore_existing_lfts = TRUE; + + osm_ucast_mgr_process(&sm->ucast_mgr); + + /* Reset flag */ + sm->p_subn->ignore_existing_lfts = FALSE; + + if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats)) + return; + + if (!sm->p_subn->subnet_initialization_error) { + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, + "REROUTE COMPLETE"); + return; + } + } + + /* go to heavy sweep */ +_repeat_discovery: + + /* First of all - unset all flags */ + sm->p_subn->force_heavy_sweep = FALSE; + sm->p_subn->force_reroute = FALSE; + sm->p_subn->subnet_initialization_error = FALSE; + + /* rescan configuration updates */ + if (osm_subn_rescan_conf_files(sm->p_subn) < 0) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 331A: " + "osm_subn_rescan_conf_file failed\n"); + + if (sm->p_subn->sm_state != IB_SMINFO_STATE_MASTER) + sm->p_subn->need_update = 1; + + status = __osm_state_mgr_sweep_hop_0(sm); + if (status != IB_SUCCESS || + wait_for_pending_transactions(&sm->p_subn->p_osm->stats)) + return; + + if (__osm_state_mgr_is_sm_port_down(sm) == TRUE) { + osm_log(sm->p_log, OSM_LOG_SYS, "SM port is down\n"); + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, "SM PORT DOWN"); + + /* Run the drop manager - we want to clear all records */ + osm_drop_mgr_process(sm); + + /* Move to DISCOVERING state */ + osm_sm_state_mgr_process(sm, OSM_SM_SIGNAL_DISCOVER); + return; + } + + status = __osm_state_mgr_sweep_hop_1(sm); + if (status != IB_SUCCESS || + wait_for_pending_transactions(&sm->p_subn->p_osm->stats)) + return; + + /* discovery completed - check other sm presense */ + if (sm->master_sm_found) { + /* + * Call the sm_state_mgr with signal + * MASTER_OR_HIGHER_SM_DETECTED_DONE + */ + osm_sm_state_mgr_process(sm, + OSM_SM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED); + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, + "ENTERING STANDBY STATE"); + /* notify master SM about us */ + osm_send_trap144(sm, 0); + return; + } + + /* if new sweep requested - don't bother with the rest */ + if (sm->p_subn->force_heavy_sweep) + goto _repeat_discovery; + + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, "HEAVY SWEEP COMPLETE"); + + /* If we are MASTER - get the highest remote_sm, and + * see if it is higher than our local sm. + */ + if (sm->p_subn->sm_state == IB_SMINFO_STATE_MASTER) { + p_remote_sm = __osm_state_mgr_get_highest_sm(sm); + if (p_remote_sm != NULL) { + /* report new ports (trap 64) before leaving MASTER */ + __osm_state_mgr_report_new_ports(sm); + + /* need to handover the mastership + * to the remote sm, and move to standby */ + __osm_state_mgr_send_handover(sm, p_remote_sm); + osm_sm_state_mgr_process(sm, + OSM_SM_SIGNAL_HANDOVER_SENT); + return; + } else { + /* We are the highest sm - check to see if there is + * a remote SM that is in master state. */ + p_remote_sm = + __osm_state_mgr_exists_other_master_sm(sm); + if (p_remote_sm != NULL) { + /* There is a remote SM that is master. + * need to wait for that SM to relinquish control + * of its portion of the subnet. C14-60.2.1. + * Also - need to start polling on that SM. */ + sm->p_polling_sm = p_remote_sm; + osm_sm_state_mgr_process(sm, + OSM_SM_SIGNAL_WAIT_FOR_HANDOVER); + return; + } + } + } + + /* Need to continue with lid assignment */ + osm_drop_mgr_process(sm); + + /* + * If we are not MASTER already - this means that we are + * in discovery state. call osm_sm_state_mgr with signal + * DISCOVERY_COMPLETED + */ + if (sm->p_subn->sm_state == IB_SMINFO_STATE_DISCOVERING) + osm_sm_state_mgr_process(sm, OSM_SM_SIGNAL_DISCOVERY_COMPLETED); + + osm_pkey_mgr_process(sm->p_subn->p_osm); + + osm_qos_setup(sm->p_subn->p_osm); + + /* try to restore SA DB (this should be before lid_mgr + because we may want to disable clients reregistration + when SA DB is restored) */ + osm_sa_db_file_load(sm->p_subn->p_osm); + + if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats)) + return; + + osm_lid_mgr_process_sm(&sm->lid_mgr); + if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats)) + return; + + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, + "SM LID ASSIGNMENT COMPLETE - STARTING SUBNET LID CONFIG"); + __osm_state_mgr_notify_lid_change(sm); + + osm_lid_mgr_process_subnet(&sm->lid_mgr); + if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats)) + return; + + /* At this point we need to check the consistency of + * the port_lid_tbl under the subnet. There might be + * errors in it if PortInfo Set requests didn't reach + * their destination. */ + __osm_state_mgr_check_tbl_consistency(sm); + + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, + "LID ASSIGNMENT COMPLETE - STARTING SWITCH TABLE CONFIG"); + + /* + * Proceed with unicast forwarding table configuration. + */ + + if (!sm->ucast_mgr.cache_valid || + osm_ucast_cache_process(&sm->ucast_mgr)) + osm_ucast_mgr_process(&sm->ucast_mgr); + + if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats)) + return; + + /* cleanup switch lft buffers */ + cl_qmap_apply_func(&sm->p_subn->sw_guid_tbl, cleanup_switch, sm->p_log); + + /* We are done setting all LFTs so clear the ignore existing. + * From now on, as long as we are still master, we want to + * take into account these lfts. */ + sm->p_subn->ignore_existing_lfts = FALSE; + + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, + "SWITCHES CONFIGURED FOR UNICAST"); + + if (!sm->p_subn->opt.disable_multicast) { + osm_mcast_mgr_process(sm); + if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats)) + return; + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, + "SWITCHES CONFIGURED FOR MULTICAST"); + } + + /* + * The LINK_PORTS state is required since we cannot count on + * the port state change MADs to succeed. This is an artifact + * of the spec defining state change from state X to state X + * as an error. The hardware then is not required to process + * other parameters provided by the Set(PortInfo) Packet. + */ + + osm_link_mgr_process(sm, IB_LINK_NO_CHANGE); + if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats)) + return; + + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, + "LINKS PORTS CONFIGURED - SET LINKS TO ARMED STATE"); + + osm_link_mgr_process(sm, IB_LINK_ARMED); + if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats)) + return; + + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_VERBOSE, + "LINKS ARMED - SET LINKS TO ACTIVE STATE"); + + osm_link_mgr_process(sm, IB_LINK_ACTIVE); + if (wait_for_pending_transactions(&sm->p_subn->p_osm->stats)) + return; + + /* + * The sweep completed! + */ + + /* + * Send trap 64 on newly discovered endports + */ + __osm_state_mgr_report_new_ports(sm); + + /* in any case we zero this flag */ + sm->p_subn->coming_out_of_standby = FALSE; + + /* If there were errors - then the subnet is not really up */ + if (sm->p_subn->subnet_initialization_error == TRUE) { + osm_log(sm->p_log, OSM_LOG_SYS, + "Errors during initialization\n"); + OSM_LOG_MSG_BOX(sm->p_log, OSM_LOG_ERROR, + "ERRORS DURING INITIALIZATION"); + } else { + sm->p_subn->need_update = 0; + osm_dump_all(sm->p_subn->p_osm); + __osm_state_mgr_up_msg(sm); + sm->p_subn->first_time_master_sweep = FALSE; + + if (osm_log_is_active(sm->p_log, OSM_LOG_VERBOSE)) + osm_sa_db_file_dump(sm->p_subn->p_osm); + } + + /* + * Finally signal the subnet up event + */ + cl_event_signal(&sm->subnet_up_event); + + osm_opensm_report_event(sm->p_subn->p_osm, OSM_EVENT_ID_SUBNET_UP, NULL); + + /* if we got a signal to force heavy sweep or errors + * in the middle of the sweep - try another sweep. */ + if (sm->p_subn->force_heavy_sweep + || sm->p_subn->subnet_initialization_error) + osm_sm_signal(sm, OSM_SIGNAL_SWEEP); +} + +static void do_process_mgrp_queue(osm_sm_t * sm) +{ + if (sm->p_subn->sm_state != IB_SMINFO_STATE_MASTER) + return; + osm_mcast_mgr_process_mgroups(sm); + wait_for_pending_transactions(&sm->p_subn->p_osm->stats); +} + +void osm_state_mgr_process(IN osm_sm_t * sm, IN osm_signal_t signal) +{ + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Received signal %s in state %s\n", + osm_get_sm_signal_str(signal), + osm_get_sm_mgr_state_str(sm->p_subn->sm_state)); + + switch (signal) { + case OSM_SIGNAL_SWEEP: + do_sweep(sm); + break; + + case OSM_SIGNAL_IDLE_TIME_PROCESS_REQUEST: + do_process_mgrp_queue(sm); + break; + + default: + CL_ASSERT(FALSE); + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3320: " + "Invalid SM signal %u\n", signal); + break; + } + + OSM_LOG_EXIT(sm->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_subnet.c b/contrib/ofed/management/opensm/opensm/osm_subnet.c new file mode 100644 index 000000000000..c41962d6c756 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_subnet.c @@ -0,0 +1,1719 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_subn_t. + * This object represents an IBA subnet. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char null_str[] = "(null)"; + +/********************************************************************** + **********************************************************************/ +void osm_subn_construct(IN osm_subn_t * const p_subn) +{ + memset(p_subn, 0, sizeof(*p_subn)); + cl_ptr_vector_construct(&p_subn->port_lid_tbl); + cl_qmap_init(&p_subn->sw_guid_tbl); + cl_qmap_init(&p_subn->node_guid_tbl); + cl_qmap_init(&p_subn->port_guid_tbl); + cl_qmap_init(&p_subn->sm_guid_tbl); + cl_qlist_init(&p_subn->sa_sr_list); + cl_qlist_init(&p_subn->sa_infr_list); + cl_qlist_init(&p_subn->prefix_routes_list); + cl_qmap_init(&p_subn->rtr_guid_tbl); + cl_qmap_init(&p_subn->prtn_pkey_tbl); +} + +/********************************************************************** + **********************************************************************/ +void osm_subn_destroy(IN osm_subn_t * const p_subn) +{ + int i; + osm_node_t *p_node, *p_next_node; + osm_port_t *p_port, *p_next_port; + osm_switch_t *p_sw, *p_next_sw; + osm_remote_sm_t *p_rsm, *p_next_rsm; + osm_prtn_t *p_prtn, *p_next_prtn; + osm_mgrp_t *p_mgrp; + osm_infr_t *p_infr, *p_next_infr; + + /* it might be a good idea to de-allocate all known objects */ + p_next_node = (osm_node_t *) cl_qmap_head(&p_subn->node_guid_tbl); + while (p_next_node != + (osm_node_t *) cl_qmap_end(&p_subn->node_guid_tbl)) { + p_node = p_next_node; + p_next_node = (osm_node_t *) cl_qmap_next(&p_node->map_item); + osm_node_delete(&p_node); + } + + p_next_port = (osm_port_t *) cl_qmap_head(&p_subn->port_guid_tbl); + while (p_next_port != + (osm_port_t *) cl_qmap_end(&p_subn->port_guid_tbl)) { + p_port = p_next_port; + p_next_port = (osm_port_t *) cl_qmap_next(&p_port->map_item); + osm_port_delete(&p_port); + } + + p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl); + while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) { + p_sw = p_next_sw; + p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); + osm_switch_delete(&p_sw); + } + + p_next_rsm = (osm_remote_sm_t *) cl_qmap_head(&p_subn->sm_guid_tbl); + while (p_next_rsm != + (osm_remote_sm_t *) cl_qmap_end(&p_subn->sm_guid_tbl)) { + p_rsm = p_next_rsm; + p_next_rsm = (osm_remote_sm_t *) cl_qmap_next(&p_rsm->map_item); + free(p_rsm); + } + + p_next_prtn = (osm_prtn_t *) cl_qmap_head(&p_subn->prtn_pkey_tbl); + while (p_next_prtn != + (osm_prtn_t *) cl_qmap_end(&p_subn->prtn_pkey_tbl)) { + p_prtn = p_next_prtn; + p_next_prtn = (osm_prtn_t *) cl_qmap_next(&p_prtn->map_item); + osm_prtn_delete(&p_prtn); + } + + for (i = 0; i <= p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO; + i++) { + p_mgrp = p_subn->mgroups[i]; + p_subn->mgroups[i] = NULL; + if (p_mgrp) + osm_mgrp_delete(p_mgrp); + } + + p_next_infr = (osm_infr_t *) cl_qlist_head(&p_subn->sa_infr_list); + while (p_next_infr != + (osm_infr_t *) cl_qlist_end(&p_subn->sa_infr_list)) { + p_infr = p_next_infr; + p_next_infr = (osm_infr_t *) cl_qlist_next(&p_infr->list_item); + osm_infr_delete(p_infr); + } + + cl_ptr_vector_destroy(&p_subn->port_lid_tbl); + + osm_qos_policy_destroy(p_subn->p_qos_policy); + + while (!cl_is_qlist_empty(&p_subn->prefix_routes_list)) { + cl_list_item_t *item = cl_qlist_remove_head(&p_subn->prefix_routes_list); + free(item); + } +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_subn_init(IN osm_subn_t * const p_subn, + IN osm_opensm_t * const p_osm, + IN const osm_subn_opt_t * const p_opt) +{ + cl_status_t status; + + p_subn->p_osm = p_osm; + + status = cl_ptr_vector_init(&p_subn->port_lid_tbl, + OSM_SUBNET_VECTOR_MIN_SIZE, + OSM_SUBNET_VECTOR_GROW_SIZE); + if (status != CL_SUCCESS) + return (status); + + status = cl_ptr_vector_set_capacity(&p_subn->port_lid_tbl, + OSM_SUBNET_VECTOR_CAPACITY); + if (status != CL_SUCCESS) + return (status); + + /* + LID zero is not valid. NULL out this entry for the + convenience of other code. + */ + cl_ptr_vector_set(&p_subn->port_lid_tbl, 0, NULL); + + p_subn->opt = *p_opt; + p_subn->max_ucast_lid_ho = IB_LID_UCAST_END_HO; + p_subn->max_mcast_lid_ho = IB_LID_MCAST_END_HO; + p_subn->min_ca_mtu = IB_MAX_MTU; + p_subn->min_ca_rate = IB_MAX_RATE; + p_subn->ignore_existing_lfts = TRUE; + + /* we assume master by default - so we only need to set it true if STANDBY */ + p_subn->coming_out_of_standby = FALSE; + + return (IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_get_gid_by_mad_addr(IN osm_log_t * p_log, + IN const osm_subn_t * p_subn, + IN const osm_mad_addr_t * p_mad_addr, + OUT ib_gid_t * p_gid) +{ + const cl_ptr_vector_t *p_tbl; + const osm_port_t *p_port = NULL; + + if (p_gid == NULL) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7505: " + "Provided output GID is NULL\n"); + return (IB_INVALID_PARAMETER); + } + + /* Find the port gid of the request in the subnet */ + p_tbl = &p_subn->port_lid_tbl; + + CL_ASSERT(cl_ptr_vector_get_size(p_tbl) < 0x10000); + + if ((uint16_t) cl_ptr_vector_get_size(p_tbl) > + cl_ntoh16(p_mad_addr->dest_lid)) { + p_port = + cl_ptr_vector_get(p_tbl, cl_ntoh16(p_mad_addr->dest_lid)); + if (p_port == NULL) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Did not find any port with LID: %u\n", + cl_ntoh16(p_mad_addr->dest_lid)); + return (IB_INVALID_PARAMETER); + } + p_gid->unicast.interface_id = p_port->p_physp->port_guid; + p_gid->unicast.prefix = p_subn->opt.subnet_prefix; + } else { + /* The dest_lid is not in the subnet table - this is an error */ + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7501: " + "LID is out of range: %u\n", + cl_ntoh16(p_mad_addr->dest_lid)); + return (IB_INVALID_PARAMETER); + } + + return (IB_SUCCESS); +} + +/********************************************************************** + **********************************************************************/ +osm_physp_t *osm_get_physp_by_mad_addr(IN osm_log_t * p_log, + IN const osm_subn_t * p_subn, + IN osm_mad_addr_t * p_mad_addr) +{ + const cl_ptr_vector_t *p_port_lid_tbl; + osm_port_t *p_port = NULL; + osm_physp_t *p_physp = NULL; + + /* Find the port gid of the request in the subnet */ + p_port_lid_tbl = &p_subn->port_lid_tbl; + + CL_ASSERT(cl_ptr_vector_get_size(p_port_lid_tbl) < 0x10000); + + if ((uint16_t) cl_ptr_vector_get_size(p_port_lid_tbl) > + cl_ntoh16(p_mad_addr->dest_lid)) { + p_port = + cl_ptr_vector_get(p_port_lid_tbl, + cl_ntoh16(p_mad_addr->dest_lid)); + if (p_port == NULL) { + /* The port is not in the port_lid table - this is an error */ + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7502: " + "Cannot locate port object by lid: %u\n", + cl_ntoh16(p_mad_addr->dest_lid)); + + goto Exit; + } + p_physp = p_port->p_physp; + } else { + /* The dest_lid is not in the subnet table - this is an error */ + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7503: " + "Lid is out of range: %u\n", + cl_ntoh16(p_mad_addr->dest_lid)); + } + +Exit: + return p_physp; +} + +/********************************************************************** + **********************************************************************/ +osm_port_t *osm_get_port_by_mad_addr(IN osm_log_t * p_log, + IN const osm_subn_t * p_subn, + IN osm_mad_addr_t * p_mad_addr) +{ + const cl_ptr_vector_t *p_port_lid_tbl; + osm_port_t *p_port = NULL; + + /* Find the port gid of the request in the subnet */ + p_port_lid_tbl = &p_subn->port_lid_tbl; + + CL_ASSERT(cl_ptr_vector_get_size(p_port_lid_tbl) < 0x10000); + + if ((uint16_t) cl_ptr_vector_get_size(p_port_lid_tbl) > + cl_ntoh16(p_mad_addr->dest_lid)) { + p_port = + cl_ptr_vector_get(p_port_lid_tbl, + cl_ntoh16(p_mad_addr->dest_lid)); + } else { + /* The dest_lid is not in the subnet table - this is an error */ + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 7504: " + "Lid is out of range: %u\n", + cl_ntoh16(p_mad_addr->dest_lid)); + } + + return p_port; +} + +/********************************************************************** + **********************************************************************/ +osm_switch_t *osm_get_switch_by_guid(IN const osm_subn_t * p_subn, + IN uint64_t guid) +{ + osm_switch_t *p_switch; + + p_switch = (osm_switch_t *) cl_qmap_get(&(p_subn->sw_guid_tbl), guid); + if (p_switch == (osm_switch_t *) cl_qmap_end(&(p_subn->sw_guid_tbl))) + p_switch = NULL; + return p_switch; +} + +/********************************************************************** + **********************************************************************/ +osm_node_t *osm_get_node_by_guid(IN osm_subn_t const *p_subn, IN uint64_t guid) +{ + osm_node_t *p_node; + + p_node = (osm_node_t *) cl_qmap_get(&(p_subn->node_guid_tbl), guid); + if (p_node == (osm_node_t *) cl_qmap_end(&(p_subn->node_guid_tbl))) + p_node = NULL; + return p_node; +} + +/********************************************************************** + **********************************************************************/ +osm_port_t *osm_get_port_by_guid(IN osm_subn_t const *p_subn, IN ib_net64_t guid) +{ + osm_port_t *p_port; + + p_port = (osm_port_t *) cl_qmap_get(&(p_subn->port_guid_tbl), guid); + if (p_port == (osm_port_t *) cl_qmap_end(&(p_subn->port_guid_tbl))) + p_port = NULL; + return p_port; +} + +/********************************************************************** + **********************************************************************/ +static void subn_set_default_qos_options(IN osm_qos_options_t * opt) +{ + opt->max_vls = OSM_DEFAULT_QOS_MAX_VLS; + opt->high_limit = OSM_DEFAULT_QOS_HIGH_LIMIT; + opt->vlarb_high = OSM_DEFAULT_QOS_VLARB_HIGH; + opt->vlarb_low = OSM_DEFAULT_QOS_VLARB_LOW; + opt->sl2vl = OSM_DEFAULT_QOS_SL2VL; +} + +static void subn_init_qos_options(IN osm_qos_options_t * opt) +{ + opt->max_vls = 0; + opt->high_limit = -1; + opt->vlarb_high = NULL; + opt->vlarb_low = NULL; + opt->sl2vl = NULL; +} + +/********************************************************************** + **********************************************************************/ +void osm_subn_set_default_opt(IN osm_subn_opt_t * const p_opt) +{ + memset(p_opt, 0, sizeof(osm_subn_opt_t)); + p_opt->guid = 0; + p_opt->m_key = OSM_DEFAULT_M_KEY; + p_opt->sm_key = OSM_DEFAULT_SM_KEY; + p_opt->sa_key = OSM_DEFAULT_SA_KEY; + p_opt->subnet_prefix = IB_DEFAULT_SUBNET_PREFIX; + p_opt->m_key_lease_period = 0; + p_opt->sweep_interval = OSM_DEFAULT_SWEEP_INTERVAL_SECS; + p_opt->max_wire_smps = OSM_DEFAULT_SMP_MAX_ON_WIRE; + p_opt->console = OSM_DEFAULT_CONSOLE; + p_opt->console_port = OSM_DEFAULT_CONSOLE_PORT; + p_opt->transaction_timeout = OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC; + /* by default we will consider waiting for 50x transaction timeout normal */ + p_opt->max_msg_fifo_timeout = 50 * OSM_DEFAULT_TRANS_TIMEOUT_MILLISEC; + p_opt->sm_priority = OSM_DEFAULT_SM_PRIORITY; + p_opt->lmc = OSM_DEFAULT_LMC; + p_opt->lmc_esp0 = FALSE; + p_opt->max_op_vls = OSM_DEFAULT_MAX_OP_VLS; + p_opt->force_link_speed = 15; + p_opt->reassign_lids = FALSE; + p_opt->ignore_other_sm = FALSE; + p_opt->single_thread = FALSE; + p_opt->disable_multicast = FALSE; + p_opt->force_log_flush = FALSE; + p_opt->subnet_timeout = OSM_DEFAULT_SUBNET_TIMEOUT; + p_opt->packet_life_time = OSM_DEFAULT_SWITCH_PACKET_LIFE; + p_opt->vl_stall_count = OSM_DEFAULT_VL_STALL_COUNT; + p_opt->leaf_vl_stall_count = OSM_DEFAULT_LEAF_VL_STALL_COUNT; + p_opt->head_of_queue_lifetime = OSM_DEFAULT_HEAD_OF_QUEUE_LIFE; + p_opt->leaf_head_of_queue_lifetime = + OSM_DEFAULT_LEAF_HEAD_OF_QUEUE_LIFE; + p_opt->local_phy_errors_threshold = OSM_DEFAULT_ERROR_THRESHOLD; + p_opt->overrun_errors_threshold = OSM_DEFAULT_ERROR_THRESHOLD; + p_opt->sminfo_polling_timeout = + OSM_SM_DEFAULT_POLLING_TIMEOUT_MILLISECS; + p_opt->polling_retry_number = OSM_SM_DEFAULT_POLLING_RETRY_NUMBER; + p_opt->force_heavy_sweep = FALSE; + p_opt->log_flags = OSM_LOG_DEFAULT_LEVEL; + p_opt->honor_guid2lid_file = FALSE; + p_opt->daemon = FALSE; + p_opt->sm_inactive = FALSE; + p_opt->babbling_port_policy = FALSE; +#ifdef ENABLE_OSM_PERF_MGR + p_opt->perfmgr = FALSE; + p_opt->perfmgr_redir = TRUE; + p_opt->perfmgr_sweep_time_s = OSM_PERFMGR_DEFAULT_SWEEP_TIME_S; + p_opt->perfmgr_max_outstanding_queries = + OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES; + p_opt->event_db_dump_file = NULL; /* use default */ +#endif /* ENABLE_OSM_PERF_MGR */ + + p_opt->event_plugin_name = NULL; + p_opt->node_name_map_name = NULL; + + p_opt->dump_files_dir = getenv("OSM_TMP_DIR"); + if (!p_opt->dump_files_dir || !(*p_opt->dump_files_dir)) + p_opt->dump_files_dir = OSM_DEFAULT_TMP_DIR; + + p_opt->log_file = OSM_DEFAULT_LOG_FILE; + p_opt->log_max_size = 0; + p_opt->partition_config_file = OSM_DEFAULT_PARTITION_CONFIG_FILE; + p_opt->no_partition_enforcement = FALSE; + p_opt->qos = FALSE; + p_opt->qos_policy_file = OSM_DEFAULT_QOS_POLICY_FILE; + p_opt->accum_log_file = TRUE; + p_opt->port_prof_ignore_file = NULL; + p_opt->port_profile_switch_nodes = FALSE; + p_opt->sweep_on_trap = TRUE; + p_opt->use_ucast_cache = FALSE; + p_opt->routing_engine_names = NULL; + p_opt->connect_roots = FALSE; + p_opt->lid_matrix_dump_file = NULL; + p_opt->lfts_file = NULL; + p_opt->root_guid_file = NULL; + p_opt->cn_guid_file = NULL; + p_opt->ids_guid_file = NULL; + p_opt->guid_routing_order_file = NULL; + p_opt->sa_db_file = NULL; + p_opt->exit_on_fatal = TRUE; + p_opt->enable_quirks = FALSE; + p_opt->no_clients_rereg = FALSE; + p_opt->prefix_routes_file = OSM_DEFAULT_PREFIX_ROUTES_FILE; + p_opt->consolidate_ipv6_snm_req = FALSE; + subn_init_qos_options(&p_opt->qos_options); + subn_init_qos_options(&p_opt->qos_ca_options); + subn_init_qos_options(&p_opt->qos_sw0_options); + subn_init_qos_options(&p_opt->qos_swe_options); + subn_init_qos_options(&p_opt->qos_rtr_options); +} + +/********************************************************************** + **********************************************************************/ +static void log_report(const char *fmt, ...) +{ + char buf[128]; + va_list args; + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + printf(buf); + cl_log_event("OpenSM", CL_LOG_INFO, buf, NULL, 0); +} + +static void log_config_value(char *name, const char *fmt, ...) +{ + char buf[128]; + va_list args; + unsigned n; + va_start(args, fmt); + n = snprintf(buf, sizeof(buf), " Loading Cached Option:%s = ", name); + if (n > sizeof(buf)) + n = sizeof(buf); + n += vsnprintf(buf + n, sizeof(buf) - n, fmt, args); + if (n > sizeof(buf)) + n = sizeof(buf); + snprintf(buf + n, sizeof(buf) - n, "\n"); + va_end(args); + printf(buf); + cl_log_event("OpenSM", CL_LOG_INFO, buf, NULL, 0); +} + +static void +opts_unpack_net64(IN char *p_req_key, + IN char *p_key, IN char *p_val_str, IN uint64_t * p_val) +{ + if (!strcmp(p_req_key, p_key)) { + uint64_t val = strtoull(p_val_str, NULL, 0); + if (cl_hton64(val) != *p_val) { + log_config_value(p_key, "0x%016" PRIx64, val); + *p_val = cl_ntoh64(val); + } + } +} + +/********************************************************************** + **********************************************************************/ +static void +opts_unpack_uint32(IN char *p_req_key, + IN char *p_key, IN char *p_val_str, IN uint32_t * p_val) +{ + if (!strcmp(p_req_key, p_key)) { + uint32_t val = strtoul(p_val_str, NULL, 0); + if (val != *p_val) { + log_config_value(p_key, "%u", val); + *p_val = val; + } + } +} + +/********************************************************************** + **********************************************************************/ +static void +opts_unpack_int32(IN char *p_req_key, + IN char *p_key, IN char *p_val_str, IN int32_t * p_val) +{ + if (!strcmp(p_req_key, p_key)) { + int32_t val = strtol(p_val_str, NULL, 0); + if (val != *p_val) { + log_config_value(p_key, "%d", val); + *p_val = val; + } + } +} + +/********************************************************************** + **********************************************************************/ +static void +opts_unpack_uint16(IN char *p_req_key, + IN char *p_key, IN char *p_val_str, IN uint16_t * p_val) +{ + if (!strcmp(p_req_key, p_key)) { + uint16_t val = (uint16_t) strtoul(p_val_str, NULL, 0); + if (val != *p_val) { + log_config_value(p_key, "%u", val); + *p_val = val; + } + } +} + +/********************************************************************** + **********************************************************************/ +static void +opts_unpack_net16(IN char *p_req_key, + IN char *p_key, IN char *p_val_str, IN uint16_t * p_val) +{ + if (!strcmp(p_req_key, p_key)) { + uint32_t val; + val = strtoul(p_val_str, NULL, 0); + CL_ASSERT(val < 0x10000); + if (cl_hton32(val) != *p_val) { + log_config_value(p_key, "0x%04x", val); + *p_val = cl_hton16((uint16_t) val); + } + } +} + +/********************************************************************** + **********************************************************************/ +static void +opts_unpack_uint8(IN char *p_req_key, + IN char *p_key, IN char *p_val_str, IN uint8_t * p_val) +{ + if (!strcmp(p_req_key, p_key)) { + uint32_t val; + val = strtoul(p_val_str, NULL, 0); + CL_ASSERT(val < 0x100); + if (val != *p_val) { + log_config_value(p_key, "%u", val); + *p_val = (uint8_t) val; + } + } +} + +/********************************************************************** + **********************************************************************/ +static void +opts_unpack_boolean(IN char *p_req_key, + IN char *p_key, IN char *p_val_str, IN boolean_t * p_val) +{ + if (!strcmp(p_req_key, p_key) && p_val_str) { + boolean_t val; + if (strcmp("TRUE", p_val_str)) + val = FALSE; + else + val = TRUE; + + if (val != *p_val) { + log_config_value(p_key, "%s", p_val_str); + *p_val = val; + } + } +} + +/********************************************************************** + **********************************************************************/ +static void +opts_unpack_charp(IN char *p_req_key, + IN char *p_key, IN char *p_val_str, IN char **p_val) +{ + if (!strcmp(p_req_key, p_key) && p_val_str) { + const char *current_str = *p_val ? *p_val : null_str ; + if (strcmp(p_val_str, current_str)) { + log_config_value(p_key, "%s", p_val_str); + /* special case the "(null)" string */ + if (strcmp(null_str, p_val_str) == 0) { + *p_val = NULL; + } else { + /* + Ignore the possible memory leak here; + the pointer may be to a static default. + */ + *p_val = strdup(p_val_str); + } + } + } +} + +/********************************************************************** + **********************************************************************/ +static char *clean_val(char *val) +{ + char *p = val; + /* clean leading spaces */ + while (isspace(*p)) + p++; + val = p; + if (!*val) + return val; + /* clean trailing spaces */ + p = val + strlen(val) - 1; + while (p > val && isspace(*p)) + p--; + p[1] = '\0'; + /* clean quotas */ + if ((*val == '\"' && *p == '\"') || (*val == '\'' && *p == '\'')) { + val++; + p--; + } + return val; +} + +/********************************************************************** + **********************************************************************/ +static void +subn_parse_qos_options(IN const char *prefix, + IN char *p_key, + IN char *p_val_str, IN osm_qos_options_t * opt) +{ + char name[256]; + + snprintf(name, sizeof(name), "%s_max_vls", prefix); + opts_unpack_uint32(name, p_key, p_val_str, &opt->max_vls); + snprintf(name, sizeof(name), "%s_high_limit", prefix); + opts_unpack_int32(name, p_key, p_val_str, &opt->high_limit); + snprintf(name, sizeof(name), "%s_vlarb_high", prefix); + opts_unpack_charp(name, p_key, p_val_str, &opt->vlarb_high); + snprintf(name, sizeof(name), "%s_vlarb_low", prefix); + opts_unpack_charp(name, p_key, p_val_str, &opt->vlarb_low); + snprintf(name, sizeof(name), "%s_sl2vl", prefix); + opts_unpack_charp(name, p_key, p_val_str, &opt->sl2vl); +} + +static int +subn_dump_qos_options(FILE * file, + const char *set_name, + const char *prefix, osm_qos_options_t * opt) +{ + return fprintf(file, "# %s\n" + "%s_max_vls %u\n" + "%s_high_limit %d\n" + "%s_vlarb_high %s\n" + "%s_vlarb_low %s\n" + "%s_sl2vl %s\n", + set_name, + prefix, opt->max_vls, + prefix, opt->high_limit, + prefix, opt->vlarb_high, + prefix, opt->vlarb_low, prefix, opt->sl2vl); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +append_prefix_route(IN osm_subn_t * const p_subn, uint64_t prefix, uint64_t guid) +{ + osm_prefix_route_t *route; + + route = malloc(sizeof *route); + if (! route) { + OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, "out of memory"); + return IB_ERROR; + } + + route->prefix = cl_hton64(prefix); + route->guid = cl_hton64(guid); + cl_qlist_insert_tail(&p_subn->prefix_routes_list, &route->list_item); + return IB_SUCCESS; +} + +static ib_api_status_t +osm_parse_prefix_routes_file(IN osm_subn_t * const p_subn) +{ + osm_log_t *log = &p_subn->p_osm->log; + FILE *fp; + char buf[1024]; + int line = 0; + int errors = 0; + + while (!cl_is_qlist_empty(&p_subn->prefix_routes_list)) { + cl_list_item_t *item = cl_qlist_remove_head(&p_subn->prefix_routes_list); + free(item); + } + + fp = fopen(p_subn->opt.prefix_routes_file, "r"); + if (! fp) { + if (errno == ENOENT) + return IB_SUCCESS; + + OSM_LOG(log, OSM_LOG_ERROR, "fopen(%s) failed: %s", + p_subn->opt.prefix_routes_file, strerror(errno)); + return IB_ERROR; + } + + while (fgets(buf, sizeof buf, fp) != NULL) { + char *p_prefix, *p_guid, *p_extra, *p_last, *p_end; + uint64_t prefix, guid; + + line++; + if (errors > 10) + break; + + p_prefix = strtok_r(buf, " \t\n", &p_last); + if (! p_prefix) + continue; /* ignore blank lines */ + + if (*p_prefix == '#') + continue; /* ignore comment lines */ + + p_guid = strtok_r(NULL, " \t\n", &p_last); + if (! p_guid) { + OSM_LOG(log, OSM_LOG_ERROR, "%s:%d: missing GUID\n", + p_subn->opt.prefix_routes_file, line); + errors++; + continue; + } + + p_extra = strtok_r(NULL, " \t\n", &p_last); + if (p_extra && *p_extra != '#') { + OSM_LOG(log, OSM_LOG_INFO, "%s:%d: extra tokens ignored\n", + p_subn->opt.prefix_routes_file, line); + } + + if (strcmp(p_prefix, "*") == 0) + prefix = 0; + else { + prefix = strtoull(p_prefix, &p_end, 16); + if (*p_end != '\0') { + OSM_LOG(log, OSM_LOG_ERROR, "%s:%d: illegal prefix: %s\n", + p_subn->opt.prefix_routes_file, line, p_prefix); + errors++; + continue; + } + } + + if (strcmp(p_guid, "*") == 0) + guid = 0; + else { + guid = strtoull(p_guid, &p_end, 16); + if (*p_end != '\0' && *p_end != '#') { + OSM_LOG(log, OSM_LOG_ERROR, "%s:%d: illegal GUID: %s\n", + p_subn->opt.prefix_routes_file, line, p_guid); + errors++; + continue; + } + } + + if (append_prefix_route(p_subn, prefix, guid) != IB_SUCCESS) { + errors++; + break; + } + } + + fclose(fp); + return (errors == 0) ? IB_SUCCESS : IB_ERROR; +} + +/********************************************************************** + **********************************************************************/ +static void subn_verify_max_vls(unsigned *max_vls, const char *prefix, unsigned dflt) +{ + if (!(*max_vls) || *max_vls > 15) { + log_report(" Invalid Cached Option: %s_max_vls=%u: " + "Using Default = %u\n", prefix, *max_vls, dflt); + *max_vls = dflt; + } +} + +static void subn_verify_high_limit(int *high_limit, const char *prefix, int dflt) +{ + if (*high_limit < 0 || *high_limit > 255) { + log_report(" Invalid Cached Option: %s_high_limit=%d: " + "Using Default: %d\n", prefix, *high_limit, dflt); + *high_limit = dflt; + } +} + +static void subn_verify_vlarb(char **vlarb, const char *prefix, + const char *suffix, char *dflt) +{ + char *str, *tok, *end, *ptr; + int count = 0; + + if (*vlarb == NULL) { + log_report(" Invalid Cached Option: %s_vlarb_%s: " + "Using Default\n", prefix, suffix); + *vlarb = dflt; + return; + } + + str = strdup(*vlarb); + + tok = strtok_r(str, ",\n", &ptr); + while (tok) { + char *vl_str, *weight_str; + + vl_str = tok; + weight_str = strchr(tok, ':'); + + if (weight_str) { + long vl, weight; + + *weight_str = '\0'; + weight_str++; + + vl = strtol(vl_str, &end, 0); + + if (*end) + log_report(" Warning: Cached Option " + "%s_vlarb_%s:vl=%s" + " improperly formatted\n", + prefix, suffix, vl_str); + else if (vl < 0 || vl > 14) + log_report(" Warning: Cached Option " + "%s_vlarb_%s:vl=%ld out of range\n", + prefix, suffix, vl); + + weight = strtol(weight_str, &end, 0); + + if (*end) + log_report(" Warning: Cached Option " + "%s_vlarb_%s:weight=%s " + "improperly formatted\n", + prefix, suffix, weight_str); + else if (weight < 0 || weight > 255) + log_report(" Warning: Cached Option " + "%s_vlarb_%s:weight=%ld " + "out of range\n", + prefix, suffix, weight); + } else + log_report(" Warning: Cached Option " + "%s_vlarb_%s:vl:weight=%s " + "improperly formatted\n", + prefix, suffix, tok); + + count++; + tok = strtok_r(NULL, ",\n", &ptr); + } + + if (count > 64) + log_report(" Warning: Cached Option %s_vlarb_%s: > 64 listed:" + " excess vl:weight pairs will be dropped\n", + prefix, suffix); + + free(str); +} + +static void subn_verify_sl2vl(char **sl2vl, const char *prefix, char *dflt) +{ + char *str, *tok, *end, *ptr; + int count = 0; + + if (*sl2vl == NULL) { + log_report(" Invalid Cached Option: %s_sl2vl: Using Default\n", + prefix); + *sl2vl = dflt; + return; + } + + str = strdup(*sl2vl); + + tok = strtok_r(str, ",\n", &ptr); + while (tok) { + long vl = strtol(tok, &end, 0); + + if (*end) + log_report(" Warning: Cached Option %s_sl2vl:vl=%s " + "improperly formatted\n", prefix, tok); + else if (vl < 0 || vl > 15) + log_report(" Warning: Cached Option %s_sl2vl:vl=%ld " + "out of range\n", prefix, vl); + + count++; + tok = strtok_r(NULL, ",\n", &ptr); + } + + if (count < 16) + log_report(" Warning: Cached Option %s_sl2vl: < 16 VLs " + "listed\n", prefix); + + if (count > 16) + log_report(" Warning: Cached Option %s_sl2vl: > 16 listed: " + "excess VLs will be dropped\n", prefix); + + free(str); +} + +static void subn_verify_qos_set(osm_qos_options_t *set, const char *prefix, + osm_qos_options_t *dflt) +{ + subn_verify_max_vls(&set->max_vls, prefix, dflt->max_vls); + subn_verify_high_limit(&set->high_limit, prefix, dflt->high_limit); + subn_verify_vlarb(&set->vlarb_low, prefix, "low", dflt->vlarb_low); + subn_verify_vlarb(&set->vlarb_high, prefix, "high", dflt->vlarb_high); + subn_verify_sl2vl(&set->sl2vl, prefix, dflt->sl2vl); +} + +int osm_subn_verify_config(IN osm_subn_opt_t * const p_opts) +{ + if (p_opts->lmc > 7) { + log_report(" Invalid Cached Option Value:lmc = %u:" + "Using Default:%u\n", p_opts->lmc, OSM_DEFAULT_LMC); + p_opts->lmc = OSM_DEFAULT_LMC; + } + + if (15 < p_opts->sm_priority) { + log_report(" Invalid Cached Option Value:sm_priority = %u:" + "Using Default:%u\n", + p_opts->sm_priority, OSM_DEFAULT_SM_PRIORITY); + p_opts->sm_priority = OSM_DEFAULT_SM_PRIORITY; + } + + if ((15 < p_opts->force_link_speed) || + (p_opts->force_link_speed > 7 && p_opts->force_link_speed < 15)) { + log_report(" Invalid Cached Option Value:force_link_speed = %u:" + "Using Default:%u\n", p_opts->force_link_speed, + IB_PORT_LINK_SPEED_ENABLED_MASK); + p_opts->force_link_speed = IB_PORT_LINK_SPEED_ENABLED_MASK; + } + + if (strcmp(p_opts->console, OSM_DISABLE_CONSOLE) + && strcmp(p_opts->console, OSM_LOCAL_CONSOLE) +#ifdef ENABLE_OSM_CONSOLE_SOCKET + && strcmp(p_opts->console, OSM_LOOPBACK_CONSOLE) + && strcmp(p_opts->console, OSM_REMOTE_CONSOLE) +#endif + ) { + log_report(" Invalid Cached Option Value:console = %s" + ", Using Default:%s\n", + p_opts->console, OSM_DEFAULT_CONSOLE); + p_opts->console = OSM_DEFAULT_CONSOLE; + } + + if (p_opts->qos) { + osm_qos_options_t dflt; + + /* the default options in qos_options must be correct. + * every other one need not be, b/c those will default + * back to whatever is in qos_options. + */ + + subn_set_default_qos_options(&dflt); + + subn_verify_qos_set(&p_opts->qos_options, "qos", &dflt); + subn_verify_qos_set(&p_opts->qos_ca_options, "qos_ca", + &p_opts->qos_options); + subn_verify_qos_set(&p_opts->qos_sw0_options, "qos_sw0", + &p_opts->qos_options); + subn_verify_qos_set(&p_opts->qos_swe_options, "qos_swe", + &p_opts->qos_options); + subn_verify_qos_set(&p_opts->qos_rtr_options, "qos_rtr", + &p_opts->qos_options); + } + +#ifdef ENABLE_OSM_PERF_MGR + if (p_opts->perfmgr_sweep_time_s < 1) { + log_report(" Invalid Cached Option Value:perfmgr_sweep_time_s " + "= %u Using Default:%u\n", + p_opts->perfmgr_sweep_time_s, + OSM_PERFMGR_DEFAULT_SWEEP_TIME_S); + p_opts->perfmgr_sweep_time_s = OSM_PERFMGR_DEFAULT_SWEEP_TIME_S; + } + if (p_opts->perfmgr_max_outstanding_queries < 1) { + log_report(" Invalid Cached Option Value:" + "perfmgr_max_outstanding_queries = %u" + " Using Default:%u\n", + p_opts->perfmgr_max_outstanding_queries, + OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES); + p_opts->perfmgr_max_outstanding_queries = + OSM_PERFMGR_DEFAULT_MAX_OUTSTANDING_QUERIES; + } +#endif + + return 0; +} + +/********************************************************************** + **********************************************************************/ +int osm_subn_parse_conf_file(char *file_name, osm_subn_opt_t * const p_opts) +{ + char line[1024]; + FILE *opts_file; + char *p_key, *p_val; + + opts_file = fopen(file_name, "r"); + if (!opts_file) { + if (errno == ENOENT) + return 1; + printf("cannot open file \'%s\': %s\n", + file_name, strerror(errno)); + return -1; + } + + printf(" Reading Cached Option File: %s\n", file_name); + cl_log_event("OpenSM", CL_LOG_INFO, line, NULL, 0); + + p_opts->config_file = file_name; + + while (fgets(line, 1023, opts_file) != NULL) { + /* get the first token */ + p_key = strtok_r(line, " \t\n", &p_val); + if (!p_key) + continue; + + p_val = clean_val(p_val); + + opts_unpack_net64("guid", p_key, p_val, &p_opts->guid); + + opts_unpack_net64("m_key", p_key, p_val, &p_opts->m_key); + + opts_unpack_net64("sm_key", p_key, p_val, &p_opts->sm_key); + + opts_unpack_net64("sa_key", p_key, p_val, &p_opts->sa_key); + + opts_unpack_net64("subnet_prefix", + p_key, p_val, &p_opts->subnet_prefix); + + opts_unpack_net16("m_key_lease_period", + p_key, p_val, &p_opts->m_key_lease_period); + + opts_unpack_uint32("sweep_interval", + p_key, p_val, &p_opts->sweep_interval); + + opts_unpack_uint32("max_wire_smps", + p_key, p_val, &p_opts->max_wire_smps); + + opts_unpack_charp("console", p_key, p_val, &p_opts->console); + + opts_unpack_uint16("console_port", + p_key, p_val, &p_opts->console_port); + + opts_unpack_uint32("transaction_timeout", + p_key, p_val, &p_opts->transaction_timeout); + + opts_unpack_uint32("max_msg_fifo_timeout", + p_key, p_val, &p_opts->max_msg_fifo_timeout); + + opts_unpack_uint8("sm_priority", + p_key, p_val, &p_opts->sm_priority); + + opts_unpack_uint8("lmc", p_key, p_val, &p_opts->lmc); + + opts_unpack_boolean("lmc_esp0", + p_key, p_val, &p_opts->lmc_esp0); + + opts_unpack_uint8("max_op_vls", + p_key, p_val, &p_opts->max_op_vls); + + opts_unpack_uint8("force_link_speed", + p_key, p_val, &p_opts->force_link_speed); + + opts_unpack_boolean("reassign_lids", + p_key, p_val, &p_opts->reassign_lids); + + opts_unpack_boolean("ignore_other_sm", + p_key, p_val, &p_opts->ignore_other_sm); + + opts_unpack_boolean("single_thread", + p_key, p_val, &p_opts->single_thread); + + opts_unpack_boolean("disable_multicast", + p_key, p_val, &p_opts->disable_multicast); + + opts_unpack_boolean("force_log_flush", + p_key, p_val, &p_opts->force_log_flush); + + opts_unpack_uint8("subnet_timeout", + p_key, p_val, &p_opts->subnet_timeout); + + opts_unpack_uint8("packet_life_time", + p_key, p_val, &p_opts->packet_life_time); + + opts_unpack_uint8("vl_stall_count", + p_key, p_val, &p_opts->vl_stall_count); + + opts_unpack_uint8("leaf_vl_stall_count", + p_key, p_val, &p_opts->leaf_vl_stall_count); + + opts_unpack_uint8("head_of_queue_lifetime", + p_key, p_val, + &p_opts->head_of_queue_lifetime); + + opts_unpack_uint8("leaf_head_of_queue_lifetime", p_key, p_val, + &p_opts->leaf_head_of_queue_lifetime); + + opts_unpack_uint8("local_phy_errors_threshold", p_key, p_val, + &p_opts->local_phy_errors_threshold); + + opts_unpack_uint8("overrun_errors_threshold", + p_key, p_val, + &p_opts->overrun_errors_threshold); + + opts_unpack_uint32("sminfo_polling_timeout", + p_key, p_val, + &p_opts->sminfo_polling_timeout); + + opts_unpack_uint32("polling_retry_number", + p_key, p_val, &p_opts->polling_retry_number); + + opts_unpack_boolean("force_heavy_sweep", + p_key, p_val, &p_opts->force_heavy_sweep); + + opts_unpack_uint8("log_flags", + p_key, p_val, &p_opts->log_flags); + + opts_unpack_charp("port_prof_ignore_file", p_key, p_val, + &p_opts->port_prof_ignore_file); + + opts_unpack_boolean("port_profile_switch_nodes", p_key, p_val, + &p_opts->port_profile_switch_nodes); + + opts_unpack_boolean("sweep_on_trap", + p_key, p_val, &p_opts->sweep_on_trap); + + opts_unpack_charp("routing_engine", + p_key, p_val, &p_opts->routing_engine_names); + + opts_unpack_boolean("connect_roots", + p_key, p_val, &p_opts->connect_roots); + + opts_unpack_boolean("use_ucast_cache", + p_key, p_val, &p_opts->use_ucast_cache); + + opts_unpack_charp("log_file", p_key, p_val, &p_opts->log_file); + + opts_unpack_uint32("log_max_size", + p_key, p_val, + (void *) & p_opts->log_max_size); + p_opts->log_max_size *= 1024 * 1024; /* convert to MB */ + + opts_unpack_charp("partition_config_file", + p_key, p_val, &p_opts->partition_config_file); + + opts_unpack_boolean("no_partition_enforcement", p_key, p_val, + &p_opts->no_partition_enforcement); + + opts_unpack_boolean("qos", p_key, p_val, &p_opts->qos); + + opts_unpack_charp("qos_policy_file", + p_key, p_val, &p_opts->qos_policy_file); + + opts_unpack_boolean("accum_log_file", + p_key, p_val, &p_opts->accum_log_file); + + opts_unpack_charp("dump_files_dir", + p_key, p_val, &p_opts->dump_files_dir); + + opts_unpack_charp("lid_matrix_dump_file", + p_key, p_val, &p_opts->lid_matrix_dump_file); + + opts_unpack_charp("lfts_file", + p_key, p_val, &p_opts->lfts_file); + + opts_unpack_charp("root_guid_file", + p_key, p_val, &p_opts->root_guid_file); + + opts_unpack_charp("cn_guid_file", + p_key, p_val, &p_opts->cn_guid_file); + + opts_unpack_charp("ids_guid_file", + p_key, p_val, &p_opts->ids_guid_file); + + opts_unpack_charp("guid_routing_order_file", + p_key, p_val, &p_opts->guid_routing_order_file); + + opts_unpack_charp("sa_db_file", + p_key, p_val, &p_opts->sa_db_file); + + opts_unpack_boolean("exit_on_fatal", + p_key, p_val, &p_opts->exit_on_fatal); + + opts_unpack_boolean("honor_guid2lid_file", + p_key, p_val, &p_opts->honor_guid2lid_file); + + opts_unpack_boolean("daemon", p_key, p_val, &p_opts->daemon); + + opts_unpack_boolean("sm_inactive", + p_key, p_val, &p_opts->sm_inactive); + + opts_unpack_boolean("babbling_port_policy", + p_key, p_val, + &p_opts->babbling_port_policy); + +#ifdef ENABLE_OSM_PERF_MGR + opts_unpack_boolean("perfmgr", p_key, p_val, &p_opts->perfmgr); + + opts_unpack_boolean("perfmgr_redir", + p_key, p_val, &p_opts->perfmgr_redir); + + opts_unpack_uint16("perfmgr_sweep_time_s", + p_key, p_val, &p_opts->perfmgr_sweep_time_s); + + opts_unpack_uint32("perfmgr_max_outstanding_queries", + p_key, p_val, + &p_opts->perfmgr_max_outstanding_queries); + + opts_unpack_charp("event_db_dump_file", + p_key, p_val, &p_opts->event_db_dump_file); +#endif /* ENABLE_OSM_PERF_MGR */ + + opts_unpack_charp("event_plugin_name", + p_key, p_val, &p_opts->event_plugin_name); + + opts_unpack_charp("node_name_map_name", + p_key, p_val, &p_opts->node_name_map_name); + + subn_parse_qos_options("qos", + p_key, p_val, &p_opts->qos_options); + + subn_parse_qos_options("qos_ca", + p_key, p_val, &p_opts->qos_ca_options); + + subn_parse_qos_options("qos_sw0", + p_key, p_val, &p_opts->qos_sw0_options); + + subn_parse_qos_options("qos_swe", + p_key, p_val, &p_opts->qos_swe_options); + + subn_parse_qos_options("qos_rtr", + p_key, p_val, &p_opts->qos_rtr_options); + + opts_unpack_boolean("enable_quirks", + p_key, p_val, &p_opts->enable_quirks); + + opts_unpack_boolean("no_clients_rereg", + p_key, p_val, &p_opts->no_clients_rereg); + + opts_unpack_charp("prefix_routes_file", + p_key, p_val, &p_opts->prefix_routes_file); + + opts_unpack_boolean("consolidate_ipv6_snm_req", + p_key, p_val, &p_opts->consolidate_ipv6_snm_req); + } + fclose(opts_file); + + osm_subn_verify_config(p_opts); + + return 0; +} + +int osm_subn_rescan_conf_files(IN osm_subn_t * const p_subn) +{ + FILE *opts_file; + char line[1024]; + char *p_key, *p_val, *p_last; + + if (!p_subn->opt.config_file) + return 0; + + opts_file = fopen(p_subn->opt.config_file, "r"); + if (!opts_file) { + if (errno == ENOENT) + return 1; + OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, + "cannot open file \'%s\': %s\n", + p_subn->opt.config_file, strerror(errno)); + return -1; + } + + subn_init_qos_options(&p_subn->opt.qos_options); + subn_init_qos_options(&p_subn->opt.qos_ca_options); + subn_init_qos_options(&p_subn->opt.qos_sw0_options); + subn_init_qos_options(&p_subn->opt.qos_swe_options); + subn_init_qos_options(&p_subn->opt.qos_rtr_options); + + while (fgets(line, 1023, opts_file) != NULL) { + /* get the first token */ + p_key = strtok_r(line, " \t\n", &p_last); + if (p_key) { + p_val = strtok_r(NULL, " \t\n", &p_last); + + subn_parse_qos_options("qos", p_key, p_val, + &p_subn->opt.qos_options); + + subn_parse_qos_options("qos_ca", p_key, p_val, + &p_subn->opt.qos_ca_options); + + subn_parse_qos_options("qos_sw0", p_key, p_val, + &p_subn->opt.qos_sw0_options); + + subn_parse_qos_options("qos_swe", p_key, p_val, + &p_subn->opt.qos_swe_options); + + subn_parse_qos_options("qos_rtr", p_key, p_val, + &p_subn->opt.qos_rtr_options); + + } + } + fclose(opts_file); + + osm_subn_verify_config(&p_subn->opt); + + osm_parse_prefix_routes_file(p_subn); + + return 0; +} + +/********************************************************************** + **********************************************************************/ +int osm_subn_output_conf(FILE *out, IN osm_subn_opt_t *const p_opts) +{ + fprintf(out, + "#\n# DEVICE ATTRIBUTES OPTIONS\n#\n" + "# The port GUID on which the OpenSM is running\n" + "guid 0x%016" PRIx64 "\n\n" + "# M_Key value sent to all ports qualifying all Set(PortInfo)\n" + "m_key 0x%016" PRIx64 "\n\n" + "# The lease period used for the M_Key on this subnet in [sec]\n" + "m_key_lease_period %u\n\n" + "# SM_Key value of the SM used for SM authentication\n" + "sm_key 0x%016" PRIx64 "\n\n" + "# SM_Key value to qualify rcv SA queries as 'trusted'\n" + "sa_key 0x%016" PRIx64 "\n\n" + "# Note that for both values above (sm_key and sa_key)\n" + "# OpenSM version 3.2.1 and below used the default value '1'\n" + "# in a host byte order, it is fixed now but you may need to\n" + "# change the values to interoperate with old OpenSM running\n" + "# on a little endian machine.\n\n" + "# Subnet prefix used on this subnet\n" + "subnet_prefix 0x%016" PRIx64 "\n\n" + "# The LMC value used on this subnet\n" + "lmc %u\n\n" + "# lmc_esp0 determines whether LMC value used on subnet is used for\n" + "# enhanced switch port 0. If TRUE, LMC value for subnet is used for\n" + "# ESP0. Otherwise, LMC value for ESP0s is 0.\n" + "lmc_esp0 %s\n\n" + "# The code of maximal time a packet can live in a switch\n" + "# The actual time is 4.096usec * 2^\n" + "# The value 0x14 disables this mechanism\n" + "packet_life_time 0x%02x\n\n" + "# The number of sequential packets dropped that cause the port\n" + "# to enter the VLStalled state. The result of setting this value to\n" + "# zero is undefined.\n" + "vl_stall_count 0x%02x\n\n" + "# The number of sequential packets dropped that cause the port\n" + "# to enter the VLStalled state. This value is for switch ports\n" + "# driving a CA or router port. The result of setting this value\n" + "# to zero is undefined.\n" + "leaf_vl_stall_count 0x%02x\n\n" + "# The code of maximal time a packet can wait at the head of\n" + "# transmission queue.\n" + "# The actual time is 4.096usec * 2^\n" + "# The value 0x14 disables this mechanism\n" + "head_of_queue_lifetime 0x%02x\n\n" + "# The maximal time a packet can wait at the head of queue on\n" + "# switch port connected to a CA or router port\n" + "leaf_head_of_queue_lifetime 0x%02x\n\n" + "# Limit the maximal operational VLs\n" + "max_op_vls %u\n\n" + "# Force PortInfo:LinkSpeedEnabled on switch ports\n" + "# If 0, don't modify PortInfo:LinkSpeedEnabled on switch port\n" + "# Otherwise, use value for PortInfo:LinkSpeedEnabled on switch port\n" + "# Values are (IB Spec 1.2.1, 14.2.5.6 Table 146 \"PortInfo\")\n" + "# 1: 2.5 Gbps\n" + "# 3: 2.5 or 5.0 Gbps\n" + "# 5: 2.5 or 10.0 Gbps\n" + "# 7: 2.5 or 5.0 or 10.0 Gbps\n" + "# 2,4,6,8-14 Reserved\n" + "# Default 15: set to PortInfo:LinkSpeedSupported\n" + "force_link_speed %u\n\n" + "# The subnet_timeout code that will be set for all the ports\n" + "# The actual timeout is 4.096usec * 2^\n" + "subnet_timeout %u\n\n" + "# Threshold of local phy errors for sending Trap 129\n" + "local_phy_errors_threshold 0x%02x\n\n" + "# Threshold of credit overrun errors for sending Trap 130\n" + "overrun_errors_threshold 0x%02x\n\n", + cl_ntoh64(p_opts->guid), + cl_ntoh64(p_opts->m_key), + cl_ntoh16(p_opts->m_key_lease_period), + cl_ntoh64(p_opts->sm_key), + cl_ntoh64(p_opts->sa_key), + cl_ntoh64(p_opts->subnet_prefix), + p_opts->lmc, + p_opts->lmc_esp0 ? "TRUE" : "FALSE", + p_opts->packet_life_time, + p_opts->vl_stall_count, + p_opts->leaf_vl_stall_count, + p_opts->head_of_queue_lifetime, + p_opts->leaf_head_of_queue_lifetime, + p_opts->max_op_vls, + p_opts->force_link_speed, + p_opts->subnet_timeout, + p_opts->local_phy_errors_threshold, + p_opts->overrun_errors_threshold); + + fprintf(out, + "#\n# PARTITIONING OPTIONS\n#\n" + "# Partition configuration file to be used\n" + "partition_config_file %s\n\n" + "# Disable partition enforcement by switches\n" + "no_partition_enforcement %s\n\n", + p_opts->partition_config_file, + p_opts->no_partition_enforcement ? "TRUE" : "FALSE"); + + fprintf(out, + "#\n# SWEEP OPTIONS\n#\n" + "# The number of seconds between subnet sweeps (0 disables it)\n" + "sweep_interval %u\n\n" + "# If TRUE cause all lids to be reassigned\n" + "reassign_lids %s\n\n" + "# If TRUE forces every sweep to be a heavy sweep\n" + "force_heavy_sweep %s\n\n" + "# If TRUE every trap will cause a heavy sweep.\n" + "# NOTE: successive identical traps (>10) are suppressed\n" + "sweep_on_trap %s\n\n", + p_opts->sweep_interval, + p_opts->reassign_lids ? "TRUE" : "FALSE", + p_opts->force_heavy_sweep ? "TRUE" : "FALSE", + p_opts->sweep_on_trap ? "TRUE" : "FALSE"); + + fprintf(out, + "#\n# ROUTING OPTIONS\n#\n" + "# If TRUE count switches as link subscriptions\n" + "port_profile_switch_nodes %s\n\n", + p_opts->port_profile_switch_nodes ? "TRUE" : "FALSE"); + + fprintf(out, + "# Name of file with port guids to be ignored by port profiling\n" + "port_prof_ignore_file %s\n\n", p_opts->port_prof_ignore_file ? + p_opts->port_prof_ignore_file : null_str); + + fprintf(out, + "# Routing engine\n" + "# Multiple routing engines can be specified separated by\n" + "# commas so that specific ordering of routing algorithms will\n" + "# be tried if earlier routing engines fail.\n" + "# Supported engines: minhop, updn, file, ftree, lash, dor\n" + "routing_engine %s\n\n", p_opts->routing_engine_names ? + p_opts->routing_engine_names : null_str); + + fprintf(out, + "# Connect roots (use FALSE if unsure)\n" + "connect_roots %s\n\n", + p_opts->connect_roots ? "TRUE" : "FALSE"); + + fprintf(out, + "# Use unicast routing cache (use FALSE if unsure)\n" + "use_ucast_cache %s\n\n", + p_opts->use_ucast_cache ? "TRUE" : "FALSE"); + + fprintf(out, + "# Lid matrix dump file name\n" + "lid_matrix_dump_file %s\n\n", p_opts->lid_matrix_dump_file ? + p_opts->lid_matrix_dump_file : null_str); + + fprintf(out, + "# LFTs file name\nlfts_file %s\n\n", + p_opts->lfts_file ? p_opts->lfts_file : null_str); + + fprintf(out, + "# The file holding the root node guids (for fat-tree or Up/Down)\n" + "# One guid in each line\nroot_guid_file %s\n\n", + p_opts->root_guid_file ? p_opts->root_guid_file : null_str); + + fprintf(out, + "# The file holding the fat-tree compute node guids\n" + "# One guid in each line\ncn_guid_file %s\n\n", + p_opts->cn_guid_file ? p_opts->cn_guid_file : null_str); + + fprintf(out, + "# The file holding the node ids which will be used by" + " Up/Down algorithm instead\n# of GUIDs (one guid and" + " id in each line)\nids_guid_file %s\n\n", + p_opts->ids_guid_file ? p_opts->ids_guid_file : null_str); + + fprintf(out, + "# The file holding guid routing order guids (for MinHop and Up/Down)\n" + "guid_routing_order_file %s\n\n", + p_opts->guid_routing_order_file ? p_opts->guid_routing_order_file : null_str); + + fprintf(out, + "# SA database file name\nsa_db_file %s\n\n", + p_opts->sa_db_file ? p_opts->sa_db_file : null_str); + + fprintf(out, + "#\n# HANDOVER - MULTIPLE SMs OPTIONS\n#\n" + "# SM priority used for deciding who is the master\n" + "# Range goes from 0 (lowest priority) to 15 (highest).\n" + "sm_priority %u\n\n" + "# If TRUE other SMs on the subnet should be ignored\n" + "ignore_other_sm %s\n\n" + "# Timeout in [msec] between two polls of active master SM\n" + "sminfo_polling_timeout %u\n\n" + "# Number of failing polls of remote SM that declares it dead\n" + "polling_retry_number %u\n\n" + "# If TRUE honor the guid2lid file when coming out of standby\n" + "# state, if such file exists and is valid\n" + "honor_guid2lid_file %s\n\n", + p_opts->sm_priority, + p_opts->ignore_other_sm ? "TRUE" : "FALSE", + p_opts->sminfo_polling_timeout, + p_opts->polling_retry_number, + p_opts->honor_guid2lid_file ? "TRUE" : "FALSE"); + + fprintf(out, + "#\n# TIMING AND THREADING OPTIONS\n#\n" + "# Maximum number of SMPs sent in parallel\n" + "max_wire_smps %u\n\n" + "# The maximum time in [msec] allowed for a transaction to complete\n" + "transaction_timeout %u\n\n" + "# Maximal time in [msec] a message can stay in the incoming message queue.\n" + "# If there is more than one message in the queue and the last message\n" + "# stayed in the queue more than this value, any SA request will be\n" + "# immediately returned with a BUSY status.\n" + "max_msg_fifo_timeout %u\n\n" + "# Use a single thread for handling SA queries\n" + "single_thread %s\n\n", + p_opts->max_wire_smps, + p_opts->transaction_timeout, + p_opts->max_msg_fifo_timeout, + p_opts->single_thread ? "TRUE" : "FALSE"); + + fprintf(out, + "#\n# MISC OPTIONS\n#\n" + "# Daemon mode\n" + "daemon %s\n\n" + "# SM Inactive\n" + "sm_inactive %s\n\n" + "# Babbling Port Policy\n" + "babbling_port_policy %s\n\n", + p_opts->daemon ? "TRUE" : "FALSE", + p_opts->sm_inactive ? "TRUE" : "FALSE", + p_opts->babbling_port_policy ? "TRUE" : "FALSE"); + +#ifdef ENABLE_OSM_PERF_MGR + fprintf(out, + "#\n# Performance Manager Options\n#\n" + "# perfmgr enable\n" + "perfmgr %s\n\n" + "# perfmgr redirection enable\n" + "perfmgr_redir %s\n\n" + "# sweep time in seconds\n" + "perfmgr_sweep_time_s %u\n\n" + "# Max outstanding queries\n" + "perfmgr_max_outstanding_queries %u\n\n", + p_opts->perfmgr ? "TRUE" : "FALSE", + p_opts->perfmgr_redir ? "TRUE" : "FALSE", + p_opts->perfmgr_sweep_time_s, + p_opts->perfmgr_max_outstanding_queries); + + fprintf(out, + "#\n# Event DB Options\n#\n" + "# Dump file to dump the events to\n" + "event_db_dump_file %s\n\n", p_opts->event_db_dump_file ? + p_opts->event_db_dump_file : null_str); +#endif /* ENABLE_OSM_PERF_MGR */ + + fprintf(out, + "#\n# Event Plugin Options\n#\n" + "event_plugin_name %s\n\n", p_opts->event_plugin_name ? + p_opts->event_plugin_name : null_str); + + fprintf(out, + "#\n# Node name map for mapping node's to more descriptive node descriptions\n" + "# (man ibnetdiscover for more information)\n#\n" + "node_name_map_name %s\n\n", p_opts->node_name_map_name ? + p_opts->node_name_map_name : null_str); + + fprintf(out, + "#\n# DEBUG FEATURES\n#\n" + "# The log flags used\n" + "log_flags 0x%02x\n\n" + "# Force flush of the log file after each log message\n" + "force_log_flush %s\n\n" + "# Log file to be used\n" + "log_file %s\n\n" + "# Limit the size of the log file in MB. If overrun, log is restarted\n" + "log_max_size %lu\n\n" + "# If TRUE will accumulate the log over multiple OpenSM sessions\n" + "accum_log_file %s\n\n" + "# The directory to hold the file OpenSM dumps\n" + "dump_files_dir %s\n\n" + "# If TRUE enables new high risk options and hardware specific quirks\n" + "enable_quirks %s\n\n" + "# If TRUE disables client reregistration\n" + "no_clients_rereg %s\n\n" + "# If TRUE OpenSM should disable multicast support and\n" + "# no multicast routing is performed if TRUE\n" + "disable_multicast %s\n\n" + "# If TRUE opensm will exit on fatal initialization issues\n" + "exit_on_fatal %s\n\n" "# console [off|local" +#ifdef ENABLE_OSM_CONSOLE_SOCKET + "|loopback|socket]\n" +#else + "]\n" +#endif + "console %s\n\n" + "# Telnet port for console (default %d)\n" + "console_port %d\n\n", + p_opts->log_flags, + p_opts->force_log_flush ? "TRUE" : "FALSE", + p_opts->log_file, + p_opts->log_max_size/1024/1024, + p_opts->accum_log_file ? "TRUE" : "FALSE", + p_opts->dump_files_dir, + p_opts->enable_quirks ? "TRUE" : "FALSE", + p_opts->no_clients_rereg ? "TRUE" : "FALSE", + p_opts->disable_multicast ? "TRUE" : "FALSE", + p_opts->exit_on_fatal ? "TRUE" : "FALSE", + p_opts->console, + OSM_DEFAULT_CONSOLE_PORT, p_opts->console_port); + + fprintf(out, + "#\n# QoS OPTIONS\n#\n" + "# Enable QoS setup\n" + "qos %s\n\n" + "# QoS policy file to be used\n" + "qos_policy_file %s\n\n", + p_opts->qos ? "TRUE" : "FALSE", p_opts->qos_policy_file); + + subn_dump_qos_options(out, + "QoS default options", "qos", + &p_opts->qos_options); + fprintf(out, "\n"); + subn_dump_qos_options(out, + "QoS CA options", "qos_ca", + &p_opts->qos_ca_options); + fprintf(out, "\n"); + subn_dump_qos_options(out, + "QoS Switch Port 0 options", "qos_sw0", + &p_opts->qos_sw0_options); + fprintf(out, "\n"); + subn_dump_qos_options(out, + "QoS Switch external ports options", "qos_swe", + &p_opts->qos_swe_options); + fprintf(out, "\n"); + subn_dump_qos_options(out, + "QoS Router ports options", "qos_rtr", + &p_opts->qos_rtr_options); + fprintf(out, "\n"); + + fprintf(out, + "# Prefix routes file name\n" + "prefix_routes_file %s\n\n", + p_opts->prefix_routes_file); + + fprintf(out, + "#\n# IPv6 Solicited Node Multicast (SNM) Options\n#\n" + "consolidate_ipv6_snm_req %s\n\n", + p_opts->consolidate_ipv6_snm_req ? "TRUE" : "FALSE"); + + /* optional string attributes ... */ + + return 0; +} + +int osm_subn_write_conf_file(char *file_name, IN osm_subn_opt_t *const p_opts) +{ + FILE *opts_file; + + opts_file = fopen(file_name, "w"); + if (!opts_file) { + printf("cannot open file \'%s\' for writing: %s\n", + file_name, strerror(errno)); + return -1; + } + + if (osm_subn_output_conf(opts_file, p_opts) < 0) + return -1; + + fclose(opts_file); + + return 0; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_sw_info_rcv.c b/contrib/ofed/management/opensm/opensm/osm_sw_info_rcv.c new file mode 100644 index 000000000000..ce86adb5a955 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_sw_info_rcv.c @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_si_rcv_t. + * This object represents the SwitchInfo Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_si_rcv_get_port_info(IN osm_sm_t * sm, IN osm_switch_t * const p_sw) +{ + osm_madw_context_t context; + uint8_t port_num; + osm_physp_t *p_physp; + osm_node_t *p_node; + uint8_t num_ports; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_sw); + + p_node = p_sw->p_node; + + CL_ASSERT(osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH); + + /* + Request PortInfo attribute for each port on the switch. + */ + p_physp = osm_node_get_physp_ptr(p_node, 0); + + context.pi_context.node_guid = osm_node_get_node_guid(p_node); + context.pi_context.port_guid = osm_physp_get_port_guid(p_physp); + context.pi_context.set_method = FALSE; + context.pi_context.light_sweep = FALSE; + context.pi_context.active_transition = FALSE; + + num_ports = osm_node_get_num_physp(p_node); + + for (port_num = 0; port_num < num_ports; port_num++) { + status = osm_req_get(sm, osm_physp_get_dr_path_ptr(p_physp), + IB_MAD_ATTR_PORT_INFO, cl_hton32(port_num), + CL_DISP_MSGID_NONE, &context); + if (status != IB_SUCCESS) + /* continue the loop despite the error */ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3602: " + "Failure initiating PortInfo request (%s)\n", + ib_get_err_str(status)); + } + + OSM_LOG_EXIT(sm->p_log); +} + +#if 0 +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_si_rcv_get_fwd_tbl(IN osm_sm_t * sm, IN osm_switch_t * const p_sw) +{ + osm_madw_context_t context; + osm_dr_path_t *p_dr_path; + osm_physp_t *p_physp; + osm_node_t *p_node; + uint32_t block_id_ho; + uint32_t max_block_id_ho; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_sw); + + p_node = p_sw->p_node; + + CL_ASSERT(osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH); + + context.lft_context.node_guid = osm_node_get_node_guid(p_node); + context.lft_context.set_method = FALSE; + + max_block_id_ho = osm_switch_get_max_block_id_in_use(p_sw); + + p_physp = osm_node_get_physp_ptr(p_node, 0); + p_dr_path = osm_physp_get_dr_path_ptr(p_physp); + + for (block_id_ho = 0; block_id_ho <= max_block_id_ho; block_id_ho++) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Retrieving FT block %u\n", block_id_ho); + + status = osm_req_get(sm, p_dr_path, IB_MAD_ATTR_LIN_FWD_TBL, + cl_hton32(block_id_ho), + CL_DISP_MSGID_NONE, &context); + if (status != IB_SUCCESS) + /* continue the loop despite the error */ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3603: " + "Failure initiating PortInfo request (%s)\n", + ib_get_err_str(status)); + } + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + The plock must be held before calling this function. +**********************************************************************/ +static void +__osm_si_rcv_get_mcast_fwd_tbl(IN osm_sm_t * sm, IN osm_switch_t * const p_sw) +{ + osm_madw_context_t context; + osm_dr_path_t *p_dr_path; + osm_physp_t *p_physp; + osm_node_t *p_node; + osm_mcast_tbl_t *p_tbl; + uint32_t block_id_ho; + uint32_t max_block_id_ho; + uint32_t position; + uint32_t max_position; + uint32_t attr_mod_ho; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_sw); + + p_node = p_sw->p_node; + + CL_ASSERT(osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH); + + if (osm_switch_get_mcast_fwd_tbl_size(p_sw) == 0) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Multicast not supported by switch 0x%016" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(p_node))); + goto Exit; + } + + context.mft_context.node_guid = osm_node_get_node_guid(p_node); + context.mft_context.set_method = FALSE; + + p_tbl = osm_switch_get_mcast_tbl_ptr(p_sw); + max_block_id_ho = osm_mcast_tbl_get_max_block(p_tbl); + + if (max_block_id_ho > IB_MCAST_MAX_BLOCK_ID) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3609: " + "Out-of-range mcast block size = %u on switch 0x%016" + PRIx64 "\n", max_block_id_ho, + cl_ntoh64(osm_node_get_node_guid(p_node))); + goto Exit; + } + + max_position = osm_mcast_tbl_get_max_position(p_tbl); + + CL_ASSERT(max_position <= IB_MCAST_POSITION_MAX); + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Max MFT block = %u, Max position = %u\n", max_block_id_ho, + max_position); + + p_physp = osm_node_get_physp_ptr(p_node, 0); + p_dr_path = osm_physp_get_dr_path_ptr(p_physp); + + for (block_id_ho = 0; block_id_ho <= max_block_id_ho; block_id_ho++) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Retrieving MFT block %u\n", block_id_ho); + + for (position = 0; position <= max_position; position++) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Retrieving MFT position %u\n", position); + + attr_mod_ho = + block_id_ho | position << IB_MCAST_POSITION_SHIFT; + status = + osm_req_get(sm, p_dr_path, + IB_MAD_ATTR_MCAST_FWD_TBL, + cl_hton32(attr_mod_ho), + CL_DISP_MSGID_NONE, &context); + if (status != IB_SUCCESS) + /* continue the loop despite the error */ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3607: " + "Failure initiating PortInfo request (%s)\n", + ib_get_err_str(status)); + } + } + +Exit: + OSM_LOG_EXIT(sm->p_log); +} +#endif + +/********************************************************************** + Lock must be held on entry to this function. +**********************************************************************/ +static void +__osm_si_rcv_process_new(IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw) +{ + osm_switch_t *p_sw; + osm_switch_t *p_check; + ib_switch_info_t *p_si; + ib_smp_t *p_smp; + cl_qmap_t *p_sw_guid_tbl; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_sw_guid_tbl = &sm->p_subn->sw_guid_tbl; + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_si = (ib_switch_info_t *) ib_smp_get_payload_ptr(p_smp); + + osm_dump_switch_info(sm->p_log, p_si, OSM_LOG_DEBUG); + + /* + Allocate a new switch object for this switch, + and place it in the switch table. + */ + p_sw = osm_switch_new(p_node, p_madw); + if (p_sw == NULL) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3608: " + "Unable to allocate new switch object\n"); + goto Exit; + } + + /* set subnet max mlid to the minimum MulticastFDBCap of all switches */ + if (p_sw->mcast_tbl.max_mlid_ho < sm->p_subn->max_mcast_lid_ho) { + sm->p_subn->max_mcast_lid_ho = p_sw->mcast_tbl.max_mlid_ho; + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Subnet max multicast lid is 0x%X\n", + sm->p_subn->max_mcast_lid_ho); + } + + /* set subnet max unicast lid to the minimum LinearFDBCap of all switches */ + if (cl_ntoh16(p_si->lin_cap) < sm->p_subn->max_ucast_lid_ho) { + sm->p_subn->max_ucast_lid_ho = cl_ntoh16(p_si->lin_cap); + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Subnet max unicast lid is 0x%X\n", + sm->p_subn->max_ucast_lid_ho); + } + + p_check = (osm_switch_t *) cl_qmap_insert(p_sw_guid_tbl, + osm_node_get_node_guid + (p_node), &p_sw->map_item); + + if (p_check != p_sw) { + /* + This shouldn't happen since we hold the lock! + */ + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3605: " + "Unable to add new switch object to database\n"); + osm_switch_delete(&p_sw); + goto Exit; + } + + p_node->sw = p_sw; + + /* + Update the switch info according to the + info we just received. + */ + osm_switch_set_switch_info(p_sw, p_si); + p_sw->discovery_count++; + + /* + Get the PortInfo attribute for every port. + */ + __osm_si_rcv_get_port_info(sm, p_sw); + + /* + Don't bother retrieving the current unicast and multicast tables + from the switches. The current version of SM does + not support silent take-over of an existing multicast + configuration. + + Gathering the multicast tables can also generate large amounts + of extra subnet-init traffic. + + The code to retrieve the tables was fully debugged. + */ +#if 0 + __osm_si_rcv_get_fwd_tbl(sm, p_sw); + if (!sm->p_subn->opt.disable_multicast) + __osm_si_rcv_get_mcast_fwd_tbl(sm, p_sw); +#endif + +Exit: + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + Lock must be held on entry to this function. + Return 1 if the caller is expected to send a change_detected event. + this can not be done internally as the event needs the lock... +**********************************************************************/ +static boolean_t +__osm_si_rcv_process_existing(IN osm_sm_t * sm, + IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw) +{ + osm_switch_t *p_sw = p_node->sw; + ib_switch_info_t *p_si; + osm_si_context_t *p_si_context; + ib_smp_t *p_smp; + boolean_t is_change_detected = FALSE; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_si = (ib_switch_info_t *) ib_smp_get_payload_ptr(p_smp); + p_si_context = osm_madw_get_si_context_ptr(p_madw); + + if (p_si_context->set_method) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Received logical SetResp()\n"); + + osm_switch_set_switch_info(p_sw, p_si); + } else { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Received logical GetResp()\n"); + + osm_switch_set_switch_info(p_sw, p_si); + + /* + Check the port state change bit. If true, then this switch + has seen a port state transition, so continue probing. + */ + if (p_si_context->light_sweep == TRUE) { + /* This is a light sweep */ + /* If the mad was returned with an error - + signal a change to the state manager. */ + if (ib_smp_get_status(p_smp) != 0) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "GetResp() received with error in light sweep. " + "Commencing heavy sweep\n"); + is_change_detected = TRUE; + } else { + /* + If something changed, then just signal the + state manager. Don't attempt to probe + further during a light sweep. + */ + if (ib_switch_info_get_state_change(p_si)) { + osm_dump_switch_info(sm->p_log, p_si, + OSM_LOG_DEBUG); + is_change_detected = TRUE; + } + } + } else { + /* + This is a heavy sweep. Get information regardless + of the state change bit. + */ + p_sw->discovery_count++; + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "discovery_count is:%u\n", + p_sw->discovery_count); + + /* If this is the first discovery - then get the port_info */ + if (p_sw->discovery_count == 1) + __osm_si_rcv_get_port_info(sm, p_sw); + else + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Not discovering again through switch:0x%" + PRIx64 "\n", + osm_node_get_node_guid(p_sw->p_node)); + } + } + + OSM_LOG_EXIT(sm->p_log); + return is_change_detected; +} + +/********************************************************************** + **********************************************************************/ +void osm_si_rcv_process(IN void *context, IN void *data) +{ + osm_sm_t *sm = context; + osm_madw_t *p_madw = data; + ib_switch_info_t *p_si; + ib_smp_t *p_smp; + osm_node_t *p_node; + ib_net64_t node_guid; + osm_si_context_t *p_context; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_si = (ib_switch_info_t *) ib_smp_get_payload_ptr(p_smp); + + /* + Acquire the switch object and add the switch info. + */ + p_context = osm_madw_get_si_context_ptr(p_madw); + + node_guid = p_context->node_guid; + + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Switch GUID 0x%016" PRIx64 ", TID 0x%" PRIx64 "\n", + cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); + + CL_PLOCK_EXCL_ACQUIRE(sm->p_lock); + + p_node = osm_get_node_by_guid(sm->p_subn, node_guid); + if (!p_node) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3606: " + "SwitchInfo received for nonexistent node " + "with GUID 0x%" PRIx64 "\n", cl_ntoh64(node_guid)); + else { + + /* + Hack for bad value in Mellanox switch + */ + if (cl_ntoh16(p_si->lin_top) > IB_LID_UCAST_END_HO) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3610: " + "\n\t\t\t\tBad LinearFDBTop value = 0x%X " + "on switch 0x%" PRIx64 + "\n\t\t\t\tForcing internal correction to 0x%X\n", + cl_ntoh16(p_si->lin_top), + cl_ntoh64(osm_node_get_node_guid(p_node)), 0); + + p_si->lin_top = 0; + } + + /* + Acquire the switch object for this switch. + */ + if (!p_node->sw) { + __osm_si_rcv_process_new(sm, p_node, p_madw); + /* + A new switch was found during the sweep so we need + to ignore the current LFT settings. + */ + sm->p_subn->ignore_existing_lfts = TRUE; + } else { + /* we might get back a request for signaling change was detected */ + if (__osm_si_rcv_process_existing(sm, p_node, p_madw)) { + CL_PLOCK_RELEASE(sm->p_lock); + sm->p_subn->force_heavy_sweep = TRUE; + goto Exit; + } + } + } + + CL_PLOCK_RELEASE(sm->p_lock); +Exit: + OSM_LOG_EXIT(sm->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_switch.c b/contrib/ofed/management/opensm/opensm/osm_switch.c new file mode 100644 index 000000000000..9807791f47af --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_switch.c @@ -0,0 +1,667 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_switch_t. + * This object represents an Infiniband switch. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +cl_status_t +osm_switch_set_hops(IN osm_switch_t * const p_sw, + IN const uint16_t lid_ho, + IN const uint8_t port_num, IN const uint8_t num_hops) +{ + if (lid_ho > p_sw->max_lid_ho) + return -1; + if (!p_sw->hops[lid_ho]) { + p_sw->hops[lid_ho] = malloc(p_sw->num_ports); + if (!p_sw->hops[lid_ho]) + return -1; + memset(p_sw->hops[lid_ho], OSM_NO_PATH, p_sw->num_ports); + } + + p_sw->hops[lid_ho][port_num] = num_hops; + if (p_sw->hops[lid_ho][0] > num_hops) + p_sw->hops[lid_ho][0] = num_hops; + + return 0; +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osm_switch_init(IN osm_switch_t * const p_sw, + IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw) +{ + ib_api_status_t status = IB_SUCCESS; + ib_switch_info_t *p_si; + ib_smp_t *p_smp; + uint8_t num_ports; + uint32_t port_num; + + p_smp = osm_madw_get_smp_ptr(p_madw); + p_si = (ib_switch_info_t *) ib_smp_get_payload_ptr(p_smp); + num_ports = osm_node_get_num_physp(p_node); + + CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_SWITCH_INFO); + + p_sw->p_node = p_node; + p_sw->switch_info = *p_si; + p_sw->num_ports = num_ports; + p_sw->need_update = 2; + + /* Initiate the linear forwarding table */ + + if (!p_si->lin_cap) { + /* This switch does not support linear forwarding tables */ + status = IB_UNSUPPORTED; + goto Exit; + } + + p_sw->lft = malloc(IB_LID_UCAST_END_HO + 1); + if (!p_sw->lft) { + status = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + + /* Initialize the table to OSM_NO_PATH, which is "invalid port" */ + memset(p_sw->lft, OSM_NO_PATH, IB_LID_UCAST_END_HO + 1); + + p_sw->p_prof = malloc(sizeof(*p_sw->p_prof) * num_ports); + if (p_sw->p_prof == NULL) { + status = IB_INSUFFICIENT_MEMORY; + goto Exit; + } + + memset(p_sw->p_prof, 0, sizeof(*p_sw->p_prof) * num_ports); + + status = osm_mcast_tbl_init(&p_sw->mcast_tbl, + osm_node_get_num_physp(p_node), + cl_ntoh16(p_si->mcast_cap)); + if (status != IB_SUCCESS) + goto Exit; + + for (port_num = 0; port_num < num_ports; port_num++) + osm_port_prof_construct(&p_sw->p_prof[port_num]); + +Exit: + return (status); +} + +/********************************************************************** + **********************************************************************/ +void osm_switch_delete(IN OUT osm_switch_t ** const pp_sw) +{ + osm_switch_t *p_sw = *pp_sw; + unsigned i; + + osm_mcast_tbl_destroy(&p_sw->mcast_tbl); + free(p_sw->p_prof); + if (p_sw->lft) + free(p_sw->lft); + if (p_sw->new_lft) + free(p_sw->new_lft); + if (p_sw->hops) { + for (i = 0; i < p_sw->num_hops; i++) + if (p_sw->hops[i]) + free(p_sw->hops[i]); + free(p_sw->hops); + } + free(*pp_sw); + *pp_sw = NULL; +} + +/********************************************************************** + **********************************************************************/ +osm_switch_t *osm_switch_new(IN osm_node_t * const p_node, + IN const osm_madw_t * const p_madw) +{ + ib_api_status_t status; + osm_switch_t *p_sw; + + CL_ASSERT(p_madw); + CL_ASSERT(p_node); + + p_sw = (osm_switch_t *) malloc(sizeof(*p_sw)); + if (p_sw) { + memset(p_sw, 0, sizeof(*p_sw)); + status = osm_switch_init(p_sw, p_node, p_madw); + if (status != IB_SUCCESS) + osm_switch_delete(&p_sw); + } + + return (p_sw); +} + +/********************************************************************** + **********************************************************************/ +boolean_t +osm_switch_get_lft_block(IN const osm_switch_t * const p_sw, + IN const uint16_t block_id, + OUT uint8_t * const p_block) +{ + uint16_t base_lid_ho = block_id * IB_SMP_DATA_SIZE; + + CL_ASSERT(p_sw); + CL_ASSERT(p_block); + + if (base_lid_ho > p_sw->max_lid_ho) + return FALSE; + + CL_ASSERT(base_lid_ho + IB_SMP_DATA_SIZE <= IB_LID_UCAST_END_HO); + memcpy(p_block, &(p_sw->lft[base_lid_ho]), IB_SMP_DATA_SIZE); + return TRUE; +} + +/********************************************************************** + **********************************************************************/ +static struct osm_remote_node * +osm_switch_find_guid_common(IN const osm_switch_t * const p_sw, + IN struct osm_remote_guids_count *r, + IN uint8_t port_num, + IN int find_sys_guid, + IN int find_node_guid) +{ + struct osm_remote_node *p_remote_guid = NULL; + osm_physp_t *p_physp; + osm_physp_t *p_rem_physp; + osm_node_t *p_rem_node; + uint64_t sys_guid; + uint64_t node_guid; + int i; + + CL_ASSERT(p_sw); + + p_physp = osm_node_get_physp_ptr(p_sw->p_node, port_num); + p_rem_physp = osm_physp_get_remote(p_physp); + p_rem_node = osm_physp_get_node_ptr(p_rem_physp); + sys_guid = p_rem_node->node_info.sys_guid; + node_guid = p_rem_node->node_info.node_guid; + + for (i = 0; i < r->count; i++) { + if ((!find_sys_guid + || r->guids[i].node->node_info.sys_guid == sys_guid) + && (!find_node_guid + || r->guids[i].node->node_info.node_guid == node_guid)) { + p_remote_guid = &r->guids[i]; + break; + } + } + + return p_remote_guid; +} + +static struct osm_remote_node * +osm_switch_find_sys_guid_count(IN const osm_switch_t * const p_sw, + IN struct osm_remote_guids_count *r, + IN uint8_t port_num) +{ + return osm_switch_find_guid_common(p_sw, r, port_num, 1, 0); +} + +static struct osm_remote_node * +osm_switch_find_node_guid_count(IN const osm_switch_t * const p_sw, + IN struct osm_remote_guids_count *r, + IN uint8_t port_num) +{ + return osm_switch_find_guid_common(p_sw, r, port_num, 0, 1); +} + +/********************************************************************** + **********************************************************************/ +uint8_t +osm_switch_recommend_path(IN const osm_switch_t * const p_sw, + IN osm_port_t * p_port, + IN const uint16_t lid_ho, + IN unsigned start_from, + IN const boolean_t ignore_existing, + IN const boolean_t dor) +{ + /* + We support an enhanced LMC aware routing mode: + In the case of LMC > 0, we can track the remote side + system and node for all of the lids of the target + and try and avoid routing again through the same + system / node. + + If this procedure is provided with the tracking array + and counter we can conduct this algorithm. + */ + boolean_t routing_for_lmc = (p_port->priv != NULL); + uint16_t base_lid; + uint8_t hops; + uint8_t least_hops; + uint8_t port_num; + uint8_t num_ports; + uint32_t least_paths = 0xFFFFFFFF; + unsigned i; + /* + The follwing will track the least paths if the + route should go through a new system/node + */ + uint32_t least_paths_other_sys = 0xFFFFFFFF; + uint32_t least_paths_other_nodes = 0xFFFFFFFF; + uint32_t least_forwarded_to = 0xFFFFFFFF; + uint32_t check_count; + uint8_t best_port = 0; + /* + These vars track the best port if it connects to + not used system/node. + */ + uint8_t best_port_other_sys = 0; + uint8_t best_port_other_node = 0; + boolean_t port_found = FALSE; + osm_physp_t *p_physp; + osm_physp_t *p_rem_physp; + osm_node_t *p_rem_node; + osm_node_t *p_rem_node_first = NULL; + struct osm_remote_node *p_remote_guid = NULL; + + CL_ASSERT(lid_ho > 0); + + if (p_port->p_node->sw) { + if (p_port->p_node->sw == p_sw) + return 0; + base_lid = osm_port_get_base_lid(p_port); + } else { + p_physp = p_port->p_physp; + if (!p_physp || !p_physp->p_remote_physp || + !p_physp->p_remote_physp->p_node->sw) + return OSM_NO_PATH; + + if (p_physp->p_remote_physp->p_node->sw == p_sw) + return p_physp->p_remote_physp->port_num; + base_lid = + osm_node_get_base_lid(p_physp->p_remote_physp->p_node, 0); + } + base_lid = cl_ntoh16(base_lid); + + num_ports = p_sw->num_ports; + + least_hops = osm_switch_get_least_hops(p_sw, base_lid); + if (least_hops == OSM_NO_PATH) + return (OSM_NO_PATH); + + /* + First, inquire with the forwarding table for an existing + route. If one is found, honor it unless: + 1. the ignore existing flag is set. + 2. the physical port is not a valid one or not healthy + 3. the physical port has a remote port (the link is up) + 4. the port has min-hops to the target (avoid loops) + */ + if (!ignore_existing) { + port_num = osm_switch_get_port_by_lid(p_sw, lid_ho); + + if (port_num != OSM_NO_PATH) { + CL_ASSERT(port_num < num_ports); + + p_physp = + osm_node_get_physp_ptr(p_sw->p_node, port_num); + /* + Don't be too trusting of the current forwarding table! + Verify that the port number is legal and that the + LID is reachable through this port. + */ + if (p_physp && osm_physp_is_healthy(p_physp) && + osm_physp_get_remote(p_physp)) { + hops = + osm_switch_get_hop_count(p_sw, base_lid, + port_num); + /* + If we aren't using pre-defined user routes + function, then we need to make sure that the + current path is the minimum one. In case of + having such a user function - this check will + not be done, and the old routing will be used. + Note: This means that it is the user's job to + clean all data in the forwarding tables that + he wants to be overridden by the minimum + hop function. + */ + if (hops == least_hops) + return (port_num); + } + } + } + + /* + This algorithm selects a port based on a static load balanced + selection across equal hop-count ports. + There is lots of room for improved sophistication here, + possibly guided by user configuration info. + */ + + /* + OpenSM routing is "local" - not considering a full lid to lid + path. As such we can not guarantee a path will not loop if we + do not always follow least hops. + So we must abort if not least hops. + */ + + /* port number starts with one and num_ports is 1 + num phys ports */ + for (i = start_from; i < start_from + num_ports; i++) { + port_num = i%num_ports; + if (!port_num || + osm_switch_get_hop_count(p_sw, base_lid, port_num) != + least_hops) + continue; + + /* let us make sure it is not down or unhealthy */ + p_physp = osm_node_get_physp_ptr(p_sw->p_node, port_num); + if (!p_physp || !osm_physp_is_healthy(p_physp) || + /* + we require all - non sma ports to be linked + to be routed through + */ + !osm_physp_get_remote(p_physp)) + continue; + + /* + We located a least-hop port, possibly one of many. + For this port, check the running total count of + the number of paths through this port. Select + the port routing the least number of paths. + */ + check_count = + osm_port_prof_path_count_get(&p_sw->p_prof[port_num]); + + /* + Advanced LMC routing requires tracking of the + best port by the node connected to the other side of + it. + */ + if (routing_for_lmc) { + /* Is the sys guid already used ? */ + p_remote_guid = osm_switch_find_sys_guid_count(p_sw, + p_port->priv, + port_num); + + /* If not update the least hops for this case */ + if (!p_remote_guid) { + if (check_count < least_paths_other_sys) { + least_paths_other_sys = check_count; + best_port_other_sys = port_num; + least_forwarded_to = 0; + } + } else { /* same sys found - try node */ + /* Else is the node guid already used ? */ + p_remote_guid = osm_switch_find_node_guid_count(p_sw, + p_port->priv, + port_num); + + /* If not update the least hops for this case */ + if (!p_remote_guid + && check_count < least_paths_other_nodes) { + least_paths_other_nodes = check_count; + best_port_other_node = port_num; + least_forwarded_to = 0; + } + /* else prior sys and node guid already used */ + + } /* same sys found */ + } + + /* routing for LMC mode */ + /* + the count is min but also lower then the max subscribed + */ + if (check_count < least_paths) { + if (dor) { + /* Get the Remote Node */ + p_rem_physp = osm_physp_get_remote(p_physp); + p_rem_node = + osm_physp_get_node_ptr(p_rem_physp); + /* use the first dimension, but spread + * traffic out among the group of ports + * representing that dimension */ + if (port_found) { + if (p_rem_node != p_rem_node_first) + continue; + } else + p_rem_node_first = p_rem_node; + } + port_found = TRUE; + best_port = port_num; + least_paths = check_count; + if (routing_for_lmc + && p_remote_guid + && p_remote_guid->forwarded_to < least_forwarded_to) + least_forwarded_to = p_remote_guid->forwarded_to; + } else if (routing_for_lmc + && p_remote_guid + && check_count == least_paths + && p_remote_guid->forwarded_to < least_forwarded_to) { + least_forwarded_to = p_remote_guid->forwarded_to; + best_port = port_num; + } + } + + if (port_found == FALSE) + return (OSM_NO_PATH); + + /* + if we are in enhanced routing mode and the best port is not + the local port 0 + */ + if (routing_for_lmc && best_port) { + /* Select the least hop port of the non used sys first */ + if (best_port_other_sys) + best_port = best_port_other_sys; + else if (best_port_other_node) + best_port = best_port_other_node; + } + + return (best_port); +} + +/********************************************************************** + **********************************************************************/ +void osm_switch_clear_hops(IN osm_switch_t * p_sw) +{ + unsigned i; + + for (i = 0; i < p_sw->num_hops; i++) + if (p_sw->hops[i]) + memset(p_sw->hops[i], OSM_NO_PATH, p_sw->num_ports); +} + +/********************************************************************** + **********************************************************************/ +int +osm_switch_prepare_path_rebuild(IN osm_switch_t * p_sw, IN uint16_t max_lids) +{ + uint8_t **hops; + unsigned i; + + for (i = 0; i < p_sw->num_ports; i++) + osm_port_prof_construct(&p_sw->p_prof[i]); + + osm_switch_clear_hops(p_sw); + + if (!p_sw->new_lft && + !(p_sw->new_lft = malloc(IB_LID_UCAST_END_HO + 1))) + return IB_INSUFFICIENT_MEMORY; + + memset(p_sw->new_lft, OSM_NO_PATH, IB_LID_UCAST_END_HO + 1); + + if (!p_sw->hops) { + hops = malloc((max_lids + 1) * sizeof(hops[0])); + if (!hops) + return -1; + memset(hops, 0, (max_lids + 1) * sizeof(hops[0])); + p_sw->hops = hops; + p_sw->num_hops = max_lids + 1; + } else if (max_lids + 1 > p_sw->num_hops) { + uint8_t **old_hops; + + hops = malloc((max_lids + 1) * sizeof(hops[0])); + if (!hops) + return -1; + memcpy(hops, p_sw->hops, p_sw->num_hops * sizeof(hops[0])); + memset(hops + p_sw->num_hops, 0, + (max_lids + 1 - p_sw->num_hops) * sizeof(hops[0])); + old_hops = p_sw->hops; + p_sw->hops = hops; + p_sw->num_hops = max_lids + 1; + free(old_hops); + } + p_sw->max_lid_ho = max_lids; + + return 0; +} + +/********************************************************************** + **********************************************************************/ +uint8_t +osm_switch_get_port_least_hops(IN const osm_switch_t * const p_sw, + IN const osm_port_t * p_port) +{ + uint16_t lid; + + if (p_port->p_node->sw) { + if (p_port->p_node->sw == p_sw) + return 0; + lid = osm_node_get_base_lid(p_port->p_node, 0); + return osm_switch_get_least_hops(p_sw, cl_ntoh16(lid)); + } else { + osm_physp_t *p = p_port->p_physp; + uint8_t hops; + + if (!p || !p->p_remote_physp || !p->p_remote_physp->p_node->sw) + return OSM_NO_PATH; + if (p->p_remote_physp->p_node->sw == p_sw) + return 1; + lid = osm_node_get_base_lid(p->p_remote_physp->p_node, 0); + hops = osm_switch_get_least_hops(p_sw, cl_ntoh16(lid)); + return hops != OSM_NO_PATH ? hops + 1 : OSM_NO_PATH; + } +} + +/********************************************************************** + **********************************************************************/ +uint8_t +osm_switch_recommend_mcast_path(IN osm_switch_t * const p_sw, + IN osm_port_t * p_port, + IN uint16_t const mlid_ho, + IN boolean_t const ignore_existing) +{ + uint16_t base_lid; + uint8_t hops; + uint8_t port_num; + uint8_t num_ports; + uint8_t least_hops; + + CL_ASSERT(mlid_ho >= IB_LID_MCAST_START_HO); + + if (p_port->p_node->sw) { + if (p_port->p_node->sw == p_sw) + return 0; + base_lid = osm_port_get_base_lid(p_port); + } else { + osm_physp_t *p_physp = p_port->p_physp; + if (!p_physp || !p_physp->p_remote_physp || + !p_physp->p_remote_physp->p_node->sw) + return OSM_NO_PATH; + if (p_physp->p_remote_physp->p_node->sw == p_sw) + return p_physp->p_remote_physp->port_num; + base_lid = + osm_node_get_base_lid(p_physp->p_remote_physp->p_node, 0); + } + base_lid = cl_ntoh16(base_lid); + num_ports = p_sw->num_ports; + + /* + If the user wants us to ignore existing multicast routes, + then simply return the shortest hop count path to the + target port. + + Otherwise, return the first port that has a path to the target, + picking from the ports that are already in the multicast group. + */ + if (!ignore_existing) { + for (port_num = 1; port_num < num_ports; port_num++) { + if (!osm_mcast_tbl_is_port + (&p_sw->mcast_tbl, mlid_ho, port_num)) + continue; + /* + Don't be too trusting of the current forwarding table! + Verify that the LID is reachable through this port. + */ + hops = + osm_switch_get_hop_count(p_sw, base_lid, port_num); + if (hops != OSM_NO_PATH) + return (port_num); + } + } + + /* + Either no existing mcast paths reach this port or we are + ignoring existing paths. + + Determine the best multicast path to the target. Note that this + algorithm is slightly different from the one used for unicast route + recommendation. In this case (multicast), we must NOT + perform any sort of load balancing. We MUST take the FIRST + port found that has <= the lowest hop count path. This prevents + more than one multicast path to the same remote switch which + prevents a multicast loop. Multicast loops are bad since the same + multicast packet will go around and around, inevitably creating + a black hole that will destroy the Earth in a firey conflagration. + */ + least_hops = osm_switch_get_least_hops(p_sw, base_lid); + for (port_num = 1; port_num < num_ports; port_num++) + if (osm_switch_get_hop_count(p_sw, base_lid, port_num) == + least_hops) + break; + + CL_ASSERT(port_num < num_ports); + return (port_num); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_trap_rcv.c b/contrib/ofed/management/opensm/opensm/osm_trap_rcv.c new file mode 100644 index 000000000000..46fbad784329 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_trap_rcv.c @@ -0,0 +1,714 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_trap_rcv_t. + * This object represents the Trap Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void osm_req_get_node_desc(IN osm_sm_t * sm, osm_physp_t *p_physp); + +/********************************************************************** + * + * TRAP HANDLING: + * + * Assuming traps can be caused by bad hardware we should provide + * a mechanism for filtering their propagation into the actual logic + * of OpenSM such that it is not overloaded by them. + * + * We will provide a trap filtering mechanism with "Aging" capability. + * This mechanism will track incoming traps, clasify them by their + * source and content and provide back their age. + * + * A timer running in the background will toggle a timer counter + * that should be referenced by the aging algorithm. + * To provide an efficient handling of aging. We also track all traps + * in a sorted list by their aging. + * + * The generic Aging Tracker mechanism is implemented in the + * cl_aging_tracker object. + * + **********************************************************************/ + +typedef struct osm_trap_agingracker_context { + osm_log_t *p_log; + osm_physp_t *p_physp; +} osm_trap_aging_tracker_context_t; + +/********************************************************************** + **********************************************************************/ +static osm_physp_t *get_physp_by_lid_and_num(IN osm_sm_t * sm, + IN uint16_t lid, IN uint8_t num) +{ + cl_ptr_vector_t *p_vec = &(sm->p_subn->port_lid_tbl); + osm_port_t *p_port; + + if (lid > cl_ptr_vector_get_size(p_vec)) + return NULL; + + p_port = (osm_port_t *) cl_ptr_vector_get(p_vec, lid); + if (!p_port) + return NULL; + + if (osm_node_get_num_physp(p_port->p_node) < num) + return NULL; + + return osm_node_get_physp_ptr(p_port->p_node, num); +} + +/********************************************************************** + **********************************************************************/ +uint64_t +osm_trap_rcv_aging_tracker_callback(IN uint64_t key, + IN uint32_t num_regs, IN void *context) +{ + osm_sm_t *sm = context; + uint16_t lid; + uint8_t port_num; + osm_physp_t *p_physp; + + OSM_LOG_ENTER(sm->p_log); + + if (osm_exit_flag) + /* We got an exit flag - do nothing */ + return 0; + + lid = cl_ntoh16((uint16_t) ((key & 0x0000FFFF00000000ULL) >> 32)); + port_num = (uint8_t) ((key & 0x00FF000000000000ULL) >> 48); + + p_physp = get_physp_by_lid_and_num(sm, lid, port_num); + if (!p_physp) + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Cannot find port num:%u with lid:%u\n", + port_num, lid); + /* make sure the physp is still valid */ + /* If the health port was false - set it to true */ + else if (!osm_physp_is_healthy(p_physp)) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Clearing health bit of port num:%u with lid:%u\n", + port_num, lid); + + /* Clear its health bit */ + osm_physp_set_health(p_physp, TRUE); + } + + OSM_LOG_EXIT(sm->p_log); + + /* We want to remove the event from the tracker - so + need to return zero. */ + return 0; +} + +/********************************************************************** + * CRC calculation for notice identification + **********************************************************************/ + +#define CRC32_POLYNOMIAL 0xEDB88320L + +/* calculate the crc for a given buffer */ +static uint32_t __osm_trap_calc_crc32(void *buffer, uint32_t count) +{ + uint32_t temp1, temp2; + uint32_t crc = -1L; + unsigned char *p = (unsigned char *)buffer; + /* pre - calculated table for faster crc calculation */ + static uint32_t crc_table[256]; + static boolean_t first = TRUE; + int i, j; + + /* if we need to initialize the lookup table */ + if (first) { + /* calc the CRC table */ + for (i = 0; i <= 255; i++) { + crc = i; + for (j = 8; j > 0; j--) + if (crc & 1) + crc = (crc >> 1) ^ CRC32_POLYNOMIAL; + else + crc >>= 1; + crc_table[i] = crc; + } + first = FALSE; + } + + crc = -1L; + /* do the calculation */ + while (count-- != 0) { + temp1 = (crc >> 8) & 0x00FFFFFFL; + temp2 = crc_table[((int)crc ^ *p++) & 0xFF]; + crc = temp1 ^ temp2; + } + return crc; +} + +/******************************************************************** + ********************************************************************/ + +/* The key is created in the following manner: + port_num lid crc + \______/ \___/ \___/ + 16b 16b 32b +*/ +static void +__osm_trap_get_key(IN uint16_t lid, + IN uint8_t port_num, + IN ib_mad_notice_attr_t * p_ntci, OUT uint64_t * trap_key) +{ + uint32_t crc = 0; + + CL_ASSERT(trap_key); + + crc = __osm_trap_calc_crc32(p_ntci, sizeof(ib_mad_notice_attr_t)); + *trap_key = ((uint64_t) port_num << 48) | ((uint64_t) lid << 32) | crc; +} + +/********************************************************************** + **********************************************************************/ +static int __print_num_received(IN uint32_t num_received) +{ + uint32_t i; + + /* Series is 10, 20, 50, 100, 200, 500, ... */ + i = num_received; + while (i >= 10) { + if (i % 10) + break; + i = i / 10; + } + + if (i == 1 || i == 2 || i == 5) + return 1; + else + return 0; +} + +static int disable_port(osm_sm_t *sm, osm_physp_t *p) +{ + uint8_t payload[IB_SMP_DATA_SIZE]; + osm_madw_context_t context; + ib_port_info_t *pi = (ib_port_info_t *)payload; + int ret; + + /* select the nearest port to master opensm */ + if (p->p_remote_physp && + p->dr_path.hop_count > p->p_remote_physp->dr_path.hop_count) + p = p->p_remote_physp; + + /* If trap 131, might want to disable peer port if available */ + /* but peer port has been observed not to respond to SM requests */ + + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3810: " + "Disabling physical port 0x%016" PRIx64 " num:%u\n", + cl_ntoh64(osm_physp_get_port_guid(p)), p->port_num); + + memcpy(payload, &p->port_info, sizeof(ib_port_info_t)); + + /* Set port to disabled/down */ + ib_port_info_set_port_state(pi, IB_LINK_DOWN); + ib_port_info_set_port_phys_state(IB_PORT_PHYS_STATE_DISABLED, pi); + + /* Issue set of PortInfo */ + context.pi_context.node_guid = osm_node_get_node_guid(p->p_node); + context.pi_context.port_guid = osm_physp_get_port_guid(p); + context.pi_context.set_method = TRUE; + context.pi_context.light_sweep = FALSE; + context.pi_context.active_transition = FALSE; + + ret = osm_req_set(sm, osm_physp_get_dr_path_ptr(p), + payload, sizeof(payload), IB_MAD_ATTR_PORT_INFO, + cl_hton32(osm_physp_get_port_num(p)), + CL_DISP_MSGID_NONE, &context); + if (ret) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3811: " + "Request to set PortInfo failed\n"); + + return ret; +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_trap_rcv_process_request(IN osm_sm_t * sm, + IN const osm_madw_t * const p_madw) +{ + uint8_t payload[sizeof(ib_mad_notice_attr_t)]; + ib_smp_t *p_smp; + ib_mad_notice_attr_t *p_ntci = (ib_mad_notice_attr_t *) payload; + ib_api_status_t status; + osm_madw_t tmp_madw; /* we need a copy to last after repress */ + uint64_t trap_key; + uint32_t num_received; + osm_physp_t *p_physp; + cl_ptr_vector_t *p_tbl; + osm_port_t *p_port; + ib_net16_t source_lid = 0; + boolean_t is_gsi = TRUE; + uint8_t port_num = 0; + boolean_t physp_change_trap = FALSE; + uint64_t event_wheel_timeout = OSM_DEFAULT_TRAP_SUPRESSION_TIMEOUT; + boolean_t run_heavy_sweep = FALSE; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + if (osm_exit_flag) + /* + We got an exit flag - do nothing + Otherwise we start a sweep on the trap 144 caused by + cleaning up SM Cap bit... + */ + goto Exit; + + /* update the is_gsi flag according to the mgmt_class field */ + if (p_madw->p_mad->mgmt_class == IB_MCLASS_SUBN_LID || + p_madw->p_mad->mgmt_class == IB_MCLASS_SUBN_DIR) + is_gsi = FALSE; + + /* No real need to grab the lock for this function. */ + memset(payload, 0, sizeof(payload)); + memset(&tmp_madw, 0, sizeof(tmp_madw)); + + p_smp = osm_madw_get_smp_ptr(p_madw); + + if (p_smp->method != IB_MAD_METHOD_TRAP) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3801: " + "Unsupported method 0x%X\n", p_smp->method); + goto Exit; + } + + /* + * The NOTICE Attribute is part of the SMP CLASS attributes + * As such the actual attribute data resides inside the SMP + * payload. + */ + + memcpy(payload, &(p_smp->data), IB_SMP_DATA_SIZE); + memcpy(&tmp_madw, p_madw, sizeof(tmp_madw)); + + if (is_gsi == FALSE) { + /* We are in smi flow */ + /* + * When we received a TRAP with dlid = 0 - it means it + * came from our own node. So we need to fix it. + */ + + if (p_madw->mad_addr.addr_type.smi.source_lid == 0) { + /* Check if the sm_base_lid is 0. If yes - this means + that the local lid wasn't configured yet. Don't send + a response to the trap. */ + if (sm->p_subn->sm_base_lid == 0) { + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Received SLID=0 Trap with local LID=0. Ignoring MAD\n"); + goto Exit; + } + OSM_LOG(sm->p_log, OSM_LOG_DEBUG, + "Received SLID=0 Trap. Using local LID:%u instead\n", + cl_ntoh16(sm->p_subn->sm_base_lid)); + tmp_madw.mad_addr.addr_type.smi.source_lid = + sm->p_subn->sm_base_lid; + } + + source_lid = tmp_madw.mad_addr.addr_type.smi.source_lid; + + /* Print some info about the incoming Trap */ + if (ib_notice_is_generic(p_ntci)) { + if ((p_ntci->g_or_v.generic.trap_num == CL_HTON16(129)) + || (p_ntci->g_or_v.generic.trap_num == + CL_HTON16(130)) + || (p_ntci->g_or_v.generic.trap_num == + CL_HTON16(131))) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "Received Generic Notice type:%u " + "num:%u (%s) Producer:%u (%s) " + "from LID:%u Port %d TID:0x%016" + PRIx64 "\n", ib_notice_get_type(p_ntci), + cl_ntoh16(p_ntci->g_or_v.generic. + trap_num), + ib_get_trap_str(p_ntci->g_or_v.generic. + trap_num), + cl_ntoh32(ib_notice_get_prod_type + (p_ntci)), + ib_get_producer_type_str + (ib_notice_get_prod_type(p_ntci)), + cl_hton16(source_lid), + p_ntci->data_details.ntc_129_131. + port_num, cl_ntoh64(p_smp->trans_id)); + else + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "Received Generic Notice type:%u " + "num:%u (%s) Producer:%u (%s) " + "from LID:%u TID:0x%016" PRIx64 + "\n", ib_notice_get_type(p_ntci), + cl_ntoh16(p_ntci->g_or_v.generic. + trap_num), + ib_get_trap_str(p_ntci->g_or_v.generic. + trap_num), + cl_ntoh32(ib_notice_get_prod_type + (p_ntci)), + ib_get_producer_type_str + (ib_notice_get_prod_type(p_ntci)), + cl_hton16(source_lid), + cl_ntoh64(p_smp->trans_id)); + } else + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "Received Vendor Notice type:%u vend:0x%06X " + "dev:%u from LID:%u TID:0x%016" PRIx64 "\n", + ib_notice_get_type(p_ntci), + cl_ntoh32(ib_notice_get_vend_id(p_ntci)), + cl_ntoh16(p_ntci->g_or_v.vend.dev_id), + cl_ntoh16(source_lid), + cl_ntoh64(p_smp->trans_id)); + } + + osm_dump_notice(sm->p_log, p_ntci, OSM_LOG_VERBOSE); + + p_physp = osm_get_physp_by_mad_addr(sm->p_log, + sm->p_subn, &tmp_madw.mad_addr); + if (p_physp) + p_smp->m_key = p_physp->port_info.m_key; + else + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3809: " + "Failed to find source physical port for trap\n"); + + status = osm_resp_send(sm, &tmp_madw, 0, payload); + if (status != IB_SUCCESS) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3802: " + "Error sending response (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + /* + * We would like to filter out recurring Traps so we track them by + * their source lid and content. If the same trap was already + * received within the aging time window more than 10 times, + * we simply ignore it. This is done only if we are in smi mode + */ + + if (is_gsi == FALSE) { + if (ib_notice_is_generic(p_ntci) && + ((p_ntci->g_or_v.generic.trap_num == CL_HTON16(129)) || + (p_ntci->g_or_v.generic.trap_num == CL_HTON16(130)) || + (p_ntci->g_or_v.generic.trap_num == CL_HTON16(131)))) { + /* If this is a trap 129, 130, or 131 - then this is a + * trap signaling a change on a physical port. + * Mark the physp_change_trap flag as TRUE. + */ + physp_change_trap = TRUE; + /* The source_lid should be based on the source_lid from the trap */ + source_lid = p_ntci->data_details.ntc_129_131.lid; + } + + /* If physp_change_trap is TRUE - the key will include the port number. + If not - the port_number in the key will be zero. */ + if (physp_change_trap == TRUE) { + port_num = p_ntci->data_details.ntc_129_131.port_num; + __osm_trap_get_key(source_lid, port_num, p_ntci, + &trap_key); + } else + __osm_trap_get_key(source_lid, 0, p_ntci, &trap_key); + + /* try to find it in the aging tracker */ + num_received = + cl_event_wheel_num_regs(&sm->trap_aging_tracker, + trap_key); + + /* Now we know how many times it provided this trap */ + if (num_received > 10) { + if (__print_num_received(num_received)) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3804: " + "Received trap %u times consecutively\n", + num_received); + /* + * If the trap provides info about a bad port + * we mark it as unhealthy. + */ + if (physp_change_trap == TRUE) { + /* get the port */ + p_physp = get_physp_by_lid_and_num(sm, + cl_ntoh16 + (p_ntci-> + data_details. + ntc_129_131. + lid), + port_num); + + if (!p_physp) + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 3805: " + "Failed to find physical port by lid:%u num:%u\n", + cl_ntoh16(p_ntci->data_details. + ntc_129_131.lid), + p_ntci->data_details. + ntc_129_131.port_num); + else { + /* When babbling port policy option is enabled and + Threshold for disabling a "babbling" port is exceeded */ + if (sm->p_subn->opt. + babbling_port_policy + && num_received >= 250 + && disable_port(sm, p_physp) == 0) + goto Exit; + + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Marking unhealthy physical port by lid:%u num:%u\n", + cl_ntoh16(p_ntci->data_details. + ntc_129_131.lid), + p_ntci->data_details. + ntc_129_131.port_num); + /* check if the current state of the p_physp is healthy. If + it is - then this is a first change of state. Run a heavy sweep. + if it is not - no need to mark it again - just restart the timer. */ + if (osm_physp_is_healthy(p_physp)) { + osm_physp_set_health(p_physp, + FALSE); + /* Make sure we sweep again - force a heavy sweep. */ + /* The sweep should be done only after the re-registration, or + else we'll be losing track of the timer. */ + run_heavy_sweep = TRUE; + } + /* If we are marking the port as unhealthy - we want to + keep this for a longer period of time than the + OSM_DEFAULT_TRAP_SUPRESSION_TIMEOUT. Use the + OSM_DEFAULT_UNHEALTHY_TIMEOUT */ + event_wheel_timeout = + OSM_DEFAULT_UNHEALTHY_TIMEOUT; + } + } + } + + /* restart the aging anyway */ + /* If physp_change_trap is TRUE - then use a callback to unset the + healthy bit. If not - no need to use a callback. */ + if (physp_change_trap == TRUE) + cl_event_wheel_reg(&sm->trap_aging_tracker, trap_key, cl_get_time_stamp() + event_wheel_timeout, osm_trap_rcv_aging_tracker_callback, /* no callback */ + sm /* no context */ ); + else + cl_event_wheel_reg(&sm->trap_aging_tracker, trap_key, cl_get_time_stamp() + event_wheel_timeout, NULL, /* no callback */ + NULL /* no context */ ); + + /* If was already registered do nothing more */ + if (num_received > 10 && run_heavy_sweep == FALSE) { + if (__print_num_received(num_received)) + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Continuously received this trap %u times. Ignoring\n", + num_received); + goto Exit; + } + } + + /* Check for node description update. IB Spec v1.2.1 pg 823 */ + if ((p_ntci->data_details.ntc_144.local_changes & TRAP_144_MASK_OTHER_LOCAL_CHANGES) && + (p_ntci->data_details.ntc_144.change_flgs & TRAP_144_MASK_NODE_DESCRIPTION_CHANGE) + ) { + OSM_LOG(sm->p_log, OSM_LOG_INFO, "Trap 144 Node description update\n"); + + if (p_physp) { + CL_PLOCK_ACQUIRE(sm->p_lock); + osm_req_get_node_desc(sm, p_physp); + CL_PLOCK_RELEASE(sm->p_lock); + } else { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "ERR 3812: No physical port found for " + "trap 144: \"node description update\"\n"); + } + } + + /* do a sweep if we received a trap */ + if (sm->p_subn->opt.sweep_on_trap) { + /* if this is trap number 128 or run_heavy_sweep is TRUE - update the + force_single_heavy_sweep flag of the subnet. + Sweep also on traps 144/145 - these traps signal a change of a certain + port capability/system image guid. + TODO: In the future we can change this to just getting PortInfo on + this port instead of sweeping the entire subnet. */ + if (ib_notice_is_generic(p_ntci) && + ((cl_ntoh16(p_ntci->g_or_v.generic.trap_num) == 128) || + (cl_ntoh16(p_ntci->g_or_v.generic.trap_num) == 144) || + (cl_ntoh16(p_ntci->g_or_v.generic.trap_num) == 145) || + run_heavy_sweep)) { + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Forcing heavy sweep. Received trap:%u\n", + cl_ntoh16(p_ntci->g_or_v.generic.trap_num)); + + sm->p_subn->force_heavy_sweep = TRUE; + } + osm_sm_signal(sm, OSM_SIGNAL_SWEEP); + } + + /* If we reached here due to trap 129/130/131 - do not need to do + the notice report. Just goto exit. We know this is the case + if physp_change_trap is TRUE. */ + if (physp_change_trap == TRUE) + goto Exit; + + /* Add a call to osm_report_notice */ + /* We are going to report the notice - so need to fix the IssuerGID + accordingly. See IBA 1.2 p.739 or IBA 1.1 p.653 for details. */ + if (is_gsi) { + if (!tmp_madw.mad_addr.addr_type.gsi.global_route) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3806: " + "Received gsi trap with global_route FALSE. " + "Cannot update issuer_gid!\n"); + goto Exit; + } + memcpy(&(p_ntci->issuer_gid), + &(tmp_madw.mad_addr.addr_type.gsi.grh_info.src_gid), + sizeof(ib_gid_t)); + } else { + /* Need to use the IssuerLID */ + p_tbl = &sm->p_subn->port_lid_tbl; + + CL_ASSERT(cl_ptr_vector_get_size(p_tbl) < 0x10000); + + if ((uint16_t) cl_ptr_vector_get_size(p_tbl) <= + cl_ntoh16(source_lid)) { + /* the source lid is out of range */ + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "source lid is out of range:%u\n", + cl_ntoh16(source_lid)); + + goto Exit; + } + p_port = cl_ptr_vector_get(p_tbl, cl_ntoh16(source_lid)); + if (p_port == 0) { + /* We have the lid - but no corresponding port */ + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Cannot find port corresponding to lid:%u\n", + cl_ntoh16(source_lid)); + + goto Exit; + } + + p_ntci->issuer_gid.unicast.prefix = + sm->p_subn->opt.subnet_prefix; + p_ntci->issuer_gid.unicast.interface_id = p_port->guid; + } + + /* we need a lock here as the InformInfo DB must be stable */ + CL_PLOCK_ACQUIRE(sm->p_lock); + status = osm_report_notice(sm->p_log, sm->p_subn, p_ntci); + CL_PLOCK_RELEASE(sm->p_lock); + if (status != IB_SUCCESS) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3803: " + "Error sending trap reports (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(sm->p_log); +} + +#if 0 +/********************************************************************** + CURRENTLY WE ARE NOT CREATING TRAPS - SO THIS CALL IS AN ERROR +**********************************************************************/ +static void +__osm_trap_rcv_process_sm(IN osm_sm_t * sm, + IN const osm_remote_sm_t * const p_sm) +{ + /* const ib_sm_info_t* p_smi; */ + + OSM_LOG_ENTER(sm->p_log); + + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3807: " + "This function is not supported yet\n"); + + OSM_LOG_EXIT(sm->p_log); +} +#endif + +/********************************************************************** + CURRENTLY WE ARE NOT CREATING TRAPS - SO THIS CALL IN AN ERROR +**********************************************************************/ +static void +__osm_trap_rcv_process_response(IN osm_sm_t * sm, + IN const osm_madw_t * const p_madw) +{ + + OSM_LOG_ENTER(sm->p_log); + + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3808: " + "This function is not supported yet\n"); + + OSM_LOG_EXIT(sm->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_trap_rcv_process(IN void *context, IN void *data) +{ + osm_sm_t *sm = context; + osm_madw_t *p_madw = data; + ib_smp_t *p_smp; + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + + /* + Determine if this is a request for our own Trap + or if this is a response to our request for another + SM's Trap. + */ + if (ib_smp_is_response(p_smp)) + __osm_trap_rcv_process_response(sm, p_madw); + else + __osm_trap_rcv_process_request(sm, p_madw); + + OSM_LOG_EXIT(sm->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_ucast_cache.c b/contrib/ofed/management/opensm/opensm/osm_ucast_cache.c new file mode 100644 index 000000000000..c89e24d5783c --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_ucast_cache.c @@ -0,0 +1,1095 @@ +/* + * Copyright (c) 2008 Mellanox Technologies LTD. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of OpenSM Cached Unicast Routing + * + * Environment: + * Linux User Mode + * + */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CACHE_SW_PORTS 36 + +typedef struct cache_port { + boolean_t is_leaf; + uint16_t remote_lid_ho; +} cache_port_t; + +typedef struct cache_switch { + cl_map_item_t map_item; + boolean_t dropped; + uint16_t max_lid_ho; + uint16_t num_hops; + uint8_t **hops; + uint8_t *lft; + uint8_t num_ports; + cache_port_t ports[0]; +} cache_switch_t; + +/********************************************************************** + **********************************************************************/ + +static uint16_t __cache_sw_get_base_lid_ho(cache_switch_t * p_sw) +{ + return p_sw->ports[0].remote_lid_ho; +} + +/********************************************************************** + **********************************************************************/ + +static boolean_t __cache_sw_is_leaf(cache_switch_t * p_sw) +{ + return p_sw->ports[0].is_leaf; +} + +/********************************************************************** + **********************************************************************/ + +static void __cache_sw_set_leaf(cache_switch_t * p_sw) +{ + p_sw->ports[0].is_leaf = TRUE; +} + +/********************************************************************** + **********************************************************************/ + +static cache_switch_t *__cache_sw_new(uint16_t lid_ho, unsigned num_ports) +{ + cache_switch_t *p_cache_sw = malloc(sizeof(cache_switch_t) + + num_ports * sizeof(cache_port_t)); + if (!p_cache_sw) + return NULL; + + memset(p_cache_sw, 0, + sizeof(*p_cache_sw) + num_ports * sizeof(cache_port_t)); + + p_cache_sw->num_ports = num_ports; + + /* port[0] fields represent this switch details - lid and type */ + p_cache_sw->ports[0].remote_lid_ho = lid_ho; + p_cache_sw->ports[0].is_leaf = FALSE; + + return p_cache_sw; +} + +/********************************************************************** + **********************************************************************/ + +static void __cache_sw_destroy(cache_switch_t * p_sw) +{ + if (!p_sw) + return; + + if (p_sw->lft) + free(p_sw->lft); + if (p_sw->hops) + free(p_sw->hops); + free(p_sw); +} + +/********************************************************************** + **********************************************************************/ + +static cache_switch_t *__cache_get_sw(osm_ucast_mgr_t * p_mgr, uint16_t lid_ho) +{ + cache_switch_t *p_cache_sw = (cache_switch_t *) + cl_qmap_get(&p_mgr->cache_sw_tbl, lid_ho); + if (p_cache_sw == (cache_switch_t *) + cl_qmap_end(&p_mgr->cache_sw_tbl)) + p_cache_sw = NULL; + + return p_cache_sw; +} + +/********************************************************************** + **********************************************************************/ +static void __cache_add_sw_link(osm_ucast_mgr_t * p_mgr, osm_physp_t *p, + uint16_t remote_lid_ho, boolean_t is_ca) +{ + cache_switch_t *p_cache_sw; + uint16_t lid_ho = cl_ntoh16(osm_node_get_base_lid(p->p_node, 0)); + + OSM_LOG_ENTER(p_mgr->p_log); + + if (!lid_ho || !remote_lid_ho || !p->port_num) + goto Exit; + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Caching switch port: lid %u [port %u] -> lid %u (%s)\n", + lid_ho, p->port_num, remote_lid_ho, (is_ca) ? "CA/RTR" : "SW"); + + p_cache_sw = __cache_get_sw(p_mgr, lid_ho); + if (!p_cache_sw) { + p_cache_sw = __cache_sw_new(lid_ho, p->p_node->sw->num_ports); + if (!p_cache_sw) { + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, + "ERR AD01: Out of memory - cache is invalid\n"); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + cl_qmap_insert(&p_mgr->cache_sw_tbl, lid_ho, + &p_cache_sw->map_item); + } + + if (p->port_num >= p_cache_sw->num_ports) { + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, + "ERR AD02: Wrong switch? - cache is invalid\n"); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + if (is_ca) + __cache_sw_set_leaf(p_cache_sw); + + if (p_cache_sw->ports[p->port_num].remote_lid_ho == 0) { + /* cache this link only if it hasn't been already cached */ + p_cache_sw->ports[p->port_num].remote_lid_ho = remote_lid_ho; + p_cache_sw->ports[p->port_num].is_leaf = is_ca; + } +Exit: + OSM_LOG_EXIT(p_mgr->p_log); +} + +/********************************************************************** + **********************************************************************/ + +static void __cache_cleanup_switches(osm_ucast_mgr_t * p_mgr) +{ + cache_switch_t *p_sw; + cache_switch_t *p_next_sw; + unsigned port_num; + boolean_t found_port; + + if (!p_mgr->cache_valid) + return; + + p_next_sw = (cache_switch_t *) cl_qmap_head(&p_mgr->cache_sw_tbl); + while (p_next_sw != + (cache_switch_t *) cl_qmap_end(&p_mgr->cache_sw_tbl)) { + p_sw = p_next_sw; + p_next_sw = (cache_switch_t *) cl_qmap_next(&p_sw->map_item); + + found_port = FALSE; + for (port_num = 1; port_num < p_sw->num_ports; port_num++) + if (p_sw->ports[port_num].remote_lid_ho) + found_port = TRUE; + + if (!found_port) { + cl_qmap_remove_item(&p_mgr->cache_sw_tbl, + &p_sw->map_item); + __cache_sw_destroy(p_sw); + } + } +} + +/********************************************************************** + **********************************************************************/ + +static void +__cache_check_link_change(osm_ucast_mgr_t * p_mgr, + osm_physp_t * p_physp_1, osm_physp_t * p_physp_2) +{ + OSM_LOG_ENTER(p_mgr->p_log); + CL_ASSERT(p_physp_1 && p_physp_2); + + if (!p_mgr->cache_valid) + goto Exit; + + if (!p_physp_1->p_remote_physp && !p_physp_2->p_remote_physp) + /* both ports were down - new link */ + goto Exit; + + /* unicast cache cannot tolerate any link location change */ + + if ((p_physp_1->p_remote_physp && + p_physp_1->p_remote_physp->p_remote_physp) || + (p_physp_2->p_remote_physp && + p_physp_2->p_remote_physp->p_remote_physp)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Link location change discovered - cache is invalid\n"); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } +Exit: + OSM_LOG_EXIT(p_mgr->p_log); +} + +/********************************************************************** + **********************************************************************/ + +static void __cache_remove_port(osm_ucast_mgr_t * p_mgr, uint16_t lid_ho, + uint8_t port_num, uint16_t remote_lid_ho, + boolean_t is_ca) +{ + cache_switch_t *p_cache_sw; + + OSM_LOG_ENTER(p_mgr->p_log); + + if (!p_mgr->cache_valid) + goto Exit; + + p_cache_sw = __cache_get_sw(p_mgr, lid_ho); + if (!p_cache_sw) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Found uncached switch/link (lid %u, port %u) - " + "cache is invalid\n", lid_ho, port_num); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + if (port_num >= p_cache_sw->num_ports || + !p_cache_sw->ports[port_num].remote_lid_ho) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Found uncached switch link (lid %u, port %u) - " + "cache is invalid\n", lid_ho, port_num); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + if (p_cache_sw->ports[port_num].remote_lid_ho != remote_lid_ho) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Remote lid change on switch lid %u, port %u " + "(was %u, now %u) - cache is invalid\n", + lid_ho, port_num, + p_cache_sw->ports[port_num].remote_lid_ho, + remote_lid_ho); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + if ((p_cache_sw->ports[port_num].is_leaf && !is_ca) || + (!p_cache_sw->ports[port_num].is_leaf && is_ca)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Remote node type change on switch lid %u, port %u - " + "cache is invalid\n", lid_ho, port_num); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "New link from lid %u, port %u to lid %u - " + "found in cache\n", lid_ho, port_num, remote_lid_ho); + + /* the new link was cached - clean it from the cache */ + + p_cache_sw->ports[port_num].remote_lid_ho = 0; + p_cache_sw->ports[port_num].is_leaf = FALSE; +Exit: + OSM_LOG_EXIT(p_mgr->p_log); +} /* __cache_remove_port() */ + +/********************************************************************** + **********************************************************************/ + +static void +__cache_restore_ucast_info(osm_ucast_mgr_t * p_mgr, + cache_switch_t * p_cache_sw, osm_switch_t * p_sw) +{ + if (!p_mgr->cache_valid) + return; + + /* when seting unicast info, the cached port + should have all the required info */ + CL_ASSERT(p_cache_sw->max_lid_ho && p_cache_sw->lft && + p_cache_sw->num_hops && p_cache_sw->hops); + + p_sw->max_lid_ho = p_cache_sw->max_lid_ho; + + if (p_sw->new_lft) + free(p_sw->new_lft); + p_sw->new_lft = p_cache_sw->lft; + p_cache_sw->lft = NULL; + + p_sw->num_hops = p_cache_sw->num_hops; + p_cache_sw->num_hops = 0; + if (p_sw->hops) + free(p_sw->hops); + p_sw->hops = p_cache_sw->hops; + p_cache_sw->hops = NULL; +} + +/********************************************************************** + **********************************************************************/ + +static void __ucast_cache_dump(osm_ucast_mgr_t * p_mgr) +{ + cache_switch_t *p_sw; + unsigned i; + + OSM_LOG_ENTER(p_mgr->p_log); + + if (!osm_log_is_active(p_mgr->p_log, OSM_LOG_DEBUG)) + goto Exit; + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Dumping missing nodes/links as logged by unicast cache:\n"); + for (p_sw = (cache_switch_t *) cl_qmap_head(&p_mgr->cache_sw_tbl); + p_sw != (cache_switch_t *) cl_qmap_end(&p_mgr->cache_sw_tbl); + p_sw = (cache_switch_t *) cl_qmap_next(&p_sw->map_item)) { + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "\t Switch lid %u %s%s\n", + __cache_sw_get_base_lid_ho(p_sw), + (__cache_sw_is_leaf(p_sw)) ? "[leaf switch] " : "", + (p_sw->dropped) ? "[whole switch missing]" : ""); + + for (i = 1; i < p_sw->num_ports; i++) + if (p_sw->ports[i].remote_lid_ho > 0) + OSM_LOG(p_mgr->p_log, + OSM_LOG_DEBUG, + "\t - port %u -> lid %u %s\n", + i, p_sw->ports[i].remote_lid_ho, + (p_sw->ports[i].is_leaf) ? + "[remote node is leaf]" : ""); + } +Exit: + OSM_LOG_EXIT(p_mgr->p_log); +} + +/********************************************************************** + **********************************************************************/ + +void osm_ucast_cache_invalidate(osm_ucast_mgr_t * p_mgr) +{ + cache_switch_t *p_sw; + cache_switch_t *p_next_sw; + + OSM_LOG_ENTER(p_mgr->p_log); + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "Invalidating unicast cache\n"); + + if (!p_mgr->cache_valid) + goto Exit; + + p_mgr->cache_valid = FALSE; + + p_next_sw = (cache_switch_t *) cl_qmap_head(&p_mgr->cache_sw_tbl); + while (p_next_sw != + (cache_switch_t *) cl_qmap_end(&p_mgr->cache_sw_tbl)) { + p_sw = p_next_sw; + p_next_sw = (cache_switch_t *) cl_qmap_next(&p_sw->map_item); + __cache_sw_destroy(p_sw); + } + cl_qmap_remove_all(&p_mgr->cache_sw_tbl); +Exit: + OSM_LOG_EXIT(p_mgr->p_log); +} + +/********************************************************************** + **********************************************************************/ + +static void ucast_cache_validate(osm_ucast_mgr_t * p_mgr) +{ + cache_switch_t *p_cache_sw; + cache_switch_t *p_remote_cache_sw; + unsigned port_num; + unsigned max_ports; + uint8_t remote_node_type; + uint16_t lid_ho; + uint16_t remote_lid_ho; + osm_switch_t *p_sw; + osm_switch_t *p_remote_sw; + osm_node_t *p_node; + osm_physp_t *p_physp; + osm_physp_t *p_remote_physp; + osm_port_t *p_remote_port; + cl_qmap_t *p_sw_tbl; + + OSM_LOG_ENTER(p_mgr->p_log); + if (!p_mgr->cache_valid) + goto Exit; + + /* If there are no switches in the subnet, we are done */ + p_sw_tbl = &p_mgr->p_subn->sw_guid_tbl; + if (cl_qmap_count(p_sw_tbl) == 0) { + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + /* + * Scan all the physical switch ports in the subnet. + * If the port need_update flag is on, check whether + * it's just some node/port reset or a cached topology + * change. Otherwise the cache is invalid. + */ + for (p_sw = (osm_switch_t *) cl_qmap_head(p_sw_tbl); + p_sw != (osm_switch_t *) cl_qmap_end(p_sw_tbl); + p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) { + + p_node = p_sw->p_node; + + lid_ho = cl_ntoh16(osm_node_get_base_lid(p_node, 0)); + p_cache_sw = __cache_get_sw(p_mgr, lid_ho); + + max_ports = osm_node_get_num_physp(p_node); + + /* skip port 0 */ + for (port_num = 1; port_num < max_ports; port_num++) { + + p_physp = osm_node_get_physp_ptr(p_node, port_num); + + if (!p_physp || !p_physp->p_remote_physp || + !osm_physp_link_exists(p_physp, + p_physp->p_remote_physp)) + /* no valid link */ + continue; + + /* + * While scanning all the physical ports in the subnet, + * mark corresponding leaf switches in the cache. + */ + if (p_cache_sw && + !p_cache_sw->dropped && + !__cache_sw_is_leaf(p_cache_sw) && + p_physp->p_remote_physp->p_node && + osm_node_get_type(p_physp->p_remote_physp-> + p_node) != IB_NODE_TYPE_SWITCH) + __cache_sw_set_leaf(p_cache_sw); + + if (!p_physp->need_update) + continue; + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Checking switch lid %u, port %u\n", + lid_ho, port_num); + + p_remote_physp = osm_physp_get_remote(p_physp); + remote_node_type = + osm_node_get_type(p_remote_physp->p_node); + + if (remote_node_type == IB_NODE_TYPE_SWITCH) + remote_lid_ho = + cl_ntoh16(osm_node_get_base_lid + (p_remote_physp->p_node, 0)); + else + remote_lid_ho = + cl_ntoh16(osm_node_get_base_lid + (p_remote_physp->p_node, + osm_physp_get_port_num + (p_remote_physp))); + + if (!p_cache_sw || + port_num >= p_cache_sw->num_ports || + !p_cache_sw->ports[port_num].remote_lid_ho) { + /* + * There is some uncached change on the port. + * In general, the reasons might be as follows: + * - switch reset + * - port reset (or port down/up) + * - quick connection location change + * - new link (or new switch) + * + * First two reasons allow cache usage, while + * the last two reasons should invalidate cache. + * + * In case of quick connection location change, + * cache would have been invalidated by + * osm_ucast_cache_check_new_link() function. + * + * In case of new link between two known nodes, + * cache also would have been invalidated by + * osm_ucast_cache_check_new_link() function. + * + * Another reason is cached link between two + * known switches went back. In this case the + * osm_ucast_cache_check_new_link() function would + * clear both sides of the link from the cache + * during the discovery process, so effectively + * this would be equivalent to port reset. + * + * So three possible reasons remain: + * - switch reset + * - port reset (or port down/up) + * - link of a new switch + * + * To validate cache, we need to check only the + * third reason - link of a new node/switch: + * - If this is the local switch that is new, + * then it should have (p_sw->need_update == 2). + * - If the remote node is switch and it's new, + * then it also should have + * (p_sw->need_update == 2). + * - If the remote node is CA/RTR and it's new, + * then its port should have is_new flag on. + */ + if (p_sw->need_update == 2) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "New switch found (lid %u) - " + "cache is invalid\n", lid_ho); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + if (remote_node_type == IB_NODE_TYPE_SWITCH) { + + p_remote_sw = + p_remote_physp->p_node->sw; + if (p_remote_sw->need_update == 2) { + /* this could also be case of + switch coming back with an + additional link that it + didn't have before */ + OSM_LOG(p_mgr->p_log, + OSM_LOG_INFO, + "New switch/link found (lid %u) - " + "cache is invalid\n", + remote_lid_ho); + osm_ucast_cache_invalidate + (p_mgr); + goto Exit; + } + } else { + /* + * Remote node is CA/RTR. + * Get p_port of the remote node and + * check its p_port->is_new flag. + */ + p_remote_port = + osm_get_port_by_guid(p_mgr->p_subn, + osm_physp_get_port_guid + (p_remote_physp)); + if (p_remote_port->is_new) { + OSM_LOG(p_mgr->p_log, + OSM_LOG_INFO, + "New CA/RTR found (lid %u) - " + "cache is invalid\n", + remote_lid_ho); + osm_ucast_cache_invalidate + (p_mgr); + goto Exit; + } + } + } else { + /* + * The change on the port is cached. + * In general, the reasons might be as follows: + * - link between two known nodes went back + * - one or more nodes went back, causing all + * the links to reappear + * + * If it was link that went back, then this case + * would have been taken care of during the + * discovery by osm_ucast_cache_check_new_link(), + * so it's some node that went back. + */ + if ((p_cache_sw->ports[port_num].is_leaf && + remote_node_type == IB_NODE_TYPE_SWITCH) || + (!p_cache_sw->ports[port_num].is_leaf && + remote_node_type != IB_NODE_TYPE_SWITCH)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Remote node type change on switch lid %u, port %u - " + "cache is invalid\n", + lid_ho, port_num); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + if (p_cache_sw->ports[port_num].remote_lid_ho != + remote_lid_ho) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Remote lid change on switch lid %u, port %u" + "(was %u, now %u) - cache is invalid\n", + lid_ho, port_num, + p_cache_sw->ports[port_num]. + remote_lid_ho, remote_lid_ho); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + /* + * We don't care who is the node that has + * reappeared in the subnet (local or remote). + * What's important that the cached link matches + * the real fabrics link. + * Just clean it from cache. + */ + + p_cache_sw->ports[port_num].remote_lid_ho = 0; + p_cache_sw->ports[port_num].is_leaf = FALSE; + if (p_cache_sw->dropped) { + __cache_restore_ucast_info(p_mgr, + p_cache_sw, + p_sw); + p_cache_sw->dropped = FALSE; + } + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Restored link from cache: lid %u, port %u to lid %u\n", + lid_ho, port_num, remote_lid_ho); + } + } + } + + /* Remove all the cached switches that + have all their ports restored */ + __cache_cleanup_switches(p_mgr); + + /* + * Done scanning all the physical switch ports in the subnet. + * Now we need to check the other side: + * Scan all the cached switches and their ports: + * - If the cached switch is missing in the subnet + * (dropped flag is on), check that it's a leaf switch. + * If it's not a leaf, the cache is invalid, because + * cache can tolerate only leaf switch removal. + * - If the cached switch exists in fabric, check all + * its cached ports. These cached ports represent + * missing link in the fabric. + * The missing links that can be tolerated are: + * + link to missing CA/RTR + * + link to missing leaf switch + */ + for (p_cache_sw = (cache_switch_t *) cl_qmap_head(&p_mgr->cache_sw_tbl); + p_cache_sw != (cache_switch_t *) cl_qmap_end(&p_mgr->cache_sw_tbl); + p_cache_sw = + (cache_switch_t *) cl_qmap_next(&p_cache_sw->map_item)) { + + if (p_cache_sw->dropped) { + if (!__cache_sw_is_leaf(p_cache_sw)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Missing non-leaf switch (lid %u) - " + "cache is invalid\n", + __cache_sw_get_base_lid_ho(p_cache_sw)); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Missing leaf switch (lid %u) - " + "continuing validation\n", + __cache_sw_get_base_lid_ho(p_cache_sw)); + continue; + } + + for (port_num = 1; port_num < p_cache_sw->num_ports; port_num++) { + if (!p_cache_sw->ports[port_num].remote_lid_ho) + continue; + + if (p_cache_sw->ports[port_num].is_leaf) { + CL_ASSERT(__cache_sw_is_leaf(p_cache_sw)); + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Switch lid %u, port %u: missing link to CA/RTR - " + "continuing validation\n", + __cache_sw_get_base_lid_ho(p_cache_sw), + port_num); + continue; + } + + p_remote_cache_sw = __cache_get_sw(p_mgr, + p_cache_sw-> + ports[port_num]. + remote_lid_ho); + + if (!p_remote_cache_sw || !p_remote_cache_sw->dropped) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Switch lid %u, port %u: missing link to existing switch - " + "cache is invalid\n", + __cache_sw_get_base_lid_ho(p_cache_sw), + port_num); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + if (!__cache_sw_is_leaf(p_remote_cache_sw)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Switch lid %u, port %u: missing link to non-leaf switch - " + "cache is invalid\n", + __cache_sw_get_base_lid_ho(p_cache_sw), + port_num); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + /* + * At this point we know that the missing link is to + * a leaf switch. However, one case deserves a special + * treatment. If there was a link between two leaf + * switches, then missing leaf switch might break + * routing. It is possible that there are routes + * that use leaf switches to get from switch to switch + * and not just to get to the CAs behind the leaf switch. + */ + if (__cache_sw_is_leaf(p_cache_sw) && + __cache_sw_is_leaf(p_remote_cache_sw)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Switch lid %u, port %u: missing leaf-2-leaf link - " + "cache is invalid\n", + __cache_sw_get_base_lid_ho(p_cache_sw), + port_num); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Switch lid %u, port %u: missing remote leaf switch - " + "continuing validation\n", + __cache_sw_get_base_lid_ho(p_cache_sw), + port_num); + } + } + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, "Unicast cache is valid\n"); + __ucast_cache_dump(p_mgr); +Exit: + OSM_LOG_EXIT(p_mgr->p_log); +} /* osm_ucast_cache_validate() */ + +/********************************************************************** + **********************************************************************/ + +void osm_ucast_cache_check_new_link(osm_ucast_mgr_t * p_mgr, + osm_node_t * p_node_1, uint8_t port_num_1, + osm_node_t * p_node_2, uint8_t port_num_2) +{ + uint16_t lid_ho_1; + uint16_t lid_ho_2; + + OSM_LOG_ENTER(p_mgr->p_log); + + if (!p_mgr->cache_valid) + goto Exit; + + __cache_check_link_change(p_mgr, + osm_node_get_physp_ptr(p_node_1, port_num_1), + osm_node_get_physp_ptr(p_node_2, port_num_2)); + + if (!p_mgr->cache_valid) + goto Exit; + + if (osm_node_get_type(p_node_1) != IB_NODE_TYPE_SWITCH && + osm_node_get_type(p_node_2) != IB_NODE_TYPE_SWITCH) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Found CA/RTR-2-CA/RTR link - cache is invalid\n"); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + /* for code simplicity, we want the first node to be switch */ + if (osm_node_get_type(p_node_1) != IB_NODE_TYPE_SWITCH) { + osm_node_t *tmp_node = p_node_1; + uint8_t tmp_port_num = port_num_1; + p_node_1 = p_node_2; + port_num_1 = port_num_2; + p_node_2 = tmp_node; + port_num_2 = tmp_port_num; + } + + lid_ho_1 = cl_ntoh16(osm_node_get_base_lid(p_node_1, 0)); + + if (osm_node_get_type(p_node_2) == IB_NODE_TYPE_SWITCH) + lid_ho_2 = cl_ntoh16(osm_node_get_base_lid(p_node_2, 0)); + else + lid_ho_2 = + cl_ntoh16(osm_node_get_base_lid(p_node_2, port_num_2)); + + if (!lid_ho_1 || !lid_ho_2) { + /* + * No lid assigned, which means that one of the nodes is new. + * Need to wait for lid manager to process this node. + * The switches and their links will be checked later when + * the whole cache validity will be verified. + */ + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Link port %u <-> %u reveals new node - cache will " + "be validated later\n", port_num_1, port_num_2); + goto Exit; + } + + __cache_remove_port(p_mgr, lid_ho_1, port_num_1, lid_ho_2, + (osm_node_get_type(p_node_2) != + IB_NODE_TYPE_SWITCH)); + + /* if node_2 is a switch, the link should be cleaned from its cache */ + + if (osm_node_get_type(p_node_2) == IB_NODE_TYPE_SWITCH) + __cache_remove_port(p_mgr, lid_ho_2, + port_num_2, lid_ho_1, FALSE); + +Exit: + OSM_LOG_EXIT(p_mgr->p_log); +} /* osm_ucast_cache_check_new_link() */ + +/********************************************************************** + **********************************************************************/ + +void osm_ucast_cache_add_link(osm_ucast_mgr_t * p_mgr, + osm_physp_t * p_physp1, osm_physp_t * p_physp2) +{ + osm_node_t *p_node_1 = p_physp1->p_node, *p_node_2 = p_physp2->p_node; + uint16_t lid_ho_1, lid_ho_2; + + OSM_LOG_ENTER(p_mgr->p_log); + + if (!p_mgr->cache_valid) + goto Exit; + + if (osm_node_get_type(p_node_1) != IB_NODE_TYPE_SWITCH && + osm_node_get_type(p_node_2) != IB_NODE_TYPE_SWITCH) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Dropping CA-2-CA link - cache invalid\n"); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + if ((osm_node_get_type(p_node_1) == IB_NODE_TYPE_SWITCH && + !osm_node_get_physp_ptr(p_node_1, 0)) || + (osm_node_get_type(p_node_2) == IB_NODE_TYPE_SWITCH && + !osm_node_get_physp_ptr(p_node_2, 0))) { + /* we're caching a link when one of the nodes + has already been dropped and cached */ + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Port %u <-> port %u: port0 on one of the nodes " + "has already been dropped and cached\n", + p_physp1->port_num, p_physp2->port_num); + goto Exit; + } + + /* One of the nodes is switch. Just for code + simplicity, make sure that it's the first node. */ + + if (osm_node_get_type(p_node_1) != IB_NODE_TYPE_SWITCH) { + osm_physp_t *tmp = p_physp1; + p_physp1 = p_physp2; + p_physp2 = tmp; + p_node_1 = p_physp1->p_node; + p_node_2 = p_physp2->p_node; + } + + if (!p_node_1->sw) { + /* something is wrong - we'd better not use cache */ + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + lid_ho_1 = cl_ntoh16(osm_node_get_base_lid(p_node_1, 0)); + + if (osm_node_get_type(p_node_2) == IB_NODE_TYPE_SWITCH) { + + if (!p_node_2->sw) { + /* something is wrong - we'd better not use cache */ + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + lid_ho_2 = cl_ntoh16(osm_node_get_base_lid(p_node_2, 0)); + + /* lost switch-2-switch link - cache both sides */ + __cache_add_sw_link(p_mgr, p_physp1, lid_ho_2, FALSE); + __cache_add_sw_link(p_mgr, p_physp2, lid_ho_1, FALSE); + } else { + lid_ho_2 = cl_ntoh16(osm_physp_get_base_lid(p_physp2)); + + /* lost link to CA/RTR - cache only switch side */ + __cache_add_sw_link(p_mgr, p_physp1, lid_ho_2, TRUE); + } + +Exit: + OSM_LOG_EXIT(p_mgr->p_log); +} /* osm_ucast_cache_add_link() */ + +/********************************************************************** + **********************************************************************/ + +void osm_ucast_cache_add_node(osm_ucast_mgr_t * p_mgr, osm_node_t * p_node) +{ + uint16_t lid_ho; + uint8_t max_ports; + uint8_t port_num; + osm_physp_t *p_physp; + cache_switch_t *p_cache_sw; + + OSM_LOG_ENTER(p_mgr->p_log); + + if (!p_mgr->cache_valid) + goto Exit; + + if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) { + + lid_ho = cl_ntoh16(osm_node_get_base_lid(p_node, 0)); + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Caching dropped switch lid %u\n", lid_ho); + + if (!p_node->sw) { + /* something is wrong - forget about cache */ + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, + "ERR AD03: no switch info for node lid %u - " + "clearing cache\n", lid_ho); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + /* unlink (add to cache) all the ports of this switch */ + max_ports = osm_node_get_num_physp(p_node); + for (port_num = 1; port_num < max_ports; port_num++) { + + p_physp = osm_node_get_physp_ptr(p_node, port_num); + if (!p_physp || !p_physp->p_remote_physp) + continue; + + osm_ucast_cache_add_link(p_mgr, p_physp, + p_physp->p_remote_physp); + } + + /* + * All the ports have been dropped (cached). + * If one of the ports was connected to CA/RTR, + * then the cached switch would be marked as leaf. + * If it isn't, then the dropped switch isn't a leaf, + * and cache can't handle it. + */ + + p_cache_sw = __cache_get_sw(p_mgr, lid_ho); + CL_ASSERT(p_cache_sw); + + if (!__cache_sw_is_leaf(p_cache_sw)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Dropped non-leaf switch (lid %u) - " + "cache is invalid\n", lid_ho); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + p_cache_sw->dropped = TRUE; + + if (!p_node->sw->num_hops || !p_node->sw->hops) { + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "No LID matrices for switch lid %u - " + "cache is invalid\n", lid_ho); + osm_ucast_cache_invalidate(p_mgr); + goto Exit; + } + + /* lid matrices */ + + p_cache_sw->num_hops = p_node->sw->num_hops; + p_node->sw->num_hops = 0; + p_cache_sw->hops = p_node->sw->hops; + p_node->sw->hops = NULL; + + /* linear forwarding table */ + + if (p_node->sw->new_lft) { + /* LFT buffer exists - we use it, because + it is more updated than the switch's LFT */ + p_cache_sw->lft = p_node->sw->new_lft; + p_node->sw->new_lft = NULL; + } else { + /* no LFT buffer, so we use the switch's LFT */ + p_cache_sw->lft = p_node->sw->lft; + p_node->sw->lft = NULL; + } + p_cache_sw->max_lid_ho = p_node->sw->max_lid_ho; + } else { + /* dropping CA/RTR: add to cache all the ports of this node */ + max_ports = osm_node_get_num_physp(p_node); + for (port_num = 1; port_num < max_ports; port_num++) { + + p_physp = osm_node_get_physp_ptr(p_node, port_num); + if (!p_physp || !p_physp->p_remote_physp) + continue; + + CL_ASSERT(osm_node_get_type + (p_physp->p_remote_physp->p_node) == + IB_NODE_TYPE_SWITCH); + + osm_ucast_cache_add_link(p_mgr, + p_physp->p_remote_physp, + p_physp); + } + } +Exit: + OSM_LOG_EXIT(p_mgr->p_log); +} /* osm_ucast_cache_add_node() */ + +/********************************************************************** + **********************************************************************/ + +int osm_ucast_cache_process(osm_ucast_mgr_t * p_mgr) +{ + cl_qmap_t *tbl = &p_mgr->p_subn->sw_guid_tbl; + cl_map_item_t *item; + osm_switch_t *p_sw; + + if (!p_mgr->p_subn->opt.use_ucast_cache) + return 1; + + ucast_cache_validate(p_mgr); + if (!p_mgr->cache_valid) + return 1; + + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "Configuring switch tables using cached routing\n"); + + for (item = cl_qmap_head(tbl); item != cl_qmap_end(tbl); + item = cl_qmap_next(item)) { + p_sw = (osm_switch_t *) item; + + if (p_sw->need_update && !p_sw->new_lft) { + /* no new routing was recently calculated for this + switch, but the LFT needs to be updated anyway */ + p_sw->new_lft = p_sw->lft; + p_sw->lft = malloc(IB_LID_UCAST_END_HO + 1); + if (!p_sw->lft) + return IB_INSUFFICIENT_MEMORY; + memset(p_sw->lft, OSM_NO_PATH, IB_LID_UCAST_END_HO + 1); + } + + osm_ucast_mgr_set_fwd_table(p_mgr, p_sw); + } + + return 0; +} + +/********************************************************************** + **********************************************************************/ diff --git a/contrib/ofed/management/opensm/opensm/osm_ucast_file.c b/contrib/ofed/management/opensm/opensm/osm_ucast_file.c new file mode 100644 index 000000000000..2505c46f0217 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_ucast_file.c @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2006,2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2008 Mellanox Technologies LTD. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of OpenSM unicast routing module which loads + * routes from the dump file + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static uint16_t remap_lid(osm_opensm_t * p_osm, uint16_t lid, ib_net64_t guid) +{ + osm_port_t *p_port; + uint16_t min_lid, max_lid; + uint8_t lmc; + + p_port = osm_get_port_by_guid(&p_osm->subn, guid); + if (!p_port) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "cannot find port guid 0x%016" PRIx64 + " , will use the same lid\n", cl_ntoh64(guid)); + return lid; + } + + osm_port_get_lid_range_ho(p_port, &min_lid, &max_lid); + if (min_lid <= lid && lid <= max_lid) + return lid; + + lmc = osm_port_get_lmc(p_port); + return min_lid + (lid & ((1 << lmc) - 1)); +} + +static void add_path(osm_opensm_t * p_osm, + osm_switch_t * p_sw, uint16_t lid, uint8_t port_num, + ib_net64_t port_guid) +{ + uint16_t new_lid; + uint8_t old_port; + + new_lid = port_guid ? remap_lid(p_osm, lid, port_guid) : lid; + old_port = osm_switch_get_port_by_lid(p_sw, new_lid); + if (old_port != OSM_NO_PATH && old_port != port_num) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "LID collision is detected on switch " + "0x016%" PRIx64 ", will overwrite LID %u entry\n", + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node)), + new_lid); + } + + p_sw->new_lft[new_lid] = port_num; + if (!(p_osm->subn.opt.port_profile_switch_nodes && port_guid && + osm_get_switch_by_guid(&p_osm->subn, port_guid))) + osm_switch_count_path(p_sw, port_num); + + OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, + "route 0x%04x(was 0x%04x) %u 0x%016" PRIx64 + " is added to switch 0x%016" PRIx64 "\n", + new_lid, lid, port_num, cl_ntoh64(port_guid), + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node))); +} + +static void add_lid_hops(osm_opensm_t * p_osm, osm_switch_t * p_sw, + uint16_t lid, ib_net64_t guid, + uint8_t hops[], unsigned len) +{ + uint16_t new_lid; + uint8_t i; + + new_lid = guid ? remap_lid(p_osm, lid, guid) : lid; + if (len > p_sw->num_ports) + len = p_sw->num_ports; + + for (i = 0; i < len; i++) + osm_switch_set_hops(p_sw, lid, i, hops[i]); +} + +static int do_ucast_file_load(void *context) +{ + char line[1024]; + char *file_name; + FILE *file; + ib_net64_t sw_guid, port_guid; + osm_opensm_t *p_osm = context; + osm_switch_t *p_sw; + uint16_t lid; + uint8_t port_num; + unsigned lineno; + + file_name = p_osm->subn.opt.lfts_file; + if (!file_name) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "LFTs file name is not given; " + "using default routing algorithm\n"); + return 1; + } + + file = fopen(file_name, "r"); + if (!file) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 6302: " + "cannot open ucast dump file \'%s\': %m\n", file_name); + return -1; + } + + lineno = 0; + p_sw = NULL; + + while (fgets(line, sizeof(line) - 1, file) != NULL) { + char *p, *q; + lineno++; + + p = line; + while (isspace(*p)) + p++; + + if (*p == '#') + continue; + + if (!strncmp(p, "Multicast mlids", 15)) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, + "ERR 6303: " + "Multicast dump file detected; " + "skipping parsing. Using default " + "routing algorithm\n"); + } else if (!strncmp(p, "Unicast lids", 12)) { + if (p_sw) + osm_ucast_mgr_set_fwd_table(&p_osm->sm. + ucast_mgr, p_sw); + q = strstr(p, " guid 0x"); + if (!q) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, + "PARSE ERROR: %s:%u: " + "cannot parse switch definition\n", + file_name, lineno); + return -1; + } + p = q + 8; + sw_guid = strtoull(p, &q, 16); + if (q == p || !isspace(*q)) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, + "PARSE ERROR: %s:%u: " + "cannot parse switch guid: \'%s\'\n", + file_name, lineno, p); + return -1; + } + sw_guid = cl_hton64(sw_guid); + + p_sw = osm_get_switch_by_guid(&p_osm->subn, sw_guid); + if (!p_sw) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "cannot find switch %016" PRIx64 "\n", + cl_ntoh64(sw_guid)); + continue; + } + memset(p_sw->new_lft, OSM_NO_PATH, + IB_LID_UCAST_END_HO + 1); + } else if (p_sw && !strncmp(p, "0x", 2)) { + p += 2; + lid = (uint16_t) strtoul(p, &q, 16); + if (q == p || !isspace(*q)) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, + "PARSE ERROR: %s:%u: " + "cannot parse lid: \'%s\'\n", + file_name, lineno, p); + return -1; + } + p = q; + while (isspace(*p)) + p++; + port_num = (uint8_t) strtoul(p, &q, 10); + if (q == p || !isspace(*q)) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, + "PARSE ERROR: %s:%u: " + "cannot parse port: \'%s\'\n", + file_name, lineno, p); + return -1; + } + p = q; + /* additionally try to exract guid */ + q = strstr(p, " portguid 0x"); + if (!q) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "PARSE WARNING: %s:%u: " + "cannot find port guid " + "(maybe broken dump): \'%s\'\n", + file_name, lineno, p); + port_guid = 0; + } else { + p = q + 12; + port_guid = strtoull(p, &q, 16); + if (q == p || (!isspace(*q) && *q != ':')) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "PARSE WARNING: %s:%u: " + "cannot parse port guid " + "(maybe broken dump): \'%s\'\n", + file_name, lineno, p); + port_guid = 0; + } + } + port_guid = cl_hton64(port_guid); + add_path(p_osm, p_sw, lid, port_num, port_guid); + } + } + + if (p_sw) + osm_ucast_mgr_set_fwd_table(&p_osm->sm.ucast_mgr, p_sw); + + fclose(file); + return 0; +} + +static int do_lid_matrix_file_load(void *context) +{ + char line[1024]; + uint8_t hops[256]; + char *file_name; + FILE *file; + ib_net64_t guid; + osm_opensm_t *p_osm = context; + osm_switch_t *p_sw; + unsigned lineno; + uint16_t lid; + + file_name = p_osm->subn.opt.lid_matrix_dump_file; + if (!file_name) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "lid matrix file name is not given; " + "using default lid matrix generation algorithm\n"); + return 1; + } + + file = fopen(file_name, "r"); + if (!file) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR | OSM_LOG_SYS, "ERR 6305: " + "cannot open lid matrix file \'%s\': %m\n", file_name); + return -1; + } + + lineno = 0; + p_sw = NULL; + + while (fgets(line, sizeof(line) - 1, file) != NULL) { + char *p, *q; + lineno++; + + p = line; + while (isspace(*p)) + p++; + + if (*p == '#') + continue; + + if (!strncmp(p, "Switch", 6)) { + q = strstr(p, " guid 0x"); + if (!q) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, + "PARSE ERROR: %s:%u: " + "cannot parse switch definition\n", + file_name, lineno); + return -1; + } + p = q + 8; + guid = strtoull(p, &q, 16); + if (q == p || !isspace(*q)) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, + "PARSE ERROR: %s:%u: " + "cannot parse switch guid: \'%s\'\n", + file_name, lineno, p); + return -1; + } + guid = cl_hton64(guid); + + p_sw = osm_get_switch_by_guid(&p_osm->subn, guid); + if (!p_sw) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "cannot find switch %016" PRIx64 "\n", + cl_ntoh64(guid)); + continue; + } + } else if (p_sw && !strncmp(p, "0x", 2)) { + unsigned long num; + unsigned len = 0; + + memset(hops, 0xff, sizeof(hops)); + + p += 2; + num = strtoul(p, &q, 16); + if (num > 0xffff || q == p || + (*q != ':' && !isspace(*q))) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, + "PARSE ERROR: %s:%u: " + "cannot parse lid: \'%s\'\n", + file_name, lineno, p); + return -1; + } + /* Just checked the range, so casting is safe */ + lid = (uint16_t) num; + p = q; + while (isspace(*p) || *p == ':') + p++; + while (len < 256 && *p && *p != '#') { + num = strtoul(p, &q, 16); + if (num > 0xff || q == p) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, + "PARSE ERROR: %s:%u: " + "cannot parse hops number: \'%s\'\n", + file_name, lineno, p); + return -1; + } + /* Just checked the range, so casting is safe */ + hops[len++] = (uint8_t) num; + p = q; + while (isspace(*p)) + p++; + } + /* additionally try to extract guid */ + q = strstr(p, " portguid 0x"); + if (!q) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "PARSE WARNING: %s:%u: " + "cannot find port guid " + "(maybe broken dump): \'%s\'\n", + file_name, lineno, p); + guid = 0; + } else { + p = q + 12; + guid = strtoull(p, &q, 16); + if (q == p || !isspace(*q)) { + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "PARSE WARNING: %s:%u: " + "cannot parse port guid " + "(maybe broken dump): \'%s\'\n", + file_name, lineno, p); + guid = 0; + } + } + guid = cl_hton64(guid); + add_lid_hops(p_osm, p_sw, lid, guid, hops, len); + } + } + + fclose(file); + return 0; +} + +int osm_ucast_file_setup(struct osm_routing_engine *r, osm_opensm_t *osm) +{ + r->context = osm; + r->build_lid_matrices = do_lid_matrix_file_load; + r->ucast_build_fwd_tables = do_ucast_file_load; + return 0; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_ucast_ftree.c b/contrib/ofed/management/opensm/opensm/osm_ucast_ftree.c new file mode 100644 index 000000000000..aa51d231c3f9 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_ucast_ftree.c @@ -0,0 +1,3669 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2007 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of OpenSM FatTree routing + */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * FatTree rank is bounded between 2 and 8: + * - Tree of rank 1 has only trivial routing paths, + * so no need to use FatTree routing. + * - Why maximum rank is 8: + * Each node (switch) is assigned a unique tuple. + * Switches are stored in two cl_qmaps - one is + * ordered by guid, and the other by a key that is + * generated from tuple. Since cl_qmap supports only + * a 64-bit key, the maximal tuple lenght is 8 bytes. + * which means that maximal tree rank is 8. + * Note that the above also implies that each switch + * can have at max 255 up/down ports. + */ + +#define FAT_TREE_MIN_RANK 2 +#define FAT_TREE_MAX_RANK 8 + +typedef enum { + FTREE_DIRECTION_DOWN = -1, + FTREE_DIRECTION_SAME, + FTREE_DIRECTION_UP +} ftree_direction_t; + +/*************************************************** + ** + ** Forward references + ** + ***************************************************/ + +struct ftree_sw_t_; +struct ftree_hca_t_; +struct ftree_port_t_; +struct ftree_port_group_t_; +struct ftree_fabric_t_; + +/*************************************************** + ** + ** ftree_tuple_t definition + ** + ***************************************************/ + +#define FTREE_TUPLE_BUFF_LEN 1024 +#define FTREE_TUPLE_LEN 8 + +typedef uint8_t ftree_tuple_t[FTREE_TUPLE_LEN]; +typedef uint64_t ftree_tuple_key_t; + +struct guid_list_item { + cl_list_item_t list; + uint64_t guid; +}; + +/*************************************************** + ** + ** ftree_sw_table_element_t definition + ** + ***************************************************/ + +typedef struct { + cl_map_item_t map_item; + struct ftree_sw_t_ *p_sw; +} ftree_sw_tbl_element_t; + +/*************************************************** + ** + ** ftree_port_t definition + ** + ***************************************************/ + +typedef struct ftree_port_t_ { + cl_map_item_t map_item; + uint8_t port_num; /* port number on the current node */ + uint8_t remote_port_num; /* port number on the remote node */ + uint32_t counter_up; /* number of allocated routs upwards */ + uint32_t counter_down; /* number of allocated routs downwards */ +} ftree_port_t; + +/*************************************************** + ** + ** ftree_port_group_t definition + ** + ***************************************************/ + +typedef union ftree_hca_or_sw_ { + struct ftree_hca_t_ *p_hca; + struct ftree_sw_t_ *p_sw; +} ftree_hca_or_sw; + +typedef struct ftree_port_group_t_ { + cl_map_item_t map_item; + ib_net16_t base_lid; /* base lid of the current node */ + ib_net16_t remote_base_lid; /* base lid of the remote node */ + ib_net64_t port_guid; /* port guid of this port */ + ib_net64_t node_guid; /* this node's guid */ + uint8_t node_type; /* this node's type */ + ib_net64_t remote_port_guid; /* port guid of the remote port */ + ib_net64_t remote_node_guid; /* node guid of the remote node */ + uint8_t remote_node_type; /* IB_NODE_TYPE_{CA,SWITCH,ROUTER,...} */ + ftree_hca_or_sw hca_or_sw; /* pointer to this hca/switch */ + ftree_hca_or_sw remote_hca_or_sw; /* pointer to remote hca/switch */ + cl_ptr_vector_t ports; /* vector of ports to the same lid */ + boolean_t is_cn; /* whether this port is a compute node */ + uint32_t counter_down; /* number of allocated routs downwards */ +} ftree_port_group_t; + +/*************************************************** + ** + ** ftree_sw_t definition + ** + ***************************************************/ + +typedef struct ftree_sw_t_ { + cl_map_item_t map_item; + osm_switch_t *p_osm_sw; + uint32_t rank; + ftree_tuple_t tuple; + ib_net16_t base_lid; + ftree_port_group_t **down_port_groups; + uint8_t down_port_groups_num; + ftree_port_group_t **up_port_groups; + uint8_t up_port_groups_num; + boolean_t is_leaf; + int down_port_groups_idx; +} ftree_sw_t; + +/*************************************************** + ** + ** ftree_hca_t definition + ** + ***************************************************/ + +typedef struct ftree_hca_t_ { + cl_map_item_t map_item; + osm_node_t *p_osm_node; + ftree_port_group_t **up_port_groups; + uint16_t up_port_groups_num; + unsigned cn_num; +} ftree_hca_t; + +/*************************************************** + ** + ** ftree_fabric_t definition + ** + ***************************************************/ + +typedef struct ftree_fabric_t_ { + osm_opensm_t *p_osm; + cl_qmap_t hca_tbl; + cl_qmap_t sw_tbl; + cl_qmap_t sw_by_tuple_tbl; + cl_qlist_t root_guid_list; + cl_qmap_t cn_guid_tbl; + unsigned cn_num; + uint8_t leaf_switch_rank; + uint8_t max_switch_rank; + ftree_sw_t **leaf_switches; + uint32_t leaf_switches_num; + uint16_t max_cn_per_leaf; + uint16_t lft_max_lid_ho; + boolean_t fabric_built; +} ftree_fabric_t; + +/*************************************************** + ** + ** comparators + ** + ***************************************************/ + +static int OSM_CDECL __osm_ftree_compare_switches_by_index(IN const void *p1, + IN const void *p2) +{ + ftree_sw_t **pp_sw1 = (ftree_sw_t **) p1; + ftree_sw_t **pp_sw2 = (ftree_sw_t **) p2; + + uint16_t i; + for (i = 0; i < FTREE_TUPLE_LEN; i++) { + if ((*pp_sw1)->tuple[i] > (*pp_sw2)->tuple[i]) + return 1; + if ((*pp_sw1)->tuple[i] < (*pp_sw2)->tuple[i]) + return -1; + } + return 0; +} + +/***************************************************/ + +static int OSM_CDECL +__osm_ftree_compare_port_groups_by_remote_switch_index(IN const void *p1, + IN const void *p2) +{ + ftree_port_group_t **pp_g1 = (ftree_port_group_t **) p1; + ftree_port_group_t **pp_g2 = (ftree_port_group_t **) p2; + + return + __osm_ftree_compare_switches_by_index(& + ((*pp_g1)->remote_hca_or_sw. + p_sw), + &((*pp_g2)->remote_hca_or_sw. + p_sw)); +} + +/*************************************************** + ** + ** ftree_tuple_t functions + ** + ***************************************************/ + +static void __osm_ftree_tuple_init(IN ftree_tuple_t tuple) +{ + memset(tuple, 0xFF, FTREE_TUPLE_LEN); +} + +/***************************************************/ + +static inline boolean_t __osm_ftree_tuple_assigned(IN ftree_tuple_t tuple) +{ + return (tuple[0] != 0xFF); +} + +/***************************************************/ + +#define FTREE_TUPLE_BUFFERS_NUM 6 + +static char *__osm_ftree_tuple_to_str(IN ftree_tuple_t tuple) +{ + static char buffer[FTREE_TUPLE_BUFFERS_NUM][FTREE_TUPLE_BUFF_LEN]; + static uint8_t ind = 0; + char *ret_buffer; + uint32_t i; + + if (!__osm_ftree_tuple_assigned(tuple)) + return "INDEX.NOT.ASSIGNED"; + + buffer[ind][0] = '\0'; + + for (i = 0; (i < FTREE_TUPLE_LEN) && (tuple[i] != 0xFF); i++) { + if ((strlen(buffer[ind]) + 10) > FTREE_TUPLE_BUFF_LEN) + return "INDEX.TOO.LONG"; + if (i != 0) + strcat(buffer[ind], "."); + sprintf(&buffer[ind][strlen(buffer[ind])], "%u", tuple[i]); + } + + ret_buffer = buffer[ind]; + ind = (ind + 1) % FTREE_TUPLE_BUFFERS_NUM; + return ret_buffer; +} /* __osm_ftree_tuple_to_str() */ + +/***************************************************/ + +static inline ftree_tuple_key_t __osm_ftree_tuple_to_key(IN ftree_tuple_t tuple) +{ + ftree_tuple_key_t key; + memcpy(&key, tuple, FTREE_TUPLE_LEN); + return key; +} + +/***************************************************/ + +static inline void __osm_ftree_tuple_from_key(IN ftree_tuple_t tuple, + IN ftree_tuple_key_t key) +{ + memcpy(tuple, &key, FTREE_TUPLE_LEN); +} + +/*************************************************** + ** + ** ftree_sw_tbl_element_t functions + ** + ***************************************************/ + +static ftree_sw_tbl_element_t *__osm_ftree_sw_tbl_element_create(IN ftree_sw_t * + p_sw) +{ + ftree_sw_tbl_element_t *p_element = + (ftree_sw_tbl_element_t *) malloc(sizeof(ftree_sw_tbl_element_t)); + if (!p_element) + return NULL; + memset(p_element, 0, sizeof(ftree_sw_tbl_element_t)); + + p_element->p_sw = p_sw; + return p_element; +} + +/***************************************************/ + +static void __osm_ftree_sw_tbl_element_destroy(IN ftree_sw_tbl_element_t * + p_element) +{ + if (!p_element) + return; + free(p_element); +} + +/*************************************************** + ** + ** ftree_port_t functions + ** + ***************************************************/ + +static ftree_port_t *__osm_ftree_port_create(IN uint8_t port_num, + IN uint8_t remote_port_num) +{ + ftree_port_t *p_port = (ftree_port_t *) malloc(sizeof(ftree_port_t)); + if (!p_port) + return NULL; + memset(p_port, 0, sizeof(ftree_port_t)); + + p_port->port_num = port_num; + p_port->remote_port_num = remote_port_num; + + return p_port; +} + +/***************************************************/ + +static void __osm_ftree_port_destroy(IN ftree_port_t * p_port) +{ + if (p_port) + free(p_port); +} + +/*************************************************** + ** + ** ftree_port_group_t functions + ** + ***************************************************/ + +static ftree_port_group_t * +__osm_ftree_port_group_create(IN ib_net16_t base_lid, + IN ib_net16_t remote_base_lid, + IN ib_net64_t port_guid, + IN ib_net64_t node_guid, + IN uint8_t node_type, + IN void *p_hca_or_sw, + IN ib_net64_t remote_port_guid, + IN ib_net64_t remote_node_guid, + IN uint8_t remote_node_type, + IN void *p_remote_hca_or_sw, + IN boolean_t is_cn) +{ + ftree_port_group_t *p_group = + (ftree_port_group_t *) malloc(sizeof(ftree_port_group_t)); + if (p_group == NULL) + return NULL; + memset(p_group, 0, sizeof(ftree_port_group_t)); + + p_group->base_lid = base_lid; + p_group->remote_base_lid = remote_base_lid; + memcpy(&p_group->port_guid, &port_guid, sizeof(ib_net64_t)); + memcpy(&p_group->node_guid, &node_guid, sizeof(ib_net64_t)); + memcpy(&p_group->remote_port_guid, &remote_port_guid, + sizeof(ib_net64_t)); + memcpy(&p_group->remote_node_guid, &remote_node_guid, + sizeof(ib_net64_t)); + + p_group->node_type = node_type; + switch (node_type) { + case IB_NODE_TYPE_CA: + p_group->hca_or_sw.p_hca = (ftree_hca_t *) p_hca_or_sw; + break; + case IB_NODE_TYPE_SWITCH: + p_group->hca_or_sw.p_sw = (ftree_sw_t *) p_hca_or_sw; + break; + default: + /* we shouldn't get here - port is created only in hca or switch */ + CL_ASSERT(0); + } + + p_group->remote_node_type = remote_node_type; + switch (remote_node_type) { + case IB_NODE_TYPE_CA: + p_group->remote_hca_or_sw.p_hca = + (ftree_hca_t *) p_remote_hca_or_sw; + break; + case IB_NODE_TYPE_SWITCH: + p_group->remote_hca_or_sw.p_sw = + (ftree_sw_t *) p_remote_hca_or_sw; + break; + default: + /* we shouldn't get here - port is created only in hca or switch */ + CL_ASSERT(0); + } + + cl_ptr_vector_init(&p_group->ports, 0, /* min size */ + 8); /* grow size */ + p_group->is_cn = is_cn; + return p_group; +} /* __osm_ftree_port_group_create() */ + +/***************************************************/ + +static void __osm_ftree_port_group_destroy(IN ftree_port_group_t * p_group) +{ + uint32_t i; + uint32_t size; + ftree_port_t *p_port; + + if (!p_group) + return; + + /* remove all the elements of p_group->ports vector */ + size = cl_ptr_vector_get_size(&p_group->ports); + for (i = 0; i < size; i++) { + cl_ptr_vector_at(&p_group->ports, i, (void *)&p_port); + __osm_ftree_port_destroy(p_port); + } + cl_ptr_vector_destroy(&p_group->ports); + free(p_group); +} /* __osm_ftree_port_group_destroy() */ + +/***************************************************/ + +static void +__osm_ftree_port_group_dump(IN ftree_fabric_t * p_ftree, + IN ftree_port_group_t * p_group, + IN ftree_direction_t direction) +{ + ftree_port_t *p_port; + uint32_t size; + uint32_t i; + char buff[10 * 1024]; + + if (!p_group) + return; + + if (!osm_log_is_active(&p_ftree->p_osm->log, OSM_LOG_DEBUG)) + return; + + size = cl_ptr_vector_get_size(&p_group->ports); + buff[0] = '\0'; + + for (i = 0; i < size; i++) { + cl_ptr_vector_at(&p_group->ports, i, (void *)&p_port); + CL_ASSERT(p_port); + + if (i != 0) + strcat(buff, ", "); + sprintf(buff + strlen(buff), "%u", p_port->port_num); + } + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + " Port Group of size %u, port(s): %s, direction: %s\n" + " Local <--> Remote GUID (LID):" + "0x%016" PRIx64 " (0x%04x) <--> 0x%016" PRIx64 " (0x%04x)\n", + size, + buff, + (direction == FTREE_DIRECTION_DOWN) ? "DOWN" : "UP", + cl_ntoh64(p_group->port_guid), + cl_ntoh16(p_group->base_lid), + cl_ntoh64(p_group->remote_port_guid), + cl_ntoh16(p_group->remote_base_lid)); + +} /* __osm_ftree_port_group_dump() */ + +/***************************************************/ + +static void +__osm_ftree_port_group_add_port(IN ftree_port_group_t * p_group, + IN uint8_t port_num, IN uint8_t remote_port_num) +{ + uint16_t i; + ftree_port_t *p_port; + + for (i = 0; i < cl_ptr_vector_get_size(&p_group->ports); i++) { + cl_ptr_vector_at(&p_group->ports, i, (void *)&p_port); + if (p_port->port_num == port_num) + return; + } + + p_port = __osm_ftree_port_create(port_num, remote_port_num); + cl_ptr_vector_insert(&p_group->ports, p_port, NULL); +} + +/*************************************************** + ** + ** ftree_sw_t functions + ** + ***************************************************/ + +static ftree_sw_t *__osm_ftree_sw_create(IN ftree_fabric_t * p_ftree, + IN osm_switch_t * p_osm_sw) +{ + ftree_sw_t *p_sw; + uint8_t ports_num; + + /* make sure that the switch has ports */ + if (p_osm_sw->num_ports == 1) + return NULL; + + p_sw = (ftree_sw_t *) malloc(sizeof(ftree_sw_t)); + if (p_sw == NULL) + return NULL; + memset(p_sw, 0, sizeof(ftree_sw_t)); + + p_sw->p_osm_sw = p_osm_sw; + p_sw->rank = 0xFFFFFFFF; + __osm_ftree_tuple_init(p_sw->tuple); + + p_sw->base_lid = osm_node_get_base_lid(p_sw->p_osm_sw->p_node, 0); + + ports_num = osm_node_get_num_physp(p_sw->p_osm_sw->p_node); + p_sw->down_port_groups = + (ftree_port_group_t **) malloc(ports_num * + sizeof(ftree_port_group_t *)); + p_sw->up_port_groups = + (ftree_port_group_t **) malloc(ports_num * + sizeof(ftree_port_group_t *)); + if (!p_sw->down_port_groups || !p_sw->up_port_groups) + return NULL; + p_sw->down_port_groups_num = 0; + p_sw->up_port_groups_num = 0; + + /* initialize lft buffer */ + memset(p_osm_sw->new_lft, OSM_NO_PATH, IB_LID_UCAST_END_HO + 1); + + p_sw->down_port_groups_idx = -1; + + return p_sw; +} /* __osm_ftree_sw_create() */ + +/***************************************************/ + +static void __osm_ftree_sw_destroy(IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw) +{ + uint8_t i; + + if (!p_sw) + return; + + for (i = 0; i < p_sw->down_port_groups_num; i++) + __osm_ftree_port_group_destroy(p_sw->down_port_groups[i]); + for (i = 0; i < p_sw->up_port_groups_num; i++) + __osm_ftree_port_group_destroy(p_sw->up_port_groups[i]); + if (p_sw->down_port_groups) + free(p_sw->down_port_groups); + if (p_sw->up_port_groups) + free(p_sw->up_port_groups); + + free(p_sw); +} /* __osm_ftree_sw_destroy() */ + +/***************************************************/ + +static uint64_t __osm_ftree_sw_get_guid_no(IN ftree_sw_t * p_sw) +{ + if (!p_sw) + return 0; + return osm_node_get_node_guid(p_sw->p_osm_sw->p_node); +} + +/***************************************************/ + +static uint64_t __osm_ftree_sw_get_guid_ho(IN ftree_sw_t * p_sw) +{ + return cl_ntoh64(__osm_ftree_sw_get_guid_no(p_sw)); +} + +/***************************************************/ + +static void __osm_ftree_sw_dump(IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw) +{ + uint32_t i; + + if (!p_sw) + return; + + if (!osm_log_is_active(&p_ftree->p_osm->log, OSM_LOG_DEBUG)) + return; + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Switch index: %s, GUID: 0x%016" PRIx64 + ", Ports: %u DOWN, %u UP\n", + __osm_ftree_tuple_to_str(p_sw->tuple), + __osm_ftree_sw_get_guid_ho(p_sw), p_sw->down_port_groups_num, + p_sw->up_port_groups_num); + + for (i = 0; i < p_sw->down_port_groups_num; i++) + __osm_ftree_port_group_dump(p_ftree, + p_sw->down_port_groups[i], + FTREE_DIRECTION_DOWN); + for (i = 0; i < p_sw->up_port_groups_num; i++) + __osm_ftree_port_group_dump(p_ftree, p_sw->up_port_groups[i], + FTREE_DIRECTION_UP); + +} /* __osm_ftree_sw_dump() */ + +/***************************************************/ + +static boolean_t __osm_ftree_sw_ranked(IN ftree_sw_t * p_sw) +{ + return (p_sw->rank != 0xFFFFFFFF); +} + +/***************************************************/ + +static ftree_port_group_t * +__osm_ftree_sw_get_port_group_by_remote_lid(IN ftree_sw_t * p_sw, + IN ib_net16_t remote_base_lid, + IN ftree_direction_t direction) +{ + uint32_t i; + uint32_t size; + ftree_port_group_t **port_groups; + + if (direction == FTREE_DIRECTION_UP) { + port_groups = p_sw->up_port_groups; + size = p_sw->up_port_groups_num; + } else { + port_groups = p_sw->down_port_groups; + size = p_sw->down_port_groups_num; + } + + for (i = 0; i < size; i++) + if (remote_base_lid == port_groups[i]->remote_base_lid) + return port_groups[i]; + + return NULL; +} /* __osm_ftree_sw_get_port_group_by_remote_lid() */ + +/***************************************************/ + +static void +__osm_ftree_sw_add_port(IN ftree_sw_t * p_sw, + IN uint8_t port_num, + IN uint8_t remote_port_num, + IN ib_net16_t base_lid, + IN ib_net16_t remote_base_lid, + IN ib_net64_t port_guid, + IN ib_net64_t remote_port_guid, + IN ib_net64_t remote_node_guid, + IN uint8_t remote_node_type, + IN void *p_remote_hca_or_sw, + IN ftree_direction_t direction) +{ + ftree_port_group_t *p_group = + __osm_ftree_sw_get_port_group_by_remote_lid(p_sw, remote_base_lid, + direction); + + if (!p_group) { + p_group = __osm_ftree_port_group_create(base_lid, + remote_base_lid, + port_guid, + __osm_ftree_sw_get_guid_no + (p_sw), + IB_NODE_TYPE_SWITCH, + p_sw, remote_port_guid, + remote_node_guid, + remote_node_type, + p_remote_hca_or_sw, + FALSE); + CL_ASSERT(p_group); + + if (direction == FTREE_DIRECTION_UP) + p_sw->up_port_groups[p_sw->up_port_groups_num++] = + p_group; + else + p_sw->down_port_groups[p_sw->down_port_groups_num++] = + p_group; + } + __osm_ftree_port_group_add_port(p_group, port_num, remote_port_num); + +} /* __osm_ftree_sw_add_port() */ + +/***************************************************/ + +static inline cl_status_t +__osm_ftree_sw_set_hops(IN ftree_sw_t * p_sw, + IN uint16_t lid_ho, IN uint8_t port_num, + IN uint8_t hops) +{ + /* set local min hop table(LID) */ + return osm_switch_set_hops(p_sw->p_osm_sw, lid_ho, port_num, hops); +} + +/*************************************************** + ** + ** ftree_hca_t functions + ** + ***************************************************/ + +static ftree_hca_t *__osm_ftree_hca_create(IN osm_node_t * p_osm_node) +{ + ftree_hca_t *p_hca = (ftree_hca_t *) malloc(sizeof(ftree_hca_t)); + if (p_hca == NULL) + return NULL; + memset(p_hca, 0, sizeof(ftree_hca_t)); + + p_hca->p_osm_node = p_osm_node; + p_hca->up_port_groups = (ftree_port_group_t **) + malloc(osm_node_get_num_physp(p_hca->p_osm_node) * + sizeof(ftree_port_group_t *)); + if (!p_hca->up_port_groups) + return NULL; + p_hca->up_port_groups_num = 0; + return p_hca; +} + +/***************************************************/ + +static void __osm_ftree_hca_destroy(IN ftree_hca_t * p_hca) +{ + uint32_t i; + + if (!p_hca) + return; + + for (i = 0; i < p_hca->up_port_groups_num; i++) + __osm_ftree_port_group_destroy(p_hca->up_port_groups[i]); + + if (p_hca->up_port_groups) + free(p_hca->up_port_groups); + + free(p_hca); +} + +/***************************************************/ + +static uint64_t __osm_ftree_hca_get_guid_no(IN ftree_hca_t * p_hca) +{ + if (!p_hca) + return 0; + return osm_node_get_node_guid(p_hca->p_osm_node); +} + +/***************************************************/ + +static uint64_t __osm_ftree_hca_get_guid_ho(IN ftree_hca_t * p_hca) +{ + return cl_ntoh64(__osm_ftree_hca_get_guid_no(p_hca)); +} + +/***************************************************/ + +static void __osm_ftree_hca_dump(IN ftree_fabric_t * p_ftree, + IN ftree_hca_t * p_hca) +{ + uint32_t i; + + if (!p_hca) + return; + + if (!osm_log_is_active(&p_ftree->p_osm->log, OSM_LOG_DEBUG)) + return; + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "CA GUID: 0x%016" PRIx64 ", Ports: %u UP\n", + __osm_ftree_hca_get_guid_ho(p_hca), p_hca->up_port_groups_num); + + for (i = 0; i < p_hca->up_port_groups_num; i++) + __osm_ftree_port_group_dump(p_ftree, p_hca->up_port_groups[i], + FTREE_DIRECTION_UP); +} + +/***************************************************/ + +static ftree_port_group_t * +__osm_ftree_hca_get_port_group_by_remote_lid(IN ftree_hca_t * p_hca, + IN ib_net16_t remote_base_lid) +{ + uint32_t i; + for (i = 0; i < p_hca->up_port_groups_num; i++) + if (remote_base_lid == + p_hca->up_port_groups[i]->remote_base_lid) + return p_hca->up_port_groups[i]; + + return NULL; +} + +/***************************************************/ + +static void +__osm_ftree_hca_add_port(IN ftree_hca_t * p_hca, + IN uint8_t port_num, + IN uint8_t remote_port_num, + IN ib_net16_t base_lid, + IN ib_net16_t remote_base_lid, + IN ib_net64_t port_guid, + IN ib_net64_t remote_port_guid, + IN ib_net64_t remote_node_guid, + IN uint8_t remote_node_type, + IN void *p_remote_hca_or_sw, IN boolean_t is_cn) +{ + ftree_port_group_t *p_group; + + /* this function is supposed to be called only for adding ports + in hca's that lead to switches */ + CL_ASSERT(remote_node_type == IB_NODE_TYPE_SWITCH); + + p_group = + __osm_ftree_hca_get_port_group_by_remote_lid(p_hca, + remote_base_lid); + + if (!p_group) { + p_group = __osm_ftree_port_group_create(base_lid, + remote_base_lid, + port_guid, + __osm_ftree_hca_get_guid_no + (p_hca), + IB_NODE_TYPE_CA, p_hca, + remote_port_guid, + remote_node_guid, + remote_node_type, + p_remote_hca_or_sw, + is_cn); + p_hca->up_port_groups[p_hca->up_port_groups_num++] = p_group; + } + __osm_ftree_port_group_add_port(p_group, port_num, remote_port_num); + +} /* __osm_ftree_hca_add_port() */ + +/*************************************************** + ** + ** ftree_fabric_t functions + ** + ***************************************************/ + +static ftree_fabric_t *__osm_ftree_fabric_create() +{ + ftree_fabric_t *p_ftree = + (ftree_fabric_t *) malloc(sizeof(ftree_fabric_t)); + if (p_ftree == NULL) + return NULL; + + memset(p_ftree, 0, sizeof(ftree_fabric_t)); + + cl_qmap_init(&p_ftree->hca_tbl); + cl_qmap_init(&p_ftree->sw_tbl); + cl_qmap_init(&p_ftree->sw_by_tuple_tbl); + cl_qmap_init(&p_ftree->cn_guid_tbl); + + cl_qlist_init(&p_ftree->root_guid_list); + + return p_ftree; +} + +/***************************************************/ + +static void __osm_ftree_fabric_clear(ftree_fabric_t * p_ftree) +{ + ftree_hca_t *p_hca; + ftree_hca_t *p_next_hca; + ftree_sw_t *p_sw; + ftree_sw_t *p_next_sw; + ftree_sw_tbl_element_t *p_element; + ftree_sw_tbl_element_t *p_next_element; + name_map_item_t *p_guid_element, *p_next_guid_element; + + if (!p_ftree) + return; + + /* remove all the elements of hca_tbl */ + + p_next_hca = (ftree_hca_t *) cl_qmap_head(&p_ftree->hca_tbl); + while (p_next_hca != (ftree_hca_t *) cl_qmap_end(&p_ftree->hca_tbl)) { + p_hca = p_next_hca; + p_next_hca = (ftree_hca_t *) cl_qmap_next(&p_hca->map_item); + __osm_ftree_hca_destroy(p_hca); + } + cl_qmap_remove_all(&p_ftree->hca_tbl); + + /* remove all the elements of sw_tbl */ + + p_next_sw = (ftree_sw_t *) cl_qmap_head(&p_ftree->sw_tbl); + while (p_next_sw != (ftree_sw_t *) cl_qmap_end(&p_ftree->sw_tbl)) { + p_sw = p_next_sw; + p_next_sw = (ftree_sw_t *) cl_qmap_next(&p_sw->map_item); + __osm_ftree_sw_destroy(p_ftree, p_sw); + } + cl_qmap_remove_all(&p_ftree->sw_tbl); + + /* remove all the elements of sw_by_tuple_tbl */ + + p_next_element = + (ftree_sw_tbl_element_t *) cl_qmap_head(&p_ftree->sw_by_tuple_tbl); + while (p_next_element != + (ftree_sw_tbl_element_t *) cl_qmap_end(&p_ftree-> + sw_by_tuple_tbl)) { + p_element = p_next_element; + p_next_element = + (ftree_sw_tbl_element_t *) cl_qmap_next(&p_element-> + map_item); + __osm_ftree_sw_tbl_element_destroy(p_element); + } + cl_qmap_remove_all(&p_ftree->sw_by_tuple_tbl); + + /* remove all the elements of cn_guid_tbl */ + p_next_guid_element = + (name_map_item_t *) cl_qmap_head(&p_ftree->cn_guid_tbl); + while (p_next_guid_element != + (name_map_item_t *) cl_qmap_end(&p_ftree->cn_guid_tbl)) { + p_guid_element = p_next_guid_element; + p_next_guid_element = + (name_map_item_t *) cl_qmap_next(&p_guid_element->item); + free(p_guid_element); + } + cl_qmap_remove_all(&p_ftree->cn_guid_tbl); + + /* remove all the elements of root_guid_list */ + while (!cl_is_qlist_empty(&p_ftree->root_guid_list)) + free(cl_qlist_remove_head(&p_ftree->root_guid_list)); + + /* free the leaf switches array */ + if ((p_ftree->leaf_switches_num > 0) && (p_ftree->leaf_switches)) + free(p_ftree->leaf_switches); + + p_ftree->leaf_switches_num = 0; + p_ftree->cn_num = 0; + p_ftree->leaf_switch_rank = 0; + p_ftree->max_switch_rank = 0; + p_ftree->max_cn_per_leaf = 0; + p_ftree->lft_max_lid_ho = 0; + p_ftree->leaf_switches = NULL; + p_ftree->fabric_built = FALSE; + +} /* __osm_ftree_fabric_destroy() */ + +/***************************************************/ + +static void __osm_ftree_fabric_destroy(ftree_fabric_t * p_ftree) +{ + if (!p_ftree) + return; + __osm_ftree_fabric_clear(p_ftree); + free(p_ftree); +} + +/***************************************************/ + +static uint8_t __osm_ftree_fabric_get_rank(ftree_fabric_t * p_ftree) +{ + return p_ftree->leaf_switch_rank + 1; +} + +/***************************************************/ + +static void __osm_ftree_fabric_add_hca(ftree_fabric_t * p_ftree, + osm_node_t * p_osm_node) +{ + ftree_hca_t *p_hca = __osm_ftree_hca_create(p_osm_node); + + CL_ASSERT(osm_node_get_type(p_osm_node) == IB_NODE_TYPE_CA); + + cl_qmap_insert(&p_ftree->hca_tbl, p_osm_node->node_info.node_guid, + &p_hca->map_item); +} + +/***************************************************/ + +static void __osm_ftree_fabric_add_sw(ftree_fabric_t * p_ftree, + osm_switch_t * p_osm_sw) +{ + ftree_sw_t *p_sw = __osm_ftree_sw_create(p_ftree, p_osm_sw); + + CL_ASSERT(osm_node_get_type(p_osm_sw->p_node) == IB_NODE_TYPE_SWITCH); + + cl_qmap_insert(&p_ftree->sw_tbl, p_osm_sw->p_node->node_info.node_guid, + &p_sw->map_item); + + /* track the max lid (in host order) that exists in the fabric */ + if (cl_ntoh16(p_sw->base_lid) > p_ftree->lft_max_lid_ho) + p_ftree->lft_max_lid_ho = cl_ntoh16(p_sw->base_lid); +} + +/***************************************************/ + +static void __osm_ftree_fabric_add_sw_by_tuple(IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw) +{ + CL_ASSERT(__osm_ftree_tuple_assigned(p_sw->tuple)); + + cl_qmap_insert(&p_ftree->sw_by_tuple_tbl, + __osm_ftree_tuple_to_key(p_sw->tuple), + &__osm_ftree_sw_tbl_element_create(p_sw)->map_item); +} + +/***************************************************/ + +static ftree_sw_t *__osm_ftree_fabric_get_sw_by_tuple(IN ftree_fabric_t * + p_ftree, + IN ftree_tuple_t tuple) +{ + ftree_sw_tbl_element_t *p_element; + + CL_ASSERT(__osm_ftree_tuple_assigned(tuple)); + + __osm_ftree_tuple_to_key(tuple); + + p_element = + (ftree_sw_tbl_element_t *) cl_qmap_get(&p_ftree->sw_by_tuple_tbl, + __osm_ftree_tuple_to_key + (tuple)); + if (p_element == + (ftree_sw_tbl_element_t *) cl_qmap_end(&p_ftree->sw_by_tuple_tbl)) + return NULL; + + return p_element->p_sw; +} + +/***************************************************/ + +static ftree_sw_t *__osm_ftree_fabric_get_sw_by_guid(IN ftree_fabric_t * + p_ftree, IN uint64_t guid) +{ + ftree_sw_t *p_sw; + p_sw = (ftree_sw_t *) cl_qmap_get(&p_ftree->sw_tbl, guid); + if (p_sw == (ftree_sw_t *) cl_qmap_end(&p_ftree->sw_tbl)) + return NULL; + return p_sw; +} + +/***************************************************/ + +static ftree_hca_t *__osm_ftree_fabric_get_hca_by_guid(IN ftree_fabric_t * + p_ftree, + IN uint64_t guid) +{ + ftree_hca_t *p_hca; + p_hca = (ftree_hca_t *) cl_qmap_get(&p_ftree->hca_tbl, guid); + if (p_hca == (ftree_hca_t *) cl_qmap_end(&p_ftree->hca_tbl)) + return NULL; + return p_hca; +} + +/***************************************************/ + +static void __osm_ftree_fabric_dump(ftree_fabric_t * p_ftree) +{ + uint32_t i; + ftree_hca_t *p_hca; + ftree_sw_t *p_sw; + + if (!osm_log_is_active(&p_ftree->p_osm->log, OSM_LOG_DEBUG)) + return; + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, "\n" + " |-------------------------------|\n" + " |- Full fabric topology dump -|\n" + " |-------------------------------|\n\n"); + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, "-- CAs:\n"); + + for (p_hca = (ftree_hca_t *) cl_qmap_head(&p_ftree->hca_tbl); + p_hca != (ftree_hca_t *) cl_qmap_end(&p_ftree->hca_tbl); + p_hca = (ftree_hca_t *) cl_qmap_next(&p_hca->map_item)) { + __osm_ftree_hca_dump(p_ftree, p_hca); + } + + for (i = 0; i < p_ftree->max_switch_rank; i++) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "-- Rank %u switches\n", i); + for (p_sw = (ftree_sw_t *) cl_qmap_head(&p_ftree->sw_tbl); + p_sw != (ftree_sw_t *) cl_qmap_end(&p_ftree->sw_tbl); + p_sw = (ftree_sw_t *) cl_qmap_next(&p_sw->map_item)) { + if (p_sw->rank == i) + __osm_ftree_sw_dump(p_ftree, p_sw); + } + } + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, "\n" + " |---------------------------------------|\n" + " |- Full fabric topology dump completed -|\n" + " |---------------------------------------|\n\n"); +} /* __osm_ftree_fabric_dump() */ + +/***************************************************/ + +static void __osm_ftree_fabric_dump_general_info(IN ftree_fabric_t * p_ftree) +{ + uint32_t i, j; + ftree_sw_t *p_sw; + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_INFO, + "General fabric topology info\n"); + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_INFO, + "============================\n"); + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_INFO, + " - FatTree rank (roots to leaf switches): %u\n", + p_ftree->leaf_switch_rank + 1); + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_INFO, + " - FatTree max switch rank: %u\n", p_ftree->max_switch_rank); + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_INFO, + " - Fabric has %u CAs (%u of them CNs), %u switches\n", + cl_qmap_count(&p_ftree->hca_tbl), p_ftree->cn_num, + cl_qmap_count(&p_ftree->sw_tbl)); + + CL_ASSERT(cl_qmap_count(&p_ftree->hca_tbl) >= p_ftree->cn_num); + + for (i = 0; i <= p_ftree->max_switch_rank; i++) { + j = 0; + for (p_sw = (ftree_sw_t *) cl_qmap_head(&p_ftree->sw_tbl); + p_sw != (ftree_sw_t *) cl_qmap_end(&p_ftree->sw_tbl); + p_sw = (ftree_sw_t *) cl_qmap_next(&p_sw->map_item)) { + if (p_sw->rank == i) + j++; + } + if (i == 0) + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_INFO, + " - Fabric has %u switches at rank %u (roots)\n", + j, i); + else if (i == p_ftree->leaf_switch_rank) + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_INFO, + " - Fabric has %u switches at rank %u (%u of them leafs)\n", + j, i, p_ftree->leaf_switches_num); + else + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_INFO, + " - Fabric has %u switches at rank %u\n", j, + i); + } + + if (osm_log_is_active(&p_ftree->p_osm->log, OSM_LOG_VERBOSE)) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + " - Root switches:\n"); + for (p_sw = (ftree_sw_t *) cl_qmap_head(&p_ftree->sw_tbl); + p_sw != (ftree_sw_t *) cl_qmap_end(&p_ftree->sw_tbl); + p_sw = (ftree_sw_t *) cl_qmap_next(&p_sw->map_item)) { + if (p_sw->rank == 0) + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + " GUID: 0x%016" PRIx64 + ", LID: %u, Index %s\n", + __osm_ftree_sw_get_guid_ho(p_sw), + cl_ntoh16(p_sw->base_lid), + __osm_ftree_tuple_to_str(p_sw->tuple)); + } + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + " - Leaf switches (sorted by index):\n"); + for (i = 0; i < p_ftree->leaf_switches_num; i++) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + " GUID: 0x%016" PRIx64 + ", LID: %u, Index %s\n", + __osm_ftree_sw_get_guid_ho(p_ftree-> + leaf_switches[i]), + cl_ntoh16(p_ftree->leaf_switches[i]->base_lid), + __osm_ftree_tuple_to_str(p_ftree-> + leaf_switches[i]-> + tuple)); + } + } +} /* __osm_ftree_fabric_dump_general_info() */ + +/***************************************************/ + +static void __osm_ftree_fabric_dump_hca_ordering(IN ftree_fabric_t * p_ftree) +{ + ftree_hca_t *p_hca; + ftree_sw_t *p_sw; + ftree_port_group_t *p_group_on_sw; + ftree_port_group_t *p_group_on_hca; + uint32_t i; + uint32_t j; + unsigned printed_hcas_on_leaf; + + char path[1024]; + FILE *p_hca_ordering_file; + char *filename = "opensm-ftree-ca-order.dump"; + + snprintf(path, sizeof(path), "%s/%s", + p_ftree->p_osm->subn.opt.dump_files_dir, filename); + p_hca_ordering_file = fopen(path, "w"); + if (!p_hca_ordering_file) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, "ERR AB01: " + "cannot open file \'%s\': %s\n", filename, + strerror(errno)); + return; + } + + /* for each leaf switch (in indexing order) */ + for (i = 0; i < p_ftree->leaf_switches_num; i++) { + p_sw = p_ftree->leaf_switches[i]; + printed_hcas_on_leaf = 0; + + /* for each real CA (CNs and not) connected to this switch */ + for (j = 0; j < p_sw->down_port_groups_num; j++) { + p_group_on_sw = p_sw->down_port_groups[j]; + + if (p_group_on_sw->remote_node_type != IB_NODE_TYPE_CA) + continue; + + p_hca = p_group_on_sw->remote_hca_or_sw.p_hca; + p_group_on_hca = + __osm_ftree_hca_get_port_group_by_remote_lid(p_hca, + p_group_on_sw-> + base_lid); + + /* treat non-compute nodes as dummies */ + if (!p_group_on_hca->is_cn) + continue; + + fprintf(p_hca_ordering_file, "0x%04x\t%s\n", + cl_ntoh16(p_group_on_hca->base_lid), + p_hca->p_osm_node->print_desc); + + printed_hcas_on_leaf++; + } + + /* now print missing HCAs */ + for (j = 0; + j < (p_ftree->max_cn_per_leaf - printed_hcas_on_leaf); j++) + fprintf(p_hca_ordering_file, "0xFFFF\tDUMMY\n"); + + } + /* done going through all the leaf switches */ + + fclose(p_hca_ordering_file); +} /* __osm_ftree_fabric_dump_hca_ordering() */ + +/***************************************************/ + +static void +__osm_ftree_fabric_assign_tuple(IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw, + IN ftree_tuple_t new_tuple) +{ + memcpy(p_sw->tuple, new_tuple, FTREE_TUPLE_LEN); + __osm_ftree_fabric_add_sw_by_tuple(p_ftree, p_sw); +} + +/***************************************************/ + +static void __osm_ftree_fabric_assign_first_tuple(IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw) +{ + uint8_t i; + ftree_tuple_t new_tuple; + + __osm_ftree_tuple_init(new_tuple); + new_tuple[0] = (uint8_t) p_sw->rank; + for (i = 1; i <= p_sw->rank; i++) + new_tuple[i] = 0; + + __osm_ftree_fabric_assign_tuple(p_ftree, p_sw, new_tuple); +} + +/***************************************************/ + +static void +__osm_ftree_fabric_get_new_tuple(IN ftree_fabric_t * p_ftree, + OUT ftree_tuple_t new_tuple, + IN ftree_tuple_t from_tuple, + IN ftree_direction_t direction) +{ + ftree_sw_t *p_sw; + ftree_tuple_t temp_tuple; + uint8_t var_index; + uint8_t i; + + __osm_ftree_tuple_init(new_tuple); + memcpy(temp_tuple, from_tuple, FTREE_TUPLE_LEN); + + if (direction == FTREE_DIRECTION_DOWN) { + temp_tuple[0]++; + var_index = from_tuple[0] + 1; + } else { + temp_tuple[0]--; + var_index = from_tuple[0]; + } + + for (i = 0; i < 0xFF; i++) { + temp_tuple[var_index] = i; + p_sw = __osm_ftree_fabric_get_sw_by_tuple(p_ftree, temp_tuple); + if (p_sw == NULL) /* found free tuple */ + break; + } + + if (i == 0xFF) { + /* new tuple not found - there are more than 255 ports in one direction */ + return; + } + memcpy(new_tuple, temp_tuple, FTREE_TUPLE_LEN); + +} /* __osm_ftree_fabric_get_new_tuple() */ + +/***************************************************/ + +static inline boolean_t __osm_ftree_fabric_roots_provided(IN ftree_fabric_t * + p_ftree) +{ + return (p_ftree->p_osm->subn.opt.root_guid_file != NULL); +} + +/***************************************************/ + +static inline boolean_t __osm_ftree_fabric_cns_provided(IN ftree_fabric_t * + p_ftree) +{ + return (p_ftree->p_osm->subn.opt.cn_guid_file != NULL); +} + +/***************************************************/ + +static int __osm_ftree_fabric_mark_leaf_switches(IN ftree_fabric_t * p_ftree) +{ + ftree_sw_t *p_sw; + ftree_hca_t *p_hca; + ftree_hca_t *p_next_hca; + unsigned i; + int res = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Marking leaf switches in fabric\n"); + + /* Scan all the CAs, if they have CNs - find CN port and mark switch + that is connected to this port as leaf switch. + Also, ensure that this marked leaf has rank of p_ftree->leaf_switch_rank. */ + p_next_hca = (ftree_hca_t *) cl_qmap_head(&p_ftree->hca_tbl); + while (p_next_hca != (ftree_hca_t *) cl_qmap_end(&p_ftree->hca_tbl)) { + p_hca = p_next_hca; + p_next_hca = (ftree_hca_t *) cl_qmap_next(&p_hca->map_item); + if (!p_hca->cn_num) + continue; + + for (i = 0; i < p_hca->up_port_groups_num; i++) { + if (!p_hca->up_port_groups[i]->is_cn) + continue; + + /* In CAs, port group alway has one port, and since this + port group is CN, we know that this port is compute node */ + CL_ASSERT(p_hca->up_port_groups[i]->remote_node_type == + IB_NODE_TYPE_SWITCH); + p_sw = p_hca->up_port_groups[i]->remote_hca_or_sw.p_sw; + + /* check if this switch was already processed */ + if (p_sw->is_leaf) + continue; + p_sw->is_leaf = TRUE; + + /* ensure that this leaf switch is at the correct tree level */ + if (p_sw->rank != p_ftree->leaf_switch_rank) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "ERR AB26: CN port 0x%" PRIx64 + " is connected to switch 0x%" PRIx64 + " with rank %u, " + "while FatTree leaf rank is %u\n", + cl_ntoh64(p_hca->up_port_groups[i]-> + port_guid), + __osm_ftree_sw_get_guid_ho(p_sw), + p_sw->rank, p_ftree->leaf_switch_rank); + res = -1; + goto Exit; + + } + } + } + +Exit: + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* __osm_ftree_fabric_mark_leaf_switches() */ + +/***************************************************/ + +static void __osm_ftree_fabric_make_indexing(IN ftree_fabric_t * p_ftree) +{ + ftree_sw_t *p_remote_sw; + ftree_sw_t *p_sw = NULL; + ftree_sw_t *p_next_sw; + ftree_tuple_t new_tuple; + uint32_t i; + cl_list_t bfs_list; + ftree_sw_tbl_element_t *p_sw_tbl_element; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Starting FatTree indexing\n"); + + /* using the first leaf switch as a starting point for indexing algorithm. */ + p_next_sw = (ftree_sw_t *) cl_qmap_head(&p_ftree->sw_tbl); + while (p_next_sw != (ftree_sw_t *) cl_qmap_end(&p_ftree->sw_tbl)) { + p_sw = p_next_sw; + if (p_sw->is_leaf) + break; + p_next_sw = (ftree_sw_t *) cl_qmap_next(&p_sw->map_item); + } + + CL_ASSERT(p_next_sw != (ftree_sw_t *) cl_qmap_end(&p_ftree->sw_tbl)); + + /* Assign the first tuple to the switch that is used as BFS starting point. + The tuple will be as follows: [rank].0.0.0... + This fuction also adds the switch it into the switch_by_tuple table. */ + __osm_ftree_fabric_assign_first_tuple(p_ftree, p_sw); + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Indexing starting point:\n" + " - Switch rank : %u\n" + " - Switch index : %s\n" + " - Node LID : %u\n" + " - Node GUID : 0x%016" + PRIx64 "\n", p_sw->rank, __osm_ftree_tuple_to_str(p_sw->tuple), + cl_ntoh16(p_sw->base_lid), __osm_ftree_sw_get_guid_ho(p_sw)); + + /* + * Now run BFS and assign indexes to all switches + * Pseudo code of the algorithm is as follows: + * + * * Add first switch to BFS queue + * * While (BFS queue not empty) + * - Pop the switch from the head of the queue + * - Scan all the downward and upward ports + * - For each port + * + Get the remote switch + * + Assign index to the remote switch + * + Add remote switch to the BFS queue + */ + + cl_list_init(&bfs_list, cl_qmap_count(&p_ftree->sw_tbl)); + cl_list_insert_tail(&bfs_list, + &__osm_ftree_sw_tbl_element_create(p_sw)->map_item); + + while (!cl_is_list_empty(&bfs_list)) { + p_sw_tbl_element = + (ftree_sw_tbl_element_t *) cl_list_remove_head(&bfs_list); + p_sw = p_sw_tbl_element->p_sw; + __osm_ftree_sw_tbl_element_destroy(p_sw_tbl_element); + + /* Discover all the nodes from ports that are pointing down */ + + if (p_sw->rank >= p_ftree->leaf_switch_rank) { + /* whether downward ports are pointing to CAs or switches, + we don't assign indexes to switches that are located + lower than leaf switches */ + } else { + /* This is not the leaf switch */ + for (i = 0; i < p_sw->down_port_groups_num; i++) { + /* Work with port groups that are pointing to switches only. + No need to assign indexing to HCAs */ + if (p_sw->down_port_groups[i]-> + remote_node_type != IB_NODE_TYPE_SWITCH) + continue; + + p_remote_sw = + p_sw->down_port_groups[i]->remote_hca_or_sw. + p_sw; + if (__osm_ftree_tuple_assigned + (p_remote_sw->tuple)) { + /* this switch has been already indexed */ + continue; + } + /* allocate new tuple */ + __osm_ftree_fabric_get_new_tuple(p_ftree, + new_tuple, + p_sw->tuple, + FTREE_DIRECTION_DOWN); + /* Assign the new tuple to the remote switch. + This fuction also adds the switch into the switch_by_tuple table. */ + __osm_ftree_fabric_assign_tuple(p_ftree, + p_remote_sw, + new_tuple); + + /* add the newly discovered switch to the BFS queue */ + cl_list_insert_tail(&bfs_list, + &__osm_ftree_sw_tbl_element_create + (p_remote_sw)->map_item); + } + /* Done assigning indexes to all the remote switches + that are pointed by the downgoing ports. + Now sort port groups according to remote index. */ + qsort(p_sw->down_port_groups, /* array */ + p_sw->down_port_groups_num, /* number of elements */ + sizeof(ftree_port_group_t *), /* size of each element */ + __osm_ftree_compare_port_groups_by_remote_switch_index); /* comparator */ + } + + /* Done indexing switches from ports that go down. + Now do the same with ports that are pointing up. */ + + if (p_sw->rank != 0) { + /* This is not the root switch, which means that all the ports + that are pointing up are taking us to another switches. */ + for (i = 0; i < p_sw->up_port_groups_num; i++) { + p_remote_sw = + p_sw->up_port_groups[i]->remote_hca_or_sw. + p_sw; + if (__osm_ftree_tuple_assigned + (p_remote_sw->tuple)) + continue; + /* allocate new tuple */ + __osm_ftree_fabric_get_new_tuple(p_ftree, + new_tuple, + p_sw->tuple, + FTREE_DIRECTION_UP); + /* Assign the new tuple to the remote switch. + This fuction also adds the switch to the + switch_by_tuple table. */ + __osm_ftree_fabric_assign_tuple(p_ftree, + p_remote_sw, + new_tuple); + /* add the newly discovered switch to the BFS queue */ + cl_list_insert_tail(&bfs_list, + &__osm_ftree_sw_tbl_element_create + (p_remote_sw)->map_item); + } + /* Done assigning indexes to all the remote switches + that are pointed by the upgoing ports. + Now sort port groups according to remote index. */ + qsort(p_sw->up_port_groups, /* array */ + p_sw->up_port_groups_num, /* number of elements */ + sizeof(ftree_port_group_t *), /* size of each element */ + __osm_ftree_compare_port_groups_by_remote_switch_index); /* comparator */ + } + /* Done assigning indexes to all the switches that are directly connected + to the current switch - go to the next switch in the BFS queue */ + } + cl_list_destroy(&bfs_list); + + OSM_LOG_EXIT(&p_ftree->p_osm->log); +} /* __osm_ftree_fabric_make_indexing() */ + +/***************************************************/ + +static int __osm_ftree_fabric_create_leaf_switch_array(IN ftree_fabric_t * + p_ftree) +{ + ftree_sw_t *p_sw; + ftree_sw_t *p_next_sw; + ftree_sw_t **all_switches_at_leaf_level; + unsigned i; + unsigned all_leaf_idx = 0; + unsigned first_leaf_idx; + unsigned last_leaf_idx; + int res = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + /* create array of ALL the switches that have leaf rank */ + all_switches_at_leaf_level = (ftree_sw_t **) + malloc(cl_qmap_count(&p_ftree->sw_tbl) * sizeof(ftree_sw_t *)); + if (!all_switches_at_leaf_level) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fat-tree routing: Memory allocation failed\n"); + res = -1; + goto Exit; + } + memset(all_switches_at_leaf_level, 0, + cl_qmap_count(&p_ftree->sw_tbl) * sizeof(ftree_sw_t *)); + + p_next_sw = (ftree_sw_t *) cl_qmap_head(&p_ftree->sw_tbl); + while (p_next_sw != (ftree_sw_t *) cl_qmap_end(&p_ftree->sw_tbl)) { + p_sw = p_next_sw; + p_next_sw = (ftree_sw_t *) cl_qmap_next(&p_sw->map_item); + if (p_sw->rank == p_ftree->leaf_switch_rank) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Adding switch 0x%" PRIx64 + " to full leaf switch array\n", + __osm_ftree_sw_get_guid_ho(p_sw)); + all_switches_at_leaf_level[all_leaf_idx++] = p_sw; + + } + } + + /* quick-sort array of leaf switches by index */ + qsort(all_switches_at_leaf_level, /* array */ + all_leaf_idx, /* number of elements */ + sizeof(ftree_sw_t *), /* size of each element */ + __osm_ftree_compare_switches_by_index); /* comparator */ + + /* check the first and the last REAL leaf (the one + that has CNs) in the array of all the leafs */ + + first_leaf_idx = all_leaf_idx; + last_leaf_idx = 0; + for (i = 0; i < all_leaf_idx; i++) { + if (all_switches_at_leaf_level[i]->is_leaf) { + if (i < first_leaf_idx) + first_leaf_idx = i; + last_leaf_idx = i; + } + } + CL_ASSERT(first_leaf_idx < last_leaf_idx); + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Full leaf array info: first_leaf_idx = %u, last_leaf_idx = %u\n", + first_leaf_idx, last_leaf_idx); + + /* Create array of REAL leaf switches, sorted by index. + This array may contain switches at the same rank w/o CNs, + in case this is the order of indexing. */ + p_ftree->leaf_switches_num = last_leaf_idx - first_leaf_idx + 1; + p_ftree->leaf_switches = (ftree_sw_t **) + malloc(p_ftree->leaf_switches_num * sizeof(ftree_sw_t *)); + if (!p_ftree->leaf_switches) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fat-tree routing: Memory allocation failed\n"); + res = -1; + goto Exit; + } + + memcpy(p_ftree->leaf_switches, + &(all_switches_at_leaf_level[first_leaf_idx]), + p_ftree->leaf_switches_num * sizeof(ftree_sw_t *)); + + free(all_switches_at_leaf_level); + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Created array of %u leaf switches\n", + p_ftree->leaf_switches_num); + +Exit: + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* __osm_ftree_fabric_create_leaf_switch_array() */ + +/***************************************************/ + +static void __osm_ftree_fabric_set_max_cn_per_leaf(IN ftree_fabric_t * p_ftree) +{ + unsigned i; + unsigned j; + unsigned cns_on_this_leaf; + ftree_sw_t *p_sw; + ftree_port_group_t *p_group; + + for (i = 0; i < p_ftree->leaf_switches_num; i++) { + p_sw = p_ftree->leaf_switches[i]; + cns_on_this_leaf = 0; + for (j = 0; j < p_sw->down_port_groups_num; j++) { + p_group = p_sw->down_port_groups[j]; + if (p_group->remote_node_type != IB_NODE_TYPE_CA) + continue; + cns_on_this_leaf += + p_group->remote_hca_or_sw.p_hca->cn_num; + } + if (cns_on_this_leaf > p_ftree->max_cn_per_leaf) + p_ftree->max_cn_per_leaf = cns_on_this_leaf; + } +} /* __osm_ftree_fabric_set_max_cn_per_leaf() */ + +/***************************************************/ + +static boolean_t __osm_ftree_fabric_validate_topology(IN ftree_fabric_t * + p_ftree) +{ + ftree_port_group_t *p_group; + ftree_port_group_t *p_ref_group; + ftree_sw_t *p_sw; + ftree_sw_t *p_next_sw; + ftree_sw_t **reference_sw_arr; + uint16_t tree_rank = __osm_ftree_fabric_get_rank(p_ftree); + boolean_t res = TRUE; + uint8_t i; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Validating fabric topology\n"); + + reference_sw_arr = + (ftree_sw_t **) malloc(tree_rank * sizeof(ftree_sw_t *)); + if (reference_sw_arr == NULL) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fat-tree routing: Memory allocation failed\n"); + return FALSE; + } + memset(reference_sw_arr, 0, tree_rank * sizeof(ftree_sw_t *)); + + p_next_sw = (ftree_sw_t *) cl_qmap_head(&p_ftree->sw_tbl); + while (res && p_next_sw != (ftree_sw_t *) cl_qmap_end(&p_ftree->sw_tbl)) { + p_sw = p_next_sw; + p_next_sw = (ftree_sw_t *) cl_qmap_next(&p_sw->map_item); + + if (!reference_sw_arr[p_sw->rank]) { + /* This is the first switch in the current level that + we're checking - use it as a reference */ + reference_sw_arr[p_sw->rank] = p_sw; + } else { + /* compare this switch properties to the reference switch */ + + if (reference_sw_arr[p_sw->rank]->up_port_groups_num != + p_sw->up_port_groups_num) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "ERR AB09: Different number of upward port groups on switches:\n" + " GUID 0x%016" PRIx64 + ", LID %u, Index %s - %u groups\n" + " GUID 0x%016" PRIx64 + ", LID %u, Index %s - %u groups\n", + __osm_ftree_sw_get_guid_ho + (reference_sw_arr[p_sw->rank]), + cl_ntoh16(reference_sw_arr[p_sw->rank]-> + base_lid), + __osm_ftree_tuple_to_str + (reference_sw_arr[p_sw->rank]->tuple), + reference_sw_arr[p_sw->rank]-> + up_port_groups_num, + __osm_ftree_sw_get_guid_ho(p_sw), + cl_ntoh16(p_sw->base_lid), + __osm_ftree_tuple_to_str(p_sw->tuple), + p_sw->up_port_groups_num); + res = FALSE; + break; + } + + if (p_sw->rank != (tree_rank - 1) && + reference_sw_arr[p_sw->rank]-> + down_port_groups_num != + p_sw->down_port_groups_num) { + /* we're allowing some hca's to be missing */ + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "ERR AB0A: Different number of downward port groups on switches:\n" + " GUID 0x%016" PRIx64 + ", LID %u, Index %s - %u port groups\n" + " GUID 0x%016" PRIx64 + ", LID %u, Index %s - %u port groups\n", + __osm_ftree_sw_get_guid_ho + (reference_sw_arr[p_sw->rank]), + cl_ntoh16(reference_sw_arr[p_sw->rank]-> + base_lid), + __osm_ftree_tuple_to_str + (reference_sw_arr[p_sw->rank]->tuple), + reference_sw_arr[p_sw->rank]-> + down_port_groups_num, + __osm_ftree_sw_get_guid_ho(p_sw), + cl_ntoh16(p_sw->base_lid), + __osm_ftree_tuple_to_str(p_sw->tuple), + p_sw->down_port_groups_num); + res = FALSE; + break; + } + + if (reference_sw_arr[p_sw->rank]->up_port_groups_num != + 0) { + p_ref_group = + reference_sw_arr[p_sw->rank]-> + up_port_groups[0]; + for (i = 0; i < p_sw->up_port_groups_num; i++) { + p_group = p_sw->up_port_groups[i]; + if (cl_ptr_vector_get_size + (&p_ref_group->ports) != + cl_ptr_vector_get_size(&p_group-> + ports)) { + OSM_LOG(&p_ftree->p_osm->log, + OSM_LOG_ERROR, + "ERR AB0B: Different number of ports in an upward port group on switches:\n" + " GUID 0x%016" + PRIx64 + ", LID %u, Index %s - %u ports\n" + " GUID 0x%016" + PRIx64 + ", LID %u, Index %s - %u ports\n", + __osm_ftree_sw_get_guid_ho + (reference_sw_arr + [p_sw->rank]), + cl_ntoh16 + (reference_sw_arr + [p_sw->rank]-> + base_lid), + __osm_ftree_tuple_to_str + (reference_sw_arr + [p_sw->rank]->tuple), + cl_ptr_vector_get_size + (&p_ref_group->ports), + __osm_ftree_sw_get_guid_ho + (p_sw), + cl_ntoh16(p_sw-> + base_lid), + __osm_ftree_tuple_to_str + (p_sw->tuple), + cl_ptr_vector_get_size + (&p_group->ports)); + res = FALSE; + break; + } + } + } + if (reference_sw_arr[p_sw->rank]-> + down_port_groups_num != 0 + && p_sw->rank != (tree_rank - 1)) { + /* we're allowing some hca's to be missing */ + p_ref_group = + reference_sw_arr[p_sw->rank]-> + down_port_groups[0]; + for (i = 0; i < p_sw->down_port_groups_num; i++) { + p_group = p_sw->down_port_groups[0]; + if (cl_ptr_vector_get_size + (&p_ref_group->ports) != + cl_ptr_vector_get_size(&p_group-> + ports)) { + OSM_LOG(&p_ftree->p_osm->log, + OSM_LOG_ERROR, + "ERR AB0C: Different number of ports in an downward port group on switches:\n" + " GUID 0x%016" + PRIx64 + ", LID %u, Index %s - %u ports\n" + " GUID 0x%016" + PRIx64 + ", LID %u, Index %s - %u ports\n", + __osm_ftree_sw_get_guid_ho + (reference_sw_arr + [p_sw->rank]), + cl_ntoh16 + (reference_sw_arr + [p_sw->rank]-> + base_lid), + __osm_ftree_tuple_to_str + (reference_sw_arr + [p_sw->rank]->tuple), + cl_ptr_vector_get_size + (&p_ref_group->ports), + __osm_ftree_sw_get_guid_ho + (p_sw), + cl_ntoh16(p_sw-> + base_lid), + __osm_ftree_tuple_to_str + (p_sw->tuple), + cl_ptr_vector_get_size + (&p_group->ports)); + res = FALSE; + break; + } + } + } + } /* end of else */ + } /* end of while */ + + if (res == TRUE) + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Fabric topology has been identified as FatTree\n"); + else + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "ERR AB0D: Fabric topology hasn't been identified as FatTree\n"); + + free(reference_sw_arr); + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* __osm_ftree_fabric_validate_topology() */ + +/*************************************************** + ***************************************************/ + +static void __osm_ftree_set_sw_fwd_table(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + ftree_sw_t *p_sw = (ftree_sw_t * const)p_map_item; + ftree_fabric_t *p_ftree = (ftree_fabric_t *) context; + + p_sw->p_osm_sw->max_lid_ho = p_ftree->lft_max_lid_ho; + osm_ucast_mgr_set_fwd_table(&p_ftree->p_osm->sm.ucast_mgr, + p_sw->p_osm_sw); +} + +/*************************************************** + ***************************************************/ + +/* + * Function: assign-up-going-port-by-descending-down + * Given : a switch and a LID + * Pseudo code: + * foreach down-going-port-group (in indexing order) + * skip this group if the LFT(LID) port is part of this group + * find the least loaded port of the group (scan in indexing order) + * r-port is the remote port connected to it + * assign the remote switch node LFT(LID) to r-port + * increase r-port usage counter + * assign-up-going-port-by-descending-down to r-port node (recursion) + */ + +static void +__osm_ftree_fabric_route_upgoing_by_going_down(IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw, + IN ftree_sw_t * p_prev_sw, + IN ib_net16_t target_lid, + IN uint8_t target_rank, + IN boolean_t is_real_lid, + IN boolean_t is_main_path, + IN uint8_t highest_rank_in_route) +{ + ftree_sw_t *p_remote_sw; + uint16_t ports_num; + ftree_port_group_t *p_group; + ftree_port_t *p_port; + ftree_port_t *p_min_port; + uint16_t i; + uint16_t j; + uint16_t k; + + /* we shouldn't enter here if both real_lid and main_path are false */ + CL_ASSERT(is_real_lid || is_main_path); + + /* if there is no down-going ports */ + if (p_sw->down_port_groups_num == 0) + return; + + /* promote the index that indicates which group should we + start with when going through all the downgoing groups */ + p_sw->down_port_groups_idx = + (p_sw->down_port_groups_idx + 1) % p_sw->down_port_groups_num; + + /* foreach down-going port group (in indexing order) */ + i = p_sw->down_port_groups_idx; + for (k = 0; k < p_sw->down_port_groups_num; k++) { + + p_group = p_sw->down_port_groups[i]; + i = (i + 1) % p_sw->down_port_groups_num; + + /* Skip this port group unless it points to a switch */ + if (p_group->remote_node_type != IB_NODE_TYPE_SWITCH) + continue; + + if (p_prev_sw + && (p_group->remote_base_lid == p_prev_sw->base_lid)) { + /* This port group has a port that was used when we entered this switch, + which means that the current group points to the switch where we were + at the previous step of the algorithm (before going up). + Skipping this group. */ + continue; + } + + /* find the least loaded port of the group (in indexing order) */ + p_min_port = NULL; + ports_num = (uint16_t) cl_ptr_vector_get_size(&p_group->ports); + /* ToDo: no need to select a least loaded port for non-main path. + Think about optimization. */ + for (j = 0; j < ports_num; j++) { + cl_ptr_vector_at(&p_group->ports, j, (void *)&p_port); + if (!p_min_port) { + /* first port that we're checking - set as port with the lowest load */ + p_min_port = p_port; + } else if (p_port->counter_up < p_min_port->counter_up) { + /* this port is less loaded - use it as min */ + p_min_port = p_port; + } + } + /* At this point we have selected a port in this group with the + lowest load of upgoing routes. + Set on the remote switch how to get to the target_lid - + set LFT(target_lid) on the remote switch to the remote port */ + p_remote_sw = p_group->remote_hca_or_sw.p_sw; + + if (osm_switch_get_least_hops(p_remote_sw->p_osm_sw, + cl_ntoh16(target_lid)) != + OSM_NO_PATH) { + /* Loop in the fabric - we already routed the remote switch + on our way UP, and now we see it again on our way DOWN */ + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Loop of lenght %d in the fabric:\n " + "Switch %s (LID %u) closes loop through switch %s (LID %u)\n", + (p_remote_sw->rank - highest_rank_in_route) * 2, + __osm_ftree_tuple_to_str(p_remote_sw->tuple), + cl_ntoh16(p_group->base_lid), + __osm_ftree_tuple_to_str(p_sw->tuple), + cl_ntoh16(p_group->remote_base_lid)); + continue; + } + + /* Four possible cases: + * + * 1. is_real_lid == TRUE && is_main_path == TRUE: + * - going DOWN(TRUE,TRUE) through ALL the groups + * + promoting port counter + * + setting path in remote switch fwd tbl + * + setting hops in remote switch on all the ports of each group + * + * 2. is_real_lid == TRUE && is_main_path == FALSE: + * - going DOWN(TRUE,FALSE) through ALL the groups but only if + * the remote (lower) switch hasn't been already configured + * for this target LID + * + NOT promoting port counter + * + setting path in remote switch fwd tbl if it hasn't been set yet + * + setting hops in remote switch on all the ports of each group + * if it hasn't been set yet + * + * 3. is_real_lid == FALSE && is_main_path == TRUE: + * - going DOWN(FALSE,TRUE) through ALL the groups + * + promoting port counter + * + NOT setting path in remote switch fwd tbl + * + NOT setting hops in remote switch + * + * 4. is_real_lid == FALSE && is_main_path == FALSE: + * - illegal state - we shouldn't get here + */ + + /* second case: skip the port group if the remote (lower) + switch has been already configured for this target LID */ + if (is_real_lid && !is_main_path && + p_remote_sw->p_osm_sw->new_lft[cl_ntoh16(target_lid)] != OSM_NO_PATH) + continue; + + /* setting fwd tbl port only if this is real LID */ + if (is_real_lid) { + p_remote_sw->p_osm_sw->new_lft[cl_ntoh16(target_lid)] = + p_min_port->remote_port_num; + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Switch %s: set path to CA LID %u through port %u\n", + __osm_ftree_tuple_to_str(p_remote_sw->tuple), + cl_ntoh16(target_lid), + p_min_port->remote_port_num); + + /* On the remote switch that is pointed by the p_group, + set hops for ALL the ports in the remote group. */ + + for (j = 0; j < ports_num; j++) { + cl_ptr_vector_at(&p_group->ports, j, + (void *)&p_port); + + __osm_ftree_sw_set_hops(p_remote_sw, + cl_ntoh16(target_lid), + p_port->remote_port_num, + ((target_rank - + highest_rank_in_route) + + (p_remote_sw->rank - + highest_rank_in_route))); + } + + } + + /* The number of upgoing routes is tracked in the + p_port->counter_up counter of the port that belongs to + the upper side of the link (on switch with lower rank). + Counter is promoted only if we're routing LID on the main + path (whether it's a real LID or a dummy one). */ + if (is_main_path) + p_min_port->counter_up++; + + /* Recursion step: + Assign upgoing ports by stepping down, starting on REMOTE switch */ + __osm_ftree_fabric_route_upgoing_by_going_down(p_ftree, p_remote_sw, /* remote switch - used as a route-upgoing alg. start point */ + NULL, /* prev. position - NULL to mark that we went down and not up */ + target_lid, /* LID that we're routing to */ + target_rank, /* rank of the LID that we're routing to */ + is_real_lid, /* whether the target LID is real or dummy */ + is_main_path, /* whether this is path to HCA that should by tracked by counters */ + highest_rank_in_route); /* highest visited point in the tree before going down */ + } + /* done scanning all the down-going port groups */ + +} /* __osm_ftree_fabric_route_upgoing_by_going_down() */ + +/***************************************************/ + +/* + * Function: assign-down-going-port-by-ascending-up + * Given : a switch and a LID + * Pseudo code: + * find the least loaded port of all the upgoing groups (scan in indexing order) + * assign the LFT(LID) of remote switch to that port + * track that port usage + * assign-up-going-port-by-descending-down on CURRENT switch + * assign-down-going-port-by-ascending-up on REMOTE switch (recursion) + */ + +static void +__osm_ftree_fabric_route_downgoing_by_going_up(IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw, + IN ftree_sw_t * p_prev_sw, + IN ib_net16_t target_lid, + IN uint8_t target_rank, + IN boolean_t is_real_lid, + IN boolean_t is_main_path) +{ + ftree_sw_t *p_remote_sw; + uint16_t ports_num; + ftree_port_group_t *p_group; + ftree_port_t *p_port; + ftree_port_group_t *p_min_group; + ftree_port_t *p_min_port; + uint16_t i; + uint16_t j; + + /* we shouldn't enter here if both real_lid and main_path are false */ + CL_ASSERT(is_real_lid || is_main_path); + + /* Assign upgoing ports by stepping down, starting on THIS switch */ + __osm_ftree_fabric_route_upgoing_by_going_down(p_ftree, p_sw, /* local switch - used as a route-upgoing alg. start point */ + p_prev_sw, /* switch that we went up from (NULL means that we went down) */ + target_lid, /* LID that we're routing to */ + target_rank, /* rank of the LID that we're routing to */ + is_real_lid, /* whether this target LID is real or dummy */ + is_main_path, /* whether this path to HCA should by tracked by counters */ + p_sw->rank); /* the highest visited point in the tree before going down */ + + /* recursion stop condition - if it's a root switch, */ + if (p_sw->rank == 0) + return; + + /* Find the least loaded upgoing port group */ + p_min_group = NULL; + for (i = 0; i < p_sw->up_port_groups_num; i++) { + p_group = p_sw->up_port_groups[i]; + if (!p_min_group) { + /* first group that we're checking - use + it as a group with the lowest load */ + p_min_group = p_group; + } else if (p_group->counter_down < p_min_group->counter_down) { + /* this group is less loaded - use it as min */ + p_min_group = p_group; + } + } + + /* Find the least loaded upgoing port in the selected group */ + p_min_port = NULL; + ports_num = (uint16_t) cl_ptr_vector_get_size(&p_min_group->ports); + for (j = 0; j < ports_num; j++) { + cl_ptr_vector_at(&p_min_group->ports, j, (void *)&p_port); + if (!p_min_port) { + /* first port that we're checking - use + it as a port with the lowest load */ + p_min_port = p_port; + } else if (p_port->counter_down < p_min_port->counter_down) { + /* this port is less loaded - use it as min */ + p_min_port = p_port; + } + } + + /* At this point we have selected a group and port with the + lowest load of downgoing routes. + Set on the remote switch how to get to the target_lid - + set LFT(target_lid) on the remote switch to the remote port */ + p_remote_sw = p_min_group->remote_hca_or_sw.p_sw; + + /* Four possible cases: + * + * 1. is_real_lid == TRUE && is_main_path == TRUE: + * - going UP(TRUE,TRUE) on selected min_group and min_port + * + promoting port counter + * + setting path in remote switch fwd tbl + * + setting hops in remote switch on all the ports of selected group + * - going UP(TRUE,FALSE) on rest of the groups, each time on port 0 + * + NOT promoting port counter + * + setting path in remote switch fwd tbl if it hasn't been set yet + * + setting hops in remote switch on all the ports of each group + * if it hasn't been set yet + * + * 2. is_real_lid == TRUE && is_main_path == FALSE: + * - going UP(TRUE,FALSE) on ALL the groups, each time on port 0, + * but only if the remote (upper) switch hasn't been already + * configured for this target LID + * + NOT promoting port counter + * + setting path in remote switch fwd tbl if it hasn't been set yet + * + setting hops in remote switch on all the ports of each group + * if it hasn't been set yet + * + * 3. is_real_lid == FALSE && is_main_path == TRUE: + * - going UP(FALSE,TRUE) ONLY on selected min_group and min_port + * + promoting port counter + * + NOT setting path in remote switch fwd tbl + * + NOT setting hops in remote switch + * + * 4. is_real_lid == FALSE && is_main_path == FALSE: + * - illegal state - we shouldn't get here + */ + + /* covering first half of case 1, and case 3 */ + if (is_main_path) { + if (p_sw->is_leaf) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + " - Routing MAIN path for %s CA LID %u: %s --> %s\n", + (is_real_lid) ? "real" : "DUMMY", + cl_ntoh16(target_lid), + __osm_ftree_tuple_to_str(p_sw->tuple), + __osm_ftree_tuple_to_str(p_remote_sw->tuple)); + } + /* The number of downgoing routes is tracked in the + p_group->counter_down p_port->counter_down counters of the + group and port that belong to the lower side of the link + (on switch with higher rank) */ + p_min_group->counter_down++; + p_min_port->counter_down++; + if (is_real_lid) { + p_remote_sw->p_osm_sw->new_lft[cl_ntoh16(target_lid)] = + p_min_port->remote_port_num; + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Switch %s: set path to CA LID %u through port %u\n", + __osm_ftree_tuple_to_str(p_remote_sw->tuple), + cl_ntoh16(target_lid), + p_min_port->remote_port_num); + + /* On the remote switch that is pointed by the min_group, + set hops for ALL the ports in the remote group. */ + + ports_num = + (uint16_t) cl_ptr_vector_get_size(&p_min_group-> + ports); + for (j = 0; j < ports_num; j++) { + cl_ptr_vector_at(&p_min_group->ports, j, + (void *)&p_port); + __osm_ftree_sw_set_hops(p_remote_sw, + cl_ntoh16(target_lid), + p_port->remote_port_num, + target_rank - + p_remote_sw->rank); + } + } + + /* Recursion step: + Assign downgoing ports by stepping up, starting on REMOTE switch. */ + __osm_ftree_fabric_route_downgoing_by_going_up(p_ftree, p_remote_sw, /* remote switch - used as a route-downgoing alg. next step point */ + p_sw, /* this switch - prev. position switch for the function */ + target_lid, /* LID that we're routing to */ + target_rank, /* rank of the LID that we're routing to */ + is_real_lid, /* whether this target LID is real or dummy */ + is_main_path); /* whether this is path to HCA that should by tracked by counters */ + } + + /* we're done for the third case */ + if (!is_real_lid) + return; + + /* What's left to do at this point: + * + * 1. is_real_lid == TRUE && is_main_path == TRUE: + * - going UP(TRUE,FALSE) on rest of the groups, each time on port 0, + * but only if the remote (upper) switch hasn't been already + * configured for this target LID + * + NOT promoting port counter + * + setting path in remote switch fwd tbl if it hasn't been set yet + * + setting hops in remote switch on all the ports of each group + * if it hasn't been set yet + * + * 2. is_real_lid == TRUE && is_main_path == FALSE: + * - going UP(TRUE,FALSE) on ALL the groups, each time on port 0, + * but only if the remote (upper) switch hasn't been already + * configured for this target LID + * + NOT promoting port counter + * + setting path in remote switch fwd tbl if it hasn't been set yet + * + setting hops in remote switch on all the ports of each group + * if it hasn't been set yet + * + * These two rules can be rephrased this way: + * - foreach UP port group + * + if remote switch has been set with the target LID + * - skip this port group + * + else + * - select port 0 + * - do NOT promote port counter + * - set path in remote switch fwd tbl + * - set hops in remote switch on all the ports of this group + * - go UP(TRUE,FALSE) to the remote switch + */ + + for (i = 0; i < p_sw->up_port_groups_num; i++) { + p_group = p_sw->up_port_groups[i]; + p_remote_sw = p_group->remote_hca_or_sw.p_sw; + + /* skip if target lid has been already set on remote switch fwd tbl */ + if (p_remote_sw->p_osm_sw->new_lft[cl_ntoh16(target_lid)] != OSM_NO_PATH) + continue; + + if (p_sw->is_leaf) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + " - Routing SECONDARY path for LID %u: %s --> %s\n", + cl_ntoh16(target_lid), + __osm_ftree_tuple_to_str(p_sw->tuple), + __osm_ftree_tuple_to_str(p_remote_sw->tuple)); + } + + /* Routing REAL lids on SECONDARY path means routing + switch-to-switch or switch-to-CA paths. + We can safely assume that switch will initiate very + few traffic, so there's no point waisting runtime on + trying to balance these routes - always pick port 0. */ + + cl_ptr_vector_at(&p_group->ports, 0, (void *)&p_port); + p_remote_sw->p_osm_sw->new_lft[cl_ntoh16(target_lid)] = + p_port->remote_port_num; + + /* On the remote switch that is pointed by the p_group, + set hops for ALL the ports in the remote group. */ + + ports_num = (uint16_t) cl_ptr_vector_get_size(&p_group->ports); + for (j = 0; j < ports_num; j++) { + cl_ptr_vector_at(&p_group->ports, j, (void *)&p_port); + + __osm_ftree_sw_set_hops(p_remote_sw, + cl_ntoh16(target_lid), + p_port->remote_port_num, + target_rank - + p_remote_sw->rank); + } + + /* Recursion step: + Assign downgoing ports by stepping up, starting on REMOTE switch. */ + __osm_ftree_fabric_route_downgoing_by_going_up(p_ftree, p_remote_sw, /* remote switch - used as a route-downgoing alg. next step point */ + p_sw, /* this switch - prev. position switch for the function */ + target_lid, /* LID that we're routing to */ + target_rank, /* rank of the LID that we're routing to */ + TRUE, /* whether the target LID is real or dummy */ + FALSE); /* whether this is path to HCA that should by tracked by counters */ + } + +} /* ftree_fabric_route_downgoing_by_going_up() */ + +/***************************************************/ + +/* + * Pseudo code: + * foreach leaf switch (in indexing order) + * for each compute node (in indexing order) + * obtain the LID of the compute node + * set local LFT(LID) of the port connecting to compute node + * call assign-down-going-port-by-ascending-up(TRUE,TRUE) on CURRENT switch + * for each MISSING compute node + * call assign-down-going-port-by-ascending-up(FALSE,TRUE) on CURRENT switch + */ + +static void __osm_ftree_fabric_route_to_cns(IN ftree_fabric_t * p_ftree) +{ + ftree_sw_t *p_sw; + ftree_hca_t *p_hca; + ftree_port_group_t *p_leaf_port_group; + ftree_port_group_t *p_hca_port_group; + ftree_port_t *p_port; + uint32_t i; + uint32_t j; + ib_net16_t hca_lid; + unsigned routed_targets_on_leaf; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + /* for each leaf switch (in indexing order) */ + for (i = 0; i < p_ftree->leaf_switches_num; i++) { + p_sw = p_ftree->leaf_switches[i]; + routed_targets_on_leaf = 0; + + /* for each HCA connected to this switch */ + for (j = 0; j < p_sw->down_port_groups_num; j++) { + p_leaf_port_group = p_sw->down_port_groups[j]; + + /* work with this port group only if the remote node is CA */ + if (p_leaf_port_group->remote_node_type != + IB_NODE_TYPE_CA) + continue; + + p_hca = p_leaf_port_group->remote_hca_or_sw.p_hca; + + /* work with this port group only if remote HCA has CNs */ + if (!p_hca->cn_num) + continue; + + p_hca_port_group = + __osm_ftree_hca_get_port_group_by_remote_lid(p_hca, + p_leaf_port_group-> + base_lid); + CL_ASSERT(p_hca_port_group); + + /* work with this port group only if remote port is CN */ + if (!p_hca_port_group->is_cn) + continue; + + /* obtain the LID of HCA port */ + hca_lid = p_leaf_port_group->remote_base_lid; + + /* set local LFT(LID) to the port that is connected to HCA */ + cl_ptr_vector_at(&p_leaf_port_group->ports, 0, + (void *)&p_port); + p_sw->p_osm_sw->new_lft[cl_ntoh16(hca_lid)] = p_port->port_num; + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Switch %s: set path to CN LID %u through port %u\n", + __osm_ftree_tuple_to_str(p_sw->tuple), + cl_ntoh16(hca_lid), p_port->port_num); + + /* set local min hop table(LID) to route to the CA */ + __osm_ftree_sw_set_hops(p_sw, + cl_ntoh16(hca_lid), + p_port->port_num, 1); + + /* Assign downgoing ports by stepping up. + Since we're routing here only CNs, we're routing it as REAL + LID and updating fat-tree balancing counters. */ + __osm_ftree_fabric_route_downgoing_by_going_up(p_ftree, p_sw, /* local switch - used as a route-downgoing alg. start point */ + NULL, /* prev. position switch */ + hca_lid, /* LID that we're routing to */ + p_sw->rank + 1, /* rank of the LID that we're routing to */ + TRUE, /* whether this HCA LID is real or dummy */ + TRUE); /* whether this path to HCA should by tracked by counters */ + + /* count how many real targets have been routed from this leaf switch */ + routed_targets_on_leaf++; + } + + /* We're done with the real targets (all CNs) of this leaf switch. + Now route the dummy HCAs that are missing or that are non-CNs. + When routing to dummy HCAs we don't fill lid matrices. */ + + if (p_ftree->max_cn_per_leaf > routed_targets_on_leaf) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Routing %u dummy CAs\n", + p_ftree->max_cn_per_leaf - + p_sw->down_port_groups_num); + for (j = 0; + ((int)j) < + (p_ftree->max_cn_per_leaf - + routed_targets_on_leaf); j++) { + /* assign downgoing ports by stepping up */ + __osm_ftree_fabric_route_downgoing_by_going_up(p_ftree, p_sw, /* local switch - used as a route-downgoing alg. start point */ + NULL, /* prev. position switch */ + 0, /* LID that we're routing to - ignored for dummy HCA */ + 0, /* rank of the LID that we're routing to - ignored for dummy HCA */ + FALSE, /* whether this HCA LID is real or dummy */ + TRUE); /* whether this path to HCA should by tracked by counters */ + } + } + } + /* done going through all the leaf switches */ + OSM_LOG_EXIT(&p_ftree->p_osm->log); +} /* __osm_ftree_fabric_route_to_cns() */ + +/***************************************************/ + +/* + * Pseudo code: + * foreach HCA non-CN port in fabric + * obtain the LID of the HCA port + * get switch that is connected to this HCA port + * set switch LFT(LID) to the port connecting to compute node + * call assign-down-going-port-by-ascending-up(TRUE,FALSE) on CURRENT switch + * + * Routing to these HCAs is routing a REAL hca lid on SECONDARY path. + * However, we do want to allow load-leveling of the traffic to the non-CNs, + * because such nodes may include IO nodes with heavy usage + * - we should set fwd tables + * - we should update port counters + * Routing to non-CNs is done after routing to CNs, so updated port + * counters will not affect CN-to-CN routing. + */ + +static void __osm_ftree_fabric_route_to_non_cns(IN ftree_fabric_t * p_ftree) +{ + ftree_sw_t *p_sw; + ftree_hca_t *p_hca; + ftree_hca_t *p_next_hca; + ftree_port_t *p_hca_port; + ftree_port_group_t *p_hca_port_group; + ib_net16_t hca_lid; + unsigned port_num_on_switch; + unsigned i; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + p_next_hca = (ftree_hca_t *) cl_qmap_head(&p_ftree->hca_tbl); + while (p_next_hca != (ftree_hca_t *) cl_qmap_end(&p_ftree->hca_tbl)) { + p_hca = p_next_hca; + p_next_hca = (ftree_hca_t *) cl_qmap_next(&p_hca->map_item); + + for (i = 0; i < p_hca->up_port_groups_num; i++) { + p_hca_port_group = p_hca->up_port_groups[i]; + + /* skip this port if it's CN, in which case it has been already routed */ + if (p_hca_port_group->is_cn) + continue; + + /* skip this port if it is not connected to switch */ + if (p_hca_port_group->remote_node_type != + IB_NODE_TYPE_SWITCH) + continue; + + p_sw = p_hca_port_group->remote_hca_or_sw.p_sw; + hca_lid = p_hca_port_group->base_lid; + + /* set switches LFT(LID) to the port that is connected to HCA */ + cl_ptr_vector_at(&p_hca_port_group->ports, 0, + (void *)&p_hca_port); + port_num_on_switch = p_hca_port->remote_port_num; + p_sw->p_osm_sw->new_lft[cl_ntoh16(hca_lid)] = port_num_on_switch; + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Switch %s: set path to non-CN HCA LID %u through port %u\n", + __osm_ftree_tuple_to_str(p_sw->tuple), + cl_ntoh16(hca_lid), port_num_on_switch); + + /* set local min hop table(LID) to route to the CA */ + __osm_ftree_sw_set_hops(p_sw, cl_ntoh16(hca_lid), + port_num_on_switch, /* port num */ + 1); /* hops */ + + /* Assign downgoing ports by stepping up. + We're routing REAL targets. They are not CNs and not included + in the leafs array, but we treat them as MAIN path to allow load + leveling, which means that the counters will be updated. */ + __osm_ftree_fabric_route_downgoing_by_going_up(p_ftree, p_sw, /* local switch - used as a route-downgoing alg. start point */ + NULL, /* prev. position switch */ + hca_lid, /* LID that we're routing to */ + p_sw->rank + 1, /* rank of the LID that we're routing to */ + TRUE, /* whether this HCA LID is real or dummy */ + TRUE); /* whether this path to HCA should by tracked by counters */ + } + /* done with all the port groups of this HCA - go to next HCA */ + } + + OSM_LOG_EXIT(&p_ftree->p_osm->log); +} /* __osm_ftree_fabric_route_to_non_cns() */ + +/***************************************************/ + +/* + * Pseudo code: + * foreach switch in fabric + * obtain its LID + * set local LFT(LID) to port 0 + * call assign-down-going-port-by-ascending-up(TRUE,FALSE) on CURRENT switch + * + * Routing to switch is similar to routing a REAL hca lid on SECONDARY path: + * - we should set fwd tables + * - we should NOT update port counters + */ + +static void __osm_ftree_fabric_route_to_switches(IN ftree_fabric_t * p_ftree) +{ + ftree_sw_t *p_sw; + ftree_sw_t *p_next_sw; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + p_next_sw = (ftree_sw_t *) cl_qmap_head(&p_ftree->sw_tbl); + while (p_next_sw != (ftree_sw_t *) cl_qmap_end(&p_ftree->sw_tbl)) { + p_sw = p_next_sw; + p_next_sw = (ftree_sw_t *) cl_qmap_next(&p_sw->map_item); + + /* set local LFT(LID) to 0 (route to itself) */ + p_sw->p_osm_sw->new_lft[cl_ntoh16(p_sw->base_lid)] = 0; + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Switch %s (LID %u): routing switch-to-switch paths\n", + __osm_ftree_tuple_to_str(p_sw->tuple), + cl_ntoh16(p_sw->base_lid)); + + /* set min hop table of the switch to itself */ + __osm_ftree_sw_set_hops(p_sw, cl_ntoh16(p_sw->base_lid), + 0, /* port_num */ + 0); /* hops */ + + __osm_ftree_fabric_route_downgoing_by_going_up(p_ftree, p_sw, /* local switch - used as a route-downgoing alg. start point */ + NULL, /* prev. position switch */ + p_sw->base_lid, /* LID that we're routing to */ + p_sw->rank, /* rank of the LID that we're routing to */ + TRUE, /* whether the target LID is a real or dummy */ + FALSE); /* whether this path should by tracked by counters */ + } + + OSM_LOG_EXIT(&p_ftree->p_osm->log); +} /* __osm_ftree_fabric_route_to_switches() */ + +/*************************************************** + ***************************************************/ + +static int __osm_ftree_fabric_populate_nodes(IN ftree_fabric_t * p_ftree) +{ + osm_node_t *p_osm_node; + osm_node_t *p_next_osm_node; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + p_next_osm_node = + (osm_node_t *) cl_qmap_head(&p_ftree->p_osm->subn.node_guid_tbl); + while (p_next_osm_node != + (osm_node_t *) cl_qmap_end(&p_ftree->p_osm->subn. + node_guid_tbl)) { + p_osm_node = p_next_osm_node; + p_next_osm_node = + (osm_node_t *) cl_qmap_next(&p_osm_node->map_item); + switch (osm_node_get_type(p_osm_node)) { + case IB_NODE_TYPE_CA: + __osm_ftree_fabric_add_hca(p_ftree, p_osm_node); + break; + case IB_NODE_TYPE_ROUTER: + break; + case IB_NODE_TYPE_SWITCH: + __osm_ftree_fabric_add_sw(p_ftree, p_osm_node->sw); + break; + default: + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, "ERR AB0E: " + "Node GUID 0x%016" PRIx64 + " - Unknown node type: %s\n", + cl_ntoh64(osm_node_get_node_guid(p_osm_node)), + ib_get_node_type_str(osm_node_get_type + (p_osm_node))); + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return -1; + } + } + + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return 0; +} /* __osm_ftree_fabric_populate_nodes() */ + +/*************************************************** + ***************************************************/ + +static boolean_t __osm_ftree_sw_update_rank(IN ftree_sw_t * p_sw, + IN uint32_t new_rank) +{ + if (__osm_ftree_sw_ranked(p_sw) && p_sw->rank <= new_rank) + return FALSE; + p_sw->rank = new_rank; + return TRUE; + +} + +/***************************************************/ + +static void +__osm_ftree_rank_switches_from_leafs(IN ftree_fabric_t * p_ftree, + IN cl_list_t * p_ranking_bfs_list) +{ + ftree_sw_t *p_sw; + ftree_sw_t *p_remote_sw; + osm_node_t *p_node; + osm_node_t *p_remote_node; + osm_physp_t *p_osm_port; + uint8_t i; + unsigned max_rank = 0; + + while (!cl_is_list_empty(p_ranking_bfs_list)) { + p_sw = (ftree_sw_t *) cl_list_remove_head(p_ranking_bfs_list); + p_node = p_sw->p_osm_sw->p_node; + + /* note: skipping port 0 on switches */ + for (i = 1; i < osm_node_get_num_physp(p_node); i++) { + p_osm_port = osm_node_get_physp_ptr(p_node, i); + if (!p_osm_port || !osm_link_is_healthy(p_osm_port)) + continue; + + p_remote_node = + osm_node_get_remote_node(p_node, i, NULL); + if (!p_remote_node) + continue; + if (osm_node_get_type(p_remote_node) != + IB_NODE_TYPE_SWITCH) + continue; + + p_remote_sw = __osm_ftree_fabric_get_sw_by_guid(p_ftree, + osm_node_get_node_guid + (p_remote_node)); + if (!p_remote_sw) { + /* remote node is not a switch */ + continue; + } + + /* if needed, rank the remote switch and add it to the BFS list */ + if (__osm_ftree_sw_update_rank + (p_remote_sw, p_sw->rank + 1)) { + max_rank = p_remote_sw->rank; + cl_list_insert_tail(p_ranking_bfs_list, + p_remote_sw); + } + } + } + + /* set FatTree maximal switch rank */ + p_ftree->max_switch_rank = max_rank; + +} /* __osm_ftree_rank_switches_from_leafs() */ + +/***************************************************/ + +static int +__osm_ftree_rank_leaf_switches(IN ftree_fabric_t * p_ftree, + IN ftree_hca_t * p_hca, + IN cl_list_t * p_ranking_bfs_list) +{ + ftree_sw_t *p_sw; + osm_node_t *p_osm_node = p_hca->p_osm_node; + osm_node_t *p_remote_osm_node; + osm_physp_t *p_osm_port; + static uint8_t i = 0; + int res = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + for (i = 0; i < osm_node_get_num_physp(p_osm_node); i++) { + p_osm_port = osm_node_get_physp_ptr(p_osm_node, i); + if (!p_osm_port || !osm_link_is_healthy(p_osm_port)) + continue; + + p_remote_osm_node = + osm_node_get_remote_node(p_osm_node, i, NULL); + if (!p_remote_osm_node) + continue; + + switch (osm_node_get_type(p_remote_osm_node)) { + case IB_NODE_TYPE_CA: + /* HCA connected directly to another HCA - not FatTree */ + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, "ERR AB0F: " + "CA conected directly to another CA: " + "0x%016" PRIx64 " <---> 0x%016" PRIx64 "\n", + __osm_ftree_hca_get_guid_ho(p_hca), + cl_ntoh64(osm_node_get_node_guid + (p_remote_osm_node))); + res = -1; + goto Exit; + + case IB_NODE_TYPE_ROUTER: + /* leaving this port - proceeding to the next one */ + continue; + + case IB_NODE_TYPE_SWITCH: + /* continue with this port */ + break; + + default: + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "ERR AB10: Node GUID 0x%016" PRIx64 + " - Unknown node type: %s\n", + cl_ntoh64(osm_node_get_node_guid + (p_remote_osm_node)), + ib_get_node_type_str(osm_node_get_type + (p_remote_osm_node))); + res = -1; + goto Exit; + } + + /* remote node is switch */ + + p_sw = __osm_ftree_fabric_get_sw_by_guid(p_ftree, + osm_node_get_node_guid + (p_osm_port-> + p_remote_physp-> + p_node)); + CL_ASSERT(p_sw); + + /* if needed, rank the remote switch and add it to the BFS list */ + + if (!__osm_ftree_sw_update_rank(p_sw, 0)) + continue; + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Marking rank of switch that is directly connected to CA:\n" + " - CA guid : 0x%016" + PRIx64 "\n" + " - Switch guid: 0x%016" + PRIx64 "\n" + " - Switch LID : %u\n", + __osm_ftree_hca_get_guid_ho(p_hca), + __osm_ftree_sw_get_guid_ho(p_sw), + cl_ntoh16(p_sw->base_lid)); + cl_list_insert_tail(p_ranking_bfs_list, p_sw); + } + +Exit: + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* __osm_ftree_rank_leaf_switches() */ + +/***************************************************/ + +static void __osm_ftree_sw_reverse_rank(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + ftree_fabric_t *p_ftree = (ftree_fabric_t *) context; + ftree_sw_t *p_sw = (ftree_sw_t * const)p_map_item; + p_sw->rank = p_ftree->max_switch_rank - p_sw->rank; +} + +/*************************************************** + ***************************************************/ + +static int +__osm_ftree_fabric_construct_hca_ports(IN ftree_fabric_t * p_ftree, + IN ftree_hca_t * p_hca) +{ + ftree_sw_t *p_remote_sw; + osm_node_t *p_node = p_hca->p_osm_node; + osm_node_t *p_remote_node; + uint8_t remote_node_type; + ib_net64_t remote_node_guid; + osm_physp_t *p_remote_osm_port; + uint8_t i; + uint8_t remote_port_num; + boolean_t is_cn = FALSE; + int res = 0; + + for (i = 0; i < osm_node_get_num_physp(p_node); i++) { + osm_physp_t *p_osm_port = osm_node_get_physp_ptr(p_node, i); + if (!p_osm_port || !osm_link_is_healthy(p_osm_port)) + continue; + + p_remote_osm_port = osm_physp_get_remote(p_osm_port); + p_remote_node = + osm_node_get_remote_node(p_node, i, &remote_port_num); + + if (!p_remote_osm_port) + continue; + + remote_node_type = osm_node_get_type(p_remote_node); + remote_node_guid = osm_node_get_node_guid(p_remote_node); + + switch (remote_node_type) { + case IB_NODE_TYPE_ROUTER: + /* leaving this port - proceeding to the next one */ + continue; + + case IB_NODE_TYPE_CA: + /* HCA connected directly to another HCA - not FatTree */ + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, "ERR AB11: " + "CA conected directly to another CA: " + "0x%016" PRIx64 " <---> 0x%016" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(p_node)), + cl_ntoh64(remote_node_guid)); + res = -1; + goto Exit; + + case IB_NODE_TYPE_SWITCH: + /* continue with this port */ + break; + + default: + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "ERR AB12: Node GUID 0x%016" PRIx64 + " - Unknown node type: %s\n", + cl_ntoh64(remote_node_guid), + ib_get_node_type_str(remote_node_type)); + res = -1; + goto Exit; + } + + /* remote node is switch */ + + p_remote_sw = + __osm_ftree_fabric_get_sw_by_guid(p_ftree, + remote_node_guid); + CL_ASSERT(p_remote_sw); + + /* If CN file is not supplied, then all the CAs considered as Compute Nodes. + Otherwise all the CAs are not CNs, and only guids that are present in the + CN file will be marked as compute nodes. */ + if (!__osm_ftree_fabric_cns_provided(p_ftree)) { + is_cn = TRUE; + } else { + name_map_item_t *p_elem = + (name_map_item_t *) cl_qmap_get(&p_ftree-> + cn_guid_tbl, + cl_ntoh64(osm_physp_get_port_guid + (p_osm_port))); + if (p_elem != + (name_map_item_t *) cl_qmap_end(&p_ftree-> + cn_guid_tbl)) + is_cn = TRUE; + } + + if (is_cn) { + p_ftree->cn_num++; + p_hca->cn_num++; + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Marking CN port GUID 0x%016" PRIx64 "\n", + cl_ntoh64(osm_physp_get_port_guid(p_osm_port))); + } else { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Marking non-CN port GUID 0x%016" PRIx64 "\n", + cl_ntoh64(osm_physp_get_port_guid(p_osm_port))); + } + + __osm_ftree_hca_add_port(p_hca, /* local ftree_hca object */ + i, /* local port number */ + remote_port_num, /* remote port number */ + osm_node_get_base_lid(p_node, i), /* local lid */ + osm_node_get_base_lid(p_remote_node, 0), /* remote lid */ + osm_physp_get_port_guid(p_osm_port), /* local port guid */ + osm_physp_get_port_guid(p_remote_osm_port), /* remote port guid */ + remote_node_guid, /* remote node guid */ + remote_node_type, /* remote node type */ + (void *)p_remote_sw, /* remote ftree_hca/sw object */ + is_cn); /* whether this port is compute node */ + } + +Exit: + return res; +} /* __osm_ftree_fabric_construct_hca_ports() */ + +/*************************************************** + ***************************************************/ + +static int __osm_ftree_fabric_construct_sw_ports(IN ftree_fabric_t * p_ftree, + IN ftree_sw_t * p_sw) +{ + ftree_hca_t *p_remote_hca; + ftree_sw_t *p_remote_sw; + osm_node_t *p_node = p_sw->p_osm_sw->p_node; + osm_node_t *p_remote_node; + ib_net16_t remote_base_lid; + uint8_t remote_node_type; + ib_net64_t remote_node_guid; + osm_physp_t *p_remote_osm_port; + ftree_direction_t direction; + void *p_remote_hca_or_sw; + uint8_t i; + uint8_t remote_port_num; + int res = 0; + + CL_ASSERT(osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH); + + for (i = 1; i < osm_node_get_num_physp(p_node); i++) { + osm_physp_t *p_osm_port = osm_node_get_physp_ptr(p_node, i); + if (!p_osm_port || !osm_link_is_healthy(p_osm_port)) + continue; + + p_remote_osm_port = osm_physp_get_remote(p_osm_port); + if (!p_remote_osm_port) + continue; + + p_remote_node = + osm_node_get_remote_node(p_node, i, &remote_port_num); + + /* ignore any loopback connection on switch */ + if (p_node == p_remote_node) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Ignoring loopback on switch GUID 0x%016" PRIx64 + ", LID %u, rank %u\n", + __osm_ftree_sw_get_guid_ho(p_sw), + cl_ntoh16(p_sw->base_lid), + p_sw->rank); + continue; + } + + remote_node_type = osm_node_get_type(p_remote_node); + remote_node_guid = osm_node_get_node_guid(p_remote_node); + + switch (remote_node_type) { + case IB_NODE_TYPE_ROUTER: + /* leaving this port - proceeding to the next one */ + continue; + + case IB_NODE_TYPE_CA: + /* switch connected to hca */ + + p_remote_hca = + __osm_ftree_fabric_get_hca_by_guid(p_ftree, + remote_node_guid); + CL_ASSERT(p_remote_hca); + + p_remote_hca_or_sw = (void *)p_remote_hca; + direction = FTREE_DIRECTION_DOWN; + + remote_base_lid = + osm_physp_get_base_lid(p_remote_osm_port); + break; + + case IB_NODE_TYPE_SWITCH: + /* switch connected to another switch */ + + p_remote_sw = + __osm_ftree_fabric_get_sw_by_guid(p_ftree, + remote_node_guid); + CL_ASSERT(p_remote_sw); + + p_remote_hca_or_sw = (void *)p_remote_sw; + + if (abs(p_sw->rank - p_remote_sw->rank) != 1) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "ERR AB16: " + "Illegal link between switches with ranks %u and %u:\n" + " GUID 0x%016" PRIx64 + ", LID %u, rank %u\n" + " GUID 0x%016" PRIx64 + ", LID %u, rank %u\n", p_sw->rank, + p_remote_sw->rank, + __osm_ftree_sw_get_guid_ho(p_sw), + cl_ntoh16(p_sw->base_lid), p_sw->rank, + __osm_ftree_sw_get_guid_ho(p_remote_sw), + cl_ntoh16(p_remote_sw->base_lid), + p_remote_sw->rank); + res = -1; + goto Exit; + } + + if (p_sw->rank > p_remote_sw->rank) + direction = FTREE_DIRECTION_UP; + else + direction = FTREE_DIRECTION_DOWN; + + /* switch LID is only in port 0 port_info structure */ + remote_base_lid = + osm_node_get_base_lid(p_remote_node, 0); + + break; + + default: + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, + "ERR AB13: Node GUID 0x%016" PRIx64 + " - Unknown node type: %s\n", + cl_ntoh64(remote_node_guid), + ib_get_node_type_str(remote_node_type)); + res = -1; + goto Exit; + } + __osm_ftree_sw_add_port(p_sw, /* local ftree_sw object */ + i, /* local port number */ + remote_port_num, /* remote port number */ + p_sw->base_lid, /* local lid */ + remote_base_lid, /* remote lid */ + osm_physp_get_port_guid(p_osm_port), /* local port guid */ + osm_physp_get_port_guid(p_remote_osm_port), /* remote port guid */ + remote_node_guid, /* remote node guid */ + remote_node_type, /* remote node type */ + p_remote_hca_or_sw, /* remote ftree_hca/sw object */ + direction); /* port direction (up or down) */ + + /* Track the max lid (in host order) that exists in the fabric */ + if (cl_ntoh16(remote_base_lid) > p_ftree->lft_max_lid_ho) + p_ftree->lft_max_lid_ho = cl_ntoh16(remote_base_lid); + } + +Exit: + return res; +} /* __osm_ftree_fabric_construct_sw_ports() */ + +/*************************************************** + ***************************************************/ + +static int __osm_ftree_fabric_rank_from_roots(IN ftree_fabric_t * p_ftree) +{ + osm_node_t *p_osm_node; + osm_node_t *p_remote_osm_node; + osm_physp_t *p_osm_physp; + ftree_sw_t *p_sw; + ftree_sw_t *p_remote_sw; + cl_list_t ranking_bfs_list; + struct guid_list_item *item; + int res = 0; + unsigned num_roots; + unsigned max_rank = 0; + unsigned i; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + cl_list_init(&ranking_bfs_list, 10); + + /* Rank all the roots and add them to list */ + for (item = (void *)cl_qlist_head(&p_ftree->root_guid_list); + item != (void *)cl_qlist_end(&p_ftree->root_guid_list); + item = (void *)cl_qlist_next(&item->list)) { + p_sw = + __osm_ftree_fabric_get_sw_by_guid(p_ftree, + cl_hton64(item->guid)); + if (!p_sw) { + /* the specified root guid wasn't found in the fabric */ + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, "ERR AB24: " + "Root switch GUID 0x%" PRIx64 " not found\n", + item->guid); + continue; + } + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Ranking root switch with GUID 0x%" PRIx64 "\n", + item->guid); + p_sw->rank = 0; + cl_list_insert_tail(&ranking_bfs_list, p_sw); + } + + num_roots = cl_list_count(&ranking_bfs_list); + if (!num_roots) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, "ERR AB25: " + "No valid roots supplied\n"); + res = -1; + goto Exit; + } + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Ranked %u valid root switches\n", num_roots); + + /* Now the list has all the roots. + BFS the subnet and update rank on all the switches. */ + + while (!cl_is_list_empty(&ranking_bfs_list)) { + p_sw = (ftree_sw_t *) cl_list_remove_head(&ranking_bfs_list); + p_osm_node = p_sw->p_osm_sw->p_node; + + /* note: skipping port 0 on switches */ + for (i = 1; i < osm_node_get_num_physp(p_osm_node); i++) { + p_osm_physp = osm_node_get_physp_ptr(p_osm_node, i); + if (!p_osm_physp || !osm_link_is_healthy(p_osm_physp)) + continue; + + p_remote_osm_node = + osm_node_get_remote_node(p_osm_node, i, NULL); + if (!p_remote_osm_node) + continue; + + if (osm_node_get_type(p_remote_osm_node) != + IB_NODE_TYPE_SWITCH) + continue; + + p_remote_sw = __osm_ftree_fabric_get_sw_by_guid(p_ftree, + osm_node_get_node_guid + (p_remote_osm_node)); + CL_ASSERT(p_remote_sw); + + /* if needed, rank the remote switch and add it to the BFS list */ + if (__osm_ftree_sw_update_rank + (p_remote_sw, p_sw->rank + 1)) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Ranking switch 0x%" PRIx64 + " with rank %u\n", + __osm_ftree_sw_get_guid_ho(p_remote_sw), + p_remote_sw->rank); + max_rank = p_remote_sw->rank; + cl_list_insert_tail(&ranking_bfs_list, + p_remote_sw); + } + } + /* done with ports of this switch - go to the next switch in the list */ + } + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Subnet ranking completed. Max Node Rank = %u\n", max_rank); + + /* set FatTree maximal switch rank */ + p_ftree->max_switch_rank = max_rank; + +Exit: + cl_list_destroy(&ranking_bfs_list); + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* __osm_ftree_fabric_rank_from_roots() */ + +/*************************************************** + ***************************************************/ + +static int __osm_ftree_fabric_rank_from_hcas(IN ftree_fabric_t * p_ftree) +{ + ftree_hca_t *p_hca; + ftree_hca_t *p_next_hca; + cl_list_t ranking_bfs_list; + int res = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + cl_list_init(&ranking_bfs_list, 10); + + /* Mark REVERSED rank of all the switches in the subnet. + Start from switches that are connected to hca's, and + scan all the switches in the subnet. */ + p_next_hca = (ftree_hca_t *) cl_qmap_head(&p_ftree->hca_tbl); + while (p_next_hca != (ftree_hca_t *) cl_qmap_end(&p_ftree->hca_tbl)) { + p_hca = p_next_hca; + p_next_hca = (ftree_hca_t *) cl_qmap_next(&p_hca->map_item); + if (__osm_ftree_rank_leaf_switches + (p_ftree, p_hca, &ranking_bfs_list) != 0) { + res = -1; + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, "ERR AB14: " + "Subnet ranking failed - subnet is not FatTree"); + goto Exit; + } + } + + /* Now rank rest of the switches in the fabric, while the + list already contains all the ranked leaf switches */ + __osm_ftree_rank_switches_from_leafs(p_ftree, &ranking_bfs_list); + + /* fix ranking of the switches by reversing the ranking direction */ + cl_qmap_apply_func(&p_ftree->sw_tbl, __osm_ftree_sw_reverse_rank, + (void *)p_ftree); + +Exit: + cl_list_destroy(&ranking_bfs_list); + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* __osm_ftree_fabric_rank_from_hcas() */ + +/*************************************************** + ***************************************************/ + +static int __osm_ftree_fabric_rank(IN ftree_fabric_t * p_ftree) +{ + int res = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + if (__osm_ftree_fabric_roots_provided(p_ftree)) + res = __osm_ftree_fabric_rank_from_roots(p_ftree); + else + res = __osm_ftree_fabric_rank_from_hcas(p_ftree); + + if (res) + goto Exit; + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_INFO, + "FatTree max switch rank is %u\n", p_ftree->max_switch_rank); + +Exit: + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* __osm_ftree_fabric_rank() */ + +/*************************************************** + ***************************************************/ + +static void __osm_ftree_fabric_set_leaf_rank(IN ftree_fabric_t * p_ftree) +{ + unsigned i; + ftree_sw_t *p_sw; + ftree_hca_t *p_hca = NULL; + ftree_hca_t *p_next_hca; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + if (!__osm_ftree_fabric_roots_provided(p_ftree)) { + /* If root file is not provided, the fabric has to be pure fat-tree + in terms of ranking. Thus, leaf switches rank is the max rank. */ + p_ftree->leaf_switch_rank = p_ftree->max_switch_rank; + } else { + /* Find the first CN and set the leaf_switch_rank to the rank + of the switch that is connected to this CN. Later we will + ensure that all the leaf switches have the same rank. */ + p_next_hca = (ftree_hca_t *) cl_qmap_head(&p_ftree->hca_tbl); + while (p_next_hca != + (ftree_hca_t *) cl_qmap_end(&p_ftree->hca_tbl)) { + p_hca = p_next_hca; + if (p_hca->cn_num) + break; + p_next_hca = + (ftree_hca_t *) cl_qmap_next(&p_hca->map_item); + } + /* we know that there are CNs in the fabric, so just to be sure... */ + CL_ASSERT(p_next_hca != + (ftree_hca_t *) cl_qmap_end(&p_ftree->hca_tbl)); + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Selected CN port GUID 0x%" PRIx64 "\n", + __osm_ftree_hca_get_guid_ho(p_hca)); + + for (i = 0; (i < p_hca->up_port_groups_num) + && (!p_hca->up_port_groups[i]->is_cn); i++) ; + CL_ASSERT(i < p_hca->up_port_groups_num); + CL_ASSERT(p_hca->up_port_groups[i]->remote_node_type == + IB_NODE_TYPE_SWITCH); + + p_sw = p_hca->up_port_groups[i]->remote_hca_or_sw.p_sw; + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Selected leaf switch GUID 0x%" PRIx64 ", rank %u\n", + __osm_ftree_sw_get_guid_ho(p_sw), p_sw->rank); + p_ftree->leaf_switch_rank = p_sw->rank; + } + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_INFO, + "FatTree leaf switch rank is %u\n", p_ftree->leaf_switch_rank); + OSM_LOG_EXIT(&p_ftree->p_osm->log); +} /* __osm_ftree_fabric_set_leaf_rank() */ + +/*************************************************** + ***************************************************/ + +static int __osm_ftree_fabric_populate_ports(IN ftree_fabric_t * p_ftree) +{ + ftree_hca_t *p_hca; + ftree_hca_t *p_next_hca; + ftree_sw_t *p_sw; + ftree_sw_t *p_next_sw; + int res = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + p_next_hca = (ftree_hca_t *) cl_qmap_head(&p_ftree->hca_tbl); + while (p_next_hca != (ftree_hca_t *) cl_qmap_end(&p_ftree->hca_tbl)) { + p_hca = p_next_hca; + p_next_hca = (ftree_hca_t *) cl_qmap_next(&p_hca->map_item); + if (__osm_ftree_fabric_construct_hca_ports(p_ftree, p_hca) != 0) { + res = -1; + goto Exit; + } + } + + p_next_sw = (ftree_sw_t *) cl_qmap_head(&p_ftree->sw_tbl); + while (p_next_sw != (ftree_sw_t *) cl_qmap_end(&p_ftree->sw_tbl)) { + p_sw = p_next_sw; + p_next_sw = (ftree_sw_t *) cl_qmap_next(&p_sw->map_item); + if (__osm_ftree_fabric_construct_sw_ports(p_ftree, p_sw) != 0) { + res = -1; + goto Exit; + } + } +Exit: + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return res; +} /* __osm_ftree_fabric_populate_ports() */ + +/*************************************************** + ***************************************************/ +static int add_guid_item_to_list(void *cxt, uint64_t guid, char *p) +{ + cl_qlist_t *list = cxt; + struct guid_list_item *item; + + item = malloc(sizeof(*item)); + if (!item) + return -1; + + item->guid = guid; + cl_qlist_insert_tail(list, &item->list); + + return 0; +} + +static int add_guid_item_to_map(void *cxt, uint64_t guid, char *p) +{ + cl_qmap_t *map = cxt; + name_map_item_t *item; + + item = malloc(sizeof(*item)); + if (!item) + return -1; + + item->guid = guid; + cl_qmap_insert(map, guid, &item->item); + + return 0; +} + +static int __osm_ftree_fabric_read_guid_files(IN ftree_fabric_t * p_ftree) +{ + int status = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + if (__osm_ftree_fabric_roots_provided(p_ftree)) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Fetching root nodes from file %s\n", + p_ftree->p_osm->subn.opt.root_guid_file); + + if (parse_node_map(p_ftree->p_osm->subn.opt.root_guid_file, + add_guid_item_to_list, + &p_ftree->root_guid_list)) { + status = -1; + goto Exit; + } + + if (!cl_qlist_count(&p_ftree->root_guid_list)) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, "ERR AB22: " + "Root guids file has no valid guids\n"); + status = -1; + goto Exit; + } + } + + if (__osm_ftree_fabric_cns_provided(p_ftree)) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_DEBUG, + "Fetching compute nodes from file %s\n", + p_ftree->p_osm->subn.opt.cn_guid_file); + + if (parse_node_map(p_ftree->p_osm->subn.opt.cn_guid_file, + add_guid_item_to_map, + &p_ftree->cn_guid_tbl)) { + status = -1; + goto Exit; + } + + if (!cl_qmap_count(&p_ftree->cn_guid_tbl)) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_ERROR, "ERR AB23: " + "Compute node guids file has no valid guids\n"); + status = -1; + goto Exit; + } + } + +Exit: + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return status; +} /*__osm_ftree_fabric_read_guid_files() */ + +/*************************************************** + ***************************************************/ + +static int __osm_ftree_construct_fabric(IN void *context) +{ + ftree_fabric_t *p_ftree = context; + int status = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + __osm_ftree_fabric_clear(p_ftree); + + if (p_ftree->p_osm->subn.opt.lmc > 0) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "LMC > 0 is not supported by fat-tree routing.\n" + "Falling back to default routing\n"); + status = -1; + goto Exit; + } + + if (cl_qmap_count(&p_ftree->p_osm->subn.sw_guid_tbl) < 2) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric has %u switches - topology is not fat-tree.\n" + "Falling back to default routing\n", + cl_qmap_count(&p_ftree->p_osm->subn.sw_guid_tbl)); + status = -1; + goto Exit; + } + + if ((cl_qmap_count(&p_ftree->p_osm->subn.node_guid_tbl) - + cl_qmap_count(&p_ftree->p_osm->subn.sw_guid_tbl)) < 2) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric has %u nodes (%u switches) - topology is not fat-tree.\n" + "Falling back to default routing\n", + cl_qmap_count(&p_ftree->p_osm->subn.node_guid_tbl), + cl_qmap_count(&p_ftree->p_osm->subn.sw_guid_tbl)); + status = -1; + goto Exit; + } + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, "\n" + " |----------------------------------------|\n" + " |- Starting FatTree fabric construction -|\n" + " |----------------------------------------|\n\n"); + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Populating FatTree Switch and CA tables\n"); + if (__osm_ftree_fabric_populate_nodes(p_ftree) != 0) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric topology is not fat-tree - " + "falling back to default routing\n"); + status = -1; + goto Exit; + } + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Reading guid files provided by user\n"); + if (__osm_ftree_fabric_read_guid_files(p_ftree) != 0) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Failed reading guid files - " + "falling back to default routing\n"); + status = -1; + goto Exit; + } + + if (cl_qmap_count(&p_ftree->hca_tbl) < 2) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric has %u CAa - topology is not fat-tree.\n" + "Falling back to default routing\n", + cl_qmap_count(&p_ftree->hca_tbl)); + status = -1; + goto Exit; + } + + /* Rank all the switches in the fabric. + After that we will know only fabric max switch rank. + We will be able to check leaf switches rank and the + whole tree rank after filling ports and marking CNs. */ + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, "Ranking FatTree\n"); + if (__osm_ftree_fabric_rank(p_ftree) != 0) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Failed ranking the tree\n"); + status = -1; + goto Exit; + } + + /* For each hca and switch, construct array of ports. + This is done after the whole FatTree data structure is ready, + because we want the ports to have pointers to ftree_{sw,hca}_t + objects, and we need the switches to be already ranked because + that's how the port direction is determined. */ + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Populating CA & switch ports\n"); + if (__osm_ftree_fabric_populate_ports(p_ftree) != 0) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric topology is not a fat-tree\n"); + status = -1; + goto Exit; + } else if (p_ftree->cn_num == 0) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric has no valid compute nodes\n"); + status = -1; + goto Exit; + } + + /* Now that the CA ports have been created and CNs were marked, + we can complete the fabric ranking - set leaf switches rank. */ + __osm_ftree_fabric_set_leaf_rank(p_ftree); + + if (__osm_ftree_fabric_get_rank(p_ftree) > FAT_TREE_MAX_RANK || + __osm_ftree_fabric_get_rank(p_ftree) < FAT_TREE_MIN_RANK) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric rank is %u (should be between %u and %u)\n", + __osm_ftree_fabric_get_rank(p_ftree), FAT_TREE_MIN_RANK, + FAT_TREE_MAX_RANK); + status = -1; + goto Exit; + } + + /* Mark all the switches in the fabric with rank equal to + p_ftree->leaf_switch_rank and that are also connected to CNs. + As a by-product, this function also runs basic topology + validation - it checks that all the CNs are at the same rank. */ + if (__osm_ftree_fabric_mark_leaf_switches(p_ftree)) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric topology is not a fat-tree\n"); + status = -1; + goto Exit; + } + + /* Assign index to all the switches in the fabric. + This function also sorts leaf switch array by the switch index, + sorts all the port arrays of the indexed switches by remote + switch index, and creates switch-by-tuple table (sw_by_tuple_tbl) */ + __osm_ftree_fabric_make_indexing(p_ftree); + + /* Create leaf switch array sorted by index. + This array contains switches with rank equal to p_ftree->leaf_switch_rank + and that are also connected to CNs (REAL leafs), and it may contain + switches at the same leaf rank w/o CNs, if this is the order of indexing. + In any case, the first and the last switches in the array are REAL leafs. */ + if (__osm_ftree_fabric_create_leaf_switch_array(p_ftree)) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric topology is not a fat-tree\n"); + status = -1; + goto Exit; + } + + /* calculate and set ftree.max_cn_per_leaf field */ + __osm_ftree_fabric_set_max_cn_per_leaf(p_ftree); + + /* print general info about fabric topology */ + __osm_ftree_fabric_dump_general_info(p_ftree); + + /* dump full tree topology */ + if (osm_log_is_active(&p_ftree->p_osm->log, OSM_LOG_DEBUG)) + __osm_ftree_fabric_dump(p_ftree); + + /* the fabric is required to be PURE fat-tree only if the root + guid file hasn't been provided by user */ + if (!__osm_ftree_fabric_roots_provided(p_ftree) && + !__osm_ftree_fabric_validate_topology(p_ftree)) { + osm_log(&p_ftree->p_osm->log, OSM_LOG_SYS, + "Fabric topology is not a fat-tree\n"); + status = -1; + goto Exit; + } + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Max LID in switch LFTs: %u\n", + p_ftree->lft_max_lid_ho); + +Exit: + if (status != 0) { + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Clearing FatTree Fabric data structures\n"); + __osm_ftree_fabric_clear(p_ftree); + } else + p_ftree->fabric_built = TRUE; + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, "\n" + " |--------------------------------------------------|\n" + " |- Done constructing FatTree fabric (status = %d) -|\n" + " |--------------------------------------------------|\n\n", + status); + + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return status; +} /* __osm_ftree_construct_fabric() */ + +/*************************************************** + ***************************************************/ + +static int __osm_ftree_do_routing(IN void *context) +{ + ftree_fabric_t *p_ftree = context; + int status = 0; + + OSM_LOG_ENTER(&p_ftree->p_osm->log); + + if (!p_ftree->fabric_built) { + status = -1; + goto Exit; + } + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Starting FatTree routing\n"); + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Filling switch forwarding tables for Compute Nodes\n"); + __osm_ftree_fabric_route_to_cns(p_ftree); + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Filling switch forwarding tables for non-CN targets\n"); + __osm_ftree_fabric_route_to_non_cns(p_ftree); + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "Filling switch forwarding tables for switch-to-switch paths\n"); + __osm_ftree_fabric_route_to_switches(p_ftree); + + /* for each switch, set its fwd table */ + cl_qmap_apply_func(&p_ftree->sw_tbl, __osm_ftree_set_sw_fwd_table, + (void *)p_ftree); + + /* write out hca ordering file */ + __osm_ftree_fabric_dump_hca_ordering(p_ftree); + + OSM_LOG(&p_ftree->p_osm->log, OSM_LOG_VERBOSE, + "FatTree routing is done\n"); + +Exit: + OSM_LOG_EXIT(&p_ftree->p_osm->log); + return status; +} + +/*************************************************** + ***************************************************/ + +static void __osm_ftree_delete(IN void *context) +{ + if (!context) + return; + __osm_ftree_fabric_destroy((ftree_fabric_t *) context); +} + +/*************************************************** + ***************************************************/ + +int osm_ucast_ftree_setup(struct osm_routing_engine *r, osm_opensm_t * p_osm) +{ + ftree_fabric_t *p_ftree = __osm_ftree_fabric_create(); + if (!p_ftree) + return -1; + + p_ftree->p_osm = p_osm; + + r->context = (void *)p_ftree; + r->build_lid_matrices = __osm_ftree_construct_fabric; + r->ucast_build_fwd_tables = __osm_ftree_do_routing; + r->delete = __osm_ftree_delete; + + return 0; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_ucast_lash.c b/contrib/ofed/management/opensm/opensm/osm_ucast_lash.c new file mode 100644 index 000000000000..f6795f67a50e --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_ucast_lash.c @@ -0,0 +1,1356 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * Copyright (c) 2007 Simula Research Laboratory. All rights reserved. + * Copyright (c) 2007 Silicon Graphics Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of LASH algorithm Calculation functions + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* //////////////////////////// */ +/* Local types */ +/* //////////////////////////// */ + +enum { + UNQUEUED, + Q_MEMBER, + MST_MEMBER, + MAX_INT = 9999, + NONE = MAX_INT +}; + +typedef struct _cdg_vertex { + int num_dependencies; + struct _cdg_vertex **dependency; + int from; + int to; + int seen; + int temp; + int visiting_number; + struct _cdg_vertex *next; + int num_temp_depend; + int num_using_vertex; + int *num_using_this_depend; +} cdg_vertex_t; + +typedef struct _reachable_dest { + int switch_id; + struct _reachable_dest *next; +} reachable_dest_t; + +typedef struct _switch { + osm_switch_t *p_sw; + int *dij_channels; + int id; + int used_channels; + int q_state; + struct routing_table { + unsigned out_link; + unsigned lane; + } *routing_table; + unsigned int num_connections; + int *virtual_physical_port_table; + int *phys_connections; +} switch_t; + +typedef struct _lash { + osm_opensm_t *p_osm; + int num_switches; + uint8_t vl_min; + int balance_limit; + switch_t **switches; + cdg_vertex_t ****cdg_vertex_matrix; + int *num_mst_in_lane; + int ***virtual_location; +} lash_t; + +static cdg_vertex_t *create_cdg_vertex(unsigned num_switches) +{ + cdg_vertex_t *cdg_vertex = (cdg_vertex_t *) malloc(sizeof(cdg_vertex_t)); + + cdg_vertex->dependency = malloc((num_switches - 1) * sizeof(cdg_vertex_t *)); + cdg_vertex->num_using_this_depend = (int *)malloc((num_switches - 1) * sizeof(int)); + return cdg_vertex; +} + +static void connect_switches(lash_t * p_lash, int sw1, int sw2, int phy_port_1) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + unsigned num = p_lash->switches[sw1]->num_connections; + + p_lash->switches[sw1]->phys_connections[num] = sw2; + p_lash->switches[sw1]->virtual_physical_port_table[num] = phy_port_1; + p_lash->switches[sw1]->num_connections++; + + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "LASH connect: %d, %d, %d\n", sw1, sw2, + phy_port_1); + +} + +static osm_switch_t *get_osm_switch_from_port(osm_port_t * port) +{ + osm_physp_t *p = port->p_physp; + if (p->p_node->sw) + return p->p_node->sw; + else if (p->p_remote_physp->p_node->sw) + return p->p_remote_physp->p_node->sw; + return NULL; +} + +#if 0 +static int randint(int high) +{ + int r; + + if (high == 0) + return 0; + r = rand(); + high++; + return (r % high); +} +#endif + +static int cycle_exists(cdg_vertex_t * start, cdg_vertex_t * current, + cdg_vertex_t * prev, int visit_num) +{ + cdg_vertex_t *h; + int i, new_visit_num; + int cycle_found = 0; + + if (current != NULL && current->visiting_number > 0) { + if (visit_num > current->visiting_number && current->seen == 0) { + h = start; + cycle_found = 1; + } + } else { + if (current == NULL) { + current = start; + CL_ASSERT(prev == NULL); + } + + current->visiting_number = visit_num; + + if (prev != NULL) { + prev->next = current; + CL_ASSERT(prev->to == current->from); + CL_ASSERT(prev->visiting_number > 0); + } + + new_visit_num = visit_num + 1; + + for (i = 0; i < current->num_dependencies; i++) { + cycle_found = + cycle_exists(start, current->dependency[i], current, + new_visit_num); + if (cycle_found == 1) + i = current->num_dependencies; + } + + current->seen = 1; + if (prev != NULL) + prev->next = NULL; + } + + return cycle_found; +} + +static void remove_semipermanent_depend_for_sp(lash_t * p_lash, int sw, + int dest_switch, int lane) +{ + switch_t **switches = p_lash->switches; + cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix; + int i_next_switch, output_link, i, next_link, i_next_next_switch, + depend = 0; + cdg_vertex_t *v; + int found; + + output_link = switches[sw]->routing_table[dest_switch].out_link; + i_next_switch = switches[sw]->phys_connections[output_link]; + + while (sw != dest_switch) { + v = cdg_vertex_matrix[lane][sw][i_next_switch]; + CL_ASSERT(v != NULL); + + if (v->num_using_vertex == 1) { + + cdg_vertex_matrix[lane][sw][i_next_switch] = NULL; + + free(v); + } else { + v->num_using_vertex--; + if (i_next_switch != dest_switch) { + next_link = + switches[i_next_switch]->routing_table[dest_switch].out_link; + i_next_next_switch = + switches[i_next_switch]->phys_connections[next_link]; + found = 0; + + for (i = 0; i < v->num_dependencies; i++) + if (v->dependency[i] == + cdg_vertex_matrix[lane][i_next_switch] + [i_next_next_switch]) { + found = 1; + depend = i; + } + + CL_ASSERT(found); + + if (v->num_using_this_depend[depend] == 1) { + for (i = depend; + i < v->num_dependencies - 1; i++) { + v->dependency[i] = + v->dependency[i + 1]; + v->num_using_this_depend[i] = + v->num_using_this_depend[i + + 1]; + } + + v->num_dependencies--; + } else + v->num_using_this_depend[depend]--; + } + } + + sw = i_next_switch; + output_link = switches[sw]->routing_table[dest_switch].out_link; + + if (sw != dest_switch) + i_next_switch = + switches[sw]->phys_connections[output_link]; + } +} + +inline static void enqueue(cl_list_t * bfsq, switch_t * sw) +{ + CL_ASSERT(sw->q_state == UNQUEUED); + sw->q_state = Q_MEMBER; + cl_list_insert_tail(bfsq, sw); +} + +inline static void dequeue(cl_list_t * bfsq, switch_t ** sw) +{ + *sw = (switch_t *) cl_list_remove_head(bfsq); + CL_ASSERT((*sw)->q_state == Q_MEMBER); + (*sw)->q_state = MST_MEMBER; +} + +static int get_phys_connection(switch_t *sw, int switch_to) +{ + unsigned int i = 0; + + for (i = 0; i < sw->num_connections; i++) + if (sw->phys_connections[i] == switch_to) + return i; + return i; +} + +static void shortest_path(lash_t * p_lash, int ir) +{ + switch_t **switches = p_lash->switches, *sw, *swi; + unsigned int i; + cl_list_t bfsq; + + cl_list_construct(&bfsq); + cl_list_init(&bfsq, 20); + + enqueue(&bfsq, switches[ir]); + + while (!cl_is_list_empty(&bfsq)) { + dequeue(&bfsq, &sw); + for (i = 0; i < sw->num_connections; i++) { + swi = switches[sw->phys_connections[i]]; + if (swi->q_state == UNQUEUED) { + enqueue(&bfsq, swi); + sw->dij_channels[sw->used_channels++] = swi->id; + } + } + } + + cl_list_destroy(&bfsq); +} + +static void generate_routing_func_for_mst(lash_t * p_lash, int sw_id, + reachable_dest_t ** destinations) +{ + int i, next_switch; + switch_t *sw = p_lash->switches[sw_id]; + int num_channels = sw->used_channels; + reachable_dest_t *dest, *i_dest, *concat_dest = NULL, *prev; + + for (i = 0; i < num_channels; i++) { + next_switch = sw->dij_channels[i]; + generate_routing_func_for_mst(p_lash, next_switch, &dest); + + i_dest = dest; + prev = i_dest; + + while (i_dest != NULL) { + if (sw->routing_table[i_dest->switch_id].out_link == + NONE) { + sw->routing_table[i_dest->switch_id].out_link = + get_phys_connection(sw, next_switch); + } + + prev = i_dest; + i_dest = i_dest->next; + } + + CL_ASSERT(prev->next == NULL); + prev->next = concat_dest; + concat_dest = dest; + } + + i_dest = (reachable_dest_t *) malloc(sizeof(reachable_dest_t)); + i_dest->switch_id = sw->id; + i_dest->next = concat_dest; + *destinations = i_dest; +} + +static void generate_cdg_for_sp(lash_t * p_lash, int sw, int dest_switch, + int lane) +{ + unsigned num_switches = p_lash->num_switches; + switch_t **switches = p_lash->switches; + cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix; + int next_switch, output_link, j, exists; + cdg_vertex_t *v, *prev = NULL; + + output_link = switches[sw]->routing_table[dest_switch].out_link; + next_switch = switches[sw]->phys_connections[output_link]; + + while (sw != dest_switch) { + + if (cdg_vertex_matrix[lane][sw][next_switch] == NULL) { + unsigned i; + v = create_cdg_vertex(num_switches); + + for (i = 0; i < num_switches - 1; i++) { + v->dependency[i] = NULL; + v->num_using_this_depend[i] = 0; + } + + v->num_using_vertex = 0; + v->num_dependencies = 0; + v->from = sw; + v->to = next_switch; + v->seen = 0; + v->visiting_number = 0; + v->next = NULL; + v->temp = 1; + v->num_temp_depend = 0; + + cdg_vertex_matrix[lane][sw][next_switch] = v; + } else + v = cdg_vertex_matrix[lane][sw][next_switch]; + + v->num_using_vertex++; + + if (prev != NULL) { + exists = 0; + + for (j = 0; j < prev->num_dependencies; j++) + if (prev->dependency[j] == v) { + exists = 1; + prev->num_using_this_depend[j]++; + } + + if (exists == 0) { + prev->dependency[prev->num_dependencies] = v; + prev->num_using_this_depend[prev->num_dependencies]++; + prev->num_dependencies++; + + CL_ASSERT(prev->num_dependencies < (int)num_switches); + + if (prev->temp == 0) + prev->num_temp_depend++; + + } + } + + sw = next_switch; + output_link = switches[sw]->routing_table[dest_switch].out_link; + + if (sw != dest_switch) { + CL_ASSERT(output_link != NONE); + next_switch = switches[sw]->phys_connections[output_link]; + } + + prev = v; + } +} + +static void set_temp_depend_to_permanent_for_sp(lash_t * p_lash, int sw, + int dest_switch, int lane) +{ + switch_t **switches = p_lash->switches; + cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix; + int next_switch, output_link; + cdg_vertex_t *v; + + output_link = switches[sw]->routing_table[dest_switch].out_link; + next_switch = switches[sw]->phys_connections[output_link]; + + while (sw != dest_switch) { + v = cdg_vertex_matrix[lane][sw][next_switch]; + CL_ASSERT(v != NULL); + + if (v->temp == 1) + v->temp = 0; + else + v->num_temp_depend = 0; + + sw = next_switch; + output_link = switches[sw]->routing_table[dest_switch].out_link; + + if (sw != dest_switch) + next_switch = + switches[sw]->phys_connections[output_link]; + } + +} + +static void remove_temp_depend_for_sp(lash_t * p_lash, int sw, int dest_switch, + int lane) +{ + switch_t **switches = p_lash->switches; + cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix; + int next_switch, output_link, i; + cdg_vertex_t *v; + + output_link = switches[sw]->routing_table[dest_switch].out_link; + next_switch = switches[sw]->phys_connections[output_link]; + + while (sw != dest_switch) { + v = cdg_vertex_matrix[lane][sw][next_switch]; + CL_ASSERT(v != NULL); + + if (v->temp == 1) { + cdg_vertex_matrix[lane][sw][next_switch] = NULL; + free(v); + } else { + CL_ASSERT(v->num_temp_depend <= v->num_dependencies); + v->num_dependencies = + v->num_dependencies - v->num_temp_depend; + v->num_temp_depend = 0; + v->num_using_vertex--; + + for (i = v->num_dependencies; + i < p_lash->num_switches - 1; i++) + v->num_using_this_depend[i] = 0; + } + + sw = next_switch; + output_link = switches[sw]->routing_table[dest_switch].out_link; + + if (sw != dest_switch) + next_switch = + switches[sw]->phys_connections[output_link]; + + } +} + +static void balance_virtual_lanes(lash_t * p_lash, unsigned lanes_needed) +{ + unsigned num_switches = p_lash->num_switches; + cdg_vertex_t ****cdg_vertex_matrix = p_lash->cdg_vertex_matrix; + int *num_mst_in_lane = p_lash->num_mst_in_lane; + int ***virtual_location = p_lash->virtual_location; + int min_filled_lane, max_filled_lane, medium_filled_lane, trials; + int old_min_filled_lane, old_max_filled_lane, new_num_min_lane, + new_num_max_lane; + unsigned int i, j; + int src, dest, start, next_switch, output_link; + int next_switch2, output_link2; + int stop = 0, cycle_found; + int cycle_found2; + + max_filled_lane = 0; + min_filled_lane = lanes_needed - 1; + + if (max_filled_lane > 1) + medium_filled_lane = max_filled_lane - 1; + + trials = num_mst_in_lane[max_filled_lane]; + if (lanes_needed == 1) + stop = 1; + + while (stop == 0) { + src = abs(rand()) % (num_switches); + dest = abs(rand()) % (num_switches); + + while (virtual_location[src][dest][max_filled_lane] != 1) { + start = dest; + if (dest == num_switches - 1) + dest = 0; + else + dest++; + + while (dest != start + && virtual_location[src][dest][max_filled_lane] + != 1) { + if (dest == num_switches - 1) + dest = 0; + else + dest++; + } + + if (virtual_location[src][dest][max_filled_lane] != 1) { + if (src == num_switches - 1) + src = 0; + else + src++; + } + } + + generate_cdg_for_sp(p_lash, src, dest, min_filled_lane); + generate_cdg_for_sp(p_lash, dest, src, min_filled_lane); + + output_link = p_lash->switches[src]->routing_table[dest].out_link; + next_switch = p_lash->switches[src]->phys_connections[output_link]; + + output_link2 = p_lash->switches[dest]->routing_table[src].out_link; + next_switch2 = p_lash->switches[dest]->phys_connections[output_link2]; + + CL_ASSERT(cdg_vertex_matrix[min_filled_lane][src][next_switch] != NULL); + CL_ASSERT(cdg_vertex_matrix[min_filled_lane][dest][next_switch2] != NULL); + + cycle_found = + cycle_exists(cdg_vertex_matrix[min_filled_lane][src][next_switch], NULL, NULL, + 1); + cycle_found2 = + cycle_exists(cdg_vertex_matrix[min_filled_lane][dest][next_switch2], NULL, NULL, + 1); + + for (i = 0; i < num_switches; i++) + for (j = 0; j < num_switches; j++) + if (cdg_vertex_matrix[min_filled_lane][i][j] != NULL) { + cdg_vertex_matrix[min_filled_lane][i][j]->visiting_number = + 0; + cdg_vertex_matrix[min_filled_lane][i][j]->seen = 0; + } + + if (cycle_found == 1 || cycle_found2 == 1) { + remove_temp_depend_for_sp(p_lash, src, dest, min_filled_lane); + remove_temp_depend_for_sp(p_lash, dest, src, min_filled_lane); + + virtual_location[src][dest][max_filled_lane] = 2; + virtual_location[dest][src][max_filled_lane] = 2; + trials--; + trials--; + } else { + set_temp_depend_to_permanent_for_sp(p_lash, src, dest, min_filled_lane); + set_temp_depend_to_permanent_for_sp(p_lash, dest, src, min_filled_lane); + + num_mst_in_lane[max_filled_lane]--; + num_mst_in_lane[max_filled_lane]--; + num_mst_in_lane[min_filled_lane]++; + num_mst_in_lane[min_filled_lane]++; + + remove_semipermanent_depend_for_sp(p_lash, src, dest, max_filled_lane); + remove_semipermanent_depend_for_sp(p_lash, dest, src, max_filled_lane); + virtual_location[src][dest][max_filled_lane] = 0; + virtual_location[dest][src][max_filled_lane] = 0; + virtual_location[src][dest][min_filled_lane] = 1; + virtual_location[dest][src][min_filled_lane] = 1; + p_lash->switches[src]->routing_table[dest].lane = min_filled_lane; + p_lash->switches[dest]->routing_table[src].lane = min_filled_lane; + } + + if (trials == 0) + stop = 1; + else { + if (num_mst_in_lane[max_filled_lane] - num_mst_in_lane[min_filled_lane] < + p_lash->balance_limit) + stop = 1; + } + + old_min_filled_lane = min_filled_lane; + old_max_filled_lane = max_filled_lane; + + new_num_min_lane = MAX_INT; + new_num_max_lane = 0; + + for (i = 0; i < lanes_needed; i++) { + + if (num_mst_in_lane[i] < new_num_min_lane) { + new_num_min_lane = num_mst_in_lane[i]; + min_filled_lane = i; + } + + if (num_mst_in_lane[i] > new_num_max_lane) { + new_num_max_lane = num_mst_in_lane[i]; + max_filled_lane = i; + } + } + + if (old_min_filled_lane != min_filled_lane) { + trials = num_mst_in_lane[max_filled_lane]; + for (i = 0; i < num_switches; i++) + for (j = 0; j < num_switches; j++) + if (virtual_location[i][j][max_filled_lane] == 2) + virtual_location[i][j][max_filled_lane] = 1; + } + + if (old_max_filled_lane != max_filled_lane) { + trials = num_mst_in_lane[max_filled_lane]; + for (i = 0; i < num_switches; i++) + for (j = 0; j < num_switches; j++) + if (virtual_location[i][j][old_max_filled_lane] == 2) + virtual_location[i][j][old_max_filled_lane] = 1; + } + } +} + +static switch_t *switch_create(lash_t * p_lash, unsigned id, osm_switch_t * p_sw) +{ + unsigned num_switches = p_lash->num_switches; + unsigned num_ports = p_sw->num_ports; + switch_t *sw; + unsigned int i; + + sw = malloc(sizeof(*sw)); + if (!sw) + return NULL; + + memset(sw, 0, sizeof(*sw)); + + sw->id = id; + sw->dij_channels = malloc(num_ports * sizeof(int)); + if (!sw->dij_channels) { + free(sw); + return NULL; + } + + sw->virtual_physical_port_table = malloc(num_ports * sizeof(int)); + if (!sw->virtual_physical_port_table) { + free(sw->dij_channels); + free(sw); + return NULL; + } + + sw->phys_connections = malloc(num_ports * sizeof(int)); + if (!sw->phys_connections) { + free(sw->virtual_physical_port_table); + free(sw->dij_channels); + free(sw); + return NULL; + } + + sw->routing_table = malloc(num_switches * sizeof(sw->routing_table[0])); + if (!sw->routing_table) { + free(sw->phys_connections); + free(sw->virtual_physical_port_table); + free(sw->dij_channels); + free(sw); + return NULL; + } + + for (i = 0; i < num_switches; i++) { + sw->routing_table[i].out_link = NONE; + sw->routing_table[i].lane = NONE; + } + + for (i = 0; i < num_ports; i++) { + sw->virtual_physical_port_table[i] = -1; + sw->phys_connections[i] = NONE; + } + + sw->p_sw = p_sw; + if (p_sw) + p_sw->priv = sw; + + return sw; +} + +static void switch_delete(switch_t * sw) +{ + if (sw->dij_channels) + free(sw->dij_channels); + if (sw->virtual_physical_port_table) + free(sw->virtual_physical_port_table); + if (sw->phys_connections) + free(sw->phys_connections); + if (sw->routing_table) + free(sw->routing_table); + free(sw); +} + +static void free_lash_structures(lash_t * p_lash) +{ + unsigned int i, j, k; + unsigned num_switches = p_lash->num_switches; + osm_log_t *p_log = &p_lash->p_osm->log; + + OSM_LOG_ENTER(p_log); + + // free cdg_vertex_matrix + for (i = 0; i < p_lash->vl_min; i++) { + for (j = 0; j < num_switches; j++) { + for (k = 0; k < num_switches; k++) { + if (p_lash->cdg_vertex_matrix[i][j][k]) { + + if (p_lash->cdg_vertex_matrix[i][j][k]->dependency) + free(p_lash->cdg_vertex_matrix[i][j][k]-> + dependency); + + if (p_lash->cdg_vertex_matrix[i][j][k]-> + num_using_this_depend) + free(p_lash->cdg_vertex_matrix[i][j][k]-> + num_using_this_depend); + + free(p_lash->cdg_vertex_matrix[i][j][k]); + } + } + if (p_lash->cdg_vertex_matrix[i][j]) + free(p_lash->cdg_vertex_matrix[i][j]); + } + if (p_lash->cdg_vertex_matrix[i]) + free(p_lash->cdg_vertex_matrix[i]); + } + + if (p_lash->cdg_vertex_matrix) + free(p_lash->cdg_vertex_matrix); + + // free virtual_location + for (i = 0; i < num_switches; i++) { + for (j = 0; j < num_switches; j++) { + if (p_lash->virtual_location[i][j]) + free(p_lash->virtual_location[i][j]); + } + if (p_lash->virtual_location[i]) + free(p_lash->virtual_location[i]); + } + if (p_lash->virtual_location) + free(p_lash->virtual_location); + + if (p_lash->num_mst_in_lane) + free(p_lash->num_mst_in_lane); + + OSM_LOG_EXIT(p_log); +} + +static int init_lash_structures(lash_t * p_lash) +{ + unsigned vl_min = p_lash->vl_min; + unsigned num_switches = p_lash->num_switches; + osm_log_t *p_log = &p_lash->p_osm->log; + int status = 0; + unsigned int i, j, k; + + OSM_LOG_ENTER(p_log); + + // initialise cdg_vertex_matrix[num_switches][num_switches][num_switches] + p_lash->cdg_vertex_matrix = + (cdg_vertex_t ****) malloc(vl_min * sizeof(cdg_vertex_t ****)); + for (i = 0; i < vl_min; i++) { + p_lash->cdg_vertex_matrix[i] = + (cdg_vertex_t ***) malloc(num_switches * + sizeof(cdg_vertex_t ***)); + + if (p_lash->cdg_vertex_matrix[i] == NULL) + goto Exit_Mem_Error; + } + + for (i = 0; i < vl_min; i++) { + for (j = 0; j < num_switches; j++) { + p_lash->cdg_vertex_matrix[i][j] = + (cdg_vertex_t **) malloc(num_switches * + sizeof(cdg_vertex_t **)); + if (p_lash->cdg_vertex_matrix[i][j] == NULL) + goto Exit_Mem_Error; + + for (k = 0; k < num_switches; k++) { + p_lash->cdg_vertex_matrix[i][j][k] = NULL; + } + } + } + + // initialise virtual_location[num_switches][num_switches][num_layers], + // default value = 0 + p_lash->virtual_location = + (int ***)malloc(num_switches * sizeof(int ***)); + if (p_lash->virtual_location == NULL) + goto Exit_Mem_Error; + + for (i = 0; i < num_switches; i++) { + p_lash->virtual_location[i] = + (int **)malloc(num_switches * sizeof(int **)); + if (p_lash->virtual_location[i] == NULL) + goto Exit_Mem_Error; + } + + for (i = 0; i < num_switches; i++) { + for (j = 0; j < num_switches; j++) { + p_lash->virtual_location[i][j] = + (int *)malloc(vl_min * sizeof(int *)); + if (p_lash->virtual_location[i][j] == NULL) + goto Exit_Mem_Error; + for (k = 0; k < vl_min; k++) { + p_lash->virtual_location[i][j][k] = 0; + } + } + } + + // initialise num_mst_in_lane[num_switches], default 0 + p_lash->num_mst_in_lane = (int *)malloc(num_switches * sizeof(int)); + if (p_lash->num_mst_in_lane == NULL) + goto Exit_Mem_Error; + memset(p_lash->num_mst_in_lane, 0, + num_switches * sizeof(p_lash->num_mst_in_lane[0])); + + goto Exit; + +Exit_Mem_Error: + status = -1; + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D01: " + "Could not allocate required memory for LASH errno %d, errno %d for lack of memory\n", + errno, ENOMEM); + +Exit: + OSM_LOG_EXIT(p_log); + return status; +} + +static int lash_core(lash_t * p_lash) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + unsigned num_switches = p_lash->num_switches; + switch_t **switches = p_lash->switches; + unsigned lanes_needed = 1; + unsigned int i, j, k, dest_switch = 0; + reachable_dest_t *dests, *idest; + int cycle_found = 0; + unsigned v_lane; + int stop = 0, output_link, i_next_switch; + int output_link2, i_next_switch2; + int cycle_found2 = 0; + int status = 0; + int *switch_bitmap; /* Bitmap to check if we have processed this pair */ + + OSM_LOG_ENTER(p_log); + + for (i = 0; i < num_switches; i++) { + + shortest_path(p_lash, i); + generate_routing_func_for_mst(p_lash, i, &dests); + + idest = dests; + while (idest != NULL) { + dests = dests->next; + free(idest); + idest = dests; + } + + for (j = 0; j < num_switches; j++) { + switches[j]->used_channels = 0; + switches[j]->q_state = UNQUEUED; + } + } + + switch_bitmap = malloc(num_switches * num_switches * sizeof(int)); + if (!switch_bitmap) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D04: " + "Failed allocating switch_bitmap - out of memory\n"); + goto Exit; + } + memset(switch_bitmap, 0, num_switches * num_switches * sizeof(int)); + + for (i = 0; i < num_switches; i++) { + for (dest_switch = 0; dest_switch < num_switches; dest_switch++) + if (dest_switch != i && switch_bitmap[i * num_switches + dest_switch] == 0) { + v_lane = 0; + stop = 0; + while (v_lane < lanes_needed && stop == 0) { + generate_cdg_for_sp(p_lash, i, dest_switch, v_lane); + generate_cdg_for_sp(p_lash, dest_switch, i, v_lane); + + output_link = + switches[i]->routing_table[dest_switch].out_link; + output_link2 = + switches[dest_switch]->routing_table[i].out_link; + + i_next_switch = switches[i]->phys_connections[output_link]; + i_next_switch2 = + switches[dest_switch]->phys_connections[output_link2]; + + CL_ASSERT(p_lash-> + cdg_vertex_matrix[v_lane][i][i_next_switch] != + NULL); + CL_ASSERT(p_lash-> + cdg_vertex_matrix[v_lane][dest_switch] + [i_next_switch2] != NULL); + + cycle_found = + cycle_exists(p_lash-> + cdg_vertex_matrix[v_lane][i] + [i_next_switch], NULL, NULL, 1); + cycle_found2 = + cycle_exists(p_lash-> + cdg_vertex_matrix[v_lane][dest_switch] + [i_next_switch2], NULL, NULL, 1); + + for (j = 0; j < num_switches; j++) + for (k = 0; k < num_switches; k++) + if (p_lash-> + cdg_vertex_matrix[v_lane][j][k] != + NULL) { + p_lash-> + cdg_vertex_matrix[v_lane][j] + [k]->visiting_number = 0; + p_lash-> + cdg_vertex_matrix[v_lane][j] + [k]->seen = 0; + } + + if (cycle_found == 1 || cycle_found2 == 1) { + remove_temp_depend_for_sp(p_lash, i, dest_switch, + v_lane); + remove_temp_depend_for_sp(p_lash, dest_switch, i, + v_lane); + v_lane++; + } else { + set_temp_depend_to_permanent_for_sp(p_lash, i, + dest_switch, + v_lane); + set_temp_depend_to_permanent_for_sp(p_lash, + dest_switch, i, + v_lane); + stop = 1; + p_lash->num_mst_in_lane[v_lane]++; + p_lash->num_mst_in_lane[v_lane]++; + } + } + + switches[i]->routing_table[dest_switch].lane = v_lane; + switches[dest_switch]->routing_table[i].lane = v_lane; + + if (cycle_found == 1 || cycle_found2 == 1) { + if (++lanes_needed > p_lash->vl_min) + goto Error_Not_Enough_Lanes; + + generate_cdg_for_sp(p_lash, i, dest_switch, v_lane); + generate_cdg_for_sp(p_lash, dest_switch, i, v_lane); + + set_temp_depend_to_permanent_for_sp(p_lash, i, dest_switch, + v_lane); + set_temp_depend_to_permanent_for_sp(p_lash, dest_switch, i, + v_lane); + + p_lash->num_mst_in_lane[v_lane]++; + p_lash->num_mst_in_lane[v_lane]++; + } + p_lash->virtual_location[i][dest_switch][v_lane] = 1; + p_lash->virtual_location[dest_switch][i][v_lane] = 1; + + switch_bitmap[i * num_switches + dest_switch] = 1; + switch_bitmap[dest_switch * num_switches + i] = 1; + } + } + + OSM_LOG(p_log, OSM_LOG_INFO, + "Lanes needed: %d, Balancing\n", lanes_needed); + + for (i = 0; i < lanes_needed; i++) { + OSM_LOG(p_log, OSM_LOG_INFO, "Lanes in layer %d: %d\n", + i, p_lash->num_mst_in_lane[i]); + } + + balance_virtual_lanes(p_lash, lanes_needed); + + for (i = 0; i < lanes_needed; i++) { + OSM_LOG(p_log, OSM_LOG_INFO, "Lanes in layer %d: %d\n", + i, p_lash->num_mst_in_lane[i]); + } + + goto Exit; + +Error_Not_Enough_Lanes: + status = -1; + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 4D02: " + "Lane requirements (%d) exceed available lanes (%d)\n", + p_lash->vl_min, lanes_needed); +Exit: + if (switch_bitmap) + free(switch_bitmap); + OSM_LOG_EXIT(p_log); + return status; +} + +static unsigned get_lash_id(osm_switch_t * p_sw) +{ + return ((switch_t *) p_sw->priv)->id; +} + +static void populate_fwd_tbls(lash_t * p_lash) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + osm_subn_t *p_subn = &p_lash->p_osm->subn; + osm_opensm_t *p_osm = p_lash->p_osm; + osm_switch_t *p_sw, *p_next_sw, *p_dst_sw; + osm_port_t *port; + uint16_t max_lid_ho, lid; + + OSM_LOG_ENTER(p_log); + + p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl); + + // Go through each swtich individually + while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) { + uint64_t current_guid; + switch_t *sw; + p_sw = p_next_sw; + p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); + + max_lid_ho = p_sw->max_lid_ho; + current_guid = p_sw->p_node->node_info.port_guid; + sw = p_sw->priv; + + memset(p_sw->new_lft, OSM_NO_PATH, IB_LID_UCAST_END_HO + 1); + + for (lid = 1; lid <= max_lid_ho; lid++) { + port = cl_ptr_vector_get(&p_subn->port_lid_tbl, lid); + if (!port) + continue; + + p_dst_sw = get_osm_switch_from_port(port); + if (p_dst_sw == p_sw) { + uint8_t egress_port = port->p_node->sw ? 0 : + port->p_physp->p_remote_physp->port_num; + p_sw->new_lft[lid] = egress_port; + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "LASH fwd MY SRC SRC GUID 0x%016" PRIx64 + " src lash id (%d), src lid no (%u) src lash port (%d) " + "DST GUID 0x%016" PRIx64 + " src lash id (%d), src lash port (%d)\n", + cl_ntoh64(current_guid), -1, lid, + egress_port, cl_ntoh64(current_guid), + -1, egress_port); + } else if (p_dst_sw) { + unsigned dst_lash_switch_id = + get_lash_id(p_dst_sw); + uint8_t lash_egress_port = + (uint8_t) sw-> + routing_table[dst_lash_switch_id].out_link; + uint8_t physical_egress_port = + (uint8_t) sw-> + virtual_physical_port_table + [lash_egress_port]; + + p_sw->new_lft[lid] = physical_egress_port; + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "LASH fwd SRC GUID 0x%016" PRIx64 + " src lash id (%d), " + "src lid no (%u) src lash port (%d) " + "DST GUID 0x%016" PRIx64 + " src lash id (%d), src lash port (%d)\n", + cl_ntoh64(current_guid), sw->id, lid, + lash_egress_port, + cl_ntoh64(p_dst_sw->p_node->node_info. + port_guid), + dst_lash_switch_id, + physical_egress_port); + } + } // for + osm_ucast_mgr_set_fwd_table(&p_osm->sm.ucast_mgr, p_sw); + } + OSM_LOG_EXIT(p_log); +} + +static void osm_lash_process_switch(lash_t * p_lash, osm_switch_t * p_sw) +{ + osm_log_t *p_log = &p_lash->p_osm->log; + int i, port_count; + osm_physp_t *p_current_physp, *p_remote_physp; + unsigned switch_a_lash_id, switch_b_lash_id; + + OSM_LOG_ENTER(p_log); + + switch_a_lash_id = get_lash_id(p_sw); + port_count = osm_node_get_num_physp(p_sw->p_node); + + // starting at port 1, ignoring management port on switch + for (i = 1; i < port_count; i++) { + + p_current_physp = osm_node_get_physp_ptr(p_sw->p_node, i); + if (p_current_physp) { + p_remote_physp = p_current_physp->p_remote_physp; + if (p_remote_physp && p_remote_physp->p_node->sw) { + int physical_port_a_num = + osm_physp_get_port_num(p_current_physp); + int physical_port_b_num = + osm_physp_get_port_num(p_remote_physp); + switch_b_lash_id = + get_lash_id(p_remote_physp->p_node->sw); + + connect_switches(p_lash, switch_a_lash_id, + switch_b_lash_id, + physical_port_a_num); + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "LASH SUCCESS connected G 0x%016" PRIx64 + " , lash_id(%u), P(%u) " " to G 0x%016" + PRIx64 " , lash_id(%u) , P(%u)\n", + cl_ntoh64(osm_physp_get_port_guid + (p_current_physp)), + switch_a_lash_id, physical_port_a_num, + cl_ntoh64(osm_physp_get_port_guid + (p_remote_physp)), + switch_b_lash_id, physical_port_b_num); + } + } + } + + OSM_LOG_EXIT(p_log); +} + +static void lash_cleanup(lash_t * p_lash) +{ + osm_subn_t *p_subn = &p_lash->p_osm->subn; + osm_switch_t *p_next_sw, *p_sw; + + /* drop any existing references to old lash switches */ + p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl); + while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) { + p_sw = p_next_sw; + p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); + p_sw->priv = NULL; + } + + if (p_lash->switches) { + unsigned id; + for (id = 0; ((int)id) < p_lash->num_switches; id++) + if (p_lash->switches[id]) + switch_delete(p_lash->switches[id]); + free(p_lash->switches); + } + p_lash->switches = NULL; +} + +/* + static int discover_network_properties() + Traverse the topology of the network in order to determine + - the maximum number of switches, + - the minimum number of virtual layers +*/ + +static int discover_network_properties(lash_t * p_lash) +{ + int i = 0, id = 0; + uint8_t vl_min; + osm_subn_t *p_subn = &p_lash->p_osm->subn; + osm_switch_t *p_next_sw, *p_sw; + osm_log_t *p_log = &p_lash->p_osm->log; + + p_lash->num_switches = cl_qmap_count(&p_subn->sw_guid_tbl); + + p_lash->switches = malloc(p_lash->num_switches * sizeof(switch_t *)); + if (!p_lash->switches) + return -1; + memset(p_lash->switches, 0, p_lash->num_switches * sizeof(switch_t *)); + + vl_min = 5; // set to a high value + + p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl); + while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) { + uint16_t port_count; + p_sw = p_next_sw; + p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); + + p_lash->switches[id] = switch_create(p_lash, id, p_sw); + if (!p_lash->switches[id]) + return -1; + id++; + + port_count = osm_node_get_num_physp(p_sw->p_node); + + // Note, ignoring port 0. management port + for (i = 1; i < port_count; i++) { + osm_physp_t *p_current_physp = + osm_node_get_physp_ptr(p_sw->p_node, i); + + if (p_current_physp + && p_current_physp->p_remote_physp) { + + ib_port_info_t *p_port_info = + &p_current_physp->port_info; + uint8_t port_vl_min = + ib_port_info_get_op_vls(p_port_info); + if (port_vl_min && port_vl_min < vl_min) + vl_min = port_vl_min; + } + } // for + } // while + + vl_min = 1 << (vl_min - 1); + if (vl_min > 15) + vl_min = 15; + + p_lash->vl_min = vl_min; + + OSM_LOG(p_log, OSM_LOG_INFO, + "min operational vl(%d) max_switches(%d)\n", p_lash->vl_min, + p_lash->num_switches); + return 0; +} + +static void process_switches(lash_t * p_lash) +{ + osm_switch_t *p_sw, *p_next_sw; + osm_subn_t *p_subn = &p_lash->p_osm->subn; + + /* Go through each swithc and process it. i.e build the connection + structure required by LASH */ + p_next_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl); + while (p_next_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl)) { + p_sw = p_next_sw; + p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); + + osm_lash_process_switch(p_lash, p_sw); + } +} + +static int lash_process(void *context) +{ + lash_t *p_lash = context; + osm_log_t *p_log = &p_lash->p_osm->log; + int return_status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + p_lash->balance_limit = 6; + + // everything starts here + lash_cleanup(p_lash); + + discover_network_properties(p_lash); + + return_status = init_lash_structures(p_lash); + if (return_status != IB_SUCCESS) + goto Exit; + + process_switches(p_lash); + + return_status = lash_core(p_lash); + if (return_status != IB_SUCCESS) + goto Exit; + + populate_fwd_tbls(p_lash); + +Exit: + free_lash_structures(p_lash); + OSM_LOG_EXIT(p_log); + + return return_status; +} + +static lash_t *lash_create(osm_opensm_t * p_osm) +{ + lash_t *p_lash; + + p_lash = malloc(sizeof(lash_t)); + if (!p_lash) + return NULL; + + memset(p_lash, 0, sizeof(lash_t)); + p_lash->p_osm = p_osm; + + return (p_lash); +} + +static void lash_delete(void *context) +{ + lash_t *p_lash = context; + if (p_lash->switches) { + unsigned id; + for (id = 0; ((int)id) < p_lash->num_switches; id++) + if (p_lash->switches[id]) + switch_delete(p_lash->switches[id]); + free(p_lash->switches); + } + free(p_lash); +} + +uint8_t osm_get_lash_sl(osm_opensm_t * p_osm, osm_port_t * p_src_port, + osm_port_t * p_dst_port) +{ + unsigned dst_id; + unsigned src_id; + osm_switch_t *p_sw; + + if (p_osm->routing_engine_used != OSM_ROUTING_ENGINE_TYPE_LASH) + return OSM_DEFAULT_SL; + + p_sw = get_osm_switch_from_port(p_dst_port); + if (!p_sw || !p_sw->priv) + return OSM_DEFAULT_SL; + dst_id = get_lash_id(p_sw); + + p_sw = get_osm_switch_from_port(p_src_port); + if (!p_sw || !p_sw->priv) + return OSM_DEFAULT_SL; + + src_id = get_lash_id(p_sw); + if (src_id == dst_id) + return OSM_DEFAULT_SL; + + return (uint8_t) ((switch_t *) p_sw->priv)->routing_table[dst_id].lane; +} + +int osm_ucast_lash_setup(struct osm_routing_engine *r, osm_opensm_t *p_osm) +{ + lash_t *p_lash = lash_create(p_osm); + if (!p_lash) + return -1; + + r->context = p_lash; + r->ucast_build_fwd_tables = lash_process; + r->delete = lash_delete; + + return 0; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_ucast_mgr.c b/contrib/ofed/management/opensm/opensm/osm_ucast_mgr.c new file mode 100644 index 000000000000..d332b3661963 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_ucast_mgr.c @@ -0,0 +1,903 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2008 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_ucast_mgr_t. + * This file implements the Unicast Manager object. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +void osm_ucast_mgr_construct(IN osm_ucast_mgr_t * const p_mgr) +{ + memset(p_mgr, 0, sizeof(*p_mgr)); +} + +/********************************************************************** + **********************************************************************/ +void osm_ucast_mgr_destroy(IN osm_ucast_mgr_t * const p_mgr) +{ + CL_ASSERT(p_mgr); + + OSM_LOG_ENTER(p_mgr->p_log); + + if (p_mgr->cache_valid) + osm_ucast_cache_invalidate(p_mgr); + + OSM_LOG_EXIT(p_mgr->p_log); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_ucast_mgr_init(IN osm_ucast_mgr_t * const p_mgr, IN osm_sm_t * sm) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(sm->p_log); + + osm_ucast_mgr_construct(p_mgr); + + p_mgr->sm = sm; + p_mgr->p_log = sm->p_log; + p_mgr->p_subn = sm->p_subn; + p_mgr->p_lock = sm->p_lock; + + if (sm->p_subn->opt.use_ucast_cache) + cl_qmap_init(&p_mgr->cache_sw_tbl); + + OSM_LOG_EXIT(p_mgr->p_log); + return (status); +} + +/********************************************************************** + Add each switch's own and neighbor LIDs to its LID matrix +**********************************************************************/ +static void +__osm_ucast_mgr_process_hop_0_1(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + osm_switch_t *const p_sw = (osm_switch_t *) p_map_item; + osm_node_t *p_remote_node; + uint16_t lid, remote_lid; + uint8_t i, remote_port; + + lid = osm_node_get_base_lid(p_sw->p_node, 0); + lid = cl_ntoh16(lid); + osm_switch_set_hops(p_sw, lid, 0, 0); + + for (i = 1; i < p_sw->num_ports; i++) { + p_remote_node = + osm_node_get_remote_node(p_sw->p_node, i, &remote_port); + + if (p_remote_node && p_remote_node->sw && + (p_remote_node != p_sw->p_node)) { + remote_lid = osm_node_get_base_lid(p_remote_node, 0); + remote_lid = cl_ntoh16(remote_lid); + osm_switch_set_hops(p_sw, remote_lid, i, 1); + osm_switch_set_hops(p_remote_node->sw, lid, remote_port, + 1); + } + } +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_ucast_mgr_process_neighbor(IN osm_ucast_mgr_t * const p_mgr, + IN osm_switch_t * const p_this_sw, + IN osm_switch_t * const p_remote_sw, + IN const uint8_t port_num, + IN const uint8_t remote_port_num) +{ + osm_switch_t *p_sw, *p_next_sw; + uint16_t lid_ho; + uint8_t hops; + + OSM_LOG_ENTER(p_mgr->p_log); + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Node 0x%" PRIx64 ", remote node 0x%" PRIx64 + ", port %u, remote port %u\n", + cl_ntoh64(osm_node_get_node_guid(p_this_sw->p_node)), + cl_ntoh64(osm_node_get_node_guid(p_remote_sw->p_node)), + port_num, remote_port_num); + + p_next_sw = (osm_switch_t *) cl_qmap_head(&p_mgr->p_subn->sw_guid_tbl); + while (p_next_sw != + (osm_switch_t *) cl_qmap_end(&p_mgr->p_subn->sw_guid_tbl)) { + p_sw = p_next_sw; + p_next_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item); + lid_ho = osm_node_get_base_lid(p_sw->p_node, 0); + lid_ho = cl_ntoh16(lid_ho); + hops = osm_switch_get_least_hops(p_remote_sw, lid_ho); + if (hops == OSM_NO_PATH) + continue; + hops++; + if (hops < + osm_switch_get_hop_count(p_this_sw, lid_ho, port_num)) { + if (osm_switch_set_hops + (p_this_sw, lid_ho, port_num, hops) != 0) + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, + "cannot set hops for lid %u at switch 0x%" + PRIx64 "\n", lid_ho, + cl_ntoh64(osm_node_get_node_guid + (p_this_sw->p_node))); + p_mgr->some_hop_count_set = TRUE; + } + } + + OSM_LOG_EXIT(p_mgr->p_log); +} + +/********************************************************************** + **********************************************************************/ +static struct osm_remote_node * +find_and_add_remote_sys(osm_switch_t *sw, uint8_t port, + struct osm_remote_guids_count *r) +{ + unsigned i; + osm_physp_t *p = osm_node_get_physp_ptr(sw->p_node, port); + osm_node_t *node = p->p_remote_physp->p_node; + + for (i = 0; i < r->count; i++) + if (r->guids[i].node == node) + return &r->guids[i]; + + r->guids[i].node = node; + r->guids[i].forwarded_to = 0; + r->count++; + return &r->guids[i]; +} + +static void +__osm_ucast_mgr_process_port(IN osm_ucast_mgr_t * const p_mgr, + IN osm_switch_t * const p_sw, + IN osm_port_t * const p_port, + IN unsigned lid_offset) +{ + uint16_t min_lid_ho; + uint16_t max_lid_ho; + uint16_t lid_ho; + uint8_t port; + boolean_t is_ignored_by_port_prof; + ib_net64_t node_guid; + unsigned start_from = 1; + + OSM_LOG_ENTER(p_mgr->p_log); + + osm_port_get_lid_range_ho(p_port, &min_lid_ho, &max_lid_ho); + + /* If the lids are zero - then there was some problem with + * the initialization. Don't handle this port. */ + if (min_lid_ho == 0 || max_lid_ho == 0) { + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A04: " + "Port 0x%" PRIx64 " has LID 0. An initialization " + "error occurred. Ignoring port\n", + cl_ntoh64(osm_port_get_guid(p_port))); + goto Exit; + } + + lid_ho = min_lid_ho + lid_offset; + + if (lid_ho > max_lid_ho) + goto Exit; + + if (lid_offset) + /* ignore potential overflow - it is handled in osm_switch.c */ + start_from = osm_switch_get_port_by_lid(p_sw, lid_ho - 1) + 1; + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Processing port 0x%" PRIx64 " (\'%s\' port %u), LID %u [%u,%u]\n", + cl_ntoh64(osm_port_get_guid(p_port)), + p_port->p_node->print_desc, p_port->p_physp->port_num, + lid_ho, min_lid_ho, max_lid_ho); + + /* TODO - This should be runtime error, not a CL_ASSERT() */ + CL_ASSERT(max_lid_ho <= IB_LID_UCAST_END_HO); + + node_guid = osm_node_get_node_guid(p_sw->p_node); + + /* + The lid matrix contains the number of hops to each + lid from each port. From this information we determine + how best to distribute the LID range across the ports + that can reach those LIDs. + */ + port = osm_switch_recommend_path(p_sw, p_port, lid_ho, start_from, + p_mgr->p_subn->ignore_existing_lfts, + p_mgr->is_dor); + + if (port == OSM_NO_PATH) { + /* do not try to overwrite the ppro of non existing port ... */ + is_ignored_by_port_prof = TRUE; + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "No path to get to LID %u from switch 0x%" PRIx64 "\n", + lid_ho, cl_ntoh64(node_guid)); + } else { + osm_physp_t *p = osm_node_get_physp_ptr(p_sw->p_node, port); + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Routing LID %u to port %u" + " for switch 0x%" PRIx64 "\n", + lid_ho, port, cl_ntoh64(node_guid)); + + /* + we would like to optionally ignore this port in equalization + as in the case of the Mellanox Anafa Internal PCI TCA port + */ + is_ignored_by_port_prof = p->is_prof_ignored; + + /* + We also would ignore this route if the target lid is of + a switch and the port_profile_switch_node is not TRUE + */ + if (!p_mgr->p_subn->opt.port_profile_switch_nodes) + is_ignored_by_port_prof |= + (osm_node_get_type(p_port->p_node) == + IB_NODE_TYPE_SWITCH); + } + + /* + We have selected the port for this LID. + Write it to the forwarding tables. + */ + p_sw->new_lft[lid_ho] = port; + if (!is_ignored_by_port_prof) { + struct osm_remote_node *rem_node_used; + osm_switch_count_path(p_sw, port); + if (port > 0 && p_port->priv && + (rem_node_used = find_and_add_remote_sys(p_sw, port, + p_port->priv))) + rem_node_used->forwarded_to++; + } + +Exit: + OSM_LOG_EXIT(p_mgr->p_log); +} + +/********************************************************************** + **********************************************************************/ +int osm_ucast_mgr_set_fwd_table(IN osm_ucast_mgr_t * const p_mgr, + IN osm_switch_t * const p_sw) +{ + osm_node_t *p_node; + osm_dr_path_t *p_path; + osm_madw_context_t context; + ib_api_status_t status; + ib_switch_info_t si; + uint16_t block_id_ho = 0; + uint8_t block[IB_SMP_DATA_SIZE]; + boolean_t set_swinfo_require = FALSE; + uint16_t lin_top; + uint8_t life_state; + + CL_ASSERT(p_mgr); + + OSM_LOG_ENTER(p_mgr->p_log); + + CL_ASSERT(p_sw); + + p_node = p_sw->p_node; + + CL_ASSERT(p_node); + + p_path = osm_physp_get_dr_path_ptr(osm_node_get_physp_ptr(p_node, 0)); + + /* + Set the top of the unicast forwarding table. + */ + si = p_sw->switch_info; + lin_top = cl_hton16(p_sw->max_lid_ho); + if (lin_top != si.lin_top) { + set_swinfo_require = TRUE; + si.lin_top = lin_top; + } + + /* check to see if the change state bit is on. If it is - then we + need to clear it. */ + if (ib_switch_info_get_state_change(&si)) + life_state = ((p_mgr->p_subn->opt.packet_life_time << 3) + | (si.life_state & IB_SWITCH_PSC)) & 0xfc; + else + life_state = (p_mgr->p_subn->opt.packet_life_time << 3) & 0xf8; + + if ((life_state != si.life_state) + || ib_switch_info_get_state_change(&si)) { + set_swinfo_require = TRUE; + si.life_state = life_state; + } + + if (set_swinfo_require) { + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Setting switch FT top to LID %u\n", p_sw->max_lid_ho); + + context.si_context.light_sweep = FALSE; + context.si_context.node_guid = osm_node_get_node_guid(p_node); + context.si_context.set_method = TRUE; + + status = osm_req_set(p_mgr->sm, p_path, (uint8_t *) & si, + sizeof(si), + IB_MAD_ATTR_SWITCH_INFO, + 0, CL_DISP_MSGID_NONE, &context); + + if (status != IB_SUCCESS) + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A06: " + "Sending SwitchInfo attribute failed (%s)\n", + ib_get_err_str(status)); + } + + /* + Send linear forwarding table blocks to the switch + as long as the switch indicates it has blocks needing + configuration. + */ + + context.lft_context.node_guid = osm_node_get_node_guid(p_node); + context.lft_context.set_method = TRUE; + + if (!p_sw->new_lft) { + /* any routing should provide the new_lft */ + CL_ASSERT(p_mgr->p_subn->opt.use_ucast_cache && + p_mgr->cache_valid && !p_sw->need_update); + goto Exit; + } + + for (block_id_ho = 0; + osm_switch_get_lft_block(p_sw, block_id_ho, block); + block_id_ho++) { + if (!p_sw->need_update && + !memcmp(block, + p_sw->new_lft + block_id_ho * IB_SMP_DATA_SIZE, + IB_SMP_DATA_SIZE)) + continue; + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Writing FT block %u\n", block_id_ho); + + status = osm_req_set(p_mgr->sm, p_path, + p_sw->new_lft + block_id_ho * IB_SMP_DATA_SIZE, + sizeof(block), + IB_MAD_ATTR_LIN_FWD_TBL, + cl_hton32(block_id_ho), + CL_DISP_MSGID_NONE, &context); + + if (status != IB_SUCCESS) + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR 3A05: " + "Sending linear fwd. tbl. block failed (%s)\n", + ib_get_err_str(status)); + } + +Exit: + OSM_LOG_EXIT(p_mgr->p_log); + return 0; +} + +/********************************************************************** + **********************************************************************/ +static void alloc_ports_priv(osm_ucast_mgr_t *mgr) +{ + cl_qmap_t *port_tbl = &mgr->p_subn->port_guid_tbl; + struct osm_remote_guids_count *r; + osm_port_t *port; + cl_map_item_t *item; + unsigned lmc; + + for (item = cl_qmap_head(port_tbl); item != cl_qmap_end(port_tbl); + item = cl_qmap_next(item)) { + port = (osm_port_t *)item; + lmc = ib_port_info_get_lmc(&port->p_physp->port_info); + if (!lmc) + continue; + r = malloc(sizeof(*r) + sizeof(r->guids[0]) * (1 << lmc)); + if (!r) { + OSM_LOG(mgr->p_log, OSM_LOG_ERROR, "ERR 3A09: " + "cannot allocate memory to track remote" + " systems for lmc > 0\n"); + port->priv = NULL; + continue; + } + memset(r, 0, sizeof(*r) + sizeof(r->guids[0]) * (1 << lmc)); + port->priv = r; + } +} + +static void free_ports_priv(osm_ucast_mgr_t *mgr) +{ + cl_qmap_t *port_tbl = &mgr->p_subn->port_guid_tbl; + osm_port_t *port; + cl_map_item_t *item; + for (item = cl_qmap_head(port_tbl); item != cl_qmap_end(port_tbl); + item = cl_qmap_next(item)) { + port = (osm_port_t *)item; + if (port->priv) { + free(port->priv); + port->priv = NULL; + } + } +} + +static void +__osm_ucast_mgr_process_tbl(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + osm_ucast_mgr_t *p_mgr = context; + osm_switch_t *const p_sw = (osm_switch_t *) p_map_item; + unsigned i, lids_per_port; + + OSM_LOG_ENTER(p_mgr->p_log); + + CL_ASSERT(p_sw && p_sw->p_node); + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Processing switch 0x%" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node))); + + /* Initialize LIDs in buffer to invalid port number. */ + memset(p_sw->new_lft, OSM_NO_PATH, IB_LID_UCAST_END_HO + 1); + + if (p_mgr->p_subn->opt.lmc) + alloc_ports_priv(p_mgr); + + /* + Iterate through every port setting LID routes for each + port based on base LID and LMC value. + */ + lids_per_port = 1 << p_mgr->p_subn->opt.lmc; + for (i = 0; i < lids_per_port; i++) { + cl_qlist_t *list = &p_mgr->port_order_list; + cl_list_item_t *item; + for (item = cl_qlist_head(list); item != cl_qlist_end(list); + item = cl_qlist_next(item)) { + osm_port_t *port = cl_item_obj(item, port, list_item); + __osm_ucast_mgr_process_port(p_mgr, p_sw, port, i); + } + } + + osm_ucast_mgr_set_fwd_table(p_mgr, p_sw); + + if (p_mgr->p_subn->opt.lmc) + free_ports_priv(p_mgr); + + OSM_LOG_EXIT(p_mgr->p_log); +} + +/********************************************************************** + **********************************************************************/ +static void +__osm_ucast_mgr_process_neighbors(IN cl_map_item_t * const p_map_item, + IN void *context) +{ + osm_switch_t *const p_sw = (osm_switch_t *) p_map_item; + osm_ucast_mgr_t *const p_mgr = (osm_ucast_mgr_t *) context; + osm_node_t *p_node; + osm_node_t *p_remote_node; + uint32_t port_num; + uint8_t remote_port_num; + uint32_t num_ports; + osm_physp_t *p_physp; + + OSM_LOG_ENTER(p_mgr->p_log); + + p_node = p_sw->p_node; + + CL_ASSERT(p_node); + CL_ASSERT(osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH); + + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Processing switch with GUID 0x%" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(p_node))); + + num_ports = osm_node_get_num_physp(p_node); + + /* + Start with port 1 to skip the switch's management port. + */ + for (port_num = 1; port_num < num_ports; port_num++) { + p_remote_node = osm_node_get_remote_node(p_node, + (uint8_t) port_num, + &remote_port_num); + + if (p_remote_node && p_remote_node->sw + && (p_remote_node != p_node)) { + /* make sure the link is healthy. If it is not - don't + propagate through it. */ + p_physp = osm_node_get_physp_ptr(p_node, port_num); + if (!p_physp || !osm_link_is_healthy(p_physp)) + continue; + + __osm_ucast_mgr_process_neighbor(p_mgr, p_sw, + p_remote_node->sw, + (uint8_t) port_num, + remote_port_num); + + } + } + + OSM_LOG_EXIT(p_mgr->p_log); +} + +/********************************************************************** + **********************************************************************/ +int osm_ucast_mgr_build_lid_matrices(IN osm_ucast_mgr_t * const p_mgr) +{ + uint32_t i; + uint32_t iteration_max; + cl_qmap_t *p_sw_guid_tbl; + + p_sw_guid_tbl = &p_mgr->p_subn->sw_guid_tbl; + + OSM_LOG(p_mgr->p_log, OSM_LOG_VERBOSE, + "Starting switches' Min Hop Table Assignment\n"); + + /* + Set the switch matrices for each switch's own port 0 LID(s) + then set the lid matrices for the each switch's leaf nodes. + */ + cl_qmap_apply_func(p_sw_guid_tbl, + __osm_ucast_mgr_process_hop_0_1, p_mgr); + + /* + Get the switch matrices for each switch's neighbors. + This process requires a number of iterations equal to + the number of switches in the subnet minus 1. + + In each iteration, a switch learns the lid/port/hop + information (as contained by a switch's lid matrix) from + its immediate neighbors. After each iteration, a switch + (and it's neighbors) know more routing information than + it did on the previous iteration. + Thus, by repeatedly absorbing the routing information of + neighbor switches, every switch eventually learns how to + route all LIDs on the subnet. + + Note that there may not be any switches in the subnet if + we are in simple p2p configuration. + */ + iteration_max = cl_qmap_count(p_sw_guid_tbl); + + /* + If there are switches in the subnet, iterate until the lid + matrix has been constructed. Otherwise, just immediately + indicate we're done if no switches exist. + */ + if (iteration_max) { + iteration_max--; + + /* + we need to find out when the propagation of + hop counts has relaxed. So this global variable + is preset to 0 on each iteration and if + if non of the switches was set will exit the + while loop + */ + p_mgr->some_hop_count_set = TRUE; + for (i = 0; (i < iteration_max) && p_mgr->some_hop_count_set; + i++) { + p_mgr->some_hop_count_set = FALSE; + cl_qmap_apply_func(p_sw_guid_tbl, + __osm_ucast_mgr_process_neighbors, + p_mgr); + } + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Min-hop propagated in %d steps\n", i); + } + + return 0; +} + +/********************************************************************** + **********************************************************************/ +static int ucast_mgr_setup_all_switches(osm_subn_t * p_subn) +{ + osm_switch_t *p_sw; + uint16_t lids; + + lids = (uint16_t) cl_ptr_vector_get_size(&p_subn->port_lid_tbl); + lids = lids ? lids - 1 : 0; + + for (p_sw = (osm_switch_t *) cl_qmap_head(&p_subn->sw_guid_tbl); + p_sw != (osm_switch_t *) cl_qmap_end(&p_subn->sw_guid_tbl); + p_sw = (osm_switch_t *) cl_qmap_next(&p_sw->map_item)) + if (osm_switch_prepare_path_rebuild(p_sw, lids)) { + OSM_LOG(&p_subn->p_osm->log, OSM_LOG_ERROR, "ERR 3A0B: " + "cannot setup switch 0x%016" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid + (p_sw->p_node))); + return -1; + } + + return 0; +} + +/********************************************************************** + **********************************************************************/ + +static int add_guid_to_order_list(void *ctx, uint64_t guid, char *p) +{ + osm_ucast_mgr_t *m = ctx; + osm_port_t *port = osm_get_port_by_guid(m->p_subn, cl_hton64(guid)); + + if (!port) { + OSM_LOG(m->p_log, OSM_LOG_DEBUG, + "port guid not found: 0x%016" PRIx64 "\n", guid); + return 0; + } + + if (port->flag) { + OSM_LOG(m->p_log, OSM_LOG_DEBUG, + "port guid specified multiple times 0x%016" PRIx64 "\n", + guid); + return 0; + } + + cl_qlist_insert_tail(&m->port_order_list, &port->list_item); + port->flag = 1; + + return 0; +} + +static void add_port_to_order_list(cl_map_item_t * const p_map_item, void *ctx) +{ + osm_port_t *port = (osm_port_t *)p_map_item; + osm_ucast_mgr_t *m = ctx; + + if (!port->flag) + cl_qlist_insert_tail(&m->port_order_list, &port->list_item); + else + port->flag = 0; +} + +static int mark_ignored_port(void *ctx, uint64_t guid, char *p) +{ + osm_ucast_mgr_t *m = ctx; + osm_node_t *node = osm_get_node_by_guid(m->p_subn, cl_hton64(guid)); + osm_physp_t *physp; + unsigned port; + + if (!node || !node->sw) { + OSM_LOG(m->p_log, OSM_LOG_DEBUG, + "switch with guid 0x%016" PRIx64 " is not found\n", + guid); + return 0; + } + + if (!p || !*p || !(port = strtoul(p, NULL, 0)) || + port >= node->sw->num_ports) { + OSM_LOG(m->p_log, OSM_LOG_DEBUG, + "bad port specified for guid 0x%016" PRIx64 "\n", guid); + return 0; + } + + physp = osm_node_get_physp_ptr(node, port); + if (!physp) + return 0; + + physp->is_prof_ignored = 1; + + return 0; +} + +static void clear_prof_ignore_flag(cl_map_item_t * const p_map_item, void *ctx) +{ + osm_switch_t *sw = (osm_switch_t *)p_map_item; + int i; + + for (i = 1; i < sw->num_ports; i++) { + osm_physp_t *p = osm_node_get_physp_ptr(sw->p_node, i); + if (p) + p->is_prof_ignored = 0; + } +} + +static int ucast_mgr_build_lfts(osm_ucast_mgr_t *p_mgr) +{ + cl_qlist_init(&p_mgr->port_order_list); + + if (p_mgr->p_subn->opt.guid_routing_order_file) { + OSM_LOG(p_mgr->p_log, OSM_LOG_DEBUG, + "Fetching guid routing order file \'%s\'\n", + p_mgr->p_subn->opt.guid_routing_order_file); + + if (parse_node_map(p_mgr->p_subn->opt.guid_routing_order_file, + add_guid_to_order_list, p_mgr)) + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR : " + "cannot parse guid routing order file \'%s\'\n", + p_mgr->p_subn->opt.guid_routing_order_file); + } + + if (p_mgr->p_subn->opt.port_prof_ignore_file) { + cl_qmap_apply_func(&p_mgr->p_subn->sw_guid_tbl, + clear_prof_ignore_flag, NULL); + if (parse_node_map(p_mgr->p_subn->opt.port_prof_ignore_file, + mark_ignored_port, p_mgr)) { + OSM_LOG(p_mgr->p_log, OSM_LOG_ERROR, "ERR : " + "cannot parse port prof ignore file \'%s\'\n", + p_mgr->p_subn->opt.port_prof_ignore_file); + } + } + + cl_qmap_apply_func(&p_mgr->p_subn->port_guid_tbl, + add_port_to_order_list, p_mgr); + + cl_qmap_apply_func(&p_mgr->p_subn->sw_guid_tbl, + __osm_ucast_mgr_process_tbl, p_mgr); + + cl_qlist_remove_all(&p_mgr->port_order_list); + + return 0; +} + +/********************************************************************** + **********************************************************************/ +static int ucast_mgr_route(struct osm_routing_engine *r, osm_opensm_t *osm) +{ + int ret; + + OSM_LOG(&osm->log, OSM_LOG_VERBOSE, + "building routing with \'%s\' routing algorithm...\n", r->name); + + if (!r->build_lid_matrices || + (ret = r->build_lid_matrices(r->context)) > 0) + ret = osm_ucast_mgr_build_lid_matrices(&osm->sm.ucast_mgr); + + if (ret < 0) { + OSM_LOG(&osm->log, OSM_LOG_ERROR, + "%s: cannot build lid matrices.\n", r->name); + return ret; + } + + if (!r->ucast_build_fwd_tables || + (ret = r->ucast_build_fwd_tables(r->context)) > 0) + ret = ucast_mgr_build_lfts(&osm->sm.ucast_mgr); + + if (ret < 0) { + OSM_LOG(&osm->log, OSM_LOG_ERROR, + "%s: cannot build fwd tables.\n", r->name); + return ret; + } + + osm->routing_engine_used = osm_routing_engine_type(r->name); + + return 0; +} + +int osm_ucast_mgr_process(IN osm_ucast_mgr_t * const p_mgr) +{ + osm_opensm_t *p_osm; + struct osm_routing_engine *p_routing_eng; + cl_qmap_t *p_sw_guid_tbl; + + OSM_LOG_ENTER(p_mgr->p_log); + + p_sw_guid_tbl = &p_mgr->p_subn->sw_guid_tbl; + p_osm = p_mgr->p_subn->p_osm; + p_routing_eng = p_osm->routing_engine_list; + + CL_PLOCK_EXCL_ACQUIRE(p_mgr->p_lock); + + /* + If there are no switches in the subnet, we are done. + */ + if (cl_qmap_count(p_sw_guid_tbl) == 0 || + ucast_mgr_setup_all_switches(p_mgr->p_subn) < 0) + goto Exit; + + p_osm->routing_engine_used = OSM_ROUTING_ENGINE_TYPE_NONE; + while (p_routing_eng) { + if (!ucast_mgr_route(p_routing_eng, p_osm)) + break; + p_routing_eng = p_routing_eng->next; + } + + if (p_osm->routing_engine_used == OSM_ROUTING_ENGINE_TYPE_NONE) { + /* If configured routing algorithm failed, use default MinHop */ + osm_ucast_mgr_build_lid_matrices(p_mgr); + ucast_mgr_build_lfts(p_mgr); + p_osm->routing_engine_used = OSM_ROUTING_ENGINE_TYPE_MINHOP; + } + + OSM_LOG(p_mgr->p_log, OSM_LOG_INFO, + "%s tables configured on all switches\n", + osm_routing_engine_type_str(p_osm->routing_engine_used)); + + if (p_mgr->p_subn->opt.use_ucast_cache) + p_mgr->cache_valid = TRUE; + +Exit: + CL_PLOCK_RELEASE(p_mgr->p_lock); + OSM_LOG_EXIT(p_mgr->p_log); + return 0; +} + +static int ucast_build_lid_matrices(void *context) +{ + return osm_ucast_mgr_build_lid_matrices(context); +} + +static int ucast_build_lfts(void *context) +{ + return ucast_mgr_build_lfts(context); +} + +int osm_ucast_minhop_setup(struct osm_routing_engine *r, osm_opensm_t *osm) +{ + r->context = &osm->sm.ucast_mgr; + r->build_lid_matrices = ucast_build_lid_matrices; + r->ucast_build_fwd_tables = ucast_build_lfts; + return 0; +} + +static int ucast_dor_build_lfts(void *context) +{ + osm_ucast_mgr_t *mgr = context; + int ret; + + mgr->is_dor = 1; + ret = ucast_mgr_build_lfts(mgr); + mgr->is_dor = 0; + + return ret; +} + +int osm_ucast_dor_setup(struct osm_routing_engine *r, osm_opensm_t *osm) +{ + r->context = &osm->sm.ucast_mgr; + r->build_lid_matrices = ucast_build_lid_matrices; + r->ucast_build_fwd_tables = ucast_dor_build_lfts; + return 0; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_ucast_updn.c b/contrib/ofed/management/opensm/opensm/osm_ucast_updn.c new file mode 100644 index 000000000000..bb9ccdafd83d --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_ucast_updn.c @@ -0,0 +1,686 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of Up Down Algorithm using ranking & Min Hop + * Calculation functions + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +/* //////////////////////////// */ +/* Local types */ +/* //////////////////////////// */ + +/* direction */ +typedef enum updn_switch_dir { + UP = 0, + DOWN +} updn_switch_dir_t; + +/* updn structure */ +typedef struct updn { + unsigned num_roots; + osm_opensm_t *p_osm; +} updn_t; + +struct updn_node { + cl_list_item_t list; + osm_switch_t *sw; + uint64_t id; + updn_switch_dir_t dir; + unsigned rank; + unsigned visited; +}; + +/********************************************************************** + **********************************************************************/ +/* This function returns direction based on rank and guid info of current & + remote ports */ +static updn_switch_dir_t updn_get_dir(unsigned cur_rank, unsigned rem_rank, + uint64_t cur_id, uint64_t rem_id) +{ + /* HACK: comes to solve root nodes connection, in a classic subnet root nodes do not connect + directly, but in case they are we assign to root node an UP direction to allow UPDN to discover + the subnet correctly (and not from the point of view of the last root node). + */ + if (!cur_rank && !rem_rank) + return UP; + + if (cur_rank < rem_rank) + return DOWN; + else if (cur_rank > rem_rank) + return UP; + else { + /* Equal rank, decide by id number, bigger == UP direction */ + if (cur_id > rem_id) + return UP; + else + return DOWN; + } +} + +/********************************************************************** + * This function does the bfs of min hop table calculation by guid index + * as a starting point. + **********************************************************************/ +static int updn_bfs_by_node(IN osm_log_t * p_log, IN osm_subn_t * p_subn, + IN osm_switch_t * p_sw) +{ + uint8_t pn, pn_rem; + cl_qlist_t list; + uint16_t lid; + struct updn_node *u; + updn_switch_dir_t next_dir, current_dir; + + OSM_LOG_ENTER(p_log); + + lid = osm_node_get_base_lid(p_sw->p_node, 0); + lid = cl_ntoh16(lid); + osm_switch_set_hops(p_sw, lid, 0, 0); + + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Starting from switch - port GUID 0x%" PRIx64 " lid %u\n", + cl_ntoh64(p_sw->p_node->node_info.port_guid), lid); + + u = p_sw->priv; + u->dir = UP; + + /* Update list with the new element */ + cl_qlist_init(&list); + cl_qlist_insert_tail(&list, &u->list); + + /* BFS the list till no next element */ + while (!cl_is_qlist_empty(&list)) { + u = (struct updn_node *)cl_qlist_remove_head(&list); + u->visited = 0; /* cleanup */ + current_dir = u->dir; + /* Go over all ports of the switch and find unvisited remote nodes */ + for (pn = 1; pn < u->sw->num_ports; pn++) { + osm_node_t *p_remote_node; + struct updn_node *rem_u; + uint8_t current_min_hop, remote_min_hop, + set_hop_return_value; + osm_switch_t *p_remote_sw; + + p_remote_node = + osm_node_get_remote_node(u->sw->p_node, pn, + &pn_rem); + /* If no remote node OR remote node is not a SWITCH + continue to next pn */ + if (!p_remote_node || !p_remote_node->sw) + continue; + /* Fetch remote guid only after validation of remote node */ + p_remote_sw = p_remote_node->sw; + rem_u = p_remote_sw->priv; + /* Decide which direction to mark it (UP/DOWN) */ + next_dir = updn_get_dir(u->rank, rem_u->rank, + u->id, rem_u->id); + + /* Check if this is a legal step : the only illegal step is going + from DOWN to UP */ + if ((current_dir == DOWN) && (next_dir == UP)) { + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Avoiding move from 0x%016" PRIx64 + " to 0x%016" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(u->sw->p_node)), + cl_ntoh64(osm_node_get_node_guid(p_remote_node))); + /* Illegal step */ + continue; + } + /* Set MinHop value for the current lid */ + current_min_hop = osm_switch_get_least_hops(u->sw, lid); + /* Check hop count if better insert into list && update + the remote node Min Hop Table */ + remote_min_hop = + osm_switch_get_hop_count(p_remote_sw, lid, pn_rem); + if (current_min_hop + 1 < remote_min_hop) { + set_hop_return_value = + osm_switch_set_hops(p_remote_sw, lid, + pn_rem, + current_min_hop + 1); + if (set_hop_return_value) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AA01: " + "Invalid value returned from set min hop is: %d\n", + set_hop_return_value); + } + /* Check if remote port has already been visited */ + if (!rem_u->visited) { + /* Insert updn_switch item into the list */ + rem_u->dir = next_dir; + rem_u->visited = 1; + cl_qlist_insert_tail(&list, + &rem_u->list); + } + } + } + } + + OSM_LOG_EXIT(p_log); + return 0; +} + +/********************************************************************** + **********************************************************************/ +/* NOTE : PLS check if we need to decide that the first */ +/* rank is a SWITCH for BFS purpose */ +static int updn_subn_rank(IN updn_t * p_updn) +{ + osm_switch_t *p_sw; + osm_physp_t *p_physp, *p_remote_physp; + cl_qlist_t list; + cl_map_item_t *item; + struct updn_node *u, *remote_u; + uint8_t num_ports, port_num; + osm_log_t *p_log = &p_updn->p_osm->log; + unsigned max_rank = 0; + + OSM_LOG_ENTER(p_log); + cl_qlist_init(&list); + + /* add all roots to the list */ + for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl); + item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl); + item = cl_qmap_next(item)) { + p_sw = (osm_switch_t *)item; + u = p_sw->priv; + if (!u->rank) + cl_qlist_insert_tail(&list, &u->list); + } + + /* BFS the list till it's empty */ + while (!cl_is_qlist_empty(&list)) { + u = (struct updn_node *)cl_qlist_remove_head(&list); + /* Go over all remote nodes and rank them (if not already visited) */ + p_sw = u->sw; + num_ports = p_sw->num_ports; + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Handling switch GUID 0x%" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node))); + for (port_num = 1; port_num < num_ports; port_num++) { + ib_net64_t port_guid; + + /* Current port fetched in order to get remote side */ + p_physp = + osm_node_get_physp_ptr(p_sw->p_node, port_num); + + if (!p_physp) + continue; + + p_remote_physp = p_physp->p_remote_physp; + + /* + make sure that all the following occur on p_remote_physp: + 1. The port isn't NULL + 2. It is a switch + */ + if (p_remote_physp && p_remote_physp->p_node->sw) { + remote_u = p_remote_physp->p_node->sw->priv; + port_guid = p_remote_physp->port_guid; + + if (remote_u->rank > u->rank + 1) { + remote_u->rank = u->rank + 1; + max_rank = remote_u->rank; + cl_qlist_insert_tail(&list, + &remote_u->list); + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Rank of port GUID 0x%" PRIx64 + " = %u\n", cl_ntoh64(port_guid), + remote_u->rank); + } + } + } + } + + /* Print Summary of ranking */ + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "Subnet ranking completed. Max Node Rank = %d\n", max_rank); + OSM_LOG_EXIT(p_log); + return 0; +} + +/********************************************************************** + **********************************************************************/ +/* hack: preserve min hops entries to any other root switches */ +static void updn_clear_root_hops(updn_t * p_updn, osm_switch_t * p_sw) +{ + osm_port_t *p_port; + unsigned i; + + for (i = 0; i < p_sw->num_hops; i++) + if (p_sw->hops[i]) { + p_port = + cl_ptr_vector_get(&p_updn->p_osm->subn.port_lid_tbl, + i); + if (!p_port || !p_port->p_node->sw + || ((struct updn_node *)p_port->p_node->sw->priv)-> + rank != 0) + memset(p_sw->hops[i], 0xff, p_sw->num_ports); + } +} + +/********************************************************************** + **********************************************************************/ +static int updn_set_min_hop_table(IN updn_t * p_updn) +{ + osm_subn_t *p_subn = &p_updn->p_osm->subn; + osm_log_t *p_log = &p_updn->p_osm->log; + osm_switch_t *p_sw; + cl_map_item_t *item; + + OSM_LOG_ENTER(p_log); + + /* Go over all the switches in the subnet - for each init their Min Hop + Table */ + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "Init Min Hop Table of all switches [\n"); + + for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl); + item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl); + item = cl_qmap_next(item)) { + p_sw = (osm_switch_t *)item; + /* Clear Min Hop Table */ + if (p_subn->opt.connect_roots) + updn_clear_root_hops(p_updn, p_sw); + else + osm_switch_clear_hops(p_sw); + } + + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "Init Min Hop Table of all switches ]\n"); + + /* Now do the BFS for each port in the subnet */ + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "BFS through all port guids in the subnet [\n"); + + for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl); + item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl); + item = cl_qmap_next(item)) { + p_sw = (osm_switch_t *)item; + updn_bfs_by_node(p_log, p_subn, p_sw); + } + + OSM_LOG(p_log, OSM_LOG_VERBOSE, + "BFS through all port guids in the subnet ]\n"); + /* Cleanup */ + OSM_LOG_EXIT(p_log); + return 0; +} + +/********************************************************************** + **********************************************************************/ +static int updn_build_lid_matrices(IN updn_t * p_updn) +{ + int status; + + OSM_LOG_ENTER(&p_updn->p_osm->log); + + OSM_LOG(&p_updn->p_osm->log, OSM_LOG_VERBOSE, + "Ranking all port guids in the list\n"); + if (!p_updn->num_roots) { + OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AA0A: " + "No guids were provided or number of guids is 0\n"); + status = -1; + goto _exit; + } + + /* Check if it's not a switched subnet */ + if (cl_is_qmap_empty(&p_updn->p_osm->subn.sw_guid_tbl)) { + OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR AAOB: " + "This is not a switched subnet, cannot perform UPDN algorithm\n"); + status = -1; + goto _exit; + } + + /* Rank the subnet switches */ + updn_subn_rank(p_updn); + + /* After multiple ranking need to set Min Hop Table by UpDn algorithm */ + OSM_LOG(&p_updn->p_osm->log, OSM_LOG_VERBOSE, + "Setting all switches' Min Hop Table\n"); + status = updn_set_min_hop_table(p_updn); + +_exit: + OSM_LOG_EXIT(&p_updn->p_osm->log); + return status; +} + +/********************************************************************** + **********************************************************************/ +static struct updn_node *create_updn_node(osm_switch_t * sw) +{ + struct updn_node *u; + + u = malloc(sizeof(*u)); + if (!u) + return NULL; + memset(u, 0, sizeof(*u)); + u->sw = sw; + u->id = cl_ntoh64(osm_node_get_node_guid(sw->p_node)); + u->rank = 0xffffffff; + return u; +} + +static void delete_updn_node(struct updn_node *u) +{ + u->sw->priv = NULL; + free(u); +} + +/********************************************************************** + **********************************************************************/ +/* Find Root nodes automatically by Min Hop Table info */ +static void updn_find_root_nodes_by_min_hop(OUT updn_t * p_updn) +{ + osm_opensm_t *p_osm = p_updn->p_osm; + osm_switch_t *p_sw; + osm_port_t *p_port; + osm_physp_t *p_physp; + cl_map_item_t *item; + double thd1, thd2; + unsigned i, cas_num = 0; + unsigned *cas_per_sw; + uint16_t lid_ho; + + OSM_LOG_ENTER(&p_osm->log); + + OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, + "Current number of ports in the subnet is %d\n", + cl_qmap_count(&p_osm->subn.port_guid_tbl)); + + cas_per_sw = malloc((IB_LID_UCAST_END_HO + 1) * sizeof(*cas_per_sw)); + if (!cas_per_sw) { + OSM_LOG(&p_osm->log, OSM_LOG_ERROR, "ERR AA14: " + "cannot alloc mem for CAs per switch counter array\n"); + goto _exit; + } + memset(cas_per_sw, 0, (IB_LID_UCAST_END_HO + 1) * sizeof(*cas_per_sw)); + + /* Find the Maximum number of CAs (and routers) for histogram normalization */ + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "Finding the number of CAs and storing them in cl_map\n"); + for (item = cl_qmap_head(&p_updn->p_osm->subn.port_guid_tbl); + item != cl_qmap_end(&p_updn->p_osm->subn.port_guid_tbl); + item = cl_qmap_next(item)) { + p_port = (osm_port_t *)item; + if (!p_port->p_node->sw) { + p_physp = p_port->p_physp->p_remote_physp; + if (!p_physp || !p_physp->p_node->sw) + continue; + lid_ho = osm_node_get_base_lid(p_physp->p_node, 0); + lid_ho = cl_ntoh16(lid_ho); + cas_per_sw[lid_ho]++; + cas_num++; + } + } + + thd1 = cas_num * 0.9; + thd2 = cas_num * 0.05; + OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, + "Found %u CAs and RTRs, %u SWs in the subnet. " + "Thresholds are thd1 = %f && thd2 = %f\n", + cas_num, cl_qmap_count(&p_osm->subn.sw_guid_tbl), thd1, thd2); + + OSM_LOG(&p_osm->log, OSM_LOG_VERBOSE, + "Passing through all switches to collect Min Hop info\n"); + for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl); + item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl); + item = cl_qmap_next(item)) { + unsigned hop_hist[IB_SUBNET_PATH_HOPS_MAX]; + uint16_t max_lid_ho; + uint8_t hop_val; + uint16_t numHopBarsOverThd1 = 0; + uint16_t numHopBarsOverThd2 = 0; + + p_sw = (osm_switch_t *) item; + + memset(hop_hist, 0, sizeof(hop_hist)); + + max_lid_ho = p_sw->max_lid_ho; + for (lid_ho = 1; lid_ho <= max_lid_ho; lid_ho++) + if (cas_per_sw[lid_ho]) { + hop_val = + osm_switch_get_least_hops(p_sw, lid_ho); + if (hop_val >= IB_SUBNET_PATH_HOPS_MAX) + continue; + + hop_hist[hop_val] += cas_per_sw[lid_ho]; + } + + /* Now recognize the spines by requiring one bar to be + above 90% of the number of CAs and RTRs */ + for (i = 0; i < IB_SUBNET_PATH_HOPS_MAX; i++) { + if (hop_hist[i] > thd1) + numHopBarsOverThd1++; + if (hop_hist[i] > thd2) + numHopBarsOverThd2++; + } + + /* If thd conditions are valid - rank the root node */ + if (numHopBarsOverThd1 == 1 && numHopBarsOverThd2 == 1) { + OSM_LOG(&p_osm->log, OSM_LOG_DEBUG, + "Ranking GUID 0x%" PRIx64 " as root node\n", + cl_ntoh64(osm_node_get_node_guid(p_sw->p_node))); + ((struct updn_node *)p_sw->priv)->rank = 0; + p_updn->num_roots++; + } + } + + free(cas_per_sw); +_exit: + OSM_LOG_EXIT(&p_osm->log); + return; +} + +/********************************************************************** + **********************************************************************/ +static void dump_roots(cl_map_item_t *item, FILE *file, void *cxt) +{ + osm_switch_t *sw = (osm_switch_t *)item; + if (!((struct updn_node *)sw->priv)->rank) + fprintf(file, "0x%" PRIx64 "\n", + cl_ntoh64(osm_node_get_node_guid(sw->p_node))); +} + +static int update_id(void *cxt, uint64_t guid, char *p) +{ + osm_opensm_t *osm = cxt; + osm_switch_t *sw; + uint64_t id; + char *e; + + sw = osm_get_switch_by_guid(&osm->subn, cl_hton64(guid)); + if (!sw) { + OSM_LOG(&osm->log, OSM_LOG_VERBOSE, + "switch with guid 0x%" PRIx64 " is not found\n", guid); + return 0; + } + + id = strtoull(p, &e, 0); + if (*e && !isspace(*e)) { + OSM_LOG(&osm->log, OSM_LOG_ERROR, + "ERR: cannot parse node id \'%s\'", p); + return -1; + } + + OSM_LOG(&osm->log, OSM_LOG_DEBUG, + "update node 0x%" PRIx64 " id to 0x%" PRIx64 "\n", guid, id); + + ((struct updn_node *)sw->priv)->id = id; + + return 0; +} + +static int rank_root_node(void *cxt, uint64_t guid, char *p) +{ + updn_t *updn = cxt; + osm_switch_t *sw; + + sw = osm_get_switch_by_guid(&updn->p_osm->subn, cl_hton64(guid)); + if (!sw) { + OSM_LOG(&updn->p_osm->log, OSM_LOG_VERBOSE, + "switch with guid 0x%" PRIx64 " is not found\n", guid); + return 0; + } + + OSM_LOG(&updn->p_osm->log, OSM_LOG_DEBUG, + "Ranking root port GUID 0x%" PRIx64 "\n", guid); + + ((struct updn_node *)sw->priv)->rank = 0; + updn->num_roots++; + + return 0; +} + +/* UPDN callback function */ +static int updn_lid_matrices(void *ctx) +{ + updn_t *p_updn = ctx; + cl_map_item_t *item; + osm_switch_t *p_sw; + int ret = 0; + + OSM_LOG_ENTER(&p_updn->p_osm->log); + + for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl); + item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl); + item = cl_qmap_next(item)) { + p_sw = (osm_switch_t *)item; + p_sw->priv = create_updn_node(p_sw); + if (!p_sw->priv) { + OSM_LOG(&(p_updn->p_osm->log), OSM_LOG_ERROR, "ERR AA0C: " + "cannot create updn node\n"); + OSM_LOG_EXIT(&p_updn->p_osm->log); + return -1; + } + } + + /* First setup root nodes */ + p_updn->num_roots = 0; + + if (p_updn->p_osm->subn.opt.root_guid_file) { + OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG, + "UPDN - Fetching root nodes from file \'%s\'\n", + p_updn->p_osm->subn.opt.root_guid_file); + + ret = parse_node_map(p_updn->p_osm->subn.opt.root_guid_file, + rank_root_node, p_updn); + if (ret) + OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR : " + "cannot parse root guids file \'%s\'\n", + p_updn->p_osm->subn.opt.root_guid_file); + if (p_updn->p_osm->subn.opt.connect_roots && + p_updn->num_roots > 1) + osm_ucast_mgr_build_lid_matrices(&p_updn->p_osm->sm.ucast_mgr); + } else { + osm_ucast_mgr_build_lid_matrices(&p_updn->p_osm->sm.ucast_mgr); + updn_find_root_nodes_by_min_hop(p_updn); + } + + if (p_updn->p_osm->subn.opt.ids_guid_file) { + OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG, + "UPDN - update node ids from file \'%s\'\n", + p_updn->p_osm->subn.opt.ids_guid_file); + + ret = parse_node_map(p_updn->p_osm->subn.opt.ids_guid_file, + update_id, p_updn->p_osm); + if (ret) + OSM_LOG(&p_updn->p_osm->log, OSM_LOG_ERROR, "ERR : " + "cannot parse node ids file \'%s\'\n", + p_updn->p_osm->subn.opt.ids_guid_file); + } + + /* Only if there are assigned root nodes do the algorithm, otherwise perform do nothing */ + if (p_updn->num_roots) { + OSM_LOG(&p_updn->p_osm->log, OSM_LOG_DEBUG, + "activating UPDN algorithm\n"); + ret = updn_build_lid_matrices(p_updn); + } else { + OSM_LOG(&p_updn->p_osm->log, OSM_LOG_INFO, + "disabling UPDN algorithm, no root nodes were found\n"); + ret = -1; + } + + if (osm_log_is_active(&p_updn->p_osm->log, OSM_LOG_ROUTING)) + osm_dump_qmap_to_file(p_updn->p_osm, "opensm-updn-roots.dump", + &p_updn->p_osm->subn.sw_guid_tbl, + dump_roots, NULL); + + for (item = cl_qmap_head(&p_updn->p_osm->subn.sw_guid_tbl); + item != cl_qmap_end(&p_updn->p_osm->subn.sw_guid_tbl); + item = cl_qmap_next(item)) { + p_sw = (osm_switch_t *) item; + delete_updn_node(p_sw->priv); + } + + OSM_LOG_EXIT(&p_updn->p_osm->log); + return ret; +} + +/********************************************************************** + **********************************************************************/ +static void updn_delete(void *context) +{ + free(context); +} + +int osm_ucast_updn_setup(struct osm_routing_engine *r, osm_opensm_t *osm) +{ + updn_t *updn; + + updn = malloc(sizeof(updn_t)); + if (!updn) + return -1; + memset(updn, 0, sizeof(updn_t)); + + updn->p_osm = osm; + + r->context = updn; + r->delete = updn_delete; + r->build_lid_matrices = updn_lid_matrices; + + return 0; +} diff --git a/contrib/ofed/management/opensm/opensm/osm_vl15intf.c b/contrib/ofed/management/opensm/opensm/osm_vl15intf.c new file mode 100644 index 000000000000..0703a4f6f08b --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_vl15intf.c @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_vl15_t. + * This object represents the VL15 Interface object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ + +static void vl15_send_mad(osm_vl15_t * p_vl, osm_madw_t * p_madw) +{ + ib_api_status_t status; + + /* + Non-response-expected mads are not throttled on the wire + since we can have no confirmation that they arrived + at their destination. + */ + if (p_madw->resp_expected == TRUE) + /* + Note that other threads may not see the response MAD + arrive before send() even returns. + In that case, the wire count would temporarily go negative. + To avoid this confusion, preincrement the counts on the + assumption that send() will succeed. + */ + cl_atomic_inc(&p_vl->p_stats->qp0_mads_outstanding_on_wire); + else + cl_atomic_inc(&p_vl->p_stats->qp0_unicasts_sent); + + cl_atomic_inc(&p_vl->p_stats->qp0_mads_sent); + + status = osm_vendor_send(osm_madw_get_bind_handle(p_madw), + p_madw, p_madw->resp_expected); + + if (status == IB_SUCCESS) { + OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG, + "%u QP0 MADs on wire, %u outstanding, " + "%u unicasts sent, %u total sent\n", + p_vl->p_stats->qp0_mads_outstanding_on_wire, + p_vl->p_stats->qp0_mads_outstanding, + p_vl->p_stats->qp0_unicasts_sent, + p_vl->p_stats->qp0_mads_sent); + return; + } + + OSM_LOG(p_vl->p_log, OSM_LOG_ERROR, "ERR 3E03: " + "MAD send failed (%s)\n", ib_get_err_str(status)); + + /* + The MAD was never successfully sent, so + fix up the pre-incremented count values. + */ + + /* Decrement qp0_mads_sent that were incremented in the code above. + qp0_mads_outstanding will be decremented by send error callback + (called by osm_vendor_send() */ + cl_atomic_dec(&p_vl->p_stats->qp0_mads_sent); + if (!p_madw->resp_expected) + cl_atomic_dec(&p_vl->p_stats->qp0_unicasts_sent); +} + +static void __osm_vl15_poller(IN void *p_ptr) +{ + ib_api_status_t status; + osm_madw_t *p_madw; + osm_vl15_t *const p_vl = (osm_vl15_t *) p_ptr; + cl_qlist_t *p_fifo; + + OSM_LOG_ENTER(p_vl->p_log); + + if (p_vl->thread_state == OSM_THREAD_STATE_NONE) + p_vl->thread_state = OSM_THREAD_STATE_RUN; + + while (p_vl->thread_state == OSM_THREAD_STATE_RUN) { + /* + Start servicing the FIFOs by pulling off MAD wrappers + and passing them to the transport interface. + There are lots of corner cases here so tread carefully. + + The unicast FIFO has priority, since somebody is waiting + for a timely response. + */ + cl_spinlock_acquire(&p_vl->lock); + + if (cl_qlist_count(&p_vl->ufifo) != 0) + p_fifo = &p_vl->ufifo; + else + p_fifo = &p_vl->rfifo; + + p_madw = (osm_madw_t *) cl_qlist_remove_head(p_fifo); + + cl_spinlock_release(&p_vl->lock); + + if (p_madw != (osm_madw_t *) cl_qlist_end(p_fifo)) { + OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG, + "Servicing p_madw = %p\n", p_madw); + if (osm_log_is_active(p_vl->p_log, OSM_LOG_FRAMES)) + osm_dump_dr_smp(p_vl->p_log, + osm_madw_get_smp_ptr(p_madw), + OSM_LOG_FRAMES); + + vl15_send_mad(p_vl, p_madw); + } else + /* + The VL15 FIFO is empty, so we have nothing left to do. + */ + status = cl_event_wait_on(&p_vl->signal, + EVENT_NO_TIMEOUT, TRUE); + + while ((p_vl->p_stats->qp0_mads_outstanding_on_wire >= + (int32_t) p_vl->max_wire_smps) && + (p_vl->thread_state == OSM_THREAD_STATE_RUN)) { + status = cl_event_wait_on(&p_vl->signal, + EVENT_NO_TIMEOUT, TRUE); + if (status != CL_SUCCESS) { + OSM_LOG(p_vl->p_log, OSM_LOG_ERROR, "ERR 3E02: " + "Event wait failed (%s)\n", + CL_STATUS_MSG(status)); + break; + } + } + } + + /* + since we abort immediately when the state != OSM_THREAD_STATE_RUN + we might have some mads on the queues. After the thread exits + the vl15 destroy routine should put these mads back... + */ + + OSM_LOG_EXIT(p_vl->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_vl15_construct(IN osm_vl15_t * const p_vl) +{ + memset(p_vl, 0, sizeof(*p_vl)); + p_vl->state = OSM_VL15_STATE_INIT; + p_vl->thread_state = OSM_THREAD_STATE_NONE; + cl_event_construct(&p_vl->signal); + cl_spinlock_construct(&p_vl->lock); + cl_qlist_init(&p_vl->rfifo); + cl_qlist_init(&p_vl->ufifo); + cl_thread_construct(&p_vl->poller); +} + +/********************************************************************** + **********************************************************************/ +void +osm_vl15_destroy(IN osm_vl15_t * const p_vl, IN struct osm_mad_pool *p_pool) +{ + osm_madw_t *p_madw; + + OSM_LOG_ENTER(p_vl->p_log); + + /* + Signal our threads that we're leaving. + */ + p_vl->thread_state = OSM_THREAD_STATE_EXIT; + + /* + Don't trigger unless event has been initialized. + Destroy the thread before we tear down the other objects. + */ + if (p_vl->state != OSM_VL15_STATE_INIT) + cl_event_signal(&p_vl->signal); + + cl_thread_destroy(&p_vl->poller); + + /* + Return the outstanding messages to the pool + */ + + cl_spinlock_acquire(&p_vl->lock); + + while (!cl_is_qlist_empty(&p_vl->rfifo)) { + p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo); + osm_mad_pool_put(p_pool, p_madw); + } + while (!cl_is_qlist_empty(&p_vl->ufifo)) { + p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo); + osm_mad_pool_put(p_pool, p_madw); + } + + cl_spinlock_release(&p_vl->lock); + + cl_event_destroy(&p_vl->signal); + p_vl->state = OSM_VL15_STATE_INIT; + cl_spinlock_destroy(&p_vl->lock); + + OSM_LOG_EXIT(p_vl->p_log); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osm_vl15_init(IN osm_vl15_t * const p_vl, + IN osm_vendor_t * const p_vend, + IN osm_log_t * const p_log, + IN osm_stats_t * const p_stats, IN const int32_t max_wire_smps) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + p_vl->p_vend = p_vend; + p_vl->p_log = p_log; + p_vl->p_stats = p_stats; + p_vl->max_wire_smps = max_wire_smps; + + status = cl_event_init(&p_vl->signal, FALSE); + if (status != IB_SUCCESS) + goto Exit; + + p_vl->state = OSM_VL15_STATE_READY; + + status = cl_spinlock_init(&p_vl->lock); + if (status != IB_SUCCESS) + goto Exit; + + /* + Initialize the thread after all other dependent objects + have been initialized. + */ + status = cl_thread_init(&p_vl->poller, __osm_vl15_poller, p_vl, + "opensm poller"); + if (status != IB_SUCCESS) + goto Exit; + +Exit: + OSM_LOG_EXIT(p_log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +void osm_vl15_poll(IN osm_vl15_t * const p_vl) +{ + OSM_LOG_ENTER(p_vl->p_log); + + CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY); + + /* + If we have room for more VL15 MADs on the wire, + then signal the poller thread. + + This is not an airtight check, since the poller thread + could be just about to send another MAD as we signal + the event here. To cover this rare case, the poller + thread checks for a spurious wake-up. + */ + if (p_vl->p_stats->qp0_mads_outstanding_on_wire < + (int32_t) p_vl->max_wire_smps) { + OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG, + "Signalling poller thread\n"); + cl_event_signal(&p_vl->signal); + } + + OSM_LOG_EXIT(p_vl->p_log); +} + +/********************************************************************** + **********************************************************************/ +void osm_vl15_post(IN osm_vl15_t * const p_vl, IN osm_madw_t * const p_madw) +{ + OSM_LOG_ENTER(p_vl->p_log); + + CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY); + + OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG, "Posting p_madw = 0x%p\n", p_madw); + + /* + Determine in which fifo to place the pending madw. + */ + cl_spinlock_acquire(&p_vl->lock); + if (p_madw->resp_expected == TRUE) { + cl_qlist_insert_tail(&p_vl->rfifo, &p_madw->list_item); + osm_stats_inc_qp0_outstanding(p_vl->p_stats); + } else + cl_qlist_insert_tail(&p_vl->ufifo, &p_madw->list_item); + cl_spinlock_release(&p_vl->lock); + + OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG, + "%u QP0 MADs on wire, %u QP0 MADs outstanding\n", + p_vl->p_stats->qp0_mads_outstanding_on_wire, + p_vl->p_stats->qp0_mads_outstanding); + + osm_vl15_poll(p_vl); + + OSM_LOG_EXIT(p_vl->p_log); +} + +void +osm_vl15_shutdown(IN osm_vl15_t * const p_vl, + IN osm_mad_pool_t * const p_mad_pool) +{ + osm_madw_t *p_madw; + + OSM_LOG_ENTER(p_vl->p_log); + + /* we only should get here after the VL15 interface was initialized */ + CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY); + + /* grap a lock on the object */ + cl_spinlock_acquire(&p_vl->lock); + + /* go over all outstanding MADs and retire their transactions */ + + /* first we handle the list of response MADs */ + p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo); + while (p_madw != (osm_madw_t *) cl_qlist_end(&p_vl->ufifo)) { + OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG, + "Releasing Response p_madw = %p\n", p_madw); + + osm_mad_pool_put(p_mad_pool, p_madw); + + p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo); + } + + /* Request MADs we send out */ + p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo); + while (p_madw != (osm_madw_t *) cl_qlist_end(&p_vl->rfifo)) { + OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG, + "Releasing Request p_madw = %p\n", p_madw); + + osm_mad_pool_put(p_mad_pool, p_madw); + osm_stats_dec_qp0_outstanding(p_vl->p_stats); + + p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo); + } + + /* free the lock */ + cl_spinlock_release(&p_vl->lock); + + OSM_LOG_EXIT(p_vl->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/osm_vl_arb_rcv.c b/contrib/ofed/management/opensm/opensm/osm_vl_arb_rcv.c new file mode 100644 index 000000000000..ec04d677ec41 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/osm_vl_arb_rcv.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of osm_vla_rcv_t. + * This object represents the Vl Arbitration Receiver object. + * This object is part of the opensm family of objects. + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + **********************************************************************/ +/* + * WE MIGHT ONLY RECEIVE GET or SET responses + */ +void osm_vla_rcv_process(IN void *context, IN void *data) +{ + osm_sm_t *sm = context; + osm_madw_t *p_madw = data; + ib_vl_arb_table_t *p_vla_tbl; + ib_smp_t *p_smp; + osm_port_t *p_port; + osm_physp_t *p_physp; + osm_node_t *p_node; + osm_vla_context_t *p_context; + ib_net64_t port_guid; + ib_net64_t node_guid; + uint8_t port_num, block_num; + + CL_ASSERT(sm); + + OSM_LOG_ENTER(sm->p_log); + + CL_ASSERT(p_madw); + + p_smp = osm_madw_get_smp_ptr(p_madw); + + p_context = osm_madw_get_vla_context_ptr(p_madw); + p_vla_tbl = (ib_vl_arb_table_t *) ib_smp_get_payload_ptr(p_smp); + + port_guid = p_context->port_guid; + node_guid = p_context->node_guid; + + CL_ASSERT(p_smp->attr_id == IB_MAD_ATTR_VL_ARBITRATION); + + cl_plock_excl_acquire(sm->p_lock); + p_port = osm_get_port_by_guid(sm->p_subn, port_guid); + if (!p_port) { + cl_plock_release(sm->p_lock); + OSM_LOG(sm->p_log, OSM_LOG_ERROR, "ERR 3F06: " + "No port object for port with GUID 0x%" PRIx64 + "\n\t\t\t\tfor parent node GUID 0x%" PRIx64 + ", TID 0x%" PRIx64 "\n", + cl_ntoh64(port_guid), + cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); + goto Exit; + } + + p_node = p_port->p_node; + CL_ASSERT(p_node); + + block_num = (uint8_t) (cl_ntoh32(p_smp->attr_mod) >> 16); + /* in case of a non switch node the attr modifier should be ignored */ + if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) { + port_num = (uint8_t) (cl_ntoh32(p_smp->attr_mod) & 0x000000FF); + p_physp = osm_node_get_physp_ptr(p_node, port_num); + } else { + p_physp = p_port->p_physp; + port_num = p_physp->port_num; + } + + /* + We do not mind if this is a result of a set or get - all we want is to update + the subnet. + */ + OSM_LOG(sm->p_log, OSM_LOG_VERBOSE, + "Got GetResp(VLArb) block:%u port_num %u with GUID 0x%" + PRIx64 " for parent node GUID 0x%" PRIx64 ", TID 0x%" + PRIx64 "\n", block_num, port_num, cl_ntoh64(port_guid), + cl_ntoh64(node_guid), cl_ntoh64(p_smp->trans_id)); + + /* + Determine if we encountered a new Physical Port. + If so, Ignore it. + */ + if (!p_physp) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "Got invalid port number %u\n", port_num); + goto Exit; + } + + osm_dump_vl_arb_table(sm->p_log, + port_guid, block_num, + port_num, p_vla_tbl, OSM_LOG_DEBUG); + + if ((block_num < 1) || (block_num > 4)) { + OSM_LOG(sm->p_log, OSM_LOG_ERROR, + "Got invalid block number 0x%X\n", block_num); + goto Exit; + } + osm_physp_set_vla_tbl(p_physp, p_vla_tbl, block_num); + +Exit: + cl_plock_release(sm->p_lock); + + OSM_LOG_EXIT(sm->p_log); +} diff --git a/contrib/ofed/management/opensm/opensm/st.c b/contrib/ofed/management/opensm/opensm/st.c new file mode 100644 index 000000000000..c5a2f537a9f9 --- /dev/null +++ b/contrib/ofed/management/opensm/opensm/st.c @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#ifdef _WIN32 +#include +#endif + +typedef struct st_table_entry st_table_entry; + +struct st_table_entry { + unsigned int hash; + st_data_t key; + st_data_t record; + st_table_entry *next; +}; + +#define ST_DEFAULT_MAX_DENSITY 5 +#define ST_DEFAULT_INIT_TABLE_SIZE 11 + +/* + * DEFAULT_MAX_DENSITY is the default for the largest we allow the + * average number of items per bin before increasing the number of + * bins + * + * DEFAULT_INIT_TABLE_SIZE is the default for the number of bins + * allocated initially + * + */ +static int numcmp(void *, void *); +static st_ptr_t numhash(void *); +static struct st_hash_type type_numhash = { + numcmp, + numhash, +}; + +/* extern int strcmp(const char *, const char *); */ +static int strhash(const char *); + +static inline st_ptr_t st_strhash(void *key) +{ + return strhash((const char *)key); +} + +static inline int st_strcmp(void *key1, void *key2) +{ + return strcmp((const char *)key1, (const char *)key2); +} + +static struct st_hash_type type_strhash = { + st_strcmp, + st_strhash +}; + +#define xmalloc malloc +#define xcalloc calloc +#define xrealloc realloc +#define xfree free + +static void rehash(st_table *); + +#define alloc(type) (type*)xmalloc(sizeof(type)) +#define Calloc(n,s) (char*)xcalloc((n), (s)) + +#define EQUAL(table,x,y) ((x)==(y) || (*table->type->compare)(((void*)x),((void *)y)) == 0) + +#define do_hash(key,table) (unsigned int)(*(table)->type->hash)(((void*)key)) +#define do_hash_bin(key,table) (do_hash(key, table)%(table)->num_bins) + +/* + * MINSIZE is the minimum size of a dictionary. + */ + +#define MINSIZE 8 + +/* + Table of prime numbers 2^n+a, 2<=n<=30. +*/ +static long primes[] = { + 8 + 3, + 16 + 3, + 32 + 5, + 64 + 3, + 128 + 3, + 256 + 27, + 512 + 9, + 1024 + 9, + 2048 + 5, + 4096 + 3, + 8192 + 27, + 16384 + 43, + 32768 + 3, + 65536 + 45, + 131072 + 29, + 262144 + 3, + 524288 + 21, + 1048576 + 7, + 2097152 + 17, + 4194304 + 15, + 8388608 + 9, + 16777216 + 43, + 33554432 + 35, + 67108864 + 15, + 134217728 + 29, + 268435456 + 3, + 536870912 + 11, + 1073741824 + 85, + 0 +}; + +static int new_size(int size) +{ + int i; + +#if 0 + for (i = 3; i < 31; i++) { + if ((1 << i) > size) + return 1 << i; + } + return -1; +#else + int newsize; + + for (i = 0, newsize = MINSIZE; + i < sizeof(primes) / sizeof(primes[0]); i++, newsize <<= 1) { + if (newsize > size) + return primes[i]; + } + /* Ran out of polynomials */ + return -1; /* should raise exception */ +#endif +} + +#ifdef HASH_LOG +static int collision = 0; +static int init_st = 0; + +static void stat_col() +{ + FILE *f = fopen("/var/log/osm_st_col", "w"); + fprintf(f, "collision: %d\n", collision); + fclose(f); +} +#endif + +st_table *st_init_table_with_size(type, size) +struct st_hash_type *type; +size_t size; +{ + st_table *tbl; + +#ifdef HASH_LOG + if (init_st == 0) { + init_st = 1; + atexit(stat_col); + } +#endif + + size = new_size(size); /* round up to prime number */ + + tbl = alloc(st_table); + tbl->type = type; + tbl->num_entries = 0; + tbl->num_bins = size; + tbl->bins = (st_table_entry **) Calloc(size, sizeof(st_table_entry *)); + + return tbl; +} + +st_table *st_init_table(type) +struct st_hash_type *type; +{ + return st_init_table_with_size(type, 0); +} + +st_table *st_init_numtable(void) +{ + return st_init_table(&type_numhash); +} + +st_table *st_init_numtable_with_size(size) +size_t size; +{ + return st_init_table_with_size(&type_numhash, size); +} + +st_table *st_init_strtable(void) +{ + return st_init_table(&type_strhash); +} + +st_table *st_init_strtable_with_size(size) +size_t size; +{ + return st_init_table_with_size(&type_strhash, size); +} + +void st_free_table(table) +st_table *table; +{ + register st_table_entry *ptr, *next; + int i; + + for (i = 0; i < table->num_bins; i++) { + ptr = table->bins[i]; + while (ptr != 0) { + next = ptr->next; + free(ptr); + ptr = next; + } + } + free(table->bins); + free(table); +} + +#define PTR_NOT_EQUAL(table, ptr, hash_val, key) \ +((ptr) != 0 && (ptr->hash != (hash_val) || !EQUAL((table), (key), (ptr)->key))) + +#ifdef HASH_LOG +#define COLLISION collision++ +#else +#define COLLISION +#endif + +#define FIND_ENTRY(table, ptr, hash_val, bin_pos) do {\ + bin_pos = hash_val%(table)->num_bins;\ + ptr = (table)->bins[bin_pos];\ + if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) \ + {\ + COLLISION;\ + while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {\ + ptr = ptr->next;\ + }\ + ptr = ptr->next;\ + }\ +} while (0) + +int st_lookup(table, key, value) +st_table *table; +register st_data_t key; +st_data_t *value; +{ + unsigned int hash_val, bin_pos; + register st_table_entry *ptr; + + hash_val = do_hash(key, table); + FIND_ENTRY(table, ptr, hash_val, bin_pos); + + if (ptr == 0) { + return 0; + } else { + if (value != 0) + *value = ptr->record; + return 1; + } +} + +#define ADD_DIRECT(table, key, value, hash_val, bin_pos)\ +do {\ + st_table_entry *entry;\ + if (table->num_entries/(table->num_bins) > ST_DEFAULT_MAX_DENSITY) \ + {\ + rehash(table);\ + bin_pos = hash_val % table->num_bins;\ + }\ + \ + entry = alloc(st_table_entry);\ + \ + entry->hash = hash_val;\ + entry->key = key;\ + entry->record = value;\ + entry->next = table->bins[bin_pos];\ + table->bins[bin_pos] = entry;\ + table->num_entries++;\ +} while (0); + +int st_insert(table, key, value) +register st_table *table; +register st_data_t key; +st_data_t value; +{ + unsigned int hash_val, bin_pos; + register st_table_entry *ptr; + + hash_val = do_hash(key, table); + FIND_ENTRY(table, ptr, hash_val, bin_pos); + + if (ptr == 0) { + ADD_DIRECT(table, key, value, hash_val, bin_pos); + return 0; + } else { + ptr->record = value; + return 1; + } +} + +void st_add_direct(table, key, value) +st_table *table; +st_data_t key; +st_data_t value; +{ + unsigned int hash_val, bin_pos; + + hash_val = do_hash(key, table); + bin_pos = hash_val % table->num_bins; + ADD_DIRECT(table, key, value, hash_val, bin_pos); +} + +static void rehash(table) +register st_table *table; +{ + register st_table_entry *ptr, *next, **new_bins; + int i, old_num_bins = table->num_bins, new_num_bins; + unsigned int hash_val; + + new_num_bins = new_size(old_num_bins + 1); + new_bins = + (st_table_entry **) Calloc(new_num_bins, sizeof(st_table_entry *)); + + for (i = 0; i < old_num_bins; i++) { + ptr = table->bins[i]; + while (ptr != 0) { + next = ptr->next; + hash_val = ptr->hash % new_num_bins; + ptr->next = new_bins[hash_val]; + new_bins[hash_val] = ptr; + ptr = next; + } + } + free(table->bins); + table->num_bins = new_num_bins; + table->bins = new_bins; +} + +st_table *st_copy(old_table) +st_table *old_table; +{ + st_table *new_table; + st_table_entry *ptr, *entry; + size_t i, num_bins = old_table->num_bins; + + new_table = alloc(st_table); + if (new_table == 0) { + return 0; + } + + *new_table = *old_table; + new_table->bins = (st_table_entry **) + Calloc(num_bins, sizeof(st_table_entry *)); + + if (new_table->bins == 0) { + free(new_table); + return 0; + } + + for (i = 0; i < num_bins; i++) { + new_table->bins[i] = 0; + ptr = old_table->bins[i]; + while (ptr != 0) { + entry = alloc(st_table_entry); + if (entry == 0) { + free(new_table->bins); + free(new_table); + return 0; + } + *entry = *ptr; + entry->next = new_table->bins[i]; + new_table->bins[i] = entry; + ptr = ptr->next; + } + } + return new_table; +} + +int st_delete(table, key, value) +register st_table *table; +register st_data_t *key; +st_data_t *value; +{ + unsigned int hash_val; + st_table_entry *tmp; + register st_table_entry *ptr; + + hash_val = do_hash_bin(*key, table); + ptr = table->bins[hash_val]; + + if (ptr == 0) { + if (value != 0) + *value = 0; + return 0; + } + + if (EQUAL(table, *key, ptr->key)) { + table->bins[hash_val] = ptr->next; + table->num_entries--; + if (value != 0) + *value = ptr->record; + *key = ptr->key; + free(ptr); + return 1; + } + + for (; ptr->next != 0; ptr = ptr->next) { + if (EQUAL(table, ptr->next->key, *key)) { + tmp = ptr->next; + ptr->next = ptr->next->next; + table->num_entries--; + if (value != 0) + *value = tmp->record; + *key = tmp->key; + free(tmp); + return 1; + } + } + + return 0; +} + +int st_delete_safe(table, key, value, never) +register st_table *table; +register st_data_t *key; +st_data_t *value; +st_data_t never; +{ + unsigned int hash_val; + register st_table_entry *ptr; + + hash_val = do_hash_bin(*key, table); + ptr = table->bins[hash_val]; + + if (ptr == 0) { + if (value != 0) + *value = 0; + return 0; + } + + for (; ptr != 0; ptr = ptr->next) { + if ((ptr->key != never) && EQUAL(table, ptr->key, *key)) { + table->num_entries--; + *key = ptr->key; + if (value != 0) + *value = ptr->record; + ptr->key = ptr->record = never; + return 1; + } + } + + return 0; +} + +static int delete_never(st_data_t key, st_data_t value, st_data_t never) +{ + if (value == never) + return ST_DELETE; + return ST_CONTINUE; +} + +void st_cleanup_safe(table, never) +st_table *table; +st_data_t never; +{ + int num_entries = table->num_entries; + + st_foreach(table, delete_never, never); + table->num_entries = num_entries; +} + +void st_foreach(table, func, arg) +st_table *table; +int (*func) (st_data_t key, st_data_t val, st_data_t arg); +st_data_t arg; +{ + st_table_entry *ptr, *last, *tmp; + enum st_retval retval; + int i; + + for (i = 0; i < table->num_bins; i++) { + last = 0; + for (ptr = table->bins[i]; ptr != 0;) { + retval = (*func) (ptr->key, ptr->record, arg); + switch (retval) { + case ST_CONTINUE: + last = ptr; + ptr = ptr->next; + break; + case ST_STOP: + return; + case ST_DELETE: + tmp = ptr; + if (last == 0) { + table->bins[i] = ptr->next; + } else { + last->next = ptr->next; + } + ptr = ptr->next; + free(tmp); + table->num_entries--; + } + } + } +} + +static int strhash(string) +register const char *string; +{ + register int c; + +#ifdef HASH_ELFHASH + register unsigned int h = 0, g; + + while ((c = *string++) != '\0') { + h = (h << 4) + c; + if (g = h & 0xF0000000) + h ^= g >> 24; + h &= ~g; + } + return h; +#elif HASH_PERL + register int val = 0; + + while ((c = *string++) != '\0') { + val = val * 33 + c; + } + + return val + (val >> 5); +#else + register int val = 0; + + while ((c = *string++) != '\0') { + val = val * 997 + c; + } + + return val + (val >> 5); +#endif +} + +static int numcmp(x, y) +void *x, *y; +{ + return (st_ptr_t) x != (st_ptr_t) y; +} + +static st_ptr_t numhash(n) +void *n; +{ + return (st_ptr_t) n; +} diff --git a/contrib/ofed/management/opensm/osmeventplugin/Makefile.am b/contrib/ofed/management/opensm/osmeventplugin/Makefile.am new file mode 100644 index 000000000000..79e3d55f5083 --- /dev/null +++ b/contrib/ofed/management/opensm/osmeventplugin/Makefile.am @@ -0,0 +1,34 @@ + +INCLUDES = -I$(srcdir)/../include \ + -I$(includedir)/infiniband + +lib_LTLIBRARIES = libosmeventplugin.la + +if DEBUG +DBGFLAGS = -ggdb -D_DEBUG_ +else +DBGFLAGS = -g +endif + +libosmeventplugin_la_CFLAGS = -Wall $(DBGFLAGS) -D_XOPEN_SOURCE=600 -D_BSD_SOURCE=1 + +if HAVE_LD_VERSION_SCRIPT + libosmeventplugin_version_script = -Wl,--version-script=$(srcdir)/libosmeventplugin.map +else + libosmeventplugin_version_script = +endif + +osmeventplugin_api_version=$(shell grep LIBVERSION= $(srcdir)/libosmeventplugin.ver | sed 's/LIBVERSION=//') + +libosmeventplugin_la_SOURCES = src/osmeventplugin.c +libosmeventplugin_la_LDFLAGS = -version-info $(osmeventplugin_api_version) \ + -export-dynamic $(libosmeventplugin_version_script) +libosmeventplugin_la_LIBADD = -L../complib $(OSMV_LDADD) -losmcomp +libosmeventplugin_la_DEPENDENCIES = $(srcdir)/libosmeventplugin.map + +libosmeventpluginincludedir = $(includedir)/infiniband/complib + +libosmeventplugininclude_HEADERS = + +# headers are distributed as part of the include dir +EXTRA_DIST = $(srcdir)/libosmeventplugin.map $(srcdir)/libosmeventplugin.ver diff --git a/contrib/ofed/management/opensm/osmeventplugin/libosmeventplugin.map b/contrib/ofed/management/opensm/osmeventplugin/libosmeventplugin.map new file mode 100644 index 000000000000..346d1f390fd6 --- /dev/null +++ b/contrib/ofed/management/opensm/osmeventplugin/libosmeventplugin.map @@ -0,0 +1,5 @@ +OSMPMDB_1.0 { + global: + osm_event_plugin; + local: *; +}; diff --git a/contrib/ofed/management/opensm/osmeventplugin/libosmeventplugin.ver b/contrib/ofed/management/opensm/osmeventplugin/libosmeventplugin.ver new file mode 100644 index 000000000000..f755ff6bee0c --- /dev/null +++ b/contrib/ofed/management/opensm/osmeventplugin/libosmeventplugin.ver @@ -0,0 +1,9 @@ +# In this file we track the current API version +# of the vendor interface (and libraries) +# The version is built of the following +# tree numbers: +# API_REV:RUNNING_REV:AGE +# API_REV - advance on any added API +# RUNNING_REV - advance any change to the vendor files +# AGE - number of backward versions the API still supports +LIBVERSION=1:0:0 diff --git a/contrib/ofed/management/opensm/osmeventplugin/src/osmeventplugin.c b/contrib/ofed/management/opensm/osmeventplugin/src/osmeventplugin.c new file mode 100644 index 000000000000..f0781ebbab84 --- /dev/null +++ b/contrib/ofed/management/opensm/osmeventplugin/src/osmeventplugin.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2007 The Regents of the University of California. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** ========================================================================= + * This is a simple example plugin which logs some of the events the OSM + * generates to this interface. + */ +#define SAMPLE_PLUGIN_OUTPUT_FILE "/tmp/osm_sample_event_plugin_output" +typedef struct _log_events { + FILE *log_file; + osm_log_t *osmlog; +} _log_events_t; + +/** ========================================================================= + */ +static void *construct(osm_opensm_t *osm) +{ + _log_events_t *log = malloc(sizeof(*log)); + if (!log) + return (NULL); + + log->log_file = fopen(SAMPLE_PLUGIN_OUTPUT_FILE, "a+"); + + if (!(log->log_file)) { + osm_log(&osm->log, OSM_LOG_ERROR, + "Sample Event Plugin: Failed to open output file \"%s\"\n", + SAMPLE_PLUGIN_OUTPUT_FILE); + free(log); + return (NULL); + } + + log->osmlog = &osm->log; + return ((void *)log); +} + +/** ========================================================================= + */ +static void destroy(void *_log) +{ + _log_events_t *log = (_log_events_t *) _log; + fclose(log->log_file); + free(log); +} + +/** ========================================================================= + */ +static void handle_port_counter(_log_events_t * log, osm_epi_pe_event_t * pc) +{ + if (pc->symbol_err_cnt > 0 + || pc->link_err_recover > 0 + || pc->link_downed > 0 + || pc->rcv_err > 0 + || pc->rcv_rem_phys_err > 0 + || pc->rcv_switch_relay_err > 0 + || pc->xmit_discards > 0 + || pc->xmit_constraint_err > 0 + || pc->rcv_constraint_err > 0 + || pc->link_integrity > 0 + || pc->buffer_overrun > 0 || pc->vl15_dropped > 0) { + fprintf(log->log_file, + "Port counter errors for node 0x%" PRIx64 + " (%s) port %d\n", pc->port_id.node_guid, + pc->port_id.node_name, pc->port_id.port_num); + } +} + +/** ========================================================================= + */ +static void +handle_port_counter_ext(_log_events_t * log, osm_epi_dc_event_t * epc) +{ + fprintf(log->log_file, + "Recieved Data counters for node 0x%" PRIx64 " (%s) port %d\n", + epc->port_id.node_guid, + epc->port_id.node_name, epc->port_id.port_num); +} + +/** ========================================================================= + */ +static void handle_port_select(_log_events_t * log, osm_epi_ps_event_t * ps) +{ + if (ps->xmit_wait > 0) { + fprintf(log->log_file, + "Port select Xmit Wait counts for node 0x%" PRIx64 + " (%s) port %d\n", ps->port_id.node_guid, + ps->port_id.node_name, ps->port_id.port_num); + } +} + +/** ========================================================================= + */ +static void handle_trap_event(_log_events_t * log, osm_epi_trap_event_t * trap) +{ + fprintf(log->log_file, + "Trap event %d from 0x%" PRIx64 " (%s) port %d\n", + trap->trap_num, + trap->port_id.node_guid, + trap->port_id.node_name, trap->port_id.port_num); +} + +/** ========================================================================= + */ +static void report(void *_log, osm_epi_event_id_t event_id, void *event_data) +{ + _log_events_t *log = (_log_events_t *) _log; + + switch (event_id) { + case OSM_EVENT_ID_PORT_ERRORS: + handle_port_counter(log, (osm_epi_pe_event_t *) event_data); + break; + case OSM_EVENT_ID_PORT_DATA_COUNTERS: + handle_port_counter_ext(log, (osm_epi_dc_event_t *) event_data); + break; + case OSM_EVENT_ID_PORT_SELECT: + handle_port_select(log, (osm_epi_ps_event_t *) event_data); + break; + case OSM_EVENT_ID_TRAP: + handle_trap_event(log, (osm_epi_trap_event_t *) event_data); + break; + case OSM_EVENT_ID_MAX: + default: + osm_log(log->osmlog, OSM_LOG_ERROR, + "Unknown event reported to plugin\n"); + } +} + +/** ========================================================================= + * Define the object symbol for loading + */ + +#if OSM_EVENT_PLUGIN_INTERFACE_VER != 2 +#error OpenSM plugin interface version missmatch +#endif + +osm_event_plugin_t osm_event_plugin = { + osm_version:OSM_VERSION, + create:construct, + delete:destroy, + report:report +}; diff --git a/contrib/ofed/management/opensm/osmtest/Makefile.am b/contrib/ofed/management/opensm/osmtest/Makefile.am new file mode 100644 index 000000000000..4c6885219088 --- /dev/null +++ b/contrib/ofed/management/opensm/osmtest/Makefile.am @@ -0,0 +1,23 @@ + +if DEBUG +DBGFLAGS = -ggdb -D_DEBUG_ +else +DBGFLAGS = -g +endif + +INCLUDES = -I$(srcdir)/include $(OSMV_INCLUDES) + +sbin_PROGRAMS = osmtest +osmtest_SOURCES = main.c osmtest.c osmt_service.c osmt_slvl_vl_arb.c \ + osmt_multicast.c osmt_inform.c +if OSMV_VAPI +osmtest_SOURCES += osmt_mtl_regular_qp.c +endif +osmtest_CFLAGS = -Wall $(DBGFLAGS) +osmtest_LDADD = -L../complib -losmcomp -L../libvendor -losmvendor -L../opensm -lopensm $(OSMV_LDADD) + +EXTRA_DIST = $(srcdir)/include/osmt_inform.h \ + $(srcdir)/include/osmtest_subnet.h \ + $(srcdir)/include/osmtest.h \ + $(srcdir)/include/osmt_mtl_regular_qp.h \ + $(srcdir)/include/osmtest_base.h diff --git a/contrib/ofed/management/opensm/osmtest/include/osmt_inform.h b/contrib/ofed/management/opensm/osmtest/include/osmt_inform.h new file mode 100644 index 000000000000..bc796cc860b2 --- /dev/null +++ b/contrib/ofed/management/opensm/osmtest/include/osmt_inform.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef __OSMT_INFORM__ +#define __OSMT_INFORM__ + +#ifdef OSM_VENDOR_INTF_MTL +#include +#include +#include "osmt_mtl_regular_qp.h" +#endif + +typedef struct _osmt_qp_ctx { +#ifdef OSM_VENDOR_INTF_MTL + osmt_mtl_mad_res_t qp_bind_hndl; +#endif + uint8_t *p_send_buf; + uint8_t *p_recv_buf; +#ifdef OSM_VENDOR_INTF_MTL + IB_MGT_mad_hndl_t ib_mgt_qp0_handle; +#endif +} osmt_qp_ctx_t; + +ib_api_status_t +osmt_bind_inform_qp(IN osmtest_t * const p_osmt, OUT osmt_qp_ctx_t * p_qp_ctx); + +void +osmt_unbind_inform_qp(IN osmtest_t * const p_osmt, IN osmt_qp_ctx_t * p_qp_ctx); + +ib_api_status_t +osmt_reg_unreg_inform_info(IN osmtest_t * p_osmt, + IN osmt_qp_ctx_t * p_qp_ctx, + IN ib_inform_info_t * p_inform_info, + IN uint8_t reg_flag); + +ib_api_status_t +osmt_trap_wait(IN osmtest_t * const p_osmt, IN osmt_qp_ctx_t * p_qp_ctx); + +ib_api_status_t +osmt_init_inform_info(IN osmtest_t * const p_osmt, OUT ib_inform_info_t * p_ii); + +ib_api_status_t +osmt_init_inform_info_by_trap(IN osmtest_t * const p_osmt, + IN ib_net16_t trap_num, + OUT ib_inform_info_t * p_ii); + +#endif /* __OSMT_INFORM__ */ diff --git a/contrib/ofed/management/opensm/osmtest/include/osmt_mtl_regular_qp.h b/contrib/ofed/management/opensm/osmtest/include/osmt_mtl_regular_qp.h new file mode 100644 index 000000000000..3fd6e9d56d15 --- /dev/null +++ b/contrib/ofed/management/opensm/osmtest/include/osmt_mtl_regular_qp.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2001-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * mad.h - + * Header file for common special QP resources creation code. + * + * Creation date: + * + * Version: osmt_mtl_regular_qp.h,v 1.2 2003/03/20 16:05:10 eitan + * + * Authors: + * Elazar Raab + * + * Changes: + */ + +#ifndef H_MAD_H +#define H_MAD_H + +#include +#include +#include +#include + +#if defined(MAD_IN) || defined(MAD_OUT) +#error MACROS MAD_IN and MAD_OUT are in use, do not override +#endif +#define MAD_IN +#define MAD_OUT + +/* HCA Constants */ +#define HCA_ID "mt21108_pci0" +#define GRH_LEN 40 +#define KNOWN_QP1_QKEY 0x80010000 + +#define MAX_OUTS_SQ 2 /* Max. buffers posted for requests in SQ */ +#define MAX_OUTS_RQ 5 /* Max. buffers posted for responses in RQ */ + +#define MAX_POLL_CNT 300 +#define POLL_SLEEP 1 /* for usleep */ + +#define MAD_SIZE 256 /* MADs are always 256B */ +#define MAD_ATTR_OFFSET 16 +#define MAD_TID_OFFSET 8 + +/* Verbs SQP resources handles */ +typedef struct { + VAPI_hca_id_t hca_id; /*id of HCA */ + u_int8_t port_num; /* the port num to use */ + VAPI_hca_hndl_t hca_hndl; /*handle of HCA */ + VAPI_qp_hndl_t qp_hndl; /*handle of QP I use */ + VAPI_mr_hndl_t mr_hndl; /*handle of memory region */ + VAPI_cq_hndl_t rq_cq_hndl, sq_cq_hndl; /*handle of send & receive completion Queues */ + VAPI_pd_hndl_t pd_hndl; /*handle of Partition Domain */ + /* VAPI_ud_av_hndl_t av_hndl; */ + IB_lid_t slid; + /*LID*/ void *buf_ptr; /*mem buffer for outstanding pkts */ + MT_size_t buf_size; /*size of mem buffer for outstanding pkts */ + + u_int32_t max_outs_sq; /*max # of outstanding pkts in send queue */ + u_int32_t max_outs_rq; /*max # of outstanding pkts in receive queue */ + + IB_rkey_t l_key; /*my l_key for memory regions */ + VAPI_qkey_t qkey; /*my qkey */ + + EVAPI_compl_handler_hndl_t rq_cq_eventh, sq_cq_eventh; /* event handlers for polling */ + + bool is_sqp; /* relate to union below - my QP */ + union { + VAPI_special_qp_t sqp_type; + VAPI_qp_num_t qp_num; + } qp_id; + void *wait_q; +} osmt_mtl_mad_res_t; + +/* init an osmt_mtl_mad_res_t with all resources initialized (use functions below) */ +VAPI_ret_t osmt_mtl_init(osmt_mtl_mad_res_t * res /*pointer to res (resources) struct */ + ); +VAPI_ret_t osmt_mtl_init_opened_hca(osmt_mtl_mad_res_t * res /*pointer to res (resources) struct */ + ); + +/* Cleanup all resources of (which are valid) in res */ +VAPI_ret_t osmt_mtl_mad_cleanup(osmt_mtl_mad_res_t * res /*pointer to res (resources) struct */ + ); + +/* create CQs and QP as given in res->is_sqp (if TRUE, get special QP) */ +VAPI_ret_t osmt_mtl_get_qp_resources(osmt_mtl_mad_res_t * res /*pointer to res (resources) struct */ + ); + +/* move QP to RTS state */ +VAPI_ret_t osmt_mtl_mad_qp_init(osmt_mtl_mad_res_t * res /*max number of outstanding packets allowed in send queue */ + ); + +/* create and register res->buf_ptr */ +VAPI_ret_t osmt_mtl_mad_create_mr(osmt_mtl_mad_res_t * res /*pointer to res (resources) struct */ + ); + +VAPI_ret_t osmt_mtl_create_av(osmt_mtl_mad_res_t * res, /* pointer to res (resources) struct */ + int16_t dlid, /*destination lid */ + VAPI_ud_av_hndl_t * avh_p /* address vectr handle to update */ + ); + +/* Send MAD to given dest QP*/ +VAPI_ret_t osmt_mtl_mad_send(osmt_mtl_mad_res_t * res, /*pointer to res (resources) struct */ + VAPI_wr_id_t id, /*wqe ID */ + void *mad, /*mad buffer to send */ + VAPI_qp_num_t dest_qp, /*destination QP */ + IB_sl_t sl, /*Service Level */ + u_int32_t dest_qkey, /*Destination QP KEY */ + VAPI_ud_av_hndl_t avh /* address vectr handle to use */ + ); + +/* post buffers to RQ. returns num of buffers actually posted */ +int osmt_mtl_mad_post_recv_bufs(osmt_mtl_mad_res_t * res, /*pointer to res (resources) struct */ + void *buf_array, /*array of receive buffers */ + u_int32_t num_o_bufs, /*number of receive buffers */ + u_int32_t size, /* size of expected receive packet - MAD */ + VAPI_wr_id_t start_id /* start id for receive buffers */ + ); + +/* Poll given CQ for completion max_poll times (POLL_SLEEP [usec] delays). result in wc_desc_p. */ +VAPI_ret_t osmt_mtl_mad_poll4cqe(VAPI_hca_hndl_t hca, /*handle for HCA */ + VAPI_cq_hndl_t cq, /*handle for Completion Queue - Rcv/Send */ + VAPI_wc_desc_t * wc_desc_p, /*handle of cqe */ + u_int32_t max_poll, /*number of polling iterations */ + u_int32_t poll_sleep, /*timeout for each polling */ + VAPI_ud_av_hndl_t * avh_p /* address vectopr handle to cleanup */ + ); + +#endif diff --git a/contrib/ofed/management/opensm/osmtest/include/osmtest.h b/contrib/ofed/management/opensm/osmtest/include/osmtest.h new file mode 100644 index 000000000000..c3134ef65189 --- /dev/null +++ b/contrib/ofed/management/opensm/osmtest/include/osmtest.h @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osmtest_t. + * This object represents the OSMTest Test object. + * + */ + +#ifndef _OSMTEST_H_ +#define _OSMTEST_H_ + +#include +#include +#include +#include +#include +#include +#include "osmtest_base.h" +#include "osmtest_subnet.h" + +enum OSMT_FLOWS { + OSMT_FLOW_ALL = 0, + OSMT_FLOW_CREATE_INVENTORY, + OSMT_FLOW_VALIDATE_INVENTORY, + OSMT_FLOW_SERVICE_REGISTRATION, + OSMT_FLOW_EVENT_FORWARDING, + OSMT_FLOW_STRESS_SA, + OSMT_FLOW_MULTICAST, + OSMT_FLOW_QOS, + OSMT_FLOW_TRAP, +}; + +/****s* OpenSM: Subnet/osmtest_opt_t + * NAME + * osmtest_opt_t + * + * DESCRIPTION + * Subnet options structure. This structure contains the various + * site specific configuration parameters for osmtest. + * + * SYNOPSIS + */ +typedef struct _osmtest_opt { + uint32_t transaction_timeout; + boolean_t force_log_flush; + boolean_t create; + uint32_t retry_count; + uint32_t stress; + uint32_t mmode; + char file_name[OSMTEST_FILE_PATH_MAX]; + uint8_t flow; + uint8_t wait_time; + char *log_file; + boolean_t ignore_path_records; +} osmtest_opt_t; + +/* + * FIELDS + * + * SEE ALSO + *********/ + +/****h* OSMTest/OSMTest + * NAME + * OSMTest + * + * DESCRIPTION + * The OSMTest object tests an SM/SA for conformance to a known + * set of data about an Infiniband subnet. + * + * AUTHOR + * Steve King, Intel + * + *********/ + +/****s* OSMTest/osmtest_t + * NAME + * osmtest_t + * + * DESCRIPTION + * OSMTest structure. + * + * This object should be treated as opaque and should + * be manipulated only through the provided functions. + * + * SYNOPSIS + */ +typedef struct _osmtest { + osm_log_t log; + struct _osm_vendor *p_vendor; + osm_bind_handle_t h_bind; + osm_mad_pool_t mad_pool; + + osmtest_opt_t opt; + ib_port_attr_t local_port; + subnet_t exp_subn; + cl_qpool_t node_pool; + cl_qpool_t port_pool; + cl_qpool_t link_pool; + + uint16_t max_lid; +} osmtest_t; + +/* + * FIELDS + * log + * Log facility used by all OSMTest components. + * + * p_vendor + * Pointer to the vendor transport layer. + * + * h_bind + * The bind handle obtained by osm_vendor_sa_api/osmv_bind_sa + * + * mad_pool + * The mad pool provided for teh vendor layer to allocate mad wrappers in + * + * opt + * osmtest options structure + * + * local_port + * Port attributes for the port over which osmtest is running. + * + * exp_subn + * Subnet object representing the expected subnet + * + * node_pool + * Pool of objects for use in populating the subnet databases. + * + * port_pool + * Pool of objects for use in populating the subnet databases. + * + * link_pool + * Pool of objects for use in populating the subnet databases. + * + * SEE ALSO + *********/ + +/****s* OpenSM: Subnet/osmtest_req_context_t + * NAME + * osmtest_req_context_t + * + * DESCRIPTION + * Query context for ib_query callback function. + * + * SYNOPSIS + */ +typedef struct _osmtest_req_context { + osmtest_t *p_osmt; + osmv_query_res_t result; +} osmtest_req_context_t; + +typedef struct _osmtest_mgrp_t { + cl_map_item_t map_item; + ib_member_rec_t mcmember_rec; +} osmtest_mgrp_t; + +/* + * FIELDS + * + * SEE ALSO + *********/ + +/****f* OSMTest/osmtest_construct + * NAME + * osmtest_construct + * + * DESCRIPTION + * This function constructs an OSMTest object. + * + * SYNOPSIS + */ +void osmtest_construct(IN osmtest_t * const p_osmt); + +/* + * PARAMETERS + * p_osmt + * [in] Pointer to a OSMTest object to construct. + * + * RETURN VALUE + * This function does not return a value. + * + * NOTES + * Allows calling osmtest_init, osmtest_destroy. + * + * Calling osmtest_construct is a prerequisite to calling any other + * method except osmtest_init. + * + * SEE ALSO + * SM object, osmtest_init, osmtest_destroy + *********/ + +/****f* OSMTest/osmtest_destroy + * NAME + * osmtest_destroy + * + * DESCRIPTION + * The osmtest_destroy function destroys an osmtest object, releasing + * all resources. + * + * SYNOPSIS + */ +void osmtest_destroy(IN osmtest_t * const p_osmt); + +/* + * PARAMETERS + * p_osmt + * [in] Pointer to a OSMTest object to destroy. + * + * RETURN VALUE + * This function does not return a value. + * + * NOTES + * Performs any necessary cleanup of the specified OSMTest object. + * Further operations should not be attempted on the destroyed object. + * This function should only be called after a call to osmtest_construct or + * osmtest_init. + * + * SEE ALSO + * SM object, osmtest_construct, osmtest_init + *********/ + +/****f* OSMTest/osmtest_init + * NAME + * osmtest_init + * + * DESCRIPTION + * The osmtest_init function initializes a OSMTest object for use. + * + * SYNOPSIS + */ +ib_api_status_t osmtest_init(IN osmtest_t * const p_osmt, + IN const osmtest_opt_t * const p_opt, + IN const osm_log_level_t log_flags); + +/* + * PARAMETERS + * p_osmt + * [in] Pointer to an osmtest_t object to initialize. + * + * p_opt + * [in] Pointer to the options structure. + * + * log_flags + * [in] Log level flags to set. + * + * RETURN VALUES + * IB_SUCCESS if the OSMTest object was initialized successfully. + * + * NOTES + * Allows calling other OSMTest methods. + * + * SEE ALSO + * SM object, osmtest_construct, osmtest_destroy + *********/ + +/****f* OSMTest/osmtest_run + * NAME + * osmtest_run + * + * DESCRIPTION + * Runs the osmtest suite. + * + * SYNOPSIS + */ +ib_api_status_t osmtest_run(IN osmtest_t * const p_osmt); + +/* + * PARAMETERS + * p_osmt + * [in] Pointer to an osmtest_t object. + * + * guid + * [in] Port GUID over which to run the test suite. + * + * RETURN VALUES + * IB_SUCCESS + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OSMTest/osmtest_bind + * NAME + * osmtest_bind + * + * DESCRIPTION + * Binds osmtest to a local port. + * + * SYNOPSIS + */ +ib_api_status_t osmtest_bind(IN osmtest_t * p_osmt, + IN uint16_t max_lid, IN ib_net64_t guid OPTIONAL); + +/* + * PARAMETERS + * p_osmt + * [in] Pointer to an osmtest_t object. + * + * max_lid + * [in] The maximal lid to query about (if RMPP is not supported) + * + * guid + * [in] Port GUID over which to run the test suite. + * If zero, the bind function will display a menu of local + * port guids and wait for user input. + * + * RETURN VALUES + * IB_SUCCESS + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OSMTest/osmtest_query_res_cb + * NAME + * osmtest_query_res_cb + * + * DESCRIPTION + * A Callback for the query to invoke on completion + * + * SYNOPSIS + */ +void osmtest_query_res_cb(IN osmv_query_res_t * p_rec); +/* + * PARAMETERS + * p_rec + * [in] Pointer to an ib_query_rec_t object used for the query. + * + * RETURN VALUES + * NONE + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OSMTest/ib_get_mad_status_str + * NAME + * ib_get_mad_status_str + * + * DESCRIPTION + * return the string representing the given mad status + * + * SYNOPSIS + */ +const char *ib_get_mad_status_str(IN const ib_mad_t * const p_mad); +/* + * PARAMETERS + * p_mad + * [in] Pointer to the mad payload + * + * RETURN VALUES + * NONE + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OSMTest/osmt_run_service_records_flow + * NAME + * osmt_run_service_records_flow + * + * DESCRIPTION + * Run the service record testing flow. + * + * SYNOPSIS + */ +ib_api_status_t osmt_run_service_records_flow(IN osmtest_t * const p_osmt); +/* + * PARAMETERS + * p_osmt + * [in] Pointer to the osmtest obj + * + * RETURN VALUES + * IB_SUCCESS if PASS + * + * NOTES + * + * SEE ALSO + *********/ + +ib_api_status_t osmt_run_inform_info_flow(IN osmtest_t * const p_osmt); + +/****f* OSMTest/osmt_run_slvl_and_vlarb_records_flow + * NAME + * osmt_run_slvl_and_vlarb_records_flow + * + * DESCRIPTION + * Run the sl2vl and vlarb tables testing flow. + * + * SYNOPSIS + */ +ib_api_status_t +osmt_run_slvl_and_vlarb_records_flow(IN osmtest_t * const p_osmt); +/* + * PARAMETERS + * p_osmt + * [in] Pointer to the osmtest obj + * + * RETURN VALUES + * IB_SUCCESS if PASS + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OSMTest/osmt_run_mcast_flow + * NAME + * osmt_run_mcast_flow + * + * DESCRIPTION + * Run the multicast test flow + * + * SYNOPSIS + */ +ib_api_status_t osmt_run_mcast_flow(IN osmtest_t * const p_osmt); +/* + * PARAMETERS + * p_osmt + * [in] Pointer to the osmtest obj + * + * RETURN VALUES + * IB_SUCCESS if PASS + * + * NOTES + * + * SEE ALSO + *********/ + +/****f* OSMTest/osmt_run_trap64_65_flow + * NAME + * osmt_run_trap64_65_flow + * + * DESCRIPTION + * Run the trap 64/65 test flow. This test is ran with + * an outside tool. + * + * SYNOPSIS + */ +ib_api_status_t osmt_run_trap64_65_flow(IN osmtest_t * const p_osmt); +/* + * PARAMETERS + * p_osmt + * [in] Pointer to the osmtest obj + * + * RETURN VALUES + * IB_SUCCESS if PASS + * + * NOTES + * + * SEE ALSO + *********/ + +ib_api_status_t +osmtest_get_all_recs(IN osmtest_t * const p_osmt, + IN ib_net16_t const attr_id, + IN size_t const attr_size, + IN OUT osmtest_req_context_t * const p_context); + +ib_api_status_t +osmtest_get_local_port_lmc(IN osmtest_t * const p_osmt, + IN ib_net16_t lid, OUT uint8_t * const p_lmc); + +/* + * A few auxiliary macros for logging + */ + +#define EXPECTING_ERRORS_START "[[ ===== Expecting Errors - START ===== " +#define EXPECTING_ERRORS_END " ===== Expecting Errors - END ===== ]]" + +#endif /* _OSMTEST_H_ */ diff --git a/contrib/ofed/management/opensm/osmtest/include/osmtest_base.h b/contrib/ofed/management/opensm/osmtest/include/osmtest_base.h new file mode 100644 index 000000000000..7c33da3163f1 --- /dev/null +++ b/contrib/ofed/management/opensm/osmtest/include/osmtest_base.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osmtest_t. + * This object represents the OSMTest Test object. + * + */ +#ifndef _OSMTEST_BASE_H_ +#define _OSMTEST_BASE_H_ + +#ifndef __WIN__ +#include +#else +#include +#endif + +#define OSMTEST_MAX_LINE_LEN 120 +#ifdef WIN32 +#define OSMTEST_FILE_PATH_MAX 4096 +#else +#define OSMTEST_FILE_PATH_MAX PATH_MAX +#endif + +#define STRESS_SMALL_RMPP_THR 100000 +/* + Take long times when quering big clusters (over 40 nodes) , an average of : 0.25 sec for query + each query receives 1000 records +*/ +#define STRESS_LARGE_RMPP_THR 4000 +#define STRESS_LARGE_PR_RMPP_THR 20000 + +extern const char *const p_file; + +#endif /* _OSMTEST_BASE_H_ */ diff --git a/contrib/ofed/management/opensm/osmtest/include/osmtest_subnet.h b/contrib/ofed/management/opensm/osmtest/include/osmtest_subnet.h new file mode 100644 index 000000000000..09063dd2ec3a --- /dev/null +++ b/contrib/ofed/management/opensm/osmtest/include/osmtest_subnet.h @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Declaration of osmtest_t. + * This object represents the OSMTest Test object. + * + */ + +#ifndef _OSMTEST_SUBNET_H_ +#define _OSMTEST_SUBNET_H_ + +#include +#include +#include +#include +#include +#include + +/****s* Subnet Database/generic_t +* NAME +* generic_t +* +* DESCRIPTION +* Subnet database object for fields common to all record types. +* All other database types must be castable to this type. +* +* SYNOPSIS +*/ +typedef struct _generic { + cl_map_item_t map_item; /* must be first element! */ + uint32_t count; /* must be second element! */ +} generic_t; + +/* +* FIELDS +* +* SEE ALSO +*********/ + +/****s* Subnet Database/node_t +* NAME +* node_t +* +* DESCRIPTION +* Subnet database object for nodes. +* Must be castable to generic_t. +* +* SYNOPSIS +*/ +typedef struct _node { + cl_map_item_t map_item; /* must be first element! */ + uint32_t count; /* must be second element! */ + ib_node_record_t rec; + ib_node_record_t comp; +} node_t; + +/* +* FIELDS +* map_item +* Provides linkage for the qmap container. +* +* rec +* NodeRecord for this node as read from the database file. +* +* comp +* NodeRecord indicating which fields should be compared against rec. +* Bits set in the comp NodeRecord indicate that bit in the rec structure +* should be compared against real-time data from the SA. +* +* count +* Utility counter used by the validation logic. Typically used to +* to indicate the number of times a matching node was received from +* the SA. +* +* SEE ALSO +*********/ + +static inline node_t *node_new(void) +{ + node_t *p_obj; + + p_obj = malloc(sizeof(*p_obj)); + if (p_obj) + memset(p_obj, 0, sizeof(*p_obj)); + return (p_obj); +} + +static inline void node_delete(IN node_t * p_obj) +{ + free(p_obj); +} + +/****s* Subnet Database/port_t +* NAME +* port_t +* +* DESCRIPTION +* Subnet database object for ports. +* Must be castable to generic_t. +* +* SYNOPSIS +*/ +typedef struct _port { + cl_map_item_t map_item; /* must be first element! */ + uint32_t count; /* must be second element! */ + /* Since there is no unique identifier for all ports we + must be able to have such a key by the lid and port num */ + uint64_t port_id; + ib_portinfo_record_t rec; + ib_portinfo_record_t comp; +} port_t; + +/* +* FIELDS +* +* map_item +* Provides linkage for the qmap container. +* +* rec +* PortInfoRecord for this port as read from the database file. +* +* comp +* PortInfoRecord indicating which fields should be compared against rec. +* Bits set in the comp NodeRecord indicate that bit in the rec structure +* should be compared against real-time data from the SA. +* +* count +* Utility counter used by the validation logic. Typically used to +* to indicate the number of times a matching node was received from +* the SA. +* +* SEE ALSO +*********/ + +static inline port_t *port_new(void) +{ + port_t *p_obj; + + p_obj = malloc(sizeof(*p_obj)); + if (p_obj) + memset(p_obj, 0, sizeof(*p_obj)); + return (p_obj); +} + +static inline void port_delete(IN port_t * p_obj) +{ + free(p_obj); +} + +static inline uint64_t +port_gen_id(IN ib_net16_t const lid, IN uint8_t const port_num) +{ + return (lid << 8 | port_num); +} + +static inline void +port_ext_id(IN uint64_t id, IN ib_net16_t * p_lid, IN uint8_t * p_port_num) +{ + CL_ASSERT((id & 0xFF) < 0x100); + *p_port_num = (uint8_t) (id & 0xFF); + CL_ASSERT(((id >> 8) & 0xFFFF) < 0x10000); + *p_lid = (uint16_t) ((id >> 8) & 0xFFFF); +} + +static inline void +port_set_id(IN port_t * p_obj, + IN ib_net16_t const lid, IN uint8_t const port_num) +{ + p_obj->port_id = port_gen_id(lid, port_num); +} + +static inline void +port_get_id(IN port_t * p_obj, IN ib_net16_t * p_lid, IN uint8_t * p_port_num) +{ + port_ext_id(p_obj->port_id, p_lid, p_port_num); +} + +/****s* Subnet Database/path_t +* NAME +* node_t +* +* DESCRIPTION +* Subnet database object for paths. +* Must be castable to generic_t. +* +* SYNOPSIS +*/ +typedef struct _path { + cl_map_item_t map_item; /* must be first element! */ + uint32_t count; /* must be second element! */ + ib_path_rec_t rec; + ib_path_rec_t comp; +} path_t; + +/* +* FIELDS +* map_item +* Provides linkage for the qmap container. +* +* rec +* PathRecord for this path as read from the database file. +* +* comp +* PathRecord indicating which fields should be compared against rec. +* Bits set in the comp PathRecord indicate that bit in the rec structure +* should be compared against real-time data from the SA. +* +* count +* Utility counter used by the validation logic. Typically used to +* to indicate the number of times a matching node was received from +* the SA. +* +* SEE ALSO +*********/ + +static inline path_t *path_new(void) +{ + path_t *p_obj; + + p_obj = malloc(sizeof(*p_obj)); + if (p_obj) + memset(p_obj, 0, sizeof(*p_obj)); + return (p_obj); +} + +static inline void path_delete(IN path_t * p_obj) +{ + free(p_obj); +} + +/****s* Subnet Database/subnet_t +* NAME +* subnet_t +* +* DESCRIPTION +* Subnet database object. +* +* SYNOPSIS +*/ +typedef struct _subnet { + cl_qmap_t node_lid_tbl; + cl_qmap_t node_guid_tbl; + cl_qmap_t mgrp_mlid_tbl; + /* cl_qmap_t port_lid_tbl; */ + /* cl_qmap_t port_guid_tbl; */ + cl_qmap_t port_key_tbl; + cl_qmap_t link_tbl; + cl_qmap_t path_tbl; +} subnet_t; + +/* +* FIELDS +* +* SEE ALSO +*********/ + +/****f* Subnet Database/subnet_construct +* NAME +* subnet_construct +* +* DESCRIPTION +* This function constructs an subnet database object. +* This function cannot fail. +* +* SYNOPSIS +*/ +void subnet_construct(IN subnet_t * const p_subn); + +/* +* FIELDS +* +* SEE ALSO +*********/ + +/****f* Subnet Database/subnet_init +* NAME +* subnet_init +* +* DESCRIPTION +* This function initializes an subnet database object. +* +* SYNOPSIS +*/ +cl_status_t subnet_init(IN subnet_t * const p_subn); + +/* +* FIELDS +* +* SEE ALSO +*********/ + +#endif diff --git a/contrib/ofed/management/opensm/osmtest/main.c b/contrib/ofed/management/opensm/osmtest/main.c new file mode 100644 index 000000000000..f87e33b2f937 --- /dev/null +++ b/contrib/ofed/management/opensm/osmtest/main.c @@ -0,0 +1,623 @@ +/* + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Command line interface for osmtest. + * + */ + +#include +#include +#include +#include +#include "osmtest.h" + +/******************************************************************** + D E F I N E G L O B A L V A R I A B L E S +*********************************************************************/ + +/* + This is the global osmtest object. + One osmtest object is required per subnet. + Future versions could support multiple subents by + instantiating more than one osmtest object. +*/ +#define GUID_ARRAY_SIZE 64 +#define OSMT_DEFAULT_RETRY_COUNT 3 +#define OSMT_DEFAULT_TRANS_TIMEOUT_MILLISEC 1000 +#define OSMT_DEFAULT_TRAP_WAIT_TIMEOUT_SEC 10 +#define INVALID_GUID (0xFFFFFFFFFFFFFFFFULL) + +/********************************************************************** + **********************************************************************/ +boolean_t osmt_is_debug(void) +{ +#if defined( _DEBUG_ ) + return TRUE; +#else + return FALSE; +#endif /* defined( _DEBUG_ ) */ +} + +/********************************************************************** + **********************************************************************/ +void show_usage(void); + +void show_usage() +{ + printf + ("\n------- osmtest - Usage and options ----------------------\n"); + printf("Usage: osmtest [options]\n"); + printf("Options:\n"); + printf("-f \n" + "--flow \n" + " This option directs osmtest to run a specific flow:\n" + " FLOW DESCRIPTION\n" + " c = create an inventory file with all nodes, ports and paths\n" + " a = run all validation tests (expecting an input inventory)\n" + " v = only validate the given inventory file\n" + " s = run service registration, deregistration, and lease test\n" + " e = run event forwarding test\n" + " f = flood the SA with queries according to the stress mode\n" + " m = multicast flow\n" + " q = QoS info: dump VLArb and SLtoVL tables\n" + " t = run trap 64/65 flow (this flow requires running of external tool)\n" + " (default is all flows except QoS)\n\n"); + + printf("-w \n" + "--wait \n" + " This option specifies the wait time for trap 64/65 in seconds\n" + " It is used only when running -f t - the trap 64/65 flow\n" + " (default to 10 sec)\n\n"); + printf("-d \n" + "--debug \n" + " This option specifies a debug option\n" + " These options are not normally needed\n" + " The number following -d selects the debug\n" + " option to enable as follows:\n" + " OPT Description\n" + " --- -----------------\n" + " -d0 - Unused.\n" + " -d1 - Do not scan/compare path records.\n" + " -d2 - Force log flushing after each log message.\n" + " Without -d, no debug options are enabled\n\n"); + printf("-m \n" + "--max_lid \n" + " This option specifies the maximal LID number to be searched\n" + " for during inventory file build (default to 100)\n\n"); + printf("-g \n" + "--guid \n" + " This option specifies the local port GUID value\n" + " with which osmtest should bind. osmtest may be\n" + " bound to 1 port at a time\n\n"); + printf("-p \n" + "--port\n" + " This option displays a menu of possible local port GUID values\n" + " with which osmtest could bind\n\n"); + printf("-h\n" + "--help\n" " Display this usage info then exit\n\n"); + printf("-i \n" + "--inventory \n" + " This option specifies the name of the inventory file\n" + " Normally, osmtest expects to find an inventory file,\n" + " which osmtest uses to validate real-time information\n" + " received from the SA during testing\n" + " If -i is not specified, osmtest defaults to the file\n" + " 'osmtest.dat'\n" + " See -c option for related information\n\n"); + printf("-s\n" + "--stress\n" + " This option runs the specified stress test instead\n" + " of the normal test suite\n" + " Stress test options are as follows:\n" + " OPT Description\n" + " --- -----------------\n" + " -s1 - Single-MAD response SA queries\n" + " -s2 - Multi-MAD (RMPP) response SA queries\n" + " -s3 - Multi-MAD (RMPP) Path Record SA queries\n" + " Without -s, stress testing is not performed\n\n"); + printf("-M\n" + "--Multicast_Mode\n" + " This option specify length of Multicast test:\n" + " OPT Description\n" + " --- -----------------\n" + " -M1 - Short Multicast Flow (default) - single mode\n" + " -M2 - Short Multicast Flow - multiple mode\n" + " -M3 - Long Multicast Flow - single mode\n" + " -M4 - Long Multicast Flow - multiple mode\n" + " Single mode - Osmtest is tested alone, with no other\n" + " apps that interact with OpenSM MC\n" + " Multiple mode - Could be run with other apps using MC with\n" + " OpenSM." + " Without -M, default flow testing is performed\n\n"); + + printf("-t \n" + " This option specifies the time in milliseconds\n" + " used for transaction timeouts\n" + " Specifying -t 0 disables timeouts\n" + " Without -t, osmtest defaults to a timeout value of\n" + " 1 second\n\n"); + printf("-l\n" + "--log_file\n" + " This option defines the log to be the given file\n" + " By default the log goes to stdout\n\n"); + printf("-v\n" + " This option increases the log verbosity level\n" + " The -v option may be specified multiple times\n" + " to further increase the verbosity level\n" + " See the -vf option for more information about.\n" + " log verbosity\n\n"); + printf("-V\n" + " This option sets the maximum verbosity level and\n" + " forces log flushing\n" + " The -V is equivalent to '-vf 0xFF -d 2'\n" + " See the -vf option for more information about.\n" + " log verbosity\n\n"); + printf("-vf \n" + " This option sets the log verbosity level\n" + " A flags field must follow the -vf option\n" + " A bit set/clear in the flags enables/disables a\n" + " specific log level as follows:\n" + " BIT LOG LEVEL ENABLED\n" + " ---- -----------------\n" + " 0x01 - ERROR (error messages)\n" + " 0x02 - INFO (basic messages, low volume)\n" + " 0x04 - VERBOSE (interesting stuff, moderate volume)\n" + " 0x08 - DEBUG (diagnostic, high volume)\n" + " 0x10 - FUNCS (function entry/exit, very high volume)\n" + " 0x20 - FRAMES (dumps all SMP and GMP frames)\n" + " 0x40 - currently unused\n" + " 0x80 - currently unused\n" + " Without -vf, osmtest defaults to ERROR + INFO (0x3)\n" + " Specifying -vf 0 disables all messages\n" + " Specifying -vf 0xFF enables all messages (see -V)\n" + " High verbosity levels may require increasing\n" + " the transaction timeout with the -t option\n\n"); +} + +/********************************************************************** + **********************************************************************/ +static void print_all_guids(IN osmtest_t * p_osmt); +static void print_all_guids(IN osmtest_t * p_osmt) +{ + ib_api_status_t status; + uint32_t num_ports = GUID_ARRAY_SIZE; + ib_port_attr_t attr_array[GUID_ARRAY_SIZE]; + int i; + + /* + Call the transport layer for a list of local port + GUID values. + */ + status = + osm_vendor_get_all_port_attr(p_osmt->p_vendor, attr_array, + &num_ports); + if (status != IB_SUCCESS) { + printf("\nError from osm_vendor_get_all_port_attr (%x)\n", + status); + return; + } + + printf("\nListing GUIDs:\n"); + for (i = 0; i < num_ports; i++) + printf("Port %i: 0x%" PRIx64 "\n", i, + cl_hton64(attr_array[i].port_guid)); +} + +/********************************************************************** + **********************************************************************/ +ib_net64_t get_port_guid(IN osmtest_t * p_osmt, uint64_t port_guid) +{ + ib_api_status_t status; + uint32_t num_ports = GUID_ARRAY_SIZE; + ib_port_attr_t attr_array[GUID_ARRAY_SIZE]; + int i; + + /* + Call the transport layer for a list of local port + GUID values. + */ +/* "local ports" is(?) phys, shouldn't this exclude port 0 then ? */ + status = + osm_vendor_get_all_port_attr(p_osmt->p_vendor, attr_array, + &num_ports); + if (status != IB_SUCCESS) { + printf("\nError from osm_vendor_get_all_port_attr (%x)\n", + status); + return (0); + } + + if (num_ports == 1) { + printf("using default guid 0x%" PRIx64 "\n", + cl_hton64(attr_array[0].port_guid)); + return (attr_array[0].port_guid); + } + + for (i = 0; i < num_ports; i++) { + if (attr_array[i].port_guid == port_guid || + (!port_guid && attr_array[i].link_state > IB_LINK_DOWN)) + return attr_array[i].port_guid; + } + + return 0; +} + +/********************************************************************** + **********************************************************************/ +int main(int argc, char *argv[]) +{ + static osmtest_t osm_test; + osmtest_opt_t opt = { 0 }; + ib_net64_t guid = 0; + uint16_t max_lid = 100; + ib_api_status_t status; + uint32_t log_flags = OSM_LOG_ERROR | OSM_LOG_INFO; + int32_t vendor_debug = 0; + char flow_name[64]; + uint32_t next_option; + const char *const short_option = "f:l:m:M:d:g:s:t:i:pcvVh"; + + /* + * In the array below, the 2nd parameter specified the number + * of arguments as follows: + * 0: no arguments + * 1: argument + * 2: optional + */ + const struct option long_option[] = { + {"create", 0, NULL, 'c'}, + {"debug", 1, NULL, 'd'}, + {"flow", 1, NULL, 'f'}, + {"wait", 1, NULL, 'w'}, + {"inventory", 1, NULL, 'i'}, + {"max_lid", 1, NULL, 'm'}, + {"guid", 2, NULL, 'g'}, + {"port", 0, NULL, 'p'}, + {"help", 0, NULL, 'h'}, + {"stress", 1, NULL, 's'}, + {"Multicast_Mode", 1, NULL, 'M'}, + {"timeout", 1, NULL, 't'}, + {"verbose", 0, NULL, 'v'}, + {"log_file", 1, NULL, 'l'}, + {"vf", 1, NULL, 'x'}, + {"V", 0, NULL, 'V'}, + + {NULL, 0, NULL, 0} /* Required at end of array */ + }; + + /* Make sure that the opensm, complib and osmtest were compiled using + same modes (debug/free) */ + if (osm_is_debug() != cl_is_debug() || osm_is_debug() != osmt_is_debug() + || osmt_is_debug() != cl_is_debug()) { + fprintf(stderr, + "-E- OpenSM, Complib and OsmTest were compiled using different modes\n"); + fprintf(stderr, + "-E- OpenSM debug:%d Complib debug:%d OsmTest debug:%d \n", + osm_is_debug(), cl_is_debug(), osmt_is_debug()); + exit(1); + } + + opt.transaction_timeout = OSMT_DEFAULT_TRANS_TIMEOUT_MILLISEC; + opt.wait_time = OSMT_DEFAULT_TRAP_WAIT_TIMEOUT_SEC; + opt.retry_count = OSMT_DEFAULT_RETRY_COUNT; + opt.force_log_flush = FALSE; + opt.stress = 0; + opt.log_file = NULL; + opt.create = FALSE; + opt.mmode = 1; + opt.ignore_path_records = FALSE; /* Do path Records too */ + opt.flow = OSMT_FLOW_ALL; /* run all validation tests */ + strcpy(flow_name, "All Validations"); + strcpy(opt.file_name, "osmtest.dat"); + + printf("\nCommand Line Arguments\n"); + do { + next_option = getopt_long_only(argc, argv, short_option, + long_option, NULL); + switch (next_option) { + case 'c': + /* + * Create the inventory file. + */ + opt.create = TRUE; + printf("\tCreating inventory file\n"); + break; + + case 'i': + /* + * Specifies inventory file name. + */ + if (strlen(optarg) > OSMTEST_FILE_PATH_MAX) + printf + ("\nError: path name too long (ignored)\n"); + else + strcpy(opt.file_name, optarg); + + printf("\tFile = %s\n", opt.file_name); + break; + + case 'f': + /* + * Specifies Flow . + */ + if (strlen(optarg) > OSMTEST_FILE_PATH_MAX) + printf + ("\nError: path name too long (ignored)\n"); + else + strcpy(flow_name, optarg); + + if (!strcmp("c", optarg)) { + strcpy(flow_name, "Create Inventory"); + opt.flow = OSMT_FLOW_CREATE_INVENTORY; + } else if (!strcmp("v", optarg)) { + strcpy(flow_name, "Validate Inventory"); + opt.flow = OSMT_FLOW_VALIDATE_INVENTORY; + } else if (!strcmp("s", optarg)) { + strcpy(flow_name, "Services Registration"); + opt.flow = OSMT_FLOW_SERVICE_REGISTRATION; + } else if (!strcmp("e", optarg)) { + strcpy(flow_name, "Event Forwarding"); + opt.flow = OSMT_FLOW_EVENT_FORWARDING; + } else if (!strcmp("f", optarg)) { + strcpy(flow_name, "Stress SA"); + opt.flow = OSMT_FLOW_STRESS_SA; + } else if (!strcmp("m", optarg)) { + strcpy(flow_name, "Multicast"); + opt.flow = OSMT_FLOW_MULTICAST; + } else if (!strcmp("q", optarg)) { + strcpy(flow_name, "QoS: VLArb and SLtoVL"); + opt.flow = OSMT_FLOW_QOS; + } else if (!strcmp("t", optarg)) { + strcpy(flow_name, "Trap 64/65"); + opt.flow = OSMT_FLOW_TRAP; + } else if (!strcmp("a", optarg)) { + strcpy(flow_name, "All Validations"); + opt.flow = OSMT_FLOW_ALL; + } else { + printf("\nError: unknown flow %s\n", flow_name); + exit(2); + } + break; + + case 'w': + /* + * Specifies trap 64/65 wait time + */ + CL_ASSERT(strtol(optarg, NULL, 0) < 0x100); + opt.wait_time = (uint8_t) strtol(optarg, NULL, 0); + printf("\tTrap 64/65 wait time = %d\n", opt.wait_time); + break; + + case 'm': + /* + * Specifies the max LID to search for during exploration. + */ + max_lid = atoi(optarg); + printf("\tMAX-LID %u\n", max_lid); + break; + + case 'g': + /* + * Specifies port guid with which to bind. + */ + guid = cl_hton64(strtoull(optarg, NULL, 16)); + printf(" Guid <0x%" PRIx64 ">\n", cl_hton64(guid)); + break; + + case 'p': + /* + * Display current port guids + */ + guid = INVALID_GUID; + break; + + case 't': + /* + * Specifies transaction timeout. + */ + opt.transaction_timeout = strtol(optarg, NULL, 0); + printf("\tTransaction timeout = %d\n", + opt.transaction_timeout); + break; + + case 'l': + opt.log_file = optarg; + printf("\tLog File:%s\n", opt.log_file); + break; + + case 'v': + /* + * Increases log verbosity. + */ + log_flags = (log_flags << 1) | 1; + printf("\tVerbose option -v (log flags = 0x%X)\n", + log_flags); + break; + + case 'V': + /* + * Specifies maximum log verbosity. + */ + log_flags = 0xFFFFFFFF; + opt.force_log_flush = TRUE; + printf("\tEnabling maximum log verbosity\n"); + break; + + case 's': + /* + * Perform stress test. + */ + opt.stress = strtol(optarg, NULL, 0); + printf("\tStress test enabled: "); + switch (opt.stress) { + case 1: + printf("Small SA queries\n"); + break; + case 2: + printf("Large SA queries\n"); + break; + case 3: + printf("Large Path Record SA queries\n"); + break; + default: + printf("Unknown value %u (ignored)\n", + opt.stress); + opt.stress = 0; + break; + } + break; + + case 'M': + /* + * Perform multicast test. + */ + opt.mmode = strtol(optarg, NULL, 0); + printf("\tMulticast test enabled: "); + switch (opt.mmode) { + case 1: + printf + ("Short MC Flow - single mode (default)\n"); + break; + case 2: + printf("Short MC Flow - multiple mode\n"); + break; + case 3: + printf("Long MC Flow - single mode\n"); + break; + case 4: + printf("Long MC Flow - multiple mode\n"); + break; + default: + printf("Unknown value %u (ignored)\n", + opt.stress); + opt.mmode = 0; + break; + } + break; + + case 'd': + /* + * Debug Options + */ + printf("\tDebug Option: "); + switch (strtol(optarg, NULL, 0)) { + case 1: + printf("Ignore Path Records\n"); + opt.ignore_path_records = TRUE; + break; + case 2: + printf("Force Log Flush\n"); + opt.force_log_flush = TRUE; + break; + case 3: + /* Used to be memory tracking */ + default: + printf("Unknown value %ld (ignored)\n", + strtol(optarg, NULL, 0)); + break; + } + break; + + case 'h': + show_usage(); + return 0; + + case 'x': + log_flags = strtol(optarg, NULL, 0); + printf + ("\t\t\t\tVerbose option -vf (log flags = 0x%X)\n", + log_flags); + break; + + case -1: + printf("Done with args\n"); + break; + + default: /* something wrong */ + abort(); + } + + } + while (next_option != -1); + + printf("\tFlow = %s\n", flow_name); + + if (vendor_debug) + osm_vendor_set_debug(osm_test.p_vendor, vendor_debug); + + complib_init(); + + status = osmtest_init(&osm_test, &opt, (osm_log_level_t) log_flags); + if (status != IB_SUCCESS) { + printf("\nError from osmtest_init: %s\n", + ib_get_err_str(status)); + goto Exit; + } + if (cl_hton64(guid) == cl_hton64(INVALID_GUID)) { + print_all_guids(&osm_test); + complib_exit(); + return (status); + } + + /* + If the user didn't specify a GUID on the command line, + then get a port GUID value with which to bind. + */ + if (guid == 0 && !(guid = get_port_guid(&osm_test, guid))) { + printf("\nError: port guid 0x%" PRIx64 " not found\n", guid); + goto Exit; + } + + /* + * Guid may be zero going into this function if the user + * hasn't specified a binding port on the command line. + */ + status = osmtest_bind(&osm_test, max_lid, guid); + if (status != IB_SUCCESS) + exit(status); + + status = osmtest_run(&osm_test); + if (status != IB_SUCCESS) { + printf("OSMTEST: TEST \"%s\" FAIL\n", flow_name); + } else { + printf("OSMTEST: TEST \"%s\" PASS\n", flow_name); + } + osmtest_destroy(&osm_test); + + complib_exit(); + +Exit: + return (status); +} diff --git a/contrib/ofed/management/opensm/osmtest/osmt_inform.c b/contrib/ofed/management/opensm/osmtest/osmt_inform.c new file mode 100644 index 000000000000..c252a4cec444 --- /dev/null +++ b/contrib/ofed/management/opensm/osmtest/osmt_inform.c @@ -0,0 +1,767 @@ +/* + * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifdef OSM_VENDOR_INTF_MTL +/* + * Abstract: + * Implementation of InformInfo testing flow.. + * Top level is osmt_run_inform_info_flow: + * osmt_bind_inform_qp + * osmt_reg_unreg_inform_info + * osmt_send_trap_wait_for_forward + * + */ + +#include +#include +#include +#include +#include +#include +#include "osmtest.h" +#include "osmt_inform.h" + +/* + * Prepare an asynchronous QP (rcv) for sending inform info and + * handling the incoming reports. + * + */ +ib_api_status_t +osmt_bind_inform_qp(IN osmtest_t * const p_osmt, OUT osmt_qp_ctx_t * p_qp_ctx) +{ + ib_net64_t port_guid; + VAPI_hca_hndl_t hca_hndl; + VAPI_hca_id_t hca_id; + uint32_t port_num; + VAPI_ret_t vapi_ret; + IB_MGT_ret_t mgt_ret; + uint8_t hca_index; + osm_log_t *p_log = &p_osmt->log; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + port_guid = p_osmt->local_port.port_guid; + + OSM_LOG(p_log, OSM_LOG_DEBUG, "Binding to port 0x%" PRIx64 "\n", + cl_ntoh64(port_guid)); + + /* obtain the hca name and port num from the guid */ + OSM_LOG(p_log, OSM_LOG_DEBUG, + "Finding CA and Port that owns port guid 0x%" PRIx64 "\n", + port_guid); + + mgt_ret = + osm_vendor_get_guid_ca_and_port(p_osmt->p_vendor, + port_guid, + &hca_hndl, + &hca_id[0], &hca_index, &port_num); + if (mgt_ret != IB_MGT_OK) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0109: " + "Unable to obtain CA and port (%d).\n"); + status = IB_ERROR; + goto Exit; + } +#define OSMT_MTL_REVERSE_QP1_WELL_KNOWN_Q_KEY 0x80010000 + + strncpy(p_qp_ctx->qp_bind_hndl.hca_id, hca_id, sizeof(hca_id)); + p_qp_ctx->qp_bind_hndl.hca_hndl = hca_hndl; + p_qp_ctx->qp_bind_hndl.port_num = port_num; + p_qp_ctx->qp_bind_hndl.max_outs_sq = 10; + p_qp_ctx->qp_bind_hndl.max_outs_rq = 10; + p_qp_ctx->qp_bind_hndl.qkey = OSMT_MTL_REVERSE_QP1_WELL_KNOWN_Q_KEY; + + vapi_ret = osmt_mtl_init_opened_hca(&p_qp_ctx->qp_bind_hndl); + if (vapi_ret != VAPI_OK) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0114: " + "Error initializing QP.\n"); + status = IB_ERROR; + goto Exit; + } + + /* we use the pre-allocated buffers for send and receive : + send from buf[0] + receive from buf[2] + */ + p_qp_ctx->p_send_buf = + (uint8_t *) p_qp_ctx->qp_bind_hndl.buf_ptr + GRH_LEN; + p_qp_ctx->p_recv_buf = + (uint8_t *) p_qp_ctx->qp_bind_hndl.buf_ptr + 2 * (GRH_LEN + + MAD_BLOCK_SIZE); + + /* Need to clear assigned memory of p_send_buf - before using it to send any data */ + memset(p_qp_ctx->p_send_buf, 0, MAD_BLOCK_SIZE); + + status = IB_SUCCESS; + OSM_LOG(p_log, OSM_LOG_DEBUG, "Initialized QP:0x%X in VAPI Mode\n", + p_qp_ctx->qp_bind_hndl.qp_id); + + OSM_LOG(p_log, OSM_LOG_DEBUG, "Binding to IB_MGT SMI\n"); + + /* we also need a QP0 handle for sending packets */ + mgt_ret = IB_MGT_get_handle(hca_id, port_num, IB_MGT_SMI, + &(p_qp_ctx->ib_mgt_qp0_handle)); + if (IB_MGT_OK != mgt_ret) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0115: " + "Error obtaining IB_MGT handle to SMI\n"); + status = IB_ERROR; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(p_log); + return status; +} + +/* + * Close the QP + */ +void +osmt_unbind_inform_qp(IN osmtest_t * const p_osmt, IN osmt_qp_ctx_t * p_qp_ctx) +{ + osm_log_t *p_log = &p_osmt->log; + + OSM_LOG_ENTER(p_log); + + osmt_mtl_mad_cleanup(&p_qp_ctx->qp_bind_hndl); + + IB_MGT_release_handle(p_qp_ctx->ib_mgt_qp0_handle); + + OSM_LOG(p_log, OSM_LOG_DEBUG, "Unbind QP handles\n"); + OSM_LOG_EXIT(&p_osmt->log); +} + +/* + * Register/Unregister to receive the given InformInfo + * + * Uses the qp context to send the inform info mad. + * Wait for GetResp(InformInfoResp) + * + */ +ib_api_status_t +osmt_reg_unreg_inform_info(IN osmtest_t * p_osmt, + IN osmt_qp_ctx_t * p_qp_ctx, + IN ib_inform_info_t * p_inform_info, + IN uint8_t reg_flag) +{ + ib_sa_mad_t *p_sa_mad = (ib_sa_mad_t *) (p_qp_ctx->p_send_buf); + ib_inform_info_t *p_ii = ib_sa_mad_get_payload_ptr(p_sa_mad); /* SA Payload */ + VAPI_ret_t vapi_ret; + VAPI_wc_desc_t wc_desc; + VAPI_ud_av_hndl_t avh; + static VAPI_wr_id_t wrid = 16198; + osm_log_t *p_log = &p_osmt->log; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + /* init the MAD */ + ib_mad_init_new((ib_mad_t *) p_sa_mad, + IB_MCLASS_SUBN_ADM, + (uint8_t) 2, + IB_MAD_METHOD_SET, cl_hton64(wrid), (ib_net16_t) 0, 0); + wrid++; + p_sa_mad->attr_id = IB_MAD_ATTR_INFORM_INFO; + + /* copy the reference inform info */ + memcpy(p_ii, p_inform_info, sizeof(ib_inform_info_t)); + + if (reg_flag) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Subscribing InformInfo: Traps from lid:0x%X to 0x%X, trap num :0x%X\n", + p_ii->lid_range_begin, p_ii->lid_range_end, + p_ii->g_or_v.generic.trap_num); + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "UnSubscribing InformInfo: Traps from lid:0x%X to 0x%X\n", + p_ii->lid_range_begin, p_ii->lid_range_end); + } + + /* set the subscribe bit */ + if (reg_flag) { + p_ii->subscribe = 1; + } else { + p_ii->subscribe = 0; + /* + * we need to set the QPN on the mad if we unsubscribe: + * o13-2.1.1 - QPN Field need to be set when unsubscribing. + */ + ib_inform_info_set_qpn(p_ii, + cl_hton32(p_qp_ctx->qp_bind_hndl.qp_id. + qp_num)); + } + + osm_dump_inform_info(&p_osmt->log, p_ii, OSM_LOG_DEBUG); + + /* --------------------- PREP ------------------------- */ + if (osmt_mtl_mad_post_recv_bufs(&p_qp_ctx->qp_bind_hndl, p_qp_ctx->p_recv_buf, 1, /* but we need only one mad at a time */ + GRH_LEN + MAD_BLOCK_SIZE, wrid) != 1) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0120: " + "Error posting recv bufs\n"); + status = IB_ERROR; + goto Exit; + } + OSM_LOG(p_log, OSM_LOG_DEBUG, "Posted recv bufs\n"); + + vapi_ret = + osmt_mtl_create_av(&p_qp_ctx->qp_bind_hndl, + p_osmt->local_port.sm_lid, &avh); + if (vapi_ret != VAPI_OK) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0121: " + "Error Preparing AVH (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_ERROR; + goto Exit; + } + OSM_LOG(p_log, OSM_LOG_DEBUG, "Prepared AVH\n"); + + if (osm_log_is_active(p_log, OSM_LOG_DEBUG)) { + osm_dump_sa_mad(p_log, (ib_sa_mad_t *) (p_qp_ctx->p_send_buf), + OSM_LOG_DEBUG); +#if 0 + for (i = 56; i < 253; i++) { + if (i % 8 == 0) { + printf("\n %d : ", i); + } + printf("0x%02X ", p_qp_ctx->p_send_buf[i]); + } +#endif + printf("\n"); + } + + /* --------------------- SEND ------------------------- */ + vapi_ret = osmt_mtl_mad_send(&p_qp_ctx->qp_bind_hndl, wrid, p_qp_ctx->p_send_buf, 1, /* SA is QP1 */ + 0, /* SL is 0 */ + OSMT_MTL_REVERSE_QP1_WELL_KNOWN_Q_KEY, + avh); + if (vapi_ret != VAPI_OK) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0122: " + "Error sending mad (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_ERROR; + goto Exit; + } + + vapi_ret = osmt_mtl_mad_poll4cqe(p_qp_ctx->qp_bind_hndl.hca_hndl, + p_qp_ctx->qp_bind_hndl.sq_cq_hndl, + &wc_desc, 20, 10000, NULL); + if (vapi_ret != VAPI_OK) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0123: " + "Error getting send completion (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_ERROR; + goto Exit; + } + + if (wc_desc.status != VAPI_SUCCESS) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0124: " + "Error on send completion (%s) (%d)\n", + VAPI_strerror_sym(wc_desc.status), wc_desc.status); + status = IB_ERROR; + goto Exit; + } + OSM_LOG(p_log, OSM_LOG_DEBUG, "Sent MAD\n"); + + /* --------------------- RECV ------------------------- */ + vapi_ret = osmt_mtl_mad_poll4cqe(p_qp_ctx->qp_bind_hndl.hca_hndl, + p_qp_ctx->qp_bind_hndl.rq_cq_hndl, + &wc_desc, 20, 10000, &avh); + if (vapi_ret != VAPI_SUCCESS) { + if (vapi_ret == VAPI_CQ_EMPTY) { + status = IB_TIMEOUT; + } else { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0125: " + "Error receiving mad (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_ERROR; + } + goto Exit; + } + + /* check to see if successful - by examination of the subscribe bit */ + p_sa_mad = (ib_sa_mad_t *) (p_qp_ctx->p_recv_buf + GRH_LEN); + + if (p_sa_mad->status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "Remote error = %s\n", + ib_get_mad_status_str((ib_mad_t *) p_sa_mad)); + status = IB_REMOTE_ERROR; + goto Exit; + } + + if (p_sa_mad->method != IB_MAD_METHOD_GET_RESP) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Expected IB_MAD_METHOD_GET_RESP but got:(%X)\n", + p_sa_mad->method); + status = IB_REMOTE_ERROR; + goto Exit; + } + + if (p_sa_mad->attr_id != IB_MAD_ATTR_INFORM_INFO) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Expected IB_MAD_ATTR_INFORM_INFO but got:(%X)\n", + cl_ntoh16(p_sa_mad->attr_id)); + status = IB_REMOTE_ERROR; + goto Exit; + } + + p_ii = ib_sa_mad_get_payload_ptr(p_sa_mad); + if (!p_ii->subscribe) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0126: " + "Subscribe/Unsubscribe Failed\n"); + status = IB_REMOTE_ERROR; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +/* + * Send a trap (Subn LID Route) Trap(Notice) through the regular + * connection QP connection (targeted at QP0) + * + * Wait for the trap repress + */ +ib_api_status_t +osmt_send_trap_wait_for_forward(IN osmtest_t * const p_osmt, + IN osmt_qp_ctx_t * p_qp_ctx) +{ + ib_smp_t *p_smp = (ib_smp_t *) (p_qp_ctx->p_send_buf); + ib_mad_notice_attr_t *p_ntc = ib_smp_get_payload_ptr(p_smp); + ib_sa_mad_t *p_sa_mad; + IB_MGT_ret_t mgt_res; + VAPI_ret_t vapi_ret; + VAPI_wc_desc_t wc_desc; + VAPI_ud_av_hndl_t avh; + IB_ud_av_t av; + static VAPI_wr_id_t wrid = 2222; + osm_log_t *p_log = &p_osmt->log; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + OSM_LOG(p_log, OSM_LOG_INFO, + "Sending Traps to QP0 of SA LID:0x%X\n", + p_osmt->local_port.sm_lid); + + /* init the MAD */ + memset(p_smp, 0, sizeof(ib_smp_t)); + ib_mad_init_new((ib_mad_t *) p_smp, + IB_MCLASS_SUBN_LID, + (uint8_t) 2, + IB_MAD_METHOD_TRAP, cl_hton64(wrid), (ib_net16_t) 0, 0); + + wrid++; + p_smp->attr_id = IB_MAD_ATTR_NOTICE; + + /* prepare the notice */ + p_ntc->generic_type = 0x82; /* generic, type = 2 */ + ib_notice_set_prod_type_ho(p_ntc, 1); + p_ntc->g_or_v.generic.trap_num = cl_hton16(0x26); + p_ntc->issuer_lid = cl_hton16(2); + + /* --------------------- PREP ------------------------- */ + if (osmt_mtl_mad_post_recv_bufs(&p_qp_ctx->qp_bind_hndl, p_qp_ctx->p_recv_buf, 1, /* we need to receive both trap repress and report */ + GRH_LEN + MAD_BLOCK_SIZE, wrid) != 1) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0127: " + "Error posting recv bufs\n"); + status = IB_ERROR; + goto Exit; + } + OSM_LOG(p_log, OSM_LOG_DEBUG, "Posted recv bufs\n"); + + av.dlid = p_osmt->local_port.sm_lid; + av.grh_flag = FALSE; + + /* EZ: returned in HACK: use constants */ + av.static_rate = 0; /* p_mad_addr->static_rate; */ + av.src_path_bits = 1; /* p_mad_addr->path_bits; */ + av.sl = 0; /* p_mad_addr->addr_type.gsi.service_level; */ + + OSM_LOG(p_log, OSM_LOG_DEBUG, + "av.dlid 0x%X, av.static_rate %d, av.path_bits %d\n", + cl_ntoh16(av.dlid), av.static_rate, av.src_path_bits); + + /* send it */ + mgt_res = IB_MGT_send_mad(p_qp_ctx->ib_mgt_qp0_handle, p_smp, /* actual payload */ + &av, /* address vector */ + wrid, /* casting the mad wrapper pointer for err cb */ + p_osmt->opt.transaction_timeout); + if (mgt_res != IB_MGT_OK) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0128: " + "Error sending mad (%d)\n", mgt_res); + status = IB_ERROR; + goto Exit; + } + + vapi_ret = + osmt_mtl_create_av(&p_qp_ctx->qp_bind_hndl, + p_osmt->local_port.sm_lid, &avh); + if (vapi_ret != VAPI_OK) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0129: " + "Error Preparing AVH (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_ERROR; + goto Exit; + } + OSM_LOG(p_log, OSM_LOG_DEBUG, "Prepared AVH\n"); + + OSM_LOG(p_log, OSM_LOG_DEBUG, "Trap MAD Sent\n"); + + /* --------------------- RECV ------------------------- */ + vapi_ret = osmt_mtl_mad_poll4cqe(p_qp_ctx->qp_bind_hndl.hca_hndl, + p_qp_ctx->qp_bind_hndl.rq_cq_hndl, + &wc_desc, 200, 10000, &avh); + if (vapi_ret != VAPI_SUCCESS) { + if (vapi_ret == VAPI_CQ_EMPTY) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0130: " + "Timeout receiving mad (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_TIMEOUT; + } else { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0131: " + "Error receiving mad (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_ERROR; + } + goto Exit; + } + + /* check to see if successful - by examination of the subscribe bit */ + p_sa_mad = (ib_sa_mad_t *) (p_qp_ctx->p_recv_buf + GRH_LEN); + + if (p_sa_mad->method == IB_MAD_METHOD_REPORT) { + if (p_sa_mad->attr_id == IB_MAD_ATTR_NOTICE) { + OSM_LOG(p_log, OSM_LOG_INFO, "Received the Report!\n"); + status = IB_SUCCESS; + } else { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 1020" + "Did not receive a Report(Notice) but attr:%d\n", + cl_ntoh16(p_sa_mad->attr_id)); + status = IB_ERROR; + } + } else { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 1020" + "Received an Unexpected Method:%d\n", p_smp->method); + status = IB_ERROR; + } + +Exit: + OSM_LOG_EXIT(p_log); + return status; +} + +/* + * Wait for a trap on QPn + * + */ +ib_api_status_t +osmt_trap_wait(IN osmtest_t * const p_osmt, IN osmt_qp_ctx_t * p_qp_ctx) +{ + ib_smp_t *p_smp = (ib_smp_t *) (p_qp_ctx->p_send_buf); + ib_sa_mad_t *p_sa_mad; + VAPI_ret_t vapi_ret; + VAPI_wc_desc_t wc_desc; + osm_log_t *p_log = &p_osmt->log; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(p_log); + + OSM_LOG(p_log, OSM_LOG_INFO, + "Waiting for Traps under QP:0x%X of SA LID:0x%X\n", + cl_ntoh16(p_osmt->local_port.sm_lid)); + + /* --------------------- RECV ------------------------- */ + vapi_ret = osmt_mtl_mad_poll4cqe(p_qp_ctx->qp_bind_hndl.hca_hndl, + p_qp_ctx->qp_bind_hndl.rq_cq_hndl, + &wc_desc, + // 200, + p_osmt->opt.wait_time * 100, + 10000, NULL); + if (vapi_ret != VAPI_SUCCESS) { + if (vapi_ret == VAPI_CQ_EMPTY) { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0130: " + "Timeout receiving mad (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_TIMEOUT; + } else { + OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0131: " + "Error receiving mad (%s)\n", + VAPI_strerror_sym(vapi_ret)); + status = IB_ERROR; + } + goto Exit; + } + + /* check to see if successful - by examination of the subscribe bit */ + p_sa_mad = (ib_sa_mad_t *) (p_qp_ctx->p_recv_buf + GRH_LEN); + + if (p_sa_mad->method == IB_MAD_METHOD_REPORT) { + if (p_sa_mad->attr_id == IB_MAD_ATTR_NOTICE) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Received the Report!\n"); + status = IB_SUCCESS; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 1020" + "Did not receive a Report(Notice) but attr:%d\n", + cl_ntoh16(p_sa_mad->attr_id)); + status = IB_ERROR; + } + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 1020" + "Received an Unexpected Method:%d\n", p_smp->method); + status = IB_ERROR; + } + +Exit: + OSM_LOG_EXIT(p_log); + return status; +} + +/* + * Initialize an inform info attribute: + * Catch all traps in the lid range of the p_osmt + * + */ +ib_api_status_t +osmt_init_inform_info(IN osmtest_t * const p_osmt, OUT ib_inform_info_t * p_ii) +{ + + memset(p_ii, 0, sizeof(ib_inform_info_t)); + /* p_ii->lid_range_begin = cl_hton16(1); */ + p_ii->lid_range_begin = 0xFFFF; + p_ii->lid_range_end = cl_hton16(p_osmt->max_lid); + p_ii->is_generic = 1; /* have to choose */ + p_ii->trap_type = 0xFFFF; /* ALL */ + p_ii->g_or_v.generic.trap_num = 0xFFFF; /* ALL */ + p_ii->g_or_v.generic.node_type_lsb = 0xFFFF; /* ALL */ + p_ii->g_or_v.generic.node_type_msb = 0xFF; /* ALL */ + return IB_SUCCESS; +} + +ib_api_status_t +osmt_init_inform_info_by_trap(IN osmtest_t * const p_osmt, + IN ib_net16_t trap_num, + OUT ib_inform_info_t * p_ii) +{ + + memset(p_ii, 0, sizeof(ib_inform_info_t)); + /* p_ii->lid_range_begin = cl_hton16(1); */ + p_ii->lid_range_begin = 0xFFFF; + p_ii->lid_range_end = cl_hton16(p_osmt->max_lid); + p_ii->is_generic = 1; /* have to choose */ + p_ii->trap_type = 0xFFFF; /* ALL */ + p_ii->g_or_v.generic.trap_num = trap_num; /* ALL */ + p_ii->g_or_v.generic.node_type_lsb = 0xFFFF; /* ALL */ + p_ii->g_or_v.generic.node_type_msb = 0xFF; /* ALL */ + return IB_SUCCESS; +} + +/* + * Run a complete inform info test flow: + * - try to unregister inform info (should fail) + * - register an inform info + * - try to unregister inform info (should succeed) + * - register an inform info + * - send a trap - sleep + * - check that a Report(Notice) arrived that match the sent one + * + */ +ib_api_status_t osmt_run_inform_info_flow(IN osmtest_t * const p_osmt) +{ + ib_inform_info_t inform_info; + ib_api_status_t status; + osmt_qp_ctx_t qp_ctx; + + OSM_LOG_ENTER(&p_osmt->log); + + /* bind the QP */ + status = osmt_bind_inform_qp(p_osmt, &qp_ctx); + if (status != IB_SUCCESS) { + goto Exit; + } + + /* init the inform info */ + osmt_init_inform_info(p_osmt, &inform_info); + + /* first try to unsubscribe */ + status = osmt_reg_unreg_inform_info(p_osmt, &qp_ctx, &inform_info, 0); + /* WAS IB_REMOTE_ERROR */ + if (status != IB_REMOTE_ERROR) { + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Error during UnSubscribe: (%s)\n", + ib_get_err_str(status)); + goto Exit; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Expected Failure to UnSubscribe non existing InformInfo\n"); + status = IB_ERROR; + goto Exit; + } + } + + /* send the inform info registration */ + status = osmt_reg_unreg_inform_info(p_osmt, &qp_ctx, &inform_info, 1); + if (status != IB_SUCCESS) { + goto Exit; + } + + /* send a trap through QP0 and wait on QPN */ + status = osmt_send_trap_wait_for_forward(p_osmt, &qp_ctx); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Error during Send Trap and Wait For Report: (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + /* try to unsubscribe for cleanup */ + status = osmt_reg_unreg_inform_info(p_osmt, &qp_ctx, &inform_info, 0); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Error during UnSubscribe: (%s)\n", + ib_get_err_str(status)); + goto Exit; + } else { + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Remote Error during UnSubscribe\n"); + status = IB_ERROR; + goto Exit; + } + } + +Exit: + osmt_unbind_inform_qp(p_osmt, &qp_ctx); + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +/* + * Run a complete inform info test flow: + * - try to unregister inform info (should fail) + * - register an inform info + * - try to unregister inform info (should succeed) + * - register an inform info + * - send a trap - sleep + * - check that a Report(Notice) arrived that match the sent one + * + */ +ib_api_status_t osmt_run_trap64_65_flow(IN osmtest_t * const p_osmt) +{ + ib_inform_info_t inform_info; + ib_api_status_t status; + osmt_qp_ctx_t qp_ctx; + + OSM_LOG_ENTER(&p_osmt->log); + + /* bind the QP */ + status = osmt_bind_inform_qp(p_osmt, &qp_ctx); + if (status != IB_SUCCESS) { + goto Exit; + } + + /* init the inform info */ + osmt_init_inform_info_by_trap(p_osmt, cl_hton16(64), &inform_info); + + /* send the inform info registration */ + status = osmt_reg_unreg_inform_info(p_osmt, &qp_ctx, &inform_info, 1); + if (status != IB_SUCCESS) { + goto Exit; + } + + /*--------------------- PREP -------------------------*/ + if (osmt_mtl_mad_post_recv_bufs(&qp_ctx.qp_bind_hndl, qp_ctx.p_recv_buf, 1, /* we need to receive the report */ + GRH_LEN + MAD_BLOCK_SIZE, 1) != 1) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0127: " + "Error posting recv bufs for trap 64\n"); + status = IB_ERROR; + goto Exit; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "Posted recv bufs for trap 64\n"); + + /* init the inform info */ + osmt_init_inform_info_by_trap(p_osmt, cl_hton16(65), &inform_info); + + /* send the inform info registration */ + status = osmt_reg_unreg_inform_info(p_osmt, &qp_ctx, &inform_info, 1); + if (status != IB_SUCCESS) { + goto Exit; + } + + /*--------------------- PREP -------------------------*/ + if (osmt_mtl_mad_post_recv_bufs(&qp_ctx.qp_bind_hndl, qp_ctx.p_recv_buf, 1, /* we need to reveive the report */ + GRH_LEN + MAD_BLOCK_SIZE, 1) != 1) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0127: " + "Error posting recv bufs for trap 65\n"); + status = IB_ERROR; + goto Exit; + } + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "Posted recv bufs for trap 65\n"); + + /* Sleep for x seconds in order to allow external script trap generation */ +#if 0 + sleep(p_osmt->opt.wait_time); +#endif + + /* wait for a trap on QPN */ + status = osmt_trap_wait(p_osmt, &qp_ctx); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Error during Send Trap and Wait For Report: (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + /* try to unsubscribe for cleanup */ + status = osmt_reg_unreg_inform_info(p_osmt, &qp_ctx, &inform_info, 0); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Error during UnSubscribe: (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + +Exit: + osmt_unbind_inform_qp(p_osmt, &qp_ctx); + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +#endif /* OSM_VENDOR_INTF_MTL */ diff --git a/contrib/ofed/management/opensm/osmtest/osmt_mtl_regular_qp.c b/contrib/ofed/management/opensm/osmtest/osmt_mtl_regular_qp.c new file mode 100644 index 000000000000..6374dc20a484 --- /dev/null +++ b/contrib/ofed/management/opensm/osmtest/osmt_mtl_regular_qp.c @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifdef OSM_VENDOR_INTF_MTL + +/* - Mellanox Confidential and Proprietary - + * + * Copyright (C) Jul. 2001, Mellanox Technologies Ltd. ALL RIGHTS RESERVED. + * + * Except as specifically permitted herein, no portion of the information, + * including but not limited to object code and source code, may be reproduced, + * modified, distributed, republished or otherwise exploited in any form or by + * any means for any purpose without the prior written permission of Mellanox + * Technologies Ltd. Use of software subject to the terms and conditions + * detailed in the file "LICENSE.txt". + * + * End of legal section ...................................................... + * + * osmt_mtl_regular_qp.c - + * Provide Simple Interface for Sending and Receiving MADS through a regular QP + * + * Creation date: + * + * Version: $Id$ + * + * Authors: + * Eitan Zahavi + * + * Changes: + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +/* + * Initialize the QP etc. + * Given in res: port_num, max_outs_sq, max_outs_rq + */ +VAPI_ret_t osmt_mtl_get_qp_resources(IN OUT osmt_mtl_mad_res_t * res) +{ + VAPI_ret_t ret; + VAPI_hca_port_t hca_port_info; + VAPI_qp_init_attr_t qp_init_attr; + VAPI_qp_prop_t qp_prop; + VAPI_cqe_num_t act_num; + + /* Get HCA LID */ + ret = + VAPI_query_hca_port_prop(res->hca_hndl, res->port_num, + &hca_port_info); + VAPI_CHECK_RET; + res->slid = hca_port_info.lid; + + /* Get a PD */ + ret = VAPI_alloc_pd(res->hca_hndl, &(res->pd_hndl)); + VAPI_CHECK_RET; + + /* Create CQ for RQ and SQ *//* TBD - Check we have enough act nums */ + ret = + VAPI_create_cq(res->hca_hndl, res->max_outs_sq + 1, + &(res->sq_cq_hndl), &act_num); + VAPI_CHECK_RET; + ret = + VAPI_create_cq(res->hca_hndl, res->max_outs_rq + 1, + &(res->rq_cq_hndl), &act_num); + VAPI_CHECK_RET; + + /* register event handlers for polling(block mode) internal use */ + /* ret= EVAPI_set_comp_eventh(res->hca_hndl,res->rq_cq_hndl, */ + /* EVAPI_POLL_CQ_UNBLOCK_HANDLER,NULL,&(res->rq_cq_eventh)); */ + /* VAPI_CHECK_RET; */ + /* ret= EVAPI_set_comp_eventh(res->hca_hndl,res->sq_cq_hndl, */ + /* EVAPI_POLL_CQ_UNBLOCK_HANDLER,NULL,&(res->sq_cq_eventh)); */ + /* VAPI_CHECK_RET; */ + + /* Create QP */ + qp_init_attr.cap.max_oust_wr_sq = res->max_outs_sq + 1; + qp_init_attr.cap.max_oust_wr_rq = res->max_outs_rq + 1; + qp_init_attr.cap.max_sg_size_sq = 4; + qp_init_attr.cap.max_sg_size_rq = 4; + + qp_init_attr.pd_hndl = res->pd_hndl; + qp_init_attr.rdd_hndl = 0; + qp_init_attr.rq_cq_hndl = res->rq_cq_hndl; + qp_init_attr.rq_sig_type = VAPI_SIGNAL_ALL_WR; /* That's default for IB */ + qp_init_attr.sq_cq_hndl = res->sq_cq_hndl; + qp_init_attr.sq_sig_type = VAPI_SIGNAL_REQ_WR; + qp_init_attr.ts_type = VAPI_TS_UD; + + ret = + VAPI_create_qp(res->hca_hndl, &qp_init_attr, &(res->qp_hndl), + &qp_prop); + VAPI_CHECK_RET; + res->qp_id.qp_num = qp_prop.qp_num; + + return (VAPI_OK); +} + +VAPI_ret_t osmt_mtl_qp_init(osmt_mtl_mad_res_t * res) +{ + VAPI_ret_t ret; + + VAPI_qp_attr_t qp_attr; + VAPI_qp_attr_mask_t qp_attr_mask; + VAPI_qp_cap_t qp_cap; + + /* + * Change QP to INIT + * + */ + QP_ATTR_MASK_CLR_ALL(qp_attr_mask); + qp_attr.qp_state = VAPI_INIT; + QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QP_STATE); + qp_attr.pkey_ix = 0; + QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_PKEY_IX); + qp_attr.port = res->port_num; + QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_PORT); + qp_attr.qkey = res->qkey; + QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QKEY); + + /* If I do not set this mask, I get an error from HH. QPM should catch it */ + ret = + VAPI_modify_qp(res->hca_hndl, res->qp_hndl, &qp_attr, &qp_attr_mask, + &qp_cap); + VAPI_CHECK_RET; + + return (ret); + +} + +VAPI_ret_t osmt_mtl_qp_2_rtr_rts(osmt_mtl_mad_res_t * res) +{ + VAPI_ret_t ret; + + VAPI_qp_attr_t qp_attr; + VAPI_qp_attr_mask_t qp_attr_mask; + VAPI_qp_cap_t qp_cap; + + /* + * Change QP to RTR + * + */ + QP_ATTR_MASK_CLR_ALL(qp_attr_mask); + qp_attr.qp_state = VAPI_RTR; + QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QP_STATE); + /* qp_attr.rq_psn = 0; */ + /* QP_ATTR_MASK_SET(qp_attr_mask,QP_ATTR_RQ_PSN); */ + + ret = + VAPI_modify_qp(res->hca_hndl, res->qp_hndl, &qp_attr, &qp_attr_mask, + &qp_cap); + VAPI_CHECK_RET; + + /* + * Change QP to RTS + * + */ + QP_ATTR_MASK_CLR_ALL(qp_attr_mask); + qp_attr.qp_state = VAPI_RTS; + QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QP_STATE); + qp_attr.sq_psn = 0; + QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_SQ_PSN); + + ret = + VAPI_modify_qp(res->hca_hndl, res->qp_hndl, &qp_attr, &qp_attr_mask, + &qp_cap); + VAPI_CHECK_RET; + + return (ret); +} + +VAPI_ret_t osmt_mtl_mad_create_mr(osmt_mtl_mad_res_t * res) +{ + + VAPI_ret_t ret; + + VAPI_mrw_t mr_in, mr_out; + + res->buf_size = + (MAD_SIZE + GRH_LEN) * (res->max_outs_sq + res->max_outs_rq + 1); + + /* Register single memory address region for all buffers */ + res->buf_ptr = VMALLOC(res->buf_size); + + if (res->buf_ptr == ((VAPI_virt_addr_t) NULL)) { + ret = VAPI_EAGAIN; + VAPI_CHECK_RET; + } + + /* Enable local and remote access to memory region */ + mr_in.acl = VAPI_EN_LOCAL_WRITE | VAPI_EN_REMOTE_WRITE; + mr_in.l_key = 0; + mr_in.pd_hndl = res->pd_hndl; + mr_in.r_key = 0; + mr_in.size = res->buf_size; + ASSERT_VOIDP2UINTN(res->buf_ptr); + mr_in.start = (VAPI_virt_addr_t) (uintn_t) (res->buf_ptr); + mr_in.type = VAPI_MR; + + ret = VAPI_register_mr(res->hca_hndl, &mr_in, &(res->mr_hndl), &mr_out); + VAPI_CHECK_RET; + + res->l_key = mr_out.l_key; + + return (ret); +} + +VAPI_ret_t osmt_mtl_init_opened_hca(osmt_mtl_mad_res_t * res) +{ + VAPI_ret_t ret; + + res->pd_hndl = VAPI_INVAL_HNDL; + res->rq_cq_hndl = VAPI_INVAL_HNDL; + res->sq_cq_hndl = VAPI_INVAL_HNDL; + res->sq_cq_eventh = VAPI_INVAL_HNDL; + res->rq_cq_eventh = VAPI_INVAL_HNDL; + res->qp_hndl = VAPI_INVAL_HNDL; + res->mr_hndl = VAPI_INVAL_HNDL; + + /* + * Create QP + * + */ + ret = osmt_mtl_get_qp_resources(res); + if (ret != VAPI_OK) { + return ret; + } + + /* + * Move to init + * + */ + ret = osmt_mtl_qp_init(res); + if (ret != VAPI_OK) { + return ret; + } + + /* + * Initialize memory regions + * + */ + ret = osmt_mtl_mad_create_mr(res); + if (ret != VAPI_OK) { + return ret; + } + + /* only now move to RTR and RTS */ + ret = osmt_mtl_qp_2_rtr_rts(res); + if (ret != VAPI_OK) { + return ret; + } + + return VAPI_OK; +} + +VAPI_ret_t osmt_mtl_mad_cleanup(osmt_mtl_mad_res_t * res) +{ + if (res->qp_hndl != VAPI_INVAL_HNDL) { + VAPI_destroy_qp(res->hca_hndl, res->qp_hndl); + } + if (res->sq_cq_eventh != VAPI_INVAL_HNDL) { + EVAPI_clear_comp_eventh(res->hca_hndl, res->sq_cq_eventh); + } + if (res->rq_cq_eventh != VAPI_INVAL_HNDL) { + EVAPI_clear_comp_eventh(res->hca_hndl, res->rq_cq_eventh); + } + if (res->rq_cq_hndl != VAPI_INVAL_HNDL) { + VAPI_destroy_cq(res->hca_hndl, res->rq_cq_hndl); + } + if (res->sq_cq_hndl != VAPI_INVAL_HNDL) { + VAPI_destroy_cq(res->hca_hndl, res->sq_cq_hndl); + } + if (res->mr_hndl != VAPI_INVAL_HNDL) { + VAPI_deregister_mr(res->hca_hndl, res->mr_hndl); + } + if (res->pd_hndl != VAPI_INVAL_HNDL) { + VAPI_dealloc_pd(res->hca_hndl, res->pd_hndl); + } +#if 0 + /* open/close of HCA should be done system wide - not per application */ + if (res->hca_hndl != VAPI_INVAL_HNDL) { + VAPI_close_hca(res->hca_hndl); /* TBD: HCA_open/close should be done on a system wide basis */ + } +#endif + return VAPI_OK; +} + +VAPI_ret_t osmt_mtl_create_av(osmt_mtl_mad_res_t * res, int16_t dlid, + VAPI_ud_av_hndl_t * avh_p) +{ + VAPI_ud_av_t av; + VAPI_ret_t ret; + + av.dlid = dlid; + av.port = res->port_num; + av.sl = 0; /* dest->sl; */ + av.src_path_bits = 0; /* dest->ee_dlid.dst_path_bits; */ + av.static_rate = 0; + /* GRH ? */ + av.grh_flag = 0; + + ret = VAPI_create_addr_hndl(res->hca_hndl, res->pd_hndl, &av, avh_p); + if (ret != VAPI_OK) { + MTL_ERROR1("%s: failed VAPI_create_addr_hndl (%s)\n", __func__, + VAPI_strerror_sym(ret)); + return ret; + } + return VAPI_OK; +} + +VAPI_ret_t osmt_mtl_mad_send(osmt_mtl_mad_res_t * res, VAPI_wr_id_t id, + void *mad, VAPI_qp_num_t dest_qp, IB_sl_t sl, + u_int32_t dest_qkey, VAPI_ud_av_hndl_t avh) +{ + VAPI_sr_desc_t sr; + VAPI_sg_lst_entry_t sg_entry; + VAPI_ret_t ret; + + /* building SEND request */ + sr.opcode = VAPI_SEND; + sr.remote_ah = avh; + sr.remote_qp = dest_qp; + sr.remote_qkey = dest_qkey; + + sr.id = id; + sr.set_se = FALSE; + sr.fence = FALSE; + sr.comp_type = VAPI_SIGNALED; + sr.sg_lst_len = 1; + sr.sg_lst_p = &sg_entry; + ASSERT_VOIDP2UINTN(mad); + sg_entry.addr = (VAPI_virt_addr_t) (uintn_t) (mad); + sg_entry.len = MAD_SIZE; + sg_entry.lkey = res->l_key; + + ret = VAPI_post_sr(res->hca_hndl, res->qp_hndl, &sr); + if (ret != VAPI_OK) { + MTL_ERROR1(__FUNCTION__ ": failed VAPI_post_sr (%s)\n", + VAPI_strerror_sym(ret)); + return ret; + } + + return VAPI_OK; +} + +int osmt_mtl_mad_post_recv_bufs(osmt_mtl_mad_res_t * res, void *buf_array, + u_int32_t num_o_bufs, u_int32_t size, + VAPI_wr_id_t start_id) +{ + uint32_t i; + void *cur_buf; + VAPI_rr_desc_t rr; + VAPI_sg_lst_entry_t sg_entry; + VAPI_ret_t ret; + + rr.opcode = VAPI_RECEIVE; + rr.comp_type = VAPI_SIGNALED; /* All with CQE (IB compliant) */ + rr.sg_lst_len = 1; /* single buffers */ + rr.sg_lst_p = &sg_entry; + sg_entry.lkey = res->l_key; + cur_buf = buf_array; + for (i = 0; i < num_o_bufs; i++) { + rr.id = start_id + i; /* WQE id used is the index to buffers ptr array */ + ASSERT_VOIDP2UINTN(cur_buf); + sg_entry.addr = (VAPI_virt_addr_t) (uintn_t) cur_buf; + sg_entry.len = size; + memset(cur_buf, 0x00, size); /* fill with 0 */ + ret = VAPI_post_rr(res->hca_hndl, res->qp_hndl, &rr); + if (ret != VAPI_OK) { + MTL_ERROR1(__FUNCTION__ + ": failed posting RQ WQE (%s)\n", + VAPI_strerror_sym(ret)); + return i; + } + MTL_DEBUG4(__FUNCTION__ ": posted buf at %p\n", cur_buf); + cur_buf += size; + } + + return i; /* num of buffers posted */ +} + +VAPI_ret_t osmt_mtl_mad_poll4cqe(VAPI_hca_hndl_t hca, VAPI_cq_hndl_t cq, + VAPI_wc_desc_t * wc_desc_p, + u_int32_t max_poll, u_int32_t poll_sleep, + VAPI_ud_av_hndl_t * avh_p) +{ + VAPI_ret_t ret = VAPI_CQ_EMPTY; + u_int32_t poll_cnt = 0; + + /* wait for something to arrive */ + while ((ret == VAPI_CQ_EMPTY) && (poll_cnt < max_poll)) { + ret = VAPI_poll_cq(hca, cq, wc_desc_p); + /* don't sleep if we already succeeded) */ + if (ret != VAPI_CQ_EMPTY) { + break; + } + usleep(poll_sleep); + poll_cnt++; + } + + /* if passed an AVH to destory - do it */ + if (avh_p != NULL) { + VAPI_destroy_addr_hndl(hca, *avh_p); + } + + if ((poll_cnt == max_poll) && (ret == VAPI_CQ_EMPTY)) { + MTL_DEBUG1(__FUNCTION__ + ": Failed to get completion on wq after %d polls.\n", + max_poll); + return VAPI_CQ_EMPTY; + } + + if (ret != VAPI_OK) { + MTL_DEBUG1(__FUNCTION__ + ": VAPI_poll_cq failed with ret=%s on sq_cq\n", + mtl_strerror_sym(ret)); + return ret; + } + + if (wc_desc_p->status != VAPI_SUCCESS) { + MTL_DEBUG1(__FUNCTION__ ": completion error (%d) detected\n", + wc_desc_p->status); + } + + return VAPI_OK; +} + +#endif /* OSM_VENDOR_INTF_MTL */ diff --git a/contrib/ofed/management/opensm/osmtest/osmt_multicast.c b/contrib/ofed/management/opensm/osmtest/osmt_multicast.c new file mode 100644 index 000000000000..165457c2cb6e --- /dev/null +++ b/contrib/ofed/management/opensm/osmtest/osmt_multicast.c @@ -0,0 +1,2707 @@ +/* + * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of Multicast Member testing flow.. + * + */ + +#ifndef __WIN__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include "osmtest.h" + +/********************************************************************** + **********************************************************************/ + +static void __osmt_print_all_multicast_records(IN osmtest_t * const p_osmt) +{ + uint32_t i; + ib_api_status_t status; + osmv_query_req_t req; + osmv_user_query_t user; + osmtest_req_context_t context; + ib_member_rec_t *mcast_record; + + memset(&context, 0, sizeof(context)); + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + + user.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + user.attr_offset = ib_get_attr_offset(sizeof(*mcast_record)); + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = 1; + req.flags = OSM_SA_FLAGS_SYNC; + context.p_osmt = p_osmt; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + + /* UnTrusted (SMKey of 0) - get the multicast groups */ + status = osmv_query_sa(p_osmt->h_bind, &req); + + if (status != IB_SUCCESS || context.result.status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02B5: " + "Failed getting the multicast groups records - %s/%s\n", + ib_get_err_str(status), + ib_get_err_str(context.result.status)); + return; + } + + osm_log(&p_osmt->log, OSM_LOG_INFO, + "\n |------------------------------------------|" + "\n | Remaining Multicast Groups |" + "\n |------------------------------------------|\n"); + + for (i = 0; i < context.result.result_cnt; i++) { + mcast_record = + osmv_get_query_mc_rec(context.result.p_result_madw, i); + osm_dump_mc_record(&p_osmt->log, mcast_record, OSM_LOG_INFO); + } + + /* Trusted - now get the multicast group members */ + req.sm_key = OSM_DEFAULT_SM_KEY; + status = osmv_query_sa(p_osmt->h_bind, &req); + + if (status != IB_SUCCESS || context.result.status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02B6: " + "Failed getting the multicast group members records - %s/%s\n", + ib_get_err_str(status), + ib_get_err_str(context.result.status)); + return; + } + + osm_log(&p_osmt->log, OSM_LOG_INFO, + "\n |--------------------------------------------------|" + "\n | Remaining Multicast Group Members |" + "\n |--------------------------------------------------|\n"); + + for (i = 0; i < context.result.result_cnt; i++) { + mcast_record = + osmv_get_query_mc_rec(context.result.p_result_madw, i); + osm_dump_mc_record(&p_osmt->log, mcast_record, OSM_LOG_INFO); + } + +} + +/********************************************************************** + **********************************************************************/ + +static cl_status_t +__match_mgids(IN const void *const p_object, IN void *context) +{ + ib_gid_t *p_mgid_context = (ib_gid_t *) context; + ib_gid_t *p_mgid_list_item = (ib_gid_t *) p_object; + int32_t count; + + count = memcmp(p_mgid_context, p_mgid_list_item, sizeof(ib_gid_t)); + if (count == 0) + return CL_SUCCESS; + else + return CL_NOT_FOUND; +} + +/********************************************************************** + **********************************************************************/ + +ib_api_status_t osmt_query_mcast(IN osmtest_t * const p_osmt) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + osmtest_req_context_t context; + ib_member_rec_t *p_rec; + uint32_t i, num_recs = 0; + cl_list_t mgids_list; + cl_list_t *p_mgids_list; + cl_list_iterator_t p_mgids_res; + cl_status_t cl_status; + cl_map_item_t *p_item, *p_next_item; + osmtest_mgrp_t *p_mgrp; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * Do a blocking query for all Multicast Records in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + + context.p_osmt = p_osmt; + user.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + user.attr_offset = ib_get_attr_offset(sizeof(ib_member_rec_t)); + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + + status = osmv_query_sa(p_osmt->h_bind, &req); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0203: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0264: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s.\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + + /* ok we have got something */ + /* First Delete the old MGID Table */ + p_next_item = cl_qmap_head(&p_osmt->exp_subn.mgrp_mlid_tbl); + while (p_next_item != cl_qmap_end(&p_osmt->exp_subn.mgrp_mlid_tbl)) { + p_item = p_next_item; + p_next_item = cl_qmap_next(p_item); + cl_qmap_remove_item(&p_osmt->exp_subn.mgrp_mlid_tbl, p_item); + free(p_item); + + } + + cl_list_construct(&mgids_list); + cl_list_init(&mgids_list, num_recs); + p_mgids_list = &mgids_list; + num_recs = context.result.result_cnt; + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Received %u records\n", + num_recs); + + for (i = 0; i < num_recs; i++) { + p_rec = osmv_get_query_result(context.result.p_result_madw, i); + p_mgids_res = + cl_list_find_from_head(p_mgids_list, __match_mgids, + &(p_rec->mgid)); + /* If returns iterator other than end of list, same mgid exists already */ + if (p_mgids_res != cl_list_end(p_mgids_list)) { + char gid_str[INET6_ADDRSTRLEN]; + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0265: " + "MCG MGIDs are the same - invalid MGID : %s\n", + inet_ntop(AF_INET6, p_rec->mgid.raw, gid_str, + sizeof gid_str)); + status = IB_ERROR; + goto Exit; + + } + osm_dump_mc_record(&p_osmt->log, p_rec, OSM_LOG_VERBOSE); + cl_status = cl_list_insert_head(p_mgids_list, &(p_rec->mgid)); + if (cl_status) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0205: " + "Could not add MGID to cl_list\n"); + status = IB_ERROR; + goto Exit; + } + p_mgrp = (osmtest_mgrp_t *) malloc(sizeof(*p_mgrp)); + if (!p_mgrp) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0204: " + "Could not allocate new MCG\n"); + status = IB_ERROR; + goto Exit; + } + memcpy(&p_mgrp->mcmember_rec, p_rec, + sizeof(p_mgrp->mcmember_rec)); + cl_qmap_insert(&p_osmt->exp_subn.mgrp_mlid_tbl, + cl_ntoh16(p_rec->mlid), &p_mgrp->map_item); + } + +Exit: + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ + +/* given a multicast request send and wait for response. */ +ib_api_status_t +osmt_send_mcast_request(IN osmtest_t * const p_osmt, + IN uint8_t is_set, + IN ib_member_rec_t * p_mc_req, + IN uint64_t comp_mask, OUT ib_sa_mad_t * p_res) +{ + osmtest_req_context_t context; + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * Do a blocking query for this record in the subnet. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&context, 0, sizeof(context)); + memset(p_res, 0, sizeof(ib_sa_mad_t)); + + context.p_osmt = p_osmt; + + user.p_attr = p_mc_req; + user.comp_mask = comp_mask; + + if (is_set == 1) { + req.query_type = OSMV_QUERY_UD_MULTICAST_SET; + } else if (is_set == 0) { + req.query_type = OSMV_QUERY_UD_MULTICAST_DELETE; + } else if (is_set == 0xee) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Set USER DEFINED QUERY\n"); + req.query_type = OSMV_QUERY_USER_DEFINED; + user.method = IB_MAD_METHOD_GET; + user.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + user.attr_offset = ib_get_attr_offset(sizeof(ib_member_rec_t)); + } else if (is_set == 0xff) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Set USER DEFINED QUERY\n"); + req.query_type = OSMV_QUERY_USER_DEFINED; + user.method = IB_MAD_METHOD_SET; + user.attr_id = IB_MAD_ATTR_MCMEMBER_RECORD; + user.attr_offset = ib_get_attr_offset(sizeof(ib_member_rec_t)); + } + + /* TODO : Check the validity of all user fields in order to use + OSMV_QUERY_USER_DEFINED + p_user_query = ( osmv_user_query_t * ) p_query_req->p_query_input; + if (p_user_query->method) sa_mad_data.method = p_user_query->method; + sa_mad_data.attr_offset = p_user_query->attr_offset; + sa_mad_data.attr_id = p_user_query->attr_id; + sa_mad_data.comp_mask = p_user_query->comp_mask; + sa_mad_data.p_attr = p_user_query->p_attr; + */ + + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + + status = osmv_query_sa(p_osmt->h_bind, &req); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0206: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + /* ok it worked */ + memcpy(p_res, + osm_madw_get_mad_ptr(context.result.p_result_madw), + sizeof(ib_sa_mad_t)); + + status = context.result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0224: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ + +void +osmt_init_mc_query_rec(IN osmtest_t * const p_osmt, + IN OUT ib_member_rec_t * p_mc_req) +{ + /* use default values so we can change only what we want later */ + memset(p_mc_req, 0, sizeof(ib_member_rec_t)); + + /* we leave the MGID to the user */ + memcpy(&p_mc_req->port_gid.unicast.interface_id, + &p_osmt->local_port.port_guid, + sizeof(p_osmt->local_port.port_guid) + ); + + /* use our own subnet prefix: */ + p_mc_req->port_gid.unicast.prefix = CL_HTON64(0xFE80000000000000ULL); + + /* ib_net32_t qkey; */ + /* ib_net16_t mlid; - we keep it zero for upper level to decide. */ + /* uint8_t mtu; - keep it zero means - anything you have please. */ + /* uint8_t tclass; can leave as zero for now (between subnets) */ + /* ib_net16_t pkey; leave as zero */ + p_mc_req->rate = IB_LINK_WIDTH_ACTIVE_4X; + /* uint8_t pkt_life; zero means greater than zero ... */ + /* ib_net32_t sl_flow_hop; keep it all zeros */ + /* we want to use a link local scope: 0x02 */ + p_mc_req->scope_state = ib_member_set_scope_state(0x02, 0); +} + +/*********************************************************************** + * UD Multicast testing flow: + * o15.0.1.3: + * - Request new MCG with not enough components in comp_mask : + * ERR_INSUFFICIENT_COMPONENTS + * o15.0.1.8: + * - Request a join with irrelevant RATE and get a ERR_INVALID_REQ + * o15.0.1.4: + * - Create an MGID by asking for a join with MGID = 0 + * providing P_Key, Q_Key, SL, FlowLabel, Tclass. + * o15.0.1.5: + * - Check the returned MGID is valid. (p 804) + * o15.0.1.6: + * - Create a new MCG with valid requested MGID. + * - Try to create a new MCG with invalid MGID : get back ERR_REQ_INVALID + * - Try again with MGID prefix = 0xA01B (maybe 0x1BA0 little or big ?) + * - Try to create again the already created group: ERR_REQ_INVALID + * o15.0.1.7 - implicitlly checked during the prev steps. + * o15.0.1.9 + * - Create MCG with Invalid JoinState.FullMember != 1 : get ERR_REQ_INVALID + * o15.0.1.10 - can't check on a single client . + * o15.0.1.11: + * - Try to join into a MGID that exists with JoinState=SendOnlyMember - + * see that it updates JoinState. What is the routing change? + * - We can not check simple join since we have only one tester (for now) + * o15.0.1.12: + * - The last join should have a special treatment in the SA (sender only) + * but what is it ? + * o15.0.1.13: + * - Try joining with wrong rate - ERR_REQ_INVALID + * o15.0.1.14: + * - Try partial delete - actually updating the join state. check it. + * - Register by InformInfo flow to receive trap 67 on MCG delete. + * - Try full delete (JoinState and should be 0) + * - Wait for trap 67. + * - Try joining (not full mem) again to see the group was deleted. + * (should fail - o15.0.1.13) + * o15.0.1.15: + * - Try deletion of the IPoIB MCG and get: ERR_REQ_INVALID + * o15.0.1.16: + * - Try GetTable with PortGUID wildcarded and get back some groups. + ***********************************************************************/ + +/* The following macro can be used only within the osmt_run_mcast_flow() function */ +#define IS_IPOIB_MGID(p_mgid) \ + ( !memcmp(&osm_ipoib_good_mgid, (p_mgid), sizeof(osm_ipoib_good_mgid)) || \ + !memcmp(&osm_ts_ipoib_good_mgid, (p_mgid), sizeof(osm_ts_ipoib_good_mgid)) ) + +ib_api_status_t osmt_run_mcast_flow(IN osmtest_t * const p_osmt) +{ + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + ib_api_status_t status; + ib_member_rec_t mc_req_rec; + ib_member_rec_t *p_mc_res; + ib_sa_mad_t res_sa_mad; + uint64_t comp_mask = 0; + ib_net64_t remote_port_guid = 0x0; + cl_qmap_t *p_mgrp_mlid_tbl; + osmtest_mgrp_t *p_mgrp; + ib_gid_t special_mgid, tmp_mgid, proxy_mgid; + ib_net16_t invalid_mlid = 0x0; + ib_net16_t max_mlid = cl_hton16(0xFFFE), tmp_mlid; + boolean_t ReachedMlidLimit = FALSE; + int start_cnt = 0, cnt, middle_cnt = 0, end_cnt = 0; + int start_ipoib_cnt = 0, end_ipoib_cnt = 0; + int mcg_outside_test_cnt = 0, fail_to_delete_mcg = 0; + osmtest_req_context_t context; + ib_node_record_t *p_rec; + uint32_t num_recs = 0, i; + uint8_t mtu_phys = 0, rate_phys = 0; + cl_map_t test_created_mlids; /* List of all mlids created in this test */ + ib_member_rec_t *p_recvd_rec; + boolean_t got_error = FALSE; + + static ib_gid_t good_mgid = { + { + 0xFF, 0x12, 0xA0, 0x1C, + 0xFE, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x12, 0x34, 0x56, 0x78} + }; + static ib_gid_t osm_ipoib_mgid = { + { + 0xff, /* multicast field */ + 0x12, /* scope */ + 0x40, 0x1b, /* IPv4 signature */ + 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */ + 0xff, 0xff, 0xff, 0xee, /* 32 bit IPv4 broadcast address */ + }, + }; + static ib_gid_t osm_ts_ipoib_good_mgid = { + { + 0xff, /* multicast field */ + 0x12, /* non-permanent bit,scope */ + 0x40, 0x1b, /* IPv4 signature */ + 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */ + 0x00, 0x00, 0x00, 0x01, /* 32 bit IPv4 broadcast address */ + }, + }; + static ib_gid_t osm_ipoib_good_mgid = { + { + 0xff, /* multicast field */ + 0x12, /* non-permanent bit,scope */ + 0x40, 0x1b, /* IPv4 signature */ + 0xff, 0xff, /* 16 bits of P_Key (to be filled in) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 48 bits of zeros */ + 0xff, 0xff, 0xff, 0xff, /* 32 bit IPv4 broadcast address */ + }, + }; + static ib_gid_t osm_link_local_mgid = { + { + 0xFF, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01}, + }; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, "GetTable of all current MCGs...\n"); + status = osmt_query_mcast(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 2FF " + "GetTable of all records has failed!\n"); + goto Exit; + } + + /* Initialize the test_created_mgrps map */ + cl_map_construct(&test_created_mlids); + cl_map_init(&test_created_mlids, 1000); + + p_mgrp_mlid_tbl = &p_osmt->exp_subn.mgrp_mlid_tbl; + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + /* Only when we are on single mode check flow - do the count comparison, otherwise skip */ + if (p_osmt->opt.mmode == 1 || p_osmt->opt.mmode == 3) { + start_cnt = cl_qmap_count(p_mgrp_mlid_tbl); + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, "(start): " + "Number of MC Records found in SA DB is %d\n", + start_cnt); + } + + /* This flow is being added due to bug discovered using SilverStorm stack - + The bug was initializing MCast with MTU & RATE min values that do + not match the subnet capability, even though that OpenSM + reponds with the correct value it does not store it in the MCG. + We want the check a join request to already existing group (ipoib) + without using MTU or RATE then getting response from OpenSM with + the correct values then join again with them and get IB_SUCCESS + all the way + */ + + /* First validate IPoIB exist in the SA DB */ + p_mgrp = (osmtest_mgrp_t *) cl_qmap_head(p_mgrp_mlid_tbl); + /* scan all available multicast groups in the DB and fill in the table */ + while (p_mgrp != (osmtest_mgrp_t *) cl_qmap_end(p_mgrp_mlid_tbl)) { + /* search for ipoib mgid */ + if (IS_IPOIB_MGID(&p_mgrp->mcmember_rec.mgid)) { + start_ipoib_cnt++; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Non-IPoIB MC Groups exist: mgid=%s\n", + inet_ntop(AF_INET6, + p_mgrp->mcmember_rec.mgid.raw, + gid_str, sizeof gid_str)); + mcg_outside_test_cnt++; + } + + p_mgrp = (osmtest_mgrp_t *) cl_qmap_next(&p_mgrp->map_item); + } + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Found %d non-IPoIB MC Groups\n", mcg_outside_test_cnt); + + if (start_ipoib_cnt) { + /* o15-0.2.4 - Check a join request to already created MCG */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Found IPoIB MC Group, so we run SilverStorm Bug Flow...\n"); + /* Try to join first like IPoIB of SilverStorm */ + memcpy(&mc_req_rec.mgid, &osm_ipoib_good_mgid, + sizeof(ib_gid_t)); + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, + IB_MC_REC_STATE_FULL_MEMBER); + comp_mask = + IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_JOIN_STATE; + + status = osmt_send_mcast_request(p_osmt, 0xff, /* User Defined query Set */ + &mc_req_rec, + comp_mask, &res_sa_mad); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Joining an existing IPoIB multicast group\n"); + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Sent Join request with :\n\t\tport_gid=%s, mgid=%s\n" + "\t\tjoin state= 0x%x, response is : %s\n", + inet_ntop(AF_INET6, mc_req_rec.port_gid.raw, + gid_str, sizeof gid_str), + inet_ntop(AF_INET6, mc_req_rec.mgid.raw, + gid_str2, sizeof gid_str2), + (mc_req_rec.scope_state & 0x0F), + ib_get_err_str(status)); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02B3: " + "Failed joining existing IPoIB MCGroup - got %s\n", + ib_get_err_str(status)); + goto Exit; + } + /* Check MTU & Rate Value and resend with SA suggested values */ + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + /* Prepare the mc_req_rec for the rest of the flow */ + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + /* + We simulate the same situation as in SilverStorm - a response with the + exact RATE & MTU as the SA responded with. Actually the query + has included some more fields but we know that problem was + genereated by the RATE + */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Received attributes of MCG : \n\t\tMTU=0x%02X, RATE=0x%02X\n", + p_mc_res->mtu, p_mc_res->rate); + + mc_req_rec.mtu = p_mc_res->mtu; + mc_req_rec.rate = p_mc_res->rate; + /* Set feasible mtu & rate that will allow check the + exact statement of OpenSM */ + mtu_phys = p_mc_res->mtu; + rate_phys = p_mc_res->rate; + + memcpy(&mc_req_rec.mgid, &osm_ipoib_good_mgid, + sizeof(ib_gid_t)); + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, + IB_MC_REC_STATE_FULL_MEMBER); + comp_mask = + IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_MTU_SEL | + IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_RATE_SEL | + IB_MCR_COMPMASK_RATE; + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Sending attributes of MCG : \n\t\tMTU=0x%02X, RATE=0x%02X\n", + mc_req_rec.mtu, mc_req_rec.rate); + status = osmt_send_mcast_request(p_osmt, 0xff, /* User Defined query */ + &mc_req_rec, + comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Sent Join request using response values, response is : %s\n", + ib_get_err_str(status)); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02EF: " + "Query as Full Member of already existing " + "ipoib group gid %s has failed\n", + inet_ntop(AF_INET6, mc_req_rec.mgid.raw, + gid_str, sizeof gid_str)); + goto Exit; + } + /* We do not want to leave the MCG since its IPoIB */ + } + + /**************************************************************************/ + /* Check Get with invalid mlid */ + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Get with invalid mlid...\n"); + /* Request Get */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + mc_req_rec.mlid = invalid_mlid; + comp_mask = IB_MCR_COMPMASK_MLID; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 0xee, /* User Defined query Get */ + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status == IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 2E0 " + "SubnAdmGet with invalid mlid 0x%x succeeded\n", + cl_ntoh16(mc_req_rec.mlid)); + status = IB_ERROR; + goto Exit; + } + + /* Prepare the mc_req_rec for the rest of the flow */ + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + /**************************************************************************/ + /* Check Get with invalid port guid */ + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Get with invalid port guid (0x0) but valid interface ID : 0x%" + PRIx64 "...\n", + cl_ntoh64(mc_req_rec.port_gid.unicast.interface_id)); + + /* Request Get */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + memset(&mc_req_rec.port_gid.unicast.interface_id, 0, + sizeof(ib_net64_t)); + comp_mask = IB_MCR_COMPMASK_GID; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 0xee, /* User Defined query Get */ + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status == IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 2E4 " + "SubnAdmGet with invalid port guid succeeded\n"); + status = IB_ERROR; + goto Exit; + } + + /* Prepare the mc_req_rec for the rest of the flow */ + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + /**************************************************************************/ + + /* o15.0.1.3: */ + /* - Request Join with insufficient comp_mask */ + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Join with insufficient comp mask qkey & pkey (o15.0.1.3)...\n"); + + /* no MGID */ + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + comp_mask = IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | + /* IB_MCR_COMPMASK_QKEY | */ + /* IB_MCR_COMPMASK_PKEY | intentionaly missed to raise the error */ + IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (res_sa_mad.status & IB_SMP_STATUS_MASK)) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02EE: " + "Expectedd REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Join with insufficient comp mask - sl (15.0.1.3)...\n"); + + /* no MGID */ + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | + /* IB_MCR_COMPMASK_SL | */ + IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (res_sa_mad.status & IB_SMP_STATUS_MASK)) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02ED: " + "Expectedd REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + /* no MGID */ + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + + mc_req_rec.mgid.raw[15] = 0x01; + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Join with insufficient comp mask - flow label (o15.0.1.3)...\n"); + + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | + /* IB_MCR_COMPMASK_FLOW | intentionaly missed to raise the error */ + IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (res_sa_mad.status & IB_SMP_STATUS_MASK)) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02EC: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Join with insufficient comp mask - tclass (o15.0.1.3)...\n"); + + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | + /* IB_MCR_COMPMASK_TCLASS | Intentionally missed to raise an error */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (res_sa_mad.status & IB_SMP_STATUS_MASK)) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02EA: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Join with insufficient comp mask - tclass qkey (o15.0.1.3)...\n"); + + /* no MGID */ + /* memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); */ + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + comp_mask = IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | + /* IB_MCR_COMPMASK_QKEY | intentionaly missed to raise the error */ + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | + /* IB_MCR_COMPMASK_TCLASS | intentionaly missed to raise the error */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (res_sa_mad.status & IB_SMP_STATUS_MASK)) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02E9: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* o15.0.1.8: */ + /* - Request join with irrelevant RATE : get a ERR_INSUFFICIENT_COMPONENTS */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Join with unrealistic rate (o15.0.1.8)...\n"); + + /* impossible requested rate */ + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_12X | IB_PATH_SELECTOR_GREATER_THAN << 6; + + comp_mask = IB_MCR_COMPMASK_GID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0207: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_REQ_INVALID got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* Check Valid value which is unreasonable now */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Join with unrealistic rate 120GB (o15.0.1.8)...\n"); + + /* impossible requested rate */ + mc_req_rec.rate = + IB_PATH_RECORD_RATE_120_GBS | IB_PATH_SELECTOR_GREATER_THAN << 6; + + comp_mask = IB_MCR_COMPMASK_GID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0208: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_REQ_INVALID got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* Check Valid value which is unreasonable now */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Join with less than min rate 2.5GB (o15.0.1.8)...\n"); + + /* impossible requested rate */ + mc_req_rec.rate = + IB_PATH_RECORD_RATE_2_5_GBS | IB_PATH_SELECTOR_LESS_THAN << 6; + + comp_mask = IB_MCR_COMPMASK_GID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02AB: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_REQ_INVALID got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* Checking above max value of MTU which is impossible */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Join with unrealistic mtu : \n\t\tmore than 4096 -" + " max (o15.0.1.8)...\n"); + + /* impossible requested mtu */ + mc_req_rec.mtu = IB_MTU_LEN_4096 | IB_PATH_SELECTOR_GREATER_THAN << 6; + + comp_mask = IB_MCR_COMPMASK_GID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | IB_MCR_COMPMASK_MTU; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02AC: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_REQ_INVALID got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad)) + ); + status = IB_ERROR; + goto Exit; + } + + /* Checking below min value of MTU which is impossible */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Join with unrealistic mtu : \n\t\tless than 256 -" + " min (o15.0.1.8)...\n"); + + /* impossible requested mtu */ + mc_req_rec.mtu = IB_MTU_LEN_256 | IB_PATH_SELECTOR_LESS_THAN << 6; + + comp_mask = IB_MCR_COMPMASK_GID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | IB_MCR_COMPMASK_MTU; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02AD: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_REQ_INVALID got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Join with unrealistic mtu (o15.0.1.8)...\n"); + + /* impossible requested mtu */ + mc_req_rec.mtu = 0x6 | IB_PATH_SELECTOR_GREATER_THAN << 6; + + comp_mask = IB_MCR_COMPMASK_GID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | IB_MCR_COMPMASK_MTU; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02AE: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_REQ_INVALID got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } +#if 0 + /* Currently PacketLifeTime isn't checked in opensm */ + /* Check PacketLifeTime as 0 */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Create with unrealistic packet life value less than 0 (o15.0.1.8)...\n"); + + /* impossible requested packet life */ + mc_req_rec.pkt_life = 0 | IB_PATH_SELECTOR_LESS_THAN << 6; + + comp_mask = IB_MCR_COMPMASK_GID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_LIFE | IB_MCR_COMPMASK_LIFE_SEL; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02AF: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_REQ_INVALID got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } +#endif + + /* o15.0.1.4: */ + /* - Create an MGID by asking for a join with MGID = 0 */ + /* providing P_Key, Q_Key, SL, FlowLabel, Tclass. */ + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Create given MGID=0 skip service level (o15.0.1.4)...\n"); + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + /* no MGID */ + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | + /* IB_MCR_COMPMASK_SL | Intentionally missed */ + IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (res_sa_mad.status & IB_SMP_STATUS_MASK)) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02A8: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* Check that no same MCG in the SMDB */ + status = osmt_query_mcast(p_osmt); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02AA: " + "Could not get all MC Records in subnet, got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* Only when we are on single mode check flow - do the count comparison, otherwise skip */ + if (p_osmt->opt.mmode == 1 || p_osmt->opt.mmode == 3) { + middle_cnt = cl_qmap_count(&p_osmt->exp_subn.mgrp_mlid_tbl); + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, "(post false create): " + "Number of MC Records found in SA DB is %d\n", + middle_cnt); + if (middle_cnt != start_cnt) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Got different number of records stored in SA DB (before any creation)\n" + "Instead of %d got %d\n", start_cnt, + middle_cnt); + } + } + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Create given MGID=0 skip Qkey and Pkey (o15.0.1.4)...\n"); + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + /* no MGID */ + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + comp_mask = IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | + /* IB_MCR_COMPMASK_QKEY | */ + /* IB_MCR_COMPMASK_PKEY | Intentionally missed */ + IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (res_sa_mad.status & IB_SMP_STATUS_MASK)) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02A7: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* Bad Query o15.0.1.4 */ + + status = osmt_query_mcast(p_osmt); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Create given MGID=0 skip TClass (o15.0.1.4)...\n"); + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + /* no MGID */ + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_QKEY | + IB_MCR_COMPMASK_PKEY | + IB_MCR_COMPMASK_SL | + IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | + /* IB_MCR_COMPMASK_TCLASS | Intentionally missed */ + /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR || + ((ib_net16_t) (res_sa_mad.status & IB_SMP_STATUS_MASK)) != + IB_SA_MAD_STATUS_INSUF_COMPS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02A6: " + "Expected REMOTE ERROR IB_SA_MAD_STATUS_INSUF_COMPS got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Create given MGID=0 valid Set several options :\n\t\t" + "First above min RATE, Second less than max RATE\n\t\t" + "Third above min MTU, Second less than max MTU\n\t\t" + "Fifth exact MTU & RATE feasible, Sixth exact RATE feasible\n\t\t" + "Seventh exact MTU feasible (o15.0.1.4)...\n"); + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_1X | IB_PATH_SELECTOR_GREATER_THAN << 6; + + comp_mask = IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02A5: " + "Failed to create MCG for MGID=0 with higher than minimum RATE - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_recvd_rec->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_recvd_rec->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_recvd_rec->mlid), + p_recvd_rec); + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_12X | IB_PATH_SELECTOR_LESS_THAN << 6; + + comp_mask = IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0211: " + "Failed to create MCG for MGID=0 with less than highest RATE - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_recvd_rec->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_recvd_rec->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_recvd_rec->mlid), + p_recvd_rec); + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + + mc_req_rec.mtu = IB_MTU_LEN_4096 | IB_PATH_SELECTOR_LESS_THAN << 6; + + comp_mask = IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | IB_MCR_COMPMASK_MTU; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0238: " + "Failed to create MCG for MGID=0 with less than highest MTU - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_recvd_rec->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_recvd_rec->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_recvd_rec->mlid), + p_recvd_rec); + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + mc_req_rec.mtu = IB_MTU_LEN_256 | IB_PATH_SELECTOR_GREATER_THAN << 6; + + comp_mask = IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | IB_MCR_COMPMASK_MTU; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0239: " + "Failed to create MCG for MGID=0 with higher than lowest MTU - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_recvd_rec->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_recvd_rec->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_recvd_rec->mlid), + p_recvd_rec); + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + /* Using Exact feasible MTU & RATE */ + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Using Exact feasible MTU & RATE: " + "MTU = 0x%02X, RATE = 0x%02X\n", mtu_phys, rate_phys); + + mc_req_rec.mtu = mtu_phys; + mc_req_rec.rate = rate_phys; + + comp_mask = IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | + IB_MCR_COMPMASK_MTU | + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0240: " + "Failed to create MCG for MGID=0 with exact MTU & RATE - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_recvd_rec->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_recvd_rec->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_recvd_rec->mlid), + p_recvd_rec); + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + /* Using Exact feasible RATE */ + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Using Exact feasible RATE: 0x%02X\n", rate_phys); + + mc_req_rec.rate = rate_phys; + + comp_mask = IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0241: " + "Failed to create MCG for MGID=0 with exact RATE - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_recvd_rec->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_recvd_rec->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_recvd_rec->mlid), + p_recvd_rec); + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + /* Using Exact feasible MTU */ + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Using Exact feasible MTU: 0x%02X\n", mtu_phys); + + mc_req_rec.mtu = mtu_phys; + + comp_mask = IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | IB_MCR_COMPMASK_MTU; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0242: " + "Failed to create MCG for MGID=0 with exact MTU - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_recvd_rec->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_recvd_rec->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_recvd_rec->mlid), + p_recvd_rec); + + /* o15.0.1.5: */ + /* - Check the returned MGID is valid. (p 804) */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Validating resulting MGID (o15.0.1.5)...\n"); + /* prefix 0xFF1 Scope 0xA01B */ + /* Since we did not directly specified SCOPE in comp mask + we should get the comp mask that is link-local scope */ + if ((p_mc_res->mgid.multicast.header[0] != 0xFF) || + (p_mc_res->mgid.multicast.header[1] != 0x12) || + (p_mc_res->mgid.multicast.raw_group_id[0] != 0xA0) || + (p_mc_res->mgid.multicast.raw_group_id[1] != 0x1B)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0209: " + "Validating MGID failed. MGID:%s\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str)); + status = IB_ERROR; + goto Exit; + } + + /* Good Flow - mgid is 0 while giving all required fields for join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + /* Using feasible GREATER_THAN 0 packet lifitime */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Create given MGID=0 (o15.0.1.4)...\n"); + + status = osmt_query_mcast(p_osmt); + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + + /* no MGID */ + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + mc_req_rec.pkt_life = 0 | IB_PATH_SELECTOR_GREATER_THAN << 6; + + comp_mask = IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_LIFE | IB_MCR_COMPMASK_LIFE_SEL; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0210: " + "Failed to create MCG for MGID=0 - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_recvd_rec->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_recvd_rec->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_recvd_rec->mlid), + p_recvd_rec); + + /* o15.0.1.6: */ + /* - Create a new MCG with valid requested MGID. */ + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + mc_req_rec.mgid = good_mgid; + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Create given valid MGID=%s (o15.0.1.6)...\n", + inet_ntop(AF_INET6, mc_req_rec.mgid.raw, gid_str, + sizeof gid_str)); + + /* Before creation, need to check that this group doesn't exist */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Verifying that MCGroup with this MGID doesn't exist by trying to Join it (o15.0.1.13)...\n"); + + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_NON_MEMBER); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, /* join */ + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0301: " + "Tried joining group that shouldn't have existed - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* Set State to full member to allow group creation */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Now creating group with given valid MGID=%s (o15.0.1.6)...\n", + inet_ntop(AF_INET6, mc_req_rec.mgid.raw, gid_str, + sizeof gid_str)); + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0211: " + "Failed to create MCG for MGID=%s (o15.0.1.6) - got %s/%s\n", + inet_ntop(AF_INET6, good_mgid.raw, gid_str, + sizeof gid_str), ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_recvd_rec->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_recvd_rec->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_recvd_rec->mlid), + p_recvd_rec); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Validating resulting MGID (o15.0.1.6)...\n"); + /* prefix 0xFF1 Scope 0xA01B */ + if ((p_mc_res->mgid.multicast.header[0] != 0xFF) || (p_mc_res->mgid.multicast.header[1] != 0x12) || /* HACK hardcoded scope = 0x02 */ + (p_mc_res->mgid.multicast.raw_group_id[0] != 0xA0) || + (p_mc_res->mgid.multicast.raw_group_id[1] != 0x1C)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0212: " + "Validating MGID failed. MGID:%s\n", + inet_ntop(AF_INET6, p_mc_res->mgid.raw, gid_str, + sizeof gid_str)); + status = IB_ERROR; + goto Exit; + } + + /* - Try to create a new MCG with invalid MGID : get back ERR_REQ_INVALID */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking BAD MGID=0xFA..... (o15.0.1.6)...\n"); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + + mc_req_rec.mgid.raw[0] = 0xFA; + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0213: " + "Failed to recognize MGID error for MGID=0xFA - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* - Try again with MGID prefix = 0xA01B (maybe 0x1BA0 little or big ?) */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking BAD MGID=0xFF12A01B..... with link-local scope (o15.0.1.6)...\n"); + + mc_req_rec.mgid.raw[0] = 0xFF; + mc_req_rec.mgid.raw[3] = 0x1B; + comp_mask = comp_mask | IB_MCR_COMPMASK_SCOPE; + mc_req_rec.scope_state = mc_req_rec.scope_state & 0x2F; /* local scope */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0214: " + "Failed to recognize MGID error for A01B with link-local bit (status %s) (rem status %s)\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* Change the mgid prefix - get back ERR_REQ_INVALID */ + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking BAD MGID PREFIX=0xEF... (o15.0.1.6)...\n"); + + mc_req_rec.mgid = good_mgid; + + mc_req_rec.mgid.raw[0] = 0xEF; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0215: " + "Failed to recognize MGID PREFIX error for MGID=0xEF - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* Change the scope to reserved - get back VALID REQ */ + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking local scope with full member \n\t\tand valid mgid %s" + " ... (o15.0.1.6)...\n", + inet_ntop(AF_INET6, mc_req_rec.mgid.raw, gid_str, + sizeof gid_str)); + + mc_req_rec.mgid = good_mgid; + + mc_req_rec.mgid.raw[1] = 0x1F; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0216: " + "Failed to create MCG for MGID=%s - got %s/%s\n", + inet_ntop(AF_INET6, good_mgid.raw, gid_str, + sizeof gid_str), ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_recvd_rec->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_recvd_rec->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_recvd_rec->mlid), + p_recvd_rec); + + /* Change the flags to invalid value 0x2 - get back INVALID REQ */ + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking invalid flags=0xFF 22 ... (o15.0.1.6)...\n"); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + + mc_req_rec.mgid = good_mgid; + + mc_req_rec.mgid.raw[1] = 0x22; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0217: " + "Failed to recognize create with invalid flags value 0x2 - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* Change the MGID to link local MGID - get back VALID REQ */ + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking link local MGID 0xFF02:0:0:0:0:0:0:1 (o15.0.1.6)...\n"); + + mc_req_rec.mgid = osm_link_local_mgid; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0218: " + "Failed to create MCG for MGID=0xFF02:0:0:0:0:0:0:1 - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_recvd_rec->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_recvd_rec->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_recvd_rec->mlid), + p_recvd_rec); + + /* o15.0.1.7 - implicitlly checked during the prev steps. */ + /* o15.0.1.8 - implicitlly checked during the prev steps. */ + + /* o15.0.1.9 */ + /* - Create MCG with Invalid JoinState.FullMember != 1 : get ERR_REQ_INVALID */ + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking new MGID with invalid join state (o15.0.1.9)...\n"); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + + mc_req_rec.mgid = good_mgid; + mc_req_rec.mgid.raw[12] = 0xFF; + mc_req_rec.scope_state = 0x22; /* link-local scope, non-member state */ + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0219: " + "Failed to recognize create with JoinState != FullMember - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* Lets try a valid join scope state */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking new MGID with valid join state (o15.0.1.9)...\n"); + + mc_req_rec.mgid = good_mgid; + mc_req_rec.scope_state = 0x23; /* link-local scope, non member and full member */ + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0220: " + "Failed to create MCG with valid join state 0x3 - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_recvd_rec->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_recvd_rec->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_recvd_rec->mlid), + p_recvd_rec); + + /* Lets try another invalid join scope state */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking new MGID with invalid join state (o15.0.1.9)...\n"); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + + /* We have created a new MCG so now we need different mgid when cresting group otherwise it will be counted as join request . */ + mc_req_rec.mgid = good_mgid; + mc_req_rec.mgid.raw[12] = 0xFC; + + mc_req_rec.scope_state = 0x24; /* link-local scope, send only member */ + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0221: " + "Failed to recognize create with JoinState != FullMember - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* Lets try another valid join scope state */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking new MGID creation with valid join state (o15.0.2.3)...\n"); + + mc_req_rec.mgid = good_mgid; + mc_req_rec.mgid.raw[12] = 0xFB; + memcpy(&special_mgid, &mc_req_rec.mgid, sizeof(ib_gid_t)); + mc_req_rec.scope_state = 0x2F; /* link-local scope, Full member with all other bits turned on */ + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0222: " + "Failed to create MCG with valid join state 0xF - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = + (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, p_recvd_rec->mgid.raw, gid_str, + sizeof gid_str), cl_ntoh16(p_recvd_rec->mlid)); + cl_map_insert(&test_created_mlids, cl_ntoh16(p_recvd_rec->mlid), + p_recvd_rec); + + /* o15.0.1.10 - can't check on a single client .-- obsolete - + checked by SilverStorm bug o15-0.2.4, never the less recheck */ + /* o15-0.2.4 - Check a join request to already created MCG */ + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, "Check o15-0.2.4 statement...\n"); + /* Try to join */ + memcpy(&mc_req_rec.mgid, &p_mc_res->mgid, sizeof(ib_gid_t)); + /* Request Join */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_NON_MEMBER); + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_JOIN_STATE; + + status = osmt_send_mcast_request(p_osmt, 0x1, /* SubnAdmSet */ + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02CC: " + "Failed to join MCG with valid req, returned status = %s\n", + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + if ((p_mc_res->scope_state & 0x7) != 0x7) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02D0: " + "Validating JoinState update failed. " + "Expected 0x27 got 0x%02X\n", + p_mc_res->scope_state); + status = IB_ERROR; + goto Exit; + } + + /* o15.0.1.11: */ + /* - Try to join into a MGID that exists with JoinState=SendOnlyMember - */ + /* see that it updates JoinState. What is the routing change? */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Retry of existing MGID - See JoinState update (o15.0.1.11)...\n"); + + mc_req_rec.mgid = good_mgid; + + /* first, make sure that the group exists */ + mc_req_rec.scope_state = 0x21; + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02CD: " + "Failed to create/join as full member - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + mc_req_rec.scope_state = 0x22; /* link-local scope, non-member */ + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02D1: " + "Failed to update existing MGID - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Validating Join State update with NonMember (o15.0.1.11)...\n"); + + if (p_mc_res->scope_state != 0x23) { /* scope is LSB */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02CE: " + "Validating JoinState update failed. Expected 0x23 got: 0x%02X\n", + p_mc_res->scope_state); + status = IB_ERROR; + goto Exit; + } + + /* Try delete current join state then update it with another value */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking JoinState update request should return 0x22 (o15.0.1.11)...\n"); + + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_1X | IB_PATH_SELECTOR_GREATER_THAN << 6; + mc_req_rec.mgid = good_mgid; + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Partially delete JoinState (o15.0.1.14)...\n"); + + /* link-local scope, both non-member bits, + so we should not be able to delete) */ + mc_req_rec.scope_state = 0x26; + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 0, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02CF: " + "Expected to fail partially update JoinState, " + "but got %s\n", + ib_get_err_str(status)); + status = IB_ERROR; + goto Exit; + } + + /* link-local scope, NonMember bit, the FullMember bit should stay */ + mc_req_rec.scope_state = 0x22; + status = osmt_send_mcast_request(p_osmt, 0, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02D3: " + "Failed to partially update JoinState : %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + if (p_mc_res->scope_state != 0x21) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02D4: " + "Failed to partially update JoinState : " + "JoinState = 0x%02X, expected 0x%02X\n", + p_mc_res->scope_state, 0x21); + status = IB_ERROR; + goto Exit; + } + + /* So far successfully delete state - Now change it */ + mc_req_rec.mgid = good_mgid; + mc_req_rec.scope_state = 0x24; /* link-local scope, send only member */ + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02C0: " + "Failed to update existing MCG - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Validating Join State update with Send Only Member (o15.0.1.11)...\n"); + + if (p_mc_res->scope_state != 0x25) { /* scope is MSB */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02C1: " + "Validating JoinState update failed. Expected 0x25 got: 0x%02X\n", + p_mc_res->scope_state); + status = IB_ERROR; + goto Exit; + } + /* Now try to update value of join state */ + mc_req_rec.scope_state = 0x21; /* link-local scope, full member */ + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02C2: " + "Failed to update existing MGID - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Validating Join State update with Full Member\n\t\t" + "to an existing 0x5 state MCG (o15.0.1.11)...\n"); + + if (p_mc_res->scope_state != 0x25) { /* scope is LSB */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02C3: " + "Validating JoinState update failed. Expected 0x25 got: 0x%02X\n", + p_mc_res->scope_state); + status = IB_ERROR; + goto Exit; + } + + /* Now try to update value of join state */ + mc_req_rec.scope_state = 0x22; /* link-local scope,non member */ + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02C4: " + "Failed to update existing MGID - got %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Validating Join State update with Non Member\n\t\t" + "to an existing 0x5 state MCG (o15.0.1.11)...\n"); + + if (p_mc_res->scope_state != 0x27) { /* scope is LSB */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02C5: " + "Validating JoinState update failed. Expected 0x27 got: 0x%02X\n", + p_mc_res->scope_state); + status = IB_ERROR; + goto Exit; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "DEBUG - Current scope_state value : 0x%02X...\n", + p_mc_res->scope_state); + + /* - We can not check simple join since we have only one tester (for now) */ + + /* o15.0.1.12: Not Supported */ + /* - The SendOnlyNonMem join should have a special treatment in the + SA but what is it ? */ + + /* o15.0.1.13: */ + /* - Try joining with rate that does not exist in any MCG - + ERR_REQ_INVALID */ + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking BAD RATE when connecting to existing MGID (o15.0.1.13)...\n"); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + + mc_req_rec.mgid = good_mgid; + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_1X | IB_PATH_SELECTOR_LESS_THAN << 6; + comp_mask = IB_MCR_COMPMASK_GID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02C6: " + "Failed to catch BAD RATE joining an exiting MGID: %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* Try MTU that does not exist in any MCG */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking BAD MTU (higher them max) when connecting to " + "existing MGID (o15.0.1.13)...\n"); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + + mc_req_rec.mgid = osm_ipoib_mgid; + mc_req_rec.mtu = IB_MTU_LEN_4096 | IB_PATH_SELECTOR_GREATER_THAN << 6; + comp_mask = IB_MCR_COMPMASK_GID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | IB_MCR_COMPMASK_MTU; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02C7: " + "Failed to catch BAD RATE (higher them max) joining an exiting MGID: %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* Try another MTU that does not exist in any MCG */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking BAD MTU (less than min) when connecting " + "to existing MGID (o15.0.1.13)...\n"); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + + mc_req_rec.mgid = osm_ipoib_mgid; + mc_req_rec.mtu = IB_MTU_LEN_256 | IB_PATH_SELECTOR_LESS_THAN << 6; + comp_mask = IB_MCR_COMPMASK_GID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | IB_MCR_COMPMASK_MTU; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02C8: " + "Failed to catch BAD RATE (less them min) joining an exiting MGID: %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* o15.0.1.14: */ + /* - Try partial delete - actually updating the join state. check it. */ + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking partial JoinState delete request - removing NonMember (o15.0.1.14)...\n"); + + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_1X | IB_PATH_SELECTOR_GREATER_THAN << 6; + mc_req_rec.mgid = good_mgid; + comp_mask = IB_MCR_COMPMASK_GID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_RATE_SEL | IB_MCR_COMPMASK_RATE; + /* link-local scope, non member (so we should not be able to delete) */ + /* but the NonMember bit should be gone */ + mc_req_rec.scope_state = 0x22; + + status = osmt_send_mcast_request(p_osmt, 0, + &mc_req_rec, comp_mask, &res_sa_mad); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02C9: " + "Fail to partially update JoinState during delete: %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Validating Join State removal of Non Member bit (o15.0.1.14)...\n"); + if (p_mc_res->scope_state != 0x25) { /* scope is MSB - now only the full member & send only member have left */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02CA: " + "Validating JoinState update failed. Expected 0x25 got: 0x%02X\n", + p_mc_res->scope_state); + status = IB_ERROR; + goto Exit; + } + + /* Now use the same scope_state and delete all JoinState - leave multicast group since state is 0x0 */ + + mc_req_rec.scope_state = 0x25; + status = osmt_send_mcast_request(p_osmt, 0, + &mc_req_rec, comp_mask, &res_sa_mad); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02CB: " + "Failed to update JoinState during delete: %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Validating Join State update remove (o15.0.1.14)...\n"); + + if (p_mc_res->scope_state != 0x25) { /* scope is MSB - now only 0x0 so port is removed from MCG */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02BF: " + "Validating JoinState update failed. Expected 0x25 got: 0x%02X\n", + p_mc_res->scope_state); + status = IB_ERROR; + goto Exit; + } + + /* - Try joining (not full mem) again to see the group was deleted. (should fail) */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Delete by trying to Join deleted group (o15.0.1.13)...\n"); + + mc_req_rec.scope_state = 0x22; /* use non member - so if no group fail */ + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, /* join */ + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status != IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02BC: " + "Succeeded Joining Deleted Group: %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* - Try deletion of the IPoIB MCG and get: ERR_REQ_INVALID */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking BAD Delete of Mgid membership (no prev join) (o15.0.1.15)...\n"); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + + mc_req_rec.mgid = osm_ipoib_mgid; + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_1X | IB_PATH_SELECTOR_GREATER_THAN << 6; + mc_req_rec.scope_state = 0x21; /* delete full member */ + + status = osmt_send_mcast_request(p_osmt, 0, /* delete flag */ + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02BD: " + "Failed to catch BAD delete from IPoIB: %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* Prepare another MCG for the following tests : */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Create given MGID=%s\n\t\t(o15.0.1.4)...\n", + inet_ntop(AF_INET6, osm_ipoib_mgid.raw, gid_str, + sizeof gid_str)); + + mc_req_rec.mgid = good_mgid; + mc_req_rec.mgid.raw[12] = 0xAA; + mc_req_rec.pkt_life = 0 | IB_PATH_SELECTOR_GREATER_THAN << 6; + mc_req_rec.scope_state = 0x21; /* Full memeber */ + comp_mask = IB_MCR_COMPMASK_GID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_LIFE | IB_MCR_COMPMASK_LIFE_SEL; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02BE: " + "Failed to create MCG for %s - got %s/%s\n", + inet_ntop(AF_INET6, good_mgid.raw, gid_str, + sizeof gid_str), ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + goto Exit; + } + + /* - Try delete with valid join state */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Full Delete of a group (o15.0.1.14)...\n"); + mc_req_rec.scope_state = 0x21; /* the FullMember is the current JoinState */ + status = osmt_send_mcast_request(p_osmt, 0, + &mc_req_rec, comp_mask, &res_sa_mad); + + if (status != IB_SUCCESS) { + goto Exit; + } + + /* o15.0.1.15: */ + /* - Try deletion of the IPoIB MCG and get: ERR_REQ_INVALID */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking BAD Delete of IPoIB membership (no prev join) (o15.0.1.15)...\n"); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + + mc_req_rec.mgid = osm_ipoib_mgid; + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_1X | IB_PATH_SELECTOR_GREATER_THAN << 6; + mc_req_rec.scope_state = 0x21; /* delete full member */ + + status = osmt_send_mcast_request(p_osmt, 0, /* delete flag */ + &mc_req_rec, comp_mask, &res_sa_mad); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if ((status != IB_REMOTE_ERROR) || + (res_sa_mad.status != IB_SA_MAD_STATUS_REQ_INVALID)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0223: " + "Failed to catch BAD delete from IPoIB: %s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /**************************************************************************/ + /* Checking join with invalid MTU */ + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Join with unrealistic mtu : \n" + "\t\tFirst create new MCG than try to join it \n" + "\t\twith unrealistic MTU greater than 4096 (o15.0.1.8)...\n"); + + /* First create new mgrp */ + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + mc_req_rec.mtu = IB_MTU_LEN_1024 | IB_PATH_SELECTOR_EXACTLY << 6; + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + comp_mask = IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MTU_SEL | IB_MCR_COMPMASK_MTU; + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02EB: " + "Failed to create new mgrp\n"); + goto Exit; + } + memcpy(&tmp_mgid, &p_mc_res->mgid, sizeof(ib_gid_t)); + osm_dump_mc_record(&p_osmt->log, p_mc_res, OSM_LOG_INFO); + /* tmp_mtu = p_mc_res->mtu & 0x3F; */ + + /* impossible requested mtu always greater than exist in MCG */ + mc_req_rec.mtu = IB_MTU_LEN_4096 | IB_PATH_SELECTOR_GREATER_THAN << 6; + memcpy(&mc_req_rec.mgid, &tmp_mgid, sizeof(ib_gid_t)); + ib_member_set_join_state(&mc_req_rec, IB_MC_REC_STATE_FULL_MEMBER); + comp_mask = + IB_MCR_COMPMASK_GID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_JOIN_STATE | + IB_MCR_COMPMASK_MTU_SEL | IB_MCR_COMPMASK_MTU; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, comp_mask, &res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status == IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02E4: " + "Expected REMOTE ERROR got:%s/%s\n", + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + /* - Try GetTable with PortGUID wildcarded and get back some groups. */ + status = osmt_query_mcast(p_osmt); + cnt = cl_qmap_count(&p_osmt->exp_subn.mgrp_mlid_tbl); + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, "(Before checking Max MCG creation): " + "Number of MC Records found in SA DB is %d\n", cnt); + + /**************************************************************************/ + /* Checking join on behalf of remote port gid */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, "Checking Proxy Join...\n"); + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + memset(&context, 0, sizeof(context)); + + /* + * Do a blocking query for all NodeRecords in the subnet. + */ + status = osmtest_get_all_recs(p_osmt, IB_MAD_ATTR_NODE_RECORD, + sizeof(*p_rec), &context); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02E5: " + "osmtest_get_all_recs failed on getting all node records(%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + /* + * Populate the database with the received records. + */ + num_recs = context.result.result_cnt; + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Received %u records\n", num_recs); + + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_node_rec(context.result.p_result_madw, i); + if (p_rec->node_info.port_guid != p_osmt->local_port.port_guid + && p_rec->node_info.node_type == IB_NODE_TYPE_CA) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "remote port_guid = 0x%" PRIx64 "\n", + cl_ntoh64(p_rec->node_info.port_guid)); + + remote_port_guid = p_rec->node_info.port_guid; + i = num_recs; + break; + } + } + + if (remote_port_guid != 0x0) { + ib_member_set_join_state(&mc_req_rec, + IB_MC_REC_STATE_FULL_MEMBER); + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + mc_req_rec.port_gid.unicast.interface_id = remote_port_guid; + comp_mask = IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS; /* all above are required */ + + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, + comp_mask, &res_sa_mad); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02B4: " + "Could not join on behalf of remote port 0x%016" + PRIx64 " remote status: %s\n", + cl_ntoh64(remote_port_guid), + ib_get_mad_status_str((ib_mad_t + *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + memcpy(&proxy_mgid, &p_mc_res->mgid, sizeof(ib_gid_t)); + + /* First try a bad deletion then good one */ + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Trying deletion of remote port with local port guid\n"); + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + ib_member_set_join_state(&mc_req_rec, + IB_MC_REC_STATE_FULL_MEMBER); + comp_mask = + IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_JOIN_STATE; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + + status = osmt_send_mcast_request(p_osmt, 0, /* delete flag */ + &mc_req_rec, + comp_mask, &res_sa_mad); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status == IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02A9: " + "Successful deletion of remote port guid with local one MGID : " + "%s, Got : %s/%s\n", + inet_ntop(AF_INET6, + p_mgrp->mcmember_rec.mgid.raw, + gid_str, sizeof gid_str), + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t + *) (&res_sa_mad))); + status = IB_ERROR; + goto Exit; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Trying deletion of remote port with the right port guid\n"); + + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + ib_member_set_join_state(&mc_req_rec, + IB_MC_REC_STATE_FULL_MEMBER); + mc_req_rec.mgid = proxy_mgid; + mc_req_rec.port_gid.unicast.interface_id = remote_port_guid; + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_JOIN_STATE; + status = osmt_send_mcast_request(p_osmt, 0, /* delete flag */ + &mc_req_rec, + comp_mask, &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02B0: " + "Failed to delete mgid with remote port guid MGID : " + "%s, Got : %s/%s\n", + inet_ntop(AF_INET6, + p_mgrp->mcmember_rec.mgid.raw, + gid_str, sizeof gid_str), + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t + *) (&res_sa_mad))); + goto Exit; + } + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Could not check proxy join since could not found remote port, different from local port\n"); + } + + /* prepare init for next check */ + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + /**************************************************************************/ + if (p_osmt->opt.mmode > 2) { + /* Check invalid Join with max mlid which is more than the + Mellanox switches support 0xC000+0x1000 = 0xd000 */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Checking Creation of Maximum avaliable Groups (MulticastFDBCap)...\n"); + tmp_mlid = cl_ntoh16(max_mlid) - cnt; + + while (tmp_mlid > 0 && !ReachedMlidLimit) { + uint16_t cur_mlid = 0; + + /* Request Set */ + ib_member_set_join_state(&mc_req_rec, + IB_MC_REC_STATE_FULL_MEMBER); + /* Good Flow - mgid is 0 while giving all required fields for + join : P_Key, Q_Key, SL, FlowLabel, Tclass */ + + mc_req_rec.rate = + IB_LINK_WIDTH_ACTIVE_1X | + IB_PATH_SELECTOR_GREATER_THAN << 6; + mc_req_rec.mlid = max_mlid; + memset(&mc_req_rec.mgid, 0, sizeof(ib_gid_t)); + comp_mask = IB_MCR_COMPMASK_MGID | IB_MCR_COMPMASK_PORT_GID | IB_MCR_COMPMASK_QKEY | IB_MCR_COMPMASK_PKEY | IB_MCR_COMPMASK_SL | IB_MCR_COMPMASK_FLOW | IB_MCR_COMPMASK_JOIN_STATE | IB_MCR_COMPMASK_TCLASS | /* all above are required */ + IB_MCR_COMPMASK_MLID; + status = osmt_send_mcast_request(p_osmt, 1, + &mc_req_rec, + comp_mask, + &res_sa_mad); + + p_mc_res = ib_sa_mad_get_payload_ptr(&res_sa_mad); + if (status != IB_SUCCESS) { + + if (cur_mlid > cl_ntoh16(max_mlid)) { + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 2E1 " + "Successful Join with greater mlid than switches support (MulticastFDBCap) 0x%04X\n", + cur_mlid); + status = IB_ERROR; + osm_dump_mc_record(&p_osmt->log, + p_mc_res, + OSM_LOG_VERBOSE); + goto Exit; + } else + if ((res_sa_mad. + status & IB_SMP_STATUS_MASK) == + IB_SA_MAD_STATUS_NO_RESOURCES) { + /* You can quitly exit the loop since no available mlid in SA DB + i.e. reached the maximum valiad avalable mlid */ + ReachedMlidLimit = TRUE; + } + } else { + cur_mlid = cl_ntoh16(p_mc_res->mlid); + /* Save the mlid created in test_created_mlids map */ + p_recvd_rec = + (ib_member_rec_t *) + ib_sa_mad_get_payload_ptr(&res_sa_mad); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Created MGID:%s MLID:0x%04X\n", + inet_ntop(AF_INET6, + p_recvd_rec->mgid.raw, + gid_str, sizeof gid_str), + cl_ntoh16(p_recvd_rec->mlid)); + cl_map_insert(&test_created_mlids, + cl_ntoh16(p_recvd_rec->mlid), + p_recvd_rec); + } + tmp_mlid--; + } + } + + /* Prepare the mc_req_rec for the rest of the flow */ + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + + /**************************************************************************/ + /* o15.0.1.16: */ + /* - Try GetTable with PortGUID wildcarded and get back some groups. */ + + status = osmt_query_mcast(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02B1: " + "Failed to query multicast groups: %s\n", + ib_get_err_str(status)); + goto Exit; + } + + cnt = cl_qmap_count(&p_osmt->exp_subn.mgrp_mlid_tbl); + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, "(Before Deletion of all MCG): " + "Number of MC Records found in SA DB is %d\n", cnt); + + /* Delete all MCG that are not of IPoIB */ + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Cleanup all MCG that are not IPoIB...\n"); + + p_mgrp_mlid_tbl = &p_osmt->exp_subn.mgrp_mlid_tbl; + p_mgrp = (osmtest_mgrp_t *) cl_qmap_head(p_mgrp_mlid_tbl); + /* scan all available multicast groups in the DB and fill in the table */ + while (p_mgrp != (osmtest_mgrp_t *) cl_qmap_end(p_mgrp_mlid_tbl)) { + /* Only if different from IPoIB Mgid try to delete */ + if (!IS_IPOIB_MGID(&p_mgrp->mcmember_rec.mgid)) { + osmt_init_mc_query_rec(p_osmt, &mc_req_rec); + mc_req_rec.mgid = p_mgrp->mcmember_rec.mgid; + + /* o15-0.1.4 - need to specify the oppsite state for a valid delete */ + if (!memcmp + (&special_mgid, &p_mgrp->mcmember_rec.mgid, + sizeof(special_mgid))) { + mc_req_rec.scope_state = 0x2F; + } else { + mc_req_rec.scope_state = 0x21; + } + comp_mask = + IB_MCR_COMPMASK_MGID | + IB_MCR_COMPMASK_PORT_GID | + IB_MCR_COMPMASK_JOIN_STATE; + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Sending request to delete MGID : %s" + ", scope_state : 0x%02X\n", + inet_ntop(AF_INET6, mc_req_rec.mgid.raw, + gid_str, sizeof gid_str), + mc_req_rec.scope_state); + status = osmt_send_mcast_request(p_osmt, 0, /* delete flag */ + &mc_req_rec, + comp_mask, + &res_sa_mad); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 02FF: Failed to delete MGID : %s" + " ,\n\t\t it is not our MCG, Status : %s/%s\n", + inet_ntop(AF_INET6, + p_mgrp->mcmember_rec.mgid.raw, + gid_str, sizeof gid_str), + ib_get_err_str(status), + ib_get_mad_status_str((ib_mad_t *) + (&res_sa_mad))); + fail_to_delete_mcg++; + } + } else { + end_ipoib_cnt++; + } + p_mgrp = (osmtest_mgrp_t *) cl_qmap_next(&p_mgrp->map_item); + } + + status = osmt_query_mcast(p_osmt); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02B2 " + "GetTable of all records has failed - got %s\n", + ib_get_err_str(status)); + goto Exit; + } + + /* If we are in single mode check flow - need to make sure all the multicast groups + that are left are not ones created during the flow. + */ + if (p_osmt->opt.mmode == 1 || p_osmt->opt.mmode == 3) { + end_cnt = cl_qmap_count(&p_osmt->exp_subn.mgrp_mlid_tbl); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, "Status of MC Records in SA DB during the test flow:\n" " Beginning of test\n" " Unrelated to the test: %d\n" " IPoIB MC Records : %d\n" " Total : %d\n" " End of test\n" " Failed to delete : %d\n" " IPoIB MC Records : %d\n" " Total : %d\n", mcg_outside_test_cnt, /* Non-IPoIB that existed at the beginning */ + start_ipoib_cnt, /* IPoIB records */ + start_cnt, /* Total: IPoIB and MC Records unrelated to the test */ + fail_to_delete_mcg, /* Failed to delete at the end */ + end_ipoib_cnt, /* IPoIB records */ + end_cnt); /* Total MC Records at the end */ + + /* when we compare num of MCG we should consider an outside source which create other MCGs */ + if ((end_cnt - fail_to_delete_mcg - end_ipoib_cnt) != + (start_cnt - mcg_outside_test_cnt - start_ipoib_cnt)) { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Got different number of non-IPoIB records stored in SA DB\n\t\t" + "at Start got %d, at End got %d (IPoIB groups only)\n", + (start_cnt - mcg_outside_test_cnt - + start_ipoib_cnt), + (end_cnt - fail_to_delete_mcg - end_ipoib_cnt)); + } + + p_mgrp_mlid_tbl = &p_osmt->exp_subn.mgrp_mlid_tbl; + p_mgrp = (osmtest_mgrp_t *) cl_qmap_head(p_mgrp_mlid_tbl); + while (p_mgrp != + (osmtest_mgrp_t *) cl_qmap_end(p_mgrp_mlid_tbl)) { + uint16_t mlid = + (uint16_t) cl_qmap_key((cl_map_item_t *) p_mgrp); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Found MLID:0x%04X\n", mlid); + /* Check if the mlid is in the test_created_mlids. If TRUE, then we + didn't delete a MCgroup that was created in this flow. */ + if (cl_map_get(&test_created_mlids, mlid) != NULL) { + /* This means that we still have an mgrp that we created!! */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 02FE: " + "Wasn't able to erase mgrp with MGID:%s" + " MLID:0x%04X\n", + inet_ntop(AF_INET6, + p_mgrp->mcmember_rec.mgid.raw, + gid_str, sizeof gid_str), + mlid); + got_error = TRUE; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Still exists %s MGID:%s\n", + (IS_IPOIB_MGID + (&p_mgrp->mcmember_rec. + mgid)) ? "IPoIB" : "non-IPoIB", + inet_ntop(AF_INET6, + p_mgrp->mcmember_rec.mgid.raw, + gid_str, sizeof gid_str)); + } + p_mgrp = + (osmtest_mgrp_t *) cl_qmap_next(&p_mgrp->map_item); + } + + if (got_error) { + __osmt_print_all_multicast_records(p_osmt); + status = IB_ERROR; + } + } +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return status; +} diff --git a/contrib/ofed/management/opensm/osmtest/osmt_service.c b/contrib/ofed/management/opensm/osmtest/osmt_service.c new file mode 100644 index 000000000000..97f14921cc9f --- /dev/null +++ b/contrib/ofed/management/opensm/osmtest/osmt_service.c @@ -0,0 +1,1616 @@ +/* + * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of service records testing flow.. + * Top level is osmt_run_service_records_flow: + * osmt_register_service + * osmt_get_service_by_name + * osmt_get_all_services + * osmt_delete_service_by_name + * + */ + +#ifndef __WIN__ +#include +#else +#include +#endif +#include +#include +#include +#include +#include "osmtest.h" + +/********************************************************************** + **********************************************************************/ + +ib_api_status_t +osmt_register_service(IN osmtest_t * const p_osmt, + IN ib_net64_t service_id, + IN ib_net16_t service_pkey, + IN ib_net32_t service_lease, + IN uint8_t service_key_lsb, IN char *service_name) +{ + osmv_query_req_t req; + osmv_user_query_t user; + osmtest_req_context_t context; + ib_service_record_t svc_rec; + osm_log_t *p_log = &p_osmt->log; + ib_api_status_t status; + + OSM_LOG_ENTER(p_log); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Registering service: name: %s id: 0x%" PRIx64 "\n", + service_name, cl_ntoh64(service_id)); + + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + memset(&user, 0, sizeof(user)); + memset(&svc_rec, 0, sizeof(svc_rec)); + + /* set the new service record fields */ + svc_rec.service_id = service_id; + svc_rec.service_pkey = service_pkey; + svc_rec.service_gid.unicast.prefix = 0; + svc_rec.service_gid.unicast.interface_id = p_osmt->local_port.port_guid; + svc_rec.service_lease = service_lease; + memset(&svc_rec.service_key, 0, 16 * sizeof(uint8_t)); + svc_rec.service_key[0] = service_key_lsb; + memset(svc_rec.service_name, 0, sizeof(svc_rec.service_name)); + memcpy(svc_rec.service_name, service_name, + (strlen(service_name) + 1) * sizeof(char)); + + /* prepare the data used for this query */ + /* sa_mad_data.method = IB_MAD_METHOD_SET; */ + /* sa_mad_data.sm_key = 0; */ + + context.p_osmt = p_osmt; + req.query_context = &context; + req.query_type = OSMV_QUERY_USER_DEFINED; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.flags = OSM_SA_FLAGS_SYNC; + req.sm_key = 0; + req.timeout_ms = p_osmt->opt.transaction_timeout; + + user.method = IB_MAD_METHOD_SET; + user.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + if (ib_pkey_is_invalid(service_pkey)) { + /* if given an invalid service_pkey - don't turn the PKEY compmask on */ + user.comp_mask = IB_SR_COMPMASK_SID | + IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SKEY | IB_SR_COMPMASK_SNAME; + } else { + user.comp_mask = IB_SR_COMPMASK_SID | + IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SPKEY | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SKEY | IB_SR_COMPMASK_SNAME; + } + user.attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + user.p_attr = &svc_rec; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A01: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A02: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + +Exit: + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +/********************************************************************** + **********************************************************************/ + +ib_api_status_t +osmt_register_service_with_full_key(IN osmtest_t * const p_osmt, + IN ib_net64_t service_id, + IN ib_net16_t service_pkey, + IN ib_net32_t service_lease, + IN uint8_t * service_key, + IN char *service_name) +{ + osmv_query_req_t req; + osmv_user_query_t user; + osmtest_req_context_t context; + ib_service_record_t svc_rec, *p_rec; + osm_log_t *p_log = &p_osmt->log; + ib_api_status_t status; + uint8_t i, skey[16]; + + OSM_LOG_ENTER(p_log); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Registering service: name: %s id: 0x%" PRIx64 "\n", + service_name, cl_ntoh64(service_id)); + + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + memset(&user, 0, sizeof(user)); + memset(&svc_rec, 0, sizeof(svc_rec)); + + /* set the new service record fields */ + svc_rec.service_id = service_id; + svc_rec.service_pkey = service_pkey; + svc_rec.service_gid.unicast.prefix = 0; + svc_rec.service_gid.unicast.interface_id = p_osmt->local_port.port_guid; + svc_rec.service_lease = service_lease; + memset(&svc_rec.service_key, 0, 16 * sizeof(uint8_t)); + memcpy(svc_rec.service_key, service_key, 16 * sizeof(uint8_t)); + memset(svc_rec.service_name, 0, sizeof(svc_rec.service_name)); + memset(skey, 0, 16 * sizeof(uint8_t)); + memcpy(svc_rec.service_name, service_name, + (strlen(service_name) + 1) * sizeof(char)); + + /* prepare the data used for this query */ + /* sa_mad_data.method = IB_MAD_METHOD_SET; */ + /* sa_mad_data.sm_key = 0; */ + + context.p_osmt = p_osmt; + req.query_context = &context; + req.query_type = OSMV_QUERY_USER_DEFINED; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.flags = OSM_SA_FLAGS_SYNC; + req.sm_key = 0; + req.timeout_ms = p_osmt->opt.transaction_timeout; + + user.method = IB_MAD_METHOD_SET; + user.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + if (ib_pkey_is_invalid(service_pkey)) { + /* if given an invalid service_pkey - don't turn the PKEY compmask on */ + user.comp_mask = IB_SR_COMPMASK_SID | + IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SKEY | IB_SR_COMPMASK_SNAME; + } else { + user.comp_mask = IB_SR_COMPMASK_SID | + IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SPKEY | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SKEY | IB_SR_COMPMASK_SNAME; + } + user.attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + user.p_attr = &svc_rec; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A03: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A04: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + + /* Check service key on context to see if match */ + p_rec = osmv_get_query_svc_rec(context.result.p_result_madw, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Comparing service key...\n" "return key is:\n"); + for (i = 0; i <= 15; i++) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "service_key sent[%u] = %u, service_key returned[%u] = %u\n", + i, service_key[i], i, p_rec->service_key[i]); + } + /* since c15-0.1.14 not supported all key association queries should bring in return zero in service key */ + if (memcmp(skey, p_rec->service_key, 16 * sizeof(uint8_t)) != 0) { + status = IB_REMOTE_ERROR; + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A33: " + "Data mismatch in service_key\n"); + goto Exit; + } + +Exit: + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +/********************************************************************** + **********************************************************************/ + +ib_api_status_t +osmt_register_service_with_data(IN osmtest_t * const p_osmt, + IN ib_net64_t service_id, + IN ib_net16_t service_pkey, + IN ib_net32_t service_lease, + IN uint8_t service_key_lsb, + IN uint8_t * service_data8, + IN ib_net16_t * service_data16, + IN ib_net32_t * service_data32, + IN ib_net64_t * service_data64, + IN char *service_name) +{ + osmv_query_req_t req; + osmv_user_query_t user; + osmtest_req_context_t context; + ib_service_record_t svc_rec, *p_rec; + osm_log_t *p_log = &p_osmt->log; + ib_api_status_t status; + /* ib_service_record_t* p_rec; */ + + OSM_LOG_ENTER(p_log); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Registering service: name: %s id: 0x%" PRIx64 "\n", + service_name, cl_ntoh64(service_id)); + + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + memset(&user, 0, sizeof(user)); + memset(&svc_rec, 0, sizeof(svc_rec)); + + /* set the new service record fields */ + svc_rec.service_id = service_id; + svc_rec.service_pkey = service_pkey; + svc_rec.service_gid.unicast.prefix = 0; + svc_rec.service_gid.unicast.interface_id = p_osmt->local_port.port_guid; + svc_rec.service_lease = service_lease; + memset(&svc_rec.service_key, 0, 16 * sizeof(uint8_t)); + svc_rec.service_key[0] = service_key_lsb; + + /* Copy data to service_data arrays */ + memcpy(svc_rec.service_data8, service_data8, 16 * sizeof(uint8_t)); + memcpy(svc_rec.service_data16, service_data16, 8 * sizeof(ib_net16_t)); + memcpy(svc_rec.service_data32, service_data32, 4 * sizeof(ib_net32_t)); + memcpy(svc_rec.service_data64, service_data64, 2 * sizeof(ib_net64_t)); + + memset(svc_rec.service_name, 0, sizeof(svc_rec.service_name)); + memcpy(svc_rec.service_name, service_name, + (strlen(service_name) + 1) * sizeof(char)); + + /* prepare the data used for this query */ + /* sa_mad_data.method = IB_MAD_METHOD_SET; */ + /* sa_mad_data.sm_key = 0; */ + + context.p_osmt = p_osmt; + req.query_context = &context; + req.query_type = OSMV_QUERY_USER_DEFINED; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.flags = OSM_SA_FLAGS_SYNC; + req.sm_key = 0; + req.timeout_ms = p_osmt->opt.transaction_timeout; + + user.method = IB_MAD_METHOD_SET; + user.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + if (ib_pkey_is_invalid(service_pkey)) { + /* if given an invalid service_pkey - don't turn the PKEY compmask on */ + user.comp_mask = IB_SR_COMPMASK_SID | + IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SKEY | + IB_SR_COMPMASK_SNAME | + IB_SR_COMPMASK_SDATA8_0 | + IB_SR_COMPMASK_SDATA8_1 | + IB_SR_COMPMASK_SDATA16_0 | + IB_SR_COMPMASK_SDATA16_1 | + IB_SR_COMPMASK_SDATA32_0 | + IB_SR_COMPMASK_SDATA32_1 | + IB_SR_COMPMASK_SDATA64_0 | IB_SR_COMPMASK_SDATA64_1; + } else { + user.comp_mask = IB_SR_COMPMASK_SID | + IB_SR_COMPMASK_SGID | + IB_SR_COMPMASK_SPKEY | + IB_SR_COMPMASK_SLEASE | + IB_SR_COMPMASK_SKEY | + IB_SR_COMPMASK_SNAME | + IB_SR_COMPMASK_SDATA8_0 | + IB_SR_COMPMASK_SDATA8_1 | + IB_SR_COMPMASK_SDATA16_0 | + IB_SR_COMPMASK_SDATA16_1 | + IB_SR_COMPMASK_SDATA32_0 | + IB_SR_COMPMASK_SDATA32_1 | + IB_SR_COMPMASK_SDATA64_0 | IB_SR_COMPMASK_SDATA64_1; + } + user.attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + user.p_attr = &svc_rec; + + /* Dump to Service Data b4 send */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Dumping service data b4 send\n"); + osm_dump_service_record(&p_osmt->log, &svc_rec, OSM_LOG_VERBOSE); + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A05: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A06: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + + /* Check data on context to see if match */ + p_rec = osmv_get_query_svc_rec(context.result.p_result_madw, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Comparing service data...\n"); + if (memcmp(service_data8, p_rec->service_data8, 16 * sizeof(uint8_t)) != + 0 + || memcmp(service_data16, p_rec->service_data16, + 8 * sizeof(uint16_t)) != 0 + || memcmp(service_data32, p_rec->service_data32, + 4 * sizeof(uint32_t)) != 0 + || memcmp(service_data64, p_rec->service_data64, + 2 * sizeof(uint64_t)) != 0) { + status = IB_REMOTE_ERROR; + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Data mismatch in service_data8\n"); + goto Exit; + } + +Exit: + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +/********************************************************************** + **********************************************************************/ + +ib_api_status_t +osmt_get_service_by_id_and_name(IN osmtest_t * const p_osmt, + IN uint32_t rec_num, + IN ib_net64_t sid, + IN char *sr_name, + OUT ib_service_record_t * p_out_rec) +{ + + ib_api_status_t status = IB_SUCCESS; + osmtest_req_context_t context; + osmv_query_req_t req; + ib_service_record_t svc_rec, *p_rec; + uint32_t num_recs = 0; + osmv_user_query_t user; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting service record: id: 0x%016" PRIx64 + " and name: %s\n", cl_ntoh64(sid), sr_name); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + /* prepare the data used for this query */ + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.sm_key = 0; + + memset(&svc_rec, 0, sizeof(svc_rec)); + memset(&user, 0, sizeof(user)); + /* set the new service record fields */ + memset(svc_rec.service_name, 0, sizeof(svc_rec.service_name)); + memcpy(svc_rec.service_name, sr_name, + (strlen(sr_name) + 1) * sizeof(char)); + svc_rec.service_id = sid; + req.p_query_input = &user; + + user.method = IB_MAD_METHOD_GET; + user.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + user.comp_mask = IB_SR_COMPMASK_SID | IB_SR_COMPMASK_SNAME; + user.attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + user.p_attr = &svc_rec; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A07: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + num_recs = context.result.result_cnt; + + if (status != IB_SUCCESS) { + char mad_stat_err[256]; + + /* If the failure is due to IB_SA_MAD_STATUS_NO_RECORDS and rec_num is 0, + then this is fine */ + if (status == IB_REMOTE_ERROR) + strcpy(mad_stat_err, + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + else + strcpy(mad_stat_err, ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR && + !strcmp(mad_stat_err, "IB_SA_MAD_STATUS_NO_RECORDS") && + rec_num == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "IS EXPECTED ERROR ^^^^\n"); + status = IB_SUCCESS; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A08: " + "Query failed: %s (%s)\n", + ib_get_err_str(status), mad_stat_err); + goto Exit; + } + } + + if (rec_num && num_recs != rec_num) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Unmatched number of records: expected: %d, received: %d\n", + rec_num, num_recs); + status = IB_REMOTE_ERROR; + goto Exit; + } + + p_rec = osmv_get_query_svc_rec(context.result.p_result_madw, 0); + *p_out_rec = *p_rec; + + if (num_recs) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Found service record: name: %s id: 0x%016" PRIx64 "\n", + p_rec->service_name, cl_ntoh64(p_rec->service_id)); + + osm_dump_service_record(&p_osmt->log, p_rec, OSM_LOG_DEBUG); + } + +Exit: + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Expected and found %d records\n", rec_num); + + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +/********************************************************************** + **********************************************************************/ + +ib_api_status_t +osmt_get_service_by_id(IN osmtest_t * const p_osmt, + IN uint32_t rec_num, + IN ib_net64_t sid, OUT ib_service_record_t * p_out_rec) +{ + + ib_api_status_t status = IB_SUCCESS; + osmtest_req_context_t context; + osmv_query_req_t req; + ib_service_record_t svc_rec, *p_rec; + uint32_t num_recs = 0; + osmv_user_query_t user; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting service record: id: 0x%016" PRIx64 "\n", + cl_ntoh64(sid)); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + /* prepare the data used for this query */ + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.sm_key = 0; + + memset(&svc_rec, 0, sizeof(svc_rec)); + memset(&user, 0, sizeof(user)); + /* set the new service record fields */ + svc_rec.service_id = sid; + req.p_query_input = &user; + + user.method = IB_MAD_METHOD_GET; + user.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + user.comp_mask = IB_SR_COMPMASK_SID; + user.attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + user.p_attr = &svc_rec; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A09: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + num_recs = context.result.result_cnt; + + if (status != IB_SUCCESS) { + char mad_stat_err[256]; + + /* If the failure is due to IB_SA_MAD_STATUS_NO_RECORDS and rec_num is 0, + then this is fine */ + if (status == IB_REMOTE_ERROR) + strcpy(mad_stat_err, + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + else + strcpy(mad_stat_err, ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR && + !strcmp(mad_stat_err, "IB_SA_MAD_STATUS_NO_RECORDS") && + rec_num == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "IS EXPECTED ERROR ^^^^\n"); + status = IB_SUCCESS; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A0A: " + "Query failed: %s (%s)\n", + ib_get_err_str(status), mad_stat_err); + goto Exit; + } + } + + if (rec_num && num_recs != rec_num) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A0B: " + "Unmatched number of records: expected: %d received: %d\n", + rec_num, num_recs); + status = IB_REMOTE_ERROR; + goto Exit; + } + + p_rec = osmv_get_query_svc_rec(context.result.p_result_madw, 0); + *p_out_rec = *p_rec; + + if (num_recs) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Found service record: name: %s id: 0x%016" PRIx64 "\n", + p_rec->service_name, cl_ntoh64(p_rec->service_id)); + + osm_dump_service_record(&p_osmt->log, p_rec, OSM_LOG_DEBUG); + } + +Exit: + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Expected and found %d records\n", rec_num); + + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +/********************************************************************** + **********************************************************************/ + +ib_api_status_t +osmt_get_service_by_name_and_key(IN osmtest_t * const p_osmt, + IN char *sr_name, + IN uint32_t rec_num, + IN uint8_t * skey, + OUT ib_service_record_t * p_out_rec) +{ + + ib_api_status_t status = IB_SUCCESS; + osmtest_req_context_t context; + osmv_query_req_t req; + ib_service_record_t svc_rec, *p_rec; + uint32_t num_recs = 0, i; + osmv_user_query_t user; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting service record: name: %s and key: " + "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + sr_name, skey[0], skey[1], skey[2], skey[3], skey[4], skey[5], + skey[6], skey[7], skey[8], skey[9], skey[10], skey[11], + skey[12], skey[13], skey[14], skey[15]); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + /* prepare the data used for this query */ + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.sm_key = 0; + + memset(&svc_rec, 0, sizeof(svc_rec)); + memset(&user, 0, sizeof(user)); + /* set the new service record fields */ + memset(svc_rec.service_name, 0, sizeof(svc_rec.service_name)); + memcpy(svc_rec.service_name, sr_name, + (strlen(sr_name) + 1) * sizeof(char)); + for (i = 0; i <= 15; i++) + svc_rec.service_key[i] = skey[i]; + + req.p_query_input = &user; + + user.method = IB_MAD_METHOD_GET; + user.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + user.comp_mask = IB_SR_COMPMASK_SNAME | IB_SR_COMPMASK_SKEY; + user.attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + user.p_attr = &svc_rec; + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A0C: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + num_recs = context.result.result_cnt; + + if (status != IB_SUCCESS) { + char mad_stat_err[256]; + + /* If the failure is due to IB_SA_MAD_STATUS_NO_RECORDS and rec_num is 0, + then this is fine */ + if (status == IB_REMOTE_ERROR) + strcpy(mad_stat_err, + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + else + strcpy(mad_stat_err, ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR && + !strcmp(mad_stat_err, "IB_SA_MAD_STATUS_NO_RECORDS") && + rec_num == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "IS EXPECTED ERROR ^^^^\n"); + status = IB_SUCCESS; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A0D: " + "Query failed:%s (%s)\n", + ib_get_err_str(status), mad_stat_err); + goto Exit; + } + } + + if (rec_num && num_recs != rec_num) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Unmatched number of records: expected: %d, received: %d\n", + rec_num, num_recs); + status = IB_REMOTE_ERROR; + goto Exit; + } + + p_rec = osmv_get_query_svc_rec(context.result.p_result_madw, 0); + *p_out_rec = *p_rec; + + if (num_recs) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Found service record: name: %s id: 0x%016" PRIx64 "\n", + sr_name, cl_ntoh64(p_rec->service_id)); + + osm_dump_service_record(&p_osmt->log, p_rec, OSM_LOG_DEBUG); + } + +Exit: + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Expected and found %d records\n", rec_num); + + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +/********************************************************************** + **********************************************************************/ + +ib_api_status_t +osmt_get_service_by_name(IN osmtest_t * const p_osmt, + IN char *sr_name, + IN uint32_t rec_num, + OUT ib_service_record_t * p_out_rec) +{ + + ib_api_status_t status = IB_SUCCESS; + osmtest_req_context_t context; + osmv_query_req_t req; + ib_service_record_t *p_rec; + ib_svc_name_t service_name; + uint32_t num_recs = 0; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting service record: name: %s\n", sr_name); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + /* prepare the data used for this query */ + req.query_type = OSMV_QUERY_SVC_REC_BY_NAME; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.sm_key = 0; + + memset(service_name, 0, sizeof(service_name)); + memcpy(service_name, sr_name, (strlen(sr_name) + 1) * sizeof(char)); + req.p_query_input = service_name; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A0E: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + num_recs = context.result.result_cnt; + + if (status != IB_SUCCESS) { + char mad_stat_err[256]; + + /* If the failure is due to IB_SA_MAD_STATUS_NO_RECORDS and rec_num is 0, + then this is fine */ + if (status == IB_REMOTE_ERROR) + strcpy(mad_stat_err, + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + else + strcpy(mad_stat_err, ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR && + !strcmp(mad_stat_err, "IB_SA_MAD_STATUS_NO_RECORDS") && + rec_num == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "IS EXPECTED ERROR ^^^^\n"); + status = IB_SUCCESS; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A0F: " + "Query failed: %s (%s)\n", + ib_get_err_str(status), mad_stat_err); + goto Exit; + } + } + + if (rec_num && num_recs != rec_num) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A10: " + "Unmatched number of records: expected: %d, received: %d\n", + rec_num, num_recs); + status = IB_REMOTE_ERROR; + goto Exit; + } + + p_rec = osmv_get_query_svc_rec(context.result.p_result_madw, 0); + *p_out_rec = *p_rec; + + if (num_recs) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Found service record: name: %s id: 0x%016" PRIx64 "\n", + sr_name, cl_ntoh64(p_rec->service_id)); + + osm_dump_service_record(&p_osmt->log, p_rec, OSM_LOG_DEBUG); + } + +Exit: + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Expected and found %d records\n", rec_num); + + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +/********************************************************************** + **********************************************************************/ + +#ifdef VENDOR_RMPP_SUPPORT +ib_api_status_t +osmt_get_all_services_and_check_names(IN osmtest_t * const p_osmt, + IN ib_svc_name_t * + const p_valid_service_names_arr, + IN uint8_t num_of_valid_names, + OUT uint32_t * num_services) +{ + ib_api_status_t status = IB_SUCCESS; + osmtest_req_context_t context; + osmv_query_req_t req; + ib_service_record_t *p_rec; + uint32_t num_recs = 0, i, j; + uint8_t *p_checked_names; + + OSM_LOG_ENTER(&p_osmt->log); + + /* Prepare tracker for the checked names */ + p_checked_names = + (uint8_t *) malloc(sizeof(uint8_t) * num_of_valid_names); + for (j = 0; j < num_of_valid_names; j++) { + p_checked_names[j] = 0; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Getting all service records\n"); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + req.query_type = OSMV_QUERY_ALL_SVC_RECS; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A12: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + + if (status != IB_SUCCESS) { + if (status != IB_INVALID_PARAMETER) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A13: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + } + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + + num_recs = context.result.result_cnt; + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Received %u records\n", num_recs); + + for (i = 0; i < num_recs; i++) { + p_rec = osmv_get_query_svc_rec(context.result.p_result_madw, i); + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Found service record: name: %s id: 0x%016" PRIx64 "\n", + p_rec->service_name, cl_ntoh64(p_rec->service_id)); + osm_dump_service_record(&p_osmt->log, p_rec, OSM_LOG_VERBOSE); + for (j = 0; j < num_of_valid_names; j++) { + /* If the service names exist in the record, mark it as checked (1) */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "-I- Comparing source name : >%s<, with record name : >%s<, idx : %d\n", + p_valid_service_names_arr[j], + p_rec->service_name, p_checked_names[j]); + if (strcmp + ((char *)p_valid_service_names_arr[j], + (char *)p_rec->service_name) == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "-I- The service %s is valid\n", + p_valid_service_names_arr[j]); + p_checked_names[j] = 1; + break; + } + } + } + /* Check that all service names have been identified */ + for (j = 0; j < num_of_valid_names; j++) + if (p_checked_names[j] == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A14: " + "Missing valid service: name: %s\n", + p_valid_service_names_arr[j]); + status = IB_ERROR; + goto Exit; + } + *num_services = num_recs; + +Exit: + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return status; +} +#endif + +/********************************************************************** + **********************************************************************/ + +ib_api_status_t +osmt_delete_service_by_name(IN osmtest_t * const p_osmt, + IN uint8_t IsServiceExist, + IN char *sr_name, IN uint32_t rec_num) +{ + osmv_query_req_t req; + osmv_user_query_t user; + osmtest_req_context_t context; + ib_service_record_t svc_rec; + ib_api_status_t status; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Trying to Delete service name: %s\n", sr_name); + + memset(&svc_rec, 0, sizeof(svc_rec)); + + status = osmt_get_service_by_name(p_osmt, sr_name, rec_num, &svc_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A15: " + "Failed to get service: name: %s\n", sr_name); + goto ExitNoDel; + } + + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + memset(&user, 0, sizeof(user)); + + /* set the new service record fields */ + memset(svc_rec.service_name, 0, sizeof(svc_rec.service_name)); + memcpy(svc_rec.service_name, sr_name, + (strlen(sr_name) + 1) * sizeof(char)); + + /* prepare the data used for this query */ + context.p_osmt = p_osmt; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.query_context = &context; + req.query_type = OSMV_QUERY_USER_DEFINED; /* basically a don't care here */ + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.flags = OSM_SA_FLAGS_SYNC; + req.sm_key = 0; + + user.method = IB_MAD_METHOD_DELETE; + user.attr_id = IB_MAD_ATTR_SERVICE_RECORD; + user.comp_mask = IB_SR_COMPMASK_SNAME; + user.attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + user.p_attr = &svc_rec; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A16: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + if (IsServiceExist) { + /* If IsServiceExist = 1 then we should succeed here */ + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A17: " + "ib_query failed (%s)\n", + ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 4A18: Remote error = %s\n", + ib_get_mad_status_str + (osm_madw_get_mad_ptr + (context.result.p_result_madw))); + } + } + } else { + /* If IsServiceExist = 0 then we should fail here */ + if (status == IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A19: " + "Succeeded to delete service: %s which " + "shouldn't exist", sr_name); + status = IB_ERROR; + } else { + /* The deletion should have failed, since the service_name + shouldn't exist. */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "IS EXPECTED ERROR ^^^^\n"); + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Failed to delete service_name: %s\n", sr_name); + status = IB_SUCCESS; + } + } + +Exit: + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + +ExitNoDel: + OSM_LOG_EXIT(&p_osmt->log); + return status; +} + +/********************************************************************** + **********************************************************************/ + +/* + * Run a complete service records flow: + * - register a service + * - register a service (with a lease period) + * - get a service by name + * - get all services / must be 2 + * - delete a service + * - get all services / must be 1 + * - wait for the lease to expire + * - get all services / must be 0 + * - get / set service by data + */ +ib_api_status_t osmt_run_service_records_flow(IN osmtest_t * const p_osmt) +{ + ib_service_record_t srv_rec; + ib_api_status_t status; + uint8_t instance, i; + uint8_t service_data8[16], service_key[16]; + ib_net16_t service_data16[8]; + ib_net32_t service_data32[4]; + ib_net64_t service_data64[2]; + uint64_t pid = getpid(); + uint64_t id[7]; + /* We use up to seven service names - we use the extra for bad flow */ + ib_svc_name_t service_name[7]; +#ifdef VENDOR_RMPP_SUPPORT + /* This array contain only the valid names after registering vs SM */ + ib_svc_name_t service_valid_names[3]; + uint32_t num_recs = 0; +#endif + + OSM_LOG_ENTER(&p_osmt->log); + + /* Init Service names */ + for (i = 0; i < 7; i++) { +#ifdef __WIN__ + uint64_t rand_val = rand() - (uint64_t) i; +#else + uint64_t rand_val = random() - (uint64_t) i; +#endif + id[i] = abs((int)(pid - rand_val)); + /* Just to be unique any place on any host */ + sprintf((char *)(service_name[i]), + "osmt.srvc.%" PRIu64 ".%" PRIu64, rand_val, pid); + /*printf("-I- Service Name is : %s, ID is : 0x%" PRIx64 "\n",service_name[i],id[i]); */ + } + + status = osmt_register_service(p_osmt, cl_ntoh64(id[0]), /* IN ib_net64_t service_id, */ + IB_DEFAULT_PKEY, /* IN ib_net16_t service_pkey, */ + 0xFFFFFFFF, /* IN ib_net32_t service_lease, */ + 11, /* IN uint8_t service_key_lsb, */ + (char *)service_name[0] /* IN char *service_name */ + ); + if (status != IB_SUCCESS) { + goto Exit; + } + + status = osmt_register_service(p_osmt, cl_ntoh64(id[1]), /* IN ib_net64_t service_id, */ + IB_DEFAULT_PKEY, /* IN ib_net16_t service_pkey, */ + cl_hton32(0x00000004), /* IN ib_net32_t service_lease, */ + 11, /* IN uint8_t service_key_lsb, */ + (char *)service_name[1] /* IN char *service_name */ + ); + if (status != IB_SUCCESS) { + goto Exit; + } + + status = osmt_register_service(p_osmt, cl_ntoh64(id[2]), /* IN ib_net64_t service_id, */ + 0, /* IN ib_net16_t service_pkey, */ + 0xFFFFFFFF, /* IN ib_net32_t service_lease, */ + 11, /* Remove Service Record IN uint8_t service_key_lsb, */ + (char *)service_name[2] /* IN char *service_name */ + ); + + if (status != IB_SUCCESS) { + goto Exit; + } + + /* Generate 2 instances of service record with consecutive data */ + for (instance = 0; instance < 2; instance++) { + /* First, clear all arrays */ + memset(service_data8, 0, 16 * sizeof(uint8_t)); + memset(service_data16, 0, 8 * sizeof(uint16_t)); + memset(service_data32, 0, 4 * sizeof(uint32_t)); + memset(service_data64, 0, 2 * sizeof(uint64_t)); + service_data8[instance] = instance + 1; + service_data16[instance] = cl_hton16(instance + 2); + service_data32[instance] = cl_hton32(instance + 3); + service_data64[instance] = cl_hton64(instance + 4); + status = osmt_register_service_with_data(p_osmt, cl_ntoh64(id[3]), /* IN ib_net64_t service_id, */ + IB_DEFAULT_PKEY, /* IN ib_net16_t service_pkey, */ + cl_ntoh32(10), /* IN ib_net32_t service_lease, */ + 12, /* IN uint8_t service_key_lsb, */ + service_data8, service_data16, service_data32, service_data64, /* service data structures */ + (char *)service_name[3] /* IN char *service_name */ + ); + + if (status != IB_SUCCESS) { + goto Exit; + } + + } + + /* Trying to create service with zero key */ + memset(service_key, 0, 16 * sizeof(uint8_t)); + status = osmt_register_service_with_full_key(p_osmt, cl_ntoh64(id[5]), /* IN ib_net64_t service_id, */ + 0, /* IN ib_net16_t service_pkey, */ + 0xFFFFFFFF, /* IN ib_net32_t service_lease, */ + service_key, /* full service_key, */ + (char *)service_name[5] /* IN char *service_name */ + ); + + if (status != IB_SUCCESS) { + goto Exit; + } + + /* Now update it with Unique key and different service name */ + for (i = 0; i <= 15; i++) { + service_key[i] = i + 1; + } + status = osmt_register_service_with_full_key(p_osmt, cl_ntoh64(id[5]), /* IN ib_net64_t service_id, */ + 0, /* IN ib_net16_t service_pkey, */ + 0xFFFFFFFF, /* IN ib_net32_t service_lease, */ + service_key, /* full service_key, */ + (char *)service_name[6] /* IN char *service_name */ + ); + if (status != IB_SUCCESS) { + goto Exit; + } + + /* Let OpenSM handle it */ + usleep(100); + + /* Make sure service_name[0] exists */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[0], 1, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A1A: " + "Fail to find service: name: %s\n", + (char *)service_name[0]); + status = IB_ERROR; + goto Exit; + } + + /* Make sure service_name[1] exists */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[1], 1, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A1B: " + "Fail to find service: name: %s\n", + (char *)service_name[1]); + status = IB_ERROR; + goto Exit; + } + + /* Make sure service_name[2] exists */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[2], 1, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A1C: " + "Fail to find service: name: %s\n", + (char *)service_name[2]); + status = IB_ERROR; + goto Exit; + } + + /* Make sure service_name[3] exists. */ + /* After 10 seconds the service should not exist: service_lease = 10 */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[3], 1, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A1D: " + "Fail to find service: name: %s\n", + (char *)service_name[3]); + status = IB_ERROR; + goto Exit; + } + + sleep(10); + + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[3], 0, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A1E: " + "Found service: name: %s that should have been " + "deleted due to service lease expiring\n", + (char *)service_name[3]); + status = IB_ERROR; + goto Exit; + } + + /* Check that for service: id[5] only one record exists */ + status = osmt_get_service_by_id(p_osmt, 1, cl_ntoh64(id[5]), &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A1F: " + "Found number of records != 1 for " + "service: id: 0x%016" PRIx64 "\n", id[5]); + status = IB_ERROR; + goto Exit; + } + + /* Bad Flow of Get with invalid Service ID: id[6] */ + status = osmt_get_service_by_id(p_osmt, 0, cl_ntoh64(id[6]), &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A20: " + "Found service: id: 0x%016" PRIx64 " " + "that is invalid\n", id[6]); + status = IB_ERROR; + goto Exit; + } + + /* Check by both id and service name: id[0], service_name[0] */ + status = osmt_get_service_by_id_and_name(p_osmt, 1, cl_ntoh64(id[0]), + (char *)service_name[0], + &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A21: " + "Fail to find service: id: 0x%016" PRIx64 " " + "name: %s\n", id[0], (char *)service_name[0]); + status = IB_ERROR; + goto Exit; + } + + /* Check by both id and service name: id[5], service_name[6] */ + status = osmt_get_service_by_id_and_name(p_osmt, 1, cl_ntoh64(id[5]), + (char *)service_name[6], + &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A22: " + "Fail to find service: id: 0x%016" PRIx64 " " + "name: %s\n", id[5], (char *)service_name[6]); + status = IB_ERROR; + goto Exit; + } + + /* Bad Flow of Get with invalid name(service_name[3]) and valid ID(id[0]) */ + status = osmt_get_service_by_id_and_name(p_osmt, 0, cl_ntoh64(id[0]), + (char *)service_name[3], + &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A23: " + "Found service: id: 0x%016" PRIx64 + "name: %s which is an invalid service\n", + id[0], (char *)service_name[3]); + status = IB_ERROR; + goto Exit; + } + + /* Bad Flow of Get with unmatched name(service_name[5]) and id(id[3]) (both valid) */ + status = osmt_get_service_by_id_and_name(p_osmt, 0, cl_ntoh64(id[3]), + (char *)service_name[5], + &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A24: " + "Found service: id: 0x%016" PRIx64 + "name: %s which is an invalid service\n", + id[3], (char *)service_name[5]); + status = IB_ERROR; + goto Exit; + } + + /* Bad Flow of Get with service name that doesn't exist (service_name[4]) */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[4], 0, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A25: " + "Found service: name: %s that shouldn't exist\n", + (char *)service_name[4]); + status = IB_ERROR; + goto Exit; + } + + /* Bad Flow : Check that getting service_name[5] brings no records since another service + has been updated with the same ID (service_name[6] */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[5], 0, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A26: " + "Found service: name: %s which is an " + "invalid service\n", (char *)service_name[5]); + status = IB_ERROR; + goto Exit; + } + + /* Check that getting service_name[6] by name ONLY is valid, + since we do not support key&name association, also trusted queries */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[6], 1, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A27: " + "Fail to find service: name: %s\n", + (char *)service_name[6]); + status = IB_ERROR; + goto Exit; + } + + /* Test Service Key */ + memset(service_key, 0, 16 * sizeof(uint8_t)); + + /* Check for service_name[5] with service_key=0 - the service shouldn't + exist with this name. */ + status = osmt_get_service_by_name_and_key(p_osmt, + (char *)service_name[5], + 0, service_key, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A28: " + "Found service: name: %s key:0 which is an " + "invalid service (wrong name)\n", + (char *)service_name[5]); + status = IB_ERROR; + goto Exit; + } + + /* Check for service_name[6] with service_key=0 - the service should + exist with different key. */ + status = osmt_get_service_by_name_and_key(p_osmt, + (char *)service_name[6], + 0, service_key, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A29: " + "Found service: name: %s key: 0 which is an " + "invalid service (wrong service_key)\n", + (char *)service_name[6]); + status = IB_ERROR; + goto Exit; + } + + /* check for service_name[6] with the correct service_key */ + for (i = 0; i <= 15; i++) + service_key[i] = i + 1; + status = osmt_get_service_by_name_and_key(p_osmt, + (char *)service_name[6], + 1, service_key, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A2A: " + "Fail to find service: name: %s with " + "correct service key\n", (char *)service_name[6]); + status = IB_ERROR; + goto Exit; + } +#ifdef VENDOR_RMPP_SUPPORT + /* These ar the only service_names which are valid */ + memcpy(&service_valid_names[0], &service_name[0], sizeof(uint8_t) * 64); + memcpy(&service_valid_names[1], &service_name[2], sizeof(uint8_t) * 64); + memcpy(&service_valid_names[2], &service_name[6], sizeof(uint8_t) * 64); + + status = + osmt_get_all_services_and_check_names(p_osmt, service_valid_names, + 3, &num_recs); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A2B: " + "Fail to find all services that should exist\n"); + status = IB_ERROR; + goto Exit; + } +#endif + + /* Delete service_name[0] */ + status = osmt_delete_service_by_name(p_osmt, 1, + (char *)service_name[0], 1); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A2C: " + "Fail to delete service: name: %s\n", + (char *)service_name[0]); + status = IB_ERROR; + goto Exit; + } + + /* Make sure deletion of service_name[0] succeeded */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[0], 0, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A2D: " + "Found service: name: %s that was deleted\n", + (char *)service_name[0]); + status = IB_ERROR; + goto Exit; + } + + /* Make sure service_name[1] doesn't exist (expired service lease) */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[1], 0, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A2E: " + "Found service: name: %s that should have expired\n", + (char *)service_name[1]); + status = IB_ERROR; + goto Exit; + } + + /* Make sure service_name[2] exists */ + status = osmt_get_service_by_name(p_osmt, + (char *)service_name[2], 1, &srv_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A2F: " + "Fail to find service: name: %s\n", + (char *)service_name[2]); + status = IB_ERROR; + goto Exit; + } + + /* Bad Flow - try to delete non-existent service_name[5] */ + status = osmt_delete_service_by_name(p_osmt, 0, + (char *)service_name[5], 0); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A30: " + "Succeed to delete non-existent service: name: %s\n", + (char *)service_name[5]); + status = IB_ERROR; + goto Exit; + } + + /* Delete service_name[2] */ + status = osmt_delete_service_by_name(p_osmt, 1, + (char *)service_name[2], 1); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A31: " + "Fail to delete service: name: %s\n", + (char *)service_name[2]); + status = IB_ERROR; + goto Exit; + } + + /* Delete service_name[6] */ + status = osmt_delete_service_by_name(p_osmt, 1, + (char *)service_name[6], 1); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 4A32: " + "Failed to delete service name: %s\n", + (char *)service_name[6]); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return status; +} diff --git a/contrib/ofed/management/opensm/osmtest/osmt_slvl_vl_arb.c b/contrib/ofed/management/opensm/osmtest/osmt_slvl_vl_arb.c new file mode 100644 index 000000000000..82a6f39af101 --- /dev/null +++ b/contrib/ofed/management/opensm/osmtest/osmt_slvl_vl_arb.c @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* + * Abstract: + * Implementation of SLtoVL and VL Arbitration testing flow.. + * Top level is osmt_run_slvl_and_vlarb_records_flow: + * osmt_query_all_ports_vl_arb + * osmt_query_all_ports_slvl_map + * + */ + +#ifndef __WIN__ +#include +#endif +#include +#include +#include +#include +#include "osmtest.h" + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_write_vl_arb_table(IN osmtest_t * const p_osmt, + IN FILE * fh, + IN const ib_vl_arb_table_record_t * const p_rec) +{ + int result, i; + cl_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + result = fprintf(fh, + "VL_ARBITRATION_TABLE\n" + "lid 0x%X\n" + "port_num 0x%X\n" + "block 0x%X\n", + cl_ntoh16(p_rec->lid), + p_rec->port_num, p_rec->block_num); + + fprintf(fh, " "); + for (i = 0; i < 32; i++) + fprintf(fh, "| %-2u ", i); + fprintf(fh, "|\nVL: "); + + for (i = 0; i < 32; i++) + fprintf(fh, "|0x%02X", p_rec->vl_arb_tbl.vl_entry[i].vl); + fprintf(fh, "|\nWEIGHT:"); + + for (i = 0; i < 32; i++) + fprintf(fh, "|0x%02X", p_rec->vl_arb_tbl.vl_entry[i].weight); + fprintf(fh, "|\nEND\n\n"); + + /* Exit: */ + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * GET A SINGLE PORT INFO BY NODE LID AND PORT NUMBER + **********************************************************************/ +ib_api_status_t +osmt_query_vl_arb(IN osmtest_t * const p_osmt, + IN ib_net16_t const lid, + IN uint8_t const port_num, + IN uint8_t const block_num, IN FILE * fh) +{ + osmtest_req_context_t context; + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_vl_arb_table_record_t record, *p_rec; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "Getting VL_Arbitration Table for port with LID 0x%X Num:0x%X\n", + cl_ntoh16(lid), port_num); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + record.lid = lid; + record.port_num = port_num; + record.block_num = block_num; + user.p_attr = &record; + + req.query_type = OSMV_QUERY_VLARB_BY_LID_PORT_BLOCK; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0405: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0466: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + + /* ok it worked */ + p_rec = osmv_get_query_result(context.result.p_result_madw, 0); + if (fh) { + osmtest_write_vl_arb_table(p_osmt, fh, p_rec); + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +static ib_api_status_t +osmt_query_all_ports_vl_arb(IN osmtest_t * const p_osmt, IN FILE * fh) +{ + cl_status_t status = CL_SUCCESS; + cl_qmap_t *p_tbl; + port_t *p_src_port; + uint8_t block, anyErr = 0; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Obtaining ALL Ports VL Arbitration Tables\n"); + + /* + * Go over all ports that exist in the subnet + * get the relevant VLarbs + */ + + p_tbl = &p_osmt->exp_subn.port_key_tbl; + + p_src_port = (port_t *) cl_qmap_head(p_tbl); + + while (p_src_port != (port_t *) cl_qmap_end(p_tbl)) { + + /* HACK we use capability_mask to know diff a CA port from switch port */ + if (p_src_port->rec.port_info.capability_mask) { + /* this is an hca port */ + for (block = 1; block <= 4; block++) { + /* NOTE to comply we must set port number to 0 and the SA should figure it out */ + /* since it is a CA port */ + status = + osmt_query_vl_arb(p_osmt, + p_src_port->rec.lid, 0, + block, fh); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0467: " + "Failed to get Lid:0x%X Port:0x%X (%s)\n", + cl_ntoh16(p_src_port->rec.lid), + 0, ib_get_err_str(status)); + anyErr = 1; + } + } + } else { + /* this is a switch port */ + for (block = 1; block <= 4; block++) { + status = + osmt_query_vl_arb(p_osmt, + p_src_port->rec.lid, + p_src_port->rec.port_num, + block, fh); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0468: " + "Failed to get Lid:0x%X Port:0x%X (%s)\n", + cl_ntoh16(p_src_port->rec.lid), + p_src_port->rec.port_num, + ib_get_err_str(status)); + anyErr = 1; + } + } + } + + p_src_port = (port_t *) cl_qmap_next(&p_src_port->map_item); + } + + OSM_LOG_EXIT(&p_osmt->log); + if (anyErr) { + status = IB_ERROR; + } + return (status); +} + +/******************************************************************************* + SLtoVL +*******************************************************************************/ +static ib_api_status_t +osmtest_write_slvl_map_table(IN osmtest_t * const p_osmt, + IN FILE * fh, + IN const ib_slvl_table_record_t * const p_rec) +{ + int result, i; + cl_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + result = fprintf(fh, + "SLtoVL_MAP_TABLE\n" + "lid 0x%X\n" + "in_port_num 0x%X\n" + "out_port_num 0x%X\n", + cl_ntoh16(p_rec->lid), + p_rec->in_port_num, p_rec->out_port_num); + + fprintf(fh, "SL:"); + for (i = 0; i < 16; i++) + fprintf(fh, "| %-2u ", i); + fprintf(fh, "|\nVL:"); + + for (i = 0; i < 16; i++) + fprintf(fh, "| 0x%01X ", + ib_slvl_table_get(&p_rec->slvl_tbl, (uint8_t) i)); + fprintf(fh, "|\nEND\n\n"); + + /* Exit: */ + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * GET A SINGLE PORT INFO BY NODE LID AND PORT NUMBER + **********************************************************************/ +ib_api_status_t +osmt_query_slvl_map(IN osmtest_t * const p_osmt, + IN ib_net16_t const lid, + IN uint8_t const out_port_num, + IN uint8_t const in_port_num, IN FILE * fh) +{ + osmtest_req_context_t context; + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_slvl_table_record_t record, *p_rec; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "Getting SLtoVL Map Table for out-port with LID 0x%X Num:0x%X from In-Port:0x%X\n", + cl_ntoh16(lid), out_port_num, in_port_num); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + record.lid = lid; + record.in_port_num = in_port_num; + record.out_port_num = out_port_num; + user.p_attr = &record; + + req.query_type = OSMV_QUERY_SLVL_BY_LID_AND_PORTS; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0469: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0470: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + + /* ok it worked */ + p_rec = osmv_get_query_result(context.result.p_result_madw, 0); + if (fh) { + osmtest_write_slvl_map_table(p_osmt, fh, p_rec); + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +static ib_api_status_t +osmt_query_all_ports_slvl_map(IN osmtest_t * const p_osmt, IN FILE * fh) +{ + cl_status_t status = CL_SUCCESS; + cl_qmap_t *p_tbl; + port_t *p_src_port; + uint8_t in_port, anyErr = 0, num_ports; + node_t *p_node; + const cl_qmap_t *p_node_tbl; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * Go over all ports that exist in the subnet + * get the relevant SLtoVLs + */ + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Obtaining ALL Ports (to other ports) SLtoVL Maps\n"); + + p_tbl = &p_osmt->exp_subn.port_key_tbl; + p_node_tbl = &p_osmt->exp_subn.node_lid_tbl; + + p_src_port = (port_t *) cl_qmap_head(p_tbl); + + while (p_src_port != (port_t *) cl_qmap_end(p_tbl)) { + + /* HACK we use capability_mask to know diff a CA port from switch port */ + if (p_src_port->rec.port_info.capability_mask) { + /* this is an hca port */ + /* NOTE to comply we must set port number to 0 and the SA should figure it out */ + /* since it is a CA port */ + status = + osmt_query_slvl_map(p_osmt, p_src_port->rec.lid, 0, + 0, fh); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0471: " + "Failed to get Lid:0x%X In-Port:0x%X Out-Port:0x%X(%s)\n", + cl_ntoh16(p_src_port->rec.lid), 0, 0, + ib_get_err_str(status)); + anyErr = 1; + } + } else { + /* this is a switch port */ + /* get the node */ + p_node = + (node_t *) cl_qmap_get(p_node_tbl, + p_src_port->rec.lid); + if (p_node == (node_t *) cl_qmap_end(p_node_tbl)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0472: " + "Failed to get Node by Lid:0x%X\n", + p_src_port->rec.lid); + goto Exit; + } + + num_ports = p_node->rec.node_info.num_ports; + + for (in_port = 1; in_port <= num_ports; in_port++) { + status = + osmt_query_slvl_map(p_osmt, + p_src_port->rec.lid, + p_src_port->rec. + port_num, in_port, fh); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0473: " + "Failed to get Lid:0x%X In-Port:0x%X Out-Port:0x%X (%s)\n", + cl_ntoh16(p_src_port->rec.lid), + p_src_port->rec.port_num, + in_port, + ib_get_err_str(status)); + anyErr = 1; + } + } + } + + p_src_port = (port_t *) cl_qmap_next(&p_src_port->map_item); + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + if (anyErr) { + status = IB_ERROR; + } + return (status); +} + +/* + * Run a vl arbitration queries and sl2vl maps queries flow: + * Good flow: + * - for each physical port on the network - obtain the VL Arb + * - for each CA physical port obtain its SLtoVL Map + * - for each SW physical port (out) obtain the SLtoVL Map to each other port + * BAD flow: + * - Try get with multiple results + * - Try gettable + * - Try providing non existing port + */ +ib_api_status_t +osmt_run_slvl_and_vlarb_records_flow(IN osmtest_t * const p_osmt) +{ + ib_api_status_t status; + FILE *fh; + ib_net16_t test_lid; + uint8_t lmc; + + OSM_LOG_ENTER(&p_osmt->log); + + fh = fopen("qos.txt", "w"); + + /* go over all ports in the subnet */ + status = osmt_query_all_ports_vl_arb(p_osmt, fh); + if (status != IB_SUCCESS) { + goto Exit; + } + + status = osmt_query_all_ports_slvl_map(p_osmt, fh); + if (status != IB_SUCCESS) { + goto Exit; + } + + /* If LMC > 0, test non base LID SA QoS Record requests */ + status = + osmtest_get_local_port_lmc(p_osmt, p_osmt->local_port.lid, &lmc); + if (status != IB_SUCCESS) + goto Exit; + + if (lmc != 0) { + test_lid = cl_ntoh16(p_osmt->local_port.lid + 1); + + status = osmt_query_vl_arb(p_osmt, test_lid, 0, 1, NULL); + if (status != IB_SUCCESS) + goto Exit; + + status = osmt_query_slvl_map(p_osmt, test_lid, 0, 0, NULL); + if (status != IB_SUCCESS) + goto Exit; + } + +Exit: + fclose(fh); + OSM_LOG_EXIT(&p_osmt->log); + return status; +} diff --git a/contrib/ofed/management/opensm/osmtest/osmtest.c b/contrib/ofed/management/opensm/osmtest/osmtest.c new file mode 100644 index 000000000000..243d0b29b5a5 --- /dev/null +++ b/contrib/ofed/management/opensm/osmtest/osmtest.c @@ -0,0 +1,7403 @@ +/* + * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +/* TODO : Check why we dont free the cl_qmap_items we store when reading DB */ + +/* + * Abstract: + * Implementation of osmtest_t. + * This object represents the OSMTest Test object. + * + */ + +#ifdef __WIN__ +#pragma warning(disable : 4996) +#endif + +#include +#include +#include +#ifdef __WIN__ +#include +#else +#include +#include +#endif +#include +#include "osmtest.h" + +#ifndef __WIN__ +#define strnicmp strncasecmp +#endif + +#define POOL_MIN_ITEMS 64 +#define GUID_ARRAY_SIZE 64 + +typedef struct _osmtest_sm_info_rec { + ib_net64_t sm_guid; + ib_net16_t lid; + uint8_t priority; + uint8_t sm_state; +} osmtest_sm_info_rec_t; + +typedef struct _osmtest_inform_info { + boolean_t subscribe; + ib_net32_t qpn; + ib_net16_t trap; +} osmtest_inform_info_t; + +typedef struct _osmtest_inform_info_rec { + ib_gid_t subscriber_gid; + ib_net16_t subscriber_enum; +} osmtest_inform_info_rec_t; + +typedef enum _osmtest_token_val { + OSMTEST_TOKEN_COMMENT = 0, + OSMTEST_TOKEN_END, + OSMTEST_TOKEN_DEFINE_NODE, + OSMTEST_TOKEN_DEFINE_PORT, + OSMTEST_TOKEN_DEFINE_PATH, + OSMTEST_TOKEN_DEFINE_LINK, + OSMTEST_TOKEN_LID, + OSMTEST_TOKEN_BASE_VERSION, + OSMTEST_TOKEN_CLASS_VERSION, + OSMTEST_TOKEN_NODE_TYPE, + OSMTEST_TOKEN_NUM_PORTS, + OSMTEST_TOKEN_SYS_GUID, + OSMTEST_TOKEN_NODE_GUID, + OSMTEST_TOKEN_PORT_GUID, + OSMTEST_TOKEN_PARTITION_CAP, + OSMTEST_TOKEN_DEVICE_ID, + OSMTEST_TOKEN_REVISION, + OSMTEST_TOKEN_PORT_NUM, + OSMTEST_TOKEN_VENDOR_ID, + OSMTEST_TOKEN_DGID, + OSMTEST_TOKEN_SGID, + OSMTEST_TOKEN_DLID, + OSMTEST_TOKEN_SLID, + OSMTEST_TOKEN_HOP_FLOW_RAW, + OSMTEST_TOKEN_TCLASS, + OSMTEST_TOKEN_NUM_PATH, + OSMTEST_TOKEN_PKEY, + OSMTEST_TOKEN_SL, + OSMTEST_TOKEN_RATE, + OSMTEST_TOKEN_PKT_LIFE, + OSMTEST_TOKEN_PREFERENCE, + OSMTEST_TOKEN_MKEY, + OSMTEST_TOKEN_SUBN_PREF, + OSMTEST_TOKEN_BASE_LID, + OSMTEST_TOKEN_SM_BASE_LID, + OSMTEST_TOKEN_CAP_MASK, + OSMTEST_TOKEN_DIAG_CODE, + OSMTEST_TOKEN_MKEY_LEASE_PER, + OSMTEST_TOKEN_LOC_PORT_NUM, + OSMTEST_TOKEN_LINK_WID_EN, + OSMTEST_TOKEN_LINK_WID_SUP, + OSMTEST_TOKEN_LINK_WID_ACT, + OSMTEST_TOKEN_LINK_SPEED_SUP, + OSMTEST_TOKEN_PORT_STATE, + OSMTEST_TOKEN_STATE_INFO2, + OSMTEST_TOKEN_MKEY_PROT_BITS, + OSMTEST_TOKEN_LMC, + OSMTEST_TOKEN_LINK_SPEED, + OSMTEST_TOKEN_MTU_SMSL, + OSMTEST_TOKEN_VL_CAP, + OSMTEST_TOKEN_VL_HIGH_LIMIT, + OSMTEST_TOKEN_VL_ARB_HIGH_CAP, + OSMTEST_TOKEN_VL_ARB_LOW_CAP, + OSMTEST_TOKEN_MTU_CAP, + OSMTEST_TOKEN_VL_STALL_LIFE, + OSMTEST_TOKEN_VL_ENFORCE, + OSMTEST_TOKEN_MKEY_VIOL, + OSMTEST_TOKEN_PKEY_VIOL, + OSMTEST_TOKEN_QKEY_VIOL, + OSMTEST_TOKEN_GUID_CAP, + OSMTEST_TOKEN_SUBN_TIMEOUT, + OSMTEST_TOKEN_RESP_TIME_VAL, + OSMTEST_TOKEN_ERR_THRESHOLD, + OSMTEST_TOKEN_MTU, + OSMTEST_TOKEN_FROMLID, + OSMTEST_TOKEN_FROMPORTNUM, + OSMTEST_TOKEN_TOPORTNUM, + OSMTEST_TOKEN_TOLID, + OSMTEST_TOKEN_UNKNOWN +} osmtest_token_val_t; + +typedef struct _osmtest_token { + osmtest_token_val_t val; + size_t str_size; + const char *str; +} osmtest_token_t; + +const osmtest_token_t token_array[] = { + {OSMTEST_TOKEN_COMMENT, 1, "#"}, + {OSMTEST_TOKEN_END, 3, "END"}, + {OSMTEST_TOKEN_DEFINE_NODE, 11, "DEFINE_NODE"}, + {OSMTEST_TOKEN_DEFINE_PORT, 11, "DEFINE_PORT"}, + {OSMTEST_TOKEN_DEFINE_PATH, 11, "DEFINE_PATH"}, + {OSMTEST_TOKEN_DEFINE_LINK, 11, "DEFINE_LINK"}, + {OSMTEST_TOKEN_LID, 3, "LID"}, + {OSMTEST_TOKEN_BASE_VERSION, 12, "BASE_VERSION"}, + {OSMTEST_TOKEN_CLASS_VERSION, 13, "CLASS_VERSION"}, + {OSMTEST_TOKEN_NODE_TYPE, 9, "NODE_TYPE"}, + {OSMTEST_TOKEN_NUM_PORTS, 9, "NUM_PORTS"}, + {OSMTEST_TOKEN_SYS_GUID, 8, "SYS_GUID"}, + {OSMTEST_TOKEN_NODE_GUID, 9, "NODE_GUID"}, + {OSMTEST_TOKEN_PORT_GUID, 9, "PORT_GUID"}, + {OSMTEST_TOKEN_PARTITION_CAP, 13, "PARTITION_CAP"}, + {OSMTEST_TOKEN_DEVICE_ID, 9, "DEVICE_ID"}, + {OSMTEST_TOKEN_REVISION, 8, "REVISION"}, + {OSMTEST_TOKEN_PORT_NUM, 8, "PORT_NUM"}, + {OSMTEST_TOKEN_VENDOR_ID, 9, "VENDOR_ID"}, + {OSMTEST_TOKEN_DGID, 4, "DGID"}, + {OSMTEST_TOKEN_SGID, 4, "SGID"}, + {OSMTEST_TOKEN_DLID, 4, "DLID"}, + {OSMTEST_TOKEN_SLID, 4, "SLID"}, + {OSMTEST_TOKEN_HOP_FLOW_RAW, 12, "HOP_FLOW_RAW"}, + {OSMTEST_TOKEN_TCLASS, 6, "TCLASS"}, + {OSMTEST_TOKEN_NUM_PATH, 8, "NUM_PATH"}, + {OSMTEST_TOKEN_PKEY, 4, "PKEY"}, + {OSMTEST_TOKEN_SL, 2, "SL"}, + {OSMTEST_TOKEN_RATE, 4, "RATE"}, + {OSMTEST_TOKEN_PKT_LIFE, 8, "PKT_LIFE"}, + {OSMTEST_TOKEN_PREFERENCE, 10, "PREFERENCE"}, + {OSMTEST_TOKEN_MKEY, 4, "M_KEY"}, + {OSMTEST_TOKEN_SUBN_PREF, 13, "SUBNET_PREFIX"}, + {OSMTEST_TOKEN_BASE_LID, 8, "BASE_LID"}, + {OSMTEST_TOKEN_SM_BASE_LID, 18, "MASTER_SM_BASE_LID"}, + {OSMTEST_TOKEN_CAP_MASK, 15, "CAPABILITY_MASK"}, + {OSMTEST_TOKEN_DIAG_CODE, 9, "DIAG_CODE"}, + {OSMTEST_TOKEN_MKEY_LEASE_PER, 18, "m_key_lease_period"}, + {OSMTEST_TOKEN_LOC_PORT_NUM, 14, "local_port_num"}, + {OSMTEST_TOKEN_LINK_WID_EN, 18, "link_width_enabled"}, + {OSMTEST_TOKEN_LINK_WID_SUP, 20, "link_width_supported"}, + {OSMTEST_TOKEN_LINK_WID_ACT, 17, "link_width_active"}, + {OSMTEST_TOKEN_LINK_SPEED_SUP, 20, "link_speed_supported"}, + {OSMTEST_TOKEN_PORT_STATE, 10, "port_state"}, + {OSMTEST_TOKEN_STATE_INFO2, 10, "state_info2"}, + {OSMTEST_TOKEN_MKEY_PROT_BITS, 3, "mpb"}, + {OSMTEST_TOKEN_LMC, 3, "lmc"}, + {OSMTEST_TOKEN_LINK_SPEED, 10, "link_speed"}, + {OSMTEST_TOKEN_MTU_SMSL, 8, "mtu_smsl"}, + {OSMTEST_TOKEN_VL_CAP, 6, "vl_cap"}, + {OSMTEST_TOKEN_VL_HIGH_LIMIT, 13, "vl_high_limit"}, + {OSMTEST_TOKEN_VL_ARB_HIGH_CAP, 15, "vl_arb_high_cap"}, + {OSMTEST_TOKEN_VL_ARB_LOW_CAP, 14, "vl_arb_low_cap"}, + {OSMTEST_TOKEN_MTU_CAP, 7, "mtu_cap"}, + {OSMTEST_TOKEN_VL_STALL_LIFE, 13, "vl_stall_life"}, + {OSMTEST_TOKEN_VL_ENFORCE, 10, "vl_enforce"}, + {OSMTEST_TOKEN_MKEY_VIOL, 16, "m_key_violations"}, + {OSMTEST_TOKEN_PKEY_VIOL, 16, "p_key_violations"}, + {OSMTEST_TOKEN_QKEY_VIOL, 16, "q_key_violations"}, + {OSMTEST_TOKEN_GUID_CAP, 8, "guid_cap"}, + {OSMTEST_TOKEN_SUBN_TIMEOUT, 14, "subnet_timeout"}, + {OSMTEST_TOKEN_RESP_TIME_VAL, 15, "resp_time_value"}, + {OSMTEST_TOKEN_ERR_THRESHOLD, 15, "error_threshold"}, + {OSMTEST_TOKEN_MTU, 3, "MTU"}, /* must be after the other mtu... tokens. */ + {OSMTEST_TOKEN_FROMLID, 8, "from_lid"}, + {OSMTEST_TOKEN_FROMPORTNUM, 13, "from_port_num"}, + {OSMTEST_TOKEN_TOPORTNUM, 11, "to_port_num"}, + {OSMTEST_TOKEN_TOLID, 6, "to_lid"}, + {OSMTEST_TOKEN_UNKNOWN, 0, ""} /* must be last entry */ +}; + +#define IB_MAD_STATUS_CLASS_MASK (CL_HTON16(0xFF00)) + +static const char ib_mad_status_str_busy[] = "IB_MAD_STATUS_BUSY"; +static const char ib_mad_status_str_redirect[] = "IB_MAD_STATUS_REDIRECT"; +static const char ib_mad_status_str_unsup_class_ver[] = + "IB_MAD_STATUS_UNSUP_CLASS_VER"; +static const char ib_mad_status_str_unsup_method[] = + "IB_MAD_STATUS_UNSUP_METHOD"; +static const char ib_mad_status_str_unsup_method_attr[] = + "IB_MAD_STATUS_UNSUP_METHOD_ATTR"; +static const char ib_mad_status_str_invalid_field[] = + "IB_MAD_STATUS_INVALID_FIELD"; +static const char ib_mad_status_str_no_resources[] = + "IB_SA_MAD_STATUS_NO_RESOURCES"; +static const char ib_mad_status_str_req_invalid[] = + "IB_SA_MAD_STATUS_REQ_INVALID"; +static const char ib_mad_status_str_no_records[] = + "IB_SA_MAD_STATUS_NO_RECORDS"; +static const char ib_mad_status_str_too_many_records[] = + "IB_SA_MAD_STATUS_TOO_MANY_RECORDS"; +static const char ib_mad_status_str_invalid_gid[] = + "IB_SA_MAD_STATUS_INVALID_GID"; +static const char ib_mad_status_str_insuf_comps[] = + "IB_SA_MAD_STATUS_INSUF_COMPS"; +static const char generic_or_str[] = " | "; + +/********************************************************************** + **********************************************************************/ +const char *ib_get_mad_status_str(IN const ib_mad_t * const p_mad) +{ + static char line[512]; + uint32_t offset = 0; + ib_net16_t status; + boolean_t first = TRUE; + + line[offset] = '\0'; + + status = (ib_net16_t) (p_mad->status & IB_SMP_STATUS_MASK); + + if (status == 0) { + strcat(&line[offset], "IB_SUCCESS"); + return (line); + } + + if (status & IB_MAD_STATUS_BUSY) { + strcat(&line[offset], ib_mad_status_str_busy); + offset += sizeof(ib_mad_status_str_busy); + } + if (status & IB_MAD_STATUS_REDIRECT) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_redirect); + offset += sizeof(ib_mad_status_str_redirect) - 1; + } + if ((status & IB_MAD_STATUS_INVALID_FIELD) == + IB_MAD_STATUS_UNSUP_CLASS_VER) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_unsup_class_ver); + offset += sizeof(ib_mad_status_str_unsup_class_ver) - 1; + } + if ((status & IB_MAD_STATUS_INVALID_FIELD) == + IB_MAD_STATUS_UNSUP_METHOD) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_unsup_method); + offset += sizeof(ib_mad_status_str_unsup_method) - 1; + } + if ((status & IB_MAD_STATUS_INVALID_FIELD) == + IB_MAD_STATUS_UNSUP_METHOD_ATTR) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_unsup_method_attr); + offset += sizeof(ib_mad_status_str_unsup_method_attr) - 1; + } + if ((status & IB_MAD_STATUS_INVALID_FIELD) == + IB_MAD_STATUS_INVALID_FIELD) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_invalid_field); + offset += sizeof(ib_mad_status_str_invalid_field) - 1; + } + if ((status & IB_MAD_STATUS_CLASS_MASK) == + IB_SA_MAD_STATUS_NO_RESOURCES) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_no_resources); + offset += sizeof(ib_mad_status_str_no_resources) - 1; + } + if ((status & IB_MAD_STATUS_CLASS_MASK) == IB_SA_MAD_STATUS_REQ_INVALID) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_req_invalid); + offset += sizeof(ib_mad_status_str_req_invalid) - 1; + } + if ((status & IB_MAD_STATUS_CLASS_MASK) == IB_SA_MAD_STATUS_NO_RECORDS) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_no_records); + offset += sizeof(ib_mad_status_str_no_records) - 1; + } + if ((status & IB_MAD_STATUS_CLASS_MASK) == + IB_SA_MAD_STATUS_TOO_MANY_RECORDS) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_too_many_records); + offset += sizeof(ib_mad_status_str_too_many_records) - 1; + } + if ((status & IB_MAD_STATUS_CLASS_MASK) == IB_SA_MAD_STATUS_INVALID_GID) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_invalid_gid); + offset += sizeof(ib_mad_status_str_invalid_gid) - 1; + } + if ((status & IB_MAD_STATUS_CLASS_MASK) == IB_SA_MAD_STATUS_INSUF_COMPS) { + if (!first) { + strcat(&line[offset], generic_or_str); + offset += sizeof(generic_or_str) - 1; + } + first = FALSE; + strcat(&line[offset], ib_mad_status_str_insuf_comps); + offset += sizeof(ib_mad_status_str_insuf_comps) - 1; + } + + return (line); +} + +/********************************************************************** + **********************************************************************/ +void subnet_construct(IN subnet_t * const p_subn) +{ + cl_qmap_init(&p_subn->link_tbl); + cl_qmap_init(&p_subn->node_lid_tbl); + cl_qmap_init(&p_subn->node_guid_tbl); + cl_qmap_init(&p_subn->mgrp_mlid_tbl); + + /* NO WAY TO HAVE UNIQUE PORT BY LID OR GUID */ + /* cl_qmap_init( &p_subn->port_lid_tbl ); */ + /* cl_qmap_init( &p_subn->port_guid_tbl ); */ + + /* port key is a lid and num pair */ + cl_qmap_init(&p_subn->port_key_tbl); + cl_qmap_init(&p_subn->path_tbl); +} + +/********************************************************************** + **********************************************************************/ +cl_status_t subnet_init(IN subnet_t * const p_subn) +{ + cl_status_t status = IB_SUCCESS; + + subnet_construct(p_subn); + + return (status); +} + +/********************************************************************** + **********************************************************************/ +void osmtest_construct(IN osmtest_t * const p_osmt) +{ + memset(p_osmt, 0, sizeof(*p_osmt)); + osm_log_construct(&p_osmt->log); + subnet_construct(&p_osmt->exp_subn); +} + +/********************************************************************** + **********************************************************************/ +void osmtest_destroy(IN osmtest_t * const p_osmt) +{ + cl_map_item_t *p_item, *p_next_item; + + /* Currently there is a problem with IBAL exit flow - memory overrun, + so bypass vendor deletion - it will be cleaned by the Windows OS */ +#ifndef __WIN__ + if (p_osmt->p_vendor) + osm_vendor_delete(&p_osmt->p_vendor); +#endif + + cl_qpool_destroy(&p_osmt->port_pool); + cl_qpool_destroy(&p_osmt->node_pool); + + /* destroy the qmap tables */ + p_next_item = cl_qmap_head(&p_osmt->exp_subn.link_tbl); + while (p_next_item != cl_qmap_end(&p_osmt->exp_subn.link_tbl)) { + p_item = p_next_item; + p_next_item = cl_qmap_next(p_item); + free(p_item); + } + p_next_item = cl_qmap_head(&p_osmt->exp_subn.mgrp_mlid_tbl); + while (p_next_item != cl_qmap_end(&p_osmt->exp_subn.mgrp_mlid_tbl)) { + p_item = p_next_item; + p_next_item = cl_qmap_next(p_item); + free(p_item); + } + p_next_item = cl_qmap_head(&p_osmt->exp_subn.node_guid_tbl); + while (p_next_item != cl_qmap_end(&p_osmt->exp_subn.node_guid_tbl)) { + p_item = p_next_item; + p_next_item = cl_qmap_next(p_item); + free(p_item); + } + + p_next_item = cl_qmap_head(&p_osmt->exp_subn.node_lid_tbl); + while (p_next_item != cl_qmap_end(&p_osmt->exp_subn.node_lid_tbl)) { + p_item = p_next_item; + p_next_item = cl_qmap_next(p_item); + free(p_item); + } + + p_next_item = cl_qmap_head(&p_osmt->exp_subn.path_tbl); + while (p_next_item != cl_qmap_end(&p_osmt->exp_subn.path_tbl)) { + p_item = p_next_item; + p_next_item = cl_qmap_next(p_item); + free(p_item); + } + p_next_item = cl_qmap_head(&p_osmt->exp_subn.port_key_tbl); + while (p_next_item != cl_qmap_end(&p_osmt->exp_subn.port_key_tbl)) { + p_item = p_next_item; + p_next_item = cl_qmap_next(p_item); + free(p_item); + } + + osm_log_destroy(&p_osmt->log); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osmtest_init(IN osmtest_t * const p_osmt, + IN const osmtest_opt_t * const p_opt, + IN const osm_log_level_t log_flags) +{ + ib_api_status_t status; + + /* Can't use log macros here, since we're initializing the log. */ + osmtest_construct(p_osmt); + + status = osm_log_init_v2(&p_osmt->log, p_opt->force_log_flush, + 0x0001, p_opt->log_file, 0, TRUE); + if (status != IB_SUCCESS) + return (status); + + /* but we do not want any extra stuff here */ + osm_log_set_level(&p_osmt->log, log_flags); + + OSM_LOG(&p_osmt->log, OSM_LOG_FUNCS, "[\n"); + + p_osmt->opt = *p_opt; + + status = cl_qpool_init(&p_osmt->node_pool, POOL_MIN_ITEMS, 0, + POOL_MIN_ITEMS, sizeof(node_t), NULL, NULL, + NULL); + CL_ASSERT(status == CL_SUCCESS); + + status = cl_qpool_init(&p_osmt->port_pool, POOL_MIN_ITEMS, 0, + POOL_MIN_ITEMS, sizeof(port_t), NULL, NULL, + NULL); + CL_ASSERT(status == CL_SUCCESS); + + p_osmt->p_vendor = osm_vendor_new(&p_osmt->log, + p_opt->transaction_timeout); + + if (p_osmt->p_vendor == NULL) { + status = IB_INSUFFICIENT_RESOURCES; + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0001: " + "Unable to allocate vendor object"); + status = IB_ERROR; + goto Exit; + } + + osm_mad_pool_construct(&p_osmt->mad_pool); + status = osm_mad_pool_init(&p_osmt->mad_pool); + if (status != IB_SUCCESS) + goto Exit; + +Exit: + OSM_LOG(&p_osmt->log, OSM_LOG_FUNCS, "]\n"); + return (status); +} + +/********************************************************************** + **********************************************************************/ +void osmtest_query_res_cb(IN osmv_query_res_t * p_rec) +{ + osmtest_req_context_t *const p_ctxt = + (osmtest_req_context_t *) p_rec->query_context; + osmtest_t *const p_osmt = p_ctxt->p_osmt; + + OSM_LOG_ENTER(&p_osmt->log); + + p_ctxt->result = *p_rec; + + if (p_rec->status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0003: " + "Error on query (%s)\n", ib_get_err_str(p_rec->status)); + } + + OSM_LOG_EXIT(&p_osmt->log); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osmtest_get_all_recs(IN osmtest_t * const p_osmt, + IN ib_net16_t const attr_id, + IN size_t const attr_size, + IN OUT osmtest_req_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "Getting all %s records\n", + ib_get_sa_attr_str(attr_id)); + + /* + * Do a blocking query for all records in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + + p_context->p_osmt = p_osmt; + user.attr_id = attr_id; + user.attr_offset = cl_ntoh16((uint16_t) (attr_size >> 3)); + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0004: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0064: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (p_context->result. + p_result_madw))); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t osmtest_validate_sa_class_port_info(IN osmtest_t * const p_osmt) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_query_req_t req; + ib_class_port_info_t *p_cpi; + osmtest_req_context_t context; + osmtest_req_context_t *p_context = &context; + ib_sa_mad_t *p_resp_sa_madp; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Getting ClassPortInfo\n"); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + + p_context->p_osmt = p_osmt; + req.query_type = OSMV_QUERY_CLASS_PORT_INFO; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = 0; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0065: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0070: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (p_context->result. + p_result_madw))); + } + goto Exit; + } + + /* ok we got it so please print it out */ + p_resp_sa_madp = + (ib_sa_mad_t *) osm_madw_get_mad_ptr(context.result.p_result_madw); + p_cpi = + (ib_class_port_info_t *) ib_sa_mad_get_payload_ptr(p_resp_sa_madp); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "\n-----------------------------\n" + "SA Class Port Info:\n" + " base_ver:%u\n" + " class_ver:%u\n" + " cap_mask:0x%X\n" + " cap_mask2:0x%X\n" + " resp_time_val:0x%X\n" + "-----------------------------\n", + p_cpi->base_ver, p_cpi->class_ver, cl_ntoh16(p_cpi->cap_mask), + ib_class_cap_mask2(p_cpi), ib_class_resp_time_val(p_cpi)); + +Exit: +#if 0 + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } +#endif + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osmtest_get_node_rec(IN osmtest_t * const p_osmt, + IN ib_net64_t const node_guid, + IN OUT osmtest_req_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_node_record_t record; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting node record for 0x%016" PRIx64 "\n", + cl_ntoh64(node_guid)); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&record, 0, sizeof(record)); + + record.node_info.node_guid = node_guid; + + p_context->p_osmt = p_osmt; + user.comp_mask = IB_NR_COMPMASK_NODEGUID; + user.attr_id = IB_MAD_ATTR_NODE_RECORD; + user.attr_offset = cl_ntoh16((uint16_t) (sizeof(record) >> 3)); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0071: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0072: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (p_context->result. + p_result_madw))); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * Get a node record by node LID + **********************************************************************/ +ib_api_status_t +osmtest_get_node_rec_by_lid(IN osmtest_t * const p_osmt, + IN ib_net16_t const lid, + IN OUT osmtest_req_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_node_record_t record; + ib_mad_t *p_mad; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting node record for LID 0x%02X\n", cl_ntoh16(lid)); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&record, 0, sizeof(record)); + + record.lid = lid; + + p_context->p_osmt = p_osmt; + user.comp_mask = IB_NR_COMPMASK_LID; + user.attr_id = IB_MAD_ATTR_NODE_RECORD; + user.attr_offset = cl_ntoh16((uint16_t) (sizeof(record) >> 3)); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0073: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0074: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR) { + p_mad = + osm_madw_get_mad_ptr(p_context->result. + p_result_madw); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(p_mad)); + + status = + (ib_net16_t) (p_mad->status & IB_SMP_STATUS_MASK); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_get_path_rec_by_guid_pair(IN osmtest_t * const p_osmt, + IN ib_net64_t sguid, + IN ib_net64_t dguid, + IN osmtest_req_context_t * p_context) +{ + cl_status_t status = IB_SUCCESS; + osmv_query_req_t req; + osmv_guid_pair_t guid_pair; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&req, 0, sizeof(req)); + memset(p_context, 0, sizeof(*p_context)); + + p_context->p_osmt = p_osmt; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + + req.query_type = OSMV_QUERY_PATH_REC_BY_PORT_GUIDS; + + guid_pair.dest_guid = dguid; + guid_pair.src_guid = sguid; + + req.p_query_input = &guid_pair; + req.sm_key = 0; + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Query for path from 0x%" PRIx64 " to 0x%" PRIx64 "\n", + sguid, dguid); + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0063: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = (*p_context).result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0066: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + ((*p_context).result. + p_result_madw))); + } + goto Exit; + } + +Exit: + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_get_path_rec_by_gid_pair(IN osmtest_t * const p_osmt, + IN ib_gid_t sgid, + IN ib_gid_t dgid, + IN osmtest_req_context_t * p_context) +{ + cl_status_t status = IB_SUCCESS; + osmv_query_req_t req; + osmv_gid_pair_t gid_pair; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&req, 0, sizeof(req)); + memset(p_context, 0, sizeof(*p_context)); + + p_context->p_osmt = p_osmt; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + + req.query_type = OSMV_QUERY_PATH_REC_BY_GIDS; + + gid_pair.dest_gid = dgid; + gid_pair.src_gid = sgid; + + req.p_query_input = &gid_pair; + req.sm_key = 0; + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Query for path from 0x%016" PRIx64 " 0x%016" PRIx64 + " to 0x%016" PRIx64 " 0x%016" PRIx64 "\n", sgid.unicast.prefix, + sgid.unicast.interface_id, dgid.unicast.prefix, + dgid.unicast.interface_id); + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 006A: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = (*p_context).result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 006B: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + ((*p_context).result. + p_result_madw))); + } + goto Exit; + } + +Exit: + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_get_multipath_rec(IN osmtest_t * const p_osmt, + IN osmv_multipath_req_t * p_request, + IN osmtest_req_context_t * p_context) +{ + cl_status_t status = IB_SUCCESS; + osmv_query_req_t req; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + + p_context->p_osmt = p_osmt; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + + req.query_type = OSMV_QUERY_MULTIPATH_REC; + + req.p_query_input = p_request; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0068: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0069: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (p_context->result. + p_result_madw))); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} +#endif + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osmtest_get_port_rec(IN osmtest_t * const p_osmt, + IN ib_net16_t const lid, + IN OUT osmtest_req_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_portinfo_record_t record; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "Getting PortInfoRecord for port with LID 0x%X\n", + cl_ntoh16(lid)); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&record, 0, sizeof(record)); + + record.lid = lid; + + p_context->p_osmt = p_osmt; + user.comp_mask = IB_PIR_COMPMASK_LID; + user.attr_id = IB_MAD_ATTR_PORTINFO_RECORD; + user.attr_offset = cl_ntoh16((uint16_t) (sizeof(record) >> 3)); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0075: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0076: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (p_context->result. + p_result_madw))); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osmtest_get_port_rec_by_num(IN osmtest_t * const p_osmt, + IN ib_net16_t const lid, + IN uint8_t const port_num, + IN OUT osmtest_req_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_portinfo_record_t record; + ib_mad_t *p_mad; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "Getting PortInfoRecord for port with LID 0x%X Num:0x%X\n", + cl_ntoh16(lid), port_num); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&record, 0, sizeof(record)); + + record.lid = lid; + record.port_num = port_num; + user.p_attr = &record; + + p_context->p_osmt = p_osmt; + + req.query_type = OSMV_QUERY_PORT_REC_BY_LID_AND_NUM; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0077: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0078: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + p_mad = + osm_madw_get_mad_ptr(p_context->result. + p_result_madw); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(p_mad)); + status = + (ib_net16_t) (p_mad->status & IB_SMP_STATUS_MASK); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osmtest_stress_port_recs_large(IN osmtest_t * const p_osmt, + OUT uint32_t * const p_num_recs, + OUT uint32_t * const p_num_queries) +{ + osmtest_req_context_t context; + ib_portinfo_record_t *p_rec; + uint32_t i; + cl_status_t status; + uint32_t num_recs = 0; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + /* + * Do a blocking query for all PortInfoRecords in the subnet. + */ + status = osmtest_get_all_recs(p_osmt, IB_MAD_ATTR_PORTINFO_RECORD, + sizeof(*p_rec), &context); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0006: " + "osmtest_get_all_recs failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + /* + * Populate the database with the received records. + */ + num_recs = context.result.result_cnt; + *p_num_recs += num_recs; + ++*p_num_queries; + + if (osm_log_is_active(&p_osmt->log, OSM_LOG_VERBOSE)) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Received %u records\n", num_recs); + + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_portinfo_rec(context.result. + p_result_madw, i); + osm_dump_portinfo_record(&p_osmt->log, p_rec, + OSM_LOG_VERBOSE); + } + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osmtest_stress_node_recs_large(IN osmtest_t * const p_osmt, + OUT uint32_t * const p_num_recs, + OUT uint32_t * const p_num_queries) +{ + osmtest_req_context_t context; + ib_node_record_t *p_rec; + uint32_t i; + cl_status_t status; + uint32_t num_recs = 0; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + /* + * Do a blocking query for all NodeRecords in the subnet. + */ + status = osmtest_get_all_recs(p_osmt, IB_MAD_ATTR_NODE_RECORD, + sizeof(*p_rec), &context); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0007: " + "osmtest_get_all_recs failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + /* + * Populate the database with the received records. + */ + num_recs = context.result.result_cnt; + *p_num_recs += num_recs; + ++*p_num_queries; + + if (osm_log_is_active(&p_osmt->log, OSM_LOG_VERBOSE)) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Received %u records\n", num_recs); + + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_node_rec(context.result. + p_result_madw, i); + osm_dump_node_record(&p_osmt->log, p_rec, + OSM_LOG_VERBOSE); + } + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osmtest_stress_path_recs_large(IN osmtest_t * const p_osmt, + OUT uint32_t * const p_num_recs, + OUT uint32_t * const p_num_queries) +{ + osmtest_req_context_t context; + ib_path_rec_t *p_rec; + uint32_t i; + cl_status_t status; + uint32_t num_recs = 0; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + /* + * Do a blocking query for all PathRecords in the subnet. + */ + status = osmtest_get_all_recs(p_osmt, IB_MAD_ATTR_PATH_RECORD, + sizeof(*p_rec), &context); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0008: " + "osmtest_get_all_recs failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + /* + * Populate the database with the received records. + */ + num_recs = context.result.result_cnt; + *p_num_recs += num_recs; + ++*p_num_queries; + + if (osm_log_is_active(&p_osmt->log, OSM_LOG_VERBOSE)) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Received %u records\n", num_recs); + + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_path_rec(context.result. + p_result_madw, i); + osm_dump_path_record(&p_osmt->log, p_rec, + OSM_LOG_VERBOSE); + } + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osmtest_stress_path_recs_by_guid(IN osmtest_t * const p_osmt, + OUT uint32_t * const p_num_recs, + OUT uint32_t * const p_num_queries) +{ + osmtest_req_context_t context; + ib_path_rec_t *p_rec; + uint32_t i; + cl_status_t status = IB_SUCCESS; + uint32_t num_recs = 0; + node_t *p_src_node, *p_dst_node; + cl_qmap_t *p_tbl; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + + p_tbl = &p_osmt->exp_subn.node_guid_tbl; + + p_src_node = (node_t *) cl_qmap_head(p_tbl); + + /* + * Go over all nodes that exist in the subnet + * for each pair that are not switch nodes get the path record + */ + while (p_src_node != (node_t *) cl_qmap_end(p_tbl)) { + p_dst_node = (node_t *) cl_qmap_head(p_tbl); + + while (p_dst_node != (node_t *) cl_qmap_end(p_tbl)) { + /* + * Do a blocking query for CA to CA Path Record + */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Source : guid = 0x%" PRIx64 " type = %d" + "Target : guid = 0x%" PRIx64 " type = %d\n", + cl_ntoh64(p_src_node->rec.node_info.port_guid), + p_src_node->rec.node_info.node_type, + cl_ntoh64(p_dst_node->rec.node_info.port_guid), + p_dst_node->rec.node_info.node_type); + + if (p_src_node->rec.node_info.node_type == + IB_NODE_TYPE_CA + && p_dst_node->rec.node_info.node_type == + IB_NODE_TYPE_CA) { + status = + osmtest_get_path_rec_by_guid_pair(p_osmt, + p_src_node-> + rec. + node_info. + port_guid, + p_dst_node-> + rec. + node_info. + port_guid, + &context); + + /* In a case of TIMEOUT you still can try sending but cant count, maybe its a temporary issue */ + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0009: " + "osmtest_get_path_rec_by_guid_pair failed (%s)\n", + ib_get_err_str(status)); + if (status != IB_TIMEOUT) + goto Exit; + } else { + /* we might have received several records */ + num_recs = context.result.result_cnt; + /* + * Populate the database with the received records. + */ + *p_num_recs += num_recs; + ++*p_num_queries; + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Received %u records\n", num_recs); + /* Dont waste time if not VERBOSE and above */ + if (p_osmt->log.level & OSM_LOG_VERBOSE) { + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_path_rec + (context.result. + p_result_madw, i); + osm_dump_path_record + (&p_osmt->log, + p_rec, + OSM_LOG_VERBOSE); + } + } + } + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result. + p_result_madw); + context.result.p_result_madw = NULL; + } + } + /* next one please */ + p_dst_node = + (node_t *) cl_qmap_next(&p_dst_node->map_item); + } + + p_src_node = (node_t *) cl_qmap_next(&p_src_node->map_item); + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osmtest_stress_port_recs_small(IN osmtest_t * const p_osmt, + OUT uint32_t * const p_num_recs, + OUT uint32_t * const p_num_queries) +{ + osmtest_req_context_t context; + ib_portinfo_record_t *p_rec; + uint32_t i; + cl_status_t status; + uint32_t num_recs = 0; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + /* + * Do a blocking query for our own PortInfoRecord in the subnet. + */ + status = osmtest_get_port_rec(p_osmt, + cl_ntoh16(p_osmt->local_port.lid), + &context); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0010: " + "osmtest_get_port_rec failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + /* + * Populate the database with the received records. + */ + num_recs = context.result.result_cnt; + *p_num_recs += num_recs; + ++*p_num_queries; + + if (osm_log_is_active(&p_osmt->log, OSM_LOG_VERBOSE)) { + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Received %u records\n", num_recs); + + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_portinfo_rec(context.result. + p_result_madw, i); + osm_dump_portinfo_record(&p_osmt->log, p_rec, + OSM_LOG_VERBOSE); + } + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osmtest_get_local_port_lmc(IN osmtest_t * const p_osmt, + IN ib_net16_t lid, OUT uint8_t * const p_lmc) +{ + osmtest_req_context_t context; + ib_portinfo_record_t *p_rec; + uint32_t i; + cl_status_t status; + uint32_t num_recs = 0; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + /* + * Do a blocking query for our own PortInfoRecord in the subnet. + */ + status = osmtest_get_port_rec(p_osmt, cl_ntoh16(lid), &context); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 001A: " + "osmtest_get_port_rec failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + num_recs = context.result.result_cnt; + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Received %u records\n", num_recs); + + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_portinfo_rec(context.result.p_result_madw, + i); + osm_dump_portinfo_record(&p_osmt->log, p_rec, OSM_LOG_VERBOSE); + if (p_lmc) { + *p_lmc = ib_port_info_get_lmc(&p_rec->port_info); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "LMC %d\n", *p_lmc); + } + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * Use a wrong SM_Key in a simple port query and report success if + * failed. + **********************************************************************/ +ib_api_status_t osmtest_wrong_sm_key_ignored(IN osmtest_t * const p_osmt) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_portinfo_record_t record; + osmtest_req_context_t context; + osmtest_req_context_t *p_context = &context; + uint8_t port_num = 1; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "Trying PortInfoRecord for port with LID 0x%X Num:0x%X\n", + p_osmt->local_port.sm_lid, port_num); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&record, 0, sizeof(record)); + + record.lid = p_osmt->local_port.sm_lid; + record.port_num = port_num; + user.p_attr = &record; + + p_context->p_osmt = p_osmt; + + req.query_type = OSMV_QUERY_PORT_REC_BY_LID_AND_NUM; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 9999; + context.result.p_result_madw = NULL; + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmv_query_sa(p_osmt->h_bind, &req); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + /* since we use a wrong sm_key we should get a timeout */ + if (status != IB_TIMEOUT) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0011: " + "Did not get a timeout but got (%s)\n", + ib_get_err_str(status)); + if (status == IB_SUCCESS) { + /* assign some error value to status, since IB_SUCCESS is a bad rc */ + status = IB_ERROR; + } + goto Exit; + } else { + status = IB_SUCCESS; + } + +Exit: + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_write_port_info(IN osmtest_t * const p_osmt, + IN FILE * fh, + IN const ib_portinfo_record_t * const p_rec) +{ + int result; + cl_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + result = fprintf(fh, + "DEFINE_PORT\n" + "lid 0x%X\n" + "port_num 0x%X\n" + "m_key 0x%016" PRIx64 "\n" + "subnet_prefix 0x%016" PRIx64 "\n" + "base_lid 0x%X\n" + "master_sm_base_lid 0x%X\n" + "capability_mask 0x%X\n" + "diag_code 0x%X\n" + "m_key_lease_period 0x%X\n" + "local_port_num 0x%X\n" + "link_width_enabled 0x%X\n" + "link_width_supported 0x%X\n" + "link_width_active 0x%X\n" + "link_speed_supported 0x%X\n" + "port_state %s\n" + "state_info2 0x%X\n" + "mpb 0x%X\n" + "lmc 0x%X\n" + "link_speed 0x%X\n" + "mtu_smsl 0x%X\n" + "vl_cap 0x%X\n" + "vl_high_limit 0x%X\n" + "vl_arb_high_cap 0x%X\n" + "vl_arb_low_cap 0x%X\n" + "mtu_cap 0x%X\n" + "vl_stall_life 0x%X\n" + "vl_enforce 0x%X\n" + "m_key_violations 0x%X\n" + "p_key_violations 0x%X\n" + "q_key_violations 0x%X\n" + "guid_cap 0x%X\n" + "subnet_timeout 0x%X\n" + "resp_time_value 0x%X\n" + "error_threshold 0x%X\n" + "END\n\n", + cl_ntoh16(p_rec->lid), + p_rec->port_num, + cl_ntoh64(p_rec->port_info.m_key), + cl_ntoh64(p_rec->port_info.subnet_prefix), + cl_ntoh16(p_rec->port_info.base_lid), + cl_ntoh16(p_rec->port_info.master_sm_base_lid), + cl_ntoh32(p_rec->port_info.capability_mask), + cl_ntoh16(p_rec->port_info.diag_code), + cl_ntoh16(p_rec->port_info.m_key_lease_period), + p_rec->port_info.local_port_num, + p_rec->port_info.link_width_enabled, + p_rec->port_info.link_width_supported, + p_rec->port_info.link_width_active, + ib_port_info_get_link_speed_sup(&p_rec->port_info), + ib_get_port_state_str(ib_port_info_get_port_state + (&p_rec->port_info)), + p_rec->port_info.state_info2, + ib_port_info_get_mpb(&p_rec->port_info), + ib_port_info_get_lmc(&p_rec->port_info), + p_rec->port_info.link_speed, p_rec->port_info.mtu_smsl, + p_rec->port_info.vl_cap, + p_rec->port_info.vl_high_limit, + p_rec->port_info.vl_arb_high_cap, + p_rec->port_info.vl_arb_low_cap, + p_rec->port_info.mtu_cap, + p_rec->port_info.vl_stall_life, + p_rec->port_info.vl_enforce, + cl_ntoh16(p_rec->port_info.m_key_violations), + cl_ntoh16(p_rec->port_info.p_key_violations), + cl_ntoh16(p_rec->port_info.q_key_violations), + p_rec->port_info.guid_cap, + ib_port_info_get_timeout(&p_rec->port_info), + p_rec->port_info.resp_time_value, + p_rec->port_info.error_threshold); + + if (result < 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0161: " + "Write failed\n"); + status = IB_ERROR; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_write_path_info(IN osmtest_t * const p_osmt, + IN FILE * fh, IN const ib_path_rec_t * const p_rec) +{ + int result; + cl_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + result = fprintf(fh, + "DEFINE_PATH\n" + "dgid 0x%016" PRIx64 " 0x%016" + PRIx64 "\nsgid 0x%016" PRIx64 + " 0x%016" PRIx64 "\ndlid 0x%X\n" + "slid 0x%X\n" + "# hop_flow_raw 0x%X\n" + "# tclass 0x%X\n" + "# num_path 0x%X\n" + "pkey 0x%X\n" + "# sl 0x%X\n" + "# qos_class 0x%X\n" + "# mtu 0x%X\n" + "# rate 0x%X\n" + "# pkt_life 0x%X\n" + "# preference 0x%X\n" "END\n\n", + cl_ntoh64(p_rec->dgid.unicast.prefix), + cl_ntoh64(p_rec->dgid.unicast.interface_id), + cl_ntoh64(p_rec->sgid.unicast.prefix), + cl_ntoh64(p_rec->sgid.unicast.interface_id), + cl_ntoh16(p_rec->dlid), cl_ntoh16(p_rec->slid), + cl_ntoh32(p_rec->hop_flow_raw), p_rec->tclass, + p_rec->num_path, cl_ntoh16(p_rec->pkey), + ib_path_rec_sl(p_rec), ib_path_rec_qos_class(p_rec), + p_rec->mtu, p_rec->rate, p_rec->pkt_life, + p_rec->preference); + + if (result < 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0162: " + "Write failed\n"); + status = IB_ERROR; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_write_node_info(IN osmtest_t * const p_osmt, + IN FILE * fh, IN const ib_node_record_t * const p_rec) +{ + int result; + cl_status_t status = IB_SUCCESS; + char desc[IB_NODE_DESCRIPTION_SIZE + 1]; + + OSM_LOG_ENTER(&p_osmt->log); + + memcpy(desc, p_rec->node_desc.description, IB_NODE_DESCRIPTION_SIZE); + desc[IB_NODE_DESCRIPTION_SIZE] = '\0'; + + result = fprintf(fh, + "DEFINE_NODE\n" + "lid 0x%X\n" + "base_version 0x%X\n" + "class_version 0x%X\n" + "node_type 0x%X # (%s)\n" + "num_ports 0x%X\n" + "sys_guid 0x%016" PRIx64 "\n" + "node_guid 0x%016" PRIx64 "\n" + "port_guid 0x%016" PRIx64 "\n" + "partition_cap 0x%X\n" + "device_id 0x%X\n" + "revision 0x%X\n" + "# port_num 0x%X\n" + "# vendor_id 0x%X\n" + "# node_desc %s\n" + "END\n\n", + cl_ntoh16(p_rec->lid), + p_rec->node_info.base_version, + p_rec->node_info.class_version, + p_rec->node_info.node_type, + ib_get_node_type_str(p_rec->node_info.node_type), + p_rec->node_info.num_ports, + cl_ntoh64(p_rec->node_info.sys_guid), + cl_ntoh64(p_rec->node_info.node_guid), + cl_ntoh64(p_rec->node_info.port_guid), + cl_ntoh16(p_rec->node_info.partition_cap), + cl_ntoh16(p_rec->node_info.device_id), + cl_ntoh32(p_rec->node_info.revision), + ib_node_info_get_local_port_num(&p_rec->node_info), + cl_ntoh32(ib_node_info_get_vendor_id + (&p_rec->node_info)), desc); + + if (result < 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0163: " + "Write failed\n"); + status = IB_ERROR; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_write_link(IN osmtest_t * const p_osmt, + IN FILE * fh, IN const ib_link_record_t * const p_rec) +{ + int result; + cl_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + result = fprintf(fh, + "DEFINE_LINK\n" + "from_lid 0x%X\n" + "from_port_num 0x%X\n" + "to_port_num 0x%X\n" + "to_lid 0x%X\n" + "END\n\n", + cl_ntoh16(p_rec->from_lid), + p_rec->from_port_num, + p_rec->to_port_num, cl_ntoh16(p_rec->to_lid)); + + if (result < 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0164: " + "Write failed\n"); + status = IB_ERROR; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_write_all_link_recs(IN osmtest_t * const p_osmt, IN FILE * fh) +{ + osmtest_req_context_t context; + const ib_link_record_t *p_rec; + uint32_t i; + cl_status_t status; + size_t num_recs; + int result; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + /* + * Do a blocking query for all NodeRecords in the subnet. + */ + status = osmtest_get_all_recs(p_osmt, IB_MAD_ATTR_LINK_RECORD, + sizeof(*p_rec), &context); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0165: " + "osmtest_get_all_recs failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + /* + * Write the received records out to the file. + */ + num_recs = context.result.result_cnt; + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Received %zu records\n", num_recs); + + result = fprintf(fh, "#\n" "# Link Records\n" "#\n"); + if (result < 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0166: " + "Write failed\n"); + status = IB_ERROR; + goto Exit; + } + + for (i = 0; i < num_recs; i++) { + p_rec = + (ib_link_record_t *) osmv_get_query_result(context.result. + p_result_madw, + i); + + osmtest_write_link(p_osmt, fh, p_rec); + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_get_path_rec_by_lid_pair(IN osmtest_t * const p_osmt, + IN ib_net16_t slid, + IN ib_net16_t dlid, + IN osmtest_req_context_t * p_context) +{ + cl_status_t status = IB_SUCCESS; + osmv_query_req_t req; + osmv_lid_pair_t lid_pair; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&req, 0, sizeof(req)); + memset(p_context, 0, sizeof(*p_context)); + + p_context->p_osmt = p_osmt; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + + req.query_type = OSMV_QUERY_PATH_REC_BY_LIDS; + + lid_pair.dest_lid = dlid; + lid_pair.src_lid = slid; + + req.p_query_input = &lid_pair; + req.sm_key = 0; + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Query for path from 0x%X to 0x%X\n", slid, dlid); + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0053: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = (*p_context).result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0067: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + ((*p_context).result. + p_result_madw))); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +#ifdef VENDOR_RMPP_SUPPORT +/********************************************************************** + * ASSUMES RMPP + **********************************************************************/ +static ib_api_status_t +osmtest_write_all_node_recs(IN osmtest_t * const p_osmt, IN FILE * fh) +{ + osmtest_req_context_t context; + const ib_node_record_t *p_rec; + uint32_t i; + cl_status_t status; + size_t num_recs; + int result; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + /* + * Do a blocking query for all NodeRecords in the subnet. + */ + status = osmtest_get_all_recs(p_osmt, IB_MAD_ATTR_NODE_RECORD, + sizeof(*p_rec), &context); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0022: " + "osmtest_get_all_recs failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + /* + * Write the received records out to the file. + */ + num_recs = context.result.result_cnt; + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Received %zu records\n", num_recs); + + result = fprintf(fh, "#\n" "# Node Records\n" "#\n"); + if (result < 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0023: " + "Write failed\n"); + status = IB_ERROR; + goto Exit; + } + + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_node_rec(context.result.p_result_madw, i); + osmtest_write_node_info(p_osmt, fh, p_rec); + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * ASSUMES RMPP + **********************************************************************/ +static ib_api_status_t +osmtest_write_all_port_recs(IN osmtest_t * const p_osmt, IN FILE * fh) +{ + osmtest_req_context_t context; + const ib_portinfo_record_t *p_rec; + uint32_t i; + cl_status_t status; + size_t num_recs; + int result; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + /* + * Do a blocking query for all NodeRecords in the subnet. + */ + status = osmtest_get_all_recs(p_osmt, IB_MAD_ATTR_PORTINFO_RECORD, + sizeof(*p_rec), &context); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0167: " + "osmtest_get_all_recs failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + /* + * Write the received records out to the file. + */ + num_recs = context.result.result_cnt; + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Received %zu records\n", num_recs); + + result = fprintf(fh, "#\n" "# PortInfo Records\n" "#\n"); + if (result < 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0024: " + "Write failed\n"); + status = IB_ERROR; + goto Exit; + } + + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_portinfo_rec(context.result.p_result_madw, + i); + osmtest_write_port_info(p_osmt, fh, p_rec); + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * ASSUMES RMPP + **********************************************************************/ +static ib_api_status_t +osmtest_write_all_path_recs(IN osmtest_t * const p_osmt, IN FILE * fh) +{ + osmtest_req_context_t context; + const ib_path_rec_t *p_rec; + uint32_t i; + cl_status_t status; + size_t num_recs; + int result; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + /* + * Do a blocking query for all PathRecords in the subnet. + */ + status = osmtest_get_all_recs(p_osmt, IB_MAD_ATTR_PATH_RECORD, + sizeof(*p_rec), &context); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0025: " + "osmtest_get_all_recs failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + /* + * Write the received records out to the file. + */ + num_recs = context.result.result_cnt; + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Received %zu records\n", num_recs); + + result = fprintf(fh, "#\n" "# Path Records\n" "#\n"); + if (result < 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0026: " + "Write failed\n"); + status = IB_ERROR; + goto Exit; + } + + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_path_rec(context.result.p_result_madw, i); + osmtest_write_path_info(p_osmt, fh, p_rec); + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +#else +/* + * NON RMPP BASED QUERY FOR ALL NODES: BASED ON THE MAX LID GIVEN BY THE USER + */ +static ib_api_status_t +osmtest_write_all_node_recs(IN osmtest_t * const p_osmt, IN FILE * fh) +{ + osmtest_req_context_t context; + node_t *p_node; + node_t *p_guid_node; + const ib_node_record_t *p_rec; + cl_status_t status = CL_SUCCESS; + int result; + uint16_t lid; + + OSM_LOG_ENTER(&p_osmt->log); + + result = fprintf(fh, "#\n" "# Node Records\n" "#\n"); + if (result < 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0027: " + "Write failed\n"); + status = IB_ERROR; + goto Exit; + } + + /* + * Go over all LIDs in the range 1 to max_lid and do a + * NodeRecord query by that lid. + */ + for (lid = 1; lid <= p_osmt->max_lid; lid++) { + /* prepare the query context */ + memset(&context, 0, sizeof(context)); + + status = + osmtest_get_node_rec_by_lid(p_osmt, cl_ntoh16(lid), + &context); + if (status != IB_SUCCESS) { + if (status != IB_SA_MAD_STATUS_NO_RECORDS) { + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "ERR 0028: " + "failed to get node info for LID:0x%02X (%s)\n", + cl_ntoh16(lid), ib_get_err_str(status)); + goto Exit; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "WRN 0121: " + "failed to get node info for LID:0x%02X (%s)\n", + cl_ntoh16(lid), ib_get_err_str(status)); + status = IB_SUCCESS; + } + } else { + /* OK we got something */ + p_rec = + osmv_get_query_node_rec(context.result. + p_result_madw, 0); + osmtest_write_node_info(p_osmt, fh, p_rec); + + /* create a subnet object */ + p_node = node_new(); + CL_ASSERT(p_node != NULL); + + /* copy the info to the subnet node object */ + p_node->rec = *p_rec; + + cl_qmap_insert(&p_osmt->exp_subn.node_lid_tbl, + p_node->rec.lid, &p_node->map_item); + + p_guid_node = node_new(); + CL_ASSERT(p_guid_node != NULL); + + *p_guid_node = *p_node; + + cl_qmap_insert(&p_osmt->exp_subn.node_guid_tbl, + p_guid_node->rec.node_info.node_guid, + &p_guid_node->map_item); + + } + + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + } + +Exit: + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/* + * GET ALL PORT RECORDS IN THE FABRIC - + * one by one by using the node info received + */ +static ib_api_status_t +osmtest_write_all_port_recs(IN osmtest_t * const p_osmt, IN FILE * fh) +{ + osmtest_req_context_t context; + const ib_node_record_t *p_node_rec; + const ib_portinfo_record_t *p_rec; + uint8_t port_num; + cl_status_t status = CL_SUCCESS; + cl_qmap_t *p_tbl; + node_t *p_node; + port_t *p_port; + int result; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + /* print header */ + result = fprintf(fh, "#\n" "# PortInfo Records\n" "#\n"); + if (result < 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0029: " + "Write failed\n"); + status = IB_ERROR; + goto Exit; + } + + /* use the pre-explored set of nodes */ + p_tbl = &p_osmt->exp_subn.node_lid_tbl; + p_node = (node_t *) cl_qmap_head(p_tbl); + + /* + * Go over all LIDs in the range 1 to max_lid and do a + * NodeRecord query by that lid. + */ + while (p_node != (node_t *) cl_qmap_end(p_tbl)) { + + p_node_rec = &(p_node->rec); + + /* go through all ports of the node: */ + for (port_num = 0; port_num <= p_node_rec->node_info.num_ports; + port_num++) { + /* prepare the query context */ + memset(&context, 0, sizeof(context)); + + status = osmtest_get_port_rec_by_num(p_osmt, + p_node_rec->lid, + port_num, + &context); + if (status != IB_SUCCESS) { + if (status != IB_SA_MAD_STATUS_NO_RECORDS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "WRN 0122: " + "Error encountered getting port info for LID:0x%04X Num:0x%02X (%s)\n", + p_node_rec->lid, port_num, + ib_get_err_str(status)); + goto Exit; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "WRN 0123: " + "failed to get port info for LID:0x%04X Num:0x%02X (%s)\n", + p_node_rec->lid, port_num, + ib_get_err_str(status)); + status = IB_SUCCESS; + } + } else { + /* OK we got something */ + p_rec = + osmv_get_query_portinfo_rec(context.result. + p_result_madw, + 0); + osmtest_write_port_info(p_osmt, fh, p_rec); + + /* create a subnet object */ + p_port = port_new(); + CL_ASSERT(p_port != NULL); + + /* copy the info to the subnet node object */ + p_port->rec = *p_rec; + + cl_qmap_insert(&p_osmt->exp_subn.port_key_tbl, + port_gen_id(p_node_rec->lid, + port_num), + &p_port->map_item); + } + + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + } + p_node = (node_t *) cl_qmap_next(&p_node->map_item); + } + + /* we must set the exist status to avoid abort of the over all algorith */ + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * ASSUMES NO RMPP + **********************************************************************/ +static ib_api_status_t +osmtest_write_all_path_recs(IN osmtest_t * const p_osmt, IN FILE * fh) +{ + osmtest_req_context_t context; + const ib_path_rec_t *p_rec; + cl_status_t status = CL_SUCCESS; + int num_recs, i; + cl_qmap_t *p_tbl; + node_t *p_src_node, *p_dst_node; + ib_api_status_t got_status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + /* + * Go over all nodes that exist in the subnet + * for each pair that are not switch nodes get the path record + */ + + context.p_osmt = p_osmt; + + p_tbl = &p_osmt->exp_subn.node_lid_tbl; + + p_src_node = (node_t *) cl_qmap_head(p_tbl); + + while (p_src_node != (node_t *) cl_qmap_end(p_tbl)) { + /* HACK we use capability_mask to know diff a CA node from switch node */ + /* if(p_src_node->rec.node_info.capability_mask ) { */ + p_dst_node = (node_t *) cl_qmap_head(p_tbl); + + while (p_dst_node != (node_t *) cl_qmap_end(p_tbl)) { + /* HACK we use capability_mask to know diff a CA node from switch node */ + /* if (p_dst_node->rec.node_info.capability_mask) { */ + + /* query for it: */ + status = osmtest_get_path_rec_by_lid_pair(p_osmt, + p_src_node-> + rec.lid, + p_dst_node-> + rec.lid, + &context); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 012D: " + "failed to get path info from LID:0x%X To LID:0x%X (%s)\n", + p_src_node->rec.lid, + p_dst_node->rec.lid, + ib_get_err_str(status)); + /* remember the first error status */ + got_status = + (got_status == + IB_SUCCESS) ? status : got_status; + } else { + /* we might have received several records */ + num_recs = context.result.result_cnt; + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_path_rec(context. + result. + p_result_madw, + i); + osmtest_write_path_info(p_osmt, fh, + p_rec); + } + } +/* } */ + + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + /* next one please */ + p_dst_node = + (node_t *) cl_qmap_next(&p_dst_node->map_item); + } +/* } */ + + p_src_node = (node_t *) cl_qmap_next(&p_src_node->map_item); + } + + if (got_status != IB_SUCCESS) + status = got_status; + + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +#endif + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_create_inventory_file(IN osmtest_t * const p_osmt) +{ + FILE *fh; + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + fh = fopen(p_osmt->opt.file_name, "w"); + if (fh == NULL) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0079: " + "Unable to open inventory file (%s)\n", + p_osmt->opt.file_name); + status = IB_ERROR; + goto Exit; + } + + /* HACK: the order is important: nodes ports paths */ + status = osmtest_write_all_node_recs(p_osmt, fh); + if (status != IB_SUCCESS) + goto Exit; + + status = osmtest_write_all_port_recs(p_osmt, fh); + if (status != IB_SUCCESS) + goto Exit; + + if (!p_osmt->opt.ignore_path_records) { + status = osmtest_write_all_path_recs(p_osmt, fh); + if (status != IB_SUCCESS) + goto Exit; + } + + status = osmtest_write_all_link_recs(p_osmt, fh); + if (status != IB_SUCCESS) + goto Exit; + + fclose(fh); + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t osmtest_stress_large_rmpp_pr(IN osmtest_t * const p_osmt) +{ + ib_api_status_t status = IB_SUCCESS; + uint64_t num_recs = 0; + uint64_t num_queries = 0; + uint32_t delta_recs; + uint32_t delta_queries; + uint32_t print_freq = 0; + struct timeval start_tv, end_tv; + long sec_diff, usec_diff; + float ratio; + + OSM_LOG_ENTER(&p_osmt->log); + gettimeofday(&start_tv, NULL); + printf("-I- Start time is : %09ld:%06ld [sec:usec]\n", start_tv.tv_sec, + (long)start_tv.tv_usec); + + while (num_queries < STRESS_LARGE_PR_RMPP_THR) { + delta_recs = 0; + delta_queries = 0; + + status = osmtest_stress_path_recs_by_guid(p_osmt, &delta_recs, + &delta_queries); + if (status != IB_SUCCESS) + goto Exit; + + num_recs += delta_recs; + num_queries += delta_queries; + + print_freq += delta_recs; + if (print_freq > 10000) { + gettimeofday(&end_tv, NULL); + if (end_tv.tv_usec > start_tv.tv_usec) { + sec_diff = end_tv.tv_sec - start_tv.tv_sec; + usec_diff = end_tv.tv_usec - start_tv.tv_usec; + } else { + sec_diff = end_tv.tv_sec - start_tv.tv_sec - 1; + usec_diff = + 1000000 - (start_tv.tv_usec - + end_tv.tv_usec); + } + printf("-I- End time is : %09ld:%06ld [sec:usec]\n", + end_tv.tv_sec, (long)end_tv.tv_usec); + printf("-I- Querying %" PRId64 + " Path Record queries CA to CA (rmpp)\n\ttook %04ld:%06ld [sec:usec]\n", + num_queries, sec_diff, usec_diff); + if (num_recs == 0) + ratio = 0; + else + ratio = ((float)num_queries / (float)num_recs); + printf("-I- Queries to Record Ratio is %" PRIu64 + " records, %" PRIu64 " queries : %.2f \n", + num_recs, num_queries, ratio); + print_freq = 0; + } + } + +Exit: + gettimeofday(&end_tv, NULL); + printf("-I- End time is : %09ld:%06ld [sec:usec]\n", + end_tv.tv_sec, (long)end_tv.tv_usec); + if (end_tv.tv_usec > start_tv.tv_usec) { + sec_diff = end_tv.tv_sec - start_tv.tv_sec; + usec_diff = end_tv.tv_usec - start_tv.tv_usec; + } else { + sec_diff = end_tv.tv_sec - start_tv.tv_sec - 1; + usec_diff = 1000000 - (start_tv.tv_usec - end_tv.tv_usec); + } + + printf("-I- Querying %" PRId64 + " Path Record queries (rmpp) took %04ld:%06ld [sec:usec]\n", + num_queries, sec_diff, usec_diff); + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t osmtest_stress_large_rmpp(IN osmtest_t * const p_osmt) +{ + ib_api_status_t status = IB_SUCCESS; + uint64_t num_recs = 0; + uint64_t num_queries = 0; + uint32_t delta_recs; + uint32_t delta_queries; + uint32_t print_freq = 0; + struct timeval start_tv, end_tv; + long sec_diff, usec_diff; + + OSM_LOG_ENTER(&p_osmt->log); + gettimeofday(&start_tv, NULL); + printf("-I- Start time is : %09ld:%06ld [sec:usec]\n", start_tv.tv_sec, + (long)start_tv.tv_usec); + + while (num_queries < STRESS_LARGE_RMPP_THR) { + delta_recs = 0; + delta_queries = 0; + + status = osmtest_stress_node_recs_large(p_osmt, &delta_recs, + &delta_queries); + if (status != IB_SUCCESS) + goto Exit; + + status = osmtest_stress_path_recs_large(p_osmt, &delta_recs, + &delta_queries); + if (status != IB_SUCCESS) + goto Exit; + + status = osmtest_stress_port_recs_large(p_osmt, &delta_recs, + &delta_queries); + if (status != IB_SUCCESS) + goto Exit; + + num_recs += delta_recs; + num_queries += delta_queries; + + print_freq += delta_recs; + + if (print_freq > 100000) { + gettimeofday(&end_tv, NULL); + if (end_tv.tv_usec > start_tv.tv_usec) { + sec_diff = end_tv.tv_sec - start_tv.tv_sec; + usec_diff = end_tv.tv_usec - start_tv.tv_usec; + } else { + sec_diff = end_tv.tv_sec - start_tv.tv_sec - 1; + usec_diff = + 1000000 - (start_tv.tv_usec - + end_tv.tv_usec); + } + printf("-I- End time is : %09ld:%06ld [sec:usec]\n", + end_tv.tv_sec, (long)end_tv.tv_usec); + printf("-I- Querying %" PRId64 + " large mixed queries (rmpp) took %04ld:%06ld [sec:usec]\n", + num_queries, sec_diff, usec_diff); + printf("%" PRIu64 " records, %" PRIu64 " queries\n", + num_recs, num_queries); + print_freq = 0; + } + } + +Exit: + gettimeofday(&end_tv, NULL); + printf("-I- End time is : %09ld:%06ld [sec:usec]\n", + end_tv.tv_sec, (long)end_tv.tv_usec); + if (end_tv.tv_usec > start_tv.tv_usec) { + sec_diff = end_tv.tv_sec - start_tv.tv_sec; + usec_diff = end_tv.tv_usec - start_tv.tv_usec; + } else { + sec_diff = end_tv.tv_sec - start_tv.tv_sec - 1; + usec_diff = 1000000 - (start_tv.tv_usec - end_tv.tv_usec); + } + + printf("-I- Querying %" PRId64 + " large mixed queries (rmpp) took %04ld:%06ld [sec:usec]\n", + num_queries, sec_diff, usec_diff); + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t osmtest_stress_small_rmpp(IN osmtest_t * const p_osmt) +{ + ib_api_status_t status = IB_SUCCESS; + uint64_t num_recs = 0; + uint64_t num_queries = 0; + uint32_t delta_recs; + uint32_t delta_queries; + uint32_t print_freq = 0; + int num_timeouts = 0; + struct timeval start_tv, end_tv; + long sec_diff, usec_diff; + + OSM_LOG_ENTER(&p_osmt->log); + gettimeofday(&start_tv, NULL); + printf("-I- Start time is : %09ld:%06ld [sec:usec]\n", + start_tv.tv_sec, (long)start_tv.tv_usec); + + while ((num_queries < STRESS_SMALL_RMPP_THR) && (num_timeouts < 100)) { + delta_recs = 0; + delta_queries = 0; + + status = osmtest_stress_port_recs_small(p_osmt, &delta_recs, + &delta_queries); + if (status != IB_SUCCESS) + goto Exit; + + num_recs += delta_recs; + num_queries += delta_queries; + + print_freq += delta_recs; + if (print_freq > 5000) { + gettimeofday(&end_tv, NULL); + printf("%" PRIu64 " records, %" PRIu64 " queries\n", + num_recs, num_queries); + if (end_tv.tv_usec > start_tv.tv_usec) { + sec_diff = end_tv.tv_sec - start_tv.tv_sec; + usec_diff = end_tv.tv_usec - start_tv.tv_usec; + } else { + sec_diff = end_tv.tv_sec - start_tv.tv_sec - 1; + usec_diff = + 1000000 - (start_tv.tv_usec - + end_tv.tv_usec); + } + printf("-I- End time is : %09ld:%06ld [sec:usec]\n", + end_tv.tv_sec, (long)end_tv.tv_usec); + printf("-I- Querying %" PRId64 + " port_info queries (single mad) took %04ld:%06ld [sec:usec]\n", + num_queries, sec_diff, usec_diff); + print_freq = 0; + } + } + +Exit: + gettimeofday(&end_tv, NULL); + printf("-I- End time is : %09ld:%06ld [sec:usec]\n", + end_tv.tv_sec, (long)end_tv.tv_usec); + if (end_tv.tv_usec > start_tv.tv_usec) { + sec_diff = end_tv.tv_sec - start_tv.tv_sec; + usec_diff = end_tv.tv_usec - start_tv.tv_usec; + } else { + sec_diff = end_tv.tv_sec - start_tv.tv_sec - 1; + usec_diff = 1000000 - (start_tv.tv_usec - end_tv.tv_usec); + } + + printf("-I- Querying %" PRId64 + " port_info queries (single mad) took %04ld:%06ld [sec:usec]\n", + num_queries, sec_diff, usec_diff); + if (num_timeouts > 50) { + status = IB_TIMEOUT; + } + /* Exit: */ + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static void +osmtest_prepare_db_generic(IN osmtest_t * const p_osmt, + IN cl_qmap_t * const p_tbl) +{ + generic_t *p_generic; + + OSM_LOG_ENTER(&p_osmt->log); + + p_generic = (generic_t *) cl_qmap_head(p_tbl); + + while (p_generic != (generic_t *) cl_qmap_end(p_tbl)) { + p_generic->count = 0; + p_generic = (generic_t *) cl_qmap_next(&p_generic->map_item); + } + + OSM_LOG_EXIT(&p_osmt->log); +} + +/********************************************************************** + **********************************************************************/ +static void osmtest_prepare_db(IN osmtest_t * const p_osmt) +{ + OSM_LOG_ENTER(&p_osmt->log); + + osmtest_prepare_db_generic(p_osmt, &p_osmt->exp_subn.node_lid_tbl); + osmtest_prepare_db_generic(p_osmt, &p_osmt->exp_subn.path_tbl); + + OSM_LOG_EXIT(&p_osmt->log); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t osmtest_check_missing_nodes(IN osmtest_t * const p_osmt) +{ + const node_t *p_node; + cl_status_t status = IB_SUCCESS; + cl_qmap_t *p_tbl; + + OSM_LOG_ENTER(&p_osmt->log); + + p_tbl = &p_osmt->exp_subn.node_lid_tbl; + + p_node = (node_t *) cl_qmap_head(p_tbl); + + while (p_node != (node_t *) cl_qmap_end(p_tbl)) { + if (p_node->count == 0) { + /* + * This node was not reported by the SA + */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0080: " + "Missing node 0x%016" PRIx64 "\n", + cl_ntoh64(p_node->rec.node_info.node_guid)); + status = IB_ERROR; + } + + p_node = (node_t *) cl_qmap_next(&p_node->map_item); + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t osmtest_check_missing_ports(IN osmtest_t * const p_osmt) +{ + const port_t *p_port; + cl_status_t status = IB_SUCCESS; + cl_qmap_t *p_tbl; + + OSM_LOG_ENTER(&p_osmt->log); + + p_tbl = &p_osmt->exp_subn.port_key_tbl; + + p_port = (port_t *) cl_qmap_head(p_tbl); + + while (p_port != (port_t *) cl_qmap_end(p_tbl)) { + if (p_port->count == 0) { + /* + * This port was not reported by the SA + */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0081: " + "Missing port LID:0x%X Num:0x%X\n", + cl_ntoh16(p_port->rec.lid), + p_port->rec.port_num); + status = IB_ERROR; + } + + p_port = (port_t *) cl_qmap_next(&p_port->map_item); + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t osmtest_check_missing_paths(IN osmtest_t * const p_osmt) +{ + const path_t *p_path; + cl_status_t status = IB_SUCCESS; + cl_qmap_t *p_tbl; + + OSM_LOG_ENTER(&p_osmt->log); + + p_tbl = &p_osmt->exp_subn.path_tbl; + + p_path = (path_t *) cl_qmap_head(p_tbl); + + while (p_path != (path_t *) cl_qmap_end(p_tbl)) { + if (p_path->count == 0) { + /* + * This path was not reported by the SA + */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0051: " + "SA did not return path SLID 0x%X to DLID 0x%X\n", + cl_ntoh16(p_path->rec.slid), + cl_ntoh16(p_path->rec.dlid)); + status = IB_ERROR; + goto Exit; + } + + p_path = (path_t *) cl_qmap_next(&p_path->map_item); + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +inline uint32_t osmtest_path_rec_key_get(IN const ib_path_rec_t * const p_rec) +{ + return (p_rec->dlid << 16 | p_rec->slid); +} + +/********************************************************************** + **********************************************************************/ +static boolean_t +osmtest_path_rec_kay_is_valid(IN osmtest_t * const p_osmt, + IN const path_t * const p_path) +{ + if ((p_path->comp.dlid == 0) || (p_path->comp.slid == 0)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0168: " + "SLID and DLID must be specified for defined paths\n"); + return (FALSE); + } + + return (TRUE); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_path_data(IN osmtest_t * const p_osmt, + IN path_t * const p_path, + IN const ib_path_rec_t * const p_rec) +{ + cl_status_t status = IB_SUCCESS; + uint8_t lmc = 0; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Checking path SLID 0x%X to DLID 0x%X\n", + cl_ntoh16(p_rec->slid), cl_ntoh16(p_rec->dlid)); + + status = + osmtest_get_local_port_lmc(p_osmt, p_osmt->local_port.lid, &lmc); + if (status != IB_SUCCESS) + goto Exit; + + /* HACK: Assume uniform LMC across endports in the subnet */ + /* This is the only LMC mode which OpenSM currently supports */ + /* In absence of this assumption, validation of this is much more complicated */ + if (lmc == 0) { + /* + * Has this record already been returned? + */ + if (p_path->count != 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0056: " + "Already received path SLID 0x%X to DLID 0x%X\n", + cl_ntoh16(p_rec->slid), cl_ntoh16(p_rec->dlid)); + status = IB_ERROR; + goto Exit; + } + } else { + /* Also, this doesn't detect fewer than the correct number of paths being returned */ + if (p_path->count >= (uint32_t) (1 << (2 * lmc))) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0052: " + "Already received path SLID 0x%X to DLID 0x%X count %d LMC %d\n", + cl_ntoh16(p_rec->slid), cl_ntoh16(p_rec->dlid), + p_path->count, lmc); + status = IB_ERROR; + goto Exit; + } + } + + ++p_path->count; + + /* + * Check the fields the user wants checked. + */ + if ((p_path->comp.dgid.unicast.interface_id & + p_path->rec.dgid.unicast.interface_id) != + (p_path->comp.dgid.unicast.interface_id & + p_rec->dgid.unicast.interface_id)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0169: " + "DGID mismatch on path SLID 0x%X to DLID 0x%X\n" + "\t\t\t\tExpected 0x%016" PRIx64 " 0x%016" PRIx64 "\n" + "\t\t\t\tReceived 0x%016" PRIx64 " 0x%016" PRIx64 "\n", + cl_ntoh16(p_path->rec.slid), + cl_ntoh16(p_path->rec.dlid), + cl_ntoh64(p_path->rec.dgid.unicast.prefix), + cl_ntoh64(p_path->rec.dgid.unicast.interface_id), + cl_ntoh64(p_rec->dgid.unicast.prefix), + cl_ntoh64(p_rec->dgid.unicast.interface_id)); + status = IB_ERROR; + goto Exit; + } + + /* + * Check the fields the user wants checked. + */ + if ((p_path->comp.sgid.unicast.interface_id & + p_path->rec.sgid.unicast.interface_id) != + (p_path->comp.sgid.unicast.interface_id & + p_rec->sgid.unicast.interface_id)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0057: " + "SGID mismatch on path SLID 0x%X to DLID 0x%X\n" + "\t\t\t\tExpected 0x%016" PRIx64 " 0x%016" PRIx64 ",\n" + "\t\t\t\tReceived 0x%016" PRIx64 " 0x%016" PRIx64 ".\n", + cl_ntoh16(p_path->rec.slid), + cl_ntoh16(p_path->rec.dlid), + cl_ntoh64(p_path->rec.sgid.unicast.prefix), + cl_ntoh64(p_path->rec.sgid.unicast.interface_id), + cl_ntoh64(p_rec->sgid.unicast.prefix), + cl_ntoh64(p_rec->sgid.unicast.interface_id)); + status = IB_ERROR; + goto Exit; + } + + /* + * Compare the fields the user wishes to validate. + */ + if ((p_path->comp.pkey & p_path->rec.pkey) != + (p_path->comp.pkey & p_rec->pkey)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0012: " + "PKEY mismatch on path SLID 0x%X to DLID 0x%X\n" + "\t\t\t\tExpected 0x%X, received 0x%X\n", + cl_ntoh16(p_path->rec.slid), + cl_ntoh16(p_path->rec.dlid), + cl_ntoh16(p_path->rec.pkey), cl_ntoh16(p_rec->pkey)); + status = IB_ERROR; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_node_data(IN osmtest_t * const p_osmt, + IN node_t * const p_node, + IN const ib_node_record_t * const p_rec) +{ + cl_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Checking node 0x%016" PRIx64 ", LID 0x%X\n", + cl_ntoh64(p_rec->node_info.node_guid), cl_ntoh16(p_rec->lid)); + + /* + * Has this record already been returned? + */ + if (p_node->count != 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0013: " + "Already received node 0x%016" PRIx64 "\n", + cl_ntoh64(p_node->rec.node_info.node_guid)); + status = IB_ERROR; + goto Exit; + } + + ++p_node->count; + + /* + * Compare the fields the user wishes to validate. + */ + if ((p_node->comp.lid & p_node->rec.lid) != + (p_node->comp.lid & p_rec->lid)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0014: " + "Field mismatch node 0x%016" PRIx64 ", LID 0x%X\n" + "\t\t\t\tExpected LID 0x%X, received 0x%X\n", + cl_ntoh64(p_rec->node_info.node_guid), + cl_ntoh16(p_rec->lid), p_node->rec.lid, p_rec->lid); + status = IB_ERROR; + goto Exit; + } + + if ((p_node->comp.node_info.base_version & + p_node->rec.node_info.base_version) != + (p_node->comp.node_info.base_version & + p_rec->node_info.base_version)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0015: " + "Field mismatch node 0x%016" PRIx64 ", LID 0x%X\n" + "\t\t\t\tExpected base_version 0x%X, received 0x%X\n", + cl_ntoh64(p_rec->node_info.node_guid), + cl_ntoh16(p_rec->lid), + p_node->rec.node_info.base_version, + p_rec->node_info.base_version); + status = IB_ERROR; + goto Exit; + } + + if ((p_node->comp.node_info.class_version & + p_node->rec.node_info.class_version) != + (p_node->comp.node_info.class_version & + p_rec->node_info.class_version)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0016: " + "Field mismatch node 0x%016" PRIx64 ", LID 0x%X\n" + "\t\t\t\tExpected class_version 0x%X, received 0x%X\n", + cl_ntoh64(p_rec->node_info.node_guid), + cl_ntoh16(p_rec->lid), + p_node->rec.node_info.class_version, + p_rec->node_info.class_version); + status = IB_ERROR; + goto Exit; + } + + if ((p_node->comp.node_info.node_type & + p_node->rec.node_info.node_type) != + (p_node->comp.node_info.node_type & p_rec->node_info.node_type)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0017: " + "Field mismatch node 0x%016" PRIx64 ", LID 0x%X\n" + "\t\t\t\tExpected node_type 0x%X, received 0x%X\n", + cl_ntoh64(p_rec->node_info.node_guid), + cl_ntoh16(p_rec->lid), + p_node->rec.node_info.node_type, + p_rec->node_info.node_type); + status = IB_ERROR; + goto Exit; + } + + if ((p_node->comp.node_info.sys_guid & + p_node->rec.node_info.sys_guid) != + (p_node->comp.node_info.sys_guid & p_rec->node_info.sys_guid)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0018: " + "Field mismatch node 0x%016" PRIx64 ", LID 0x%X\n" + "\t\t\t\tExpected sys_guid 0x%016" PRIx64 + ", received 0x%016" PRIx64 "\n", + cl_ntoh64(p_rec->node_info.node_guid), + cl_ntoh16(p_rec->lid), + cl_ntoh64(p_node->rec.node_info.sys_guid), + cl_ntoh64(p_rec->node_info.sys_guid)); + status = IB_ERROR; + goto Exit; + } + + if ((p_node->comp.node_info.node_guid & + p_node->rec.node_info.node_guid) != + (p_node->comp.node_info.node_guid & p_rec->node_info.node_guid)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0019: " + "Field mismatch node 0x%016" PRIx64 ", LID 0x%X\n" + "\t\t\t\tExpected node_guid 0x%016" PRIx64 + ", received 0x%016" PRIx64 "\n", + cl_ntoh64(p_rec->node_info.node_guid), + cl_ntoh16(p_rec->lid), + cl_ntoh64(p_node->rec.node_info.node_guid), + cl_ntoh64(p_rec->node_info.node_guid)); + status = IB_ERROR; + goto Exit; + } + + if ((p_node->comp.node_info.port_guid & + p_node->rec.node_info.port_guid) != + (p_node->comp.node_info.port_guid & p_rec->node_info.port_guid)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0031: " + "Field mismatch node 0x%016" PRIx64 ", LID 0x%X\n" + "\t\t\t\tExpected port_guid 0x%016" PRIx64 + ", received 0x%016" PRIx64 "\n", + cl_ntoh64(p_rec->node_info.node_guid), + cl_ntoh16(p_rec->lid), + cl_ntoh64(p_node->rec.node_info.port_guid), + cl_ntoh64(p_rec->node_info.port_guid)); + status = IB_ERROR; + goto Exit; + } + + if ((p_node->comp.node_info.partition_cap & + p_node->rec.node_info.partition_cap) != + (p_node->comp.node_info.partition_cap & + p_rec->node_info.partition_cap)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0032: " + "Field mismatch node 0x%016" PRIx64 ", LID 0x%X\n" + "\t\t\t\tExpected partition_cap 0x%X, received 0x%X\n", + cl_ntoh64(p_rec->node_info.node_guid), + cl_ntoh16(p_rec->lid), + cl_ntoh16(p_node->rec.node_info.partition_cap), + cl_ntoh16(p_rec->node_info.partition_cap)); + status = IB_ERROR; + goto Exit; + } + + if ((p_node->comp.node_info.device_id & + p_node->rec.node_info.device_id) != + (p_node->comp.node_info.device_id & p_rec->node_info.device_id)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0033: " + "Field mismatch node 0x%016" PRIx64 ", LID 0x%X\n" + "\t\t\t\tExpected device_id 0x%X, received 0x%X\n", + cl_ntoh64(p_rec->node_info.node_guid), + cl_ntoh16(p_rec->lid), + cl_ntoh16(p_node->rec.node_info.device_id), + cl_ntoh16(p_rec->node_info.device_id)); + status = IB_ERROR; + goto Exit; + } + + if ((p_node->comp.node_info.revision & + p_node->rec.node_info.revision) != + (p_node->comp.node_info.revision & p_rec->node_info.revision)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0034: " + "Field mismatch node 0x%016" PRIx64 ", LID 0x%X\n" + "\t\t\t\tExpected revision 0x%X, received 0x%X\n", + cl_ntoh64(p_rec->node_info.node_guid), + cl_ntoh16(p_rec->lid), + cl_ntoh32(p_node->rec.node_info.revision), + cl_ntoh32(p_rec->node_info.revision)); + status = IB_ERROR; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_node_rec(IN osmtest_t * const p_osmt, + IN const ib_node_record_t * const p_rec) +{ + cl_status_t status = IB_SUCCESS; + node_t *p_node; + const cl_qmap_t *p_tbl; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * Find proper node record in the database. + */ + p_tbl = &p_osmt->exp_subn.node_lid_tbl; + p_node = (node_t *) cl_qmap_get(p_tbl, p_rec->lid); + if (p_node == (node_t *) cl_qmap_end(p_tbl)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0035: " + "Unexpected node 0x%016" PRIx64 ", LID 0x%X\n", + cl_ntoh64(p_rec->node_info.node_guid), + cl_ntoh16(p_rec->lid)); + status = IB_ERROR; + goto Exit; + } + + status = osmtest_validate_node_data(p_osmt, p_node, p_rec); + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_port_data(IN osmtest_t * const p_osmt, + IN port_t * const p_port, + IN const ib_portinfo_record_t * const p_rec) +{ + cl_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Checking port LID 0x%X, Num 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num); + + /* + * Has this record already been returned? + */ + if (p_port->count != 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0036: " + "Already received port LID 0x%X, Num 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num); + status = IB_ERROR; + goto Exit; + } + + ++p_port->count; + + /* + * Compare the fields the user wishes to validate. + */ + if ((p_port->comp.lid & p_port->rec.lid) != + (p_port->comp.lid & p_rec->lid)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0037: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected LID 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.lid, p_rec->lid); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_num & p_port->rec.port_num) != + (p_port->comp.port_num & p_rec->port_num)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0038: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected port_num 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_num, p_rec->port_num); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.m_key & p_port->rec.port_info.m_key) != + (p_port->comp.port_info.m_key & p_rec->port_info.m_key)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0039: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected m_key 0x%016" PRIx64 + ", received 0x%016" PRIx64 "\n", cl_ntoh16(p_rec->lid), + p_rec->port_num, p_port->rec.port_info.m_key, + p_rec->port_info.m_key); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.subnet_prefix & p_port->rec.port_info. + subnet_prefix) != + (p_port->comp.port_info.subnet_prefix & p_rec->port_info. + subnet_prefix)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0040: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected subnet_prefix 0x%016" PRIx64 + ", received 0x%016" PRIx64 "\n", cl_ntoh16(p_rec->lid), + p_rec->port_num, p_port->rec.port_info.subnet_prefix, + p_rec->port_info.subnet_prefix); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.base_lid & p_port->rec.port_info. + base_lid) != + (p_port->comp.port_info.base_lid & p_rec->port_info.base_lid)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0041: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected base_lid 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.base_lid, + p_rec->port_info.base_lid); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.master_sm_base_lid & p_port->rec.port_info. + master_sm_base_lid) != + (p_port->comp.port_info.master_sm_base_lid & p_rec->port_info. + master_sm_base_lid)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0042: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected master_sm_base_lid 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.master_sm_base_lid, + p_rec->port_info.master_sm_base_lid); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.capability_mask & p_port->rec.port_info. + capability_mask) != + (p_port->comp.port_info.capability_mask & p_rec->port_info. + capability_mask)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0043: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected capability_mask 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + cl_ntoh32(p_port->rec.port_info.capability_mask), + cl_ntoh32(p_rec->port_info.capability_mask)); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.diag_code & p_port->rec.port_info. + diag_code) != + (p_port->comp.port_info.diag_code & p_rec->port_info.diag_code)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0044: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected diag_code 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.diag_code, + p_rec->port_info.diag_code); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.m_key_lease_period & p_port->rec.port_info. + m_key_lease_period) != + (p_port->comp.port_info.m_key_lease_period & p_rec->port_info. + m_key_lease_period)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0045: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected m_key_lease_period 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.m_key_lease_period, + p_rec->port_info.m_key_lease_period); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.local_port_num & p_port->rec.port_info. + local_port_num) != + (p_port->comp.port_info.local_port_num & p_rec->port_info. + local_port_num)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0046: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected local_port_num 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.local_port_num, + p_rec->port_info.local_port_num); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.link_width_enabled & p_port->rec.port_info. + link_width_enabled) != + (p_port->comp.port_info.link_width_enabled & p_rec->port_info. + link_width_enabled)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0047: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected link_width_enabled 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.link_width_enabled, + p_rec->port_info.link_width_enabled); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.link_width_supported & p_port->rec. + port_info.link_width_supported) != + (p_port->comp.port_info.link_width_supported & p_rec->port_info. + link_width_supported)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0048: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected link_width_supported 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.link_width_supported, + p_rec->port_info.link_width_supported); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.link_width_active & p_port->rec.port_info. + link_width_active) != + (p_port->comp.port_info.link_width_active & p_rec->port_info. + link_width_active)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0049: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected link_width_active 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.link_width_active, + p_rec->port_info.link_width_active); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.link_speed & p_port->rec.port_info. + link_speed) != + (p_port->comp.port_info.link_speed & p_rec->port_info.link_speed)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0054: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected link_speed 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.link_speed, + p_rec->port_info.link_speed); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.state_info1 & p_port->rec.port_info. + state_info1) != + (p_port->comp.port_info.state_info1 & p_rec->port_info. + state_info1)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0055: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected state_info1 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.state_info1, + p_rec->port_info.state_info1); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.state_info2 & p_port->rec.port_info. + state_info2) != + (p_port->comp.port_info.state_info2 & p_rec->port_info. + state_info2)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0058: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected state_info2 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.state_info2, + p_rec->port_info.state_info2); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.mkey_lmc & p_port->rec.port_info. + mkey_lmc) != + (p_port->comp.port_info.mkey_lmc & p_rec->port_info.mkey_lmc)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0059: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected mkey_lmc 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.mkey_lmc, + p_rec->port_info.mkey_lmc); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.link_speed & p_port->rec.port_info. + link_speed) != + (p_port->comp.port_info.link_speed & p_rec->port_info.link_speed)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0060: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected link_speed 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.link_speed, + p_rec->port_info.link_speed); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.mtu_smsl & p_port->rec.port_info. + mtu_smsl) != + (p_port->comp.port_info.mtu_smsl & p_rec->port_info.mtu_smsl)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0061: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected mtu_smsl 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.mtu_smsl, + p_rec->port_info.mtu_smsl); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.vl_cap & p_port->rec.port_info.vl_cap) != + (p_port->comp.port_info.vl_cap & p_rec->port_info.vl_cap)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0062: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected vl_cap 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.vl_cap, p_rec->port_info.vl_cap); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.vl_high_limit & p_port->rec.port_info. + vl_high_limit) != + (p_port->comp.port_info.vl_high_limit & p_rec->port_info. + vl_high_limit)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0082: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected vl_high_limit 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.vl_high_limit, + p_rec->port_info.vl_high_limit); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.vl_arb_high_cap & p_port->rec.port_info. + vl_arb_high_cap) != + (p_port->comp.port_info.vl_arb_high_cap & p_rec->port_info. + vl_arb_high_cap)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0083: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected vl_arb_high_cap 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.vl_arb_high_cap, + p_rec->port_info.vl_arb_high_cap); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.vl_arb_low_cap & p_port->rec.port_info. + vl_arb_low_cap) != + (p_port->comp.port_info.vl_arb_low_cap & p_rec->port_info. + vl_arb_low_cap)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0084: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected vl_arb_low_cap 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.vl_arb_low_cap, + p_rec->port_info.vl_arb_low_cap); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.mtu_cap & p_port->rec.port_info.mtu_cap) != + (p_port->comp.port_info.mtu_cap & p_rec->port_info.mtu_cap)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0085: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected mtu_cap 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.mtu_cap, + p_rec->port_info.mtu_cap); + status = IB_ERROR; + goto Exit; + } +#if 0 + /* this is a dynamic attribute */ + if ((p_port->comp.port_info.vl_stall_life & p_port->rec.port_info. + vl_stall_life) != + (p_port->comp.port_info.vl_stall_life & p_rec->port_info. + vl_stall_life)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 012F: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected vl_stall_life 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.vl_stall_life, + p_rec->port_info.vl_stall_life); + status = IB_ERROR; + goto Exit; + } +#endif + + if ((p_port->comp.port_info.vl_enforce & p_port->rec.port_info. + vl_enforce) != + (p_port->comp.port_info.vl_enforce & p_rec->port_info.vl_enforce)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0086: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected vl_enforce 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.vl_enforce, + p_rec->port_info.vl_enforce); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.m_key_violations & p_port->rec.port_info. + m_key_violations) != + (p_port->comp.port_info.m_key_violations & p_rec->port_info. + m_key_violations)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0087: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected m_key_violations 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + cl_ntoh16(p_port->rec.port_info.m_key_violations), + cl_ntoh16(p_rec->port_info.m_key_violations)); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.p_key_violations & p_port->rec.port_info. + p_key_violations) != + (p_port->comp.port_info.p_key_violations & p_rec->port_info. + p_key_violations)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0088: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected p_key_violations 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + cl_ntoh16(p_port->rec.port_info.p_key_violations), + cl_ntoh16(p_rec->port_info.p_key_violations)); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.q_key_violations & p_port->rec.port_info. + q_key_violations) != + (p_port->comp.port_info.q_key_violations & p_rec->port_info. + q_key_violations)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0089: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected q_key_violations 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + cl_ntoh16(p_port->rec.port_info.q_key_violations), + cl_ntoh16(p_rec->port_info.q_key_violations)); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.guid_cap & p_port->rec.port_info. + guid_cap) != + (p_port->comp.port_info.guid_cap & p_rec->port_info.guid_cap)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0090: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected guid_cap 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.guid_cap, + p_rec->port_info.guid_cap); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.subnet_timeout & p_port->rec.port_info. + subnet_timeout) != + (p_port->comp.port_info.subnet_timeout & p_rec->port_info. + subnet_timeout)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0091: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected subnet_timeout 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + ib_port_info_get_timeout(&p_port->rec.port_info), + ib_port_info_get_timeout(&p_rec->port_info)); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.resp_time_value & p_port->rec.port_info. + resp_time_value) != + (p_port->comp.port_info.resp_time_value & p_rec->port_info. + resp_time_value)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0092: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected resp_time_value 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.resp_time_value, + p_rec->port_info.resp_time_value); + status = IB_ERROR; + goto Exit; + } + + if ((p_port->comp.port_info.error_threshold & p_port->rec.port_info. + error_threshold) != + (p_port->comp.port_info.error_threshold & p_rec->port_info. + error_threshold)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0093: " + "Field mismatch port LID 0x%X Num:0x%X\n" + "\t\t\t\tExpected error_threshold 0x%X, received 0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num, + p_port->rec.port_info.error_threshold, + p_rec->port_info.error_threshold); + status = IB_ERROR; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_port_rec(IN osmtest_t * const p_osmt, + IN const ib_portinfo_record_t * const p_rec) +{ + cl_status_t status = IB_SUCCESS; + port_t *p_port; + const cl_qmap_t *p_tbl; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * Find proper port record in the database. + * (we use by guid - since lid is not unique) + */ + p_tbl = &p_osmt->exp_subn.port_key_tbl; + p_port = + (port_t *) cl_qmap_get(p_tbl, + port_gen_id(p_rec->lid, p_rec->port_num)); + if (p_port == (port_t *) cl_qmap_end(p_tbl)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0094: " + "Unexpected port LID 0x%X, Num:0x%X\n", + cl_ntoh16(p_rec->lid), p_rec->port_num); + status = IB_ERROR; + goto Exit; + } + + status = osmtest_validate_port_data(p_osmt, p_port, p_rec); + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_path_rec(IN osmtest_t * const p_osmt, + IN const ib_path_rec_t * const p_rec) +{ + cl_status_t status = IB_SUCCESS; + path_t *p_path; + const cl_qmap_t *p_tbl; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * Find proper path record in the database. + */ + p_tbl = &p_osmt->exp_subn.path_tbl; + p_path = (path_t *) cl_qmap_get(p_tbl, osmtest_path_rec_key_get(p_rec)); + if (p_path == (path_t *) cl_qmap_end(p_tbl)) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0095: " + "Unexpected path SLID 0x%X to DLID 0x%X\n", + cl_ntoh16(p_rec->slid), cl_ntoh16(p_rec->dlid)); + status = IB_ERROR; + goto Exit; + } + + status = osmtest_validate_path_data(p_osmt, p_path, p_rec); + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +#ifdef VENDOR_RMPP_SUPPORT +ib_net64_t portguid = 0; + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_all_node_recs(IN osmtest_t * const p_osmt) +{ + osmtest_req_context_t context; + const ib_node_record_t *p_rec; + uint32_t i; + cl_status_t status; + size_t num_recs; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + /* + * Do a blocking query for all NodeRecords in the subnet. + */ + status = osmtest_get_all_recs(p_osmt, IB_MAD_ATTR_NODE_RECORD, + sizeof(*p_rec), &context); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0096: " + "osmtest_get_all_recs failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + num_recs = context.result.result_cnt; + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Received %zu records\n", + num_recs); + + /* + * Compare the received records to the database. + */ + osmtest_prepare_db(p_osmt); + + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_node_rec(context.result.p_result_madw, i); + + status = osmtest_validate_node_rec(p_osmt, p_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0097: " + "osmtest_valid_node_rec failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + if (!portguid) + portguid = p_rec->node_info.port_guid; + } + + status = osmtest_check_missing_nodes(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0098: " + "osmtest_check_missing_nodes failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_all_guidinfo_recs(IN osmtest_t * const p_osmt) +{ + osmtest_req_context_t context; + const ib_guidinfo_record_t *p_rec; + cl_status_t status; + size_t num_recs; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + /* + * Do a blocking query for all GuidInfoRecords in the subnet. + */ + status = osmtest_get_all_recs(p_osmt, IB_MAD_ATTR_GUIDINFO_RECORD, + sizeof(*p_rec), &context); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0099: " + "osmtest_get_all_recs failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + num_recs = context.result.result_cnt; + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Received %zu records\n", + num_recs); + + /* No validation as yet */ + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_all_path_recs(IN osmtest_t * const p_osmt) +{ + osmtest_req_context_t context; + const ib_path_rec_t *p_rec; + uint32_t i; + cl_status_t status; + size_t num_recs; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + /* + * Do a blocking query for all PathRecords in the subnet. + */ + status = osmtest_get_all_recs(p_osmt, IB_MAD_ATTR_PATH_RECORD, + sizeof(*p_rec), &context); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 009A: " + "osmtest_get_all_recs failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + num_recs = context.result.result_cnt; + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "Received %zu records\n", + num_recs); + + /* + * Compare the received records to the database. + */ + osmtest_prepare_db(p_osmt); + + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_path_rec(context.result.p_result_madw, i); + + status = osmtest_validate_path_rec(p_osmt, p_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0100: " + "osmtest_validate_path_rec failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + } + + status = osmtest_check_missing_paths(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0101: " + "osmtest_check_missing_paths failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * Get link record by LID + **********************************************************************/ +ib_api_status_t +osmtest_get_link_rec_by_lid(IN osmtest_t * const p_osmt, + IN ib_net16_t const from_lid, + IN ib_net16_t const to_lid, + IN OUT osmtest_req_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_link_record_t record; + ib_mad_t *p_mad; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting link record from LID 0x%02X to LID 0x%02X\n", + cl_ntoh16(from_lid), cl_ntoh16(to_lid)); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&record, 0, sizeof(record)); + + record.from_lid = from_lid; + record.to_lid = to_lid; + p_context->p_osmt = p_osmt; + if (from_lid) + user.comp_mask |= IB_LR_COMPMASK_FROM_LID; + if (to_lid) + user.comp_mask |= IB_LR_COMPMASK_TO_LID; + user.attr_id = IB_MAD_ATTR_LINK_RECORD; + user.attr_offset = cl_ntoh16((uint16_t) (sizeof(record) >> 3)); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 007A: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 007B: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR) { + p_mad = + osm_madw_get_mad_ptr(p_context->result. + p_result_madw); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "osmtest_get_link_rec_by_lid: " + "Remote error = %s\n", + ib_get_mad_status_str(p_mad)); + + status = + (ib_net16_t) (p_mad->status & IB_SMP_STATUS_MASK); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * Get GUIDInfo record by LID + **********************************************************************/ +ib_api_status_t +osmtest_get_guidinfo_rec_by_lid(IN osmtest_t * const p_osmt, + IN ib_net16_t const lid, + IN OUT osmtest_req_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_guidinfo_record_t record; + ib_mad_t *p_mad; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting GUIDInfo record for LID 0x%02X\n", cl_ntoh16(lid)); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&record, 0, sizeof(record)); + + record.lid = lid; + p_context->p_osmt = p_osmt; + user.comp_mask = IB_GIR_COMPMASK_LID; + user.attr_id = IB_MAD_ATTR_GUIDINFO_RECORD; + user.attr_offset = cl_ntoh16((uint16_t) (sizeof(record) >> 3)); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 007C: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 007D: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR) { + p_mad = + osm_madw_get_mad_ptr(p_context->result. + p_result_madw); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(p_mad)); + + status = + (ib_net16_t) (p_mad->status & IB_SMP_STATUS_MASK); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * Get PKeyTable record by LID + **********************************************************************/ +ib_api_status_t +osmtest_get_pkeytbl_rec_by_lid(IN osmtest_t * const p_osmt, + IN ib_net16_t const lid, + IN ib_net64_t const sm_key, + IN OUT osmtest_req_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_pkey_table_record_t record; + ib_mad_t *p_mad; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting PKeyTable record for LID 0x%02X\n", cl_ntoh16(lid)); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&record, 0, sizeof(record)); + + record.lid = lid; + p_context->p_osmt = p_osmt; + user.comp_mask = IB_PKEY_COMPMASK_LID; + user.attr_id = IB_MAD_ATTR_PKEY_TBL_RECORD; + user.attr_offset = cl_ntoh16((uint16_t) (sizeof(record) >> 3)); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = sm_key; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 007E: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 007F: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR) { + p_mad = + osm_madw_get_mad_ptr(p_context->result. + p_result_madw); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(p_mad)); + + status = + (ib_net16_t) (p_mad->status & IB_SMP_STATUS_MASK); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * Get SwitchInfo record by LID + **********************************************************************/ +ib_api_status_t +osmtest_get_sw_info_rec_by_lid(IN osmtest_t * const p_osmt, + IN ib_net16_t const lid, + IN OUT osmtest_req_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_switch_info_record_t record; + ib_mad_t *p_mad; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting SwitchInfo record for LID 0x%02X\n", cl_ntoh16(lid)); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&record, 0, sizeof(record)); + + record.lid = lid; + p_context->p_osmt = p_osmt; + if (lid) + user.comp_mask = IB_SWIR_COMPMASK_LID; + user.attr_id = IB_MAD_ATTR_SWITCH_INFO_RECORD; + user.attr_offset = cl_ntoh16((uint16_t) (sizeof(record) >> 3)); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 006C: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 006D: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR) { + p_mad = + osm_madw_get_mad_ptr(p_context->result. + p_result_madw); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(p_mad)); + + status = + (ib_net16_t) (p_mad->status & IB_SMP_STATUS_MASK); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * Get LFT record by LID + **********************************************************************/ +ib_api_status_t +osmtest_get_lft_rec_by_lid(IN osmtest_t * const p_osmt, + IN ib_net16_t const lid, + IN OUT osmtest_req_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_lft_record_t record; + ib_mad_t *p_mad; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting LFT record for LID 0x%02X\n", cl_ntoh16(lid)); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&record, 0, sizeof(record)); + + record.lid = lid; + p_context->p_osmt = p_osmt; + if (lid) + user.comp_mask = IB_LFTR_COMPMASK_LID; + user.attr_id = IB_MAD_ATTR_LFT_RECORD; + user.attr_offset = cl_ntoh16((uint16_t) (sizeof(record) >> 3)); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 008A: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 008B: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR) { + p_mad = + osm_madw_get_mad_ptr(p_context->result. + p_result_madw); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(p_mad)); + + status = + (ib_net16_t) (p_mad->status & IB_SMP_STATUS_MASK); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + * Get MFT record by LID + **********************************************************************/ +ib_api_status_t +osmtest_get_mft_rec_by_lid(IN osmtest_t * const p_osmt, + IN ib_net16_t const lid, + IN OUT osmtest_req_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_mft_record_t record; + ib_mad_t *p_mad; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Getting MFT record for LID 0x%02X\n", cl_ntoh16(lid)); + + /* + * Do a blocking query for this record in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&record, 0, sizeof(record)); + + record.lid = lid; + p_context->p_osmt = p_osmt; + if (lid) + user.comp_mask = IB_MFTR_COMPMASK_LID; + user.attr_id = IB_MAD_ATTR_MFT_RECORD; + user.attr_offset = cl_ntoh16((uint16_t) (sizeof(record) >> 3)); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 009B: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 009C: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + if (status == IB_REMOTE_ERROR) { + p_mad = + osm_madw_get_mad_ptr(p_context->result. + p_result_madw); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(p_mad)); + + status = + (ib_net16_t) (p_mad->status & IB_SMP_STATUS_MASK); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_sminfo_record_request(IN osmtest_t * const p_osmt, + IN uint8_t method, + IN void *p_options, + IN OUT osmtest_req_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_sminfo_record_t record; + ib_mad_t *p_mad; + osmtest_sm_info_rec_t *p_sm_info_opt; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * Do a blocking query for these records in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&record, 0, sizeof(record)); + + p_context->p_osmt = p_osmt; + user.attr_id = IB_MAD_ATTR_SMINFO_RECORD; + user.attr_offset = cl_ntoh16((uint16_t) (sizeof(record) >> 3)); + p_sm_info_opt = p_options; + if (p_sm_info_opt->sm_guid != 0) { + record.sm_info.guid = p_sm_info_opt->sm_guid; + user.comp_mask |= IB_SMIR_COMPMASK_GUID; + } + if (p_sm_info_opt->lid != 0) { + record.lid = p_sm_info_opt->lid; + user.comp_mask |= IB_SMIR_COMPMASK_LID; + } + if (p_sm_info_opt->priority != 0) { + record.sm_info.pri_state = + (p_sm_info_opt->priority & 0x0F) << 4; + user.comp_mask |= IB_SMIR_COMPMASK_PRIORITY; + } + if (p_sm_info_opt->sm_state != 0) { + record.sm_info.pri_state |= p_sm_info_opt->sm_state & 0x0F; + user.comp_mask |= IB_SMIR_COMPMASK_SMSTATE; + } + + user.method = method; + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 008C: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + if (status != IB_INVALID_PARAMETER) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 008D: " + "ib_query failed (%s)\n", + ib_get_err_str(status)); + } + if (status == IB_REMOTE_ERROR) { + p_mad = + osm_madw_get_mad_ptr(p_context->result. + p_result_madw); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(p_mad)); + + status = + (ib_net16_t) (p_mad->status & IB_SMP_STATUS_MASK); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_informinfo_request(IN osmtest_t * const p_osmt, + IN ib_net16_t attr_id, + IN uint8_t method, + IN void *p_options, + IN OUT osmtest_req_context_t * const p_context) +{ + ib_api_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_inform_info_t rec; + ib_inform_info_record_t record; + ib_mad_t *p_mad; + osmtest_inform_info_t *p_inform_info_opt; + osmtest_inform_info_rec_t *p_inform_info_rec_opt; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * Do a blocking query for these records in the subnet. + * The result is returned in the result field of the caller's + * context structure. + * + * The query structures are locals. + */ + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&rec, 0, sizeof(rec)); + memset(&record, 0, sizeof(record)); + + p_context->p_osmt = p_osmt; + user.attr_id = attr_id; + if (attr_id == IB_MAD_ATTR_INFORM_INFO_RECORD) { + user.attr_offset = cl_ntoh16((uint16_t) (sizeof(record) >> 3)); + p_inform_info_rec_opt = p_options; + if (p_inform_info_rec_opt->subscriber_gid.unicast.prefix != 0 && + p_inform_info_rec_opt->subscriber_gid.unicast. + interface_id != 0) { + record.subscriber_gid = + p_inform_info_rec_opt->subscriber_gid; + user.comp_mask = IB_IIR_COMPMASK_SUBSCRIBERGID; + } + record.subscriber_enum = + cl_hton16(p_inform_info_rec_opt->subscriber_enum); + user.comp_mask |= IB_IIR_COMPMASK_ENUM; + user.p_attr = &record; + } else { + user.attr_offset = cl_ntoh16((uint16_t) (sizeof(rec) >> 3)); + /* comp mask bits below are for InformInfoRecord rather than InformInfo */ + /* as currently no comp mask bits defined for InformInfo!!! */ + user.comp_mask = IB_IIR_COMPMASK_SUBSCRIBE; + p_inform_info_opt = p_options; + rec.subscribe = (uint8_t) p_inform_info_opt->subscribe; + if (p_inform_info_opt->qpn) { + rec.g_or_v.generic.qpn_resp_time_val = + cl_hton32(p_inform_info_opt->qpn << 8); + user.comp_mask |= IB_IIR_COMPMASK_QPN; + } + if (p_inform_info_opt->trap) { + rec.g_or_v.generic.trap_num = + cl_hton16(p_inform_info_opt->trap); + user.comp_mask |= IB_IIR_COMPMASK_TRAPNUMB; + } + user.p_attr = &rec; + } + user.method = method; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = p_context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 008E: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = p_context->result.status; + + if (status != IB_SUCCESS) { + if (status != IB_INVALID_PARAMETER) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 008F: " + "ib_query failed (%s)\n", + ib_get_err_str(status)); + } + if (status == IB_REMOTE_ERROR) { + p_mad = + osm_madw_get_mad_ptr(p_context->result. + p_result_madw); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(p_mad)); + + status = + (ib_net16_t) (p_mad->status & IB_SMP_STATUS_MASK); + } + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} +#endif + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_single_path_rec_lid_pair(IN osmtest_t * const p_osmt, + IN path_t * const p_path) +{ + osmtest_req_context_t context; + const ib_path_rec_t *p_rec; + cl_status_t status = IB_SUCCESS; + size_t num_recs; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + status = osmtest_get_path_rec_by_lid_pair(p_osmt, + p_path->rec.slid, + p_path->rec.dlid, &context); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0102: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + num_recs = context.result.result_cnt; + if (num_recs != 1) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0103: " + "Too many records. Expected 1, received %zu\n", + num_recs); + + status = IB_ERROR; + } else { + p_rec = + osmv_get_query_path_rec(context.result.p_result_madw, 0); + + status = osmtest_validate_path_data(p_osmt, p_path, p_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0104: " + "osmtest_validate_path_data failed (%s)\n", + ib_get_err_str(status)); + } + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_single_node_rec_lid(IN osmtest_t * const p_osmt, + IN ib_net16_t const lid, + IN node_t * const p_node) +{ + cl_status_t status = IB_SUCCESS; + osmv_user_query_t user; + osmv_query_req_t req; + ib_node_record_t record; + + osmtest_req_context_t context; + const ib_node_record_t *p_rec; + int num_recs, i; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "Getting NodeRecord for node with LID 0x%X\n", cl_ntoh16(lid)); + + memset(&context, 0, sizeof(context)); + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + memset(&record, 0, sizeof(record)); + + record.lid = lid; + + context.p_osmt = p_osmt; + user.comp_mask = IB_NR_COMPMASK_LID; + user.attr_id = IB_MAD_ATTR_NODE_RECORD; + user.attr_offset = cl_ntoh16((uint16_t) (sizeof(record) >> 3)); + user.p_attr = &record; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + req.p_query_input = &user; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0105: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0106: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + + num_recs = context.result.result_cnt; + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Received %d nodes\n", num_recs); + + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_node_rec(context.result.p_result_madw, i); + + status = osmtest_validate_node_rec(p_osmt, p_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0107: " + "osmtest_validate_node_data failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_single_port_rec_lid(IN osmtest_t * const p_osmt, + IN port_t * const p_port) +{ + osmtest_req_context_t context; + + const ib_portinfo_record_t *p_rec; + cl_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&context, 0, sizeof(context)); + + context.p_osmt = p_osmt; + osmtest_get_port_rec_by_num(p_osmt, + p_port->rec.lid, + p_port->rec.port_num, &context); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0108: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + goto Exit; + } + + /* we should have got exactly one port */ + p_rec = osmv_get_query_portinfo_rec(context.result.p_result_madw, 0); + status = osmtest_validate_port_rec(p_osmt, p_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0109: " + "osmtest_validate_port_data failed (%s)\n", + ib_get_err_str(status)); + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_single_path_rec_guid_pair(IN osmtest_t * const p_osmt, + IN const osmv_guid_pair_t * + const p_pair) +{ + osmtest_req_context_t context; + const ib_path_rec_t *p_rec; + cl_status_t status = IB_SUCCESS; + size_t num_recs; + osmv_query_req_t req; + uint32_t i; + boolean_t got_error = FALSE; + + OSM_LOG_ENTER(&p_osmt->log); + + memset(&req, 0, sizeof(req)); + memset(&context, 0, sizeof(context)); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "\n\t\t\t\tChecking src 0x%016" PRIx64 + " to dest 0x%016" PRIx64 "\n", + cl_ntoh64(p_pair->src_guid), cl_ntoh64(p_pair->dest_guid)); + + context.p_osmt = p_osmt; + + req.timeout_ms = p_osmt->opt.transaction_timeout; + req.retry_cnt = p_osmt->opt.retry_count; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = &context; + req.pfn_query_cb = osmtest_query_res_cb; + + req.query_type = OSMV_QUERY_PATH_REC_BY_PORT_GUIDS; + req.p_query_input = p_pair; + req.sm_key = 0; + + status = osmv_query_sa(p_osmt->h_bind, &req); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0110: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + goto Exit; + } + + status = context.result.status; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0111: " + "ib_query failed (%s)\n", ib_get_err_str(status)); + + if (status == IB_REMOTE_ERROR) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Remote error = %s\n", + ib_get_mad_status_str(osm_madw_get_mad_ptr + (context.result. + p_result_madw))); + } + goto Exit; + } + + num_recs = context.result.result_cnt; + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "%zu records\n", num_recs); + + for (i = 0; i < num_recs; i++) { + p_rec = + osmv_get_query_path_rec(context.result.p_result_madw, i); + + /* + * Make sure the GUID values are correct + */ + if (p_rec->dgid.unicast.interface_id != p_pair->dest_guid) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0112: " + "Destination GUID mismatch\n" + "\t\t\t\texpected 0x%016" PRIx64 + ", received 0x%016" PRIx64 "\n", + cl_ntoh64(p_pair->dest_guid), + cl_ntoh64(p_rec->dgid.unicast.interface_id)); + got_error = TRUE; + } + + if (p_rec->sgid.unicast.interface_id != p_pair->src_guid) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0113: " + "Source GUID mismatch\n" + "\t\t\t\texpected 0x%016" PRIx64 + ", received 0x%016" PRIx64 ".\n", + cl_ntoh64(p_pair->src_guid), + cl_ntoh64(p_rec->sgid.unicast.interface_id)); + got_error = TRUE; + } + + status = osmtest_validate_path_rec(p_osmt, p_rec); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0114: " + "osmtest_validate_path_rec failed (%s)\n", + ib_get_err_str(status)); + got_error = TRUE; + } + if (got_error || (status != IB_SUCCESS)) { + osm_dump_path_record(&p_osmt->log, p_rec, + OSM_LOG_VERBOSE); + if (status == IB_SUCCESS) + status = IB_ERROR; + goto Exit; + } + } + +Exit: + /* + * Return the IB query MAD to the pool as necessary. + */ + if (context.result.p_result_madw != NULL) { + osm_mad_pool_put(&p_osmt->mad_pool, + context.result.p_result_madw); + context.result.p_result_madw = NULL; + } + + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_single_path_recs(IN osmtest_t * const p_osmt) +{ + path_t *p_path; + cl_status_t status = IB_SUCCESS; + const cl_qmap_t *p_path_tbl; +/* We skip node to node path record validation since it might contains + NONEXISTENT PATHS, i.e. when using UPDN */ + osmv_guid_pair_t guid_pair; + uint16_t cnt; + + OSM_LOG_ENTER(&p_osmt->log); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Validating individual path record queries\n"); + p_path_tbl = &p_osmt->exp_subn.path_tbl; + + osmtest_prepare_db(p_osmt); + + /* + * Walk the list of all path records, and ask for each one + * specifically. Make sure we get it. + */ + cnt = 0; + p_path = (path_t *) cl_qmap_head(p_path_tbl); + while (p_path != (path_t *) cl_qmap_end(p_path_tbl)) { + status = + osmtest_validate_single_path_rec_lid_pair(p_osmt, p_path); + if (status != IB_SUCCESS) + goto Exit; + cnt++; + p_path = (path_t *) cl_qmap_next(&p_path->map_item); + } + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Total of %u path records validated using LID based query\n", + cnt); + + status = osmtest_check_missing_paths(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0115: " + "osmtest_check_missing_paths failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + /* + * Do the whole thing again with port GUID pairs. + * Note that multiple path records may be returned + * for each guid pair if LMC > 0. + */ + osmtest_prepare_db(p_osmt); + cnt = 0; + p_path = (path_t *) cl_qmap_head(p_path_tbl); + while (p_path != (path_t *) cl_qmap_end(p_path_tbl)) { + guid_pair.src_guid = p_path->rec.sgid.unicast.interface_id; + guid_pair.dest_guid = p_path->rec.dgid.unicast.interface_id; + status = osmtest_validate_single_path_rec_guid_pair(p_osmt, + &guid_pair); + if (status != IB_SUCCESS) + goto Exit; + cnt++; + p_path = (path_t *) cl_qmap_next(&p_path->map_item); + } + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Total of %u path records validated using GUID based query\n", + cnt); + + status = osmtest_check_missing_paths(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0116: " + "osmtest_check_missing_paths failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_single_node_recs(IN osmtest_t * const p_osmt) +{ + node_t *p_node; + cl_status_t status = IB_SUCCESS; + const cl_qmap_t *p_node_lid_tbl; + uint16_t cnt = 0; + + OSM_LOG_ENTER(&p_osmt->log); + + p_node_lid_tbl = &p_osmt->exp_subn.node_lid_tbl; + + osmtest_prepare_db(p_osmt); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Validating individual node record queries\n"); + + /* + * Walk the list of all node records, and ask for each one + * specifically. Make sure we get it. + */ + p_node = (node_t *) cl_qmap_head(p_node_lid_tbl); + while (p_node != (node_t *) cl_qmap_end(p_node_lid_tbl)) { + status = osmtest_validate_single_node_rec_lid(p_osmt, + (ib_net16_t) + cl_qmap_key((cl_map_item_t *) p_node), p_node); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 011A: " + "osmtest_validate_single_node_rec_lid (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + cnt++; + p_node = (node_t *) cl_qmap_next(&p_node->map_item); + } + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Total of %u node records validated\n", cnt); + + status = osmtest_check_missing_nodes(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0117: " + "osmtest_check_missing_nodes (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_validate_single_port_recs(IN osmtest_t * const p_osmt) +{ + port_t *p_port; + cl_status_t status = IB_SUCCESS; + const cl_qmap_t *p_port_key_tbl; + uint16_t cnt = 0; + + OSM_LOG_ENTER(&p_osmt->log); + + p_port_key_tbl = &p_osmt->exp_subn.port_key_tbl; + + osmtest_prepare_db(p_osmt); + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Validating individual port record queries\n"); + + /* + * Walk the list of all port records, and ask for each one + * specifically. Make sure we get it. + */ + p_port = (port_t *) cl_qmap_head(p_port_key_tbl); + while (p_port != (port_t *) cl_qmap_end(p_port_key_tbl)) { + status = osmtest_validate_single_port_rec_lid(p_osmt, p_port); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 011B: " + "osmtest_validate_single_port_rec_lid (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + cnt++; + p_port = (port_t *) cl_qmap_next(&p_port->map_item); + } + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, + "Total of %u port records validated\n", cnt); + + status = osmtest_check_missing_ports(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0118: " + "osmtest_check_missing_paths failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t osmtest_validate_against_db(IN osmtest_t * const p_osmt) +{ + ib_api_status_t status = IB_SUCCESS; + ib_gid_t portgid, mgid; + osmtest_sm_info_rec_t sm_info_rec_opt; + osmtest_inform_info_t inform_info_opt; + osmtest_inform_info_rec_t inform_info_rec_opt; +#ifdef VENDOR_RMPP_SUPPORT + ib_net64_t sm_key; + ib_net16_t test_lid; + uint8_t lmc; + osmtest_req_context_t context; +#ifdef DUAL_SIDED_RMPP + osmv_multipath_req_t request; +#endif + uint8_t i; +#endif + + OSM_LOG_ENTER(&p_osmt->log); + +#ifdef VENDOR_RMPP_SUPPORT + status = osmtest_validate_all_node_recs(p_osmt); + if (status != IB_SUCCESS) + goto Exit; +#endif + + status = osmtest_validate_single_node_recs(p_osmt); + if (status != IB_SUCCESS) + goto Exit; + + /* Exercise SA PathRecord multicast destination code */ + memset(&context, 0, sizeof(context)); + ib_gid_set_default(&portgid, portguid); + /* Set IPoIB broadcast MGID */ + mgid.unicast.prefix = CL_HTON64(0xff12401bffff0000ULL); + mgid.unicast.interface_id = CL_HTON64(0x00000000ffffffffULL); + /* Can't check status as don't know whether port is running IPoIB */ + osmtest_get_path_rec_by_gid_pair(p_osmt, portgid, mgid, &context); + + /* Other link local unicast PathRecord */ + memset(&context, 0, sizeof(context)); + ib_gid_set_default(&portgid, portguid); + ib_gid_set_default(&mgid, portguid); + mgid.raw[7] = 0xff; /* not default GID prefix */ + /* Can't check status as don't know whether ??? */ + osmtest_get_path_rec_by_gid_pair(p_osmt, portgid, mgid, &context); + + /* Off subnet (site local) unicast PathRecord */ + memset(&context, 0, sizeof(context)); + ib_gid_set_default(&portgid, portguid); + ib_gid_set_default(&mgid, portguid); + mgid.raw[1] = 0xc0; /* site local */ + /* Can't check status as don't know whether ??? */ + osmtest_get_path_rec_by_gid_pair(p_osmt, portgid, mgid, &context); + + /* More than link local scope multicast PathRecord */ + memset(&context, 0, sizeof(context)); + ib_gid_set_default(&portgid, portguid); + /* Set IPoIB broadcast MGID */ + mgid.unicast.prefix = CL_HTON64(0xff15401bffff0000ULL); /* site local */ + mgid.unicast.interface_id = CL_HTON64(0x00000000ffffffffULL); + /* Can't check status as don't know whether port is running IPoIB */ + osmtest_get_path_rec_by_gid_pair(p_osmt, portgid, mgid, &context); + +#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP) + memset(&context, 0, sizeof(context)); + memset(&request, 0, sizeof(request)); + request.comp_mask = + IB_MPR_COMPMASK_SGIDCOUNT | IB_MPR_COMPMASK_DGIDCOUNT; + request.sgid_count = 1; + request.dgid_count = 1; + ib_gid_set_default(&request.gids[0], portguid); + ib_gid_set_default(&request.gids[1], portguid); + status = osmtest_get_multipath_rec(p_osmt, &request, &context); + if (status != IB_SUCCESS) + goto Exit; + + memset(&context, 0, sizeof(context)); + memset(&request, 0, sizeof(request)); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmtest_get_multipath_rec(p_osmt, &request, &context); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Got error %s\n", ib_get_err_str(status)); + } + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status == IB_SUCCESS) { + status = IB_ERROR; + goto Exit; + } + + memset(&context, 0, sizeof(context)); + memset(&request, 0, sizeof(request)); + request.comp_mask = IB_MPR_COMPMASK_SGIDCOUNT; + request.sgid_count = 1; + ib_gid_set_default(&request.gids[0], portguid); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmtest_get_multipath_rec(p_osmt, &request, &context); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Got error %s\n", ib_get_err_str(status)); + } + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status == IB_SUCCESS) { + status = IB_ERROR; + goto Exit; + } + + memset(&context, 0, sizeof(context)); + memset(&request, 0, sizeof(request)); + request.comp_mask = + IB_MPR_COMPMASK_SGIDCOUNT | IB_MPR_COMPMASK_DGIDCOUNT; + request.sgid_count = 1; + request.dgid_count = 1; + ib_gid_set_default(&request.gids[0], portguid); + /* Set IPoIB broadcast MGID as DGID */ + request.gids[1].unicast.prefix = CL_HTON64(0xff12401bffff0000ULL); + request.gids[1].unicast.interface_id = CL_HTON64(0x00000000ffffffffULL); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmtest_get_multipath_rec(p_osmt, &request, &context); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Got error %s\n", ib_get_err_str(status)); + } + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status == IB_SUCCESS) { + status = IB_ERROR; + goto Exit; + } + + memset(&context, 0, sizeof(context)); + request.comp_mask = + IB_MPR_COMPMASK_SGIDCOUNT | IB_MPR_COMPMASK_DGIDCOUNT; + request.sgid_count = 1; + request.dgid_count = 1; + /* Set IPoIB broadcast MGID as SGID */ + request.gids[0].unicast.prefix = CL_HTON64(0xff12401bffff0000ULL); + request.gids[0].unicast.interface_id = CL_HTON64(0x00000000ffffffffULL); + ib_gid_set_default(&request.gids[1], portguid); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmtest_get_multipath_rec(p_osmt, &request, &context); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Got error %s\n", ib_get_err_str(status)); + } + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status == IB_SUCCESS) { + status = IB_ERROR; + goto Exit; + } + + memset(&context, 0, sizeof(context)); + memset(&request, 0, sizeof(request)); + request.comp_mask = + IB_MPR_COMPMASK_SGIDCOUNT | IB_MPR_COMPMASK_DGIDCOUNT | + IB_MPR_COMPMASK_NUMBPATH; + request.sgid_count = 2; + request.dgid_count = 2; + request.num_path = 2; + ib_gid_set_default(&request.gids[0], portguid); + ib_gid_set_default(&request.gids[1], portguid); + ib_gid_set_default(&request.gids[2], portguid); + ib_gid_set_default(&request.gids[3], portguid); + status = osmtest_get_multipath_rec(p_osmt, &request, &context); + if (status != IB_SUCCESS) + goto Exit; +#endif + +#ifdef VENDOR_RMPP_SUPPORT + /* GUIDInfoRecords */ + status = osmtest_validate_all_guidinfo_recs(p_osmt); + if (status != IB_SUCCESS) + goto Exit; + + /* If LMC > 0, test non base LID SA PortInfoRecord request */ + status = + osmtest_get_local_port_lmc(p_osmt, p_osmt->local_port.lid, &lmc); + if (status != IB_SUCCESS) + goto Exit; + + if (lmc != 0) { + status = + osmtest_get_local_port_lmc(p_osmt, + p_osmt->local_port.lid + 1, + NULL); + if (status != IB_SUCCESS) + goto Exit; + } + + status = osmtest_get_local_port_lmc(p_osmt, 0xffff, NULL); + if (status != IB_SUCCESS) + goto Exit; + + test_lid = cl_ntoh16(p_osmt->local_port.lid); + + /* More GUIDInfo Record tests */ + memset(&context, 0, sizeof(context)); + status = osmtest_get_guidinfo_rec_by_lid(p_osmt, test_lid, &context); + if (status != IB_SUCCESS) + goto Exit; + + memset(&context, 0, sizeof(context)); + status = osmtest_get_guidinfo_rec_by_lid(p_osmt, 0xffff, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Some PKeyTable Record tests */ + sm_key = OSM_DEFAULT_SM_KEY; + memset(&context, 0, sizeof(context)); + status = + osmtest_get_pkeytbl_rec_by_lid(p_osmt, test_lid, sm_key, &context); + if (status != IB_SUCCESS) + goto Exit; + + memset(&context, 0, sizeof(context)); + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_START "\n"); + status = osmtest_get_pkeytbl_rec_by_lid(p_osmt, test_lid, 0, &context); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Got error %s\n", ib_get_err_str(status)); + } + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, EXPECTING_ERRORS_END "\n"); + + if (status == IB_SUCCESS) { + status = IB_ERROR; + goto Exit; + } + + memset(&context, 0, sizeof(context)); + status = + osmtest_get_pkeytbl_rec_by_lid(p_osmt, 0xffff, sm_key, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* SwitchInfo Record tests */ + memset(&context, 0, sizeof(context)); + status = osmtest_get_sw_info_rec_by_lid(p_osmt, 0, &context); + if (status != IB_SUCCESS) + goto Exit; + + memset(&context, 0, sizeof(context)); + status = osmtest_get_sw_info_rec_by_lid(p_osmt, test_lid, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* LFT Record tests */ + memset(&context, 0, sizeof(context)); + status = osmtest_get_lft_rec_by_lid(p_osmt, 0, &context); + if (status != IB_SUCCESS) + goto Exit; + + memset(&context, 0, sizeof(context)); + status = osmtest_get_lft_rec_by_lid(p_osmt, test_lid, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* MFT Record tests */ + memset(&context, 0, sizeof(context)); + status = osmtest_get_mft_rec_by_lid(p_osmt, 0, &context); + if (status != IB_SUCCESS) + goto Exit; + + memset(&context, 0, sizeof(context)); + status = osmtest_get_mft_rec_by_lid(p_osmt, test_lid, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Some LinkRecord tests */ + /* FromLID */ + memset(&context, 0, sizeof(context)); + status = osmtest_get_link_rec_by_lid(p_osmt, test_lid, 0, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* ToLID */ + memset(&context, 0, sizeof(context)); + status = osmtest_get_link_rec_by_lid(p_osmt, 0, test_lid, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* FromLID & ToLID */ + memset(&context, 0, sizeof(context)); + status = + osmtest_get_link_rec_by_lid(p_osmt, test_lid, test_lid, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* NodeRecord test */ + memset(&context, 0, sizeof(context)); + status = osmtest_get_node_rec_by_lid(p_osmt, 0xffff, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* SMInfoRecord tests */ + memset(&sm_info_rec_opt, 0, sizeof(sm_info_rec_opt)); + memset(&context, 0, sizeof(context)); + status = osmtest_sminfo_record_request(p_osmt, IB_MAD_METHOD_SET, + &sm_info_rec_opt, &context); + if (status == IB_SUCCESS) { + status = IB_ERROR; + goto Exit; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "IS EXPECTED ERROR ^^^^\n"); + } + + memset(&sm_info_rec_opt, 0, sizeof(sm_info_rec_opt)); + memset(&context, 0, sizeof(context)); + status = osmtest_sminfo_record_request(p_osmt, IB_MAD_METHOD_GETTABLE, + &sm_info_rec_opt, &context); + if (status != IB_SUCCESS) + goto Exit; + + memset(&sm_info_rec_opt, 0, sizeof(sm_info_rec_opt)); + sm_info_rec_opt.lid = test_lid; /* local LID */ + memset(&context, 0, sizeof(context)); + status = osmtest_sminfo_record_request(p_osmt, IB_MAD_METHOD_GETTABLE, + &sm_info_rec_opt, &context); + if (status != IB_SUCCESS) + goto Exit; + + if (portguid != 0) { + memset(&sm_info_rec_opt, 0, sizeof(sm_info_rec_opt)); + sm_info_rec_opt.sm_guid = portguid; /* local GUID */ + memset(&context, 0, sizeof(context)); + status = + osmtest_sminfo_record_request(p_osmt, + IB_MAD_METHOD_GETTABLE, + &sm_info_rec_opt, &context); + if (status != IB_SUCCESS) + goto Exit; + } + + for (i = 1; i < 16; i++) { + memset(&sm_info_rec_opt, 0, sizeof(sm_info_rec_opt)); + sm_info_rec_opt.priority = i; + memset(&context, 0, sizeof(context)); + status = + osmtest_sminfo_record_request(p_osmt, + IB_MAD_METHOD_GETTABLE, + &sm_info_rec_opt, &context); + if (status != IB_SUCCESS) + goto Exit; + } + + for (i = 1; i < 4; i++) { + memset(&sm_info_rec_opt, 0, sizeof(sm_info_rec_opt)); + sm_info_rec_opt.sm_state = i; + memset(&context, 0, sizeof(context)); + status = + osmtest_sminfo_record_request(p_osmt, + IB_MAD_METHOD_GETTABLE, + &sm_info_rec_opt, &context); + if (status != IB_SUCCESS) + goto Exit; + } + + /* InformInfoRecord tests */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfoRecord " + "Sending a BAD - Set Unsubscribe request\n"); + memset(&inform_info_opt, 0, sizeof(inform_info_opt)); + memset(&inform_info_rec_opt, 0, sizeof(inform_info_rec_opt)); + memset(&context, 0, sizeof(context)); + status = + osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO_RECORD, + IB_MAD_METHOD_SET, &inform_info_rec_opt, + &context); + if (status == IB_SUCCESS) { + status = IB_ERROR; + goto Exit; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "InformInfoRecord " + "IS EXPECTED ERROR ^^^^\n"); + } + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfoRecord " + "Sending a Good - Empty GetTable request\n"); + memset(&context, 0, sizeof(context)); + status = + osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO_RECORD, + IB_MAD_METHOD_GETTABLE, + &inform_info_rec_opt, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* InformInfo tests */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfo " + "Sending a BAD - Empty Get request " + "(should fail with NO_RECORDS)\n"); + memset(&context, 0, sizeof(context)); + status = osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO, + IB_MAD_METHOD_GET, &inform_info_opt, + &context); + if (status == IB_SUCCESS) { + status = IB_ERROR; + goto Exit; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "InformInfo " + "IS EXPECTED ERROR ^^^^\n"); + } + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfo " + "Sending a BAD - Set Unsubscribe request\n"); + memset(&context, 0, sizeof(context)); + status = osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO, + IB_MAD_METHOD_SET, &inform_info_opt, + &context); + if (status == IB_SUCCESS) { + status = IB_ERROR; + goto Exit; + } else { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "InformInfo UnSubscribe " + "IS EXPECTED ERROR ^^^^\n"); + } + + /* Now subscribe */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfo " + "Sending a Good - Set Subscribe request\n"); + inform_info_opt.subscribe = TRUE; + memset(&context, 0, sizeof(context)); + status = osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO, + IB_MAD_METHOD_SET, &inform_info_opt, + &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Now unsubscribe (QPN needs to be 1 to work) */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfo " + "Sending a Good - Set Unsubscribe request\n"); + inform_info_opt.subscribe = FALSE; + inform_info_opt.qpn = 1; + memset(&context, 0, sizeof(context)); + status = osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO, + IB_MAD_METHOD_SET, &inform_info_opt, + &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Now subscribe again */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfo " + "Sending a Good - Set Subscribe request\n"); + inform_info_opt.subscribe = TRUE; + inform_info_opt.qpn = 1; + memset(&context, 0, sizeof(context)); + status = osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO, + IB_MAD_METHOD_SET, &inform_info_opt, + &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Subscribe over existing subscription */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfo " + "Sending a Good - Set Subscribe (again) request\n"); + inform_info_opt.qpn = 0; + memset(&context, 0, sizeof(context)); + status = osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO, + IB_MAD_METHOD_SET, &inform_info_opt, + &context); + if (status != IB_SUCCESS) + goto Exit; + + /* More InformInfoRecord tests */ + /* RID lookup (with currently invalid enum) */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfoRecord " + "Sending a Good - GetTable by GID\n"); + ib_gid_set_default(&inform_info_rec_opt.subscriber_gid, + p_osmt->local_port.port_guid); + inform_info_rec_opt.subscriber_enum = 1; + memset(&context, 0, sizeof(context)); + status = + osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO_RECORD, + IB_MAD_METHOD_GETTABLE, + &inform_info_rec_opt, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Enum lookup */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfoRecord " + "Sending a Good - GetTable (subscriber_enum == 0) request\n"); + inform_info_rec_opt.subscriber_enum = 0; + memset(&context, 0, sizeof(context)); + status = + osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO_RECORD, + IB_MAD_METHOD_GETTABLE, + &inform_info_rec_opt, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Get all InformInfoRecords */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfoRecord " + "Sending a Good - GetTable (ALL records) request\n"); + memset(&inform_info_rec_opt, 0, sizeof(inform_info_rec_opt)); + memset(&context, 0, sizeof(context)); + status = + osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO_RECORD, + IB_MAD_METHOD_GETTABLE, + &inform_info_rec_opt, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Another subscription */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfo " + "Sending another Good - Set Subscribe (again) request\n"); + inform_info_opt.qpn = 0; + inform_info_opt.trap = 0x1234; + memset(&context, 0, sizeof(context)); + status = osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO, + IB_MAD_METHOD_SET, &inform_info_opt, + &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Get all InformInfoRecords again */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfoRecord " + "Sending a Good - GetTable (ALL records) request\n"); + memset(&inform_info_rec_opt, 0, sizeof(inform_info_rec_opt)); + memset(&context, 0, sizeof(context)); + status = + osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO_RECORD, + IB_MAD_METHOD_GETTABLE, + &inform_info_rec_opt, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Cleanup subscriptions before further testing */ + /* Does order of deletion matter ? Test this !!! */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfo " + "Sending a Good - Set (cleanup) request\n"); + inform_info_opt.subscribe = FALSE; + inform_info_opt.qpn = 1; + memset(&context, 0, sizeof(context)); + status = osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO, + IB_MAD_METHOD_SET, + &inform_info_opt, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Get all InformInfoRecords again */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfoRecord " + "Sending a Good - GetTable (ALL records) request\n"); + memset(&inform_info_rec_opt, 0, sizeof(inform_info_rec_opt)); + memset(&context, 0, sizeof(context)); + status = + osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO_RECORD, + IB_MAD_METHOD_GETTABLE, + &inform_info_rec_opt, &context); + if (status != IB_SUCCESS) + goto Exit; + + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfo" + "Sending a Good - Set (cleanup) request\n"); + inform_info_opt.subscribe = FALSE; + inform_info_opt.qpn = 1; + inform_info_opt.trap = 0; + memset(&context, 0, sizeof(context)); + status = osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO, + IB_MAD_METHOD_SET, + &inform_info_opt, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Get all InformInfoRecords a final time */ + OSM_LOG(&p_osmt->log, OSM_LOG_VERBOSE, "InformInfoRecord " + "Sending a Good - GetTable (ALL records) request\n"); + memset(&inform_info_rec_opt, 0, sizeof(inform_info_rec_opt)); + memset(&context, 0, sizeof(context)); + status = + osmtest_informinfo_request(p_osmt, IB_MAD_ATTR_INFORM_INFO_RECORD, + IB_MAD_METHOD_GETTABLE, + &inform_info_rec_opt, &context); + if (status != IB_SUCCESS) + goto Exit; + + if (lmc != 0) { + test_lid = cl_ntoh16(p_osmt->local_port.lid + 1); + + /* Another GUIDInfo Record test */ + memset(&context, 0, sizeof(context)); + status = + osmtest_get_guidinfo_rec_by_lid(p_osmt, test_lid, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Another PKeyTable Record test */ + memset(&context, 0, sizeof(context)); + status = + osmtest_get_pkeytbl_rec_by_lid(p_osmt, test_lid, sm_key, + &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Another SwitchInfo Record test */ + memset(&context, 0, sizeof(context)); + status = + osmtest_get_sw_info_rec_by_lid(p_osmt, test_lid, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Another LFT Record test */ + memset(&context, 0, sizeof(context)); + status = osmtest_get_lft_rec_by_lid(p_osmt, test_lid, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Another MFT Record test */ + memset(&context, 0, sizeof(context)); + status = osmtest_get_mft_rec_by_lid(p_osmt, test_lid, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* More LinkRecord tests */ + /* FromLID */ + memset(&context, 0, sizeof(context)); + status = + osmtest_get_link_rec_by_lid(p_osmt, test_lid, 0, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* ToLID */ + memset(&context, 0, sizeof(context)); + status = + osmtest_get_link_rec_by_lid(p_osmt, 0, test_lid, &context); + if (status != IB_SUCCESS) + goto Exit; + + /* Another NodeRecord test */ + memset(&context, 0, sizeof(context)); + status = + osmtest_get_node_rec_by_lid(p_osmt, test_lid, &context); + if (status != IB_SUCCESS) + goto Exit; + } + + /* PathRecords */ + if (!p_osmt->opt.ignore_path_records) { + status = osmtest_validate_all_path_recs(p_osmt); + if (status != IB_SUCCESS) + goto Exit; + + if (lmc != 0) { + memset(&context, 0, sizeof(context)); + status = + osmtest_get_path_rec_by_lid_pair(p_osmt, test_lid, + test_lid, + &context); + if (status != IB_SUCCESS) + goto Exit; + + memset(&context, 0, sizeof(context)); + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + EXPECTING_ERRORS_START "\n"); + status = + osmtest_get_path_rec_by_lid_pair(p_osmt, 0xffff, + 0xffff, &context); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Got error %s\n", + ib_get_err_str(status)); + } + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + EXPECTING_ERRORS_END "\n"); + + if (status == IB_SUCCESS) { + status = IB_ERROR; + goto Exit; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + EXPECTING_ERRORS_START "\n"); + + status = + osmtest_get_path_rec_by_lid_pair(p_osmt, test_lid, + 0xffff, &context); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "Got error %s\n", + ib_get_err_str(status)); + } + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + EXPECTING_ERRORS_END "\n"); + + if (status == IB_SUCCESS) { + status = IB_ERROR; + goto Exit; + } + } + } +#endif + + status = osmtest_validate_single_port_recs(p_osmt); + if (status != IB_SUCCESS) + goto Exit; + + if (!p_osmt->opt.ignore_path_records) { + status = osmtest_validate_single_path_recs(p_osmt); + if (status != IB_SUCCESS) + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static const osmtest_token_t *str_get_token(IN char *const p_str) +{ + const osmtest_token_t *p_tok; + uint32_t index = 0; + + p_tok = &token_array[index]; + + while (p_tok->val != OSMTEST_TOKEN_UNKNOWN) { + if (strnicmp(p_str, p_tok->str, p_tok->str_size) == 0) + return (p_tok); + + p_tok = &token_array[++index]; + } + + return (NULL); +} + +/********************************************************************** + Returns true if not whitespace character encountered before EOL. +**********************************************************************/ +static boolean_t +str_skip_white(IN char line[], IN OUT uint32_t * const p_offset) +{ + while (((line[*p_offset] == '\t') || + (line[*p_offset] == ' ')) && + (line[*p_offset] != '\n') && (line[*p_offset] != '\0')) { + ++*p_offset; + } + + if ((line[*p_offset] == '\n') || (line[*p_offset] == '\0')) + return (FALSE); + else + return (TRUE); +} + +/********************************************************************** + Returns true if not whitespace character encountered before EOL. +**********************************************************************/ +static void str_skip_token(IN char line[], IN OUT uint32_t * const p_offset) +{ + while ((line[*p_offset] != '\t') && + (line[*p_offset] != ' ') && (line[*p_offset] != '\0')) { + ++*p_offset; + } +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_parse_node(IN osmtest_t * const p_osmt, + IN FILE * const fh, IN OUT uint32_t * const p_line_num) +{ + ib_api_status_t status = IB_SUCCESS; + uint32_t offset; + char line[OSMTEST_MAX_LINE_LEN]; + boolean_t done = FALSE; + node_t *p_node; + node_t *p_guid_node; + const osmtest_token_t *p_tok; + + OSM_LOG_ENTER(&p_osmt->log); + + p_node = node_new(); + CL_ASSERT(p_node != NULL); + + /* + * Parse the inventory file and create the database. + */ + while (!done) { + if (fgets(line, OSMTEST_MAX_LINE_LEN, fh) == NULL) { + /* + * End of file in the middle of a definition. + */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0119: " + "Unexpected end of file\n"); + status = IB_ERROR; + goto Exit; + } + + ++*p_line_num; + + /* + * Skip whitespace + */ + offset = 0; + if (!str_skip_white(line, &offset)) + continue; /* whole line was whitespace */ + + p_tok = str_get_token(&line[offset]); + if (p_tok == NULL) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0120: " + "Ignoring line %u with unknown token: %s\n", + *p_line_num, &line[offset]); + continue; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "Found '%s' (line %u)\n", p_tok->str, *p_line_num); + + str_skip_token(line, &offset); + + switch (p_tok->val) { + case OSMTEST_TOKEN_COMMENT: + break; + + case OSMTEST_TOKEN_LID: + p_node->comp.lid = 0xFFFF; + p_node->rec.lid = + cl_hton16((uint16_t) + strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "lid = 0x%X\n", + cl_ntoh16(p_node->rec.lid)); + break; + + case OSMTEST_TOKEN_BASE_VERSION: + p_node->comp.node_info.base_version = 0xFF; + p_node->rec.node_info.base_version = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "base_version = 0x%X\n", + p_node->rec.node_info.base_version); + break; + + case OSMTEST_TOKEN_CLASS_VERSION: + p_node->comp.node_info.class_version = 0xFF; + p_node->rec.node_info.class_version = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "class_version = 0x%X\n", + p_node->rec.node_info.class_version); + break; + + case OSMTEST_TOKEN_NODE_TYPE: + p_node->comp.node_info.node_type = 0xFF; + p_node->rec.node_info.node_type = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "node_type = 0x%X\n", + p_node->rec.node_info.node_type); + break; + + case OSMTEST_TOKEN_NUM_PORTS: + p_node->comp.node_info.num_ports = 0xFF; + p_node->rec.node_info.num_ports = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "num_ports = 0x%X\n", + p_node->rec.node_info.num_ports); + break; + + case OSMTEST_TOKEN_SYS_GUID: + p_node->comp.node_info.sys_guid = 0xFFFFFFFFFFFFFFFFULL; + p_node->rec.node_info.sys_guid = + cl_hton64(strtoull(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "sys_guid = 0x%016" PRIx64 "\n", + cl_ntoh64(p_node->rec.node_info.sys_guid)); + break; + + case OSMTEST_TOKEN_NODE_GUID: + p_node->comp.node_info.node_guid = + 0xFFFFFFFFFFFFFFFFULL; + p_node->rec.node_info.node_guid = + cl_hton64(strtoull(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "node_guid = 0x%016" PRIx64 "\n", + cl_ntoh64(p_node->rec.node_info.node_guid)); + break; + + case OSMTEST_TOKEN_PORT_GUID: + p_node->comp.node_info.port_guid = + 0xFFFFFFFFFFFFFFFFULL; + p_node->rec.node_info.port_guid = + cl_hton64(strtoull(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "port_guid = 0x%016" PRIx64 "\n", + cl_ntoh64(p_node->rec.node_info.port_guid)); + break; + + case OSMTEST_TOKEN_PARTITION_CAP: + p_node->comp.node_info.partition_cap = 0xFFFF; + p_node->rec.node_info.partition_cap = + cl_hton16((uint16_t) + strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "partition_cap = 0x%X\n", + cl_ntoh16(p_node->rec.node_info.partition_cap)); + break; + + case OSMTEST_TOKEN_DEVICE_ID: + p_node->comp.node_info.device_id = 0xFFFF; + p_node->rec.node_info.device_id = cl_hton16((uint16_t) + strtoul + (&line + [offset], + NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "device_id = 0x%X\n", + cl_ntoh16(p_node->rec.node_info.device_id)); + break; + + case OSMTEST_TOKEN_REVISION: + p_node->comp.node_info.revision = 0xFFFFFFFF; + p_node->rec.node_info.revision = + cl_hton32(strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "revision = 0x%X\n", + cl_ntoh32(p_node->rec.node_info.revision)); + break; + + case OSMTEST_TOKEN_PORT_NUM: + p_node->comp.node_info.port_num_vendor_id |= + IB_NODE_INFO_PORT_NUM_MASK; + p_node->rec.node_info.port_num_vendor_id |= + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "local_port_num = 0x%X\n", + ib_node_info_get_local_port_num + (&p_node->rec.node_info)); + break; + + case OSMTEST_TOKEN_VENDOR_ID: + p_node->comp.node_info.port_num_vendor_id |= + IB_NODE_INFO_VEND_ID_MASK; + p_node->rec.node_info.port_num_vendor_id |= + cl_hton32(strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "vendor_id = 0x%X\n", + cl_ntoh32(ib_node_info_get_vendor_id + (&p_node->rec.node_info))); + break; + + case OSMTEST_TOKEN_END: + done = TRUE; + break; + + default: + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0121: " + "Ignoring line %u with unknown token: %s\n", + *p_line_num, &line[offset]); + + break; + } + } + + /* + * Make sure the user specified enough information, then + * add this object to the database. + */ + if (p_node->comp.lid == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0122: " + "LID must be specified for defined nodes\n"); + node_delete(p_node); + goto Exit; + } + + cl_qmap_insert(&p_osmt->exp_subn.node_lid_tbl, + p_node->rec.lid, &p_node->map_item); + + p_guid_node = node_new(); + CL_ASSERT(p_node != NULL); + + *p_guid_node = *p_node; + + cl_qmap_insert(&p_osmt->exp_subn.node_guid_tbl, + p_guid_node->rec.node_info.node_guid, + &p_guid_node->map_item); + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_parse_port(IN osmtest_t * const p_osmt, + IN FILE * const fh, IN OUT uint32_t * const p_line_num) +{ + ib_api_status_t status = IB_SUCCESS; + uint32_t offset; + char line[OSMTEST_MAX_LINE_LEN]; + boolean_t done = FALSE; + port_t *p_port; + const osmtest_token_t *p_tok; + + OSM_LOG_ENTER(&p_osmt->log); + + p_port = port_new(); + CL_ASSERT(p_port != NULL); + + /* + * Parse the inventory file and create the database. + */ + while (!done) { + if (fgets(line, OSMTEST_MAX_LINE_LEN, fh) == NULL) { + /* + * End of file in the middle of a definition. + */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0123: " + "Unexpected end of file\n"); + status = IB_ERROR; + goto Exit; + } + + ++*p_line_num; + + /* + * Skip whitespace + */ + offset = 0; + if (!str_skip_white(line, &offset)) + continue; /* whole line was whitespace */ + + p_tok = str_get_token(&line[offset]); + if (p_tok == NULL) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0124: " + "Ignoring line %u with unknown token: %s\n", + *p_line_num, &line[offset]); + continue; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "Found '%s' (line %u)\n", p_tok->str, *p_line_num); + + str_skip_token(line, &offset); + + switch (p_tok->val) { + case OSMTEST_TOKEN_COMMENT: + break; + + case OSMTEST_TOKEN_LID: + p_port->comp.lid = 0xFFFF; + p_port->rec.lid = + cl_hton16((uint16_t) + strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "lid = 0x%X\n", + cl_ntoh16(p_port->rec.lid)); + break; + + case OSMTEST_TOKEN_PORT_NUM: + p_port->comp.port_num = 0xFF; + p_port->rec.port_num = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "port_num = 0x%u\n", p_port->rec.port_num); + break; + + case OSMTEST_TOKEN_MKEY: + p_port->comp.port_info.m_key = 0xFFFFFFFFFFFFFFFFULL; + p_port->rec.port_info.m_key = + cl_hton64(strtoull(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "m_key = 0x%016" PRIx64 "\n", + cl_ntoh64(p_port->rec.port_info.m_key)); + break; + + case OSMTEST_TOKEN_SUBN_PREF: + p_port->comp.port_info.subnet_prefix = + 0xFFFFFFFFFFFFFFFFULL; + p_port->rec.port_info.subnet_prefix = + cl_hton64(strtoull(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "subnet_prefix = 0x%016" PRIx64 "\n", + cl_ntoh64(p_port->rec.port_info.subnet_prefix)); + break; + + case OSMTEST_TOKEN_BASE_LID: + p_port->comp.port_info.base_lid = 0xFFFF; + p_port->rec.port_info.base_lid = + cl_hton16((uint16_t) + strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "base_lid = 0x%X\n", + cl_ntoh16(p_port->rec.port_info.base_lid)); + break; + + case OSMTEST_TOKEN_SM_BASE_LID: + p_port->comp.port_info.master_sm_base_lid = 0xFFFF; + p_port->rec.port_info.master_sm_base_lid = + cl_hton16((uint16_t) + strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "master_sm_base_lid = 0x%X\n", + cl_ntoh16(p_port->rec.port_info.master_sm_base_lid)); + break; + + case OSMTEST_TOKEN_CAP_MASK: + p_port->comp.port_info.capability_mask = 0xFFFFFFFF; + p_port->rec.port_info.capability_mask = + cl_hton32((uint32_t) + strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "capability_mask = 0x%X\n", + cl_ntoh32(p_port->rec.port_info.capability_mask)); + break; + + case OSMTEST_TOKEN_DIAG_CODE: + p_port->comp.port_info.diag_code = 0xFFFF; + p_port->rec.port_info.diag_code = + cl_hton16((uint16_t) + strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "diag_code = 0x%X\n", + cl_ntoh16(p_port->rec.port_info.diag_code)); + break; + + case OSMTEST_TOKEN_MKEY_LEASE_PER: + p_port->comp.port_info.m_key_lease_period = 0xFFFF; + p_port->rec.port_info.m_key_lease_period = + cl_hton16((uint16_t) + strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "m_key_lease_period = 0x%X\n", + cl_ntoh16(p_port->rec.port_info.m_key_lease_period)); + break; + + case OSMTEST_TOKEN_LOC_PORT_NUM: + p_port->comp.port_info.local_port_num = 0xFF; + p_port->rec.port_info.local_port_num = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "local_port_num = 0x%u\n", + p_port->rec.port_info.local_port_num); + break; + + case OSMTEST_TOKEN_LINK_WID_EN: + p_port->comp.port_info.link_width_enabled = 0xFF; + p_port->rec.port_info.link_width_enabled = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "link_width_enabled = 0x%u\n", + p_port->rec.port_info.link_width_enabled); + break; + + case OSMTEST_TOKEN_LINK_WID_SUP: + p_port->comp.port_info.link_width_supported = 0xFF; + p_port->rec.port_info.link_width_supported = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "link_width_supported = 0x%u\n", + p_port->rec.port_info.link_width_supported); + break; + + case OSMTEST_TOKEN_LINK_WID_ACT: + p_port->comp.port_info.link_width_active = 0xFF; + p_port->rec.port_info.link_width_active = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "link_width_active = 0x%u\n", + p_port->rec.port_info.link_width_active); + break; + + case OSMTEST_TOKEN_LINK_SPEED_SUP: + p_port->comp.port_info.state_info1 = 0xFF; + ib_port_info_set_link_speed_sup((uint8_t) + strtoul(&line[offset], + NULL, 0), + &p_port->rec.port_info); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "link_speed_supported = 0x%u\n", + ib_port_info_get_link_speed_sup(&p_port->rec.port_info)); + break; + + case OSMTEST_TOKEN_PORT_STATE: + str_skip_white(line, &offset); + p_port->comp.port_info.state_info1 = 0xFF; + ib_port_info_set_port_state(&p_port->rec.port_info, + ib_get_port_state_from_str + (&line[offset])); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "port_state = 0x%u\n", + ib_port_info_get_port_state(&p_port->rec.port_info)); + break; + + case OSMTEST_TOKEN_STATE_INFO2: + p_port->comp.port_info.state_info2 = 0xFF; + p_port->rec.port_info.state_info2 = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "state_info2 = 0x%u\n", + p_port->rec.port_info.state_info2); + break; + + case OSMTEST_TOKEN_MKEY_PROT_BITS: + p_port->comp.port_info.mkey_lmc = 0xFF; + ib_port_info_set_mpb(&p_port->rec.port_info, + (uint8_t) strtoul(&line[offset], + NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "mpb = 0x%u\n", + ib_port_info_get_mpb(&p_port->rec.port_info)); + break; + + case OSMTEST_TOKEN_LMC: + p_port->comp.port_info.mkey_lmc = 0xFF; + ib_port_info_set_lmc(&p_port->rec.port_info, + (uint8_t) strtoul(&line[offset], + NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "lmc = 0x%u\n", + ib_port_info_get_lmc(&p_port->rec.port_info)); + break; + + case OSMTEST_TOKEN_LINK_SPEED: + p_port->comp.port_info.link_speed = 0xFF; + p_port->rec.port_info.link_speed = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "link_speed = 0x%u\n", + p_port->rec.port_info.link_speed); + break; + + case OSMTEST_TOKEN_MTU_SMSL: + p_port->comp.port_info.mtu_smsl = 0xFF; + p_port->rec.port_info.mtu_smsl = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "mtu_smsl = 0x%u\n", + p_port->rec.port_info.mtu_smsl); + break; + + case OSMTEST_TOKEN_VL_CAP: + p_port->comp.port_info.vl_cap = 0xFF; + p_port->rec.port_info.vl_cap = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "vl_cap = 0x%u\n", + p_port->rec.port_info.vl_cap); + break; + + case OSMTEST_TOKEN_VL_HIGH_LIMIT: + p_port->comp.port_info.vl_high_limit = 0xFF; + p_port->rec.port_info.vl_high_limit = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "vl_high_limit = 0x%u\n", + p_port->rec.port_info.vl_high_limit); + break; + + case OSMTEST_TOKEN_VL_ARB_HIGH_CAP: + p_port->comp.port_info.vl_arb_high_cap = 0xFF; + p_port->rec.port_info.vl_arb_high_cap = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "vl_arb_high_cap = 0x%u\n", + p_port->rec.port_info.vl_arb_high_cap); + break; + + case OSMTEST_TOKEN_VL_ARB_LOW_CAP: + p_port->comp.port_info.vl_arb_low_cap = 0xFF; + p_port->rec.port_info.vl_arb_low_cap = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "vl_arb_low_cap = 0x%u\n", + p_port->rec.port_info.vl_arb_low_cap); + break; + + case OSMTEST_TOKEN_MTU_CAP: + p_port->comp.port_info.mtu_cap = 0xFF; + p_port->rec.port_info.mtu_cap = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "mtu_cap = 0x%u\n", + p_port->rec.port_info.mtu_cap); + break; + + case OSMTEST_TOKEN_VL_STALL_LIFE: + p_port->comp.port_info.vl_stall_life = 0xFF; + p_port->rec.port_info.vl_stall_life = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "vl_stall_life = 0x%u\n", + p_port->rec.port_info.vl_stall_life); + break; + + case OSMTEST_TOKEN_VL_ENFORCE: + p_port->comp.port_info.vl_enforce = 0xFF; + p_port->rec.port_info.vl_enforce = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "vl_enforce = 0x%u\n", + p_port->rec.port_info.vl_enforce); + break; + + case OSMTEST_TOKEN_MKEY_VIOL: + p_port->comp.port_info.m_key_violations = 0xFFFF; + p_port->rec.port_info.m_key_violations = + cl_hton16((uint16_t) + strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "m_key_violations = 0x%X\n", + cl_ntoh16(p_port->rec.port_info.m_key_violations)); + break; + + case OSMTEST_TOKEN_PKEY_VIOL: + p_port->comp.port_info.p_key_violations = 0xFFFF; + p_port->rec.port_info.p_key_violations = + cl_hton16((uint16_t) + strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "p_key_violations = 0x%X\n", + cl_ntoh16(p_port->rec.port_info.p_key_violations)); + break; + + case OSMTEST_TOKEN_QKEY_VIOL: + p_port->comp.port_info.q_key_violations = 0xFFFF; + p_port->rec.port_info.q_key_violations = + cl_hton16((uint16_t) + strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "q_key_violations = 0x%X\n", + cl_ntoh16(p_port->rec.port_info.q_key_violations)); + break; + + case OSMTEST_TOKEN_GUID_CAP: + p_port->comp.port_info.guid_cap = 0xFF; + p_port->rec.port_info.guid_cap = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "guid_cap = 0x%u\n", + p_port->rec.port_info.guid_cap); + break; + + case OSMTEST_TOKEN_SUBN_TIMEOUT: + p_port->comp.port_info.subnet_timeout = 0x1F; + p_port->rec.port_info.subnet_timeout = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "subnet_timeout = 0x%u\n", + ib_port_info_get_timeout(&p_port->rec.port_info)); + break; + + case OSMTEST_TOKEN_RESP_TIME_VAL: + p_port->comp.port_info.resp_time_value = 0xFF; + p_port->rec.port_info.resp_time_value = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "resp_time_value = 0x%u\n", + p_port->rec.port_info.resp_time_value); + break; + + case OSMTEST_TOKEN_ERR_THRESHOLD: + p_port->comp.port_info.error_threshold = 0xFF; + p_port->rec.port_info.error_threshold = + (uint8_t) strtoul(&line[offset], NULL, 0); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "error_threshold = 0x%u\n", + p_port->rec.port_info.error_threshold); + break; + + case OSMTEST_TOKEN_END: + done = TRUE; + break; + + default: + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0125: " + "Ignoring line %u with unknown token: %s\n", + *p_line_num, &line[offset]); + break; + } + } + + /* + * Make sure the user specified enough information, then + * add this object to the database. + */ + if (p_port->comp.lid == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0126: " + "LID must be specified for defined ports\n"); + port_delete(p_port); + status = IB_ERROR; + goto Exit; + } + + cl_qmap_insert(&p_osmt->exp_subn.port_key_tbl, + port_gen_id(p_port->rec.lid, p_port->rec.port_num), + &p_port->map_item); + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_parse_path(IN osmtest_t * const p_osmt, + IN FILE * const fh, IN OUT uint32_t * const p_line_num) +{ + ib_api_status_t status = IB_SUCCESS; + uint32_t offset; + char line[OSMTEST_MAX_LINE_LEN]; + boolean_t done = FALSE; + path_t *p_path; + const osmtest_token_t *p_tok; + boolean_t got_error = FALSE; + + OSM_LOG_ENTER(&p_osmt->log); + + p_path = path_new(); + CL_ASSERT(p_path != NULL); + + /* + * Parse the inventory file and create the database. + */ + while (!done) { + if (fgets(line, OSMTEST_MAX_LINE_LEN, fh) == NULL) { + /* + * End of file in the middle of a definition. + */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0127: " + "Unexpected end of file\n"); + status = IB_ERROR; + goto Exit; + } + + ++*p_line_num; + + /* + * Skip whitespace + */ + offset = 0; + if (!str_skip_white(line, &offset)) + continue; /* whole line was whitespace */ + + p_tok = str_get_token(&line[offset]); + if (p_tok == NULL) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0128: " + "Ignoring line %u with unknown token: %s\n", + *p_line_num, &line[offset]); + got_error = TRUE; + continue; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "Found '%s' (line %u)\n", p_tok->str, *p_line_num); + + str_skip_token(line, &offset); + + switch (p_tok->val) { + case OSMTEST_TOKEN_COMMENT: + break; + + case OSMTEST_TOKEN_DGID: + p_path->comp.dgid.unicast.prefix = + 0xFFFFFFFFFFFFFFFFULL; + p_path->comp.dgid.unicast.interface_id = + 0xFFFFFFFFFFFFFFFFULL; + + str_skip_white(line, &offset); + p_path->rec.dgid.unicast.prefix = + cl_hton64(strtoull(&line[offset], NULL, 0)); + str_skip_token(line, &offset); + p_path->rec.dgid.unicast.interface_id = + cl_hton64(strtoull(&line[offset], NULL, 0)); + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "dgid = 0x%016" PRIx64 " 0x%016" PRIx64 "\n", + cl_ntoh64(p_path->rec.dgid.unicast.prefix), + cl_ntoh64(p_path->rec.dgid.unicast.interface_id)); + break; + + case OSMTEST_TOKEN_SGID: + p_path->comp.sgid.unicast.prefix = + 0xFFFFFFFFFFFFFFFFULL; + p_path->comp.sgid.unicast.interface_id = + 0xFFFFFFFFFFFFFFFFULL; + + str_skip_white(line, &offset); + p_path->rec.sgid.unicast.prefix = + cl_hton64(strtoull(&line[offset], NULL, 0)); + str_skip_token(line, &offset); + p_path->rec.sgid.unicast.interface_id = + cl_hton64(strtoull(&line[offset], NULL, 0)); + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "sgid = 0x%016" PRIx64 " 0x%016" PRIx64 "\n", + cl_ntoh64(p_path->rec.sgid.unicast.prefix), + cl_ntoh64(p_path->rec.sgid.unicast.interface_id)); + break; + + case OSMTEST_TOKEN_DLID: + p_path->comp.dlid = 0xFFFF; + p_path->rec.dlid = + cl_hton16((uint16_t) + strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "dlid = 0x%X\n", + cl_ntoh16(p_path->rec.dlid)); + break; + + case OSMTEST_TOKEN_SLID: + p_path->comp.slid = 0xFFFF; + p_path->rec.slid = + cl_hton16((uint16_t) + strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "slid = 0x%X\n", + cl_ntoh16(p_path->rec.slid)); + break; + + case OSMTEST_TOKEN_PKEY: + p_path->comp.pkey = 0xFFFF; + p_path->rec.pkey = + cl_hton16((uint16_t) + strtoul(&line[offset], NULL, 0)); + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, "pkey = 0x%X\n", + cl_ntoh16(p_path->rec.pkey)); + break; + + case OSMTEST_TOKEN_END: + done = TRUE; + break; + + default: + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0129: " + "Ignoring line %u with unknown token: %s\n", + *p_line_num, &line[offset]); + got_error = TRUE; + break; + } + } + + if (got_error) { + status = IB_ERROR; + goto Exit; + } + /* + * Make sure the user specified enough information, then + * add this object to the database. + */ + if (osmtest_path_rec_kay_is_valid(p_osmt, p_path) == FALSE) { + path_delete(p_path); + status = IB_ERROR; + goto Exit; + } + + cl_qmap_insert(&p_osmt->exp_subn.path_tbl, + osmtest_path_rec_key_get(&p_path->rec), + &p_path->map_item); + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t +osmtest_parse_link(IN osmtest_t * const p_osmt, + IN FILE * const fh, IN OUT uint32_t * const p_line_num) +{ + ib_api_status_t status = IB_SUCCESS; + uint32_t offset; + char line[OSMTEST_MAX_LINE_LEN]; + boolean_t done = FALSE; + const osmtest_token_t *p_tok; + boolean_t got_error = FALSE; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * Parse the inventory file and create the database. + */ + while (!done) { + if (fgets(line, OSMTEST_MAX_LINE_LEN, fh) == NULL) { + /* + * End of file in the middle of a definition. + */ + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 012A: " + "Unexpected end of file\n"); + status = IB_ERROR; + goto Exit; + } + + ++*p_line_num; + + /* + * Skip whitespace + */ + offset = 0; + if (!str_skip_white(line, &offset)) + continue; /* whole line was whitespace */ + + p_tok = str_get_token(&line[offset]); + if (p_tok == NULL) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 012B: " + "Ignoring line %u with unknown token: %s\n", + *p_line_num, &line[offset]); + got_error = TRUE; + continue; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "Found '%s' (line %u)\n", p_tok->str, *p_line_num); + + str_skip_token(line, &offset); + + switch (p_tok->val) { + case OSMTEST_TOKEN_FROMLID: + case OSMTEST_TOKEN_FROMPORTNUM: + case OSMTEST_TOKEN_TOPORTNUM: + case OSMTEST_TOKEN_TOLID: + /* For now */ + break; + + case OSMTEST_TOKEN_END: + done = TRUE; + break; + + default: + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 012C: " + "Ignoring line %u with unknown token: %s\n", + *p_line_num, &line[offset]); + got_error = TRUE; + break; + } + } + + if (got_error) + status = IB_ERROR; + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +static ib_api_status_t osmtest_create_db(IN osmtest_t * const p_osmt) +{ + FILE *fh; + ib_api_status_t status = IB_SUCCESS; + uint32_t offset; + char line[OSMTEST_MAX_LINE_LEN]; + uint32_t line_num = 0; + const osmtest_token_t *p_tok; + boolean_t got_error = FALSE; + + OSM_LOG_ENTER(&p_osmt->log); + + fh = fopen(p_osmt->opt.file_name, "r"); + if (fh == NULL) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0130: " + "Unable to open inventory file (%s)\n", + p_osmt->opt.file_name); + status = IB_ERROR; + goto Exit; + } + + /* + * Parse the inventory file and create the database. + */ + while (fgets(line, OSMTEST_MAX_LINE_LEN, fh) != NULL) { + line_num++; + + /* + * Skip whitespace + */ + offset = 0; + if (!str_skip_white(line, &offset)) + continue; /* whole line was whitespace */ + + p_tok = str_get_token(&line[offset]); + if (p_tok == NULL) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0131: " + "Ignoring line %u: %s\n", line_num, + &line[offset]); + got_error = TRUE; + continue; + } + + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "Found '%s' (line %u)\n", p_tok->str, line_num); + + switch (p_tok->val) { + case OSMTEST_TOKEN_COMMENT: + break; + + case OSMTEST_TOKEN_DEFINE_NODE: + status = osmtest_parse_node(p_osmt, fh, &line_num); + break; + + case OSMTEST_TOKEN_DEFINE_PORT: + status = osmtest_parse_port(p_osmt, fh, &line_num); + break; + + case OSMTEST_TOKEN_DEFINE_PATH: + status = osmtest_parse_path(p_osmt, fh, &line_num); + break; + + case OSMTEST_TOKEN_DEFINE_LINK: + status = osmtest_parse_link(p_osmt, fh, &line_num); + break; + + default: + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0132: " + "Ignoring line %u: %s\n", line_num, + &line[offset]); + got_error = TRUE; + break; + } + + if (got_error) + status = IB_ERROR; + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0133: " + "Bad status received during parsing (%s)\n", + ib_get_err_str(status)); + fclose(fh); + goto Exit; + } + } + + fclose(fh); + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + Returns the index in the local port attribute array for the + user's selection. +**********************************************************************/ +static uint32_t +osmtest_get_user_port(IN osmtest_t * const p_osmt, + IN const ib_port_attr_t p_attr_array[], + IN uint32_t const num_ports) +{ + uint32_t i; + uint32_t choice = 0; + boolean_t done_flag = FALSE; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * User needs prompting for the local port GUID with which + * to bind. + */ + + while (done_flag == FALSE) { + printf("\nChoose a local port number with which to bind:\n\n"); + for (i = 0; i < num_ports; i++) { + /* + * Print the index + 1 since by convention, port numbers + * start with 1 on host channel adapters. + */ + + printf("\t%u: GUID = 0x%8" PRIx64 + ", lid = 0x%04X, state = %s\n", i + 1, + cl_ntoh64(p_attr_array[i].port_guid), + p_attr_array[i].lid, + ib_get_port_state_str(p_attr_array[i]. + link_state)); + } + + printf("\nEnter choice (1-%u): ", i); + scanf("%u", &choice); + if (choice > num_ports) + printf("\nError: Lame choice!\n"); + else + done_flag = TRUE; + + } + printf("\n"); + OSM_LOG_EXIT(&p_osmt->log); + return (choice - 1); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t +osmtest_bind(IN osmtest_t * p_osmt, + IN uint16_t max_lid, IN ib_net64_t guid OPTIONAL) +{ + uint32_t port_index; + ib_api_status_t status; + uint32_t num_ports = GUID_ARRAY_SIZE; + ib_port_attr_t attr_array[GUID_ARRAY_SIZE]; + + OSM_LOG_ENTER(&p_osmt->log); + + /* + * Call the transport layer for a list of local port + * GUID values. + */ + status = osm_vendor_get_all_port_attr(p_osmt->p_vendor, + attr_array, &num_ports); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0134: " + "Failure getting local port attributes (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + if (guid == 0) { + /* + * User needs prompting for the local port GUID with which + * to bind. + */ + port_index = + osmtest_get_user_port(p_osmt, attr_array, num_ports); + + if (num_ports == 0) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0135: " + "No local ports. Unable to proceed\n"); + goto Exit; + } + guid = attr_array[port_index].port_guid; + } else { + for (port_index = 0; port_index < num_ports; port_index++) { + if (attr_array[port_index].port_guid == guid) + break; + } + + if (port_index == num_ports) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0136: " + "No local port with guid 0x%016" PRIx64 "\n", + cl_ntoh64(guid)); + status = IB_NOT_FOUND; + goto Exit; + } + } + + /* + * Copy the port info for the selected port. + */ + memcpy(&p_osmt->local_port, &attr_array[port_index], + sizeof(p_osmt->local_port)); + + /* bind to the SA */ + OSM_LOG(&p_osmt->log, OSM_LOG_DEBUG, + "Using port with SM LID:0x%04X\n", p_osmt->local_port.sm_lid); + p_osmt->max_lid = max_lid; + + p_osmt->h_bind = + osmv_bind_sa(p_osmt->p_vendor, &p_osmt->mad_pool, guid); + + if (p_osmt->h_bind == OSM_BIND_INVALID_HANDLE) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0137: " + "Unable to bind to SA\n"); + status = IB_ERROR; + goto Exit; + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} + +/********************************************************************** + **********************************************************************/ +ib_api_status_t osmtest_run(IN osmtest_t * const p_osmt) +{ + ib_api_status_t status = IB_SUCCESS; + + OSM_LOG_ENTER(&p_osmt->log); + + status = osmtest_validate_sa_class_port_info(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0138: " + "Could not obtain SA ClassPortInfo (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + if (p_osmt->opt.flow == OSMT_FLOW_CREATE_INVENTORY) { + /* + * Creating an inventory file with all nodes, ports and paths + */ + status = osmtest_create_inventory_file(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, "ERR 0139: " + "Inventory file create failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + } else { + if (p_osmt->opt.flow == OSMT_FLOW_STRESS_SA) { + /* + * Stress SA - flood the SA with queries + */ + switch (p_osmt->opt.stress) { + case 0: + case 1: /* small response SA query stress */ + status = osmtest_stress_small_rmpp(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0140: " + "Small RMPP stress test failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + break; + case 2: /* large response SA query stress */ + status = osmtest_stress_large_rmpp(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0141: " + "Large RMPP stress test failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + break; + case 3: /* large response Path Record SA query stress */ + status = osmtest_create_db(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0142: " + "Database creation failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + status = osmtest_stress_large_rmpp_pr(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0143: " + "Large RMPP stress test failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + break; + default: + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0144: " + "Unknown stress test value %u\n", + p_osmt->opt.stress); + break; + } + } else { + + /* + * Run normal validation tests. + */ + if (p_osmt->opt.flow == OSMT_FLOW_ALL || + p_osmt->opt.flow == OSMT_FLOW_VALIDATE_INVENTORY) { + /* + * Only validate the given inventory file + */ + status = osmtest_create_db(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0145: " + "Database creation failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + status = osmtest_validate_against_db(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0146: " + "SA validation database failure (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + } + + if (p_osmt->opt.flow == OSMT_FLOW_ALL) { + status = osmtest_wrong_sm_key_ignored(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0147: " + "Try wrong SM_Key failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + } + + if (p_osmt->opt.flow == OSMT_FLOW_ALL || + p_osmt->opt.flow == OSMT_FLOW_SERVICE_REGISTRATION) + { + /* + * run service registration, deregistration, and lease test + */ + status = osmt_run_service_records_flow(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0148: " + "Service Flow failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + } + + if (p_osmt->opt.flow == OSMT_FLOW_ALL || + p_osmt->opt.flow == OSMT_FLOW_EVENT_FORWARDING) { + /* + * Run event forwarding test + */ +#ifdef OSM_VENDOR_INTF_MTL + status = osmt_run_inform_info_flow(p_osmt); + + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0149: " + "Inform Info Flow failed: (%s)\n", + ib_get_err_str(status)); + goto Exit; + } +#else + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "The event forwarding flow " + "is not implemented yet!\n"); + status = IB_SUCCESS; + goto Exit; +#endif + } + + if (p_osmt->opt.flow == OSMT_FLOW_QOS) { + /* + * QoS info: dump VLArb and SLtoVL tables. + * Since it generates a huge file, we run it only + * if explicitly required to + */ + status = osmtest_create_db(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 014A: " + "Database creation failed (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + + status = + osmt_run_slvl_and_vlarb_records_flow + (p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0150: " + "Failed to get SLtoVL and VL Arbitration Tables (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + } + + if (p_osmt->opt.flow == OSMT_FLOW_TRAP) { + /* + * Run trap 64/65 flow (this flow requires running of external tool) + */ +#ifdef OSM_VENDOR_INTF_MTL + status = osmt_run_trap64_65_flow(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0151: " + "Trap 64/65 Flow failed: (%s)\n", + ib_get_err_str(status)); + goto Exit; + } +#else + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "The event forwarding flow " + "is not implemented yet!\n"); + status = IB_SUCCESS; + goto Exit; +#endif + } + + if (p_osmt->opt.flow == OSMT_FLOW_ALL || + p_osmt->opt.flow == OSMT_FLOW_MULTICAST) { + /* + * Multicast flow + */ + status = osmt_run_mcast_flow(p_osmt); + if (status != IB_SUCCESS) { + OSM_LOG(&p_osmt->log, OSM_LOG_ERROR, + "ERR 0152: " + "Multicast Flow failed: (%s)\n", + ib_get_err_str(status)); + goto Exit; + } + } + + OSM_LOG(&p_osmt->log, OSM_LOG_INFO, + "\n\n***************** ALL TESTS PASS *****************\n\n"); + + } + } + +Exit: + OSM_LOG_EXIT(&p_osmt->log); + return (status); +} diff --git a/contrib/ofed/management/opensm/scripts/opensm.init.in b/contrib/ofed/management/opensm/scripts/opensm.init.in new file mode 100644 index 000000000000..52293eb59e41 --- /dev/null +++ b/contrib/ofed/management/opensm/scripts/opensm.init.in @@ -0,0 +1,133 @@ +#!/bin/bash +# +# opensm: Manage OpenSM +# +# chkconfig: - 09 91 +# description: Manage OpenSM +# +### BEGIN INIT INFO +# Provides: opensm +# Required-Start: $syslog +# Default-Start: none +# Default-Stop: 0 1 6 +# Description: Manage OpenSM +### END INIT INFO +# +# Copyright (c) 2008 Voltaire, Inc. All rights reserved. +# Copyright 2006 PathScale, 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. + +prefix=@prefix@ +exec_prefix=@exec_prefix@ + +# Source function library. +if [[ -s /etc/init.d/functions ]]; then + . /etc/init.d/functions + rc_status() { :; } + rc_exit() { exit $RETVAL; } +fi +if [[ -s /etc/rc.status ]]; then + . /etc/rc.status + failure() { rc_status -v; } + success() { rc_status -v; } +fi + +CONFIG=@sysconfdir@/sysconfig/opensm +if [[ -s $CONFIG ]]; then + . $CONFIG +fi + +start () { + echo -n "Starting opensm: " + @sbindir@/opensm --daemon $OPTIONS > /dev/null + if [[ $RETVAL -eq 0 ]]; then + touch /var/lock/subsys/opensm + success + else + failure + fi + echo +} + +stop () { + echo -n "Shutting down opensm: " + killproc opensm + if [[ $RETVAL -eq 0 ]]; then + rm -f /var/lock/subsys/opensm + success + else + failure + fi + echo +} + +Xstatus () { + pid="`pidof opensm`" + ret=$? + if [ $ret -eq 0 ] ; then + echo "OpenSM is running... pid=$pid" + else + echo "OpenSM is not running." + fi +} + +restart() { + stop + start +} + +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + Xstatus + ;; + restart | force-reload | reload) + restart + ;; + try-restart | condrestart) + [ -e /var/lock/subsys/opensm ] && restart + ;; + resweep) + killall -HUP opensm + RETVAL=$? + ;; + rotatelog) + killall -USR1 opensm + RETVAL=$? + ;; + *) + echo $"Usage: $0 {start|stop|status|restart|reload|condrestart|resweep|rotatelog}" + RETVAL=1 + ;; +esac + +_rc_status_all=$RETVAL +rc_exit diff --git a/contrib/ofed/management/opensm/scripts/opensm.logrotate b/contrib/ofed/management/opensm/scripts/opensm.logrotate new file mode 100644 index 000000000000..e16e227aae4a --- /dev/null +++ b/contrib/ofed/management/opensm/scripts/opensm.logrotate @@ -0,0 +1,7 @@ +/var/log/opensm.log { + missingok + notifempty + copytruncate + weekly + compress +} diff --git a/contrib/ofed/management/opensm/scripts/opensm.sysconfig b/contrib/ofed/management/opensm/scripts/opensm.sysconfig new file mode 100644 index 000000000000..2cc02e65afd0 --- /dev/null +++ b/contrib/ofed/management/opensm/scripts/opensm.sysconfig @@ -0,0 +1,2 @@ +# It will be used for sldd.sh +OSM_HOSTS="" diff --git a/contrib/ofed/management/opensm/scripts/redhat-opensm.init.in b/contrib/ofed/management/opensm/scripts/redhat-opensm.init.in new file mode 100755 index 000000000000..9c222756b59e --- /dev/null +++ b/contrib/ofed/management/opensm/scripts/redhat-opensm.init.in @@ -0,0 +1,292 @@ +#!/bin/bash +# +# Bring up/down opensm +# +# chkconfig: - 15 85 +# description: Activates/Deactivates InfiniBand Subnet Manager +# +### BEGIN INIT INFO +# Provides: opensm +### END INIT INFO +# +# Copyright (c) 2008 Voltaire, Inc. All rights reserved. +# Copyright (c) 2006 Mellanox Technologies. 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. +# +# +# $Id: openib-1.0-opensm.init,v 1.5 2006/08/02 18:18:23 dledford Exp $ +# +# processname: @sbindir@/opensm +# config: @sysconfdir@/sysconfig/opensm +# pidfile: /var/run/opensm.pid + +prefix=@prefix@ +exec_prefix=@exec_prefix@ + +. /etc/rc.d/init.d/functions + +CONFIG=@sysconfdir@/sysconfig/opensm +if [ -f $CONFIG ]; then + . $CONFIG +fi + +prog=@sbindir@/opensm +bin=${prog##*/} + +# Handover daemon for updating guid2lid cache file +sldd_prog=@sbindir@/sldd.sh +sldd_bin=${sldd_prog##*/} +sldd_pid_file=/var/run/sldd.pid + +ACTION=$1 + +# Setting OpenSM start parameters +PID_FILE=/var/run/${bin}.pid +touch $PID_FILE + +if [[ -n "${OSM_HOSTS}" && $(echo -n ${OSM_HOSTS} | wc -w | tr -d '[:space:]') -gt 1 ]]; then + HONORE_GUID2LID="--honor_guid2lid" +fi + +######################################################################### + +start_sldd() +{ + if [ -f $sldd_pid_file ]; then + local line p + read line < $sldd_pid_file + for p in $line ; do + [ -z "${p//[0-9]/}" -a -d "/proc/$p" ] && sldd_pid="$sldd_pid $p" + done + fi + + if [ -z "$sldd_pid" ]; then + sldd_pid=`pidof -x $sldd_bin` + fi + + if [ -n "${sldd_pid:-}" ] ; then + kill -9 ${sldd_pid} > /dev/null 2>&1 + fi + + $sldd_prog > /dev/null 2>&1 & + sldd_pid=$! + + echo ${sldd_pid} > $sldd_pid_file + # Sleep is needed in order to update local gid2lid cache file before running opensm + sleep 3 +} + +stop_sldd() +{ + if [ -f $sldd_pid_file ]; then + local line p + read line < $sldd_pid_file + for p in $line ; do + [ -z "${p//[0-9]/}" -a -d "/proc/$p" ] && sldd_pid="$sldd_pid $p" + done + fi + + if [ -z "$sldd_pid" ]; then + sldd_pid=`pidof -x $sldd_bin` + fi + + if [ -n "${sldd_pid:-}" ] ; then + kill -15 ${sldd_pid} > /dev/null 2>&1 + fi + +} + +start() +{ + local OSM_PID= + + pid="" + + if [ -f $PID_FILE ]; then + local line p + read line < $PID_FILE + for p in $line ; do + [ -z "${p//[0-9]/}" -a -d "/proc/$p" ] && pid="$pid $p" + done + fi + + if [ -z "$pid" ]; then + pid=`pidof -o $$ -o $PPID -o %PPID -x $bin` + fi + + if [ -n "${pid:-}" ] ; then + echo $"${bin} (pid $pid) is already running..." + else + + if [ -n "${HONORE_GUID2LID}" ]; then + # Run sldd daemod + start_sldd + fi + + # Start opensm + echo -n "Starting IB Subnet Manager" + $prog --daemon ${HONORE_GUID2LID} ${OPTIONS} > /dev/null + cnt=0; alive=0 + while [ $cnt -lt 6 -a $alive -ne 1 ]; do + echo -n "."; + sleep 1 + alive=0 + OSM_PID=`pidof $prog` + if [ "$OSM_PID" != "" ]; then + alive=1 + fi + let cnt++; + done + + echo $OSM_PID > $PID_FILE + checkpid $OSM_PID + RC=$? + [ $RC -eq 0 ] && echo_success || echo_failure + [ $RC -eq 0 ] && touch /var/lock/subsys/opensm + echo + + fi +return $RC +} + +stop() +{ + local pid= + local pid1= + local pid2= + + # Stop sldd daemon + stop_sldd + + if [ -f $PID_FILE ]; then + local line p + read line < $PID_FILE + for p in $line ; do + [ -z "${p//[0-9]/}" -a -d "/proc/$p" ] && pid1="$pid1 $p" + done + fi + + pid2=`pidof -o $$ -o $PPID -o %PPID -x $bin` + + pid=`echo "$pid1 $pid2" | sed -e 's/\ /\n/g' | sort -n | uniq | sed -e 's/\n/\ /g'` + + if [ -n "${pid:-}" ] ; then + # Kill opensm + echo -n "Stopping IB Subnet Manager." + kill -15 $pid > /dev/null 2>&1 + cnt=0; alive=1 + while [ $cnt -lt 6 -a $alive -ne 0 ]; do + echo -n "."; + alive=0 + for p in $pid; do + if checkpid $p ; then alive=1; echo -n "-"; fi + done + let cnt++; + sleep $alive + done + + for p in $pid + do + while checkpid $p ; do + kill -KILL $p > /dev/null 2>&1 + echo -n "+" + sleep 1 + done + done + checkpid $pid + RC=$? + [ $RC -eq 0 ] && echo_failure || echo_success + echo + RC=$((! $RC)) + else + echo -n "Stopping IB Subnet Manager." + echo_failure + echo + RC=1 + fi + + # Remove pid file if any. + rm -f $PID_FILE + rm -f /var/lock/subsys/opensm + return $RC +} + +status() +{ + local pid + + # First try "pidof" + pid=`pidof -o $$ -o $PPID -o %PPID -x ${bin}` + if [ -n "$pid" ]; then + echo $"${bin} (pid $pid) is running..." + return 0 + fi + + # Next try "/var/run/opensm.pid" files + if [ -f $PID_FILE ] ; then + read pid < $PID_FILE + if [ -n "$pid" ]; then + echo $"${bin} dead but pid file $PID_FILE exists" + return 1 + fi + fi + echo $"${bin} is stopped" + return 3 +} + + + +case $ACTION in + start) + start + ;; + stop) + stop + ;; + restart) + stop + start + ;; + status) + status + ;; + condrestart) + pid=`pidof -o $$ -o $PPID -o %PPID -x $bin` + if [ -n "$pid" ]; then + stop + sleep 1 + start + fi + ;; + *) + echo + echo "Usage: `basename $0` {start|stop|restart|status}" + echo + exit 1 + ;; +esac + +RC=$? +exit $RC diff --git a/contrib/ofed/management/opensm/scripts/sldd.sh.in b/contrib/ofed/management/opensm/scripts/sldd.sh.in new file mode 100755 index 000000000000..f7635fe597a2 --- /dev/null +++ b/contrib/ofed/management/opensm/scripts/sldd.sh.in @@ -0,0 +1,246 @@ +#!/bin/bash +# +# Copyright (c) 2008 Voltaire, Inc. All rights reserved. +# Copyright (c) 2006 Mellanox Technologies. 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. +# +# + +# OpenSM found to have the following problem +# when handover is performed: +# If some of the cluster nodes are rebooted during the handover they loose their LID assignment. +# The reason for it is that the standby SM does not obey its own Guid to LID table +# and simply uses the discovered LIDs. If some nodes are not available for it +# their previous LID assignment is lost forever. + +# The idea is to use an external daemon that will distribute +# the semi-static LID assignment table from the master SM to all standby SMs. +# A standby SM, becoming a master . needs to obey the copied semi static LID assignment table. + +prefix=@prefix@ +exec_prefix=@exec_prefix@ + +CONFIG=@sysconfdir@/sysconfig/opensm +if [ -f $CONFIG ]; then + . $CONFIG +fi + +SLDD_DEBUG=${SLDD_DEBUG:-0} + +CACHE_FILE=${CACHE_FILE:-/var/cache/opensm/guid2lid} +CACHE_DIR=$(dirname ${CACHE_FILE}) +tmp_cache=${CACHE_FILE}.tmp + +PING='ping -w 1 -c 1' + +RCP=${RCP:-/usr/bin/scp} +RSH=${RSH:-/usr/bin/ssh} +IFCONFIG=${IFCONFIG:-'/sbin/ifconfig -a'} + +declare -i SLDD_DEBUG +RESCAN_TIME=${RESCAN_TIME:-60} + +if [ -z "${OSM_HOSTS}" ]; then + [ $SLDD_DEBUG -eq 1 ] && + echo "No OpenSM servers (OSM_HOSTS) configured for the IB subnet." + exit 0 +fi + + +declare -a arr_OSM_HOSTS +arr_OSM_HOSTS=(${OSM_HOSTS}) + +num_of_osm_hosts=${#arr_OSM_HOSTS[@]} + +if [ ${num_of_osm_hosts} -eq 1 ]; then + [ $SLDD_DEBUG -eq 1 ] && + echo "One OpenSM server configured in the IB subnet." && + echo "Nothing to be done for SLDD" + + exit 0 +fi + +trap 'trap_handler' 15 + +trap_handler() +{ + logger -i "SLDD: Exiting." + exit 0 +} + +is_alive() +{ + $PING $1 > /dev/null 2>&1 + return $? +} + +is_local() +{ + $IFCONFIG | grep -w "$1" > /dev/null 2>&1 + return $? +} + +update_remote_cache() +{ + /bin/rm -f ${CACHE_FILE}.upd + /bin/cp -a ${CACHE_FILE} ${CACHE_FILE}.upd + + [ $SLDD_DEBUG -eq 1 ] && + echo "Updating remote cache file" + + for host in ${OSM_HOSTS} + do + # Skip local host update + if [ "${host}" == "${local_host}" ]; then + continue + fi + + if is_alive $host; then + stat=$($RSH $host "/bin/mkdir -p ${CACHE_DIR} > /dev/null 2>&1; /bin/rm -f ${CACHE_FILE}.${local_host} > /dev/null 2>&1; echo \$?" | tr -d '[:space:]') + if [ "X${stat}" == "X0" ]; then + [ $SLDD_DEBUG -eq 1 ] && + echo "Updating $host" + logger -i "SLDD: updating $host with ${CACHE_FILE}" + $RCP ${CACHE_FILE}.upd ${host}:${CACHE_FILE}.${local_host} + /bin/cp ${CACHE_FILE}.upd ${CACHE_FILE}.${host} + else + [ $SLDD_DEBUG -eq 1 ] && + echo "$RSH to $host failed." + logger -i "SLDD: Failed to update $host with ${CACHE_FILE}. $RSH without password should be enabled" + exit 5 + fi + else + [ $SLDD_DEBUG -eq 1 ] && + echo "$host is down." + continue + fi + done +} + +get_latest_remote_cache() +{ + # Find most updated remote cache file (the suffix should be like ip address: *.*.*.*) + echo -n "$(/bin/ls -1t ${CACHE_FILE}.*.* 2> /dev/null | head -1)" +} + +get_largest_remote_cache() +{ + # Find largest (size) remote cache file (the suffix should be like ip address: *.*.*.*) + echo -n "$(/bin/ls -1S ${CACHE_FILE}.*.* 2> /dev/null | head -1)" +} + +swap_cache_files() +{ + /bin/rm -f ${CACHE_FILE}.old + /bin/mv ${CACHE_FILE} ${CACHE_FILE}.old + /bin/cp ${largest_remote_cache} ${CACHE_FILE} + touch ${CACHE_FILE}.tmp +} + +# Find local host in the osm hosts list +local_host="" +for host in ${OSM_HOSTS} +do + if is_local $host; then + local_host=${host} + fi +done + +# Get cache file info +declare -i new_size=0 +declare -i last_size=0 +declare -i largest_remote_cache_size=0 + +if [ -e ${CACHE_FILE} ]; then + last_size=$(du -b ${CACHE_FILE} | awk '{print$1}' | tr -d '[:space:]') +else + touch ${CACHE_FILE} ${CACHE_FILE}.tmp +fi + +# if [ ${last_size} -gt 0 ]; then +# # First time update +# update_remote_cache +# fi + +while true +do + if [ -s "${CACHE_FILE}" ]; then + new_size=$(du -b ${CACHE_FILE} | awk '{print$1}' | tr -d '[:space:]') + # Check if local cache file grew from its last version or the time stamp changed + if [ ${new_size} -gt ${last_size} ] + [ "$(/bin/ls -1t ${CACHE_FILE} ${CACHE_FILE}.tmp 2> /dev/null | head -1)" != "${CACHE_FILE}.tmp" ]; then + largest_remote_cache=$(get_largest_remote_cache) + if [[ -n "${largest_remote_cache}" && -s "${largest_remote_cache}" ]]; then + largest_remote_cache_size=$(du -b ${largest_remote_cache} 2> /dev/null | awk '{print$1}' | tr -d '[:space:]') + else + largest_remote_cache_size=0 + fi + + # Check if local cache file larger than remote chache file + if [ ${new_size} -gt ${largest_remote_cache_size} ]; then + [ $SLDD_DEBUG -eq 1 ] && + echo "Local cache file larger then remote. Update remote cache files" + last_size=${new_size} + update_remote_cache + continue + fi + fi + + largest_remote_cache=$(get_largest_remote_cache) + if [[ -n "${largest_remote_cache}" && -s "${largest_remote_cache}" ]]; then + largest_remote_cache_size=$(du -b ${largest_remote_cache} 2> /dev/null | awk '{print$1}' | tr -d '[:space:]') + else + largest_remote_cache_size=0 + fi + + # Update local cache file from remote + if [ ${largest_remote_cache_size} -gt ${new_size} ]; then + [ $SLDD_DEBUG -eq 1 ] && + echo "Local cache file shorter then remote. Use ${largest_remote_cache}" + logger -i "SLDD: updating local cache file with ${largest_remote_cache}" + swap_cache_files + last_size=${largest_remote_cache_size} + fi + + else # The local cache file is empty + [ $SLDD_DEBUG -eq 1 ] && + echo "${CACHE_FILE} is empty" + + largest_remote_cache=$(get_largest_remote_cache) + if [[ -n "${largest_remote_cache}" && -s "${largest_remote_cache}" ]]; then + # Copy it to the current cache + [ $SLDD_DEBUG -eq 1 ] && + echo "Local cache file is empty. Use ${largest_remote_cache}" + logger -i "SLDD: updating local cache file with ${largest_remote_cache}" + swap_cache_files + fi + + fi + + [ $SLDD_DEBUG -eq 1 ] && + echo "Sleeping ${RESCAN_TIME} seconds." + sleep ${RESCAN_TIME} + +done diff --git a/contrib/ofed/usr.bin/Makefile b/contrib/ofed/usr.bin/Makefile new file mode 100644 index 000000000000..aa27a51600d1 --- /dev/null +++ b/contrib/ofed/usr.bin/Makefile @@ -0,0 +1,7 @@ +.include + +SUBDIR = ibaddr ibnetdiscover ibping ibportstate ibroute ibsendtrap ibstat +SUBDIR += ibsysstat ibtracert opensm perfquery saquery +SUBDIR += sminfo smpdump smpquery vendstat + +.include diff --git a/contrib/ofed/usr.bin/Makefile.inc b/contrib/ofed/usr.bin/Makefile.inc new file mode 100644 index 000000000000..e6a0550b82d3 --- /dev/null +++ b/contrib/ofed/usr.bin/Makefile.inc @@ -0,0 +1,4 @@ +DIAGPATH= ${.CURDIR}/../../management/infiniband-diags +BINDIR?= /usr/bin +CFLAGS+= -I${.CURDIR}/../../include/infiniband +CFLAGS+= -I${.CURDIR}/../../management/opensm/include/ diff --git a/contrib/ofed/usr.bin/ibaddr/Makefile b/contrib/ofed/usr.bin/ibaddr/Makefile new file mode 100644 index 000000000000..b0af50064ffd --- /dev/null +++ b/contrib/ofed/usr.bin/ibaddr/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= ibaddr +SRCS= ibaddr.c ibdiag_common.c +LDADD= -libumad -libcommon -libmad +CFLAGS+= -I${DIAGPATH}/include +MAN= ibaddr.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/ibnetdiscover/Makefile b/contrib/ofed/usr.bin/ibnetdiscover/Makefile new file mode 100644 index 000000000000..1e6bc0e799fb --- /dev/null +++ b/contrib/ofed/usr.bin/ibnetdiscover/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= ibnetdiscover +SRCS= ibnetdiscover.c grouping.c ibdiag_common.c +LDADD= -libumad -libcommon -libmad -losmcomp +CFLAGS+= -pthread -I${DIAGPATH}/include +MAN= ibnetdiscover.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/ibping/Makefile b/contrib/ofed/usr.bin/ibping/Makefile new file mode 100644 index 000000000000..f152855c495b --- /dev/null +++ b/contrib/ofed/usr.bin/ibping/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= ibping +SRCS= ibping.c ibdiag_common.c +LDADD= -libumad -libcommon -libmad +CFLAGS+= -I${DIAGPATH}/include +MAN= ibping.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/ibportstate/Makefile b/contrib/ofed/usr.bin/ibportstate/Makefile new file mode 100644 index 000000000000..e6af8bc28249 --- /dev/null +++ b/contrib/ofed/usr.bin/ibportstate/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= ibportstate +SRCS= ibportstate.c ibdiag_common.c +LDADD= -libumad -libcommon -libmad +CFLAGS+= -I${DIAGPATH}/include +MAN= ibportstate.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/ibroute/Makefile b/contrib/ofed/usr.bin/ibroute/Makefile new file mode 100644 index 000000000000..bbbbda396075 --- /dev/null +++ b/contrib/ofed/usr.bin/ibroute/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= ibroute +SRCS= ibroute.c ibdiag_common.c +LDADD= -libumad -libcommon -libmad -losmcomp +CFLAGS+= -pthread -I${DIAGPATH}/include +MAN= ibroute.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/ibsendtrap/Makefile b/contrib/ofed/usr.bin/ibsendtrap/Makefile new file mode 100644 index 000000000000..183e58d488f3 --- /dev/null +++ b/contrib/ofed/usr.bin/ibsendtrap/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= ibsendtrap +SRCS= ibsendtrap.c ibdiag_common.c +LDADD= -libumad -libcommon -libmad +CFLAGS+= -I${DIAGPATH}/include +NO_MAN= true + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/ibstat/Makefile b/contrib/ofed/usr.bin/ibstat/Makefile new file mode 100644 index 000000000000..6c2c23c96a19 --- /dev/null +++ b/contrib/ofed/usr.bin/ibstat/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= ibstat +SRCS= ibstat.c +LDADD= -libumad -libcommon +CFLAGS+= -I${DIAGPATH}/include +MAN= ibstat.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/ibsysstat/Makefile b/contrib/ofed/usr.bin/ibsysstat/Makefile new file mode 100644 index 000000000000..974e015579e5 --- /dev/null +++ b/contrib/ofed/usr.bin/ibsysstat/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= ibsysstat +SRCS= ibsysstat.c ibdiag_common.c +LDADD= -libumad -libcommon -libmad +CFLAGS+= -I${DIAGPATH}/include +MAN= ibsysstat.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/ibtracert/Makefile b/contrib/ofed/usr.bin/ibtracert/Makefile new file mode 100644 index 000000000000..cbfae3e1c7e6 --- /dev/null +++ b/contrib/ofed/usr.bin/ibtracert/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= ibtracert +SRCS= ibtracert.c ibdiag_common.c +LDADD= -libumad -libcommon -libmad -losmcomp +CFLAGS+= -pthread -I${DIAGPATH}/include +MAN= ibtracert.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/opensm/Makefile b/contrib/ofed/usr.bin/opensm/Makefile new file mode 100644 index 000000000000..ae45eaa4a230 --- /dev/null +++ b/contrib/ofed/usr.bin/opensm/Makefile @@ -0,0 +1,40 @@ +# $FreeBSD$ + +.include "../Makefile.inc" + +OPENSM = ${.CURDIR}/../../management/opensm +.PATH: ${OPENSM}/opensm ${OPENSM}/man + +PROG= opensm + +SRCS= main.c osm_console_io.c osm_console.c osm_db_files.c +SRCS+= osm_db_pack.c osm_drop_mgr.c osm_inform.c osm_lid_mgr.c +SRCS+= osm_lin_fwd_rcv.c osm_link_mgr.c osm_mcast_fwd_rcv.c osm_mcast_mgr.c +SRCS+= osm_mcast_tbl.c osm_mcm_info.c osm_mcm_port.c osm_mtree.c +SRCS+= osm_multicast.c osm_node.c osm_node_desc_rcv.c osm_node_info_rcv.c +SRCS+= osm_opensm.c osm_pkey.c osm_pkey_mgr.c osm_pkey_rcv.c osm_port.c +SRCS+= osm_port_info_rcv.c osm_remote_sm.c osm_req.c osm_resp.c osm_sa.c +SRCS+= osm_sa_class_port_info.c osm_sa_informinfo.c osm_sa_lft_record.c +SRCS+= osm_sa_mft_record.c osm_sa_link_record.c osm_sa_mad_ctrl.c +SRCS+= osm_sa_mcmember_record.c osm_sa_node_record.c osm_sa_path_record.c +SRCS+= osm_sa_pkey_record.c osm_sa_portinfo_record.c osm_sa_guidinfo_record.c +SRCS+= osm_sa_multipath_record.c osm_sa_service_record.c osm_sa_slvl_record.c +SRCS+= osm_sa_sminfo_record.c osm_sa_vlarb_record.c osm_sa_sw_info_record.c +SRCS+= osm_service.c osm_slvl_map_rcv.c osm_sm.c osm_sminfo_rcv.c +SRCS+= osm_sm_mad_ctrl.c osm_sm_state_mgr.c osm_state_mgr.c osm_subnet.c +SRCS+= osm_sw_info_rcv.c osm_switch.c osm_prtn.c osm_prtn_config.c osm_qos.c +SRCS+= osm_router.c osm_trap_rcv.c osm_ucast_mgr.c osm_ucast_updn.c +SRCS+= osm_ucast_lash.c osm_ucast_file.c osm_ucast_ftree.c osm_vl15intf.c +SRCS+= osm_vl_arb_rcv.c st.c osm_perfmgr.c osm_perfmgr_db.c osm_event_plugin.c +SRCS+= osm_dump.c osm_ucast_cache.c osm_qos_parser_y.y osm_qos_parser_l.l +SRCS+= osm_qos_policy.c + +LDADD= -lopensm -losmvendor -losmcomp -libmad -libumad -libcommon +CFLAGS+= -pthread +CFLAGS+= -DVENDOR_RMPP_SUPPORT -DDUAL_SIDED_RMPP + +MAN= opensm.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/perfquery/Makefile b/contrib/ofed/usr.bin/perfquery/Makefile new file mode 100644 index 000000000000..792d575052e7 --- /dev/null +++ b/contrib/ofed/usr.bin/perfquery/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= perfquery +SRCS= perfquery.c ibdiag_common.c +LDADD= -libumad -libcommon -libmad +CFLAGS+= -I${DIAGPATH}/include +MAN= perfquery.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/saquery/Makefile b/contrib/ofed/usr.bin/saquery/Makefile new file mode 100644 index 000000000000..efb60366c597 --- /dev/null +++ b/contrib/ofed/usr.bin/saquery/Makefile @@ -0,0 +1,16 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= saquery +SRCS= saquery.c ibdiag_common.c +LDADD= -libumad -libcommon -libmad -losmcomp -losmvendor -lopensm +CFLAGS+= -I${DIAGPATH}/include +CFLAGS+= -DOSM_VENDOR_INTF_OPENIB -DVENDOR_RMPP_SUPPORT -DDUAL_SIDED_RMPP +CFLAGS+= -pthread +MAN= saquery.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/sminfo/Makefile b/contrib/ofed/usr.bin/sminfo/Makefile new file mode 100644 index 000000000000..90f98873c9ad --- /dev/null +++ b/contrib/ofed/usr.bin/sminfo/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= sminfo +SRCS= sminfo.c ibdiag_common.c +LDADD= -libumad -libcommon -libmad +CFLAGS+= -I${DIAGPATH}/include +MAN= sminfo.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/smpdump/Makefile b/contrib/ofed/usr.bin/smpdump/Makefile new file mode 100644 index 000000000000..4db68be51c26 --- /dev/null +++ b/contrib/ofed/usr.bin/smpdump/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= smpdump +SRCS= smpdump.c +LDADD= -libumad -libcommon -libmad +CFLAGS+= -I${DIAGPATH}/include +MAN= smpdump.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/smpquery/Makefile b/contrib/ofed/usr.bin/smpquery/Makefile new file mode 100644 index 000000000000..edfedd1e11d1 --- /dev/null +++ b/contrib/ofed/usr.bin/smpquery/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= smpquery +SRCS= smpquery.c ibdiag_common.c +LDADD= -libumad -libcommon -libmad -losmcomp +CFLAGS+= -pthread -I${DIAGPATH}/include +MAN= smpquery.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.bin/vendstat/Makefile b/contrib/ofed/usr.bin/vendstat/Makefile new file mode 100644 index 000000000000..bfca2c8848c5 --- /dev/null +++ b/contrib/ofed/usr.bin/vendstat/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include "../Makefile.inc" +.PATH: ${DIAGPATH}/src ${DIAGPATH}/man + +PROG= vendstat +SRCS= vendstat.c ibdiag_common.c +LDADD= -libumad -libcommon -libmad +CFLAGS+= -I${DIAGPATH}/include +MAN= vendstat.8 + +WARNS?= 1 + +.include diff --git a/contrib/ofed/usr.lib/Makefile b/contrib/ofed/usr.lib/Makefile new file mode 100644 index 000000000000..a26440b3beb6 --- /dev/null +++ b/contrib/ofed/usr.lib/Makefile @@ -0,0 +1,6 @@ +.include + +SUBDIR = libibcommon libibmad libibumad libibverbs libmlx4 libmthca +SUBDIR += libopensm libosmcomp libosmvendor libibcm librdmacm libsdp + +.include diff --git a/contrib/ofed/usr.lib/Makefile.inc b/contrib/ofed/usr.lib/Makefile.inc new file mode 100644 index 000000000000..67ef39fa2de9 --- /dev/null +++ b/contrib/ofed/usr.lib/Makefile.inc @@ -0,0 +1,17 @@ +IBMGMT= ${.CURDIR}/../../management +IBCOMMONDIR= ${IBMGMT}/libibcommon +IBMADDIR= ${IBMGMT}/libibmad +UMADDIR= ${IBMGMT}/libibumad +OPENSMDIR= ${IBMGMT}/opensm +COMPLIBDIR= ${OPENSMDIR}/complib +VENDORLIBDIR= ${OPENSMDIR}/libvendor +IBVERBSDIR= ${.CURDIR}/../../libibverbs +IBINC= ${.CURDIR}/../../include + +CFLAGS+= -I${.CURDIR} -I${IBINC}/infiniband +CFLAGS+= -I${IBCOMMONDIR}/include/infiniband +CFLAGS+= -I${IBMADDIR}/include/infiniband +CFLAGS+= -I${UMADDIR}/include/infiniband +CFLAGS+= -I${OPENSMDIR}/include +# CFLAGS+= -I${UMADDIR}/include +# CFLAGS+= -I${IBVERBSDIR}/include diff --git a/contrib/ofed/usr.lib/libibcm/Makefile b/contrib/ofed/usr.lib/libibcm/Makefile new file mode 100644 index 000000000000..fd9db835c34f --- /dev/null +++ b/contrib/ofed/usr.lib/libibcm/Makefile @@ -0,0 +1,23 @@ +# $FreeBSD$ + +SHLIBDIR?= /usr/lib + +.include +.include "../Makefile.inc" + +IBCMDIR= ${.CURDIR}/../../libibcm +IBSRCDIR= ${IBCMDIR}/src + +.PATH: ${IBSRCDIR} + +LIB= ibcm +SHLIB_MAJOR= 1 +NO_PROFILE= + +SRCS= cm.c +CFLAGS+= -I ${IBCMDIR}/include + +MAN= +VERSION_MAP= ${IBSRCDIR}/libibcm.map + +.include diff --git a/contrib/ofed/usr.lib/libibcommon/Makefile b/contrib/ofed/usr.lib/libibcommon/Makefile new file mode 100644 index 000000000000..7153ca10c362 --- /dev/null +++ b/contrib/ofed/usr.lib/libibcommon/Makefile @@ -0,0 +1,20 @@ +# $FreeBSD$ + +SHLIBDIR?= /usr/lib + +.include +.include "../Makefile.inc" + +IBSRCDIR= ${IBCOMMONDIR}/src + +.PATH: ${IBSRCDIR} + +LIB= ibcommon +SHLIB_MAJOR= 1 +NO_PROFILE= + +SRCS= sysfs.c util.c hash.c stack.c time.c + +VERSION_MAP= ${IBSRCDIR}/libibcommon.map + +.include diff --git a/contrib/ofed/usr.lib/libibmad/Makefile b/contrib/ofed/usr.lib/libibmad/Makefile new file mode 100644 index 000000000000..2fbb274fbd03 --- /dev/null +++ b/contrib/ofed/usr.lib/libibmad/Makefile @@ -0,0 +1,23 @@ +# $FreeBSD$ + +SHLIBDIR?= /usr/lib + +.include +.include "../Makefile.inc" + +IBSRCDIR= ${IBMADDIR}/src + +.PATH: ${IBSRCDIR} + +LIB= ibmad +SHLIB_MAJOR= 1 +NO_PROFILE= + +SRCS= dump.c fields.c gs.c mad.c portid.c register.c resolve.c rpc.c sa.c \ + serv.c smp.c vendor.c + +CFLAGS+= -DHAVE_CONFIG_H + +VERSION_MAP= ${IBSRCDIR}/libibmad.map + +.include diff --git a/contrib/ofed/usr.lib/libibmad/config.h b/contrib/ofed/usr.lib/libibmad/config.h new file mode 100644 index 000000000000..dc979c053726 --- /dev/null +++ b/contrib/ofed/usr.lib/libibmad/config.h @@ -0,0 +1 @@ +#include diff --git a/contrib/ofed/usr.lib/libibumad/Makefile b/contrib/ofed/usr.lib/libibumad/Makefile new file mode 100644 index 000000000000..2e2e258ba9d4 --- /dev/null +++ b/contrib/ofed/usr.lib/libibumad/Makefile @@ -0,0 +1,22 @@ +# $FreeBSD$ + +SHLIBDIR?= /usr/lib + +.include +.include "../Makefile.inc" + +IBSRCDIR= ${UMADDIR}/src + +.PATH: ${IBSRCDIR} + +LIB= ibumad +SHLIB_MAJOR= 1 +NO_PROFILE= + +SRCS= umad.c + +CFLAGS+= -DHAVE_CONFIG_H + +VERSION_MAP= ${IBSRCDIR}/libibumad.map + +.include diff --git a/contrib/ofed/usr.lib/libibumad/config.h b/contrib/ofed/usr.lib/libibumad/config.h new file mode 100644 index 000000000000..dc979c053726 --- /dev/null +++ b/contrib/ofed/usr.lib/libibumad/config.h @@ -0,0 +1 @@ +#include diff --git a/contrib/ofed/usr.lib/libibverbs/Makefile b/contrib/ofed/usr.lib/libibverbs/Makefile new file mode 100644 index 000000000000..8f45174d76d9 --- /dev/null +++ b/contrib/ofed/usr.lib/libibverbs/Makefile @@ -0,0 +1,39 @@ +# $FreeBSD$ + +SHLIBDIR?= /usr/lib + +.include +.include "../Makefile.inc" + +IBSRCDIR= ${IBVERBSDIR}/src +IBMANDIR= ${IBVERBSDIR}/man + +.PATH: ${IBSRCDIR} ${IBMANDIR} + +LIB= ibverbs +SHLIB_MAJOR= 1 +NO_PROFILE= + +SRCS= device.c init.c marshall.c verbs.c cmd.c enum_strs.c kern_abi.h \ + memory.c compat-1_0.c sysfs.c + +MAN= ibv_alloc_pd.3 ibv_asyncwatch.1 ibv_attach_mcast.3 ibv_create_ah.3 \ + ibv_create_ah_from_wc.3 ibv_create_comp_channel.3 ibv_create_cq.3 \ + ibv_create_qp.3 ibv_create_srq.3 ibv_devices.1 ibv_devinfo.1 \ + ibv_event_type_str.3 ibv_fork_init.3 ibv_get_async_event.3 \ + ibv_get_cq_event.3 ibv_get_device_guid.3 ibv_get_device_list.3 \ + ibv_get_device_name.3 ibv_modify_qp.3 ibv_modify_srq.3 \ + ibv_open_device.3 ibv_poll_cq.3 ibv_post_recv.3 ibv_post_send.3 \ + ibv_post_srq_recv.3 ibv_query_device.3 ibv_query_gid.3 \ + ibv_query_pkey.3 ibv_query_port.3 ibv_query_qp.3 ibv_query_srq.3 \ + ibv_rate_to_mult.3 ibv_rc_pingpong.1 ibv_reg_mr.3 ibv_req_notify_cq.3 \ + ibv_resize_cq.3 ibv_srq_pingpong.1 ibv_uc_pingpong.1 ibv_ud_pingpong.1 \ + ibv_query_xrc_rcv_qp.3 ibv_reg_xrc_rcv_qp.3 ibv_modify_xrc_rcv_qp.3 \ + verbs.7 ibv_create_xrc_rcv_qp.3 ibv_open_xrc_domain.3 + + +CFLAGS+= -DHAVE_CONFIG_H -DIBV_CONFIG_DIR=\"/etc/ibverbs/\" + +VERSION_MAP= ${IBSRCDIR}/libibverbs.map + +.include diff --git a/contrib/ofed/usr.lib/libibverbs/alloca.h b/contrib/ofed/usr.lib/libibverbs/alloca.h new file mode 100644 index 000000000000..b0311c066275 --- /dev/null +++ b/contrib/ofed/usr.lib/libibverbs/alloca.h @@ -0,0 +1,18 @@ +#ifndef _LIBIBVERBS_ALLOCA_H_ +#define _LIBIBVERBS_ALLOCA_H_ +#include +#include +#include + +#define strdupa(_s) \ +({ \ + char *_d; \ + int _len; \ + \ + _len = strlen(_s) + 1; \ + _d = alloca(_len); \ + if (_d) \ + memcpy(_d, _s, _len); \ + _d; \ +}) +#endif /* _LIBIBVERBS_ALLOCA_H_ */ diff --git a/contrib/ofed/usr.lib/libibverbs/config.h b/contrib/ofed/usr.lib/libibverbs/config.h new file mode 100644 index 000000000000..688ab16590bb --- /dev/null +++ b/contrib/ofed/usr.lib/libibverbs/config.h @@ -0,0 +1,2 @@ +#define _WITH_GETLINE +#include diff --git a/contrib/ofed/usr.lib/libmlx4/Makefile b/contrib/ofed/usr.lib/libmlx4/Makefile new file mode 100644 index 000000000000..0710a8ab832c --- /dev/null +++ b/contrib/ofed/usr.lib/libmlx4/Makefile @@ -0,0 +1,24 @@ +# $FreeBSD$ + +SHLIBDIR?= /usr/lib + +.include + +MLX4DIR= ${.CURDIR}/../../libmlx4 +IBVERBSDIR= ${.CURDIR}/../../libibverbs +MLXSRCDIR= ${MLX4DIR}/src + +.PATH: ${MLXSRCDIR} + +LIB= mlx4 +SHLIB_MAJOR= 1 +NO_PROFILE= + +SRCS= buf.c cq.c dbrec.c mlx4.c qp.c srq.c verbs.c + +CFLAGS+= -DHAVE_CONFIG_H +CFLAGS+= -I${.CURDIR} -I${MLXSRCDIR} -I${IBVERBSDIR}/include + +VERSION_MAP= ${MLXSRCDIR}/mlx4.map + +.include diff --git a/contrib/ofed/usr.lib/libmlx4/config.h b/contrib/ofed/usr.lib/libmlx4/config.h new file mode 100644 index 000000000000..a2350135ef60 --- /dev/null +++ b/contrib/ofed/usr.lib/libmlx4/config.h @@ -0,0 +1,4 @@ +#define HAVE_IBV_DONTFORK_RANGE +#define HAVE_IBV_DOFORK_RANGE +#define HAVE_IBV_REGISTER_DRIVER +#define HAVE_IBV_READ_SYSFS_FILE diff --git a/contrib/ofed/usr.lib/libmthca/Makefile b/contrib/ofed/usr.lib/libmthca/Makefile new file mode 100644 index 000000000000..525b0b6bf7d7 --- /dev/null +++ b/contrib/ofed/usr.lib/libmthca/Makefile @@ -0,0 +1,25 @@ +# $FreeBSD$ + +SHLIBDIR?= /usr/lib + +.include + +MTHCADIR= ${.CURDIR}/../../libmthca +IBVERBSDIR= ${.CURDIR}/../../libibverbs +MTHCASRCDIR= ${MTHCADIR}/src + +.PATH: ${MTHCASRCDIR} + +LIB= mthca +SHLIB_MAJOR= 1 +NO_PROFILE= + +SRCS= ah.c buf.c cq.c memfree.c mthca.c qp.c srq.c verbs.c + + +CFLAGS+= -DHAVE_CONFIG_H +CFLAGS+= -I${.CURDIR} -I${MTHCASRCDIR} -I${IBVERBSDIR}/include + +VERSION_MAP= ${MTHCASRCDIR}/mthca.map + +.include diff --git a/contrib/ofed/usr.lib/libmthca/config.h b/contrib/ofed/usr.lib/libmthca/config.h new file mode 100644 index 000000000000..564ebef33591 --- /dev/null +++ b/contrib/ofed/usr.lib/libmthca/config.h @@ -0,0 +1,9 @@ +#define HAVE_IBV_DONTFORK_RANGE +#define HAVE_IBV_DOFORK_RANGE +#define HAVE_IBV_REGISTER_DRIVER +#define HAVE_IBV_READ_SYSFS_FILE +#ifdef __LP64__ +#define SIZEOF_LONG 8 +#else +#define SIZEOF_LONG 4 +#endif diff --git a/contrib/ofed/usr.lib/libopensm/Makefile b/contrib/ofed/usr.lib/libopensm/Makefile new file mode 100644 index 000000000000..63f64191ec05 --- /dev/null +++ b/contrib/ofed/usr.lib/libopensm/Makefile @@ -0,0 +1,18 @@ +# $FreeBSD$ + +SHLIBDIR?= /usr/lib + +.include +.include "../Makefile.inc" + +.PATH: ${OPENSMDIR}/opensm + +LIB= opensm +SHLIB_MAJOR= 1 +NO_PROFILE= + +SRCS= osm_log.c osm_mad_pool.c osm_helper.c + +VERSION_MAP= ${OPENSMDIR}/opensm/libopensm.map + +.include diff --git a/contrib/ofed/usr.lib/libosmcomp/Makefile b/contrib/ofed/usr.lib/libosmcomp/Makefile new file mode 100644 index 000000000000..be53800bb754 --- /dev/null +++ b/contrib/ofed/usr.lib/libosmcomp/Makefile @@ -0,0 +1,21 @@ +# $FreeBSD$ + +SHLIBDIR?= /usr/lib + +.include +.include "../Makefile.inc" + +.PATH: ${COMPLIBDIR} + +LIB= osmcomp +SHLIB_MAJOR= 1 +NO_PROFILE= + +SRCS= cl_complib.c cl_dispatcher.c cl_event.c cl_event_wheel.c cl_list.c +SRCS+= cl_log.c cl_map.c cl_pool.c cl_ptr_vector.c cl_spinlock.c +SRCS+= cl_statustext.c cl_thread.c cl_threadpool.c cl_timer.c cl_vector.c +SRCS+= ib_statustext.c cl_nodenamemap.c + +VERSION_MAP= ${COMPLIBDIR}/libosmcomp.map + +.include diff --git a/contrib/ofed/usr.lib/libosmvendor/Makefile b/contrib/ofed/usr.lib/libosmvendor/Makefile new file mode 100644 index 000000000000..f45d821f4c05 --- /dev/null +++ b/contrib/ofed/usr.lib/libosmvendor/Makefile @@ -0,0 +1,20 @@ +# $FreeBSD$ + +SHLIBDIR?= /usr/lib + +.include +.include "../Makefile.inc" + +.PATH: ${VENDORLIBDIR} + +LIB= osmvendor +SHLIB_MAJOR= 1 +NO_PROFILE= + +SRCS= osm_vendor_ibumad.c osm_vendor_ibumad_sa.c + +CFLAGS+= -DOSM_VENDOR_INTF_OPENIB + +VERSION_MAP= ${VENDORLIBDIR}/libosmvendor.map + +.include diff --git a/contrib/ofed/usr.lib/librdmacm/Makefile b/contrib/ofed/usr.lib/librdmacm/Makefile new file mode 100644 index 000000000000..e171ce8089ac --- /dev/null +++ b/contrib/ofed/usr.lib/librdmacm/Makefile @@ -0,0 +1,33 @@ +# $FreeBSD$ + +SHLIBDIR?= /usr/lib + +.include + +RDMACMDIR= ${.CURDIR}/../../librdmacm +RDMASRCDIR= ${RDMACMDIR}/src +RDMAMANDIR= ${RDMACMDIR}/man + +.PATH: ${RDMASRCDIR} ${RDMAMANDIR} + +LIB= rdmacm +SHLIB_MAJOR= 1 +NO_PROFILE= + +SRCS= cma.c + +MAN= rdma_get_devices.3 mckey.1 rdma_get_dst_port.3 rdma_accept.3 +MAN+= rdma_get_local_addr.3 rdma_ack_cm_event.3 rdma_get_peer_addr.3 +MAN+= rdma_bind_addr.3 rdma_get_src_port.3 rdma_cm.7 rdma_join_multicast.3 +MAN+= rdma_connect.3 rdma_leave_multicast.3 rdma_create_event_channel.3 +MAN+= rdma_listen.3 rdma_create_id.3 rdma_migrate_id.3 rdma_create_qp.3 +MAN+= rdma_notify.3 rdma_destroy_event_channel.3 rdma_reject.3 +MAN+= rdma_destroy_id.3 rdma_resolve_addr.3 rdma_destroy_qp.3 +MAN+= rdma_resolve_route.3 rdma_disconnect.3 rdma_set_option.3 +MAN+= rdma_event_str.3 rping.1 rdma_free_devices.3 ucmatose.1 +MAN+= rdma_get_cm_event.3 udaddy.1 + + +VERSION_MAP= ${RDMASRCDIR}/librdmacm.map + +.include diff --git a/contrib/ofed/usr.lib/libsdp/Makefile b/contrib/ofed/usr.lib/libsdp/Makefile new file mode 100644 index 000000000000..e65b515060f5 --- /dev/null +++ b/contrib/ofed/usr.lib/libsdp/Makefile @@ -0,0 +1,21 @@ +# $FreeBSD$ + +SHLIBDIR?= /usr/lib + +.include + +SDPDIR= ${.CURDIR}/../../libsdp/src + +.PATH: ${SDPDIR} + +LIB= ibsdp +SHLIB_MAJOR= 1 +NO_PROFILE= +NO_MAN= + +SRCS= log.c match.c port.c config_parser.c config_scanner.c + +CFLAGS+= -DSYSCONFDIR=\"/etc\" +CFLAGS+= -I${OFEDSYS}/include + +.include diff --git a/etc/defaults/rc.conf b/etc/defaults/rc.conf index 703cebc0a969..42722b98fc87 100644 --- a/etc/defaults/rc.conf +++ b/etc/defaults/rc.conf @@ -647,6 +647,7 @@ bsdextended_script="/etc/rc.bsdextended" # Default mac_bsdextended(4) newsyslog_enable="YES" # Run newsyslog at startup. newsyslog_flags="-CN" # Newsyslog flags to create marked files mixer_enable="YES" # Run the sound mixer. +opensm_enable="NO" # Opensm(8) for infiniband devices defaults to off ############################################################## ### Jail Configuration ####################################### diff --git a/etc/mtree/BSD.include.dist b/etc/mtree/BSD.include.dist index 2d9fa2651dda..b227bdb30ca7 100644 --- a/etc/mtree/BSD.include.dist +++ b/etc/mtree/BSD.include.dist @@ -207,6 +207,16 @@ .. gssapi .. + infiniband + complib + .. + iba + .. + opensm + .. + vendor + .. + .. isofs cd9660 .. @@ -275,6 +285,8 @@ .. protocols .. + rdma + .. readline .. rpc diff --git a/etc/mtree/BSD.var.dist b/etc/mtree/BSD.var.dist index 9ad314bfef12..4481b10ada2d 100644 --- a/etc/mtree/BSD.var.dist +++ b/etc/mtree/BSD.var.dist @@ -22,6 +22,8 @@ /set gname=wheel backups .. + cache + .. crash .. cron diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile index 6f80b875c829..ed10b872ee68 100644 --- a/etc/rc.d/Makefile +++ b/etc/rc.d/Makefile @@ -42,6 +42,10 @@ FILES= DAEMON FILESYSTEMS LOGIN NETWORKING SERVERS \ ypset ypupdated ypxfrd \ zfs zvol +.if ${MK_OFED} != "no" +FILES+= opensm +.endif + .if ${MK_OPENSSH} != "no" FILES+= sshd .endif diff --git a/etc/rc.d/opensm b/etc/rc.d/opensm new file mode 100644 index 000000000000..310476be4d90 --- /dev/null +++ b/etc/rc.d/opensm @@ -0,0 +1,28 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: opensm +# BEFORE: netif +# REQUIRE: FILESYSTEMS + +. /etc/rc.subr + +name="opensm" +start_cmd="opensm_start" +rcvar="opensm_enable" + +command=/usr/bin/opensm +command_args="-B" + +opensm_start() +{ + for guid in `ibstat | grep "Port GUID" | cut -d ':' -f2`; do + [ -z "${rc_quiet}" ] && echo "Starting ${guid} opensm." + ${command} ${command_args} -g ${guid} >> /dev/null + done +} + +load_rc_config $name +run_rc_command $* diff --git a/share/mk/bsd.own.mk b/share/mk/bsd.own.mk index dc28a07dcf14..de482933da4a 100644 --- a/share/mk/bsd.own.mk +++ b/share/mk/bsd.own.mk @@ -430,7 +430,8 @@ MK_${var}:= yes GPIO \ HESIOD \ ICONV \ - IDEA + IDEA \ + OFED .if defined(WITH_${var}) && defined(WITHOUT_${var}) .error WITH_${var} and WITHOUT_${var} can't both be set. .endif diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 41ed4bfe8721..0925a21a3c1b 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -185,6 +185,9 @@ SUBDIR= ${_3dfx} \ mfi \ mii \ mlx \ + mlx4 \ + mlx4ib \ + mlxen \ ${_mly} \ mmc \ mmcsd \ @@ -195,6 +198,7 @@ SUBDIR= ${_3dfx} \ msdosfs_iconv \ ${_mse} \ msk \ + mthca \ mvs \ mwl \ mwlfw \ diff --git a/sys/modules/mlx4/Makefile b/sys/modules/mlx4/Makefile new file mode 100644 index 000000000000..8ea3340ed513 --- /dev/null +++ b/sys/modules/mlx4/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ +.PATH: ${.CURDIR}/../../ofed/drivers/net/mlx4 +KMOD = mlx4 +SRCS = device_if.h bus_if.h pci_if.h vnode_if.h +SRCS+= alloc.c catas.c cmd.c cq.c eq.c fw.c icm.c intf.c main.c mcg.c mr.c +SRCS+= pd.c port.c profile.c qp.c reset.c sense.c srq.c xrcd.c + +CFLAGS+= -I${.CURDIR}/../../ofed/drivers/net/mlx4 +CFLAGS+= -I${.CURDIR}/../../ofed/include/ +CFLAGS+= -DINET6 + +.include + +CFLAGS+= -Wno-cast-qual -Wno-pointer-arith -fms-extensions diff --git a/sys/modules/mlx4ib/Makefile b/sys/modules/mlx4ib/Makefile new file mode 100644 index 000000000000..5fe01e733a88 --- /dev/null +++ b/sys/modules/mlx4ib/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ +.PATH: ${.CURDIR}/../../ofed/drivers/infiniband/hw/mlx4 +KMOD = mlx4ib +SRCS = device_if.h bus_if.h pci_if.h vnode_if.h +SRCS+= ah.c cq.c doorbell.c mad.c main.c mr.c qp.c srq.c wc.c + +CFLAGS+= -I${.CURDIR}/../../ofed/include/ -DINET6 + +.include + +CFLAGS+= -Wno-cast-qual -Wno-pointer-arith -fms-extensions diff --git a/sys/modules/mlxen/Makefile b/sys/modules/mlxen/Makefile new file mode 100644 index 000000000000..b83b4a534be2 --- /dev/null +++ b/sys/modules/mlxen/Makefile @@ -0,0 +1,13 @@ +# $FreeBSD$ +.PATH: ${.CURDIR}/../../ofed/drivers/net/mlx4 +KMOD = mlxen +SRCS = device_if.h bus_if.h pci_if.h vnode_if.h +SRCS += en_cq.c en_frag.c en_main.c en_netdev.c en_port.c en_resources.c +SRCS += en_rx.c en_tx.c +CFLAGS+= -I${.CURDIR}/../../ofed/drivers/net/mlx4 +CFLAGS+= -I${.CURDIR}/../../ofed/include/ +CFLAGS+= -DINET6 + +.include + +CFLAGS+= -Wno-cast-qual -Wno-pointer-arith -fms-extensions diff --git a/sys/modules/mthca/Makefile b/sys/modules/mthca/Makefile new file mode 100644 index 000000000000..de860fe9df96 --- /dev/null +++ b/sys/modules/mthca/Makefile @@ -0,0 +1,15 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../ofed/drivers/infiniband/hw/mthca +KMOD = mthca +SRCS = device_if.h bus_if.h pci_if.h vnode_if.h +SRCS+= mthca_allocator.c mthca_av.c mthca_catas.c mthca_cmd.c mthca_cq.c +SRCS+= mthca_eq.c mthca_mad.c mthca_main.c mthca_mcg.c mthca_memfree.c +SRCS+= mthca_mr.c mthca_pd.c mthca_profile.c mthca_provider.c mthca_qp.c +SRCS+= mthca_reset.c mthca_srq.c mthca_uar.c + +CFLAGS+= -I${.CURDIR}/../../ofed/include/ -DINET6 + +.include + +CFLAGS+= -Wno-cast-qual -Wno-pointer-arith -fms-extensions diff --git a/sys/ofed/drivers/infiniband/Kconfig b/sys/ofed/drivers/infiniband/Kconfig new file mode 100644 index 000000000000..0a2ef113622c --- /dev/null +++ b/sys/ofed/drivers/infiniband/Kconfig @@ -0,0 +1,66 @@ +menuconfig INFINIBAND + tristate "InfiniBand support" + depends on PCI || BROKEN + depends on HAS_IOMEM + ---help--- + Core support for InfiniBand (IB). Make sure to also select + any protocols you wish to use as well as drivers for your + InfiniBand hardware. + +if INFINIBAND + +config INFINIBAND_USER_MAD + tristate "InfiniBand userspace MAD support" + depends on INFINIBAND + ---help--- + Userspace InfiniBand Management Datagram (MAD) support. This + is the kernel side of the userspace MAD support, which allows + userspace processes to send and receive MADs. You will also + need libibumad from . + +config INFINIBAND_USER_ACCESS + tristate "InfiniBand userspace access (verbs and CM)" + ---help--- + Userspace InfiniBand access support. This enables the + kernel side of userspace verbs and the userspace + communication manager (CM). This allows userspace processes + to set up connections and directly access InfiniBand + hardware for fast-path operations. You will also need + libibverbs, libibcm and a hardware driver library from + . + +config INFINIBAND_USER_MEM + bool + depends on INFINIBAND_USER_ACCESS != n + default y + +config INFINIBAND_ADDR_TRANS + bool + depends on INET + depends on !(INFINIBAND = y && IPV6 = m) + default y + +source "drivers/infiniband/hw/mthca/Kconfig" +source "drivers/infiniband/hw/ipath/Kconfig" +source "drivers/infiniband/hw/qib/Kconfig" +source "drivers/infiniband/hw/ehca/Kconfig" +source "drivers/infiniband/hw/amso1100/Kconfig" +source "drivers/infiniband/hw/cxgb3/Kconfig" +source "drivers/infiniband/hw/mlx4/Kconfig" +source "drivers/infiniband/hw/nes/Kconfig" + +source "drivers/infiniband/ulp/ipoib/Kconfig" + +source "drivers/infiniband/ulp/srp/Kconfig" + +source "drivers/infiniband/ulp/srpt/Kconfig" + +source "drivers/infiniband/ulp/iser/Kconfig" + +source "drivers/infiniband/ulp/sdp/Kconfig" + +source "drivers/infiniband/ulp/qlgc_vnic/Kconfig" + +source "drivers/infiniband/util/Kconfig" + +endif # INFINIBAND diff --git a/sys/ofed/drivers/infiniband/Makefile b/sys/ofed/drivers/infiniband/Makefile new file mode 100644 index 000000000000..ea5dbe0fda22 --- /dev/null +++ b/sys/ofed/drivers/infiniband/Makefile @@ -0,0 +1,17 @@ +obj-$(CONFIG_INFINIBAND) += core/ +obj-$(CONFIG_INFINIBAND_MTHCA) += hw/mthca/ +obj-$(CONFIG_INFINIBAND_IPATH) += hw/ipath/ +obj-$(CONFIG_INFINIBAND_QIB) += hw/qib/ +obj-$(CONFIG_INFINIBAND_EHCA) += hw/ehca/ +obj-$(CONFIG_INFINIBAND_AMSO1100) += hw/amso1100/ +obj-$(CONFIG_INFINIBAND_CXGB3) += hw/cxgb3/ +obj-$(CONFIG_INFINIBAND_NES) += hw/nes/ +obj-$(CONFIG_MLX4_INFINIBAND) += hw/mlx4/ +obj-$(CONFIG_INFINIBAND_NES) += hw/nes/ +obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/ +obj-$(CONFIG_INFINIBAND_SRP) += ulp/srp/ +obj-$(CONFIG_INFINIBAND_SRPT) += ulp/srpt/ +obj-$(CONFIG_INFINIBAND_ISER) += ulp/iser/ +obj-$(CONFIG_INFINIBAND_SDP) += ulp/sdp/ +obj-$(CONFIG_INFINIBAND_QLGC_VNIC) += ulp/qlgc_vnic/ +obj-$(CONFIG_INFINIBAND_MADEYE) += util/ diff --git a/sys/ofed/drivers/infiniband/core/Makefile b/sys/ofed/drivers/infiniband/core/Makefile new file mode 100644 index 000000000000..f64604019939 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/Makefile @@ -0,0 +1,32 @@ +infiniband-$(CONFIG_INFINIBAND_ADDR_TRANS) := ib_addr.o rdma_cm.o +user_access-$(CONFIG_INFINIBAND_ADDR_TRANS) := rdma_ucm.o + +obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o \ + ib_cm.o iw_cm.o $(infiniband-y) +obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o +obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o \ + $(user_access-y) + +ib_core-y := packer.o ud_header.o verbs.o sysfs.o \ + device.o fmr_pool.o cache.o +ib_core-$(CONFIG_INFINIBAND_USER_MEM) += umem.o + +ib_mad-y := mad.o smi.o agent.o mad_rmpp.o + +ib_sa-y := sa_query.o multicast.o notice.o local_sa.o + +ib_cm-y := cm.o + +iw_cm-y := iwcm.o + +rdma_cm-y := cma.o + +rdma_ucm-y := ucma.o + +ib_addr-y := addr.o + +ib_umad-y := user_mad.o + +ib_ucm-y := ucm.o + +ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o diff --git a/sys/ofed/drivers/infiniband/core/addr.c b/sys/ofed/drivers/infiniband/core/addr.c new file mode 100644 index 000000000000..cde40374759f --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/addr.c @@ -0,0 +1,630 @@ +/* + * Copyright (c) 2005 Voltaire Inc. All rights reserved. + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Sean Hefty"); +MODULE_DESCRIPTION("IB Address Translation"); +MODULE_LICENSE("Dual BSD/GPL"); + +struct addr_req { + struct list_head list; + struct sockaddr_storage src_addr; + struct sockaddr_storage dst_addr; + struct rdma_dev_addr *addr; + struct rdma_addr_client *client; + void *context; + void (*callback)(int status, struct sockaddr *src_addr, + struct rdma_dev_addr *addr, void *context); + unsigned long timeout; + int status; +}; + +static void process_req(struct work_struct *work); + +static DEFINE_MUTEX(lock); +static LIST_HEAD(req_list); +static struct delayed_work work; +static struct workqueue_struct *addr_wq; + +void rdma_addr_register_client(struct rdma_addr_client *client) +{ + atomic_set(&client->refcount, 1); + init_completion(&client->comp); +} +EXPORT_SYMBOL(rdma_addr_register_client); + +static inline void put_client(struct rdma_addr_client *client) +{ + if (atomic_dec_and_test(&client->refcount)) + complete(&client->comp); +} + +void rdma_addr_unregister_client(struct rdma_addr_client *client) +{ + put_client(client); + wait_for_completion(&client->comp); +} +EXPORT_SYMBOL(rdma_addr_unregister_client); + +#ifdef __linux__ +int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, + const unsigned char *dst_dev_addr) +{ + dev_addr->dev_type = dev->type; + memcpy(dev_addr->src_dev_addr, dev->dev_addr, MAX_ADDR_LEN); + memcpy(dev_addr->broadcast, dev->broadcast, MAX_ADDR_LEN); + if (dst_dev_addr) + memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN); + dev_addr->bound_dev_if = dev->ifindex; + return 0; +} +#else +int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct ifnet *dev, + const unsigned char *dst_dev_addr) +{ + if (dev->if_type == IFT_INFINIBAND) + dev_addr->dev_type = ARPHRD_INFINIBAND; + else if (dev->if_type == IFT_ETHER) + dev_addr->dev_type = ARPHRD_ETHER; + else + dev_addr->dev_type = 0; + memcpy(dev_addr->src_dev_addr, IF_LLADDR(dev), dev->if_addrlen); + memcpy(dev_addr->broadcast, __DECONST(char *, dev->if_broadcastaddr), + dev->if_addrlen); + if (dst_dev_addr) + memcpy(dev_addr->dst_dev_addr, dst_dev_addr, dev->if_addrlen); + dev_addr->bound_dev_if = dev->if_index; + return 0; +} +#endif +EXPORT_SYMBOL(rdma_copy_addr); + +int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) +{ + struct net_device *dev; + int ret = -EADDRNOTAVAIL; + + if (dev_addr->bound_dev_if) { + dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if); + if (!dev) + return -ENODEV; + ret = rdma_copy_addr(dev_addr, dev, NULL); + dev_put(dev); + return ret; + } + + switch (addr->sa_family) { + case AF_INET: + dev = ip_dev_find(NULL, + ((struct sockaddr_in *) addr)->sin_addr.s_addr); + + if (!dev) + return ret; + + ret = rdma_copy_addr(dev_addr, dev, NULL); + dev_put(dev); + break; + +#if defined(INET6) + case AF_INET6: +#ifdef __linux__ + read_lock(&dev_base_lock); + for_each_netdev(&init_net, dev) { + if (ipv6_chk_addr(&init_net, + &((struct sockaddr_in6 *) addr)->sin6_addr, + dev, 1)) { + ret = rdma_copy_addr(dev_addr, dev, NULL); + break; + } + } + read_unlock(&dev_base_lock); +#else + { + struct sockaddr_in6 *sin6; + struct ifaddr *ifa; + in_port_t port; + + sin6 = (struct sockaddr_in6 *)addr; + port = sin6->sin6_port; + sin6->sin6_port = 0; + ifa = ifa_ifwithaddr(addr); + sin6->sin6_port = port; + if (ifa == NULL) { + ret = -ENODEV; + break; + } + ret = rdma_copy_addr(dev_addr, ifa->ifa_ifp, NULL); + ifa_free(ifa); + break; + } +#endif + break; +#endif + } + return ret; +} +EXPORT_SYMBOL(rdma_translate_ip); + +static void set_timeout(unsigned long time) +{ + unsigned long delay; + + cancel_delayed_work(&work); + + delay = time - jiffies; + if ((long)delay <= 0) + delay = 1; + + queue_delayed_work(addr_wq, &work, delay); +} + +static void queue_req(struct addr_req *req) +{ + struct addr_req *temp_req; + + mutex_lock(&lock); + list_for_each_entry_reverse(temp_req, &req_list, list) { + if (time_after_eq(req->timeout, temp_req->timeout)) + break; + } + + list_add(&req->list, &temp_req->list); + + if (req_list.next == &req->list) + set_timeout(req->timeout); + mutex_unlock(&lock); +} + +#ifdef __linux__ +static int addr4_resolve(struct sockaddr_in *src_in, + struct sockaddr_in *dst_in, + struct rdma_dev_addr *addr) +{ + __be32 src_ip = src_in->sin_addr.s_addr; + __be32 dst_ip = dst_in->sin_addr.s_addr; + struct flowi fl; + struct rtable *rt; + struct neighbour *neigh; + int ret; + + memset(&fl, 0, sizeof fl); + fl.nl_u.ip4_u.daddr = dst_ip; + fl.nl_u.ip4_u.saddr = src_ip; + fl.oif = addr->bound_dev_if; + + ret = ip_route_output_key(&init_net, &rt, &fl); + if (ret) + goto out; + + src_in->sin_family = AF_INET; + src_in->sin_addr.s_addr = rt->rt_src; + + if (rt->idev->dev->flags & IFF_LOOPBACK) { + ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); + if (!ret) + memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN); + goto put; + } + + /* If the device does ARP internally, return 'done' */ + if (rt->idev->dev->flags & IFF_NOARP) { + rdma_copy_addr(addr, rt->idev->dev, NULL); + goto put; + } + + neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev); + if (!neigh || !(neigh->nud_state & NUD_VALID)) { + neigh_event_send(rt->u.dst.neighbour, NULL); + ret = -ENODATA; + if (neigh) + goto release; + goto put; + } + + ret = rdma_copy_addr(addr, neigh->dev, neigh->ha); +release: + neigh_release(neigh); +put: + ip_rt_put(rt); +out: + return ret; +} + +#if defined(INET6) +static int addr6_resolve(struct sockaddr_in6 *src_in, + struct sockaddr_in6 *dst_in, + struct rdma_dev_addr *addr) +{ + struct flowi fl; + struct neighbour *neigh; + struct dst_entry *dst; + int ret; + + memset(&fl, 0, sizeof fl); + ipv6_addr_copy(&fl.fl6_dst, &dst_in->sin6_addr); + ipv6_addr_copy(&fl.fl6_src, &src_in->sin6_addr); + fl.oif = addr->bound_dev_if; + + dst = ip6_route_output(&init_net, NULL, &fl); + if ((ret = dst->error)) + goto put; + + if (ipv6_addr_any(&fl.fl6_src)) { + ret = ipv6_dev_get_saddr(&init_net, ip6_dst_idev(dst)->dev, + &fl.fl6_dst, 0, &fl.fl6_src); + if (ret) + goto put; + + src_in->sin6_family = AF_INET6; + ipv6_addr_copy(&src_in->sin6_addr, &fl.fl6_src); + } + + if (dst->dev->flags & IFF_LOOPBACK) { + ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); + if (!ret) + memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN); + goto put; + } + + /* If the device does ARP internally, return 'done' */ + if (dst->dev->flags & IFF_NOARP) { + ret = rdma_copy_addr(addr, dst->dev, NULL); + goto put; + } + + neigh = dst->neighbour; + if (!neigh || !(neigh->nud_state & NUD_VALID)) { + neigh_event_send(dst->neighbour, NULL); + ret = -ENODATA; + goto put; + } + + ret = rdma_copy_addr(addr, dst->dev, neigh->ha); +put: + dst_release(dst); + return ret; +} +#else +static int addr6_resolve(struct sockaddr_in6 *src_in, + struct sockaddr_in6 *dst_in, + struct rdma_dev_addr *addr) +{ + return -EADDRNOTAVAIL; +} +#endif + +#else +#include + +static int addr_resolve(struct sockaddr *src_in, + struct sockaddr *dst_in, + struct rdma_dev_addr *addr) +{ + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + struct ifaddr *ifa; + struct ifnet *ifp; + struct llentry *lle; + struct rtentry *rte; + in_port_t port; + u_char edst[MAX_ADDR_LEN]; + int multi; + int bcast; + int error; + + /* + * Determine whether the address is unicast, multicast, or broadcast + * and whether the source interface is valid. + */ + multi = 0; + bcast = 0; + sin = NULL; + sin6 = NULL; + ifp = NULL; + rte = NULL; + switch (dst_in->sa_family) { + case AF_INET: + sin = (struct sockaddr_in *)dst_in; + if (sin->sin_addr.s_addr == INADDR_BROADCAST) + bcast = 1; + if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) + multi = 1; + sin = (struct sockaddr_in *)src_in; + if (sin->sin_addr.s_addr != INADDR_ANY) { + /* + * Address comparison fails if the port is set + * cache it here to be restored later. + */ + port = sin->sin_port; + sin->sin_port = 0; + memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); + } else + src_in = NULL; + break; +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *)dst_in; + if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) + multi = 1; + sin6 = (struct sockaddr_in6 *)src_in; + if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + port = sin6->sin6_port; + sin6->sin6_port = 0; + } else + src_in = NULL; + break; +#endif + default: + return -EINVAL; + } + /* + * If we have a source address to use look it up first and verify + * that it is a local interface. + */ + if (src_in) { + ifa = ifa_ifwithaddr(src_in); + if (sin) + sin->sin_port = port; + if (sin6) + sin6->sin6_port = port; + if (ifa == NULL) + return -ENETUNREACH; + ifp = ifa->ifa_ifp; + ifa_free(ifa); + if (bcast || multi) + goto mcast; + } + /* + * Make sure the route exists and has a valid link. + */ + rte = rtalloc1(dst_in, 1, 0); + if (rte == NULL || rte->rt_ifp == NULL || !RT_LINK_IS_UP(rte->rt_ifp)) { + if (rte) + RTFREE_LOCKED(rte); + return -EHOSTUNREACH; + } + /* + * If it's not multicast or broadcast and the route doesn't match the + * requested interface return unreachable. Otherwise fetch the + * correct interface pointer and unlock the route. + */ + if (multi || bcast) { + if (ifp == NULL) + ifp = rte->rt_ifp; + RTFREE_LOCKED(rte); + } else if (ifp && ifp != rte->rt_ifp) { + RTFREE_LOCKED(rte); + return -ENETUNREACH; + } else { + if (ifp == NULL) + ifp = rte->rt_ifp; + RT_UNLOCK(rte); + } +mcast: + if (bcast) + return rdma_copy_addr(addr, ifp, ifp->if_broadcastaddr); + if (multi) { + struct sockaddr *llsa; + + error = ifp->if_resolvemulti(ifp, &llsa, dst_in); + if (error) + return -error; + error = rdma_copy_addr(addr, ifp, + LLADDR((struct sockaddr_dl *)llsa)); + free(llsa, M_IFMADDR); + return error; + } + /* + * Resolve the link local address. + */ + if (dst_in->sa_family == AF_INET) + error = arpresolve(ifp, rte, NULL, dst_in, edst, &lle); +#ifdef INET6 + else + error = nd6_storelladdr(ifp, NULL, dst_in, (u_char *)edst, &lle); +#endif + RTFREE(rte); + if (error == 0) + return rdma_copy_addr(addr, ifp, edst); + if (error == EWOULDBLOCK) + return -ENODATA; + return -error; +} + +#endif + +static void process_req(struct work_struct *work) +{ + struct addr_req *req, *temp_req; + struct sockaddr *src_in, *dst_in; + struct list_head done_list; + + INIT_LIST_HEAD(&done_list); + + mutex_lock(&lock); + list_for_each_entry_safe(req, temp_req, &req_list, list) { + if (req->status == -ENODATA) { + src_in = (struct sockaddr *) &req->src_addr; + dst_in = (struct sockaddr *) &req->dst_addr; + req->status = addr_resolve(src_in, dst_in, req->addr); + if (req->status && time_after_eq(jiffies, req->timeout)) + req->status = -ETIMEDOUT; + else if (req->status == -ENODATA) + continue; + } + list_move_tail(&req->list, &done_list); + } + + if (!list_empty(&req_list)) { + req = list_entry(req_list.next, struct addr_req, list); + set_timeout(req->timeout); + } + mutex_unlock(&lock); + + list_for_each_entry_safe(req, temp_req, &done_list, list) { + list_del(&req->list); + req->callback(req->status, (struct sockaddr *) &req->src_addr, + req->addr, req->context); + put_client(req->client); + kfree(req); + } +} + +int rdma_resolve_ip(struct rdma_addr_client *client, + struct sockaddr *src_addr, struct sockaddr *dst_addr, + struct rdma_dev_addr *addr, int timeout_ms, + void (*callback)(int status, struct sockaddr *src_addr, + struct rdma_dev_addr *addr, void *context), + void *context) +{ + struct sockaddr *src_in, *dst_in; + struct addr_req *req; + int ret = 0; + + req = kzalloc(sizeof *req, GFP_KERNEL); + if (!req) + return -ENOMEM; + + src_in = (struct sockaddr *) &req->src_addr; + dst_in = (struct sockaddr *) &req->dst_addr; + + if (src_addr) { + if (src_addr->sa_family != dst_addr->sa_family) { + ret = -EINVAL; + goto err; + } + + memcpy(src_in, src_addr, ip_addr_size(src_addr)); + } else { + src_in->sa_family = dst_addr->sa_family; + } + + memcpy(dst_in, dst_addr, ip_addr_size(dst_addr)); + req->addr = addr; + req->callback = callback; + req->context = context; + req->client = client; + atomic_inc(&client->refcount); + + req->status = addr_resolve(src_in, dst_in, addr); + switch (req->status) { + case 0: + req->timeout = jiffies; + queue_req(req); + break; + case -ENODATA: + req->timeout = msecs_to_jiffies(timeout_ms) + jiffies; + queue_req(req); + break; + default: + ret = req->status; + atomic_dec(&client->refcount); + goto err; + } + return ret; +err: + kfree(req); + return ret; +} +EXPORT_SYMBOL(rdma_resolve_ip); + +void rdma_addr_cancel(struct rdma_dev_addr *addr) +{ + struct addr_req *req, *temp_req; + + mutex_lock(&lock); + list_for_each_entry_safe(req, temp_req, &req_list, list) { + if (req->addr == addr) { + req->status = -ECANCELED; + req->timeout = jiffies; + list_move(&req->list, &req_list); + set_timeout(req->timeout); + break; + } + } + mutex_unlock(&lock); +} +EXPORT_SYMBOL(rdma_addr_cancel); + +static int netevent_callback(struct notifier_block *self, unsigned long event, + void *ctx) +{ + if (event == NETEVENT_NEIGH_UPDATE) { +#ifdef __linux__ + struct neighbour *neigh = ctx; + + if (neigh->nud_state & NUD_VALID) { + set_timeout(jiffies); + } +#else + set_timeout(jiffies); +#endif + } + return 0; +} + +static struct notifier_block nb = { + .notifier_call = netevent_callback +}; + +static int addr_init(void) +{ + INIT_DELAYED_WORK(&work, process_req); + addr_wq = create_singlethread_workqueue("ib_addr"); + if (!addr_wq) + return -ENOMEM; + + register_netevent_notifier(&nb); + return 0; +} + +static void addr_cleanup(void) +{ + unregister_netevent_notifier(&nb); + destroy_workqueue(addr_wq); +} + +module_init(addr_init); +module_exit(addr_cleanup); diff --git a/sys/ofed/drivers/infiniband/core/agent.c b/sys/ofed/drivers/infiniband/core/agent.c new file mode 100644 index 000000000000..91916a8d5de4 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/agent.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2004, 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved. + * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include + +#include "agent.h" +#include "smi.h" +#include "mad_priv.h" + +#define SPFX "ib_agent: " + +struct ib_agent_port_private { + struct list_head port_list; + struct ib_mad_agent *agent[2]; +}; + +static DEFINE_SPINLOCK(ib_agent_port_list_lock); +static LIST_HEAD(ib_agent_port_list); + +static struct ib_agent_port_private * +__ib_get_agent_port(struct ib_device *device, int port_num) +{ + struct ib_agent_port_private *entry; + + list_for_each_entry(entry, &ib_agent_port_list, port_list) { + if (entry->agent[1]->device == device && + entry->agent[1]->port_num == port_num) + return entry; + } + return NULL; +} + +static struct ib_agent_port_private * +ib_get_agent_port(struct ib_device *device, int port_num) +{ + struct ib_agent_port_private *entry; + unsigned long flags; + + spin_lock_irqsave(&ib_agent_port_list_lock, flags); + entry = __ib_get_agent_port(device, port_num); + spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); + return entry; +} + +void agent_send_response(struct ib_mad *mad, struct ib_grh *grh, + struct ib_wc *wc, struct ib_device *device, + int port_num, int qpn) +{ + struct ib_agent_port_private *port_priv; + struct ib_mad_agent *agent; + struct ib_mad_send_buf *send_buf; + struct ib_ah *ah; + struct ib_mad_send_wr_private *mad_send_wr; + + if (device->node_type == RDMA_NODE_IB_SWITCH) + port_priv = ib_get_agent_port(device, 0); + else + port_priv = ib_get_agent_port(device, port_num); + + if (!port_priv) { + printk(KERN_ERR SPFX "Unable to find port agent\n"); + return; + } + + agent = port_priv->agent[qpn]; + ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num); + if (IS_ERR(ah)) { + printk(KERN_ERR SPFX "ib_create_ah_from_wc error\n"); + return; + } + + send_buf = ib_create_send_mad(agent, wc->src_qp, wc->pkey_index, 0, + IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, + GFP_KERNEL); + if (IS_ERR(send_buf)) { + printk(KERN_ERR SPFX "ib_create_send_mad error\n"); + goto err1; + } + + memcpy(send_buf->mad, mad, sizeof *mad); + send_buf->ah = ah; + + if (device->node_type == RDMA_NODE_IB_SWITCH) { + mad_send_wr = container_of(send_buf, + struct ib_mad_send_wr_private, + send_buf); + mad_send_wr->send_wr.wr.ud.port_num = port_num; + } + + if (ib_post_send_mad(send_buf, NULL)) { + printk(KERN_ERR SPFX "ib_post_send_mad error\n"); + goto err2; + } + return; +err2: + ib_free_send_mad(send_buf); +err1: + ib_destroy_ah(ah); +} + +static void agent_send_handler(struct ib_mad_agent *mad_agent, + struct ib_mad_send_wc *mad_send_wc) +{ + ib_destroy_ah(mad_send_wc->send_buf->ah); + ib_free_send_mad(mad_send_wc->send_buf); +} + +int ib_agent_port_open(struct ib_device *device, int port_num) +{ + struct ib_agent_port_private *port_priv; + unsigned long flags; + int ret; + + /* Create new device info */ + port_priv = kzalloc(sizeof *port_priv, GFP_KERNEL); + if (!port_priv) { + printk(KERN_ERR SPFX "No memory for ib_agent_port_private\n"); + ret = -ENOMEM; + goto error1; + } + + if (rdma_port_get_link_layer(device, port_num) == IB_LINK_LAYER_INFINIBAND) { + /* Obtain send only MAD agent for SMI QP */ + port_priv->agent[0] = ib_register_mad_agent(device, port_num, + IB_QPT_SMI, NULL, 0, + &agent_send_handler, + NULL, NULL); + if (IS_ERR(port_priv->agent[0])) { + ret = PTR_ERR(port_priv->agent[0]); + goto error2; + } + } + + /* Obtain send only MAD agent for GSI QP */ + port_priv->agent[1] = ib_register_mad_agent(device, port_num, + IB_QPT_GSI, NULL, 0, + &agent_send_handler, + NULL, NULL); + if (IS_ERR(port_priv->agent[1])) { + ret = PTR_ERR(port_priv->agent[1]); + goto error3; + } + + spin_lock_irqsave(&ib_agent_port_list_lock, flags); + list_add_tail(&port_priv->port_list, &ib_agent_port_list); + spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); + + return 0; + +error3: + if (port_priv->agent[0]) + ib_unregister_mad_agent(port_priv->agent[0]); +error2: + kfree(port_priv); +error1: + return ret; +} + +int ib_agent_port_close(struct ib_device *device, int port_num) +{ + struct ib_agent_port_private *port_priv; + unsigned long flags; + + spin_lock_irqsave(&ib_agent_port_list_lock, flags); + port_priv = __ib_get_agent_port(device, port_num); + if (port_priv == NULL) { + spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); + printk(KERN_ERR SPFX "Port %d not found\n", port_num); + return -ENODEV; + } + list_del(&port_priv->port_list); + spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); + + ib_unregister_mad_agent(port_priv->agent[1]); + if (port_priv->agent[0]) + ib_unregister_mad_agent(port_priv->agent[0]); + + kfree(port_priv); + return 0; +} diff --git a/sys/ofed/drivers/infiniband/core/agent.h b/sys/ofed/drivers/infiniband/core/agent.h new file mode 100644 index 000000000000..6669287009c2 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/agent.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __AGENT_H_ +#define __AGENT_H_ + +#include +#include + +extern int ib_agent_port_open(struct ib_device *device, int port_num); + +extern int ib_agent_port_close(struct ib_device *device, int port_num); + +extern void agent_send_response(struct ib_mad *mad, struct ib_grh *grh, + struct ib_wc *wc, struct ib_device *device, + int port_num, int qpn); + +#endif /* __AGENT_H_ */ diff --git a/sys/ofed/drivers/infiniband/core/cache.c b/sys/ofed/drivers/infiniband/core/cache.c new file mode 100644 index 000000000000..660bff50a7db --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/cache.c @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +#include + +#include "core_priv.h" + +struct ib_pkey_cache { + int table_len; + u16 table[0]; +}; + +struct ib_gid_cache { + int table_len; + union ib_gid table[0]; +}; + +struct ib_update_work { + struct work_struct work; + struct ib_device *device; + u8 port_num; +}; + +static inline int start_port(struct ib_device *device) +{ + return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1; +} + +static inline int end_port(struct ib_device *device) +{ + return (device->node_type == RDMA_NODE_IB_SWITCH) ? + 0 : device->phys_port_cnt; +} + +int ib_get_cached_gid(struct ib_device *device, + u8 port_num, + int index, + union ib_gid *gid) +{ + struct ib_gid_cache *cache; + unsigned long flags; + int ret = 0; + + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + read_lock_irqsave(&device->cache.lock, flags); + + cache = device->cache.gid_cache[port_num - start_port(device)]; + + if (index < 0 || index >= cache->table_len) + ret = -EINVAL; + else + *gid = cache->table[index]; + + read_unlock_irqrestore(&device->cache.lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_get_cached_gid); + +int ib_find_cached_gid(struct ib_device *device, + union ib_gid *gid, + u8 *port_num, + u16 *index) +{ + struct ib_gid_cache *cache; + unsigned long flags; + int p, i; + int ret = -ENOENT; + + *port_num = -1; + if (index) + *index = -1; + + read_lock_irqsave(&device->cache.lock, flags); + + for (p = 0; p <= end_port(device) - start_port(device); ++p) { + cache = device->cache.gid_cache[p]; + for (i = 0; i < cache->table_len; ++i) { + if (!memcmp(gid, &cache->table[i], sizeof *gid)) { + *port_num = p + start_port(device); + if (index) + *index = i; + ret = 0; + goto found; + } + } + } +found: + read_unlock_irqrestore(&device->cache.lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_find_cached_gid); + +int ib_get_cached_pkey(struct ib_device *device, + u8 port_num, + int index, + u16 *pkey) +{ + struct ib_pkey_cache *cache; + unsigned long flags; + int ret = 0; + + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + read_lock_irqsave(&device->cache.lock, flags); + + cache = device->cache.pkey_cache[port_num - start_port(device)]; + + if (index < 0 || index >= cache->table_len) + ret = -EINVAL; + else + *pkey = cache->table[index]; + + read_unlock_irqrestore(&device->cache.lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_get_cached_pkey); + +int ib_find_cached_pkey(struct ib_device *device, + u8 port_num, + u16 pkey, + u16 *index) +{ + struct ib_pkey_cache *cache; + unsigned long flags; + int i; + int ret = -ENOENT; + + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + read_lock_irqsave(&device->cache.lock, flags); + + cache = device->cache.pkey_cache[port_num - start_port(device)]; + + *index = -1; + + for (i = 0; i < cache->table_len; ++i) + if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) { + *index = i; + ret = 0; + break; + } + + read_unlock_irqrestore(&device->cache.lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_find_cached_pkey); + +int ib_get_cached_lmc(struct ib_device *device, + u8 port_num, + u8 *lmc) +{ + unsigned long flags; + int ret = 0; + + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + read_lock_irqsave(&device->cache.lock, flags); + *lmc = device->cache.lmc_cache[port_num - start_port(device)]; + read_unlock_irqrestore(&device->cache.lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_get_cached_lmc); + +static void ib_cache_update(struct ib_device *device, + u8 port) +{ + struct ib_port_attr *tprops = NULL; + struct ib_pkey_cache *pkey_cache = NULL, *old_pkey_cache; + struct ib_gid_cache *gid_cache = NULL, *old_gid_cache; + int i; + int ret; + + tprops = kmalloc(sizeof *tprops, GFP_KERNEL); + if (!tprops) + return; + + ret = ib_query_port(device, port, tprops); + if (ret) { + printk(KERN_WARNING "ib_query_port failed (%d) for %s\n", + ret, device->name); + goto err; + } + + pkey_cache = kmalloc(sizeof *pkey_cache + tprops->pkey_tbl_len * + sizeof *pkey_cache->table, GFP_KERNEL); + if (!pkey_cache) + goto err; + + pkey_cache->table_len = tprops->pkey_tbl_len; + + gid_cache = kmalloc(sizeof *gid_cache + tprops->gid_tbl_len * + sizeof *gid_cache->table, GFP_KERNEL); + if (!gid_cache) + goto err; + + gid_cache->table_len = tprops->gid_tbl_len; + + for (i = 0; i < pkey_cache->table_len; ++i) { + ret = ib_query_pkey(device, port, i, pkey_cache->table + i); + if (ret) { + printk(KERN_WARNING "ib_query_pkey failed (%d) for %s (index %d)\n", + ret, device->name, i); + goto err; + } + } + + for (i = 0; i < gid_cache->table_len; ++i) { + ret = ib_query_gid(device, port, i, gid_cache->table + i); + if (ret) { + printk(KERN_WARNING "ib_query_gid failed (%d) for %s (index %d)\n", + ret, device->name, i); + goto err; + } + } + + write_lock_irq(&device->cache.lock); + + old_pkey_cache = device->cache.pkey_cache[port - start_port(device)]; + old_gid_cache = device->cache.gid_cache [port - start_port(device)]; + + device->cache.pkey_cache[port - start_port(device)] = pkey_cache; + device->cache.gid_cache [port - start_port(device)] = gid_cache; + + device->cache.lmc_cache[port - start_port(device)] = tprops->lmc; + + write_unlock_irq(&device->cache.lock); + + kfree(old_pkey_cache); + kfree(old_gid_cache); + kfree(tprops); + return; + +err: + kfree(pkey_cache); + kfree(gid_cache); + kfree(tprops); +} + +static void ib_cache_task(struct work_struct *_work) +{ + struct ib_update_work *work = + container_of(_work, struct ib_update_work, work); + + ib_cache_update(work->device, work->port_num); + kfree(work); +} + +static void ib_cache_event(struct ib_event_handler *handler, + struct ib_event *event) +{ + struct ib_update_work *work; + + if (event->event == IB_EVENT_PORT_ERR || + event->event == IB_EVENT_PORT_ACTIVE || + event->event == IB_EVENT_LID_CHANGE || + event->event == IB_EVENT_PKEY_CHANGE || + event->event == IB_EVENT_SM_CHANGE || + event->event == IB_EVENT_CLIENT_REREGISTER || + event->event == IB_EVENT_GID_CHANGE) { + work = kmalloc(sizeof *work, GFP_ATOMIC); + if (work) { + INIT_WORK(&work->work, ib_cache_task); + work->device = event->device; + work->port_num = event->element.port_num; + schedule_work(&work->work); + } + } +} + +static void ib_cache_setup_one(struct ib_device *device) +{ + int p; + + rwlock_init(&device->cache.lock); + + device->cache.pkey_cache = + kmalloc(sizeof *device->cache.pkey_cache * + (end_port(device) - start_port(device) + 1), GFP_KERNEL); + device->cache.gid_cache = + kmalloc(sizeof *device->cache.gid_cache * + (end_port(device) - start_port(device) + 1), GFP_KERNEL); + + device->cache.lmc_cache = kmalloc(sizeof *device->cache.lmc_cache * + (end_port(device) - + start_port(device) + 1), + GFP_KERNEL); + + if (!device->cache.pkey_cache || !device->cache.gid_cache || + !device->cache.lmc_cache) { + printk(KERN_WARNING "Couldn't allocate cache " + "for %s\n", device->name); + goto err; + } + + for (p = 0; p <= end_port(device) - start_port(device); ++p) { + device->cache.pkey_cache[p] = NULL; + device->cache.gid_cache [p] = NULL; + ib_cache_update(device, p + start_port(device)); + } + + INIT_IB_EVENT_HANDLER(&device->cache.event_handler, + device, ib_cache_event); + if (ib_register_event_handler(&device->cache.event_handler)) + goto err_cache; + + return; + +err_cache: + for (p = 0; p <= end_port(device) - start_port(device); ++p) { + kfree(device->cache.pkey_cache[p]); + kfree(device->cache.gid_cache[p]); + } + +err: + kfree(device->cache.pkey_cache); + kfree(device->cache.gid_cache); + kfree(device->cache.lmc_cache); +} + +static void ib_cache_cleanup_one(struct ib_device *device) +{ + int p; + + ib_unregister_event_handler(&device->cache.event_handler); + flush_scheduled_work(); + + for (p = 0; p <= end_port(device) - start_port(device); ++p) { + kfree(device->cache.pkey_cache[p]); + kfree(device->cache.gid_cache[p]); + } + + kfree(device->cache.pkey_cache); + kfree(device->cache.gid_cache); + kfree(device->cache.lmc_cache); +} + +static struct ib_client cache_client = { + .name = "cache", + .add = ib_cache_setup_one, + .remove = ib_cache_cleanup_one +}; + +int __init ib_cache_setup(void) +{ + return ib_register_client(&cache_client); +} + +void __exit ib_cache_cleanup(void) +{ + ib_unregister_client(&cache_client); +} diff --git a/sys/ofed/drivers/infiniband/core/cm.c b/sys/ofed/drivers/infiniband/core/cm.c new file mode 100644 index 000000000000..24f8b1250bb9 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/cm.c @@ -0,0 +1,3894 @@ +/* + * Copyright (c) 2004-2007 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "cm_msgs.h" + +MODULE_AUTHOR("Sean Hefty"); +MODULE_DESCRIPTION("InfiniBand CM"); +MODULE_LICENSE("Dual BSD/GPL"); + +#define PFX "ib_cm: " + +/* + * Limit CM message timeouts to something reasonable: + * 8 seconds per message, with up to 15 retries + */ +static int max_timeout = 21; +module_param(max_timeout, int, 0644); +MODULE_PARM_DESC(max_timeout, "Maximum IB CM per message timeout " + "(default=21, or ~8 seconds)"); + +static void cm_add_one(struct ib_device *device); +static void cm_remove_one(struct ib_device *device); + +static struct ib_client cm_client = { + .name = "cm", + .add = cm_add_one, + .remove = cm_remove_one +}; + +static struct ib_cm { + spinlock_t lock; + struct list_head device_list; + rwlock_t device_lock; + struct rb_root listen_service_table; + u64 listen_service_id; + /* struct rb_root peer_service_table; todo: fix peer to peer */ + struct rb_root remote_qp_table; + struct rb_root remote_id_table; + struct rb_root remote_sidr_table; + struct idr local_id_table; + __be32 random_id_operand; + struct list_head timewait_list; + struct workqueue_struct *wq; +} cm; + +/* Counter indexes ordered by attribute ID */ +enum { + CM_REQ_COUNTER, + CM_MRA_COUNTER, + CM_REJ_COUNTER, + CM_REP_COUNTER, + CM_RTU_COUNTER, + CM_DREQ_COUNTER, + CM_DREP_COUNTER, + CM_SIDR_REQ_COUNTER, + CM_SIDR_REP_COUNTER, + CM_LAP_COUNTER, + CM_APR_COUNTER, + CM_ATTR_COUNT, + CM_ATTR_ID_OFFSET = 0x0010, +}; + +enum { + CM_XMIT, + CM_XMIT_RETRIES, + CM_RECV, + CM_RECV_DUPLICATES, + CM_COUNTER_GROUPS +}; + +static char const counter_group_names[CM_COUNTER_GROUPS] + [sizeof("cm_rx_duplicates")] = { + "cm_tx_msgs", "cm_tx_retries", + "cm_rx_msgs", "cm_rx_duplicates" +}; + +struct cm_counter_group { + struct kobject obj; + atomic_long_t counter[CM_ATTR_COUNT]; +}; + +struct cm_counter_attribute { + struct attribute attr; + int index; +}; + +#define CM_COUNTER_ATTR(_name, _index) \ +struct cm_counter_attribute cm_##_name##_counter_attr = { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .index = _index \ +} + +static CM_COUNTER_ATTR(req, CM_REQ_COUNTER); +static CM_COUNTER_ATTR(mra, CM_MRA_COUNTER); +static CM_COUNTER_ATTR(rej, CM_REJ_COUNTER); +static CM_COUNTER_ATTR(rep, CM_REP_COUNTER); +static CM_COUNTER_ATTR(rtu, CM_RTU_COUNTER); +static CM_COUNTER_ATTR(dreq, CM_DREQ_COUNTER); +static CM_COUNTER_ATTR(drep, CM_DREP_COUNTER); +static CM_COUNTER_ATTR(sidr_req, CM_SIDR_REQ_COUNTER); +static CM_COUNTER_ATTR(sidr_rep, CM_SIDR_REP_COUNTER); +static CM_COUNTER_ATTR(lap, CM_LAP_COUNTER); +static CM_COUNTER_ATTR(apr, CM_APR_COUNTER); + +static struct attribute *cm_counter_default_attrs[] = { + &cm_req_counter_attr.attr, + &cm_mra_counter_attr.attr, + &cm_rej_counter_attr.attr, + &cm_rep_counter_attr.attr, + &cm_rtu_counter_attr.attr, + &cm_dreq_counter_attr.attr, + &cm_drep_counter_attr.attr, + &cm_sidr_req_counter_attr.attr, + &cm_sidr_rep_counter_attr.attr, + &cm_lap_counter_attr.attr, + &cm_apr_counter_attr.attr, + NULL +}; + +struct cm_port { + struct cm_device *cm_dev; + struct ib_mad_agent *mad_agent; + struct kobject port_obj; + u8 port_num; + struct cm_counter_group counter_group[CM_COUNTER_GROUPS]; +}; + +struct cm_device { + struct list_head list; + struct ib_device *ib_device; + struct device *device; + u8 ack_delay; + struct cm_port *port[0]; +}; + +struct cm_av { + struct cm_port *port; + union ib_gid dgid; + struct ib_ah_attr ah_attr; + u16 pkey_index; + u8 timeout; +}; + +struct cm_work { + struct delayed_work work; + struct list_head list; + struct cm_port *port; + struct ib_mad_recv_wc *mad_recv_wc; /* Received MADs */ + __be32 local_id; /* Established / timewait */ + __be32 remote_id; + struct ib_cm_event cm_event; + struct ib_sa_path_rec path[0]; +}; + +struct cm_timewait_info { + struct cm_work work; /* Must be first. */ + struct list_head list; + struct rb_node remote_qp_node; + struct rb_node remote_id_node; + __be64 remote_ca_guid; + __be32 remote_qpn; + u8 inserted_remote_qp; + u8 inserted_remote_id; +}; + +struct cm_id_private { + struct ib_cm_id id; + + struct rb_node service_node; + struct rb_node sidr_id_node; + spinlock_t lock; /* Do not acquire inside cm.lock */ + struct completion comp; + atomic_t refcount; + + struct ib_mad_send_buf *msg; + struct cm_timewait_info *timewait_info; + /* todo: use alternate port on send failure */ + struct cm_av av; + struct cm_av alt_av; + struct ib_cm_compare_data *compare_data; + + void *private_data; + __be64 tid; + __be32 local_qpn; + __be32 remote_qpn; + enum ib_qp_type qp_type; + __be32 sq_psn; + __be32 rq_psn; + int timeout_ms; + enum ib_mtu path_mtu; + __be16 pkey; + u8 private_data_len; + u8 max_cm_retries; + u8 peer_to_peer; + u8 responder_resources; + u8 initiator_depth; + u8 retry_count; + u8 rnr_retry_count; + u8 service_timeout; + u8 target_ack_delay; + + struct list_head work_list; + atomic_t work_count; +}; + +static void cm_work_handler(struct work_struct *work); + +static inline void cm_deref_id(struct cm_id_private *cm_id_priv) +{ + if (atomic_dec_and_test(&cm_id_priv->refcount)) + complete(&cm_id_priv->comp); +} + +static int cm_alloc_msg(struct cm_id_private *cm_id_priv, + struct ib_mad_send_buf **msg) +{ + struct ib_mad_agent *mad_agent; + struct ib_mad_send_buf *m; + struct ib_ah *ah; + + mad_agent = cm_id_priv->av.port->mad_agent; + ah = ib_create_ah(mad_agent->qp->pd, &cm_id_priv->av.ah_attr); + if (IS_ERR(ah)) + return PTR_ERR(ah); + + m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn, + cm_id_priv->av.pkey_index, + 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, + GFP_ATOMIC); + if (IS_ERR(m)) { + ib_destroy_ah(ah); + return PTR_ERR(m); + } + + /* Timeout set by caller if response is expected. */ + m->ah = ah; + m->retries = cm_id_priv->max_cm_retries; + + atomic_inc(&cm_id_priv->refcount); + m->context[0] = cm_id_priv; + *msg = m; + return 0; +} + +static int cm_alloc_response_msg(struct cm_port *port, + struct ib_mad_recv_wc *mad_recv_wc, + struct ib_mad_send_buf **msg) +{ + struct ib_mad_send_buf *m; + struct ib_ah *ah; + + ah = ib_create_ah_from_wc(port->mad_agent->qp->pd, mad_recv_wc->wc, + mad_recv_wc->recv_buf.grh, port->port_num); + if (IS_ERR(ah)) + return PTR_ERR(ah); + + m = ib_create_send_mad(port->mad_agent, 1, mad_recv_wc->wc->pkey_index, + 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, + GFP_ATOMIC); + if (IS_ERR(m)) { + ib_destroy_ah(ah); + return PTR_ERR(m); + } + m->ah = ah; + *msg = m; + return 0; +} + +static void cm_free_msg(struct ib_mad_send_buf *msg) +{ + ib_destroy_ah(msg->ah); + if (msg->context[0]) + cm_deref_id(msg->context[0]); + ib_free_send_mad(msg); +} + +static void * cm_copy_private_data(const void *private_data, + u8 private_data_len) +{ + void *data; + + if (!private_data || !private_data_len) + return NULL; + + data = kmemdup(private_data, private_data_len, GFP_KERNEL); + if (!data) + return ERR_PTR(-ENOMEM); + + return data; +} + +static void cm_set_private_data(struct cm_id_private *cm_id_priv, + void *private_data, u8 private_data_len) +{ + if (cm_id_priv->private_data && cm_id_priv->private_data_len) + kfree(cm_id_priv->private_data); + + cm_id_priv->private_data = private_data; + cm_id_priv->private_data_len = private_data_len; +} + +static void cm_init_av_for_response(struct cm_port *port, struct ib_wc *wc, + struct ib_grh *grh, struct cm_av *av) +{ + av->port = port; + av->pkey_index = wc->pkey_index; + ib_init_ah_from_wc(port->cm_dev->ib_device, port->port_num, wc, + grh, &av->ah_attr); +} + +static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av) +{ + struct cm_device *cm_dev; + struct cm_port *port = NULL; + unsigned long flags; + int ret; + u8 p; + + read_lock_irqsave(&cm.device_lock, flags); + list_for_each_entry(cm_dev, &cm.device_list, list) { + if (!ib_find_cached_gid(cm_dev->ib_device, &path->sgid, + &p, NULL)) { + port = cm_dev->port[p-1]; + break; + } + } + read_unlock_irqrestore(&cm.device_lock, flags); + + if (!port) + return -EINVAL; + + ret = ib_find_cached_pkey(cm_dev->ib_device, port->port_num, + be16_to_cpu(path->pkey), &av->pkey_index); + if (ret) + return ret; + + av->port = port; + ib_init_ah_from_path(cm_dev->ib_device, port->port_num, path, + &av->ah_attr); + av->timeout = path->packet_life_time + 1; + return 0; +} + +static int cm_alloc_id(struct cm_id_private *cm_id_priv) +{ + unsigned long flags; + int ret, id; + static int next_id; + + do { + spin_lock_irqsave(&cm.lock, flags); + ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, + next_id, &id); + if (!ret) + next_id = ((unsigned) id + 1) & MAX_ID_MASK; + spin_unlock_irqrestore(&cm.lock, flags); + } while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) ); + + cm_id_priv->id.local_id = (__force __be32)id ^ cm.random_id_operand; + return ret; +} + +static void cm_free_id(__be32 local_id) +{ + spin_lock_irq(&cm.lock); + idr_remove(&cm.local_id_table, + (__force int) (local_id ^ cm.random_id_operand)); + spin_unlock_irq(&cm.lock); +} + +static struct cm_id_private * cm_get_id(__be32 local_id, __be32 remote_id) +{ + struct cm_id_private *cm_id_priv; + + cm_id_priv = idr_find(&cm.local_id_table, + (__force int) (local_id ^ cm.random_id_operand)); + if (cm_id_priv) { + if (cm_id_priv->id.remote_id == remote_id) + atomic_inc(&cm_id_priv->refcount); + else + cm_id_priv = NULL; + } + + return cm_id_priv; +} + +static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id) +{ + struct cm_id_private *cm_id_priv; + + spin_lock_irq(&cm.lock); + cm_id_priv = cm_get_id(local_id, remote_id); + spin_unlock_irq(&cm.lock); + + return cm_id_priv; +} + +static void cm_mask_copy(u8 *dst, u8 *src, u8 *mask) +{ + int i; + + for (i = 0; i < IB_CM_COMPARE_SIZE / sizeof(unsigned long); i++) + ((unsigned long *) dst)[i] = ((unsigned long *) src)[i] & + ((unsigned long *) mask)[i]; +} + +static int cm_compare_data(struct ib_cm_compare_data *src_data, + struct ib_cm_compare_data *dst_data) +{ + u8 src[IB_CM_COMPARE_SIZE]; + u8 dst[IB_CM_COMPARE_SIZE]; + + if (!src_data || !dst_data) + return 0; + + cm_mask_copy(src, src_data->data, dst_data->mask); + cm_mask_copy(dst, dst_data->data, src_data->mask); + return memcmp(src, dst, IB_CM_COMPARE_SIZE); +} + +static int cm_compare_private_data(u8 *private_data, + struct ib_cm_compare_data *dst_data) +{ + u8 src[IB_CM_COMPARE_SIZE]; + + if (!dst_data) + return 0; + + cm_mask_copy(src, private_data, dst_data->mask); + return memcmp(src, dst_data->data, IB_CM_COMPARE_SIZE); +} + +/* + * Trivial helpers to strip endian annotation and compare; the + * endianness doesn't actually matter since we just need a stable + * order for the RB tree. + */ +static int be32_lt(__be32 a, __be32 b) +{ + return (__force u32) a < (__force u32) b; +} + +static int be32_gt(__be32 a, __be32 b) +{ + return (__force u32) a > (__force u32) b; +} + +static int be64_lt(__be64 a, __be64 b) +{ + return (__force u64) a < (__force u64) b; +} + +static int be64_gt(__be64 a, __be64 b) +{ + return (__force u64) a > (__force u64) b; +} + +static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) +{ + struct rb_node **link = &cm.listen_service_table.rb_node; + struct rb_node *parent = NULL; + struct cm_id_private *cur_cm_id_priv; + __be64 service_id = cm_id_priv->id.service_id; + __be64 service_mask = cm_id_priv->id.service_mask; + int data_cmp; + + while (*link) { + parent = *link; + cur_cm_id_priv = rb_entry(parent, struct cm_id_private, + service_node); + data_cmp = cm_compare_data(cm_id_priv->compare_data, + cur_cm_id_priv->compare_data); + if ((cur_cm_id_priv->id.service_mask & service_id) == + (service_mask & cur_cm_id_priv->id.service_id) && + (cm_id_priv->id.device == cur_cm_id_priv->id.device) && + !data_cmp) + return cur_cm_id_priv; + + if (cm_id_priv->id.device < cur_cm_id_priv->id.device) + link = &(*link)->rb_left; + else if (cm_id_priv->id.device > cur_cm_id_priv->id.device) + link = &(*link)->rb_right; + else if (be64_lt(service_id, cur_cm_id_priv->id.service_id)) + link = &(*link)->rb_left; + else if (be64_gt(service_id, cur_cm_id_priv->id.service_id)) + link = &(*link)->rb_right; + else if (data_cmp < 0) + link = &(*link)->rb_left; + else + link = &(*link)->rb_right; + } + rb_link_node(&cm_id_priv->service_node, parent, link); + rb_insert_color(&cm_id_priv->service_node, &cm.listen_service_table); + return NULL; +} + +static struct cm_id_private * cm_find_listen(struct ib_device *device, + __be64 service_id, + u8 *private_data) +{ + struct rb_node *node = cm.listen_service_table.rb_node; + struct cm_id_private *cm_id_priv; + int data_cmp; + + while (node) { + cm_id_priv = rb_entry(node, struct cm_id_private, service_node); + data_cmp = cm_compare_private_data(private_data, + cm_id_priv->compare_data); + if ((cm_id_priv->id.service_mask & service_id) == + cm_id_priv->id.service_id && + (cm_id_priv->id.device == device) && !data_cmp) + return cm_id_priv; + + if (device < cm_id_priv->id.device) + node = node->rb_left; + else if (device > cm_id_priv->id.device) + node = node->rb_right; + else if (be64_lt(service_id, cm_id_priv->id.service_id)) + node = node->rb_left; + else if (be64_gt(service_id, cm_id_priv->id.service_id)) + node = node->rb_right; + else if (data_cmp < 0) + node = node->rb_left; + else + node = node->rb_right; + } + return NULL; +} + +static struct cm_timewait_info * cm_insert_remote_id(struct cm_timewait_info + *timewait_info) +{ + struct rb_node **link = &cm.remote_id_table.rb_node; + struct rb_node *parent = NULL; + struct cm_timewait_info *cur_timewait_info; + __be64 remote_ca_guid = timewait_info->remote_ca_guid; + __be32 remote_id = timewait_info->work.remote_id; + + while (*link) { + parent = *link; + cur_timewait_info = rb_entry(parent, struct cm_timewait_info, + remote_id_node); + if (be32_lt(remote_id, cur_timewait_info->work.remote_id)) + link = &(*link)->rb_left; + else if (be32_gt(remote_id, cur_timewait_info->work.remote_id)) + link = &(*link)->rb_right; + else if (be64_lt(remote_ca_guid, cur_timewait_info->remote_ca_guid)) + link = &(*link)->rb_left; + else if (be64_gt(remote_ca_guid, cur_timewait_info->remote_ca_guid)) + link = &(*link)->rb_right; + else + return cur_timewait_info; + } + timewait_info->inserted_remote_id = 1; + rb_link_node(&timewait_info->remote_id_node, parent, link); + rb_insert_color(&timewait_info->remote_id_node, &cm.remote_id_table); + return NULL; +} + +static struct cm_timewait_info * cm_find_remote_id(__be64 remote_ca_guid, + __be32 remote_id) +{ + struct rb_node *node = cm.remote_id_table.rb_node; + struct cm_timewait_info *timewait_info; + + while (node) { + timewait_info = rb_entry(node, struct cm_timewait_info, + remote_id_node); + if (be32_lt(remote_id, timewait_info->work.remote_id)) + node = node->rb_left; + else if (be32_gt(remote_id, timewait_info->work.remote_id)) + node = node->rb_right; + else if (be64_lt(remote_ca_guid, timewait_info->remote_ca_guid)) + node = node->rb_left; + else if (be64_gt(remote_ca_guid, timewait_info->remote_ca_guid)) + node = node->rb_right; + else + return timewait_info; + } + return NULL; +} + +static struct cm_timewait_info * cm_insert_remote_qpn(struct cm_timewait_info + *timewait_info) +{ + struct rb_node **link = &cm.remote_qp_table.rb_node; + struct rb_node *parent = NULL; + struct cm_timewait_info *cur_timewait_info; + __be64 remote_ca_guid = timewait_info->remote_ca_guid; + __be32 remote_qpn = timewait_info->remote_qpn; + + while (*link) { + parent = *link; + cur_timewait_info = rb_entry(parent, struct cm_timewait_info, + remote_qp_node); + if (be32_lt(remote_qpn, cur_timewait_info->remote_qpn)) + link = &(*link)->rb_left; + else if (be32_gt(remote_qpn, cur_timewait_info->remote_qpn)) + link = &(*link)->rb_right; + else if (be64_lt(remote_ca_guid, cur_timewait_info->remote_ca_guid)) + link = &(*link)->rb_left; + else if (be64_gt(remote_ca_guid, cur_timewait_info->remote_ca_guid)) + link = &(*link)->rb_right; + else + return cur_timewait_info; + } + timewait_info->inserted_remote_qp = 1; + rb_link_node(&timewait_info->remote_qp_node, parent, link); + rb_insert_color(&timewait_info->remote_qp_node, &cm.remote_qp_table); + return NULL; +} + +static struct cm_id_private * cm_insert_remote_sidr(struct cm_id_private + *cm_id_priv) +{ + struct rb_node **link = &cm.remote_sidr_table.rb_node; + struct rb_node *parent = NULL; + struct cm_id_private *cur_cm_id_priv; + union ib_gid *port_gid = &cm_id_priv->av.dgid; + __be32 remote_id = cm_id_priv->id.remote_id; + + while (*link) { + parent = *link; + cur_cm_id_priv = rb_entry(parent, struct cm_id_private, + sidr_id_node); + if (be32_lt(remote_id, cur_cm_id_priv->id.remote_id)) + link = &(*link)->rb_left; + else if (be32_gt(remote_id, cur_cm_id_priv->id.remote_id)) + link = &(*link)->rb_right; + else { + int cmp; + cmp = memcmp(port_gid, &cur_cm_id_priv->av.dgid, + sizeof *port_gid); + if (cmp < 0) + link = &(*link)->rb_left; + else if (cmp > 0) + link = &(*link)->rb_right; + else + return cur_cm_id_priv; + } + } + rb_link_node(&cm_id_priv->sidr_id_node, parent, link); + rb_insert_color(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); + return NULL; +} + +static void cm_reject_sidr_req(struct cm_id_private *cm_id_priv, + enum ib_cm_sidr_status status) +{ + struct ib_cm_sidr_rep_param param; + + memset(¶m, 0, sizeof param); + param.status = status; + ib_send_cm_sidr_rep(&cm_id_priv->id, ¶m); +} + +struct ib_cm_id *ib_create_cm_id(struct ib_device *device, + ib_cm_handler cm_handler, + void *context) +{ + struct cm_id_private *cm_id_priv; + int ret; + + cm_id_priv = kzalloc(sizeof *cm_id_priv, GFP_KERNEL); + if (!cm_id_priv) + return ERR_PTR(-ENOMEM); + + cm_id_priv->id.state = IB_CM_IDLE; + cm_id_priv->id.device = device; + cm_id_priv->id.cm_handler = cm_handler; + cm_id_priv->id.context = context; + cm_id_priv->id.remote_cm_qpn = 1; + ret = cm_alloc_id(cm_id_priv); + if (ret) + goto error; + + spin_lock_init(&cm_id_priv->lock); + init_completion(&cm_id_priv->comp); + INIT_LIST_HEAD(&cm_id_priv->work_list); + atomic_set(&cm_id_priv->work_count, -1); + atomic_set(&cm_id_priv->refcount, 1); + return &cm_id_priv->id; + +error: + kfree(cm_id_priv); + return ERR_PTR(-ENOMEM); +} +EXPORT_SYMBOL(ib_create_cm_id); + +static struct cm_work * cm_dequeue_work(struct cm_id_private *cm_id_priv) +{ + struct cm_work *work; + + if (list_empty(&cm_id_priv->work_list)) + return NULL; + + work = list_entry(cm_id_priv->work_list.next, struct cm_work, list); + list_del(&work->list); + return work; +} + +static void cm_free_work(struct cm_work *work) +{ + if (work->mad_recv_wc) + ib_free_recv_mad(work->mad_recv_wc); + kfree(work); +} + +static inline int cm_convert_to_ms(int iba_time) +{ + /* approximate conversion to ms from 4.096us x 2^iba_time */ + return 1 << max(iba_time - 8, 0); +} + +/* + * calculate: 4.096x2^ack_timeout = 4.096x2^ack_delay + 2x4.096x2^life_time + * Because of how ack_timeout is stored, adding one doubles the timeout. + * To avoid large timeouts, select the max(ack_delay, life_time + 1), and + * increment it (round up) only if the other is within 50%. + */ +static u8 cm_ack_timeout(u8 ca_ack_delay, u8 packet_life_time) +{ + int ack_timeout = packet_life_time + 1; + + if (ack_timeout >= ca_ack_delay) + ack_timeout += (ca_ack_delay >= (ack_timeout - 1)); + else + ack_timeout = ca_ack_delay + + (ack_timeout >= (ca_ack_delay - 1)); + + return min(31, ack_timeout); +} + +static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info) +{ + if (timewait_info->inserted_remote_id) { + rb_erase(&timewait_info->remote_id_node, &cm.remote_id_table); + timewait_info->inserted_remote_id = 0; + } + + if (timewait_info->inserted_remote_qp) { + rb_erase(&timewait_info->remote_qp_node, &cm.remote_qp_table); + timewait_info->inserted_remote_qp = 0; + } +} + +static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id) +{ + struct cm_timewait_info *timewait_info; + + timewait_info = kzalloc(sizeof *timewait_info, GFP_KERNEL); + if (!timewait_info) + return ERR_PTR(-ENOMEM); + + timewait_info->work.local_id = local_id; + INIT_DELAYED_WORK(&timewait_info->work.work, cm_work_handler); + timewait_info->work.cm_event.event = IB_CM_TIMEWAIT_EXIT; + return timewait_info; +} + +static void cm_enter_timewait(struct cm_id_private *cm_id_priv) +{ + int wait_time; + unsigned long flags; + + spin_lock_irqsave(&cm.lock, flags); + cm_cleanup_timewait(cm_id_priv->timewait_info); + list_add_tail(&cm_id_priv->timewait_info->list, &cm.timewait_list); + spin_unlock_irqrestore(&cm.lock, flags); + + /* + * The cm_id could be destroyed by the user before we exit timewait. + * To protect against this, we search for the cm_id after exiting + * timewait before notifying the user that we've exited timewait. + */ + cm_id_priv->id.state = IB_CM_TIMEWAIT; + wait_time = cm_convert_to_ms(cm_id_priv->av.timeout); + queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work, + msecs_to_jiffies(wait_time)); + cm_id_priv->timewait_info = NULL; +} + +static void cm_reset_to_idle(struct cm_id_private *cm_id_priv) +{ + unsigned long flags; + + cm_id_priv->id.state = IB_CM_IDLE; + if (cm_id_priv->timewait_info) { + spin_lock_irqsave(&cm.lock, flags); + cm_cleanup_timewait(cm_id_priv->timewait_info); + spin_unlock_irqrestore(&cm.lock, flags); + kfree(cm_id_priv->timewait_info); + cm_id_priv->timewait_info = NULL; + } +} + +static void cm_destroy_id(struct ib_cm_id *cm_id, int err) +{ + struct cm_id_private *cm_id_priv; + struct cm_work *work; + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); +retest: + spin_lock_irq(&cm_id_priv->lock); + switch (cm_id->state) { + case IB_CM_LISTEN: + cm_id->state = IB_CM_IDLE; + spin_unlock_irq(&cm_id_priv->lock); + spin_lock_irq(&cm.lock); + rb_erase(&cm_id_priv->service_node, &cm.listen_service_table); + spin_unlock_irq(&cm.lock); + break; + case IB_CM_SIDR_REQ_SENT: + cm_id->state = IB_CM_IDLE; + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + spin_unlock_irq(&cm_id_priv->lock); + break; + case IB_CM_SIDR_REQ_RCVD: + spin_unlock_irq(&cm_id_priv->lock); + cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT); + break; + case IB_CM_REQ_SENT: + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + spin_unlock_irq(&cm_id_priv->lock); + ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT, + &cm_id_priv->id.device->node_guid, + sizeof cm_id_priv->id.device->node_guid, + NULL, 0); + break; + case IB_CM_REQ_RCVD: + if (err == -ENOMEM) { + /* Do not reject to allow future retries. */ + cm_reset_to_idle(cm_id_priv); + spin_unlock_irq(&cm_id_priv->lock); + } else { + spin_unlock_irq(&cm_id_priv->lock); + ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED, + NULL, 0, NULL, 0); + } + break; + case IB_CM_MRA_REQ_RCVD: + case IB_CM_REP_SENT: + case IB_CM_MRA_REP_RCVD: + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + /* Fall through */ + case IB_CM_MRA_REQ_SENT: + case IB_CM_REP_RCVD: + case IB_CM_MRA_REP_SENT: + spin_unlock_irq(&cm_id_priv->lock); + ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED, + NULL, 0, NULL, 0); + break; + case IB_CM_ESTABLISHED: + spin_unlock_irq(&cm_id_priv->lock); + ib_send_cm_dreq(cm_id, NULL, 0); + goto retest; + case IB_CM_DREQ_SENT: + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + cm_enter_timewait(cm_id_priv); + spin_unlock_irq(&cm_id_priv->lock); + break; + case IB_CM_DREQ_RCVD: + spin_unlock_irq(&cm_id_priv->lock); + ib_send_cm_drep(cm_id, NULL, 0); + break; + default: + spin_unlock_irq(&cm_id_priv->lock); + break; + } + + cm_free_id(cm_id->local_id); + cm_deref_id(cm_id_priv); + wait_for_completion(&cm_id_priv->comp); + while ((work = cm_dequeue_work(cm_id_priv)) != NULL) + cm_free_work(work); + kfree(cm_id_priv->compare_data); + kfree(cm_id_priv->private_data); + kfree(cm_id_priv); +} + +void ib_destroy_cm_id(struct ib_cm_id *cm_id) +{ + cm_destroy_id(cm_id, 0); +} +EXPORT_SYMBOL(ib_destroy_cm_id); + +int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, + struct ib_cm_compare_data *compare_data) +{ + struct cm_id_private *cm_id_priv, *cur_cm_id_priv; + unsigned long flags; + int ret = 0; + + service_mask = service_mask ? service_mask : ~cpu_to_be64(0); + service_id &= service_mask; + if ((service_id & IB_SERVICE_ID_AGN_MASK) == IB_CM_ASSIGN_SERVICE_ID && + (service_id != IB_CM_ASSIGN_SERVICE_ID)) + return -EINVAL; + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + if (cm_id->state != IB_CM_IDLE) + return -EINVAL; + + if (compare_data) { + cm_id_priv->compare_data = kzalloc(sizeof *compare_data, + GFP_KERNEL); + if (!cm_id_priv->compare_data) + return -ENOMEM; + cm_mask_copy(cm_id_priv->compare_data->data, + compare_data->data, compare_data->mask); + memcpy(cm_id_priv->compare_data->mask, compare_data->mask, + IB_CM_COMPARE_SIZE); + } + + cm_id->state = IB_CM_LISTEN; + + spin_lock_irqsave(&cm.lock, flags); + if (service_id == IB_CM_ASSIGN_SERVICE_ID) { + cm_id->service_id = cpu_to_be64(cm.listen_service_id++); + cm_id->service_mask = ~cpu_to_be64(0); + } else { + cm_id->service_id = service_id; + cm_id->service_mask = service_mask; + } + cur_cm_id_priv = cm_insert_listen(cm_id_priv); + spin_unlock_irqrestore(&cm.lock, flags); + + if (cur_cm_id_priv) { + cm_id->state = IB_CM_IDLE; + kfree(cm_id_priv->compare_data); + cm_id_priv->compare_data = NULL; + ret = -EBUSY; + } + return ret; +} +EXPORT_SYMBOL(ib_cm_listen); + +static __be64 cm_form_tid(struct cm_id_private *cm_id_priv, + enum cm_msg_sequence msg_seq) +{ + u64 hi_tid, low_tid; + + hi_tid = ((u64) cm_id_priv->av.port->mad_agent->hi_tid) << 32; + low_tid = (u64) ((__force u32)cm_id_priv->id.local_id | + (msg_seq << 30)); + return cpu_to_be64(hi_tid | low_tid); +} + +static void cm_format_mad_hdr(struct ib_mad_hdr *hdr, + __be16 attr_id, __be64 tid) +{ + hdr->base_version = IB_MGMT_BASE_VERSION; + hdr->mgmt_class = IB_MGMT_CLASS_CM; + hdr->class_version = IB_CM_CLASS_VERSION; + hdr->method = IB_MGMT_METHOD_SEND; + hdr->attr_id = attr_id; + hdr->tid = tid; +} + +static void cm_format_req(struct cm_req_msg *req_msg, + struct cm_id_private *cm_id_priv, + struct ib_cm_req_param *param) +{ + struct ib_sa_path_rec *pri_path = param->primary_path; + struct ib_sa_path_rec *alt_path = param->alternate_path; + + cm_format_mad_hdr(&req_msg->hdr, CM_REQ_ATTR_ID, + cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_REQ)); + + req_msg->local_comm_id = cm_id_priv->id.local_id; + req_msg->service_id = param->service_id; + req_msg->local_ca_guid = cm_id_priv->id.device->node_guid; + cm_req_set_local_qpn(req_msg, cpu_to_be32(param->qp_num)); + cm_req_set_resp_res(req_msg, param->responder_resources); + cm_req_set_init_depth(req_msg, param->initiator_depth); + cm_req_set_remote_resp_timeout(req_msg, + param->remote_cm_response_timeout); + if (param->remote_cm_response_timeout > (u8) max_timeout) { + printk(KERN_WARNING PFX "req remote_cm_response_timeout %d > " + "%d, decreasing\n", param->remote_cm_response_timeout, + max_timeout); + cm_req_set_remote_resp_timeout(req_msg, (u8) max_timeout); + } + cm_req_set_qp_type(req_msg, param->qp_type); + cm_req_set_flow_ctrl(req_msg, param->flow_control); + cm_req_set_starting_psn(req_msg, cpu_to_be32(param->starting_psn)); + cm_req_set_local_resp_timeout(req_msg, + param->local_cm_response_timeout); + if (param->local_cm_response_timeout > (u8) max_timeout) { + printk(KERN_WARNING PFX "req local_cm_response_timeout %d > " + "%d, decreasing\n", param->local_cm_response_timeout, + max_timeout); + cm_req_set_local_resp_timeout(req_msg, (u8) max_timeout); + } + cm_req_set_retry_count(req_msg, param->retry_count); + req_msg->pkey = param->primary_path->pkey; + cm_req_set_path_mtu(req_msg, param->primary_path->mtu); + cm_req_set_rnr_retry_count(req_msg, param->rnr_retry_count); + cm_req_set_max_cm_retries(req_msg, param->max_cm_retries); + cm_req_set_srq(req_msg, param->srq); + + if (pri_path->hop_limit <= 1) { + req_msg->primary_local_lid = pri_path->slid; + req_msg->primary_remote_lid = pri_path->dlid; + } else { + /* Work-around until there's a way to obtain remote LID info */ + req_msg->primary_local_lid = IB_LID_PERMISSIVE; + req_msg->primary_remote_lid = IB_LID_PERMISSIVE; + } + req_msg->primary_local_gid = pri_path->sgid; + req_msg->primary_remote_gid = pri_path->dgid; + cm_req_set_primary_flow_label(req_msg, pri_path->flow_label); + cm_req_set_primary_packet_rate(req_msg, pri_path->rate); + req_msg->primary_traffic_class = pri_path->traffic_class; + req_msg->primary_hop_limit = pri_path->hop_limit; + cm_req_set_primary_sl(req_msg, pri_path->sl); + cm_req_set_primary_subnet_local(req_msg, (pri_path->hop_limit <= 1)); + cm_req_set_primary_local_ack_timeout(req_msg, + cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay, + pri_path->packet_life_time)); + + if (alt_path) { + if (alt_path->hop_limit <= 1) { + req_msg->alt_local_lid = alt_path->slid; + req_msg->alt_remote_lid = alt_path->dlid; + } else { + req_msg->alt_local_lid = IB_LID_PERMISSIVE; + req_msg->alt_remote_lid = IB_LID_PERMISSIVE; + } + req_msg->alt_local_gid = alt_path->sgid; + req_msg->alt_remote_gid = alt_path->dgid; + cm_req_set_alt_flow_label(req_msg, + alt_path->flow_label); + cm_req_set_alt_packet_rate(req_msg, alt_path->rate); + req_msg->alt_traffic_class = alt_path->traffic_class; + req_msg->alt_hop_limit = alt_path->hop_limit; + cm_req_set_alt_sl(req_msg, alt_path->sl); + cm_req_set_alt_subnet_local(req_msg, (alt_path->hop_limit <= 1)); + cm_req_set_alt_local_ack_timeout(req_msg, + cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay, + alt_path->packet_life_time)); + } + + if (param->private_data && param->private_data_len) + memcpy(req_msg->private_data, param->private_data, + param->private_data_len); +} + +static int cm_validate_req_param(struct ib_cm_req_param *param) +{ + /* peer-to-peer not supported */ + if (param->peer_to_peer) + return -EINVAL; + + if (!param->primary_path) + return -EINVAL; + + if (param->qp_type != IB_QPT_RC && param->qp_type != IB_QPT_UC) + return -EINVAL; + + if (param->private_data && + param->private_data_len > IB_CM_REQ_PRIVATE_DATA_SIZE) + return -EINVAL; + + if (param->alternate_path && + (param->alternate_path->pkey != param->primary_path->pkey || + param->alternate_path->mtu != param->primary_path->mtu)) + return -EINVAL; + + return 0; +} + +int ib_send_cm_req(struct ib_cm_id *cm_id, + struct ib_cm_req_param *param) +{ + struct cm_id_private *cm_id_priv; + struct cm_req_msg *req_msg; + unsigned long flags; + int ret; + + ret = cm_validate_req_param(param); + if (ret) + return ret; + + /* Verify that we're not in timewait. */ + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id->state != IB_CM_IDLE) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + ret = -EINVAL; + goto out; + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + + cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv-> + id.local_id); + if (IS_ERR(cm_id_priv->timewait_info)) { + ret = PTR_ERR(cm_id_priv->timewait_info); + goto out; + } + + ret = cm_init_av_by_path(param->primary_path, &cm_id_priv->av); + if (ret) + goto error1; + if (param->alternate_path) { + ret = cm_init_av_by_path(param->alternate_path, + &cm_id_priv->alt_av); + if (ret) + goto error1; + } + cm_id->service_id = param->service_id; + cm_id->service_mask = ~cpu_to_be64(0); + cm_id_priv->timeout_ms = cm_convert_to_ms( + param->primary_path->packet_life_time) * 2 + + cm_convert_to_ms( + param->remote_cm_response_timeout); + if (cm_id_priv->timeout_ms > cm_convert_to_ms(max_timeout)) { + printk(KERN_WARNING PFX "req timeout_ms %d > %d, decreasing\n", + cm_id_priv->timeout_ms, cm_convert_to_ms(max_timeout)); + cm_id_priv->timeout_ms = cm_convert_to_ms(max_timeout); + } + cm_id_priv->max_cm_retries = param->max_cm_retries; + cm_id_priv->initiator_depth = param->initiator_depth; + cm_id_priv->responder_resources = param->responder_resources; + cm_id_priv->retry_count = param->retry_count; + cm_id_priv->path_mtu = param->primary_path->mtu; + cm_id_priv->pkey = param->primary_path->pkey; + cm_id_priv->qp_type = param->qp_type; + + ret = cm_alloc_msg(cm_id_priv, &cm_id_priv->msg); + if (ret) + goto error1; + + req_msg = (struct cm_req_msg *) cm_id_priv->msg->mad; + cm_format_req(req_msg, cm_id_priv, param); + cm_id_priv->tid = req_msg->hdr.tid; + cm_id_priv->msg->timeout_ms = cm_id_priv->timeout_ms; + cm_id_priv->msg->context[1] = (void *) (unsigned long) IB_CM_REQ_SENT; + + cm_id_priv->local_qpn = cm_req_get_local_qpn(req_msg); + cm_id_priv->rq_psn = cm_req_get_starting_psn(req_msg); + + spin_lock_irqsave(&cm_id_priv->lock, flags); + ret = ib_post_send_mad(cm_id_priv->msg, NULL); + if (ret) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + goto error2; + } + BUG_ON(cm_id->state != IB_CM_IDLE); + cm_id->state = IB_CM_REQ_SENT; + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return 0; + +error2: cm_free_msg(cm_id_priv->msg); +error1: kfree(cm_id_priv->timewait_info); +out: return ret; +} +EXPORT_SYMBOL(ib_send_cm_req); + +static int cm_issue_rej(struct cm_port *port, + struct ib_mad_recv_wc *mad_recv_wc, + enum ib_cm_rej_reason reason, + enum cm_msg_response msg_rejected, + void *ari, u8 ari_length) +{ + struct ib_mad_send_buf *msg = NULL; + struct cm_rej_msg *rej_msg, *rcv_msg; + int ret; + + ret = cm_alloc_response_msg(port, mad_recv_wc, &msg); + if (ret) + return ret; + + /* We just need common CM header information. Cast to any message. */ + rcv_msg = (struct cm_rej_msg *) mad_recv_wc->recv_buf.mad; + rej_msg = (struct cm_rej_msg *) msg->mad; + + cm_format_mad_hdr(&rej_msg->hdr, CM_REJ_ATTR_ID, rcv_msg->hdr.tid); + rej_msg->remote_comm_id = rcv_msg->local_comm_id; + rej_msg->local_comm_id = rcv_msg->remote_comm_id; + cm_rej_set_msg_rejected(rej_msg, msg_rejected); + rej_msg->reason = cpu_to_be16(reason); + + if (ari && ari_length) { + cm_rej_set_reject_info_len(rej_msg, ari_length); + memcpy(rej_msg->ari, ari, ari_length); + } + + ret = ib_post_send_mad(msg, NULL); + if (ret) + cm_free_msg(msg); + + return ret; +} + +static inline int cm_is_active_peer(__be64 local_ca_guid, __be64 remote_ca_guid, + __be32 local_qpn, __be32 remote_qpn) +{ + return (be64_to_cpu(local_ca_guid) > be64_to_cpu(remote_ca_guid) || + ((local_ca_guid == remote_ca_guid) && + (be32_to_cpu(local_qpn) > be32_to_cpu(remote_qpn)))); +} + +static void cm_format_paths_from_req(struct cm_req_msg *req_msg, + struct ib_sa_path_rec *primary_path, + struct ib_sa_path_rec *alt_path) +{ + memset(primary_path, 0, sizeof *primary_path); + primary_path->dgid = req_msg->primary_local_gid; + primary_path->sgid = req_msg->primary_remote_gid; + primary_path->dlid = req_msg->primary_local_lid; + primary_path->slid = req_msg->primary_remote_lid; + primary_path->flow_label = cm_req_get_primary_flow_label(req_msg); + primary_path->hop_limit = req_msg->primary_hop_limit; + primary_path->traffic_class = req_msg->primary_traffic_class; + primary_path->reversible = 1; + primary_path->pkey = req_msg->pkey; + primary_path->sl = cm_req_get_primary_sl(req_msg); + primary_path->mtu_selector = IB_SA_EQ; + primary_path->mtu = cm_req_get_path_mtu(req_msg); + primary_path->rate_selector = IB_SA_EQ; + primary_path->rate = cm_req_get_primary_packet_rate(req_msg); + primary_path->packet_life_time_selector = IB_SA_EQ; + primary_path->packet_life_time = + cm_req_get_primary_local_ack_timeout(req_msg); + primary_path->packet_life_time -= (primary_path->packet_life_time > 0); + + if (req_msg->alt_local_lid) { + memset(alt_path, 0, sizeof *alt_path); + alt_path->dgid = req_msg->alt_local_gid; + alt_path->sgid = req_msg->alt_remote_gid; + alt_path->dlid = req_msg->alt_local_lid; + alt_path->slid = req_msg->alt_remote_lid; + alt_path->flow_label = cm_req_get_alt_flow_label(req_msg); + alt_path->hop_limit = req_msg->alt_hop_limit; + alt_path->traffic_class = req_msg->alt_traffic_class; + alt_path->reversible = 1; + alt_path->pkey = req_msg->pkey; + alt_path->sl = cm_req_get_alt_sl(req_msg); + alt_path->mtu_selector = IB_SA_EQ; + alt_path->mtu = cm_req_get_path_mtu(req_msg); + alt_path->rate_selector = IB_SA_EQ; + alt_path->rate = cm_req_get_alt_packet_rate(req_msg); + alt_path->packet_life_time_selector = IB_SA_EQ; + alt_path->packet_life_time = + cm_req_get_alt_local_ack_timeout(req_msg); + alt_path->packet_life_time -= (alt_path->packet_life_time > 0); + } +} + +static void cm_format_req_event(struct cm_work *work, + struct cm_id_private *cm_id_priv, + struct ib_cm_id *listen_id) +{ + struct cm_req_msg *req_msg; + struct ib_cm_req_event_param *param; + + req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; + param = &work->cm_event.param.req_rcvd; + param->listen_id = listen_id; + param->port = cm_id_priv->av.port->port_num; + param->primary_path = &work->path[0]; + if (req_msg->alt_local_lid) + param->alternate_path = &work->path[1]; + else + param->alternate_path = NULL; + param->remote_ca_guid = req_msg->local_ca_guid; + param->remote_qkey = be32_to_cpu(req_msg->local_qkey); + param->remote_qpn = be32_to_cpu(cm_req_get_local_qpn(req_msg)); + param->qp_type = cm_req_get_qp_type(req_msg); + param->starting_psn = be32_to_cpu(cm_req_get_starting_psn(req_msg)); + param->responder_resources = cm_req_get_init_depth(req_msg); + param->initiator_depth = cm_req_get_resp_res(req_msg); + param->local_cm_response_timeout = + cm_req_get_remote_resp_timeout(req_msg); + param->flow_control = cm_req_get_flow_ctrl(req_msg); + param->remote_cm_response_timeout = + cm_req_get_local_resp_timeout(req_msg); + param->retry_count = cm_req_get_retry_count(req_msg); + param->rnr_retry_count = cm_req_get_rnr_retry_count(req_msg); + param->srq = cm_req_get_srq(req_msg); + work->cm_event.private_data = &req_msg->private_data; +} + +static void cm_process_work(struct cm_id_private *cm_id_priv, + struct cm_work *work) +{ + int ret; + + /* We will typically only have the current event to report. */ + ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, &work->cm_event); + cm_free_work(work); + + while (!ret && !atomic_add_negative(-1, &cm_id_priv->work_count)) { + spin_lock_irq(&cm_id_priv->lock); + work = cm_dequeue_work(cm_id_priv); + spin_unlock_irq(&cm_id_priv->lock); + BUG_ON(!work); + ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, + &work->cm_event); + cm_free_work(work); + } + cm_deref_id(cm_id_priv); + if (ret) + cm_destroy_id(&cm_id_priv->id, ret); +} + +static void cm_format_mra(struct cm_mra_msg *mra_msg, + struct cm_id_private *cm_id_priv, + enum cm_msg_response msg_mraed, u8 service_timeout, + const void *private_data, u8 private_data_len) +{ + cm_format_mad_hdr(&mra_msg->hdr, CM_MRA_ATTR_ID, cm_id_priv->tid); + cm_mra_set_msg_mraed(mra_msg, msg_mraed); + mra_msg->local_comm_id = cm_id_priv->id.local_id; + mra_msg->remote_comm_id = cm_id_priv->id.remote_id; + cm_mra_set_service_timeout(mra_msg, service_timeout); + + if (private_data && private_data_len) + memcpy(mra_msg->private_data, private_data, private_data_len); +} + +static void cm_format_rej(struct cm_rej_msg *rej_msg, + struct cm_id_private *cm_id_priv, + enum ib_cm_rej_reason reason, + void *ari, + u8 ari_length, + const void *private_data, + u8 private_data_len) +{ + cm_format_mad_hdr(&rej_msg->hdr, CM_REJ_ATTR_ID, cm_id_priv->tid); + rej_msg->remote_comm_id = cm_id_priv->id.remote_id; + + switch(cm_id_priv->id.state) { + case IB_CM_REQ_RCVD: + rej_msg->local_comm_id = 0; + cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_REQ); + break; + case IB_CM_MRA_REQ_SENT: + rej_msg->local_comm_id = cm_id_priv->id.local_id; + cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_REQ); + break; + case IB_CM_REP_RCVD: + case IB_CM_MRA_REP_SENT: + rej_msg->local_comm_id = cm_id_priv->id.local_id; + cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_REP); + break; + default: + rej_msg->local_comm_id = cm_id_priv->id.local_id; + cm_rej_set_msg_rejected(rej_msg, CM_MSG_RESPONSE_OTHER); + break; + } + + rej_msg->reason = cpu_to_be16(reason); + if (ari && ari_length) { + cm_rej_set_reject_info_len(rej_msg, ari_length); + memcpy(rej_msg->ari, ari, ari_length); + } + + if (private_data && private_data_len) + memcpy(rej_msg->private_data, private_data, private_data_len); +} + +static void cm_dup_req_handler(struct cm_work *work, + struct cm_id_private *cm_id_priv) +{ + struct ib_mad_send_buf *msg = NULL; + int ret; + + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_REQ_COUNTER]); + + /* Quick state check to discard duplicate REQs. */ + if (cm_id_priv->id.state == IB_CM_REQ_RCVD) + return; + + ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg); + if (ret) + return; + + spin_lock_irq(&cm_id_priv->lock); + switch (cm_id_priv->id.state) { + case IB_CM_MRA_REQ_SENT: + cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, + CM_MSG_RESPONSE_REQ, cm_id_priv->service_timeout, + cm_id_priv->private_data, + cm_id_priv->private_data_len); + break; + case IB_CM_TIMEWAIT: + cm_format_rej((struct cm_rej_msg *) msg->mad, cm_id_priv, + IB_CM_REJ_STALE_CONN, NULL, 0, NULL, 0); + break; + default: + goto unlock; + } + spin_unlock_irq(&cm_id_priv->lock); + + ret = ib_post_send_mad(msg, NULL); + if (ret) + goto free; + return; + +unlock: spin_unlock_irq(&cm_id_priv->lock); +free: cm_free_msg(msg); +} + +static struct cm_id_private * cm_match_req(struct cm_work *work, + struct cm_id_private *cm_id_priv) +{ + struct cm_id_private *listen_cm_id_priv, *cur_cm_id_priv; + struct cm_timewait_info *timewait_info; + struct cm_req_msg *req_msg; + + req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; + + /* Check for possible duplicate REQ. */ + spin_lock_irq(&cm.lock); + timewait_info = cm_insert_remote_id(cm_id_priv->timewait_info); + if (timewait_info) { + cur_cm_id_priv = cm_get_id(timewait_info->work.local_id, + timewait_info->work.remote_id); + spin_unlock_irq(&cm.lock); + if (cur_cm_id_priv) { + cm_dup_req_handler(work, cur_cm_id_priv); + cm_deref_id(cur_cm_id_priv); + } + return NULL; + } + + /* Check for stale connections. */ + timewait_info = cm_insert_remote_qpn(cm_id_priv->timewait_info); + if (timewait_info) { + cm_cleanup_timewait(cm_id_priv->timewait_info); + spin_unlock_irq(&cm.lock); + cm_issue_rej(work->port, work->mad_recv_wc, + IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REQ, + NULL, 0); + return NULL; + } + + /* Find matching listen request. */ + listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device, + req_msg->service_id, + req_msg->private_data); + if (!listen_cm_id_priv) { + cm_cleanup_timewait(cm_id_priv->timewait_info); + spin_unlock_irq(&cm.lock); + cm_issue_rej(work->port, work->mad_recv_wc, + IB_CM_REJ_INVALID_SERVICE_ID, CM_MSG_RESPONSE_REQ, + NULL, 0); + goto out; + } + atomic_inc(&listen_cm_id_priv->refcount); + atomic_inc(&cm_id_priv->refcount); + cm_id_priv->id.state = IB_CM_REQ_RCVD; + atomic_inc(&cm_id_priv->work_count); + spin_unlock_irq(&cm.lock); +out: + return listen_cm_id_priv; +} + +/* + * Work-around for inter-subnet connections. If the LIDs are permissive, + * we need to override the LID/SL data in the REQ with the LID information + * in the work completion. + */ +static void cm_process_routed_req(struct cm_req_msg *req_msg, struct ib_wc *wc) +{ + if (!cm_req_get_primary_subnet_local(req_msg)) { + if (req_msg->primary_local_lid == IB_LID_PERMISSIVE) { + req_msg->primary_local_lid = cpu_to_be16(wc->slid); + cm_req_set_primary_sl(req_msg, wc->sl); + } + + if (req_msg->primary_remote_lid == IB_LID_PERMISSIVE) + req_msg->primary_remote_lid = cpu_to_be16(wc->dlid_path_bits); + } + + if (!cm_req_get_alt_subnet_local(req_msg)) { + if (req_msg->alt_local_lid == IB_LID_PERMISSIVE) { + req_msg->alt_local_lid = cpu_to_be16(wc->slid); + cm_req_set_alt_sl(req_msg, wc->sl); + } + + if (req_msg->alt_remote_lid == IB_LID_PERMISSIVE) + req_msg->alt_remote_lid = cpu_to_be16(wc->dlid_path_bits); + } +} + +static int cm_req_handler(struct cm_work *work) +{ + struct ib_cm_id *cm_id; + struct cm_id_private *cm_id_priv, *listen_cm_id_priv; + struct cm_req_msg *req_msg; + int ret; + + req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; + + cm_id = ib_create_cm_id(work->port->cm_dev->ib_device, NULL, NULL); + if (IS_ERR(cm_id)) + return PTR_ERR(cm_id); + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + cm_id_priv->id.remote_id = req_msg->local_comm_id; + cm_init_av_for_response(work->port, work->mad_recv_wc->wc, + work->mad_recv_wc->recv_buf.grh, + &cm_id_priv->av); + cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv-> + id.local_id); + if (IS_ERR(cm_id_priv->timewait_info)) { + ret = PTR_ERR(cm_id_priv->timewait_info); + goto destroy; + } + cm_id_priv->timewait_info->work.remote_id = req_msg->local_comm_id; + cm_id_priv->timewait_info->remote_ca_guid = req_msg->local_ca_guid; + cm_id_priv->timewait_info->remote_qpn = cm_req_get_local_qpn(req_msg); + + listen_cm_id_priv = cm_match_req(work, cm_id_priv); + if (!listen_cm_id_priv) { + ret = -EINVAL; + kfree(cm_id_priv->timewait_info); + goto destroy; + } + + cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler; + cm_id_priv->id.context = listen_cm_id_priv->id.context; + cm_id_priv->id.service_id = req_msg->service_id; + cm_id_priv->id.service_mask = ~cpu_to_be64(0); + + cm_process_routed_req(req_msg, work->mad_recv_wc->wc); + cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]); + ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av); + if (ret) { + ib_get_cached_gid(work->port->cm_dev->ib_device, + work->port->port_num, 0, &work->path[0].sgid); + ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_GID, + &work->path[0].sgid, sizeof work->path[0].sgid, + NULL, 0); + goto rejected; + } + if (req_msg->alt_local_lid) { + ret = cm_init_av_by_path(&work->path[1], &cm_id_priv->alt_av); + if (ret) { + ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_ALT_GID, + &work->path[0].sgid, + sizeof work->path[0].sgid, NULL, 0); + goto rejected; + } + } + cm_id_priv->tid = req_msg->hdr.tid; + cm_id_priv->timeout_ms = cm_convert_to_ms( + cm_req_get_local_resp_timeout(req_msg)); + if (cm_req_get_local_resp_timeout(req_msg) > (u8) max_timeout) { + printk(KERN_WARNING PFX "rcvd cm_local_resp_timeout %d > %d, " + "decreasing used timeout_ms\n", + cm_req_get_local_resp_timeout(req_msg), max_timeout); + cm_id_priv->timeout_ms = cm_convert_to_ms(max_timeout); + } + + cm_id_priv->max_cm_retries = cm_req_get_max_cm_retries(req_msg); + cm_id_priv->remote_qpn = cm_req_get_local_qpn(req_msg); + cm_id_priv->initiator_depth = cm_req_get_resp_res(req_msg); + cm_id_priv->responder_resources = cm_req_get_init_depth(req_msg); + cm_id_priv->path_mtu = cm_req_get_path_mtu(req_msg); + cm_id_priv->pkey = req_msg->pkey; + cm_id_priv->sq_psn = cm_req_get_starting_psn(req_msg); + cm_id_priv->retry_count = cm_req_get_retry_count(req_msg); + cm_id_priv->rnr_retry_count = cm_req_get_rnr_retry_count(req_msg); + cm_id_priv->qp_type = cm_req_get_qp_type(req_msg); + + cm_format_req_event(work, cm_id_priv, &listen_cm_id_priv->id); + cm_process_work(cm_id_priv, work); + cm_deref_id(listen_cm_id_priv); + return 0; + +rejected: + atomic_dec(&cm_id_priv->refcount); + cm_deref_id(listen_cm_id_priv); +destroy: + ib_destroy_cm_id(cm_id); + return ret; +} + +static void cm_format_rep(struct cm_rep_msg *rep_msg, + struct cm_id_private *cm_id_priv, + struct ib_cm_rep_param *param) +{ + cm_format_mad_hdr(&rep_msg->hdr, CM_REP_ATTR_ID, cm_id_priv->tid); + rep_msg->local_comm_id = cm_id_priv->id.local_id; + rep_msg->remote_comm_id = cm_id_priv->id.remote_id; + cm_rep_set_local_qpn(rep_msg, cpu_to_be32(param->qp_num)); + cm_rep_set_starting_psn(rep_msg, cpu_to_be32(param->starting_psn)); + rep_msg->resp_resources = param->responder_resources; + rep_msg->initiator_depth = param->initiator_depth; + cm_rep_set_target_ack_delay(rep_msg, + cm_id_priv->av.port->cm_dev->ack_delay); + cm_rep_set_failover(rep_msg, param->failover_accepted); + cm_rep_set_flow_ctrl(rep_msg, param->flow_control); + cm_rep_set_rnr_retry_count(rep_msg, param->rnr_retry_count); + cm_rep_set_srq(rep_msg, param->srq); + rep_msg->local_ca_guid = cm_id_priv->id.device->node_guid; + + if (param->private_data && param->private_data_len) + memcpy(rep_msg->private_data, param->private_data, + param->private_data_len); +} + +int ib_send_cm_rep(struct ib_cm_id *cm_id, + struct ib_cm_rep_param *param) +{ + struct cm_id_private *cm_id_priv; + struct ib_mad_send_buf *msg; + struct cm_rep_msg *rep_msg; + unsigned long flags; + int ret; + + if (param->private_data && + param->private_data_len > IB_CM_REP_PRIVATE_DATA_SIZE) + return -EINVAL; + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id->state != IB_CM_REQ_RCVD && + cm_id->state != IB_CM_MRA_REQ_SENT) { + ret = -EINVAL; + goto out; + } + + ret = cm_alloc_msg(cm_id_priv, &msg); + if (ret) + goto out; + + rep_msg = (struct cm_rep_msg *) msg->mad; + cm_format_rep(rep_msg, cm_id_priv, param); + msg->timeout_ms = cm_id_priv->timeout_ms; + msg->context[1] = (void *) (unsigned long) IB_CM_REP_SENT; + + ret = ib_post_send_mad(msg, NULL); + if (ret) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + cm_free_msg(msg); + return ret; + } + + cm_id->state = IB_CM_REP_SENT; + cm_id_priv->msg = msg; + cm_id_priv->initiator_depth = param->initiator_depth; + cm_id_priv->responder_resources = param->responder_resources; + cm_id_priv->rq_psn = cm_rep_get_starting_psn(rep_msg); + cm_id_priv->local_qpn = cm_rep_get_local_qpn(rep_msg); + +out: spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return ret; +} +EXPORT_SYMBOL(ib_send_cm_rep); + +static void cm_format_rtu(struct cm_rtu_msg *rtu_msg, + struct cm_id_private *cm_id_priv, + const void *private_data, + u8 private_data_len) +{ + cm_format_mad_hdr(&rtu_msg->hdr, CM_RTU_ATTR_ID, cm_id_priv->tid); + rtu_msg->local_comm_id = cm_id_priv->id.local_id; + rtu_msg->remote_comm_id = cm_id_priv->id.remote_id; + + if (private_data && private_data_len) + memcpy(rtu_msg->private_data, private_data, private_data_len); +} + +int ib_send_cm_rtu(struct ib_cm_id *cm_id, + const void *private_data, + u8 private_data_len) +{ + struct cm_id_private *cm_id_priv; + struct ib_mad_send_buf *msg; + unsigned long flags; + void *data; + int ret; + + if (private_data && private_data_len > IB_CM_RTU_PRIVATE_DATA_SIZE) + return -EINVAL; + + data = cm_copy_private_data(private_data, private_data_len); + if (IS_ERR(data)) + return PTR_ERR(data); + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id->state != IB_CM_REP_RCVD && + cm_id->state != IB_CM_MRA_REP_SENT) { + ret = -EINVAL; + goto error; + } + + ret = cm_alloc_msg(cm_id_priv, &msg); + if (ret) + goto error; + + cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv, + private_data, private_data_len); + + ret = ib_post_send_mad(msg, NULL); + if (ret) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + cm_free_msg(msg); + kfree(data); + return ret; + } + + cm_id->state = IB_CM_ESTABLISHED; + cm_set_private_data(cm_id_priv, data, private_data_len); + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return 0; + +error: spin_unlock_irqrestore(&cm_id_priv->lock, flags); + kfree(data); + return ret; +} +EXPORT_SYMBOL(ib_send_cm_rtu); + +static void cm_format_rep_event(struct cm_work *work) +{ + struct cm_rep_msg *rep_msg; + struct ib_cm_rep_event_param *param; + + rep_msg = (struct cm_rep_msg *)work->mad_recv_wc->recv_buf.mad; + param = &work->cm_event.param.rep_rcvd; + param->remote_ca_guid = rep_msg->local_ca_guid; + param->remote_qkey = be32_to_cpu(rep_msg->local_qkey); + param->remote_qpn = be32_to_cpu(cm_rep_get_local_qpn(rep_msg)); + param->starting_psn = be32_to_cpu(cm_rep_get_starting_psn(rep_msg)); + param->responder_resources = rep_msg->initiator_depth; + param->initiator_depth = rep_msg->resp_resources; + param->target_ack_delay = cm_rep_get_target_ack_delay(rep_msg); + param->failover_accepted = cm_rep_get_failover(rep_msg); + param->flow_control = cm_rep_get_flow_ctrl(rep_msg); + param->rnr_retry_count = cm_rep_get_rnr_retry_count(rep_msg); + param->srq = cm_rep_get_srq(rep_msg); + work->cm_event.private_data = &rep_msg->private_data; +} + +static void cm_dup_rep_handler(struct cm_work *work) +{ + struct cm_id_private *cm_id_priv; + struct cm_rep_msg *rep_msg; + struct ib_mad_send_buf *msg = NULL; + int ret; + + rep_msg = (struct cm_rep_msg *) work->mad_recv_wc->recv_buf.mad; + cm_id_priv = cm_acquire_id(rep_msg->remote_comm_id, + rep_msg->local_comm_id); + if (!cm_id_priv) + return; + + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_REP_COUNTER]); + ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg); + if (ret) + goto deref; + + spin_lock_irq(&cm_id_priv->lock); + if (cm_id_priv->id.state == IB_CM_ESTABLISHED) + cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv, + cm_id_priv->private_data, + cm_id_priv->private_data_len); + else if (cm_id_priv->id.state == IB_CM_MRA_REP_SENT) + cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, + CM_MSG_RESPONSE_REP, cm_id_priv->service_timeout, + cm_id_priv->private_data, + cm_id_priv->private_data_len); + else + goto unlock; + spin_unlock_irq(&cm_id_priv->lock); + + ret = ib_post_send_mad(msg, NULL); + if (ret) + goto free; + goto deref; + +unlock: spin_unlock_irq(&cm_id_priv->lock); +free: cm_free_msg(msg); +deref: cm_deref_id(cm_id_priv); +} + +static int cm_rep_handler(struct cm_work *work) +{ + struct cm_id_private *cm_id_priv; + struct cm_rep_msg *rep_msg; + int ret; + + rep_msg = (struct cm_rep_msg *)work->mad_recv_wc->recv_buf.mad; + cm_id_priv = cm_acquire_id(rep_msg->remote_comm_id, 0); + if (!cm_id_priv) { + cm_dup_rep_handler(work); + return -EINVAL; + } + + cm_format_rep_event(work); + + spin_lock_irq(&cm_id_priv->lock); + switch (cm_id_priv->id.state) { + case IB_CM_REQ_SENT: + case IB_CM_MRA_REQ_RCVD: + break; + default: + spin_unlock_irq(&cm_id_priv->lock); + ret = -EINVAL; + goto error; + } + + cm_id_priv->timewait_info->work.remote_id = rep_msg->local_comm_id; + cm_id_priv->timewait_info->remote_ca_guid = rep_msg->local_ca_guid; + cm_id_priv->timewait_info->remote_qpn = cm_rep_get_local_qpn(rep_msg); + + spin_lock(&cm.lock); + /* Check for duplicate REP. */ + if (cm_insert_remote_id(cm_id_priv->timewait_info)) { + spin_unlock(&cm.lock); + spin_unlock_irq(&cm_id_priv->lock); + ret = -EINVAL; + goto error; + } + /* Check for a stale connection. */ + if (cm_insert_remote_qpn(cm_id_priv->timewait_info)) { + rb_erase(&cm_id_priv->timewait_info->remote_id_node, + &cm.remote_id_table); + cm_id_priv->timewait_info->inserted_remote_id = 0; + spin_unlock(&cm.lock); + spin_unlock_irq(&cm_id_priv->lock); + cm_issue_rej(work->port, work->mad_recv_wc, + IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REP, + NULL, 0); + ret = -EINVAL; + goto error; + } + spin_unlock(&cm.lock); + + cm_id_priv->id.state = IB_CM_REP_RCVD; + cm_id_priv->id.remote_id = rep_msg->local_comm_id; + cm_id_priv->remote_qpn = cm_rep_get_local_qpn(rep_msg); + cm_id_priv->initiator_depth = rep_msg->resp_resources; + cm_id_priv->responder_resources = rep_msg->initiator_depth; + cm_id_priv->sq_psn = cm_rep_get_starting_psn(rep_msg); + cm_id_priv->rnr_retry_count = cm_rep_get_rnr_retry_count(rep_msg); + cm_id_priv->target_ack_delay = cm_rep_get_target_ack_delay(rep_msg); + cm_id_priv->av.timeout = + cm_ack_timeout(cm_id_priv->target_ack_delay, + cm_id_priv->av.timeout - 1); + cm_id_priv->alt_av.timeout = + cm_ack_timeout(cm_id_priv->target_ack_delay, + cm_id_priv->alt_av.timeout - 1); + + /* todo: handle peer_to_peer */ + + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + ret = atomic_inc_and_test(&cm_id_priv->work_count); + if (!ret) + list_add_tail(&work->list, &cm_id_priv->work_list); + spin_unlock_irq(&cm_id_priv->lock); + + if (ret) + cm_process_work(cm_id_priv, work); + else + cm_deref_id(cm_id_priv); + return 0; + +error: + cm_deref_id(cm_id_priv); + return ret; +} + +static int cm_establish_handler(struct cm_work *work) +{ + struct cm_id_private *cm_id_priv; + int ret; + + /* See comment in cm_establish about lookup. */ + cm_id_priv = cm_acquire_id(work->local_id, work->remote_id); + if (!cm_id_priv) + return -EINVAL; + + spin_lock_irq(&cm_id_priv->lock); + if (cm_id_priv->id.state != IB_CM_ESTABLISHED) { + spin_unlock_irq(&cm_id_priv->lock); + goto out; + } + + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + ret = atomic_inc_and_test(&cm_id_priv->work_count); + if (!ret) + list_add_tail(&work->list, &cm_id_priv->work_list); + spin_unlock_irq(&cm_id_priv->lock); + + if (ret) + cm_process_work(cm_id_priv, work); + else + cm_deref_id(cm_id_priv); + return 0; +out: + cm_deref_id(cm_id_priv); + return -EINVAL; +} + +static int cm_rtu_handler(struct cm_work *work) +{ + struct cm_id_private *cm_id_priv; + struct cm_rtu_msg *rtu_msg; + int ret; + + rtu_msg = (struct cm_rtu_msg *)work->mad_recv_wc->recv_buf.mad; + cm_id_priv = cm_acquire_id(rtu_msg->remote_comm_id, + rtu_msg->local_comm_id); + if (!cm_id_priv) + return -EINVAL; + + work->cm_event.private_data = &rtu_msg->private_data; + + spin_lock_irq(&cm_id_priv->lock); + if (cm_id_priv->id.state != IB_CM_REP_SENT && + cm_id_priv->id.state != IB_CM_MRA_REP_RCVD) { + spin_unlock_irq(&cm_id_priv->lock); + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_RTU_COUNTER]); + goto out; + } + cm_id_priv->id.state = IB_CM_ESTABLISHED; + + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + ret = atomic_inc_and_test(&cm_id_priv->work_count); + if (!ret) + list_add_tail(&work->list, &cm_id_priv->work_list); + spin_unlock_irq(&cm_id_priv->lock); + + if (ret) + cm_process_work(cm_id_priv, work); + else + cm_deref_id(cm_id_priv); + return 0; +out: + cm_deref_id(cm_id_priv); + return -EINVAL; +} + +static void cm_format_dreq(struct cm_dreq_msg *dreq_msg, + struct cm_id_private *cm_id_priv, + const void *private_data, + u8 private_data_len) +{ + cm_format_mad_hdr(&dreq_msg->hdr, CM_DREQ_ATTR_ID, + cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_DREQ)); + dreq_msg->local_comm_id = cm_id_priv->id.local_id; + dreq_msg->remote_comm_id = cm_id_priv->id.remote_id; + cm_dreq_set_remote_qpn(dreq_msg, cm_id_priv->remote_qpn); + + if (private_data && private_data_len) + memcpy(dreq_msg->private_data, private_data, private_data_len); +} + +int ib_send_cm_dreq(struct ib_cm_id *cm_id, + const void *private_data, + u8 private_data_len) +{ + struct cm_id_private *cm_id_priv; + struct ib_mad_send_buf *msg; + unsigned long flags; + int ret; + + if (private_data && private_data_len > IB_CM_DREQ_PRIVATE_DATA_SIZE) + return -EINVAL; + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id->state != IB_CM_ESTABLISHED) { + ret = -EINVAL; + goto out; + } + + ret = cm_alloc_msg(cm_id_priv, &msg); + if (ret) { + cm_enter_timewait(cm_id_priv); + goto out; + } + + cm_format_dreq((struct cm_dreq_msg *) msg->mad, cm_id_priv, + private_data, private_data_len); + msg->timeout_ms = cm_id_priv->timeout_ms; + msg->context[1] = (void *) (unsigned long) IB_CM_DREQ_SENT; + + ret = ib_post_send_mad(msg, NULL); + if (ret) { + cm_enter_timewait(cm_id_priv); + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + cm_free_msg(msg); + return ret; + } + + cm_id->state = IB_CM_DREQ_SENT; + cm_id_priv->msg = msg; +out: spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return ret; +} +EXPORT_SYMBOL(ib_send_cm_dreq); + +static void cm_format_drep(struct cm_drep_msg *drep_msg, + struct cm_id_private *cm_id_priv, + const void *private_data, + u8 private_data_len) +{ + cm_format_mad_hdr(&drep_msg->hdr, CM_DREP_ATTR_ID, cm_id_priv->tid); + drep_msg->local_comm_id = cm_id_priv->id.local_id; + drep_msg->remote_comm_id = cm_id_priv->id.remote_id; + + if (private_data && private_data_len) + memcpy(drep_msg->private_data, private_data, private_data_len); +} + +int ib_send_cm_drep(struct ib_cm_id *cm_id, + const void *private_data, + u8 private_data_len) +{ + struct cm_id_private *cm_id_priv; + struct ib_mad_send_buf *msg; + unsigned long flags; + void *data; + int ret; + + if (private_data && private_data_len > IB_CM_DREP_PRIVATE_DATA_SIZE) + return -EINVAL; + + data = cm_copy_private_data(private_data, private_data_len); + if (IS_ERR(data)) + return PTR_ERR(data); + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id->state != IB_CM_DREQ_RCVD) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + kfree(data); + return -EINVAL; + } + + cm_set_private_data(cm_id_priv, data, private_data_len); + cm_enter_timewait(cm_id_priv); + + ret = cm_alloc_msg(cm_id_priv, &msg); + if (ret) + goto out; + + cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv, + private_data, private_data_len); + + ret = ib_post_send_mad(msg, NULL); + if (ret) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + cm_free_msg(msg); + return ret; + } + +out: spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return ret; +} +EXPORT_SYMBOL(ib_send_cm_drep); + +static int cm_issue_drep(struct cm_port *port, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_mad_send_buf *msg = NULL; + struct cm_dreq_msg *dreq_msg; + struct cm_drep_msg *drep_msg; + int ret; + + ret = cm_alloc_response_msg(port, mad_recv_wc, &msg); + if (ret) + return ret; + + dreq_msg = (struct cm_dreq_msg *) mad_recv_wc->recv_buf.mad; + drep_msg = (struct cm_drep_msg *) msg->mad; + + cm_format_mad_hdr(&drep_msg->hdr, CM_DREP_ATTR_ID, dreq_msg->hdr.tid); + drep_msg->remote_comm_id = dreq_msg->local_comm_id; + drep_msg->local_comm_id = dreq_msg->remote_comm_id; + + ret = ib_post_send_mad(msg, NULL); + if (ret) + cm_free_msg(msg); + + return ret; +} + +static int cm_dreq_handler(struct cm_work *work) +{ + struct cm_id_private *cm_id_priv; + struct cm_dreq_msg *dreq_msg; + struct ib_mad_send_buf *msg = NULL; + int ret; + + dreq_msg = (struct cm_dreq_msg *)work->mad_recv_wc->recv_buf.mad; + cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id, + dreq_msg->local_comm_id); + if (!cm_id_priv) { + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_DREQ_COUNTER]); + cm_issue_drep(work->port, work->mad_recv_wc); + return -EINVAL; + } + + work->cm_event.private_data = &dreq_msg->private_data; + + spin_lock_irq(&cm_id_priv->lock); + if (cm_id_priv->local_qpn != cm_dreq_get_remote_qpn(dreq_msg)) + goto unlock; + + switch (cm_id_priv->id.state) { + case IB_CM_REP_SENT: + case IB_CM_DREQ_SENT: + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + break; + case IB_CM_ESTABLISHED: + case IB_CM_MRA_REP_RCVD: + break; + case IB_CM_TIMEWAIT: + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_DREQ_COUNTER]); + if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg)) + goto unlock; + + cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv, + cm_id_priv->private_data, + cm_id_priv->private_data_len); + spin_unlock_irq(&cm_id_priv->lock); + + if (ib_post_send_mad(msg, NULL)) + cm_free_msg(msg); + goto deref; + case IB_CM_DREQ_RCVD: + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_DREQ_COUNTER]); + goto unlock; + default: + goto unlock; + } + cm_id_priv->id.state = IB_CM_DREQ_RCVD; + cm_id_priv->tid = dreq_msg->hdr.tid; + ret = atomic_inc_and_test(&cm_id_priv->work_count); + if (!ret) + list_add_tail(&work->list, &cm_id_priv->work_list); + spin_unlock_irq(&cm_id_priv->lock); + + if (ret) + cm_process_work(cm_id_priv, work); + else + cm_deref_id(cm_id_priv); + return 0; + +unlock: spin_unlock_irq(&cm_id_priv->lock); +deref: cm_deref_id(cm_id_priv); + return -EINVAL; +} + +static int cm_drep_handler(struct cm_work *work) +{ + struct cm_id_private *cm_id_priv; + struct cm_drep_msg *drep_msg; + int ret; + + drep_msg = (struct cm_drep_msg *)work->mad_recv_wc->recv_buf.mad; + cm_id_priv = cm_acquire_id(drep_msg->remote_comm_id, + drep_msg->local_comm_id); + if (!cm_id_priv) + return -EINVAL; + + work->cm_event.private_data = &drep_msg->private_data; + + spin_lock_irq(&cm_id_priv->lock); + if (cm_id_priv->id.state != IB_CM_DREQ_SENT && + cm_id_priv->id.state != IB_CM_DREQ_RCVD) { + spin_unlock_irq(&cm_id_priv->lock); + goto out; + } + cm_enter_timewait(cm_id_priv); + + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + ret = atomic_inc_and_test(&cm_id_priv->work_count); + if (!ret) + list_add_tail(&work->list, &cm_id_priv->work_list); + spin_unlock_irq(&cm_id_priv->lock); + + if (ret) + cm_process_work(cm_id_priv, work); + else + cm_deref_id(cm_id_priv); + return 0; +out: + cm_deref_id(cm_id_priv); + return -EINVAL; +} + +int ib_send_cm_rej(struct ib_cm_id *cm_id, + enum ib_cm_rej_reason reason, + void *ari, + u8 ari_length, + const void *private_data, + u8 private_data_len) +{ + struct cm_id_private *cm_id_priv; + struct ib_mad_send_buf *msg; + unsigned long flags; + int ret; + + if ((private_data && private_data_len > IB_CM_REJ_PRIVATE_DATA_SIZE) || + (ari && ari_length > IB_CM_REJ_ARI_LENGTH)) + return -EINVAL; + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + + spin_lock_irqsave(&cm_id_priv->lock, flags); + switch (cm_id->state) { + case IB_CM_REQ_SENT: + case IB_CM_MRA_REQ_RCVD: + case IB_CM_REQ_RCVD: + case IB_CM_MRA_REQ_SENT: + case IB_CM_REP_RCVD: + case IB_CM_MRA_REP_SENT: + ret = cm_alloc_msg(cm_id_priv, &msg); + if (!ret) + cm_format_rej((struct cm_rej_msg *) msg->mad, + cm_id_priv, reason, ari, ari_length, + private_data, private_data_len); + + cm_reset_to_idle(cm_id_priv); + break; + case IB_CM_REP_SENT: + case IB_CM_MRA_REP_RCVD: + ret = cm_alloc_msg(cm_id_priv, &msg); + if (!ret) + cm_format_rej((struct cm_rej_msg *) msg->mad, + cm_id_priv, reason, ari, ari_length, + private_data, private_data_len); + + cm_enter_timewait(cm_id_priv); + break; + default: + ret = -EINVAL; + goto out; + } + + if (ret) + goto out; + + ret = ib_post_send_mad(msg, NULL); + if (ret) + cm_free_msg(msg); + +out: spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return ret; +} +EXPORT_SYMBOL(ib_send_cm_rej); + +static void cm_format_rej_event(struct cm_work *work) +{ + struct cm_rej_msg *rej_msg; + struct ib_cm_rej_event_param *param; + + rej_msg = (struct cm_rej_msg *)work->mad_recv_wc->recv_buf.mad; + param = &work->cm_event.param.rej_rcvd; + param->ari = rej_msg->ari; + param->ari_length = cm_rej_get_reject_info_len(rej_msg); + param->reason = __be16_to_cpu(rej_msg->reason); + work->cm_event.private_data = &rej_msg->private_data; +} + +static struct cm_id_private * cm_acquire_rejected_id(struct cm_rej_msg *rej_msg) +{ + struct cm_timewait_info *timewait_info; + struct cm_id_private *cm_id_priv; + __be32 remote_id; + + remote_id = rej_msg->local_comm_id; + + if (__be16_to_cpu(rej_msg->reason) == IB_CM_REJ_TIMEOUT) { + spin_lock_irq(&cm.lock); + timewait_info = cm_find_remote_id( *((__be64 *) rej_msg->ari), + remote_id); + if (!timewait_info) { + spin_unlock_irq(&cm.lock); + return NULL; + } + cm_id_priv = idr_find(&cm.local_id_table, (__force int) + (timewait_info->work.local_id ^ + cm.random_id_operand)); + if (cm_id_priv) { + if (cm_id_priv->id.remote_id == remote_id) + atomic_inc(&cm_id_priv->refcount); + else + cm_id_priv = NULL; + } + spin_unlock_irq(&cm.lock); + } else if (cm_rej_get_msg_rejected(rej_msg) == CM_MSG_RESPONSE_REQ) + cm_id_priv = cm_acquire_id(rej_msg->remote_comm_id, 0); + else + cm_id_priv = cm_acquire_id(rej_msg->remote_comm_id, remote_id); + + return cm_id_priv; +} + +static int cm_rej_handler(struct cm_work *work) +{ + struct cm_id_private *cm_id_priv; + struct cm_rej_msg *rej_msg; + int ret; + + rej_msg = (struct cm_rej_msg *)work->mad_recv_wc->recv_buf.mad; + cm_id_priv = cm_acquire_rejected_id(rej_msg); + if (!cm_id_priv) + return -EINVAL; + + cm_format_rej_event(work); + + spin_lock_irq(&cm_id_priv->lock); + switch (cm_id_priv->id.state) { + case IB_CM_REQ_SENT: + case IB_CM_MRA_REQ_RCVD: + case IB_CM_REP_SENT: + case IB_CM_MRA_REP_RCVD: + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + /* fall through */ + case IB_CM_REQ_RCVD: + case IB_CM_MRA_REQ_SENT: + if (__be16_to_cpu(rej_msg->reason) == IB_CM_REJ_STALE_CONN) + cm_enter_timewait(cm_id_priv); + else + cm_reset_to_idle(cm_id_priv); + break; + case IB_CM_DREQ_SENT: + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + /* fall through */ + case IB_CM_REP_RCVD: + case IB_CM_MRA_REP_SENT: + case IB_CM_ESTABLISHED: + cm_enter_timewait(cm_id_priv); + break; + default: + spin_unlock_irq(&cm_id_priv->lock); + ret = -EINVAL; + goto out; + } + + ret = atomic_inc_and_test(&cm_id_priv->work_count); + if (!ret) + list_add_tail(&work->list, &cm_id_priv->work_list); + spin_unlock_irq(&cm_id_priv->lock); + + if (ret) + cm_process_work(cm_id_priv, work); + else + cm_deref_id(cm_id_priv); + return 0; +out: + cm_deref_id(cm_id_priv); + return -EINVAL; +} + +int ib_send_cm_mra(struct ib_cm_id *cm_id, + u8 service_timeout, + const void *private_data, + u8 private_data_len) +{ + struct cm_id_private *cm_id_priv; + struct ib_mad_send_buf *msg; + enum ib_cm_state cm_state; + enum ib_cm_lap_state lap_state; + enum cm_msg_response msg_response; + void *data; + unsigned long flags; + int ret; + + if (private_data && private_data_len > IB_CM_MRA_PRIVATE_DATA_SIZE) + return -EINVAL; + + data = cm_copy_private_data(private_data, private_data_len); + if (IS_ERR(data)) + return PTR_ERR(data); + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + + spin_lock_irqsave(&cm_id_priv->lock, flags); + switch(cm_id_priv->id.state) { + case IB_CM_REQ_RCVD: + cm_state = IB_CM_MRA_REQ_SENT; + lap_state = cm_id->lap_state; + msg_response = CM_MSG_RESPONSE_REQ; + break; + case IB_CM_REP_RCVD: + cm_state = IB_CM_MRA_REP_SENT; + lap_state = cm_id->lap_state; + msg_response = CM_MSG_RESPONSE_REP; + break; + case IB_CM_ESTABLISHED: + if (cm_id->lap_state == IB_CM_LAP_RCVD) { + cm_state = cm_id->state; + lap_state = IB_CM_MRA_LAP_SENT; + msg_response = CM_MSG_RESPONSE_OTHER; + break; + } + default: + ret = -EINVAL; + goto error1; + } + + if (!(service_timeout & IB_CM_MRA_FLAG_DELAY)) { + ret = cm_alloc_msg(cm_id_priv, &msg); + if (ret) + goto error1; + + cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, + msg_response, service_timeout, + private_data, private_data_len); + ret = ib_post_send_mad(msg, NULL); + if (ret) + goto error2; + } + + cm_id->state = cm_state; + cm_id->lap_state = lap_state; + cm_id_priv->service_timeout = service_timeout; + cm_set_private_data(cm_id_priv, data, private_data_len); + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return 0; + +error1: spin_unlock_irqrestore(&cm_id_priv->lock, flags); + kfree(data); + return ret; + +error2: spin_unlock_irqrestore(&cm_id_priv->lock, flags); + kfree(data); + cm_free_msg(msg); + return ret; +} +EXPORT_SYMBOL(ib_send_cm_mra); + +static struct cm_id_private * cm_acquire_mraed_id(struct cm_mra_msg *mra_msg) +{ + switch (cm_mra_get_msg_mraed(mra_msg)) { + case CM_MSG_RESPONSE_REQ: + return cm_acquire_id(mra_msg->remote_comm_id, 0); + case CM_MSG_RESPONSE_REP: + case CM_MSG_RESPONSE_OTHER: + return cm_acquire_id(mra_msg->remote_comm_id, + mra_msg->local_comm_id); + default: + return NULL; + } +} + +static int cm_mra_handler(struct cm_work *work) +{ + struct cm_id_private *cm_id_priv; + struct cm_mra_msg *mra_msg; + int timeout, ret; + + mra_msg = (struct cm_mra_msg *)work->mad_recv_wc->recv_buf.mad; + cm_id_priv = cm_acquire_mraed_id(mra_msg); + if (!cm_id_priv) + return -EINVAL; + + work->cm_event.private_data = &mra_msg->private_data; + work->cm_event.param.mra_rcvd.service_timeout = + cm_mra_get_service_timeout(mra_msg); + timeout = cm_convert_to_ms(cm_mra_get_service_timeout(mra_msg)) + + cm_convert_to_ms(cm_id_priv->av.timeout); + if (timeout > cm_convert_to_ms(max_timeout)) { + printk(KERN_WARNING PFX "calculated mra timeout %d > %d, " + "decreasing used timeout_ms\n", timeout, + cm_convert_to_ms(max_timeout)); + timeout = cm_convert_to_ms(max_timeout); + } + + spin_lock_irq(&cm_id_priv->lock); + switch (cm_id_priv->id.state) { + case IB_CM_REQ_SENT: + if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_REQ || + ib_modify_mad(cm_id_priv->av.port->mad_agent, + cm_id_priv->msg, timeout)) + goto out; + cm_id_priv->id.state = IB_CM_MRA_REQ_RCVD; + break; + case IB_CM_REP_SENT: + if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_REP || + ib_modify_mad(cm_id_priv->av.port->mad_agent, + cm_id_priv->msg, timeout)) + goto out; + cm_id_priv->id.state = IB_CM_MRA_REP_RCVD; + break; + case IB_CM_ESTABLISHED: + if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_OTHER || + cm_id_priv->id.lap_state != IB_CM_LAP_SENT || + ib_modify_mad(cm_id_priv->av.port->mad_agent, + cm_id_priv->msg, timeout)) { + if (cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD) + atomic_long_inc(&work->port-> + counter_group[CM_RECV_DUPLICATES]. + counter[CM_MRA_COUNTER]); + goto out; + } + cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD; + break; + case IB_CM_MRA_REQ_RCVD: + case IB_CM_MRA_REP_RCVD: + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_MRA_COUNTER]); + /* fall through */ + default: + goto out; + } + + cm_id_priv->msg->context[1] = (void *) (unsigned long) + cm_id_priv->id.state; + ret = atomic_inc_and_test(&cm_id_priv->work_count); + if (!ret) + list_add_tail(&work->list, &cm_id_priv->work_list); + spin_unlock_irq(&cm_id_priv->lock); + + if (ret) + cm_process_work(cm_id_priv, work); + else + cm_deref_id(cm_id_priv); + return 0; +out: + spin_unlock_irq(&cm_id_priv->lock); + cm_deref_id(cm_id_priv); + return -EINVAL; +} + +static void cm_format_lap(struct cm_lap_msg *lap_msg, + struct cm_id_private *cm_id_priv, + struct ib_sa_path_rec *alternate_path, + const void *private_data, + u8 private_data_len) +{ + cm_format_mad_hdr(&lap_msg->hdr, CM_LAP_ATTR_ID, + cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_LAP)); + lap_msg->local_comm_id = cm_id_priv->id.local_id; + lap_msg->remote_comm_id = cm_id_priv->id.remote_id; + cm_lap_set_remote_qpn(lap_msg, cm_id_priv->remote_qpn); + /* todo: need remote CM response timeout */ + cm_lap_set_remote_resp_timeout(lap_msg, 0x1F); + lap_msg->alt_local_lid = alternate_path->slid; + lap_msg->alt_remote_lid = alternate_path->dlid; + lap_msg->alt_local_gid = alternate_path->sgid; + lap_msg->alt_remote_gid = alternate_path->dgid; + cm_lap_set_flow_label(lap_msg, alternate_path->flow_label); + cm_lap_set_traffic_class(lap_msg, alternate_path->traffic_class); + lap_msg->alt_hop_limit = alternate_path->hop_limit; + cm_lap_set_packet_rate(lap_msg, alternate_path->rate); + cm_lap_set_sl(lap_msg, alternate_path->sl); + cm_lap_set_subnet_local(lap_msg, 1); /* local only... */ + cm_lap_set_local_ack_timeout(lap_msg, + cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay, + alternate_path->packet_life_time)); + + if (private_data && private_data_len) + memcpy(lap_msg->private_data, private_data, private_data_len); +} + +int ib_send_cm_lap(struct ib_cm_id *cm_id, + struct ib_sa_path_rec *alternate_path, + const void *private_data, + u8 private_data_len) +{ + struct cm_id_private *cm_id_priv; + struct ib_mad_send_buf *msg; + unsigned long flags; + int ret; + + if (private_data && private_data_len > IB_CM_LAP_PRIVATE_DATA_SIZE) + return -EINVAL; + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id->state != IB_CM_ESTABLISHED || + (cm_id->lap_state != IB_CM_LAP_UNINIT && + cm_id->lap_state != IB_CM_LAP_IDLE)) { + ret = -EINVAL; + goto out; + } + + ret = cm_init_av_by_path(alternate_path, &cm_id_priv->alt_av); + if (ret) + goto out; + cm_id_priv->alt_av.timeout = + cm_ack_timeout(cm_id_priv->target_ack_delay, + cm_id_priv->alt_av.timeout - 1); + + ret = cm_alloc_msg(cm_id_priv, &msg); + if (ret) + goto out; + + cm_format_lap((struct cm_lap_msg *) msg->mad, cm_id_priv, + alternate_path, private_data, private_data_len); + msg->timeout_ms = cm_id_priv->timeout_ms; + msg->context[1] = (void *) (unsigned long) IB_CM_ESTABLISHED; + + ret = ib_post_send_mad(msg, NULL); + if (ret) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + cm_free_msg(msg); + return ret; + } + + cm_id->lap_state = IB_CM_LAP_SENT; + cm_id_priv->msg = msg; + +out: spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return ret; +} +EXPORT_SYMBOL(ib_send_cm_lap); + +static void cm_format_path_from_lap(struct cm_id_private *cm_id_priv, + struct ib_sa_path_rec *path, + struct cm_lap_msg *lap_msg) +{ + memset(path, 0, sizeof *path); + path->dgid = lap_msg->alt_local_gid; + path->sgid = lap_msg->alt_remote_gid; + path->dlid = lap_msg->alt_local_lid; + path->slid = lap_msg->alt_remote_lid; + path->flow_label = cm_lap_get_flow_label(lap_msg); + path->hop_limit = lap_msg->alt_hop_limit; + path->traffic_class = cm_lap_get_traffic_class(lap_msg); + path->reversible = 1; + path->pkey = cm_id_priv->pkey; + path->sl = cm_lap_get_sl(lap_msg); + path->mtu_selector = IB_SA_EQ; + path->mtu = cm_id_priv->path_mtu; + path->rate_selector = IB_SA_EQ; + path->rate = cm_lap_get_packet_rate(lap_msg); + path->packet_life_time_selector = IB_SA_EQ; + path->packet_life_time = cm_lap_get_local_ack_timeout(lap_msg); + path->packet_life_time -= (path->packet_life_time > 0); +} + +static int cm_lap_handler(struct cm_work *work) +{ + struct cm_id_private *cm_id_priv; + struct cm_lap_msg *lap_msg; + struct ib_cm_lap_event_param *param; + struct ib_mad_send_buf *msg = NULL; + int ret; + + /* todo: verify LAP request and send reject APR if invalid. */ + lap_msg = (struct cm_lap_msg *)work->mad_recv_wc->recv_buf.mad; + cm_id_priv = cm_acquire_id(lap_msg->remote_comm_id, + lap_msg->local_comm_id); + if (!cm_id_priv) + return -EINVAL; + + param = &work->cm_event.param.lap_rcvd; + param->alternate_path = &work->path[0]; + cm_format_path_from_lap(cm_id_priv, param->alternate_path, lap_msg); + work->cm_event.private_data = &lap_msg->private_data; + + spin_lock_irq(&cm_id_priv->lock); + if (cm_id_priv->id.state != IB_CM_ESTABLISHED) + goto unlock; + + switch (cm_id_priv->id.lap_state) { + case IB_CM_LAP_UNINIT: + case IB_CM_LAP_IDLE: + break; + case IB_CM_MRA_LAP_SENT: + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_LAP_COUNTER]); + if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg)) + goto unlock; + + cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv, + CM_MSG_RESPONSE_OTHER, + cm_id_priv->service_timeout, + cm_id_priv->private_data, + cm_id_priv->private_data_len); + spin_unlock_irq(&cm_id_priv->lock); + + if (ib_post_send_mad(msg, NULL)) + cm_free_msg(msg); + goto deref; + case IB_CM_LAP_RCVD: + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_LAP_COUNTER]); + goto unlock; + default: + goto unlock; + } + + cm_id_priv->id.lap_state = IB_CM_LAP_RCVD; + cm_id_priv->tid = lap_msg->hdr.tid; + cm_init_av_for_response(work->port, work->mad_recv_wc->wc, + work->mad_recv_wc->recv_buf.grh, + &cm_id_priv->av); + cm_init_av_by_path(param->alternate_path, &cm_id_priv->alt_av); + ret = atomic_inc_and_test(&cm_id_priv->work_count); + if (!ret) + list_add_tail(&work->list, &cm_id_priv->work_list); + spin_unlock_irq(&cm_id_priv->lock); + + if (ret) + cm_process_work(cm_id_priv, work); + else + cm_deref_id(cm_id_priv); + return 0; + +unlock: spin_unlock_irq(&cm_id_priv->lock); +deref: cm_deref_id(cm_id_priv); + return -EINVAL; +} + +static void cm_format_apr(struct cm_apr_msg *apr_msg, + struct cm_id_private *cm_id_priv, + enum ib_cm_apr_status status, + void *info, + u8 info_length, + const void *private_data, + u8 private_data_len) +{ + cm_format_mad_hdr(&apr_msg->hdr, CM_APR_ATTR_ID, cm_id_priv->tid); + apr_msg->local_comm_id = cm_id_priv->id.local_id; + apr_msg->remote_comm_id = cm_id_priv->id.remote_id; + apr_msg->ap_status = (u8) status; + + if (info && info_length) { + apr_msg->info_length = info_length; + memcpy(apr_msg->info, info, info_length); + } + + if (private_data && private_data_len) + memcpy(apr_msg->private_data, private_data, private_data_len); +} + +int ib_send_cm_apr(struct ib_cm_id *cm_id, + enum ib_cm_apr_status status, + void *info, + u8 info_length, + const void *private_data, + u8 private_data_len) +{ + struct cm_id_private *cm_id_priv; + struct ib_mad_send_buf *msg; + unsigned long flags; + int ret; + + if ((private_data && private_data_len > IB_CM_APR_PRIVATE_DATA_SIZE) || + (info && info_length > IB_CM_APR_INFO_LENGTH)) + return -EINVAL; + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id->state != IB_CM_ESTABLISHED || + (cm_id->lap_state != IB_CM_LAP_RCVD && + cm_id->lap_state != IB_CM_MRA_LAP_SENT)) { + ret = -EINVAL; + goto out; + } + + ret = cm_alloc_msg(cm_id_priv, &msg); + if (ret) + goto out; + + cm_format_apr((struct cm_apr_msg *) msg->mad, cm_id_priv, status, + info, info_length, private_data, private_data_len); + ret = ib_post_send_mad(msg, NULL); + if (ret) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + cm_free_msg(msg); + return ret; + } + + cm_id->lap_state = IB_CM_LAP_IDLE; +out: spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return ret; +} +EXPORT_SYMBOL(ib_send_cm_apr); + +static int cm_apr_handler(struct cm_work *work) +{ + struct cm_id_private *cm_id_priv; + struct cm_apr_msg *apr_msg; + int ret; + + apr_msg = (struct cm_apr_msg *)work->mad_recv_wc->recv_buf.mad; + cm_id_priv = cm_acquire_id(apr_msg->remote_comm_id, + apr_msg->local_comm_id); + if (!cm_id_priv) + return -EINVAL; /* Unmatched reply. */ + + work->cm_event.param.apr_rcvd.ap_status = apr_msg->ap_status; + work->cm_event.param.apr_rcvd.apr_info = &apr_msg->info; + work->cm_event.param.apr_rcvd.info_len = apr_msg->info_length; + work->cm_event.private_data = &apr_msg->private_data; + + spin_lock_irq(&cm_id_priv->lock); + if (cm_id_priv->id.state != IB_CM_ESTABLISHED || + (cm_id_priv->id.lap_state != IB_CM_LAP_SENT && + cm_id_priv->id.lap_state != IB_CM_MRA_LAP_RCVD)) { + spin_unlock_irq(&cm_id_priv->lock); + goto out; + } + cm_id_priv->id.lap_state = IB_CM_LAP_IDLE; + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + cm_id_priv->msg = NULL; + + ret = atomic_inc_and_test(&cm_id_priv->work_count); + if (!ret) + list_add_tail(&work->list, &cm_id_priv->work_list); + spin_unlock_irq(&cm_id_priv->lock); + + if (ret) + cm_process_work(cm_id_priv, work); + else + cm_deref_id(cm_id_priv); + return 0; +out: + cm_deref_id(cm_id_priv); + return -EINVAL; +} + +static int cm_timewait_handler(struct cm_work *work) +{ + struct cm_timewait_info *timewait_info; + struct cm_id_private *cm_id_priv; + int ret; + + timewait_info = (struct cm_timewait_info *)work; + spin_lock_irq(&cm.lock); + list_del(&timewait_info->list); + spin_unlock_irq(&cm.lock); + + cm_id_priv = cm_acquire_id(timewait_info->work.local_id, + timewait_info->work.remote_id); + if (!cm_id_priv) + return -EINVAL; + + spin_lock_irq(&cm_id_priv->lock); + if (cm_id_priv->id.state != IB_CM_TIMEWAIT || + cm_id_priv->remote_qpn != timewait_info->remote_qpn) { + spin_unlock_irq(&cm_id_priv->lock); + goto out; + } + cm_id_priv->id.state = IB_CM_IDLE; + ret = atomic_inc_and_test(&cm_id_priv->work_count); + if (!ret) + list_add_tail(&work->list, &cm_id_priv->work_list); + spin_unlock_irq(&cm_id_priv->lock); + + if (ret) + cm_process_work(cm_id_priv, work); + else + cm_deref_id(cm_id_priv); + return 0; +out: + cm_deref_id(cm_id_priv); + return -EINVAL; +} + +static void cm_format_sidr_req(struct cm_sidr_req_msg *sidr_req_msg, + struct cm_id_private *cm_id_priv, + struct ib_cm_sidr_req_param *param) +{ + cm_format_mad_hdr(&sidr_req_msg->hdr, CM_SIDR_REQ_ATTR_ID, + cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_SIDR)); + sidr_req_msg->request_id = cm_id_priv->id.local_id; + sidr_req_msg->pkey = param->path->pkey; + sidr_req_msg->service_id = param->service_id; + + if (param->private_data && param->private_data_len) + memcpy(sidr_req_msg->private_data, param->private_data, + param->private_data_len); +} + +int ib_send_cm_sidr_req(struct ib_cm_id *cm_id, + struct ib_cm_sidr_req_param *param) +{ + struct cm_id_private *cm_id_priv; + struct ib_mad_send_buf *msg; + unsigned long flags; + int ret; + + if (!param->path || (param->private_data && + param->private_data_len > IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE)) + return -EINVAL; + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + ret = cm_init_av_by_path(param->path, &cm_id_priv->av); + if (ret) + goto out; + + cm_id->service_id = param->service_id; + cm_id->service_mask = ~cpu_to_be64(0); + cm_id_priv->timeout_ms = param->timeout_ms; + if (cm_id_priv->timeout_ms > cm_convert_to_ms(max_timeout)) { + printk(KERN_WARNING PFX "sidr req timeout_ms %d > %d, " + "decreasing used timeout_ms\n", param->timeout_ms, + cm_convert_to_ms(max_timeout)); + cm_id_priv->timeout_ms = cm_convert_to_ms(max_timeout); + } + cm_id_priv->max_cm_retries = param->max_cm_retries; + ret = cm_alloc_msg(cm_id_priv, &msg); + if (ret) + goto out; + + cm_format_sidr_req((struct cm_sidr_req_msg *) msg->mad, cm_id_priv, + param); + msg->timeout_ms = cm_id_priv->timeout_ms; + msg->context[1] = (void *) (unsigned long) IB_CM_SIDR_REQ_SENT; + + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id->state == IB_CM_IDLE) + ret = ib_post_send_mad(msg, NULL); + else + ret = -EINVAL; + + if (ret) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + cm_free_msg(msg); + goto out; + } + cm_id->state = IB_CM_SIDR_REQ_SENT; + cm_id_priv->msg = msg; + spin_unlock_irqrestore(&cm_id_priv->lock, flags); +out: + return ret; +} +EXPORT_SYMBOL(ib_send_cm_sidr_req); + +static void cm_format_sidr_req_event(struct cm_work *work, + struct ib_cm_id *listen_id) +{ + struct cm_sidr_req_msg *sidr_req_msg; + struct ib_cm_sidr_req_event_param *param; + + sidr_req_msg = (struct cm_sidr_req_msg *) + work->mad_recv_wc->recv_buf.mad; + param = &work->cm_event.param.sidr_req_rcvd; + param->pkey = __be16_to_cpu(sidr_req_msg->pkey); + param->listen_id = listen_id; + param->port = work->port->port_num; + work->cm_event.private_data = &sidr_req_msg->private_data; +} + +static int cm_sidr_req_handler(struct cm_work *work) +{ + struct ib_cm_id *cm_id; + struct cm_id_private *cm_id_priv, *cur_cm_id_priv; + struct cm_sidr_req_msg *sidr_req_msg; + struct ib_wc *wc; + + cm_id = ib_create_cm_id(work->port->cm_dev->ib_device, NULL, NULL); + if (IS_ERR(cm_id)) + return PTR_ERR(cm_id); + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + + /* Record SGID/SLID and request ID for lookup. */ + sidr_req_msg = (struct cm_sidr_req_msg *) + work->mad_recv_wc->recv_buf.mad; + wc = work->mad_recv_wc->wc; + cm_id_priv->av.dgid.global.subnet_prefix = cpu_to_be64(wc->slid); + cm_id_priv->av.dgid.global.interface_id = 0; + cm_init_av_for_response(work->port, work->mad_recv_wc->wc, + work->mad_recv_wc->recv_buf.grh, + &cm_id_priv->av); + cm_id_priv->id.remote_id = sidr_req_msg->request_id; + cm_id_priv->tid = sidr_req_msg->hdr.tid; + atomic_inc(&cm_id_priv->work_count); + + spin_lock_irq(&cm.lock); + cur_cm_id_priv = cm_insert_remote_sidr(cm_id_priv); + if (cur_cm_id_priv) { + spin_unlock_irq(&cm.lock); + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_SIDR_REQ_COUNTER]); + goto out; /* Duplicate message. */ + } + cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD; + cur_cm_id_priv = cm_find_listen(cm_id->device, + sidr_req_msg->service_id, + sidr_req_msg->private_data); + if (!cur_cm_id_priv) { + spin_unlock_irq(&cm.lock); + cm_reject_sidr_req(cm_id_priv, IB_SIDR_UNSUPPORTED); + goto out; /* No match. */ + } + atomic_inc(&cur_cm_id_priv->refcount); + spin_unlock_irq(&cm.lock); + + cm_id_priv->id.cm_handler = cur_cm_id_priv->id.cm_handler; + cm_id_priv->id.context = cur_cm_id_priv->id.context; + cm_id_priv->id.service_id = sidr_req_msg->service_id; + cm_id_priv->id.service_mask = ~cpu_to_be64(0); + + cm_format_sidr_req_event(work, &cur_cm_id_priv->id); + cm_process_work(cm_id_priv, work); + cm_deref_id(cur_cm_id_priv); + return 0; +out: + ib_destroy_cm_id(&cm_id_priv->id); + return -EINVAL; +} + +static void cm_format_sidr_rep(struct cm_sidr_rep_msg *sidr_rep_msg, + struct cm_id_private *cm_id_priv, + struct ib_cm_sidr_rep_param *param) +{ + cm_format_mad_hdr(&sidr_rep_msg->hdr, CM_SIDR_REP_ATTR_ID, + cm_id_priv->tid); + sidr_rep_msg->request_id = cm_id_priv->id.remote_id; + sidr_rep_msg->status = param->status; + cm_sidr_rep_set_qpn(sidr_rep_msg, cpu_to_be32(param->qp_num)); + sidr_rep_msg->service_id = cm_id_priv->id.service_id; + sidr_rep_msg->qkey = cpu_to_be32(param->qkey); + + if (param->info && param->info_length) + memcpy(sidr_rep_msg->info, param->info, param->info_length); + + if (param->private_data && param->private_data_len) + memcpy(sidr_rep_msg->private_data, param->private_data, + param->private_data_len); +} + +int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id, + struct ib_cm_sidr_rep_param *param) +{ + struct cm_id_private *cm_id_priv; + struct ib_mad_send_buf *msg; + unsigned long flags; + int ret; + + if ((param->info && param->info_length > IB_CM_SIDR_REP_INFO_LENGTH) || + (param->private_data && + param->private_data_len > IB_CM_SIDR_REP_PRIVATE_DATA_SIZE)) + return -EINVAL; + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id->state != IB_CM_SIDR_REQ_RCVD) { + ret = -EINVAL; + goto error; + } + + ret = cm_alloc_msg(cm_id_priv, &msg); + if (ret) + goto error; + + cm_format_sidr_rep((struct cm_sidr_rep_msg *) msg->mad, cm_id_priv, + param); + ret = ib_post_send_mad(msg, NULL); + if (ret) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + cm_free_msg(msg); + return ret; + } + cm_id->state = IB_CM_IDLE; + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + + spin_lock_irqsave(&cm.lock, flags); + rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); + spin_unlock_irqrestore(&cm.lock, flags); + return 0; + +error: spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return ret; +} +EXPORT_SYMBOL(ib_send_cm_sidr_rep); + +static void cm_format_sidr_rep_event(struct cm_work *work) +{ + struct cm_sidr_rep_msg *sidr_rep_msg; + struct ib_cm_sidr_rep_event_param *param; + + sidr_rep_msg = (struct cm_sidr_rep_msg *) + work->mad_recv_wc->recv_buf.mad; + param = &work->cm_event.param.sidr_rep_rcvd; + param->status = sidr_rep_msg->status; + param->qkey = be32_to_cpu(sidr_rep_msg->qkey); + param->qpn = be32_to_cpu(cm_sidr_rep_get_qpn(sidr_rep_msg)); + param->info = &sidr_rep_msg->info; + param->info_len = sidr_rep_msg->info_length; + work->cm_event.private_data = &sidr_rep_msg->private_data; +} + +static int cm_sidr_rep_handler(struct cm_work *work) +{ + struct cm_sidr_rep_msg *sidr_rep_msg; + struct cm_id_private *cm_id_priv; + + sidr_rep_msg = (struct cm_sidr_rep_msg *) + work->mad_recv_wc->recv_buf.mad; + cm_id_priv = cm_acquire_id(sidr_rep_msg->request_id, 0); + if (!cm_id_priv) + return -EINVAL; /* Unmatched reply. */ + + spin_lock_irq(&cm_id_priv->lock); + if (cm_id_priv->id.state != IB_CM_SIDR_REQ_SENT) { + spin_unlock_irq(&cm_id_priv->lock); + goto out; + } + cm_id_priv->id.state = IB_CM_IDLE; + ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); + spin_unlock_irq(&cm_id_priv->lock); + + cm_format_sidr_rep_event(work); + cm_process_work(cm_id_priv, work); + return 0; +out: + cm_deref_id(cm_id_priv); + return -EINVAL; +} + +static void cm_process_send_error(struct ib_mad_send_buf *msg, + enum ib_wc_status wc_status) +{ + struct cm_id_private *cm_id_priv; + struct ib_cm_event cm_event; + enum ib_cm_state state; + int ret; + + memset(&cm_event, 0, sizeof cm_event); + cm_id_priv = msg->context[0]; + + /* Discard old sends or ones without a response. */ + spin_lock_irq(&cm_id_priv->lock); + state = (enum ib_cm_state) (unsigned long) msg->context[1]; + if (msg != cm_id_priv->msg || state != cm_id_priv->id.state) + goto discard; + + switch (state) { + case IB_CM_REQ_SENT: + case IB_CM_MRA_REQ_RCVD: + cm_reset_to_idle(cm_id_priv); + cm_event.event = IB_CM_REQ_ERROR; + break; + case IB_CM_REP_SENT: + case IB_CM_MRA_REP_RCVD: + cm_reset_to_idle(cm_id_priv); + cm_event.event = IB_CM_REP_ERROR; + break; + case IB_CM_DREQ_SENT: + cm_enter_timewait(cm_id_priv); + cm_event.event = IB_CM_DREQ_ERROR; + break; + case IB_CM_SIDR_REQ_SENT: + cm_id_priv->id.state = IB_CM_IDLE; + cm_event.event = IB_CM_SIDR_REQ_ERROR; + break; + default: + goto discard; + } + spin_unlock_irq(&cm_id_priv->lock); + cm_event.param.send_status = wc_status; + + /* No other events can occur on the cm_id at this point. */ + ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, &cm_event); + cm_free_msg(msg); + if (ret) + ib_destroy_cm_id(&cm_id_priv->id); + return; +discard: + spin_unlock_irq(&cm_id_priv->lock); + cm_free_msg(msg); +} + +static void cm_send_handler(struct ib_mad_agent *mad_agent, + struct ib_mad_send_wc *mad_send_wc) +{ + struct ib_mad_send_buf *msg = mad_send_wc->send_buf; + struct cm_port *port; + u16 attr_index; + + port = mad_agent->context; + attr_index = be16_to_cpu(((struct ib_mad_hdr *) + msg->mad)->attr_id) - CM_ATTR_ID_OFFSET; + + /* + * If the send was in response to a received message (context[0] is not + * set to a cm_id), and is not a REJ, then it is a send that was + * manually retried. + */ + if (!msg->context[0] && (attr_index != CM_REJ_COUNTER)) + msg->retries = 1; + + atomic_long_add(1 + msg->retries, + &port->counter_group[CM_XMIT].counter[attr_index]); + if (msg->retries) + atomic_long_add(msg->retries, + &port->counter_group[CM_XMIT_RETRIES]. + counter[attr_index]); + + switch (mad_send_wc->status) { + case IB_WC_SUCCESS: + case IB_WC_WR_FLUSH_ERR: + cm_free_msg(msg); + break; + default: + if (msg->context[0] && msg->context[1]) + cm_process_send_error(msg, mad_send_wc->status); + else + cm_free_msg(msg); + break; + } +} + +static void cm_work_handler(struct work_struct *_work) +{ + struct cm_work *work = container_of(_work, struct cm_work, work.work); + int ret; + + switch (work->cm_event.event) { + case IB_CM_REQ_RECEIVED: + ret = cm_req_handler(work); + break; + case IB_CM_MRA_RECEIVED: + ret = cm_mra_handler(work); + break; + case IB_CM_REJ_RECEIVED: + ret = cm_rej_handler(work); + break; + case IB_CM_REP_RECEIVED: + ret = cm_rep_handler(work); + break; + case IB_CM_RTU_RECEIVED: + ret = cm_rtu_handler(work); + break; + case IB_CM_USER_ESTABLISHED: + ret = cm_establish_handler(work); + break; + case IB_CM_DREQ_RECEIVED: + ret = cm_dreq_handler(work); + break; + case IB_CM_DREP_RECEIVED: + ret = cm_drep_handler(work); + break; + case IB_CM_SIDR_REQ_RECEIVED: + ret = cm_sidr_req_handler(work); + break; + case IB_CM_SIDR_REP_RECEIVED: + ret = cm_sidr_rep_handler(work); + break; + case IB_CM_LAP_RECEIVED: + ret = cm_lap_handler(work); + break; + case IB_CM_APR_RECEIVED: + ret = cm_apr_handler(work); + break; + case IB_CM_TIMEWAIT_EXIT: + ret = cm_timewait_handler(work); + break; + default: + ret = -EINVAL; + break; + } + if (ret) + cm_free_work(work); +} + +static int cm_establish(struct ib_cm_id *cm_id) +{ + struct cm_id_private *cm_id_priv; + struct cm_work *work; + unsigned long flags; + int ret = 0; + + work = kmalloc(sizeof *work, GFP_ATOMIC); + if (!work) + return -ENOMEM; + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + spin_lock_irqsave(&cm_id_priv->lock, flags); + switch (cm_id->state) + { + case IB_CM_REP_SENT: + case IB_CM_MRA_REP_RCVD: + cm_id->state = IB_CM_ESTABLISHED; + break; + case IB_CM_ESTABLISHED: + ret = -EISCONN; + break; + default: + ret = -EINVAL; + break; + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + + if (ret) { + kfree(work); + goto out; + } + + /* + * The CM worker thread may try to destroy the cm_id before it + * can execute this work item. To prevent potential deadlock, + * we need to find the cm_id once we're in the context of the + * worker thread, rather than holding a reference on it. + */ + INIT_DELAYED_WORK(&work->work, cm_work_handler); + work->local_id = cm_id->local_id; + work->remote_id = cm_id->remote_id; + work->mad_recv_wc = NULL; + work->cm_event.event = IB_CM_USER_ESTABLISHED; + queue_delayed_work(cm.wq, &work->work, 0); +out: + return ret; +} + +static int cm_migrate(struct ib_cm_id *cm_id) +{ + struct cm_id_private *cm_id_priv; + unsigned long flags; + int ret = 0; + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id->state == IB_CM_ESTABLISHED && + (cm_id->lap_state == IB_CM_LAP_UNINIT || + cm_id->lap_state == IB_CM_LAP_IDLE)) { + cm_id->lap_state = IB_CM_LAP_IDLE; + cm_id_priv->av = cm_id_priv->alt_av; + } else + ret = -EINVAL; + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + + return ret; +} + +int ib_cm_notify(struct ib_cm_id *cm_id, enum ib_event_type event) +{ + int ret; + + switch (event) { + case IB_EVENT_COMM_EST: + ret = cm_establish(cm_id); + break; + case IB_EVENT_PATH_MIG: + ret = cm_migrate(cm_id); + break; + default: + ret = -EINVAL; + } + return ret; +} +EXPORT_SYMBOL(ib_cm_notify); + +static void cm_recv_handler(struct ib_mad_agent *mad_agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct cm_port *port = mad_agent->context; + struct cm_work *work; + enum ib_cm_event_type event; + u16 attr_id; + int paths = 0; + + switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) { + case CM_REQ_ATTR_ID: + paths = 1 + (((struct cm_req_msg *) mad_recv_wc->recv_buf.mad)-> + alt_local_lid != 0); + event = IB_CM_REQ_RECEIVED; + break; + case CM_MRA_ATTR_ID: + event = IB_CM_MRA_RECEIVED; + break; + case CM_REJ_ATTR_ID: + event = IB_CM_REJ_RECEIVED; + break; + case CM_REP_ATTR_ID: + event = IB_CM_REP_RECEIVED; + break; + case CM_RTU_ATTR_ID: + event = IB_CM_RTU_RECEIVED; + break; + case CM_DREQ_ATTR_ID: + event = IB_CM_DREQ_RECEIVED; + break; + case CM_DREP_ATTR_ID: + event = IB_CM_DREP_RECEIVED; + break; + case CM_SIDR_REQ_ATTR_ID: + event = IB_CM_SIDR_REQ_RECEIVED; + break; + case CM_SIDR_REP_ATTR_ID: + event = IB_CM_SIDR_REP_RECEIVED; + break; + case CM_LAP_ATTR_ID: + paths = 1; + event = IB_CM_LAP_RECEIVED; + break; + case CM_APR_ATTR_ID: + event = IB_CM_APR_RECEIVED; + break; + default: + ib_free_recv_mad(mad_recv_wc); + return; + } + + attr_id = be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id); + atomic_long_inc(&port->counter_group[CM_RECV]. + counter[attr_id - CM_ATTR_ID_OFFSET]); + + work = kmalloc(sizeof *work + sizeof(struct ib_sa_path_rec) * paths, + GFP_KERNEL); + if (!work) { + ib_free_recv_mad(mad_recv_wc); + return; + } + + INIT_DELAYED_WORK(&work->work, cm_work_handler); + work->cm_event.event = event; + work->mad_recv_wc = mad_recv_wc; + work->port = port; + queue_delayed_work(cm.wq, &work->work, 0); +} + +static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv, + struct ib_qp_attr *qp_attr, + int *qp_attr_mask) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&cm_id_priv->lock, flags); + switch (cm_id_priv->id.state) { + case IB_CM_REQ_SENT: + case IB_CM_MRA_REQ_RCVD: + case IB_CM_REQ_RCVD: + case IB_CM_MRA_REQ_SENT: + case IB_CM_REP_RCVD: + case IB_CM_MRA_REP_SENT: + case IB_CM_REP_SENT: + case IB_CM_MRA_REP_RCVD: + case IB_CM_ESTABLISHED: + *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS | + IB_QP_PKEY_INDEX | IB_QP_PORT; + qp_attr->qp_access_flags = IB_ACCESS_REMOTE_WRITE; + if (cm_id_priv->responder_resources) + qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ | + IB_ACCESS_REMOTE_ATOMIC; + qp_attr->pkey_index = cm_id_priv->av.pkey_index; + qp_attr->port_num = cm_id_priv->av.port->port_num; + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return ret; +} + +static int cm_init_qp_rtr_attr(struct cm_id_private *cm_id_priv, + struct ib_qp_attr *qp_attr, + int *qp_attr_mask) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&cm_id_priv->lock, flags); + switch (cm_id_priv->id.state) { + case IB_CM_REQ_RCVD: + case IB_CM_MRA_REQ_SENT: + case IB_CM_REP_RCVD: + case IB_CM_MRA_REP_SENT: + case IB_CM_REP_SENT: + case IB_CM_MRA_REP_RCVD: + case IB_CM_ESTABLISHED: + *qp_attr_mask = IB_QP_STATE | IB_QP_AV | IB_QP_PATH_MTU | + IB_QP_DEST_QPN | IB_QP_RQ_PSN; + qp_attr->ah_attr = cm_id_priv->av.ah_attr; + qp_attr->path_mtu = cm_id_priv->path_mtu; + qp_attr->dest_qp_num = be32_to_cpu(cm_id_priv->remote_qpn); + qp_attr->rq_psn = be32_to_cpu(cm_id_priv->rq_psn); + if (cm_id_priv->qp_type == IB_QPT_RC) { + *qp_attr_mask |= IB_QP_MAX_DEST_RD_ATOMIC | + IB_QP_MIN_RNR_TIMER; + qp_attr->max_dest_rd_atomic = + cm_id_priv->responder_resources; + qp_attr->min_rnr_timer = 0; + } + if (cm_id_priv->alt_av.ah_attr.dlid) { + *qp_attr_mask |= IB_QP_ALT_PATH; + qp_attr->alt_port_num = cm_id_priv->alt_av.port->port_num; + qp_attr->alt_pkey_index = cm_id_priv->alt_av.pkey_index; + qp_attr->alt_timeout = cm_id_priv->alt_av.timeout; + qp_attr->alt_ah_attr = cm_id_priv->alt_av.ah_attr; + } + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return ret; +} + +static int cm_init_qp_rts_attr(struct cm_id_private *cm_id_priv, + struct ib_qp_attr *qp_attr, + int *qp_attr_mask) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&cm_id_priv->lock, flags); + switch (cm_id_priv->id.state) { + /* Allow transition to RTS before sending REP */ + case IB_CM_REQ_RCVD: + case IB_CM_MRA_REQ_SENT: + + case IB_CM_REP_RCVD: + case IB_CM_MRA_REP_SENT: + case IB_CM_REP_SENT: + case IB_CM_MRA_REP_RCVD: + case IB_CM_ESTABLISHED: + if (cm_id_priv->id.lap_state == IB_CM_LAP_UNINIT) { + *qp_attr_mask = IB_QP_STATE | IB_QP_SQ_PSN; + qp_attr->sq_psn = be32_to_cpu(cm_id_priv->sq_psn); + if (cm_id_priv->qp_type == IB_QPT_RC) { + *qp_attr_mask |= IB_QP_TIMEOUT | IB_QP_RETRY_CNT | + IB_QP_RNR_RETRY | + IB_QP_MAX_QP_RD_ATOMIC; + qp_attr->timeout = cm_id_priv->av.timeout; + qp_attr->retry_cnt = cm_id_priv->retry_count; + qp_attr->rnr_retry = cm_id_priv->rnr_retry_count; + qp_attr->max_rd_atomic = + cm_id_priv->initiator_depth; + } + if (cm_id_priv->alt_av.ah_attr.dlid) { + *qp_attr_mask |= IB_QP_PATH_MIG_STATE; + qp_attr->path_mig_state = IB_MIG_REARM; + } + } else { + *qp_attr_mask = IB_QP_ALT_PATH | IB_QP_PATH_MIG_STATE; + qp_attr->alt_port_num = cm_id_priv->alt_av.port->port_num; + qp_attr->alt_pkey_index = cm_id_priv->alt_av.pkey_index; + qp_attr->alt_timeout = cm_id_priv->alt_av.timeout; + qp_attr->alt_ah_attr = cm_id_priv->alt_av.ah_attr; + qp_attr->path_mig_state = IB_MIG_REARM; + } + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return ret; +} + +int ib_cm_init_qp_attr(struct ib_cm_id *cm_id, + struct ib_qp_attr *qp_attr, + int *qp_attr_mask) +{ + struct cm_id_private *cm_id_priv; + int ret; + + cm_id_priv = container_of(cm_id, struct cm_id_private, id); + switch (qp_attr->qp_state) { + case IB_QPS_INIT: + ret = cm_init_qp_init_attr(cm_id_priv, qp_attr, qp_attr_mask); + break; + case IB_QPS_RTR: + ret = cm_init_qp_rtr_attr(cm_id_priv, qp_attr, qp_attr_mask); + break; + case IB_QPS_RTS: + ret = cm_init_qp_rts_attr(cm_id_priv, qp_attr, qp_attr_mask); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} +EXPORT_SYMBOL(ib_cm_init_qp_attr); + +static void cm_get_ack_delay(struct cm_device *cm_dev) +{ + struct ib_device_attr attr; + + if (ib_query_device(cm_dev->ib_device, &attr)) + cm_dev->ack_delay = 0; /* acks will rely on packet life time */ + else + cm_dev->ack_delay = attr.local_ca_ack_delay; +} + +static ssize_t cm_show_counter(struct kobject *obj, struct attribute *attr, + char *buf) +{ + struct cm_counter_group *group; + struct cm_counter_attribute *cm_attr; + + group = container_of(obj, struct cm_counter_group, obj); + cm_attr = container_of(attr, struct cm_counter_attribute, attr); + + return sprintf(buf, "%ld\n", + atomic_long_read(&group->counter[cm_attr->index])); +} + +static struct sysfs_ops cm_counter_ops = { + .show = cm_show_counter +}; + +static struct kobj_type cm_counter_obj_type = { + .sysfs_ops = &cm_counter_ops, + .default_attrs = cm_counter_default_attrs +}; + +static void cm_release_port_obj(struct kobject *obj) +{ + struct cm_port *cm_port; + + cm_port = container_of(obj, struct cm_port, port_obj); + kfree(cm_port); +} + +static struct kobj_type cm_port_obj_type = { + .release = cm_release_port_obj +}; + +struct class cm_class = { + .name = "infiniband_cm", +}; +EXPORT_SYMBOL(cm_class); + +static int cm_create_port_fs(struct cm_port *port) +{ + int i, ret; + + ret = kobject_init_and_add(&port->port_obj, &cm_port_obj_type, + &port->cm_dev->device->kobj, + "%d", port->port_num); + if (ret) { + kfree(port); + return ret; + } + + for (i = 0; i < CM_COUNTER_GROUPS; i++) { + ret = kobject_init_and_add(&port->counter_group[i].obj, + &cm_counter_obj_type, + &port->port_obj, + "%s", counter_group_names[i]); + if (ret) + goto error; + } + + return 0; + +error: + while (i--) + kobject_put(&port->counter_group[i].obj); + kobject_put(&port->port_obj); + return ret; + +} + +static void cm_remove_port_fs(struct cm_port *port) +{ + int i; + + for (i = 0; i < CM_COUNTER_GROUPS; i++) + kobject_put(&port->counter_group[i].obj); + + kobject_put(&port->port_obj); +} + +static void cm_add_one(struct ib_device *ib_device) +{ + struct cm_device *cm_dev; + struct cm_port *port; + struct ib_mad_reg_req reg_req = { + .mgmt_class = IB_MGMT_CLASS_CM, + .mgmt_class_version = IB_CM_CLASS_VERSION + }; + struct ib_port_modify port_modify = { + .set_port_cap_mask = IB_PORT_CM_SUP + }; + unsigned long flags; + int ret; + u8 i; + + if (rdma_node_get_transport(ib_device->node_type) != RDMA_TRANSPORT_IB) + return; + + cm_dev = kzalloc(sizeof(*cm_dev) + sizeof(*port) * + ib_device->phys_port_cnt, GFP_KERNEL); + if (!cm_dev) + return; + + cm_dev->ib_device = ib_device; + cm_get_ack_delay(cm_dev); + + cm_dev->device = device_create(&cm_class, &ib_device->dev, + MKDEV(0, 0), NULL, + "%s", ib_device->name); + if (!cm_dev->device) { + kfree(cm_dev); + return; + } + + set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask); + for (i = 1; i <= ib_device->phys_port_cnt; i++) { + port = kzalloc(sizeof *port, GFP_KERNEL); + if (!port) + goto error1; + + cm_dev->port[i-1] = port; + port->cm_dev = cm_dev; + port->port_num = i; + + ret = cm_create_port_fs(port); + if (ret) + goto error1; + + port->mad_agent = ib_register_mad_agent(ib_device, i, + IB_QPT_GSI, + ®_req, + 0, + cm_send_handler, + cm_recv_handler, + port); + if (IS_ERR(port->mad_agent)) + goto error2; + + ret = ib_modify_port(ib_device, i, 0, &port_modify); + if (ret) + goto error3; + } + ib_set_client_data(ib_device, &cm_client, cm_dev); + + write_lock_irqsave(&cm.device_lock, flags); + list_add_tail(&cm_dev->list, &cm.device_list); + write_unlock_irqrestore(&cm.device_lock, flags); + return; + +error3: + ib_unregister_mad_agent(port->mad_agent); +error2: + cm_remove_port_fs(port); +error1: + port_modify.set_port_cap_mask = 0; + port_modify.clr_port_cap_mask = IB_PORT_CM_SUP; + while (--i) { + port = cm_dev->port[i-1]; + ib_modify_port(ib_device, port->port_num, 0, &port_modify); + ib_unregister_mad_agent(port->mad_agent); + cm_remove_port_fs(port); + } + device_unregister(cm_dev->device); + kfree(cm_dev); +} + +static void cm_remove_one(struct ib_device *ib_device) +{ + struct cm_device *cm_dev; + struct cm_port *port; + struct ib_port_modify port_modify = { + .clr_port_cap_mask = IB_PORT_CM_SUP + }; + unsigned long flags; + int i; + + cm_dev = ib_get_client_data(ib_device, &cm_client); + if (!cm_dev) + return; + + write_lock_irqsave(&cm.device_lock, flags); + list_del(&cm_dev->list); + write_unlock_irqrestore(&cm.device_lock, flags); + + for (i = 1; i <= ib_device->phys_port_cnt; i++) { + port = cm_dev->port[i-1]; + ib_modify_port(ib_device, port->port_num, 0, &port_modify); + ib_unregister_mad_agent(port->mad_agent); + flush_workqueue(cm.wq); + cm_remove_port_fs(port); + } + device_unregister(cm_dev->device); + kfree(cm_dev); +} + +static int __init ib_cm_init(void) +{ + int ret; + + memset(&cm, 0, sizeof cm); + INIT_LIST_HEAD(&cm.device_list); + rwlock_init(&cm.device_lock); + spin_lock_init(&cm.lock); + cm.listen_service_table = RB_ROOT; + cm.listen_service_id = be64_to_cpu(IB_CM_ASSIGN_SERVICE_ID); + cm.remote_id_table = RB_ROOT; + cm.remote_qp_table = RB_ROOT; + cm.remote_sidr_table = RB_ROOT; + idr_init(&cm.local_id_table); + get_random_bytes(&cm.random_id_operand, sizeof cm.random_id_operand); + idr_pre_get(&cm.local_id_table, GFP_KERNEL); + INIT_LIST_HEAD(&cm.timewait_list); + + ret = class_register(&cm_class); + if (ret) + return -ENOMEM; + + cm.wq = create_workqueue("ib_cm"); + if (!cm.wq) { + ret = -ENOMEM; + goto error1; + } + + ret = ib_register_client(&cm_client); + if (ret) + goto error2; + + return 0; +error2: + destroy_workqueue(cm.wq); +error1: + class_unregister(&cm_class); + return ret; +} + +static void __exit ib_cm_cleanup(void) +{ + struct cm_timewait_info *timewait_info, *tmp; + + spin_lock_irq(&cm.lock); + list_for_each_entry(timewait_info, &cm.timewait_list, list) + cancel_delayed_work(&timewait_info->work.work); + spin_unlock_irq(&cm.lock); + + ib_unregister_client(&cm_client); + destroy_workqueue(cm.wq); + + list_for_each_entry_safe(timewait_info, tmp, &cm.timewait_list, list) { + list_del(&timewait_info->list); + kfree(timewait_info); + } + + class_unregister(&cm_class); + idr_destroy(&cm.local_id_table); +} + +module_init_order(ib_cm_init, SI_ORDER_SECOND); +module_exit(ib_cm_cleanup); + diff --git a/sys/ofed/drivers/infiniband/core/cm_msgs.h b/sys/ofed/drivers/infiniband/core/cm_msgs.h new file mode 100644 index 000000000000..7e63c08f697c --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/cm_msgs.h @@ -0,0 +1,819 @@ +/* + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING the madirectory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use source and binary forms, with or + * withmodification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retathe above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHWARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS THE + * SOFTWARE. + */ +#if !defined(CM_MSGS_H) +#define CM_MSGS_H + +#include +#include + +/* + * Parameters to routines below should be in network-byte order, and values + * are returned in network-byte order. + */ + +#define IB_CM_CLASS_VERSION 2 /* IB specification 1.2 */ + +#define CM_REQ_ATTR_ID cpu_to_be16(0x0010) +#define CM_MRA_ATTR_ID cpu_to_be16(0x0011) +#define CM_REJ_ATTR_ID cpu_to_be16(0x0012) +#define CM_REP_ATTR_ID cpu_to_be16(0x0013) +#define CM_RTU_ATTR_ID cpu_to_be16(0x0014) +#define CM_DREQ_ATTR_ID cpu_to_be16(0x0015) +#define CM_DREP_ATTR_ID cpu_to_be16(0x0016) +#define CM_SIDR_REQ_ATTR_ID cpu_to_be16(0x0017) +#define CM_SIDR_REP_ATTR_ID cpu_to_be16(0x0018) +#define CM_LAP_ATTR_ID cpu_to_be16(0x0019) +#define CM_APR_ATTR_ID cpu_to_be16(0x001A) + +enum cm_msg_sequence { + CM_MSG_SEQUENCE_REQ, + CM_MSG_SEQUENCE_LAP, + CM_MSG_SEQUENCE_DREQ, + CM_MSG_SEQUENCE_SIDR +}; + +struct cm_req_msg { + struct ib_mad_hdr hdr; + + __be32 local_comm_id; + __be32 rsvd4; + __be64 service_id; + __be64 local_ca_guid; + __be32 rsvd24; + __be32 local_qkey; + /* local QPN:24, responder resources:8 */ + __be32 offset32; + /* local EECN:24, initiator depth:8 */ + __be32 offset36; + /* + * remote EECN:24, remote CM response timeout:5, + * transport service type:2, end-to-end flow control:1 + */ + __be32 offset40; + /* starting PSN:24, local CM response timeout:5, retry count:3 */ + __be32 offset44; + __be16 pkey; + /* path MTU:4, RDC exists:1, RNR retry count:3. */ + u8 offset50; + /* max CM Retries:4, SRQ:1, rsvd:3 */ + u8 offset51; + + __be16 primary_local_lid; + __be16 primary_remote_lid; + union ib_gid primary_local_gid; + union ib_gid primary_remote_gid; + /* flow label:20, rsvd:6, packet rate:6 */ + __be32 primary_offset88; + u8 primary_traffic_class; + u8 primary_hop_limit; + /* SL:4, subnet local:1, rsvd:3 */ + u8 primary_offset94; + /* local ACK timeout:5, rsvd:3 */ + u8 primary_offset95; + + __be16 alt_local_lid; + __be16 alt_remote_lid; + union ib_gid alt_local_gid; + union ib_gid alt_remote_gid; + /* flow label:20, rsvd:6, packet rate:6 */ + __be32 alt_offset132; + u8 alt_traffic_class; + u8 alt_hop_limit; + /* SL:4, subnet local:1, rsvd:3 */ + u8 alt_offset138; + /* local ACK timeout:5, rsvd:3 */ + u8 alt_offset139; + + u8 private_data[IB_CM_REQ_PRIVATE_DATA_SIZE]; + +} __attribute__ ((packed)); + +static inline __be32 cm_req_get_local_qpn(struct cm_req_msg *req_msg) +{ + return cpu_to_be32(be32_to_cpu(req_msg->offset32) >> 8); +} + +static inline void cm_req_set_local_qpn(struct cm_req_msg *req_msg, __be32 qpn) +{ + req_msg->offset32 = cpu_to_be32((be32_to_cpu(qpn) << 8) | + (be32_to_cpu(req_msg->offset32) & + 0x000000FF)); +} + +static inline u8 cm_req_get_resp_res(struct cm_req_msg *req_msg) +{ + return (u8) be32_to_cpu(req_msg->offset32); +} + +static inline void cm_req_set_resp_res(struct cm_req_msg *req_msg, u8 resp_res) +{ + req_msg->offset32 = cpu_to_be32(resp_res | + (be32_to_cpu(req_msg->offset32) & + 0xFFFFFF00)); +} + +static inline u8 cm_req_get_init_depth(struct cm_req_msg *req_msg) +{ + return (u8) be32_to_cpu(req_msg->offset36); +} + +static inline void cm_req_set_init_depth(struct cm_req_msg *req_msg, + u8 init_depth) +{ + req_msg->offset36 = cpu_to_be32(init_depth | + (be32_to_cpu(req_msg->offset36) & + 0xFFFFFF00)); +} + +static inline u8 cm_req_get_remote_resp_timeout(struct cm_req_msg *req_msg) +{ + return (u8) ((be32_to_cpu(req_msg->offset40) & 0xF8) >> 3); +} + +static inline void cm_req_set_remote_resp_timeout(struct cm_req_msg *req_msg, + u8 resp_timeout) +{ + req_msg->offset40 = cpu_to_be32((resp_timeout << 3) | + (be32_to_cpu(req_msg->offset40) & + 0xFFFFFF07)); +} + +static inline enum ib_qp_type cm_req_get_qp_type(struct cm_req_msg *req_msg) +{ + u8 transport_type = (u8) (be32_to_cpu(req_msg->offset40) & 0x06) >> 1; + switch(transport_type) { + case 0: return IB_QPT_RC; + case 1: return IB_QPT_UC; + default: return 0; + } +} + +static inline void cm_req_set_qp_type(struct cm_req_msg *req_msg, + enum ib_qp_type qp_type) +{ + switch(qp_type) { + case IB_QPT_UC: + req_msg->offset40 = cpu_to_be32((be32_to_cpu( + req_msg->offset40) & + 0xFFFFFFF9) | 0x2); + break; + default: + req_msg->offset40 = cpu_to_be32(be32_to_cpu( + req_msg->offset40) & + 0xFFFFFFF9); + } +} + +static inline u8 cm_req_get_flow_ctrl(struct cm_req_msg *req_msg) +{ + return be32_to_cpu(req_msg->offset40) & 0x1; +} + +static inline void cm_req_set_flow_ctrl(struct cm_req_msg *req_msg, + u8 flow_ctrl) +{ + req_msg->offset40 = cpu_to_be32((flow_ctrl & 0x1) | + (be32_to_cpu(req_msg->offset40) & + 0xFFFFFFFE)); +} + +static inline __be32 cm_req_get_starting_psn(struct cm_req_msg *req_msg) +{ + return cpu_to_be32(be32_to_cpu(req_msg->offset44) >> 8); +} + +static inline void cm_req_set_starting_psn(struct cm_req_msg *req_msg, + __be32 starting_psn) +{ + req_msg->offset44 = cpu_to_be32((be32_to_cpu(starting_psn) << 8) | + (be32_to_cpu(req_msg->offset44) & 0x000000FF)); +} + +static inline u8 cm_req_get_local_resp_timeout(struct cm_req_msg *req_msg) +{ + return (u8) ((be32_to_cpu(req_msg->offset44) & 0xF8) >> 3); +} + +static inline void cm_req_set_local_resp_timeout(struct cm_req_msg *req_msg, + u8 resp_timeout) +{ + req_msg->offset44 = cpu_to_be32((resp_timeout << 3) | + (be32_to_cpu(req_msg->offset44) & 0xFFFFFF07)); +} + +static inline u8 cm_req_get_retry_count(struct cm_req_msg *req_msg) +{ + return (u8) (be32_to_cpu(req_msg->offset44) & 0x7); +} + +static inline void cm_req_set_retry_count(struct cm_req_msg *req_msg, + u8 retry_count) +{ + req_msg->offset44 = cpu_to_be32((retry_count & 0x7) | + (be32_to_cpu(req_msg->offset44) & 0xFFFFFFF8)); +} + +static inline u8 cm_req_get_path_mtu(struct cm_req_msg *req_msg) +{ + return req_msg->offset50 >> 4; +} + +static inline void cm_req_set_path_mtu(struct cm_req_msg *req_msg, u8 path_mtu) +{ + req_msg->offset50 = (u8) ((req_msg->offset50 & 0xF) | (path_mtu << 4)); +} + +static inline u8 cm_req_get_rnr_retry_count(struct cm_req_msg *req_msg) +{ + return req_msg->offset50 & 0x7; +} + +static inline void cm_req_set_rnr_retry_count(struct cm_req_msg *req_msg, + u8 rnr_retry_count) +{ + req_msg->offset50 = (u8) ((req_msg->offset50 & 0xF8) | + (rnr_retry_count & 0x7)); +} + +static inline u8 cm_req_get_max_cm_retries(struct cm_req_msg *req_msg) +{ + return req_msg->offset51 >> 4; +} + +static inline void cm_req_set_max_cm_retries(struct cm_req_msg *req_msg, + u8 retries) +{ + req_msg->offset51 = (u8) ((req_msg->offset51 & 0xF) | (retries << 4)); +} + +static inline u8 cm_req_get_srq(struct cm_req_msg *req_msg) +{ + return (req_msg->offset51 & 0x8) >> 3; +} + +static inline void cm_req_set_srq(struct cm_req_msg *req_msg, u8 srq) +{ + req_msg->offset51 = (u8) ((req_msg->offset51 & 0xF7) | + ((srq & 0x1) << 3)); +} + +static inline __be32 cm_req_get_primary_flow_label(struct cm_req_msg *req_msg) +{ + return cpu_to_be32(be32_to_cpu(req_msg->primary_offset88) >> 12); +} + +static inline void cm_req_set_primary_flow_label(struct cm_req_msg *req_msg, + __be32 flow_label) +{ + req_msg->primary_offset88 = cpu_to_be32( + (be32_to_cpu(req_msg->primary_offset88) & + 0x00000FFF) | + (be32_to_cpu(flow_label) << 12)); +} + +static inline u8 cm_req_get_primary_packet_rate(struct cm_req_msg *req_msg) +{ + return (u8) (be32_to_cpu(req_msg->primary_offset88) & 0x3F); +} + +static inline void cm_req_set_primary_packet_rate(struct cm_req_msg *req_msg, + u8 rate) +{ + req_msg->primary_offset88 = cpu_to_be32( + (be32_to_cpu(req_msg->primary_offset88) & + 0xFFFFFFC0) | (rate & 0x3F)); +} + +static inline u8 cm_req_get_primary_sl(struct cm_req_msg *req_msg) +{ + return (u8) (req_msg->primary_offset94 >> 4); +} + +static inline void cm_req_set_primary_sl(struct cm_req_msg *req_msg, u8 sl) +{ + req_msg->primary_offset94 = (u8) ((req_msg->primary_offset94 & 0x0F) | + (sl << 4)); +} + +static inline u8 cm_req_get_primary_subnet_local(struct cm_req_msg *req_msg) +{ + return (u8) ((req_msg->primary_offset94 & 0x08) >> 3); +} + +static inline void cm_req_set_primary_subnet_local(struct cm_req_msg *req_msg, + u8 subnet_local) +{ + req_msg->primary_offset94 = (u8) ((req_msg->primary_offset94 & 0xF7) | + ((subnet_local & 0x1) << 3)); +} + +static inline u8 cm_req_get_primary_local_ack_timeout(struct cm_req_msg *req_msg) +{ + return (u8) (req_msg->primary_offset95 >> 3); +} + +static inline void cm_req_set_primary_local_ack_timeout(struct cm_req_msg *req_msg, + u8 local_ack_timeout) +{ + req_msg->primary_offset95 = (u8) ((req_msg->primary_offset95 & 0x07) | + (local_ack_timeout << 3)); +} + +static inline __be32 cm_req_get_alt_flow_label(struct cm_req_msg *req_msg) +{ + return cpu_to_be32(be32_to_cpu(req_msg->alt_offset132) >> 12); +} + +static inline void cm_req_set_alt_flow_label(struct cm_req_msg *req_msg, + __be32 flow_label) +{ + req_msg->alt_offset132 = cpu_to_be32( + (be32_to_cpu(req_msg->alt_offset132) & + 0x00000FFF) | + (be32_to_cpu(flow_label) << 12)); +} + +static inline u8 cm_req_get_alt_packet_rate(struct cm_req_msg *req_msg) +{ + return (u8) (be32_to_cpu(req_msg->alt_offset132) & 0x3F); +} + +static inline void cm_req_set_alt_packet_rate(struct cm_req_msg *req_msg, + u8 rate) +{ + req_msg->alt_offset132 = cpu_to_be32( + (be32_to_cpu(req_msg->alt_offset132) & + 0xFFFFFFC0) | (rate & 0x3F)); +} + +static inline u8 cm_req_get_alt_sl(struct cm_req_msg *req_msg) +{ + return (u8) (req_msg->alt_offset138 >> 4); +} + +static inline void cm_req_set_alt_sl(struct cm_req_msg *req_msg, u8 sl) +{ + req_msg->alt_offset138 = (u8) ((req_msg->alt_offset138 & 0x0F) | + (sl << 4)); +} + +static inline u8 cm_req_get_alt_subnet_local(struct cm_req_msg *req_msg) +{ + return (u8) ((req_msg->alt_offset138 & 0x08) >> 3); +} + +static inline void cm_req_set_alt_subnet_local(struct cm_req_msg *req_msg, + u8 subnet_local) +{ + req_msg->alt_offset138 = (u8) ((req_msg->alt_offset138 & 0xF7) | + ((subnet_local & 0x1) << 3)); +} + +static inline u8 cm_req_get_alt_local_ack_timeout(struct cm_req_msg *req_msg) +{ + return (u8) (req_msg->alt_offset139 >> 3); +} + +static inline void cm_req_set_alt_local_ack_timeout(struct cm_req_msg *req_msg, + u8 local_ack_timeout) +{ + req_msg->alt_offset139 = (u8) ((req_msg->alt_offset139 & 0x07) | + (local_ack_timeout << 3)); +} + +/* Message REJected or MRAed */ +enum cm_msg_response { + CM_MSG_RESPONSE_REQ = 0x0, + CM_MSG_RESPONSE_REP = 0x1, + CM_MSG_RESPONSE_OTHER = 0x2 +}; + + struct cm_mra_msg { + struct ib_mad_hdr hdr; + + __be32 local_comm_id; + __be32 remote_comm_id; + /* message MRAed:2, rsvd:6 */ + u8 offset8; + /* service timeout:5, rsvd:3 */ + u8 offset9; + + u8 private_data[IB_CM_MRA_PRIVATE_DATA_SIZE]; + +} __attribute__ ((packed)); + +static inline u8 cm_mra_get_msg_mraed(struct cm_mra_msg *mra_msg) +{ + return (u8) (mra_msg->offset8 >> 6); +} + +static inline void cm_mra_set_msg_mraed(struct cm_mra_msg *mra_msg, u8 msg) +{ + mra_msg->offset8 = (u8) ((mra_msg->offset8 & 0x3F) | (msg << 6)); +} + +static inline u8 cm_mra_get_service_timeout(struct cm_mra_msg *mra_msg) +{ + return (u8) (mra_msg->offset9 >> 3); +} + +static inline void cm_mra_set_service_timeout(struct cm_mra_msg *mra_msg, + u8 service_timeout) +{ + mra_msg->offset9 = (u8) ((mra_msg->offset9 & 0x07) | + (service_timeout << 3)); +} + +struct cm_rej_msg { + struct ib_mad_hdr hdr; + + __be32 local_comm_id; + __be32 remote_comm_id; + /* message REJected:2, rsvd:6 */ + u8 offset8; + /* reject info length:7, rsvd:1. */ + u8 offset9; + __be16 reason; + u8 ari[IB_CM_REJ_ARI_LENGTH]; + + u8 private_data[IB_CM_REJ_PRIVATE_DATA_SIZE]; + +} __attribute__ ((packed)); + +static inline u8 cm_rej_get_msg_rejected(struct cm_rej_msg *rej_msg) +{ + return (u8) (rej_msg->offset8 >> 6); +} + +static inline void cm_rej_set_msg_rejected(struct cm_rej_msg *rej_msg, u8 msg) +{ + rej_msg->offset8 = (u8) ((rej_msg->offset8 & 0x3F) | (msg << 6)); +} + +static inline u8 cm_rej_get_reject_info_len(struct cm_rej_msg *rej_msg) +{ + return (u8) (rej_msg->offset9 >> 1); +} + +static inline void cm_rej_set_reject_info_len(struct cm_rej_msg *rej_msg, + u8 len) +{ + rej_msg->offset9 = (u8) ((rej_msg->offset9 & 0x1) | (len << 1)); +} + +struct cm_rep_msg { + struct ib_mad_hdr hdr; + + __be32 local_comm_id; + __be32 remote_comm_id; + __be32 local_qkey; + /* local QPN:24, rsvd:8 */ + __be32 offset12; + /* local EECN:24, rsvd:8 */ + __be32 offset16; + /* starting PSN:24 rsvd:8 */ + __be32 offset20; + u8 resp_resources; + u8 initiator_depth; + /* target ACK delay:5, failover accepted:2, end-to-end flow control:1 */ + u8 offset26; + /* RNR retry count:3, SRQ:1, rsvd:5 */ + u8 offset27; + __be64 local_ca_guid; + + u8 private_data[IB_CM_REP_PRIVATE_DATA_SIZE]; + +} __attribute__ ((packed)); + +static inline __be32 cm_rep_get_local_qpn(struct cm_rep_msg *rep_msg) +{ + return cpu_to_be32(be32_to_cpu(rep_msg->offset12) >> 8); +} + +static inline void cm_rep_set_local_qpn(struct cm_rep_msg *rep_msg, __be32 qpn) +{ + rep_msg->offset12 = cpu_to_be32((be32_to_cpu(qpn) << 8) | + (be32_to_cpu(rep_msg->offset12) & 0x000000FF)); +} + +static inline __be32 cm_rep_get_starting_psn(struct cm_rep_msg *rep_msg) +{ + return cpu_to_be32(be32_to_cpu(rep_msg->offset20) >> 8); +} + +static inline void cm_rep_set_starting_psn(struct cm_rep_msg *rep_msg, + __be32 starting_psn) +{ + rep_msg->offset20 = cpu_to_be32((be32_to_cpu(starting_psn) << 8) | + (be32_to_cpu(rep_msg->offset20) & 0x000000FF)); +} + +static inline u8 cm_rep_get_target_ack_delay(struct cm_rep_msg *rep_msg) +{ + return (u8) (rep_msg->offset26 >> 3); +} + +static inline void cm_rep_set_target_ack_delay(struct cm_rep_msg *rep_msg, + u8 target_ack_delay) +{ + rep_msg->offset26 = (u8) ((rep_msg->offset26 & 0x07) | + (target_ack_delay << 3)); +} + +static inline u8 cm_rep_get_failover(struct cm_rep_msg *rep_msg) +{ + return (u8) ((rep_msg->offset26 & 0x06) >> 1); +} + +static inline void cm_rep_set_failover(struct cm_rep_msg *rep_msg, u8 failover) +{ + rep_msg->offset26 = (u8) ((rep_msg->offset26 & 0xF9) | + ((failover & 0x3) << 1)); +} + +static inline u8 cm_rep_get_flow_ctrl(struct cm_rep_msg *rep_msg) +{ + return (u8) (rep_msg->offset26 & 0x01); +} + +static inline void cm_rep_set_flow_ctrl(struct cm_rep_msg *rep_msg, + u8 flow_ctrl) +{ + rep_msg->offset26 = (u8) ((rep_msg->offset26 & 0xFE) | + (flow_ctrl & 0x1)); +} + +static inline u8 cm_rep_get_rnr_retry_count(struct cm_rep_msg *rep_msg) +{ + return (u8) (rep_msg->offset27 >> 5); +} + +static inline void cm_rep_set_rnr_retry_count(struct cm_rep_msg *rep_msg, + u8 rnr_retry_count) +{ + rep_msg->offset27 = (u8) ((rep_msg->offset27 & 0x1F) | + (rnr_retry_count << 5)); +} + +static inline u8 cm_rep_get_srq(struct cm_rep_msg *rep_msg) +{ + return (u8) ((rep_msg->offset27 >> 4) & 0x1); +} + +static inline void cm_rep_set_srq(struct cm_rep_msg *rep_msg, u8 srq) +{ + rep_msg->offset27 = (u8) ((rep_msg->offset27 & 0xEF) | + ((srq & 0x1) << 4)); +} + +struct cm_rtu_msg { + struct ib_mad_hdr hdr; + + __be32 local_comm_id; + __be32 remote_comm_id; + + u8 private_data[IB_CM_RTU_PRIVATE_DATA_SIZE]; + +} __attribute__ ((packed)); + +struct cm_dreq_msg { + struct ib_mad_hdr hdr; + + __be32 local_comm_id; + __be32 remote_comm_id; + /* remote QPN/EECN:24, rsvd:8 */ + __be32 offset8; + + u8 private_data[IB_CM_DREQ_PRIVATE_DATA_SIZE]; + +} __attribute__ ((packed)); + +static inline __be32 cm_dreq_get_remote_qpn(struct cm_dreq_msg *dreq_msg) +{ + return cpu_to_be32(be32_to_cpu(dreq_msg->offset8) >> 8); +} + +static inline void cm_dreq_set_remote_qpn(struct cm_dreq_msg *dreq_msg, __be32 qpn) +{ + dreq_msg->offset8 = cpu_to_be32((be32_to_cpu(qpn) << 8) | + (be32_to_cpu(dreq_msg->offset8) & 0x000000FF)); +} + +struct cm_drep_msg { + struct ib_mad_hdr hdr; + + __be32 local_comm_id; + __be32 remote_comm_id; + + u8 private_data[IB_CM_DREP_PRIVATE_DATA_SIZE]; + +} __attribute__ ((packed)); + +struct cm_lap_msg { + struct ib_mad_hdr hdr; + + __be32 local_comm_id; + __be32 remote_comm_id; + + __be32 rsvd8; + /* remote QPN/EECN:24, remote CM response timeout:5, rsvd:3 */ + __be32 offset12; + __be32 rsvd16; + + __be16 alt_local_lid; + __be16 alt_remote_lid; + union ib_gid alt_local_gid; + union ib_gid alt_remote_gid; + /* flow label:20, rsvd:4, traffic class:8 */ + __be32 offset56; + u8 alt_hop_limit; + /* rsvd:2, packet rate:6 */ + u8 offset61; + /* SL:4, subnet local:1, rsvd:3 */ + u8 offset62; + /* local ACK timeout:5, rsvd:3 */ + u8 offset63; + + u8 private_data[IB_CM_LAP_PRIVATE_DATA_SIZE]; +} __attribute__ ((packed)); + +static inline __be32 cm_lap_get_remote_qpn(struct cm_lap_msg *lap_msg) +{ + return cpu_to_be32(be32_to_cpu(lap_msg->offset12) >> 8); +} + +static inline void cm_lap_set_remote_qpn(struct cm_lap_msg *lap_msg, __be32 qpn) +{ + lap_msg->offset12 = cpu_to_be32((be32_to_cpu(qpn) << 8) | + (be32_to_cpu(lap_msg->offset12) & + 0x000000FF)); +} + +static inline u8 cm_lap_get_remote_resp_timeout(struct cm_lap_msg *lap_msg) +{ + return (u8) ((be32_to_cpu(lap_msg->offset12) & 0xF8) >> 3); +} + +static inline void cm_lap_set_remote_resp_timeout(struct cm_lap_msg *lap_msg, + u8 resp_timeout) +{ + lap_msg->offset12 = cpu_to_be32((resp_timeout << 3) | + (be32_to_cpu(lap_msg->offset12) & + 0xFFFFFF07)); +} + +static inline __be32 cm_lap_get_flow_label(struct cm_lap_msg *lap_msg) +{ + return cpu_to_be32(be32_to_cpu(lap_msg->offset56) >> 12); +} + +static inline void cm_lap_set_flow_label(struct cm_lap_msg *lap_msg, + __be32 flow_label) +{ + lap_msg->offset56 = cpu_to_be32( + (be32_to_cpu(lap_msg->offset56) & 0x00000FFF) | + (be32_to_cpu(flow_label) << 12)); +} + +static inline u8 cm_lap_get_traffic_class(struct cm_lap_msg *lap_msg) +{ + return (u8) be32_to_cpu(lap_msg->offset56); +} + +static inline void cm_lap_set_traffic_class(struct cm_lap_msg *lap_msg, + u8 traffic_class) +{ + lap_msg->offset56 = cpu_to_be32(traffic_class | + (be32_to_cpu(lap_msg->offset56) & + 0xFFFFFF00)); +} + +static inline u8 cm_lap_get_packet_rate(struct cm_lap_msg *lap_msg) +{ + return lap_msg->offset61 & 0x3F; +} + +static inline void cm_lap_set_packet_rate(struct cm_lap_msg *lap_msg, + u8 packet_rate) +{ + lap_msg->offset61 = (packet_rate & 0x3F) | (lap_msg->offset61 & 0xC0); +} + +static inline u8 cm_lap_get_sl(struct cm_lap_msg *lap_msg) +{ + return lap_msg->offset62 >> 4; +} + +static inline void cm_lap_set_sl(struct cm_lap_msg *lap_msg, u8 sl) +{ + lap_msg->offset62 = (sl << 4) | (lap_msg->offset62 & 0x0F); +} + +static inline u8 cm_lap_get_subnet_local(struct cm_lap_msg *lap_msg) +{ + return (lap_msg->offset62 >> 3) & 0x1; +} + +static inline void cm_lap_set_subnet_local(struct cm_lap_msg *lap_msg, + u8 subnet_local) +{ + lap_msg->offset62 = ((subnet_local & 0x1) << 3) | + (lap_msg->offset61 & 0xF7); +} +static inline u8 cm_lap_get_local_ack_timeout(struct cm_lap_msg *lap_msg) +{ + return lap_msg->offset63 >> 3; +} + +static inline void cm_lap_set_local_ack_timeout(struct cm_lap_msg *lap_msg, + u8 local_ack_timeout) +{ + lap_msg->offset63 = (local_ack_timeout << 3) | + (lap_msg->offset63 & 0x07); +} + +struct cm_apr_msg { + struct ib_mad_hdr hdr; + + __be32 local_comm_id; + __be32 remote_comm_id; + + u8 info_length; + u8 ap_status; + u8 info[IB_CM_APR_INFO_LENGTH]; + + u8 private_data[IB_CM_APR_PRIVATE_DATA_SIZE]; +} __attribute__ ((packed)); + +struct cm_sidr_req_msg { + struct ib_mad_hdr hdr; + + __be32 request_id; + __be16 pkey; + __be16 rsvd; + __be64 service_id; + + u8 private_data[IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE]; +} __attribute__ ((packed)); + +struct cm_sidr_rep_msg { + struct ib_mad_hdr hdr; + + __be32 request_id; + u8 status; + u8 info_length; + __be16 rsvd; + /* QPN:24, rsvd:8 */ + __be32 offset8; + __be64 service_id; + __be32 qkey; + u8 info[IB_CM_SIDR_REP_INFO_LENGTH]; + + u8 private_data[IB_CM_SIDR_REP_PRIVATE_DATA_SIZE]; +} __attribute__ ((packed)); + +static inline __be32 cm_sidr_rep_get_qpn(struct cm_sidr_rep_msg *sidr_rep_msg) +{ + return cpu_to_be32(be32_to_cpu(sidr_rep_msg->offset8) >> 8); +} + +static inline void cm_sidr_rep_set_qpn(struct cm_sidr_rep_msg *sidr_rep_msg, + __be32 qpn) +{ + sidr_rep_msg->offset8 = cpu_to_be32((be32_to_cpu(qpn) << 8) | + (be32_to_cpu(sidr_rep_msg->offset8) & + 0x000000FF)); +} + +#endif /* CM_MSGS_H */ diff --git a/sys/ofed/drivers/infiniband/core/cma.c b/sys/ofed/drivers/infiniband/core/cma.c new file mode 100644 index 000000000000..c016451ba0b0 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/cma.c @@ -0,0 +1,3386 @@ +/* + * Copyright (c) 2005 Voltaire Inc. All rights reserved. + * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. + * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved. + * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Sean Hefty"); +MODULE_DESCRIPTION("Generic RDMA CM Agent"); +MODULE_LICENSE("Dual BSD/GPL"); + +static int tavor_quirk = 0; +module_param_named(tavor_quirk, tavor_quirk, int, 0644); +MODULE_PARM_DESC(tavor_quirk, "Tavor performance quirk: limit MTU to 1K if > 0"); + +int unify_tcp_port_space = 0; +module_param(unify_tcp_port_space, int, 0644); +MODULE_PARM_DESC(unify_tcp_port_space, "Unify the host TCP and RDMA port " + "space allocation (default=0)"); + +#define CMA_CM_RESPONSE_TIMEOUT 20 +#define CMA_MAX_CM_RETRIES 15 +#define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24) +#define IBOE_PACKET_LIFETIME 18 + +static int cma_response_timeout = CMA_CM_RESPONSE_TIMEOUT; +module_param_named(cma_response_timeout, cma_response_timeout, int, 0644); +MODULE_PARM_DESC(cma_response_timeout, "CMA_CM_RESPONSE_TIMEOUT default=20"); + +static int def_prec2sl = 3; +module_param_named(def_prec2sl, def_prec2sl, int, 0644); +MODULE_PARM_DESC(def_prec2sl, "Default value for SL priority with RoCE. Valid values 0 - 7"); + +static void cma_add_one(struct ib_device *device); +static void cma_remove_one(struct ib_device *device); + +static struct ib_client cma_client = { + .name = "cma", + .add = cma_add_one, + .remove = cma_remove_one +}; + +static struct ib_sa_client sa_client; +static struct rdma_addr_client addr_client; +static LIST_HEAD(dev_list); +static LIST_HEAD(listen_any_list); +static DEFINE_MUTEX(lock); +static struct workqueue_struct *cma_wq; +static DEFINE_IDR(sdp_ps); +static DEFINE_IDR(tcp_ps); +static DEFINE_IDR(udp_ps); +static DEFINE_IDR(ipoib_ps); +static int next_port; + +struct cma_device { + struct list_head list; + struct ib_device *device; + struct completion comp; + atomic_t refcount; + struct list_head id_list; +}; + +enum cma_state { + CMA_IDLE, + CMA_ADDR_QUERY, + CMA_ADDR_RESOLVED, + CMA_ROUTE_QUERY, + CMA_ROUTE_RESOLVED, + CMA_CONNECT, + CMA_DISCONNECT, + CMA_ADDR_BOUND, + CMA_LISTEN, + CMA_DEVICE_REMOVAL, + CMA_DESTROYING +}; + +struct rdma_bind_list { + struct idr *ps; + struct hlist_head owners; + unsigned short port; +}; + +/* + * Device removal can occur at anytime, so we need extra handling to + * serialize notifying the user of device removal with other callbacks. + * We do this by disabling removal notification while a callback is in process, + * and reporting it after the callback completes. + */ +struct rdma_id_private { + struct rdma_cm_id id; + + struct rdma_bind_list *bind_list; + struct socket *sock; + struct hlist_node node; + struct list_head list; /* listen_any_list or cma_device.list */ + struct list_head listen_list; /* per device listens */ + struct cma_device *cma_dev; + struct list_head mc_list; + + int internal_id; + enum cma_state state; + spinlock_t lock; + struct mutex qp_mutex; + + struct completion comp; + atomic_t refcount; + struct mutex handler_mutex; + + int backlog; + int timeout_ms; + struct ib_sa_query *query; + int query_id; + union { + struct ib_cm_id *ib; + struct iw_cm_id *iw; + } cm_id; + + u32 seq_num; + u32 qkey; + u32 qp_num; + u8 srq; + u8 tos; +}; + +struct cma_multicast { + struct rdma_id_private *id_priv; + union { + struct ib_sa_multicast *ib; + } multicast; + struct list_head list; + void *context; + struct sockaddr_storage addr; + struct kref mcref; +}; + +struct cma_work { + struct work_struct work; + struct rdma_id_private *id; + enum cma_state old_state; + enum cma_state new_state; + struct rdma_cm_event event; +}; + +struct cma_ndev_work { + struct work_struct work; + struct rdma_id_private *id; + struct rdma_cm_event event; +}; + +struct iboe_mcast_work { + struct work_struct work; + struct rdma_id_private *id; + struct cma_multicast *mc; +}; + +union cma_ip_addr { + struct in6_addr ip6; + struct { + __be32 pad[3]; + __be32 addr; + } ip4; +}; + +struct cma_hdr { + u8 cma_version; + u8 ip_version; /* IP version: 7:4 */ + __be16 port; + union cma_ip_addr src_addr; + union cma_ip_addr dst_addr; +}; + +struct sdp_hh { + u8 bsdh[16]; + u8 sdp_version; /* Major version: 7:4 */ + u8 ip_version; /* IP version: 7:4 */ + u8 sdp_specific1[10]; + __be16 port; + __be16 sdp_specific2; + union cma_ip_addr src_addr; + union cma_ip_addr dst_addr; +}; + +struct sdp_hah { + u8 bsdh[16]; + u8 sdp_version; +}; + +#define CMA_VERSION 0x00 +#define SDP_MAJ_VERSION 0x2 + +static int cma_comp(struct rdma_id_private *id_priv, enum cma_state comp) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&id_priv->lock, flags); + ret = (id_priv->state == comp); + spin_unlock_irqrestore(&id_priv->lock, flags); + return ret; +} + +static int cma_comp_exch(struct rdma_id_private *id_priv, + enum cma_state comp, enum cma_state exch) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&id_priv->lock, flags); + if ((ret = (id_priv->state == comp))) + id_priv->state = exch; + spin_unlock_irqrestore(&id_priv->lock, flags); + return ret; +} + +static enum cma_state cma_exch(struct rdma_id_private *id_priv, + enum cma_state exch) +{ + unsigned long flags; + enum cma_state old; + + spin_lock_irqsave(&id_priv->lock, flags); + old = id_priv->state; + id_priv->state = exch; + spin_unlock_irqrestore(&id_priv->lock, flags); + return old; +} + +static inline u8 cma_get_ip_ver(struct cma_hdr *hdr) +{ + return hdr->ip_version >> 4; +} + +static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver) +{ + hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF); +} + +static inline u8 sdp_get_majv(u8 sdp_version) +{ + return sdp_version >> 4; +} + +static inline u8 sdp_get_ip_ver(struct sdp_hh *hh) +{ + return hh->ip_version >> 4; +} + +static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver) +{ + hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF); +} + +static inline int cma_is_ud_ps(enum rdma_port_space ps) +{ + return (ps == RDMA_PS_UDP || ps == RDMA_PS_IPOIB); +} + +static void cma_attach_to_dev(struct rdma_id_private *id_priv, + struct cma_device *cma_dev) +{ + atomic_inc(&cma_dev->refcount); + id_priv->cma_dev = cma_dev; + id_priv->id.device = cma_dev->device; + id_priv->id.route.addr.dev_addr.transport = + rdma_node_get_transport(cma_dev->device->node_type); + list_add_tail(&id_priv->list, &cma_dev->id_list); +} + +static inline void cma_deref_dev(struct cma_device *cma_dev) +{ + if (atomic_dec_and_test(&cma_dev->refcount)) + complete(&cma_dev->comp); +} + +static inline void release_mc(struct kref *kref) +{ + struct cma_multicast *mc = container_of(kref, struct cma_multicast, mcref); + + kfree(mc->multicast.ib); + kfree(mc); +} + +static void cma_detach_from_dev(struct rdma_id_private *id_priv) +{ + list_del(&id_priv->list); + cma_deref_dev(id_priv->cma_dev); + id_priv->cma_dev = NULL; +} + +static int cma_set_qkey(struct rdma_id_private *id_priv) +{ + struct ib_sa_mcmember_rec rec; + int ret = 0; + + if (id_priv->qkey) + return 0; + + switch (id_priv->id.ps) { + case RDMA_PS_UDP: + id_priv->qkey = RDMA_UDP_QKEY; + break; + case RDMA_PS_IPOIB: + ib_addr_get_mgid(&id_priv->id.route.addr.dev_addr, &rec.mgid); + ret = ib_sa_get_mcmember_rec(id_priv->id.device, + id_priv->id.port_num, &rec.mgid, + &rec); + if (!ret) + id_priv->qkey = be32_to_cpu(rec.qkey); + break; + default: + break; + } + return ret; +} + +static int cma_acquire_dev(struct rdma_id_private *id_priv) +{ + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; + struct cma_device *cma_dev; + union ib_gid gid; + int ret = -ENODEV; + + if (dev_addr->dev_type != ARPHRD_INFINIBAND) { + iboe_addr_get_sgid(dev_addr, &gid); + list_for_each_entry(cma_dev, &dev_list, list) { + ret = ib_find_cached_gid(cma_dev->device, &gid, + &id_priv->id.port_num, NULL); + if (!ret) + goto out; + } + } + + memcpy(&gid, dev_addr->src_dev_addr + + rdma_addr_gid_offset(dev_addr), sizeof gid); + list_for_each_entry(cma_dev, &dev_list, list) { + ret = ib_find_cached_gid(cma_dev->device, &gid, + &id_priv->id.port_num, NULL); + if (!ret) + break; + } + +out: + if (!ret) + cma_attach_to_dev(id_priv, cma_dev); + + return ret; +} + +static void cma_deref_id(struct rdma_id_private *id_priv) +{ + if (atomic_dec_and_test(&id_priv->refcount)) + complete(&id_priv->comp); +} + +static int cma_disable_callback(struct rdma_id_private *id_priv, + enum cma_state state) +{ + mutex_lock(&id_priv->handler_mutex); + if (id_priv->state != state) { + mutex_unlock(&id_priv->handler_mutex); + return -EINVAL; + } + return 0; +} + +static int cma_has_cm_dev(struct rdma_id_private *id_priv) +{ + return (id_priv->id.device && id_priv->cm_id.ib); +} + +struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, + void *context, enum rdma_port_space ps) +{ + struct rdma_id_private *id_priv; + + id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL); + if (!id_priv) + return ERR_PTR(-ENOMEM); + + id_priv->state = CMA_IDLE; + id_priv->id.context = context; + id_priv->id.event_handler = event_handler; + id_priv->id.ps = ps; + spin_lock_init(&id_priv->lock); + mutex_init(&id_priv->qp_mutex); + init_completion(&id_priv->comp); + atomic_set(&id_priv->refcount, 1); + mutex_init(&id_priv->handler_mutex); + INIT_LIST_HEAD(&id_priv->listen_list); + INIT_LIST_HEAD(&id_priv->mc_list); + get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); + + return &id_priv->id; +} +EXPORT_SYMBOL(rdma_create_id); + +static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) +{ + struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; + + qp_attr.qp_state = IB_QPS_INIT; + ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); + if (ret) + return ret; + + ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); + if (ret) + return ret; + + qp_attr.qp_state = IB_QPS_RTR; + ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); + if (ret) + return ret; + + qp_attr.qp_state = IB_QPS_RTS; + qp_attr.sq_psn = 0; + ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); + + return ret; +} + +static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) +{ + struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; + + qp_attr.qp_state = IB_QPS_INIT; + ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); + if (ret) + return ret; + + return ib_modify_qp(qp, &qp_attr, qp_attr_mask); +} + +int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, + struct ib_qp_init_attr *qp_init_attr) +{ + struct rdma_id_private *id_priv; + struct ib_qp *qp; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (id->device != pd->device) + return -EINVAL; + + qp = ib_create_qp(pd, qp_init_attr); + if (IS_ERR(qp)) + return PTR_ERR(qp); + + if (cma_is_ud_ps(id_priv->id.ps)) + ret = cma_init_ud_qp(id_priv, qp); + else + ret = cma_init_conn_qp(id_priv, qp); + if (ret) + goto err; + + id->qp = qp; + id_priv->qp_num = qp->qp_num; + id_priv->srq = (qp->srq != NULL); + return 0; +err: + ib_destroy_qp(qp); + return ret; +} +EXPORT_SYMBOL(rdma_create_qp); + +void rdma_destroy_qp(struct rdma_cm_id *id) +{ + struct rdma_id_private *id_priv; + + id_priv = container_of(id, struct rdma_id_private, id); + mutex_lock(&id_priv->qp_mutex); + ib_destroy_qp(id_priv->id.qp); + id_priv->id.qp = NULL; + mutex_unlock(&id_priv->qp_mutex); +} +EXPORT_SYMBOL(rdma_destroy_qp); + +static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, + struct rdma_conn_param *conn_param) +{ + struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; + + mutex_lock(&id_priv->qp_mutex); + if (!id_priv->id.qp) { + ret = 0; + goto out; + } + + /* Need to update QP attributes from default values. */ + qp_attr.qp_state = IB_QPS_INIT; + ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); + if (ret) + goto out; + + ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); + if (ret) + goto out; + + qp_attr.qp_state = IB_QPS_RTR; + ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); + if (ret) + goto out; + + if (conn_param) + qp_attr.max_dest_rd_atomic = conn_param->responder_resources; + ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); +out: + mutex_unlock(&id_priv->qp_mutex); + return ret; +} + +static int cma_modify_qp_rts(struct rdma_id_private *id_priv, + struct rdma_conn_param *conn_param) +{ + struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; + + mutex_lock(&id_priv->qp_mutex); + if (!id_priv->id.qp) { + ret = 0; + goto out; + } + + qp_attr.qp_state = IB_QPS_RTS; + ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); + if (ret) + goto out; + + if (conn_param) + qp_attr.max_rd_atomic = conn_param->initiator_depth; + ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); +out: + mutex_unlock(&id_priv->qp_mutex); + return ret; +} + +static int cma_modify_qp_err(struct rdma_id_private *id_priv) +{ + struct ib_qp_attr qp_attr; + int ret; + + mutex_lock(&id_priv->qp_mutex); + if (!id_priv->id.qp) { + ret = 0; + goto out; + } + + qp_attr.qp_state = IB_QPS_ERR; + ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE); +out: + mutex_unlock(&id_priv->qp_mutex); + return ret; +} + +static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv, + struct ib_qp_attr *qp_attr, int *qp_attr_mask) +{ + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; + int ret; + u16 pkey; + + if (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num) == + IB_LINK_LAYER_INFINIBAND) + pkey = ib_addr_get_pkey(dev_addr); + else + pkey = 0xffff; + + ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, + pkey, &qp_attr->pkey_index); + if (ret) + return ret; + + qp_attr->port_num = id_priv->id.port_num; + *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT; + + if (cma_is_ud_ps(id_priv->id.ps)) { + ret = cma_set_qkey(id_priv); + if (ret) + return ret; + + qp_attr->qkey = id_priv->qkey; + *qp_attr_mask |= IB_QP_QKEY; + } else { + qp_attr->qp_access_flags = 0; + *qp_attr_mask |= IB_QP_ACCESS_FLAGS; + } + return 0; +} + +int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, + int *qp_attr_mask) +{ + struct rdma_id_private *id_priv; + int ret = 0; + + id_priv = container_of(id, struct rdma_id_private, id); + switch (rdma_node_get_transport(id_priv->id.device->node_type)) { + case RDMA_TRANSPORT_IB: + if (!id_priv->cm_id.ib || cma_is_ud_ps(id_priv->id.ps)) + ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask); + else + ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, + qp_attr_mask); + if (qp_attr->qp_state == IB_QPS_RTR) + qp_attr->rq_psn = id_priv->seq_num; + break; + case RDMA_TRANSPORT_IWARP: + if (!id_priv->cm_id.iw) { + qp_attr->qp_access_flags = 0; + *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; + } else + ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, + qp_attr_mask); + break; + default: + ret = -ENOSYS; + break; + } + + return ret; +} +EXPORT_SYMBOL(rdma_init_qp_attr); + +static inline int cma_zero_addr(struct sockaddr *addr) +{ + struct in6_addr *ip6; + + if (addr->sa_family == AF_INET) + return ipv4_is_zeronet( + ((struct sockaddr_in *)addr)->sin_addr.s_addr); + else { + ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr; + return (ip6->s6_addr32[0] | ip6->s6_addr32[1] | + ip6->s6_addr32[2] | ip6->s6_addr32[3]) == 0; + } +} + +static inline int cma_loopback_addr(struct sockaddr *addr) +{ + if (addr->sa_family == AF_INET) + return ipv4_is_loopback( + ((struct sockaddr_in *) addr)->sin_addr.s_addr); + else + return ipv6_addr_loopback( + &((struct sockaddr_in6 *) addr)->sin6_addr); +} + +static inline int cma_any_addr(struct sockaddr *addr) +{ + return cma_zero_addr(addr) || cma_loopback_addr(addr); +} + +static inline __be16 cma_port(struct sockaddr *addr) +{ + if (addr->sa_family == AF_INET) + return ((struct sockaddr_in *) addr)->sin_port; + else + return ((struct sockaddr_in6 *) addr)->sin6_port; +} + +static inline int cma_any_port(struct sockaddr *addr) +{ + return !cma_port(addr); +} + +static int cma_get_net_info(void *hdr, enum rdma_port_space ps, + u8 *ip_ver, __be16 *port, + union cma_ip_addr **src, union cma_ip_addr **dst) +{ + switch (ps) { + case RDMA_PS_SDP: + if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) != + SDP_MAJ_VERSION) + return -EINVAL; + + *ip_ver = sdp_get_ip_ver(hdr); + *port = ((struct sdp_hh *) hdr)->port; + *src = &((struct sdp_hh *) hdr)->src_addr; + *dst = &((struct sdp_hh *) hdr)->dst_addr; + break; + default: + if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION) + return -EINVAL; + + *ip_ver = cma_get_ip_ver(hdr); + *port = ((struct cma_hdr *) hdr)->port; + *src = &((struct cma_hdr *) hdr)->src_addr; + *dst = &((struct cma_hdr *) hdr)->dst_addr; + break; + } + + if (*ip_ver != 4 && *ip_ver != 6) + return -EINVAL; + return 0; +} + +static void cma_save_net_info(struct rdma_addr *addr, + struct rdma_addr *listen_addr, + u8 ip_ver, __be16 port, + union cma_ip_addr *src, union cma_ip_addr *dst) +{ + struct sockaddr_in *listen4, *ip4; + struct sockaddr_in6 *listen6, *ip6; + + switch (ip_ver) { + case 4: + listen4 = (struct sockaddr_in *) &listen_addr->src_addr; + ip4 = (struct sockaddr_in *) &addr->src_addr; + ip4->sin_family = listen4->sin_family; + ip4->sin_addr.s_addr = dst->ip4.addr; + ip4->sin_port = listen4->sin_port; + + ip4 = (struct sockaddr_in *) &addr->dst_addr; + ip4->sin_family = listen4->sin_family; + ip4->sin_addr.s_addr = src->ip4.addr; + ip4->sin_port = port; + break; + case 6: + listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr; + ip6 = (struct sockaddr_in6 *) &addr->src_addr; + ip6->sin6_family = listen6->sin6_family; + ip6->sin6_addr = dst->ip6; + ip6->sin6_port = listen6->sin6_port; + + ip6 = (struct sockaddr_in6 *) &addr->dst_addr; + ip6->sin6_family = listen6->sin6_family; + ip6->sin6_addr = src->ip6; + ip6->sin6_port = port; + break; + default: + break; + } +} + +static inline int cma_user_data_offset(enum rdma_port_space ps) +{ + switch (ps) { + case RDMA_PS_SDP: + return 0; + default: + return sizeof(struct cma_hdr); + } +} + +static void cma_cancel_route(struct rdma_id_private *id_priv) +{ + switch (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num)) { + case IB_LINK_LAYER_INFINIBAND: + if (id_priv->query) + ib_sa_cancel_query(id_priv->query_id, id_priv->query); + break; + default: + break; + } +} + +static void cma_cancel_listens(struct rdma_id_private *id_priv) +{ + struct rdma_id_private *dev_id_priv; + + /* + * Remove from listen_any_list to prevent added devices from spawning + * additional listen requests. + */ + mutex_lock(&lock); + list_del(&id_priv->list); + + while (!list_empty(&id_priv->listen_list)) { + dev_id_priv = list_entry(id_priv->listen_list.next, + struct rdma_id_private, listen_list); + /* sync with device removal to avoid duplicate destruction */ + list_del_init(&dev_id_priv->list); + list_del(&dev_id_priv->listen_list); + mutex_unlock(&lock); + + rdma_destroy_id(&dev_id_priv->id); + mutex_lock(&lock); + } + mutex_unlock(&lock); +} + +static void cma_cancel_operation(struct rdma_id_private *id_priv, + enum cma_state state) +{ + switch (state) { + case CMA_ADDR_QUERY: + rdma_addr_cancel(&id_priv->id.route.addr.dev_addr); + break; + case CMA_ROUTE_QUERY: + cma_cancel_route(id_priv); + break; + case CMA_LISTEN: + if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr) + && !id_priv->cma_dev) + cma_cancel_listens(id_priv); + break; + default: + break; + } +} + +static void cma_release_port(struct rdma_id_private *id_priv) +{ + struct rdma_bind_list *bind_list = id_priv->bind_list; + + if (!bind_list) + return; + + mutex_lock(&lock); + hlist_del(&id_priv->node); + if (hlist_empty(&bind_list->owners)) { + idr_remove(bind_list->ps, bind_list->port); + kfree(bind_list); + } + mutex_unlock(&lock); + if (id_priv->sock) + sock_release(id_priv->sock); +} + +static void cma_leave_mc_groups(struct rdma_id_private *id_priv) +{ + struct cma_multicast *mc; + + while (!list_empty(&id_priv->mc_list)) { + mc = container_of(id_priv->mc_list.next, + struct cma_multicast, list); + list_del(&mc->list); + switch (rdma_port_get_link_layer(id_priv->cma_dev->device, id_priv->id.port_num)) { + case IB_LINK_LAYER_INFINIBAND: + ib_sa_free_multicast(mc->multicast.ib); + kfree(mc); + break; + case IB_LINK_LAYER_ETHERNET: + kref_put(&mc->mcref, release_mc); + break; + default: + break; + } + } +} + +void rdma_destroy_id(struct rdma_cm_id *id) +{ + struct rdma_id_private *id_priv; + enum cma_state state; + + id_priv = container_of(id, struct rdma_id_private, id); + state = cma_exch(id_priv, CMA_DESTROYING); + cma_cancel_operation(id_priv, state); + + mutex_lock(&lock); + if (id_priv->cma_dev) { + mutex_unlock(&lock); + switch (rdma_node_get_transport(id_priv->id.device->node_type)) { + case RDMA_TRANSPORT_IB: + if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib)) + ib_destroy_cm_id(id_priv->cm_id.ib); + break; + case RDMA_TRANSPORT_IWARP: + if (id_priv->cm_id.iw && !IS_ERR(id_priv->cm_id.iw)) + iw_destroy_cm_id(id_priv->cm_id.iw); + break; + default: + break; + } + cma_leave_mc_groups(id_priv); + mutex_lock(&lock); + cma_detach_from_dev(id_priv); + } + mutex_unlock(&lock); + + cma_release_port(id_priv); + cma_deref_id(id_priv); + wait_for_completion(&id_priv->comp); + + if (id_priv->internal_id) + cma_deref_id(id_priv->id.context); + + kfree(id_priv->id.route.path_rec); + kfree(id_priv); +} +EXPORT_SYMBOL(rdma_destroy_id); + +static int cma_rep_recv(struct rdma_id_private *id_priv) +{ + int ret; + + ret = cma_modify_qp_rtr(id_priv, NULL); + if (ret) + goto reject; + + ret = cma_modify_qp_rts(id_priv, NULL); + if (ret) + goto reject; + + ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0); + if (ret) + goto reject; + + return 0; +reject: + cma_modify_qp_err(id_priv); + ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, + NULL, 0, NULL, 0); + return ret; +} + +static int cma_verify_rep(struct rdma_id_private *id_priv, void *data) +{ + if (id_priv->id.ps == RDMA_PS_SDP && + sdp_get_majv(((struct sdp_hah *) data)->sdp_version) != + SDP_MAJ_VERSION) + return -EINVAL; + + return 0; +} + +static void cma_set_rep_event_data(struct rdma_cm_event *event, + struct ib_cm_rep_event_param *rep_data, + void *private_data) +{ + event->param.conn.private_data = private_data; + event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE; + event->param.conn.responder_resources = rep_data->responder_resources; + event->param.conn.initiator_depth = rep_data->initiator_depth; + event->param.conn.flow_control = rep_data->flow_control; + event->param.conn.rnr_retry_count = rep_data->rnr_retry_count; + event->param.conn.srq = rep_data->srq; + event->param.conn.qp_num = rep_data->remote_qpn; +} + +static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) +{ + struct rdma_id_private *id_priv = cm_id->context; + struct rdma_cm_event event; + int ret = 0; + + if ((ib_event->event != IB_CM_TIMEWAIT_EXIT && + cma_disable_callback(id_priv, CMA_CONNECT)) || + (ib_event->event == IB_CM_TIMEWAIT_EXIT && + cma_disable_callback(id_priv, CMA_DISCONNECT))) + return 0; + + memset(&event, 0, sizeof event); + switch (ib_event->event) { + case IB_CM_REQ_ERROR: + case IB_CM_REP_ERROR: + event.event = RDMA_CM_EVENT_UNREACHABLE; + event.status = -ETIMEDOUT; + break; + case IB_CM_REP_RECEIVED: + event.status = cma_verify_rep(id_priv, ib_event->private_data); + if (event.status) + event.event = RDMA_CM_EVENT_CONNECT_ERROR; + else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) { + event.status = cma_rep_recv(id_priv); + event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR : + RDMA_CM_EVENT_ESTABLISHED; + } else + event.event = RDMA_CM_EVENT_CONNECT_RESPONSE; + cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd, + ib_event->private_data); + break; + case IB_CM_RTU_RECEIVED: + case IB_CM_USER_ESTABLISHED: + event.event = RDMA_CM_EVENT_ESTABLISHED; + break; + case IB_CM_DREQ_ERROR: + event.status = -ETIMEDOUT; /* fall through */ + case IB_CM_DREQ_RECEIVED: + case IB_CM_DREP_RECEIVED: + if (!cma_comp_exch(id_priv, CMA_CONNECT, CMA_DISCONNECT)) + goto out; + event.event = RDMA_CM_EVENT_DISCONNECTED; + break; + case IB_CM_TIMEWAIT_EXIT: + event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT; + break; + case IB_CM_MRA_RECEIVED: + /* ignore event */ + goto out; + case IB_CM_REJ_RECEIVED: + cma_modify_qp_err(id_priv); + event.status = ib_event->param.rej_rcvd.reason; + event.event = RDMA_CM_EVENT_REJECTED; + event.param.conn.private_data = ib_event->private_data; + event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE; + break; + default: + printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", + ib_event->event); + goto out; + } + + ret = id_priv->id.event_handler(&id_priv->id, &event); + if (ret) { + /* Destroy the CM ID by returning a non-zero value. */ + id_priv->cm_id.ib = NULL; + cma_exch(id_priv, CMA_DESTROYING); + mutex_unlock(&id_priv->handler_mutex); + rdma_destroy_id(&id_priv->id); + return ret; + } +out: + mutex_unlock(&id_priv->handler_mutex); + return ret; +} + +static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id, + struct ib_cm_event *ib_event) +{ + struct rdma_id_private *id_priv; + struct rdma_cm_id *id; + struct rdma_route *rt; + union cma_ip_addr *src, *dst; + __be16 port; + u8 ip_ver; + int ret; + + if (cma_get_net_info(ib_event->private_data, listen_id->ps, + &ip_ver, &port, &src, &dst)) + goto err; + + id = rdma_create_id(listen_id->event_handler, listen_id->context, + listen_id->ps); + if (IS_ERR(id)) + goto err; + + cma_save_net_info(&id->route.addr, &listen_id->route.addr, + ip_ver, port, src, dst); + + rt = &id->route; + rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; + rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, + GFP_KERNEL); + if (!rt->path_rec) + goto destroy_id; + + rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path; + if (rt->num_paths == 2) + rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; + + if (cma_any_addr((struct sockaddr *) &rt->addr.src_addr)) { + rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND; + rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid); + ib_addr_set_pkey(&rt->addr.dev_addr, rt->path_rec[0].pkey); + } else { + ret = rdma_translate_ip((struct sockaddr *) &rt->addr.src_addr, + &rt->addr.dev_addr); + if (ret) + goto destroy_id; + } + rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); + + id_priv = container_of(id, struct rdma_id_private, id); + id_priv->state = CMA_CONNECT; + return id_priv; + +destroy_id: + rdma_destroy_id(id); +err: + return NULL; +} + +static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id, + struct ib_cm_event *ib_event) +{ + struct rdma_id_private *id_priv; + struct rdma_cm_id *id; + union cma_ip_addr *src, *dst; + __be16 port; + u8 ip_ver; + int ret; + + id = rdma_create_id(listen_id->event_handler, listen_id->context, + listen_id->ps); + if (IS_ERR(id)) + return NULL; + + + if (cma_get_net_info(ib_event->private_data, listen_id->ps, + &ip_ver, &port, &src, &dst)) + goto err; + + cma_save_net_info(&id->route.addr, &listen_id->route.addr, + ip_ver, port, src, dst); + + if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) { + ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr, + &id->route.addr.dev_addr); + if (ret) + goto err; + } + + id_priv = container_of(id, struct rdma_id_private, id); + id_priv->state = CMA_CONNECT; + return id_priv; +err: + rdma_destroy_id(id); + return NULL; +} + +static void cma_set_req_event_data(struct rdma_cm_event *event, + struct ib_cm_req_event_param *req_data, + void *private_data, int offset) +{ + event->param.conn.private_data = private_data + offset; + event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset; + event->param.conn.responder_resources = req_data->responder_resources; + event->param.conn.initiator_depth = req_data->initiator_depth; + event->param.conn.flow_control = req_data->flow_control; + event->param.conn.retry_count = req_data->retry_count; + event->param.conn.rnr_retry_count = req_data->rnr_retry_count; + event->param.conn.srq = req_data->srq; + event->param.conn.qp_num = req_data->remote_qpn; +} + +static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) +{ + struct rdma_id_private *listen_id, *conn_id; + struct rdma_cm_event event; + int offset, ret; + + listen_id = cm_id->context; + if (cma_disable_callback(listen_id, CMA_LISTEN)) + return -ECONNABORTED; + + memset(&event, 0, sizeof event); + offset = cma_user_data_offset(listen_id->id.ps); + event.event = RDMA_CM_EVENT_CONNECT_REQUEST; + if (cma_is_ud_ps(listen_id->id.ps)) { + conn_id = cma_new_udp_id(&listen_id->id, ib_event); + event.param.ud.private_data = ib_event->private_data + offset; + event.param.ud.private_data_len = + IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; + } else { + conn_id = cma_new_conn_id(&listen_id->id, ib_event); + cma_set_req_event_data(&event, &ib_event->param.req_rcvd, + ib_event->private_data, offset); + } + if (!conn_id) { + ret = -ENOMEM; + goto out; + } + + mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); + mutex_lock(&lock); + ret = cma_acquire_dev(conn_id); + mutex_unlock(&lock); + if (ret) + goto release_conn_id; + + conn_id->cm_id.ib = cm_id; + cm_id->context = conn_id; + cm_id->cm_handler = cma_ib_handler; + + ret = conn_id->id.event_handler(&conn_id->id, &event); + if (!ret) { + /* + * Acquire mutex to prevent user executing rdma_destroy_id() + * while we're accessing the cm_id. + */ + mutex_lock(&lock); + if (cma_comp(conn_id, CMA_CONNECT) && + !cma_is_ud_ps(conn_id->id.ps)) + ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); + mutex_unlock(&lock); + mutex_unlock(&conn_id->handler_mutex); + goto out; + } + + /* Destroy the CM ID by returning a non-zero value. */ + conn_id->cm_id.ib = NULL; + +release_conn_id: + cma_exch(conn_id, CMA_DESTROYING); + mutex_unlock(&conn_id->handler_mutex); + rdma_destroy_id(&conn_id->id); + +out: + mutex_unlock(&listen_id->handler_mutex); + return ret; +} + +static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr) +{ + return cpu_to_be64(((u64)ps << 16) + be16_to_cpu(cma_port(addr))); +} + +static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr, + struct ib_cm_compare_data *compare) +{ + struct cma_hdr *cma_data, *cma_mask; + struct sdp_hh *sdp_data, *sdp_mask; + __be32 ip4_addr; + struct in6_addr ip6_addr; + + memset(compare, 0, sizeof *compare); + cma_data = (void *) compare->data; + cma_mask = (void *) compare->mask; + sdp_data = (void *) compare->data; + sdp_mask = (void *) compare->mask; + + switch (addr->sa_family) { + case AF_INET: + ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; + if (ps == RDMA_PS_SDP) { + sdp_set_ip_ver(sdp_data, 4); + sdp_set_ip_ver(sdp_mask, 0xF); + sdp_data->dst_addr.ip4.addr = ip4_addr; + sdp_mask->dst_addr.ip4.addr = htonl(~0); + } else { + cma_set_ip_ver(cma_data, 4); + cma_set_ip_ver(cma_mask, 0xF); + cma_data->dst_addr.ip4.addr = ip4_addr; + cma_mask->dst_addr.ip4.addr = htonl(~0); + } + break; +#ifdef INET6 + case AF_INET6: + ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr; + if (ps == RDMA_PS_SDP) { + sdp_set_ip_ver(sdp_data, 6); + sdp_set_ip_ver(sdp_mask, 0xF); + sdp_data->dst_addr.ip6 = ip6_addr; + memset(&sdp_mask->dst_addr.ip6, 0xFF, + sizeof sdp_mask->dst_addr.ip6); + } else { + cma_set_ip_ver(cma_data, 6); + cma_set_ip_ver(cma_mask, 0xF); + cma_data->dst_addr.ip6 = ip6_addr; + memset(&cma_mask->dst_addr.ip6, 0xFF, + sizeof cma_mask->dst_addr.ip6); + } + break; +#endif + default: + break; + } +} + +static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) +{ + struct rdma_id_private *id_priv = iw_id->context; + struct rdma_cm_event event; + struct sockaddr_in *sin; + int ret = 0; + + if (cma_disable_callback(id_priv, CMA_CONNECT)) + return 0; + + memset(&event, 0, sizeof event); + switch (iw_event->event) { + case IW_CM_EVENT_CLOSE: + event.event = RDMA_CM_EVENT_DISCONNECTED; + break; + case IW_CM_EVENT_CONNECT_REPLY: + sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; + *sin = iw_event->local_addr; + sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr; + *sin = iw_event->remote_addr; + switch (iw_event->status) { + case 0: + event.event = RDMA_CM_EVENT_ESTABLISHED; + break; + case -ECONNRESET: + case -ECONNREFUSED: + event.event = RDMA_CM_EVENT_REJECTED; + break; + case -ETIMEDOUT: + event.event = RDMA_CM_EVENT_UNREACHABLE; + break; + default: + event.event = RDMA_CM_EVENT_CONNECT_ERROR; + break; + } + break; + case IW_CM_EVENT_ESTABLISHED: + event.event = RDMA_CM_EVENT_ESTABLISHED; + break; + default: + BUG_ON(1); + } + + event.status = iw_event->status; + event.param.conn.private_data = iw_event->private_data; + event.param.conn.private_data_len = iw_event->private_data_len; + ret = id_priv->id.event_handler(&id_priv->id, &event); + if (ret) { + /* Destroy the CM ID by returning a non-zero value. */ + id_priv->cm_id.iw = NULL; + cma_exch(id_priv, CMA_DESTROYING); + mutex_unlock(&id_priv->handler_mutex); + rdma_destroy_id(&id_priv->id); + return ret; + } + + mutex_unlock(&id_priv->handler_mutex); + return ret; +} + +static int iw_conn_req_handler(struct iw_cm_id *cm_id, + struct iw_cm_event *iw_event) +{ + struct rdma_cm_id *new_cm_id; + struct rdma_id_private *listen_id, *conn_id; + struct sockaddr_in *sin; + struct net_device *dev = NULL; + struct rdma_cm_event event; + int ret; + struct ib_device_attr attr; + + listen_id = cm_id->context; + if (cma_disable_callback(listen_id, CMA_LISTEN)) + return -ECONNABORTED; + + /* Create a new RDMA id for the new IW CM ID */ + new_cm_id = rdma_create_id(listen_id->id.event_handler, + listen_id->id.context, + RDMA_PS_TCP); + if (IS_ERR(new_cm_id)) { + ret = -ENOMEM; + goto out; + } + conn_id = container_of(new_cm_id, struct rdma_id_private, id); + mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); + conn_id->state = CMA_CONNECT; + + dev = ip_dev_find(NULL, iw_event->local_addr.sin_addr.s_addr); + if (!dev) { + ret = -EADDRNOTAVAIL; + mutex_unlock(&conn_id->handler_mutex); + rdma_destroy_id(new_cm_id); + goto out; + } + ret = rdma_copy_addr(&conn_id->id.route.addr.dev_addr, dev, NULL); + if (ret) { + mutex_unlock(&conn_id->handler_mutex); + rdma_destroy_id(new_cm_id); + goto out; + } + + mutex_lock(&lock); + ret = cma_acquire_dev(conn_id); + mutex_unlock(&lock); + if (ret) { + mutex_unlock(&conn_id->handler_mutex); + rdma_destroy_id(new_cm_id); + goto out; + } + + conn_id->cm_id.iw = cm_id; + cm_id->context = conn_id; + cm_id->cm_handler = cma_iw_handler; + + sin = (struct sockaddr_in *) &new_cm_id->route.addr.src_addr; + *sin = iw_event->local_addr; + sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr; + *sin = iw_event->remote_addr; + + ret = ib_query_device(conn_id->id.device, &attr); + if (ret) { + mutex_unlock(&conn_id->handler_mutex); + rdma_destroy_id(new_cm_id); + goto out; + } + + memset(&event, 0, sizeof event); + event.event = RDMA_CM_EVENT_CONNECT_REQUEST; + event.param.conn.private_data = iw_event->private_data; + event.param.conn.private_data_len = iw_event->private_data_len; + event.param.conn.initiator_depth = attr.max_qp_init_rd_atom; + event.param.conn.responder_resources = attr.max_qp_rd_atom; + ret = conn_id->id.event_handler(&conn_id->id, &event); + if (ret) { + /* User wants to destroy the CM ID */ + conn_id->cm_id.iw = NULL; + cma_exch(conn_id, CMA_DESTROYING); + mutex_unlock(&conn_id->handler_mutex); + rdma_destroy_id(&conn_id->id); + goto out; + } + + mutex_unlock(&conn_id->handler_mutex); + +out: + if (dev) + dev_put(dev); + mutex_unlock(&listen_id->handler_mutex); + return ret; +} + +static int cma_ib_listen(struct rdma_id_private *id_priv) +{ + struct ib_cm_compare_data compare_data; + struct sockaddr *addr; + __be64 svc_id; + int ret; + + id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_req_handler, + id_priv); + if (IS_ERR(id_priv->cm_id.ib)) + return PTR_ERR(id_priv->cm_id.ib); + + addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; + svc_id = cma_get_service_id(id_priv->id.ps, addr); + if (cma_any_addr(addr)) + ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL); + else { + cma_set_compare_data(id_priv->id.ps, addr, &compare_data); + ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, &compare_data); + } + + if (ret) { + ib_destroy_cm_id(id_priv->cm_id.ib); + id_priv->cm_id.ib = NULL; + } + + return ret; +} + +static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog) +{ + int ret; + struct sockaddr_in *sin; + + id_priv->cm_id.iw = iw_create_cm_id(id_priv->id.device, + iw_conn_req_handler, + id_priv); + if (IS_ERR(id_priv->cm_id.iw)) + return PTR_ERR(id_priv->cm_id.iw); + + sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; + id_priv->cm_id.iw->local_addr = *sin; + + ret = iw_cm_listen(id_priv->cm_id.iw, backlog); + + if (ret) { + iw_destroy_cm_id(id_priv->cm_id.iw); + id_priv->cm_id.iw = NULL; + } + + return ret; +} + +static int cma_listen_handler(struct rdma_cm_id *id, + struct rdma_cm_event *event) +{ + struct rdma_id_private *id_priv = id->context; + + id->context = id_priv->id.context; + id->event_handler = id_priv->id.event_handler; + return id_priv->id.event_handler(id, event); +} + +static void cma_listen_on_dev(struct rdma_id_private *id_priv, + struct cma_device *cma_dev) +{ + struct rdma_id_private *dev_id_priv; + struct rdma_cm_id *id; + int ret; + + id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps); + if (IS_ERR(id)) + return; + + dev_id_priv = container_of(id, struct rdma_id_private, id); + + dev_id_priv->state = CMA_ADDR_BOUND; + memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr, + ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr)); + + cma_attach_to_dev(dev_id_priv, cma_dev); + list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); + atomic_inc(&id_priv->refcount); + dev_id_priv->internal_id = 1; + + ret = rdma_listen(id, id_priv->backlog); + if (ret) + printk(KERN_WARNING "RDMA CMA: cma_listen_on_dev, error %d, " + "listening on device %s\n", ret, cma_dev->device->name); +} + +static void cma_listen_on_all(struct rdma_id_private *id_priv) +{ + struct cma_device *cma_dev; + + mutex_lock(&lock); + list_add_tail(&id_priv->list, &listen_any_list); + list_for_each_entry(cma_dev, &dev_list, list) + cma_listen_on_dev(id_priv, cma_dev); + mutex_unlock(&lock); +} + +int rdma_listen(struct rdma_cm_id *id, int backlog) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (id_priv->state == CMA_IDLE) { + ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET; + ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr); + if (ret) + return ret; + } + + if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN)) + return -EINVAL; + + id_priv->backlog = backlog; + if (id->device) { + switch (rdma_node_get_transport(id->device->node_type)) { + case RDMA_TRANSPORT_IB: + ret = cma_ib_listen(id_priv); + if (ret) + goto err; + break; + case RDMA_TRANSPORT_IWARP: + ret = cma_iw_listen(id_priv, backlog); + if (ret) + goto err; + break; + default: + ret = -ENOSYS; + goto err; + } + } else + cma_listen_on_all(id_priv); + + return 0; +err: + id_priv->backlog = 0; + cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND); + return ret; +} +EXPORT_SYMBOL(rdma_listen); + +void rdma_set_service_type(struct rdma_cm_id *id, int tos) +{ + struct rdma_id_private *id_priv; + + id_priv = container_of(id, struct rdma_id_private, id); + id_priv->tos = (u8) tos; +} +EXPORT_SYMBOL(rdma_set_service_type); + +static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, + void *context) +{ + struct cma_work *work = context; + struct rdma_route *route; + + route = &work->id->id.route; + + if (!status) { + route->num_paths = 1; + *route->path_rec = *path_rec; + } else { + work->old_state = CMA_ROUTE_QUERY; + work->new_state = CMA_ADDR_RESOLVED; + work->event.event = RDMA_CM_EVENT_ROUTE_ERROR; + work->event.status = status; + } + + queue_work(cma_wq, &work->work); +} + +static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, + struct cma_work *work) +{ + struct rdma_addr *addr = &id_priv->id.route.addr; + struct ib_sa_path_rec path_rec; + ib_sa_comp_mask comp_mask; + struct sockaddr_in6 *sin6; + + memset(&path_rec, 0, sizeof path_rec); + rdma_addr_get_sgid(&addr->dev_addr, &path_rec.sgid); + rdma_addr_get_dgid(&addr->dev_addr, &path_rec.dgid); + path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr)); + path_rec.numb_path = 1; + path_rec.reversible = 1; + path_rec.service_id = cma_get_service_id(id_priv->id.ps, + (struct sockaddr *) &addr->dst_addr); + + comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | + IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | + IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID; + + if (addr->src_addr.ss_family == AF_INET) { + path_rec.qos_class = cpu_to_be16((u16) id_priv->tos); + comp_mask |= IB_SA_PATH_REC_QOS_CLASS; + } else { + sin6 = (struct sockaddr_in6 *) &addr->src_addr; + path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20); + comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS; + } + + if (tavor_quirk) { + path_rec.mtu_selector = IB_SA_LT; + path_rec.mtu = IB_MTU_2048; + } + + id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device, + id_priv->id.port_num, &path_rec, + comp_mask, timeout_ms, + GFP_KERNEL, cma_query_handler, + work, &id_priv->query); + + return (id_priv->query_id < 0) ? id_priv->query_id : 0; +} + +static void cma_work_handler(struct work_struct *_work) +{ + struct cma_work *work = container_of(_work, struct cma_work, work); + struct rdma_id_private *id_priv = work->id; + int destroy = 0; + + mutex_lock(&id_priv->handler_mutex); + if (!cma_comp_exch(id_priv, work->old_state, work->new_state)) + goto out; + + if (id_priv->id.event_handler(&id_priv->id, &work->event)) { + cma_exch(id_priv, CMA_DESTROYING); + destroy = 1; + } +out: + mutex_unlock(&id_priv->handler_mutex); + cma_deref_id(id_priv); + if (destroy) + rdma_destroy_id(&id_priv->id); + kfree(work); +} + +static void cma_ndev_work_handler(struct work_struct *_work) +{ + struct cma_ndev_work *work = container_of(_work, struct cma_ndev_work, work); + struct rdma_id_private *id_priv = work->id; + int destroy = 0; + + mutex_lock(&id_priv->handler_mutex); + if (id_priv->state == CMA_DESTROYING || + id_priv->state == CMA_DEVICE_REMOVAL) + goto out; + + if (id_priv->id.event_handler(&id_priv->id, &work->event)) { + cma_exch(id_priv, CMA_DESTROYING); + destroy = 1; + } + +out: + mutex_unlock(&id_priv->handler_mutex); + cma_deref_id(id_priv); + if (destroy) + rdma_destroy_id(&id_priv->id); + kfree(work); +} + +static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms) +{ + struct rdma_route *route = &id_priv->id.route; + struct cma_work *work; + int ret; + + work = kzalloc(sizeof *work, GFP_KERNEL); + if (!work) + return -ENOMEM; + + work->id = id_priv; + INIT_WORK(&work->work, cma_work_handler); + work->old_state = CMA_ROUTE_QUERY; + work->new_state = CMA_ROUTE_RESOLVED; + work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; + + route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL); + if (!route->path_rec) { + ret = -ENOMEM; + goto err1; + } + + ret = cma_query_ib_route(id_priv, timeout_ms, work); + if (ret) + goto err2; + + return 0; +err2: + kfree(route->path_rec); + route->path_rec = NULL; +err1: + kfree(work); + return ret; +} + +int rdma_set_ib_paths(struct rdma_cm_id *id, + struct ib_sa_path_rec *path_rec, int num_paths) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_RESOLVED)) + return -EINVAL; + + id->route.path_rec = kmalloc(sizeof *path_rec * num_paths, GFP_KERNEL); + if (!id->route.path_rec) { + ret = -ENOMEM; + goto err; + } + + memcpy(id->route.path_rec, path_rec, sizeof *path_rec * num_paths); + return 0; +err: + cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_ADDR_RESOLVED); + return ret; +} +EXPORT_SYMBOL(rdma_set_ib_paths); + +static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms) +{ + struct cma_work *work; + + work = kzalloc(sizeof *work, GFP_KERNEL); + if (!work) + return -ENOMEM; + + work->id = id_priv; + INIT_WORK(&work->work, cma_work_handler); + work->old_state = CMA_ROUTE_QUERY; + work->new_state = CMA_ROUTE_RESOLVED; + work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; + queue_work(cma_wq, &work->work); + return 0; +} + +static u8 tos_to_sl(u8 tos) +{ + return def_prec2sl & 7; +} + +static int cma_resolve_iboe_route(struct rdma_id_private *id_priv) +{ + struct rdma_route *route = &id_priv->id.route; + struct rdma_addr *addr = &route->addr; + struct cma_work *work; + int ret; + struct sockaddr_in *src_addr = (struct sockaddr_in *)&route->addr.src_addr; + struct sockaddr_in *dst_addr = (struct sockaddr_in *)&route->addr.dst_addr; + struct net_device *ndev = NULL; + u16 vid; + + if (src_addr->sin_family != dst_addr->sin_family) + return -EINVAL; + + work = kzalloc(sizeof *work, GFP_KERNEL); + if (!work) + return -ENOMEM; + + work->id = id_priv; + INIT_WORK(&work->work, cma_work_handler); + + route->path_rec = kzalloc(sizeof *route->path_rec, GFP_KERNEL); + if (!route->path_rec) { + ret = -ENOMEM; + goto err1; + } + + route->num_paths = 1; + + if (addr->dev_addr.bound_dev_if) + ndev = dev_get_by_index(&init_net, addr->dev_addr.bound_dev_if); + if (!ndev) { + ret = -ENODEV; + goto err2; + } + + vid = rdma_vlan_dev_vlan_id(ndev); + + iboe_mac_vlan_to_ll(&route->path_rec->sgid, addr->dev_addr.src_dev_addr, vid); + iboe_mac_vlan_to_ll(&route->path_rec->dgid, addr->dev_addr.dst_dev_addr, vid); + + route->path_rec->hop_limit = 1; + route->path_rec->reversible = 1; + route->path_rec->pkey = cpu_to_be16(0xffff); + route->path_rec->mtu_selector = IB_SA_EQ; + route->path_rec->sl = tos_to_sl(id_priv->tos); + +#ifdef __linux__ + route->path_rec->mtu = iboe_get_mtu(ndev->mtu); +#else + route->path_rec->mtu = iboe_get_mtu(ndev->if_mtu); +#endif + route->path_rec->rate_selector = IB_SA_EQ; + route->path_rec->rate = iboe_get_rate(ndev); + dev_put(ndev); + route->path_rec->packet_life_time_selector = IB_SA_EQ; + route->path_rec->packet_life_time = IBOE_PACKET_LIFETIME; + if (!route->path_rec->mtu) { + ret = -EINVAL; + goto err2; + } + + work->old_state = CMA_ROUTE_QUERY; + work->new_state = CMA_ROUTE_RESOLVED; + work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; + work->event.status = 0; + + queue_work(cma_wq, &work->work); + + return 0; + +err2: + kfree(route->path_rec); + route->path_rec = NULL; +err1: + kfree(work); + return ret; +} + +int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_QUERY)) + return -EINVAL; + + atomic_inc(&id_priv->refcount); + switch (rdma_node_get_transport(id->device->node_type)) { + case RDMA_TRANSPORT_IB: + switch (rdma_port_get_link_layer(id->device, id->port_num)) { + case IB_LINK_LAYER_INFINIBAND: + ret = cma_resolve_ib_route(id_priv, timeout_ms); + break; + case IB_LINK_LAYER_ETHERNET: + ret = cma_resolve_iboe_route(id_priv); + break; + default: + ret = -ENOSYS; + } + break; + case RDMA_TRANSPORT_IWARP: + ret = cma_resolve_iw_route(id_priv, timeout_ms); + break; + default: + ret = -ENOSYS; + break; + } + if (ret) + goto err; + + return 0; +err: + cma_comp_exch(id_priv, CMA_ROUTE_QUERY, CMA_ADDR_RESOLVED); + cma_deref_id(id_priv); + return ret; +} +EXPORT_SYMBOL(rdma_resolve_route); + +static int cma_bind_loopback(struct rdma_id_private *id_priv) +{ + struct cma_device *cma_dev; + struct ib_port_attr port_attr; + union ib_gid gid; + u16 pkey; + int ret; + u8 p; + + mutex_lock(&lock); + if (list_empty(&dev_list)) { + ret = -ENODEV; + goto out; + } + list_for_each_entry(cma_dev, &dev_list, list) + for (p = 1; p <= cma_dev->device->phys_port_cnt; ++p) + if (!ib_query_port(cma_dev->device, p, &port_attr) && + port_attr.state == IB_PORT_ACTIVE) + goto port_found; + + p = 1; + cma_dev = list_entry(dev_list.next, struct cma_device, list); + +port_found: + ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid); + if (ret) + goto out; + + ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey); + if (ret) + goto out; + + id_priv->id.route.addr.dev_addr.dev_type = + (rdma_port_get_link_layer(cma_dev->device, p) == IB_LINK_LAYER_INFINIBAND) ? + ARPHRD_INFINIBAND : ARPHRD_ETHER; + + rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid); + ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey); + id_priv->id.port_num = p; + cma_attach_to_dev(id_priv, cma_dev); +out: + mutex_unlock(&lock); + return ret; +} + +static void addr_handler(int status, struct sockaddr *src_addr, + struct rdma_dev_addr *dev_addr, void *context) +{ + struct rdma_id_private *id_priv = context; + struct rdma_cm_event event; + + memset(&event, 0, sizeof event); + mutex_lock(&id_priv->handler_mutex); + + /* + * Grab mutex to block rdma_destroy_id() from removing the device while + * we're trying to acquire it. + */ + mutex_lock(&lock); + if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED)) { + mutex_unlock(&lock); + goto out; + } + + if (!status && !id_priv->cma_dev) + status = cma_acquire_dev(id_priv); + mutex_unlock(&lock); + + if (status) { + if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ADDR_BOUND)) + goto out; + event.event = RDMA_CM_EVENT_ADDR_ERROR; + event.status = status; + } else { + memcpy(&id_priv->id.route.addr.src_addr, src_addr, + ip_addr_size(src_addr)); + event.event = RDMA_CM_EVENT_ADDR_RESOLVED; + } + + if (id_priv->id.event_handler(&id_priv->id, &event)) { + cma_exch(id_priv, CMA_DESTROYING); + mutex_unlock(&id_priv->handler_mutex); + cma_deref_id(id_priv); + rdma_destroy_id(&id_priv->id); + return; + } +out: + mutex_unlock(&id_priv->handler_mutex); + cma_deref_id(id_priv); +} + +static int cma_resolve_loopback(struct rdma_id_private *id_priv) +{ + struct cma_work *work; + struct sockaddr *src, *dst; + union ib_gid gid; + int ret; + + work = kzalloc(sizeof *work, GFP_KERNEL); + if (!work) + return -ENOMEM; + + if (!id_priv->cma_dev) { + ret = cma_bind_loopback(id_priv); + if (ret) + goto err; + } + + rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); + rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid); + + src = (struct sockaddr *) &id_priv->id.route.addr.src_addr; + if (cma_zero_addr(src)) { + dst = (struct sockaddr *) &id_priv->id.route.addr.dst_addr; + if ((src->sa_family = dst->sa_family) == AF_INET) { + ((struct sockaddr_in *) src)->sin_addr.s_addr = + ((struct sockaddr_in *) dst)->sin_addr.s_addr; + } else { + ipv6_addr_copy(&((struct sockaddr_in6 *) src)->sin6_addr, + &((struct sockaddr_in6 *) dst)->sin6_addr); + } + } + + work->id = id_priv; + INIT_WORK(&work->work, cma_work_handler); + work->old_state = CMA_ADDR_QUERY; + work->new_state = CMA_ADDR_RESOLVED; + work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; + queue_work(cma_wq, &work->work); + return 0; +err: + kfree(work); + return ret; +} + +static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, + struct sockaddr *dst_addr) +{ + if (!src_addr || !src_addr->sa_family) { + src_addr = (struct sockaddr *) &id->route.addr.src_addr; + if ((src_addr->sa_family = dst_addr->sa_family) == AF_INET6) { + ((struct sockaddr_in6 *) src_addr)->sin6_scope_id = + ((struct sockaddr_in6 *) dst_addr)->sin6_scope_id; + } + } + return rdma_bind_addr(id, src_addr); +} + +int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, + struct sockaddr *dst_addr, int timeout_ms) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (id_priv->state == CMA_IDLE) { + ret = cma_bind_addr(id, src_addr, dst_addr); + if (ret) + return ret; + } + + if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_ADDR_QUERY)) + return -EINVAL; + + atomic_inc(&id_priv->refcount); + memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr)); + if (cma_any_addr(dst_addr)) + ret = cma_resolve_loopback(id_priv); + else + ret = rdma_resolve_ip(&addr_client, (struct sockaddr *) &id->route.addr.src_addr, + dst_addr, &id->route.addr.dev_addr, + timeout_ms, addr_handler, id_priv); + if (ret) + goto err; + + return 0; +err: + cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND); + cma_deref_id(id_priv); + return ret; +} +EXPORT_SYMBOL(rdma_resolve_addr); + +static void cma_bind_port(struct rdma_bind_list *bind_list, + struct rdma_id_private *id_priv) +{ + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; + sin->sin_port = htons(bind_list->port); + id_priv->bind_list = bind_list; + hlist_add_head(&id_priv->node, &bind_list->owners); +} + +static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, + unsigned short snum) +{ + struct rdma_bind_list *bind_list; + int port, ret; + + bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); + if (!bind_list) + return -ENOMEM; + + do { + ret = idr_get_new_above(ps, bind_list, snum, &port); + } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); + + if (ret) + goto err1; + + if (port != snum) { + ret = -EADDRNOTAVAIL; + goto err2; + } + + bind_list->ps = ps; + bind_list->port = (unsigned short) port; + cma_bind_port(bind_list, id_priv); + return 0; +err2: + idr_remove(ps, port); +err1: + kfree(bind_list); + return ret; +} + +static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) +{ + struct rdma_bind_list *bind_list; + int port, ret, low, high; + + bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); + if (!bind_list) + return -ENOMEM; + +retry: + /* FIXME: add proper port randomization per like inet_csk_get_port */ + do { + ret = idr_get_new_above(ps, bind_list, next_port, &port); + } while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL)); + + if (ret) + goto err1; + + inet_get_local_port_range(&low, &high); + if (port > high) { + if (next_port != low) { + idr_remove(ps, port); + next_port = low; + goto retry; + } + ret = -EADDRNOTAVAIL; + goto err2; + } + + if (port == high) + next_port = low; + else + next_port = port + 1; + + bind_list->ps = ps; + bind_list->port = (unsigned short) port; + cma_bind_port(bind_list, id_priv); + return 0; +err2: + idr_remove(ps, port); +err1: + kfree(bind_list); + return ret; +} + +static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) +{ + struct rdma_id_private *cur_id; + struct sockaddr_in *sin, *cur_sin; + struct rdma_bind_list *bind_list; + struct hlist_node *node; + unsigned short snum; + + sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; + snum = ntohs(sin->sin_port); +#ifdef __linux__ + if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) + return -EACCES; +#endif + + bind_list = idr_find(ps, snum); + if (!bind_list) + return cma_alloc_port(ps, id_priv, snum); + + /* + * We don't support binding to any address if anyone is bound to + * a specific address on the same port. + */ + if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)) + return -EADDRNOTAVAIL; + + hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { + if (cma_any_addr((struct sockaddr *) &cur_id->id.route.addr.src_addr)) + return -EADDRNOTAVAIL; + + cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr; + if (sin->sin_addr.s_addr == cur_sin->sin_addr.s_addr) + return -EADDRINUSE; + } + + cma_bind_port(bind_list, id_priv); + return 0; +} + +static int cma_get_tcp_port(struct rdma_id_private *id_priv) +{ + int ret; + int size; + struct socket *sock; + + ret = sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); + if (ret) + return ret; +#ifdef __linux__ + ret = sock->ops->bind(sock, + (struct sockaddr *) &id_priv->id.route.addr.src_addr, + ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr)); +#else + ret = -sobind(sock, + (struct sockaddr *)&id_priv->id.route.addr.src_addr, + curthread); +#endif + if (ret) { + sock_release(sock); + return ret; + } + size = ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr); + ret = sock_getname(sock, + (struct sockaddr *) &id_priv->id.route.addr.src_addr, + &size, 0); + if (ret) { + sock_release(sock); + return ret; + } + id_priv->sock = sock; + return 0; +} + +static int cma_get_port(struct rdma_id_private *id_priv) +{ + struct idr *ps; + int ret; + + switch (id_priv->id.ps) { + case RDMA_PS_SDP: + ps = &sdp_ps; + break; + case RDMA_PS_TCP: + ps = &tcp_ps; + if (unify_tcp_port_space) { + ret = cma_get_tcp_port(id_priv); + if (ret) + goto out; + } + break; + case RDMA_PS_UDP: + ps = &udp_ps; + break; + case RDMA_PS_IPOIB: + ps = &ipoib_ps; + break; + default: + return -EPROTONOSUPPORT; + } + + mutex_lock(&lock); + if (cma_any_port((struct sockaddr *) &id_priv->id.route.addr.src_addr)) + ret = cma_alloc_any_port(ps, id_priv); + else + ret = cma_use_port(ps, id_priv); + mutex_unlock(&lock); +out: + return ret; +} + +static int cma_check_linklocal(struct rdma_dev_addr *dev_addr, + struct sockaddr *addr) +{ +#if defined(INET6) + struct sockaddr_in6 *sin6; + + if (addr->sa_family != AF_INET6) + return 0; + + sin6 = (struct sockaddr_in6 *) addr; +#ifdef __linux__ + if ((ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) && +#else + if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) && +#endif + !sin6->sin6_scope_id) + return -EINVAL; + + dev_addr->bound_dev_if = sin6->sin6_scope_id; +#endif + return 0; +} + +int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) +{ + struct rdma_id_private *id_priv; + int ret; + + if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6) + return -EAFNOSUPPORT; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND)) + return -EINVAL; + + ret = cma_check_linklocal(&id->route.addr.dev_addr, addr); + if (ret) + goto err1; + + if (!cma_any_addr(addr)) { + ret = rdma_translate_ip(addr, &id->route.addr.dev_addr); + if (ret) + goto err1; + + mutex_lock(&lock); + ret = cma_acquire_dev(id_priv); + mutex_unlock(&lock); + if (ret) + goto err1; + } + + memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr)); + ret = cma_get_port(id_priv); + if (ret) + goto err2; + + return 0; +err2: + if (id_priv->cma_dev) { + mutex_lock(&lock); + cma_detach_from_dev(id_priv); + mutex_unlock(&lock); + } +err1: + cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE); + return ret; +} +EXPORT_SYMBOL(rdma_bind_addr); + +static int cma_format_hdr(void *hdr, enum rdma_port_space ps, + struct rdma_route *route) +{ + struct cma_hdr *cma_hdr; + struct sdp_hh *sdp_hdr; + + if (route->addr.src_addr.ss_family == AF_INET) { + struct sockaddr_in *src4, *dst4; + + src4 = (struct sockaddr_in *) &route->addr.src_addr; + dst4 = (struct sockaddr_in *) &route->addr.dst_addr; + + switch (ps) { + case RDMA_PS_SDP: + sdp_hdr = hdr; + if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) + return -EINVAL; + sdp_set_ip_ver(sdp_hdr, 4); + sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; + sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; + sdp_hdr->port = src4->sin_port; + break; + default: + cma_hdr = hdr; + cma_hdr->cma_version = CMA_VERSION; + cma_set_ip_ver(cma_hdr, 4); + cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; + cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; + cma_hdr->port = src4->sin_port; + break; + } + } else { + struct sockaddr_in6 *src6, *dst6; + + src6 = (struct sockaddr_in6 *) &route->addr.src_addr; + dst6 = (struct sockaddr_in6 *) &route->addr.dst_addr; + + switch (ps) { + case RDMA_PS_SDP: + sdp_hdr = hdr; + if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) + return -EINVAL; + sdp_set_ip_ver(sdp_hdr, 6); + sdp_hdr->src_addr.ip6 = src6->sin6_addr; + sdp_hdr->dst_addr.ip6 = dst6->sin6_addr; + sdp_hdr->port = src6->sin6_port; + break; + default: + cma_hdr = hdr; + cma_hdr->cma_version = CMA_VERSION; + cma_set_ip_ver(cma_hdr, 6); + cma_hdr->src_addr.ip6 = src6->sin6_addr; + cma_hdr->dst_addr.ip6 = dst6->sin6_addr; + cma_hdr->port = src6->sin6_port; + break; + } + } + return 0; +} + +static int cma_sidr_rep_handler(struct ib_cm_id *cm_id, + struct ib_cm_event *ib_event) +{ + struct rdma_id_private *id_priv = cm_id->context; + struct rdma_cm_event event; + struct ib_cm_sidr_rep_event_param *rep = &ib_event->param.sidr_rep_rcvd; + int ret = 0; + + if (cma_disable_callback(id_priv, CMA_CONNECT)) + return 0; + + memset(&event, 0, sizeof event); + switch (ib_event->event) { + case IB_CM_SIDR_REQ_ERROR: + event.event = RDMA_CM_EVENT_UNREACHABLE; + event.status = -ETIMEDOUT; + break; + case IB_CM_SIDR_REP_RECEIVED: + event.param.ud.private_data = ib_event->private_data; + event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE; + if (rep->status != IB_SIDR_SUCCESS) { + event.event = RDMA_CM_EVENT_UNREACHABLE; + event.status = ib_event->param.sidr_rep_rcvd.status; + break; + } + ret = cma_set_qkey(id_priv); + if (ret) { + event.event = RDMA_CM_EVENT_ADDR_ERROR; + event.status = -EINVAL; + break; + } + if (id_priv->qkey != rep->qkey) { + event.event = RDMA_CM_EVENT_UNREACHABLE; + event.status = -EINVAL; + break; + } + ib_init_ah_from_path(id_priv->id.device, id_priv->id.port_num, + id_priv->id.route.path_rec, + &event.param.ud.ah_attr); + event.param.ud.qp_num = rep->qpn; + event.param.ud.qkey = rep->qkey; + event.event = RDMA_CM_EVENT_ESTABLISHED; + event.status = 0; + break; + default: + printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", + ib_event->event); + goto out; + } + + ret = id_priv->id.event_handler(&id_priv->id, &event); + if (ret) { + /* Destroy the CM ID by returning a non-zero value. */ + id_priv->cm_id.ib = NULL; + cma_exch(id_priv, CMA_DESTROYING); + mutex_unlock(&id_priv->handler_mutex); + rdma_destroy_id(&id_priv->id); + return ret; + } +out: + mutex_unlock(&id_priv->handler_mutex); + return ret; +} + +static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, + struct rdma_conn_param *conn_param) +{ + struct ib_cm_sidr_req_param req; + struct rdma_route *route; + int ret; + + req.private_data_len = sizeof(struct cma_hdr) + + conn_param->private_data_len; + req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC); + if (!req.private_data) + return -ENOMEM; + + if (conn_param->private_data && conn_param->private_data_len) + memcpy((void *) req.private_data + sizeof(struct cma_hdr), + conn_param->private_data, conn_param->private_data_len); + + route = &id_priv->id.route; + ret = cma_format_hdr((void *) req.private_data, id_priv->id.ps, route); + if (ret) + goto out; + + id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, + cma_sidr_rep_handler, id_priv); + if (IS_ERR(id_priv->cm_id.ib)) { + ret = PTR_ERR(id_priv->cm_id.ib); + goto out; + } + + req.path = route->path_rec; + req.service_id = cma_get_service_id(id_priv->id.ps, + (struct sockaddr *) &route->addr.dst_addr); + req.timeout_ms = 1 << (cma_response_timeout - 8); + req.max_cm_retries = CMA_MAX_CM_RETRIES; + + ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req); + if (ret) { + ib_destroy_cm_id(id_priv->cm_id.ib); + id_priv->cm_id.ib = NULL; + } +out: + kfree(req.private_data); + return ret; +} + +static int cma_connect_ib(struct rdma_id_private *id_priv, + struct rdma_conn_param *conn_param) +{ + struct ib_cm_req_param req; + struct rdma_route *route; + void *private_data; + int offset, ret; + + memset(&req, 0, sizeof req); + offset = cma_user_data_offset(id_priv->id.ps); + req.private_data_len = offset + conn_param->private_data_len; + private_data = kzalloc(req.private_data_len, GFP_ATOMIC); + if (!private_data) + return -ENOMEM; + + if (conn_param->private_data && conn_param->private_data_len) + memcpy(private_data + offset, conn_param->private_data, + conn_param->private_data_len); + + id_priv->cm_id.ib = ib_create_cm_id(id_priv->id.device, cma_ib_handler, + id_priv); + if (IS_ERR(id_priv->cm_id.ib)) { + ret = PTR_ERR(id_priv->cm_id.ib); + goto out; + } + + route = &id_priv->id.route; + ret = cma_format_hdr(private_data, id_priv->id.ps, route); + if (ret) + goto out; + req.private_data = private_data; + + req.primary_path = &route->path_rec[0]; + if (route->num_paths == 2) + req.alternate_path = &route->path_rec[1]; + + req.service_id = cma_get_service_id(id_priv->id.ps, + (struct sockaddr *) &route->addr.dst_addr); + req.qp_num = id_priv->qp_num; + req.qp_type = IB_QPT_RC; + req.starting_psn = id_priv->seq_num; + req.responder_resources = conn_param->responder_resources; + req.initiator_depth = conn_param->initiator_depth; + req.flow_control = conn_param->flow_control; + req.retry_count = conn_param->retry_count; + req.rnr_retry_count = conn_param->rnr_retry_count; + req.remote_cm_response_timeout = cma_response_timeout; + req.local_cm_response_timeout = cma_response_timeout; + req.max_cm_retries = CMA_MAX_CM_RETRIES; + req.srq = id_priv->srq ? 1 : 0; + + ret = ib_send_cm_req(id_priv->cm_id.ib, &req); +out: + if (ret && !IS_ERR(id_priv->cm_id.ib)) { + ib_destroy_cm_id(id_priv->cm_id.ib); + id_priv->cm_id.ib = NULL; + } + + kfree(private_data); + return ret; +} + +static int cma_connect_iw(struct rdma_id_private *id_priv, + struct rdma_conn_param *conn_param) +{ + struct iw_cm_id *cm_id; + struct sockaddr_in* sin; + int ret; + struct iw_cm_conn_param iw_param; + + cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv); + if (IS_ERR(cm_id)) { + ret = PTR_ERR(cm_id); + goto out; + } + + id_priv->cm_id.iw = cm_id; + + sin = (struct sockaddr_in*) &id_priv->id.route.addr.src_addr; + cm_id->local_addr = *sin; + + sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr; + cm_id->remote_addr = *sin; + + ret = cma_modify_qp_rtr(id_priv, conn_param); + if (ret) + goto out; + + iw_param.ord = conn_param->initiator_depth; + iw_param.ird = conn_param->responder_resources; + iw_param.private_data = conn_param->private_data; + iw_param.private_data_len = conn_param->private_data_len; + if (id_priv->id.qp) + iw_param.qpn = id_priv->qp_num; + else + iw_param.qpn = conn_param->qp_num; + ret = iw_cm_connect(cm_id, &iw_param); +out: + if (ret && !IS_ERR(cm_id)) { + iw_destroy_cm_id(cm_id); + id_priv->cm_id.iw = NULL; + } + return ret; +} + +int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_CONNECT)) + return -EINVAL; + + if (!id->qp) { + id_priv->qp_num = conn_param->qp_num; + id_priv->srq = conn_param->srq; + } + + switch (rdma_node_get_transport(id->device->node_type)) { + case RDMA_TRANSPORT_IB: + if (cma_is_ud_ps(id->ps)) + ret = cma_resolve_ib_udp(id_priv, conn_param); + else + ret = cma_connect_ib(id_priv, conn_param); + break; + case RDMA_TRANSPORT_IWARP: + ret = cma_connect_iw(id_priv, conn_param); + break; + default: + ret = -ENOSYS; + break; + } + if (ret) + goto err; + + return 0; +err: + cma_comp_exch(id_priv, CMA_CONNECT, CMA_ROUTE_RESOLVED); + return ret; +} +EXPORT_SYMBOL(rdma_connect); + +static int cma_accept_ib(struct rdma_id_private *id_priv, + struct rdma_conn_param *conn_param) +{ + struct ib_cm_rep_param rep; + int ret; + + ret = cma_modify_qp_rtr(id_priv, conn_param); + if (ret) + goto out; + + ret = cma_modify_qp_rts(id_priv, conn_param); + if (ret) + goto out; + + memset(&rep, 0, sizeof rep); + rep.qp_num = id_priv->qp_num; + rep.starting_psn = id_priv->seq_num; + rep.private_data = conn_param->private_data; + rep.private_data_len = conn_param->private_data_len; + rep.responder_resources = conn_param->responder_resources; + rep.initiator_depth = conn_param->initiator_depth; + rep.failover_accepted = 0; + rep.flow_control = conn_param->flow_control; + rep.rnr_retry_count = conn_param->rnr_retry_count; + rep.srq = id_priv->srq ? 1 : 0; + + ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep); +out: + return ret; +} + +static int cma_accept_iw(struct rdma_id_private *id_priv, + struct rdma_conn_param *conn_param) +{ + struct iw_cm_conn_param iw_param; + int ret; + + ret = cma_modify_qp_rtr(id_priv, conn_param); + if (ret) + return ret; + + iw_param.ord = conn_param->initiator_depth; + iw_param.ird = conn_param->responder_resources; + iw_param.private_data = conn_param->private_data; + iw_param.private_data_len = conn_param->private_data_len; + if (id_priv->id.qp) { + iw_param.qpn = id_priv->qp_num; + } else + iw_param.qpn = conn_param->qp_num; + + return iw_cm_accept(id_priv->cm_id.iw, &iw_param); +} + +static int cma_send_sidr_rep(struct rdma_id_private *id_priv, + enum ib_cm_sidr_status status, + const void *private_data, int private_data_len) +{ + struct ib_cm_sidr_rep_param rep; + int ret; + + memset(&rep, 0, sizeof rep); + rep.status = status; + if (status == IB_SIDR_SUCCESS) { + ret = cma_set_qkey(id_priv); + if (ret) + return ret; + rep.qp_num = id_priv->qp_num; + rep.qkey = id_priv->qkey; + } + rep.private_data = private_data; + rep.private_data_len = private_data_len; + + return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep); +} + +int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp(id_priv, CMA_CONNECT)) + return -EINVAL; + + if (!id->qp && conn_param) { + id_priv->qp_num = conn_param->qp_num; + id_priv->srq = conn_param->srq; + } + + switch (rdma_node_get_transport(id->device->node_type)) { + case RDMA_TRANSPORT_IB: + if (cma_is_ud_ps(id->ps)) + ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, + conn_param->private_data, + conn_param->private_data_len); + else if (conn_param) + ret = cma_accept_ib(id_priv, conn_param); + else + ret = cma_rep_recv(id_priv); + break; + case RDMA_TRANSPORT_IWARP: + ret = cma_accept_iw(id_priv, conn_param); + break; + default: + ret = -ENOSYS; + break; + } + + if (ret) + goto reject; + + return 0; +reject: + cma_modify_qp_err(id_priv); + rdma_reject(id, NULL, 0); + return ret; +} +EXPORT_SYMBOL(rdma_accept); + +int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_has_cm_dev(id_priv)) + return -EINVAL; + + switch (id->device->node_type) { + case RDMA_NODE_IB_CA: + ret = ib_cm_notify(id_priv->cm_id.ib, event); + break; + default: + ret = 0; + break; + } + return ret; +} +EXPORT_SYMBOL(rdma_notify); + +int rdma_reject(struct rdma_cm_id *id, const void *private_data, + u8 private_data_len) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_has_cm_dev(id_priv)) + return -EINVAL; + + switch (rdma_node_get_transport(id->device->node_type)) { + case RDMA_TRANSPORT_IB: + if (cma_is_ud_ps(id->ps)) + ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, + private_data, private_data_len); + else + ret = ib_send_cm_rej(id_priv->cm_id.ib, + IB_CM_REJ_CONSUMER_DEFINED, NULL, + 0, private_data, private_data_len); + break; + case RDMA_TRANSPORT_IWARP: + ret = iw_cm_reject(id_priv->cm_id.iw, + private_data, private_data_len); + break; + default: + ret = -ENOSYS; + break; + } + return ret; +} +EXPORT_SYMBOL(rdma_reject); + +int rdma_disconnect(struct rdma_cm_id *id) +{ + struct rdma_id_private *id_priv; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_has_cm_dev(id_priv)) + return -EINVAL; + + switch (rdma_node_get_transport(id->device->node_type)) { + case RDMA_TRANSPORT_IB: + ret = cma_modify_qp_err(id_priv); + if (ret) + goto out; + /* Initiate or respond to a disconnect. */ + if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0)) + ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0); + break; + case RDMA_TRANSPORT_IWARP: + ret = iw_cm_disconnect(id_priv->cm_id.iw, 0); + break; + default: + ret = -EINVAL; + break; + } +out: + return ret; +} +EXPORT_SYMBOL(rdma_disconnect); + +static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) +{ + struct rdma_id_private *id_priv; + struct cma_multicast *mc = multicast->context; + struct rdma_cm_event event; + int ret; + + id_priv = mc->id_priv; + if (cma_disable_callback(id_priv, CMA_ADDR_BOUND) && + cma_disable_callback(id_priv, CMA_ADDR_RESOLVED)) + return 0; + + mutex_lock(&id_priv->qp_mutex); + if (!status && id_priv->id.qp) + status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid, + multicast->rec.mlid); + mutex_unlock(&id_priv->qp_mutex); + + memset(&event, 0, sizeof event); + event.status = status; + event.param.ud.private_data = mc->context; + if (!status) { + event.event = RDMA_CM_EVENT_MULTICAST_JOIN; + ib_init_ah_from_mcmember(id_priv->id.device, + id_priv->id.port_num, &multicast->rec, + &event.param.ud.ah_attr); + event.param.ud.qp_num = 0xFFFFFF; + event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey); + } else + event.event = RDMA_CM_EVENT_MULTICAST_ERROR; + + ret = id_priv->id.event_handler(&id_priv->id, &event); + if (ret) { + cma_exch(id_priv, CMA_DESTROYING); + mutex_unlock(&id_priv->handler_mutex); + rdma_destroy_id(&id_priv->id); + return 0; + } + + mutex_unlock(&id_priv->handler_mutex); + return 0; +} + +static void cma_set_mgid(struct rdma_id_private *id_priv, + struct sockaddr *addr, union ib_gid *mgid) +{ + unsigned char mc_map[MAX_ADDR_LEN]; + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; + struct sockaddr_in *sin = (struct sockaddr_in *) addr; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; + + if (cma_any_addr(addr)) { + memset(mgid, 0, sizeof *mgid); + } else if ((addr->sa_family == AF_INET6) && + ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFFF0FFFF) == + 0xFF10A01B)) { + /* IPv6 address is an SA assigned MGID. */ + memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); + } else if ((addr->sa_family == AF_INET6)) { + ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map); + if (id_priv->id.ps == RDMA_PS_UDP) + mc_map[7] = 0x01; /* Use RDMA CM signature */ + *mgid = *(union ib_gid *) (mc_map + 4); + } else { + ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map); + if (id_priv->id.ps == RDMA_PS_UDP) + mc_map[7] = 0x01; /* Use RDMA CM signature */ + *mgid = *(union ib_gid *) (mc_map + 4); + } +} + +static int cma_join_ib_multicast(struct rdma_id_private *id_priv, + struct cma_multicast *mc) +{ + struct ib_sa_mcmember_rec rec; + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; + ib_sa_comp_mask comp_mask; + int ret; + + ib_addr_get_mgid(dev_addr, &rec.mgid); + ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num, + &rec.mgid, &rec); + if (ret) + return ret; + + cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid); + if (id_priv->id.ps == RDMA_PS_UDP) + rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); + rdma_addr_get_sgid(dev_addr, &rec.port_gid); + rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); + rec.join_state = 1; + + comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | + IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE | + IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL | + IB_SA_MCMEMBER_REC_FLOW_LABEL | + IB_SA_MCMEMBER_REC_TRAFFIC_CLASS; + + if (id_priv->id.ps == RDMA_PS_IPOIB) + comp_mask |= IB_SA_MCMEMBER_REC_RATE | + IB_SA_MCMEMBER_REC_RATE_SELECTOR; + + mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device, + id_priv->id.port_num, &rec, + comp_mask, GFP_KERNEL, + cma_ib_mc_handler, mc); + if (IS_ERR(mc->multicast.ib)) + return PTR_ERR(mc->multicast.ib); + + return 0; +} + + +static void iboe_mcast_work_handler(struct work_struct *work) +{ + struct iboe_mcast_work *mw = container_of(work, struct iboe_mcast_work, work); + struct cma_multicast *mc = mw->mc; + struct ib_sa_multicast *m = mc->multicast.ib; + + mc->multicast.ib->context = mc; + cma_ib_mc_handler(0, m); + kref_put(&mc->mcref, release_mc); + kfree(mw); +} + +static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid) +{ + struct sockaddr_in *sin = (struct sockaddr_in *)addr; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; + + if (cma_any_addr(addr)) { + memset(mgid, 0, sizeof *mgid); + } else if (addr->sa_family == AF_INET6) + memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); + else { + mgid->raw[0] = 0xff; + mgid->raw[1] = 0x0e; + mgid->raw[2] = 0; + mgid->raw[3] = 0; + mgid->raw[4] = 0; + mgid->raw[5] = 0; + mgid->raw[6] = 0; + mgid->raw[7] = 0; + mgid->raw[8] = 0; + mgid->raw[9] = 0; + mgid->raw[10] = 0xff; + mgid->raw[11] = 0xff; + *(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr; + } +} + +static int cma_iboe_join_multicast(struct rdma_id_private *id_priv, + struct cma_multicast *mc) +{ + struct iboe_mcast_work *work; + struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; + int err; + struct sockaddr *addr = (struct sockaddr *)&mc->addr; + struct net_device *ndev = NULL; + + if (cma_zero_addr((struct sockaddr *)&mc->addr)) + return -EINVAL; + + work = kzalloc(sizeof *work, GFP_KERNEL); + if (!work) + return -ENOMEM; + + mc->multicast.ib = kzalloc(sizeof(struct ib_sa_multicast), GFP_KERNEL); + if (!mc->multicast.ib) { + err = -ENOMEM; + goto out1; + } + + cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid); + + mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff); + if (id_priv->id.ps == RDMA_PS_UDP) + mc->multicast.ib->rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); + + if (dev_addr->bound_dev_if) + ndev = dev_get_by_index(&init_net, dev_addr->bound_dev_if); + if (!ndev) { + err = -ENODEV; + goto out2; + } + + mc->multicast.ib->rec.rate = iboe_get_rate(ndev); + mc->multicast.ib->rec.hop_limit = 1; +#ifdef __linux__ + mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu); +#else + mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->if_mtu); +#endif + dev_put(ndev); + if (!mc->multicast.ib->rec.mtu) { + err = -EINVAL; + goto out2; + } + iboe_addr_get_sgid(dev_addr, &mc->multicast.ib->rec.port_gid); + work->id = id_priv; + work->mc = mc; + INIT_WORK(&work->work, iboe_mcast_work_handler); + kref_get(&mc->mcref); + queue_work(cma_wq, &work->work); + + return 0; + +out2: + kfree(mc->multicast.ib); +out1: + kfree(work); + return err; +} + +int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, + void *context) +{ + struct rdma_id_private *id_priv; + struct cma_multicast *mc; + int ret; + + id_priv = container_of(id, struct rdma_id_private, id); + if (!cma_comp(id_priv, CMA_ADDR_BOUND) && + !cma_comp(id_priv, CMA_ADDR_RESOLVED)) + return -EINVAL; + + mc = kmalloc(sizeof *mc, GFP_KERNEL); + if (!mc) + return -ENOMEM; + + memcpy(&mc->addr, addr, ip_addr_size(addr)); + mc->context = context; + mc->id_priv = id_priv; + + spin_lock(&id_priv->lock); + list_add(&mc->list, &id_priv->mc_list); + spin_unlock(&id_priv->lock); + + switch (rdma_node_get_transport(id->device->node_type)) { + case RDMA_TRANSPORT_IB: + switch (rdma_port_get_link_layer(id->device, id->port_num)) { + case IB_LINK_LAYER_INFINIBAND: + ret = cma_join_ib_multicast(id_priv, mc); + break; + case IB_LINK_LAYER_ETHERNET: + kref_init(&mc->mcref); + ret = cma_iboe_join_multicast(id_priv, mc); + break; + default: + ret = -EINVAL; + } + break; + default: + ret = -ENOSYS; + break; + } + + if (ret) { + spin_lock_irq(&id_priv->lock); + list_del(&mc->list); + spin_unlock_irq(&id_priv->lock); + kfree(mc); + } + + return ret; +} +EXPORT_SYMBOL(rdma_join_multicast); + +void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) +{ + struct rdma_id_private *id_priv; + struct cma_multicast *mc; + + id_priv = container_of(id, struct rdma_id_private, id); + spin_lock_irq(&id_priv->lock); + list_for_each_entry(mc, &id_priv->mc_list, list) { + if (!memcmp(&mc->addr, addr, ip_addr_size(addr))) { + list_del(&mc->list); + spin_unlock_irq(&id_priv->lock); + + if (id->qp) + ib_detach_mcast(id->qp, + &mc->multicast.ib->rec.mgid, + mc->multicast.ib->rec.mlid); + if (rdma_node_get_transport(id_priv->cma_dev->device->node_type) == RDMA_TRANSPORT_IB) { + switch (rdma_port_get_link_layer(id->device, id->port_num)) { + case IB_LINK_LAYER_INFINIBAND: + ib_sa_free_multicast(mc->multicast.ib); + kfree(mc); + break; + case IB_LINK_LAYER_ETHERNET: + kref_put(&mc->mcref, release_mc); + break; + default: + break; + } + } + return; + } + } + spin_unlock_irq(&id_priv->lock); +} +EXPORT_SYMBOL(rdma_leave_multicast); + +static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id_priv) +{ + struct rdma_dev_addr *dev_addr; + struct cma_ndev_work *work; + + dev_addr = &id_priv->id.route.addr.dev_addr; + +#ifdef __linux__ + if ((dev_addr->bound_dev_if == ndev->ifindex) && + memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) { + printk(KERN_INFO "RDMA CM addr change for ndev %s used by id %p\n", + ndev->name, &id_priv->id); +#else + if ((dev_addr->bound_dev_if == ndev->if_index) && + memcmp(dev_addr->src_dev_addr, IF_LLADDR(ndev), ndev->if_addrlen)) { + printk(KERN_INFO "RDMA CM addr change for ndev %s used by id %p\n", + ndev->if_xname, &id_priv->id); +#endif + work = kzalloc(sizeof *work, GFP_KERNEL); + if (!work) + return -ENOMEM; + + INIT_WORK(&work->work, cma_ndev_work_handler); + work->id = id_priv; + work->event.event = RDMA_CM_EVENT_ADDR_CHANGE; + atomic_inc(&id_priv->refcount); + queue_work(cma_wq, &work->work); + } + + return 0; +} + +static int cma_netdev_callback(struct notifier_block *self, unsigned long event, + void *ctx) +{ + struct net_device *ndev = (struct net_device *)ctx; + struct cma_device *cma_dev; + struct rdma_id_private *id_priv; + int ret = NOTIFY_DONE; + +#ifdef __linux__ + if (dev_net(ndev) != &init_net) + return NOTIFY_DONE; + + if (event != NETDEV_BONDING_FAILOVER) + return NOTIFY_DONE; + + if (!(ndev->flags & IFF_MASTER) || !(ndev->priv_flags & IFF_BONDING)) + return NOTIFY_DONE; +#else + if (event != NETDEV_DOWN && event != NETDEV_UNREGISTER) + return NOTIFY_DONE; +#endif + + mutex_lock(&lock); + list_for_each_entry(cma_dev, &dev_list, list) + list_for_each_entry(id_priv, &cma_dev->id_list, list) { + ret = cma_netdev_change(ndev, id_priv); + if (ret) + goto out; + } + +out: + mutex_unlock(&lock); + return ret; +} + +static struct notifier_block cma_nb = { + .notifier_call = cma_netdev_callback +}; + +static void cma_add_one(struct ib_device *device) +{ + struct cma_device *cma_dev; + struct rdma_id_private *id_priv; + + cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL); + if (!cma_dev) + return; + + cma_dev->device = device; + + init_completion(&cma_dev->comp); + atomic_set(&cma_dev->refcount, 1); + INIT_LIST_HEAD(&cma_dev->id_list); + ib_set_client_data(device, &cma_client, cma_dev); + + mutex_lock(&lock); + list_add_tail(&cma_dev->list, &dev_list); + list_for_each_entry(id_priv, &listen_any_list, list) + cma_listen_on_dev(id_priv, cma_dev); + mutex_unlock(&lock); +} + +static int cma_remove_id_dev(struct rdma_id_private *id_priv) +{ + struct rdma_cm_event event; + enum cma_state state; + int ret = 0; + + /* Record that we want to remove the device */ + state = cma_exch(id_priv, CMA_DEVICE_REMOVAL); + if (state == CMA_DESTROYING) + return 0; + + cma_cancel_operation(id_priv, state); + mutex_lock(&id_priv->handler_mutex); + + /* Check for destruction from another callback. */ + if (!cma_comp(id_priv, CMA_DEVICE_REMOVAL)) + goto out; + + memset(&event, 0, sizeof event); + event.event = RDMA_CM_EVENT_DEVICE_REMOVAL; + ret = id_priv->id.event_handler(&id_priv->id, &event); +out: + mutex_unlock(&id_priv->handler_mutex); + return ret; +} + +static void cma_process_remove(struct cma_device *cma_dev) +{ + struct rdma_id_private *id_priv; + int ret; + + mutex_lock(&lock); + while (!list_empty(&cma_dev->id_list)) { + id_priv = list_entry(cma_dev->id_list.next, + struct rdma_id_private, list); + + list_del(&id_priv->listen_list); + list_del_init(&id_priv->list); + atomic_inc(&id_priv->refcount); + mutex_unlock(&lock); + + ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv); + cma_deref_id(id_priv); + if (ret) + rdma_destroy_id(&id_priv->id); + + mutex_lock(&lock); + } + mutex_unlock(&lock); + + cma_deref_dev(cma_dev); + wait_for_completion(&cma_dev->comp); +} + +static void cma_remove_one(struct ib_device *device) +{ + struct cma_device *cma_dev; + + cma_dev = ib_get_client_data(device, &cma_client); + if (!cma_dev) + return; + + mutex_lock(&lock); + list_del(&cma_dev->list); + mutex_unlock(&lock); + + cma_process_remove(cma_dev); + kfree(cma_dev); +} + +static int cma_init(void) +{ + int ret, low, high, remaining; + + get_random_bytes(&next_port, sizeof next_port); + inet_get_local_port_range(&low, &high); + remaining = (high - low) + 1; + next_port = ((unsigned int) next_port % remaining) + low; + + cma_wq = create_singlethread_workqueue("rdma_cm"); + if (!cma_wq) + return -ENOMEM; + + ib_sa_register_client(&sa_client); + rdma_addr_register_client(&addr_client); + register_netdevice_notifier(&cma_nb); + + ret = ib_register_client(&cma_client); + if (ret) + goto err; + return 0; + +err: + unregister_netdevice_notifier(&cma_nb); + rdma_addr_unregister_client(&addr_client); + ib_sa_unregister_client(&sa_client); + destroy_workqueue(cma_wq); + return ret; +} + +static void cma_cleanup(void) +{ + ib_unregister_client(&cma_client); + unregister_netdevice_notifier(&cma_nb); + rdma_addr_unregister_client(&addr_client); + ib_sa_unregister_client(&sa_client); + destroy_workqueue(cma_wq); + idr_destroy(&sdp_ps); + idr_destroy(&tcp_ps); + idr_destroy(&udp_ps); + idr_destroy(&ipoib_ps); +} + +module_init(cma_init); +module_exit(cma_cleanup); diff --git a/sys/ofed/drivers/infiniband/core/core_priv.h b/sys/ofed/drivers/infiniband/core/core_priv.h new file mode 100644 index 000000000000..05ac36e6acdb --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/core_priv.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _CORE_PRIV_H +#define _CORE_PRIV_H + +#include +#include + +#include + +int ib_device_register_sysfs(struct ib_device *device); +void ib_device_unregister_sysfs(struct ib_device *device); + +int ib_sysfs_setup(void); +void ib_sysfs_cleanup(void); + +int ib_cache_setup(void); +void ib_cache_cleanup(void); + +#endif /* _CORE_PRIV_H */ diff --git a/sys/ofed/drivers/infiniband/core/device.c b/sys/ofed/drivers/infiniband/core/device.c new file mode 100644 index 000000000000..9d34bb6bce65 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/device.c @@ -0,0 +1,754 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core_priv.h" + +MODULE_AUTHOR("Roland Dreier"); +MODULE_DESCRIPTION("core kernel InfiniBand API"); +MODULE_LICENSE("Dual BSD/GPL"); + +#ifdef __ia64__ +/* workaround for a bug in hp chipset that would cause kernel + panic when dma resources are exhaused */ +int dma_map_sg_hp_wa = 0; +#endif + +struct ib_client_data { + struct list_head list; + struct ib_client *client; + void * data; +}; + +static LIST_HEAD(device_list); +static LIST_HEAD(client_list); + +/* + * device_mutex protects access to both device_list and client_list. + * There's no real point to using multiple locks or something fancier + * like an rwsem: we always access both lists, and we're always + * modifying one list or the other list. In any case this is not a + * hot path so there's no point in trying to optimize. + */ +static DEFINE_MUTEX(device_mutex); + +static int ib_device_check_mandatory(struct ib_device *device) +{ +#define IB_MANDATORY_FUNC(x) { offsetof(struct ib_device, x), #x } + static const struct { + size_t offset; + char *name; + } mandatory_table[] = { + IB_MANDATORY_FUNC(query_device), + IB_MANDATORY_FUNC(query_port), + IB_MANDATORY_FUNC(query_pkey), + IB_MANDATORY_FUNC(query_gid), + IB_MANDATORY_FUNC(alloc_pd), + IB_MANDATORY_FUNC(dealloc_pd), + IB_MANDATORY_FUNC(create_ah), + IB_MANDATORY_FUNC(destroy_ah), + IB_MANDATORY_FUNC(create_qp), + IB_MANDATORY_FUNC(modify_qp), + IB_MANDATORY_FUNC(destroy_qp), + IB_MANDATORY_FUNC(post_send), + IB_MANDATORY_FUNC(post_recv), + IB_MANDATORY_FUNC(create_cq), + IB_MANDATORY_FUNC(destroy_cq), + IB_MANDATORY_FUNC(poll_cq), + IB_MANDATORY_FUNC(req_notify_cq), + IB_MANDATORY_FUNC(get_dma_mr), + IB_MANDATORY_FUNC(dereg_mr) + }; + int i; + + for (i = 0; i < ARRAY_SIZE(mandatory_table); ++i) { + if (!*(void **) ((u_char *) device + mandatory_table[i].offset)) { + printk(KERN_WARNING "Device %s is missing mandatory function %s\n", + device->name, mandatory_table[i].name); + return -EINVAL; + } + } + + return 0; +} + +static struct ib_device *__ib_device_get_by_name(const char *name) +{ + struct ib_device *device; + + list_for_each_entry(device, &device_list, core_list) + if (!strncmp(name, device->name, IB_DEVICE_NAME_MAX)) + return device; + + return NULL; +} + + +static int alloc_name(char *name) +{ + unsigned long *inuse; + char buf[IB_DEVICE_NAME_MAX]; + struct ib_device *device; + int i; + + inuse = (unsigned long *) get_zeroed_page(GFP_KERNEL); + if (!inuse) + return -ENOMEM; + + list_for_each_entry(device, &device_list, core_list) { + if (!sscanf(device->name, name, &i)) + continue; + if (i < 0 || i >= PAGE_SIZE * 8) + continue; + snprintf(buf, sizeof buf, name, i); + if (!strncmp(buf, device->name, IB_DEVICE_NAME_MAX)) + set_bit(i, inuse); + } + + i = find_first_zero_bit(inuse, PAGE_SIZE * 8); + free_page((unsigned long) inuse); + snprintf(buf, sizeof buf, name, i); + + if (__ib_device_get_by_name(buf)) + return -ENFILE; + + strlcpy(name, buf, IB_DEVICE_NAME_MAX); + return 0; +} + +static int start_port(struct ib_device *device) +{ + return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1; +} + + +static int end_port(struct ib_device *device) +{ + return (device->node_type == RDMA_NODE_IB_SWITCH) ? + 0 : device->phys_port_cnt; +} + +/** + * ib_alloc_device - allocate an IB device struct + * @size:size of structure to allocate + * + * Low-level drivers should use ib_alloc_device() to allocate &struct + * ib_device. @size is the size of the structure to be allocated, + * including any private data used by the low-level driver. + * ib_dealloc_device() must be used to free structures allocated with + * ib_alloc_device(). + */ +struct ib_device *ib_alloc_device(size_t size) +{ + BUG_ON(size < sizeof (struct ib_device)); + + return kzalloc(size, GFP_KERNEL); +} +EXPORT_SYMBOL(ib_alloc_device); + +/** + * ib_dealloc_device - free an IB device struct + * @device:structure to free + * + * Free a structure allocated with ib_alloc_device(). + */ +void ib_dealloc_device(struct ib_device *device) +{ + if (device->reg_state == IB_DEV_UNINITIALIZED) { + kfree(device); + return; + } + + BUG_ON(device->reg_state != IB_DEV_UNREGISTERED); + + kobject_put(&device->dev.kobj); +} +EXPORT_SYMBOL(ib_dealloc_device); + +static int add_client_context(struct ib_device *device, struct ib_client *client) +{ + struct ib_client_data *context; + unsigned long flags; + + context = kmalloc(sizeof *context, GFP_KERNEL); + if (!context) { + printk(KERN_WARNING "Couldn't allocate client context for %s/%s\n", + device->name, client->name); + return -ENOMEM; + } + + context->client = client; + context->data = NULL; + + spin_lock_irqsave(&device->client_data_lock, flags); + list_add(&context->list, &device->client_data_list); + spin_unlock_irqrestore(&device->client_data_lock, flags); + + return 0; +} + +static int read_port_table_lengths(struct ib_device *device) +{ + struct ib_port_attr *tprops = NULL; + int num_ports, ret = -ENOMEM; + u8 port_index; + + tprops = kmalloc(sizeof *tprops, GFP_KERNEL); + if (!tprops) + goto out; + + num_ports = end_port(device) - start_port(device) + 1; + + device->pkey_tbl_len = kmalloc(sizeof *device->pkey_tbl_len * num_ports, + GFP_KERNEL); + device->gid_tbl_len = kmalloc(sizeof *device->gid_tbl_len * num_ports, + GFP_KERNEL); + if (!device->pkey_tbl_len || !device->gid_tbl_len) + goto err; + + for (port_index = 0; port_index < num_ports; ++port_index) { + ret = ib_query_port(device, port_index + start_port(device), + tprops); + if (ret) + goto err; + device->pkey_tbl_len[port_index] = tprops->pkey_tbl_len; + device->gid_tbl_len[port_index] = tprops->gid_tbl_len; + } + + ret = 0; + goto out; + +err: + kfree(device->gid_tbl_len); + kfree(device->pkey_tbl_len); +out: + kfree(tprops); + return ret; +} + +/** + * ib_register_device - Register an IB device with IB core + * @device:Device to register + * + * Low-level drivers use ib_register_device() to register their + * devices with the IB core. All registered clients will receive a + * callback for each device that is added. @device must be allocated + * with ib_alloc_device(). + */ +int ib_register_device(struct ib_device *device) +{ + int ret; + + mutex_lock(&device_mutex); + + if (strchr(device->name, '%')) { + ret = alloc_name(device->name); + if (ret) + goto out; + } + + if (ib_device_check_mandatory(device)) { + ret = -EINVAL; + goto out; + } + + INIT_LIST_HEAD(&device->event_handler_list); + INIT_LIST_HEAD(&device->client_data_list); + spin_lock_init(&device->event_handler_lock); + spin_lock_init(&device->client_data_lock); + device->ib_uverbs_xrcd_table = RB_ROOT; + mutex_init(&device->xrcd_table_mutex); + + ret = read_port_table_lengths(device); + if (ret) { + printk(KERN_WARNING "Couldn't create table lengths cache for device %s\n", + device->name); + goto out; + } + + ret = ib_device_register_sysfs(device); + if (ret) { + printk(KERN_WARNING "Couldn't register device %s with driver model\n", + device->name); + kfree(device->gid_tbl_len); + kfree(device->pkey_tbl_len); + goto out; + } + + list_add_tail(&device->core_list, &device_list); + + device->reg_state = IB_DEV_REGISTERED; + + { + struct ib_client *client; + + list_for_each_entry(client, &client_list, list) + if (client->add && !add_client_context(device, client)) + client->add(device); + } + + out: + mutex_unlock(&device_mutex); + return ret; +} +EXPORT_SYMBOL(ib_register_device); + +/** + * ib_unregister_device - Unregister an IB device + * @device:Device to unregister + * + * Unregister an IB device. All clients will receive a remove callback. + */ +void ib_unregister_device(struct ib_device *device) +{ + struct ib_client *client; + struct ib_client_data *context, *tmp; + unsigned long flags; + + mutex_lock(&device_mutex); + + list_for_each_entry_reverse(client, &client_list, list) + if (client->remove) + client->remove(device); + + list_del(&device->core_list); + + kfree(device->gid_tbl_len); + kfree(device->pkey_tbl_len); + + mutex_unlock(&device_mutex); + + ib_device_unregister_sysfs(device); + + spin_lock_irqsave(&device->client_data_lock, flags); + list_for_each_entry_safe(context, tmp, &device->client_data_list, list) + kfree(context); + spin_unlock_irqrestore(&device->client_data_lock, flags); + + device->reg_state = IB_DEV_UNREGISTERED; +} +EXPORT_SYMBOL(ib_unregister_device); + +/** + * ib_register_client - Register an IB client + * @client:Client to register + * + * Upper level users of the IB drivers can use ib_register_client() to + * register callbacks for IB device addition and removal. When an IB + * device is added, each registered client's add method will be called + * (in the order the clients were registered), and when a device is + * removed, each client's remove method will be called (in the reverse + * order that clients were registered). In addition, when + * ib_register_client() is called, the client will receive an add + * callback for all devices already registered. + */ +int ib_register_client(struct ib_client *client) +{ + struct ib_device *device; + + mutex_lock(&device_mutex); + + list_add_tail(&client->list, &client_list); + list_for_each_entry(device, &device_list, core_list) + if (client->add && !add_client_context(device, client)) + client->add(device); + + mutex_unlock(&device_mutex); + + return 0; +} +EXPORT_SYMBOL(ib_register_client); + +/** + * ib_unregister_client - Unregister an IB client + * @client:Client to unregister + * + * Upper level users use ib_unregister_client() to remove their client + * registration. When ib_unregister_client() is called, the client + * will receive a remove callback for each IB device still registered. + */ +void ib_unregister_client(struct ib_client *client) +{ + struct ib_client_data *context, *tmp; + struct ib_device *device; + unsigned long flags; + + mutex_lock(&device_mutex); + + list_for_each_entry(device, &device_list, core_list) { + if (client->remove) + client->remove(device); + + spin_lock_irqsave(&device->client_data_lock, flags); + list_for_each_entry_safe(context, tmp, &device->client_data_list, list) + if (context->client == client) { + list_del(&context->list); + kfree(context); + } + spin_unlock_irqrestore(&device->client_data_lock, flags); + } + list_del(&client->list); + + mutex_unlock(&device_mutex); +} +EXPORT_SYMBOL(ib_unregister_client); + +/** + * ib_get_client_data - Get IB client context + * @device:Device to get context for + * @client:Client to get context for + * + * ib_get_client_data() returns client context set with + * ib_set_client_data(). + */ +void *ib_get_client_data(struct ib_device *device, struct ib_client *client) +{ + struct ib_client_data *context; + void *ret = NULL; + unsigned long flags; + + spin_lock_irqsave(&device->client_data_lock, flags); + list_for_each_entry(context, &device->client_data_list, list) + if (context->client == client) { + ret = context->data; + break; + } + spin_unlock_irqrestore(&device->client_data_lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_get_client_data); + +/** + * ib_set_client_data - Set IB client context + * @device:Device to set context for + * @client:Client to set context for + * @data:Context to set + * + * ib_set_client_data() sets client context that can be retrieved with + * ib_get_client_data(). + */ +void ib_set_client_data(struct ib_device *device, struct ib_client *client, + void *data) +{ + struct ib_client_data *context; + unsigned long flags; + + spin_lock_irqsave(&device->client_data_lock, flags); + list_for_each_entry(context, &device->client_data_list, list) + if (context->client == client) { + context->data = data; + goto out; + } + + printk(KERN_WARNING "No client context found for %s/%s\n", + device->name, client->name); + +out: + spin_unlock_irqrestore(&device->client_data_lock, flags); +} +EXPORT_SYMBOL(ib_set_client_data); + +/** + * ib_register_event_handler - Register an IB event handler + * @event_handler:Handler to register + * + * ib_register_event_handler() registers an event handler that will be + * called back when asynchronous IB events occur (as defined in + * chapter 11 of the InfiniBand Architecture Specification). This + * callback may occur in interrupt context. + */ +int ib_register_event_handler (struct ib_event_handler *event_handler) +{ + unsigned long flags; + + spin_lock_irqsave(&event_handler->device->event_handler_lock, flags); + list_add_tail(&event_handler->list, + &event_handler->device->event_handler_list); + spin_unlock_irqrestore(&event_handler->device->event_handler_lock, flags); + + return 0; +} +EXPORT_SYMBOL(ib_register_event_handler); + +/** + * ib_unregister_event_handler - Unregister an event handler + * @event_handler:Handler to unregister + * + * Unregister an event handler registered with + * ib_register_event_handler(). + */ +int ib_unregister_event_handler(struct ib_event_handler *event_handler) +{ + unsigned long flags; + + spin_lock_irqsave(&event_handler->device->event_handler_lock, flags); + list_del(&event_handler->list); + spin_unlock_irqrestore(&event_handler->device->event_handler_lock, flags); + + return 0; +} +EXPORT_SYMBOL(ib_unregister_event_handler); + +/** + * ib_dispatch_event - Dispatch an asynchronous event + * @event:Event to dispatch + * + * Low-level drivers must call ib_dispatch_event() to dispatch the + * event to all registered event handlers when an asynchronous event + * occurs. + */ +void ib_dispatch_event(struct ib_event *event) +{ + unsigned long flags; + struct ib_event_handler *handler; + + spin_lock_irqsave(&event->device->event_handler_lock, flags); + + list_for_each_entry(handler, &event->device->event_handler_list, list) + handler->handler(handler, event); + + spin_unlock_irqrestore(&event->device->event_handler_lock, flags); +} +EXPORT_SYMBOL(ib_dispatch_event); + +/** + * ib_query_device - Query IB device attributes + * @device:Device to query + * @device_attr:Device attributes + * + * ib_query_device() returns the attributes of a device through the + * @device_attr pointer. + */ +int ib_query_device(struct ib_device *device, + struct ib_device_attr *device_attr) +{ + return device->query_device(device, device_attr); +} +EXPORT_SYMBOL(ib_query_device); + +/** + * ib_query_port - Query IB port attributes + * @device:Device to query + * @port_num:Port number to query + * @port_attr:Port attributes + * + * ib_query_port() returns the attributes of a port through the + * @port_attr pointer. + */ +int ib_query_port(struct ib_device *device, + u8 port_num, + struct ib_port_attr *port_attr) +{ + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + return device->query_port(device, port_num, port_attr); +} +EXPORT_SYMBOL(ib_query_port); + +/** + * ib_query_gid - Get GID table entry + * @device:Device to query + * @port_num:Port number to query + * @index:GID table index to query + * @gid:Returned GID + * + * ib_query_gid() fetches the specified GID table entry. + */ +int ib_query_gid(struct ib_device *device, + u8 port_num, int index, union ib_gid *gid) +{ + return device->query_gid(device, port_num, index, gid); +} +EXPORT_SYMBOL(ib_query_gid); + +/** + * ib_query_pkey - Get P_Key table entry + * @device:Device to query + * @port_num:Port number to query + * @index:P_Key table index to query + * @pkey:Returned P_Key + * + * ib_query_pkey() fetches the specified P_Key table entry. + */ +int ib_query_pkey(struct ib_device *device, + u8 port_num, u16 index, u16 *pkey) +{ + return device->query_pkey(device, port_num, index, pkey); +} +EXPORT_SYMBOL(ib_query_pkey); + +/** + * ib_modify_device - Change IB device attributes + * @device:Device to modify + * @device_modify_mask:Mask of attributes to change + * @device_modify:New attribute values + * + * ib_modify_device() changes a device's attributes as specified by + * the @device_modify_mask and @device_modify structure. + */ +int ib_modify_device(struct ib_device *device, + int device_modify_mask, + struct ib_device_modify *device_modify) +{ + return device->modify_device(device, device_modify_mask, + device_modify); +} +EXPORT_SYMBOL(ib_modify_device); + +/** + * ib_modify_port - Modifies the attributes for the specified port. + * @device: The device to modify. + * @port_num: The number of the port to modify. + * @port_modify_mask: Mask used to specify which attributes of the port + * to change. + * @port_modify: New attribute values for the port. + * + * ib_modify_port() changes a port's attributes as specified by the + * @port_modify_mask and @port_modify structure. + */ +int ib_modify_port(struct ib_device *device, + u8 port_num, int port_modify_mask, + struct ib_port_modify *port_modify) +{ + if (port_num < start_port(device) || port_num > end_port(device)) + return -EINVAL; + + return device->modify_port(device, port_num, port_modify_mask, + port_modify); +} +EXPORT_SYMBOL(ib_modify_port); + +/** + * ib_find_gid - Returns the port number and GID table index where + * a specified GID value occurs. + * @device: The device to query. + * @gid: The GID value to search for. + * @port_num: The port number of the device where the GID value was found. + * @index: The index into the GID table where the GID was found. This + * parameter may be NULL. + */ +int ib_find_gid(struct ib_device *device, union ib_gid *gid, + u8 *port_num, u16 *index) +{ + union ib_gid tmp_gid; + int ret, port, i; + + for (port = start_port(device); port <= end_port(device); ++port) { + for (i = 0; i < device->gid_tbl_len[port - start_port(device)]; ++i) { + ret = ib_query_gid(device, port, i, &tmp_gid); + if (ret) + return ret; + if (!memcmp(&tmp_gid, gid, sizeof *gid)) { + *port_num = port; + if (index) + *index = i; + return 0; + } + } + } + + return -ENOENT; +} +EXPORT_SYMBOL(ib_find_gid); + +/** + * ib_find_pkey - Returns the PKey table index where a specified + * PKey value occurs. + * @device: The device to query. + * @port_num: The port number of the device to search for the PKey. + * @pkey: The PKey value to search for. + * @index: The index into the PKey table where the PKey was found. + */ +int ib_find_pkey(struct ib_device *device, + u8 port_num, u16 pkey, u16 *index) +{ + int ret, i; + u16 tmp_pkey; + + for (i = 0; i < device->pkey_tbl_len[port_num - start_port(device)]; ++i) { + ret = ib_query_pkey(device, port_num, i, &tmp_pkey); + if (ret) + return ret; + + if ((pkey & 0x7fff) == (tmp_pkey & 0x7fff)) { + *index = i; + return 0; + } + } + + return -ENOENT; +} +EXPORT_SYMBOL(ib_find_pkey); + +static int __init ib_core_init(void) +{ + int ret; + +#ifdef __ia64__ + if (ia64_platform_is("hpzx1")) + dma_map_sg_hp_wa = 1; +#endif + + ret = ib_sysfs_setup(); + if (ret) + printk(KERN_WARNING "Couldn't create InfiniBand device class\n"); + + ret = ib_cache_setup(); + if (ret) { + printk(KERN_WARNING "Couldn't set up InfiniBand P_Key/GID cache\n"); + ib_sysfs_cleanup(); + } + + return ret; +} + +static void __exit ib_core_cleanup(void) +{ + ib_cache_cleanup(); + ib_sysfs_cleanup(); + /* Make sure that any pending umem accounting work is done. */ + flush_scheduled_work(); +} + +module_init(ib_core_init); +module_exit(ib_core_cleanup); diff --git a/sys/ofed/drivers/infiniband/core/fmr_pool.c b/sys/ofed/drivers/infiniband/core/fmr_pool.c new file mode 100644 index 000000000000..4507043d24c8 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/fmr_pool.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include + +#include "core_priv.h" + +#define PFX "fmr_pool: " + +enum { + IB_FMR_MAX_REMAPS = 32, + + IB_FMR_HASH_BITS = 8, + IB_FMR_HASH_SIZE = 1 << IB_FMR_HASH_BITS, + IB_FMR_HASH_MASK = IB_FMR_HASH_SIZE - 1 +}; + +/* + * If an FMR is not in use, then the list member will point to either + * its pool's free_list (if the FMR can be mapped again; that is, + * remap_count < pool->max_remaps) or its pool's dirty_list (if the + * FMR needs to be unmapped before being remapped). In either of + * these cases it is a bug if the ref_count is not 0. In other words, + * if ref_count is > 0, then the list member must not be linked into + * either free_list or dirty_list. + * + * The cache_node member is used to link the FMR into a cache bucket + * (if caching is enabled). This is independent of the reference + * count of the FMR. When a valid FMR is released, its ref_count is + * decremented, and if ref_count reaches 0, the FMR is placed in + * either free_list or dirty_list as appropriate. However, it is not + * removed from the cache and may be "revived" if a call to + * ib_fmr_register_physical() occurs before the FMR is remapped. In + * this case we just increment the ref_count and remove the FMR from + * free_list/dirty_list. + * + * Before we remap an FMR from free_list, we remove it from the cache + * (to prevent another user from obtaining a stale FMR). When an FMR + * is released, we add it to the tail of the free list, so that our + * cache eviction policy is "least recently used." + * + * All manipulation of ref_count, list and cache_node is protected by + * pool_lock to maintain consistency. + */ + +struct ib_fmr_pool { + spinlock_t pool_lock; + + int pool_size; + int max_pages; + int max_remaps; + int dirty_watermark; + int dirty_len; + struct list_head free_list; + struct list_head dirty_list; + struct hlist_head *cache_bucket; + + void (*flush_function)(struct ib_fmr_pool *pool, + void * arg); + void *flush_arg; + + struct task_struct *thread; + + atomic_t req_ser; + atomic_t flush_ser; + + wait_queue_head_t force_wait; +}; + +static inline u32 ib_fmr_hash(u64 first_page) +{ + return jhash_2words((u32) first_page, (u32) (first_page >> 32), 0) & + (IB_FMR_HASH_SIZE - 1); +} + +/* Caller must hold pool_lock */ +static inline struct ib_pool_fmr *ib_fmr_cache_lookup(struct ib_fmr_pool *pool, + u64 *page_list, + int page_list_len, + u64 io_virtual_address) +{ + struct hlist_head *bucket; + struct ib_pool_fmr *fmr; + struct hlist_node *pos; + + if (!pool->cache_bucket) + return NULL; + + bucket = pool->cache_bucket + ib_fmr_hash(*page_list); + + hlist_for_each_entry(fmr, pos, bucket, cache_node) + if (io_virtual_address == fmr->io_virtual_address && + page_list_len == fmr->page_list_len && + !memcmp(page_list, fmr->page_list, + page_list_len * sizeof *page_list)) + return fmr; + + return NULL; +} + +static void ib_fmr_batch_release(struct ib_fmr_pool *pool) +{ + int ret; + struct ib_pool_fmr *fmr; + LIST_HEAD(unmap_list); + LIST_HEAD(fmr_list); + + spin_lock_irq(&pool->pool_lock); + + list_for_each_entry(fmr, &pool->dirty_list, list) { + hlist_del_init(&fmr->cache_node); + fmr->remap_count = 0; + list_add_tail(&fmr->fmr->list, &fmr_list); + +#ifdef DEBUG + if (fmr->ref_count !=0) { + printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d\n", + fmr, fmr->ref_count); + } +#endif + } + + list_splice_init(&pool->dirty_list, &unmap_list); + pool->dirty_len = 0; + + spin_unlock_irq(&pool->pool_lock); + + if (list_empty(&unmap_list)) { + return; + } + + ret = ib_unmap_fmr(&fmr_list); + if (ret) + printk(KERN_WARNING PFX "ib_unmap_fmr returned %d\n", ret); + + spin_lock_irq(&pool->pool_lock); + list_splice(&unmap_list, &pool->free_list); + spin_unlock_irq(&pool->pool_lock); +} + +static int ib_fmr_cleanup_thread(void *pool_ptr) +{ + struct ib_fmr_pool *pool = pool_ptr; + + do { + if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) { + ib_fmr_batch_release(pool); + + atomic_inc(&pool->flush_ser); + wake_up_interruptible(&pool->force_wait); + + if (pool->flush_function) + pool->flush_function(pool, pool->flush_arg); + } + + set_current_state(TASK_INTERRUPTIBLE); + if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 && + !kthread_should_stop()) + schedule(); + __set_current_state(TASK_RUNNING); + } while (!kthread_should_stop()); + + return 0; +} + +/** + * ib_create_fmr_pool - Create an FMR pool + * @pd:Protection domain for FMRs + * @params:FMR pool parameters + * + * Create a pool of FMRs. Return value is pointer to new pool or + * error code if creation failed. + */ +struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, + struct ib_fmr_pool_param *params) +{ + struct ib_device *device; + struct ib_fmr_pool *pool; + struct ib_device_attr *attr; + int i; + int ret; + int max_remaps; + + if (!params) + return ERR_PTR(-EINVAL); + + device = pd->device; + if (!device->alloc_fmr || !device->dealloc_fmr || + !device->map_phys_fmr || !device->unmap_fmr) { + printk(KERN_INFO PFX "Device %s does not support FMRs\n", + device->name); + return ERR_PTR(-ENOSYS); + } + + attr = kmalloc(sizeof *attr, GFP_KERNEL); + if (!attr) { + printk(KERN_WARNING PFX "couldn't allocate device attr struct\n"); + return ERR_PTR(-ENOMEM); + } + + ret = ib_query_device(device, attr); + if (ret) { + printk(KERN_WARNING PFX "couldn't query device: %d\n", ret); + kfree(attr); + return ERR_PTR(ret); + } + + if (!attr->max_map_per_fmr) + max_remaps = IB_FMR_MAX_REMAPS; + else + max_remaps = attr->max_map_per_fmr; + + kfree(attr); + + pool = kmalloc(sizeof *pool, GFP_KERNEL); + if (!pool) { + printk(KERN_WARNING PFX "couldn't allocate pool struct\n"); + return ERR_PTR(-ENOMEM); + } + + pool->cache_bucket = NULL; + + pool->flush_function = params->flush_function; + pool->flush_arg = params->flush_arg; + + INIT_LIST_HEAD(&pool->free_list); + INIT_LIST_HEAD(&pool->dirty_list); + + if (params->cache) { + pool->cache_bucket = + kmalloc(IB_FMR_HASH_SIZE * sizeof *pool->cache_bucket, + GFP_KERNEL); + if (!pool->cache_bucket) { + printk(KERN_WARNING PFX "Failed to allocate cache in pool\n"); + ret = -ENOMEM; + goto out_free_pool; + } + + for (i = 0; i < IB_FMR_HASH_SIZE; ++i) + INIT_HLIST_HEAD(pool->cache_bucket + i); + } + + pool->pool_size = 0; + pool->max_pages = params->max_pages_per_fmr; + pool->max_remaps = max_remaps; + pool->dirty_watermark = params->dirty_watermark; + pool->dirty_len = 0; + spin_lock_init(&pool->pool_lock); + atomic_set(&pool->req_ser, 0); + atomic_set(&pool->flush_ser, 0); + init_waitqueue_head(&pool->force_wait); + + pool->thread = kthread_run(ib_fmr_cleanup_thread, + pool, + "ib_fmr(%s)", + device->name); + if (IS_ERR(pool->thread)) { + printk(KERN_WARNING PFX "couldn't start cleanup thread\n"); + ret = PTR_ERR(pool->thread); + goto out_free_pool; + } + + { + struct ib_pool_fmr *fmr; + struct ib_fmr_attr fmr_attr = { + .max_pages = params->max_pages_per_fmr, + .max_maps = pool->max_remaps, + .page_shift = params->page_shift + }; + int bytes_per_fmr = sizeof *fmr; + + if (pool->cache_bucket) + bytes_per_fmr += params->max_pages_per_fmr * sizeof (u64); + + for (i = 0; i < params->pool_size; ++i) { + fmr = kmalloc(bytes_per_fmr, GFP_KERNEL); + if (!fmr) { + printk(KERN_WARNING PFX "failed to allocate fmr " + "struct for FMR %d\n", i); + goto out_fail; + } + + fmr->pool = pool; + fmr->remap_count = 0; + fmr->ref_count = 0; + INIT_HLIST_NODE(&fmr->cache_node); + + fmr->fmr = ib_alloc_fmr(pd, params->access, &fmr_attr); + if (IS_ERR(fmr->fmr)) { + printk(KERN_WARNING PFX "fmr_create failed " + "for FMR %d\n", i); + kfree(fmr); + goto out_fail; + } + + list_add_tail(&fmr->list, &pool->free_list); + ++pool->pool_size; + } + } + + return pool; + + out_free_pool: + kfree(pool->cache_bucket); + kfree(pool); + + return ERR_PTR(ret); + + out_fail: + ib_destroy_fmr_pool(pool); + + return ERR_PTR(-ENOMEM); +} +EXPORT_SYMBOL(ib_create_fmr_pool); + +/** + * ib_destroy_fmr_pool - Free FMR pool + * @pool:FMR pool to free + * + * Destroy an FMR pool and free all associated resources. + */ +void ib_destroy_fmr_pool(struct ib_fmr_pool *pool) +{ + struct ib_pool_fmr *fmr; + struct ib_pool_fmr *tmp; + LIST_HEAD(fmr_list); + int i; + + kthread_stop(pool->thread); + ib_fmr_batch_release(pool); + + i = 0; + list_for_each_entry_safe(fmr, tmp, &pool->free_list, list) { + if (fmr->remap_count) { + INIT_LIST_HEAD(&fmr_list); + list_add_tail(&fmr->fmr->list, &fmr_list); + ib_unmap_fmr(&fmr_list); + } + ib_dealloc_fmr(fmr->fmr); + list_del(&fmr->list); + kfree(fmr); + ++i; + } + + if (i < pool->pool_size) + printk(KERN_WARNING PFX "pool still has %d regions registered\n", + pool->pool_size - i); + + kfree(pool->cache_bucket); + kfree(pool); +} +EXPORT_SYMBOL(ib_destroy_fmr_pool); + +/** + * ib_flush_fmr_pool - Invalidate all unmapped FMRs + * @pool:FMR pool to flush + * + * Ensure that all unmapped FMRs are fully invalidated. + */ +int ib_flush_fmr_pool(struct ib_fmr_pool *pool) +{ + int serial; + struct ib_pool_fmr *fmr, *next; + + /* + * The free_list holds FMRs that may have been used + * but have not been remapped enough times to be dirty. + * Put them on the dirty list now so that the cleanup + * thread will reap them too. + */ + spin_lock_irq(&pool->pool_lock); + list_for_each_entry_safe(fmr, next, &pool->free_list, list) { + if (fmr->remap_count > 0) + list_move(&fmr->list, &pool->dirty_list); + } + spin_unlock_irq(&pool->pool_lock); + + serial = atomic_inc_return(&pool->req_ser); + wake_up_process(pool->thread); + + if (wait_event_interruptible(pool->force_wait, + atomic_read(&pool->flush_ser) - serial >= 0)) + return -EINTR; + + return 0; +} +EXPORT_SYMBOL(ib_flush_fmr_pool); + +/** + * ib_fmr_pool_map_phys - + * @pool:FMR pool to allocate FMR from + * @page_list:List of pages to map + * @list_len:Number of pages in @page_list + * @io_virtual_address:I/O virtual address for new FMR + * + * Map an FMR from an FMR pool. + */ +struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle, + u64 *page_list, + int list_len, + u64 io_virtual_address) +{ + struct ib_fmr_pool *pool = pool_handle; + struct ib_pool_fmr *fmr; + unsigned long flags; + int result; + + if (list_len < 1 || list_len > pool->max_pages) + return ERR_PTR(-EINVAL); + + spin_lock_irqsave(&pool->pool_lock, flags); + fmr = ib_fmr_cache_lookup(pool, + page_list, + list_len, + io_virtual_address); + if (fmr) { + /* found in cache */ + ++fmr->ref_count; + if (fmr->ref_count == 1) { + list_del(&fmr->list); + } + + spin_unlock_irqrestore(&pool->pool_lock, flags); + + return fmr; + } + + if (list_empty(&pool->free_list)) { + spin_unlock_irqrestore(&pool->pool_lock, flags); + return ERR_PTR(-EAGAIN); + } + + fmr = list_entry(pool->free_list.next, struct ib_pool_fmr, list); + list_del(&fmr->list); + hlist_del_init(&fmr->cache_node); + spin_unlock_irqrestore(&pool->pool_lock, flags); + + result = ib_map_phys_fmr(fmr->fmr, page_list, list_len, + io_virtual_address); + + if (result) { + spin_lock_irqsave(&pool->pool_lock, flags); + list_add(&fmr->list, &pool->free_list); + spin_unlock_irqrestore(&pool->pool_lock, flags); + + printk(KERN_WARNING PFX "fmr_map returns %d\n", result); + + return ERR_PTR(result); + } + + ++fmr->remap_count; + fmr->ref_count = 1; + + if (pool->cache_bucket) { + fmr->io_virtual_address = io_virtual_address; + fmr->page_list_len = list_len; + memcpy(fmr->page_list, page_list, list_len * sizeof(*page_list)); + + spin_lock_irqsave(&pool->pool_lock, flags); + hlist_add_head(&fmr->cache_node, + pool->cache_bucket + ib_fmr_hash(fmr->page_list[0])); + spin_unlock_irqrestore(&pool->pool_lock, flags); + } + + return fmr; +} +EXPORT_SYMBOL(ib_fmr_pool_map_phys); + +/** + * ib_fmr_pool_unmap - Unmap FMR + * @fmr:FMR to unmap + * + * Unmap an FMR. The FMR mapping may remain valid until the FMR is + * reused (or until ib_flush_fmr_pool() is called). + */ +int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr) +{ + struct ib_fmr_pool *pool; + unsigned long flags; + + pool = fmr->pool; + + spin_lock_irqsave(&pool->pool_lock, flags); + + --fmr->ref_count; + if (!fmr->ref_count) { + if (fmr->remap_count < pool->max_remaps) { + list_add_tail(&fmr->list, &pool->free_list); + } else { + list_add_tail(&fmr->list, &pool->dirty_list); + if (++pool->dirty_len >= pool->dirty_watermark) { + atomic_inc(&pool->req_ser); + wake_up_process(pool->thread); + } + } + } + +#ifdef DEBUG + if (fmr->ref_count < 0) + printk(KERN_WARNING PFX "FMR %p has ref count %d < 0\n", + fmr, fmr->ref_count); +#endif + + spin_unlock_irqrestore(&pool->pool_lock, flags); + + return 0; +} +EXPORT_SYMBOL(ib_fmr_pool_unmap); diff --git a/sys/ofed/drivers/infiniband/core/iwcm.c b/sys/ofed/drivers/infiniband/core/iwcm.c new file mode 100644 index 000000000000..625fec5a741c --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/iwcm.c @@ -0,0 +1,1025 @@ +/* + * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. + * Copyright (c) 2005 Network Appliance, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "iwcm.h" + +MODULE_AUTHOR("Tom Tucker"); +MODULE_DESCRIPTION("iWARP CM"); +MODULE_LICENSE("Dual BSD/GPL"); + +static struct workqueue_struct *iwcm_wq; +struct iwcm_work { + struct work_struct work; + struct iwcm_id_private *cm_id; + struct list_head list; + struct iw_cm_event event; + struct list_head free_list; +}; + +/* + * The following services provide a mechanism for pre-allocating iwcm_work + * elements. The design pre-allocates them based on the cm_id type: + * LISTENING IDS: Get enough elements preallocated to handle the + * listen backlog. + * ACTIVE IDS: 4: CONNECT_REPLY, ESTABLISHED, DISCONNECT, CLOSE + * PASSIVE IDS: 3: ESTABLISHED, DISCONNECT, CLOSE + * + * Allocating them in connect and listen avoids having to deal + * with allocation failures on the event upcall from the provider (which + * is called in the interrupt context). + * + * One exception is when creating the cm_id for incoming connection requests. + * There are two cases: + * 1) in the event upcall, cm_event_handler(), for a listening cm_id. If + * the backlog is exceeded, then no more connection request events will + * be processed. cm_event_handler() returns -ENOMEM in this case. Its up + * to the provider to reject the connection request. + * 2) in the connection request workqueue handler, cm_conn_req_handler(). + * If work elements cannot be allocated for the new connect request cm_id, + * then IWCM will call the provider reject method. This is ok since + * cm_conn_req_handler() runs in the workqueue thread context. + */ + +static struct iwcm_work *get_work(struct iwcm_id_private *cm_id_priv) +{ + struct iwcm_work *work; + + if (list_empty(&cm_id_priv->work_free_list)) + return NULL; + work = list_entry(cm_id_priv->work_free_list.next, struct iwcm_work, + free_list); + list_del_init(&work->free_list); + return work; +} + +static void put_work(struct iwcm_work *work) +{ + list_add(&work->free_list, &work->cm_id->work_free_list); +} + +static void dealloc_work_entries(struct iwcm_id_private *cm_id_priv) +{ + struct list_head *e, *tmp; + + list_for_each_safe(e, tmp, &cm_id_priv->work_free_list) + kfree(list_entry(e, struct iwcm_work, free_list)); +} + +static int alloc_work_entries(struct iwcm_id_private *cm_id_priv, int count) +{ + struct iwcm_work *work; + + BUG_ON(!list_empty(&cm_id_priv->work_free_list)); + while (count--) { + work = kmalloc(sizeof(struct iwcm_work), GFP_KERNEL); + if (!work) { + dealloc_work_entries(cm_id_priv); + return -ENOMEM; + } + work->cm_id = cm_id_priv; + INIT_LIST_HEAD(&work->list); + put_work(work); + } + return 0; +} + +/* + * Save private data from incoming connection requests to + * iw_cm_event, so the low level driver doesn't have to. Adjust + * the event ptr to point to the local copy. + */ +static int copy_private_data(struct iw_cm_event *event) +{ + void *p; + + p = kmemdup(event->private_data, event->private_data_len, GFP_ATOMIC); + if (!p) + return -ENOMEM; + event->private_data = p; + return 0; +} + +static void free_cm_id(struct iwcm_id_private *cm_id_priv) +{ + dealloc_work_entries(cm_id_priv); + kfree(cm_id_priv); +} + +/* + * Release a reference on cm_id. If the last reference is being + * released, enable the waiting thread (in iw_destroy_cm_id) to + * get woken up, and return 1 if a thread is already waiting. + */ +static int iwcm_deref_id(struct iwcm_id_private *cm_id_priv) +{ + BUG_ON(atomic_read(&cm_id_priv->refcount)==0); + if (atomic_dec_and_test(&cm_id_priv->refcount)) { + BUG_ON(!list_empty(&cm_id_priv->work_list)); + complete(&cm_id_priv->destroy_comp); + return 1; + } + + return 0; +} + +static void add_ref(struct iw_cm_id *cm_id) +{ + struct iwcm_id_private *cm_id_priv; + cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); + atomic_inc(&cm_id_priv->refcount); +} + +static void rem_ref(struct iw_cm_id *cm_id) +{ + struct iwcm_id_private *cm_id_priv; + cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); + if (iwcm_deref_id(cm_id_priv) && + test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags)) { + BUG_ON(!list_empty(&cm_id_priv->work_list)); + free_cm_id(cm_id_priv); + } +} + +static int cm_event_handler(struct iw_cm_id *cm_id, struct iw_cm_event *event); + +struct iw_cm_id *iw_create_cm_id(struct ib_device *device, + iw_cm_handler cm_handler, + void *context) +{ + struct iwcm_id_private *cm_id_priv; + + cm_id_priv = kzalloc(sizeof(*cm_id_priv), GFP_KERNEL); + if (!cm_id_priv) + return ERR_PTR(-ENOMEM); + + cm_id_priv->state = IW_CM_STATE_IDLE; + cm_id_priv->id.device = device; + cm_id_priv->id.cm_handler = cm_handler; + cm_id_priv->id.context = context; + cm_id_priv->id.event_handler = cm_event_handler; + cm_id_priv->id.add_ref = add_ref; + cm_id_priv->id.rem_ref = rem_ref; + spin_lock_init(&cm_id_priv->lock); + atomic_set(&cm_id_priv->refcount, 1); + init_waitqueue_head(&cm_id_priv->connect_wait); + init_completion(&cm_id_priv->destroy_comp); + INIT_LIST_HEAD(&cm_id_priv->work_list); + INIT_LIST_HEAD(&cm_id_priv->work_free_list); + + return &cm_id_priv->id; +} +EXPORT_SYMBOL(iw_create_cm_id); + + +static int iwcm_modify_qp_err(struct ib_qp *qp) +{ + struct ib_qp_attr qp_attr; + + if (!qp) + return -EINVAL; + + qp_attr.qp_state = IB_QPS_ERR; + return ib_modify_qp(qp, &qp_attr, IB_QP_STATE); +} + +/* + * This is really the RDMAC CLOSING state. It is most similar to the + * IB SQD QP state. + */ +static int iwcm_modify_qp_sqd(struct ib_qp *qp) +{ + struct ib_qp_attr qp_attr; + + BUG_ON(qp == NULL); + qp_attr.qp_state = IB_QPS_SQD; + return ib_modify_qp(qp, &qp_attr, IB_QP_STATE); +} + +/* + * CM_ID <-- CLOSING + * + * Block if a passive or active connection is currently being processed. Then + * process the event as follows: + * - If we are ESTABLISHED, move to CLOSING and modify the QP state + * based on the abrupt flag + * - If the connection is already in the CLOSING or IDLE state, the peer is + * disconnecting concurrently with us and we've already seen the + * DISCONNECT event -- ignore the request and return 0 + * - Disconnect on a listening endpoint returns -EINVAL + */ +int iw_cm_disconnect(struct iw_cm_id *cm_id, int abrupt) +{ + struct iwcm_id_private *cm_id_priv; + unsigned long flags; + int ret = 0; + struct ib_qp *qp = NULL; + + cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); + /* Wait if we're currently in a connect or accept downcall */ + wait_event(cm_id_priv->connect_wait, + !test_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags)); + + spin_lock_irqsave(&cm_id_priv->lock, flags); + switch (cm_id_priv->state) { + case IW_CM_STATE_ESTABLISHED: + cm_id_priv->state = IW_CM_STATE_CLOSING; + + /* QP could be for user-mode client */ + if (cm_id_priv->qp) + qp = cm_id_priv->qp; + else + ret = -EINVAL; + break; + case IW_CM_STATE_LISTEN: + ret = -EINVAL; + break; + case IW_CM_STATE_CLOSING: + /* remote peer closed first */ + case IW_CM_STATE_IDLE: + /* accept or connect returned !0 */ + break; + case IW_CM_STATE_CONN_RECV: + /* + * App called disconnect before/without calling accept after + * connect_request event delivered. + */ + break; + case IW_CM_STATE_CONN_SENT: + /* Can only get here if wait above fails */ + default: + BUG(); + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + + if (qp) { + if (abrupt) + ret = iwcm_modify_qp_err(qp); + else + ret = iwcm_modify_qp_sqd(qp); + + /* + * If both sides are disconnecting the QP could + * already be in ERR or SQD states + */ + ret = 0; + } + + return ret; +} +EXPORT_SYMBOL(iw_cm_disconnect); + +/* + * CM_ID <-- DESTROYING + * + * Clean up all resources associated with the connection and release + * the initial reference taken by iw_create_cm_id. + */ +static void destroy_cm_id(struct iw_cm_id *cm_id) +{ + struct iwcm_id_private *cm_id_priv; + unsigned long flags; + int ret; + + cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); + /* + * Wait if we're currently in a connect or accept downcall. A + * listening endpoint should never block here. + */ + wait_event(cm_id_priv->connect_wait, + !test_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags)); + + spin_lock_irqsave(&cm_id_priv->lock, flags); + switch (cm_id_priv->state) { + case IW_CM_STATE_LISTEN: + cm_id_priv->state = IW_CM_STATE_DESTROYING; + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + /* destroy the listening endpoint */ + ret = cm_id->device->iwcm->destroy_listen(cm_id); + spin_lock_irqsave(&cm_id_priv->lock, flags); + break; + case IW_CM_STATE_ESTABLISHED: + cm_id_priv->state = IW_CM_STATE_DESTROYING; + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + /* Abrupt close of the connection */ + (void)iwcm_modify_qp_err(cm_id_priv->qp); + spin_lock_irqsave(&cm_id_priv->lock, flags); + break; + case IW_CM_STATE_IDLE: + case IW_CM_STATE_CLOSING: + cm_id_priv->state = IW_CM_STATE_DESTROYING; + break; + case IW_CM_STATE_CONN_RECV: + /* + * App called destroy before/without calling accept after + * receiving connection request event notification or + * returned non zero from the event callback function. + * In either case, must tell the provider to reject. + */ + cm_id_priv->state = IW_CM_STATE_DESTROYING; + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + cm_id->device->iwcm->reject(cm_id, NULL, 0); + spin_lock_irqsave(&cm_id_priv->lock, flags); + break; + case IW_CM_STATE_CONN_SENT: + case IW_CM_STATE_DESTROYING: + default: + BUG(); + break; + } + if (cm_id_priv->qp) { + cm_id_priv->id.device->iwcm->rem_ref(cm_id_priv->qp); + cm_id_priv->qp = NULL; + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + + (void)iwcm_deref_id(cm_id_priv); +} + +/* + * This function is only called by the application thread and cannot + * be called by the event thread. The function will wait for all + * references to be released on the cm_id and then kfree the cm_id + * object. + */ +void iw_destroy_cm_id(struct iw_cm_id *cm_id) +{ + struct iwcm_id_private *cm_id_priv; + + cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); + BUG_ON(test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags)); + + destroy_cm_id(cm_id); + + wait_for_completion(&cm_id_priv->destroy_comp); + + free_cm_id(cm_id_priv); +} +EXPORT_SYMBOL(iw_destroy_cm_id); + +/* + * CM_ID <-- LISTEN + * + * Start listening for connect requests. Generates one CONNECT_REQUEST + * event for each inbound connect request. + */ +int iw_cm_listen(struct iw_cm_id *cm_id, int backlog) +{ + struct iwcm_id_private *cm_id_priv; + unsigned long flags; + int ret; + + cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); + + ret = alloc_work_entries(cm_id_priv, backlog); + if (ret) + return ret; + + spin_lock_irqsave(&cm_id_priv->lock, flags); + switch (cm_id_priv->state) { + case IW_CM_STATE_IDLE: + cm_id_priv->state = IW_CM_STATE_LISTEN; + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + ret = cm_id->device->iwcm->create_listen(cm_id, backlog); + if (ret) + cm_id_priv->state = IW_CM_STATE_IDLE; + spin_lock_irqsave(&cm_id_priv->lock, flags); + break; + default: + ret = -EINVAL; + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + + return ret; +} +EXPORT_SYMBOL(iw_cm_listen); + +/* + * CM_ID <-- IDLE + * + * Rejects an inbound connection request. No events are generated. + */ +int iw_cm_reject(struct iw_cm_id *cm_id, + const void *private_data, + u8 private_data_len) +{ + struct iwcm_id_private *cm_id_priv; + unsigned long flags; + int ret; + + cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); + set_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags); + + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id_priv->state != IW_CM_STATE_CONN_RECV) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags); + wake_up_all(&cm_id_priv->connect_wait); + return -EINVAL; + } + cm_id_priv->state = IW_CM_STATE_IDLE; + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + + ret = cm_id->device->iwcm->reject(cm_id, private_data, + private_data_len); + + clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags); + wake_up_all(&cm_id_priv->connect_wait); + + return ret; +} +EXPORT_SYMBOL(iw_cm_reject); + +/* + * CM_ID <-- ESTABLISHED + * + * Accepts an inbound connection request and generates an ESTABLISHED + * event. Callers of iw_cm_disconnect and iw_destroy_cm_id will block + * until the ESTABLISHED event is received from the provider. + */ +int iw_cm_accept(struct iw_cm_id *cm_id, + struct iw_cm_conn_param *iw_param) +{ + struct iwcm_id_private *cm_id_priv; + struct ib_qp *qp; + unsigned long flags; + int ret; + + cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); + set_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags); + + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id_priv->state != IW_CM_STATE_CONN_RECV) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags); + wake_up_all(&cm_id_priv->connect_wait); + return -EINVAL; + } + /* Get the ib_qp given the QPN */ + qp = cm_id->device->iwcm->get_qp(cm_id->device, iw_param->qpn); + if (!qp) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return -EINVAL; + } + cm_id->device->iwcm->add_ref(qp); + cm_id_priv->qp = qp; + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + + ret = cm_id->device->iwcm->accept(cm_id, iw_param); + if (ret) { + /* An error on accept precludes provider events */ + BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_RECV); + cm_id_priv->state = IW_CM_STATE_IDLE; + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id_priv->qp) { + cm_id->device->iwcm->rem_ref(qp); + cm_id_priv->qp = NULL; + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags); + wake_up_all(&cm_id_priv->connect_wait); + } + + return ret; +} +EXPORT_SYMBOL(iw_cm_accept); + +/* + * Active Side: CM_ID <-- CONN_SENT + * + * If successful, results in the generation of a CONNECT_REPLY + * event. iw_cm_disconnect and iw_cm_destroy will block until the + * CONNECT_REPLY event is received from the provider. + */ +int iw_cm_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param) +{ + struct iwcm_id_private *cm_id_priv; + int ret; + unsigned long flags; + struct ib_qp *qp; + + cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); + + ret = alloc_work_entries(cm_id_priv, 4); + if (ret) + return ret; + + set_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags); + spin_lock_irqsave(&cm_id_priv->lock, flags); + + if (cm_id_priv->state != IW_CM_STATE_IDLE) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags); + wake_up_all(&cm_id_priv->connect_wait); + return -EINVAL; + } + + /* Get the ib_qp given the QPN */ + qp = cm_id->device->iwcm->get_qp(cm_id->device, iw_param->qpn); + if (!qp) { + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return -EINVAL; + } + cm_id->device->iwcm->add_ref(qp); + cm_id_priv->qp = qp; + cm_id_priv->state = IW_CM_STATE_CONN_SENT; + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + + ret = cm_id->device->iwcm->connect(cm_id, iw_param); + if (ret) { + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id_priv->qp) { + cm_id->device->iwcm->rem_ref(qp); + cm_id_priv->qp = NULL; + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_SENT); + cm_id_priv->state = IW_CM_STATE_IDLE; + clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags); + wake_up_all(&cm_id_priv->connect_wait); + } + + return ret; +} +EXPORT_SYMBOL(iw_cm_connect); + +/* + * Passive Side: new CM_ID <-- CONN_RECV + * + * Handles an inbound connect request. The function creates a new + * iw_cm_id to represent the new connection and inherits the client + * callback function and other attributes from the listening parent. + * + * The work item contains a pointer to the listen_cm_id and the event. The + * listen_cm_id contains the client cm_handler, context and + * device. These are copied when the device is cloned. The event + * contains the new four tuple. + * + * An error on the child should not affect the parent, so this + * function does not return a value. + */ +static void cm_conn_req_handler(struct iwcm_id_private *listen_id_priv, + struct iw_cm_event *iw_event) +{ + unsigned long flags; + struct iw_cm_id *cm_id; + struct iwcm_id_private *cm_id_priv; + int ret; + + /* + * The provider should never generate a connection request + * event with a bad status. + */ + BUG_ON(iw_event->status); + + /* + * We could be destroying the listening id. If so, ignore this + * upcall. + */ + spin_lock_irqsave(&listen_id_priv->lock, flags); + if (listen_id_priv->state != IW_CM_STATE_LISTEN) { + spin_unlock_irqrestore(&listen_id_priv->lock, flags); + goto out; + } + spin_unlock_irqrestore(&listen_id_priv->lock, flags); + + cm_id = iw_create_cm_id(listen_id_priv->id.device, + listen_id_priv->id.cm_handler, + listen_id_priv->id.context); + /* If the cm_id could not be created, ignore the request */ + if (IS_ERR(cm_id)) + goto out; + + cm_id->provider_data = iw_event->provider_data; + cm_id->local_addr = iw_event->local_addr; + cm_id->remote_addr = iw_event->remote_addr; + + cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); + cm_id_priv->state = IW_CM_STATE_CONN_RECV; + + ret = alloc_work_entries(cm_id_priv, 3); + if (ret) { + iw_cm_reject(cm_id, NULL, 0); + iw_destroy_cm_id(cm_id); + goto out; + } + + /* Call the client CM handler */ + ret = cm_id->cm_handler(cm_id, iw_event); + if (ret) { + iw_cm_reject(cm_id, NULL, 0); + set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags); + destroy_cm_id(cm_id); + if (atomic_read(&cm_id_priv->refcount)==0) + free_cm_id(cm_id_priv); + } + +out: + if (iw_event->private_data_len) + kfree(iw_event->private_data); +} + +/* + * Passive Side: CM_ID <-- ESTABLISHED + * + * The provider generated an ESTABLISHED event which means that + * the MPA negotion has completed successfully and we are now in MPA + * FPDU mode. + * + * This event can only be received in the CONN_RECV state. If the + * remote peer closed, the ESTABLISHED event would be received followed + * by the CLOSE event. If the app closes, it will block until we wake + * it up after processing this event. + */ +static int cm_conn_est_handler(struct iwcm_id_private *cm_id_priv, + struct iw_cm_event *iw_event) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&cm_id_priv->lock, flags); + + /* + * We clear the CONNECT_WAIT bit here to allow the callback + * function to call iw_cm_disconnect. Calling iw_destroy_cm_id + * from a callback handler is not allowed. + */ + clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags); + BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_RECV); + cm_id_priv->state = IW_CM_STATE_ESTABLISHED; + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event); + wake_up_all(&cm_id_priv->connect_wait); + + return ret; +} + +/* + * Active Side: CM_ID <-- ESTABLISHED + * + * The app has called connect and is waiting for the established event to + * post it's requests to the server. This event will wake up anyone + * blocked in iw_cm_disconnect or iw_destroy_id. + */ +static int cm_conn_rep_handler(struct iwcm_id_private *cm_id_priv, + struct iw_cm_event *iw_event) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&cm_id_priv->lock, flags); + /* + * Clear the connect wait bit so a callback function calling + * iw_cm_disconnect will not wait and deadlock this thread + */ + clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags); + BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_SENT); + if (iw_event->status == IW_CM_EVENT_STATUS_ACCEPTED) { + cm_id_priv->id.local_addr = iw_event->local_addr; + cm_id_priv->id.remote_addr = iw_event->remote_addr; + cm_id_priv->state = IW_CM_STATE_ESTABLISHED; + } else { + /* REJECTED or RESET */ + cm_id_priv->id.device->iwcm->rem_ref(cm_id_priv->qp); + cm_id_priv->qp = NULL; + cm_id_priv->state = IW_CM_STATE_IDLE; + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event); + + if (iw_event->private_data_len) + kfree(iw_event->private_data); + + /* Wake up waiters on connect complete */ + wake_up_all(&cm_id_priv->connect_wait); + + return ret; +} + +/* + * CM_ID <-- CLOSING + * + * If in the ESTABLISHED state, move to CLOSING. + */ +static void cm_disconnect_handler(struct iwcm_id_private *cm_id_priv, + struct iw_cm_event *iw_event) +{ + unsigned long flags; + + spin_lock_irqsave(&cm_id_priv->lock, flags); + if (cm_id_priv->state == IW_CM_STATE_ESTABLISHED) + cm_id_priv->state = IW_CM_STATE_CLOSING; + spin_unlock_irqrestore(&cm_id_priv->lock, flags); +} + +/* + * CM_ID <-- IDLE + * + * If in the ESTBLISHED or CLOSING states, the QP will have have been + * moved by the provider to the ERR state. Disassociate the CM_ID from + * the QP, move to IDLE, and remove the 'connected' reference. + * + * If in some other state, the cm_id was destroyed asynchronously. + * This is the last reference that will result in waking up + * the app thread blocked in iw_destroy_cm_id. + */ +static int cm_close_handler(struct iwcm_id_private *cm_id_priv, + struct iw_cm_event *iw_event) +{ + unsigned long flags; + int ret = 0; + spin_lock_irqsave(&cm_id_priv->lock, flags); + + if (cm_id_priv->qp) { + cm_id_priv->id.device->iwcm->rem_ref(cm_id_priv->qp); + cm_id_priv->qp = NULL; + } + switch (cm_id_priv->state) { + case IW_CM_STATE_ESTABLISHED: + case IW_CM_STATE_CLOSING: + cm_id_priv->state = IW_CM_STATE_IDLE; + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event); + spin_lock_irqsave(&cm_id_priv->lock, flags); + break; + case IW_CM_STATE_DESTROYING: + break; + default: + BUG(); + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + + return ret; +} + +static int process_event(struct iwcm_id_private *cm_id_priv, + struct iw_cm_event *iw_event) +{ + int ret = 0; + + switch (iw_event->event) { + case IW_CM_EVENT_CONNECT_REQUEST: + cm_conn_req_handler(cm_id_priv, iw_event); + break; + case IW_CM_EVENT_CONNECT_REPLY: + ret = cm_conn_rep_handler(cm_id_priv, iw_event); + break; + case IW_CM_EVENT_ESTABLISHED: + ret = cm_conn_est_handler(cm_id_priv, iw_event); + break; + case IW_CM_EVENT_DISCONNECT: + cm_disconnect_handler(cm_id_priv, iw_event); + break; + case IW_CM_EVENT_CLOSE: + ret = cm_close_handler(cm_id_priv, iw_event); + break; + default: + BUG(); + } + + return ret; +} + +/* + * Process events on the work_list for the cm_id. If the callback + * function requests that the cm_id be deleted, a flag is set in the + * cm_id flags to indicate that when the last reference is + * removed, the cm_id is to be destroyed. This is necessary to + * distinguish between an object that will be destroyed by the app + * thread asleep on the destroy_comp list vs. an object destroyed + * here synchronously when the last reference is removed. + */ +static void cm_work_handler(struct work_struct *_work) +{ + struct iwcm_work *work = container_of(_work, struct iwcm_work, work); + struct iw_cm_event levent; + struct iwcm_id_private *cm_id_priv = work->cm_id; + unsigned long flags; + int empty; + int ret = 0; + int destroy_id; + + spin_lock_irqsave(&cm_id_priv->lock, flags); + empty = list_empty(&cm_id_priv->work_list); + while (!empty) { + work = list_entry(cm_id_priv->work_list.next, + struct iwcm_work, list); + list_del_init(&work->list); + empty = list_empty(&cm_id_priv->work_list); + levent = work->event; + put_work(work); + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + + ret = process_event(cm_id_priv, &levent); + if (ret) { + set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags); + destroy_cm_id(&cm_id_priv->id); + } + BUG_ON(atomic_read(&cm_id_priv->refcount)==0); + destroy_id = test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags); + if (iwcm_deref_id(cm_id_priv)) { + if (destroy_id) { + BUG_ON(!list_empty(&cm_id_priv->work_list)); + free_cm_id(cm_id_priv); + } + return; + } + spin_lock_irqsave(&cm_id_priv->lock, flags); + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); +} + +/* + * This function is called on interrupt context. Schedule events on + * the iwcm_wq thread to allow callback functions to downcall into + * the CM and/or block. Events are queued to a per-CM_ID + * work_list. If this is the first event on the work_list, the work + * element is also queued on the iwcm_wq thread. + * + * Each event holds a reference on the cm_id. Until the last posted + * event has been delivered and processed, the cm_id cannot be + * deleted. + * + * Returns: + * 0 - the event was handled. + * -ENOMEM - the event was not handled due to lack of resources. + */ +static int cm_event_handler(struct iw_cm_id *cm_id, + struct iw_cm_event *iw_event) +{ + struct iwcm_work *work; + struct iwcm_id_private *cm_id_priv; + unsigned long flags; + int ret = 0; + + cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); + + spin_lock_irqsave(&cm_id_priv->lock, flags); + work = get_work(cm_id_priv); + if (!work) { + ret = -ENOMEM; + goto out; + } + + INIT_WORK(&work->work, cm_work_handler); + work->cm_id = cm_id_priv; + work->event = *iw_event; + + if ((work->event.event == IW_CM_EVENT_CONNECT_REQUEST || + work->event.event == IW_CM_EVENT_CONNECT_REPLY) && + work->event.private_data_len) { + ret = copy_private_data(&work->event); + if (ret) { + put_work(work); + goto out; + } + } + + atomic_inc(&cm_id_priv->refcount); + if (list_empty(&cm_id_priv->work_list)) { + list_add_tail(&work->list, &cm_id_priv->work_list); + queue_work(iwcm_wq, &work->work); + } else + list_add_tail(&work->list, &cm_id_priv->work_list); +out: + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return ret; +} + +static int iwcm_init_qp_init_attr(struct iwcm_id_private *cm_id_priv, + struct ib_qp_attr *qp_attr, + int *qp_attr_mask) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&cm_id_priv->lock, flags); + switch (cm_id_priv->state) { + case IW_CM_STATE_IDLE: + case IW_CM_STATE_CONN_SENT: + case IW_CM_STATE_CONN_RECV: + case IW_CM_STATE_ESTABLISHED: + *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; + qp_attr->qp_access_flags = IB_ACCESS_REMOTE_WRITE| + IB_ACCESS_REMOTE_READ; + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return ret; +} + +static int iwcm_init_qp_rts_attr(struct iwcm_id_private *cm_id_priv, + struct ib_qp_attr *qp_attr, + int *qp_attr_mask) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&cm_id_priv->lock, flags); + switch (cm_id_priv->state) { + case IW_CM_STATE_IDLE: + case IW_CM_STATE_CONN_SENT: + case IW_CM_STATE_CONN_RECV: + case IW_CM_STATE_ESTABLISHED: + *qp_attr_mask = 0; + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + spin_unlock_irqrestore(&cm_id_priv->lock, flags); + return ret; +} + +int iw_cm_init_qp_attr(struct iw_cm_id *cm_id, + struct ib_qp_attr *qp_attr, + int *qp_attr_mask) +{ + struct iwcm_id_private *cm_id_priv; + int ret; + + cm_id_priv = container_of(cm_id, struct iwcm_id_private, id); + switch (qp_attr->qp_state) { + case IB_QPS_INIT: + case IB_QPS_RTR: + ret = iwcm_init_qp_init_attr(cm_id_priv, + qp_attr, qp_attr_mask); + break; + case IB_QPS_RTS: + ret = iwcm_init_qp_rts_attr(cm_id_priv, + qp_attr, qp_attr_mask); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} +EXPORT_SYMBOL(iw_cm_init_qp_attr); + +static int __init iw_cm_init(void) +{ + iwcm_wq = create_singlethread_workqueue("iw_cm_wq"); + if (!iwcm_wq) + return -ENOMEM; + + return 0; +} + +static void __exit iw_cm_cleanup(void) +{ + destroy_workqueue(iwcm_wq); +} + +module_init(iw_cm_init); +module_exit(iw_cm_cleanup); diff --git a/sys/ofed/drivers/infiniband/core/iwcm.h b/sys/ofed/drivers/infiniband/core/iwcm.h new file mode 100644 index 000000000000..3f6cc82564c8 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/iwcm.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2005 Network Appliance, Inc. All rights reserved. + * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef IWCM_H +#define IWCM_H + +enum iw_cm_state { + IW_CM_STATE_IDLE, /* unbound, inactive */ + IW_CM_STATE_LISTEN, /* listen waiting for connect */ + IW_CM_STATE_CONN_RECV, /* inbound waiting for user accept */ + IW_CM_STATE_CONN_SENT, /* outbound waiting for peer accept */ + IW_CM_STATE_ESTABLISHED, /* established */ + IW_CM_STATE_CLOSING, /* disconnect */ + IW_CM_STATE_DESTROYING /* object being deleted */ +}; + +struct iwcm_id_private { + struct iw_cm_id id; + enum iw_cm_state state; + unsigned long flags; + struct ib_qp *qp; + struct completion destroy_comp; + wait_queue_head_t connect_wait; + struct list_head work_list; + spinlock_t lock; + atomic_t refcount; + struct list_head work_free_list; +}; + +#define IWCM_F_CALLBACK_DESTROY 1 +#define IWCM_F_CONNECT_WAIT 2 + +#endif /* IWCM_H */ diff --git a/sys/ofed/drivers/infiniband/core/local_sa.c b/sys/ofed/drivers/infiniband/core/local_sa.c new file mode 100644 index 000000000000..eb62c429528e --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/local_sa.c @@ -0,0 +1,1273 @@ +/* + * Copyright (c) 2006 Intel Corporation.  All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "sa.h" + +MODULE_AUTHOR("Sean Hefty"); +MODULE_DESCRIPTION("InfiniBand subnet administration caching"); +MODULE_LICENSE("Dual BSD/GPL"); + +enum { + SA_DB_MAX_PATHS_PER_DEST = 0x7F, + SA_DB_MIN_RETRY_TIMER = 4000, /* 4 sec */ + SA_DB_MAX_RETRY_TIMER = 256000 /* 256 sec */ +}; + +static int set_paths_per_dest(const char *val, struct kernel_param *kp); +static unsigned long paths_per_dest = 0; +module_param_call(paths_per_dest, set_paths_per_dest, param_get_ulong, + &paths_per_dest, 0644); +MODULE_PARM_DESC(paths_per_dest, "Maximum number of paths to retrieve " + "to each destination (DGID). Set to 0 " + "to disable cache."); + +static int set_subscribe_inform_info(const char *val, struct kernel_param *kp); +static char subscribe_inform_info = 1; +module_param_call(subscribe_inform_info, set_subscribe_inform_info, + param_get_bool, &subscribe_inform_info, 0644); +MODULE_PARM_DESC(subscribe_inform_info, + "Subscribe for SA InformInfo/Notice events."); + +static int do_refresh(const char *val, struct kernel_param *kp); +module_param_call(refresh, do_refresh, NULL, NULL, 0200); + +static unsigned long retry_timer = SA_DB_MIN_RETRY_TIMER; + +enum sa_db_lookup_method { + SA_DB_LOOKUP_LEAST_USED, + SA_DB_LOOKUP_RANDOM +}; + +static int set_lookup_method(const char *val, struct kernel_param *kp); +static int get_lookup_method(char *buf, struct kernel_param *kp); +static unsigned long lookup_method; +module_param_call(lookup_method, set_lookup_method, get_lookup_method, + &lookup_method, 0644); +MODULE_PARM_DESC(lookup_method, "Method used to return path records when " + "multiple paths exist to a given destination."); + +static void sa_db_add_dev(struct ib_device *device); +static void sa_db_remove_dev(struct ib_device *device); + +static struct ib_client sa_db_client = { + .name = "local_sa", + .add = sa_db_add_dev, + .remove = sa_db_remove_dev +}; + +static LIST_HEAD(dev_list); +static DEFINE_MUTEX(lock); +static rwlock_t rwlock; +static struct workqueue_struct *sa_wq; +static struct ib_sa_client sa_client; + +enum sa_db_state { + SA_DB_IDLE, + SA_DB_REFRESH, + SA_DB_DESTROY +}; + +struct sa_db_port { + struct sa_db_device *dev; + struct ib_mad_agent *agent; + /* Limit number of outstanding MADs to SA to reduce SA flooding */ + struct ib_mad_send_buf *msg; + u16 sm_lid; + u8 sm_sl; + struct ib_inform_info *in_info; + struct ib_inform_info *out_info; + struct rb_root paths; + struct list_head update_list; + unsigned long update_id; + enum sa_db_state state; + struct work_struct work; + union ib_gid gid; + int port_num; +}; + +struct sa_db_device { + struct list_head list; + struct ib_device *device; + struct ib_event_handler event_handler; + int start_port; + int port_count; + struct sa_db_port port[0]; +}; + +struct ib_sa_iterator { + struct ib_sa_iterator *next; +}; + +struct ib_sa_attr_iter { + struct ib_sa_iterator *iter; + unsigned long flags; +}; + +struct ib_sa_attr_list { + struct ib_sa_iterator iter; + struct ib_sa_iterator *tail; + int update_id; + union ib_gid gid; + struct rb_node node; +}; + +struct ib_path_rec_info { + struct ib_sa_iterator iter; /* keep first */ + struct ib_sa_path_rec rec; + unsigned long lookups; +}; + +struct ib_sa_mad_iter { + struct ib_mad_recv_wc *recv_wc; + struct ib_mad_recv_buf *recv_buf; + int attr_size; + int attr_offset; + int data_offset; + int data_left; + void *attr; + u8 attr_data[0]; +}; + +enum sa_update_type { + SA_UPDATE_FULL, + SA_UPDATE_ADD, + SA_UPDATE_REMOVE +}; + +struct update_info { + struct list_head list; + union ib_gid gid; + enum sa_update_type type; +}; + +struct sa_path_request { + struct work_struct work; + struct ib_sa_client *client; + void (*callback)(int, struct ib_sa_path_rec *, void *); + void *context; + struct ib_sa_path_rec path_rec; +}; + +static void process_updates(struct sa_db_port *port); + +static void free_attr_list(struct ib_sa_attr_list *attr_list) +{ + struct ib_sa_iterator *cur; + + for (cur = attr_list->iter.next; cur; cur = attr_list->iter.next) { + attr_list->iter.next = cur->next; + kfree(cur); + } + attr_list->tail = &attr_list->iter; +} + +static void remove_attr(struct rb_root *root, struct ib_sa_attr_list *attr_list) +{ + rb_erase(&attr_list->node, root); + free_attr_list(attr_list); + kfree(attr_list); +} + +static void remove_all_attrs(struct rb_root *root) +{ + struct rb_node *node, *next_node; + struct ib_sa_attr_list *attr_list; + + write_lock_irq(&rwlock); + for (node = rb_first(root); node; node = next_node) { + next_node = rb_next(node); + attr_list = rb_entry(node, struct ib_sa_attr_list, node); + remove_attr(root, attr_list); + } + write_unlock_irq(&rwlock); +} + +static void remove_old_attrs(struct rb_root *root, unsigned long update_id) +{ + struct rb_node *node, *next_node; + struct ib_sa_attr_list *attr_list; + + write_lock_irq(&rwlock); + for (node = rb_first(root); node; node = next_node) { + next_node = rb_next(node); + attr_list = rb_entry(node, struct ib_sa_attr_list, node); + if (attr_list->update_id != update_id) + remove_attr(root, attr_list); + } + write_unlock_irq(&rwlock); +} + +static struct ib_sa_attr_list *insert_attr_list(struct rb_root *root, + struct ib_sa_attr_list *attr_list) +{ + struct rb_node **link = &root->rb_node; + struct rb_node *parent = NULL; + struct ib_sa_attr_list *cur_attr_list; + int cmp; + + while (*link) { + parent = *link; + cur_attr_list = rb_entry(parent, struct ib_sa_attr_list, node); + cmp = memcmp(&cur_attr_list->gid, &attr_list->gid, + sizeof attr_list->gid); + if (cmp < 0) + link = &(*link)->rb_left; + else if (cmp > 0) + link = &(*link)->rb_right; + else + return cur_attr_list; + } + rb_link_node(&attr_list->node, parent, link); + rb_insert_color(&attr_list->node, root); + return NULL; +} + +static struct ib_sa_attr_list *find_attr_list(struct rb_root *root, u8 *gid) +{ + struct rb_node *node = root->rb_node; + struct ib_sa_attr_list *attr_list; + int cmp; + + while (node) { + attr_list = rb_entry(node, struct ib_sa_attr_list, node); + cmp = memcmp(&attr_list->gid, gid, sizeof attr_list->gid); + if (cmp < 0) + node = node->rb_left; + else if (cmp > 0) + node = node->rb_right; + else + return attr_list; + } + return NULL; +} + +static int insert_attr(struct rb_root *root, unsigned long update_id, void *key, + struct ib_sa_iterator *iter) +{ + struct ib_sa_attr_list *attr_list; + void *err; + + write_lock_irq(&rwlock); + attr_list = find_attr_list(root, key); + if (!attr_list) { + write_unlock_irq(&rwlock); + attr_list = kmalloc(sizeof *attr_list, GFP_KERNEL); + if (!attr_list) + return -ENOMEM; + + attr_list->iter.next = NULL; + attr_list->tail = &attr_list->iter; + attr_list->update_id = update_id; + memcpy(attr_list->gid.raw, key, sizeof attr_list->gid); + + write_lock_irq(&rwlock); + err = insert_attr_list(root, attr_list); + if (err) { + write_unlock_irq(&rwlock); + kfree(attr_list); + return PTR_ERR(err); + } + } else if (attr_list->update_id != update_id) { + free_attr_list(attr_list); + attr_list->update_id = update_id; + } + + attr_list->tail->next = iter; + iter->next = NULL; + attr_list->tail = iter; + write_unlock_irq(&rwlock); + return 0; +} + +static struct ib_sa_mad_iter *ib_sa_iter_create(struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_sa_mad_iter *iter; + struct ib_sa_mad *mad = (struct ib_sa_mad *) mad_recv_wc->recv_buf.mad; + int attr_size, attr_offset; + + attr_offset = be16_to_cpu(mad->sa_hdr.attr_offset) * 8; + attr_size = 64; /* path record length */ + if (attr_offset < attr_size) + return ERR_PTR(-EINVAL); + + iter = kzalloc(sizeof *iter + attr_size, GFP_KERNEL); + if (!iter) + return ERR_PTR(-ENOMEM); + + iter->data_left = mad_recv_wc->mad_len - IB_MGMT_SA_HDR; + iter->recv_wc = mad_recv_wc; + iter->recv_buf = &mad_recv_wc->recv_buf; + iter->attr_offset = attr_offset; + iter->attr_size = attr_size; + return iter; +} + +static void ib_sa_iter_free(struct ib_sa_mad_iter *iter) +{ + kfree(iter); +} + +static void *ib_sa_iter_next(struct ib_sa_mad_iter *iter) +{ + struct ib_sa_mad *mad; + int left, offset = 0; + + while (iter->data_left >= iter->attr_offset) { + while (iter->data_offset < IB_MGMT_SA_DATA) { + mad = (struct ib_sa_mad *) iter->recv_buf->mad; + + left = IB_MGMT_SA_DATA - iter->data_offset; + if (left < iter->attr_size) { + /* copy first piece of the attribute */ + iter->attr = &iter->attr_data; + memcpy(iter->attr, + &mad->data[iter->data_offset], left); + offset = left; + break; + } else if (offset) { + /* copy the second piece of the attribute */ + memcpy(iter->attr + offset, &mad->data[0], + iter->attr_size - offset); + iter->data_offset = iter->attr_size - offset; + offset = 0; + } else { + iter->attr = &mad->data[iter->data_offset]; + iter->data_offset += iter->attr_size; + } + + iter->data_left -= iter->attr_offset; + goto out; + } + iter->data_offset = 0; + iter->recv_buf = list_entry(iter->recv_buf->list.next, + struct ib_mad_recv_buf, list); + } + iter->attr = NULL; +out: + return iter->attr; +} + +/* + * Copy path records from a received response and insert them into our cache. + * A path record in the MADs are in network order, packed, and may + * span multiple MAD buffers, just to make our life hard. + */ +static void update_path_db(struct sa_db_port *port, + struct ib_mad_recv_wc *mad_recv_wc, + enum sa_update_type type) +{ + struct ib_sa_mad_iter *iter; + struct ib_path_rec_info *path_info; + void *attr; + int ret; + + iter = ib_sa_iter_create(mad_recv_wc); + if (IS_ERR(iter)) + return; + + port->update_id += (type == SA_UPDATE_FULL); + + while ((attr = ib_sa_iter_next(iter)) && + (path_info = kmalloc(sizeof *path_info, GFP_KERNEL))) { + + ib_sa_unpack_attr(&path_info->rec, attr, IB_SA_ATTR_PATH_REC); + + ret = insert_attr(&port->paths, port->update_id, + path_info->rec.dgid.raw, &path_info->iter); + if (ret) { + kfree(path_info); + break; + } + } + ib_sa_iter_free(iter); + + if (type == SA_UPDATE_FULL) + remove_old_attrs(&port->paths, port->update_id); +} + +static struct ib_mad_send_buf *get_sa_msg(struct sa_db_port *port, + struct update_info *update) +{ + struct ib_ah_attr ah_attr; + struct ib_mad_send_buf *msg; + + msg = ib_create_send_mad(port->agent, 1, 0, 0, IB_MGMT_SA_HDR, + IB_MGMT_SA_DATA, GFP_KERNEL); + if (IS_ERR(msg)) + return NULL; + + memset(&ah_attr, 0, sizeof ah_attr); + ah_attr.dlid = port->sm_lid; + ah_attr.sl = port->sm_sl; + ah_attr.port_num = port->port_num; + + msg->ah = ib_create_ah(port->agent->qp->pd, &ah_attr); + if (IS_ERR(msg->ah)) { + ib_free_send_mad(msg); + return NULL; + } + + msg->timeout_ms = retry_timer; + msg->retries = 0; + msg->context[0] = port; + msg->context[1] = update; + return msg; +} + +static __be64 form_tid(u32 hi_tid) +{ + static atomic_t tid; + return cpu_to_be64((((u64) hi_tid) << 32) | + ((u32) atomic_inc_return(&tid))); +} + +static void format_path_req(struct sa_db_port *port, + struct update_info *update, + struct ib_mad_send_buf *msg) +{ + struct ib_sa_mad *mad = msg->mad; + struct ib_sa_path_rec path_rec; + + mad->mad_hdr.base_version = IB_MGMT_BASE_VERSION; + mad->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM; + mad->mad_hdr.class_version = IB_SA_CLASS_VERSION; + mad->mad_hdr.method = IB_SA_METHOD_GET_TABLE; + mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_PATH_REC); + mad->mad_hdr.tid = form_tid(msg->mad_agent->hi_tid); + + mad->sa_hdr.comp_mask = IB_SA_PATH_REC_SGID | IB_SA_PATH_REC_NUMB_PATH; + + path_rec.sgid = port->gid; + path_rec.numb_path = (u8) paths_per_dest; + + if (update->type == SA_UPDATE_ADD) { + mad->sa_hdr.comp_mask |= IB_SA_PATH_REC_DGID; + memcpy(&path_rec.dgid, &update->gid, sizeof path_rec.dgid); + } + + ib_sa_pack_attr(mad->data, &path_rec, IB_SA_ATTR_PATH_REC); +} + +static int send_query(struct sa_db_port *port, + struct update_info *update) +{ + int ret; + + port->msg = get_sa_msg(port, update); + if (!port->msg) + return -ENOMEM; + + format_path_req(port, update, port->msg); + + ret = ib_post_send_mad(port->msg, NULL); + if (ret) + goto err; + + return 0; + +err: + ib_destroy_ah(port->msg->ah); + ib_free_send_mad(port->msg); + return ret; +} + +static void add_update(struct sa_db_port *port, u8 *gid, + enum sa_update_type type) +{ + struct update_info *update; + + update = kmalloc(sizeof *update, GFP_KERNEL); + if (update) { + if (gid) + memcpy(&update->gid, gid, sizeof update->gid); + update->type = type; + list_add(&update->list, &port->update_list); + } + + if (port->state == SA_DB_IDLE) { + port->state = SA_DB_REFRESH; + process_updates(port); + } +} + +static void clean_update_list(struct sa_db_port *port) +{ + struct update_info *update; + + while (!list_empty(&port->update_list)) { + update = list_entry(port->update_list.next, + struct update_info, list); + list_del(&update->list); + kfree(update); + } +} + +static int notice_handler(int status, struct ib_inform_info *info, + struct ib_sa_notice *notice) +{ + struct sa_db_port *port = info->context; + struct ib_sa_notice_data_gid *gid_data; + struct ib_inform_info **pinfo; + enum sa_update_type type; + + if (info->trap_number == IB_SA_SM_TRAP_GID_IN_SERVICE) { + pinfo = &port->in_info; + type = SA_UPDATE_ADD; + } else { + pinfo = &port->out_info; + type = SA_UPDATE_REMOVE; + } + + mutex_lock(&lock); + if (port->state == SA_DB_DESTROY || !*pinfo) { + mutex_unlock(&lock); + return 0; + } + + if (notice) { + gid_data = (struct ib_sa_notice_data_gid *) + ¬ice->data_details; + add_update(port, gid_data->gid, type); + mutex_unlock(&lock); + } else if (status == -ENETRESET) { + *pinfo = NULL; + mutex_unlock(&lock); + } else { + if (status) + *pinfo = ERR_PTR(-EINVAL); + port->state = SA_DB_IDLE; + clean_update_list(port); + mutex_unlock(&lock); + queue_work(sa_wq, &port->work); + } + + return status; +} + +static int reg_in_info(struct sa_db_port *port) +{ + int ret = 0; + + port->in_info = ib_sa_register_inform_info(&sa_client, + port->dev->device, + port->port_num, + IB_SA_SM_TRAP_GID_IN_SERVICE, + GFP_KERNEL, notice_handler, + port); + if (IS_ERR(port->in_info)) + ret = PTR_ERR(port->in_info); + + return ret; +} + +static int reg_out_info(struct sa_db_port *port) +{ + int ret = 0; + + port->out_info = ib_sa_register_inform_info(&sa_client, + port->dev->device, + port->port_num, + IB_SA_SM_TRAP_GID_OUT_OF_SERVICE, + GFP_KERNEL, notice_handler, + port); + if (IS_ERR(port->out_info)) + ret = PTR_ERR(port->out_info); + + return ret; +} + +static void unsubscribe_port(struct sa_db_port *port) +{ + if (port->in_info && !IS_ERR(port->in_info)) + ib_sa_unregister_inform_info(port->in_info); + + if (port->out_info && !IS_ERR(port->out_info)) + ib_sa_unregister_inform_info(port->out_info); + + port->out_info = NULL; + port->in_info = NULL; + +} + +static void cleanup_port(struct sa_db_port *port) +{ + unsubscribe_port(port); + + clean_update_list(port); + remove_all_attrs(&port->paths); +} + +static int update_port_info(struct sa_db_port *port) +{ + struct ib_port_attr port_attr; + int ret; + + ret = ib_query_port(port->dev->device, port->port_num, &port_attr); + if (ret) + return ret; + + if (port_attr.state != IB_PORT_ACTIVE) + return -ENODATA; + + port->sm_lid = port_attr.sm_lid; + port->sm_sl = port_attr.sm_sl; + return 0; +} + +static void process_updates(struct sa_db_port *port) +{ + struct update_info *update; + struct ib_sa_attr_list *attr_list; + int ret; + + if (!paths_per_dest || update_port_info(port)) { + cleanup_port(port); + goto out; + } + + /* Event registration is an optimization, so ignore failures. */ + if (subscribe_inform_info) { + if (!port->out_info) { + ret = reg_out_info(port); + if (!ret) + return; + } + + if (!port->in_info) { + ret = reg_in_info(port); + if (!ret) + return; + } + } else + unsubscribe_port(port); + + while (!list_empty(&port->update_list)) { + update = list_entry(port->update_list.next, + struct update_info, list); + + if (update->type == SA_UPDATE_REMOVE) { + write_lock_irq(&rwlock); + attr_list = find_attr_list(&port->paths, + update->gid.raw); + if (attr_list) + remove_attr(&port->paths, attr_list); + write_unlock_irq(&rwlock); + } else { + ret = send_query(port, update); + if (!ret) + return; + + } + list_del(&update->list); + kfree(update); + } +out: + port->state = SA_DB_IDLE; +} + +static void refresh_port_db(struct sa_db_port *port) +{ + if (port->state == SA_DB_DESTROY) + return; + + if (port->state == SA_DB_REFRESH) { + clean_update_list(port); + ib_cancel_mad(port->agent, port->msg); + } + + add_update(port, NULL, SA_UPDATE_FULL); +} + +static void refresh_dev_db(struct sa_db_device *dev) +{ + int i; + + for (i = 0; i < dev->port_count; i++) + refresh_port_db(&dev->port[i]); +} + +static void refresh_db(void) +{ + struct sa_db_device *dev; + + list_for_each_entry(dev, &dev_list, list) + refresh_dev_db(dev); +} + +static int do_refresh(const char *val, struct kernel_param *kp) +{ + mutex_lock(&lock); + refresh_db(); + mutex_unlock(&lock); + return 0; +} + +static int get_lookup_method(char *buf, struct kernel_param *kp) +{ + return sprintf(buf, + "%c %d round robin\n" + "%c %d random", + (lookup_method == SA_DB_LOOKUP_LEAST_USED) ? '*' : ' ', + SA_DB_LOOKUP_LEAST_USED, + (lookup_method == SA_DB_LOOKUP_RANDOM) ? '*' : ' ', + SA_DB_LOOKUP_RANDOM); +} + +static int set_lookup_method(const char *val, struct kernel_param *kp) +{ + unsigned long method; + int ret = 0; + + method = simple_strtoul(val, NULL, 0); + + switch (method) { + case SA_DB_LOOKUP_LEAST_USED: + case SA_DB_LOOKUP_RANDOM: + lookup_method = method; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int set_paths_per_dest(const char *val, struct kernel_param *kp) +{ + int ret; + + mutex_lock(&lock); + ret = param_set_ulong(val, kp); + if (ret) + goto out; + + if (paths_per_dest > SA_DB_MAX_PATHS_PER_DEST) + paths_per_dest = SA_DB_MAX_PATHS_PER_DEST; + refresh_db(); +out: + mutex_unlock(&lock); + return ret; +} + +static int set_subscribe_inform_info(const char *val, struct kernel_param *kp) +{ + int ret; + + ret = param_set_bool(val, kp); + if (ret) + return ret; + + return do_refresh(val, kp); +} + +static void port_work_handler(struct work_struct *work) +{ + struct sa_db_port *port; + + port = container_of(work, typeof(*port), work); + mutex_lock(&lock); + refresh_port_db(port); + mutex_unlock(&lock); +} + +static void handle_event(struct ib_event_handler *event_handler, + struct ib_event *event) +{ + struct sa_db_device *dev; + struct sa_db_port *port; + + dev = container_of(event_handler, typeof(*dev), event_handler); + port = &dev->port[event->element.port_num - dev->start_port]; + + switch (event->event) { + case IB_EVENT_PORT_ERR: + case IB_EVENT_LID_CHANGE: + case IB_EVENT_SM_CHANGE: + case IB_EVENT_CLIENT_REREGISTER: + case IB_EVENT_PKEY_CHANGE: + case IB_EVENT_PORT_ACTIVE: + queue_work(sa_wq, &port->work); + break; + default: + break; + } +} + +static void ib_free_path_iter(struct ib_sa_attr_iter *iter) +{ + read_unlock_irqrestore(&rwlock, iter->flags); +} + +static int ib_create_path_iter(struct ib_device *device, u8 port_num, + union ib_gid *dgid, struct ib_sa_attr_iter *iter) +{ + struct sa_db_device *dev; + struct sa_db_port *port; + struct ib_sa_attr_list *list; + + dev = ib_get_client_data(device, &sa_db_client); + if (!dev) + return -ENODEV; + + port = &dev->port[port_num - dev->start_port]; + + read_lock_irqsave(&rwlock, iter->flags); + list = find_attr_list(&port->paths, dgid->raw); + if (!list) { + ib_free_path_iter(iter); + return -ENODATA; + } + + iter->iter = &list->iter; + return 0; +} + +static struct ib_sa_path_rec *ib_get_next_path(struct ib_sa_attr_iter *iter) +{ + struct ib_path_rec_info *next_path; + + iter->iter = iter->iter->next; + if (iter->iter) { + next_path = container_of(iter->iter, struct ib_path_rec_info, iter); + return &next_path->rec; + } else + return NULL; +} + +static int cmp_rec(struct ib_sa_path_rec *src, + struct ib_sa_path_rec *dst, ib_sa_comp_mask comp_mask) +{ + /* DGID check already done */ + if (comp_mask & IB_SA_PATH_REC_SGID && + memcmp(&src->sgid, &dst->sgid, sizeof src->sgid)) + return -EINVAL; + if (comp_mask & IB_SA_PATH_REC_DLID && src->dlid != dst->dlid) + return -EINVAL; + if (comp_mask & IB_SA_PATH_REC_SLID && src->slid != dst->slid) + return -EINVAL; + if (comp_mask & IB_SA_PATH_REC_RAW_TRAFFIC && + src->raw_traffic != dst->raw_traffic) + return -EINVAL; + + if (comp_mask & IB_SA_PATH_REC_FLOW_LABEL && + src->flow_label != dst->flow_label) + return -EINVAL; + if (comp_mask & IB_SA_PATH_REC_HOP_LIMIT && + src->hop_limit != dst->hop_limit) + return -EINVAL; + if (comp_mask & IB_SA_PATH_REC_TRAFFIC_CLASS && + src->traffic_class != dst->traffic_class) + return -EINVAL; + if (comp_mask & IB_SA_PATH_REC_REVERSIBLE && + dst->reversible && !src->reversible) + return -EINVAL; + /* Numb path check already done */ + if (comp_mask & IB_SA_PATH_REC_PKEY && src->pkey != dst->pkey) + return -EINVAL; + + if (comp_mask & IB_SA_PATH_REC_SL && src->sl != dst->sl) + return -EINVAL; + + if (ib_sa_check_selector(comp_mask, IB_SA_PATH_REC_MTU_SELECTOR, + IB_SA_PATH_REC_MTU, dst->mtu_selector, + src->mtu, dst->mtu)) + return -EINVAL; + if (ib_sa_check_selector(comp_mask, IB_SA_PATH_REC_RATE_SELECTOR, + IB_SA_PATH_REC_RATE, dst->rate_selector, + src->rate, dst->rate)) + return -EINVAL; + if (ib_sa_check_selector(comp_mask, + IB_SA_PATH_REC_PACKET_LIFE_TIME_SELECTOR, + IB_SA_PATH_REC_PACKET_LIFE_TIME, + dst->packet_life_time_selector, + src->packet_life_time, dst->packet_life_time)) + return -EINVAL; + + return 0; +} + +static struct ib_sa_path_rec *get_random_path(struct ib_sa_attr_iter *iter, + struct ib_sa_path_rec *req_path, + ib_sa_comp_mask comp_mask) +{ + struct ib_sa_path_rec *path, *rand_path = NULL; + int num, count = 0; + + for (path = ib_get_next_path(iter); path; + path = ib_get_next_path(iter)) { + if (!cmp_rec(path, req_path, comp_mask)) { + get_random_bytes(&num, sizeof num); + if ((num % ++count) == 0) + rand_path = path; + } + } + + return rand_path; +} + +static struct ib_sa_path_rec *get_next_path(struct ib_sa_attr_iter *iter, + struct ib_sa_path_rec *req_path, + ib_sa_comp_mask comp_mask) +{ + struct ib_path_rec_info *cur_path, *next_path = NULL; + struct ib_sa_path_rec *path; + unsigned long lookups = ~0; + + for (path = ib_get_next_path(iter); path; + path = ib_get_next_path(iter)) { + if (!cmp_rec(path, req_path, comp_mask)) { + + cur_path = container_of(iter->iter, struct ib_path_rec_info, + iter); + if (cur_path->lookups < lookups) { + lookups = cur_path->lookups; + next_path = cur_path; + } + } + } + + if (next_path) { + next_path->lookups++; + return &next_path->rec; + } else + return NULL; +} + +static void report_path(struct work_struct *work) +{ + struct sa_path_request *req; + + req = container_of(work, struct sa_path_request, work); + req->callback(0, &req->path_rec, req->context); + ib_sa_client_put(req->client); + kfree(req); +} + +/** + * ib_sa_path_rec_get - Start a Path get query + * @client:SA client + * @device:device to send query on + * @port_num: port number to send query on + * @rec:Path Record to send in query + * @comp_mask:component mask to send in query + * @timeout_ms:time to wait for response + * @gfp_mask:GFP mask to use for internal allocations + * @callback:function called when query completes, times out or is + * canceled + * @context:opaque user context passed to callback + * @sa_query:query context, used to cancel query + * + * Send a Path Record Get query to the SA to look up a path. The + * callback function will be called when the query completes (or + * fails); status is 0 for a successful response, -EINTR if the query + * is canceled, -ETIMEDOUT is the query timed out, or -EIO if an error + * occurred sending the query. The resp parameter of the callback is + * only valid if status is 0. + * + * If the return value of ib_sa_path_rec_get() is negative, it is an + * error code. Otherwise it is a query ID that can be used to cancel + * the query. + */ +int ib_sa_path_rec_get(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + struct ib_sa_path_rec *rec, + ib_sa_comp_mask comp_mask, + int timeout_ms, gfp_t gfp_mask, + void (*callback)(int status, + struct ib_sa_path_rec *resp, + void *context), + void *context, + struct ib_sa_query **sa_query) +{ + struct sa_path_request *req; + struct ib_sa_attr_iter iter; + struct ib_sa_path_rec *path_rec; + int ret; + + if (!paths_per_dest) + goto query_sa; + + if (!(comp_mask & IB_SA_PATH_REC_DGID) || + !(comp_mask & IB_SA_PATH_REC_NUMB_PATH) || rec->numb_path != 1) + goto query_sa; + + req = kmalloc(sizeof *req, gfp_mask); + if (!req) + goto query_sa; + + ret = ib_create_path_iter(device, port_num, &rec->dgid, &iter); + if (ret) + goto free_req; + + if (lookup_method == SA_DB_LOOKUP_RANDOM) + path_rec = get_random_path(&iter, rec, comp_mask); + else + path_rec = get_next_path(&iter, rec, comp_mask); + + if (!path_rec) + goto free_iter; + + memcpy(&req->path_rec, path_rec, sizeof *path_rec); + ib_free_path_iter(&iter); + + INIT_WORK(&req->work, report_path); + req->client = client; + req->callback = callback; + req->context = context; + + ib_sa_client_get(client); + queue_work(sa_wq, &req->work); + *sa_query = ERR_PTR(-EEXIST); + return 0; + +free_iter: + ib_free_path_iter(&iter); +free_req: + kfree(req); +query_sa: + return ib_sa_path_rec_query(client, device, port_num, rec, comp_mask, + timeout_ms, gfp_mask, callback, context, + sa_query); +} +EXPORT_SYMBOL(ib_sa_path_rec_get); + +static void recv_handler(struct ib_mad_agent *mad_agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct sa_db_port *port; + struct update_info *update; + struct ib_mad_send_buf *msg; + enum sa_update_type type; + + msg = (struct ib_mad_send_buf *) (unsigned long) mad_recv_wc->wc->wr_id; + port = msg->context[0]; + update = msg->context[1]; + + mutex_lock(&lock); + if (port->state == SA_DB_DESTROY || + update != list_entry(port->update_list.next, + struct update_info, list)) { + mutex_unlock(&lock); + } else { + type = update->type; + mutex_unlock(&lock); + update_path_db(mad_agent->context, mad_recv_wc, type); + } + + ib_free_recv_mad(mad_recv_wc); +} + +static void send_handler(struct ib_mad_agent *agent, + struct ib_mad_send_wc *mad_send_wc) +{ + struct ib_mad_send_buf *msg; + struct sa_db_port *port; + struct update_info *update; + int ret; + + msg = mad_send_wc->send_buf; + port = msg->context[0]; + update = msg->context[1]; + + mutex_lock(&lock); + if (port->state == SA_DB_DESTROY) + goto unlock; + + if (update == list_entry(port->update_list.next, + struct update_info, list)) { + + if (mad_send_wc->status == IB_WC_RESP_TIMEOUT_ERR && + msg->timeout_ms < SA_DB_MAX_RETRY_TIMER) { + + msg->timeout_ms <<= 1; + ret = ib_post_send_mad(msg, NULL); + if (!ret) { + mutex_unlock(&lock); + return; + } + } + list_del(&update->list); + kfree(update); + } + process_updates(port); +unlock: + mutex_unlock(&lock); + + ib_destroy_ah(msg->ah); + ib_free_send_mad(msg); +} + +static int init_port(struct sa_db_device *dev, int port_num) +{ + struct sa_db_port *port; + int ret; + + port = &dev->port[port_num - dev->start_port]; + port->dev = dev; + port->port_num = port_num; + INIT_WORK(&port->work, port_work_handler); + port->paths = RB_ROOT; + INIT_LIST_HEAD(&port->update_list); + + ret = ib_get_cached_gid(dev->device, port_num, 0, &port->gid); + if (ret) + return ret; + + port->agent = ib_register_mad_agent(dev->device, port_num, IB_QPT_GSI, + NULL, IB_MGMT_RMPP_VERSION, + send_handler, recv_handler, port); + if (IS_ERR(port->agent)) + ret = PTR_ERR(port->agent); + + return ret; +} + +static void destroy_port(struct sa_db_port *port) +{ + mutex_lock(&lock); + port->state = SA_DB_DESTROY; + mutex_unlock(&lock); + + ib_unregister_mad_agent(port->agent); + cleanup_port(port); + flush_workqueue(sa_wq); +} + +static void sa_db_add_dev(struct ib_device *device) +{ + struct sa_db_device *dev; + struct sa_db_port *port; + int s, e, i, ret; + + if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) + return; + + if (device->node_type == RDMA_NODE_IB_SWITCH) { + s = e = 0; + } else { + s = 1; + e = device->phys_port_cnt; + } + + dev = kzalloc(sizeof *dev + (e - s + 1) * sizeof *port, GFP_KERNEL); + if (!dev) + return; + + dev->start_port = s; + dev->port_count = e - s + 1; + dev->device = device; + for (i = 0; i < dev->port_count; i++) { + ret = init_port(dev, s + i); + if (ret) + goto err; + } + + ib_set_client_data(device, &sa_db_client, dev); + + INIT_IB_EVENT_HANDLER(&dev->event_handler, device, handle_event); + + mutex_lock(&lock); + list_add_tail(&dev->list, &dev_list); + refresh_dev_db(dev); + mutex_unlock(&lock); + + ib_register_event_handler(&dev->event_handler); + return; +err: + while (i--) + destroy_port(&dev->port[i]); + kfree(dev); +} + +static void sa_db_remove_dev(struct ib_device *device) +{ + struct sa_db_device *dev; + int i; + + dev = ib_get_client_data(device, &sa_db_client); + if (!dev) + return; + + ib_unregister_event_handler(&dev->event_handler); + flush_workqueue(sa_wq); + + for (i = 0; i < dev->port_count; i++) + destroy_port(&dev->port[i]); + + mutex_lock(&lock); + list_del(&dev->list); + mutex_unlock(&lock); + + kfree(dev); +} + +int sa_db_init(void) +{ + int ret; + + rwlock_init(&rwlock); + sa_wq = create_singlethread_workqueue("local_sa"); + if (!sa_wq) + return -ENOMEM; + + ib_sa_register_client(&sa_client); + ret = ib_register_client(&sa_db_client); + if (ret) + goto err; + + return 0; + +err: + ib_sa_unregister_client(&sa_client); + destroy_workqueue(sa_wq); + return ret; +} + +void sa_db_cleanup(void) +{ + ib_unregister_client(&sa_db_client); + ib_sa_unregister_client(&sa_client); + destroy_workqueue(sa_wq); +} diff --git a/sys/ofed/drivers/infiniband/core/mad.c b/sys/ofed/drivers/infiniband/core/mad.c new file mode 100644 index 000000000000..64e660c38e4f --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/mad.c @@ -0,0 +1,3057 @@ +/* + * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#include +#include + +#include "mad_priv.h" +#include "mad_rmpp.h" +#include "smi.h" +#include "agent.h" + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("kernel IB MAD API"); +MODULE_AUTHOR("Hal Rosenstock"); +MODULE_AUTHOR("Sean Hefty"); + +int mad_sendq_size = IB_MAD_QP_SEND_SIZE; +int mad_recvq_size = IB_MAD_QP_RECV_SIZE; + +module_param_named(send_queue_size, mad_sendq_size, int, 0444); +MODULE_PARM_DESC(send_queue_size, "Size of send queue in number of work requests"); +module_param_named(recv_queue_size, mad_recvq_size, int, 0444); +MODULE_PARM_DESC(recv_queue_size, "Size of receive queue in number of work requests"); + +static struct kmem_cache *ib_mad_cache; + +static struct list_head ib_mad_port_list; +static u32 ib_mad_client_id = 0; + +/* Port list lock */ +static spinlock_t ib_mad_port_list_lock; + + +/* Forward declarations */ +static int method_in_use(struct ib_mad_mgmt_method_table **method, + struct ib_mad_reg_req *mad_reg_req); +static void remove_mad_reg_req(struct ib_mad_agent_private *priv); +static struct ib_mad_agent_private *find_mad_agent( + struct ib_mad_port_private *port_priv, + struct ib_mad *mad); +static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info, + struct ib_mad_private *mad); +static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv); +static void timeout_sends(struct work_struct *work); +static void local_completions(struct work_struct *work); +static int add_nonoui_reg_req(struct ib_mad_reg_req *mad_reg_req, + struct ib_mad_agent_private *agent_priv, + u8 mgmt_class); +static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req, + struct ib_mad_agent_private *agent_priv); + +/* + * Returns a ib_mad_port_private structure or NULL for a device/port + * Assumes ib_mad_port_list_lock is being held + */ +static inline struct ib_mad_port_private * +__ib_get_mad_port(struct ib_device *device, int port_num) +{ + struct ib_mad_port_private *entry; + + list_for_each_entry(entry, &ib_mad_port_list, port_list) { + if (entry->device == device && entry->port_num == port_num) + return entry; + } + return NULL; +} + +/* + * Wrapper function to return a ib_mad_port_private structure or NULL + * for a device/port + */ +static inline struct ib_mad_port_private * +ib_get_mad_port(struct ib_device *device, int port_num) +{ + struct ib_mad_port_private *entry; + unsigned long flags; + + spin_lock_irqsave(&ib_mad_port_list_lock, flags); + entry = __ib_get_mad_port(device, port_num); + spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); + + return entry; +} + +static inline u8 convert_mgmt_class(u8 mgmt_class) +{ + /* Alias IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE to 0 */ + return mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ? + 0 : mgmt_class; +} + +static int get_spl_qp_index(enum ib_qp_type qp_type) +{ + switch (qp_type) + { + case IB_QPT_SMI: + return 0; + case IB_QPT_GSI: + return 1; + default: + return -1; + } +} + +static int vendor_class_index(u8 mgmt_class) +{ + return mgmt_class - IB_MGMT_CLASS_VENDOR_RANGE2_START; +} + +static int is_vendor_class(u8 mgmt_class) +{ + if ((mgmt_class < IB_MGMT_CLASS_VENDOR_RANGE2_START) || + (mgmt_class > IB_MGMT_CLASS_VENDOR_RANGE2_END)) + return 0; + return 1; +} + +static int is_vendor_oui(char *oui) +{ + if (oui[0] || oui[1] || oui[2]) + return 1; + return 0; +} + +static int is_vendor_method_in_use( + struct ib_mad_mgmt_vendor_class *vendor_class, + struct ib_mad_reg_req *mad_reg_req) +{ + struct ib_mad_mgmt_method_table *method; + int i; + + for (i = 0; i < MAX_MGMT_OUI; i++) { + if (!memcmp(vendor_class->oui[i], mad_reg_req->oui, 3)) { + method = vendor_class->method_table[i]; + if (method) { + if (method_in_use(&method, mad_reg_req)) + return 1; + else + break; + } + } + } + return 0; +} + +int ib_response_mad(struct ib_mad *mad) +{ + return ((mad->mad_hdr.method & IB_MGMT_METHOD_RESP) || + (mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) || + ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_BM) && + (mad->mad_hdr.attr_mod & IB_BM_ATTR_MOD_RESP))); +} +EXPORT_SYMBOL(ib_response_mad); + +static void timeout_callback(unsigned long data) +{ + struct ib_mad_agent_private *mad_agent_priv = + (struct ib_mad_agent_private *) data; + + queue_work(mad_agent_priv->qp_info->port_priv->wq, + &mad_agent_priv->timeout_work); +} + +/* + * ib_register_mad_agent - Register to send/receive MADs + */ +struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, + u8 port_num, + enum ib_qp_type qp_type, + struct ib_mad_reg_req *mad_reg_req, + u8 rmpp_version, + ib_mad_send_handler send_handler, + ib_mad_recv_handler recv_handler, + void *context) +{ + struct ib_mad_port_private *port_priv; + struct ib_mad_agent *ret = ERR_PTR(-EINVAL); + struct ib_mad_agent_private *mad_agent_priv; + struct ib_mad_reg_req *reg_req = NULL; + struct ib_mad_mgmt_class_table *class; + struct ib_mad_mgmt_vendor_class_table *vendor; + struct ib_mad_mgmt_vendor_class *vendor_class; + struct ib_mad_mgmt_method_table *method; + int ret2, qpn; + unsigned long flags; + u8 mgmt_class, vclass; + + /* Validate parameters */ + qpn = get_spl_qp_index(qp_type); + if (qpn == -1) + goto error1; + + if (rmpp_version && rmpp_version != IB_MGMT_RMPP_VERSION) + goto error1; + + /* Validate MAD registration request if supplied */ + if (mad_reg_req) { + if (mad_reg_req->mgmt_class_version >= MAX_MGMT_VERSION) + goto error1; + if (!recv_handler) + goto error1; + if (mad_reg_req->mgmt_class >= MAX_MGMT_CLASS) { + /* + * IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE is the only + * one in this range currently allowed + */ + if (mad_reg_req->mgmt_class != + IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) + goto error1; + } else if (mad_reg_req->mgmt_class == 0) { + /* + * Class 0 is reserved in IBA and is used for + * aliasing of IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE + */ + goto error1; + } else if (is_vendor_class(mad_reg_req->mgmt_class)) { + /* + * If class is in "new" vendor range, + * ensure supplied OUI is not zero + */ + if (!is_vendor_oui(mad_reg_req->oui)) + goto error1; + } + /* Make sure class supplied is consistent with RMPP */ + if (!ib_is_mad_class_rmpp(mad_reg_req->mgmt_class)) { + if (rmpp_version) + goto error1; + } + /* Make sure class supplied is consistent with QP type */ + if (qp_type == IB_QPT_SMI) { + if ((mad_reg_req->mgmt_class != + IB_MGMT_CLASS_SUBN_LID_ROUTED) && + (mad_reg_req->mgmt_class != + IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)) + goto error1; + } else { + if ((mad_reg_req->mgmt_class == + IB_MGMT_CLASS_SUBN_LID_ROUTED) || + (mad_reg_req->mgmt_class == + IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)) + goto error1; + } + } else { + /* No registration request supplied */ + if (!send_handler) + goto error1; + } + + /* Validate device and port */ + port_priv = ib_get_mad_port(device, port_num); + if (!port_priv) { + ret = ERR_PTR(-ENODEV); + goto error1; + } + + /* Allocate structures */ + mad_agent_priv = kzalloc(sizeof *mad_agent_priv, GFP_KERNEL); + if (!mad_agent_priv) { + ret = ERR_PTR(-ENOMEM); + goto error1; + } + + mad_agent_priv->agent.mr = ib_get_dma_mr(port_priv->qp_info[qpn].qp->pd, + IB_ACCESS_LOCAL_WRITE); + if (IS_ERR(mad_agent_priv->agent.mr)) { + ret = ERR_PTR(-ENOMEM); + goto error2; + } + + if (mad_reg_req) { + reg_req = kmalloc(sizeof *reg_req, GFP_KERNEL); + if (!reg_req) { + ret = ERR_PTR(-ENOMEM); + goto error3; + } + /* Make a copy of the MAD registration request */ + memcpy(reg_req, mad_reg_req, sizeof *reg_req); + } + + /* Now, fill in the various structures */ + mad_agent_priv->qp_info = &port_priv->qp_info[qpn]; + mad_agent_priv->reg_req = reg_req; + mad_agent_priv->agent.rmpp_version = rmpp_version; + mad_agent_priv->agent.device = device; + mad_agent_priv->agent.recv_handler = recv_handler; + mad_agent_priv->agent.send_handler = send_handler; + mad_agent_priv->agent.context = context; + mad_agent_priv->agent.qp = port_priv->qp_info[qpn].qp; + mad_agent_priv->agent.port_num = port_num; + spin_lock_init(&mad_agent_priv->lock); + INIT_LIST_HEAD(&mad_agent_priv->send_list); + INIT_LIST_HEAD(&mad_agent_priv->wait_list); + INIT_LIST_HEAD(&mad_agent_priv->done_list); + INIT_LIST_HEAD(&mad_agent_priv->rmpp_list); + INIT_WORK(&mad_agent_priv->timeout_work, timeout_sends); + setup_timer(&mad_agent_priv->timeout_timer, timeout_callback, + (unsigned long) mad_agent_priv); + INIT_LIST_HEAD(&mad_agent_priv->local_list); + INIT_WORK(&mad_agent_priv->local_work, local_completions); + atomic_set(&mad_agent_priv->refcount, 1); + init_completion(&mad_agent_priv->comp); + + spin_lock_irqsave(&port_priv->reg_lock, flags); + mad_agent_priv->agent.hi_tid = ++ib_mad_client_id; + + /* + * Make sure MAD registration (if supplied) + * is non overlapping with any existing ones + */ + if (mad_reg_req) { + mgmt_class = convert_mgmt_class(mad_reg_req->mgmt_class); + if (!is_vendor_class(mgmt_class)) { + class = port_priv->version[mad_reg_req-> + mgmt_class_version].class; + if (class) { + method = class->method_table[mgmt_class]; + if (method) { + if (method_in_use(&method, + mad_reg_req)) + goto error4; + } + } + ret2 = add_nonoui_reg_req(mad_reg_req, mad_agent_priv, + mgmt_class); + } else { + /* "New" vendor class range */ + vendor = port_priv->version[mad_reg_req-> + mgmt_class_version].vendor; + if (vendor) { + vclass = vendor_class_index(mgmt_class); + vendor_class = vendor->vendor_class[vclass]; + if (vendor_class) { + if (is_vendor_method_in_use( + vendor_class, + mad_reg_req)) + goto error4; + } + } + ret2 = add_oui_reg_req(mad_reg_req, mad_agent_priv); + } + if (ret2) { + ret = ERR_PTR(ret2); + goto error4; + } + } + + /* Add mad agent into port's agent list */ + list_add_tail(&mad_agent_priv->agent_list, &port_priv->agent_list); + spin_unlock_irqrestore(&port_priv->reg_lock, flags); + + return &mad_agent_priv->agent; + +error4: + spin_unlock_irqrestore(&port_priv->reg_lock, flags); + kfree(reg_req); +error3: + ib_dereg_mr(mad_agent_priv->agent.mr); +error2: + kfree(mad_agent_priv); +error1: + return ret; +} +EXPORT_SYMBOL(ib_register_mad_agent); + +static inline int is_snooping_sends(int mad_snoop_flags) +{ + return (mad_snoop_flags & + (/*IB_MAD_SNOOP_POSTED_SENDS | + IB_MAD_SNOOP_RMPP_SENDS |*/ + IB_MAD_SNOOP_SEND_COMPLETIONS /*| + IB_MAD_SNOOP_RMPP_SEND_COMPLETIONS*/)); +} + +static inline int is_snooping_recvs(int mad_snoop_flags) +{ + return (mad_snoop_flags & + (IB_MAD_SNOOP_RECVS /*| + IB_MAD_SNOOP_RMPP_RECVS*/)); +} + +static int register_snoop_agent(struct ib_mad_qp_info *qp_info, + struct ib_mad_snoop_private *mad_snoop_priv) +{ + struct ib_mad_snoop_private **new_snoop_table; + unsigned long flags; + int i; + + spin_lock_irqsave(&qp_info->snoop_lock, flags); + /* Check for empty slot in array. */ + for (i = 0; i < qp_info->snoop_table_size; i++) + if (!qp_info->snoop_table[i]) + break; + + if (i == qp_info->snoop_table_size) { + /* Grow table. */ + new_snoop_table = krealloc(qp_info->snoop_table, + sizeof mad_snoop_priv * + (qp_info->snoop_table_size + 1), + GFP_ATOMIC); + if (!new_snoop_table) { + i = -ENOMEM; + goto out; + } + + qp_info->snoop_table = new_snoop_table; + qp_info->snoop_table_size++; + } + qp_info->snoop_table[i] = mad_snoop_priv; + atomic_inc(&qp_info->snoop_count); +out: + spin_unlock_irqrestore(&qp_info->snoop_lock, flags); + return i; +} + +struct ib_mad_agent *ib_register_mad_snoop(struct ib_device *device, + u8 port_num, + enum ib_qp_type qp_type, + int mad_snoop_flags, + ib_mad_snoop_handler snoop_handler, + ib_mad_recv_handler recv_handler, + void *context) +{ + struct ib_mad_port_private *port_priv; + struct ib_mad_agent *ret; + struct ib_mad_snoop_private *mad_snoop_priv; + int qpn; + + /* Validate parameters */ + if ((is_snooping_sends(mad_snoop_flags) && !snoop_handler) || + (is_snooping_recvs(mad_snoop_flags) && !recv_handler)) { + ret = ERR_PTR(-EINVAL); + goto error1; + } + qpn = get_spl_qp_index(qp_type); + if (qpn == -1) { + ret = ERR_PTR(-EINVAL); + goto error1; + } + port_priv = ib_get_mad_port(device, port_num); + if (!port_priv) { + ret = ERR_PTR(-ENODEV); + goto error1; + } + /* Allocate structures */ + mad_snoop_priv = kzalloc(sizeof *mad_snoop_priv, GFP_KERNEL); + if (!mad_snoop_priv) { + ret = ERR_PTR(-ENOMEM); + goto error1; + } + + /* Now, fill in the various structures */ + mad_snoop_priv->qp_info = &port_priv->qp_info[qpn]; + mad_snoop_priv->agent.device = device; + mad_snoop_priv->agent.recv_handler = recv_handler; + mad_snoop_priv->agent.snoop_handler = snoop_handler; + mad_snoop_priv->agent.context = context; + mad_snoop_priv->agent.qp = port_priv->qp_info[qpn].qp; + mad_snoop_priv->agent.port_num = port_num; + mad_snoop_priv->mad_snoop_flags = mad_snoop_flags; + init_completion(&mad_snoop_priv->comp); + mad_snoop_priv->snoop_index = register_snoop_agent( + &port_priv->qp_info[qpn], + mad_snoop_priv); + if (mad_snoop_priv->snoop_index < 0) { + ret = ERR_PTR(mad_snoop_priv->snoop_index); + goto error2; + } + + atomic_set(&mad_snoop_priv->refcount, 1); + return &mad_snoop_priv->agent; + +error2: + kfree(mad_snoop_priv); +error1: + return ret; +} +EXPORT_SYMBOL(ib_register_mad_snoop); + +static inline void deref_mad_agent(struct ib_mad_agent_private *mad_agent_priv) +{ + if (atomic_dec_and_test(&mad_agent_priv->refcount)) + complete(&mad_agent_priv->comp); +} + +static inline void deref_snoop_agent(struct ib_mad_snoop_private *mad_snoop_priv) +{ + if (atomic_dec_and_test(&mad_snoop_priv->refcount)) + complete(&mad_snoop_priv->comp); +} + +static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv) +{ + struct ib_mad_port_private *port_priv; + unsigned long flags; + + /* Note that we could still be handling received MADs */ + + /* + * Canceling all sends results in dropping received response + * MADs, preventing us from queuing additional work + */ + cancel_mads(mad_agent_priv); + port_priv = mad_agent_priv->qp_info->port_priv; + del_timer_sync(&mad_agent_priv->timeout_timer); + cancel_work_sync(&mad_agent_priv->timeout_work); + + spin_lock_irqsave(&port_priv->reg_lock, flags); + remove_mad_reg_req(mad_agent_priv); + list_del(&mad_agent_priv->agent_list); + spin_unlock_irqrestore(&port_priv->reg_lock, flags); + + flush_workqueue(port_priv->wq); + ib_cancel_rmpp_recvs(mad_agent_priv); + + deref_mad_agent(mad_agent_priv); + wait_for_completion(&mad_agent_priv->comp); + + kfree(mad_agent_priv->reg_req); + ib_dereg_mr(mad_agent_priv->agent.mr); + kfree(mad_agent_priv); +} + +static void unregister_mad_snoop(struct ib_mad_snoop_private *mad_snoop_priv) +{ + struct ib_mad_qp_info *qp_info; + unsigned long flags; + + qp_info = mad_snoop_priv->qp_info; + spin_lock_irqsave(&qp_info->snoop_lock, flags); + qp_info->snoop_table[mad_snoop_priv->snoop_index] = NULL; + atomic_dec(&qp_info->snoop_count); + spin_unlock_irqrestore(&qp_info->snoop_lock, flags); + + deref_snoop_agent(mad_snoop_priv); + wait_for_completion(&mad_snoop_priv->comp); + + kfree(mad_snoop_priv); +} + +/* + * ib_unregister_mad_agent - Unregisters a client from using MAD services + */ +int ib_unregister_mad_agent(struct ib_mad_agent *mad_agent) +{ + struct ib_mad_agent_private *mad_agent_priv; + struct ib_mad_snoop_private *mad_snoop_priv; + + /* If the TID is zero, the agent can only snoop. */ + if (mad_agent->hi_tid) { + mad_agent_priv = container_of(mad_agent, + struct ib_mad_agent_private, + agent); + unregister_mad_agent(mad_agent_priv); + } else { + mad_snoop_priv = container_of(mad_agent, + struct ib_mad_snoop_private, + agent); + unregister_mad_snoop(mad_snoop_priv); + } + return 0; +} +EXPORT_SYMBOL(ib_unregister_mad_agent); + +static void dequeue_mad(struct ib_mad_list_head *mad_list) +{ + struct ib_mad_queue *mad_queue; + unsigned long flags; + + BUG_ON(!mad_list->mad_queue); + mad_queue = mad_list->mad_queue; + spin_lock_irqsave(&mad_queue->lock, flags); + list_del(&mad_list->list); + mad_queue->count--; + spin_unlock_irqrestore(&mad_queue->lock, flags); +} + +static void snoop_send(struct ib_mad_qp_info *qp_info, + struct ib_mad_send_buf *send_buf, + struct ib_mad_send_wc *mad_send_wc, + int mad_snoop_flags) +{ + struct ib_mad_snoop_private *mad_snoop_priv; + unsigned long flags; + int i; + + spin_lock_irqsave(&qp_info->snoop_lock, flags); + for (i = 0; i < qp_info->snoop_table_size; i++) { + mad_snoop_priv = qp_info->snoop_table[i]; + if (!mad_snoop_priv || + !(mad_snoop_priv->mad_snoop_flags & mad_snoop_flags)) + continue; + + atomic_inc(&mad_snoop_priv->refcount); + spin_unlock_irqrestore(&qp_info->snoop_lock, flags); + mad_snoop_priv->agent.snoop_handler(&mad_snoop_priv->agent, + send_buf, mad_send_wc); + deref_snoop_agent(mad_snoop_priv); + spin_lock_irqsave(&qp_info->snoop_lock, flags); + } + spin_unlock_irqrestore(&qp_info->snoop_lock, flags); +} + +static void snoop_recv(struct ib_mad_qp_info *qp_info, + struct ib_mad_recv_wc *mad_recv_wc, + int mad_snoop_flags) +{ + struct ib_mad_snoop_private *mad_snoop_priv; + unsigned long flags; + int i; + + spin_lock_irqsave(&qp_info->snoop_lock, flags); + for (i = 0; i < qp_info->snoop_table_size; i++) { + mad_snoop_priv = qp_info->snoop_table[i]; + if (!mad_snoop_priv || + !(mad_snoop_priv->mad_snoop_flags & mad_snoop_flags)) + continue; + + atomic_inc(&mad_snoop_priv->refcount); + spin_unlock_irqrestore(&qp_info->snoop_lock, flags); + mad_snoop_priv->agent.recv_handler(&mad_snoop_priv->agent, + mad_recv_wc); + deref_snoop_agent(mad_snoop_priv); + spin_lock_irqsave(&qp_info->snoop_lock, flags); + } + spin_unlock_irqrestore(&qp_info->snoop_lock, flags); +} + +static void build_smp_wc(struct ib_qp *qp, + u64 wr_id, u16 slid, u16 pkey_index, u8 port_num, + struct ib_wc *wc) +{ + memset(wc, 0, sizeof *wc); + wc->wr_id = wr_id; + wc->status = IB_WC_SUCCESS; + wc->opcode = IB_WC_RECV; + wc->pkey_index = pkey_index; + wc->byte_len = sizeof(struct ib_mad) + sizeof(struct ib_grh); + wc->src_qp = IB_QP0; + wc->qp = qp; + wc->slid = slid; + wc->sl = 0; + wc->dlid_path_bits = 0; + wc->port_num = port_num; +} + +/* + * Return 0 if SMP is to be sent + * Return 1 if SMP was consumed locally (whether or not solicited) + * Return < 0 if error + */ +static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, + struct ib_mad_send_wr_private *mad_send_wr) +{ + int ret = 0; + struct ib_smp *smp = mad_send_wr->send_buf.mad; + unsigned long flags; + struct ib_mad_local_private *local; + struct ib_mad_private *mad_priv; + struct ib_mad_port_private *port_priv; + struct ib_mad_agent_private *recv_mad_agent = NULL; + struct ib_device *device = mad_agent_priv->agent.device; + u8 port_num; + struct ib_wc mad_wc; + struct ib_send_wr *send_wr = &mad_send_wr->send_wr; + + if (device->node_type == RDMA_NODE_IB_SWITCH) + port_num = send_wr->wr.ud.port_num; + else + port_num = mad_agent_priv->agent.port_num; + + /* + * Directed route handling starts if the initial LID routed part of + * a request or the ending LID routed part of a response is empty. + * If we are at the start of the LID routed part, don't update the + * hop_ptr or hop_cnt. See section 14.2.2, Vol 1 IB spec. + */ + if ((ib_get_smp_direction(smp) ? smp->dr_dlid : smp->dr_slid) != + IB_LID_PERMISSIVE) + goto out; + if (smi_handle_dr_smp_send(smp, device->node_type, port_num) == + IB_SMI_DISCARD) { + ret = -EINVAL; + printk(KERN_ERR PFX "Invalid directed route\n"); + goto out; + } + + /* Check to post send on QP or process locally */ + if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD && + smi_check_local_returning_smp(smp, device) == IB_SMI_DISCARD) + goto out; + + local = kmalloc(sizeof *local, GFP_ATOMIC); + if (!local) { + ret = -ENOMEM; + printk(KERN_ERR PFX "No memory for ib_mad_local_private\n"); + goto out; + } + local->mad_priv = NULL; + local->recv_mad_agent = NULL; + mad_priv = kmem_cache_alloc(ib_mad_cache, GFP_ATOMIC); + if (!mad_priv) { + ret = -ENOMEM; + printk(KERN_ERR PFX "No memory for local response MAD\n"); + kfree(local); + goto out; + } + + build_smp_wc(mad_agent_priv->agent.qp, + send_wr->wr_id, be16_to_cpu(smp->dr_slid), + send_wr->wr.ud.pkey_index, + send_wr->wr.ud.port_num, &mad_wc); + + /* No GRH for DR SMP */ + ret = device->process_mad(device, 0, port_num, &mad_wc, NULL, + (struct ib_mad *)smp, + (struct ib_mad *)&mad_priv->mad); + switch (ret) + { + case IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY: + if (ib_response_mad(&mad_priv->mad.mad) && + mad_agent_priv->agent.recv_handler) { + local->mad_priv = mad_priv; + local->recv_mad_agent = mad_agent_priv; + /* + * Reference MAD agent until receive + * side of local completion handled + */ + atomic_inc(&mad_agent_priv->refcount); + } else + kmem_cache_free(ib_mad_cache, mad_priv); + break; + case IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED: + kmem_cache_free(ib_mad_cache, mad_priv); + break; + case IB_MAD_RESULT_SUCCESS: + /* Treat like an incoming receive MAD */ + port_priv = ib_get_mad_port(mad_agent_priv->agent.device, + mad_agent_priv->agent.port_num); + if (port_priv) { + memcpy(&mad_priv->mad.mad, smp, sizeof(struct ib_mad)); + recv_mad_agent = find_mad_agent(port_priv, + &mad_priv->mad.mad); + } + if (!port_priv || !recv_mad_agent) { + /* + * No receiving agent so drop packet and + * generate send completion. + */ + kmem_cache_free(ib_mad_cache, mad_priv); + break; + } + local->mad_priv = mad_priv; + local->recv_mad_agent = recv_mad_agent; + break; + default: + kmem_cache_free(ib_mad_cache, mad_priv); + kfree(local); + ret = -EINVAL; + goto out; + } + + local->mad_send_wr = mad_send_wr; + /* Reference MAD agent until send side of local completion handled */ + atomic_inc(&mad_agent_priv->refcount); + /* Queue local completion to local list */ + spin_lock_irqsave(&mad_agent_priv->lock, flags); + list_add_tail(&local->completion_list, &mad_agent_priv->local_list); + spin_unlock_irqrestore(&mad_agent_priv->lock, flags); + queue_work(mad_agent_priv->qp_info->port_priv->wq, + &mad_agent_priv->local_work); + ret = 1; +out: + return ret; +} + +static int get_pad_size(int hdr_len, int data_len) +{ + int seg_size, pad; + + seg_size = sizeof(struct ib_mad) - hdr_len; + if (data_len && seg_size) { + pad = seg_size - data_len % seg_size; + return pad == seg_size ? 0 : pad; + } else + return seg_size; +} + +static void free_send_rmpp_list(struct ib_mad_send_wr_private *mad_send_wr) +{ + struct ib_rmpp_segment *s, *t; + + list_for_each_entry_safe(s, t, &mad_send_wr->rmpp_list, list) { + list_del(&s->list); + kfree(s); + } +} + +static int alloc_send_rmpp_list(struct ib_mad_send_wr_private *send_wr, + gfp_t gfp_mask) +{ + struct ib_mad_send_buf *send_buf = &send_wr->send_buf; + struct ib_rmpp_mad *rmpp_mad = send_buf->mad; + struct ib_rmpp_segment *seg = NULL; + int left, seg_size, pad; + + send_buf->seg_size = sizeof (struct ib_mad) - send_buf->hdr_len; + seg_size = send_buf->seg_size; + pad = send_wr->pad; + + /* Allocate data segments. */ + for (left = send_buf->data_len + pad; left > 0; left -= seg_size) { + seg = kmalloc(sizeof (*seg) + seg_size, gfp_mask); + if (!seg) { + printk(KERN_ERR "alloc_send_rmpp_segs: RMPP mem " + "alloc failed for len %zd, gfp %#x\n", + sizeof (*seg) + seg_size, gfp_mask); + free_send_rmpp_list(send_wr); + return -ENOMEM; + } + seg->num = ++send_buf->seg_count; + list_add_tail(&seg->list, &send_wr->rmpp_list); + } + + /* Zero any padding */ + if (pad) + memset(seg->data + seg_size - pad, 0, pad); + + rmpp_mad->rmpp_hdr.rmpp_version = send_wr->mad_agent_priv-> + agent.rmpp_version; + rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_DATA; + ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE); + + send_wr->cur_seg = container_of(send_wr->rmpp_list.next, + struct ib_rmpp_segment, list); + send_wr->last_ack_seg = send_wr->cur_seg; + return 0; +} + +struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, + u32 remote_qpn, u16 pkey_index, + int rmpp_active, + int hdr_len, int data_len, + gfp_t gfp_mask) +{ + struct ib_mad_agent_private *mad_agent_priv; + struct ib_mad_send_wr_private *mad_send_wr; + int pad, message_size, ret, size; + void *buf; + + mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private, + agent); + pad = get_pad_size(hdr_len, data_len); + message_size = hdr_len + data_len + pad; + + if ((!mad_agent->rmpp_version && + (rmpp_active || message_size > sizeof(struct ib_mad))) || + (!rmpp_active && message_size > sizeof(struct ib_mad))) + return ERR_PTR(-EINVAL); + + size = rmpp_active ? hdr_len : sizeof(struct ib_mad); + buf = kzalloc(sizeof *mad_send_wr + size, gfp_mask); + if (!buf) + return ERR_PTR(-ENOMEM); + + mad_send_wr = buf + size; + INIT_LIST_HEAD(&mad_send_wr->rmpp_list); + mad_send_wr->send_buf.mad = buf; + mad_send_wr->send_buf.hdr_len = hdr_len; + mad_send_wr->send_buf.data_len = data_len; + mad_send_wr->pad = pad; + + mad_send_wr->mad_agent_priv = mad_agent_priv; + mad_send_wr->sg_list[0].length = hdr_len; + mad_send_wr->sg_list[0].lkey = mad_agent->mr->lkey; + mad_send_wr->sg_list[1].length = sizeof(struct ib_mad) - hdr_len; + mad_send_wr->sg_list[1].lkey = mad_agent->mr->lkey; + + mad_send_wr->send_wr.wr_id = (unsigned long) mad_send_wr; + mad_send_wr->send_wr.sg_list = mad_send_wr->sg_list; + mad_send_wr->send_wr.num_sge = 2; + mad_send_wr->send_wr.opcode = IB_WR_SEND; + mad_send_wr->send_wr.send_flags = IB_SEND_SIGNALED; + mad_send_wr->send_wr.wr.ud.remote_qpn = remote_qpn; + mad_send_wr->send_wr.wr.ud.remote_qkey = IB_QP_SET_QKEY; + mad_send_wr->send_wr.wr.ud.pkey_index = pkey_index; + + if (rmpp_active) { + ret = alloc_send_rmpp_list(mad_send_wr, gfp_mask); + if (ret) { + kfree(buf); + return ERR_PTR(ret); + } + } + + mad_send_wr->send_buf.mad_agent = mad_agent; + atomic_inc(&mad_agent_priv->refcount); + return &mad_send_wr->send_buf; +} +EXPORT_SYMBOL(ib_create_send_mad); + +int ib_get_mad_data_offset(u8 mgmt_class) +{ + if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM) + return IB_MGMT_SA_HDR; + else if ((mgmt_class == IB_MGMT_CLASS_DEVICE_MGMT) || + (mgmt_class == IB_MGMT_CLASS_DEVICE_ADM) || + (mgmt_class == IB_MGMT_CLASS_BIS)) + return IB_MGMT_DEVICE_HDR; + else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && + (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) + return IB_MGMT_VENDOR_HDR; + else + return IB_MGMT_MAD_HDR; +} +EXPORT_SYMBOL(ib_get_mad_data_offset); + +int ib_is_mad_class_rmpp(u8 mgmt_class) +{ + if ((mgmt_class == IB_MGMT_CLASS_SUBN_ADM) || + (mgmt_class == IB_MGMT_CLASS_DEVICE_MGMT) || + (mgmt_class == IB_MGMT_CLASS_DEVICE_ADM) || + (mgmt_class == IB_MGMT_CLASS_BIS) || + ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && + (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))) + return 1; + return 0; +} +EXPORT_SYMBOL(ib_is_mad_class_rmpp); + +void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num) +{ + struct ib_mad_send_wr_private *mad_send_wr; + struct list_head *list; + + mad_send_wr = container_of(send_buf, struct ib_mad_send_wr_private, + send_buf); + list = &mad_send_wr->cur_seg->list; + + if (mad_send_wr->cur_seg->num < seg_num) { + list_for_each_entry(mad_send_wr->cur_seg, list, list) + if (mad_send_wr->cur_seg->num == seg_num) + break; + } else if (mad_send_wr->cur_seg->num > seg_num) { + list_for_each_entry_reverse(mad_send_wr->cur_seg, list, list) + if (mad_send_wr->cur_seg->num == seg_num) + break; + } + return mad_send_wr->cur_seg->data; +} +EXPORT_SYMBOL(ib_get_rmpp_segment); + +static inline void *ib_get_payload(struct ib_mad_send_wr_private *mad_send_wr) +{ + if (mad_send_wr->send_buf.seg_count) + return ib_get_rmpp_segment(&mad_send_wr->send_buf, + mad_send_wr->seg_num); + else + return mad_send_wr->send_buf.mad + + mad_send_wr->send_buf.hdr_len; +} + +void ib_free_send_mad(struct ib_mad_send_buf *send_buf) +{ + struct ib_mad_agent_private *mad_agent_priv; + struct ib_mad_send_wr_private *mad_send_wr; + + mad_agent_priv = container_of(send_buf->mad_agent, + struct ib_mad_agent_private, agent); + mad_send_wr = container_of(send_buf, struct ib_mad_send_wr_private, + send_buf); + + free_send_rmpp_list(mad_send_wr); + kfree(send_buf->mad); + deref_mad_agent(mad_agent_priv); +} +EXPORT_SYMBOL(ib_free_send_mad); + +int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr) +{ + struct ib_mad_qp_info *qp_info; + struct list_head *list; + struct ib_send_wr *bad_send_wr; + struct ib_mad_agent *mad_agent; + struct ib_sge *sge; + unsigned long flags; + int ret; + + /* Set WR ID to find mad_send_wr upon completion */ + qp_info = mad_send_wr->mad_agent_priv->qp_info; + mad_send_wr->send_wr.wr_id = (unsigned long)&mad_send_wr->mad_list; + mad_send_wr->mad_list.mad_queue = &qp_info->send_queue; + + mad_agent = mad_send_wr->send_buf.mad_agent; + sge = mad_send_wr->sg_list; + sge[0].addr = ib_dma_map_single(mad_agent->device, + mad_send_wr->send_buf.mad, + sge[0].length, + DMA_TO_DEVICE); + mad_send_wr->header_mapping = sge[0].addr; + + sge[1].addr = ib_dma_map_single(mad_agent->device, + ib_get_payload(mad_send_wr), + sge[1].length, + DMA_TO_DEVICE); + mad_send_wr->payload_mapping = sge[1].addr; + + spin_lock_irqsave(&qp_info->send_queue.lock, flags); + if (qp_info->send_queue.count < qp_info->send_queue.max_active) { + ret = ib_post_send(mad_agent->qp, &mad_send_wr->send_wr, + &bad_send_wr); + list = &qp_info->send_queue.list; + } else { + ret = 0; + list = &qp_info->overflow_list; + } + + if (!ret) { + qp_info->send_queue.count++; + list_add_tail(&mad_send_wr->mad_list.list, list); + } + spin_unlock_irqrestore(&qp_info->send_queue.lock, flags); + if (ret) { + ib_dma_unmap_single(mad_agent->device, + mad_send_wr->header_mapping, + sge[0].length, DMA_TO_DEVICE); + ib_dma_unmap_single(mad_agent->device, + mad_send_wr->payload_mapping, + sge[1].length, DMA_TO_DEVICE); + } + return ret; +} + +/* + * ib_post_send_mad - Posts MAD(s) to the send queue of the QP associated + * with the registered client + */ +int ib_post_send_mad(struct ib_mad_send_buf *send_buf, + struct ib_mad_send_buf **bad_send_buf) +{ + struct ib_mad_agent_private *mad_agent_priv; + struct ib_mad_send_buf *next_send_buf; + struct ib_mad_send_wr_private *mad_send_wr; + unsigned long flags; + int ret = -EINVAL; + + /* Walk list of send WRs and post each on send list */ + for (; send_buf; send_buf = next_send_buf) { + + mad_send_wr = container_of(send_buf, + struct ib_mad_send_wr_private, + send_buf); + mad_agent_priv = mad_send_wr->mad_agent_priv; + + if (!send_buf->mad_agent->send_handler || + (send_buf->timeout_ms && + !send_buf->mad_agent->recv_handler)) { + ret = -EINVAL; + goto error; + } + + if (!ib_is_mad_class_rmpp(((struct ib_mad_hdr *) send_buf->mad)->mgmt_class)) { + if (mad_agent_priv->agent.rmpp_version) { + ret = -EINVAL; + goto error; + } + } + + /* + * Save pointer to next work request to post in case the + * current one completes, and the user modifies the work + * request associated with the completion + */ + next_send_buf = send_buf->next; + mad_send_wr->send_wr.wr.ud.ah = send_buf->ah; + + if (((struct ib_mad_hdr *) send_buf->mad)->mgmt_class == + IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { + ret = handle_outgoing_dr_smp(mad_agent_priv, + mad_send_wr); + if (ret < 0) /* error */ + goto error; + else if (ret == 1) /* locally consumed */ + continue; + } + + mad_send_wr->tid = ((struct ib_mad_hdr *) send_buf->mad)->tid; + /* Timeout will be updated after send completes */ + mad_send_wr->timeout = msecs_to_jiffies(send_buf->timeout_ms); + mad_send_wr->max_retries = send_buf->retries; + mad_send_wr->retries_left = send_buf->retries; + send_buf->retries = 0; + /* Reference for work request to QP + response */ + mad_send_wr->refcount = 1 + (mad_send_wr->timeout > 0); + mad_send_wr->status = IB_WC_SUCCESS; + + /* Reference MAD agent until send completes */ + atomic_inc(&mad_agent_priv->refcount); + spin_lock_irqsave(&mad_agent_priv->lock, flags); + list_add_tail(&mad_send_wr->agent_list, + &mad_agent_priv->send_list); + spin_unlock_irqrestore(&mad_agent_priv->lock, flags); + + if (mad_agent_priv->agent.rmpp_version) { + ret = ib_send_rmpp_mad(mad_send_wr); + if (ret >= 0 && ret != IB_RMPP_RESULT_CONSUMED) + ret = ib_send_mad(mad_send_wr); + } else + ret = ib_send_mad(mad_send_wr); + if (ret < 0) { + /* Fail send request */ + spin_lock_irqsave(&mad_agent_priv->lock, flags); + list_del(&mad_send_wr->agent_list); + spin_unlock_irqrestore(&mad_agent_priv->lock, flags); + atomic_dec(&mad_agent_priv->refcount); + goto error; + } + } + return 0; +error: + if (bad_send_buf) + *bad_send_buf = send_buf; + return ret; +} +EXPORT_SYMBOL(ib_post_send_mad); + +/* + * ib_free_recv_mad - Returns data buffers used to receive + * a MAD to the access layer + */ +void ib_free_recv_mad(struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_mad_recv_buf *mad_recv_buf, *temp_recv_buf; + struct ib_mad_private_header *mad_priv_hdr; + struct ib_mad_private *priv; + struct list_head free_list; + + INIT_LIST_HEAD(&free_list); + list_splice_init(&mad_recv_wc->rmpp_list, &free_list); + + list_for_each_entry_safe(mad_recv_buf, temp_recv_buf, + &free_list, list) { + mad_recv_wc = container_of(mad_recv_buf, struct ib_mad_recv_wc, + recv_buf); + mad_priv_hdr = container_of(mad_recv_wc, + struct ib_mad_private_header, + recv_wc); + priv = container_of(mad_priv_hdr, struct ib_mad_private, + header); + kmem_cache_free(ib_mad_cache, priv); + } +} +EXPORT_SYMBOL(ib_free_recv_mad); + +struct ib_mad_agent *ib_redirect_mad_qp(struct ib_qp *qp, + u8 rmpp_version, + ib_mad_send_handler send_handler, + ib_mad_recv_handler recv_handler, + void *context) +{ + return ERR_PTR(-EINVAL); /* XXX: for now */ +} +EXPORT_SYMBOL(ib_redirect_mad_qp); + +int ib_process_mad_wc(struct ib_mad_agent *mad_agent, + struct ib_wc *wc) +{ + printk(KERN_ERR PFX "ib_process_mad_wc() not implemented yet\n"); + return 0; +} +EXPORT_SYMBOL(ib_process_mad_wc); + +static int method_in_use(struct ib_mad_mgmt_method_table **method, + struct ib_mad_reg_req *mad_reg_req) +{ + int i; + + for (i = find_first_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS); + i < IB_MGMT_MAX_METHODS; + i = find_next_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS, + 1+i)) { + if ((*method)->agent[i]) { + printk(KERN_ERR PFX "Method %d already in use\n", i); + return -EINVAL; + } + } + return 0; +} + +static int allocate_method_table(struct ib_mad_mgmt_method_table **method) +{ + /* Allocate management method table */ + *method = kzalloc(sizeof **method, GFP_ATOMIC); + if (!*method) { + printk(KERN_ERR PFX "No memory for " + "ib_mad_mgmt_method_table\n"); + return -ENOMEM; + } + + return 0; +} + +/* + * Check to see if there are any methods still in use + */ +static int check_method_table(struct ib_mad_mgmt_method_table *method) +{ + int i; + + for (i = 0; i < IB_MGMT_MAX_METHODS; i++) + if (method->agent[i]) + return 1; + return 0; +} + +/* + * Check to see if there are any method tables for this class still in use + */ +static int check_class_table(struct ib_mad_mgmt_class_table *class) +{ + int i; + + for (i = 0; i < MAX_MGMT_CLASS; i++) + if (class->method_table[i]) + return 1; + return 0; +} + +static int check_vendor_class(struct ib_mad_mgmt_vendor_class *vendor_class) +{ + int i; + + for (i = 0; i < MAX_MGMT_OUI; i++) + if (vendor_class->method_table[i]) + return 1; + return 0; +} + +static int find_vendor_oui(struct ib_mad_mgmt_vendor_class *vendor_class, + char *oui) +{ + int i; + + for (i = 0; i < MAX_MGMT_OUI; i++) + /* Is there matching OUI for this vendor class ? */ + if (!memcmp(vendor_class->oui[i], oui, 3)) + return i; + + return -1; +} + +static int check_vendor_table(struct ib_mad_mgmt_vendor_class_table *vendor) +{ + int i; + + for (i = 0; i < MAX_MGMT_VENDOR_RANGE2; i++) + if (vendor->vendor_class[i]) + return 1; + + return 0; +} + +static void remove_methods_mad_agent(struct ib_mad_mgmt_method_table *method, + struct ib_mad_agent_private *agent) +{ + int i; + + /* Remove any methods for this mad agent */ + for (i = 0; i < IB_MGMT_MAX_METHODS; i++) { + if (method->agent[i] == agent) { + method->agent[i] = NULL; + } + } +} + +static int add_nonoui_reg_req(struct ib_mad_reg_req *mad_reg_req, + struct ib_mad_agent_private *agent_priv, + u8 mgmt_class) +{ + struct ib_mad_port_private *port_priv; + struct ib_mad_mgmt_class_table **class; + struct ib_mad_mgmt_method_table **method; + int i, ret; + + port_priv = agent_priv->qp_info->port_priv; + class = &port_priv->version[mad_reg_req->mgmt_class_version].class; + if (!*class) { + /* Allocate management class table for "new" class version */ + *class = kzalloc(sizeof **class, GFP_ATOMIC); + if (!*class) { + printk(KERN_ERR PFX "No memory for " + "ib_mad_mgmt_class_table\n"); + ret = -ENOMEM; + goto error1; + } + + /* Allocate method table for this management class */ + method = &(*class)->method_table[mgmt_class]; + if ((ret = allocate_method_table(method))) + goto error2; + } else { + method = &(*class)->method_table[mgmt_class]; + if (!*method) { + /* Allocate method table for this management class */ + if ((ret = allocate_method_table(method))) + goto error1; + } + } + + /* Now, make sure methods are not already in use */ + if (method_in_use(method, mad_reg_req)) + goto error3; + + /* Finally, add in methods being registered */ + for (i = find_first_bit(mad_reg_req->method_mask, + IB_MGMT_MAX_METHODS); + i < IB_MGMT_MAX_METHODS; + i = find_next_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS, + 1+i)) { + (*method)->agent[i] = agent_priv; + } + return 0; + +error3: + /* Remove any methods for this mad agent */ + remove_methods_mad_agent(*method, agent_priv); + /* Now, check to see if there are any methods in use */ + if (!check_method_table(*method)) { + /* If not, release management method table */ + kfree(*method); + *method = NULL; + } + ret = -EINVAL; + goto error1; +error2: + kfree(*class); + *class = NULL; +error1: + return ret; +} + +static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req, + struct ib_mad_agent_private *agent_priv) +{ + struct ib_mad_port_private *port_priv; + struct ib_mad_mgmt_vendor_class_table **vendor_table; + struct ib_mad_mgmt_vendor_class_table *vendor = NULL; + struct ib_mad_mgmt_vendor_class *vendor_class = NULL; + struct ib_mad_mgmt_method_table **method; + int i, ret = -ENOMEM; + u8 vclass; + + /* "New" vendor (with OUI) class */ + vclass = vendor_class_index(mad_reg_req->mgmt_class); + port_priv = agent_priv->qp_info->port_priv; + vendor_table = &port_priv->version[ + mad_reg_req->mgmt_class_version].vendor; + if (!*vendor_table) { + /* Allocate mgmt vendor class table for "new" class version */ + vendor = kzalloc(sizeof *vendor, GFP_ATOMIC); + if (!vendor) { + printk(KERN_ERR PFX "No memory for " + "ib_mad_mgmt_vendor_class_table\n"); + goto error1; + } + + *vendor_table = vendor; + } + if (!(*vendor_table)->vendor_class[vclass]) { + /* Allocate table for this management vendor class */ + vendor_class = kzalloc(sizeof *vendor_class, GFP_ATOMIC); + if (!vendor_class) { + printk(KERN_ERR PFX "No memory for " + "ib_mad_mgmt_vendor_class\n"); + goto error2; + } + + (*vendor_table)->vendor_class[vclass] = vendor_class; + } + for (i = 0; i < MAX_MGMT_OUI; i++) { + /* Is there matching OUI for this vendor class ? */ + if (!memcmp((*vendor_table)->vendor_class[vclass]->oui[i], + mad_reg_req->oui, 3)) { + method = &(*vendor_table)->vendor_class[ + vclass]->method_table[i]; + BUG_ON(!*method); + goto check_in_use; + } + } + for (i = 0; i < MAX_MGMT_OUI; i++) { + /* OUI slot available ? */ + if (!is_vendor_oui((*vendor_table)->vendor_class[ + vclass]->oui[i])) { + method = &(*vendor_table)->vendor_class[ + vclass]->method_table[i]; + BUG_ON(*method); + /* Allocate method table for this OUI */ + if ((ret = allocate_method_table(method))) + goto error3; + memcpy((*vendor_table)->vendor_class[vclass]->oui[i], + mad_reg_req->oui, 3); + goto check_in_use; + } + } + printk(KERN_ERR PFX "All OUI slots in use\n"); + goto error3; + +check_in_use: + /* Now, make sure methods are not already in use */ + if (method_in_use(method, mad_reg_req)) + goto error4; + + /* Finally, add in methods being registered */ + for (i = find_first_bit(mad_reg_req->method_mask, + IB_MGMT_MAX_METHODS); + i < IB_MGMT_MAX_METHODS; + i = find_next_bit(mad_reg_req->method_mask, IB_MGMT_MAX_METHODS, + 1+i)) { + (*method)->agent[i] = agent_priv; + } + return 0; + +error4: + /* Remove any methods for this mad agent */ + remove_methods_mad_agent(*method, agent_priv); + /* Now, check to see if there are any methods in use */ + if (!check_method_table(*method)) { + /* If not, release management method table */ + kfree(*method); + *method = NULL; + } + ret = -EINVAL; +error3: + if (vendor_class) { + (*vendor_table)->vendor_class[vclass] = NULL; + kfree(vendor_class); + } +error2: + if (vendor) { + *vendor_table = NULL; + kfree(vendor); + } +error1: + return ret; +} + +static void remove_mad_reg_req(struct ib_mad_agent_private *agent_priv) +{ + struct ib_mad_port_private *port_priv; + struct ib_mad_mgmt_class_table *class; + struct ib_mad_mgmt_method_table *method; + struct ib_mad_mgmt_vendor_class_table *vendor; + struct ib_mad_mgmt_vendor_class *vendor_class; + int index; + u8 mgmt_class; + + /* + * Was MAD registration request supplied + * with original registration ? + */ + if (!agent_priv->reg_req) { + goto out; + } + + port_priv = agent_priv->qp_info->port_priv; + mgmt_class = convert_mgmt_class(agent_priv->reg_req->mgmt_class); + class = port_priv->version[ + agent_priv->reg_req->mgmt_class_version].class; + if (!class) + goto vendor_check; + + method = class->method_table[mgmt_class]; + if (method) { + /* Remove any methods for this mad agent */ + remove_methods_mad_agent(method, agent_priv); + /* Now, check to see if there are any methods still in use */ + if (!check_method_table(method)) { + /* If not, release management method table */ + kfree(method); + class->method_table[mgmt_class] = NULL; + /* Any management classes left ? */ + if (!check_class_table(class)) { + /* If not, release management class table */ + kfree(class); + port_priv->version[ + agent_priv->reg_req-> + mgmt_class_version].class = NULL; + } + } + } + +vendor_check: + if (!is_vendor_class(mgmt_class)) + goto out; + + /* normalize mgmt_class to vendor range 2 */ + mgmt_class = vendor_class_index(agent_priv->reg_req->mgmt_class); + vendor = port_priv->version[ + agent_priv->reg_req->mgmt_class_version].vendor; + + if (!vendor) + goto out; + + vendor_class = vendor->vendor_class[mgmt_class]; + if (vendor_class) { + index = find_vendor_oui(vendor_class, agent_priv->reg_req->oui); + if (index < 0) + goto out; + method = vendor_class->method_table[index]; + if (method) { + /* Remove any methods for this mad agent */ + remove_methods_mad_agent(method, agent_priv); + /* + * Now, check to see if there are + * any methods still in use + */ + if (!check_method_table(method)) { + /* If not, release management method table */ + kfree(method); + vendor_class->method_table[index] = NULL; + memset(vendor_class->oui[index], 0, 3); + /* Any OUIs left ? */ + if (!check_vendor_class(vendor_class)) { + /* If not, release vendor class table */ + kfree(vendor_class); + vendor->vendor_class[mgmt_class] = NULL; + /* Any other vendor classes left ? */ + if (!check_vendor_table(vendor)) { + kfree(vendor); + port_priv->version[ + agent_priv->reg_req-> + mgmt_class_version]. + vendor = NULL; + } + } + } + } + } + +out: + return; +} + +static struct ib_mad_agent_private * +find_mad_agent(struct ib_mad_port_private *port_priv, + struct ib_mad *mad) +{ + struct ib_mad_agent_private *mad_agent = NULL; + unsigned long flags; + + spin_lock_irqsave(&port_priv->reg_lock, flags); + if (ib_response_mad(mad)) { + u32 hi_tid; + struct ib_mad_agent_private *entry; + + /* + * Routing is based on high 32 bits of transaction ID + * of MAD. + */ + hi_tid = be64_to_cpu(mad->mad_hdr.tid) >> 32; + list_for_each_entry(entry, &port_priv->agent_list, agent_list) { + if (entry->agent.hi_tid == hi_tid) { + mad_agent = entry; + break; + } + } + } else { + struct ib_mad_mgmt_class_table *class; + struct ib_mad_mgmt_method_table *method; + struct ib_mad_mgmt_vendor_class_table *vendor; + struct ib_mad_mgmt_vendor_class *vendor_class; + struct ib_vendor_mad *vendor_mad; + int index; + + /* + * Routing is based on version, class, and method + * For "newer" vendor MADs, also based on OUI + */ + if (mad->mad_hdr.class_version >= MAX_MGMT_VERSION) + goto out; + if (!is_vendor_class(mad->mad_hdr.mgmt_class)) { + class = port_priv->version[ + mad->mad_hdr.class_version].class; + if (!class) + goto out; + method = class->method_table[convert_mgmt_class( + mad->mad_hdr.mgmt_class)]; + if (method) + mad_agent = method->agent[mad->mad_hdr.method & + ~IB_MGMT_METHOD_RESP]; + } else { + vendor = port_priv->version[ + mad->mad_hdr.class_version].vendor; + if (!vendor) + goto out; + vendor_class = vendor->vendor_class[vendor_class_index( + mad->mad_hdr.mgmt_class)]; + if (!vendor_class) + goto out; + /* Find matching OUI */ + vendor_mad = (struct ib_vendor_mad *)mad; + index = find_vendor_oui(vendor_class, vendor_mad->oui); + if (index == -1) + goto out; + method = vendor_class->method_table[index]; + if (method) { + mad_agent = method->agent[mad->mad_hdr.method & + ~IB_MGMT_METHOD_RESP]; + } + } + } + + if (mad_agent) { + if (mad_agent->agent.recv_handler) + atomic_inc(&mad_agent->refcount); + else { + printk(KERN_NOTICE PFX "No receive handler for client " + "%p on port %d\n", + &mad_agent->agent, port_priv->port_num); + mad_agent = NULL; + } + } +out: + spin_unlock_irqrestore(&port_priv->reg_lock, flags); + + return mad_agent; +} + +static int validate_mad(struct ib_mad *mad, u32 qp_num) +{ + int valid = 0; + + /* Make sure MAD base version is understood */ + if (mad->mad_hdr.base_version != IB_MGMT_BASE_VERSION) { + printk(KERN_ERR PFX "MAD received with unsupported base " + "version %d\n", mad->mad_hdr.base_version); + goto out; + } + + /* Filter SMI packets sent to other than QP0 */ + if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED) || + (mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)) { + if (qp_num == 0) + valid = 1; + } else { + /* Filter GSI packets sent to QP0 */ + if (qp_num != 0) + valid = 1; + } + +out: + return valid; +} + +static int is_data_mad(struct ib_mad_agent_private *mad_agent_priv, + struct ib_mad_hdr *mad_hdr) +{ + struct ib_rmpp_mad *rmpp_mad; + + rmpp_mad = (struct ib_rmpp_mad *)mad_hdr; + return !mad_agent_priv->agent.rmpp_version || + !(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & + IB_MGMT_RMPP_FLAG_ACTIVE) || + (rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_DATA); +} + +static inline int rcv_has_same_class(struct ib_mad_send_wr_private *wr, + struct ib_mad_recv_wc *rwc) +{ + return ((struct ib_mad *)(wr->send_buf.mad))->mad_hdr.mgmt_class == + rwc->recv_buf.mad->mad_hdr.mgmt_class; +} + +static inline int rcv_has_same_gid(struct ib_mad_agent_private *mad_agent_priv, + struct ib_mad_send_wr_private *wr, + struct ib_mad_recv_wc *rwc ) +{ + struct ib_ah_attr attr; + u8 send_resp, rcv_resp; + union ib_gid sgid; + struct ib_device *device = mad_agent_priv->agent.device; + u8 port_num = mad_agent_priv->agent.port_num; + u8 lmc; + + send_resp = ib_response_mad((struct ib_mad *)wr->send_buf.mad); + rcv_resp = ib_response_mad(rwc->recv_buf.mad); + + if (send_resp == rcv_resp) + /* both requests, or both responses. GIDs different */ + return 0; + + if (ib_query_ah(wr->send_buf.ah, &attr)) + /* Assume not equal, to avoid false positives. */ + return 0; + + if (!!(attr.ah_flags & IB_AH_GRH) != + !!(rwc->wc->wc_flags & IB_WC_GRH)) + /* one has GID, other does not. Assume different */ + return 0; + + if (!send_resp && rcv_resp) { + /* is request/response. */ + if (!(attr.ah_flags & IB_AH_GRH)) { + if (ib_get_cached_lmc(device, port_num, &lmc)) + return 0; + return (!lmc || !((attr.src_path_bits ^ + rwc->wc->dlid_path_bits) & + ((1 << lmc) - 1))); + } else { + if (ib_get_cached_gid(device, port_num, + attr.grh.sgid_index, &sgid)) + return 0; + return !memcmp(sgid.raw, rwc->recv_buf.grh->dgid.raw, + 16); + } + } + + if (!(attr.ah_flags & IB_AH_GRH)) + return attr.dlid == rwc->wc->slid; + else + return !memcmp(attr.grh.dgid.raw, rwc->recv_buf.grh->sgid.raw, + 16); +} + +static inline int is_direct(u8 class) +{ + return (class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE); +} + +struct ib_mad_send_wr_private* +ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, + struct ib_mad_recv_wc *wc) +{ + struct ib_mad_send_wr_private *wr; + struct ib_mad *mad; + + mad = (struct ib_mad *)wc->recv_buf.mad; + + list_for_each_entry(wr, &mad_agent_priv->wait_list, agent_list) { + if ((wr->tid == mad->mad_hdr.tid) && + rcv_has_same_class(wr, wc) && + /* + * Don't check GID for direct routed MADs. + * These might have permissive LIDs. + */ + (is_direct(wc->recv_buf.mad->mad_hdr.mgmt_class) || + rcv_has_same_gid(mad_agent_priv, wr, wc))) + return (wr->status == IB_WC_SUCCESS) ? wr : NULL; + } + + /* + * It's possible to receive the response before we've + * been notified that the send has completed + */ + list_for_each_entry(wr, &mad_agent_priv->send_list, agent_list) { + if (is_data_mad(mad_agent_priv, wr->send_buf.mad) && + wr->tid == mad->mad_hdr.tid && + wr->timeout && + rcv_has_same_class(wr, wc) && + /* + * Don't check GID for direct routed MADs. + * These might have permissive LIDs. + */ + (is_direct(wc->recv_buf.mad->mad_hdr.mgmt_class) || + rcv_has_same_gid(mad_agent_priv, wr, wc))) + /* Verify request has not been canceled */ + return (wr->status == IB_WC_SUCCESS) ? wr : NULL; + } + return NULL; +} + +void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr) +{ + mad_send_wr->timeout = 0; + if (mad_send_wr->refcount == 1) + list_move_tail(&mad_send_wr->agent_list, + &mad_send_wr->mad_agent_priv->done_list); +} + +static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_mad_send_wr_private *mad_send_wr; + struct ib_mad_send_wc mad_send_wc; + unsigned long flags; + + INIT_LIST_HEAD(&mad_recv_wc->rmpp_list); + list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list); + if (mad_agent_priv->agent.rmpp_version) { + mad_recv_wc = ib_process_rmpp_recv_wc(mad_agent_priv, + mad_recv_wc); + if (!mad_recv_wc) { + deref_mad_agent(mad_agent_priv); + return; + } + } + + /* Complete corresponding request */ + if (ib_response_mad(mad_recv_wc->recv_buf.mad)) { + spin_lock_irqsave(&mad_agent_priv->lock, flags); + mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc); + if (!mad_send_wr) { + spin_unlock_irqrestore(&mad_agent_priv->lock, flags); + ib_free_recv_mad(mad_recv_wc); + deref_mad_agent(mad_agent_priv); + return; + } + ib_mark_mad_done(mad_send_wr); + spin_unlock_irqrestore(&mad_agent_priv->lock, flags); + + /* Defined behavior is to complete response before request */ + mad_recv_wc->wc->wr_id = (unsigned long) &mad_send_wr->send_buf; + mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent, + mad_recv_wc); + atomic_dec(&mad_agent_priv->refcount); + + mad_send_wc.status = IB_WC_SUCCESS; + mad_send_wc.vendor_err = 0; + mad_send_wc.send_buf = &mad_send_wr->send_buf; + ib_mad_complete_send_wr(mad_send_wr, &mad_send_wc); + } else { + mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent, + mad_recv_wc); + deref_mad_agent(mad_agent_priv); + } +} + +static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv, + struct ib_wc *wc) +{ + struct ib_mad_qp_info *qp_info; + struct ib_mad_private_header *mad_priv_hdr; + struct ib_mad_private *recv, *response = NULL; + struct ib_mad_list_head *mad_list; + struct ib_mad_agent_private *mad_agent; + int port_num; + + mad_list = (struct ib_mad_list_head *)(unsigned long)wc->wr_id; + qp_info = mad_list->mad_queue->qp_info; + dequeue_mad(mad_list); + + mad_priv_hdr = container_of(mad_list, struct ib_mad_private_header, + mad_list); + recv = container_of(mad_priv_hdr, struct ib_mad_private, header); + ib_dma_unmap_single(port_priv->device, + recv->header.mapping, + sizeof(struct ib_mad_private) - + sizeof(struct ib_mad_private_header), + DMA_FROM_DEVICE); + + /* Setup MAD receive work completion from "normal" work completion */ + recv->header.wc = *wc; + recv->header.recv_wc.wc = &recv->header.wc; + recv->header.recv_wc.mad_len = sizeof(struct ib_mad); + recv->header.recv_wc.recv_buf.mad = &recv->mad.mad; + recv->header.recv_wc.recv_buf.grh = &recv->grh; + + if (atomic_read(&qp_info->snoop_count)) + snoop_recv(qp_info, &recv->header.recv_wc, IB_MAD_SNOOP_RECVS); + + /* Validate MAD */ + if (!validate_mad(&recv->mad.mad, qp_info->qp->qp_num)) + goto out; + + response = kmem_cache_alloc(ib_mad_cache, GFP_KERNEL); + if (!response) { + printk(KERN_ERR PFX "ib_mad_recv_done_handler no memory " + "for response buffer\n"); + goto out; + } + + if (port_priv->device->node_type == RDMA_NODE_IB_SWITCH) + port_num = wc->port_num; + else + port_num = port_priv->port_num; + + if (recv->mad.mad.mad_hdr.mgmt_class == + IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { + enum smi_forward_action retsmi; + + if (smi_handle_dr_smp_recv(&recv->mad.smp, + port_priv->device->node_type, + port_num, + port_priv->device->phys_port_cnt) == + IB_SMI_DISCARD) + goto out; + + retsmi = smi_check_forward_dr_smp(&recv->mad.smp); + if (retsmi == IB_SMI_LOCAL) + goto local; + + if (retsmi == IB_SMI_SEND) { /* don't forward */ + if (smi_handle_dr_smp_send(&recv->mad.smp, + port_priv->device->node_type, + port_num) == IB_SMI_DISCARD) + goto out; + + if (smi_check_local_smp(&recv->mad.smp, port_priv->device) == IB_SMI_DISCARD) + goto out; + } else if (port_priv->device->node_type == RDMA_NODE_IB_SWITCH) { + /* forward case for switches */ + memcpy(response, recv, sizeof(*response)); + response->header.recv_wc.wc = &response->header.wc; + response->header.recv_wc.recv_buf.mad = &response->mad.mad; + response->header.recv_wc.recv_buf.grh = &response->grh; + + agent_send_response(&response->mad.mad, + &response->grh, wc, + port_priv->device, + smi_get_fwd_port(&recv->mad.smp), + qp_info->qp->qp_num); + + goto out; + } + } + +local: + /* Give driver "right of first refusal" on incoming MAD */ + if (port_priv->device->process_mad) { + int ret; + + ret = port_priv->device->process_mad(port_priv->device, 0, + port_priv->port_num, + wc, &recv->grh, + &recv->mad.mad, + &response->mad.mad); + if (ret & IB_MAD_RESULT_SUCCESS) { + if (ret & IB_MAD_RESULT_CONSUMED) + goto out; + if (ret & IB_MAD_RESULT_REPLY) { + agent_send_response(&response->mad.mad, + &recv->grh, wc, + port_priv->device, + port_num, + qp_info->qp->qp_num); + goto out; + } + } + } + + mad_agent = find_mad_agent(port_priv, &recv->mad.mad); + if (mad_agent) { + ib_mad_complete_recv(mad_agent, &recv->header.recv_wc); + /* + * recv is freed up in error cases in ib_mad_complete_recv + * or via recv_handler in ib_mad_complete_recv() + */ + recv = NULL; + } + +out: + /* Post another receive request for this QP */ + if (response) { + ib_mad_post_receive_mads(qp_info, response); + if (recv) + kmem_cache_free(ib_mad_cache, recv); + } else + ib_mad_post_receive_mads(qp_info, recv); +} + +static void adjust_timeout(struct ib_mad_agent_private *mad_agent_priv) +{ + struct ib_mad_send_wr_private *mad_send_wr; + + if (list_empty(&mad_agent_priv->wait_list)) { + del_timer(&mad_agent_priv->timeout_timer); + } else { + mad_send_wr = list_entry(mad_agent_priv->wait_list.next, + struct ib_mad_send_wr_private, + agent_list); + + if (time_after(mad_agent_priv->timeout, + mad_send_wr->timeout)) { + mad_agent_priv->timeout = mad_send_wr->timeout; + mod_timer(&mad_agent_priv->timeout_timer, + mad_send_wr->timeout); + } + } +} + +static void wait_for_response(struct ib_mad_send_wr_private *mad_send_wr) +{ + struct ib_mad_agent_private *mad_agent_priv; + struct ib_mad_send_wr_private *temp_mad_send_wr; + struct list_head *list_item; + unsigned long delay; + + mad_agent_priv = mad_send_wr->mad_agent_priv; + list_del(&mad_send_wr->agent_list); + + delay = mad_send_wr->timeout; + mad_send_wr->timeout += jiffies; + + if (delay) { + list_for_each_prev(list_item, &mad_agent_priv->wait_list) { + temp_mad_send_wr = list_entry(list_item, + struct ib_mad_send_wr_private, + agent_list); + if (time_after(mad_send_wr->timeout, + temp_mad_send_wr->timeout)) + break; + } + } else + list_item = &mad_agent_priv->wait_list; + list_add(&mad_send_wr->agent_list, list_item); + + /* Reschedule a work item if we have a shorter timeout */ + if (mad_agent_priv->wait_list.next == &mad_send_wr->agent_list) + mod_timer(&mad_agent_priv->timeout_timer, + mad_send_wr->timeout); +} + +void ib_reset_mad_timeout(struct ib_mad_send_wr_private *mad_send_wr, + int timeout_ms) +{ + mad_send_wr->timeout = msecs_to_jiffies(timeout_ms); + wait_for_response(mad_send_wr); +} + +/* + * Process a send work completion + */ +void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr, + struct ib_mad_send_wc *mad_send_wc) +{ + struct ib_mad_agent_private *mad_agent_priv; + unsigned long flags; + int ret; + + mad_agent_priv = mad_send_wr->mad_agent_priv; + spin_lock_irqsave(&mad_agent_priv->lock, flags); + if (mad_agent_priv->agent.rmpp_version) { + ret = ib_process_rmpp_send_wc(mad_send_wr, mad_send_wc); + if (ret == IB_RMPP_RESULT_CONSUMED) + goto done; + } else + ret = IB_RMPP_RESULT_UNHANDLED; + + if (mad_send_wc->status != IB_WC_SUCCESS && + mad_send_wr->status == IB_WC_SUCCESS) { + mad_send_wr->status = mad_send_wc->status; + mad_send_wr->refcount -= (mad_send_wr->timeout > 0); + } + + if (--mad_send_wr->refcount > 0) { + if (mad_send_wr->refcount == 1 && mad_send_wr->timeout && + mad_send_wr->status == IB_WC_SUCCESS) { + wait_for_response(mad_send_wr); + } + goto done; + } + + /* Remove send from MAD agent and notify client of completion */ + list_del(&mad_send_wr->agent_list); + adjust_timeout(mad_agent_priv); + spin_unlock_irqrestore(&mad_agent_priv->lock, flags); + + if (mad_send_wr->status != IB_WC_SUCCESS ) + mad_send_wc->status = mad_send_wr->status; + if (ret == IB_RMPP_RESULT_INTERNAL) + ib_rmpp_send_handler(mad_send_wc); + else + mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, + mad_send_wc); + + /* Release reference on agent taken when sending */ + deref_mad_agent(mad_agent_priv); + return; +done: + spin_unlock_irqrestore(&mad_agent_priv->lock, flags); +} + +static void ib_mad_send_done_handler(struct ib_mad_port_private *port_priv, + struct ib_wc *wc) +{ + struct ib_mad_send_wr_private *mad_send_wr, *queued_send_wr; + struct ib_mad_list_head *mad_list; + struct ib_mad_qp_info *qp_info; + struct ib_mad_queue *send_queue; + struct ib_send_wr *bad_send_wr; + struct ib_mad_send_wc mad_send_wc; + unsigned long flags; + int ret; + + mad_list = (struct ib_mad_list_head *)(unsigned long)wc->wr_id; + mad_send_wr = container_of(mad_list, struct ib_mad_send_wr_private, + mad_list); + send_queue = mad_list->mad_queue; + qp_info = send_queue->qp_info; + +retry: + ib_dma_unmap_single(mad_send_wr->send_buf.mad_agent->device, + mad_send_wr->header_mapping, + mad_send_wr->sg_list[0].length, DMA_TO_DEVICE); + ib_dma_unmap_single(mad_send_wr->send_buf.mad_agent->device, + mad_send_wr->payload_mapping, + mad_send_wr->sg_list[1].length, DMA_TO_DEVICE); + queued_send_wr = NULL; + spin_lock_irqsave(&send_queue->lock, flags); + list_del(&mad_list->list); + + /* Move queued send to the send queue */ + if (send_queue->count-- > send_queue->max_active) { + mad_list = container_of(qp_info->overflow_list.next, + struct ib_mad_list_head, list); + queued_send_wr = container_of(mad_list, + struct ib_mad_send_wr_private, + mad_list); + list_move_tail(&mad_list->list, &send_queue->list); + } + spin_unlock_irqrestore(&send_queue->lock, flags); + + mad_send_wc.send_buf = &mad_send_wr->send_buf; + mad_send_wc.status = wc->status; + mad_send_wc.vendor_err = wc->vendor_err; + if (atomic_read(&qp_info->snoop_count)) + snoop_send(qp_info, &mad_send_wr->send_buf, &mad_send_wc, + IB_MAD_SNOOP_SEND_COMPLETIONS); + ib_mad_complete_send_wr(mad_send_wr, &mad_send_wc); + + if (queued_send_wr) { + ret = ib_post_send(qp_info->qp, &queued_send_wr->send_wr, + &bad_send_wr); + if (ret) { + printk(KERN_ERR PFX "ib_post_send failed: %d\n", ret); + mad_send_wr = queued_send_wr; + wc->status = IB_WC_LOC_QP_OP_ERR; + goto retry; + } + } +} + +static void mark_sends_for_retry(struct ib_mad_qp_info *qp_info) +{ + struct ib_mad_send_wr_private *mad_send_wr; + struct ib_mad_list_head *mad_list; + unsigned long flags; + + spin_lock_irqsave(&qp_info->send_queue.lock, flags); + list_for_each_entry(mad_list, &qp_info->send_queue.list, list) { + mad_send_wr = container_of(mad_list, + struct ib_mad_send_wr_private, + mad_list); + mad_send_wr->retry = 1; + } + spin_unlock_irqrestore(&qp_info->send_queue.lock, flags); +} + +static void mad_error_handler(struct ib_mad_port_private *port_priv, + struct ib_wc *wc) +{ + struct ib_mad_list_head *mad_list; + struct ib_mad_qp_info *qp_info; + struct ib_mad_send_wr_private *mad_send_wr; + int ret; + + /* Determine if failure was a send or receive */ + mad_list = (struct ib_mad_list_head *)(unsigned long)wc->wr_id; + qp_info = mad_list->mad_queue->qp_info; + if (mad_list->mad_queue == &qp_info->recv_queue) + /* + * Receive errors indicate that the QP has entered the error + * state - error handling/shutdown code will cleanup + */ + return; + + /* + * Send errors will transition the QP to SQE - move + * QP to RTS and repost flushed work requests + */ + mad_send_wr = container_of(mad_list, struct ib_mad_send_wr_private, + mad_list); + if (wc->status == IB_WC_WR_FLUSH_ERR) { + if (mad_send_wr->retry) { + /* Repost send */ + struct ib_send_wr *bad_send_wr; + + mad_send_wr->retry = 0; + ret = ib_post_send(qp_info->qp, &mad_send_wr->send_wr, + &bad_send_wr); + if (ret) + ib_mad_send_done_handler(port_priv, wc); + } else + ib_mad_send_done_handler(port_priv, wc); + } else { + struct ib_qp_attr *attr; + + /* Transition QP to RTS and fail offending send */ + attr = kmalloc(sizeof *attr, GFP_KERNEL); + if (attr) { + attr->qp_state = IB_QPS_RTS; + attr->cur_qp_state = IB_QPS_SQE; + ret = ib_modify_qp(qp_info->qp, attr, + IB_QP_STATE | IB_QP_CUR_STATE); + kfree(attr); + if (ret) + printk(KERN_ERR PFX "mad_error_handler - " + "ib_modify_qp to RTS : %d\n", ret); + else + mark_sends_for_retry(qp_info); + } + ib_mad_send_done_handler(port_priv, wc); + } +} + +/* + * IB MAD completion callback + */ +static void ib_mad_completion_handler(struct work_struct *work) +{ + struct ib_mad_port_private *port_priv; + struct ib_wc wc; + + port_priv = container_of(work, struct ib_mad_port_private, work); + ib_req_notify_cq(port_priv->cq, IB_CQ_NEXT_COMP); + + while (ib_poll_cq(port_priv->cq, 1, &wc) == 1) { + if (wc.status == IB_WC_SUCCESS) { + switch (wc.opcode) { + case IB_WC_SEND: + ib_mad_send_done_handler(port_priv, &wc); + break; + case IB_WC_RECV: + ib_mad_recv_done_handler(port_priv, &wc); + break; + default: + BUG_ON(1); + break; + } + } else + mad_error_handler(port_priv, &wc); + } +} + +static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv) +{ + unsigned long flags; + struct ib_mad_send_wr_private *mad_send_wr, *temp_mad_send_wr; + struct ib_mad_send_wc mad_send_wc; + struct list_head cancel_list; + + INIT_LIST_HEAD(&cancel_list); + + spin_lock_irqsave(&mad_agent_priv->lock, flags); + list_for_each_entry_safe(mad_send_wr, temp_mad_send_wr, + &mad_agent_priv->send_list, agent_list) { + if (mad_send_wr->status == IB_WC_SUCCESS) { + mad_send_wr->status = IB_WC_WR_FLUSH_ERR; + mad_send_wr->refcount -= (mad_send_wr->timeout > 0); + } + } + + /* Empty wait list to prevent receives from finding a request */ + list_splice_init(&mad_agent_priv->wait_list, &cancel_list); + spin_unlock_irqrestore(&mad_agent_priv->lock, flags); + + /* Report all cancelled requests */ + mad_send_wc.status = IB_WC_WR_FLUSH_ERR; + mad_send_wc.vendor_err = 0; + + list_for_each_entry_safe(mad_send_wr, temp_mad_send_wr, + &cancel_list, agent_list) { + mad_send_wc.send_buf = &mad_send_wr->send_buf; + list_del(&mad_send_wr->agent_list); + mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, + &mad_send_wc); + atomic_dec(&mad_agent_priv->refcount); + } +} + +static struct ib_mad_send_wr_private* +find_send_wr(struct ib_mad_agent_private *mad_agent_priv, + struct ib_mad_send_buf *send_buf) +{ + struct ib_mad_send_wr_private *mad_send_wr; + + list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list, + agent_list) { + if (&mad_send_wr->send_buf == send_buf) + return mad_send_wr; + } + + list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list, + agent_list) { + if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) && + &mad_send_wr->send_buf == send_buf) + return mad_send_wr; + } + return NULL; +} + +int ib_modify_mad(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf, u32 timeout_ms) +{ + struct ib_mad_agent_private *mad_agent_priv; + struct ib_mad_send_wr_private *mad_send_wr; + unsigned long flags; + int active; + + mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private, + agent); + spin_lock_irqsave(&mad_agent_priv->lock, flags); + mad_send_wr = find_send_wr(mad_agent_priv, send_buf); + if (!mad_send_wr || mad_send_wr->status != IB_WC_SUCCESS) { + spin_unlock_irqrestore(&mad_agent_priv->lock, flags); + return -EINVAL; + } + + active = (!mad_send_wr->timeout || mad_send_wr->refcount > 1); + if (!timeout_ms) { + mad_send_wr->status = IB_WC_WR_FLUSH_ERR; + mad_send_wr->refcount -= (mad_send_wr->timeout > 0); + } + + mad_send_wr->send_buf.timeout_ms = timeout_ms; + if (active) + mad_send_wr->timeout = msecs_to_jiffies(timeout_ms); + else + ib_reset_mad_timeout(mad_send_wr, timeout_ms); + + spin_unlock_irqrestore(&mad_agent_priv->lock, flags); + return 0; +} +EXPORT_SYMBOL(ib_modify_mad); + +void ib_cancel_mad(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf) +{ + ib_modify_mad(mad_agent, send_buf, 0); +} +EXPORT_SYMBOL(ib_cancel_mad); + +static void local_completions(struct work_struct *work) +{ + struct ib_mad_agent_private *mad_agent_priv; + struct ib_mad_local_private *local; + struct ib_mad_agent_private *recv_mad_agent; + unsigned long flags; + int free_mad; + struct ib_wc wc; + struct ib_mad_send_wc mad_send_wc; + + mad_agent_priv = + container_of(work, struct ib_mad_agent_private, local_work); + + spin_lock_irqsave(&mad_agent_priv->lock, flags); + while (!list_empty(&mad_agent_priv->local_list)) { + local = list_entry(mad_agent_priv->local_list.next, + struct ib_mad_local_private, + completion_list); + list_del(&local->completion_list); + spin_unlock_irqrestore(&mad_agent_priv->lock, flags); + free_mad = 0; + if (local->mad_priv) { + recv_mad_agent = local->recv_mad_agent; + if (!recv_mad_agent) { + printk(KERN_ERR PFX "No receive MAD agent for local completion\n"); + free_mad = 1; + goto local_send_completion; + } + + /* + * Defined behavior is to complete response + * before request + */ + build_smp_wc(recv_mad_agent->agent.qp, + (unsigned long) local->mad_send_wr, + be16_to_cpu(IB_LID_PERMISSIVE), + 0, recv_mad_agent->agent.port_num, &wc); + + local->mad_priv->header.recv_wc.wc = &wc; + local->mad_priv->header.recv_wc.mad_len = + sizeof(struct ib_mad); + INIT_LIST_HEAD(&local->mad_priv->header.recv_wc.rmpp_list); + list_add(&local->mad_priv->header.recv_wc.recv_buf.list, + &local->mad_priv->header.recv_wc.rmpp_list); + local->mad_priv->header.recv_wc.recv_buf.grh = NULL; + local->mad_priv->header.recv_wc.recv_buf.mad = + &local->mad_priv->mad.mad; + if (atomic_read(&recv_mad_agent->qp_info->snoop_count)) + snoop_recv(recv_mad_agent->qp_info, + &local->mad_priv->header.recv_wc, + IB_MAD_SNOOP_RECVS); + recv_mad_agent->agent.recv_handler( + &recv_mad_agent->agent, + &local->mad_priv->header.recv_wc); + spin_lock_irqsave(&recv_mad_agent->lock, flags); + atomic_dec(&recv_mad_agent->refcount); + spin_unlock_irqrestore(&recv_mad_agent->lock, flags); + } + +local_send_completion: + /* Complete send */ + mad_send_wc.status = IB_WC_SUCCESS; + mad_send_wc.vendor_err = 0; + mad_send_wc.send_buf = &local->mad_send_wr->send_buf; + if (atomic_read(&mad_agent_priv->qp_info->snoop_count)) + snoop_send(mad_agent_priv->qp_info, + &local->mad_send_wr->send_buf, + &mad_send_wc, IB_MAD_SNOOP_SEND_COMPLETIONS); + mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, + &mad_send_wc); + + spin_lock_irqsave(&mad_agent_priv->lock, flags); + atomic_dec(&mad_agent_priv->refcount); + if (free_mad) + kmem_cache_free(ib_mad_cache, local->mad_priv); + kfree(local); + } + spin_unlock_irqrestore(&mad_agent_priv->lock, flags); +} + +static int retry_send(struct ib_mad_send_wr_private *mad_send_wr) +{ + int ret; + + if (!mad_send_wr->retries_left) + return -ETIMEDOUT; + + mad_send_wr->retries_left--; + mad_send_wr->send_buf.retries++; + + mad_send_wr->timeout = msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms); + + if (mad_send_wr->mad_agent_priv->agent.rmpp_version) { + ret = ib_retry_rmpp(mad_send_wr); + switch (ret) { + case IB_RMPP_RESULT_UNHANDLED: + ret = ib_send_mad(mad_send_wr); + break; + case IB_RMPP_RESULT_CONSUMED: + ret = 0; + break; + default: + ret = -ECOMM; + break; + } + } else + ret = ib_send_mad(mad_send_wr); + + if (!ret) { + mad_send_wr->refcount++; + list_add_tail(&mad_send_wr->agent_list, + &mad_send_wr->mad_agent_priv->send_list); + } + return ret; +} + +static void timeout_sends(struct work_struct *work) +{ + struct ib_mad_agent_private *mad_agent_priv; + struct ib_mad_send_wr_private *mad_send_wr; + struct ib_mad_send_wc mad_send_wc; + unsigned long flags; + + mad_agent_priv = container_of(work, struct ib_mad_agent_private, + timeout_work); + mad_send_wc.vendor_err = 0; + + spin_lock_irqsave(&mad_agent_priv->lock, flags); + while (!list_empty(&mad_agent_priv->wait_list)) { + mad_send_wr = list_entry(mad_agent_priv->wait_list.next, + struct ib_mad_send_wr_private, + agent_list); + + if (time_after(mad_send_wr->timeout, jiffies)) { + mod_timer(&mad_agent_priv->timeout_timer, + mad_send_wr->timeout); + break; + } + + list_del(&mad_send_wr->agent_list); + if (mad_send_wr->status == IB_WC_SUCCESS && + !retry_send(mad_send_wr)) + continue; + + spin_unlock_irqrestore(&mad_agent_priv->lock, flags); + + if (mad_send_wr->status == IB_WC_SUCCESS) + mad_send_wc.status = IB_WC_RESP_TIMEOUT_ERR; + else + mad_send_wc.status = mad_send_wr->status; + mad_send_wc.send_buf = &mad_send_wr->send_buf; + mad_agent_priv->agent.send_handler(&mad_agent_priv->agent, + &mad_send_wc); + + atomic_dec(&mad_agent_priv->refcount); + spin_lock_irqsave(&mad_agent_priv->lock, flags); + } + spin_unlock_irqrestore(&mad_agent_priv->lock, flags); +} + +static void ib_mad_thread_completion_handler(struct ib_cq *cq, void *arg) +{ + struct ib_mad_port_private *port_priv = cq->cq_context; + unsigned long flags; + + spin_lock_irqsave(&ib_mad_port_list_lock, flags); + if (!list_empty(&port_priv->port_list)) + queue_work(port_priv->wq, &port_priv->work); + spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); +} + +/* + * Allocate receive MADs and post receive WRs for them + */ +static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info, + struct ib_mad_private *mad) +{ + unsigned long flags; + int post, ret; + struct ib_mad_private *mad_priv; + struct ib_sge sg_list; + struct ib_recv_wr recv_wr, *bad_recv_wr; + struct ib_mad_queue *recv_queue = &qp_info->recv_queue; + + /* Initialize common scatter list fields */ + sg_list.length = sizeof *mad_priv - sizeof mad_priv->header; + sg_list.lkey = (*qp_info->port_priv->mr).lkey; + + /* Initialize common receive WR fields */ + recv_wr.next = NULL; + recv_wr.sg_list = &sg_list; + recv_wr.num_sge = 1; + + do { + /* Allocate and map receive buffer */ + if (mad) { + mad_priv = mad; + mad = NULL; + } else { + mad_priv = kmem_cache_alloc(ib_mad_cache, GFP_KERNEL); + if (!mad_priv) { + printk(KERN_ERR PFX "No memory for receive buffer\n"); + ret = -ENOMEM; + break; + } + } + sg_list.addr = ib_dma_map_single(qp_info->port_priv->device, + &mad_priv->grh, + sizeof *mad_priv - + sizeof mad_priv->header, + DMA_FROM_DEVICE); + mad_priv->header.mapping = sg_list.addr; + recv_wr.wr_id = (unsigned long)&mad_priv->header.mad_list; + mad_priv->header.mad_list.mad_queue = recv_queue; + + /* Post receive WR */ + spin_lock_irqsave(&recv_queue->lock, flags); + post = (++recv_queue->count < recv_queue->max_active); + list_add_tail(&mad_priv->header.mad_list.list, &recv_queue->list); + spin_unlock_irqrestore(&recv_queue->lock, flags); + ret = ib_post_recv(qp_info->qp, &recv_wr, &bad_recv_wr); + if (ret) { + spin_lock_irqsave(&recv_queue->lock, flags); + list_del(&mad_priv->header.mad_list.list); + recv_queue->count--; + spin_unlock_irqrestore(&recv_queue->lock, flags); + ib_dma_unmap_single(qp_info->port_priv->device, + mad_priv->header.mapping, + sizeof *mad_priv - + sizeof mad_priv->header, + DMA_FROM_DEVICE); + kmem_cache_free(ib_mad_cache, mad_priv); + printk(KERN_ERR PFX "ib_post_recv failed: %d\n", ret); + break; + } + } while (post); + + return ret; +} + +/* + * Return all the posted receive MADs + */ +static void cleanup_recv_queue(struct ib_mad_qp_info *qp_info) +{ + struct ib_mad_private_header *mad_priv_hdr; + struct ib_mad_private *recv; + struct ib_mad_list_head *mad_list; + + if (!qp_info->qp) + return; + + while (!list_empty(&qp_info->recv_queue.list)) { + + mad_list = list_entry(qp_info->recv_queue.list.next, + struct ib_mad_list_head, list); + mad_priv_hdr = container_of(mad_list, + struct ib_mad_private_header, + mad_list); + recv = container_of(mad_priv_hdr, struct ib_mad_private, + header); + + /* Remove from posted receive MAD list */ + list_del(&mad_list->list); + + ib_dma_unmap_single(qp_info->port_priv->device, + recv->header.mapping, + sizeof(struct ib_mad_private) - + sizeof(struct ib_mad_private_header), + DMA_FROM_DEVICE); + kmem_cache_free(ib_mad_cache, recv); + } + + qp_info->recv_queue.count = 0; +} + +/* + * Start the port + */ +static int ib_mad_port_start(struct ib_mad_port_private *port_priv) +{ + int ret, i; + struct ib_qp_attr *attr; + struct ib_qp *qp; + + attr = kmalloc(sizeof *attr, GFP_KERNEL); + if (!attr) { + printk(KERN_ERR PFX "Couldn't kmalloc ib_qp_attr\n"); + return -ENOMEM; + } + + for (i = 0; i < IB_MAD_QPS_CORE; i++) { + qp = port_priv->qp_info[i].qp; + if (!qp) + continue; + + /* + * PKey index for QP1 is irrelevant but + * one is needed for the Reset to Init transition + */ + attr->qp_state = IB_QPS_INIT; + attr->pkey_index = 0; + attr->qkey = (qp->qp_num == 0) ? 0 : IB_QP1_QKEY; + ret = ib_modify_qp(qp, attr, IB_QP_STATE | + IB_QP_PKEY_INDEX | IB_QP_QKEY); + if (ret) { + printk(KERN_ERR PFX "Couldn't change QP%d state to " + "INIT: %d\n", i, ret); + goto out; + } + + attr->qp_state = IB_QPS_RTR; + ret = ib_modify_qp(qp, attr, IB_QP_STATE); + if (ret) { + printk(KERN_ERR PFX "Couldn't change QP%d state to " + "RTR: %d\n", i, ret); + goto out; + } + + attr->qp_state = IB_QPS_RTS; + attr->sq_psn = IB_MAD_SEND_Q_PSN; + ret = ib_modify_qp(qp, attr, IB_QP_STATE | IB_QP_SQ_PSN); + if (ret) { + printk(KERN_ERR PFX "Couldn't change QP%d state to " + "RTS: %d\n", i, ret); + goto out; + } + } + + ret = ib_req_notify_cq(port_priv->cq, IB_CQ_NEXT_COMP); + if (ret) { + printk(KERN_ERR PFX "Failed to request completion " + "notification: %d\n", ret); + goto out; + } + + for (i = 0; i < IB_MAD_QPS_CORE; i++) { + if (!port_priv->qp_info[i].qp) + continue; + + ret = ib_mad_post_receive_mads(&port_priv->qp_info[i], NULL); + if (ret) { + printk(KERN_ERR PFX "Couldn't post receive WRs\n"); + goto out; + } + } +out: + kfree(attr); + return ret; +} + +static void qp_event_handler(struct ib_event *event, void *qp_context) +{ + struct ib_mad_qp_info *qp_info = qp_context; + + /* It's worse than that! He's dead, Jim! */ + printk(KERN_ERR PFX "Fatal error (%d) on MAD QP (%d)\n", + event->event, qp_info->qp->qp_num); +} + +static void init_mad_queue(struct ib_mad_qp_info *qp_info, + struct ib_mad_queue *mad_queue) +{ + mad_queue->qp_info = qp_info; + mad_queue->count = 0; + spin_lock_init(&mad_queue->lock); + INIT_LIST_HEAD(&mad_queue->list); +} + +static void init_mad_qp(struct ib_mad_port_private *port_priv, + struct ib_mad_qp_info *qp_info) +{ + qp_info->port_priv = port_priv; + init_mad_queue(qp_info, &qp_info->send_queue); + init_mad_queue(qp_info, &qp_info->recv_queue); + INIT_LIST_HEAD(&qp_info->overflow_list); + spin_lock_init(&qp_info->snoop_lock); + qp_info->snoop_table = NULL; + qp_info->snoop_table_size = 0; + atomic_set(&qp_info->snoop_count, 0); +} + +static int create_mad_qp(struct ib_mad_qp_info *qp_info, + enum ib_qp_type qp_type) +{ + struct ib_qp_init_attr qp_init_attr; + int ret; + + memset(&qp_init_attr, 0, sizeof qp_init_attr); + qp_init_attr.send_cq = qp_info->port_priv->cq; + qp_init_attr.recv_cq = qp_info->port_priv->cq; + qp_init_attr.sq_sig_type = IB_SIGNAL_ALL_WR; + qp_init_attr.cap.max_send_wr = mad_sendq_size; + qp_init_attr.cap.max_recv_wr = mad_recvq_size; + qp_init_attr.cap.max_send_sge = IB_MAD_SEND_REQ_MAX_SG; + qp_init_attr.cap.max_recv_sge = IB_MAD_RECV_REQ_MAX_SG; + qp_init_attr.qp_type = qp_type; + qp_init_attr.port_num = qp_info->port_priv->port_num; + qp_init_attr.qp_context = qp_info; + qp_init_attr.event_handler = qp_event_handler; + qp_info->qp = ib_create_qp(qp_info->port_priv->pd, &qp_init_attr); + if (IS_ERR(qp_info->qp)) { + printk(KERN_ERR PFX "Couldn't create ib_mad QP%d\n", + get_spl_qp_index(qp_type)); + ret = PTR_ERR(qp_info->qp); + goto error; + } + /* Use minimum queue sizes unless the CQ is resized */ + qp_info->send_queue.max_active = mad_sendq_size; + qp_info->recv_queue.max_active = mad_recvq_size; + return 0; + +error: + return ret; +} + +static void destroy_mad_qp(struct ib_mad_qp_info *qp_info) +{ + if (!qp_info->qp) + return; + + ib_destroy_qp(qp_info->qp); + kfree(qp_info->snoop_table); +} + +/* + * Open the port + * Create the QP, PD, MR, and CQ if needed + */ +static int ib_mad_port_open(struct ib_device *device, + int port_num) +{ + int ret, cq_size; + struct ib_mad_port_private *port_priv; + unsigned long flags; + char name[sizeof "ib_mad123"]; + int has_smi; + + /* Create new device info */ + port_priv = kzalloc(sizeof *port_priv, GFP_KERNEL); + if (!port_priv) { + printk(KERN_ERR PFX "No memory for ib_mad_port_private\n"); + return -ENOMEM; + } + + port_priv->device = device; + port_priv->port_num = port_num; + spin_lock_init(&port_priv->reg_lock); + INIT_LIST_HEAD(&port_priv->agent_list); + init_mad_qp(port_priv, &port_priv->qp_info[0]); + init_mad_qp(port_priv, &port_priv->qp_info[1]); + + cq_size = mad_sendq_size + mad_recvq_size; + has_smi = rdma_port_get_link_layer(device, port_num) == IB_LINK_LAYER_INFINIBAND; + if (has_smi) + cq_size *= 2; + + port_priv->cq = ib_create_cq(port_priv->device, + ib_mad_thread_completion_handler, + NULL, port_priv, cq_size, 0); + if (IS_ERR(port_priv->cq)) { + printk(KERN_ERR PFX "Couldn't create ib_mad CQ\n"); + ret = PTR_ERR(port_priv->cq); + goto error3; + } + + port_priv->pd = ib_alloc_pd(device); + if (IS_ERR(port_priv->pd)) { + printk(KERN_ERR PFX "Couldn't create ib_mad PD\n"); + ret = PTR_ERR(port_priv->pd); + goto error4; + } + + port_priv->mr = ib_get_dma_mr(port_priv->pd, IB_ACCESS_LOCAL_WRITE); + if (IS_ERR(port_priv->mr)) { + printk(KERN_ERR PFX "Couldn't get ib_mad DMA MR\n"); + ret = PTR_ERR(port_priv->mr); + goto error5; + } + + if (has_smi) { + ret = create_mad_qp(&port_priv->qp_info[0], IB_QPT_SMI); + if (ret) + goto error6; + } + ret = create_mad_qp(&port_priv->qp_info[1], IB_QPT_GSI); + if (ret) + goto error7; + + snprintf(name, sizeof name, "ib_mad%d", port_num); + port_priv->wq = create_singlethread_workqueue(name); + if (!port_priv->wq) { + ret = -ENOMEM; + goto error8; + } + INIT_WORK(&port_priv->work, ib_mad_completion_handler); + + spin_lock_irqsave(&ib_mad_port_list_lock, flags); + list_add_tail(&port_priv->port_list, &ib_mad_port_list); + spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); + + ret = ib_mad_port_start(port_priv); + if (ret) { + printk(KERN_ERR PFX "Couldn't start port\n"); + goto error9; + } + + return 0; + +error9: + spin_lock_irqsave(&ib_mad_port_list_lock, flags); + list_del_init(&port_priv->port_list); + spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); + + destroy_workqueue(port_priv->wq); +error8: + destroy_mad_qp(&port_priv->qp_info[1]); +error7: + destroy_mad_qp(&port_priv->qp_info[0]); +error6: + ib_dereg_mr(port_priv->mr); +error5: + ib_dealloc_pd(port_priv->pd); +error4: + ib_destroy_cq(port_priv->cq); + cleanup_recv_queue(&port_priv->qp_info[1]); + cleanup_recv_queue(&port_priv->qp_info[0]); +error3: + kfree(port_priv); + + return ret; +} + +/* + * Close the port + * If there are no classes using the port, free the port + * resources (CQ, MR, PD, QP) and remove the port's info structure + */ +static int ib_mad_port_close(struct ib_device *device, int port_num) +{ + struct ib_mad_port_private *port_priv; + unsigned long flags; + + spin_lock_irqsave(&ib_mad_port_list_lock, flags); + port_priv = __ib_get_mad_port(device, port_num); + if (port_priv == NULL) { + spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); + printk(KERN_ERR PFX "Port %d not found\n", port_num); + return -ENODEV; + } + list_del_init(&port_priv->port_list); + spin_unlock_irqrestore(&ib_mad_port_list_lock, flags); + + destroy_workqueue(port_priv->wq); + destroy_mad_qp(&port_priv->qp_info[1]); + destroy_mad_qp(&port_priv->qp_info[0]); + ib_dereg_mr(port_priv->mr); + ib_dealloc_pd(port_priv->pd); + ib_destroy_cq(port_priv->cq); + cleanup_recv_queue(&port_priv->qp_info[1]); + cleanup_recv_queue(&port_priv->qp_info[0]); + /* XXX: Handle deallocation of MAD registration tables */ + + kfree(port_priv); + + return 0; +} + +static void ib_mad_init_device(struct ib_device *device) +{ + int start, end, i; + + if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) + return; + + if (device->node_type == RDMA_NODE_IB_SWITCH) { + start = 0; + end = 0; + } else { + start = 1; + end = device->phys_port_cnt; + } + + for (i = start; i <= end; i++) { + if (ib_mad_port_open(device, i)) { + printk(KERN_ERR PFX "Couldn't open %s port %d\n", + device->name, i); + goto error; + } + if (ib_agent_port_open(device, i)) { + printk(KERN_ERR PFX "Couldn't open %s port %d " + "for agents\n", + device->name, i); + goto error_agent; + } + } + return; + +error_agent: + if (ib_mad_port_close(device, i)) + printk(KERN_ERR PFX "Couldn't close %s port %d\n", + device->name, i); + +error: + i--; + + while (i >= start) { + if (ib_agent_port_close(device, i)) + printk(KERN_ERR PFX "Couldn't close %s port %d " + "for agents\n", + device->name, i); + if (ib_mad_port_close(device, i)) + printk(KERN_ERR PFX "Couldn't close %s port %d\n", + device->name, i); + i--; + } +} + +static void ib_mad_remove_device(struct ib_device *device) +{ + int i, num_ports, cur_port; + + if (device->node_type == RDMA_NODE_IB_SWITCH) { + num_ports = 1; + cur_port = 0; + } else { + num_ports = device->phys_port_cnt; + cur_port = 1; + } + for (i = 0; i < num_ports; i++, cur_port++) { + if (ib_agent_port_close(device, cur_port)) + printk(KERN_ERR PFX "Couldn't close %s port %d " + "for agents\n", + device->name, cur_port); + if (ib_mad_port_close(device, cur_port)) + printk(KERN_ERR PFX "Couldn't close %s port %d\n", + device->name, cur_port); + } +} + +static struct ib_client mad_client = { + .name = "mad", + .add = ib_mad_init_device, + .remove = ib_mad_remove_device +}; + +static int __init ib_mad_init_module(void) +{ + int ret; + + mad_recvq_size = min(mad_recvq_size, IB_MAD_QP_MAX_SIZE); + mad_recvq_size = max(mad_recvq_size, IB_MAD_QP_MIN_SIZE); + + mad_sendq_size = min(mad_sendq_size, IB_MAD_QP_MAX_SIZE); + mad_sendq_size = max(mad_sendq_size, IB_MAD_QP_MIN_SIZE); + + spin_lock_init(&ib_mad_port_list_lock); + + ib_mad_cache = kmem_cache_create("ib_mad", + sizeof(struct ib_mad_private), + 0, + SLAB_HWCACHE_ALIGN, + NULL); + if (!ib_mad_cache) { + printk(KERN_ERR PFX "Couldn't create ib_mad cache\n"); + ret = -ENOMEM; + goto error1; + } + + INIT_LIST_HEAD(&ib_mad_port_list); + + if (ib_register_client(&mad_client)) { + printk(KERN_ERR PFX "Couldn't register ib_mad client\n"); + ret = -EINVAL; + goto error2; + } + + return 0; + +error2: + kmem_cache_destroy(ib_mad_cache); +error1: + return ret; +} + +static void __exit ib_mad_cleanup_module(void) +{ + ib_unregister_client(&mad_client); + kmem_cache_destroy(ib_mad_cache); +} + +module_init(ib_mad_init_module); +module_exit(ib_mad_cleanup_module); + diff --git a/sys/ofed/drivers/infiniband/core/mad_priv.h b/sys/ofed/drivers/infiniband/core/mad_priv.h new file mode 100644 index 000000000000..8b4df0a33e0b --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/mad_priv.h @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2004, 2005, Voltaire, Inc. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2009 HNR Consulting. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __IB_MAD_PRIV_H__ +#define __IB_MAD_PRIV_H__ + +#include +#include +#include +#include +#include + + +#define PFX "ib_mad: " + +#define IB_MAD_QPS_CORE 2 /* Always QP0 and QP1 as a minimum */ + +/* QP and CQ parameters */ +#define IB_MAD_QP_SEND_SIZE 128 +#define IB_MAD_QP_RECV_SIZE 512 +#define IB_MAD_QP_MIN_SIZE 64 +#define IB_MAD_QP_MAX_SIZE 8192 +#define IB_MAD_SEND_REQ_MAX_SG 2 +#define IB_MAD_RECV_REQ_MAX_SG 1 + +#define IB_MAD_SEND_Q_PSN 0 + +/* Registration table sizes */ +#define MAX_MGMT_CLASS 80 +#define MAX_MGMT_VERSION 8 +#define MAX_MGMT_OUI 8 +#define MAX_MGMT_VENDOR_RANGE2 (IB_MGMT_CLASS_VENDOR_RANGE2_END - \ + IB_MGMT_CLASS_VENDOR_RANGE2_START + 1) + +struct ib_mad_list_head { + struct list_head list; + struct ib_mad_queue *mad_queue; +}; + +struct ib_mad_private_header { + struct ib_mad_list_head mad_list; + struct ib_mad_recv_wc recv_wc; + struct ib_wc wc; + u64 mapping; +} __attribute__ ((packed)); + +struct ib_mad_private { + struct ib_mad_private_header header; + struct ib_grh grh; + union { + struct ib_mad mad; + struct ib_rmpp_mad rmpp_mad; + struct ib_smp smp; + } mad; +} __attribute__ ((packed)); + +struct ib_rmpp_segment { + struct list_head list; + u32 num; + u8 data[0]; +}; + +struct ib_mad_agent_private { + struct list_head agent_list; + struct ib_mad_agent agent; + struct ib_mad_reg_req *reg_req; + struct ib_mad_qp_info *qp_info; + + spinlock_t lock; + struct list_head send_list; + struct list_head wait_list; + struct list_head done_list; + struct work_struct timeout_work; + struct timer_list timeout_timer; + unsigned long timeout; + struct list_head local_list; + struct work_struct local_work; + struct list_head rmpp_list; + + atomic_t refcount; + struct completion comp; +}; + +struct ib_mad_snoop_private { + struct ib_mad_agent agent; + struct ib_mad_qp_info *qp_info; + int snoop_index; + int mad_snoop_flags; + atomic_t refcount; + struct completion comp; +}; + +struct ib_mad_send_wr_private { + struct ib_mad_list_head mad_list; + struct list_head agent_list; + struct ib_mad_agent_private *mad_agent_priv; + struct ib_mad_send_buf send_buf; + u64 header_mapping; + u64 payload_mapping; + struct ib_send_wr send_wr; + struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG]; + __be64 tid; + unsigned long timeout; + int max_retries; + int retries_left; + int retry; + int refcount; + enum ib_wc_status status; + + /* RMPP control */ + struct list_head rmpp_list; + struct ib_rmpp_segment *last_ack_seg; + struct ib_rmpp_segment *cur_seg; + int last_ack; + int seg_num; + int newwin; + int pad; +}; + +struct ib_mad_local_private { + struct list_head completion_list; + struct ib_mad_private *mad_priv; + struct ib_mad_agent_private *recv_mad_agent; + struct ib_mad_send_wr_private *mad_send_wr; +}; + +struct ib_mad_mgmt_method_table { + struct ib_mad_agent_private *agent[IB_MGMT_MAX_METHODS]; +}; + +struct ib_mad_mgmt_class_table { + struct ib_mad_mgmt_method_table *method_table[MAX_MGMT_CLASS]; +}; + +struct ib_mad_mgmt_vendor_class { + u8 oui[MAX_MGMT_OUI][3]; + struct ib_mad_mgmt_method_table *method_table[MAX_MGMT_OUI]; +}; + +struct ib_mad_mgmt_vendor_class_table { + struct ib_mad_mgmt_vendor_class *vendor_class[MAX_MGMT_VENDOR_RANGE2]; +}; + +struct ib_mad_mgmt_version_table { + struct ib_mad_mgmt_class_table *class; + struct ib_mad_mgmt_vendor_class_table *vendor; +}; + +struct ib_mad_queue { + spinlock_t lock; + struct list_head list; + int count; + int max_active; + struct ib_mad_qp_info *qp_info; +}; + +struct ib_mad_qp_info { + struct ib_mad_port_private *port_priv; + struct ib_qp *qp; + struct ib_mad_queue send_queue; + struct ib_mad_queue recv_queue; + struct list_head overflow_list; + spinlock_t snoop_lock; + struct ib_mad_snoop_private **snoop_table; + int snoop_table_size; + atomic_t snoop_count; +}; + +struct ib_mad_port_private { + struct list_head port_list; + struct ib_device *device; + int port_num; + struct ib_cq *cq; + struct ib_pd *pd; + struct ib_mr *mr; + + spinlock_t reg_lock; + struct ib_mad_mgmt_version_table version[MAX_MGMT_VERSION]; + struct list_head agent_list; + struct workqueue_struct *wq; + struct work_struct work; + struct ib_mad_qp_info qp_info[IB_MAD_QPS_CORE]; +}; + +int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr); + +struct ib_mad_send_wr_private * +ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, + struct ib_mad_recv_wc *mad_recv_wc); + +void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr, + struct ib_mad_send_wc *mad_send_wc); + +void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr); + +void ib_reset_mad_timeout(struct ib_mad_send_wr_private *mad_send_wr, + int timeout_ms); + +#endif /* __IB_MAD_PRIV_H__ */ diff --git a/sys/ofed/drivers/infiniband/core/mad_rmpp.c b/sys/ofed/drivers/infiniband/core/mad_rmpp.c new file mode 100644 index 000000000000..4e0f2829e0e5 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/mad_rmpp.c @@ -0,0 +1,951 @@ +/* + * Copyright (c) 2005 Intel Inc. All rights reserved. + * Copyright (c) 2005-2006 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mad_priv.h" +#include "mad_rmpp.h" + +enum rmpp_state { + RMPP_STATE_ACTIVE, + RMPP_STATE_TIMEOUT, + RMPP_STATE_COMPLETE, + RMPP_STATE_CANCELING +}; + +struct mad_rmpp_recv { + struct ib_mad_agent_private *agent; + struct list_head list; + struct delayed_work timeout_work; + struct delayed_work cleanup_work; + struct completion comp; + enum rmpp_state state; + spinlock_t lock; + atomic_t refcount; + + struct ib_ah *ah; + struct ib_mad_recv_wc *rmpp_wc; + struct ib_mad_recv_buf *cur_seg_buf; + int last_ack; + int seg_num; + int newwin; + int repwin; + + __be64 tid; + u32 src_qp; + u16 slid; + u8 mgmt_class; + u8 class_version; + u8 method; +}; + +static inline void deref_rmpp_recv(struct mad_rmpp_recv *rmpp_recv) +{ + if (atomic_dec_and_test(&rmpp_recv->refcount)) + complete(&rmpp_recv->comp); +} + +static void destroy_rmpp_recv(struct mad_rmpp_recv *rmpp_recv) +{ + deref_rmpp_recv(rmpp_recv); + wait_for_completion(&rmpp_recv->comp); + ib_destroy_ah(rmpp_recv->ah); + kfree(rmpp_recv); +} + +void ib_cancel_rmpp_recvs(struct ib_mad_agent_private *agent) +{ + struct mad_rmpp_recv *rmpp_recv, *temp_rmpp_recv; + unsigned long flags; + + spin_lock_irqsave(&agent->lock, flags); + list_for_each_entry(rmpp_recv, &agent->rmpp_list, list) { + if (rmpp_recv->state != RMPP_STATE_COMPLETE) + ib_free_recv_mad(rmpp_recv->rmpp_wc); + rmpp_recv->state = RMPP_STATE_CANCELING; + } + spin_unlock_irqrestore(&agent->lock, flags); + + list_for_each_entry(rmpp_recv, &agent->rmpp_list, list) { + cancel_delayed_work(&rmpp_recv->timeout_work); + cancel_delayed_work(&rmpp_recv->cleanup_work); + } + + flush_workqueue(agent->qp_info->port_priv->wq); + + list_for_each_entry_safe(rmpp_recv, temp_rmpp_recv, + &agent->rmpp_list, list) { + list_del(&rmpp_recv->list); + destroy_rmpp_recv(rmpp_recv); + } +} + +static void format_ack(struct ib_mad_send_buf *msg, + struct ib_rmpp_mad *data, + struct mad_rmpp_recv *rmpp_recv) +{ + struct ib_rmpp_mad *ack = msg->mad; + unsigned long flags; + + memcpy(ack, &data->mad_hdr, msg->hdr_len); + + ack->mad_hdr.method ^= IB_MGMT_METHOD_RESP; + ack->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_ACK; + ib_set_rmpp_flags(&ack->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE); + + spin_lock_irqsave(&rmpp_recv->lock, flags); + rmpp_recv->last_ack = rmpp_recv->seg_num; + ack->rmpp_hdr.seg_num = cpu_to_be32(rmpp_recv->seg_num); + ack->rmpp_hdr.paylen_newwin = cpu_to_be32(rmpp_recv->newwin); + spin_unlock_irqrestore(&rmpp_recv->lock, flags); +} + +static void ack_recv(struct mad_rmpp_recv *rmpp_recv, + struct ib_mad_recv_wc *recv_wc) +{ + struct ib_mad_send_buf *msg; + int ret, hdr_len; + + hdr_len = ib_get_mad_data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class); + msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp, + recv_wc->wc->pkey_index, 1, hdr_len, + 0, GFP_KERNEL); + if (IS_ERR(msg)) + return; + + format_ack(msg, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, rmpp_recv); + msg->ah = rmpp_recv->ah; + ret = ib_post_send_mad(msg, NULL); + if (ret) + ib_free_send_mad(msg); +} + +static struct ib_mad_send_buf *alloc_response_msg(struct ib_mad_agent *agent, + struct ib_mad_recv_wc *recv_wc) +{ + struct ib_mad_send_buf *msg; + struct ib_ah *ah; + int hdr_len; + + ah = ib_create_ah_from_wc(agent->qp->pd, recv_wc->wc, + recv_wc->recv_buf.grh, agent->port_num); + if (IS_ERR(ah)) + return (void *) ah; + + hdr_len = ib_get_mad_data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class); + msg = ib_create_send_mad(agent, recv_wc->wc->src_qp, + recv_wc->wc->pkey_index, 1, + hdr_len, 0, GFP_KERNEL); + if (IS_ERR(msg)) + ib_destroy_ah(ah); + else { + msg->ah = ah; + msg->context[0] = ah; + } + + return msg; +} + +static void ack_ds_ack(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *recv_wc) +{ + struct ib_mad_send_buf *msg; + struct ib_rmpp_mad *rmpp_mad; + int ret; + + msg = alloc_response_msg(&agent->agent, recv_wc); + if (IS_ERR(msg)) + return; + + rmpp_mad = msg->mad; + memcpy(rmpp_mad, recv_wc->recv_buf.mad, msg->hdr_len); + + rmpp_mad->mad_hdr.method ^= IB_MGMT_METHOD_RESP; + ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE); + rmpp_mad->rmpp_hdr.seg_num = 0; + rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(1); + + ret = ib_post_send_mad(msg, NULL); + if (ret) { + ib_destroy_ah(msg->ah); + ib_free_send_mad(msg); + } +} + +void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc) +{ + if (mad_send_wc->send_buf->context[0] == mad_send_wc->send_buf->ah) + ib_destroy_ah(mad_send_wc->send_buf->ah); + ib_free_send_mad(mad_send_wc->send_buf); +} + +static void nack_recv(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *recv_wc, u8 rmpp_status) +{ + struct ib_mad_send_buf *msg; + struct ib_rmpp_mad *rmpp_mad; + int ret; + + msg = alloc_response_msg(&agent->agent, recv_wc); + if (IS_ERR(msg)) + return; + + rmpp_mad = msg->mad; + memcpy(rmpp_mad, recv_wc->recv_buf.mad, msg->hdr_len); + + rmpp_mad->mad_hdr.method ^= IB_MGMT_METHOD_RESP; + rmpp_mad->rmpp_hdr.rmpp_version = IB_MGMT_RMPP_VERSION; + rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_ABORT; + ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE); + rmpp_mad->rmpp_hdr.rmpp_status = rmpp_status; + rmpp_mad->rmpp_hdr.seg_num = 0; + rmpp_mad->rmpp_hdr.paylen_newwin = 0; + + ret = ib_post_send_mad(msg, NULL); + if (ret) { + ib_destroy_ah(msg->ah); + ib_free_send_mad(msg); + } +} + +static void recv_timeout_handler(struct work_struct *work) +{ + struct mad_rmpp_recv *rmpp_recv = + container_of(work, struct mad_rmpp_recv, timeout_work.work); + struct ib_mad_recv_wc *rmpp_wc; + unsigned long flags; + + spin_lock_irqsave(&rmpp_recv->agent->lock, flags); + if (rmpp_recv->state != RMPP_STATE_ACTIVE) { + spin_unlock_irqrestore(&rmpp_recv->agent->lock, flags); + return; + } + rmpp_recv->state = RMPP_STATE_TIMEOUT; + list_del(&rmpp_recv->list); + spin_unlock_irqrestore(&rmpp_recv->agent->lock, flags); + + rmpp_wc = rmpp_recv->rmpp_wc; + nack_recv(rmpp_recv->agent, rmpp_wc, IB_MGMT_RMPP_STATUS_T2L); + destroy_rmpp_recv(rmpp_recv); + ib_free_recv_mad(rmpp_wc); +} + +static void recv_cleanup_handler(struct work_struct *work) +{ + struct mad_rmpp_recv *rmpp_recv = + container_of(work, struct mad_rmpp_recv, cleanup_work.work); + unsigned long flags; + + spin_lock_irqsave(&rmpp_recv->agent->lock, flags); + if (rmpp_recv->state == RMPP_STATE_CANCELING) { + spin_unlock_irqrestore(&rmpp_recv->agent->lock, flags); + return; + } + list_del(&rmpp_recv->list); + spin_unlock_irqrestore(&rmpp_recv->agent->lock, flags); + destroy_rmpp_recv(rmpp_recv); +} + +static struct mad_rmpp_recv * +create_rmpp_recv(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct mad_rmpp_recv *rmpp_recv; + struct ib_mad_hdr *mad_hdr; + + rmpp_recv = kmalloc(sizeof *rmpp_recv, GFP_KERNEL); + if (!rmpp_recv) + return NULL; + + rmpp_recv->ah = ib_create_ah_from_wc(agent->agent.qp->pd, + mad_recv_wc->wc, + mad_recv_wc->recv_buf.grh, + agent->agent.port_num); + if (IS_ERR(rmpp_recv->ah)) + goto error; + + rmpp_recv->agent = agent; + init_completion(&rmpp_recv->comp); + INIT_DELAYED_WORK(&rmpp_recv->timeout_work, recv_timeout_handler); + INIT_DELAYED_WORK(&rmpp_recv->cleanup_work, recv_cleanup_handler); + spin_lock_init(&rmpp_recv->lock); + rmpp_recv->state = RMPP_STATE_ACTIVE; + atomic_set(&rmpp_recv->refcount, 1); + + rmpp_recv->rmpp_wc = mad_recv_wc; + rmpp_recv->cur_seg_buf = &mad_recv_wc->recv_buf; + rmpp_recv->newwin = 1; + rmpp_recv->seg_num = 1; + rmpp_recv->last_ack = 0; + rmpp_recv->repwin = 1; + + mad_hdr = &mad_recv_wc->recv_buf.mad->mad_hdr; + rmpp_recv->tid = mad_hdr->tid; + rmpp_recv->src_qp = mad_recv_wc->wc->src_qp; + rmpp_recv->slid = mad_recv_wc->wc->slid; + rmpp_recv->mgmt_class = mad_hdr->mgmt_class; + rmpp_recv->class_version = mad_hdr->class_version; + rmpp_recv->method = mad_hdr->method; + return rmpp_recv; + +error: kfree(rmpp_recv); + return NULL; +} + +static struct mad_rmpp_recv * +find_rmpp_recv(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct mad_rmpp_recv *rmpp_recv; + struct ib_mad_hdr *mad_hdr = &mad_recv_wc->recv_buf.mad->mad_hdr; + + list_for_each_entry(rmpp_recv, &agent->rmpp_list, list) { + if (rmpp_recv->tid == mad_hdr->tid && + rmpp_recv->src_qp == mad_recv_wc->wc->src_qp && + rmpp_recv->slid == mad_recv_wc->wc->slid && + rmpp_recv->mgmt_class == mad_hdr->mgmt_class && + rmpp_recv->class_version == mad_hdr->class_version && + rmpp_recv->method == mad_hdr->method) + return rmpp_recv; + } + return NULL; +} + +static struct mad_rmpp_recv * +acquire_rmpp_recv(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct mad_rmpp_recv *rmpp_recv; + unsigned long flags; + + spin_lock_irqsave(&agent->lock, flags); + rmpp_recv = find_rmpp_recv(agent, mad_recv_wc); + if (rmpp_recv) + atomic_inc(&rmpp_recv->refcount); + spin_unlock_irqrestore(&agent->lock, flags); + return rmpp_recv; +} + +static struct mad_rmpp_recv * +insert_rmpp_recv(struct ib_mad_agent_private *agent, + struct mad_rmpp_recv *rmpp_recv) +{ + struct mad_rmpp_recv *cur_rmpp_recv; + + cur_rmpp_recv = find_rmpp_recv(agent, rmpp_recv->rmpp_wc); + if (!cur_rmpp_recv) + list_add_tail(&rmpp_recv->list, &agent->rmpp_list); + + return cur_rmpp_recv; +} + +static inline int get_last_flag(struct ib_mad_recv_buf *seg) +{ + struct ib_rmpp_mad *rmpp_mad; + + rmpp_mad = (struct ib_rmpp_mad *) seg->mad; + return ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_LAST; +} + +static inline int get_seg_num(struct ib_mad_recv_buf *seg) +{ + struct ib_rmpp_mad *rmpp_mad; + + rmpp_mad = (struct ib_rmpp_mad *) seg->mad; + return be32_to_cpu(rmpp_mad->rmpp_hdr.seg_num); +} + +static inline struct ib_mad_recv_buf * get_next_seg(struct list_head *rmpp_list, + struct ib_mad_recv_buf *seg) +{ + if (seg->list.next == rmpp_list) + return NULL; + + return container_of(seg->list.next, struct ib_mad_recv_buf, list); +} + +static inline int window_size(struct ib_mad_agent_private *agent) +{ + return max(agent->qp_info->recv_queue.max_active >> 3, 1); +} + +static struct ib_mad_recv_buf * find_seg_location(struct list_head *rmpp_list, + int seg_num) +{ + struct ib_mad_recv_buf *seg_buf; + int cur_seg_num; + + list_for_each_entry_reverse(seg_buf, rmpp_list, list) { + cur_seg_num = get_seg_num(seg_buf); + if (seg_num > cur_seg_num) + return seg_buf; + if (seg_num == cur_seg_num) + break; + } + return NULL; +} + +static void update_seg_num(struct mad_rmpp_recv *rmpp_recv, + struct ib_mad_recv_buf *new_buf) +{ + struct list_head *rmpp_list = &rmpp_recv->rmpp_wc->rmpp_list; + + while (new_buf && (get_seg_num(new_buf) == rmpp_recv->seg_num + 1)) { + rmpp_recv->cur_seg_buf = new_buf; + rmpp_recv->seg_num++; + new_buf = get_next_seg(rmpp_list, new_buf); + } +} + +static inline int get_mad_len(struct mad_rmpp_recv *rmpp_recv) +{ + struct ib_rmpp_mad *rmpp_mad; + int hdr_size, data_size, pad; + + rmpp_mad = (struct ib_rmpp_mad *)rmpp_recv->cur_seg_buf->mad; + + hdr_size = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class); + data_size = sizeof(struct ib_rmpp_mad) - hdr_size; + pad = IB_MGMT_RMPP_DATA - be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin); + if (pad > IB_MGMT_RMPP_DATA || pad < 0) + pad = 0; + + return hdr_size + rmpp_recv->seg_num * data_size - pad; +} + +static struct ib_mad_recv_wc * complete_rmpp(struct mad_rmpp_recv *rmpp_recv) +{ + struct ib_mad_recv_wc *rmpp_wc; + + ack_recv(rmpp_recv, rmpp_recv->rmpp_wc); + if (rmpp_recv->seg_num > 1) + cancel_delayed_work(&rmpp_recv->timeout_work); + + rmpp_wc = rmpp_recv->rmpp_wc; + rmpp_wc->mad_len = get_mad_len(rmpp_recv); + /* 10 seconds until we can find the packet lifetime */ + queue_delayed_work(rmpp_recv->agent->qp_info->port_priv->wq, + &rmpp_recv->cleanup_work, msecs_to_jiffies(10000)); + return rmpp_wc; +} + +static struct ib_mad_recv_wc * +continue_rmpp(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct mad_rmpp_recv *rmpp_recv; + struct ib_mad_recv_buf *prev_buf; + struct ib_mad_recv_wc *done_wc; + int seg_num; + unsigned long flags; + + rmpp_recv = acquire_rmpp_recv(agent, mad_recv_wc); + if (!rmpp_recv) + goto drop1; + + seg_num = get_seg_num(&mad_recv_wc->recv_buf); + + spin_lock_irqsave(&rmpp_recv->lock, flags); + if ((rmpp_recv->state == RMPP_STATE_TIMEOUT) || + (seg_num > rmpp_recv->newwin)) + goto drop3; + + if ((seg_num <= rmpp_recv->last_ack) || + (rmpp_recv->state == RMPP_STATE_COMPLETE)) { + spin_unlock_irqrestore(&rmpp_recv->lock, flags); + ack_recv(rmpp_recv, mad_recv_wc); + goto drop2; + } + + prev_buf = find_seg_location(&rmpp_recv->rmpp_wc->rmpp_list, seg_num); + if (!prev_buf) + goto drop3; + + done_wc = NULL; + list_add(&mad_recv_wc->recv_buf.list, &prev_buf->list); + if (rmpp_recv->cur_seg_buf == prev_buf) { + update_seg_num(rmpp_recv, &mad_recv_wc->recv_buf); + if (get_last_flag(rmpp_recv->cur_seg_buf)) { + rmpp_recv->state = RMPP_STATE_COMPLETE; + spin_unlock_irqrestore(&rmpp_recv->lock, flags); + done_wc = complete_rmpp(rmpp_recv); + goto out; + } else if (rmpp_recv->seg_num == rmpp_recv->newwin) { + rmpp_recv->newwin += window_size(agent); + spin_unlock_irqrestore(&rmpp_recv->lock, flags); + ack_recv(rmpp_recv, mad_recv_wc); + goto out; + } + } + spin_unlock_irqrestore(&rmpp_recv->lock, flags); +out: + deref_rmpp_recv(rmpp_recv); + return done_wc; + +drop3: spin_unlock_irqrestore(&rmpp_recv->lock, flags); +drop2: deref_rmpp_recv(rmpp_recv); +drop1: ib_free_recv_mad(mad_recv_wc); + return NULL; +} + +static struct ib_mad_recv_wc * +start_rmpp(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct mad_rmpp_recv *rmpp_recv; + unsigned long flags; + + rmpp_recv = create_rmpp_recv(agent, mad_recv_wc); + if (!rmpp_recv) { + ib_free_recv_mad(mad_recv_wc); + return NULL; + } + + spin_lock_irqsave(&agent->lock, flags); + if (insert_rmpp_recv(agent, rmpp_recv)) { + spin_unlock_irqrestore(&agent->lock, flags); + /* duplicate first MAD */ + destroy_rmpp_recv(rmpp_recv); + return continue_rmpp(agent, mad_recv_wc); + } + atomic_inc(&rmpp_recv->refcount); + + if (get_last_flag(&mad_recv_wc->recv_buf)) { + rmpp_recv->state = RMPP_STATE_COMPLETE; + spin_unlock_irqrestore(&agent->lock, flags); + complete_rmpp(rmpp_recv); + } else { + spin_unlock_irqrestore(&agent->lock, flags); + /* 40 seconds until we can find the packet lifetimes */ + queue_delayed_work(agent->qp_info->port_priv->wq, + &rmpp_recv->timeout_work, + msecs_to_jiffies(40000)); + rmpp_recv->newwin += window_size(agent); + ack_recv(rmpp_recv, mad_recv_wc); + mad_recv_wc = NULL; + } + deref_rmpp_recv(rmpp_recv); + return mad_recv_wc; +} + +static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) +{ + struct ib_rmpp_mad *rmpp_mad; + int timeout; + u32 paylen = 0; + + rmpp_mad = mad_send_wr->send_buf.mad; + ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE); + rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(++mad_send_wr->seg_num); + + if (mad_send_wr->seg_num == 1) { + rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_FIRST; + paylen = mad_send_wr->send_buf.seg_count * IB_MGMT_RMPP_DATA - + mad_send_wr->pad; + } + + if (mad_send_wr->seg_num == mad_send_wr->send_buf.seg_count) { + rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_LAST; + paylen = IB_MGMT_RMPP_DATA - mad_send_wr->pad; + } + rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen); + + /* 2 seconds for an ACK until we can find the packet lifetime */ + timeout = mad_send_wr->send_buf.timeout_ms; + if (!timeout || timeout > 2000) + mad_send_wr->timeout = msecs_to_jiffies(2000); + + return ib_send_mad(mad_send_wr); +} + +static void abort_send(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *mad_recv_wc, u8 rmpp_status) +{ + struct ib_mad_send_wr_private *mad_send_wr; + struct ib_mad_send_wc wc; + unsigned long flags; + + spin_lock_irqsave(&agent->lock, flags); + mad_send_wr = ib_find_send_mad(agent, mad_recv_wc); + if (!mad_send_wr) + goto out; /* Unmatched send */ + + if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) || + (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS)) + goto out; /* Send is already done */ + + ib_mark_mad_done(mad_send_wr); + spin_unlock_irqrestore(&agent->lock, flags); + + wc.status = IB_WC_REM_ABORT_ERR; + wc.vendor_err = rmpp_status; + wc.send_buf = &mad_send_wr->send_buf; + ib_mad_complete_send_wr(mad_send_wr, &wc); + return; +out: + spin_unlock_irqrestore(&agent->lock, flags); +} + +static inline void adjust_last_ack(struct ib_mad_send_wr_private *wr, + int seg_num) +{ + struct list_head *list; + + wr->last_ack = seg_num; + list = &wr->last_ack_seg->list; + list_for_each_entry(wr->last_ack_seg, list, list) + if (wr->last_ack_seg->num == seg_num) + break; +} + +static void process_ds_ack(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *mad_recv_wc, int newwin) +{ + struct mad_rmpp_recv *rmpp_recv; + + rmpp_recv = find_rmpp_recv(agent, mad_recv_wc); + if (rmpp_recv && rmpp_recv->state == RMPP_STATE_COMPLETE) + rmpp_recv->repwin = newwin; +} + +static void process_rmpp_ack(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_mad_send_wr_private *mad_send_wr; + struct ib_rmpp_mad *rmpp_mad; + unsigned long flags; + int seg_num, newwin, ret; + + rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad; + if (rmpp_mad->rmpp_hdr.rmpp_status) { + abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); + nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); + return; + } + + seg_num = be32_to_cpu(rmpp_mad->rmpp_hdr.seg_num); + newwin = be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin); + if (newwin < seg_num) { + abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S); + nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S); + return; + } + + spin_lock_irqsave(&agent->lock, flags); + mad_send_wr = ib_find_send_mad(agent, mad_recv_wc); + if (!mad_send_wr) { + if (!seg_num) + process_ds_ack(agent, mad_recv_wc, newwin); + goto out; /* Unmatched or DS RMPP ACK */ + } + + if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) && + (mad_send_wr->timeout)) { + spin_unlock_irqrestore(&agent->lock, flags); + ack_ds_ack(agent, mad_recv_wc); + return; /* Repeated ACK for DS RMPP transaction */ + } + + if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) || + (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS)) + goto out; /* Send is already done */ + + if (seg_num > mad_send_wr->send_buf.seg_count || + seg_num > mad_send_wr->newwin) { + spin_unlock_irqrestore(&agent->lock, flags); + abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B); + nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B); + return; + } + + if (newwin < mad_send_wr->newwin || seg_num < mad_send_wr->last_ack) + goto out; /* Old ACK */ + + if (seg_num > mad_send_wr->last_ack) { + adjust_last_ack(mad_send_wr, seg_num); + mad_send_wr->retries_left = mad_send_wr->max_retries; + } + mad_send_wr->newwin = newwin; + if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) { + /* If no response is expected, the ACK completes the send */ + if (!mad_send_wr->send_buf.timeout_ms) { + struct ib_mad_send_wc wc; + + ib_mark_mad_done(mad_send_wr); + spin_unlock_irqrestore(&agent->lock, flags); + + wc.status = IB_WC_SUCCESS; + wc.vendor_err = 0; + wc.send_buf = &mad_send_wr->send_buf; + ib_mad_complete_send_wr(mad_send_wr, &wc); + return; + } + if (mad_send_wr->refcount == 1) + ib_reset_mad_timeout(mad_send_wr, + mad_send_wr->send_buf.timeout_ms); + spin_unlock_irqrestore(&agent->lock, flags); + ack_ds_ack(agent, mad_recv_wc); + return; + } else if (mad_send_wr->refcount == 1 && + mad_send_wr->seg_num < mad_send_wr->newwin && + mad_send_wr->seg_num < mad_send_wr->send_buf.seg_count) { + /* Send failure will just result in a timeout/retry */ + ret = send_next_seg(mad_send_wr); + if (ret) + goto out; + + mad_send_wr->refcount++; + list_move_tail(&mad_send_wr->agent_list, + &mad_send_wr->mad_agent_priv->send_list); + } +out: + spin_unlock_irqrestore(&agent->lock, flags); +} + +static struct ib_mad_recv_wc * +process_rmpp_data(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_rmpp_hdr *rmpp_hdr; + u8 rmpp_status; + + rmpp_hdr = &((struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad)->rmpp_hdr; + + if (rmpp_hdr->rmpp_status) { + rmpp_status = IB_MGMT_RMPP_STATUS_BAD_STATUS; + goto bad; + } + + if (rmpp_hdr->seg_num == cpu_to_be32(1)) { + if (!(ib_get_rmpp_flags(rmpp_hdr) & IB_MGMT_RMPP_FLAG_FIRST)) { + rmpp_status = IB_MGMT_RMPP_STATUS_BAD_SEG; + goto bad; + } + return start_rmpp(agent, mad_recv_wc); + } else { + if (ib_get_rmpp_flags(rmpp_hdr) & IB_MGMT_RMPP_FLAG_FIRST) { + rmpp_status = IB_MGMT_RMPP_STATUS_BAD_SEG; + goto bad; + } + return continue_rmpp(agent, mad_recv_wc); + } +bad: + nack_recv(agent, mad_recv_wc, rmpp_status); + ib_free_recv_mad(mad_recv_wc); + return NULL; +} + +static void process_rmpp_stop(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_rmpp_mad *rmpp_mad; + + rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad; + + if (rmpp_mad->rmpp_hdr.rmpp_status != IB_MGMT_RMPP_STATUS_RESX) { + abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); + nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); + } else + abort_send(agent, mad_recv_wc, rmpp_mad->rmpp_hdr.rmpp_status); +} + +static void process_rmpp_abort(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_rmpp_mad *rmpp_mad; + + rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad; + + if (rmpp_mad->rmpp_hdr.rmpp_status < IB_MGMT_RMPP_STATUS_ABORT_MIN || + rmpp_mad->rmpp_hdr.rmpp_status > IB_MGMT_RMPP_STATUS_ABORT_MAX) { + abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); + nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); + } else + abort_send(agent, mad_recv_wc, rmpp_mad->rmpp_hdr.rmpp_status); +} + +struct ib_mad_recv_wc * +ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_rmpp_mad *rmpp_mad; + + rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad; + if (!(rmpp_mad->rmpp_hdr.rmpp_rtime_flags & IB_MGMT_RMPP_FLAG_ACTIVE)) + return mad_recv_wc; + + if (rmpp_mad->rmpp_hdr.rmpp_version != IB_MGMT_RMPP_VERSION) { + abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV); + nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV); + goto out; + } + + switch (rmpp_mad->rmpp_hdr.rmpp_type) { + case IB_MGMT_RMPP_TYPE_DATA: + return process_rmpp_data(agent, mad_recv_wc); + case IB_MGMT_RMPP_TYPE_ACK: + process_rmpp_ack(agent, mad_recv_wc); + break; + case IB_MGMT_RMPP_TYPE_STOP: + process_rmpp_stop(agent, mad_recv_wc); + break; + case IB_MGMT_RMPP_TYPE_ABORT: + process_rmpp_abort(agent, mad_recv_wc); + break; + default: + abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT); + nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT); + break; + } +out: + ib_free_recv_mad(mad_recv_wc); + return NULL; +} + +static int init_newwin(struct ib_mad_send_wr_private *mad_send_wr) +{ + struct ib_mad_agent_private *agent = mad_send_wr->mad_agent_priv; + struct ib_mad_hdr *mad_hdr = mad_send_wr->send_buf.mad; + struct mad_rmpp_recv *rmpp_recv; + struct ib_ah_attr ah_attr; + unsigned long flags; + int newwin = 1; + + if (!(mad_hdr->method & IB_MGMT_METHOD_RESP)) + goto out; + + spin_lock_irqsave(&agent->lock, flags); + list_for_each_entry(rmpp_recv, &agent->rmpp_list, list) { + if (rmpp_recv->tid != mad_hdr->tid || + rmpp_recv->mgmt_class != mad_hdr->mgmt_class || + rmpp_recv->class_version != mad_hdr->class_version || + (rmpp_recv->method & IB_MGMT_METHOD_RESP)) + continue; + + if (ib_query_ah(mad_send_wr->send_buf.ah, &ah_attr)) + continue; + + if (rmpp_recv->slid == ah_attr.dlid) { + newwin = rmpp_recv->repwin; + break; + } + } + spin_unlock_irqrestore(&agent->lock, flags); +out: + return newwin; +} + +int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr) +{ + struct ib_rmpp_mad *rmpp_mad; + int ret; + + rmpp_mad = mad_send_wr->send_buf.mad; + if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & + IB_MGMT_RMPP_FLAG_ACTIVE)) + return IB_RMPP_RESULT_UNHANDLED; + + if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) { + mad_send_wr->seg_num = 1; + return IB_RMPP_RESULT_INTERNAL; + } + + mad_send_wr->newwin = init_newwin(mad_send_wr); + + /* We need to wait for the final ACK even if there isn't a response */ + mad_send_wr->refcount += (mad_send_wr->timeout == 0); + ret = send_next_seg(mad_send_wr); + if (!ret) + return IB_RMPP_RESULT_CONSUMED; + return ret; +} + +int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr, + struct ib_mad_send_wc *mad_send_wc) +{ + struct ib_rmpp_mad *rmpp_mad; + int ret; + + rmpp_mad = mad_send_wr->send_buf.mad; + if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & + IB_MGMT_RMPP_FLAG_ACTIVE)) + return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */ + + if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) + return IB_RMPP_RESULT_INTERNAL; /* ACK, STOP, or ABORT */ + + if (mad_send_wc->status != IB_WC_SUCCESS || + mad_send_wr->status != IB_WC_SUCCESS) + return IB_RMPP_RESULT_PROCESSED; /* Canceled or send error */ + + if (!mad_send_wr->timeout) + return IB_RMPP_RESULT_PROCESSED; /* Response received */ + + if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) { + mad_send_wr->timeout = + msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms); + return IB_RMPP_RESULT_PROCESSED; /* Send done */ + } + + if (mad_send_wr->seg_num == mad_send_wr->newwin || + mad_send_wr->seg_num == mad_send_wr->send_buf.seg_count) + return IB_RMPP_RESULT_PROCESSED; /* Wait for ACK */ + + ret = send_next_seg(mad_send_wr); + if (ret) { + mad_send_wc->status = IB_WC_GENERAL_ERR; + return IB_RMPP_RESULT_PROCESSED; + } + return IB_RMPP_RESULT_CONSUMED; +} + +int ib_retry_rmpp(struct ib_mad_send_wr_private *mad_send_wr) +{ + struct ib_rmpp_mad *rmpp_mad; + int ret; + + rmpp_mad = mad_send_wr->send_buf.mad; + if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & + IB_MGMT_RMPP_FLAG_ACTIVE)) + return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */ + + if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) + return IB_RMPP_RESULT_PROCESSED; + + mad_send_wr->seg_num = mad_send_wr->last_ack; + mad_send_wr->cur_seg = mad_send_wr->last_ack_seg; + + ret = send_next_seg(mad_send_wr); + if (ret) + return IB_RMPP_RESULT_PROCESSED; + + return IB_RMPP_RESULT_CONSUMED; +} diff --git a/sys/ofed/drivers/infiniband/core/mad_rmpp.h b/sys/ofed/drivers/infiniband/core/mad_rmpp.h new file mode 100644 index 000000000000..3d336bff1148 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/mad_rmpp.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2005 Intel Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef __MAD_RMPP_H__ +#define __MAD_RMPP_H__ + +enum { + IB_RMPP_RESULT_PROCESSED, + IB_RMPP_RESULT_CONSUMED, + IB_RMPP_RESULT_INTERNAL, + IB_RMPP_RESULT_UNHANDLED +}; + +int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr); + +struct ib_mad_recv_wc * +ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *mad_recv_wc); + +int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr, + struct ib_mad_send_wc *mad_send_wc); + +void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc); + +void ib_cancel_rmpp_recvs(struct ib_mad_agent_private *agent); + +int ib_retry_rmpp(struct ib_mad_send_wr_private *mad_send_wr); + +#endif /* __MAD_RMPP_H__ */ diff --git a/sys/ofed/drivers/infiniband/core/multicast.c b/sys/ofed/drivers/infiniband/core/multicast.c new file mode 100644 index 000000000000..f8d7ef81e190 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/multicast.c @@ -0,0 +1,868 @@ +/* + * Copyright (c) 2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include "sa.h" + +static void mcast_add_one(struct ib_device *device); +static void mcast_remove_one(struct ib_device *device); + +static struct ib_client mcast_client = { + .name = "ib_multicast", + .add = mcast_add_one, + .remove = mcast_remove_one +}; + +static struct ib_sa_client sa_client; +static struct workqueue_struct *mcast_wq; +static union ib_gid mgid0; + +struct mcast_device; + +struct mcast_port { + struct mcast_device *dev; + spinlock_t lock; + struct rb_root table; + atomic_t refcount; + struct completion comp; + u8 port_num; +}; + +struct mcast_device { + struct ib_device *device; + struct ib_event_handler event_handler; + int start_port; + int end_port; + struct mcast_port port[0]; +}; + +enum mcast_state { + MCAST_JOINING, + MCAST_MEMBER, + MCAST_ERROR, +}; + +enum mcast_group_state { + MCAST_IDLE, + MCAST_BUSY, + MCAST_GROUP_ERROR, + MCAST_PKEY_EVENT +}; + +enum { + MCAST_INVALID_PKEY_INDEX = 0xFFFF +}; + +struct mcast_member; + +struct mcast_group { + struct ib_sa_mcmember_rec rec; + struct rb_node node; + struct mcast_port *port; + spinlock_t lock; + struct work_struct work; + struct list_head pending_list; + struct list_head active_list; + struct mcast_member *last_join; + int members[3]; + atomic_t refcount; + enum mcast_group_state state; + struct ib_sa_query *query; + int query_id; + u16 pkey_index; + u8 leave_state; + int retries; +}; + +struct mcast_member { + struct ib_sa_multicast multicast; + struct ib_sa_client *client; + struct mcast_group *group; + struct list_head list; + enum mcast_state state; + atomic_t refcount; + struct completion comp; +}; + +static void join_handler(int status, struct ib_sa_mcmember_rec *rec, + void *context); +static void leave_handler(int status, struct ib_sa_mcmember_rec *rec, + void *context); + +static struct mcast_group *mcast_find(struct mcast_port *port, + union ib_gid *mgid) +{ + struct rb_node *node = port->table.rb_node; + struct mcast_group *group; + int ret; + + while (node) { + group = rb_entry(node, struct mcast_group, node); + ret = memcmp(mgid->raw, group->rec.mgid.raw, sizeof *mgid); + if (!ret) + return group; + + if (ret < 0) + node = node->rb_left; + else + node = node->rb_right; + } + return NULL; +} + +static struct mcast_group *mcast_insert(struct mcast_port *port, + struct mcast_group *group, + int allow_duplicates) +{ + struct rb_node **link = &port->table.rb_node; + struct rb_node *parent = NULL; + struct mcast_group *cur_group; + int ret; + + while (*link) { + parent = *link; + cur_group = rb_entry(parent, struct mcast_group, node); + + ret = memcmp(group->rec.mgid.raw, cur_group->rec.mgid.raw, + sizeof group->rec.mgid); + if (ret < 0) + link = &(*link)->rb_left; + else if (ret > 0) + link = &(*link)->rb_right; + else if (allow_duplicates) + link = &(*link)->rb_left; + else + return cur_group; + } + rb_link_node(&group->node, parent, link); + rb_insert_color(&group->node, &port->table); + return NULL; +} + +static void deref_port(struct mcast_port *port) +{ + if (atomic_dec_and_test(&port->refcount)) + complete(&port->comp); +} + +static void release_group(struct mcast_group *group) +{ + struct mcast_port *port = group->port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (atomic_dec_and_test(&group->refcount)) { + rb_erase(&group->node, &port->table); + spin_unlock_irqrestore(&port->lock, flags); + kfree(group); + deref_port(port); + } else + spin_unlock_irqrestore(&port->lock, flags); +} + +static void deref_member(struct mcast_member *member) +{ + if (atomic_dec_and_test(&member->refcount)) + complete(&member->comp); +} + +static void queue_join(struct mcast_member *member) +{ + struct mcast_group *group = member->group; + unsigned long flags; + + spin_lock_irqsave(&group->lock, flags); + list_add_tail(&member->list, &group->pending_list); + if (group->state == MCAST_IDLE) { + group->state = MCAST_BUSY; + atomic_inc(&group->refcount); + queue_work(mcast_wq, &group->work); + } + spin_unlock_irqrestore(&group->lock, flags); +} + +/* + * A multicast group has three types of members: full member, non member, and + * send only member. We need to keep track of the number of members of each + * type based on their join state. Adjust the number of members the belong to + * the specified join states. + */ +static void adjust_membership(struct mcast_group *group, u8 join_state, int inc) +{ + int i; + + for (i = 0; i < 3; i++, join_state >>= 1) + if (join_state & 0x1) + group->members[i] += inc; +} + +/* + * If a multicast group has zero members left for a particular join state, but + * the group is still a member with the SA, we need to leave that join state. + * Determine which join states we still belong to, but that do not have any + * active members. + */ +static u8 get_leave_state(struct mcast_group *group) +{ + u8 leave_state = 0; + int i; + + for (i = 0; i < 3; i++) + if (!group->members[i]) + leave_state |= (0x1 << i); + + return leave_state & group->rec.join_state; +} + +static int cmp_rec(struct ib_sa_mcmember_rec *src, + struct ib_sa_mcmember_rec *dst, ib_sa_comp_mask comp_mask) +{ + /* MGID must already match */ + + if (comp_mask & IB_SA_MCMEMBER_REC_PORT_GID && + memcmp(&src->port_gid, &dst->port_gid, sizeof src->port_gid)) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_QKEY && src->qkey != dst->qkey) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_MLID && src->mlid != dst->mlid) + return -EINVAL; + if (ib_sa_check_selector(comp_mask, IB_SA_MCMEMBER_REC_MTU_SELECTOR, + IB_SA_MCMEMBER_REC_MTU, dst->mtu_selector, + src->mtu, dst->mtu)) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_TRAFFIC_CLASS && + src->traffic_class != dst->traffic_class) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_PKEY && src->pkey != dst->pkey) + return -EINVAL; + if (ib_sa_check_selector(comp_mask, IB_SA_MCMEMBER_REC_RATE_SELECTOR, + IB_SA_MCMEMBER_REC_RATE, dst->rate_selector, + src->rate, dst->rate)) + return -EINVAL; + if (ib_sa_check_selector(comp_mask, + IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR, + IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME, + dst->packet_life_time_selector, + src->packet_life_time, dst->packet_life_time)) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_SL && src->sl != dst->sl) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_FLOW_LABEL && + src->flow_label != dst->flow_label) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_HOP_LIMIT && + src->hop_limit != dst->hop_limit) + return -EINVAL; + if (comp_mask & IB_SA_MCMEMBER_REC_SCOPE && src->scope != dst->scope) + return -EINVAL; + + /* join_state checked separately, proxy_join ignored */ + + return 0; +} + +static int send_join(struct mcast_group *group, struct mcast_member *member) +{ + struct mcast_port *port = group->port; + int ret; + + group->last_join = member; + ret = ib_sa_mcmember_rec_query(&sa_client, port->dev->device, + port->port_num, IB_MGMT_METHOD_SET, + &member->multicast.rec, + member->multicast.comp_mask, + 3000, GFP_KERNEL, join_handler, group, + &group->query); + if (ret >= 0) { + group->query_id = ret; + ret = 0; + } + return ret; +} + +static int send_leave(struct mcast_group *group, u8 leave_state) +{ + struct mcast_port *port = group->port; + struct ib_sa_mcmember_rec rec; + int ret; + + rec = group->rec; + rec.join_state = leave_state; + group->leave_state = leave_state; + + ret = ib_sa_mcmember_rec_query(&sa_client, port->dev->device, + port->port_num, IB_SA_METHOD_DELETE, &rec, + IB_SA_MCMEMBER_REC_MGID | + IB_SA_MCMEMBER_REC_PORT_GID | + IB_SA_MCMEMBER_REC_JOIN_STATE, + 3000, GFP_KERNEL, leave_handler, + group, &group->query); + if (ret >= 0) { + group->query_id = ret; + ret = 0; + } + return ret; +} + +static void join_group(struct mcast_group *group, struct mcast_member *member, + u8 join_state) +{ + member->state = MCAST_MEMBER; + adjust_membership(group, join_state, 1); + group->rec.join_state |= join_state; + member->multicast.rec = group->rec; + member->multicast.rec.join_state = join_state; + list_move(&member->list, &group->active_list); +} + +static int fail_join(struct mcast_group *group, struct mcast_member *member, + int status) +{ + spin_lock_irq(&group->lock); + list_del_init(&member->list); + spin_unlock_irq(&group->lock); + return member->multicast.callback(status, &member->multicast); +} + +static void process_group_error(struct mcast_group *group) +{ + struct mcast_member *member; + int ret = 0; + u16 pkey_index; + + if (group->state == MCAST_PKEY_EVENT) + ret = ib_find_pkey(group->port->dev->device, + group->port->port_num, + be16_to_cpu(group->rec.pkey), &pkey_index); + + spin_lock_irq(&group->lock); + if (group->state == MCAST_PKEY_EVENT && !ret && + group->pkey_index == pkey_index) + goto out; + + while (!list_empty(&group->active_list)) { + member = list_entry(group->active_list.next, + struct mcast_member, list); + atomic_inc(&member->refcount); + list_del_init(&member->list); + adjust_membership(group, member->multicast.rec.join_state, -1); + member->state = MCAST_ERROR; + spin_unlock_irq(&group->lock); + + ret = member->multicast.callback(-ENETRESET, + &member->multicast); + deref_member(member); + if (ret) + ib_sa_free_multicast(&member->multicast); + spin_lock_irq(&group->lock); + } + + group->rec.join_state = 0; +out: + group->state = MCAST_BUSY; + spin_unlock_irq(&group->lock); +} + +static void mcast_work_handler(struct work_struct *work) +{ + struct mcast_group *group; + struct mcast_member *member; + struct ib_sa_multicast *multicast; + int status, ret; + u8 join_state; + + group = container_of(work, typeof(*group), work); +retest: + spin_lock_irq(&group->lock); + while (!list_empty(&group->pending_list) || + (group->state != MCAST_BUSY)) { + + if (group->state != MCAST_BUSY) { + spin_unlock_irq(&group->lock); + process_group_error(group); + goto retest; + } + + member = list_entry(group->pending_list.next, + struct mcast_member, list); + multicast = &member->multicast; + join_state = multicast->rec.join_state; + atomic_inc(&member->refcount); + + if (join_state == (group->rec.join_state & join_state)) { + status = cmp_rec(&group->rec, &multicast->rec, + multicast->comp_mask); + if (!status) + join_group(group, member, join_state); + else + list_del_init(&member->list); + spin_unlock_irq(&group->lock); + ret = multicast->callback(status, multicast); + } else { + spin_unlock_irq(&group->lock); + status = send_join(group, member); + if (!status) { + deref_member(member); + return; + } + ret = fail_join(group, member, status); + } + + deref_member(member); + if (ret) + ib_sa_free_multicast(&member->multicast); + spin_lock_irq(&group->lock); + } + + join_state = get_leave_state(group); + if (join_state) { + group->rec.join_state &= ~join_state; + spin_unlock_irq(&group->lock); + if (send_leave(group, join_state)) + goto retest; + } else { + group->state = MCAST_IDLE; + spin_unlock_irq(&group->lock); + release_group(group); + } +} + +/* + * Fail a join request if it is still active - at the head of the pending queue. + */ +static void process_join_error(struct mcast_group *group, int status) +{ + struct mcast_member *member; + int ret; + + spin_lock_irq(&group->lock); + member = list_entry(group->pending_list.next, + struct mcast_member, list); + if (group->last_join == member) { + atomic_inc(&member->refcount); + list_del_init(&member->list); + spin_unlock_irq(&group->lock); + ret = member->multicast.callback(status, &member->multicast); + deref_member(member); + if (ret) + ib_sa_free_multicast(&member->multicast); + } else + spin_unlock_irq(&group->lock); +} + +static void join_handler(int status, struct ib_sa_mcmember_rec *rec, + void *context) +{ + struct mcast_group *group = context; + u16 pkey_index = MCAST_INVALID_PKEY_INDEX; + + if (status) + process_join_error(group, status); + else { + ib_find_pkey(group->port->dev->device, group->port->port_num, + be16_to_cpu(rec->pkey), &pkey_index); + + spin_lock_irq(&group->port->lock); + group->rec = *rec; + if (group->state == MCAST_BUSY && + group->pkey_index == MCAST_INVALID_PKEY_INDEX) + group->pkey_index = pkey_index; + if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) { + rb_erase(&group->node, &group->port->table); + mcast_insert(group->port, group, 1); + } + spin_unlock_irq(&group->port->lock); + } + mcast_work_handler(&group->work); +} + +static void leave_handler(int status, struct ib_sa_mcmember_rec *rec, + void *context) +{ + struct mcast_group *group = context; + + if (status && (group->retries > 0) && + !send_leave(group, group->leave_state)) + group->retries--; + else + mcast_work_handler(&group->work); +} + +static struct mcast_group *acquire_group(struct mcast_port *port, + union ib_gid *mgid, gfp_t gfp_mask) +{ + struct mcast_group *group, *cur_group; + unsigned long flags; + int is_mgid0; + + is_mgid0 = !memcmp(&mgid0, mgid, sizeof mgid0); + if (!is_mgid0) { + spin_lock_irqsave(&port->lock, flags); + group = mcast_find(port, mgid); + if (group) + goto found; + spin_unlock_irqrestore(&port->lock, flags); + } + + group = kzalloc(sizeof *group, gfp_mask); + if (!group) + return NULL; + + group->retries = 3; + group->port = port; + group->rec.mgid = *mgid; + group->pkey_index = MCAST_INVALID_PKEY_INDEX; + INIT_LIST_HEAD(&group->pending_list); + INIT_LIST_HEAD(&group->active_list); + INIT_WORK(&group->work, mcast_work_handler); + spin_lock_init(&group->lock); + + spin_lock_irqsave(&port->lock, flags); + cur_group = mcast_insert(port, group, is_mgid0); + if (cur_group) { + kfree(group); + group = cur_group; + } else + atomic_inc(&port->refcount); +found: + atomic_inc(&group->refcount); + spin_unlock_irqrestore(&port->lock, flags); + return group; +} + +/* + * We serialize all join requests to a single group to make our lives much + * easier. Otherwise, two users could try to join the same group + * simultaneously, with different configurations, one could leave while the + * join is in progress, etc., which makes locking around error recovery + * difficult. + */ +struct ib_sa_multicast * +ib_sa_join_multicast(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + struct ib_sa_mcmember_rec *rec, + ib_sa_comp_mask comp_mask, gfp_t gfp_mask, + int (*callback)(int status, + struct ib_sa_multicast *multicast), + void *context) +{ + struct mcast_device *dev; + struct mcast_member *member; + struct ib_sa_multicast *multicast; + int ret; + + dev = ib_get_client_data(device, &mcast_client); + if (!dev) + return ERR_PTR(-ENODEV); + + member = kmalloc(sizeof *member, gfp_mask); + if (!member) + return ERR_PTR(-ENOMEM); + + ib_sa_client_get(client); + member->client = client; + member->multicast.rec = *rec; + member->multicast.comp_mask = comp_mask; + member->multicast.callback = callback; + member->multicast.context = context; + init_completion(&member->comp); + atomic_set(&member->refcount, 1); + member->state = MCAST_JOINING; + + member->group = acquire_group(&dev->port[port_num - dev->start_port], + &rec->mgid, gfp_mask); + if (!member->group) { + ret = -ENOMEM; + goto err; + } + + /* + * The user will get the multicast structure in their callback. They + * could then free the multicast structure before we can return from + * this routine. So we save the pointer to return before queuing + * any callback. + */ + multicast = &member->multicast; + queue_join(member); + return multicast; + +err: + ib_sa_client_put(client); + kfree(member); + return ERR_PTR(ret); +} +EXPORT_SYMBOL(ib_sa_join_multicast); + +void ib_sa_free_multicast(struct ib_sa_multicast *multicast) +{ + struct mcast_member *member; + struct mcast_group *group; + + member = container_of(multicast, struct mcast_member, multicast); + group = member->group; + + spin_lock_irq(&group->lock); + if (member->state == MCAST_MEMBER) + adjust_membership(group, multicast->rec.join_state, -1); + + list_del_init(&member->list); + + if (group->state == MCAST_IDLE) { + group->state = MCAST_BUSY; + spin_unlock_irq(&group->lock); + /* Continue to hold reference on group until callback */ + queue_work(mcast_wq, &group->work); + } else { + spin_unlock_irq(&group->lock); + release_group(group); + } + + deref_member(member); + wait_for_completion(&member->comp); + ib_sa_client_put(member->client); + kfree(member); +} +EXPORT_SYMBOL(ib_sa_free_multicast); + +int ib_sa_get_mcmember_rec(struct ib_device *device, u8 port_num, + union ib_gid *mgid, struct ib_sa_mcmember_rec *rec) +{ + struct mcast_device *dev; + struct mcast_port *port; + struct mcast_group *group; + unsigned long flags; + int ret = 0; + + dev = ib_get_client_data(device, &mcast_client); + if (!dev) + return -ENODEV; + + port = &dev->port[port_num - dev->start_port]; + spin_lock_irqsave(&port->lock, flags); + group = mcast_find(port, mgid); + if (group) + *rec = group->rec; + else + ret = -EADDRNOTAVAIL; + spin_unlock_irqrestore(&port->lock, flags); + + return ret; +} +EXPORT_SYMBOL(ib_sa_get_mcmember_rec); + +int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num, + struct ib_sa_mcmember_rec *rec, + struct ib_ah_attr *ah_attr) +{ + int ret; + u16 gid_index; + u8 p; + + ret = ib_find_cached_gid(device, &rec->port_gid, &p, &gid_index); + if (ret) + return ret; + + memset(ah_attr, 0, sizeof *ah_attr); + ah_attr->dlid = be16_to_cpu(rec->mlid); + ah_attr->sl = rec->sl; + ah_attr->port_num = port_num; + ah_attr->static_rate = rec->rate; + + ah_attr->ah_flags = IB_AH_GRH; + ah_attr->grh.dgid = rec->mgid; + + ah_attr->grh.sgid_index = (u8) gid_index; + ah_attr->grh.flow_label = be32_to_cpu(rec->flow_label); + ah_attr->grh.hop_limit = rec->hop_limit; + ah_attr->grh.traffic_class = rec->traffic_class; + + return 0; +} +EXPORT_SYMBOL(ib_init_ah_from_mcmember); + +static void mcast_groups_event(struct mcast_port *port, + enum mcast_group_state state) +{ + struct mcast_group *group; + struct rb_node *node; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + for (node = rb_first(&port->table); node; node = rb_next(node)) { + group = rb_entry(node, struct mcast_group, node); + spin_lock(&group->lock); + if (group->state == MCAST_IDLE) { + atomic_inc(&group->refcount); + queue_work(mcast_wq, &group->work); + } + if (group->state != MCAST_GROUP_ERROR) + group->state = state; + spin_unlock(&group->lock); + } + spin_unlock_irqrestore(&port->lock, flags); +} + +static void mcast_event_handler(struct ib_event_handler *handler, + struct ib_event *event) +{ + struct mcast_device *dev; + int index; + + dev = container_of(handler, struct mcast_device, event_handler); + if (rdma_port_get_link_layer(dev->device, event->element.port_num) != + IB_LINK_LAYER_INFINIBAND) + return; + + index = event->element.port_num - dev->start_port; + + switch (event->event) { + case IB_EVENT_PORT_ERR: + case IB_EVENT_LID_CHANGE: + case IB_EVENT_SM_CHANGE: + case IB_EVENT_CLIENT_REREGISTER: + mcast_groups_event(&dev->port[index], MCAST_GROUP_ERROR); + break; + case IB_EVENT_PKEY_CHANGE: + mcast_groups_event(&dev->port[index], MCAST_PKEY_EVENT); + break; + default: + break; + } +} + +static void mcast_add_one(struct ib_device *device) +{ + struct mcast_device *dev; + struct mcast_port *port; + int i; + int count = 0; + + if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) + return; + + dev = kmalloc(sizeof *dev + device->phys_port_cnt * sizeof *port, + GFP_KERNEL); + if (!dev) + return; + + if (device->node_type == RDMA_NODE_IB_SWITCH) + dev->start_port = dev->end_port = 0; + else { + dev->start_port = 1; + dev->end_port = device->phys_port_cnt; + } + + for (i = 0; i <= dev->end_port - dev->start_port; i++) { + if (rdma_port_get_link_layer(device, dev->start_port + i) != + IB_LINK_LAYER_INFINIBAND) + continue; + port = &dev->port[i]; + port->dev = dev; + port->port_num = dev->start_port + i; + spin_lock_init(&port->lock); + port->table = RB_ROOT; + init_completion(&port->comp); + atomic_set(&port->refcount, 1); + ++count; + } + + if (!count) { + kfree(dev); + return; + } + + dev->device = device; + ib_set_client_data(device, &mcast_client, dev); + + INIT_IB_EVENT_HANDLER(&dev->event_handler, device, mcast_event_handler); + ib_register_event_handler(&dev->event_handler); +} + +static void mcast_remove_one(struct ib_device *device) +{ + struct mcast_device *dev; + struct mcast_port *port; + int i; + + dev = ib_get_client_data(device, &mcast_client); + if (!dev) + return; + + ib_unregister_event_handler(&dev->event_handler); + flush_workqueue(mcast_wq); + + for (i = 0; i <= dev->end_port - dev->start_port; i++) { + if (rdma_port_get_link_layer(device, dev->start_port + i) == + IB_LINK_LAYER_INFINIBAND) { + port = &dev->port[i]; + deref_port(port); + wait_for_completion(&port->comp); + } + } + + kfree(dev); +} + +int mcast_init(void) +{ + int ret; + + mcast_wq = create_singlethread_workqueue("ib_mcast"); + if (!mcast_wq) + return -ENOMEM; + + ib_sa_register_client(&sa_client); + + ret = ib_register_client(&mcast_client); + if (ret) + goto err; + return 0; + +err: + ib_sa_unregister_client(&sa_client); + destroy_workqueue(mcast_wq); + return ret; +} + +void mcast_cleanup(void) +{ + ib_unregister_client(&mcast_client); + ib_sa_unregister_client(&sa_client); + destroy_workqueue(mcast_wq); +} diff --git a/sys/ofed/drivers/infiniband/core/notice.c b/sys/ofed/drivers/infiniband/core/notice.c new file mode 100644 index 000000000000..4a8d98f3e06c --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/notice.c @@ -0,0 +1,749 @@ +/* + * Copyright (c) 2006 Intel Corporation.  All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sa.h" + +MODULE_AUTHOR("Sean Hefty"); +MODULE_DESCRIPTION("InfiniBand InformInfo & Notice event handling"); +MODULE_LICENSE("Dual BSD/GPL"); + +static void inform_add_one(struct ib_device *device); +static void inform_remove_one(struct ib_device *device); + +static struct ib_client inform_client = { + .name = "ib_notice", + .add = inform_add_one, + .remove = inform_remove_one +}; + +static struct ib_sa_client sa_client; +static struct workqueue_struct *inform_wq; + +struct inform_device; + +struct inform_port { + struct inform_device *dev; + spinlock_t lock; + struct rb_root table; + atomic_t refcount; + struct completion comp; + u8 port_num; +}; + +struct inform_device { + struct ib_device *device; + struct ib_event_handler event_handler; + int start_port; + int end_port; + struct inform_port port[0]; +}; + +enum inform_state { + INFORM_IDLE, + INFORM_REGISTERING, + INFORM_MEMBER, + INFORM_BUSY, + INFORM_ERROR +}; + +struct inform_member; + +struct inform_group { + u16 trap_number; + struct rb_node node; + struct inform_port *port; + spinlock_t lock; + struct work_struct work; + struct list_head pending_list; + struct list_head active_list; + struct list_head notice_list; + struct inform_member *last_join; + int members; + enum inform_state join_state; /* State relative to SA */ + atomic_t refcount; + enum inform_state state; + struct ib_sa_query *query; + int query_id; +}; + +struct inform_member { + struct ib_inform_info info; + struct ib_sa_client *client; + struct inform_group *group; + struct list_head list; + enum inform_state state; + atomic_t refcount; + struct completion comp; +}; + +struct inform_notice { + struct list_head list; + struct ib_sa_notice notice; +}; + +static void reg_handler(int status, struct ib_sa_inform *inform, + void *context); +static void unreg_handler(int status, struct ib_sa_inform *inform, + void *context); + +static struct inform_group *inform_find(struct inform_port *port, + u16 trap_number) +{ + struct rb_node *node = port->table.rb_node; + struct inform_group *group; + + while (node) { + group = rb_entry(node, struct inform_group, node); + if (trap_number < group->trap_number) + node = node->rb_left; + else if (trap_number > group->trap_number) + node = node->rb_right; + else + return group; + } + return NULL; +} + +static struct inform_group *inform_insert(struct inform_port *port, + struct inform_group *group) +{ + struct rb_node **link = &port->table.rb_node; + struct rb_node *parent = NULL; + struct inform_group *cur_group; + + while (*link) { + parent = *link; + cur_group = rb_entry(parent, struct inform_group, node); + if (group->trap_number < cur_group->trap_number) + link = &(*link)->rb_left; + else if (group->trap_number > cur_group->trap_number) + link = &(*link)->rb_right; + else + return cur_group; + } + rb_link_node(&group->node, parent, link); + rb_insert_color(&group->node, &port->table); + return NULL; +} + +static void deref_port(struct inform_port *port) +{ + if (atomic_dec_and_test(&port->refcount)) + complete(&port->comp); +} + +static void release_group(struct inform_group *group) +{ + struct inform_port *port = group->port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (atomic_dec_and_test(&group->refcount)) { + rb_erase(&group->node, &port->table); + spin_unlock_irqrestore(&port->lock, flags); + kfree(group); + deref_port(port); + } else + spin_unlock_irqrestore(&port->lock, flags); +} + +static void deref_member(struct inform_member *member) +{ + if (atomic_dec_and_test(&member->refcount)) + complete(&member->comp); +} + +static void queue_reg(struct inform_member *member) +{ + struct inform_group *group = member->group; + unsigned long flags; + + spin_lock_irqsave(&group->lock, flags); + list_add(&member->list, &group->pending_list); + if (group->state == INFORM_IDLE) { + group->state = INFORM_BUSY; + atomic_inc(&group->refcount); + queue_work(inform_wq, &group->work); + } + spin_unlock_irqrestore(&group->lock, flags); +} + +static int send_reg(struct inform_group *group, struct inform_member *member) +{ + struct inform_port *port = group->port; + struct ib_sa_inform inform; + int ret; + + memset(&inform, 0, sizeof inform); + inform.lid_range_begin = cpu_to_be16(0xFFFF); + inform.is_generic = 1; + inform.subscribe = 1; + inform.type = cpu_to_be16(IB_SA_EVENT_TYPE_ALL); + inform.trap.generic.trap_num = cpu_to_be16(member->info.trap_number); + inform.trap.generic.resp_time = 19; + inform.trap.generic.producer_type = + cpu_to_be32(IB_SA_EVENT_PRODUCER_TYPE_ALL); + + group->last_join = member; + ret = ib_sa_informinfo_query(&sa_client, port->dev->device, + port->port_num, &inform, 3000, GFP_KERNEL, + reg_handler, group,&group->query); + if (ret >= 0) { + group->query_id = ret; + ret = 0; + } + return ret; +} + +static int send_unreg(struct inform_group *group) +{ + struct inform_port *port = group->port; + struct ib_sa_inform inform; + int ret; + + memset(&inform, 0, sizeof inform); + inform.lid_range_begin = cpu_to_be16(0xFFFF); + inform.is_generic = 1; + inform.type = cpu_to_be16(IB_SA_EVENT_TYPE_ALL); + inform.trap.generic.trap_num = cpu_to_be16(group->trap_number); + inform.trap.generic.qpn = IB_QP1; + inform.trap.generic.resp_time = 19; + inform.trap.generic.producer_type = + cpu_to_be32(IB_SA_EVENT_PRODUCER_TYPE_ALL); + + ret = ib_sa_informinfo_query(&sa_client, port->dev->device, + port->port_num, &inform, 3000, GFP_KERNEL, + unreg_handler, group, &group->query); + if (ret >= 0) { + group->query_id = ret; + ret = 0; + } + return ret; +} + +static void join_group(struct inform_group *group, struct inform_member *member) +{ + member->state = INFORM_MEMBER; + group->members++; + list_move(&member->list, &group->active_list); +} + +static int fail_join(struct inform_group *group, struct inform_member *member, + int status) +{ + spin_lock_irq(&group->lock); + list_del_init(&member->list); + spin_unlock_irq(&group->lock); + return member->info.callback(status, &member->info, NULL); +} + +static void process_group_error(struct inform_group *group) +{ + struct inform_member *member; + int ret; + + spin_lock_irq(&group->lock); + while (!list_empty(&group->active_list)) { + member = list_entry(group->active_list.next, + struct inform_member, list); + atomic_inc(&member->refcount); + list_del_init(&member->list); + group->members--; + member->state = INFORM_ERROR; + spin_unlock_irq(&group->lock); + + ret = member->info.callback(-ENETRESET, &member->info, NULL); + deref_member(member); + if (ret) + ib_sa_unregister_inform_info(&member->info); + spin_lock_irq(&group->lock); + } + + group->join_state = INFORM_IDLE; + group->state = INFORM_BUSY; + spin_unlock_irq(&group->lock); +} + +/* + * Report a notice to all active subscribers. We use a temporary list to + * handle unsubscription requests while the notice is being reported, which + * avoids holding the group lock while in the user's callback. + */ +static void process_notice(struct inform_group *group, + struct inform_notice *info_notice) +{ + struct inform_member *member; + struct list_head list; + int ret; + + INIT_LIST_HEAD(&list); + + spin_lock_irq(&group->lock); + list_splice_init(&group->active_list, &list); + while (!list_empty(&list)) { + + member = list_entry(list.next, struct inform_member, list); + atomic_inc(&member->refcount); + list_move(&member->list, &group->active_list); + spin_unlock_irq(&group->lock); + + ret = member->info.callback(0, &member->info, + &info_notice->notice); + deref_member(member); + if (ret) + ib_sa_unregister_inform_info(&member->info); + spin_lock_irq(&group->lock); + } + spin_unlock_irq(&group->lock); +} + +static void inform_work_handler(struct work_struct *work) +{ + struct inform_group *group; + struct inform_member *member; + struct ib_inform_info *info; + struct inform_notice *info_notice; + int status, ret; + + group = container_of(work, typeof(*group), work); +retest: + spin_lock_irq(&group->lock); + while (!list_empty(&group->pending_list) || + !list_empty(&group->notice_list) || + (group->state == INFORM_ERROR)) { + + if (group->state == INFORM_ERROR) { + spin_unlock_irq(&group->lock); + process_group_error(group); + goto retest; + } + + if (!list_empty(&group->notice_list)) { + info_notice = list_entry(group->notice_list.next, + struct inform_notice, list); + list_del(&info_notice->list); + spin_unlock_irq(&group->lock); + process_notice(group, info_notice); + kfree(info_notice); + goto retest; + } + + member = list_entry(group->pending_list.next, + struct inform_member, list); + info = &member->info; + atomic_inc(&member->refcount); + + if (group->join_state == INFORM_MEMBER) { + join_group(group, member); + spin_unlock_irq(&group->lock); + ret = info->callback(0, info, NULL); + } else { + spin_unlock_irq(&group->lock); + status = send_reg(group, member); + if (!status) { + deref_member(member); + return; + } + ret = fail_join(group, member, status); + } + + deref_member(member); + if (ret) + ib_sa_unregister_inform_info(&member->info); + spin_lock_irq(&group->lock); + } + + if (!group->members && (group->join_state == INFORM_MEMBER)) { + group->join_state = INFORM_IDLE; + spin_unlock_irq(&group->lock); + if (send_unreg(group)) + goto retest; + } else { + group->state = INFORM_IDLE; + spin_unlock_irq(&group->lock); + release_group(group); + } +} + +/* + * Fail a join request if it is still active - at the head of the pending queue. + */ +static void process_join_error(struct inform_group *group, int status) +{ + struct inform_member *member; + int ret; + + spin_lock_irq(&group->lock); + member = list_entry(group->pending_list.next, + struct inform_member, list); + if (group->last_join == member) { + atomic_inc(&member->refcount); + list_del_init(&member->list); + spin_unlock_irq(&group->lock); + ret = member->info.callback(status, &member->info, NULL); + deref_member(member); + if (ret) + ib_sa_unregister_inform_info(&member->info); + } else + spin_unlock_irq(&group->lock); +} + +static void reg_handler(int status, struct ib_sa_inform *inform, void *context) +{ + struct inform_group *group = context; + + if (status) + process_join_error(group, status); + else + group->join_state = INFORM_MEMBER; + + inform_work_handler(&group->work); +} + +static void unreg_handler(int status, struct ib_sa_inform *rec, void *context) +{ + struct inform_group *group = context; + + inform_work_handler(&group->work); +} + +int notice_dispatch(struct ib_device *device, u8 port_num, + struct ib_sa_notice *notice) +{ + struct inform_device *dev; + struct inform_port *port; + struct inform_group *group; + struct inform_notice *info_notice; + + dev = ib_get_client_data(device, &inform_client); + if (!dev) + return 0; /* No one to give notice to. */ + + port = &dev->port[port_num - dev->start_port]; + spin_lock_irq(&port->lock); + group = inform_find(port, __be16_to_cpu(notice->trap. + generic.trap_num)); + if (!group) { + spin_unlock_irq(&port->lock); + return 0; + } + + atomic_inc(&group->refcount); + spin_unlock_irq(&port->lock); + + info_notice = kmalloc(sizeof *info_notice, GFP_KERNEL); + if (!info_notice) { + release_group(group); + return -ENOMEM; + } + + info_notice->notice = *notice; + + spin_lock_irq(&group->lock); + list_add(&info_notice->list, &group->notice_list); + if (group->state == INFORM_IDLE) { + group->state = INFORM_BUSY; + spin_unlock_irq(&group->lock); + inform_work_handler(&group->work); + } else { + spin_unlock_irq(&group->lock); + release_group(group); + } + + return 0; +} + +static struct inform_group *acquire_group(struct inform_port *port, + u16 trap_number, gfp_t gfp_mask) +{ + struct inform_group *group, *cur_group; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + group = inform_find(port, trap_number); + if (group) + goto found; + spin_unlock_irqrestore(&port->lock, flags); + + group = kzalloc(sizeof *group, gfp_mask); + if (!group) + return NULL; + + group->port = port; + group->trap_number = trap_number; + INIT_LIST_HEAD(&group->pending_list); + INIT_LIST_HEAD(&group->active_list); + INIT_LIST_HEAD(&group->notice_list); + INIT_WORK(&group->work, inform_work_handler); + spin_lock_init(&group->lock); + + spin_lock_irqsave(&port->lock, flags); + cur_group = inform_insert(port, group); + if (cur_group) { + kfree(group); + group = cur_group; + } else + atomic_inc(&port->refcount); +found: + atomic_inc(&group->refcount); + spin_unlock_irqrestore(&port->lock, flags); + return group; +} + +/* + * We serialize all join requests to a single group to make our lives much + * easier. Otherwise, two users could try to join the same group + * simultaneously, with different configurations, one could leave while the + * join is in progress, etc., which makes locking around error recovery + * difficult. + */ +struct ib_inform_info * +ib_sa_register_inform_info(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + u16 trap_number, gfp_t gfp_mask, + int (*callback)(int status, + struct ib_inform_info *info, + struct ib_sa_notice *notice), + void *context) +{ + struct inform_device *dev; + struct inform_member *member; + struct ib_inform_info *info; + int ret; + + dev = ib_get_client_data(device, &inform_client); + if (!dev) + return ERR_PTR(-ENODEV); + + member = kzalloc(sizeof *member, gfp_mask); + if (!member) + return ERR_PTR(-ENOMEM); + + ib_sa_client_get(client); + member->client = client; + member->info.trap_number = trap_number; + member->info.callback = callback; + member->info.context = context; + init_completion(&member->comp); + atomic_set(&member->refcount, 1); + member->state = INFORM_REGISTERING; + + member->group = acquire_group(&dev->port[port_num - dev->start_port], + trap_number, gfp_mask); + if (!member->group) { + ret = -ENOMEM; + goto err; + } + + /* + * The user will get the info structure in their callback. They + * could then free the info structure before we can return from + * this routine. So we save the pointer to return before queuing + * any callback. + */ + info = &member->info; + queue_reg(member); + return info; + +err: + ib_sa_client_put(member->client); + kfree(member); + return ERR_PTR(ret); +} +EXPORT_SYMBOL(ib_sa_register_inform_info); + +void ib_sa_unregister_inform_info(struct ib_inform_info *info) +{ + struct inform_member *member; + struct inform_group *group; + + member = container_of(info, struct inform_member, info); + group = member->group; + + spin_lock_irq(&group->lock); + if (member->state == INFORM_MEMBER) + group->members--; + + list_del_init(&member->list); + + if (group->state == INFORM_IDLE) { + group->state = INFORM_BUSY; + spin_unlock_irq(&group->lock); + /* Continue to hold reference on group until callback */ + queue_work(inform_wq, &group->work); + } else { + spin_unlock_irq(&group->lock); + release_group(group); + } + + deref_member(member); + wait_for_completion(&member->comp); + ib_sa_client_put(member->client); + kfree(member); +} +EXPORT_SYMBOL(ib_sa_unregister_inform_info); + +static void inform_groups_lost(struct inform_port *port) +{ + struct inform_group *group; + struct rb_node *node; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + for (node = rb_first(&port->table); node; node = rb_next(node)) { + group = rb_entry(node, struct inform_group, node); + spin_lock(&group->lock); + if (group->state == INFORM_IDLE) { + atomic_inc(&group->refcount); + queue_work(inform_wq, &group->work); + } + group->state = INFORM_ERROR; + spin_unlock(&group->lock); + } + spin_unlock_irqrestore(&port->lock, flags); +} + +static void inform_event_handler(struct ib_event_handler *handler, + struct ib_event *event) +{ + struct inform_device *dev; + + dev = container_of(handler, struct inform_device, event_handler); + + switch (event->event) { + case IB_EVENT_PORT_ERR: + case IB_EVENT_LID_CHANGE: + case IB_EVENT_SM_CHANGE: + case IB_EVENT_CLIENT_REREGISTER: + inform_groups_lost(&dev->port[event->element.port_num - + dev->start_port]); + break; + default: + break; + } +} + +static void inform_add_one(struct ib_device *device) +{ + struct inform_device *dev; + struct inform_port *port; + int i; + + if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) + return; + + dev = kmalloc(sizeof *dev + device->phys_port_cnt * sizeof *port, + GFP_KERNEL); + if (!dev) + return; + + if (device->node_type == RDMA_NODE_IB_SWITCH) + dev->start_port = dev->end_port = 0; + else { + dev->start_port = 1; + dev->end_port = device->phys_port_cnt; + } + + for (i = 0; i <= dev->end_port - dev->start_port; i++) { + port = &dev->port[i]; + port->dev = dev; + port->port_num = dev->start_port + i; + spin_lock_init(&port->lock); + port->table = RB_ROOT; + init_completion(&port->comp); + atomic_set(&port->refcount, 1); + } + + dev->device = device; + ib_set_client_data(device, &inform_client, dev); + + INIT_IB_EVENT_HANDLER(&dev->event_handler, device, inform_event_handler); + ib_register_event_handler(&dev->event_handler); +} + +static void inform_remove_one(struct ib_device *device) +{ + struct inform_device *dev; + struct inform_port *port; + int i; + + dev = ib_get_client_data(device, &inform_client); + if (!dev) + return; + + ib_unregister_event_handler(&dev->event_handler); + flush_workqueue(inform_wq); + + for (i = 0; i <= dev->end_port - dev->start_port; i++) { + port = &dev->port[i]; + deref_port(port); + wait_for_completion(&port->comp); + } + + kfree(dev); +} + +int notice_init(void) +{ + int ret; + + inform_wq = create_singlethread_workqueue("ib_inform"); + if (!inform_wq) + return -ENOMEM; + + ib_sa_register_client(&sa_client); + + ret = ib_register_client(&inform_client); + if (ret) + goto err; + return 0; + +err: + ib_sa_unregister_client(&sa_client); + destroy_workqueue(inform_wq); + return ret; +} + +void notice_cleanup(void) +{ + ib_unregister_client(&inform_client); + ib_sa_unregister_client(&sa_client); + destroy_workqueue(inform_wq); +} diff --git a/sys/ofed/drivers/infiniband/core/packer.c b/sys/ofed/drivers/infiniband/core/packer.c new file mode 100644 index 000000000000..019bd4b0863e --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/packer.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include + +static u64 value_read(int offset, int size, void *structure) +{ + switch (size) { + case 1: return *(u8 *) (structure + offset); + case 2: return be16_to_cpup((__be16 *) (structure + offset)); + case 4: return be32_to_cpup((__be32 *) (structure + offset)); + case 8: return be64_to_cpup((__be64 *) (structure + offset)); + default: + printk(KERN_WARNING "Field size %d bits not handled\n", size * 8); + return 0; + } +} + +/** + * ib_pack - Pack a structure into a buffer + * @desc:Array of structure field descriptions + * @desc_len:Number of entries in @desc + * @structure:Structure to pack from + * @buf:Buffer to pack into + * + * ib_pack() packs a list of structure fields into a buffer, + * controlled by the array of fields in @desc. + */ +void ib_pack(const struct ib_field *desc, + int desc_len, + void *structure, + void *buf) +{ + int i; + + for (i = 0; i < desc_len; ++i) { + if (desc[i].size_bits <= 32) { + int shift; + u32 val; + __be32 mask; + __be32 *addr; + + shift = 32 - desc[i].offset_bits - desc[i].size_bits; + if (desc[i].struct_size_bytes) + val = value_read(desc[i].struct_offset_bytes, + desc[i].struct_size_bytes, + structure) << shift; + else + val = 0; + + mask = cpu_to_be32(((1ull << desc[i].size_bits) - 1) << shift); + addr = (__be32 *) buf + desc[i].offset_words; + *addr = (*addr & ~mask) | (cpu_to_be32(val) & mask); + } else if (desc[i].size_bits <= 64) { + int shift; + u64 val; + __be64 mask; + __be64 *addr; + + shift = 64 - desc[i].offset_bits - desc[i].size_bits; + if (desc[i].struct_size_bytes) + val = value_read(desc[i].struct_offset_bytes, + desc[i].struct_size_bytes, + structure) << shift; + else + val = 0; + + mask = cpu_to_be64((~0ull >> (64 - desc[i].size_bits)) << shift); + addr = (__be64 *) ((__be32 *) buf + desc[i].offset_words); + *addr = (*addr & ~mask) | (cpu_to_be64(val) & mask); + } else { + if (desc[i].offset_bits % 8 || + desc[i].size_bits % 8) { + printk(KERN_WARNING "Structure field %s of size %d " + "bits is not byte-aligned\n", + desc[i].field_name, desc[i].size_bits); + } + + if (desc[i].struct_size_bytes) + memcpy(buf + desc[i].offset_words * 4 + + desc[i].offset_bits / 8, + structure + desc[i].struct_offset_bytes, + desc[i].size_bits / 8); + else + memset(buf + desc[i].offset_words * 4 + + desc[i].offset_bits / 8, + 0, + desc[i].size_bits / 8); + } + } +} +EXPORT_SYMBOL(ib_pack); + +static void value_write(int offset, int size, u64 val, void *structure) +{ + switch (size * 8) { + case 8: *( u8 *) (structure + offset) = val; break; + case 16: *(__be16 *) (structure + offset) = cpu_to_be16(val); break; + case 32: *(__be32 *) (structure + offset) = cpu_to_be32(val); break; + case 64: *(__be64 *) (structure + offset) = cpu_to_be64(val); break; + default: + printk(KERN_WARNING "Field size %d bits not handled\n", size * 8); + } +} + +/** + * ib_unpack - Unpack a buffer into a structure + * @desc:Array of structure field descriptions + * @desc_len:Number of entries in @desc + * @buf:Buffer to unpack from + * @structure:Structure to unpack into + * + * ib_pack() unpacks a list of structure fields from a buffer, + * controlled by the array of fields in @desc. + */ +void ib_unpack(const struct ib_field *desc, + int desc_len, + void *buf, + void *structure) +{ + int i; + + for (i = 0; i < desc_len; ++i) { + if (!desc[i].struct_size_bytes) + continue; + + if (desc[i].size_bits <= 32) { + int shift; + u32 val; + u32 mask; + __be32 *addr; + + shift = 32 - desc[i].offset_bits - desc[i].size_bits; + mask = ((1ull << desc[i].size_bits) - 1) << shift; + addr = (__be32 *) buf + desc[i].offset_words; + val = (be32_to_cpup(addr) & mask) >> shift; + value_write(desc[i].struct_offset_bytes, + desc[i].struct_size_bytes, + val, + structure); + } else if (desc[i].size_bits <= 64) { + int shift; + u64 val; + u64 mask; + __be64 *addr; + + shift = 64 - desc[i].offset_bits - desc[i].size_bits; + mask = (~0ull >> (64 - desc[i].size_bits)) << shift; + addr = (__be64 *) buf + desc[i].offset_words; + val = (be64_to_cpup(addr) & mask) >> shift; + value_write(desc[i].struct_offset_bytes, + desc[i].struct_size_bytes, + val, + structure); + } else { + if (desc[i].offset_bits % 8 || + desc[i].size_bits % 8) { + printk(KERN_WARNING "Structure field %s of size %d " + "bits is not byte-aligned\n", + desc[i].field_name, desc[i].size_bits); + } + + memcpy(structure + desc[i].struct_offset_bytes, + buf + desc[i].offset_words * 4 + + desc[i].offset_bits / 8, + desc[i].size_bits / 8); + } + } +} +EXPORT_SYMBOL(ib_unpack); diff --git a/sys/ofed/drivers/infiniband/core/sa.h b/sys/ofed/drivers/infiniband/core/sa.h new file mode 100644 index 000000000000..b8abdd767b6c --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/sa.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef SA_H +#define SA_H + +#include + +static inline void ib_sa_client_get(struct ib_sa_client *client) +{ + atomic_inc(&client->users); +} + +static inline void ib_sa_client_put(struct ib_sa_client *client) +{ + if (atomic_dec_and_test(&client->users)) + complete(&client->comp); +} + +int ib_sa_check_selector(ib_sa_comp_mask comp_mask, + ib_sa_comp_mask selector_mask, + ib_sa_comp_mask value_mask, + u8 selector, u8 src_value, u8 dst_value); + +int ib_sa_pack_attr(void *dst, void *src, int attr_id); + +int ib_sa_unpack_attr(void *dst, void *src, int attr_id); + +int ib_sa_path_rec_query(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + struct ib_sa_path_rec *rec, + ib_sa_comp_mask comp_mask, + int timeout_ms, gfp_t gfp_mask, + void (*callback)(int status, + struct ib_sa_path_rec *resp, + void *context), + void *context, + struct ib_sa_query **sa_query); + +int sa_db_init(void); +void sa_db_cleanup(void); + +int ib_sa_mcmember_rec_query(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + u8 method, + struct ib_sa_mcmember_rec *rec, + ib_sa_comp_mask comp_mask, + int timeout_ms, gfp_t gfp_mask, + void (*callback)(int status, + struct ib_sa_mcmember_rec *resp, + void *context), + void *context, + struct ib_sa_query **sa_query); + +int mcast_init(void); +void mcast_cleanup(void); + +int ib_sa_informinfo_query(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + struct ib_sa_inform *rec, + int timeout_ms, gfp_t gfp_mask, + void (*callback)(int status, + struct ib_sa_inform *resp, + void *context), + void *context, + struct ib_sa_query **sa_query); + +int notice_dispatch(struct ib_device *device, u8 port_num, + struct ib_sa_notice *notice); + +int notice_init(void); +void notice_cleanup(void); + +#endif /* SA_H */ diff --git a/sys/ofed/drivers/infiniband/core/sa_query.c b/sys/ofed/drivers/infiniband/core/sa_query.c new file mode 100644 index 000000000000..0fc1c0ec5c6d --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/sa_query.c @@ -0,0 +1,1480 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "sa.h" + +MODULE_AUTHOR("Roland Dreier"); +MODULE_DESCRIPTION("InfiniBand subnet administration query support"); +MODULE_LICENSE("Dual BSD/GPL"); + +struct ib_sa_sm_ah { + struct ib_ah *ah; + struct kref ref; + u16 pkey_index; + u8 src_path_mask; +}; + +struct ib_sa_port { + struct ib_mad_agent *agent; + struct ib_mad_agent *notice_agent; + struct ib_sa_sm_ah *sm_ah; + struct work_struct update_task; + spinlock_t ah_lock; + u8 port_num; + struct ib_device *device; +}; + +struct ib_sa_device { + int start_port, end_port; + struct ib_event_handler event_handler; + struct ib_sa_port port[0]; +}; + +struct ib_sa_query { + void (*callback)(struct ib_sa_query *, int, struct ib_sa_mad *); + void (*release)(struct ib_sa_query *); + struct ib_sa_client *client; + struct ib_sa_port *port; + struct ib_mad_send_buf *mad_buf; + struct ib_sa_sm_ah *sm_ah; + int id; +}; + +struct ib_sa_service_query { + void (*callback)(int, struct ib_sa_service_rec *, void *); + void *context; + struct ib_sa_query sa_query; +}; + +struct ib_sa_path_query { + void (*callback)(int, struct ib_sa_path_rec *, void *); + void *context; + struct ib_sa_query sa_query; +}; + +struct ib_sa_mcmember_query { + void (*callback)(int, struct ib_sa_mcmember_rec *, void *); + void *context; + struct ib_sa_query sa_query; +}; + +struct ib_sa_inform_query { + void (*callback)(int, struct ib_sa_inform *, void *); + void *context; + struct ib_sa_query sa_query; +}; + +static void ib_sa_add_one(struct ib_device *device); +static void ib_sa_remove_one(struct ib_device *device); + +static struct ib_client sa_client = { + .name = "sa", + .add = ib_sa_add_one, + .remove = ib_sa_remove_one +}; + +static spinlock_t idr_lock; +static DEFINE_IDR(query_idr); + +static spinlock_t tid_lock; +static u32 tid; + +#define PATH_REC_FIELD(field) \ + .struct_offset_bytes = offsetof(struct ib_sa_path_rec, field), \ + .struct_size_bytes = sizeof ((struct ib_sa_path_rec *) 0)->field, \ + .field_name = "sa_path_rec:" #field + +static const struct ib_field path_rec_table[] = { + { PATH_REC_FIELD(service_id), + .offset_words = 0, + .offset_bits = 0, + .size_bits = 64 }, + { PATH_REC_FIELD(dgid), + .offset_words = 2, + .offset_bits = 0, + .size_bits = 128 }, + { PATH_REC_FIELD(sgid), + .offset_words = 6, + .offset_bits = 0, + .size_bits = 128 }, + { PATH_REC_FIELD(dlid), + .offset_words = 10, + .offset_bits = 0, + .size_bits = 16 }, + { PATH_REC_FIELD(slid), + .offset_words = 10, + .offset_bits = 16, + .size_bits = 16 }, + { PATH_REC_FIELD(raw_traffic), + .offset_words = 11, + .offset_bits = 0, + .size_bits = 1 }, + { RESERVED, + .offset_words = 11, + .offset_bits = 1, + .size_bits = 3 }, + { PATH_REC_FIELD(flow_label), + .offset_words = 11, + .offset_bits = 4, + .size_bits = 20 }, + { PATH_REC_FIELD(hop_limit), + .offset_words = 11, + .offset_bits = 24, + .size_bits = 8 }, + { PATH_REC_FIELD(traffic_class), + .offset_words = 12, + .offset_bits = 0, + .size_bits = 8 }, + { PATH_REC_FIELD(reversible), + .offset_words = 12, + .offset_bits = 8, + .size_bits = 1 }, + { PATH_REC_FIELD(numb_path), + .offset_words = 12, + .offset_bits = 9, + .size_bits = 7 }, + { PATH_REC_FIELD(pkey), + .offset_words = 12, + .offset_bits = 16, + .size_bits = 16 }, + { PATH_REC_FIELD(qos_class), + .offset_words = 13, + .offset_bits = 0, + .size_bits = 12 }, + { PATH_REC_FIELD(sl), + .offset_words = 13, + .offset_bits = 12, + .size_bits = 4 }, + { PATH_REC_FIELD(mtu_selector), + .offset_words = 13, + .offset_bits = 16, + .size_bits = 2 }, + { PATH_REC_FIELD(mtu), + .offset_words = 13, + .offset_bits = 18, + .size_bits = 6 }, + { PATH_REC_FIELD(rate_selector), + .offset_words = 13, + .offset_bits = 24, + .size_bits = 2 }, + { PATH_REC_FIELD(rate), + .offset_words = 13, + .offset_bits = 26, + .size_bits = 6 }, + { PATH_REC_FIELD(packet_life_time_selector), + .offset_words = 14, + .offset_bits = 0, + .size_bits = 2 }, + { PATH_REC_FIELD(packet_life_time), + .offset_words = 14, + .offset_bits = 2, + .size_bits = 6 }, + { PATH_REC_FIELD(preference), + .offset_words = 14, + .offset_bits = 8, + .size_bits = 8 }, + { RESERVED, + .offset_words = 14, + .offset_bits = 16, + .size_bits = 48 }, +}; + +#define MCMEMBER_REC_FIELD(field) \ + .struct_offset_bytes = offsetof(struct ib_sa_mcmember_rec, field), \ + .struct_size_bytes = sizeof ((struct ib_sa_mcmember_rec *) 0)->field, \ + .field_name = "sa_mcmember_rec:" #field + +static const struct ib_field mcmember_rec_table[] = { + { MCMEMBER_REC_FIELD(mgid), + .offset_words = 0, + .offset_bits = 0, + .size_bits = 128 }, + { MCMEMBER_REC_FIELD(port_gid), + .offset_words = 4, + .offset_bits = 0, + .size_bits = 128 }, + { MCMEMBER_REC_FIELD(qkey), + .offset_words = 8, + .offset_bits = 0, + .size_bits = 32 }, + { MCMEMBER_REC_FIELD(mlid), + .offset_words = 9, + .offset_bits = 0, + .size_bits = 16 }, + { MCMEMBER_REC_FIELD(mtu_selector), + .offset_words = 9, + .offset_bits = 16, + .size_bits = 2 }, + { MCMEMBER_REC_FIELD(mtu), + .offset_words = 9, + .offset_bits = 18, + .size_bits = 6 }, + { MCMEMBER_REC_FIELD(traffic_class), + .offset_words = 9, + .offset_bits = 24, + .size_bits = 8 }, + { MCMEMBER_REC_FIELD(pkey), + .offset_words = 10, + .offset_bits = 0, + .size_bits = 16 }, + { MCMEMBER_REC_FIELD(rate_selector), + .offset_words = 10, + .offset_bits = 16, + .size_bits = 2 }, + { MCMEMBER_REC_FIELD(rate), + .offset_words = 10, + .offset_bits = 18, + .size_bits = 6 }, + { MCMEMBER_REC_FIELD(packet_life_time_selector), + .offset_words = 10, + .offset_bits = 24, + .size_bits = 2 }, + { MCMEMBER_REC_FIELD(packet_life_time), + .offset_words = 10, + .offset_bits = 26, + .size_bits = 6 }, + { MCMEMBER_REC_FIELD(sl), + .offset_words = 11, + .offset_bits = 0, + .size_bits = 4 }, + { MCMEMBER_REC_FIELD(flow_label), + .offset_words = 11, + .offset_bits = 4, + .size_bits = 20 }, + { MCMEMBER_REC_FIELD(hop_limit), + .offset_words = 11, + .offset_bits = 24, + .size_bits = 8 }, + { MCMEMBER_REC_FIELD(scope), + .offset_words = 12, + .offset_bits = 0, + .size_bits = 4 }, + { MCMEMBER_REC_FIELD(join_state), + .offset_words = 12, + .offset_bits = 4, + .size_bits = 4 }, + { MCMEMBER_REC_FIELD(proxy_join), + .offset_words = 12, + .offset_bits = 8, + .size_bits = 1 }, + { RESERVED, + .offset_words = 12, + .offset_bits = 9, + .size_bits = 23 }, +}; + +#define SERVICE_REC_FIELD(field) \ + .struct_offset_bytes = offsetof(struct ib_sa_service_rec, field), \ + .struct_size_bytes = sizeof ((struct ib_sa_service_rec *) 0)->field, \ + .field_name = "sa_service_rec:" #field + +static const struct ib_field service_rec_table[] = { + { SERVICE_REC_FIELD(id), + .offset_words = 0, + .offset_bits = 0, + .size_bits = 64 }, + { SERVICE_REC_FIELD(gid), + .offset_words = 2, + .offset_bits = 0, + .size_bits = 128 }, + { SERVICE_REC_FIELD(pkey), + .offset_words = 6, + .offset_bits = 0, + .size_bits = 16 }, + { SERVICE_REC_FIELD(lease), + .offset_words = 7, + .offset_bits = 0, + .size_bits = 32 }, + { SERVICE_REC_FIELD(key), + .offset_words = 8, + .offset_bits = 0, + .size_bits = 128 }, + { SERVICE_REC_FIELD(name), + .offset_words = 12, + .offset_bits = 0, + .size_bits = 64*8 }, + { SERVICE_REC_FIELD(data8), + .offset_words = 28, + .offset_bits = 0, + .size_bits = 16*8 }, + { SERVICE_REC_FIELD(data16), + .offset_words = 32, + .offset_bits = 0, + .size_bits = 8*16 }, + { SERVICE_REC_FIELD(data32), + .offset_words = 36, + .offset_bits = 0, + .size_bits = 4*32 }, + { SERVICE_REC_FIELD(data64), + .offset_words = 40, + .offset_bits = 0, + .size_bits = 2*64 }, +}; + +#define INFORM_FIELD(field) \ + .struct_offset_bytes = offsetof(struct ib_sa_inform, field), \ + .struct_size_bytes = sizeof ((struct ib_sa_inform *) 0)->field, \ + .field_name = "sa_inform:" #field + +static const struct ib_field inform_table[] = { + { INFORM_FIELD(gid), + .offset_words = 0, + .offset_bits = 0, + .size_bits = 128 }, + { INFORM_FIELD(lid_range_begin), + .offset_words = 4, + .offset_bits = 0, + .size_bits = 16 }, + { INFORM_FIELD(lid_range_end), + .offset_words = 4, + .offset_bits = 16, + .size_bits = 16 }, + { RESERVED, + .offset_words = 5, + .offset_bits = 0, + .size_bits = 16 }, + { INFORM_FIELD(is_generic), + .offset_words = 5, + .offset_bits = 16, + .size_bits = 8 }, + { INFORM_FIELD(subscribe), + .offset_words = 5, + .offset_bits = 24, + .size_bits = 8 }, + { INFORM_FIELD(type), + .offset_words = 6, + .offset_bits = 0, + .size_bits = 16 }, + { INFORM_FIELD(trap.generic.trap_num), + .offset_words = 6, + .offset_bits = 16, + .size_bits = 16 }, + { INFORM_FIELD(trap.generic.qpn), + .offset_words = 7, + .offset_bits = 0, + .size_bits = 24 }, + { RESERVED, + .offset_words = 7, + .offset_bits = 24, + .size_bits = 3 }, + { INFORM_FIELD(trap.generic.resp_time), + .offset_words = 7, + .offset_bits = 27, + .size_bits = 5 }, + { RESERVED, + .offset_words = 8, + .offset_bits = 0, + .size_bits = 8 }, + { INFORM_FIELD(trap.generic.producer_type), + .offset_words = 8, + .offset_bits = 8, + .size_bits = 24 }, +}; + +#define NOTICE_FIELD(field) \ + .struct_offset_bytes = offsetof(struct ib_sa_notice, field), \ + .struct_size_bytes = sizeof ((struct ib_sa_notice *) 0)->field, \ + .field_name = "sa_notice:" #field + +static const struct ib_field notice_table[] = { + { NOTICE_FIELD(is_generic), + .offset_words = 0, + .offset_bits = 0, + .size_bits = 1 }, + { NOTICE_FIELD(type), + .offset_words = 0, + .offset_bits = 1, + .size_bits = 7 }, + { NOTICE_FIELD(trap.generic.producer_type), + .offset_words = 0, + .offset_bits = 8, + .size_bits = 24 }, + { NOTICE_FIELD(trap.generic.trap_num), + .offset_words = 1, + .offset_bits = 0, + .size_bits = 16 }, + { NOTICE_FIELD(issuer_lid), + .offset_words = 1, + .offset_bits = 16, + .size_bits = 16 }, + { NOTICE_FIELD(notice_toggle), + .offset_words = 2, + .offset_bits = 0, + .size_bits = 1 }, + { NOTICE_FIELD(notice_count), + .offset_words = 2, + .offset_bits = 1, + .size_bits = 15 }, + { NOTICE_FIELD(data_details), + .offset_words = 2, + .offset_bits = 16, + .size_bits = 432 }, + { NOTICE_FIELD(issuer_gid), + .offset_words = 16, + .offset_bits = 0, + .size_bits = 128 }, +}; + +int ib_sa_check_selector(ib_sa_comp_mask comp_mask, + ib_sa_comp_mask selector_mask, + ib_sa_comp_mask value_mask, + u8 selector, u8 src_value, u8 dst_value) +{ + int err; + + if (!(comp_mask & selector_mask) || !(comp_mask & value_mask)) + return 0; + + switch (selector) { + case IB_SA_GT: + err = (src_value <= dst_value); + break; + case IB_SA_LT: + err = (src_value >= dst_value); + break; + case IB_SA_EQ: + err = (src_value != dst_value); + break; + default: + err = 0; + break; + } + + return err; +} + +int ib_sa_pack_attr(void *dst, void *src, int attr_id) +{ + switch (attr_id) { + case IB_SA_ATTR_PATH_REC: + ib_pack(path_rec_table, ARRAY_SIZE(path_rec_table), src, dst); + break; + default: + return -EINVAL; + } + return 0; +} + +int ib_sa_unpack_attr(void *dst, void *src, int attr_id) +{ + switch (attr_id) { + case IB_SA_ATTR_PATH_REC: + ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table), src, dst); + break; + default: + return -EINVAL; + } + return 0; +} + +static void free_sm_ah(struct kref *kref) +{ + struct ib_sa_sm_ah *sm_ah = container_of(kref, struct ib_sa_sm_ah, ref); + + ib_destroy_ah(sm_ah->ah); + kfree(sm_ah); +} + +static void update_sm_ah(struct work_struct *work) +{ + struct ib_sa_port *port = + container_of(work, struct ib_sa_port, update_task); + struct ib_sa_sm_ah *new_ah; + struct ib_port_attr port_attr; + struct ib_ah_attr ah_attr; + + if (ib_query_port(port->agent->device, port->port_num, &port_attr)) { + printk(KERN_WARNING "Couldn't query port\n"); + return; + } + + new_ah = kmalloc(sizeof *new_ah, GFP_KERNEL); + if (!new_ah) { + printk(KERN_WARNING "Couldn't allocate new SM AH\n"); + return; + } + + kref_init(&new_ah->ref); + new_ah->src_path_mask = (1 << port_attr.lmc) - 1; + + new_ah->pkey_index = 0; + if (ib_find_pkey(port->agent->device, port->port_num, + IB_DEFAULT_PKEY_FULL, &new_ah->pkey_index)) + printk(KERN_ERR "Couldn't find index for default PKey\n"); + + memset(&ah_attr, 0, sizeof ah_attr); + ah_attr.dlid = port_attr.sm_lid; + ah_attr.sl = port_attr.sm_sl; + ah_attr.port_num = port->port_num; + + new_ah->ah = ib_create_ah(port->agent->qp->pd, &ah_attr); + if (IS_ERR(new_ah->ah)) { + printk(KERN_WARNING "Couldn't create new SM AH\n"); + kfree(new_ah); + return; + } + + spin_lock_irq(&port->ah_lock); + if (port->sm_ah) + kref_put(&port->sm_ah->ref, free_sm_ah); + port->sm_ah = new_ah; + spin_unlock_irq(&port->ah_lock); + +} + +static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event) +{ + if (event->event == IB_EVENT_PORT_ERR || + event->event == IB_EVENT_PORT_ACTIVE || + event->event == IB_EVENT_LID_CHANGE || + event->event == IB_EVENT_PKEY_CHANGE || + event->event == IB_EVENT_SM_CHANGE || + event->event == IB_EVENT_CLIENT_REREGISTER) { + unsigned long flags; + struct ib_sa_device *sa_dev = + container_of(handler, typeof(*sa_dev), event_handler); + struct ib_sa_port *port = + &sa_dev->port[event->element.port_num - sa_dev->start_port]; + + if (rdma_port_get_link_layer(handler->device, port->port_num) != IB_LINK_LAYER_INFINIBAND) + return; + + spin_lock_irqsave(&port->ah_lock, flags); + if (port->sm_ah) + kref_put(&port->sm_ah->ref, free_sm_ah); + port->sm_ah = NULL; + spin_unlock_irqrestore(&port->ah_lock, flags); + + schedule_work(&sa_dev->port[event->element.port_num - + sa_dev->start_port].update_task); + } +} + +void ib_sa_register_client(struct ib_sa_client *client) +{ + atomic_set(&client->users, 1); + init_completion(&client->comp); +} +EXPORT_SYMBOL(ib_sa_register_client); + +void ib_sa_unregister_client(struct ib_sa_client *client) +{ + ib_sa_client_put(client); + wait_for_completion(&client->comp); +} +EXPORT_SYMBOL(ib_sa_unregister_client); + +/** + * ib_sa_cancel_query - try to cancel an SA query + * @id:ID of query to cancel + * @query:query pointer to cancel + * + * Try to cancel an SA query. If the id and query don't match up or + * the query has already completed, nothing is done. Otherwise the + * query is canceled and will complete with a status of -EINTR. + */ +void ib_sa_cancel_query(int id, struct ib_sa_query *query) +{ + unsigned long flags; + struct ib_mad_agent *agent; + struct ib_mad_send_buf *mad_buf; + + spin_lock_irqsave(&idr_lock, flags); + if (idr_find(&query_idr, id) != query) { + spin_unlock_irqrestore(&idr_lock, flags); + return; + } + agent = query->port->agent; + mad_buf = query->mad_buf; + spin_unlock_irqrestore(&idr_lock, flags); + + ib_cancel_mad(agent, mad_buf); +} +EXPORT_SYMBOL(ib_sa_cancel_query); + +static u8 get_src_path_mask(struct ib_device *device, u8 port_num) +{ + struct ib_sa_device *sa_dev; + struct ib_sa_port *port; + unsigned long flags; + u8 src_path_mask; + + sa_dev = ib_get_client_data(device, &sa_client); + if (!sa_dev) + return 0x7f; + + port = &sa_dev->port[port_num - sa_dev->start_port]; + spin_lock_irqsave(&port->ah_lock, flags); + src_path_mask = port->sm_ah ? port->sm_ah->src_path_mask : 0x7f; + spin_unlock_irqrestore(&port->ah_lock, flags); + + return src_path_mask; +} + +int ib_init_ah_from_path(struct ib_device *device, u8 port_num, + struct ib_sa_path_rec *rec, struct ib_ah_attr *ah_attr) +{ + int ret; + u16 gid_index; + int force_grh; + + memset(ah_attr, 0, sizeof *ah_attr); + ah_attr->dlid = be16_to_cpu(rec->dlid); + ah_attr->sl = rec->sl; + ah_attr->src_path_bits = be16_to_cpu(rec->slid) & + get_src_path_mask(device, port_num); + ah_attr->port_num = port_num; + ah_attr->static_rate = rec->rate; + + force_grh = rdma_port_get_link_layer(device, port_num) == IB_LINK_LAYER_ETHERNET; + + if (rec->hop_limit > 1 || force_grh) { + ah_attr->ah_flags = IB_AH_GRH; + ah_attr->grh.dgid = rec->dgid; + + ret = ib_find_cached_gid(device, &rec->sgid, &port_num, + &gid_index); + if (ret) + return ret; + + ah_attr->grh.sgid_index = gid_index; + ah_attr->grh.flow_label = be32_to_cpu(rec->flow_label); + ah_attr->grh.hop_limit = rec->hop_limit; + ah_attr->grh.traffic_class = rec->traffic_class; + } + return 0; +} +EXPORT_SYMBOL(ib_init_ah_from_path); + +static int alloc_mad(struct ib_sa_query *query, gfp_t gfp_mask) +{ + unsigned long flags; + + spin_lock_irqsave(&query->port->ah_lock, flags); + if (!query->port->sm_ah) { + spin_unlock_irqrestore(&query->port->ah_lock, flags); + return -EAGAIN; + } + kref_get(&query->port->sm_ah->ref); + query->sm_ah = query->port->sm_ah; + spin_unlock_irqrestore(&query->port->ah_lock, flags); + + query->mad_buf = ib_create_send_mad(query->port->agent, 1, + query->sm_ah->pkey_index, + 0, IB_MGMT_SA_HDR, IB_MGMT_SA_DATA, + gfp_mask); + if (IS_ERR(query->mad_buf)) { + kref_put(&query->sm_ah->ref, free_sm_ah); + return -ENOMEM; + } + + query->mad_buf->ah = query->sm_ah->ah; + + return 0; +} + +static void free_mad(struct ib_sa_query *query) +{ + ib_free_send_mad(query->mad_buf); + kref_put(&query->sm_ah->ref, free_sm_ah); +} + +static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent) +{ + unsigned long flags; + + memset(mad, 0, sizeof *mad); + + mad->mad_hdr.base_version = IB_MGMT_BASE_VERSION; + mad->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM; + mad->mad_hdr.class_version = IB_SA_CLASS_VERSION; + + spin_lock_irqsave(&tid_lock, flags); + mad->mad_hdr.tid = + cpu_to_be64(((u64) agent->hi_tid) << 32 | tid++); + spin_unlock_irqrestore(&tid_lock, flags); +} + +static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask) +{ + unsigned long flags; + int ret, id; + +retry: + if (!idr_pre_get(&query_idr, gfp_mask)) + return -ENOMEM; + spin_lock_irqsave(&idr_lock, flags); + ret = idr_get_new(&query_idr, query, &id); + spin_unlock_irqrestore(&idr_lock, flags); + if (ret == -EAGAIN) + goto retry; + if (ret) + return ret; + + query->mad_buf->timeout_ms = timeout_ms; + query->mad_buf->context[0] = query; + query->id = id; + + ret = ib_post_send_mad(query->mad_buf, NULL); + if (ret) { + spin_lock_irqsave(&idr_lock, flags); + idr_remove(&query_idr, id); + spin_unlock_irqrestore(&idr_lock, flags); + } + + /* + * It's not safe to dereference query any more, because the + * send may already have completed and freed the query in + * another context. + */ + return ret ? ret : id; +} + +void ib_sa_unpack_path(void *attribute, struct ib_sa_path_rec *rec) +{ + ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table), attribute, rec); +} +EXPORT_SYMBOL(ib_sa_unpack_path); + +static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query, + int status, + struct ib_sa_mad *mad) +{ + struct ib_sa_path_query *query = + container_of(sa_query, struct ib_sa_path_query, sa_query); + + if (mad) { + struct ib_sa_path_rec rec; + + ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table), + mad->data, &rec); + query->callback(status, &rec, query->context); + } else + query->callback(status, NULL, query->context); +} + +static void ib_sa_path_rec_release(struct ib_sa_query *sa_query) +{ + kfree(container_of(sa_query, struct ib_sa_path_query, sa_query)); +} + +int ib_sa_path_rec_query(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + struct ib_sa_path_rec *rec, + ib_sa_comp_mask comp_mask, + int timeout_ms, gfp_t gfp_mask, + void (*callback)(int status, + struct ib_sa_path_rec *resp, + void *context), + void *context, + struct ib_sa_query **sa_query) +{ + struct ib_sa_path_query *query; + struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); + struct ib_sa_port *port; + struct ib_mad_agent *agent; + struct ib_sa_mad *mad; + int ret; + + if (!sa_dev) + return -ENODEV; + + port = &sa_dev->port[port_num - sa_dev->start_port]; + agent = port->agent; + + query = kmalloc(sizeof *query, gfp_mask); + if (!query) + return -ENOMEM; + + query->sa_query.port = port; + ret = alloc_mad(&query->sa_query, gfp_mask); + if (ret) + goto err1; + + ib_sa_client_get(client); + query->sa_query.client = client; + query->callback = callback; + query->context = context; + + mad = query->sa_query.mad_buf->mad; + init_mad(mad, agent); + + query->sa_query.callback = callback ? ib_sa_path_rec_callback : NULL; + query->sa_query.release = ib_sa_path_rec_release; + mad->mad_hdr.method = IB_MGMT_METHOD_GET; + mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_PATH_REC); + mad->sa_hdr.comp_mask = comp_mask; + + ib_pack(path_rec_table, ARRAY_SIZE(path_rec_table), rec, mad->data); + + *sa_query = &query->sa_query; + + ret = send_mad(&query->sa_query, timeout_ms, gfp_mask); + if (ret < 0) + goto err2; + + return ret; + +err2: + *sa_query = NULL; + ib_sa_client_put(query->sa_query.client); + free_mad(&query->sa_query); + +err1: + kfree(query); + return ret; +} + +static void ib_sa_service_rec_callback(struct ib_sa_query *sa_query, + int status, + struct ib_sa_mad *mad) +{ + struct ib_sa_service_query *query = + container_of(sa_query, struct ib_sa_service_query, sa_query); + + if (mad) { + struct ib_sa_service_rec rec; + + ib_unpack(service_rec_table, ARRAY_SIZE(service_rec_table), + mad->data, &rec); + query->callback(status, &rec, query->context); + } else + query->callback(status, NULL, query->context); +} + +static void ib_sa_service_rec_release(struct ib_sa_query *sa_query) +{ + kfree(container_of(sa_query, struct ib_sa_service_query, sa_query)); +} + +/** + * ib_sa_service_rec_query - Start Service Record operation + * @client:SA client + * @device:device to send request on + * @port_num: port number to send request on + * @method:SA method - should be get, set, or delete + * @rec:Service Record to send in request + * @comp_mask:component mask to send in request + * @timeout_ms:time to wait for response + * @gfp_mask:GFP mask to use for internal allocations + * @callback:function called when request completes, times out or is + * canceled + * @context:opaque user context passed to callback + * @sa_query:request context, used to cancel request + * + * Send a Service Record set/get/delete to the SA to register, + * unregister or query a service record. + * The callback function will be called when the request completes (or + * fails); status is 0 for a successful response, -EINTR if the query + * is canceled, -ETIMEDOUT is the query timed out, or -EIO if an error + * occurred sending the query. The resp parameter of the callback is + * only valid if status is 0. + * + * If the return value of ib_sa_service_rec_query() is negative, it is an + * error code. Otherwise it is a request ID that can be used to cancel + * the query. + */ +int ib_sa_service_rec_query(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, u8 method, + struct ib_sa_service_rec *rec, + ib_sa_comp_mask comp_mask, + int timeout_ms, gfp_t gfp_mask, + void (*callback)(int status, + struct ib_sa_service_rec *resp, + void *context), + void *context, + struct ib_sa_query **sa_query) +{ + struct ib_sa_service_query *query; + struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); + struct ib_sa_port *port; + struct ib_mad_agent *agent; + struct ib_sa_mad *mad; + int ret; + + if (!sa_dev) + return -ENODEV; + + port = &sa_dev->port[port_num - sa_dev->start_port]; + agent = port->agent; + + if (method != IB_MGMT_METHOD_GET && + method != IB_MGMT_METHOD_SET && + method != IB_SA_METHOD_DELETE) + return -EINVAL; + + query = kmalloc(sizeof *query, gfp_mask); + if (!query) + return -ENOMEM; + + query->sa_query.port = port; + ret = alloc_mad(&query->sa_query, gfp_mask); + if (ret) + goto err1; + + ib_sa_client_get(client); + query->sa_query.client = client; + query->callback = callback; + query->context = context; + + mad = query->sa_query.mad_buf->mad; + init_mad(mad, agent); + + query->sa_query.callback = callback ? ib_sa_service_rec_callback : NULL; + query->sa_query.release = ib_sa_service_rec_release; + mad->mad_hdr.method = method; + mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_SERVICE_REC); + mad->sa_hdr.comp_mask = comp_mask; + + ib_pack(service_rec_table, ARRAY_SIZE(service_rec_table), + rec, mad->data); + + *sa_query = &query->sa_query; + + ret = send_mad(&query->sa_query, timeout_ms, gfp_mask); + if (ret < 0) + goto err2; + + return ret; + +err2: + *sa_query = NULL; + ib_sa_client_put(query->sa_query.client); + free_mad(&query->sa_query); + +err1: + kfree(query); + return ret; +} +EXPORT_SYMBOL(ib_sa_service_rec_query); + +static void ib_sa_mcmember_rec_callback(struct ib_sa_query *sa_query, + int status, + struct ib_sa_mad *mad) +{ + struct ib_sa_mcmember_query *query = + container_of(sa_query, struct ib_sa_mcmember_query, sa_query); + + if (mad) { + struct ib_sa_mcmember_rec rec; + + ib_unpack(mcmember_rec_table, ARRAY_SIZE(mcmember_rec_table), + mad->data, &rec); + query->callback(status, &rec, query->context); + } else + query->callback(status, NULL, query->context); +} + +static void ib_sa_mcmember_rec_release(struct ib_sa_query *sa_query) +{ + kfree(container_of(sa_query, struct ib_sa_mcmember_query, sa_query)); +} + +int ib_sa_mcmember_rec_query(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + u8 method, + struct ib_sa_mcmember_rec *rec, + ib_sa_comp_mask comp_mask, + int timeout_ms, gfp_t gfp_mask, + void (*callback)(int status, + struct ib_sa_mcmember_rec *resp, + void *context), + void *context, + struct ib_sa_query **sa_query) +{ + struct ib_sa_mcmember_query *query; + struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); + struct ib_sa_port *port; + struct ib_mad_agent *agent; + struct ib_sa_mad *mad; + int ret; + + if (!sa_dev) + return -ENODEV; + + port = &sa_dev->port[port_num - sa_dev->start_port]; + agent = port->agent; + + query = kmalloc(sizeof *query, gfp_mask); + if (!query) + return -ENOMEM; + + query->sa_query.port = port; + ret = alloc_mad(&query->sa_query, gfp_mask); + if (ret) + goto err1; + + ib_sa_client_get(client); + query->sa_query.client = client; + query->callback = callback; + query->context = context; + + mad = query->sa_query.mad_buf->mad; + init_mad(mad, agent); + + query->sa_query.callback = callback ? ib_sa_mcmember_rec_callback : NULL; + query->sa_query.release = ib_sa_mcmember_rec_release; + mad->mad_hdr.method = method; + mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_MC_MEMBER_REC); + mad->sa_hdr.comp_mask = comp_mask; + + ib_pack(mcmember_rec_table, ARRAY_SIZE(mcmember_rec_table), + rec, mad->data); + + *sa_query = &query->sa_query; + + ret = send_mad(&query->sa_query, timeout_ms, gfp_mask); + if (ret < 0) + goto err2; + + return ret; + +err2: + *sa_query = NULL; + ib_sa_client_put(query->sa_query.client); + free_mad(&query->sa_query); + +err1: + kfree(query); + return ret; +} + +static void ib_sa_inform_callback(struct ib_sa_query *sa_query, + int status, + struct ib_sa_mad *mad) +{ + struct ib_sa_inform_query *query = + container_of(sa_query, struct ib_sa_inform_query, sa_query); + + if (mad) { + struct ib_sa_inform rec; + + ib_unpack(inform_table, ARRAY_SIZE(inform_table), + mad->data, &rec); + query->callback(status, &rec, query->context); + } else + query->callback(status, NULL, query->context); +} + +static void ib_sa_inform_release(struct ib_sa_query *sa_query) +{ + kfree(container_of(sa_query, struct ib_sa_inform_query, sa_query)); +} + +/** + * ib_sa_informinfo_query - Start an InformInfo registration. + * @client:SA client + * @device:device to send query on + * @port_num: port number to send query on + * @rec:Inform record to send in query + * @timeout_ms:time to wait for response + * @gfp_mask:GFP mask to use for internal allocations + * @callback:function called when notice handler registration completes, + * times out or is canceled + * @context:opaque user context passed to callback + * @sa_query:query context, used to cancel query + * + * This function sends inform info to register with SA to receive + * in-service notice. + * The callback function will be called when the query completes (or + * fails); status is 0 for a successful response, -EINTR if the query + * is canceled, -ETIMEDOUT is the query timed out, or -EIO if an error + * occurred sending the query. The resp parameter of the callback is + * only valid if status is 0. + * + * If the return value of ib_sa_inform_query() is negative, it is an + * error code. Otherwise it is a query ID that can be used to cancel + * the query. + */ +int ib_sa_informinfo_query(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + struct ib_sa_inform *rec, + int timeout_ms, gfp_t gfp_mask, + void (*callback)(int status, + struct ib_sa_inform *resp, + void *context), + void *context, + struct ib_sa_query **sa_query) +{ + struct ib_sa_inform_query *query; + struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); + struct ib_sa_port *port; + struct ib_mad_agent *agent; + struct ib_sa_mad *mad; + int ret; + + if (!sa_dev) + return -ENODEV; + + port = &sa_dev->port[port_num - sa_dev->start_port]; + agent = port->agent; + + query = kmalloc(sizeof *query, gfp_mask); + if (!query) + return -ENOMEM; + + query->sa_query.port = port; + ret = alloc_mad(&query->sa_query, gfp_mask); + if (ret) + goto err1; + + ib_sa_client_get(client); + query->sa_query.client = client; + query->callback = callback; + query->context = context; + + mad = query->sa_query.mad_buf->mad; + init_mad(mad, agent); + + query->sa_query.callback = callback ? ib_sa_inform_callback : NULL; + query->sa_query.release = ib_sa_inform_release; + query->sa_query.port = port; + mad->mad_hdr.method = IB_MGMT_METHOD_SET; + mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_INFORM_INFO); + + ib_pack(inform_table, ARRAY_SIZE(inform_table), rec, mad->data); + + *sa_query = &query->sa_query; + ret = send_mad(&query->sa_query, timeout_ms, gfp_mask); + if (ret < 0) + goto err2; + + return ret; + +err2: + *sa_query = NULL; + ib_sa_client_put(query->sa_query.client); + free_mad(&query->sa_query); +err1: + kfree(query); + return ret; +} + +static void ib_sa_notice_resp(struct ib_sa_port *port, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_mad_send_buf *mad_buf; + struct ib_sa_mad *mad; + int ret; + unsigned long flags; + + mad_buf = ib_create_send_mad(port->notice_agent, 1, 0, 0, + IB_MGMT_SA_HDR, IB_MGMT_SA_DATA, + GFP_KERNEL); + if (IS_ERR(mad_buf)) + return; + + mad = mad_buf->mad; + memcpy(mad, mad_recv_wc->recv_buf.mad, sizeof *mad); + mad->mad_hdr.method = IB_MGMT_METHOD_REPORT_RESP; + + spin_lock_irqsave(&port->ah_lock, flags); + if (!port->sm_ah) { + spin_unlock_irqrestore(&port->ah_lock, flags); + ib_free_send_mad(mad_buf); + return; + } + kref_get(&port->sm_ah->ref); + mad_buf->context[0] = &port->sm_ah->ref; + mad_buf->ah = port->sm_ah->ah; + spin_unlock_irqrestore(&port->ah_lock, flags); + + ret = ib_post_send_mad(mad_buf, NULL); + if (ret) + goto err; + + return; +err: + kref_put(mad_buf->context[0], free_sm_ah); + ib_free_send_mad(mad_buf); +} + +static void send_handler(struct ib_mad_agent *agent, + struct ib_mad_send_wc *mad_send_wc) +{ + struct ib_sa_query *query = mad_send_wc->send_buf->context[0]; + unsigned long flags; + + if (query->callback) + switch (mad_send_wc->status) { + case IB_WC_SUCCESS: + /* No callback -- already got recv */ + break; + case IB_WC_RESP_TIMEOUT_ERR: + query->callback(query, -ETIMEDOUT, NULL); + break; + case IB_WC_WR_FLUSH_ERR: + query->callback(query, -EINTR, NULL); + break; + default: + query->callback(query, -EIO, NULL); + break; + } + + spin_lock_irqsave(&idr_lock, flags); + idr_remove(&query_idr, query->id); + spin_unlock_irqrestore(&idr_lock, flags); + + free_mad(query); + ib_sa_client_put(query->client); + query->release(query); +} + +static void recv_handler(struct ib_mad_agent *mad_agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_sa_query *query; + struct ib_mad_send_buf *mad_buf; + + mad_buf = (void *) (unsigned long) mad_recv_wc->wc->wr_id; + query = mad_buf->context[0]; + + if (query->callback) { + if (mad_recv_wc->wc->status == IB_WC_SUCCESS) + query->callback(query, + mad_recv_wc->recv_buf.mad->mad_hdr.status ? + -EINVAL : 0, + (struct ib_sa_mad *) mad_recv_wc->recv_buf.mad); + else + query->callback(query, -EIO, NULL); + } + + ib_free_recv_mad(mad_recv_wc); +} + +static void notice_resp_handler(struct ib_mad_agent *agent, + struct ib_mad_send_wc *mad_send_wc) +{ + kref_put(mad_send_wc->send_buf->context[0], free_sm_ah); + ib_free_send_mad(mad_send_wc->send_buf); +} + +static void notice_handler(struct ib_mad_agent *mad_agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_sa_port *port; + struct ib_sa_mad *mad; + struct ib_sa_notice notice; + + port = mad_agent->context; + mad = (struct ib_sa_mad *) mad_recv_wc->recv_buf.mad; + ib_unpack(notice_table, ARRAY_SIZE(notice_table), mad->data, ¬ice); + + if (!notice_dispatch(port->device, port->port_num, ¬ice)) + ib_sa_notice_resp(port, mad_recv_wc); + ib_free_recv_mad(mad_recv_wc); +} + +static void ib_sa_add_one(struct ib_device *device) +{ + struct ib_sa_device *sa_dev; + struct ib_mad_reg_req reg_req = { + .mgmt_class = IB_MGMT_CLASS_SUBN_ADM, + .mgmt_class_version = 2 + }; + int s, e, i; + + if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) + return; + + if (device->node_type == RDMA_NODE_IB_SWITCH) + s = e = 0; + else { + s = 1; + e = device->phys_port_cnt; + } + + sa_dev = kzalloc(sizeof *sa_dev + + (e - s + 1) * sizeof (struct ib_sa_port), + GFP_KERNEL); + if (!sa_dev) + return; + + sa_dev->start_port = s; + sa_dev->end_port = e; + + for (i = 0; i <= e - s; ++i) { + spin_lock_init(&sa_dev->port[i].ah_lock); + if (rdma_port_get_link_layer(device, i + 1) != IB_LINK_LAYER_INFINIBAND) + continue; + + sa_dev->port[i].sm_ah = NULL; + sa_dev->port[i].port_num = i + s; + + sa_dev->port[i].agent = + ib_register_mad_agent(device, i + s, IB_QPT_GSI, + NULL, 0, send_handler, + recv_handler, sa_dev); + if (IS_ERR(sa_dev->port[i].agent)) + goto err; + + sa_dev->port[i].device = device; + set_bit(IB_MGMT_METHOD_REPORT, reg_req.method_mask); + sa_dev->port[i].notice_agent = + ib_register_mad_agent(device, i + s, IB_QPT_GSI, + ®_req, 0, notice_resp_handler, + notice_handler, &sa_dev->port[i]); + + if (IS_ERR(sa_dev->port[i].notice_agent)) + goto err; + + INIT_WORK(&sa_dev->port[i].update_task, update_sm_ah); + } + + ib_set_client_data(device, &sa_client, sa_dev); + + /* + * We register our event handler after everything is set up, + * and then update our cached info after the event handler is + * registered to avoid any problems if a port changes state + * during our initialization. + */ + + INIT_IB_EVENT_HANDLER(&sa_dev->event_handler, device, ib_sa_event); + if (ib_register_event_handler(&sa_dev->event_handler)) + goto err; + + for (i = 0; i <= e - s; ++i) + if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND) + update_sm_ah(&sa_dev->port[i].update_task); + + return; + +err: + while (--i >= 0) + if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND) { + if (!IS_ERR(sa_dev->port[i].notice_agent)) + ib_unregister_mad_agent(sa_dev->port[i].notice_agent); + if (!IS_ERR(sa_dev->port[i].agent)) + ib_unregister_mad_agent(sa_dev->port[i].agent); + } + + kfree(sa_dev); + + return; +} + +static void ib_sa_remove_one(struct ib_device *device) +{ + struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); + int i; + + if (!sa_dev) + return; + + ib_unregister_event_handler(&sa_dev->event_handler); + + flush_scheduled_work(); + + for (i = 0; i <= sa_dev->end_port - sa_dev->start_port; ++i) { + if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND) { + ib_unregister_mad_agent(sa_dev->port[i].notice_agent); + ib_unregister_mad_agent(sa_dev->port[i].agent); + if (sa_dev->port[i].sm_ah) + kref_put(&sa_dev->port[i].sm_ah->ref, free_sm_ah); + } + + } + + kfree(sa_dev); +} + +static int __init ib_sa_init(void) +{ + int ret; + + spin_lock_init(&idr_lock); + spin_lock_init(&tid_lock); + + get_random_bytes(&tid, sizeof tid); + + ret = ib_register_client(&sa_client); + if (ret) { + printk(KERN_ERR "Couldn't register ib_sa client\n"); + goto err1; + } + + ret = mcast_init(); + if (ret) { + printk(KERN_ERR "Couldn't initialize multicast handling\n"); + goto err2; + } + + ret = notice_init(); + if (ret) { + printk(KERN_ERR "Couldn't initialize notice handling\n"); + goto err3; + } + + ret = sa_db_init(); + if (ret) { + printk(KERN_ERR "Couldn't initialize local SA\n"); + goto err4; + } + + return 0; +err4: + notice_cleanup(); +err3: + mcast_cleanup(); +err2: + ib_unregister_client(&sa_client); +err1: + return ret; +} + +static void __exit ib_sa_cleanup(void) +{ + sa_db_cleanup(); + mcast_cleanup(); + notice_cleanup(); + ib_unregister_client(&sa_client); + idr_destroy(&query_idr); +} + +module_init_order(ib_sa_init, SI_ORDER_SECOND); +module_exit(ib_sa_cleanup); diff --git a/sys/ofed/drivers/infiniband/core/smi.c b/sys/ofed/drivers/infiniband/core/smi.c new file mode 100644 index 000000000000..87236753bce9 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/smi.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2004, 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved. + * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include "smi.h" + +/* + * Fixup a directed route SMP for sending + * Return 0 if the SMP should be discarded + */ +enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, + u8 node_type, int port_num) +{ + u8 hop_ptr, hop_cnt; + + hop_ptr = smp->hop_ptr; + hop_cnt = smp->hop_cnt; + + /* See section 14.2.2.2, Vol 1 IB spec */ + if (!ib_get_smp_direction(smp)) { + /* C14-9:1 */ + if (hop_cnt && hop_ptr == 0) { + smp->hop_ptr++; + return (smp->initial_path[smp->hop_ptr] == + port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); + } + + /* C14-9:2 */ + if (hop_ptr && hop_ptr < hop_cnt) { + if (node_type != RDMA_NODE_IB_SWITCH) + return IB_SMI_DISCARD; + + /* smp->return_path set when received */ + smp->hop_ptr++; + return (smp->initial_path[smp->hop_ptr] == + port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); + } + + /* C14-9:3 -- We're at the end of the DR segment of path */ + if (hop_ptr == hop_cnt) { + /* smp->return_path set when received */ + smp->hop_ptr++; + return (node_type == RDMA_NODE_IB_SWITCH || + smp->dr_dlid == IB_LID_PERMISSIVE ? + IB_SMI_HANDLE : IB_SMI_DISCARD); + } + + /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ + /* C14-9:5 -- Fail unreasonable hop pointer */ + return (hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD); + + } else { + /* C14-13:1 */ + if (hop_cnt && hop_ptr == hop_cnt + 1) { + smp->hop_ptr--; + return (smp->return_path[smp->hop_ptr] == + port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); + } + + /* C14-13:2 */ + if (2 <= hop_ptr && hop_ptr <= hop_cnt) { + if (node_type != RDMA_NODE_IB_SWITCH) + return IB_SMI_DISCARD; + + smp->hop_ptr--; + return (smp->return_path[smp->hop_ptr] == + port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); + } + + /* C14-13:3 -- at the end of the DR segment of path */ + if (hop_ptr == 1) { + smp->hop_ptr--; + /* C14-13:3 -- SMPs destined for SM shouldn't be here */ + return (node_type == RDMA_NODE_IB_SWITCH || + smp->dr_slid == IB_LID_PERMISSIVE ? + IB_SMI_HANDLE : IB_SMI_DISCARD); + } + + /* C14-13:4 -- hop_ptr = 0 -> should have gone to SM */ + if (hop_ptr == 0) + return IB_SMI_HANDLE; + + /* C14-13:5 -- Check for unreasonable hop pointer */ + return IB_SMI_DISCARD; + } +} + +/* + * Adjust information for a received SMP + * Return 0 if the SMP should be dropped + */ +enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, + int port_num, int phys_port_cnt) +{ + u8 hop_ptr, hop_cnt; + + hop_ptr = smp->hop_ptr; + hop_cnt = smp->hop_cnt; + + /* See section 14.2.2.2, Vol 1 IB spec */ + if (!ib_get_smp_direction(smp)) { + /* C14-9:1 -- sender should have incremented hop_ptr */ + if (hop_cnt && hop_ptr == 0) + return IB_SMI_DISCARD; + + /* C14-9:2 -- intermediate hop */ + if (hop_ptr && hop_ptr < hop_cnt) { + if (node_type != RDMA_NODE_IB_SWITCH) + return IB_SMI_DISCARD; + + smp->return_path[hop_ptr] = port_num; + /* smp->hop_ptr updated when sending */ + return (smp->initial_path[hop_ptr+1] <= phys_port_cnt ? + IB_SMI_HANDLE : IB_SMI_DISCARD); + } + + /* C14-9:3 -- We're at the end of the DR segment of path */ + if (hop_ptr == hop_cnt) { + if (hop_cnt) + smp->return_path[hop_ptr] = port_num; + /* smp->hop_ptr updated when sending */ + + return (node_type == RDMA_NODE_IB_SWITCH || + smp->dr_dlid == IB_LID_PERMISSIVE ? + IB_SMI_HANDLE : IB_SMI_DISCARD); + } + + /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ + /* C14-9:5 -- fail unreasonable hop pointer */ + return (hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD); + + } else { + + /* C14-13:1 */ + if (hop_cnt && hop_ptr == hop_cnt + 1) { + smp->hop_ptr--; + return (smp->return_path[smp->hop_ptr] == + port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); + } + + /* C14-13:2 */ + if (2 <= hop_ptr && hop_ptr <= hop_cnt) { + if (node_type != RDMA_NODE_IB_SWITCH) + return IB_SMI_DISCARD; + + /* smp->hop_ptr updated when sending */ + return (smp->return_path[hop_ptr-1] <= phys_port_cnt ? + IB_SMI_HANDLE : IB_SMI_DISCARD); + } + + /* C14-13:3 -- We're at the end of the DR segment of path */ + if (hop_ptr == 1) { + if (smp->dr_slid == IB_LID_PERMISSIVE) { + /* giving SMP to SM - update hop_ptr */ + smp->hop_ptr--; + return IB_SMI_HANDLE; + } + /* smp->hop_ptr updated when sending */ + return (node_type == RDMA_NODE_IB_SWITCH ? + IB_SMI_HANDLE : IB_SMI_DISCARD); + } + + /* C14-13:4 -- hop_ptr = 0 -> give to SM */ + /* C14-13:5 -- Check for unreasonable hop pointer */ + return (hop_ptr == 0 ? IB_SMI_HANDLE : IB_SMI_DISCARD); + } +} + +enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp) +{ + u8 hop_ptr, hop_cnt; + + hop_ptr = smp->hop_ptr; + hop_cnt = smp->hop_cnt; + + if (!ib_get_smp_direction(smp)) { + /* C14-9:2 -- intermediate hop */ + if (hop_ptr && hop_ptr < hop_cnt) + return IB_SMI_FORWARD; + + /* C14-9:3 -- at the end of the DR segment of path */ + if (hop_ptr == hop_cnt) + return (smp->dr_dlid == IB_LID_PERMISSIVE ? + IB_SMI_SEND : IB_SMI_LOCAL); + + /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ + if (hop_ptr == hop_cnt + 1) + return IB_SMI_SEND; + } else { + /* C14-13:2 -- intermediate hop */ + if (2 <= hop_ptr && hop_ptr <= hop_cnt) + return IB_SMI_FORWARD; + + /* C14-13:3 -- at the end of the DR segment of path */ + if (hop_ptr == 1) + return (smp->dr_slid != IB_LID_PERMISSIVE ? + IB_SMI_SEND : IB_SMI_LOCAL); + } + return IB_SMI_LOCAL; +} + +/* + * Return the forwarding port number from initial_path for outgoing SMP and + * from return_path for returning SMP + */ +int smi_get_fwd_port(struct ib_smp *smp) +{ + return (!ib_get_smp_direction(smp) ? smp->initial_path[smp->hop_ptr+1] : + smp->return_path[smp->hop_ptr-1]); +} diff --git a/sys/ofed/drivers/infiniband/core/smi.h b/sys/ofed/drivers/infiniband/core/smi.h new file mode 100644 index 000000000000..aff96bac49b4 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/smi.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef __SMI_H_ +#define __SMI_H_ + +#include + +enum smi_action { + IB_SMI_DISCARD, + IB_SMI_HANDLE +}; + +enum smi_forward_action { + IB_SMI_LOCAL, /* SMP should be completed up the stack */ + IB_SMI_SEND, /* received DR SMP should be forwarded to the send queue */ + IB_SMI_FORWARD /* SMP should be forwarded (for switches only) */ +}; + +enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, + int port_num, int phys_port_cnt); +int smi_get_fwd_port(struct ib_smp *smp); +extern enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp); +extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, + u8 node_type, int port_num); + +/* + * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM + * via process_mad + */ +static inline enum smi_action smi_check_local_smp(struct ib_smp *smp, + struct ib_device *device) +{ + /* C14-9:3 -- We're at the end of the DR segment of path */ + /* C14-9:4 -- Hop Pointer = Hop Count + 1 -> give to SMA/SM */ + return ((device->process_mad && + !ib_get_smp_direction(smp) && + (smp->hop_ptr == smp->hop_cnt + 1)) ? + IB_SMI_HANDLE : IB_SMI_DISCARD); +} + +/* + * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM + * via process_mad + */ +static inline enum smi_action smi_check_local_returning_smp(struct ib_smp *smp, + struct ib_device *device) +{ + /* C14-13:3 -- We're at the end of the DR segment of path */ + /* C14-13:4 -- Hop Pointer == 0 -> give to SM */ + return ((device->process_mad && + ib_get_smp_direction(smp) && + !smp->hop_ptr) ? IB_SMI_HANDLE : IB_SMI_DISCARD); +} + +#endif /* __SMI_H_ */ diff --git a/sys/ofed/drivers/infiniband/core/sysfs.c b/sys/ofed/drivers/infiniband/core/sysfs.c new file mode 100644 index 000000000000..a40640686aa1 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/sysfs.c @@ -0,0 +1,911 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "core_priv.h" + +#include +#include + +#include + +struct ib_port { + struct kobject kobj; + struct ib_device *ibdev; + struct attribute_group gid_group; + struct attribute_group pkey_group; + u8 port_num; +}; + +struct port_attribute { + struct attribute attr; + ssize_t (*show)(struct ib_port *, struct port_attribute *, char *buf); + ssize_t (*store)(struct ib_port *, struct port_attribute *, + const char *buf, size_t count); +}; + +#define PORT_ATTR(_name, _mode, _show, _store) \ +struct port_attribute port_attr_##_name = __ATTR(_name, _mode, _show, _store) + +#define PORT_ATTR_RO(_name) \ +struct port_attribute port_attr_##_name = __ATTR_RO(_name) + +struct port_table_attribute { + struct port_attribute attr; + char name[8]; + int index; +}; + +static ssize_t port_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct port_attribute *port_attr = + container_of(attr, struct port_attribute, attr); + struct ib_port *p = container_of(kobj, struct ib_port, kobj); + + if (!port_attr->show) + return -EIO; + + return port_attr->show(p, port_attr, buf); +} + +static const struct sysfs_ops port_sysfs_ops = { + .show = port_attr_show +}; + +static ssize_t state_show(struct ib_port *p, struct port_attribute *unused, + char *buf) +{ + struct ib_port_attr attr; + ssize_t ret; + + static const char *state_name[] = { + [IB_PORT_NOP] = "NOP", + [IB_PORT_DOWN] = "DOWN", + [IB_PORT_INIT] = "INIT", + [IB_PORT_ARMED] = "ARMED", + [IB_PORT_ACTIVE] = "ACTIVE", + [IB_PORT_ACTIVE_DEFER] = "ACTIVE_DEFER" + }; + + ret = ib_query_port(p->ibdev, p->port_num, &attr); + if (ret) + return ret; + + return sprintf(buf, "%d: %s\n", attr.state, + attr.state >= 0 && attr.state < ARRAY_SIZE(state_name) ? + state_name[attr.state] : "UNKNOWN"); +} + +static ssize_t lid_show(struct ib_port *p, struct port_attribute *unused, + char *buf) +{ + struct ib_port_attr attr; + ssize_t ret; + + ret = ib_query_port(p->ibdev, p->port_num, &attr); + if (ret) + return ret; + + return sprintf(buf, "0x%x\n", attr.lid); +} + +static ssize_t lid_mask_count_show(struct ib_port *p, + struct port_attribute *unused, + char *buf) +{ + struct ib_port_attr attr; + ssize_t ret; + + ret = ib_query_port(p->ibdev, p->port_num, &attr); + if (ret) + return ret; + + return sprintf(buf, "%d\n", attr.lmc); +} + +static ssize_t sm_lid_show(struct ib_port *p, struct port_attribute *unused, + char *buf) +{ + struct ib_port_attr attr; + ssize_t ret; + + ret = ib_query_port(p->ibdev, p->port_num, &attr); + if (ret) + return ret; + + return sprintf(buf, "0x%x\n", attr.sm_lid); +} + +static ssize_t sm_sl_show(struct ib_port *p, struct port_attribute *unused, + char *buf) +{ + struct ib_port_attr attr; + ssize_t ret; + + ret = ib_query_port(p->ibdev, p->port_num, &attr); + if (ret) + return ret; + + return sprintf(buf, "%d\n", attr.sm_sl); +} + +static ssize_t cap_mask_show(struct ib_port *p, struct port_attribute *unused, + char *buf) +{ + struct ib_port_attr attr; + ssize_t ret; + + ret = ib_query_port(p->ibdev, p->port_num, &attr); + if (ret) + return ret; + + return sprintf(buf, "0x%08x\n", attr.port_cap_flags); +} + +static ssize_t rate_show(struct ib_port *p, struct port_attribute *unused, + char *buf) +{ + struct ib_port_attr attr; + char *speed = ""; + int rate; + ssize_t ret; + + ret = ib_query_port(p->ibdev, p->port_num, &attr); + if (ret) + return ret; + + switch (attr.active_speed) { + case 2: speed = " DDR"; break; + case 4: speed = " QDR"; break; + } + + rate = 25 * ib_width_enum_to_int(attr.active_width) * attr.active_speed; + if (rate < 0) + return -EINVAL; + + return sprintf(buf, "%d%s Gb/sec (%dX%s)\n", + rate / 10, rate % 10 ? ".5" : "", + ib_width_enum_to_int(attr.active_width), speed); +} + +static ssize_t phys_state_show(struct ib_port *p, struct port_attribute *unused, + char *buf) +{ + struct ib_port_attr attr; + + ssize_t ret; + + ret = ib_query_port(p->ibdev, p->port_num, &attr); + if (ret) + return ret; + + switch (attr.phys_state) { + case 1: return sprintf(buf, "1: Sleep\n"); + case 2: return sprintf(buf, "2: Polling\n"); + case 3: return sprintf(buf, "3: Disabled\n"); + case 4: return sprintf(buf, "4: PortConfigurationTraining\n"); + case 5: return sprintf(buf, "5: LinkUp\n"); + case 6: return sprintf(buf, "6: LinkErrorRecovery\n"); + case 7: return sprintf(buf, "7: Phy Test\n"); + default: return sprintf(buf, "%d: \n", attr.phys_state); + } +} + +static ssize_t link_layer_show(struct ib_port *p, struct port_attribute *unused, + char *buf) +{ + switch (rdma_port_get_link_layer(p->ibdev, p->port_num)) { + case IB_LINK_LAYER_INFINIBAND: + return sprintf(buf, "%s\n", "IB"); + case IB_LINK_LAYER_ETHERNET: + return sprintf(buf, "%s\n", "Ethernet"); + default: + return sprintf(buf, "%s\n", "Unknown"); + } +} + +static PORT_ATTR_RO(state); +static PORT_ATTR_RO(lid); +static PORT_ATTR_RO(lid_mask_count); +static PORT_ATTR_RO(sm_lid); +static PORT_ATTR_RO(sm_sl); +static PORT_ATTR_RO(cap_mask); +static PORT_ATTR_RO(rate); +static PORT_ATTR_RO(phys_state); +static PORT_ATTR_RO(link_layer); + +static struct attribute *port_default_attrs[] = { + &port_attr_state.attr, + &port_attr_lid.attr, + &port_attr_lid_mask_count.attr, + &port_attr_sm_lid.attr, + &port_attr_sm_sl.attr, + &port_attr_cap_mask.attr, + &port_attr_rate.attr, + &port_attr_phys_state.attr, + &port_attr_link_layer.attr, + NULL +}; + +static ssize_t show_port_gid(struct ib_port *p, struct port_attribute *attr, + char *buf) +{ + struct port_table_attribute *tab_attr = + container_of(attr, struct port_table_attribute, attr); + union ib_gid gid; + ssize_t ret; + u16 *raw; + + ret = ib_query_gid(p->ibdev, p->port_num, tab_attr->index, &gid); + if (ret) + return ret; + + raw = (u16 *)gid.raw; + return sprintf(buf, "%.4x:%.4x:%.4x:%.4x:%.4x:%.4x:%.4x:%.4x\n", + htons(raw[0]), htons(raw[1]), htons(raw[2]), htons(raw[3]), + htons(raw[4]), htons(raw[5]), htons(raw[6]), htons(raw[7])); +} + +static ssize_t show_port_pkey(struct ib_port *p, struct port_attribute *attr, + char *buf) +{ + struct port_table_attribute *tab_attr = + container_of(attr, struct port_table_attribute, attr); + u16 pkey; + ssize_t ret; + + ret = ib_query_pkey(p->ibdev, p->port_num, tab_attr->index, &pkey); + if (ret) + return ret; + + return sprintf(buf, "0x%04x\n", pkey); +} + +#define PORT_PMA_ATTR(_name, _counter, _width, _offset) \ +struct port_table_attribute port_pma_attr_##_name = { \ + .attr = __ATTR(_name, S_IRUGO, show_pma_counter, NULL), \ + .index = (_offset) | ((_width) << 16) | ((_counter) << 24) \ +} + +static ssize_t show_pma_counter(struct ib_port *p, struct port_attribute *attr, + char *buf) +{ + struct port_table_attribute *tab_attr = + container_of(attr, struct port_table_attribute, attr); + int offset = tab_attr->index & 0xffff; + int width = (tab_attr->index >> 16) & 0xff; + struct ib_mad *in_mad = NULL; + struct ib_mad *out_mad = NULL; + ssize_t ret; + + if (!p->ibdev->process_mad) + return sprintf(buf, "N/A (no PMA)\n"); + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) { + ret = -ENOMEM; + goto out; + } + + in_mad->mad_hdr.base_version = 1; + in_mad->mad_hdr.mgmt_class = IB_MGMT_CLASS_PERF_MGMT; + in_mad->mad_hdr.class_version = 1; + in_mad->mad_hdr.method = IB_MGMT_METHOD_GET; + in_mad->mad_hdr.attr_id = cpu_to_be16(0x12); /* PortCounters */ + + in_mad->data[41] = p->port_num; /* PortSelect field */ + + if ((p->ibdev->process_mad(p->ibdev, IB_MAD_IGNORE_MKEY, + p->port_num, NULL, NULL, in_mad, out_mad) & + (IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY)) != + (IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY)) { + ret = -EINVAL; + goto out; + } + + switch (width) { + case 4: + ret = sprintf(buf, "%u\n", (out_mad->data[40 + offset / 8] >> + (4 - (offset % 8))) & 0xf); + break; + case 8: + ret = sprintf(buf, "%u\n", out_mad->data[40 + offset / 8]); + break; + case 16: + ret = sprintf(buf, "%u\n", + be16_to_cpup((__be16 *)(out_mad->data + 40 + offset / 8))); + break; + case 32: + ret = sprintf(buf, "%u\n", + be32_to_cpup((__be32 *)(out_mad->data + 40 + offset / 8))); + break; + default: + ret = 0; + } + +out: + kfree(in_mad); + kfree(out_mad); + + return ret; +} + +static PORT_PMA_ATTR(symbol_error , 0, 16, 32); +static PORT_PMA_ATTR(link_error_recovery , 1, 8, 48); +static PORT_PMA_ATTR(link_downed , 2, 8, 56); +static PORT_PMA_ATTR(port_rcv_errors , 3, 16, 64); +static PORT_PMA_ATTR(port_rcv_remote_physical_errors, 4, 16, 80); +static PORT_PMA_ATTR(port_rcv_switch_relay_errors , 5, 16, 96); +static PORT_PMA_ATTR(port_xmit_discards , 6, 16, 112); +static PORT_PMA_ATTR(port_xmit_constraint_errors , 7, 8, 128); +static PORT_PMA_ATTR(port_rcv_constraint_errors , 8, 8, 136); +static PORT_PMA_ATTR(local_link_integrity_errors , 9, 4, 152); +static PORT_PMA_ATTR(excessive_buffer_overrun_errors, 10, 4, 156); +static PORT_PMA_ATTR(VL15_dropped , 11, 16, 176); +static PORT_PMA_ATTR(port_xmit_data , 12, 32, 192); +static PORT_PMA_ATTR(port_rcv_data , 13, 32, 224); +static PORT_PMA_ATTR(port_xmit_packets , 14, 32, 256); +static PORT_PMA_ATTR(port_rcv_packets , 15, 32, 288); +/* + * There is no bit allocated for port_xmit_wait in the CounterSelect field + * (IB spec). However, since this bit is ignored when reading + * (show_pma_counter), the _counter field of port_xmit_wait can be set to zero. + */ +static PORT_PMA_ATTR(port_xmit_wait , 0, 32, 320); + +static struct attribute *pma_attrs[] = { + &port_pma_attr_symbol_error.attr.attr, + &port_pma_attr_link_error_recovery.attr.attr, + &port_pma_attr_link_downed.attr.attr, + &port_pma_attr_port_rcv_errors.attr.attr, + &port_pma_attr_port_rcv_remote_physical_errors.attr.attr, + &port_pma_attr_port_rcv_switch_relay_errors.attr.attr, + &port_pma_attr_port_xmit_discards.attr.attr, + &port_pma_attr_port_xmit_constraint_errors.attr.attr, + &port_pma_attr_port_rcv_constraint_errors.attr.attr, + &port_pma_attr_local_link_integrity_errors.attr.attr, + &port_pma_attr_excessive_buffer_overrun_errors.attr.attr, + &port_pma_attr_VL15_dropped.attr.attr, + &port_pma_attr_port_xmit_data.attr.attr, + &port_pma_attr_port_rcv_data.attr.attr, + &port_pma_attr_port_xmit_packets.attr.attr, + &port_pma_attr_port_rcv_packets.attr.attr, + &port_pma_attr_port_xmit_wait.attr.attr, + NULL +}; + +static struct attribute_group pma_group = { + .name = "counters", + .attrs = pma_attrs +}; + +static void ib_port_release(struct kobject *kobj) +{ + struct ib_port *p = container_of(kobj, struct ib_port, kobj); + struct attribute *a; + int i; + + for (i = 0; (a = p->gid_group.attrs[i]); ++i) + kfree(a); + + kfree(p->gid_group.attrs); + + for (i = 0; (a = p->pkey_group.attrs[i]); ++i) + kfree(a); + + kfree(p->pkey_group.attrs); + + kfree(p); +} + +static struct kobj_type port_type = { + .release = ib_port_release, + .sysfs_ops = &port_sysfs_ops, + .default_attrs = port_default_attrs +}; + +static void ib_device_release(struct device *device) +{ + struct ib_device *dev = container_of(device, struct ib_device, dev); + + kfree(dev); +} + +#ifdef __linux__ +/* BSD supports this through devfs(5) and devd(8). */ +static int ib_device_uevent(struct device *device, + struct kobj_uevent_env *env) +{ + struct ib_device *dev = container_of(device, struct ib_device, dev); + + if (add_uevent_var(env, "NAME=%s", dev->name)) + return -ENOMEM; + + /* + * It would be nice to pass the node GUID with the event... + */ + + return 0; +} +#endif + +static struct attribute ** +alloc_group_attrs(ssize_t (*show)(struct ib_port *, + struct port_attribute *, char *buf), + int len) +{ + struct attribute **tab_attr; + struct port_table_attribute *element; + int i; + + tab_attr = kcalloc(1 + len, sizeof(struct attribute *), GFP_KERNEL); + if (!tab_attr) + return NULL; + + for (i = 0; i < len; i++) { + element = kzalloc(sizeof(struct port_table_attribute), + GFP_KERNEL); + if (!element) + goto err; + + if (snprintf(element->name, sizeof(element->name), + "%d", i) >= sizeof(element->name)) { + kfree(element); + goto err; + } + + element->attr.attr.name = element->name; + element->attr.attr.mode = S_IRUGO; + element->attr.show = show; + element->index = i; + + tab_attr[i] = &element->attr.attr; + } + + return tab_attr; + +err: + while (--i >= 0) + kfree(tab_attr[i]); + kfree(tab_attr); + return NULL; +} + +static int add_port(struct ib_device *device, int port_num) +{ + struct ib_port *p; + struct ib_port_attr attr; + int i; + int ret; + + ret = ib_query_port(device, port_num, &attr); + if (ret) + return ret; + + p = kzalloc(sizeof *p, GFP_KERNEL); + if (!p) + return -ENOMEM; + + p->ibdev = device; + p->port_num = port_num; + + ret = kobject_init_and_add(&p->kobj, &port_type, + device->ports_parent, + "%d", port_num); + if (ret) + goto err_put; + + ret = sysfs_create_group(&p->kobj, &pma_group); + if (ret) + goto err_put; + + p->gid_group.name = "gids"; + p->gid_group.attrs = alloc_group_attrs(show_port_gid, attr.gid_tbl_len); + if (!p->gid_group.attrs) + goto err_remove_pma; + + ret = sysfs_create_group(&p->kobj, &p->gid_group); + if (ret) + goto err_free_gid; + + p->pkey_group.name = "pkeys"; + p->pkey_group.attrs = alloc_group_attrs(show_port_pkey, + attr.pkey_tbl_len); + if (!p->pkey_group.attrs) + goto err_remove_gid; + + ret = sysfs_create_group(&p->kobj, &p->pkey_group); + if (ret) + goto err_free_pkey; + + list_add_tail(&p->kobj.entry, &device->port_list); + +#ifdef __linux__ + kobject_uevent(&p->kobj, KOBJ_ADD); +#endif + return 0; + +err_free_pkey: + for (i = 0; i < attr.pkey_tbl_len; ++i) + kfree(p->pkey_group.attrs[i]); + + kfree(p->pkey_group.attrs); + +err_remove_gid: + sysfs_remove_group(&p->kobj, &p->gid_group); + +err_free_gid: + for (i = 0; i < attr.gid_tbl_len; ++i) + kfree(p->gid_group.attrs[i]); + + kfree(p->gid_group.attrs); + +err_remove_pma: + sysfs_remove_group(&p->kobj, &pma_group); + +err_put: + kobject_put(device->ports_parent); + kfree(p); + return ret; +} + +static ssize_t show_node_type(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ib_device *dev = container_of(device, struct ib_device, dev); + + switch (dev->node_type) { + case RDMA_NODE_IB_CA: return sprintf(buf, "%d: CA\n", dev->node_type); + case RDMA_NODE_RNIC: return sprintf(buf, "%d: RNIC\n", dev->node_type); + case RDMA_NODE_IB_SWITCH: return sprintf(buf, "%d: switch\n", dev->node_type); + case RDMA_NODE_IB_ROUTER: return sprintf(buf, "%d: router\n", dev->node_type); + default: return sprintf(buf, "%d: \n", dev->node_type); + } +} + +static ssize_t show_sys_image_guid(struct device *device, + struct device_attribute *dev_attr, char *buf) +{ + struct ib_device *dev = container_of(device, struct ib_device, dev); + struct ib_device_attr attr; + ssize_t ret; + + ret = ib_query_device(dev, &attr); + if (ret) + return ret; + + return sprintf(buf, "%04x:%04x:%04x:%04x\n", + be16_to_cpu(((__be16 *) &attr.sys_image_guid)[0]), + be16_to_cpu(((__be16 *) &attr.sys_image_guid)[1]), + be16_to_cpu(((__be16 *) &attr.sys_image_guid)[2]), + be16_to_cpu(((__be16 *) &attr.sys_image_guid)[3])); +} + +static ssize_t show_node_guid(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ib_device *dev = container_of(device, struct ib_device, dev); + + return sprintf(buf, "%04x:%04x:%04x:%04x\n", + be16_to_cpu(((__be16 *) &dev->node_guid)[0]), + be16_to_cpu(((__be16 *) &dev->node_guid)[1]), + be16_to_cpu(((__be16 *) &dev->node_guid)[2]), + be16_to_cpu(((__be16 *) &dev->node_guid)[3])); +} + +static ssize_t show_node_desc(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ib_device *dev = container_of(device, struct ib_device, dev); + + return sprintf(buf, "%.64s\n", dev->node_desc); +} + +static ssize_t set_node_desc(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ib_device *dev = container_of(device, struct ib_device, dev); + struct ib_device_modify desc = {}; + int ret; + + if (!dev->modify_device) + return -EIO; + + memcpy(desc.node_desc, buf, min_t(int, count, 64)); + ret = ib_modify_device(dev, IB_DEVICE_MODIFY_NODE_DESC, &desc); + if (ret) + return ret; + + return count; +} + +static DEVICE_ATTR(node_type, S_IRUGO, show_node_type, NULL); +static DEVICE_ATTR(sys_image_guid, S_IRUGO, show_sys_image_guid, NULL); +static DEVICE_ATTR(node_guid, S_IRUGO, show_node_guid, NULL); +static DEVICE_ATTR(node_desc, S_IRUGO | S_IWUSR, show_node_desc, set_node_desc); + +static struct device_attribute *ib_class_attributes[] = { + &dev_attr_node_type, + &dev_attr_sys_image_guid, + &dev_attr_node_guid, + &dev_attr_node_desc +}; + +static struct class ib_class = { + .name = "infiniband", + .dev_release = ib_device_release, +#ifdef __linux__ + .dev_uevent = ib_device_uevent, +#endif +}; + +/* Show a given an attribute in the statistics group */ +static ssize_t show_protocol_stat(const struct device *device, + struct device_attribute *attr, char *buf, + unsigned offset) +{ + struct ib_device *dev = container_of(__DECONST(struct device *, device), struct ib_device, dev); + union rdma_protocol_stats stats; + ssize_t ret; + + ret = dev->get_protocol_stats(dev, &stats); + if (ret) + return ret; + + return sprintf(buf, "%llu\n", + (unsigned long long) ((u64 *) &stats)[offset]); +} + +/* generate a read-only iwarp statistics attribute */ +#define IW_STATS_ENTRY(name) \ +static ssize_t show_##name(struct device *device, \ + struct device_attribute *attr, char *buf) \ +{ \ + return show_protocol_stat(device, attr, buf, \ + offsetof(struct iw_protocol_stats, name) / \ + sizeof (u64)); \ +} \ +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) + +IW_STATS_ENTRY(ipInReceives); +IW_STATS_ENTRY(ipInHdrErrors); +IW_STATS_ENTRY(ipInTooBigErrors); +IW_STATS_ENTRY(ipInNoRoutes); +IW_STATS_ENTRY(ipInAddrErrors); +IW_STATS_ENTRY(ipInUnknownProtos); +IW_STATS_ENTRY(ipInTruncatedPkts); +IW_STATS_ENTRY(ipInDiscards); +IW_STATS_ENTRY(ipInDelivers); +IW_STATS_ENTRY(ipOutForwDatagrams); +IW_STATS_ENTRY(ipOutRequests); +IW_STATS_ENTRY(ipOutDiscards); +IW_STATS_ENTRY(ipOutNoRoutes); +IW_STATS_ENTRY(ipReasmTimeout); +IW_STATS_ENTRY(ipReasmReqds); +IW_STATS_ENTRY(ipReasmOKs); +IW_STATS_ENTRY(ipReasmFails); +IW_STATS_ENTRY(ipFragOKs); +IW_STATS_ENTRY(ipFragFails); +IW_STATS_ENTRY(ipFragCreates); +IW_STATS_ENTRY(ipInMcastPkts); +IW_STATS_ENTRY(ipOutMcastPkts); +IW_STATS_ENTRY(ipInBcastPkts); +IW_STATS_ENTRY(ipOutBcastPkts); +IW_STATS_ENTRY(tcpRtoAlgorithm); +IW_STATS_ENTRY(tcpRtoMin); +IW_STATS_ENTRY(tcpRtoMax); +IW_STATS_ENTRY(tcpMaxConn); +IW_STATS_ENTRY(tcpActiveOpens); +IW_STATS_ENTRY(tcpPassiveOpens); +IW_STATS_ENTRY(tcpAttemptFails); +IW_STATS_ENTRY(tcpEstabResets); +IW_STATS_ENTRY(tcpCurrEstab); +IW_STATS_ENTRY(tcpInSegs); +IW_STATS_ENTRY(tcpOutSegs); +IW_STATS_ENTRY(tcpRetransSegs); +IW_STATS_ENTRY(tcpInErrs); +IW_STATS_ENTRY(tcpOutRsts); + +static struct attribute *iw_proto_stats_attrs[] = { + &dev_attr_ipInReceives.attr, + &dev_attr_ipInHdrErrors.attr, + &dev_attr_ipInTooBigErrors.attr, + &dev_attr_ipInNoRoutes.attr, + &dev_attr_ipInAddrErrors.attr, + &dev_attr_ipInUnknownProtos.attr, + &dev_attr_ipInTruncatedPkts.attr, + &dev_attr_ipInDiscards.attr, + &dev_attr_ipInDelivers.attr, + &dev_attr_ipOutForwDatagrams.attr, + &dev_attr_ipOutRequests.attr, + &dev_attr_ipOutDiscards.attr, + &dev_attr_ipOutNoRoutes.attr, + &dev_attr_ipReasmTimeout.attr, + &dev_attr_ipReasmReqds.attr, + &dev_attr_ipReasmOKs.attr, + &dev_attr_ipReasmFails.attr, + &dev_attr_ipFragOKs.attr, + &dev_attr_ipFragFails.attr, + &dev_attr_ipFragCreates.attr, + &dev_attr_ipInMcastPkts.attr, + &dev_attr_ipOutMcastPkts.attr, + &dev_attr_ipInBcastPkts.attr, + &dev_attr_ipOutBcastPkts.attr, + &dev_attr_tcpRtoAlgorithm.attr, + &dev_attr_tcpRtoMin.attr, + &dev_attr_tcpRtoMax.attr, + &dev_attr_tcpMaxConn.attr, + &dev_attr_tcpActiveOpens.attr, + &dev_attr_tcpPassiveOpens.attr, + &dev_attr_tcpAttemptFails.attr, + &dev_attr_tcpEstabResets.attr, + &dev_attr_tcpCurrEstab.attr, + &dev_attr_tcpInSegs.attr, + &dev_attr_tcpOutSegs.attr, + &dev_attr_tcpRetransSegs.attr, + &dev_attr_tcpInErrs.attr, + &dev_attr_tcpOutRsts.attr, + NULL +}; + +static struct attribute_group iw_stats_group = { + .name = "proto_stats", + .attrs = iw_proto_stats_attrs, +}; + +int ib_device_register_sysfs(struct ib_device *device) +{ + struct device *class_dev = &device->dev; + int ret; + int i; + + class_dev->class = &ib_class; + class_dev->driver_data = device; + class_dev->parent = device->dma_device; + dev_set_name(class_dev, device->name); + + INIT_LIST_HEAD(&device->port_list); + + ret = device_register(class_dev); + if (ret) + goto err; + + for (i = 0; i < ARRAY_SIZE(ib_class_attributes); ++i) { + ret = device_create_file(class_dev, ib_class_attributes[i]); + if (ret) + goto err_unregister; + } + + device->ports_parent = kobject_create_and_add("ports", + &class_dev->kobj); + if (!device->ports_parent) { + ret = -ENOMEM; + goto err_put; + } + + if (device->node_type == RDMA_NODE_IB_SWITCH) { + ret = add_port(device, 0); + if (ret) + goto err_put; + } else { + for (i = 1; i <= device->phys_port_cnt; ++i) { + ret = add_port(device, i); + if (ret) + goto err_put; + } + } + + if (device->node_type == RDMA_NODE_RNIC && device->get_protocol_stats) { + ret = sysfs_create_group(&class_dev->kobj, &iw_stats_group); + if (ret) + goto err_put; + } + + return 0; + +err_put: + { + struct kobject *p, *t; + struct ib_port *port; + + list_for_each_entry_safe(p, t, &device->port_list, entry) { + list_del(&p->entry); + port = container_of(p, struct ib_port, kobj); + sysfs_remove_group(p, &pma_group); + sysfs_remove_group(p, &port->pkey_group); + sysfs_remove_group(p, &port->gid_group); + kobject_put(p); + } + } + + kobject_put(&class_dev->kobj); + +err_unregister: + device_unregister(class_dev); + +err: + return ret; +} + +void ib_device_unregister_sysfs(struct ib_device *device) +{ + struct kobject *p, *t; + struct ib_port *port; + + /* Hold kobject until ib_dealloc_device() */ + kobject_get(&device->dev.kobj); + + list_for_each_entry_safe(p, t, &device->port_list, entry) { + list_del(&p->entry); + port = container_of(p, struct ib_port, kobj); + sysfs_remove_group(p, &pma_group); + sysfs_remove_group(p, &port->pkey_group); + sysfs_remove_group(p, &port->gid_group); + kobject_put(p); + } + + kobject_put(device->ports_parent); + device_unregister(&device->dev); +} + +int ib_sysfs_setup(void) +{ + return class_register(&ib_class); +} + +void ib_sysfs_cleanup(void) +{ + class_unregister(&ib_class); +} + +int ib_sysfs_create_port_files(struct ib_device *device, + int (*create)(struct ib_device *dev, u8 port_num, + struct kobject *kobj)) +{ + struct kobject *p; + struct ib_port *port; + int ret = 0; + + list_for_each_entry(p, &device->port_list, entry) { + port = container_of(p, struct ib_port, kobj); + ret = create(device, port->port_num, &port->kobj); + if (ret) + break; + } + + return ret; +} +EXPORT_SYMBOL(ib_sysfs_create_port_files); diff --git a/sys/ofed/drivers/infiniband/core/ucm.c b/sys/ofed/drivers/infiniband/core/ucm.c new file mode 100644 index 000000000000..90e0b31368e9 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/ucm.c @@ -0,0 +1,1348 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +MODULE_AUTHOR("Libor Michalek"); +MODULE_DESCRIPTION("InfiniBand userspace Connection Manager access"); +MODULE_LICENSE("Dual BSD/GPL"); + +struct ib_ucm_device { + int devnum; + struct cdev cdev; + struct device dev; + struct ib_device *ib_dev; +}; + +struct ib_ucm_file { + struct mutex file_mutex; + struct file *filp; + struct ib_ucm_device *device; + + struct list_head ctxs; + struct list_head events; + wait_queue_head_t poll_wait; +}; + +struct ib_ucm_context { + int id; + struct completion comp; + atomic_t ref; + int events_reported; + + struct ib_ucm_file *file; + struct ib_cm_id *cm_id; + __u64 uid; + + struct list_head events; /* list of pending events. */ + struct list_head file_list; /* member in file ctx list */ +}; + +struct ib_ucm_event { + struct ib_ucm_context *ctx; + struct list_head file_list; /* member in file event list */ + struct list_head ctx_list; /* member in ctx event list */ + + struct ib_cm_id *cm_id; + struct ib_ucm_event_resp resp; + void *data; + void *info; + int data_len; + int info_len; +}; + +enum { + IB_UCM_MAJOR = 231, + IB_UCM_BASE_MINOR = 224, + IB_UCM_MAX_DEVICES = 32 +}; + +/* ib_cm and ib_user_cm modules share /sys/class/infiniband_cm */ +extern struct class cm_class; + +#define IB_UCM_BASE_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_BASE_MINOR) + +static void ib_ucm_add_one(struct ib_device *device); +static void ib_ucm_remove_one(struct ib_device *device); + +static struct ib_client ucm_client = { + .name = "ucm", + .add = ib_ucm_add_one, + .remove = ib_ucm_remove_one +}; + +static DEFINE_MUTEX(ctx_id_mutex); +static DEFINE_IDR(ctx_id_table); +static DECLARE_BITMAP(dev_map, IB_UCM_MAX_DEVICES); + +static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id) +{ + struct ib_ucm_context *ctx; + + mutex_lock(&ctx_id_mutex); + ctx = idr_find(&ctx_id_table, id); + if (!ctx) + ctx = ERR_PTR(-ENOENT); + else if (ctx->file != file) + ctx = ERR_PTR(-EINVAL); + else + atomic_inc(&ctx->ref); + mutex_unlock(&ctx_id_mutex); + + return ctx; +} + +static void ib_ucm_ctx_put(struct ib_ucm_context *ctx) +{ + if (atomic_dec_and_test(&ctx->ref)) + complete(&ctx->comp); +} + +static inline int ib_ucm_new_cm_id(int event) +{ + return event == IB_CM_REQ_RECEIVED || event == IB_CM_SIDR_REQ_RECEIVED; +} + +static void ib_ucm_cleanup_events(struct ib_ucm_context *ctx) +{ + struct ib_ucm_event *uevent; + + mutex_lock(&ctx->file->file_mutex); + list_del(&ctx->file_list); + while (!list_empty(&ctx->events)) { + + uevent = list_entry(ctx->events.next, + struct ib_ucm_event, ctx_list); + list_del(&uevent->file_list); + list_del(&uevent->ctx_list); + mutex_unlock(&ctx->file->file_mutex); + + /* clear incoming connections. */ + if (ib_ucm_new_cm_id(uevent->resp.event)) + ib_destroy_cm_id(uevent->cm_id); + + kfree(uevent); + mutex_lock(&ctx->file->file_mutex); + } + mutex_unlock(&ctx->file->file_mutex); +} + +static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file) +{ + struct ib_ucm_context *ctx; + int result; + + ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + if (!ctx) + return NULL; + + atomic_set(&ctx->ref, 1); + init_completion(&ctx->comp); + ctx->file = file; + INIT_LIST_HEAD(&ctx->events); + + do { + result = idr_pre_get(&ctx_id_table, GFP_KERNEL); + if (!result) + goto error; + + mutex_lock(&ctx_id_mutex); + result = idr_get_new(&ctx_id_table, ctx, &ctx->id); + mutex_unlock(&ctx_id_mutex); + } while (result == -EAGAIN); + + if (result) + goto error; + + list_add_tail(&ctx->file_list, &file->ctxs); + return ctx; + +error: + kfree(ctx); + return NULL; +} + +static void ib_ucm_event_req_get(struct ib_ucm_req_event_resp *ureq, + struct ib_cm_req_event_param *kreq) +{ + ureq->remote_ca_guid = kreq->remote_ca_guid; + ureq->remote_qkey = kreq->remote_qkey; + ureq->remote_qpn = kreq->remote_qpn; + ureq->qp_type = kreq->qp_type; + ureq->starting_psn = kreq->starting_psn; + ureq->responder_resources = kreq->responder_resources; + ureq->initiator_depth = kreq->initiator_depth; + ureq->local_cm_response_timeout = kreq->local_cm_response_timeout; + ureq->flow_control = kreq->flow_control; + ureq->remote_cm_response_timeout = kreq->remote_cm_response_timeout; + ureq->retry_count = kreq->retry_count; + ureq->rnr_retry_count = kreq->rnr_retry_count; + ureq->srq = kreq->srq; + ureq->port = kreq->port; + + ib_copy_path_rec_to_user(&ureq->primary_path, kreq->primary_path); + if (kreq->alternate_path) + ib_copy_path_rec_to_user(&ureq->alternate_path, + kreq->alternate_path); +} + +static void ib_ucm_event_rep_get(struct ib_ucm_rep_event_resp *urep, + struct ib_cm_rep_event_param *krep) +{ + urep->remote_ca_guid = krep->remote_ca_guid; + urep->remote_qkey = krep->remote_qkey; + urep->remote_qpn = krep->remote_qpn; + urep->starting_psn = krep->starting_psn; + urep->responder_resources = krep->responder_resources; + urep->initiator_depth = krep->initiator_depth; + urep->target_ack_delay = krep->target_ack_delay; + urep->failover_accepted = krep->failover_accepted; + urep->flow_control = krep->flow_control; + urep->rnr_retry_count = krep->rnr_retry_count; + urep->srq = krep->srq; +} + +static void ib_ucm_event_sidr_rep_get(struct ib_ucm_sidr_rep_event_resp *urep, + struct ib_cm_sidr_rep_event_param *krep) +{ + urep->status = krep->status; + urep->qkey = krep->qkey; + urep->qpn = krep->qpn; +}; + +static int ib_ucm_event_process(struct ib_cm_event *evt, + struct ib_ucm_event *uvt) +{ + void *info = NULL; + + switch (evt->event) { + case IB_CM_REQ_RECEIVED: + ib_ucm_event_req_get(&uvt->resp.u.req_resp, + &evt->param.req_rcvd); + uvt->data_len = IB_CM_REQ_PRIVATE_DATA_SIZE; + uvt->resp.present = IB_UCM_PRES_PRIMARY; + uvt->resp.present |= (evt->param.req_rcvd.alternate_path ? + IB_UCM_PRES_ALTERNATE : 0); + break; + case IB_CM_REP_RECEIVED: + ib_ucm_event_rep_get(&uvt->resp.u.rep_resp, + &evt->param.rep_rcvd); + uvt->data_len = IB_CM_REP_PRIVATE_DATA_SIZE; + break; + case IB_CM_RTU_RECEIVED: + uvt->data_len = IB_CM_RTU_PRIVATE_DATA_SIZE; + uvt->resp.u.send_status = evt->param.send_status; + break; + case IB_CM_DREQ_RECEIVED: + uvt->data_len = IB_CM_DREQ_PRIVATE_DATA_SIZE; + uvt->resp.u.send_status = evt->param.send_status; + break; + case IB_CM_DREP_RECEIVED: + uvt->data_len = IB_CM_DREP_PRIVATE_DATA_SIZE; + uvt->resp.u.send_status = evt->param.send_status; + break; + case IB_CM_MRA_RECEIVED: + uvt->resp.u.mra_resp.timeout = + evt->param.mra_rcvd.service_timeout; + uvt->data_len = IB_CM_MRA_PRIVATE_DATA_SIZE; + break; + case IB_CM_REJ_RECEIVED: + uvt->resp.u.rej_resp.reason = evt->param.rej_rcvd.reason; + uvt->data_len = IB_CM_REJ_PRIVATE_DATA_SIZE; + uvt->info_len = evt->param.rej_rcvd.ari_length; + info = evt->param.rej_rcvd.ari; + break; + case IB_CM_LAP_RECEIVED: + ib_copy_path_rec_to_user(&uvt->resp.u.lap_resp.path, + evt->param.lap_rcvd.alternate_path); + uvt->data_len = IB_CM_LAP_PRIVATE_DATA_SIZE; + uvt->resp.present = IB_UCM_PRES_ALTERNATE; + break; + case IB_CM_APR_RECEIVED: + uvt->resp.u.apr_resp.status = evt->param.apr_rcvd.ap_status; + uvt->data_len = IB_CM_APR_PRIVATE_DATA_SIZE; + uvt->info_len = evt->param.apr_rcvd.info_len; + info = evt->param.apr_rcvd.apr_info; + break; + case IB_CM_SIDR_REQ_RECEIVED: + uvt->resp.u.sidr_req_resp.pkey = + evt->param.sidr_req_rcvd.pkey; + uvt->resp.u.sidr_req_resp.port = + evt->param.sidr_req_rcvd.port; + uvt->data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE; + break; + case IB_CM_SIDR_REP_RECEIVED: + ib_ucm_event_sidr_rep_get(&uvt->resp.u.sidr_rep_resp, + &evt->param.sidr_rep_rcvd); + uvt->data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE; + uvt->info_len = evt->param.sidr_rep_rcvd.info_len; + info = evt->param.sidr_rep_rcvd.info; + break; + default: + uvt->resp.u.send_status = evt->param.send_status; + break; + } + + if (uvt->data_len) { + uvt->data = kmemdup(evt->private_data, uvt->data_len, GFP_KERNEL); + if (!uvt->data) + goto err1; + + uvt->resp.present |= IB_UCM_PRES_DATA; + } + + if (uvt->info_len) { + uvt->info = kmemdup(info, uvt->info_len, GFP_KERNEL); + if (!uvt->info) + goto err2; + + uvt->resp.present |= IB_UCM_PRES_INFO; + } + return 0; + +err2: + kfree(uvt->data); +err1: + return -ENOMEM; +} + +static int ib_ucm_event_handler(struct ib_cm_id *cm_id, + struct ib_cm_event *event) +{ + struct ib_ucm_event *uevent; + struct ib_ucm_context *ctx; + int result = 0; + + ctx = cm_id->context; + + uevent = kzalloc(sizeof *uevent, GFP_KERNEL); + if (!uevent) + goto err1; + + uevent->ctx = ctx; + uevent->cm_id = cm_id; + uevent->resp.uid = ctx->uid; + uevent->resp.id = ctx->id; + uevent->resp.event = event->event; + + result = ib_ucm_event_process(event, uevent); + if (result) + goto err2; + + mutex_lock(&ctx->file->file_mutex); + list_add_tail(&uevent->file_list, &ctx->file->events); + list_add_tail(&uevent->ctx_list, &ctx->events); + wake_up_interruptible(&ctx->file->poll_wait); + if (ctx->file->filp) + selwakeup(&ctx->file->filp->f_selinfo); + mutex_unlock(&ctx->file->file_mutex); + return 0; + +err2: + kfree(uevent); +err1: + /* Destroy new cm_id's */ + return ib_ucm_new_cm_id(event->event); +} + +static ssize_t ib_ucm_event(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct ib_ucm_context *ctx; + struct ib_ucm_event_get cmd; + struct ib_ucm_event *uevent; + int result = 0; + DEFINE_WAIT(wait); + + if (out_len < sizeof(struct ib_ucm_event_resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + mutex_lock(&file->file_mutex); + while (list_empty(&file->events)) { + mutex_unlock(&file->file_mutex); + + if (file->filp->f_flags & O_NONBLOCK) + return -EAGAIN; + + if (wait_event_interruptible(file->poll_wait, + !list_empty(&file->events))) + return -ERESTARTSYS; + + mutex_lock(&file->file_mutex); + } + + uevent = list_entry(file->events.next, struct ib_ucm_event, file_list); + + if (ib_ucm_new_cm_id(uevent->resp.event)) { + ctx = ib_ucm_ctx_alloc(file); + if (!ctx) { + result = -ENOMEM; + goto done; + } + + ctx->cm_id = uevent->cm_id; + ctx->cm_id->context = ctx; + uevent->resp.id = ctx->id; + } + + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &uevent->resp, sizeof(uevent->resp))) { + result = -EFAULT; + goto done; + } + + if (uevent->data) { + if (cmd.data_len < uevent->data_len) { + result = -ENOMEM; + goto done; + } + if (copy_to_user((void __user *)(unsigned long)cmd.data, + uevent->data, uevent->data_len)) { + result = -EFAULT; + goto done; + } + } + + if (uevent->info) { + if (cmd.info_len < uevent->info_len) { + result = -ENOMEM; + goto done; + } + if (copy_to_user((void __user *)(unsigned long)cmd.info, + uevent->info, uevent->info_len)) { + result = -EFAULT; + goto done; + } + } + + list_del(&uevent->file_list); + list_del(&uevent->ctx_list); + uevent->ctx->events_reported++; + + kfree(uevent->data); + kfree(uevent->info); + kfree(uevent); +done: + mutex_unlock(&file->file_mutex); + return result; +} + +static ssize_t ib_ucm_create_id(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct ib_ucm_create_id cmd; + struct ib_ucm_create_id_resp resp; + struct ib_ucm_context *ctx; + int result; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + mutex_lock(&file->file_mutex); + ctx = ib_ucm_ctx_alloc(file); + mutex_unlock(&file->file_mutex); + if (!ctx) + return -ENOMEM; + + ctx->uid = cmd.uid; + ctx->cm_id = ib_create_cm_id(file->device->ib_dev, + ib_ucm_event_handler, ctx); + if (IS_ERR(ctx->cm_id)) { + result = PTR_ERR(ctx->cm_id); + goto err1; + } + + resp.id = ctx->id; + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) { + result = -EFAULT; + goto err2; + } + return 0; + +err2: + ib_destroy_cm_id(ctx->cm_id); +err1: + mutex_lock(&ctx_id_mutex); + idr_remove(&ctx_id_table, ctx->id); + mutex_unlock(&ctx_id_mutex); + kfree(ctx); + return result; +} + +static ssize_t ib_ucm_destroy_id(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct ib_ucm_destroy_id cmd; + struct ib_ucm_destroy_id_resp resp; + struct ib_ucm_context *ctx; + int result = 0; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + mutex_lock(&ctx_id_mutex); + ctx = idr_find(&ctx_id_table, cmd.id); + if (!ctx) + ctx = ERR_PTR(-ENOENT); + else if (ctx->file != file) + ctx = ERR_PTR(-EINVAL); + else + idr_remove(&ctx_id_table, ctx->id); + mutex_unlock(&ctx_id_mutex); + + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ib_ucm_ctx_put(ctx); + wait_for_completion(&ctx->comp); + + /* No new events will be generated after destroying the cm_id. */ + ib_destroy_cm_id(ctx->cm_id); + /* Cleanup events not yet reported to the user. */ + ib_ucm_cleanup_events(ctx); + + resp.events_reported = ctx->events_reported; + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) + result = -EFAULT; + + kfree(ctx); + return result; +} + +static ssize_t ib_ucm_attr_id(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct ib_ucm_attr_id_resp resp; + struct ib_ucm_attr_id cmd; + struct ib_ucm_context *ctx; + int result = 0; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ib_ucm_ctx_get(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + resp.service_id = ctx->cm_id->service_id; + resp.service_mask = ctx->cm_id->service_mask; + resp.local_id = ctx->cm_id->local_id; + resp.remote_id = ctx->cm_id->remote_id; + + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) + result = -EFAULT; + + ib_ucm_ctx_put(ctx); + return result; +} + +static ssize_t ib_ucm_init_qp_attr(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct ib_uverbs_qp_attr resp; + struct ib_ucm_init_qp_attr cmd; + struct ib_ucm_context *ctx; + struct ib_qp_attr qp_attr; + int result = 0; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ib_ucm_ctx_get(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + resp.qp_attr_mask = 0; + memset(&qp_attr, 0, sizeof qp_attr); + qp_attr.qp_state = cmd.qp_state; + result = ib_cm_init_qp_attr(ctx->cm_id, &qp_attr, &resp.qp_attr_mask); + if (result) + goto out; + + ib_copy_qp_attr_to_user(&resp, &qp_attr); + + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) + result = -EFAULT; + +out: + ib_ucm_ctx_put(ctx); + return result; +} + +static int ucm_validate_listen(__be64 service_id, __be64 service_mask) +{ + service_id &= service_mask; + + if (((service_id & IB_CMA_SERVICE_ID_MASK) == IB_CMA_SERVICE_ID) || + ((service_id & IB_SDP_SERVICE_ID_MASK) == IB_SDP_SERVICE_ID)) + return -EINVAL; + + return 0; +} + +static ssize_t ib_ucm_listen(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct ib_ucm_listen cmd; + struct ib_ucm_context *ctx; + int result; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ib_ucm_ctx_get(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + result = ucm_validate_listen(cmd.service_id, cmd.service_mask); + if (result) + goto out; + + result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask, + NULL); +out: + ib_ucm_ctx_put(ctx); + return result; +} + +static ssize_t ib_ucm_notify(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct ib_ucm_notify cmd; + struct ib_ucm_context *ctx; + int result; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ib_ucm_ctx_get(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + result = ib_cm_notify(ctx->cm_id, (enum ib_event_type) cmd.event); + ib_ucm_ctx_put(ctx); + return result; +} + +static int ib_ucm_alloc_data(const void **dest, u64 src, u32 len) +{ + void *data; + + *dest = NULL; + + if (!len) + return 0; + + data = kmalloc(len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + if (copy_from_user(data, (void __user *)(unsigned long)src, len)) { + kfree(data); + return -EFAULT; + } + + *dest = data; + return 0; +} + +static int ib_ucm_path_get(struct ib_sa_path_rec **path, u64 src) +{ + struct ib_user_path_rec upath; + struct ib_sa_path_rec *sa_path; + + *path = NULL; + + if (!src) + return 0; + + sa_path = kmalloc(sizeof(*sa_path), GFP_KERNEL); + if (!sa_path) + return -ENOMEM; + + if (copy_from_user(&upath, (void __user *)(unsigned long)src, + sizeof(upath))) { + + kfree(sa_path); + return -EFAULT; + } + + ib_copy_path_rec_from_user(sa_path, &upath); + *path = sa_path; + return 0; +} + +static ssize_t ib_ucm_send_req(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct ib_cm_req_param param; + struct ib_ucm_context *ctx; + struct ib_ucm_req cmd; + int result; + + param.private_data = NULL; + param.primary_path = NULL; + param.alternate_path = NULL; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + result = ib_ucm_alloc_data(¶m.private_data, cmd.data, cmd.len); + if (result) + goto done; + + result = ib_ucm_path_get(¶m.primary_path, cmd.primary_path); + if (result) + goto done; + + result = ib_ucm_path_get(¶m.alternate_path, cmd.alternate_path); + if (result) + goto done; + + param.private_data_len = cmd.len; + param.service_id = cmd.sid; + param.qp_num = cmd.qpn; + param.qp_type = cmd.qp_type; + param.starting_psn = cmd.psn; + param.peer_to_peer = cmd.peer_to_peer; + param.responder_resources = cmd.responder_resources; + param.initiator_depth = cmd.initiator_depth; + param.remote_cm_response_timeout = cmd.remote_cm_response_timeout; + param.flow_control = cmd.flow_control; + param.local_cm_response_timeout = cmd.local_cm_response_timeout; + param.retry_count = cmd.retry_count; + param.rnr_retry_count = cmd.rnr_retry_count; + param.max_cm_retries = cmd.max_cm_retries; + param.srq = cmd.srq; + + ctx = ib_ucm_ctx_get(file, cmd.id); + if (!IS_ERR(ctx)) { + result = ib_send_cm_req(ctx->cm_id, ¶m); + ib_ucm_ctx_put(ctx); + } else + result = PTR_ERR(ctx); + +done: + kfree(param.private_data); + kfree(param.primary_path); + kfree(param.alternate_path); + return result; +} + +static ssize_t ib_ucm_send_rep(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct ib_cm_rep_param param; + struct ib_ucm_context *ctx; + struct ib_ucm_rep cmd; + int result; + + param.private_data = NULL; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + result = ib_ucm_alloc_data(¶m.private_data, cmd.data, cmd.len); + if (result) + return result; + + param.qp_num = cmd.qpn; + param.starting_psn = cmd.psn; + param.private_data_len = cmd.len; + param.responder_resources = cmd.responder_resources; + param.initiator_depth = cmd.initiator_depth; + param.failover_accepted = cmd.failover_accepted; + param.flow_control = cmd.flow_control; + param.rnr_retry_count = cmd.rnr_retry_count; + param.srq = cmd.srq; + + ctx = ib_ucm_ctx_get(file, cmd.id); + if (!IS_ERR(ctx)) { + ctx->uid = cmd.uid; + result = ib_send_cm_rep(ctx->cm_id, ¶m); + ib_ucm_ctx_put(ctx); + } else + result = PTR_ERR(ctx); + + kfree(param.private_data); + return result; +} + +static ssize_t ib_ucm_send_private_data(struct ib_ucm_file *file, + const char __user *inbuf, int in_len, + int (*func)(struct ib_cm_id *cm_id, + const void *private_data, + u8 private_data_len)) +{ + struct ib_ucm_private_data cmd; + struct ib_ucm_context *ctx; + const void *private_data = NULL; + int result; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + result = ib_ucm_alloc_data(&private_data, cmd.data, cmd.len); + if (result) + return result; + + ctx = ib_ucm_ctx_get(file, cmd.id); + if (!IS_ERR(ctx)) { + result = func(ctx->cm_id, private_data, cmd.len); + ib_ucm_ctx_put(ctx); + } else + result = PTR_ERR(ctx); + + kfree(private_data); + return result; +} + +static ssize_t ib_ucm_send_rtu(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + return ib_ucm_send_private_data(file, inbuf, in_len, ib_send_cm_rtu); +} + +static ssize_t ib_ucm_send_dreq(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + return ib_ucm_send_private_data(file, inbuf, in_len, ib_send_cm_dreq); +} + +static ssize_t ib_ucm_send_drep(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + return ib_ucm_send_private_data(file, inbuf, in_len, ib_send_cm_drep); +} + +static ssize_t ib_ucm_send_info(struct ib_ucm_file *file, + const char __user *inbuf, int in_len, + int (*func)(struct ib_cm_id *cm_id, + int status, + const void *info, + u8 info_len, + const void *data, + u8 data_len)) +{ + struct ib_ucm_context *ctx; + struct ib_ucm_info cmd; + const void *data = NULL; + const void *info = NULL; + int result; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + result = ib_ucm_alloc_data(&data, cmd.data, cmd.data_len); + if (result) + goto done; + + result = ib_ucm_alloc_data(&info, cmd.info, cmd.info_len); + if (result) + goto done; + + ctx = ib_ucm_ctx_get(file, cmd.id); + if (!IS_ERR(ctx)) { + result = func(ctx->cm_id, cmd.status, info, cmd.info_len, + data, cmd.data_len); + ib_ucm_ctx_put(ctx); + } else + result = PTR_ERR(ctx); + +done: + kfree(data); + kfree(info); + return result; +} + +static ssize_t ib_ucm_send_rej(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + return ib_ucm_send_info(file, inbuf, in_len, (void *)ib_send_cm_rej); +} + +static ssize_t ib_ucm_send_apr(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + return ib_ucm_send_info(file, inbuf, in_len, (void *)ib_send_cm_apr); +} + +static ssize_t ib_ucm_send_mra(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct ib_ucm_context *ctx; + struct ib_ucm_mra cmd; + const void *data = NULL; + int result; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + result = ib_ucm_alloc_data(&data, cmd.data, cmd.len); + if (result) + return result; + + ctx = ib_ucm_ctx_get(file, cmd.id); + if (!IS_ERR(ctx)) { + result = ib_send_cm_mra(ctx->cm_id, cmd.timeout, data, cmd.len); + ib_ucm_ctx_put(ctx); + } else + result = PTR_ERR(ctx); + + kfree(data); + return result; +} + +static ssize_t ib_ucm_send_lap(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct ib_ucm_context *ctx; + struct ib_sa_path_rec *path = NULL; + struct ib_ucm_lap cmd; + const void *data = NULL; + int result; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + result = ib_ucm_alloc_data(&data, cmd.data, cmd.len); + if (result) + goto done; + + result = ib_ucm_path_get(&path, cmd.path); + if (result) + goto done; + + ctx = ib_ucm_ctx_get(file, cmd.id); + if (!IS_ERR(ctx)) { + result = ib_send_cm_lap(ctx->cm_id, path, data, cmd.len); + ib_ucm_ctx_put(ctx); + } else + result = PTR_ERR(ctx); + +done: + kfree(data); + kfree(path); + return result; +} + +static ssize_t ib_ucm_send_sidr_req(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct ib_cm_sidr_req_param param; + struct ib_ucm_context *ctx; + struct ib_ucm_sidr_req cmd; + int result; + + param.private_data = NULL; + param.path = NULL; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + result = ib_ucm_alloc_data(¶m.private_data, cmd.data, cmd.len); + if (result) + goto done; + + result = ib_ucm_path_get(¶m.path, cmd.path); + if (result) + goto done; + + param.private_data_len = cmd.len; + param.service_id = cmd.sid; + param.timeout_ms = cmd.timeout; + param.max_cm_retries = cmd.max_cm_retries; + + ctx = ib_ucm_ctx_get(file, cmd.id); + if (!IS_ERR(ctx)) { + result = ib_send_cm_sidr_req(ctx->cm_id, ¶m); + ib_ucm_ctx_put(ctx); + } else + result = PTR_ERR(ctx); + +done: + kfree(param.private_data); + kfree(param.path); + return result; +} + +static ssize_t ib_ucm_send_sidr_rep(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct ib_cm_sidr_rep_param param; + struct ib_ucm_sidr_rep cmd; + struct ib_ucm_context *ctx; + int result; + + param.info = NULL; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + result = ib_ucm_alloc_data(¶m.private_data, + cmd.data, cmd.data_len); + if (result) + goto done; + + result = ib_ucm_alloc_data(¶m.info, cmd.info, cmd.info_len); + if (result) + goto done; + + param.qp_num = cmd.qpn; + param.qkey = cmd.qkey; + param.status = cmd.status; + param.info_length = cmd.info_len; + param.private_data_len = cmd.data_len; + + ctx = ib_ucm_ctx_get(file, cmd.id); + if (!IS_ERR(ctx)) { + result = ib_send_cm_sidr_rep(ctx->cm_id, ¶m); + ib_ucm_ctx_put(ctx); + } else + result = PTR_ERR(ctx); + +done: + kfree(param.private_data); + kfree(param.info); + return result; +} + +static ssize_t (*ucm_cmd_table[])(struct ib_ucm_file *file, + const char __user *inbuf, + int in_len, int out_len) = { + [IB_USER_CM_CMD_CREATE_ID] = ib_ucm_create_id, + [IB_USER_CM_CMD_DESTROY_ID] = ib_ucm_destroy_id, + [IB_USER_CM_CMD_ATTR_ID] = ib_ucm_attr_id, + [IB_USER_CM_CMD_LISTEN] = ib_ucm_listen, + [IB_USER_CM_CMD_NOTIFY] = ib_ucm_notify, + [IB_USER_CM_CMD_SEND_REQ] = ib_ucm_send_req, + [IB_USER_CM_CMD_SEND_REP] = ib_ucm_send_rep, + [IB_USER_CM_CMD_SEND_RTU] = ib_ucm_send_rtu, + [IB_USER_CM_CMD_SEND_DREQ] = ib_ucm_send_dreq, + [IB_USER_CM_CMD_SEND_DREP] = ib_ucm_send_drep, + [IB_USER_CM_CMD_SEND_REJ] = ib_ucm_send_rej, + [IB_USER_CM_CMD_SEND_MRA] = ib_ucm_send_mra, + [IB_USER_CM_CMD_SEND_LAP] = ib_ucm_send_lap, + [IB_USER_CM_CMD_SEND_APR] = ib_ucm_send_apr, + [IB_USER_CM_CMD_SEND_SIDR_REQ] = ib_ucm_send_sidr_req, + [IB_USER_CM_CMD_SEND_SIDR_REP] = ib_ucm_send_sidr_rep, + [IB_USER_CM_CMD_EVENT] = ib_ucm_event, + [IB_USER_CM_CMD_INIT_QP_ATTR] = ib_ucm_init_qp_attr, +}; + +static ssize_t ib_ucm_write(struct file *filp, const char __user *buf, + size_t len, loff_t *pos) +{ + struct ib_ucm_file *file = filp->private_data; + struct ib_ucm_cmd_hdr hdr; + ssize_t result; + + if (len < sizeof(hdr)) + return -EINVAL; + + if (copy_from_user(&hdr, buf, sizeof(hdr))) + return -EFAULT; + + if (hdr.cmd < 0 || hdr.cmd >= ARRAY_SIZE(ucm_cmd_table)) + return -EINVAL; + + if (hdr.in + sizeof(hdr) > len) + return -EINVAL; + + result = ucm_cmd_table[hdr.cmd](file, buf + sizeof(hdr), + hdr.in, hdr.out); + if (!result) + result = len; + + return result; +} + +static unsigned int ib_ucm_poll(struct file *filp, + struct poll_table_struct *wait) +{ + struct ib_ucm_file *file = filp->private_data; + unsigned int mask = 0; + + poll_wait(filp, &file->poll_wait, wait); + + if (!list_empty(&file->events)) + mask = POLLIN | POLLRDNORM; + + return mask; +} + +/* + * ib_ucm_open() does not need the BKL: + * + * - no global state is referred to; + * - there is no ioctl method to race against; + * - no further module initialization is required for open to work + * after the device is registered. + */ +static int ib_ucm_open(struct inode *inode, struct file *filp) +{ + struct ib_ucm_file *file; + + file = kzalloc(sizeof(*file), GFP_KERNEL); + if (!file) + return -ENOMEM; + + INIT_LIST_HEAD(&file->events); + INIT_LIST_HEAD(&file->ctxs); + init_waitqueue_head(&file->poll_wait); + + mutex_init(&file->file_mutex); + + filp->private_data = file; + file->filp = filp; + file->device = container_of(inode->i_cdev->si_drv1, struct ib_ucm_device, cdev); + + return 0; +} + +static int ib_ucm_close(struct inode *inode, struct file *filp) +{ + struct ib_ucm_file *file = filp->private_data; + struct ib_ucm_context *ctx; + + mutex_lock(&file->file_mutex); + while (!list_empty(&file->ctxs)) { + ctx = list_entry(file->ctxs.next, + struct ib_ucm_context, file_list); + mutex_unlock(&file->file_mutex); + + mutex_lock(&ctx_id_mutex); + idr_remove(&ctx_id_table, ctx->id); + mutex_unlock(&ctx_id_mutex); + + ib_destroy_cm_id(ctx->cm_id); + ib_ucm_cleanup_events(ctx); + kfree(ctx); + + mutex_lock(&file->file_mutex); + } + mutex_unlock(&file->file_mutex); + kfree(file); + return 0; +} + +static void ib_ucm_release_dev(struct device *dev) +{ + struct ib_ucm_device *ucm_dev; + + ucm_dev = container_of(dev, struct ib_ucm_device, dev); + cdev_del(&ucm_dev->cdev); + clear_bit(ucm_dev->devnum, dev_map); + kfree(ucm_dev); +} + +static const struct file_operations ucm_fops = { + .owner = THIS_MODULE, + .open = ib_ucm_open, + .release = ib_ucm_close, + .write = ib_ucm_write, + .poll = ib_ucm_poll, +}; + +static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ib_ucm_device *ucm_dev; + + ucm_dev = container_of(dev, struct ib_ucm_device, dev); + return sprintf(buf, "%s\n", ucm_dev->ib_dev->name); +} +static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); + +static void ib_ucm_add_one(struct ib_device *device) +{ + struct ib_ucm_device *ucm_dev; + + if (!device->alloc_ucontext || + rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) + return; + + ucm_dev = kzalloc(sizeof *ucm_dev, GFP_KERNEL); + if (!ucm_dev) + return; + + ucm_dev->ib_dev = device; + + ucm_dev->devnum = find_first_zero_bit(dev_map, IB_UCM_MAX_DEVICES); + if (ucm_dev->devnum >= IB_UCM_MAX_DEVICES) + goto err; + + set_bit(ucm_dev->devnum, dev_map); + + cdev_init(&ucm_dev->cdev, &ucm_fops); + ucm_dev->cdev.owner = THIS_MODULE; + kobject_set_name(&ucm_dev->cdev.kobj, "ucm%d", ucm_dev->devnum); + if (cdev_add(&ucm_dev->cdev, IB_UCM_BASE_DEV + ucm_dev->devnum, 1)) + goto err; + + ucm_dev->dev.class = &cm_class; + ucm_dev->dev.parent = device->dma_device; + ucm_dev->dev.devt = ucm_dev->cdev.dev; + ucm_dev->dev.release = ib_ucm_release_dev; + dev_set_name(&ucm_dev->dev, "ucm%d", ucm_dev->devnum); + if (device_register(&ucm_dev->dev)) + goto err_cdev; + + if (device_create_file(&ucm_dev->dev, &dev_attr_ibdev)) + goto err_dev; + + ib_set_client_data(device, &ucm_client, ucm_dev); + return; + +err_dev: + device_unregister(&ucm_dev->dev); +err_cdev: + cdev_del(&ucm_dev->cdev); + clear_bit(ucm_dev->devnum, dev_map); +err: + kfree(ucm_dev); + return; +} + +static void ib_ucm_remove_one(struct ib_device *device) +{ + struct ib_ucm_device *ucm_dev = ib_get_client_data(device, &ucm_client); + + if (!ucm_dev) + return; + + device_unregister(&ucm_dev->dev); +} + +static ssize_t show_abi_version(struct class *class, char *buf) +{ + return sprintf(buf, "%d\n", IB_USER_CM_ABI_VERSION); +} +static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); + +static int __init ib_ucm_init(void) +{ + int ret; + + ret = register_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES, + "infiniband_cm"); + if (ret) { + printk(KERN_ERR "ucm: couldn't register device number\n"); + goto error1; + } + + ret = class_create_file(&cm_class, &class_attr_abi_version); + if (ret) { + printk(KERN_ERR "ucm: couldn't create abi_version attribute\n"); + goto error2; + } + + ret = ib_register_client(&ucm_client); + if (ret) { + printk(KERN_ERR "ucm: couldn't register client\n"); + goto error3; + } + return 0; + +error3: + class_remove_file(&cm_class, &class_attr_abi_version); +error2: + unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES); +error1: + return ret; +} + +static void __exit ib_ucm_cleanup(void) +{ + ib_unregister_client(&ucm_client); + class_remove_file(&cm_class, &class_attr_abi_version); + unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES); + idr_destroy(&ctx_id_table); +} + +module_init_order(ib_ucm_init, SI_ORDER_THIRD); +module_exit(ib_ucm_cleanup); diff --git a/sys/ofed/drivers/infiniband/core/ucma.c b/sys/ofed/drivers/infiniband/core/ucma.c new file mode 100644 index 000000000000..23cbf7b5ac09 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/ucma.c @@ -0,0 +1,1337 @@ +/* + * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +MODULE_AUTHOR("Sean Hefty"); +MODULE_DESCRIPTION("RDMA Userspace Connection Manager Access"); +MODULE_LICENSE("Dual BSD/GPL"); + +enum { + UCMA_MAX_BACKLOG = 1024 +}; + +struct ucma_file { + struct mutex mut; + struct file *filp; + struct list_head ctx_list; + struct list_head event_list; + wait_queue_head_t poll_wait; +}; + +struct ucma_context { + int id; + struct completion comp; + atomic_t ref; + int events_reported; + int backlog; + + struct ucma_file *file; + struct rdma_cm_id *cm_id; + u64 uid; + + struct list_head list; + struct list_head mc_list; +}; + +struct ucma_multicast { + struct ucma_context *ctx; + int id; + int events_reported; + + u64 uid; + struct list_head list; + struct sockaddr_storage addr; +}; + +struct ucma_event { + struct ucma_context *ctx; + struct ucma_multicast *mc; + struct list_head list; + struct rdma_cm_id *cm_id; + struct rdma_ucm_event_resp resp; +}; + +static DEFINE_MUTEX(mut); +static DEFINE_IDR(ctx_idr); +static DEFINE_IDR(multicast_idr); + +static inline struct ucma_context *_ucma_find_context(int id, + struct ucma_file *file) +{ + struct ucma_context *ctx; + + ctx = idr_find(&ctx_idr, id); + if (!ctx) + ctx = ERR_PTR(-ENOENT); + else if (ctx->file != file) + ctx = ERR_PTR(-EINVAL); + return ctx; +} + +static struct ucma_context *ucma_get_ctx(struct ucma_file *file, int id) +{ + struct ucma_context *ctx; + + mutex_lock(&mut); + ctx = _ucma_find_context(id, file); + if (!IS_ERR(ctx)) + atomic_inc(&ctx->ref); + mutex_unlock(&mut); + return ctx; +} + +static void ucma_put_ctx(struct ucma_context *ctx) +{ + if (atomic_dec_and_test(&ctx->ref)) + complete(&ctx->comp); +} + +static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file) +{ + struct ucma_context *ctx; + int ret; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return NULL; + + atomic_set(&ctx->ref, 1); + init_completion(&ctx->comp); + INIT_LIST_HEAD(&ctx->mc_list); + ctx->file = file; + + do { + ret = idr_pre_get(&ctx_idr, GFP_KERNEL); + if (!ret) + goto error; + + mutex_lock(&mut); + ret = idr_get_new(&ctx_idr, ctx, &ctx->id); + mutex_unlock(&mut); + } while (ret == -EAGAIN); + + if (ret) + goto error; + + list_add_tail(&ctx->list, &file->ctx_list); + return ctx; + +error: + kfree(ctx); + return NULL; +} + +static struct ucma_multicast* ucma_alloc_multicast(struct ucma_context *ctx) +{ + struct ucma_multicast *mc; + int ret; + + mc = kzalloc(sizeof(*mc), GFP_KERNEL); + if (!mc) + return NULL; + + do { + ret = idr_pre_get(&multicast_idr, GFP_KERNEL); + if (!ret) + goto error; + + mutex_lock(&mut); + ret = idr_get_new(&multicast_idr, mc, &mc->id); + mutex_unlock(&mut); + } while (ret == -EAGAIN); + + if (ret) + goto error; + + mc->ctx = ctx; + list_add_tail(&mc->list, &ctx->mc_list); + return mc; + +error: + kfree(mc); + return NULL; +} + +static void ucma_copy_conn_event(struct rdma_ucm_conn_param *dst, + struct rdma_conn_param *src) +{ + if (src->private_data_len) + memcpy(dst->private_data, src->private_data, + src->private_data_len); + dst->private_data_len = src->private_data_len; + dst->responder_resources =src->responder_resources; + dst->initiator_depth = src->initiator_depth; + dst->flow_control = src->flow_control; + dst->retry_count = src->retry_count; + dst->rnr_retry_count = src->rnr_retry_count; + dst->srq = src->srq; + dst->qp_num = src->qp_num; +} + +static void ucma_copy_ud_event(struct rdma_ucm_ud_param *dst, + struct rdma_ud_param *src) +{ + if (src->private_data_len) + memcpy(dst->private_data, src->private_data, + src->private_data_len); + dst->private_data_len = src->private_data_len; + ib_copy_ah_attr_to_user(&dst->ah_attr, &src->ah_attr); + dst->qp_num = src->qp_num; + dst->qkey = src->qkey; +} + +static void ucma_set_event_context(struct ucma_context *ctx, + struct rdma_cm_event *event, + struct ucma_event *uevent) +{ + uevent->ctx = ctx; + switch (event->event) { + case RDMA_CM_EVENT_MULTICAST_JOIN: + case RDMA_CM_EVENT_MULTICAST_ERROR: + uevent->mc = (struct ucma_multicast *) + event->param.ud.private_data; + uevent->resp.uid = uevent->mc->uid; + uevent->resp.id = uevent->mc->id; + break; + default: + uevent->resp.uid = ctx->uid; + uevent->resp.id = ctx->id; + break; + } +} + +static int ucma_event_handler(struct rdma_cm_id *cm_id, + struct rdma_cm_event *event) +{ + struct ucma_event *uevent; + struct ucma_context *ctx = cm_id->context; + int ret = 0; + + uevent = kzalloc(sizeof(*uevent), GFP_KERNEL); + if (!uevent) + return event->event == RDMA_CM_EVENT_CONNECT_REQUEST; + + uevent->cm_id = cm_id; + ucma_set_event_context(ctx, event, uevent); + uevent->resp.event = event->event; + uevent->resp.status = event->status; + if (cm_id->ps == RDMA_PS_UDP || cm_id->ps == RDMA_PS_IPOIB) + ucma_copy_ud_event(&uevent->resp.param.ud, &event->param.ud); + else + ucma_copy_conn_event(&uevent->resp.param.conn, + &event->param.conn); + + mutex_lock(&ctx->file->mut); + if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) { + if (!ctx->backlog) { + ret = -ENOMEM; + kfree(uevent); + goto out; + } + ctx->backlog--; + } else if (!ctx->uid) { + /* + * We ignore events for new connections until userspace has set + * their context. This can only happen if an error occurs on a + * new connection before the user accepts it. This is okay, + * since the accept will just fail later. + */ + kfree(uevent); + goto out; + } + + list_add_tail(&uevent->list, &ctx->file->event_list); + wake_up_interruptible(&ctx->file->poll_wait); + if (ctx->file->filp) + selwakeup(&ctx->file->filp->f_selinfo); +out: + mutex_unlock(&ctx->file->mut); + return ret; +} + +static ssize_t ucma_get_event(struct ucma_file *file, const char __user *inbuf, + int in_len, int out_len) +{ + struct ucma_context *ctx; + struct rdma_ucm_get_event cmd; + struct ucma_event *uevent; + int ret = 0; + DEFINE_WAIT(wait); + + if (out_len < sizeof uevent->resp) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + mutex_lock(&file->mut); + while (list_empty(&file->event_list)) { + mutex_unlock(&file->mut); + + if (file->filp->f_flags & O_NONBLOCK) + return -EAGAIN; + + if (wait_event_interruptible(file->poll_wait, + !list_empty(&file->event_list))) + return -ERESTARTSYS; + + mutex_lock(&file->mut); + } + + uevent = list_entry(file->event_list.next, struct ucma_event, list); + + if (uevent->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST) { + ctx = ucma_alloc_ctx(file); + if (!ctx) { + ret = -ENOMEM; + goto done; + } + uevent->ctx->backlog++; + ctx->cm_id = uevent->cm_id; + ctx->cm_id->context = ctx; + uevent->resp.id = ctx->id; + } + + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &uevent->resp, sizeof uevent->resp)) { + ret = -EFAULT; + goto done; + } + + list_del(&uevent->list); + uevent->ctx->events_reported++; + if (uevent->mc) + uevent->mc->events_reported++; + kfree(uevent); +done: + mutex_unlock(&file->mut); + return ret; +} + +static ssize_t ucma_create_id(struct ucma_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_create_id cmd; + struct rdma_ucm_create_id_resp resp; + struct ucma_context *ctx; + int ret; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + mutex_lock(&file->mut); + ctx = ucma_alloc_ctx(file); + mutex_unlock(&file->mut); + if (!ctx) + return -ENOMEM; + + ctx->uid = cmd.uid; + ctx->cm_id = rdma_create_id(ucma_event_handler, ctx, cmd.ps); + if (IS_ERR(ctx->cm_id)) { + ret = PTR_ERR(ctx->cm_id); + goto err1; + } + + resp.id = ctx->id; + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) { + ret = -EFAULT; + goto err2; + } + return 0; + +err2: + rdma_destroy_id(ctx->cm_id); +err1: + mutex_lock(&mut); + idr_remove(&ctx_idr, ctx->id); + mutex_unlock(&mut); + kfree(ctx); + return ret; +} + +static void ucma_cleanup_multicast(struct ucma_context *ctx) +{ + struct ucma_multicast *mc, *tmp; + + mutex_lock(&mut); + list_for_each_entry_safe(mc, tmp, &ctx->mc_list, list) { + list_del(&mc->list); + idr_remove(&multicast_idr, mc->id); + kfree(mc); + } + mutex_unlock(&mut); +} + +static void ucma_cleanup_events(struct ucma_context *ctx) +{ + struct ucma_event *uevent, *tmp; + + list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list) { + if (uevent->ctx != ctx) + continue; + + list_del(&uevent->list); + + /* clear incoming connections. */ + if (uevent->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST) + rdma_destroy_id(uevent->cm_id); + + kfree(uevent); + } +} + +static void ucma_cleanup_mc_events(struct ucma_multicast *mc) +{ + struct ucma_event *uevent, *tmp; + + list_for_each_entry_safe(uevent, tmp, &mc->ctx->file->event_list, list) { + if (uevent->mc != mc) + continue; + + list_del(&uevent->list); + kfree(uevent); + } +} + +static int ucma_free_ctx(struct ucma_context *ctx) +{ + int events_reported; + + /* No new events will be generated after destroying the id. */ + rdma_destroy_id(ctx->cm_id); + + ucma_cleanup_multicast(ctx); + + /* Cleanup events not yet reported to the user. */ + mutex_lock(&ctx->file->mut); + ucma_cleanup_events(ctx); + list_del(&ctx->list); + mutex_unlock(&ctx->file->mut); + + events_reported = ctx->events_reported; + kfree(ctx); + return events_reported; +} + +static ssize_t ucma_destroy_id(struct ucma_file *file, const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_destroy_id cmd; + struct rdma_ucm_destroy_id_resp resp; + struct ucma_context *ctx; + int ret = 0; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + mutex_lock(&mut); + ctx = _ucma_find_context(cmd.id, file); + if (!IS_ERR(ctx)) + idr_remove(&ctx_idr, ctx->id); + mutex_unlock(&mut); + + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ucma_put_ctx(ctx); + wait_for_completion(&ctx->comp); + resp.events_reported = ucma_free_ctx(ctx); + + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) + ret = -EFAULT; + + return ret; +} + +static ssize_t ucma_bind_addr(struct ucma_file *file, const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_bind_addr cmd; + struct ucma_context *ctx; + int ret; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ret = rdma_bind_addr(ctx->cm_id, (struct sockaddr *) &cmd.addr); + ucma_put_ctx(ctx); + return ret; +} + +static ssize_t ucma_resolve_addr(struct ucma_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_resolve_addr cmd; + struct ucma_context *ctx; + int ret; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr, + (struct sockaddr *) &cmd.dst_addr, + cmd.timeout_ms); + ucma_put_ctx(ctx); + return ret; +} + +static ssize_t ucma_resolve_route(struct ucma_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_resolve_route cmd; + struct ucma_context *ctx; + int ret; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ret = rdma_resolve_route(ctx->cm_id, cmd.timeout_ms); + ucma_put_ctx(ctx); + return ret; +} + +static void ucma_copy_ib_route(struct rdma_ucm_query_route_resp *resp, + struct rdma_route *route) +{ + struct rdma_dev_addr *dev_addr; + + resp->num_paths = route->num_paths; + switch (route->num_paths) { + case 0: + dev_addr = &route->addr.dev_addr; + rdma_addr_get_dgid(dev_addr, + (union ib_gid *) &resp->ib_route[0].dgid); + rdma_addr_get_sgid(dev_addr, + (union ib_gid *) &resp->ib_route[0].sgid); + resp->ib_route[0].pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); + break; + case 2: + ib_copy_path_rec_to_user(&resp->ib_route[1], + &route->path_rec[1]); + /* fall through */ + case 1: + ib_copy_path_rec_to_user(&resp->ib_route[0], + &route->path_rec[0]); + break; + default: + break; + } +} + +static void ucma_copy_iboe_route(struct rdma_ucm_query_route_resp *resp, + struct rdma_route *route) +{ + struct rdma_dev_addr *dev_addr; + struct net_device *dev; + u16 vid = 0; + + resp->num_paths = route->num_paths; + switch (route->num_paths) { + case 0: + dev_addr = &route->addr.dev_addr; + dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if); + if (dev) { + vid = rdma_vlan_dev_vlan_id(dev); + dev_put(dev); + } + + iboe_mac_vlan_to_ll((union ib_gid *) &resp->ib_route[0].dgid, + dev_addr->dst_dev_addr, vid); + iboe_addr_get_sgid(dev_addr, + (union ib_gid *) &resp->ib_route[0].sgid); + resp->ib_route[0].pkey = cpu_to_be16(0xffff); + break; + case 2: + ib_copy_path_rec_to_user(&resp->ib_route[1], + &route->path_rec[1]); + /* fall through */ + case 1: + ib_copy_path_rec_to_user(&resp->ib_route[0], + &route->path_rec[0]); + break; + default: + break; + } +} + +static ssize_t ucma_query_route(struct ucma_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_query_route cmd; + struct rdma_ucm_query_route_resp resp; + struct ucma_context *ctx; + struct sockaddr *addr; + int ret = 0; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + memset(&resp, 0, sizeof resp); + addr = (struct sockaddr *) &ctx->cm_id->route.addr.src_addr; + memcpy(&resp.src_addr, addr, addr->sa_family == AF_INET ? + sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6)); + addr = (struct sockaddr *) &ctx->cm_id->route.addr.dst_addr; + memcpy(&resp.dst_addr, addr, addr->sa_family == AF_INET ? + sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6)); + if (!ctx->cm_id->device) + goto out; + + resp.node_guid = (__force __u64) ctx->cm_id->device->node_guid; + resp.port_num = ctx->cm_id->port_num; + if (rdma_node_get_transport(ctx->cm_id->device->node_type) == RDMA_TRANSPORT_IB) { + switch (rdma_port_get_link_layer(ctx->cm_id->device, ctx->cm_id->port_num)) { + case IB_LINK_LAYER_INFINIBAND: + ucma_copy_ib_route(&resp, &ctx->cm_id->route); + break; + case IB_LINK_LAYER_ETHERNET: + ucma_copy_iboe_route(&resp, &ctx->cm_id->route); + break; + default: + break; + } + } + +out: + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) + ret = -EFAULT; + + ucma_put_ctx(ctx); + return ret; +} + +static void ucma_copy_conn_param(struct rdma_conn_param *dst, + struct rdma_ucm_conn_param *src) +{ + dst->private_data = src->private_data; + dst->private_data_len = src->private_data_len; + dst->responder_resources =src->responder_resources; + dst->initiator_depth = src->initiator_depth; + dst->flow_control = src->flow_control; + dst->retry_count = src->retry_count; + dst->rnr_retry_count = src->rnr_retry_count; + dst->srq = src->srq; + dst->qp_num = src->qp_num; +} + +static ssize_t ucma_connect(struct ucma_file *file, const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_connect cmd; + struct rdma_conn_param conn_param; + struct ucma_context *ctx; + int ret; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + if (!cmd.conn_param.valid) + return -EINVAL; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ucma_copy_conn_param(&conn_param, &cmd.conn_param); + ret = rdma_connect(ctx->cm_id, &conn_param); + ucma_put_ctx(ctx); + return ret; +} + +static ssize_t ucma_listen(struct ucma_file *file, const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_listen cmd; + struct ucma_context *ctx; + int ret; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ctx->backlog = cmd.backlog > 0 && cmd.backlog < UCMA_MAX_BACKLOG ? + cmd.backlog : UCMA_MAX_BACKLOG; + ret = rdma_listen(ctx->cm_id, ctx->backlog); + ucma_put_ctx(ctx); + return ret; +} + +static ssize_t ucma_accept(struct ucma_file *file, const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_accept cmd; + struct rdma_conn_param conn_param; + struct ucma_context *ctx; + int ret; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + if (cmd.conn_param.valid) { + ctx->uid = cmd.uid; + ucma_copy_conn_param(&conn_param, &cmd.conn_param); + ret = rdma_accept(ctx->cm_id, &conn_param); + } else + ret = rdma_accept(ctx->cm_id, NULL); + + ucma_put_ctx(ctx); + return ret; +} + +static ssize_t ucma_reject(struct ucma_file *file, const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_reject cmd; + struct ucma_context *ctx; + int ret; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ret = rdma_reject(ctx->cm_id, cmd.private_data, cmd.private_data_len); + ucma_put_ctx(ctx); + return ret; +} + +static ssize_t ucma_disconnect(struct ucma_file *file, const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_disconnect cmd; + struct ucma_context *ctx; + int ret; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ret = rdma_disconnect(ctx->cm_id); + ucma_put_ctx(ctx); + return ret; +} + +static ssize_t ucma_init_qp_attr(struct ucma_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_init_qp_attr cmd; + struct ib_uverbs_qp_attr resp; + struct ucma_context *ctx; + struct ib_qp_attr qp_attr; + int ret; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + resp.qp_attr_mask = 0; + memset(&qp_attr, 0, sizeof qp_attr); + qp_attr.qp_state = cmd.qp_state; + ret = rdma_init_qp_attr(ctx->cm_id, &qp_attr, &resp.qp_attr_mask); + if (ret) + goto out; + + ib_copy_qp_attr_to_user(&resp, &qp_attr); + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) + ret = -EFAULT; + +out: + ucma_put_ctx(ctx); + return ret; +} + +static int ucma_set_option_id(struct ucma_context *ctx, int optname, + void *optval, size_t optlen) +{ + int ret = 0; + + switch (optname) { + case RDMA_OPTION_ID_TOS: + if (optlen != sizeof(u8)) { + ret = -EINVAL; + break; + } + rdma_set_service_type(ctx->cm_id, *((u8 *) optval)); + break; + default: + ret = -ENOSYS; + } + + return ret; +} + +static int ucma_set_ib_path(struct ucma_context *ctx, + struct ib_path_rec_data *path_data, size_t optlen) +{ + struct ib_sa_path_rec sa_path; + struct rdma_cm_event event; + int ret; + + if (optlen % sizeof(*path_data)) + return -EINVAL; + + for (; optlen; optlen -= sizeof(*path_data), path_data++) { + if (path_data->flags == (IB_PATH_GMP | IB_PATH_PRIMARY | + IB_PATH_BIDIRECTIONAL)) + break; + } + + if (!optlen) + return -EINVAL; + + ib_sa_unpack_path(path_data->path_rec, &sa_path); + ret = rdma_set_ib_paths(ctx->cm_id, &sa_path, 1); + if (ret) + return ret; + + memset(&event, 0, sizeof event); + event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; + return ucma_event_handler(ctx->cm_id, &event); +} + +static int ucma_set_option_ib(struct ucma_context *ctx, int optname, + void *optval, size_t optlen) +{ + int ret; + + switch (optname) { + case RDMA_OPTION_IB_PATH: + ret = ucma_set_ib_path(ctx, optval, optlen); + break; + default: + ret = -ENOSYS; + } + + return ret; +} + +static int ucma_set_option_level(struct ucma_context *ctx, int level, + int optname, void *optval, size_t optlen) +{ + int ret; + + switch (level) { + case RDMA_OPTION_ID: + ret = ucma_set_option_id(ctx, optname, optval, optlen); + break; + case RDMA_OPTION_IB: + ret = ucma_set_option_ib(ctx, optname, optval, optlen); + break; + default: + ret = -ENOSYS; + } + + return ret; +} + +static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_set_option cmd; + struct ucma_context *ctx; + void *optval; + int ret; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + optval = kmalloc(cmd.optlen, GFP_KERNEL); + if (!optval) { + ret = -ENOMEM; + goto out1; + } + + if (copy_from_user(optval, (void __user *) (unsigned long) cmd.optval, + cmd.optlen)) { + ret = -EFAULT; + goto out2; + } + + ret = ucma_set_option_level(ctx, cmd.level, cmd.optname, optval, + cmd.optlen); +out2: + kfree(optval); +out1: + ucma_put_ctx(ctx); + return ret; +} + +static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_notify cmd; + struct ucma_context *ctx; + int ret; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ret = rdma_notify(ctx->cm_id, (enum ib_event_type) cmd.event); + ucma_put_ctx(ctx); + return ret; +} + +static ssize_t ucma_join_multicast(struct ucma_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_join_mcast cmd; + struct rdma_ucm_create_id_resp resp; + struct ucma_context *ctx; + struct ucma_multicast *mc; + int ret; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + ctx = ucma_get_ctx(file, cmd.id); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + mutex_lock(&file->mut); + mc = ucma_alloc_multicast(ctx); + if (!mc) { + ret = -ENOMEM; + goto err1; + } + + mc->uid = cmd.uid; + memcpy(&mc->addr, &cmd.addr, sizeof cmd.addr); + ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr, mc); + if (ret) + goto err2; + + resp.id = mc->id; + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) { + ret = -EFAULT; + goto err3; + } + + mutex_unlock(&file->mut); + ucma_put_ctx(ctx); + return 0; + +err3: + rdma_leave_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr); + ucma_cleanup_mc_events(mc); +err2: + mutex_lock(&mut); + idr_remove(&multicast_idr, mc->id); + mutex_unlock(&mut); + list_del(&mc->list); + kfree(mc); +err1: + mutex_unlock(&file->mut); + ucma_put_ctx(ctx); + return ret; +} + +static ssize_t ucma_leave_multicast(struct ucma_file *file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_destroy_id cmd; + struct rdma_ucm_destroy_id_resp resp; + struct ucma_multicast *mc; + int ret = 0; + + if (out_len < sizeof(resp)) + return -ENOSPC; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + mutex_lock(&mut); + mc = idr_find(&multicast_idr, cmd.id); + if (!mc) + mc = ERR_PTR(-ENOENT); + else if (mc->ctx->file != file) + mc = ERR_PTR(-EINVAL); + else { + idr_remove(&multicast_idr, mc->id); + atomic_inc(&mc->ctx->ref); + } + mutex_unlock(&mut); + + if (IS_ERR(mc)) { + ret = PTR_ERR(mc); + goto out; + } + + rdma_leave_multicast(mc->ctx->cm_id, (struct sockaddr *) &mc->addr); + mutex_lock(&mc->ctx->file->mut); + ucma_cleanup_mc_events(mc); + list_del(&mc->list); + mutex_unlock(&mc->ctx->file->mut); + + ucma_put_ctx(mc->ctx); + resp.events_reported = mc->events_reported; + kfree(mc); + + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) + ret = -EFAULT; +out: + return ret; +} + +static void ucma_lock_files(struct ucma_file *file1, struct ucma_file *file2) +{ + /* Acquire mutex's based on pointer comparison to prevent deadlock. */ + if (file1 < file2) { + mutex_lock(&file1->mut); + mutex_lock(&file2->mut); + } else { + mutex_lock(&file2->mut); + mutex_lock(&file1->mut); + } +} + +static void ucma_unlock_files(struct ucma_file *file1, struct ucma_file *file2) +{ + if (file1 < file2) { + mutex_unlock(&file2->mut); + mutex_unlock(&file1->mut); + } else { + mutex_unlock(&file1->mut); + mutex_unlock(&file2->mut); + } +} + +static void ucma_move_events(struct ucma_context *ctx, struct ucma_file *file) +{ + struct ucma_event *uevent, *tmp; + + list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list) + if (uevent->ctx == ctx) + list_move_tail(&uevent->list, &file->event_list); +} + +static ssize_t ucma_migrate_id(struct ucma_file *new_file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_migrate_id cmd; + struct rdma_ucm_migrate_resp resp; + struct ucma_context *ctx; + struct file *filp; + struct ucma_file *cur_file; + int ret = 0; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + /* Get current fd to protect against it being closed */ + filp = fget(cmd.fd); + if (!filp) + return -ENOENT; + + /* Validate current fd and prevent destruction of id. */ + ctx = ucma_get_ctx(filp->private_data, cmd.id); + if (IS_ERR(ctx)) { + ret = PTR_ERR(ctx); + goto file_put; + } + + cur_file = ctx->file; + if (cur_file == new_file) { + resp.events_reported = ctx->events_reported; + goto response; + } + + /* + * Migrate events between fd's, maintaining order, and avoiding new + * events being added before existing events. + */ + ucma_lock_files(cur_file, new_file); + mutex_lock(&mut); + + list_move_tail(&ctx->list, &new_file->ctx_list); + ucma_move_events(ctx, new_file); + ctx->file = new_file; + resp.events_reported = ctx->events_reported; + + mutex_unlock(&mut); + ucma_unlock_files(cur_file, new_file); + +response: + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) + ret = -EFAULT; + + ucma_put_ctx(ctx); +file_put: + fput(filp); + return ret; +} + +static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, + const char __user *inbuf, + int in_len, int out_len) = { + [RDMA_USER_CM_CMD_CREATE_ID] = ucma_create_id, + [RDMA_USER_CM_CMD_DESTROY_ID] = ucma_destroy_id, + [RDMA_USER_CM_CMD_BIND_ADDR] = ucma_bind_addr, + [RDMA_USER_CM_CMD_RESOLVE_ADDR] = ucma_resolve_addr, + [RDMA_USER_CM_CMD_RESOLVE_ROUTE]= ucma_resolve_route, + [RDMA_USER_CM_CMD_QUERY_ROUTE] = ucma_query_route, + [RDMA_USER_CM_CMD_CONNECT] = ucma_connect, + [RDMA_USER_CM_CMD_LISTEN] = ucma_listen, + [RDMA_USER_CM_CMD_ACCEPT] = ucma_accept, + [RDMA_USER_CM_CMD_REJECT] = ucma_reject, + [RDMA_USER_CM_CMD_DISCONNECT] = ucma_disconnect, + [RDMA_USER_CM_CMD_INIT_QP_ATTR] = ucma_init_qp_attr, + [RDMA_USER_CM_CMD_GET_EVENT] = ucma_get_event, + [RDMA_USER_CM_CMD_GET_OPTION] = NULL, + [RDMA_USER_CM_CMD_SET_OPTION] = ucma_set_option, + [RDMA_USER_CM_CMD_NOTIFY] = ucma_notify, + [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast, + [RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast, + [RDMA_USER_CM_CMD_MIGRATE_ID] = ucma_migrate_id +}; + +static ssize_t ucma_write(struct file *filp, const char __user *buf, + size_t len, loff_t *pos) +{ + struct ucma_file *file = filp->private_data; + struct rdma_ucm_cmd_hdr hdr; + ssize_t ret; + + if (len < sizeof(hdr)) + return -EINVAL; + + if (copy_from_user(&hdr, buf, sizeof(hdr))) + return -EFAULT; + + if (hdr.cmd < 0 || hdr.cmd >= ARRAY_SIZE(ucma_cmd_table)) + return -EINVAL; + + if (hdr.in + sizeof(hdr) > len) + return -EINVAL; + + if (!ucma_cmd_table[hdr.cmd]) + return -ENOSYS; + + ret = ucma_cmd_table[hdr.cmd](file, buf + sizeof(hdr), hdr.in, hdr.out); + if (!ret) + ret = len; + + return ret; +} + +static unsigned int ucma_poll(struct file *filp, struct poll_table_struct *wait) +{ + struct ucma_file *file = filp->private_data; + unsigned int mask = 0; + + poll_wait(filp, &file->poll_wait, wait); + + if (!list_empty(&file->event_list)) + mask = POLLIN | POLLRDNORM; + + return mask; +} + +/* + * ucma_open() does not need the BKL: + * + * - no global state is referred to; + * - there is no ioctl method to race against; + * - no further module initialization is required for open to work + * after the device is registered. + */ +static int ucma_open(struct inode *inode, struct file *filp) +{ + struct ucma_file *file; + + file = kmalloc(sizeof *file, GFP_KERNEL); + if (!file) + return -ENOMEM; + + INIT_LIST_HEAD(&file->event_list); + INIT_LIST_HEAD(&file->ctx_list); + init_waitqueue_head(&file->poll_wait); + mutex_init(&file->mut); + + filp->private_data = file; + file->filp = filp; + return 0; +} + +static int ucma_close(struct inode *inode, struct file *filp) +{ + struct ucma_file *file = filp->private_data; + struct ucma_context *ctx, *tmp; + + mutex_lock(&file->mut); + list_for_each_entry_safe(ctx, tmp, &file->ctx_list, list) { + mutex_unlock(&file->mut); + + mutex_lock(&mut); + idr_remove(&ctx_idr, ctx->id); + mutex_unlock(&mut); + + ucma_free_ctx(ctx); + mutex_lock(&file->mut); + } + mutex_unlock(&file->mut); + kfree(file); + return 0; +} + +static const struct file_operations ucma_fops = { + .owner = THIS_MODULE, + .open = ucma_open, + .release = ucma_close, + .write = ucma_write, + .poll = ucma_poll, +}; + +static struct miscdevice ucma_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "rdma_cm", + .fops = &ucma_fops, +}; + +static ssize_t show_abi_version(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", RDMA_USER_CM_ABI_VERSION); +} +static DEVICE_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); + +static int __init ucma_init(void) +{ + int ret; + + ret = misc_register(&ucma_misc); + if (ret) + return ret; + + ret = device_create_file(ucma_misc.this_device, &dev_attr_abi_version); + if (ret) { + printk(KERN_ERR "rdma_ucm: couldn't create abi_version attr\n"); + goto err; + } + return 0; +err: + misc_deregister(&ucma_misc); + return ret; +} + +static void __exit ucma_cleanup(void) +{ + device_remove_file(ucma_misc.this_device, &dev_attr_abi_version); + misc_deregister(&ucma_misc); + idr_destroy(&ctx_idr); +} + +module_init(ucma_init); +module_exit(ucma_cleanup); diff --git a/sys/ofed/drivers/infiniband/core/ud_header.c b/sys/ofed/drivers/infiniband/core/ud_header.c new file mode 100644 index 000000000000..e095a12b0ace --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/ud_header.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include + +#define STRUCT_FIELD(header, field) \ + .struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field), \ + .struct_size_bytes = sizeof ((struct ib_unpacked_ ## header *) 0)->field, \ + .field_name = #header ":" #field + +static const struct ib_field lrh_table[] = { + { STRUCT_FIELD(lrh, virtual_lane), + .offset_words = 0, + .offset_bits = 0, + .size_bits = 4 }, + { STRUCT_FIELD(lrh, link_version), + .offset_words = 0, + .offset_bits = 4, + .size_bits = 4 }, + { STRUCT_FIELD(lrh, service_level), + .offset_words = 0, + .offset_bits = 8, + .size_bits = 4 }, + { RESERVED, + .offset_words = 0, + .offset_bits = 12, + .size_bits = 2 }, + { STRUCT_FIELD(lrh, link_next_header), + .offset_words = 0, + .offset_bits = 14, + .size_bits = 2 }, + { STRUCT_FIELD(lrh, destination_lid), + .offset_words = 0, + .offset_bits = 16, + .size_bits = 16 }, + { RESERVED, + .offset_words = 1, + .offset_bits = 0, + .size_bits = 5 }, + { STRUCT_FIELD(lrh, packet_length), + .offset_words = 1, + .offset_bits = 5, + .size_bits = 11 }, + { STRUCT_FIELD(lrh, source_lid), + .offset_words = 1, + .offset_bits = 16, + .size_bits = 16 } +}; + +static const struct ib_field eth_table[] = { + { STRUCT_FIELD(eth, dmac_h), + .offset_words = 0, + .offset_bits = 0, + .size_bits = 32 }, + { STRUCT_FIELD(eth, dmac_l), + .offset_words = 1, + .offset_bits = 0, + .size_bits = 16 }, + { STRUCT_FIELD(eth, smac_h), + .offset_words = 1, + .offset_bits = 16, + .size_bits = 16 }, + { STRUCT_FIELD(eth, smac_l), + .offset_words = 2, + .offset_bits = 0, + .size_bits = 32 }, + { STRUCT_FIELD(eth, type), + .offset_words = 3, + .offset_bits = 0, + .size_bits = 16 } +}; + +static const struct ib_field vlan_table[] = { + { STRUCT_FIELD(vlan, tag), + .offset_words = 0, + .offset_bits = 0, + .size_bits = 16 }, + { STRUCT_FIELD(vlan, type), + .offset_words = 0, + .offset_bits = 16, + .size_bits = 16 } +}; + +static const struct ib_field grh_table[] = { + { STRUCT_FIELD(grh, ip_version), + .offset_words = 0, + .offset_bits = 0, + .size_bits = 4 }, + { STRUCT_FIELD(grh, traffic_class), + .offset_words = 0, + .offset_bits = 4, + .size_bits = 8 }, + { STRUCT_FIELD(grh, flow_label), + .offset_words = 0, + .offset_bits = 12, + .size_bits = 20 }, + { STRUCT_FIELD(grh, payload_length), + .offset_words = 1, + .offset_bits = 0, + .size_bits = 16 }, + { STRUCT_FIELD(grh, next_header), + .offset_words = 1, + .offset_bits = 16, + .size_bits = 8 }, + { STRUCT_FIELD(grh, hop_limit), + .offset_words = 1, + .offset_bits = 24, + .size_bits = 8 }, + { STRUCT_FIELD(grh, source_gid), + .offset_words = 2, + .offset_bits = 0, + .size_bits = 128 }, + { STRUCT_FIELD(grh, destination_gid), + .offset_words = 6, + .offset_bits = 0, + .size_bits = 128 } +}; + +static const struct ib_field bth_table[] = { + { STRUCT_FIELD(bth, opcode), + .offset_words = 0, + .offset_bits = 0, + .size_bits = 8 }, + { STRUCT_FIELD(bth, solicited_event), + .offset_words = 0, + .offset_bits = 8, + .size_bits = 1 }, + { STRUCT_FIELD(bth, mig_req), + .offset_words = 0, + .offset_bits = 9, + .size_bits = 1 }, + { STRUCT_FIELD(bth, pad_count), + .offset_words = 0, + .offset_bits = 10, + .size_bits = 2 }, + { STRUCT_FIELD(bth, transport_header_version), + .offset_words = 0, + .offset_bits = 12, + .size_bits = 4 }, + { STRUCT_FIELD(bth, pkey), + .offset_words = 0, + .offset_bits = 16, + .size_bits = 16 }, + { RESERVED, + .offset_words = 1, + .offset_bits = 0, + .size_bits = 8 }, + { STRUCT_FIELD(bth, destination_qpn), + .offset_words = 1, + .offset_bits = 8, + .size_bits = 24 }, + { STRUCT_FIELD(bth, ack_req), + .offset_words = 2, + .offset_bits = 0, + .size_bits = 1 }, + { RESERVED, + .offset_words = 2, + .offset_bits = 1, + .size_bits = 7 }, + { STRUCT_FIELD(bth, psn), + .offset_words = 2, + .offset_bits = 8, + .size_bits = 24 } +}; + +static const struct ib_field deth_table[] = { + { STRUCT_FIELD(deth, qkey), + .offset_words = 0, + .offset_bits = 0, + .size_bits = 32 }, + { RESERVED, + .offset_words = 1, + .offset_bits = 0, + .size_bits = 8 }, + { STRUCT_FIELD(deth, source_qpn), + .offset_words = 1, + .offset_bits = 8, + .size_bits = 24 } +}; + +/** + * ib_ud_header_init - Initialize UD header structure + * @payload_bytes:Length of packet payload + * @lrh_present: specify if LRH is present + * @eth_present: specify if Eth header is present + * @vlan_present: packet is tagged vlan + * @grh_present:GRH flag (if non-zero, GRH will be included) + * @immediate_present: specify if immediate data is present + * @header:Structure to initialize + */ +void ib_ud_header_init(int payload_bytes, + int lrh_present, + int eth_present, + int vlan_present, + int grh_present, + int immediate_present, + struct ib_ud_header *header) +{ + u16 packet_length; + + memset(header, 0, sizeof *header); + + if (lrh_present) { + header->lrh.link_version = 0; + header->lrh.link_next_header = + grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL; + packet_length = IB_LRH_BYTES; + } + + if (eth_present) { + if (vlan_present) { + header->eth.type = cpu_to_be16(ETH_P_8021Q); + packet_length += IB_VLAN_BYTES; + + } + packet_length += IB_ETH_BYTES; + } + + packet_length += IB_BTH_BYTES + IB_DETH_BYTES + payload_bytes + + 4 + /* ICRC */ + 3; /* round up */ + packet_length /= 4; + if (grh_present) { + packet_length += IB_GRH_BYTES / 4; + header->grh.ip_version = 6; + header->grh.payload_length = + cpu_to_be16((IB_BTH_BYTES + + IB_DETH_BYTES + + payload_bytes + + 4 + /* ICRC */ + 3) & ~3); /* round up */ + header->grh.next_header = 0x1b; + } + + if (lrh_present) + header->lrh.packet_length = cpu_to_be16(packet_length); + + if (immediate_present) + header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; + else + header->bth.opcode = IB_OPCODE_UD_SEND_ONLY; + header->bth.pad_count = (4 - payload_bytes) & 3; + header->bth.transport_header_version = 0; + + header->lrh_present = lrh_present; + header->eth_present = eth_present; + header->vlan_present = vlan_present; + header->grh_present = grh_present; + header->immediate_present = immediate_present; +} +EXPORT_SYMBOL(ib_ud_header_init); + +/** + * ib_lrh_header_pack - Pack LRH header struct into wire format + * @lrh:unpacked LRH header struct + * @buf:Buffer to pack into + * + * ib_lrh_header_pack() packs the LRH header structure @lrh into + * wire format in the buffer @buf. + */ +int ib_lrh_header_pack(struct ib_unpacked_lrh *lrh, void *buf) +{ + ib_pack(lrh_table, ARRAY_SIZE(lrh_table), lrh, buf); + return 0; +} +EXPORT_SYMBOL(ib_lrh_header_pack); + +/** + * ib_lrh_header_unpack - Unpack LRH structure from wire format + * @lrh:unpacked LRH header struct + * @buf:Buffer to pack into + * + * ib_lrh_header_unpack() unpacks the LRH header structure from + * wire format (in buf) into @lrh. + */ +int ib_lrh_header_unpack(void *buf, struct ib_unpacked_lrh *lrh) +{ + ib_unpack(lrh_table, ARRAY_SIZE(lrh_table), buf, lrh); + return 0; +} +EXPORT_SYMBOL(ib_lrh_header_unpack); + +/** + * ib_ud_header_pack - Pack UD header struct into wire format + * @header:UD header struct + * @buf:Buffer to pack into + * + * ib_ud_header_pack() packs the UD header structure @header into wire + * format in the buffer @buf. + */ +int ib_ud_header_pack(struct ib_ud_header *header, + void *buf) +{ + int len = 0; + + if (header->lrh_present) { + ib_pack(lrh_table, ARRAY_SIZE(lrh_table), + &header->lrh, buf + len); + len += IB_LRH_BYTES; + } + if (header->eth_present) { + ib_pack(eth_table, ARRAY_SIZE(eth_table), + &header->eth, buf + len); + len += IB_ETH_BYTES; + } + + + if (header->vlan_present) { + ib_pack(vlan_table, ARRAY_SIZE(vlan_table), + &header->vlan, buf + len); + len += IB_VLAN_BYTES; + } + + if (header->grh_present) { + ib_pack(grh_table, ARRAY_SIZE(grh_table), + &header->grh, buf + len); + len += IB_GRH_BYTES; + } + + ib_pack(bth_table, ARRAY_SIZE(bth_table), + &header->bth, buf + len); + len += IB_BTH_BYTES; + + ib_pack(deth_table, ARRAY_SIZE(deth_table), + &header->deth, buf + len); + len += IB_DETH_BYTES; + + if (header->immediate_present) { + memcpy(buf + len, &header->immediate_data, sizeof header->immediate_data); + len += sizeof header->immediate_data; + } + + return len; +} +EXPORT_SYMBOL(ib_ud_header_pack); + +/** + * ib_ud_header_unpack - Unpack UD header struct from wire format + * @header:UD header struct + * @buf:Buffer to pack into + * + * ib_ud_header_pack() unpacks the UD header structure @header from wire + * format in the buffer @buf. + */ +int ib_ud_header_unpack(void *buf, + struct ib_ud_header *header) +{ + ib_unpack(lrh_table, ARRAY_SIZE(lrh_table), + buf, &header->lrh); + buf += IB_LRH_BYTES; + + if (header->lrh.link_version != 0) { + printk(KERN_WARNING "Invalid LRH.link_version %d\n", + header->lrh.link_version); + return -EINVAL; + } + + switch (header->lrh.link_next_header) { + case IB_LNH_IBA_LOCAL: + header->grh_present = 0; + break; + + case IB_LNH_IBA_GLOBAL: + header->grh_present = 1; + ib_unpack(grh_table, ARRAY_SIZE(grh_table), + buf, &header->grh); + buf += IB_GRH_BYTES; + + if (header->grh.ip_version != 6) { + printk(KERN_WARNING "Invalid GRH.ip_version %d\n", + header->grh.ip_version); + return -EINVAL; + } + if (header->grh.next_header != 0x1b) { + printk(KERN_WARNING "Invalid GRH.next_header 0x%02x\n", + header->grh.next_header); + return -EINVAL; + } + break; + + default: + printk(KERN_WARNING "Invalid LRH.link_next_header %d\n", + header->lrh.link_next_header); + return -EINVAL; + } + + ib_unpack(bth_table, ARRAY_SIZE(bth_table), + buf, &header->bth); + buf += IB_BTH_BYTES; + + switch (header->bth.opcode) { + case IB_OPCODE_UD_SEND_ONLY: + header->immediate_present = 0; + break; + case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE: + header->immediate_present = 1; + break; + default: + printk(KERN_WARNING "Invalid BTH.opcode 0x%02x\n", + header->bth.opcode); + return -EINVAL; + } + + if (header->bth.transport_header_version != 0) { + printk(KERN_WARNING "Invalid BTH.transport_header_version %d\n", + header->bth.transport_header_version); + return -EINVAL; + } + + ib_unpack(deth_table, ARRAY_SIZE(deth_table), + buf, &header->deth); + buf += IB_DETH_BYTES; + + if (header->immediate_present) + memcpy(&header->immediate_data, buf, sizeof header->immediate_data); + + return 0; +} +EXPORT_SYMBOL(ib_ud_header_unpack); diff --git a/sys/ofed/drivers/infiniband/core/umem.c b/sys/ofed/drivers/infiniband/core/umem.c new file mode 100644 index 000000000000..0c6fed2f14f6 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/umem.c @@ -0,0 +1,532 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#ifdef __linux__ +#include +#endif +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "uverbs.h" + +static int allow_weak_ordering; +module_param(allow_weak_ordering, bool, 0444); +MODULE_PARM_DESC(allow_weak_ordering, "Allow weak ordering for data registered memory"); + +#define IB_UMEM_MAX_PAGE_CHUNK \ + ((PAGE_SIZE - offsetof(struct ib_umem_chunk, page_list)) / \ + ((void *) &((struct ib_umem_chunk *) 0)->page_list[1] - \ + (void *) &((struct ib_umem_chunk *) 0)->page_list[0])) + +#ifdef __ia64__ +extern int dma_map_sg_hp_wa; + +static int dma_map_sg_ia64(struct ib_device *ibdev, + struct scatterlist *sg, + int nents, + enum dma_data_direction dir) +{ + int i, rc, j, lents = 0; + struct device *dev; + + if (!dma_map_sg_hp_wa) + return ib_dma_map_sg(ibdev, sg, nents, dir); + + dev = ibdev->dma_device; + for (i = 0; i < nents; ++i) { + rc = dma_map_sg(dev, sg + i, 1, dir); + if (rc <= 0) { + for (j = 0; j < i; ++j) + dma_unmap_sg(dev, sg + j, 1, dir); + + return 0; + } + lents += rc; + } + + return lents; +} + +static void dma_unmap_sg_ia64(struct ib_device *ibdev, + struct scatterlist *sg, + int nents, + enum dma_data_direction dir) +{ + int i; + struct device *dev; + + if (!dma_map_sg_hp_wa) + return ib_dma_unmap_sg(ibdev, sg, nents, dir); + + dev = ibdev->dma_device; + for (i = 0; i < nents; ++i) + dma_unmap_sg(dev, sg + i, 1, dir); +} + +#define ib_dma_map_sg(dev, sg, nents, dir) dma_map_sg_ia64(dev, sg, nents, dir) +#define ib_dma_unmap_sg(dev, sg, nents, dir) dma_unmap_sg_ia64(dev, sg, nents, dir) + +#endif + +static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int dirty) +{ +#ifdef __linux__ + struct ib_umem_chunk *chunk, *tmp; + int i; + + list_for_each_entry_safe(chunk, tmp, &umem->chunk_list, list) { + ib_dma_unmap_sg_attrs(dev, chunk->page_list, + chunk->nents, DMA_BIDIRECTIONAL, &chunk->attrs); + for (i = 0; i < chunk->nents; ++i) { + struct page *page = sg_page(&chunk->page_list[i]); + if (umem->writable && dirty) + set_page_dirty_lock(page); + put_page(page); + } + kfree(chunk); + } +#else + struct ib_umem_chunk *chunk, *tmp; + vm_object_t object; + int i; + + object = NULL; + list_for_each_entry_safe(chunk, tmp, &umem->chunk_list, list) { + ib_dma_unmap_sg_attrs(dev, chunk->page_list, + chunk->nents, DMA_BIDIRECTIONAL, &chunk->attrs); + for (i = 0; i < chunk->nents; ++i) { + struct page *page = sg_page(&chunk->page_list[i]); + if (umem->writable && dirty) { + if (object && object != page->object) + VM_OBJECT_UNLOCK(object); + if (object != page->object) { + object = page->object; + VM_OBJECT_LOCK(object); + } + vm_page_dirty(page); + } + } + kfree(chunk); + } + if (object) + VM_OBJECT_UNLOCK(object); + +#endif +} + +/** + * ib_umem_get - Pin and DMA map userspace memory. + * @context: userspace context to pin memory for + * @addr: userspace virtual address to start at + * @size: length of region to pin + * @access: IB_ACCESS_xxx flags for memory being pinned + * @dmasync: flush in-flight DMA when the memory region is written + */ +struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, + size_t size, int access, int dmasync) +{ +#ifdef __linux__ + struct ib_umem *umem; + struct page **page_list; + struct vm_area_struct **vma_list; + struct ib_umem_chunk *chunk; + unsigned long locked; + unsigned long lock_limit; + unsigned long cur_base; + unsigned long npages; + int ret; + int off; + int i; + DEFINE_DMA_ATTRS(attrs); + + if (dmasync) + dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs); + else if (allow_weak_ordering) + dma_set_attr(DMA_ATTR_WEAK_ORDERING, &attrs); + + if (!can_do_mlock()) + return ERR_PTR(-EPERM); + + umem = kmalloc(sizeof *umem, GFP_KERNEL); + if (!umem) + return ERR_PTR(-ENOMEM); + + umem->context = context; + umem->length = size; + umem->offset = addr & ~PAGE_MASK; + umem->page_size = PAGE_SIZE; + /* + * We ask for writable memory if any access flags other than + * "remote read" are set. "Local write" and "remote write" + * obviously require write access. "Remote atomic" can do + * things like fetch and add, which will modify memory, and + * "MW bind" can change permissions by binding a window. + */ + umem->writable = !!(access & ~IB_ACCESS_REMOTE_READ); + + /* We assume the memory is from hugetlb until proved otherwise */ + umem->hugetlb = 1; + + INIT_LIST_HEAD(&umem->chunk_list); + + page_list = (struct page **) __get_free_page(GFP_KERNEL); + if (!page_list) { + kfree(umem); + return ERR_PTR(-ENOMEM); + } + + /* + * if we can't alloc the vma_list, it's not so bad; + * just assume the memory is not hugetlb memory + */ + vma_list = (struct vm_area_struct **) __get_free_page(GFP_KERNEL); + if (!vma_list) + umem->hugetlb = 0; + + npages = PAGE_ALIGN(size + umem->offset) >> PAGE_SHIFT; + + down_write(¤t->mm->mmap_sem); + + locked = npages + current->mm->locked_vm; + lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT; + + if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) { + ret = -ENOMEM; + goto out; + } + + cur_base = addr & PAGE_MASK; + + ret = 0; + + while (npages) { + ret = get_user_pages(current, current->mm, cur_base, + min_t(unsigned long, npages, + PAGE_SIZE / sizeof (struct page *)), + 1, !umem->writable, page_list, vma_list); + + if (ret < 0) + goto out; + + cur_base += ret * PAGE_SIZE; + npages -= ret; + + off = 0; + + while (ret) { + chunk = kmalloc(sizeof *chunk + sizeof (struct scatterlist) * + min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK), + GFP_KERNEL); + if (!chunk) { + ret = -ENOMEM; + goto out; + } + + chunk->attrs = attrs; + chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK); + sg_init_table(chunk->page_list, chunk->nents); + for (i = 0; i < chunk->nents; ++i) { + if (vma_list && + !is_vm_hugetlb_page(vma_list[i + off])) + umem->hugetlb = 0; + sg_set_page(&chunk->page_list[i], page_list[i + off], PAGE_SIZE, 0); + } + + chunk->nmap = ib_dma_map_sg_attrs(context->device, + &chunk->page_list[0], + chunk->nents, + DMA_BIDIRECTIONAL, + &attrs); + if (chunk->nmap <= 0) { + for (i = 0; i < chunk->nents; ++i) + put_page(sg_page(&chunk->page_list[i])); + kfree(chunk); + + ret = -ENOMEM; + goto out; + } + + ret -= chunk->nents; + off += chunk->nents; + list_add_tail(&chunk->list, &umem->chunk_list); + } + + ret = 0; + } + +out: + if (ret < 0) { + __ib_umem_release(context->device, umem, 0); + kfree(umem); + } else + current->mm->locked_vm = locked; + + up_write(¤t->mm->mmap_sem); + if (vma_list) + free_page((unsigned long) vma_list); + free_page((unsigned long) page_list); + + return ret < 0 ? ERR_PTR(ret) : umem; +#else + struct ib_umem *umem; + struct ib_umem_chunk *chunk; + struct proc *proc; + pmap_t pmap; + vm_offset_t end, last, start; + vm_size_t npages; + int error; + int ents; + int ret; + int i; + DEFINE_DMA_ATTRS(attrs); + + error = priv_check(curthread, PRIV_VM_MLOCK); + if (error) + return ERR_PTR(-error); + + last = addr + size; + start = addr & PAGE_MASK; /* Use the linux PAGE_MASK definition. */ + end = roundup2(last, PAGE_SIZE); /* Use PAGE_MASK safe operation. */ + if (last < addr || end < addr) + return ERR_PTR(-EINVAL); + npages = atop(end - start); + if (npages > vm_page_max_wired) + return ERR_PTR(-ENOMEM); + umem = kzalloc(sizeof *umem, GFP_KERNEL); + if (!umem) + return ERR_PTR(-ENOMEM); + proc = curthread->td_proc; + PROC_LOCK(proc); + if (ptoa(npages + + pmap_wired_count(vm_map_pmap(&proc->p_vmspace->vm_map))) > + lim_cur(proc, RLIMIT_MEMLOCK)) { + PROC_UNLOCK(proc); + kfree(umem); + return ERR_PTR(-ENOMEM); + } + PROC_UNLOCK(proc); + if (npages + cnt.v_wire_count > vm_page_max_wired) { + kfree(umem); + return ERR_PTR(-EAGAIN); + } + error = vm_map_wire(&proc->p_vmspace->vm_map, start, end, + VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES | + (umem->writable ? VM_MAP_WIRE_WRITE : 0)); + if (error != KERN_SUCCESS) { + kfree(umem); + return ERR_PTR(-ENOMEM); + } + + umem->context = context; + umem->length = size; + umem->offset = addr & ~PAGE_MASK; + umem->page_size = PAGE_SIZE; + umem->start = addr; + /* + * We ask for writable memory if any access flags other than + * "remote read" are set. "Local write" and "remote write" + * obviously require write access. "Remote atomic" can do + * things like fetch and add, which will modify memory, and + * "MW bind" can change permissions by binding a window. + */ + umem->writable = !!(access & ~IB_ACCESS_REMOTE_READ); + umem->hugetlb = 0; + INIT_LIST_HEAD(&umem->chunk_list); + + pmap = vm_map_pmap(&proc->p_vmspace->vm_map); + ret = 0; + while (npages) { + ents = min_t(int, npages, IB_UMEM_MAX_PAGE_CHUNK); + chunk = kmalloc(sizeof(*chunk) + + (sizeof(struct scatterlist) * ents), + GFP_KERNEL); + if (!chunk) { + ret = -ENOMEM; + goto out; + } + + chunk->attrs = attrs; + chunk->nents = ents; + sg_init_table(&chunk->page_list[0], ents); + for (i = 0; i < chunk->nents; ++i) { + vm_paddr_t pa; + + pa = pmap_extract(pmap, start); + if (pa == 0) { + ret = -ENOMEM; + kfree(chunk); + goto out; + } + sg_set_page(&chunk->page_list[i], PHYS_TO_VM_PAGE(pa), + PAGE_SIZE, 0); + npages--; + start += PAGE_SIZE; + } + + chunk->nmap = ib_dma_map_sg_attrs(context->device, + &chunk->page_list[0], + chunk->nents, + DMA_BIDIRECTIONAL, + &attrs); + if (chunk->nmap != chunk->nents) { + kfree(chunk); + ret = -ENOMEM; + goto out; + } + + list_add_tail(&chunk->list, &umem->chunk_list); + } + +out: + if (ret < 0) { + __ib_umem_release(context->device, umem, 0); + kfree(umem); + } + + return ret < 0 ? ERR_PTR(ret) : umem; +#endif +} +EXPORT_SYMBOL(ib_umem_get); + +#ifdef __linux__ +static void ib_umem_account(struct work_struct *work) +{ + struct ib_umem *umem = container_of(work, struct ib_umem, work); + + down_write(&umem->mm->mmap_sem); + umem->mm->locked_vm -= umem->diff; + up_write(&umem->mm->mmap_sem); + mmput(umem->mm); + kfree(umem); +} +#endif + +/** + * ib_umem_release - release memory pinned with ib_umem_get + * @umem: umem struct to release + */ +void ib_umem_release(struct ib_umem *umem) +{ +#ifdef __linux__ + struct ib_ucontext *context = umem->context; + struct mm_struct *mm; + unsigned long diff; + + __ib_umem_release(umem->context->device, umem, 1); + + mm = get_task_mm(current); + if (!mm) { + kfree(umem); + return; + } + + diff = PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT; + + /* + * We may be called with the mm's mmap_sem already held. This + * can happen when a userspace munmap() is the call that drops + * the last reference to our file and calls our release + * method. If there are memory regions to destroy, we'll end + * up here and not be able to take the mmap_sem. In that case + * we defer the vm_locked accounting to the system workqueue. + */ + if (context->closing) { + if (!down_write_trylock(&mm->mmap_sem)) { + INIT_WORK(&umem->work, ib_umem_account); + umem->mm = mm; + umem->diff = diff; + + schedule_work(&umem->work); + return; + } + } else + down_write(&mm->mmap_sem); + + current->mm->locked_vm -= diff; + up_write(&mm->mmap_sem); + mmput(mm); +#else + vm_offset_t addr, end, last, start; + vm_size_t size; + int error; + + __ib_umem_release(umem->context->device, umem, 1); + if (umem->context->closing) { + kfree(umem); + return; + } + error = priv_check(curthread, PRIV_VM_MUNLOCK); + if (error) + return; + addr = umem->start; + size = umem->length; + last = addr + size; + start = addr & PAGE_MASK; /* Use the linux PAGE_MASK definition. */ + end = roundup2(last, PAGE_SIZE); /* Use PAGE_MASK safe operation. */ + vm_map_unwire(&curthread->td_proc->p_vmspace->vm_map, start, end, + VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); + +#endif + kfree(umem); +} +EXPORT_SYMBOL(ib_umem_release); + +int ib_umem_page_count(struct ib_umem *umem) +{ + struct ib_umem_chunk *chunk; + int shift; + int i; + int n; + + shift = ilog2(umem->page_size); + + n = 0; + list_for_each_entry(chunk, &umem->chunk_list, list) + for (i = 0; i < chunk->nmap; ++i) + n += sg_dma_len(&chunk->page_list[i]) >> shift; + + return n; +} +EXPORT_SYMBOL(ib_umem_page_count); diff --git a/sys/ofed/drivers/infiniband/core/user_mad.c b/sys/ofed/drivers/infiniband/core/user_mad.c new file mode 100644 index 000000000000..3dae9ce6cd84 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/user_mad.c @@ -0,0 +1,1225 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Cisco. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +MODULE_AUTHOR("Roland Dreier"); +MODULE_DESCRIPTION("InfiniBand userspace MAD packet access"); +MODULE_LICENSE("Dual BSD/GPL"); + +enum { + IB_UMAD_MAX_PORTS = 64, + IB_UMAD_MAX_AGENTS = 32, + + IB_UMAD_MAJOR = 231, + IB_UMAD_MINOR_BASE = 0 +}; + +/* + * Our lifetime rules for these structs are the following: each time a + * device special file is opened, we look up the corresponding struct + * ib_umad_port by minor in the umad_port[] table while holding the + * port_lock. If this lookup succeeds, we take a reference on the + * ib_umad_port's struct ib_umad_device while still holding the + * port_lock; if the lookup fails, we fail the open(). We drop these + * references in the corresponding close(). + * + * In addition to references coming from open character devices, there + * is one more reference to each ib_umad_device representing the + * module's reference taken when allocating the ib_umad_device in + * ib_umad_add_one(). + * + * When destroying an ib_umad_device, we clear all of its + * ib_umad_ports from umad_port[] while holding port_lock before + * dropping the module's reference to the ib_umad_device. This is + * always safe because any open() calls will either succeed and obtain + * a reference before we clear the umad_port[] entries, or fail after + * we clear the umad_port[] entries. + */ + +struct ib_umad_port { + struct cdev *cdev; + struct device *dev; + + struct cdev *sm_cdev; + struct device *sm_dev; + struct semaphore sm_sem; + + struct mutex file_mutex; + struct list_head file_list; + + struct ib_device *ib_dev; + struct ib_umad_device *umad_dev; + int dev_num; + u8 port_num; +}; + +struct ib_umad_device { + int start_port, end_port; + struct kref ref; + struct ib_umad_port port[0]; +}; + +struct ib_umad_file { + struct mutex mutex; + struct ib_umad_port *port; + struct file *filp; + struct list_head recv_list; + struct list_head send_list; + struct list_head port_list; + spinlock_t send_lock; + wait_queue_head_t recv_wait; + struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS]; + int agents_dead; + u8 use_pkey_index; + u8 already_used; +}; + +struct ib_umad_packet { + struct ib_mad_send_buf *msg; + struct ib_mad_recv_wc *recv_wc; + struct list_head list; + int length; + struct ib_user_mad mad; +}; + +static struct class *umad_class; + +static const dev_t base_dev = MKDEV(IB_UMAD_MAJOR, IB_UMAD_MINOR_BASE); + +static DEFINE_SPINLOCK(port_lock); +static struct ib_umad_port *umad_port[IB_UMAD_MAX_PORTS]; +static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS); + +static void ib_umad_add_one(struct ib_device *device); +static void ib_umad_remove_one(struct ib_device *device); + +static void ib_umad_release_dev(struct kref *ref) +{ + struct ib_umad_device *dev = + container_of(ref, struct ib_umad_device, ref); + + kfree(dev); +} + +static int hdr_size(struct ib_umad_file *file) +{ + return file->use_pkey_index ? sizeof (struct ib_user_mad_hdr) : + sizeof (struct ib_user_mad_hdr_old); +} + +/* caller must hold file->mutex */ +static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id) +{ + return file->agents_dead ? NULL : file->agent[id]; +} + +static int queue_packet(struct ib_umad_file *file, + struct ib_mad_agent *agent, + struct ib_umad_packet *packet) +{ + int ret = 1; + + mutex_lock(&file->mutex); + + for (packet->mad.hdr.id = 0; + packet->mad.hdr.id < IB_UMAD_MAX_AGENTS; + packet->mad.hdr.id++) + if (agent == __get_agent(file, packet->mad.hdr.id)) { + list_add_tail(&packet->list, &file->recv_list); + selwakeup(&file->filp->f_selinfo); + wake_up_interruptible(&file->recv_wait); + ret = 0; + break; + } + + mutex_unlock(&file->mutex); + + return ret; +} + +static void dequeue_send(struct ib_umad_file *file, + struct ib_umad_packet *packet) +{ + spin_lock_irq(&file->send_lock); + list_del(&packet->list); + spin_unlock_irq(&file->send_lock); +} + +static void send_handler(struct ib_mad_agent *agent, + struct ib_mad_send_wc *send_wc) +{ + struct ib_umad_file *file = agent->context; + struct ib_umad_packet *packet = send_wc->send_buf->context[0]; + + dequeue_send(file, packet); + ib_destroy_ah(packet->msg->ah); + ib_free_send_mad(packet->msg); + + if (send_wc->status == IB_WC_RESP_TIMEOUT_ERR) { + packet->length = IB_MGMT_MAD_HDR; + packet->mad.hdr.status = ETIMEDOUT; + if (!queue_packet(file, agent, packet)) + return; + } + kfree(packet); +} + +static void recv_handler(struct ib_mad_agent *agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_umad_file *file = agent->context; + struct ib_umad_packet *packet; + + if (mad_recv_wc->wc->status != IB_WC_SUCCESS) + goto err1; + + packet = kzalloc(sizeof *packet, GFP_KERNEL); + if (!packet) + goto err1; + + packet->length = mad_recv_wc->mad_len; + packet->recv_wc = mad_recv_wc; + + packet->mad.hdr.status = 0; + packet->mad.hdr.length = hdr_size(file) + mad_recv_wc->mad_len; + packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp); + packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid); + packet->mad.hdr.sl = mad_recv_wc->wc->sl; + packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits; + packet->mad.hdr.pkey_index = mad_recv_wc->wc->pkey_index; + packet->mad.hdr.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH); + if (packet->mad.hdr.grh_present) { + struct ib_ah_attr ah_attr; + + ib_init_ah_from_wc(agent->device, agent->port_num, + mad_recv_wc->wc, mad_recv_wc->recv_buf.grh, + &ah_attr); + + packet->mad.hdr.gid_index = ah_attr.grh.sgid_index; + packet->mad.hdr.hop_limit = ah_attr.grh.hop_limit; + packet->mad.hdr.traffic_class = ah_attr.grh.traffic_class; + memcpy(packet->mad.hdr.gid, &ah_attr.grh.dgid, 16); + packet->mad.hdr.flow_label = cpu_to_be32(ah_attr.grh.flow_label); + } + + if (queue_packet(file, agent, packet)) + goto err2; + return; + +err2: + kfree(packet); +err1: + ib_free_recv_mad(mad_recv_wc); +} + +static ssize_t copy_recv_mad(struct ib_umad_file *file, char __user *buf, + struct ib_umad_packet *packet, size_t count) +{ + struct ib_mad_recv_buf *recv_buf; + int left, seg_payload, offset, max_seg_payload; + + /* We need enough room to copy the first (or only) MAD segment. */ + recv_buf = &packet->recv_wc->recv_buf; + if ((packet->length <= sizeof (*recv_buf->mad) && + count < hdr_size(file) + packet->length) || + (packet->length > sizeof (*recv_buf->mad) && + count < hdr_size(file) + sizeof (*recv_buf->mad))) + return -EINVAL; + + if (copy_to_user(buf, &packet->mad, hdr_size(file))) + return -EFAULT; + + buf += hdr_size(file); + seg_payload = min_t(int, packet->length, sizeof (*recv_buf->mad)); + if (copy_to_user(buf, recv_buf->mad, seg_payload)) + return -EFAULT; + + if (seg_payload < packet->length) { + /* + * Multipacket RMPP MAD message. Copy remainder of message. + * Note that last segment may have a shorter payload. + */ + if (count < hdr_size(file) + packet->length) { + /* + * The buffer is too small, return the first RMPP segment, + * which includes the RMPP message length. + */ + return -ENOSPC; + } + offset = ib_get_mad_data_offset(recv_buf->mad->mad_hdr.mgmt_class); + max_seg_payload = sizeof (struct ib_mad) - offset; + + for (left = packet->length - seg_payload, buf += seg_payload; + left; left -= seg_payload, buf += seg_payload) { + recv_buf = container_of(recv_buf->list.next, + struct ib_mad_recv_buf, list); + seg_payload = min(left, max_seg_payload); + if (copy_to_user(buf, ((void *) recv_buf->mad) + offset, + seg_payload)) + return -EFAULT; + } + } + return hdr_size(file) + packet->length; +} + +static ssize_t copy_send_mad(struct ib_umad_file *file, char __user *buf, + struct ib_umad_packet *packet, size_t count) +{ + ssize_t size = hdr_size(file) + packet->length; + + if (count < size) + return -EINVAL; + + if (copy_to_user(buf, &packet->mad, hdr_size(file))) + return -EFAULT; + + buf += hdr_size(file); + + if (copy_to_user(buf, packet->mad.data, packet->length)) + return -EFAULT; + + return size; +} + +static ssize_t ib_umad_read(struct file *filp, char __user *buf, + size_t count, loff_t *pos) +{ + struct ib_umad_file *file = filp->private_data; + struct ib_umad_packet *packet; + ssize_t ret; + + if (count < hdr_size(file)) + return -EINVAL; + + mutex_lock(&file->mutex); + + while (list_empty(&file->recv_list)) { + mutex_unlock(&file->mutex); + + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + + if (wait_event_interruptible(file->recv_wait, + !list_empty(&file->recv_list))) + return -ERESTARTSYS; + + mutex_lock(&file->mutex); + } + + packet = list_entry(file->recv_list.next, struct ib_umad_packet, list); + list_del(&packet->list); + + mutex_unlock(&file->mutex); + + if (packet->recv_wc) + ret = copy_recv_mad(file, buf, packet, count); + else + ret = copy_send_mad(file, buf, packet, count); + + if (ret < 0) { + /* Requeue packet */ + mutex_lock(&file->mutex); + list_add(&packet->list, &file->recv_list); + mutex_unlock(&file->mutex); + } else { + if (packet->recv_wc) + ib_free_recv_mad(packet->recv_wc); + kfree(packet); + } + return ret; +} + +static int copy_rmpp_mad(struct ib_mad_send_buf *msg, const char __user *buf) +{ + int left, seg; + + /* Copy class specific header */ + if ((msg->hdr_len > IB_MGMT_RMPP_HDR) && + copy_from_user(msg->mad + IB_MGMT_RMPP_HDR, buf + IB_MGMT_RMPP_HDR, + msg->hdr_len - IB_MGMT_RMPP_HDR)) + return -EFAULT; + + /* All headers are in place. Copy data segments. */ + for (seg = 1, left = msg->data_len, buf += msg->hdr_len; left > 0; + seg++, left -= msg->seg_size, buf += msg->seg_size) { + if (copy_from_user(ib_get_rmpp_segment(msg, seg), buf, + min(left, msg->seg_size))) + return -EFAULT; + } + return 0; +} + +static int same_destination(struct ib_user_mad_hdr *hdr1, + struct ib_user_mad_hdr *hdr2) +{ + if (!hdr1->grh_present && !hdr2->grh_present) + return (hdr1->lid == hdr2->lid); + + if (hdr1->grh_present && hdr2->grh_present) + return !memcmp(hdr1->gid, hdr2->gid, 16); + + return 0; +} + +static int is_duplicate(struct ib_umad_file *file, + struct ib_umad_packet *packet) +{ + struct ib_umad_packet *sent_packet; + struct ib_mad_hdr *sent_hdr, *hdr; + + hdr = (struct ib_mad_hdr *) packet->mad.data; + list_for_each_entry(sent_packet, &file->send_list, list) { + sent_hdr = (struct ib_mad_hdr *) sent_packet->mad.data; + + if ((hdr->tid != sent_hdr->tid) || + (hdr->mgmt_class != sent_hdr->mgmt_class)) + continue; + + /* + * No need to be overly clever here. If two new operations have + * the same TID, reject the second as a duplicate. This is more + * restrictive than required by the spec. + */ + if (!ib_response_mad((struct ib_mad *) hdr)) { + if (!ib_response_mad((struct ib_mad *) sent_hdr)) + return 1; + continue; + } else if (!ib_response_mad((struct ib_mad *) sent_hdr)) + continue; + + if (same_destination(&packet->mad.hdr, &sent_packet->mad.hdr)) + return 1; + } + + return 0; +} + +static ssize_t ib_umad_write(struct file *filp, const char __user *buf, + size_t count, loff_t *pos) +{ + struct ib_umad_file *file = filp->private_data; + struct ib_umad_packet *packet; + struct ib_mad_agent *agent; + struct ib_ah_attr ah_attr; + struct ib_ah *ah; + struct ib_rmpp_mad *rmpp_mad; + __be64 *tid; + int ret, data_len, hdr_len, copy_offset, rmpp_active; + + if (count < hdr_size(file) + IB_MGMT_RMPP_HDR) + return -EINVAL; + + packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL); + if (!packet) + return -ENOMEM; + + if (copy_from_user(&packet->mad, buf, hdr_size(file))) { + ret = -EFAULT; + goto err; + } + + if (packet->mad.hdr.id < 0 || + packet->mad.hdr.id >= IB_UMAD_MAX_AGENTS) { + ret = -EINVAL; + goto err; + } + + buf += hdr_size(file); + + if (copy_from_user(packet->mad.data, buf, IB_MGMT_RMPP_HDR)) { + ret = -EFAULT; + goto err; + } + + mutex_lock(&file->mutex); + + agent = __get_agent(file, packet->mad.hdr.id); + if (!agent) { + ret = -EINVAL; + goto err_up; + } + + memset(&ah_attr, 0, sizeof ah_attr); + ah_attr.dlid = be16_to_cpu(packet->mad.hdr.lid); + ah_attr.sl = packet->mad.hdr.sl; + ah_attr.src_path_bits = packet->mad.hdr.path_bits; + ah_attr.port_num = file->port->port_num; + if (packet->mad.hdr.grh_present) { + ah_attr.ah_flags = IB_AH_GRH; + memcpy(ah_attr.grh.dgid.raw, packet->mad.hdr.gid, 16); + ah_attr.grh.sgid_index = packet->mad.hdr.gid_index; + ah_attr.grh.flow_label = be32_to_cpu(packet->mad.hdr.flow_label); + ah_attr.grh.hop_limit = packet->mad.hdr.hop_limit; + ah_attr.grh.traffic_class = packet->mad.hdr.traffic_class; + } + + ah = ib_create_ah(agent->qp->pd, &ah_attr); + if (IS_ERR(ah)) { + ret = PTR_ERR(ah); + goto err_up; + } + + rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data; + hdr_len = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class); + if (!ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class)) { + copy_offset = IB_MGMT_MAD_HDR; + rmpp_active = 0; + } else { + copy_offset = IB_MGMT_RMPP_HDR; + rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & + IB_MGMT_RMPP_FLAG_ACTIVE; + } + + data_len = count - hdr_size(file) - hdr_len; + packet->msg = ib_create_send_mad(agent, + be32_to_cpu(packet->mad.hdr.qpn), + packet->mad.hdr.pkey_index, rmpp_active, + hdr_len, data_len, GFP_KERNEL); + if (IS_ERR(packet->msg)) { + ret = PTR_ERR(packet->msg); + goto err_ah; + } + + packet->msg->ah = ah; + packet->msg->timeout_ms = packet->mad.hdr.timeout_ms; + packet->msg->retries = packet->mad.hdr.retries; + packet->msg->context[0] = packet; + + /* Copy MAD header. Any RMPP header is already in place. */ + memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR); + + if (!rmpp_active) { + if (copy_from_user(packet->msg->mad + copy_offset, + buf + copy_offset, + hdr_len + data_len - copy_offset)) { + ret = -EFAULT; + goto err_msg; + } + } else { + ret = copy_rmpp_mad(packet->msg, buf); + if (ret) + goto err_msg; + } + + /* + * Set the high-order part of the transaction ID to make MADs from + * different agents unique, and allow routing responses back to the + * original requestor. + */ + if (!ib_response_mad(packet->msg->mad)) { + tid = &((struct ib_mad_hdr *) packet->msg->mad)->tid; + *tid = cpu_to_be64(((u64) agent->hi_tid) << 32 | + (be64_to_cpup(tid) & 0xffffffff)); + rmpp_mad->mad_hdr.tid = *tid; + } + + spin_lock_irq(&file->send_lock); + ret = is_duplicate(file, packet); + if (!ret) + list_add_tail(&packet->list, &file->send_list); + spin_unlock_irq(&file->send_lock); + if (ret) { + ret = -EINVAL; + goto err_msg; + } + + ret = ib_post_send_mad(packet->msg, NULL); + if (ret) + goto err_send; + + mutex_unlock(&file->mutex); + return count; + +err_send: + dequeue_send(file, packet); +err_msg: + ib_free_send_mad(packet->msg); +err_ah: + ib_destroy_ah(ah); +err_up: + mutex_unlock(&file->mutex); +err: + kfree(packet); + return ret; +} + +static unsigned int ib_umad_poll(struct file *filp, struct poll_table_struct *wait) +{ + struct ib_umad_file *file = filp->private_data; + + /* we will always be able to post a MAD send */ + unsigned int mask = POLLOUT | POLLWRNORM; + + poll_wait(filp, &file->recv_wait, wait); + + if (!list_empty(&file->recv_list)) + mask |= POLLIN | POLLRDNORM; + + return mask; +} + +static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg, + int compat_method_mask) +{ + struct ib_user_mad_reg_req ureq; + struct ib_mad_reg_req req; + struct ib_mad_agent *agent = NULL; + int agent_id; + int ret; + + mutex_lock(&file->port->file_mutex); + mutex_lock(&file->mutex); + + if (!file->port->ib_dev) { + ret = -EPIPE; + goto out; + } + + if (copy_from_user(&ureq, arg, sizeof ureq)) { + ret = -EFAULT; + goto out; + } + + if (ureq.qpn != 0 && ureq.qpn != 1) { + ret = -EINVAL; + goto out; + } + + for (agent_id = 0; agent_id < IB_UMAD_MAX_AGENTS; ++agent_id) + if (!__get_agent(file, agent_id)) + goto found; + + ret = -ENOMEM; + goto out; + +found: + if (ureq.mgmt_class) { + req.mgmt_class = ureq.mgmt_class; + req.mgmt_class_version = ureq.mgmt_class_version; + memcpy(req.oui, ureq.oui, sizeof req.oui); + + if (compat_method_mask) { + u32 *umm = (u32 *) ureq.method_mask; + int i; + + for (i = 0; i < BITS_TO_LONGS(IB_MGMT_MAX_METHODS); ++i) + req.method_mask[i] = + umm[i * 2] | ((u64) umm[i * 2 + 1] << 32); + } else + memcpy(req.method_mask, ureq.method_mask, + sizeof req.method_mask); + } + + agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num, + ureq.qpn ? IB_QPT_GSI : IB_QPT_SMI, + ureq.mgmt_class ? &req : NULL, + ureq.rmpp_version, + send_handler, recv_handler, file); + if (IS_ERR(agent)) { + ret = PTR_ERR(agent); + agent = NULL; + goto out; + } + + if (put_user(agent_id, + (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) { + ret = -EFAULT; + goto out; + } + + if (!file->already_used) { + file->already_used = 1; + if (!file->use_pkey_index) { + printk(KERN_WARNING "user_mad: process %s did not enable " + "P_Key index support.\n", curproc->p_comm); + printk(KERN_WARNING "user_mad: Documentation/infiniband/user_mad.txt " + "has info on the new ABI.\n"); + } + } + + file->agent[agent_id] = agent; + ret = 0; + +out: + mutex_unlock(&file->mutex); + + if (ret && agent) + ib_unregister_mad_agent(agent); + + mutex_unlock(&file->port->file_mutex); + + return ret; +} + +static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg) +{ + struct ib_mad_agent *agent = NULL; + u32 id; + int ret = 0; + + if (get_user(id, arg)) + return -EFAULT; + + mutex_lock(&file->port->file_mutex); + mutex_lock(&file->mutex); + + if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) { + ret = -EINVAL; + goto out; + } + + agent = file->agent[id]; + file->agent[id] = NULL; + +out: + mutex_unlock(&file->mutex); + + if (agent) + ib_unregister_mad_agent(agent); + + mutex_unlock(&file->port->file_mutex); + + return ret; +} + +static long ib_umad_enable_pkey(struct ib_umad_file *file) +{ + int ret = 0; + + mutex_lock(&file->mutex); + if (file->already_used) + ret = -EINVAL; + else + file->use_pkey_index = 1; + mutex_unlock(&file->mutex); + + return ret; +} + +static long ib_umad_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case IB_USER_MAD_REGISTER_AGENT: + return ib_umad_reg_agent(filp->private_data, (void __user *) arg, 0); + case IB_USER_MAD_UNREGISTER_AGENT: + return ib_umad_unreg_agent(filp->private_data, (__u32 __user *) arg); + case IB_USER_MAD_ENABLE_PKEY: + return ib_umad_enable_pkey(filp->private_data); + default: + return -ENOIOCTLCMD; + } +} + +#ifdef CONFIG_COMPAT +static long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case IB_USER_MAD_REGISTER_AGENT: + return ib_umad_reg_agent(filp->private_data, compat_ptr(arg), 1); + case IB_USER_MAD_UNREGISTER_AGENT: + return ib_umad_unreg_agent(filp->private_data, compat_ptr(arg)); + case IB_USER_MAD_ENABLE_PKEY: + return ib_umad_enable_pkey(filp->private_data); + default: + return -ENOIOCTLCMD; + } +} +#endif + +/* + * ib_umad_open() does not need the BKL: + * + * - umad_port[] accesses are protected by port_lock, the + * ib_umad_port structures are properly reference counted, and + * everything else is purely local to the file being created, so + * races against other open calls are not a problem; + * - the ioctl method does not affect any global state outside of the + * file structure being operated on; + * - the port is added to umad_port[] as the last part of module + * initialization so the open method will either immediately run + * -ENXIO, or all required initialization will be done. + */ +static int ib_umad_open(struct inode *inode, struct file *filp) +{ + struct ib_umad_port *port; + struct ib_umad_file *file; + int ret = 0; + + spin_lock(&port_lock); + port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE]; + if (port) + kref_get(&port->umad_dev->ref); + spin_unlock(&port_lock); + + if (!port) + return -ENXIO; + + mutex_lock(&port->file_mutex); + + if (!port->ib_dev) { + ret = -ENXIO; + goto out; + } + + file = kzalloc(sizeof *file, GFP_KERNEL); + if (!file) { + kref_put(&port->umad_dev->ref, ib_umad_release_dev); + ret = -ENOMEM; + goto out; + } + + mutex_init(&file->mutex); + spin_lock_init(&file->send_lock); + INIT_LIST_HEAD(&file->recv_list); + INIT_LIST_HEAD(&file->send_list); + init_waitqueue_head(&file->recv_wait); + + file->port = port; + file->filp = filp; + filp->private_data = file; + + list_add_tail(&file->port_list, &port->file_list); + +out: + mutex_unlock(&port->file_mutex); + return ret; +} + +static int ib_umad_close(struct inode *inode, struct file *filp) +{ + struct ib_umad_file *file = filp->private_data; + struct ib_umad_device *dev = file->port->umad_dev; + struct ib_umad_packet *packet, *tmp; + int already_dead; + int i; + + mutex_lock(&file->port->file_mutex); + mutex_lock(&file->mutex); + + already_dead = file->agents_dead; + file->agents_dead = 1; + + list_for_each_entry_safe(packet, tmp, &file->recv_list, list) { + if (packet->recv_wc) + ib_free_recv_mad(packet->recv_wc); + kfree(packet); + } + + list_del(&file->port_list); + + mutex_unlock(&file->mutex); + + if (!already_dead) + for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i) + if (file->agent[i]) + ib_unregister_mad_agent(file->agent[i]); + + mutex_unlock(&file->port->file_mutex); + + kfree(file); + kref_put(&dev->ref, ib_umad_release_dev); + + return 0; +} + +static const struct file_operations umad_fops = { + .owner = THIS_MODULE, + .read = ib_umad_read, + .write = ib_umad_write, + .poll = ib_umad_poll, + .unlocked_ioctl = ib_umad_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ib_umad_compat_ioctl, +#endif + .open = ib_umad_open, + .release = ib_umad_close +}; + +static int ib_umad_sm_open(struct inode *inode, struct file *filp) +{ + struct ib_umad_port *port; + struct ib_port_modify props = { + .set_port_cap_mask = IB_PORT_SM + }; + int ret; + + spin_lock(&port_lock); + port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE - IB_UMAD_MAX_PORTS]; + if (port) + kref_get(&port->umad_dev->ref); + spin_unlock(&port_lock); + + if (!port) + return -ENXIO; + + if (filp->f_flags & O_NONBLOCK) { + if (down_trylock(&port->sm_sem)) { + ret = -EAGAIN; + goto fail; + } + } else { + if (down_interruptible(&port->sm_sem)) { + ret = -ERESTARTSYS; + goto fail; + } + } + + ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props); + if (ret) { + up(&port->sm_sem); + goto fail; + } + + filp->private_data = port; + + return 0; + +fail: + kref_put(&port->umad_dev->ref, ib_umad_release_dev); + return ret; +} + +static int ib_umad_sm_close(struct inode *inode, struct file *filp) +{ + struct ib_umad_port *port = filp->private_data; + struct ib_port_modify props = { + .clr_port_cap_mask = IB_PORT_SM + }; + int ret = 0; + + mutex_lock(&port->file_mutex); + if (port->ib_dev) + ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props); + mutex_unlock(&port->file_mutex); + + up(&port->sm_sem); + + kref_put(&port->umad_dev->ref, ib_umad_release_dev); + + return ret; +} + +static const struct file_operations umad_sm_fops = { + .owner = THIS_MODULE, + .open = ib_umad_sm_open, + .release = ib_umad_sm_close +}; + +static struct ib_client umad_client = { + .name = "umad", + .add = ib_umad_add_one, + .remove = ib_umad_remove_one +}; + +static ssize_t show_ibdev(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ib_umad_port *port = dev_get_drvdata(dev); + + if (!port) + return -ENODEV; + + return sprintf(buf, "%s\n", port->ib_dev->name); +} +static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); + +static ssize_t show_port(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ib_umad_port *port = dev_get_drvdata(dev); + + if (!port) + return -ENODEV; + + return sprintf(buf, "%d\n", port->port_num); +} +static DEVICE_ATTR(port, S_IRUGO, show_port, NULL); + +static ssize_t show_abi_version(struct class *class, char *buf) +{ + return sprintf(buf, "%d\n", IB_USER_MAD_ABI_VERSION); +} +static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); + +static int ib_umad_init_port(struct ib_device *device, int port_num, + struct ib_umad_port *port) +{ + spin_lock(&port_lock); + port->dev_num = find_first_zero_bit(dev_map, IB_UMAD_MAX_PORTS); + if (port->dev_num >= IB_UMAD_MAX_PORTS) { + spin_unlock(&port_lock); + return -1; + } + set_bit(port->dev_num, dev_map); + spin_unlock(&port_lock); + + port->ib_dev = device; + port->port_num = port_num; + init_MUTEX(&port->sm_sem); + mutex_init(&port->file_mutex); + INIT_LIST_HEAD(&port->file_list); + + port->cdev = cdev_alloc(); + if (!port->cdev) + return -1; + port->cdev->owner = THIS_MODULE; + port->cdev->ops = &umad_fops; + kobject_set_name(&port->cdev->kobj, "umad%d", port->dev_num); + if (cdev_add(port->cdev, base_dev + port->dev_num, 1)) + goto err_cdev; + + port->dev = device_create(umad_class, device->dma_device, + port->cdev->dev, port, + "umad%d", port->dev_num); + if (IS_ERR(port->dev)) + goto err_cdev; + + if (device_create_file(port->dev, &dev_attr_ibdev)) + goto err_dev; + if (device_create_file(port->dev, &dev_attr_port)) + goto err_dev; + + port->sm_cdev = cdev_alloc(); + if (!port->sm_cdev) + goto err_dev; + port->sm_cdev->owner = THIS_MODULE; + port->sm_cdev->ops = &umad_sm_fops; + kobject_set_name(&port->sm_cdev->kobj, "issm%d", port->dev_num); + if (cdev_add(port->sm_cdev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1)) + goto err_sm_cdev; + + port->sm_dev = device_create(umad_class, device->dma_device, + port->sm_cdev->dev, port, + "issm%d", port->dev_num); + if (IS_ERR(port->sm_dev)) + goto err_sm_cdev; + + if (device_create_file(port->sm_dev, &dev_attr_ibdev)) + goto err_sm_dev; + if (device_create_file(port->sm_dev, &dev_attr_port)) + goto err_sm_dev; + + spin_lock(&port_lock); + umad_port[port->dev_num] = port; + spin_unlock(&port_lock); + + return 0; + +err_sm_dev: + device_destroy(umad_class, port->sm_cdev->dev); + +err_sm_cdev: + cdev_del(port->sm_cdev); + +err_dev: + device_destroy(umad_class, port->cdev->dev); + +err_cdev: + cdev_del(port->cdev); + clear_bit(port->dev_num, dev_map); + + return -1; +} + +static void ib_umad_kill_port(struct ib_umad_port *port) +{ + struct ib_umad_file *file; + int already_dead; + int id; + + dev_set_drvdata(port->dev, NULL); + dev_set_drvdata(port->sm_dev, NULL); + + device_destroy(umad_class, port->cdev->dev); + device_destroy(umad_class, port->sm_cdev->dev); + + cdev_del(port->cdev); + cdev_del(port->sm_cdev); + + spin_lock(&port_lock); + umad_port[port->dev_num] = NULL; + spin_unlock(&port_lock); + + mutex_lock(&port->file_mutex); + + port->ib_dev = NULL; + + list_for_each_entry(file, &port->file_list, port_list) { + mutex_lock(&file->mutex); + already_dead = file->agents_dead; + file->agents_dead = 1; + mutex_unlock(&file->mutex); + + for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id) + if (file->agent[id]) + ib_unregister_mad_agent(file->agent[id]); + } + + mutex_unlock(&port->file_mutex); + + clear_bit(port->dev_num, dev_map); +} + +static void ib_umad_add_one(struct ib_device *device) +{ + struct ib_umad_device *umad_dev; + int s, e, i; + + if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) + return; + + if (device->node_type == RDMA_NODE_IB_SWITCH) + s = e = 0; + else { + s = 1; + e = device->phys_port_cnt; + } + + umad_dev = kzalloc(sizeof *umad_dev + + (e - s + 1) * sizeof (struct ib_umad_port), + GFP_KERNEL); + if (!umad_dev) + return; + + kref_init(&umad_dev->ref); + + umad_dev->start_port = s; + umad_dev->end_port = e; + + for (i = s; i <= e; ++i) { + umad_dev->port[i - s].umad_dev = umad_dev; + + if (rdma_port_get_link_layer(device, i) == IB_LINK_LAYER_INFINIBAND) + if (ib_umad_init_port(device, i, &umad_dev->port[i - s])) + goto err; + } + + ib_set_client_data(device, &umad_client, umad_dev); + + return; + +err: + while (--i >= s) + if (rdma_port_get_link_layer(device, i) == IB_LINK_LAYER_INFINIBAND) + ib_umad_kill_port(&umad_dev->port[i - s]); + + kref_put(&umad_dev->ref, ib_umad_release_dev); +} + +static void ib_umad_remove_one(struct ib_device *device) +{ + struct ib_umad_device *umad_dev = ib_get_client_data(device, &umad_client); + int i; + + if (!umad_dev) + return; + + for (i = 0; i <= umad_dev->end_port - umad_dev->start_port; ++i) + if (rdma_port_get_link_layer(device, i + 1) == IB_LINK_LAYER_INFINIBAND) + ib_umad_kill_port(&umad_dev->port[i]); + + kref_put(&umad_dev->ref, ib_umad_release_dev); +} + +static int __init ib_umad_init(void) +{ + int ret; + + ret = register_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2, + "infiniband_mad"); + if (ret) { + printk(KERN_ERR "user_mad: couldn't register device number\n"); + goto out; + } + + umad_class = class_create(THIS_MODULE, "infiniband_mad"); + if (IS_ERR(umad_class)) { + ret = PTR_ERR(umad_class); + printk(KERN_ERR "user_mad: couldn't create class infiniband_mad\n"); + goto out_chrdev; + } + + ret = class_create_file(umad_class, &class_attr_abi_version); + if (ret) { + printk(KERN_ERR "user_mad: couldn't create abi_version attribute\n"); + goto out_class; + } + + ret = ib_register_client(&umad_client); + if (ret) { + printk(KERN_ERR "user_mad: couldn't register ib_umad client\n"); + goto out_class; + } + + return 0; + +out_class: + class_destroy(umad_class); + +out_chrdev: + unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2); + +out: + return ret; +} + +static void __exit ib_umad_cleanup(void) +{ + ib_unregister_client(&umad_client); + class_destroy(umad_class); + unregister_chrdev_region(base_dev, IB_UMAD_MAX_PORTS * 2); +} + +module_init(ib_umad_init); +module_exit(ib_umad_cleanup); diff --git a/sys/ofed/drivers/infiniband/core/uverbs.h b/sys/ofed/drivers/infiniband/core/uverbs.h new file mode 100644 index 000000000000..fa64da542b95 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/uverbs.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef UVERBS_H +#define UVERBS_H + +#include +#include +#include +#include + +#include +#include +#include + +/* + * Our lifetime rules for these structs are the following: + * + * struct ib_uverbs_device: One reference is held by the module and + * released in ib_uverbs_remove_one(). Another reference is taken by + * ib_uverbs_open() each time the character special file is opened, + * and released in ib_uverbs_release_file() when the file is released. + * + * struct ib_uverbs_file: One reference is held by the VFS and + * released when the file is closed. Another reference is taken when + * an asynchronous event queue file is created and released when the + * event file is closed. + * + * struct ib_uverbs_event_file: One reference is held by the VFS and + * released when the file is closed. For asynchronous event files, + * another reference is held by the corresponding main context file + * and released when that file is closed. For completion event files, + * a reference is taken when a CQ is created that uses the file, and + * released when the CQ is destroyed. + */ + +struct ib_uverbs_device { + struct kref ref; + struct completion comp; + int devnum; + struct cdev *cdev; + struct device *dev; + struct ib_device *ib_dev; + int num_comp_vectors; +}; + +struct ib_uverbs_event_file { + struct kref ref; + struct file *filp; + struct ib_uverbs_file *uverbs_file; + spinlock_t lock; + wait_queue_head_t poll_wait; + struct fasync_struct *async_queue; + struct list_head event_list; + int is_async; + int is_closed; +}; + +struct ib_uverbs_file { + struct kref ref; + struct mutex mutex; + struct ib_uverbs_device *device; + struct ib_ucontext *ucontext; + struct ib_event_handler event_handler; + struct ib_uverbs_event_file *async_file; +}; + +struct ib_uverbs_event { + union { + struct ib_uverbs_async_event_desc async; + struct ib_uverbs_comp_event_desc comp; + } desc; + struct list_head list; + struct list_head obj_list; + u32 *counter; +}; + +struct ib_uverbs_mcast_entry { + struct list_head list; + union ib_gid gid; + u16 lid; +}; + +struct ib_uevent_object { + struct ib_uobject uobject; + struct list_head event_list; + u32 events_reported; +}; + +struct ib_uqp_object { + struct ib_uevent_object uevent; + struct list_head mcast_list; +}; + +struct ib_ucq_object { + struct ib_uobject uobject; + struct ib_uverbs_file *uverbs_file; + struct list_head comp_list; + struct list_head async_list; + u32 comp_events_reported; + u32 async_events_reported; +}; + +struct ib_uxrcd_object { + struct ib_uobject uobject; + struct list_head xrc_reg_qp_list; +}; + +extern spinlock_t ib_uverbs_idr_lock; +extern struct idr ib_uverbs_pd_idr; +extern struct idr ib_uverbs_mr_idr; +extern struct idr ib_uverbs_mw_idr; +extern struct idr ib_uverbs_ah_idr; +extern struct idr ib_uverbs_cq_idr; +extern struct idr ib_uverbs_qp_idr; +extern struct idr ib_uverbs_srq_idr; +extern struct idr ib_uverbs_xrc_domain_idr; + +void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj); + +struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, + int is_async, int *fd); +struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd); + +void ib_uverbs_release_ucq(struct ib_uverbs_file *file, + struct ib_uverbs_event_file *ev_file, + struct ib_ucq_object *uobj); +void ib_uverbs_release_uevent(struct ib_uverbs_file *file, + struct ib_uevent_object *uobj); + +void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context); +void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr); +void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr); +void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr); +void ib_uverbs_event_handler(struct ib_event_handler *handler, + struct ib_event *event); +void ib_uverbs_xrc_rcv_qp_event_handler(struct ib_event *event, + void *context_ptr); +void ib_uverbs_dealloc_xrcd(struct ib_device *ib_dev, + struct ib_xrcd *xrcd); +int ib_uverbs_cleanup_xrc_rcv_qp(struct ib_uverbs_file *file, + struct ib_xrcd *xrcd, u32 qp_num); + +#define IB_UVERBS_DECLARE_CMD(name) \ + ssize_t ib_uverbs_##name(struct ib_uverbs_file *file, \ + const char __user *buf, int in_len, \ + int out_len) + +IB_UVERBS_DECLARE_CMD(get_context); +IB_UVERBS_DECLARE_CMD(query_device); +IB_UVERBS_DECLARE_CMD(query_port); +IB_UVERBS_DECLARE_CMD(alloc_pd); +IB_UVERBS_DECLARE_CMD(dealloc_pd); +IB_UVERBS_DECLARE_CMD(reg_mr); +IB_UVERBS_DECLARE_CMD(dereg_mr); +IB_UVERBS_DECLARE_CMD(create_comp_channel); +IB_UVERBS_DECLARE_CMD(create_cq); +IB_UVERBS_DECLARE_CMD(resize_cq); +IB_UVERBS_DECLARE_CMD(poll_cq); +IB_UVERBS_DECLARE_CMD(req_notify_cq); +IB_UVERBS_DECLARE_CMD(destroy_cq); +IB_UVERBS_DECLARE_CMD(create_qp); +IB_UVERBS_DECLARE_CMD(query_qp); +IB_UVERBS_DECLARE_CMD(modify_qp); +IB_UVERBS_DECLARE_CMD(destroy_qp); +IB_UVERBS_DECLARE_CMD(post_send); +IB_UVERBS_DECLARE_CMD(post_recv); +IB_UVERBS_DECLARE_CMD(post_srq_recv); +IB_UVERBS_DECLARE_CMD(create_ah); +IB_UVERBS_DECLARE_CMD(destroy_ah); +IB_UVERBS_DECLARE_CMD(attach_mcast); +IB_UVERBS_DECLARE_CMD(detach_mcast); +IB_UVERBS_DECLARE_CMD(create_srq); +IB_UVERBS_DECLARE_CMD(modify_srq); +IB_UVERBS_DECLARE_CMD(query_srq); +IB_UVERBS_DECLARE_CMD(destroy_srq); +IB_UVERBS_DECLARE_CMD(create_xrc_srq); +IB_UVERBS_DECLARE_CMD(open_xrc_domain); +IB_UVERBS_DECLARE_CMD(close_xrc_domain); +IB_UVERBS_DECLARE_CMD(create_xrc_rcv_qp); +IB_UVERBS_DECLARE_CMD(modify_xrc_rcv_qp); +IB_UVERBS_DECLARE_CMD(query_xrc_rcv_qp); +IB_UVERBS_DECLARE_CMD(reg_xrc_rcv_qp); +IB_UVERBS_DECLARE_CMD(unreg_xrc_rcv_qp); + + +#endif /* UVERBS_H */ diff --git a/sys/ofed/drivers/infiniband/core/uverbs_cmd.c b/sys/ofed/drivers/infiniband/core/uverbs_cmd.c new file mode 100644 index 000000000000..3520182a6cec --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/uverbs_cmd.c @@ -0,0 +1,3022 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include +#include + +#include "uverbs.h" + +static struct lock_class_key pd_lock_key; +static struct lock_class_key mr_lock_key; +static struct lock_class_key cq_lock_key; +static struct lock_class_key qp_lock_key; +static struct lock_class_key ah_lock_key; +static struct lock_class_key srq_lock_key; + +#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \ + do { \ + (udata)->inbuf = (void __user *) (ibuf); \ + (udata)->outbuf = (void __user *) (obuf); \ + (udata)->inlen = (ilen); \ + (udata)->outlen = (olen); \ + } while (0) + +/* + * The ib_uobject locking scheme is as follows: + * + * - ib_uverbs_idr_lock protects the uverbs idrs themselves, so it + * needs to be held during all idr operations. When an object is + * looked up, a reference must be taken on the object's kref before + * dropping this lock. + * + * - Each object also has an rwsem. This rwsem must be held for + * reading while an operation that uses the object is performed. + * For example, while registering an MR, the associated PD's + * uobject.mutex must be held for reading. The rwsem must be held + * for writing while initializing or destroying an object. + * + * - In addition, each object has a "live" flag. If this flag is not + * set, then lookups of the object will fail even if it is found in + * the idr. This handles a reader that blocks and does not acquire + * the rwsem until after the object is destroyed. The destroy + * operation will set the live flag to 0 and then drop the rwsem; + * this will allow the reader to acquire the rwsem, see that the + * live flag is 0, and then drop the rwsem and its reference to + * object. The underlying storage will not be freed until the last + * reference to the object is dropped. + */ + +static void init_uobj(struct ib_uobject *uobj, u64 user_handle, + struct ib_ucontext *context, struct lock_class_key *key) +{ + uobj->user_handle = user_handle; + uobj->context = context; + kref_init(&uobj->ref); + init_rwsem(&uobj->mutex); + lockdep_set_class(&uobj->mutex, key); + uobj->live = 0; +} + +static void release_uobj(struct kref *kref) +{ + kfree(container_of(kref, struct ib_uobject, ref)); +} + +static void put_uobj(struct ib_uobject *uobj) +{ + kref_put(&uobj->ref, release_uobj); +} + +static void put_uobj_read(struct ib_uobject *uobj) +{ + up_read(&uobj->mutex); + put_uobj(uobj); +} + +static void put_uobj_write(struct ib_uobject *uobj) +{ + up_write(&uobj->mutex); + put_uobj(uobj); +} + +static int idr_add_uobj(struct idr *idr, struct ib_uobject *uobj) +{ + int ret; + +retry: + if (!idr_pre_get(idr, GFP_KERNEL)) + return -ENOMEM; + + spin_lock(&ib_uverbs_idr_lock); + ret = idr_get_new(idr, uobj, &uobj->id); + spin_unlock(&ib_uverbs_idr_lock); + + if (ret == -EAGAIN) + goto retry; + + return ret; +} + +void idr_remove_uobj(struct idr *idr, struct ib_uobject *uobj) +{ + spin_lock(&ib_uverbs_idr_lock); + idr_remove(idr, uobj->id); + spin_unlock(&ib_uverbs_idr_lock); +} + +static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id, + struct ib_ucontext *context) +{ + struct ib_uobject *uobj; + + spin_lock(&ib_uverbs_idr_lock); + uobj = idr_find(idr, id); + if (uobj) { + if (uobj->context == context) + kref_get(&uobj->ref); + else + uobj = NULL; + } + spin_unlock(&ib_uverbs_idr_lock); + + return uobj; +} + +static struct ib_uobject *idr_read_uobj(struct idr *idr, int id, + struct ib_ucontext *context, int nested) +{ + struct ib_uobject *uobj; + + uobj = __idr_get_uobj(idr, id, context); + if (!uobj) + return NULL; + + if (nested) + down_read_nested(&uobj->mutex, SINGLE_DEPTH_NESTING); + else + down_read(&uobj->mutex); + if (!uobj->live) { + put_uobj_read(uobj); + return NULL; + } + + return uobj; +} + +static struct ib_uobject *idr_write_uobj(struct idr *idr, int id, + struct ib_ucontext *context) +{ + struct ib_uobject *uobj; + + uobj = __idr_get_uobj(idr, id, context); + if (!uobj) + return NULL; + + down_write(&uobj->mutex); + if (!uobj->live) { + put_uobj_write(uobj); + return NULL; + } + + return uobj; +} + +static void *idr_read_obj(struct idr *idr, int id, struct ib_ucontext *context, + int nested) +{ + struct ib_uobject *uobj; + + uobj = idr_read_uobj(idr, id, context, nested); + return uobj ? uobj->object : NULL; +} + +static struct ib_pd *idr_read_pd(int pd_handle, struct ib_ucontext *context) +{ + return idr_read_obj(&ib_uverbs_pd_idr, pd_handle, context, 0); +} + +static void put_pd_read(struct ib_pd *pd) +{ + put_uobj_read(pd->uobject); +} + +static struct ib_cq *idr_read_cq(int cq_handle, struct ib_ucontext *context, int nested) +{ + return idr_read_obj(&ib_uverbs_cq_idr, cq_handle, context, nested); +} + +static void put_cq_read(struct ib_cq *cq) +{ + put_uobj_read(cq->uobject); +} + +static struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context) +{ + return idr_read_obj(&ib_uverbs_ah_idr, ah_handle, context, 0); +} + +static void put_ah_read(struct ib_ah *ah) +{ + put_uobj_read(ah->uobject); +} + +static struct ib_qp *idr_read_qp(int qp_handle, struct ib_ucontext *context) +{ + return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context, 0); +} + +static void put_qp_read(struct ib_qp *qp) +{ + put_uobj_read(qp->uobject); +} + +static struct ib_srq *idr_read_srq(int srq_handle, struct ib_ucontext *context) +{ + return idr_read_obj(&ib_uverbs_srq_idr, srq_handle, context, 0); +} + +static void put_srq_read(struct ib_srq *srq) +{ + put_uobj_read(srq->uobject); +} + +static struct ib_xrcd *idr_read_xrcd(int xrcd_handle, + struct ib_ucontext *context, + struct ib_uobject **uobj) +{ + *uobj = idr_read_uobj(&ib_uverbs_xrc_domain_idr, xrcd_handle, + context, 0); + return *uobj ? (*uobj)->object : NULL; +} + +static void put_xrcd_read(struct ib_uobject *uobj) +{ + put_uobj_read(uobj); +} + +ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, + const char __user *buf, + int in_len, int out_len) +{ + struct ib_uverbs_get_context cmd; + struct ib_uverbs_get_context_resp resp; + struct ib_udata udata; + struct ib_device *ibdev = file->device->ib_dev; + struct ib_ucontext *ucontext; + struct file *filp; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + mutex_lock(&file->mutex); + + if (file->ucontext) { + ret = -EINVAL; + goto err; + } + + INIT_UDATA(&udata, buf + sizeof cmd, + (unsigned long) cmd.response + sizeof resp, + in_len - sizeof cmd, out_len - sizeof resp); + + ucontext = ibdev->alloc_ucontext(ibdev, &udata); + if (IS_ERR(ucontext)) { + ret = PTR_ERR(file->ucontext); + goto err; + } + + ucontext->device = ibdev; + INIT_LIST_HEAD(&ucontext->pd_list); + INIT_LIST_HEAD(&ucontext->mr_list); + INIT_LIST_HEAD(&ucontext->mw_list); + INIT_LIST_HEAD(&ucontext->cq_list); + INIT_LIST_HEAD(&ucontext->qp_list); + INIT_LIST_HEAD(&ucontext->srq_list); + INIT_LIST_HEAD(&ucontext->ah_list); + INIT_LIST_HEAD(&ucontext->xrc_domain_list); + ucontext->closing = 0; + + resp.num_comp_vectors = file->device->num_comp_vectors; + + filp = ib_uverbs_alloc_event_file(file, 1, &resp.async_fd); + if (IS_ERR(filp)) { + ret = PTR_ERR(filp); + goto err_free; + } + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_file; + } + + file->async_file = filp->private_data; + + INIT_IB_EVENT_HANDLER(&file->event_handler, file->device->ib_dev, + ib_uverbs_event_handler); + ret = ib_register_event_handler(&file->event_handler); + if (ret) + goto err_file; + + kref_get(&file->async_file->ref); + kref_get(&file->ref); + file->ucontext = ucontext; + + fd_install(resp.async_fd, filp); + + mutex_unlock(&file->mutex); + + return in_len; + +err_file: + put_unused_fd(resp.async_fd); + fput(filp); + +err_free: + ibdev->dealloc_ucontext(ucontext); + +err: + mutex_unlock(&file->mutex); + return ret; +} + +ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file, + const char __user *buf, + int in_len, int out_len) +{ + struct ib_uverbs_query_device cmd; + struct ib_uverbs_query_device_resp resp; + struct ib_device_attr attr; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + ret = ib_query_device(file->device->ib_dev, &attr); + if (ret) + return ret; + + memset(&resp, 0, sizeof resp); + + resp.fw_ver = attr.fw_ver; + resp.node_guid = file->device->ib_dev->node_guid; + resp.sys_image_guid = attr.sys_image_guid; + resp.max_mr_size = attr.max_mr_size; + resp.page_size_cap = attr.page_size_cap; + resp.vendor_id = attr.vendor_id; + resp.vendor_part_id = attr.vendor_part_id; + resp.hw_ver = attr.hw_ver; + resp.max_qp = attr.max_qp; + resp.max_qp_wr = attr.max_qp_wr; + resp.device_cap_flags = attr.device_cap_flags; + resp.max_sge = attr.max_sge; + resp.max_sge_rd = attr.max_sge_rd; + resp.max_cq = attr.max_cq; + resp.max_cqe = attr.max_cqe; + resp.max_mr = attr.max_mr; + resp.max_pd = attr.max_pd; + resp.max_qp_rd_atom = attr.max_qp_rd_atom; + resp.max_ee_rd_atom = attr.max_ee_rd_atom; + resp.max_res_rd_atom = attr.max_res_rd_atom; + resp.max_qp_init_rd_atom = attr.max_qp_init_rd_atom; + resp.max_ee_init_rd_atom = attr.max_ee_init_rd_atom; + resp.atomic_cap = attr.atomic_cap; + resp.max_ee = attr.max_ee; + resp.max_rdd = attr.max_rdd; + resp.max_mw = attr.max_mw; + resp.max_raw_ipv6_qp = attr.max_raw_ipv6_qp; + resp.max_raw_ethy_qp = attr.max_raw_ethy_qp; + resp.max_mcast_grp = attr.max_mcast_grp; + resp.max_mcast_qp_attach = attr.max_mcast_qp_attach; + resp.max_total_mcast_qp_attach = attr.max_total_mcast_qp_attach; + resp.max_ah = attr.max_ah; + resp.max_fmr = attr.max_fmr; + resp.max_map_per_fmr = attr.max_map_per_fmr; + resp.max_srq = attr.max_srq; + resp.max_srq_wr = attr.max_srq_wr; + resp.max_srq_sge = attr.max_srq_sge; + resp.max_pkeys = attr.max_pkeys; + resp.local_ca_ack_delay = attr.local_ca_ack_delay; + resp.phys_port_cnt = file->device->ib_dev->phys_port_cnt; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + return -EFAULT; + + return in_len; +} + +ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file, + const char __user *buf, + int in_len, int out_len) +{ + struct ib_uverbs_query_port cmd; + struct ib_uverbs_query_port_resp resp; + struct ib_port_attr attr; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + ret = ib_query_port(file->device->ib_dev, cmd.port_num, &attr); + if (ret) + return ret; + + memset(&resp, 0, sizeof resp); + + resp.state = attr.state; + resp.max_mtu = attr.max_mtu; + resp.active_mtu = attr.active_mtu; + resp.gid_tbl_len = attr.gid_tbl_len; + resp.port_cap_flags = attr.port_cap_flags; + resp.max_msg_sz = attr.max_msg_sz; + resp.bad_pkey_cntr = attr.bad_pkey_cntr; + resp.qkey_viol_cntr = attr.qkey_viol_cntr; + resp.pkey_tbl_len = attr.pkey_tbl_len; + resp.lid = attr.lid; + resp.sm_lid = attr.sm_lid; + resp.lmc = attr.lmc; + resp.max_vl_num = attr.max_vl_num; + resp.sm_sl = attr.sm_sl; + resp.subnet_timeout = attr.subnet_timeout; + resp.init_type_reply = attr.init_type_reply; + resp.active_width = attr.active_width; + resp.active_speed = attr.active_speed; + resp.phys_state = attr.phys_state; + resp.link_layer = attr.link_layer; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + return -EFAULT; + + return in_len; +} + +ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, + const char __user *buf, + int in_len, int out_len) +{ + struct ib_uverbs_alloc_pd cmd; + struct ib_uverbs_alloc_pd_resp resp; + struct ib_udata udata; + struct ib_uobject *uobj; + struct ib_pd *pd; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, + (unsigned long) cmd.response + sizeof resp, + in_len - sizeof cmd, out_len - sizeof resp); + + uobj = kmalloc(sizeof *uobj, GFP_KERNEL); + if (!uobj) + return -ENOMEM; + + init_uobj(uobj, 0, file->ucontext, &pd_lock_key); + down_write(&uobj->mutex); + + pd = file->device->ib_dev->alloc_pd(file->device->ib_dev, + file->ucontext, &udata); + if (IS_ERR(pd)) { + ret = PTR_ERR(pd); + goto err; + } + + pd->device = file->device->ib_dev; + pd->uobject = uobj; + atomic_set(&pd->usecnt, 0); + + uobj->object = pd; + ret = idr_add_uobj(&ib_uverbs_pd_idr, uobj); + if (ret) + goto err_idr; + + memset(&resp, 0, sizeof resp); + resp.pd_handle = uobj->id; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_copy; + } + + mutex_lock(&file->mutex); + list_add_tail(&uobj->list, &file->ucontext->pd_list); + mutex_unlock(&file->mutex); + + uobj->live = 1; + + up_write(&uobj->mutex); + + return in_len; + +err_copy: + idr_remove_uobj(&ib_uverbs_pd_idr, uobj); + +err_idr: + ib_dealloc_pd(pd); + +err: + put_uobj_write(uobj); + return ret; +} + +ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file, + const char __user *buf, + int in_len, int out_len) +{ + struct ib_uverbs_dealloc_pd cmd; + struct ib_uobject *uobj; + int ret; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + uobj = idr_write_uobj(&ib_uverbs_pd_idr, cmd.pd_handle, file->ucontext); + if (!uobj) + return -EINVAL; + + ret = ib_dealloc_pd(uobj->object); + if (!ret) + uobj->live = 0; + + put_uobj_write(uobj); + + if (ret) + return ret; + + idr_remove_uobj(&ib_uverbs_pd_idr, uobj); + + mutex_lock(&file->mutex); + list_del(&uobj->list); + mutex_unlock(&file->mutex); + + put_uobj(uobj); + + return in_len; +} + +ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_reg_mr cmd; + struct ib_uverbs_reg_mr_resp resp; + struct ib_udata udata; + struct ib_uobject *uobj; + struct ib_pd *pd; + struct ib_mr *mr; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, + (unsigned long) cmd.response + sizeof resp, + in_len - sizeof cmd, out_len - sizeof resp); + + if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK)) + return -EINVAL; + + /* + * Local write permission is required if remote write or + * remote atomic permission is also requested. + */ + if (cmd.access_flags & (IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_REMOTE_WRITE) && + !(cmd.access_flags & IB_ACCESS_LOCAL_WRITE)) + return -EINVAL; + + uobj = kmalloc(sizeof *uobj, GFP_KERNEL); + if (!uobj) + return -ENOMEM; + + init_uobj(uobj, 0, file->ucontext, &mr_lock_key); + down_write(&uobj->mutex); + + pd = idr_read_pd(cmd.pd_handle, file->ucontext); + if (!pd) { + ret = -EINVAL; + goto err_free; + } + + mr = pd->device->reg_user_mr(pd, cmd.start, cmd.length, cmd.hca_va, + cmd.access_flags, &udata); + if (IS_ERR(mr)) { + ret = PTR_ERR(mr); + goto err_put; + } + + mr->device = pd->device; + mr->pd = pd; + mr->uobject = uobj; + atomic_inc(&pd->usecnt); + atomic_set(&mr->usecnt, 0); + + uobj->object = mr; + ret = idr_add_uobj(&ib_uverbs_mr_idr, uobj); + if (ret) + goto err_unreg; + + memset(&resp, 0, sizeof resp); + resp.lkey = mr->lkey; + resp.rkey = mr->rkey; + resp.mr_handle = uobj->id; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_copy; + } + + put_pd_read(pd); + + mutex_lock(&file->mutex); + list_add_tail(&uobj->list, &file->ucontext->mr_list); + mutex_unlock(&file->mutex); + + uobj->live = 1; + + up_write(&uobj->mutex); + + return in_len; + +err_copy: + idr_remove_uobj(&ib_uverbs_mr_idr, uobj); + +err_unreg: + ib_dereg_mr(mr); + +err_put: + put_pd_read(pd); + +err_free: + put_uobj_write(uobj); + return ret; +} + +ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_dereg_mr cmd; + struct ib_mr *mr; + struct ib_uobject *uobj; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + uobj = idr_write_uobj(&ib_uverbs_mr_idr, cmd.mr_handle, file->ucontext); + if (!uobj) + return -EINVAL; + + mr = uobj->object; + + ret = ib_dereg_mr(mr); + if (!ret) + uobj->live = 0; + + put_uobj_write(uobj); + + if (ret) + return ret; + + idr_remove_uobj(&ib_uverbs_mr_idr, uobj); + + mutex_lock(&file->mutex); + list_del(&uobj->list); + mutex_unlock(&file->mutex); + + put_uobj(uobj); + + return in_len; +} + +ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_create_comp_channel cmd; + struct ib_uverbs_create_comp_channel_resp resp; + struct file *filp; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + filp = ib_uverbs_alloc_event_file(file, 0, &resp.fd); + if (IS_ERR(filp)) + return PTR_ERR(filp); + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + put_unused_fd(resp.fd); + fput(filp); + return -EFAULT; + } + + fd_install(resp.fd, filp); + return in_len; +} + +ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_create_cq cmd; + struct ib_uverbs_create_cq_resp resp; + struct ib_udata udata; + struct ib_ucq_object *obj; + struct ib_uverbs_event_file *ev_file = NULL; + struct ib_cq *cq; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, + (unsigned long) cmd.response + sizeof resp, + in_len - sizeof cmd, out_len - sizeof resp); + + if (cmd.comp_vector >= file->device->num_comp_vectors) + return -EINVAL; + + obj = kmalloc(sizeof *obj, GFP_KERNEL); + if (!obj) + return -ENOMEM; + + init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, &cq_lock_key); + down_write(&obj->uobject.mutex); + + if (cmd.comp_channel >= 0) { + ev_file = ib_uverbs_lookup_comp_file(cmd.comp_channel); + if (!ev_file) { + ret = -EINVAL; + goto err; + } + } + + obj->uverbs_file = file; + obj->comp_events_reported = 0; + obj->async_events_reported = 0; + INIT_LIST_HEAD(&obj->comp_list); + INIT_LIST_HEAD(&obj->async_list); + + cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe, + cmd.comp_vector, + file->ucontext, &udata); + if (IS_ERR(cq)) { + ret = PTR_ERR(cq); + goto err_file; + } + + cq->device = file->device->ib_dev; + cq->uobject = &obj->uobject; + cq->comp_handler = ib_uverbs_comp_handler; + cq->event_handler = ib_uverbs_cq_event_handler; + cq->cq_context = ev_file; + atomic_set(&cq->usecnt, 0); + + obj->uobject.object = cq; + ret = idr_add_uobj(&ib_uverbs_cq_idr, &obj->uobject); + if (ret) + goto err_free; + + memset(&resp, 0, sizeof resp); + resp.cq_handle = obj->uobject.id; + resp.cqe = cq->cqe; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_copy; + } + + mutex_lock(&file->mutex); + list_add_tail(&obj->uobject.list, &file->ucontext->cq_list); + mutex_unlock(&file->mutex); + + obj->uobject.live = 1; + + up_write(&obj->uobject.mutex); + + return in_len; + +err_copy: + idr_remove_uobj(&ib_uverbs_cq_idr, &obj->uobject); + +err_free: + ib_destroy_cq(cq); + +err_file: + if (ev_file) + ib_uverbs_release_ucq(file, ev_file, obj); + +err: + put_uobj_write(&obj->uobject); + return ret; +} + +ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_resize_cq cmd; + struct ib_uverbs_resize_cq_resp resp; + struct ib_udata udata; + struct ib_cq *cq; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, + (unsigned long) cmd.response + sizeof resp, + in_len - sizeof cmd, out_len - sizeof resp); + + cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0); + if (!cq) + return -EINVAL; + + ret = cq->device->resize_cq(cq, cmd.cqe, &udata); + if (ret) + goto out; + + resp.cqe = cq->cqe; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp.cqe)) + ret = -EFAULT; + +out: + put_cq_read(cq); + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_poll_cq cmd; + struct ib_uverbs_poll_cq_resp *resp; + struct ib_cq *cq; + struct ib_wc *wc; + int ret = 0; + int i; + int rsize; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL); + if (!wc) + return -ENOMEM; + + rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc); + resp = kmalloc(rsize, GFP_KERNEL); + if (!resp) { + ret = -ENOMEM; + goto out_wc; + } + + cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0); + if (!cq) { + ret = -EINVAL; + goto out; + } + + resp->count = ib_poll_cq(cq, cmd.ne, wc); + + put_cq_read(cq); + + for (i = 0; i < resp->count; i++) { + resp->wc[i].wr_id = wc[i].wr_id; + resp->wc[i].status = wc[i].status; + resp->wc[i].opcode = wc[i].opcode; + resp->wc[i].vendor_err = wc[i].vendor_err; + resp->wc[i].byte_len = wc[i].byte_len; + resp->wc[i].ex.imm_data = (__u32 __force) wc[i].ex.imm_data; + resp->wc[i].qp_num = wc[i].qp->qp_num; + resp->wc[i].src_qp = wc[i].src_qp; + resp->wc[i].wc_flags = wc[i].wc_flags; + resp->wc[i].pkey_index = wc[i].pkey_index; + resp->wc[i].slid = wc[i].slid; + resp->wc[i].sl = wc[i].sl; + resp->wc[i].dlid_path_bits = wc[i].dlid_path_bits; + resp->wc[i].port_num = wc[i].port_num; + } + + if (copy_to_user((void __user *) (unsigned long) cmd.response, resp, rsize)) + ret = -EFAULT; + +out: + kfree(resp); + +out_wc: + kfree(wc); + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_req_notify_cq cmd; + struct ib_cq *cq; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0); + if (!cq) + return -EINVAL; + + ib_req_notify_cq(cq, cmd.solicited_only ? + IB_CQ_SOLICITED : IB_CQ_NEXT_COMP); + + put_cq_read(cq); + + return in_len; +} + +ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_destroy_cq cmd; + struct ib_uverbs_destroy_cq_resp resp; + struct ib_uobject *uobj; + struct ib_cq *cq; + struct ib_ucq_object *obj; + struct ib_uverbs_event_file *ev_file; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + uobj = idr_write_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext); + if (!uobj) + return -EINVAL; + cq = uobj->object; + ev_file = cq->cq_context; + obj = container_of(cq->uobject, struct ib_ucq_object, uobject); + + ret = ib_destroy_cq(cq); + if (!ret) + uobj->live = 0; + + put_uobj_write(uobj); + + if (ret) + return ret; + + idr_remove_uobj(&ib_uverbs_cq_idr, uobj); + + mutex_lock(&file->mutex); + list_del(&uobj->list); + mutex_unlock(&file->mutex); + + ib_uverbs_release_ucq(file, ev_file, obj); + + memset(&resp, 0, sizeof resp); + resp.comp_events_reported = obj->comp_events_reported; + resp.async_events_reported = obj->async_events_reported; + + put_uobj(uobj); + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + return -EFAULT; + + return in_len; +} + +ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_create_qp cmd; + struct ib_uverbs_create_qp_resp resp; + struct ib_udata udata; + struct ib_uqp_object *obj; + struct ib_pd *pd; + struct ib_cq *scq, *rcq; + struct ib_srq *srq; + struct ib_qp *qp; + struct ib_qp_init_attr attr; + struct ib_xrcd *xrcd; + struct ib_uobject *xrcd_uobj; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, + (unsigned long) cmd.response + sizeof resp, + in_len - sizeof cmd, out_len - sizeof resp); + + obj = kmalloc(sizeof *obj, GFP_KERNEL); + if (!obj) + return -ENOMEM; + + init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext, &qp_lock_key); + down_write(&obj->uevent.uobject.mutex); + + srq = (cmd.is_srq && cmd.qp_type != IB_QPT_XRC) ? + idr_read_srq(cmd.srq_handle, file->ucontext) : NULL; + xrcd = cmd.qp_type == IB_QPT_XRC ? + idr_read_xrcd(cmd.srq_handle, file->ucontext, &xrcd_uobj) : NULL; + pd = idr_read_pd(cmd.pd_handle, file->ucontext); + scq = idr_read_cq(cmd.send_cq_handle, file->ucontext, 0); + rcq = cmd.recv_cq_handle == cmd.send_cq_handle ? + scq : idr_read_cq(cmd.recv_cq_handle, file->ucontext, 1); + + if (!pd || !scq || !rcq || (cmd.is_srq && !srq) || + (cmd.qp_type == IB_QPT_XRC && !xrcd)) { + ret = -EINVAL; + goto err_put; + } + + attr.create_flags = 0; + attr.event_handler = ib_uverbs_qp_event_handler; + attr.qp_context = file; + attr.send_cq = scq; + attr.recv_cq = rcq; + attr.srq = srq; + attr.sq_sig_type = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; + attr.qp_type = cmd.qp_type; + attr.xrc_domain = xrcd; + attr.create_flags = 0; + + attr.cap.max_send_wr = cmd.max_send_wr; + attr.cap.max_recv_wr = cmd.max_recv_wr; + attr.cap.max_send_sge = cmd.max_send_sge; + attr.cap.max_recv_sge = cmd.max_recv_sge; + attr.cap.max_inline_data = cmd.max_inline_data; + + obj->uevent.events_reported = 0; + INIT_LIST_HEAD(&obj->uevent.event_list); + INIT_LIST_HEAD(&obj->mcast_list); + + qp = pd->device->create_qp(pd, &attr, &udata); + if (IS_ERR(qp)) { + ret = PTR_ERR(qp); + goto err_put; + } + + qp->device = pd->device; + qp->pd = pd; + qp->send_cq = attr.send_cq; + qp->recv_cq = attr.recv_cq; + qp->srq = attr.srq; + qp->uobject = &obj->uevent.uobject; + qp->event_handler = attr.event_handler; + qp->qp_context = attr.qp_context; + qp->qp_type = attr.qp_type; + qp->xrcd = attr.xrc_domain; + atomic_inc(&pd->usecnt); + atomic_inc(&attr.send_cq->usecnt); + atomic_inc(&attr.recv_cq->usecnt); + if (attr.srq) + atomic_inc(&attr.srq->usecnt); + else if (attr.xrc_domain) + atomic_inc(&attr.xrc_domain->usecnt); + + obj->uevent.uobject.object = qp; + ret = idr_add_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject); + if (ret) + goto err_destroy; + + memset(&resp, 0, sizeof resp); + resp.qpn = qp->qp_num; + resp.qp_handle = obj->uevent.uobject.id; + resp.max_recv_sge = attr.cap.max_recv_sge; + resp.max_send_sge = attr.cap.max_send_sge; + resp.max_recv_wr = attr.cap.max_recv_wr; + resp.max_send_wr = attr.cap.max_send_wr; + resp.max_inline_data = attr.cap.max_inline_data; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_copy; + } + + put_pd_read(pd); + put_cq_read(scq); + if (rcq != scq) + put_cq_read(rcq); + if (srq) + put_srq_read(srq); + if (xrcd) + put_xrcd_read(xrcd_uobj); + + mutex_lock(&file->mutex); + list_add_tail(&obj->uevent.uobject.list, &file->ucontext->qp_list); + mutex_unlock(&file->mutex); + + obj->uevent.uobject.live = 1; + + up_write(&obj->uevent.uobject.mutex); + + return in_len; + +err_copy: + idr_remove_uobj(&ib_uverbs_qp_idr, &obj->uevent.uobject); + +err_destroy: + ib_destroy_qp(qp); + +err_put: + if (pd) + put_pd_read(pd); + if (scq) + put_cq_read(scq); + if (rcq && rcq != scq) + put_cq_read(rcq); + if (srq) + put_srq_read(srq); + if (xrcd) + put_xrcd_read(xrcd_uobj); + + put_uobj_write(&obj->uevent.uobject); + return ret; +} + +ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_query_qp cmd; + struct ib_uverbs_query_qp_resp resp; + struct ib_qp *qp; + struct ib_qp_attr *attr; + struct ib_qp_init_attr *init_attr; + int ret; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + attr = kmalloc(sizeof *attr, GFP_KERNEL); + init_attr = kmalloc(sizeof *init_attr, GFP_KERNEL); + if (!attr || !init_attr) { + ret = -ENOMEM; + goto out; + } + + qp = idr_read_qp(cmd.qp_handle, file->ucontext); + if (!qp) { + ret = -EINVAL; + goto out; + } + + ret = ib_query_qp(qp, attr, cmd.attr_mask, init_attr); + + put_qp_read(qp); + + if (ret) + goto out; + + memset(&resp, 0, sizeof resp); + + resp.qp_state = attr->qp_state; + resp.cur_qp_state = attr->cur_qp_state; + resp.path_mtu = attr->path_mtu; + resp.path_mig_state = attr->path_mig_state; + resp.qkey = attr->qkey; + resp.rq_psn = attr->rq_psn; + resp.sq_psn = attr->sq_psn; + resp.dest_qp_num = attr->dest_qp_num; + resp.qp_access_flags = attr->qp_access_flags; + resp.pkey_index = attr->pkey_index; + resp.alt_pkey_index = attr->alt_pkey_index; + resp.sq_draining = attr->sq_draining; + resp.max_rd_atomic = attr->max_rd_atomic; + resp.max_dest_rd_atomic = attr->max_dest_rd_atomic; + resp.min_rnr_timer = attr->min_rnr_timer; + resp.port_num = attr->port_num; + resp.timeout = attr->timeout; + resp.retry_cnt = attr->retry_cnt; + resp.rnr_retry = attr->rnr_retry; + resp.alt_port_num = attr->alt_port_num; + resp.alt_timeout = attr->alt_timeout; + + memcpy(resp.dest.dgid, attr->ah_attr.grh.dgid.raw, 16); + resp.dest.flow_label = attr->ah_attr.grh.flow_label; + resp.dest.sgid_index = attr->ah_attr.grh.sgid_index; + resp.dest.hop_limit = attr->ah_attr.grh.hop_limit; + resp.dest.traffic_class = attr->ah_attr.grh.traffic_class; + resp.dest.dlid = attr->ah_attr.dlid; + resp.dest.sl = attr->ah_attr.sl; + resp.dest.src_path_bits = attr->ah_attr.src_path_bits; + resp.dest.static_rate = attr->ah_attr.static_rate; + resp.dest.is_global = !!(attr->ah_attr.ah_flags & IB_AH_GRH); + resp.dest.port_num = attr->ah_attr.port_num; + + memcpy(resp.alt_dest.dgid, attr->alt_ah_attr.grh.dgid.raw, 16); + resp.alt_dest.flow_label = attr->alt_ah_attr.grh.flow_label; + resp.alt_dest.sgid_index = attr->alt_ah_attr.grh.sgid_index; + resp.alt_dest.hop_limit = attr->alt_ah_attr.grh.hop_limit; + resp.alt_dest.traffic_class = attr->alt_ah_attr.grh.traffic_class; + resp.alt_dest.dlid = attr->alt_ah_attr.dlid; + resp.alt_dest.sl = attr->alt_ah_attr.sl; + resp.alt_dest.src_path_bits = attr->alt_ah_attr.src_path_bits; + resp.alt_dest.static_rate = attr->alt_ah_attr.static_rate; + resp.alt_dest.is_global = !!(attr->alt_ah_attr.ah_flags & IB_AH_GRH); + resp.alt_dest.port_num = attr->alt_ah_attr.port_num; + + resp.max_send_wr = init_attr->cap.max_send_wr; + resp.max_recv_wr = init_attr->cap.max_recv_wr; + resp.max_send_sge = init_attr->cap.max_send_sge; + resp.max_recv_sge = init_attr->cap.max_recv_sge; + resp.max_inline_data = init_attr->cap.max_inline_data; + resp.sq_sig_all = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + +out: + kfree(attr); + kfree(init_attr); + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_modify_qp cmd; + struct ib_udata udata; + struct ib_qp *qp; + struct ib_qp_attr *attr; + int ret; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd, + out_len); + + attr = kmalloc(sizeof *attr, GFP_KERNEL); + if (!attr) + return -ENOMEM; + + qp = idr_read_qp(cmd.qp_handle, file->ucontext); + if (!qp) { + ret = -EINVAL; + goto out; + } + + attr->qp_state = cmd.qp_state; + attr->cur_qp_state = cmd.cur_qp_state; + attr->path_mtu = cmd.path_mtu; + attr->path_mig_state = cmd.path_mig_state; + attr->qkey = cmd.qkey; + attr->rq_psn = cmd.rq_psn; + attr->sq_psn = cmd.sq_psn; + attr->dest_qp_num = cmd.dest_qp_num; + attr->qp_access_flags = cmd.qp_access_flags; + attr->pkey_index = cmd.pkey_index; + attr->alt_pkey_index = cmd.alt_pkey_index; + attr->en_sqd_async_notify = cmd.en_sqd_async_notify; + attr->max_rd_atomic = cmd.max_rd_atomic; + attr->max_dest_rd_atomic = cmd.max_dest_rd_atomic; + attr->min_rnr_timer = cmd.min_rnr_timer; + attr->port_num = cmd.port_num; + attr->timeout = cmd.timeout; + attr->retry_cnt = cmd.retry_cnt; + attr->rnr_retry = cmd.rnr_retry; + attr->alt_port_num = cmd.alt_port_num; + attr->alt_timeout = cmd.alt_timeout; + + memcpy(attr->ah_attr.grh.dgid.raw, cmd.dest.dgid, 16); + attr->ah_attr.grh.flow_label = cmd.dest.flow_label; + attr->ah_attr.grh.sgid_index = cmd.dest.sgid_index; + attr->ah_attr.grh.hop_limit = cmd.dest.hop_limit; + attr->ah_attr.grh.traffic_class = cmd.dest.traffic_class; + attr->ah_attr.dlid = cmd.dest.dlid; + attr->ah_attr.sl = cmd.dest.sl; + attr->ah_attr.src_path_bits = cmd.dest.src_path_bits; + attr->ah_attr.static_rate = cmd.dest.static_rate; + attr->ah_attr.ah_flags = cmd.dest.is_global ? IB_AH_GRH : 0; + attr->ah_attr.port_num = cmd.dest.port_num; + + memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd.alt_dest.dgid, 16); + attr->alt_ah_attr.grh.flow_label = cmd.alt_dest.flow_label; + attr->alt_ah_attr.grh.sgid_index = cmd.alt_dest.sgid_index; + attr->alt_ah_attr.grh.hop_limit = cmd.alt_dest.hop_limit; + attr->alt_ah_attr.grh.traffic_class = cmd.alt_dest.traffic_class; + attr->alt_ah_attr.dlid = cmd.alt_dest.dlid; + attr->alt_ah_attr.sl = cmd.alt_dest.sl; + attr->alt_ah_attr.src_path_bits = cmd.alt_dest.src_path_bits; + attr->alt_ah_attr.static_rate = cmd.alt_dest.static_rate; + attr->alt_ah_attr.ah_flags = cmd.alt_dest.is_global ? IB_AH_GRH : 0; + attr->alt_ah_attr.port_num = cmd.alt_dest.port_num; + + ret = qp->device->modify_qp(qp, attr, cmd.attr_mask, &udata); + + put_qp_read(qp); + + if (ret) + goto out; + + ret = in_len; + +out: + kfree(attr); + + return ret; +} + +ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_destroy_qp cmd; + struct ib_uverbs_destroy_qp_resp resp; + struct ib_uobject *uobj; + struct ib_qp *qp; + struct ib_uqp_object *obj; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + memset(&resp, 0, sizeof resp); + + uobj = idr_write_uobj(&ib_uverbs_qp_idr, cmd.qp_handle, file->ucontext); + if (!uobj) + return -EINVAL; + qp = uobj->object; + obj = container_of(uobj, struct ib_uqp_object, uevent.uobject); + + if (!list_empty(&obj->mcast_list)) { + put_uobj_write(uobj); + return -EBUSY; + } + + ret = ib_destroy_qp(qp); + if (!ret) + uobj->live = 0; + + put_uobj_write(uobj); + + if (ret) + return ret; + + idr_remove_uobj(&ib_uverbs_qp_idr, uobj); + + mutex_lock(&file->mutex); + list_del(&uobj->list); + mutex_unlock(&file->mutex); + + ib_uverbs_release_uevent(file, &obj->uevent); + + resp.events_reported = obj->uevent.events_reported; + + put_uobj(uobj); + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + return -EFAULT; + + return in_len; +} + +ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_post_send cmd; + struct ib_uverbs_post_send_resp resp; + struct ib_uverbs_send_wr *user_wr; + struct ib_send_wr *wr = NULL, *last, *next, *bad_wr; + struct ib_qp *qp; + int i, sg_ind; + int is_ud; + ssize_t ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + if (in_len < sizeof cmd + cmd.wqe_size * cmd.wr_count + + cmd.sge_count * sizeof (struct ib_uverbs_sge)) + return -EINVAL; + + if (cmd.wqe_size < sizeof (struct ib_uverbs_send_wr)) + return -EINVAL; + + user_wr = kmalloc(cmd.wqe_size, GFP_KERNEL); + if (!user_wr) + return -ENOMEM; + + qp = idr_read_qp(cmd.qp_handle, file->ucontext); + if (!qp) + goto out; + + is_ud = qp->qp_type == IB_QPT_UD; + sg_ind = 0; + last = NULL; + for (i = 0; i < cmd.wr_count; ++i) { + if (copy_from_user(user_wr, + buf + sizeof cmd + i * cmd.wqe_size, + cmd.wqe_size)) { + ret = -EFAULT; + goto out_put; + } + + if (user_wr->num_sge + sg_ind > cmd.sge_count) { + ret = -EINVAL; + goto out_put; + } + + next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) + + user_wr->num_sge * sizeof (struct ib_sge), + GFP_KERNEL); + if (!next) { + ret = -ENOMEM; + goto out_put; + } + + if (!last) + wr = next; + else + last->next = next; + last = next; + + next->next = NULL; + next->wr_id = user_wr->wr_id; + next->num_sge = user_wr->num_sge; + next->opcode = user_wr->opcode; + next->send_flags = user_wr->send_flags; + + if (is_ud) { + next->wr.ud.ah = idr_read_ah(user_wr->wr.ud.ah, + file->ucontext); + if (!next->wr.ud.ah) { + ret = -EINVAL; + goto out_put; + } + next->wr.ud.remote_qpn = user_wr->wr.ud.remote_qpn; + next->wr.ud.remote_qkey = user_wr->wr.ud.remote_qkey; + } else { + switch (next->opcode) { + case IB_WR_RDMA_WRITE_WITH_IMM: + next->ex.imm_data = + (__be32 __force) user_wr->ex.imm_data; + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_READ: + next->wr.rdma.remote_addr = + user_wr->wr.rdma.remote_addr; + next->wr.rdma.rkey = + user_wr->wr.rdma.rkey; + break; + case IB_WR_SEND_WITH_IMM: + next->ex.imm_data = + (__be32 __force) user_wr->ex.imm_data; + break; + case IB_WR_SEND_WITH_INV: + next->ex.invalidate_rkey = + user_wr->ex.invalidate_rkey; + break; + case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_ATOMIC_FETCH_AND_ADD: + next->wr.atomic.remote_addr = + user_wr->wr.atomic.remote_addr; + next->wr.atomic.compare_add = + user_wr->wr.atomic.compare_add; + next->wr.atomic.swap = user_wr->wr.atomic.swap; + next->wr.atomic.rkey = user_wr->wr.atomic.rkey; + break; + default: + break; + } + } + + if (next->num_sge) { + next->sg_list = (void *) next + + ALIGN(sizeof *next, sizeof (struct ib_sge)); + if (copy_from_user(next->sg_list, + buf + sizeof cmd + + cmd.wr_count * cmd.wqe_size + + sg_ind * sizeof (struct ib_sge), + next->num_sge * sizeof (struct ib_sge))) { + ret = -EFAULT; + goto out_put; + } + sg_ind += next->num_sge; + } else + next->sg_list = NULL; + } + + resp.bad_wr = 0; + ret = qp->device->post_send(qp, wr, &bad_wr); + if (ret) + for (next = wr; next; next = next->next) { + ++resp.bad_wr; + if (next == bad_wr) + break; + } + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + +out_put: + put_qp_read(qp); + + while (wr) { + if (is_ud && wr->wr.ud.ah) + put_ah_read(wr->wr.ud.ah); + next = wr->next; + kfree(wr); + wr = next; + } + +out: + kfree(user_wr); + + return ret ? ret : in_len; +} + +static struct ib_recv_wr *ib_uverbs_unmarshall_recv(const char __user *buf, + int in_len, + u32 wr_count, + u32 sge_count, + u32 wqe_size) +{ + struct ib_uverbs_recv_wr *user_wr; + struct ib_recv_wr *wr = NULL, *last, *next; + int sg_ind; + int i; + int ret; + + if (in_len < wqe_size * wr_count + + sge_count * sizeof (struct ib_uverbs_sge)) + return ERR_PTR(-EINVAL); + + if (wqe_size < sizeof (struct ib_uverbs_recv_wr)) + return ERR_PTR(-EINVAL); + + user_wr = kmalloc(wqe_size, GFP_KERNEL); + if (!user_wr) + return ERR_PTR(-ENOMEM); + + sg_ind = 0; + last = NULL; + for (i = 0; i < wr_count; ++i) { + if (copy_from_user(user_wr, buf + i * wqe_size, + wqe_size)) { + ret = -EFAULT; + goto err; + } + + if (user_wr->num_sge + sg_ind > sge_count) { + ret = -EINVAL; + goto err; + } + + next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) + + user_wr->num_sge * sizeof (struct ib_sge), + GFP_KERNEL); + if (!next) { + ret = -ENOMEM; + goto err; + } + + if (!last) + wr = next; + else + last->next = next; + last = next; + + next->next = NULL; + next->wr_id = user_wr->wr_id; + next->num_sge = user_wr->num_sge; + + if (next->num_sge) { + next->sg_list = (void *) next + + ALIGN(sizeof *next, sizeof (struct ib_sge)); + if (copy_from_user(next->sg_list, + buf + wr_count * wqe_size + + sg_ind * sizeof (struct ib_sge), + next->num_sge * sizeof (struct ib_sge))) { + ret = -EFAULT; + goto err; + } + sg_ind += next->num_sge; + } else + next->sg_list = NULL; + } + + kfree(user_wr); + return wr; + +err: + kfree(user_wr); + + while (wr) { + next = wr->next; + kfree(wr); + wr = next; + } + + return ERR_PTR(ret); +} + +ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_post_recv cmd; + struct ib_uverbs_post_recv_resp resp; + struct ib_recv_wr *wr, *next, *bad_wr; + struct ib_qp *qp; + ssize_t ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + wr = ib_uverbs_unmarshall_recv(buf + sizeof cmd, + in_len - sizeof cmd, cmd.wr_count, + cmd.sge_count, cmd.wqe_size); + if (IS_ERR(wr)) + return PTR_ERR(wr); + + qp = idr_read_qp(cmd.qp_handle, file->ucontext); + if (!qp) + goto out; + + resp.bad_wr = 0; + ret = qp->device->post_recv(qp, wr, &bad_wr); + + put_qp_read(qp); + + if (ret) + for (next = wr; next; next = next->next) { + ++resp.bad_wr; + if (next == bad_wr) + break; + } + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + +out: + while (wr) { + next = wr->next; + kfree(wr); + wr = next; + } + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_post_srq_recv cmd; + struct ib_uverbs_post_srq_recv_resp resp; + struct ib_recv_wr *wr, *next, *bad_wr; + struct ib_srq *srq; + ssize_t ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + wr = ib_uverbs_unmarshall_recv(buf + sizeof cmd, + in_len - sizeof cmd, cmd.wr_count, + cmd.sge_count, cmd.wqe_size); + if (IS_ERR(wr)) + return PTR_ERR(wr); + + srq = idr_read_srq(cmd.srq_handle, file->ucontext); + if (!srq) + goto out; + + resp.bad_wr = 0; + ret = srq->device->post_srq_recv(srq, wr, &bad_wr); + + put_srq_read(srq); + + if (ret) + for (next = wr; next; next = next->next) { + ++resp.bad_wr; + if (next == bad_wr) + break; + } + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + +out: + while (wr) { + next = wr->next; + kfree(wr); + wr = next; + } + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_create_ah cmd; + struct ib_uverbs_create_ah_resp resp; + struct ib_uobject *uobj; + struct ib_pd *pd; + struct ib_ah *ah; + struct ib_ah_attr attr; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + uobj = kmalloc(sizeof *uobj, GFP_KERNEL); + if (!uobj) + return -ENOMEM; + + init_uobj(uobj, cmd.user_handle, file->ucontext, &ah_lock_key); + down_write(&uobj->mutex); + + pd = idr_read_pd(cmd.pd_handle, file->ucontext); + if (!pd) { + ret = -EINVAL; + goto err; + } + + attr.dlid = cmd.attr.dlid; + attr.sl = cmd.attr.sl; + attr.src_path_bits = cmd.attr.src_path_bits; + attr.static_rate = cmd.attr.static_rate; + attr.ah_flags = cmd.attr.is_global ? IB_AH_GRH : 0; + attr.port_num = cmd.attr.port_num; + attr.grh.flow_label = cmd.attr.grh.flow_label; + attr.grh.sgid_index = cmd.attr.grh.sgid_index; + attr.grh.hop_limit = cmd.attr.grh.hop_limit; + attr.grh.traffic_class = cmd.attr.grh.traffic_class; + memcpy(attr.grh.dgid.raw, cmd.attr.grh.dgid, 16); + + ah = ib_create_ah(pd, &attr); + if (IS_ERR(ah)) { + ret = PTR_ERR(ah); + goto err_put; + } + + ah->uobject = uobj; + uobj->object = ah; + + ret = idr_add_uobj(&ib_uverbs_ah_idr, uobj); + if (ret) + goto err_destroy; + + resp.ah_handle = uobj->id; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_copy; + } + + put_pd_read(pd); + + mutex_lock(&file->mutex); + list_add_tail(&uobj->list, &file->ucontext->ah_list); + mutex_unlock(&file->mutex); + + uobj->live = 1; + + up_write(&uobj->mutex); + + return in_len; + +err_copy: + idr_remove_uobj(&ib_uverbs_ah_idr, uobj); + +err_destroy: + ib_destroy_ah(ah); + +err_put: + put_pd_read(pd); + +err: + put_uobj_write(uobj); + return ret; +} + +ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file, + const char __user *buf, int in_len, int out_len) +{ + struct ib_uverbs_destroy_ah cmd; + struct ib_ah *ah; + struct ib_uobject *uobj; + int ret; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + uobj = idr_write_uobj(&ib_uverbs_ah_idr, cmd.ah_handle, file->ucontext); + if (!uobj) + return -EINVAL; + ah = uobj->object; + + ret = ib_destroy_ah(ah); + if (!ret) + uobj->live = 0; + + put_uobj_write(uobj); + + if (ret) + return ret; + + idr_remove_uobj(&ib_uverbs_ah_idr, uobj); + + mutex_lock(&file->mutex); + list_del(&uobj->list); + mutex_unlock(&file->mutex); + + put_uobj(uobj); + + return in_len; +} + +ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_attach_mcast cmd; + struct ib_qp *qp; + struct ib_uqp_object *obj; + struct ib_uverbs_mcast_entry *mcast; + int ret; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + qp = idr_read_qp(cmd.qp_handle, file->ucontext); + if (!qp) + return -EINVAL; + + obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); + + list_for_each_entry(mcast, &obj->mcast_list, list) + if (cmd.mlid == mcast->lid && + !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) { + ret = 0; + goto out_put; + } + + mcast = kmalloc(sizeof *mcast, GFP_KERNEL); + if (!mcast) { + ret = -ENOMEM; + goto out_put; + } + + mcast->lid = cmd.mlid; + memcpy(mcast->gid.raw, cmd.gid, sizeof mcast->gid.raw); + + ret = ib_attach_mcast(qp, &mcast->gid, cmd.mlid); + if (!ret) + list_add_tail(&mcast->list, &obj->mcast_list); + else + kfree(mcast); + +out_put: + put_qp_read(qp); + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_detach_mcast cmd; + struct ib_uqp_object *obj; + struct ib_qp *qp; + struct ib_uverbs_mcast_entry *mcast; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + qp = idr_read_qp(cmd.qp_handle, file->ucontext); + if (!qp) + return -EINVAL; + + ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); + if (ret) + goto out_put; + + obj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); + + list_for_each_entry(mcast, &obj->mcast_list, list) + if (cmd.mlid == mcast->lid && + !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) { + list_del(&mcast->list); + kfree(mcast); + break; + } + +out_put: + put_qp_read(qp); + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_create_srq cmd; + struct ib_uverbs_create_srq_resp resp; + struct ib_udata udata; + struct ib_uevent_object *obj; + struct ib_pd *pd; + struct ib_srq *srq; + struct ib_srq_init_attr attr; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, + (unsigned long) cmd.response + sizeof resp, + in_len - sizeof cmd, out_len - sizeof resp); + + obj = kmalloc(sizeof *obj, GFP_KERNEL); + if (!obj) + return -ENOMEM; + + init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, &srq_lock_key); + down_write(&obj->uobject.mutex); + + pd = idr_read_pd(cmd.pd_handle, file->ucontext); + if (!pd) { + ret = -EINVAL; + goto err; + } + + attr.event_handler = ib_uverbs_srq_event_handler; + attr.srq_context = file; + attr.attr.max_wr = cmd.max_wr; + attr.attr.max_sge = cmd.max_sge; + attr.attr.srq_limit = cmd.srq_limit; + + obj->events_reported = 0; + INIT_LIST_HEAD(&obj->event_list); + + srq = pd->device->create_srq(pd, &attr, &udata); + if (IS_ERR(srq)) { + ret = PTR_ERR(srq); + goto err_put; + } + + srq->device = pd->device; + srq->pd = pd; + srq->uobject = &obj->uobject; + srq->event_handler = attr.event_handler; + srq->srq_context = attr.srq_context; + srq->xrc_cq = NULL; + srq->xrcd = NULL; + atomic_inc(&pd->usecnt); + atomic_set(&srq->usecnt, 0); + + obj->uobject.object = srq; + ret = idr_add_uobj(&ib_uverbs_srq_idr, &obj->uobject); + if (ret) + goto err_destroy; + + memset(&resp, 0, sizeof resp); + resp.srq_handle = obj->uobject.id; + resp.max_wr = attr.attr.max_wr; + resp.max_sge = attr.attr.max_sge; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_copy; + } + + put_pd_read(pd); + + mutex_lock(&file->mutex); + list_add_tail(&obj->uobject.list, &file->ucontext->srq_list); + mutex_unlock(&file->mutex); + + obj->uobject.live = 1; + + up_write(&obj->uobject.mutex); + + return in_len; + +err_copy: + idr_remove_uobj(&ib_uverbs_srq_idr, &obj->uobject); + +err_destroy: + ib_destroy_srq(srq); + +err_put: + put_pd_read(pd); + +err: + put_uobj_write(&obj->uobject); + return ret; +} + +ssize_t ib_uverbs_create_xrc_srq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_create_xrc_srq cmd; + struct ib_uverbs_create_srq_resp resp; + struct ib_udata udata; + struct ib_uevent_object *obj; + struct ib_pd *pd; + struct ib_srq *srq; + struct ib_cq *xrc_cq; + struct ib_xrcd *xrcd; + struct ib_srq_init_attr attr; + struct ib_uobject *xrcd_uobj; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, + (unsigned long) cmd.response + sizeof resp, + in_len - sizeof cmd, out_len - sizeof resp); + + obj = kmalloc(sizeof *obj, GFP_KERNEL); + if (!obj) + return -ENOMEM; + + init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, + &srq_lock_key); + down_write(&obj->uobject.mutex); + + pd = idr_read_pd(cmd.pd_handle, file->ucontext); + if (!pd) { + ret = -EINVAL; + goto err; + } + + xrc_cq = idr_read_cq(cmd.xrc_cq, file->ucontext, 0); + if (!xrc_cq) { + ret = -EINVAL; + goto err_put_pd; + } + + xrcd = idr_read_xrcd(cmd.xrcd_handle, file->ucontext, &xrcd_uobj); + if (!xrcd) { + ret = -EINVAL; + goto err_put_cq; + } + + + attr.event_handler = ib_uverbs_srq_event_handler; + attr.srq_context = file; + attr.attr.max_wr = cmd.max_wr; + attr.attr.max_sge = cmd.max_sge; + attr.attr.srq_limit = cmd.srq_limit; + + obj->events_reported = 0; + INIT_LIST_HEAD(&obj->event_list); + + srq = pd->device->create_xrc_srq(pd, xrc_cq, xrcd, &attr, &udata); + if (IS_ERR(srq)) { + ret = PTR_ERR(srq); + goto err_put; + } + + srq->device = pd->device; + srq->pd = pd; + srq->uobject = &obj->uobject; + srq->event_handler = attr.event_handler; + srq->srq_context = attr.srq_context; + srq->xrc_cq = xrc_cq; + srq->xrcd = xrcd; + atomic_inc(&pd->usecnt); + atomic_inc(&xrc_cq->usecnt); + atomic_inc(&xrcd->usecnt); + + atomic_set(&srq->usecnt, 0); + + obj->uobject.object = srq; + ret = idr_add_uobj(&ib_uverbs_srq_idr, &obj->uobject); + if (ret) + goto err_destroy; + + memset(&resp, 0, sizeof resp); + resp.srq_handle = obj->uobject.id; + resp.max_wr = attr.attr.max_wr; + resp.max_sge = attr.attr.max_sge; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_copy; + } + + put_xrcd_read(xrcd_uobj); + put_cq_read(xrc_cq); + put_pd_read(pd); + + mutex_lock(&file->mutex); + list_add_tail(&obj->uobject.list, &file->ucontext->srq_list); + mutex_unlock(&file->mutex); + + obj->uobject.live = 1; + + up_write(&obj->uobject.mutex); + + return in_len; + +err_copy: + idr_remove_uobj(&ib_uverbs_srq_idr, &obj->uobject); + +err_destroy: + ib_destroy_srq(srq); + +err_put: + put_xrcd_read(xrcd_uobj); + +err_put_cq: + put_cq_read(xrc_cq); + +err_put_pd: + put_pd_read(pd); + +err: + put_uobj_write(&obj->uobject); + return ret; +} + +ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_modify_srq cmd; + struct ib_udata udata; + struct ib_srq *srq; + struct ib_srq_attr attr; + int ret; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd, + out_len); + + srq = idr_read_srq(cmd.srq_handle, file->ucontext); + if (!srq) + return -EINVAL; + + attr.max_wr = cmd.max_wr; + attr.srq_limit = cmd.srq_limit; + + ret = srq->device->modify_srq(srq, &attr, cmd.attr_mask, &udata); + + put_srq_read(srq); + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file, + const char __user *buf, + int in_len, int out_len) +{ + struct ib_uverbs_query_srq cmd; + struct ib_uverbs_query_srq_resp resp; + struct ib_srq_attr attr; + struct ib_srq *srq; + int ret; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + srq = idr_read_srq(cmd.srq_handle, file->ucontext); + if (!srq) + return -EINVAL; + + ret = ib_query_srq(srq, &attr); + + put_srq_read(srq); + + if (ret) + return ret; + + memset(&resp, 0, sizeof resp); + + resp.max_wr = attr.max_wr; + resp.max_sge = attr.max_sge; + resp.srq_limit = attr.srq_limit; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + return -EFAULT; + + return in_len; +} + +ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_destroy_srq cmd; + struct ib_uverbs_destroy_srq_resp resp; + struct ib_uobject *uobj; + struct ib_srq *srq; + struct ib_uevent_object *obj; + int ret = -EINVAL; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + uobj = idr_write_uobj(&ib_uverbs_srq_idr, cmd.srq_handle, file->ucontext); + if (!uobj) + return -EINVAL; + srq = uobj->object; + obj = container_of(uobj, struct ib_uevent_object, uobject); + + ret = ib_destroy_srq(srq); + if (!ret) + uobj->live = 0; + + put_uobj_write(uobj); + + if (ret) + return ret; + + idr_remove_uobj(&ib_uverbs_srq_idr, uobj); + + mutex_lock(&file->mutex); + list_del(&uobj->list); + mutex_unlock(&file->mutex); + + ib_uverbs_release_uevent(file, obj); + + memset(&resp, 0, sizeof resp); + resp.events_reported = obj->events_reported; + + put_uobj(uobj); + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + + return ret ? ret : in_len; +} + +static struct inode *xrc_file2inode(struct file *f) +{ + return f->f_dentry->d_inode; +} + +struct xrcd_table_entry { + struct rb_node node; + struct inode *inode; + struct ib_xrcd *xrcd; +}; + +static int xrcd_table_insert(struct ib_device *dev, + struct inode *i_n, + struct ib_xrcd *xrcd) +{ + struct xrcd_table_entry *entry, *scan; + struct rb_node **p = &dev->ib_uverbs_xrcd_table.rb_node; + struct rb_node *parent = NULL; + + entry = kmalloc(sizeof(struct xrcd_table_entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + entry->inode = i_n; + entry->xrcd = xrcd; + + while (*p) { + parent = *p; + scan = rb_entry(parent, struct xrcd_table_entry, node); + + if (i_n < scan->inode) + p = &(*p)->rb_left; + else if (i_n > scan->inode) + p = &(*p)->rb_right; + else { + kfree(entry); + return -EEXIST; + } + } + + rb_link_node(&entry->node, parent, p); + rb_insert_color(&entry->node, &dev->ib_uverbs_xrcd_table); + igrab(i_n); + return 0; +} + +static struct xrcd_table_entry *xrcd_table_search(struct ib_device *dev, + struct inode *i_n) +{ + struct xrcd_table_entry *scan; + struct rb_node **p = &dev->ib_uverbs_xrcd_table.rb_node; + struct rb_node *parent = NULL; + + while (*p) { + parent = *p; + scan = rb_entry(parent, struct xrcd_table_entry, node); + + if (i_n < scan->inode) + p = &(*p)->rb_left; + else if (i_n > scan->inode) + p = &(*p)->rb_right; + else + return scan; + } + return NULL; +} + +static int find_xrcd(struct ib_device *dev, struct inode *i_n, + struct ib_xrcd **xrcd) +{ + struct xrcd_table_entry *entry; + + entry = xrcd_table_search(dev, i_n); + if (!entry) + return -EINVAL; + + *xrcd = entry->xrcd; + return 0; +} + + +static void xrcd_table_delete(struct ib_device *dev, + struct inode *i_n) +{ + struct xrcd_table_entry *entry = xrcd_table_search(dev, i_n); + + if (entry) { + iput(i_n); + rb_erase(&entry->node, &dev->ib_uverbs_xrcd_table); + kfree(entry); + } +} + +ssize_t ib_uverbs_open_xrc_domain(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_open_xrc_domain cmd; + struct ib_uverbs_open_xrc_domain_resp resp; + struct ib_udata udata; + struct ib_uobject *uobj; + struct ib_uxrcd_object *xrcd_uobj; + struct ib_xrcd *xrcd = NULL; + struct file *f = NULL; + struct inode *inode = NULL; + int ret = 0; + int new_xrcd = 0; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + INIT_UDATA(&udata, buf + sizeof cmd, + (unsigned long) cmd.response + sizeof resp, + in_len - sizeof cmd, out_len - sizeof resp); + + mutex_lock(&file->device->ib_dev->xrcd_table_mutex); + if (cmd.fd != (u32) (-1)) { + /* search for file descriptor */ + f = fget(cmd.fd); + if (!f) { + ret = -EBADF; + goto err_table_mutex_unlock; + } + + inode = xrc_file2inode(f); + if (!inode) { + ret = -EBADF; + goto err_table_mutex_unlock; + } + + ret = find_xrcd(file->device->ib_dev, inode, &xrcd); + if (ret && !(cmd.oflags & O_CREAT)) { + /* no file descriptor. Need CREATE flag */ + ret = -EAGAIN; + goto err_table_mutex_unlock; + } + + if (xrcd && cmd.oflags & O_EXCL) { + ret = -EINVAL; + goto err_table_mutex_unlock; + } + } + + xrcd_uobj = kmalloc(sizeof *xrcd_uobj, GFP_KERNEL); + if (!xrcd_uobj) { + ret = -ENOMEM; + goto err_table_mutex_unlock; + } + + uobj = &xrcd_uobj->uobject; + init_uobj(uobj, 0, file->ucontext, &pd_lock_key); + down_write(&uobj->mutex); + + if (!xrcd) { + xrcd = file->device->ib_dev->alloc_xrcd(file->device->ib_dev, + file->ucontext, &udata); + if (IS_ERR(xrcd)) { + ret = PTR_ERR(xrcd); + goto err; + } + xrcd->uobject = (cmd.fd == -1) ? uobj : NULL; + xrcd->inode = inode; + xrcd->device = file->device->ib_dev; + atomic_set(&xrcd->usecnt, 0); + new_xrcd = 1; + } + + uobj->object = xrcd; + ret = idr_add_uobj(&ib_uverbs_xrc_domain_idr, uobj); + if (ret) + goto err_idr; + + memset(&resp, 0, sizeof resp); + resp.xrcd_handle = uobj->id; + + if (inode) { + if (new_xrcd) { + /* create new inode/xrcd table entry */ + ret = xrcd_table_insert(file->device->ib_dev, inode, xrcd); + if (ret) + goto err_insert_xrcd; + } + atomic_inc(&xrcd->usecnt); + } + if (f) + fput(f); + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + ret = -EFAULT; + goto err_copy; + } + + INIT_LIST_HEAD(&xrcd_uobj->xrc_reg_qp_list); + + mutex_lock(&file->mutex); + list_add_tail(&uobj->list, &file->ucontext->xrc_domain_list); + mutex_unlock(&file->mutex); + + uobj->live = 1; + + up_write(&uobj->mutex); + + mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); + return in_len; + +err_copy: + + if (inode) { + if (new_xrcd) + xrcd_table_delete(file->device->ib_dev, inode); + atomic_dec(&xrcd->usecnt); + } + +err_insert_xrcd: + idr_remove_uobj(&ib_uverbs_xrc_domain_idr, uobj); + +err_idr: + ib_dealloc_xrcd(xrcd); + +err: + put_uobj_write(uobj); + +err_table_mutex_unlock: + + if (f) + fput(f); + mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); + return ret; +} + +ssize_t ib_uverbs_close_xrc_domain(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_close_xrc_domain cmd; + struct ib_uobject *uobj, *t_uobj; + struct ib_uxrcd_object *xrcd_uobj; + struct ib_xrcd *xrcd = NULL; + struct inode *inode = NULL; + int ret = 0; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + mutex_lock(&file->device->ib_dev->xrcd_table_mutex); + uobj = idr_write_uobj(&ib_uverbs_xrc_domain_idr, cmd.xrcd_handle, + file->ucontext); + if (!uobj) { + ret = -EINVAL; + goto err_unlock_mutex; + } + + mutex_lock(&file->mutex); + if (!ret) { + list_for_each_entry(t_uobj, &file->ucontext->qp_list, list) { + struct ib_qp *qp = t_uobj->object; + if (qp->xrcd && qp->xrcd == uobj->object) { + ret = -EBUSY; + break; + } + } + } + if (!ret) { + list_for_each_entry(t_uobj, &file->ucontext->srq_list, list) { + struct ib_srq *srq = t_uobj->object; + if (srq->xrcd && srq->xrcd == uobj->object) { + ret = -EBUSY; + break; + } + } + } + mutex_unlock(&file->mutex); + if (ret) { + put_uobj_write(uobj); + goto err_unlock_mutex; + } + + xrcd_uobj = container_of(uobj, struct ib_uxrcd_object, uobject); + if (!list_empty(&xrcd_uobj->xrc_reg_qp_list)) { + ret = -EBUSY; + put_uobj_write(uobj); + goto err_unlock_mutex; + } + + xrcd = (struct ib_xrcd *) (uobj->object); + inode = xrcd->inode; + + if (inode) + atomic_dec(&xrcd->usecnt); + + ret = ib_dealloc_xrcd(uobj->object); + if (!ret) + uobj->live = 0; + + put_uobj_write(uobj); + + if (ret && !inode) + goto err_unlock_mutex; + + if (!ret && inode) + xrcd_table_delete(file->device->ib_dev, inode); + + idr_remove_uobj(&ib_uverbs_xrc_domain_idr, uobj); + + mutex_lock(&file->mutex); + list_del(&uobj->list); + mutex_unlock(&file->mutex); + + put_uobj(uobj); + + mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); + return in_len; + +err_unlock_mutex: + mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); + return ret; +} + +void ib_uverbs_dealloc_xrcd(struct ib_device *ib_dev, + struct ib_xrcd *xrcd) +{ + struct inode *inode = NULL; + int ret = 0; + + inode = xrcd->inode; + if (inode) + atomic_dec(&xrcd->usecnt); + + ret = ib_dealloc_xrcd(xrcd); + if (!ret && inode) + xrcd_table_delete(ib_dev, inode); +} + +ssize_t ib_uverbs_create_xrc_rcv_qp(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_create_xrc_rcv_qp cmd; + struct ib_uverbs_create_xrc_rcv_qp_resp resp; + struct ib_uxrc_rcv_object *obj; + struct ib_qp_init_attr init_attr; + struct ib_xrcd *xrcd; + struct ib_uobject *uobj; + struct ib_uxrcd_object *xrcd_uobj; + u32 qp_num; + int err; + + if (out_len < sizeof resp) + return -ENOSPC; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + obj = kzalloc(sizeof *obj, GFP_KERNEL); + if (!obj) + return -ENOMEM; + + xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj); + if (!xrcd) { + err = -EINVAL; + goto err_out; + } + + init_attr.event_handler = ib_uverbs_xrc_rcv_qp_event_handler; + init_attr.qp_context = file; + init_attr.srq = NULL; + init_attr.sq_sig_type = + cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR; + init_attr.qp_type = IB_QPT_XRC; + init_attr.xrc_domain = xrcd; + + init_attr.cap.max_send_wr = 1; + init_attr.cap.max_recv_wr = 0; + init_attr.cap.max_send_sge = 1; + init_attr.cap.max_recv_sge = 0; + init_attr.cap.max_inline_data = 0; + + err = xrcd->device->create_xrc_rcv_qp(&init_attr, &qp_num); + if (err) + goto err_put; + + memset(&resp, 0, sizeof resp); + resp.qpn = qp_num; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) { + err = -EFAULT; + goto err_destroy; + } + + atomic_inc(&xrcd->usecnt); + put_xrcd_read(uobj); + obj->qp_num = qp_num; + obj->domain_handle = cmd.xrc_domain_handle; + xrcd_uobj = container_of(uobj, struct ib_uxrcd_object, uobject); + mutex_lock(&file->device->ib_dev->xrcd_table_mutex); + list_add_tail(&obj->list, &xrcd_uobj->xrc_reg_qp_list); + mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); + + return in_len; + +err_destroy: + xrcd->device->unreg_xrc_rcv_qp(xrcd, file, qp_num); +err_put: + put_xrcd_read(uobj); +err_out: + kfree(obj); + return err; +} + +ssize_t ib_uverbs_modify_xrc_rcv_qp(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_modify_xrc_rcv_qp cmd; + struct ib_qp_attr *attr; + struct ib_xrcd *xrcd; + struct ib_uobject *uobj; + int err; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + attr = kzalloc(sizeof *attr, GFP_KERNEL); + if (!attr) + return -ENOMEM; + + xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj); + if (!xrcd) { + kfree(attr); + return -EINVAL; + } + + attr->qp_state = cmd.qp_state; + attr->cur_qp_state = cmd.cur_qp_state; + attr->qp_access_flags = cmd.qp_access_flags; + attr->pkey_index = cmd.pkey_index; + attr->port_num = cmd.port_num; + attr->path_mtu = cmd.path_mtu; + attr->path_mig_state = cmd.path_mig_state; + attr->qkey = cmd.qkey; + attr->rq_psn = cmd.rq_psn; + attr->sq_psn = cmd.sq_psn; + attr->dest_qp_num = cmd.dest_qp_num; + attr->alt_pkey_index = cmd.alt_pkey_index; + attr->en_sqd_async_notify = cmd.en_sqd_async_notify; + attr->max_rd_atomic = cmd.max_rd_atomic; + attr->max_dest_rd_atomic = cmd.max_dest_rd_atomic; + attr->min_rnr_timer = cmd.min_rnr_timer; + attr->port_num = cmd.port_num; + attr->timeout = cmd.timeout; + attr->retry_cnt = cmd.retry_cnt; + attr->rnr_retry = cmd.rnr_retry; + attr->alt_port_num = cmd.alt_port_num; + attr->alt_timeout = cmd.alt_timeout; + + memcpy(attr->ah_attr.grh.dgid.raw, cmd.dest.dgid, 16); + attr->ah_attr.grh.flow_label = cmd.dest.flow_label; + attr->ah_attr.grh.sgid_index = cmd.dest.sgid_index; + attr->ah_attr.grh.hop_limit = cmd.dest.hop_limit; + attr->ah_attr.grh.traffic_class = cmd.dest.traffic_class; + attr->ah_attr.dlid = cmd.dest.dlid; + attr->ah_attr.sl = cmd.dest.sl; + attr->ah_attr.src_path_bits = cmd.dest.src_path_bits; + attr->ah_attr.static_rate = cmd.dest.static_rate; + attr->ah_attr.ah_flags = cmd.dest.is_global ? IB_AH_GRH : 0; + attr->ah_attr.port_num = cmd.dest.port_num; + + memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd.alt_dest.dgid, 16); + attr->alt_ah_attr.grh.flow_label = cmd.alt_dest.flow_label; + attr->alt_ah_attr.grh.sgid_index = cmd.alt_dest.sgid_index; + attr->alt_ah_attr.grh.hop_limit = cmd.alt_dest.hop_limit; + attr->alt_ah_attr.grh.traffic_class = cmd.alt_dest.traffic_class; + attr->alt_ah_attr.dlid = cmd.alt_dest.dlid; + attr->alt_ah_attr.sl = cmd.alt_dest.sl; + attr->alt_ah_attr.src_path_bits = cmd.alt_dest.src_path_bits; + attr->alt_ah_attr.static_rate = cmd.alt_dest.static_rate; + attr->alt_ah_attr.ah_flags = cmd.alt_dest.is_global ? IB_AH_GRH : 0; + attr->alt_ah_attr.port_num = cmd.alt_dest.port_num; + + err = xrcd->device->modify_xrc_rcv_qp(xrcd, cmd.qp_num, attr, cmd.attr_mask); + put_xrcd_read(uobj); + kfree(attr); + return err ? err : in_len; +} + +ssize_t ib_uverbs_query_xrc_rcv_qp(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_query_xrc_rcv_qp cmd; + struct ib_uverbs_query_qp_resp resp; + struct ib_qp_attr *attr; + struct ib_qp_init_attr *init_attr; + struct ib_xrcd *xrcd; + struct ib_uobject *uobj; + int ret; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + attr = kmalloc(sizeof *attr, GFP_KERNEL); + init_attr = kmalloc(sizeof *init_attr, GFP_KERNEL); + if (!attr || !init_attr) { + ret = -ENOMEM; + goto out; + } + + xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj); + if (!xrcd) { + ret = -EINVAL; + goto out; + } + + ret = xrcd->device->query_xrc_rcv_qp(xrcd, cmd.qp_num, attr, + cmd.attr_mask, init_attr); + + put_xrcd_read(uobj); + + if (ret) + goto out; + + memset(&resp, 0, sizeof resp); + resp.qp_state = attr->qp_state; + resp.cur_qp_state = attr->cur_qp_state; + resp.path_mtu = attr->path_mtu; + resp.path_mig_state = attr->path_mig_state; + resp.qkey = attr->qkey; + resp.rq_psn = attr->rq_psn; + resp.sq_psn = attr->sq_psn; + resp.dest_qp_num = attr->dest_qp_num; + resp.qp_access_flags = attr->qp_access_flags; + resp.pkey_index = attr->pkey_index; + resp.alt_pkey_index = attr->alt_pkey_index; + resp.sq_draining = attr->sq_draining; + resp.max_rd_atomic = attr->max_rd_atomic; + resp.max_dest_rd_atomic = attr->max_dest_rd_atomic; + resp.min_rnr_timer = attr->min_rnr_timer; + resp.port_num = attr->port_num; + resp.timeout = attr->timeout; + resp.retry_cnt = attr->retry_cnt; + resp.rnr_retry = attr->rnr_retry; + resp.alt_port_num = attr->alt_port_num; + resp.alt_timeout = attr->alt_timeout; + + memcpy(resp.dest.dgid, attr->ah_attr.grh.dgid.raw, 16); + resp.dest.flow_label = attr->ah_attr.grh.flow_label; + resp.dest.sgid_index = attr->ah_attr.grh.sgid_index; + resp.dest.hop_limit = attr->ah_attr.grh.hop_limit; + resp.dest.traffic_class = attr->ah_attr.grh.traffic_class; + resp.dest.dlid = attr->ah_attr.dlid; + resp.dest.sl = attr->ah_attr.sl; + resp.dest.src_path_bits = attr->ah_attr.src_path_bits; + resp.dest.static_rate = attr->ah_attr.static_rate; + resp.dest.is_global = !!(attr->ah_attr.ah_flags & IB_AH_GRH); + resp.dest.port_num = attr->ah_attr.port_num; + + memcpy(resp.alt_dest.dgid, attr->alt_ah_attr.grh.dgid.raw, 16); + resp.alt_dest.flow_label = attr->alt_ah_attr.grh.flow_label; + resp.alt_dest.sgid_index = attr->alt_ah_attr.grh.sgid_index; + resp.alt_dest.hop_limit = attr->alt_ah_attr.grh.hop_limit; + resp.alt_dest.traffic_class = attr->alt_ah_attr.grh.traffic_class; + resp.alt_dest.dlid = attr->alt_ah_attr.dlid; + resp.alt_dest.sl = attr->alt_ah_attr.sl; + resp.alt_dest.src_path_bits = attr->alt_ah_attr.src_path_bits; + resp.alt_dest.static_rate = attr->alt_ah_attr.static_rate; + resp.alt_dest.is_global = !!(attr->alt_ah_attr.ah_flags & IB_AH_GRH); + resp.alt_dest.port_num = attr->alt_ah_attr.port_num; + + resp.max_send_wr = init_attr->cap.max_send_wr; + resp.max_recv_wr = init_attr->cap.max_recv_wr; + resp.max_send_sge = init_attr->cap.max_send_sge; + resp.max_recv_sge = init_attr->cap.max_recv_sge; + resp.max_inline_data = init_attr->cap.max_inline_data; + resp.sq_sig_all = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR; + + if (copy_to_user((void __user *) (unsigned long) cmd.response, + &resp, sizeof resp)) + ret = -EFAULT; + +out: + kfree(attr); + kfree(init_attr); + + return ret ? ret : in_len; +} + +ssize_t ib_uverbs_reg_xrc_rcv_qp(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_reg_xrc_rcv_qp cmd; + struct ib_uxrc_rcv_object *qp_obj, *tmp; + struct ib_xrcd *xrcd; + struct ib_uobject *uobj; + struct ib_uxrcd_object *xrcd_uobj; + int ret; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + qp_obj = kmalloc(sizeof *qp_obj, GFP_KERNEL); + if (!qp_obj) + return -ENOMEM; + + xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj); + if (!xrcd) { + ret = -EINVAL; + goto err_out; + } + + ret = xrcd->device->reg_xrc_rcv_qp(xrcd, file, cmd.qp_num); + if (ret) + goto err_put; + + xrcd_uobj = container_of(uobj, struct ib_uxrcd_object, uobject); + mutex_lock(&file->device->ib_dev->xrcd_table_mutex); + list_for_each_entry(tmp, &xrcd_uobj->xrc_reg_qp_list, list) + if (cmd.qp_num == tmp->qp_num) { + kfree(qp_obj); + mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); + put_xrcd_read(uobj); + return in_len; + } + qp_obj->qp_num = cmd.qp_num; + qp_obj->domain_handle = cmd.xrc_domain_handle; + list_add_tail(&qp_obj->list, &xrcd_uobj->xrc_reg_qp_list); + mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); + atomic_inc(&xrcd->usecnt); + put_xrcd_read(uobj); + return in_len; + +err_put: + put_xrcd_read(uobj); +err_out: + + kfree(qp_obj); + return ret; +} + +int ib_uverbs_cleanup_xrc_rcv_qp(struct ib_uverbs_file *file, + struct ib_xrcd *xrcd, u32 qp_num) +{ + int err; + err = xrcd->device->unreg_xrc_rcv_qp(xrcd, file, qp_num); + if (!err) + atomic_dec(&xrcd->usecnt); + return err; +} + +ssize_t ib_uverbs_unreg_xrc_rcv_qp(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_unreg_xrc_rcv_qp cmd; + struct ib_uxrc_rcv_object *qp_obj, *tmp; + struct ib_xrcd *xrcd; + struct ib_uobject *uobj; + struct ib_uxrcd_object *xrcd_uobj; + int ret; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + + xrcd = idr_read_xrcd(cmd.xrc_domain_handle, file->ucontext, &uobj); + if (!xrcd) + return -EINVAL; + + ret = xrcd->device->unreg_xrc_rcv_qp(xrcd, file, cmd.qp_num); + if (ret) { + put_xrcd_read(uobj); + return -EINVAL; + } + atomic_dec(&xrcd->usecnt); + + xrcd_uobj = container_of(uobj, struct ib_uxrcd_object, uobject); + mutex_lock(&file->device->ib_dev->xrcd_table_mutex); + list_for_each_entry_safe(qp_obj, tmp, &xrcd_uobj->xrc_reg_qp_list, list) + if (cmd.qp_num == qp_obj->qp_num) { + list_del(&qp_obj->list); + kfree(qp_obj); + break; + } + mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); + put_xrcd_read(uobj); + return in_len; +} diff --git a/sys/ofed/drivers/infiniband/core/uverbs_main.c b/sys/ofed/drivers/infiniband/core/uverbs_main.c new file mode 100644 index 000000000000..380abd314dc6 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/uverbs_main.c @@ -0,0 +1,1012 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "uverbs.h" + +MODULE_AUTHOR("Roland Dreier"); +MODULE_DESCRIPTION("InfiniBand userspace verbs access"); +MODULE_LICENSE("Dual BSD/GPL"); + +#define INFINIBANDEVENTFS_MAGIC 0x49426576 /* "IBev" */ + +enum { + IB_UVERBS_MAJOR = 231, + IB_UVERBS_BASE_MINOR = 192, + IB_UVERBS_MAX_DEVICES = 32 +}; + +#define IB_UVERBS_BASE_DEV MKDEV(IB_UVERBS_MAJOR, IB_UVERBS_BASE_MINOR) + +static struct class *uverbs_class; + +DEFINE_SPINLOCK(ib_uverbs_idr_lock); +DEFINE_IDR(ib_uverbs_pd_idr); +DEFINE_IDR(ib_uverbs_mr_idr); +DEFINE_IDR(ib_uverbs_mw_idr); +DEFINE_IDR(ib_uverbs_ah_idr); +DEFINE_IDR(ib_uverbs_cq_idr); +DEFINE_IDR(ib_uverbs_qp_idr); +DEFINE_IDR(ib_uverbs_srq_idr); +DEFINE_IDR(ib_uverbs_xrc_domain_idr); + +static spinlock_t map_lock; +static struct ib_uverbs_device *dev_table[IB_UVERBS_MAX_DEVICES]; +static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); + +static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) = { + [IB_USER_VERBS_CMD_GET_CONTEXT] = ib_uverbs_get_context, + [IB_USER_VERBS_CMD_QUERY_DEVICE] = ib_uverbs_query_device, + [IB_USER_VERBS_CMD_QUERY_PORT] = ib_uverbs_query_port, + [IB_USER_VERBS_CMD_ALLOC_PD] = ib_uverbs_alloc_pd, + [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd, + [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr, + [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr, + [IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL] = ib_uverbs_create_comp_channel, + [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq, + [IB_USER_VERBS_CMD_RESIZE_CQ] = ib_uverbs_resize_cq, + [IB_USER_VERBS_CMD_POLL_CQ] = ib_uverbs_poll_cq, + [IB_USER_VERBS_CMD_REQ_NOTIFY_CQ] = ib_uverbs_req_notify_cq, + [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq, + [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp, + [IB_USER_VERBS_CMD_QUERY_QP] = ib_uverbs_query_qp, + [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp, + [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp, + [IB_USER_VERBS_CMD_POST_SEND] = ib_uverbs_post_send, + [IB_USER_VERBS_CMD_POST_RECV] = ib_uverbs_post_recv, + [IB_USER_VERBS_CMD_POST_SRQ_RECV] = ib_uverbs_post_srq_recv, + [IB_USER_VERBS_CMD_CREATE_AH] = ib_uverbs_create_ah, + [IB_USER_VERBS_CMD_DESTROY_AH] = ib_uverbs_destroy_ah, + [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast, + [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast, + [IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq, + [IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq, + [IB_USER_VERBS_CMD_QUERY_SRQ] = ib_uverbs_query_srq, + [IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq, + [IB_USER_VERBS_CMD_CREATE_XRC_SRQ] = ib_uverbs_create_xrc_srq, + [IB_USER_VERBS_CMD_OPEN_XRC_DOMAIN] = ib_uverbs_open_xrc_domain, + [IB_USER_VERBS_CMD_CLOSE_XRC_DOMAIN] = ib_uverbs_close_xrc_domain, + [IB_USER_VERBS_CMD_CREATE_XRC_RCV_QP] = ib_uverbs_create_xrc_rcv_qp, + [IB_USER_VERBS_CMD_MODIFY_XRC_RCV_QP] = ib_uverbs_modify_xrc_rcv_qp, + [IB_USER_VERBS_CMD_QUERY_XRC_RCV_QP] = ib_uverbs_query_xrc_rcv_qp, + [IB_USER_VERBS_CMD_REG_XRC_RCV_QP] = ib_uverbs_reg_xrc_rcv_qp, + [IB_USER_VERBS_CMD_UNREG_XRC_RCV_QP] = ib_uverbs_unreg_xrc_rcv_qp, +}; + +#ifdef __linux__ +/* BSD Does not require a fake mountpoint for all files. */ +static struct vfsmount *uverbs_event_mnt; +#endif + +static void ib_uverbs_add_one(struct ib_device *device); +static void ib_uverbs_remove_one(struct ib_device *device); + +static void ib_uverbs_release_dev(struct kref *ref) +{ + struct ib_uverbs_device *dev = + container_of(ref, struct ib_uverbs_device, ref); + + complete(&dev->comp); +} + +static void ib_uverbs_release_event_file(struct kref *ref) +{ + struct ib_uverbs_event_file *file = + container_of(ref, struct ib_uverbs_event_file, ref); + + kfree(file); +} + +void ib_uverbs_release_ucq(struct ib_uverbs_file *file, + struct ib_uverbs_event_file *ev_file, + struct ib_ucq_object *uobj) +{ + struct ib_uverbs_event *evt, *tmp; + + if (ev_file) { + spin_lock_irq(&ev_file->lock); + list_for_each_entry_safe(evt, tmp, &uobj->comp_list, obj_list) { + list_del(&evt->list); + kfree(evt); + } + spin_unlock_irq(&ev_file->lock); + + kref_put(&ev_file->ref, ib_uverbs_release_event_file); + } + + spin_lock_irq(&file->async_file->lock); + list_for_each_entry_safe(evt, tmp, &uobj->async_list, obj_list) { + list_del(&evt->list); + kfree(evt); + } + spin_unlock_irq(&file->async_file->lock); +} + +void ib_uverbs_release_uevent(struct ib_uverbs_file *file, + struct ib_uevent_object *uobj) +{ + struct ib_uverbs_event *evt, *tmp; + + spin_lock_irq(&file->async_file->lock); + list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { + list_del(&evt->list); + kfree(evt); + } + spin_unlock_irq(&file->async_file->lock); +} + +static void ib_uverbs_detach_umcast(struct ib_qp *qp, + struct ib_uqp_object *uobj) +{ + struct ib_uverbs_mcast_entry *mcast, *tmp; + + list_for_each_entry_safe(mcast, tmp, &uobj->mcast_list, list) { + ib_detach_mcast(qp, &mcast->gid, mcast->lid); + list_del(&mcast->list); + kfree(mcast); + } +} + +static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, + struct ib_ucontext *context) +{ + struct ib_uobject *uobj, *tmp; + + if (!context) + return 0; + + context->closing = 1; + + list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) { + struct ib_ah *ah = uobj->object; + + idr_remove_uobj(&ib_uverbs_ah_idr, uobj); + ib_destroy_ah(ah); + kfree(uobj); + } + + list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { + struct ib_qp *qp = uobj->object; + struct ib_uqp_object *uqp = + container_of(uobj, struct ib_uqp_object, uevent.uobject); + + idr_remove_uobj(&ib_uverbs_qp_idr, uobj); + ib_uverbs_detach_umcast(qp, uqp); + ib_destroy_qp(qp); + ib_uverbs_release_uevent(file, &uqp->uevent); + kfree(uqp); + } + + + list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { + struct ib_srq *srq = uobj->object; + struct ib_uevent_object *uevent = + container_of(uobj, struct ib_uevent_object, uobject); + + idr_remove_uobj(&ib_uverbs_srq_idr, uobj); + ib_destroy_srq(srq); + ib_uverbs_release_uevent(file, uevent); + kfree(uevent); + } + + list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { + struct ib_cq *cq = uobj->object; + struct ib_uverbs_event_file *ev_file = cq->cq_context; + struct ib_ucq_object *ucq = + container_of(uobj, struct ib_ucq_object, uobject); + + idr_remove_uobj(&ib_uverbs_cq_idr, uobj); + ib_destroy_cq(cq); + ib_uverbs_release_ucq(file, ev_file, ucq); + kfree(ucq); + } + + /* XXX Free MWs */ + + list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) { + struct ib_mr *mr = uobj->object; + + idr_remove_uobj(&ib_uverbs_mr_idr, uobj); + ib_dereg_mr(mr); + kfree(uobj); + } + + mutex_lock(&file->device->ib_dev->xrcd_table_mutex); + list_for_each_entry_safe(uobj, tmp, &context->xrc_domain_list, list) { + struct ib_xrcd *xrcd = uobj->object; + struct ib_uxrc_rcv_object *xrc_qp_obj, *tmp1; + struct ib_uxrcd_object *xrcd_uobj = + container_of(uobj, struct ib_uxrcd_object, uobject); + + list_for_each_entry_safe(xrc_qp_obj, tmp1, + &xrcd_uobj->xrc_reg_qp_list, list) { + list_del(&xrc_qp_obj->list); + ib_uverbs_cleanup_xrc_rcv_qp(file, xrcd, + xrc_qp_obj->qp_num); + kfree(xrc_qp_obj); + } + + idr_remove_uobj(&ib_uverbs_xrc_domain_idr, uobj); + ib_uverbs_dealloc_xrcd(file->device->ib_dev, xrcd); + kfree(uobj); + } + mutex_unlock(&file->device->ib_dev->xrcd_table_mutex); + + list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) { + struct ib_pd *pd = uobj->object; + + idr_remove_uobj(&ib_uverbs_pd_idr, uobj); + ib_dealloc_pd(pd); + kfree(uobj); + } + + return context->device->dealloc_ucontext(context); +} + +static void ib_uverbs_release_file(struct kref *ref) +{ + struct ib_uverbs_file *file = + container_of(ref, struct ib_uverbs_file, ref); + + module_put(file->device->ib_dev->owner); + kref_put(&file->device->ref, ib_uverbs_release_dev); + + kfree(file); +} + +static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf, + size_t count, loff_t *pos) +{ + struct ib_uverbs_event_file *file = filp->private_data; + struct ib_uverbs_event *event; + int eventsz; + int ret = 0; + + spin_lock_irq(&file->lock); + + while (list_empty(&file->event_list)) { + spin_unlock_irq(&file->lock); + + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + + if (wait_event_interruptible(file->poll_wait, + !list_empty(&file->event_list))) + return -ERESTARTSYS; + + spin_lock_irq(&file->lock); + } + + event = list_entry(file->event_list.next, struct ib_uverbs_event, list); + + if (file->is_async) + eventsz = sizeof (struct ib_uverbs_async_event_desc); + else + eventsz = sizeof (struct ib_uverbs_comp_event_desc); + + if (eventsz > count) { + ret = -EINVAL; + event = NULL; + } else { + list_del(file->event_list.next); + if (event->counter) { + ++(*event->counter); + list_del(&event->obj_list); + } + } + + spin_unlock_irq(&file->lock); + + if (event) { + if (copy_to_user(buf, event, eventsz)) + ret = -EFAULT; + else + ret = eventsz; + } + + kfree(event); + + return ret; +} + +static unsigned int ib_uverbs_event_poll(struct file *filp, + struct poll_table_struct *wait) +{ + unsigned int pollflags = 0; + struct ib_uverbs_event_file *file = filp->private_data; + + file->filp = filp; + poll_wait(filp, &file->poll_wait, wait); + + spin_lock_irq(&file->lock); + if (!list_empty(&file->event_list)) + pollflags = POLLIN | POLLRDNORM; + spin_unlock_irq(&file->lock); + + return pollflags; +} + +static int ib_uverbs_event_fasync(int fd, struct file *filp, int on) +{ + struct ib_uverbs_event_file *file = filp->private_data; + + return fasync_helper(fd, filp, on, &file->async_queue); +} + +static int ib_uverbs_event_close(struct inode *inode, struct file *filp) +{ + struct ib_uverbs_event_file *file = filp->private_data; + struct ib_uverbs_event *entry, *tmp; + + spin_lock_irq(&file->lock); + file->is_closed = 1; + list_for_each_entry_safe(entry, tmp, &file->event_list, list) { + if (entry->counter) + list_del(&entry->obj_list); + kfree(entry); + } + spin_unlock_irq(&file->lock); + + if (file->is_async) { + ib_unregister_event_handler(&file->uverbs_file->event_handler); + kref_put(&file->uverbs_file->ref, ib_uverbs_release_file); + } + kref_put(&file->ref, ib_uverbs_release_event_file); + + return 0; +} + +static const struct file_operations uverbs_event_fops = { + .owner = THIS_MODULE, + .read = ib_uverbs_event_read, + .poll = ib_uverbs_event_poll, + .release = ib_uverbs_event_close, + .fasync = ib_uverbs_event_fasync +}; + +void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) +{ + struct ib_uverbs_event_file *file = cq_context; + struct ib_ucq_object *uobj; + struct ib_uverbs_event *entry; + unsigned long flags; + + if (!file) + return; + + spin_lock_irqsave(&file->lock, flags); + if (file->is_closed) { + spin_unlock_irqrestore(&file->lock, flags); + return; + } + + entry = kmalloc(sizeof *entry, GFP_ATOMIC); + if (!entry) { + spin_unlock_irqrestore(&file->lock, flags); + return; + } + + uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); + + entry->desc.comp.cq_handle = cq->uobject->user_handle; + entry->counter = &uobj->comp_events_reported; + + list_add_tail(&entry->list, &file->event_list); + list_add_tail(&entry->obj_list, &uobj->comp_list); + spin_unlock_irqrestore(&file->lock, flags); + + wake_up_interruptible(&file->poll_wait); + if (file->filp) + selwakeup(&file->filp->f_selinfo); + kill_fasync(&file->async_queue, SIGIO, POLL_IN); +} + +static void ib_uverbs_async_handler(struct ib_uverbs_file *file, + __u64 element, __u64 event, + struct list_head *obj_list, + u32 *counter) +{ + struct ib_uverbs_event *entry; + unsigned long flags; + + spin_lock_irqsave(&file->async_file->lock, flags); + if (file->async_file->is_closed) { + spin_unlock_irqrestore(&file->async_file->lock, flags); + return; + } + + entry = kmalloc(sizeof *entry, GFP_ATOMIC); + if (!entry) { + spin_unlock_irqrestore(&file->async_file->lock, flags); + return; + } + + entry->desc.async.element = element; + entry->desc.async.event_type = event; + entry->counter = counter; + + list_add_tail(&entry->list, &file->async_file->event_list); + if (obj_list) + list_add_tail(&entry->obj_list, obj_list); + spin_unlock_irqrestore(&file->async_file->lock, flags); + + wake_up_interruptible(&file->async_file->poll_wait); + if (file->async_file->filp) + selwakeup(&file->async_file->filp->f_selinfo); + kill_fasync(&file->async_file->async_queue, SIGIO, POLL_IN); +} + +void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr) +{ + struct ib_ucq_object *uobj = container_of(event->element.cq->uobject, + struct ib_ucq_object, uobject); + + ib_uverbs_async_handler(uobj->uverbs_file, uobj->uobject.user_handle, + event->event, &uobj->async_list, + &uobj->async_events_reported); +} + +void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr) +{ + struct ib_uevent_object *uobj; + + uobj = container_of(event->element.qp->uobject, + struct ib_uevent_object, uobject); + + ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, + event->event, &uobj->event_list, + &uobj->events_reported); +} + +void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr) +{ + struct ib_uevent_object *uobj; + + uobj = container_of(event->element.srq->uobject, + struct ib_uevent_object, uobject); + + ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, + event->event, &uobj->event_list, + &uobj->events_reported); +} + +void ib_uverbs_event_handler(struct ib_event_handler *handler, + struct ib_event *event) +{ + struct ib_uverbs_file *file = + container_of(handler, struct ib_uverbs_file, event_handler); + + ib_uverbs_async_handler(file, event->element.port_num, event->event, + NULL, NULL); +} + +void ib_uverbs_xrc_rcv_qp_event_handler(struct ib_event *event, + void *context_ptr) +{ + ib_uverbs_async_handler(context_ptr, event->element.xrc_qp_num, + event->event, NULL, NULL); +} + +struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, + int is_async, int *fd) +{ + struct ib_uverbs_event_file *ev_file; + struct file *filp; + int ret; + + ev_file = kmalloc(sizeof *ev_file, GFP_KERNEL); + if (!ev_file) + return ERR_PTR(-ENOMEM); + + kref_init(&ev_file->ref); + spin_lock_init(&ev_file->lock); + INIT_LIST_HEAD(&ev_file->event_list); + init_waitqueue_head(&ev_file->poll_wait); + ev_file->uverbs_file = uverbs_file; + ev_file->async_queue = NULL; + ev_file->is_async = is_async; + ev_file->is_closed = 0; + ev_file->filp = NULL; + + *fd = get_unused_fd(); + if (*fd < 0) { + ret = *fd; + goto err; + } + + /* + * fops_get() can't fail here, because we're coming from a + * system call on a uverbs file, which will already have a + * module reference. + */ + filp = alloc_file(uverbs_event_mnt, dget(uverbs_event_mnt->mnt_root), + FMODE_READ, fops_get(&uverbs_event_fops)); + if (!filp) { + ret = -ENFILE; + goto err_fd; + } + + filp->private_data = ev_file; + + return filp; + +err_fd: + put_unused_fd(*fd); + +err: + kfree(ev_file); + return ERR_PTR(ret); +} + +/* + * Look up a completion event file by FD. If lookup is successful, + * takes a ref to the event file struct that it returns; if + * unsuccessful, returns NULL. + */ +struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd) +{ + struct ib_uverbs_event_file *ev_file = NULL; + struct file *filp; + + filp = fget(fd); + if (!filp) + return NULL; + + if (filp->f_op != &uverbs_event_fops) + goto out; + + ev_file = filp->private_data; + if (ev_file->is_async) { + ev_file = NULL; + goto out; + } + + kref_get(&ev_file->ref); + +out: + fput(filp); + return ev_file; +} + +static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, + size_t count, loff_t *pos) +{ + struct ib_uverbs_file *file = filp->private_data; + struct ib_uverbs_cmd_hdr hdr; + + if (count < sizeof hdr) + return -EINVAL; + + if (copy_from_user(&hdr, buf, sizeof hdr)) + return -EFAULT; + + if (hdr.in_words * 4 != count) + return -EINVAL; + + if (hdr.command < 0 || + hdr.command >= ARRAY_SIZE(uverbs_cmd_table) || + !uverbs_cmd_table[hdr.command] || + !(file->device->ib_dev->uverbs_cmd_mask & (1ull << hdr.command))) + return -EINVAL; + + if (!file->ucontext && + hdr.command != IB_USER_VERBS_CMD_GET_CONTEXT) + return -EINVAL; + + return uverbs_cmd_table[hdr.command](file, buf + sizeof hdr, + hdr.in_words * 4, hdr.out_words * 4); +} + +static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct ib_uverbs_file *file = filp->private_data; + + if (!file->ucontext) + return -ENODEV; + else + return file->device->ib_dev->mmap(file->ucontext, vma); +} + +/* + * ib_uverbs_open() does not need the BKL: + * + * - dev_table[] accesses are protected by map_lock, the + * ib_uverbs_device structures are properly reference counted, and + * everything else is purely local to the file being created, so + * races against other open calls are not a problem; + * - there is no ioctl method to race against; + * - the device is added to dev_table[] as the last part of module + * initialization, the open method will either immediately run + * -ENXIO, or all required initialization will be done. + */ +static int ib_uverbs_open(struct inode *inode, struct file *filp) +{ + struct ib_uverbs_device *dev; + struct ib_uverbs_file *file; + int ret; + + spin_lock(&map_lock); + dev = dev_table[iminor(inode) - IB_UVERBS_BASE_MINOR]; + if (dev) + kref_get(&dev->ref); + spin_unlock(&map_lock); + + if (!dev) + return -ENXIO; + + if (!try_module_get(dev->ib_dev->owner)) { + ret = -ENODEV; + goto err; + } + + file = kmalloc(sizeof *file, GFP_KERNEL); + if (!file) { + ret = -ENOMEM; + goto err_module; + } + + file->device = dev; + file->ucontext = NULL; + file->async_file = NULL; + kref_init(&file->ref); + mutex_init(&file->mutex); + + filp->private_data = file; + + return 0; + +err_module: + module_put(dev->ib_dev->owner); + +err: + kref_put(&dev->ref, ib_uverbs_release_dev); + return ret; +} + +static int ib_uverbs_close(struct inode *inode, struct file *filp) +{ + struct ib_uverbs_file *file = filp->private_data; + + ib_uverbs_cleanup_ucontext(file, file->ucontext); + + if (file->async_file) + kref_put(&file->async_file->ref, ib_uverbs_release_event_file); + + kref_put(&file->ref, ib_uverbs_release_file); + + return 0; +} + +static const struct file_operations uverbs_fops = { + .owner = THIS_MODULE, + .write = ib_uverbs_write, + .open = ib_uverbs_open, + .release = ib_uverbs_close +}; + +static const struct file_operations uverbs_mmap_fops = { + .owner = THIS_MODULE, + .write = ib_uverbs_write, + .mmap = ib_uverbs_mmap, + .open = ib_uverbs_open, + .release = ib_uverbs_close +}; + +static struct ib_client uverbs_client = { + .name = "uverbs", + .add = ib_uverbs_add_one, + .remove = ib_uverbs_remove_one +}; + +static ssize_t show_ibdev(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct ib_uverbs_device *dev = dev_get_drvdata(device); + + if (!dev) + return -ENODEV; + + return sprintf(buf, "%s\n", dev->ib_dev->name); +} +static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); + +static ssize_t show_dev_abi_version(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct ib_uverbs_device *dev = dev_get_drvdata(device); + + if (!dev) + return -ENODEV; + + return sprintf(buf, "%d\n", dev->ib_dev->uverbs_abi_ver); +} +static DEVICE_ATTR(abi_version, S_IRUGO, show_dev_abi_version, NULL); + +static ssize_t show_abi_version(struct class *class, char *buf) +{ + return sprintf(buf, "%d\n", IB_USER_VERBS_ABI_VERSION); +} +static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); + +#include + +static ssize_t +show_dev_device(struct device *device, struct device_attribute *attr, char *buf) +{ + struct ib_uverbs_device *dev = dev_get_drvdata(device); + + if (!dev) + return -ENODEV; + + return sprintf(buf, "0x%04x\n", + ((struct pci_dev *)dev->ib_dev->dma_device)->device); +} +static DEVICE_ATTR(device, S_IRUGO, show_dev_device, NULL); + +static ssize_t +show_dev_vendor(struct device *device, struct device_attribute *attr, char *buf) +{ + struct ib_uverbs_device *dev = dev_get_drvdata(device); + + if (!dev) + return -ENODEV; + + return sprintf(buf, "0x%04x\n", + ((struct pci_dev *)dev->ib_dev->dma_device)->vendor); +} +static DEVICE_ATTR(vendor, S_IRUGO, show_dev_vendor, NULL); + +struct attribute *device_attrs[] = +{ + &dev_attr_device.attr, + &dev_attr_vendor.attr, + NULL +}; + +static struct attribute_group device_group = { + .name = "device", + .attrs = device_attrs +}; + +static void ib_uverbs_add_one(struct ib_device *device) +{ + struct ib_uverbs_device *uverbs_dev; + + if (!device->alloc_ucontext) + return; + + uverbs_dev = kzalloc(sizeof *uverbs_dev, GFP_KERNEL); + if (!uverbs_dev) + return; + + kref_init(&uverbs_dev->ref); + init_completion(&uverbs_dev->comp); + + spin_lock(&map_lock); + uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); + if (uverbs_dev->devnum >= IB_UVERBS_MAX_DEVICES) { + spin_unlock(&map_lock); + goto err; + } + set_bit(uverbs_dev->devnum, dev_map); + spin_unlock(&map_lock); + + uverbs_dev->ib_dev = device; + uverbs_dev->num_comp_vectors = device->num_comp_vectors; + + uverbs_dev->cdev = cdev_alloc(); + if (!uverbs_dev->cdev) + goto err; + uverbs_dev->cdev->owner = THIS_MODULE; + uverbs_dev->cdev->ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; + kobject_set_name(&uverbs_dev->cdev->kobj, "uverbs%d", uverbs_dev->devnum); + if (cdev_add(uverbs_dev->cdev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1)) + goto err_cdev; + + uverbs_dev->dev = device_create(uverbs_class, device->dma_device, + uverbs_dev->cdev->dev, uverbs_dev, + "uverbs%d", uverbs_dev->devnum); + if (IS_ERR(uverbs_dev->dev)) + goto err_cdev; + + if (device_create_file(uverbs_dev->dev, &dev_attr_ibdev)) + goto err_class; + if (device_create_file(uverbs_dev->dev, &dev_attr_abi_version)) + goto err_class; + if (sysfs_create_group(&uverbs_dev->dev->kobj, &device_group)) + goto err_class; + + spin_lock(&map_lock); + dev_table[uverbs_dev->devnum] = uverbs_dev; + spin_unlock(&map_lock); + + ib_set_client_data(device, &uverbs_client, uverbs_dev); + + return; + +err_class: + device_destroy(uverbs_class, uverbs_dev->cdev->dev); + +err_cdev: + cdev_del(uverbs_dev->cdev); + clear_bit(uverbs_dev->devnum, dev_map); + +err: + kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); + wait_for_completion(&uverbs_dev->comp); + kfree(uverbs_dev); + return; +} + +static void ib_uverbs_remove_one(struct ib_device *device) +{ + struct ib_uverbs_device *uverbs_dev = ib_get_client_data(device, &uverbs_client); + + if (!uverbs_dev) + return; + + sysfs_remove_group(&uverbs_dev->dev->kobj, &device_group); + dev_set_drvdata(uverbs_dev->dev, NULL); + device_destroy(uverbs_class, uverbs_dev->cdev->dev); + cdev_del(uverbs_dev->cdev); + + spin_lock(&map_lock); + dev_table[uverbs_dev->devnum] = NULL; + spin_unlock(&map_lock); + + clear_bit(uverbs_dev->devnum, dev_map); + + kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); + wait_for_completion(&uverbs_dev->comp); + kfree(uverbs_dev); +} +#ifdef __linux__ +static int uverbs_event_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, + struct vfsmount *mnt) +{ + return get_sb_pseudo(fs_type, "infinibandevent:", NULL, + INFINIBANDEVENTFS_MAGIC, mnt); +} + +static struct file_system_type uverbs_event_fs = { + /* No owner field so module can be unloaded */ + .name = "infinibandeventfs", + .get_sb = uverbs_event_get_sb, + .kill_sb = kill_litter_super +}; +#endif + +static int __init ib_uverbs_init(void) +{ + int ret; + + spin_lock_init(&map_lock); + + ret = register_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES, + "infiniband_verbs"); + if (ret) { + printk(KERN_ERR "user_verbs: couldn't register device number\n"); + goto out; + } + + uverbs_class = class_create(THIS_MODULE, "infiniband_verbs"); + if (IS_ERR(uverbs_class)) { + ret = PTR_ERR(uverbs_class); + printk(KERN_ERR "user_verbs: couldn't create class infiniband_verbs\n"); + goto out_chrdev; + } + + ret = class_create_file(uverbs_class, &class_attr_abi_version); + if (ret) { + printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n"); + goto out_class; + } + +#ifdef __linux__ + ret = register_filesystem(&uverbs_event_fs); + if (ret) { + printk(KERN_ERR "user_verbs: couldn't register infinibandeventfs\n"); + goto out_class; + } + + uverbs_event_mnt = kern_mount(&uverbs_event_fs); + if (IS_ERR(uverbs_event_mnt)) { + ret = PTR_ERR(uverbs_event_mnt); + printk(KERN_ERR "user_verbs: couldn't mount infinibandeventfs\n"); + goto out_fs; + } +#endif + + ret = ib_register_client(&uverbs_client); + if (ret) { + printk(KERN_ERR "user_verbs: couldn't register client\n"); + goto out_mnt; + } + + return 0; + +out_mnt: +#ifdef __linux__ + mntput(uverbs_event_mnt); + +out_fs: + unregister_filesystem(&uverbs_event_fs); +#endif + +out_class: + class_destroy(uverbs_class); + +out_chrdev: + unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); + +out: + return ret; +} + +static void __exit ib_uverbs_cleanup(void) +{ + ib_unregister_client(&uverbs_client); +#ifdef __linux__ + mntput(uverbs_event_mnt); + unregister_filesystem(&uverbs_event_fs); +#endif + class_destroy(uverbs_class); + unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); + idr_destroy(&ib_uverbs_pd_idr); + idr_destroy(&ib_uverbs_mr_idr); + idr_destroy(&ib_uverbs_mw_idr); + idr_destroy(&ib_uverbs_ah_idr); + idr_destroy(&ib_uverbs_cq_idr); + idr_destroy(&ib_uverbs_qp_idr); + idr_destroy(&ib_uverbs_srq_idr); +} + +module_init(ib_uverbs_init); +module_exit(ib_uverbs_cleanup); diff --git a/sys/ofed/drivers/infiniband/core/uverbs_marshall.c b/sys/ofed/drivers/infiniband/core/uverbs_marshall.c new file mode 100644 index 000000000000..5440da0e59b4 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/uverbs_marshall.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst, + struct ib_ah_attr *src) +{ + memcpy(dst->grh.dgid, src->grh.dgid.raw, sizeof src->grh.dgid); + dst->grh.flow_label = src->grh.flow_label; + dst->grh.sgid_index = src->grh.sgid_index; + dst->grh.hop_limit = src->grh.hop_limit; + dst->grh.traffic_class = src->grh.traffic_class; + dst->dlid = src->dlid; + dst->sl = src->sl; + dst->src_path_bits = src->src_path_bits; + dst->static_rate = src->static_rate; + dst->is_global = src->ah_flags & IB_AH_GRH ? 1 : 0; + dst->port_num = src->port_num; +} +EXPORT_SYMBOL(ib_copy_ah_attr_to_user); + +void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst, + struct ib_qp_attr *src) +{ + dst->cur_qp_state = src->cur_qp_state; + dst->path_mtu = src->path_mtu; + dst->path_mig_state = src->path_mig_state; + dst->qkey = src->qkey; + dst->rq_psn = src->rq_psn; + dst->sq_psn = src->sq_psn; + dst->dest_qp_num = src->dest_qp_num; + dst->qp_access_flags = src->qp_access_flags; + + dst->max_send_wr = src->cap.max_send_wr; + dst->max_recv_wr = src->cap.max_recv_wr; + dst->max_send_sge = src->cap.max_send_sge; + dst->max_recv_sge = src->cap.max_recv_sge; + dst->max_inline_data = src->cap.max_inline_data; + + ib_copy_ah_attr_to_user(&dst->ah_attr, &src->ah_attr); + ib_copy_ah_attr_to_user(&dst->alt_ah_attr, &src->alt_ah_attr); + + dst->pkey_index = src->pkey_index; + dst->alt_pkey_index = src->alt_pkey_index; + dst->en_sqd_async_notify = src->en_sqd_async_notify; + dst->sq_draining = src->sq_draining; + dst->max_rd_atomic = src->max_rd_atomic; + dst->max_dest_rd_atomic = src->max_dest_rd_atomic; + dst->min_rnr_timer = src->min_rnr_timer; + dst->port_num = src->port_num; + dst->timeout = src->timeout; + dst->retry_cnt = src->retry_cnt; + dst->rnr_retry = src->rnr_retry; + dst->alt_port_num = src->alt_port_num; + dst->alt_timeout = src->alt_timeout; +} +EXPORT_SYMBOL(ib_copy_qp_attr_to_user); + +void ib_copy_path_rec_to_user(struct ib_user_path_rec *dst, + struct ib_sa_path_rec *src) +{ + memcpy(dst->dgid, src->dgid.raw, sizeof src->dgid); + memcpy(dst->sgid, src->sgid.raw, sizeof src->sgid); + + dst->dlid = src->dlid; + dst->slid = src->slid; + dst->raw_traffic = src->raw_traffic; + dst->flow_label = src->flow_label; + dst->hop_limit = src->hop_limit; + dst->traffic_class = src->traffic_class; + dst->reversible = src->reversible; + dst->numb_path = src->numb_path; + dst->pkey = src->pkey; + dst->sl = src->sl; + dst->mtu_selector = src->mtu_selector; + dst->mtu = src->mtu; + dst->rate_selector = src->rate_selector; + dst->rate = src->rate; + dst->packet_life_time = src->packet_life_time; + dst->preference = src->preference; + dst->packet_life_time_selector = src->packet_life_time_selector; +} +EXPORT_SYMBOL(ib_copy_path_rec_to_user); + +void ib_copy_path_rec_from_user(struct ib_sa_path_rec *dst, + struct ib_user_path_rec *src) +{ + memcpy(dst->dgid.raw, src->dgid, sizeof dst->dgid); + memcpy(dst->sgid.raw, src->sgid, sizeof dst->sgid); + + dst->dlid = src->dlid; + dst->slid = src->slid; + dst->raw_traffic = src->raw_traffic; + dst->flow_label = src->flow_label; + dst->hop_limit = src->hop_limit; + dst->traffic_class = src->traffic_class; + dst->reversible = src->reversible; + dst->numb_path = src->numb_path; + dst->pkey = src->pkey; + dst->sl = src->sl; + dst->mtu_selector = src->mtu_selector; + dst->mtu = src->mtu; + dst->rate_selector = src->rate_selector; + dst->rate = src->rate; + dst->packet_life_time = src->packet_life_time; + dst->preference = src->preference; + dst->packet_life_time_selector = src->packet_life_time_selector; +} +EXPORT_SYMBOL(ib_copy_path_rec_from_user); diff --git a/sys/ofed/drivers/infiniband/core/verbs.c b/sys/ofed/drivers/infiniband/core/verbs.c new file mode 100644 index 000000000000..90bdeaa91987 --- /dev/null +++ b/sys/ofed/drivers/infiniband/core/verbs.c @@ -0,0 +1,1073 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include +#include + +int ib_rate_to_mult(enum ib_rate rate) +{ + switch (rate) { + case IB_RATE_2_5_GBPS: return 1; + case IB_RATE_5_GBPS: return 2; + case IB_RATE_10_GBPS: return 4; + case IB_RATE_20_GBPS: return 8; + case IB_RATE_30_GBPS: return 12; + case IB_RATE_40_GBPS: return 16; + case IB_RATE_60_GBPS: return 24; + case IB_RATE_80_GBPS: return 32; + case IB_RATE_120_GBPS: return 48; + default: return -1; + } +} +EXPORT_SYMBOL(ib_rate_to_mult); + +enum ib_rate mult_to_ib_rate(int mult) +{ + switch (mult) { + case 1: return IB_RATE_2_5_GBPS; + case 2: return IB_RATE_5_GBPS; + case 4: return IB_RATE_10_GBPS; + case 8: return IB_RATE_20_GBPS; + case 12: return IB_RATE_30_GBPS; + case 16: return IB_RATE_40_GBPS; + case 24: return IB_RATE_60_GBPS; + case 32: return IB_RATE_80_GBPS; + case 48: return IB_RATE_120_GBPS; + default: return IB_RATE_PORT_CURRENT; + } +} +EXPORT_SYMBOL(mult_to_ib_rate); + +enum rdma_transport_type +rdma_node_get_transport(enum rdma_node_type node_type) +{ + switch (node_type) { + case RDMA_NODE_IB_CA: + case RDMA_NODE_IB_SWITCH: + case RDMA_NODE_IB_ROUTER: + return RDMA_TRANSPORT_IB; + case RDMA_NODE_RNIC: + return RDMA_TRANSPORT_IWARP; + default: + BUG(); + return 0; + } +} +EXPORT_SYMBOL(rdma_node_get_transport); + +enum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device, u8 port_num) +{ + if (device->get_link_layer) + return device->get_link_layer(device, port_num); + + switch (rdma_node_get_transport(device->node_type)) { + case RDMA_TRANSPORT_IB: + return IB_LINK_LAYER_INFINIBAND; + case RDMA_TRANSPORT_IWARP: + return IB_LINK_LAYER_ETHERNET; + default: + return IB_LINK_LAYER_UNSPECIFIED; + } +} +EXPORT_SYMBOL(rdma_port_get_link_layer); + +/* Protection domains */ + +struct ib_pd *ib_alloc_pd(struct ib_device *device) +{ + struct ib_pd *pd; + + pd = device->alloc_pd(device, NULL, NULL); + + if (!IS_ERR(pd)) { + pd->device = device; + pd->uobject = NULL; + atomic_set(&pd->usecnt, 0); + } + + return pd; +} +EXPORT_SYMBOL(ib_alloc_pd); + +int ib_dealloc_pd(struct ib_pd *pd) +{ + if (atomic_read(&pd->usecnt)) + return -EBUSY; + + return pd->device->dealloc_pd(pd); +} +EXPORT_SYMBOL(ib_dealloc_pd); + +/* Address handles */ + +struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) +{ + struct ib_ah *ah; + + ah = pd->device->create_ah(pd, ah_attr); + + if (!IS_ERR(ah)) { + ah->device = pd->device; + ah->pd = pd; + ah->uobject = NULL; + atomic_inc(&pd->usecnt); + } + + return ah; +} +EXPORT_SYMBOL(ib_create_ah); + +int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, struct ib_wc *wc, + struct ib_grh *grh, struct ib_ah_attr *ah_attr) +{ + u32 flow_class; + u16 gid_index; + int ret; + + memset(ah_attr, 0, sizeof *ah_attr); + ah_attr->dlid = wc->slid; + ah_attr->sl = wc->sl; + ah_attr->src_path_bits = wc->dlid_path_bits; + ah_attr->port_num = port_num; + + if (wc->wc_flags & IB_WC_GRH) { + ah_attr->ah_flags = IB_AH_GRH; + ah_attr->grh.dgid = grh->sgid; + + ret = ib_find_cached_gid(device, &grh->dgid, &port_num, + &gid_index); + if (ret) + return ret; + + ah_attr->grh.sgid_index = (u8) gid_index; + flow_class = be32_to_cpu(grh->version_tclass_flow); + ah_attr->grh.flow_label = flow_class & 0xFFFFF; + ah_attr->grh.hop_limit = 0xFF; + ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF; + } + return 0; +} +EXPORT_SYMBOL(ib_init_ah_from_wc); + +struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc, + struct ib_grh *grh, u8 port_num) +{ + struct ib_ah_attr ah_attr; + int ret; + + ret = ib_init_ah_from_wc(pd->device, port_num, wc, grh, &ah_attr); + if (ret) + return ERR_PTR(ret); + + return ib_create_ah(pd, &ah_attr); +} +EXPORT_SYMBOL(ib_create_ah_from_wc); + +int ib_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr) +{ + return ah->device->modify_ah ? + ah->device->modify_ah(ah, ah_attr) : + -ENOSYS; +} +EXPORT_SYMBOL(ib_modify_ah); + +int ib_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr) +{ + return ah->device->query_ah ? + ah->device->query_ah(ah, ah_attr) : + -ENOSYS; +} +EXPORT_SYMBOL(ib_query_ah); + +int ib_destroy_ah(struct ib_ah *ah) +{ + struct ib_pd *pd; + int ret; + + pd = ah->pd; + ret = ah->device->destroy_ah(ah); + if (!ret) + atomic_dec(&pd->usecnt); + + return ret; +} +EXPORT_SYMBOL(ib_destroy_ah); + +/* Shared receive queues */ + +struct ib_srq *ib_create_srq(struct ib_pd *pd, + struct ib_srq_init_attr *srq_init_attr) +{ + struct ib_srq *srq; + + if (!pd->device->create_srq) + return ERR_PTR(-ENOSYS); + + srq = pd->device->create_srq(pd, srq_init_attr, NULL); + + if (!IS_ERR(srq)) { + srq->device = pd->device; + srq->pd = pd; + srq->uobject = NULL; + srq->event_handler = srq_init_attr->event_handler; + srq->srq_context = srq_init_attr->srq_context; + srq->xrc_cq = NULL; + srq->xrcd = NULL; + atomic_inc(&pd->usecnt); + atomic_set(&srq->usecnt, 0); + } + + return srq; +} +EXPORT_SYMBOL(ib_create_srq); + +struct ib_srq *ib_create_xrc_srq(struct ib_pd *pd, + struct ib_cq *xrc_cq, + struct ib_xrcd *xrcd, + struct ib_srq_init_attr *srq_init_attr) +{ + struct ib_srq *srq; + + if (!pd->device->create_xrc_srq) + return ERR_PTR(-ENOSYS); + + srq = pd->device->create_xrc_srq(pd, xrc_cq, xrcd, srq_init_attr, NULL); + + if (!IS_ERR(srq)) { + srq->device = pd->device; + srq->pd = pd; + srq->uobject = NULL; + srq->event_handler = srq_init_attr->event_handler; + srq->srq_context = srq_init_attr->srq_context; + srq->xrc_cq = xrc_cq; + srq->xrcd = xrcd; + atomic_inc(&pd->usecnt); + atomic_inc(&xrcd->usecnt); + atomic_inc(&xrc_cq->usecnt); + atomic_set(&srq->usecnt, 0); + } + + return srq; +} +EXPORT_SYMBOL(ib_create_xrc_srq); + +int ib_modify_srq(struct ib_srq *srq, + struct ib_srq_attr *srq_attr, + enum ib_srq_attr_mask srq_attr_mask) +{ + return srq->device->modify_srq ? + srq->device->modify_srq(srq, srq_attr, srq_attr_mask, NULL) : + -ENOSYS; +} +EXPORT_SYMBOL(ib_modify_srq); + +int ib_query_srq(struct ib_srq *srq, + struct ib_srq_attr *srq_attr) +{ + return srq->device->query_srq ? + srq->device->query_srq(srq, srq_attr) : -ENOSYS; +} +EXPORT_SYMBOL(ib_query_srq); + +int ib_destroy_srq(struct ib_srq *srq) +{ + struct ib_pd *pd; + struct ib_cq *xrc_cq; + struct ib_xrcd *xrcd; + int ret; + + if (atomic_read(&srq->usecnt)) + return -EBUSY; + + pd = srq->pd; + xrc_cq = srq->xrc_cq; + xrcd = srq->xrcd; + + ret = srq->device->destroy_srq(srq); + if (!ret) { + atomic_dec(&pd->usecnt); + if (xrc_cq) + atomic_dec(&xrc_cq->usecnt); + if (xrcd) + atomic_dec(&xrcd->usecnt); + } + + return ret; +} +EXPORT_SYMBOL(ib_destroy_srq); + +/* Queue pairs */ + +struct ib_qp *ib_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *qp_init_attr) +{ + struct ib_qp *qp; + + qp = pd->device->create_qp(pd, qp_init_attr, NULL); + + if (!IS_ERR(qp)) { + qp->device = pd->device; + qp->pd = pd; + qp->send_cq = qp_init_attr->send_cq; + qp->recv_cq = qp_init_attr->recv_cq; + qp->srq = qp_init_attr->srq; + qp->uobject = NULL; + qp->event_handler = qp_init_attr->event_handler; + qp->qp_context = qp_init_attr->qp_context; + qp->qp_type = qp_init_attr->qp_type; + qp->xrcd = qp->qp_type == IB_QPT_XRC ? + qp_init_attr->xrc_domain : NULL; + atomic_inc(&pd->usecnt); + atomic_inc(&qp_init_attr->send_cq->usecnt); + atomic_inc(&qp_init_attr->recv_cq->usecnt); + if (qp_init_attr->srq) + atomic_inc(&qp_init_attr->srq->usecnt); + if (qp->qp_type == IB_QPT_XRC) + atomic_inc(&qp->xrcd->usecnt); + } + + return qp; +} +EXPORT_SYMBOL(ib_create_qp); + +static const struct { + int valid; + enum ib_qp_attr_mask req_param[IB_QPT_RAW_ETH + 1]; + enum ib_qp_attr_mask opt_param[IB_QPT_RAW_ETH + 1]; +} qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = { + [IB_QPS_RESET] = { + [IB_QPS_RESET] = { .valid = 1 }, + [IB_QPS_INIT] = { + .valid = 1, + .req_param = { + [IB_QPT_UD] = (IB_QP_PKEY_INDEX | + IB_QP_PORT | + IB_QP_QKEY), + [IB_QPT_RAW_ETH] = IB_QP_PORT, + [IB_QPT_UC] = (IB_QP_PKEY_INDEX | + IB_QP_PORT | + IB_QP_ACCESS_FLAGS), + [IB_QPT_RC] = (IB_QP_PKEY_INDEX | + IB_QP_PORT | + IB_QP_ACCESS_FLAGS), + [IB_QPT_XRC] = (IB_QP_PKEY_INDEX | + IB_QP_PORT | + IB_QP_ACCESS_FLAGS), + [IB_QPT_SMI] = (IB_QP_PKEY_INDEX | + IB_QP_QKEY), + [IB_QPT_GSI] = (IB_QP_PKEY_INDEX | + IB_QP_QKEY), + } + }, + }, + [IB_QPS_INIT] = { + [IB_QPS_RESET] = { .valid = 1 }, + [IB_QPS_ERR] = { .valid = 1 }, + [IB_QPS_INIT] = { + .valid = 1, + .opt_param = { + [IB_QPT_UD] = (IB_QP_PKEY_INDEX | + IB_QP_PORT | + IB_QP_QKEY), + [IB_QPT_UC] = (IB_QP_PKEY_INDEX | + IB_QP_PORT | + IB_QP_ACCESS_FLAGS), + [IB_QPT_RC] = (IB_QP_PKEY_INDEX | + IB_QP_PORT | + IB_QP_ACCESS_FLAGS), + [IB_QPT_XRC] = (IB_QP_PKEY_INDEX | + IB_QP_PORT | + IB_QP_ACCESS_FLAGS), + [IB_QPT_SMI] = (IB_QP_PKEY_INDEX | + IB_QP_QKEY), + [IB_QPT_GSI] = (IB_QP_PKEY_INDEX | + IB_QP_QKEY), + } + }, + [IB_QPS_RTR] = { + .valid = 1, + .req_param = { + [IB_QPT_UC] = (IB_QP_AV | + IB_QP_PATH_MTU | + IB_QP_DEST_QPN | + IB_QP_RQ_PSN), + [IB_QPT_RC] = (IB_QP_AV | + IB_QP_PATH_MTU | + IB_QP_DEST_QPN | + IB_QP_RQ_PSN | + IB_QP_MAX_DEST_RD_ATOMIC | + IB_QP_MIN_RNR_TIMER), + [IB_QPT_XRC] = (IB_QP_AV | + IB_QP_PATH_MTU | + IB_QP_DEST_QPN | + IB_QP_RQ_PSN | + IB_QP_MAX_DEST_RD_ATOMIC | + IB_QP_MIN_RNR_TIMER), + }, + .opt_param = { + [IB_QPT_UD] = (IB_QP_PKEY_INDEX | + IB_QP_QKEY), + [IB_QPT_UC] = (IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS | + IB_QP_PKEY_INDEX), + [IB_QPT_RC] = (IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS | + IB_QP_PKEY_INDEX), + [IB_QPT_XRC] = (IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS | + IB_QP_PKEY_INDEX), + [IB_QPT_SMI] = (IB_QP_PKEY_INDEX | + IB_QP_QKEY), + [IB_QPT_GSI] = (IB_QP_PKEY_INDEX | + IB_QP_QKEY), + } + } + }, + [IB_QPS_RTR] = { + [IB_QPS_RESET] = { .valid = 1 }, + [IB_QPS_ERR] = { .valid = 1 }, + [IB_QPS_RTS] = { + .valid = 1, + .req_param = { + [IB_QPT_UD] = IB_QP_SQ_PSN, + [IB_QPT_UC] = IB_QP_SQ_PSN, + [IB_QPT_RC] = (IB_QP_TIMEOUT | + IB_QP_RETRY_CNT | + IB_QP_RNR_RETRY | + IB_QP_SQ_PSN | + IB_QP_MAX_QP_RD_ATOMIC), + [IB_QPT_XRC] = (IB_QP_TIMEOUT | + IB_QP_RETRY_CNT | + IB_QP_RNR_RETRY | + IB_QP_SQ_PSN | + IB_QP_MAX_QP_RD_ATOMIC), + [IB_QPT_SMI] = IB_QP_SQ_PSN, + [IB_QPT_GSI] = IB_QP_SQ_PSN, + }, + .opt_param = { + [IB_QPT_UD] = (IB_QP_CUR_STATE | + IB_QP_QKEY), + [IB_QPT_UC] = (IB_QP_CUR_STATE | + IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS | + IB_QP_PATH_MIG_STATE), + [IB_QPT_RC] = (IB_QP_CUR_STATE | + IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS | + IB_QP_MIN_RNR_TIMER | + IB_QP_PATH_MIG_STATE), + [IB_QPT_XRC] = (IB_QP_CUR_STATE | + IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS | + IB_QP_MIN_RNR_TIMER | + IB_QP_PATH_MIG_STATE), + [IB_QPT_SMI] = (IB_QP_CUR_STATE | + IB_QP_QKEY), + [IB_QPT_GSI] = (IB_QP_CUR_STATE | + IB_QP_QKEY), + } + } + }, + [IB_QPS_RTS] = { + [IB_QPS_RESET] = { .valid = 1 }, + [IB_QPS_ERR] = { .valid = 1 }, + [IB_QPS_RTS] = { + .valid = 1, + .opt_param = { + [IB_QPT_UD] = (IB_QP_CUR_STATE | + IB_QP_QKEY), + [IB_QPT_UC] = (IB_QP_CUR_STATE | + IB_QP_ACCESS_FLAGS | + IB_QP_ALT_PATH | + IB_QP_PATH_MIG_STATE), + [IB_QPT_RC] = (IB_QP_CUR_STATE | + IB_QP_ACCESS_FLAGS | + IB_QP_ALT_PATH | + IB_QP_PATH_MIG_STATE | + IB_QP_MIN_RNR_TIMER), + [IB_QPT_XRC] = (IB_QP_CUR_STATE | + IB_QP_ACCESS_FLAGS | + IB_QP_ALT_PATH | + IB_QP_PATH_MIG_STATE | + IB_QP_MIN_RNR_TIMER), + [IB_QPT_SMI] = (IB_QP_CUR_STATE | + IB_QP_QKEY), + [IB_QPT_GSI] = (IB_QP_CUR_STATE | + IB_QP_QKEY), + } + }, + [IB_QPS_SQD] = { + .valid = 1, + .opt_param = { + [IB_QPT_UD] = IB_QP_EN_SQD_ASYNC_NOTIFY, + [IB_QPT_UC] = IB_QP_EN_SQD_ASYNC_NOTIFY, + [IB_QPT_RC] = IB_QP_EN_SQD_ASYNC_NOTIFY, + [IB_QPT_XRC] = IB_QP_EN_SQD_ASYNC_NOTIFY, + [IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY, + [IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY + } + }, + }, + [IB_QPS_SQD] = { + [IB_QPS_RESET] = { .valid = 1 }, + [IB_QPS_ERR] = { .valid = 1 }, + [IB_QPS_RTS] = { + .valid = 1, + .opt_param = { + [IB_QPT_UD] = (IB_QP_CUR_STATE | + IB_QP_QKEY), + [IB_QPT_UC] = (IB_QP_CUR_STATE | + IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS | + IB_QP_PATH_MIG_STATE), + [IB_QPT_RC] = (IB_QP_CUR_STATE | + IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS | + IB_QP_MIN_RNR_TIMER | + IB_QP_PATH_MIG_STATE), + [IB_QPT_XRC] = (IB_QP_CUR_STATE | + IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS | + IB_QP_MIN_RNR_TIMER | + IB_QP_PATH_MIG_STATE), + [IB_QPT_SMI] = (IB_QP_CUR_STATE | + IB_QP_QKEY), + [IB_QPT_GSI] = (IB_QP_CUR_STATE | + IB_QP_QKEY), + } + }, + [IB_QPS_SQD] = { + .valid = 1, + .opt_param = { + [IB_QPT_UD] = (IB_QP_PKEY_INDEX | + IB_QP_QKEY), + [IB_QPT_UC] = (IB_QP_AV | + IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS | + IB_QP_PKEY_INDEX | + IB_QP_PATH_MIG_STATE), + [IB_QPT_RC] = (IB_QP_PORT | + IB_QP_AV | + IB_QP_TIMEOUT | + IB_QP_RETRY_CNT | + IB_QP_RNR_RETRY | + IB_QP_MAX_QP_RD_ATOMIC | + IB_QP_MAX_DEST_RD_ATOMIC | + IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS | + IB_QP_PKEY_INDEX | + IB_QP_MIN_RNR_TIMER | + IB_QP_PATH_MIG_STATE), + [IB_QPT_XRC] = (IB_QP_PORT | + IB_QP_AV | + IB_QP_TIMEOUT | + IB_QP_RETRY_CNT | + IB_QP_RNR_RETRY | + IB_QP_MAX_QP_RD_ATOMIC | + IB_QP_MAX_DEST_RD_ATOMIC | + IB_QP_ALT_PATH | + IB_QP_ACCESS_FLAGS | + IB_QP_PKEY_INDEX | + IB_QP_MIN_RNR_TIMER | + IB_QP_PATH_MIG_STATE), + [IB_QPT_SMI] = (IB_QP_PKEY_INDEX | + IB_QP_QKEY), + [IB_QPT_GSI] = (IB_QP_PKEY_INDEX | + IB_QP_QKEY), + } + } + }, + [IB_QPS_SQE] = { + [IB_QPS_RESET] = { .valid = 1 }, + [IB_QPS_ERR] = { .valid = 1 }, + [IB_QPS_RTS] = { + .valid = 1, + .opt_param = { + [IB_QPT_UD] = (IB_QP_CUR_STATE | + IB_QP_QKEY), + [IB_QPT_UC] = (IB_QP_CUR_STATE | + IB_QP_ACCESS_FLAGS), + [IB_QPT_SMI] = (IB_QP_CUR_STATE | + IB_QP_QKEY), + [IB_QPT_GSI] = (IB_QP_CUR_STATE | + IB_QP_QKEY), + } + } + }, + [IB_QPS_ERR] = { + [IB_QPS_RESET] = { .valid = 1 }, + [IB_QPS_ERR] = { .valid = 1 } + } +}; + +int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state, + enum ib_qp_type type, enum ib_qp_attr_mask mask) +{ + enum ib_qp_attr_mask req_param, opt_param; + + if (cur_state < 0 || cur_state > IB_QPS_ERR || + next_state < 0 || next_state > IB_QPS_ERR) + return 0; + + if (mask & IB_QP_CUR_STATE && + cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS && + cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE) + return 0; + + if (!qp_state_table[cur_state][next_state].valid) + return 0; + + req_param = qp_state_table[cur_state][next_state].req_param[type]; + opt_param = qp_state_table[cur_state][next_state].opt_param[type]; + + if ((mask & req_param) != req_param) + return 0; + + if (mask & ~(req_param | opt_param | IB_QP_STATE)) + return 0; + + return 1; +} +EXPORT_SYMBOL(ib_modify_qp_is_ok); + +int ib_modify_qp(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask) +{ + return qp->device->modify_qp(qp, qp_attr, qp_attr_mask, NULL); +} +EXPORT_SYMBOL(ib_modify_qp); + +int ib_query_qp(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr) +{ + return qp->device->query_qp ? + qp->device->query_qp(qp, qp_attr, qp_attr_mask, qp_init_attr) : + -ENOSYS; +} +EXPORT_SYMBOL(ib_query_qp); + +int ib_destroy_qp(struct ib_qp *qp) +{ + struct ib_pd *pd; + struct ib_cq *scq, *rcq; + struct ib_srq *srq; + struct ib_xrcd *xrcd; + enum ib_qp_type qp_type = qp->qp_type; + int ret; + + pd = qp->pd; + scq = qp->send_cq; + rcq = qp->recv_cq; + srq = qp->srq; + xrcd = qp->xrcd; + + ret = qp->device->destroy_qp(qp); + if (!ret) { + atomic_dec(&pd->usecnt); + atomic_dec(&scq->usecnt); + atomic_dec(&rcq->usecnt); + if (srq) + atomic_dec(&srq->usecnt); + if (qp_type == IB_QPT_XRC) + atomic_dec(&xrcd->usecnt); + } + + return ret; +} +EXPORT_SYMBOL(ib_destroy_qp); + +/* Completion queues */ + +struct ib_cq *ib_create_cq(struct ib_device *device, + ib_comp_handler comp_handler, + void (*event_handler)(struct ib_event *, void *), + void *cq_context, int cqe, int comp_vector) +{ + struct ib_cq *cq; + + cq = device->create_cq(device, cqe, comp_vector, NULL, NULL); + + if (!IS_ERR(cq)) { + cq->device = device; + cq->uobject = NULL; + cq->comp_handler = comp_handler; + cq->event_handler = event_handler; + cq->cq_context = cq_context; + atomic_set(&cq->usecnt, 0); + } + + return cq; +} +EXPORT_SYMBOL(ib_create_cq); + +int ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) +{ + return cq->device->modify_cq ? + cq->device->modify_cq(cq, cq_count, cq_period) : -ENOSYS; +} +EXPORT_SYMBOL(ib_modify_cq); + +int ib_destroy_cq(struct ib_cq *cq) +{ + if (atomic_read(&cq->usecnt)) + return -EBUSY; + + return cq->device->destroy_cq(cq); +} +EXPORT_SYMBOL(ib_destroy_cq); + +int ib_resize_cq(struct ib_cq *cq, int cqe) +{ + return cq->device->resize_cq ? + cq->device->resize_cq(cq, cqe, NULL) : -ENOSYS; +} +EXPORT_SYMBOL(ib_resize_cq); + +/* Memory regions */ + +struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags) +{ + struct ib_mr *mr; + + mr = pd->device->get_dma_mr(pd, mr_access_flags); + + if (!IS_ERR(mr)) { + mr->device = pd->device; + mr->pd = pd; + mr->uobject = NULL; + atomic_inc(&pd->usecnt); + atomic_set(&mr->usecnt, 0); + } + + return mr; +} +EXPORT_SYMBOL(ib_get_dma_mr); + +struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + int mr_access_flags, + u64 *iova_start) +{ + struct ib_mr *mr; + + if (!pd->device->reg_phys_mr) + return ERR_PTR(-ENOSYS); + + mr = pd->device->reg_phys_mr(pd, phys_buf_array, num_phys_buf, + mr_access_flags, iova_start); + + if (!IS_ERR(mr)) { + mr->device = pd->device; + mr->pd = pd; + mr->uobject = NULL; + atomic_inc(&pd->usecnt); + atomic_set(&mr->usecnt, 0); + } + + return mr; +} +EXPORT_SYMBOL(ib_reg_phys_mr); + +int ib_rereg_phys_mr(struct ib_mr *mr, + int mr_rereg_mask, + struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + int mr_access_flags, + u64 *iova_start) +{ + struct ib_pd *old_pd; + int ret; + + if (!mr->device->rereg_phys_mr) + return -ENOSYS; + + if (atomic_read(&mr->usecnt)) + return -EBUSY; + + old_pd = mr->pd; + + ret = mr->device->rereg_phys_mr(mr, mr_rereg_mask, pd, + phys_buf_array, num_phys_buf, + mr_access_flags, iova_start); + + if (!ret && (mr_rereg_mask & IB_MR_REREG_PD)) { + atomic_dec(&old_pd->usecnt); + atomic_inc(&pd->usecnt); + } + + return ret; +} +EXPORT_SYMBOL(ib_rereg_phys_mr); + +int ib_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr) +{ + return mr->device->query_mr ? + mr->device->query_mr(mr, mr_attr) : -ENOSYS; +} +EXPORT_SYMBOL(ib_query_mr); + +int ib_dereg_mr(struct ib_mr *mr) +{ + struct ib_pd *pd; + int ret; + + if (atomic_read(&mr->usecnt)) + return -EBUSY; + + pd = mr->pd; + ret = mr->device->dereg_mr(mr); + if (!ret) + atomic_dec(&pd->usecnt); + + return ret; +} +EXPORT_SYMBOL(ib_dereg_mr); + +struct ib_mr *ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len) +{ + struct ib_mr *mr; + + if (!pd->device->alloc_fast_reg_mr) + return ERR_PTR(-ENOSYS); + + mr = pd->device->alloc_fast_reg_mr(pd, max_page_list_len); + + if (!IS_ERR(mr)) { + mr->device = pd->device; + mr->pd = pd; + mr->uobject = NULL; + atomic_inc(&pd->usecnt); + atomic_set(&mr->usecnt, 0); + } + + return mr; +} +EXPORT_SYMBOL(ib_alloc_fast_reg_mr); + +struct ib_fast_reg_page_list *ib_alloc_fast_reg_page_list(struct ib_device *device, + int max_page_list_len) +{ + struct ib_fast_reg_page_list *page_list; + + if (!device->alloc_fast_reg_page_list) + return ERR_PTR(-ENOSYS); + + page_list = device->alloc_fast_reg_page_list(device, max_page_list_len); + + if (!IS_ERR(page_list)) { + page_list->device = device; + page_list->max_page_list_len = max_page_list_len; + } + + return page_list; +} +EXPORT_SYMBOL(ib_alloc_fast_reg_page_list); + +void ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list) +{ + page_list->device->free_fast_reg_page_list(page_list); +} +EXPORT_SYMBOL(ib_free_fast_reg_page_list); + +/* Memory windows */ + +struct ib_mw *ib_alloc_mw(struct ib_pd *pd) +{ + struct ib_mw *mw; + + if (!pd->device->alloc_mw) + return ERR_PTR(-ENOSYS); + + mw = pd->device->alloc_mw(pd); + if (!IS_ERR(mw)) { + mw->device = pd->device; + mw->pd = pd; + mw->uobject = NULL; + atomic_inc(&pd->usecnt); + } + + return mw; +} +EXPORT_SYMBOL(ib_alloc_mw); + +int ib_dealloc_mw(struct ib_mw *mw) +{ + struct ib_pd *pd; + int ret; + + pd = mw->pd; + ret = mw->device->dealloc_mw(mw); + if (!ret) + atomic_dec(&pd->usecnt); + + return ret; +} +EXPORT_SYMBOL(ib_dealloc_mw); + +/* "Fast" memory regions */ + +struct ib_fmr *ib_alloc_fmr(struct ib_pd *pd, + int mr_access_flags, + struct ib_fmr_attr *fmr_attr) +{ + struct ib_fmr *fmr; + + if (!pd->device->alloc_fmr) + return ERR_PTR(-ENOSYS); + + fmr = pd->device->alloc_fmr(pd, mr_access_flags, fmr_attr); + if (!IS_ERR(fmr)) { + fmr->device = pd->device; + fmr->pd = pd; + atomic_inc(&pd->usecnt); + } + + return fmr; +} +EXPORT_SYMBOL(ib_alloc_fmr); + +int ib_unmap_fmr(struct list_head *fmr_list) +{ + struct ib_fmr *fmr; + + if (list_empty(fmr_list)) + return 0; + + fmr = list_entry(fmr_list->next, struct ib_fmr, list); + return fmr->device->unmap_fmr(fmr_list); +} +EXPORT_SYMBOL(ib_unmap_fmr); + +int ib_dealloc_fmr(struct ib_fmr *fmr) +{ + struct ib_pd *pd; + int ret; + + pd = fmr->pd; + ret = fmr->device->dealloc_fmr(fmr); + if (!ret) + atomic_dec(&pd->usecnt); + + return ret; +} +EXPORT_SYMBOL(ib_dealloc_fmr); + +/* Multicast groups */ + +int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) +{ + if (!qp->device->attach_mcast) + return -ENOSYS; + + switch (rdma_node_get_transport(qp->device->node_type)) { + case RDMA_TRANSPORT_IB: + if (qp->qp_type == IB_QPT_RAW_ETH) { + /* In raw Etherent mgids the 63 msb's should be 0 */ + if (gid->global.subnet_prefix & cpu_to_be64(~1ULL)) + return -EINVAL; + } else if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD) + return -EINVAL; + break; + case RDMA_TRANSPORT_IWARP: + if (qp->qp_type != IB_QPT_RAW_ETH) + return -EINVAL; + break; + } + return qp->device->attach_mcast(qp, gid, lid); +} +EXPORT_SYMBOL(ib_attach_mcast); + +int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid) +{ + if (!qp->device->detach_mcast) + return -ENOSYS; + + switch (rdma_node_get_transport(qp->device->node_type)) { + case RDMA_TRANSPORT_IB: + if (qp->qp_type == IB_QPT_RAW_ETH) { + /* In raw Etherent mgids the 63 msb's should be 0 */ + if (gid->global.subnet_prefix & cpu_to_be64(~1ULL)) + return -EINVAL; + } else if (gid->raw[0] != 0xff || qp->qp_type != IB_QPT_UD) + return -EINVAL; + break; + case RDMA_TRANSPORT_IWARP: + if (qp->qp_type != IB_QPT_RAW_ETH) + return -EINVAL; + break; + } + return qp->device->detach_mcast(qp, gid, lid); +} +EXPORT_SYMBOL(ib_detach_mcast); + +int ib_dealloc_xrcd(struct ib_xrcd *xrcd) +{ + if (atomic_read(&xrcd->usecnt)) + return -EBUSY; + + return xrcd->device->dealloc_xrcd(xrcd); +} +EXPORT_SYMBOL(ib_dealloc_xrcd); + +struct ib_xrcd *ib_alloc_xrcd(struct ib_device *device) +{ + struct ib_xrcd *xrcd; + + if (!device->alloc_xrcd) + return ERR_PTR(-ENOSYS); + + xrcd = device->alloc_xrcd(device, NULL, NULL); + if (!IS_ERR(xrcd)) { + xrcd->device = device; + xrcd->inode = NULL; + xrcd->uobject = NULL; + atomic_set(&xrcd->usecnt, 0); + } + return xrcd; +} +EXPORT_SYMBOL(ib_alloc_xrcd); + diff --git a/sys/ofed/drivers/infiniband/debug/Makefile b/sys/ofed/drivers/infiniband/debug/Makefile new file mode 100644 index 000000000000..e9d9f4b8fd21 --- /dev/null +++ b/sys/ofed/drivers/infiniband/debug/Makefile @@ -0,0 +1,3 @@ +EXTRA_CFLAGS := $(subst $(KERNEL_MEMTRACK_CFLAGS),,$(EXTRA_CFLAGS)) + +obj-m += memtrack.o diff --git a/sys/ofed/drivers/infiniband/debug/memtrack.c b/sys/ofed/drivers/infiniband/debug/memtrack.c new file mode 100644 index 000000000000..199b33b7709d --- /dev/null +++ b/sys/ofed/drivers/infiniband/debug/memtrack.c @@ -0,0 +1,600 @@ +/* + This software is available to you under a choice of one of two + licenses. You may choose to be licensed under the terms of the GNU + General Public License (GPL) Version 2, available at + , or the OpenIB.org BSD + license, available in the LICENSE.TXT file accompanying this + software. These details are also available at + . + + 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. + + Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. +*/ + +#define C_MEMTRACK_C + +#ifdef kmalloc + #undef kmalloc +#endif +#ifdef kfree + #undef kfree +#endif +#ifdef vmalloc + #undef vmalloc +#endif +#ifdef vfree + #undef vfree +#endif +#ifdef kmem_cache_alloc + #undef kmem_cache_alloc +#endif +#ifdef kmem_cache_free + #undef kmem_cache_free +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +MODULE_AUTHOR("Mellanox Technologies LTD."); +MODULE_DESCRIPTION("Memory allocations tracking"); +MODULE_LICENSE("GPL"); + +#define MEMTRACK_HASH_SZ ((1<<15)-19) /* prime: http://www.utm.edu/research/primes/lists/2small/0bit.html */ +#define MAX_FILENAME_LEN 31 + +#define memtrack_spin_lock(spl, flags) spin_lock_irqsave(spl, flags) +#define memtrack_spin_unlock(spl, flags) spin_unlock_irqrestore(spl, flags) + +/* if a bit is set then the corresponding allocation is tracked. + bit0 corresponds to MEMTRACK_KMALLOC, bit1 corresponds to MEMTRACK_VMALLOC etc. */ +static unsigned long track_mask = -1; /* effectively everything */ +module_param(track_mask, ulong, 0444); +MODULE_PARM_DESC(track_mask, "bitmask definenig what is tracked"); + +/* if a bit is set then the corresponding allocation is strictly tracked. + That is, before inserting the whole range is checked to not overlap any + of the allocations already in the database */ +static unsigned long strict_track_mask = 0; /* no strict tracking */ +module_param(strict_track_mask, ulong, 0444); +MODULE_PARM_DESC(strict_track_mask, "bitmask which allocation requires strict tracking"); + +typedef struct memtrack_meminfo_st { + unsigned long addr; + unsigned long size; + unsigned long line_num; + struct memtrack_meminfo_st *next; + struct list_head list; /* used to link all items from a certain type together */ + char filename[MAX_FILENAME_LEN + 1]; /* putting the char array last is better for struct. packing */ +} memtrack_meminfo_t; + +static struct kmem_cache *meminfo_cache; + +typedef struct { + memtrack_meminfo_t *mem_hash[MEMTRACK_HASH_SZ]; + spinlock_t hash_lock; + unsigned long count; /* size of memory tracked (*malloc) or number of objects tracked */ + struct list_head tracked_objs_head; /* head of list of all objects */ + int strict_track; /* if 1 then for each object inserted check if it overlaps any of the objects already in the list */ +} tracked_obj_desc_t; + +static tracked_obj_desc_t *tracked_objs_arr[MEMTRACK_NUM_OF_MEMTYPES]; + +static const char *rsc_names[MEMTRACK_NUM_OF_MEMTYPES] = { + "kmalloc", + "vmalloc", + "kmem_cache_alloc" +}; + + +static const char *rsc_free_names[MEMTRACK_NUM_OF_MEMTYPES] = { + "kfree", + "vfree", + "kmem_cache_free" +}; + + +static inline const char *memtype_alloc_str(memtrack_memtype_t memtype) +{ + switch (memtype) { + case MEMTRACK_KMALLOC: + case MEMTRACK_VMALLOC: + case MEMTRACK_KMEM_OBJ: + return rsc_names[memtype]; + default: + return "(Unknown allocation type)"; + } +} + +static inline const char *memtype_free_str(memtrack_memtype_t memtype) +{ + switch (memtype) { + case MEMTRACK_KMALLOC: + case MEMTRACK_VMALLOC: + case MEMTRACK_KMEM_OBJ: + return rsc_free_names[memtype]; + default: + return "(Unknown allocation type)"; + } +} + +/* + * overlap_a_b + */ +static int overlap_a_b(unsigned long a_start, unsigned long a_end, + unsigned long b_start, unsigned long b_end) +{ + if ((b_start > a_end) || (a_start > b_end)) { + return 0; + } + return 1; +} + +/* + * check_overlap + */ +static void check_overlap(memtrack_memtype_t memtype, + memtrack_meminfo_t * mem_info_p, + tracked_obj_desc_t * obj_desc_p) +{ + struct list_head *pos, *next; + memtrack_meminfo_t *cur; + unsigned long start_a, end_a, start_b, end_b; + + list_for_each_safe(pos, next, &obj_desc_p->tracked_objs_head) { + cur = list_entry(pos, memtrack_meminfo_t, list); + + start_a = mem_info_p->addr; + end_a = mem_info_p->addr + mem_info_p->size - 1; + start_b = cur->addr; + end_b = cur->addr + cur->size - 1; + + if (overlap_a_b(start_a, end_a, start_b, end_b)) { + printk + ("%s overlaps! new_start=0x%lx, new_end=0x%lx, item_start=0x%lx, item_end=0x%lx\n", + memtype_alloc_str(memtype), mem_info_p->addr, + mem_info_p->addr + mem_info_p->size - 1, cur->addr, + cur->addr + cur->size - 1); + } + } +} + +/* Invoke on memory allocation */ +void memtrack_alloc(memtrack_memtype_t memtype, unsigned long addr, + unsigned long size, const char *filename, + const unsigned long line_num, int alloc_flags) +{ + unsigned long hash_val; + memtrack_meminfo_t *cur_mem_info_p, *new_mem_info_p; + tracked_obj_desc_t *obj_desc_p; + unsigned long flags; + + if (memtype >= MEMTRACK_NUM_OF_MEMTYPES) { + printk("%s: Invalid memory type (%d)\n", __func__, memtype); + return; + } + + if (!tracked_objs_arr[memtype]) { + /* object is not tracked */ + return; + } + obj_desc_p = tracked_objs_arr[memtype]; + + hash_val = addr % MEMTRACK_HASH_SZ; + + new_mem_info_p = (memtrack_meminfo_t *) + kmem_cache_alloc(meminfo_cache, alloc_flags); + if (new_mem_info_p == NULL) { + printk + ("%s: Failed allocating kmem_cache item for new mem_info. " + "Lost tracking on allocation at %s:%lu...\n", __func__, + filename, line_num); + return; + } + /* save allocation properties */ + new_mem_info_p->addr = addr; + new_mem_info_p->size = size; + new_mem_info_p->line_num = line_num; + /* Make sure that we will print out the path tail if the given filename is longer + * than MAX_FILENAME_LEN. (otherwise, we will not see the name of the actual file + * in the printout -- only the path head! + */ + if (strlen(filename) > MAX_FILENAME_LEN) { + strncpy(new_mem_info_p->filename, filename + strlen(filename) - MAX_FILENAME_LEN, MAX_FILENAME_LEN); + } else { + strncpy(new_mem_info_p->filename, filename, MAX_FILENAME_LEN); + } + new_mem_info_p->filename[MAX_FILENAME_LEN] = 0; /* NULL terminate anyway */ + + memtrack_spin_lock(&obj_desc_p->hash_lock, flags); + /* make sure given memory location is not already allocated */ + cur_mem_info_p = obj_desc_p->mem_hash[hash_val]; + while (cur_mem_info_p != NULL) { + if (cur_mem_info_p->addr == addr) { + /* Found given address in the database */ + printk + ("mtl rsc inconsistency: %s: %s::%lu: %s @ addr=0x%lX which is already known from %s:%lu\n", + __func__, filename, line_num, + memtype_alloc_str(memtype), addr, + cur_mem_info_p->filename, + cur_mem_info_p->line_num); + memtrack_spin_unlock(&obj_desc_p->hash_lock, flags); + kmem_cache_free(meminfo_cache, new_mem_info_p); + return; + } + cur_mem_info_p = cur_mem_info_p->next; + } + /* not found - we can put in the hash bucket */ + /* link as first */ + new_mem_info_p->next = obj_desc_p->mem_hash[hash_val]; + obj_desc_p->mem_hash[hash_val] = new_mem_info_p; + if (obj_desc_p->strict_track) { + check_overlap(memtype, new_mem_info_p, obj_desc_p); + } + obj_desc_p->count += size; + list_add(&new_mem_info_p->list, &obj_desc_p->tracked_objs_head); + + memtrack_spin_unlock(&obj_desc_p->hash_lock, flags); + return; +} + +/* Invoke on memory free */ +void memtrack_free(memtrack_memtype_t memtype, unsigned long addr, + const char *filename, const unsigned long line_num) +{ + unsigned long hash_val; + memtrack_meminfo_t *cur_mem_info_p, *prev_mem_info_p; + tracked_obj_desc_t *obj_desc_p; + unsigned long flags; + + if (memtype >= MEMTRACK_NUM_OF_MEMTYPES) { + printk("%s: Invalid memory type (%d)\n", __func__, memtype); + return; + } + + if (!tracked_objs_arr[memtype]) { + /* object is not tracked */ + return; + } + obj_desc_p = tracked_objs_arr[memtype]; + + hash_val = addr % MEMTRACK_HASH_SZ; + + memtrack_spin_lock(&obj_desc_p->hash_lock, flags); + /* find mem_info of given memory location */ + prev_mem_info_p = NULL; + cur_mem_info_p = obj_desc_p->mem_hash[hash_val]; + while (cur_mem_info_p != NULL) { + if (cur_mem_info_p->addr == addr) { + /* Found given address in the database - remove from the bucket/list */ + if (prev_mem_info_p == NULL) { + obj_desc_p->mem_hash[hash_val] = cur_mem_info_p->next; /* removing first */ + } else { + prev_mem_info_p->next = cur_mem_info_p->next; /* "crossover" */ + } + list_del(&cur_mem_info_p->list); + + obj_desc_p->count -= cur_mem_info_p->size; + memtrack_spin_unlock(&obj_desc_p->hash_lock, flags); + kmem_cache_free(meminfo_cache, cur_mem_info_p); + return; + } + prev_mem_info_p = cur_mem_info_p; + cur_mem_info_p = cur_mem_info_p->next; + } + + /* not found */ + printk + ("mtl rsc inconsistency: %s: %s::%lu: %s for unknown address=0x%lX\n", + __func__, filename, line_num, memtype_free_str(memtype), addr); + memtrack_spin_unlock(&obj_desc_p->hash_lock, flags); + return; +} + +/* Report current allocations status (for all memory types) */ +static void memtrack_report(void) +{ + memtrack_memtype_t memtype; + unsigned long cur_bucket; + memtrack_meminfo_t *cur_mem_info_p; + int serial = 1; + tracked_obj_desc_t *obj_desc_p; + unsigned long flags; + + printk("%s: Currently known allocations:\n", __func__); + for (memtype = 0; memtype < MEMTRACK_NUM_OF_MEMTYPES; memtype++) { + if (tracked_objs_arr[memtype]) { + printk("%d) %s:\n", serial, memtype_alloc_str(memtype)); + obj_desc_p = tracked_objs_arr[memtype]; + /* Scan all buckets to find existing allocations */ + /* TBD: this may be optimized by holding a linked list of all hash items */ + for (cur_bucket = 0; cur_bucket < MEMTRACK_HASH_SZ; + cur_bucket++) { + memtrack_spin_lock(&obj_desc_p->hash_lock, flags); /* protect per bucket/list */ + cur_mem_info_p = + obj_desc_p->mem_hash[cur_bucket]; + while (cur_mem_info_p != NULL) { /* scan bucket */ + printk("%s::%lu: %s(%lu)==%lX\n", + cur_mem_info_p->filename, + cur_mem_info_p->line_num, + memtype_alloc_str(memtype), + cur_mem_info_p->size, + cur_mem_info_p->addr); + cur_mem_info_p = cur_mem_info_p->next; + } /* while cur_mem_info_p */ + memtrack_spin_unlock(&obj_desc_p->hash_lock, flags); + } /* for cur_bucket */ + serial++; + } + } /* for memtype */ +} + + + +static struct proc_dir_entry *memtrack_tree; + +static memtrack_memtype_t get_rsc_by_name(const char *name) +{ + memtrack_memtype_t i; + + for (i=0; if_dentry->d_name.name; + + memtype= get_rsc_by_name(fname); + if (memtype >= MEMTRACK_NUM_OF_MEMTYPES) { + printk("invalid file name\n"); + return -EINVAL; + } + + if ( pos == 0 ) { + memtrack_spin_lock(&tracked_objs_arr[memtype]->hash_lock, flags); + cur= tracked_objs_arr[memtype]->count; + memtrack_spin_unlock(&tracked_objs_arr[memtype]->hash_lock, flags); + _read = sprintf(kbuf, "%lu\n", cur); + if ( _read < 0 ) { + return _read; + } + else { + file_len = _read; + } + } + + left = file_len - pos; + to_ret = (left < size) ? left : size; + if ( copy_to_user(buf, kbuf+pos, to_ret) ) { + return -EFAULT; + } + else { + *offset = pos + to_ret; + return to_ret; + } +} + +static struct file_operations memtrack_proc_fops = { + .read = memtrack_read, +}; + +static const char *memtrack_proc_entry_name = "mt_memtrack"; + +static int create_procfs_tree(void) +{ + struct proc_dir_entry *dir_ent; + struct proc_dir_entry *proc_ent; + int i, j; + unsigned long bit_mask; + + dir_ent = proc_mkdir(memtrack_proc_entry_name, NULL); + if ( !dir_ent ) { + return -1; + } + + memtrack_tree = dir_ent; + + for (i=0, bit_mask=1; iproc_fops = &memtrack_proc_fops; + } + } + + goto exit_ok; + +undo_create_root: + for (j=0, bit_mask=1; jhash_lock); + INIT_LIST_HEAD(&tracked_objs_arr[i]->tracked_objs_head); + if (bit_mask & strict_track_mask) { + tracked_objs_arr[i]->strict_track = 1; + } else { + tracked_objs_arr[i]->strict_track = 0; + } + } + } + + + if ( create_procfs_tree() ) { + printk("%s: create_procfs_tree() failed\n", __FILE__); + goto undo_cache_create; + } + + + printk("memtrack::%s done.\n", __func__); + + return 0; + +undo_cache_create: + for (j=0; jhash_lock, flags); /* protect per bucket/list */ + cur_mem_info_p = + obj_desc_p->mem_hash[cur_bucket]; + while (cur_mem_info_p != NULL) { /* scan bucket */ + next_mem_info_p = cur_mem_info_p->next; /* save "next" pointer before the "free" */ + kmem_cache_free(meminfo_cache, + cur_mem_info_p); + cur_mem_info_p = next_mem_info_p; + } /* while cur_mem_info_p */ + memtrack_spin_unlock(&obj_desc_p->hash_lock, flags); + } /* for cur_bucket */ + vfree(obj_desc_p); + } + } /* for memtype */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) + if (kmem_cache_destroy(meminfo_cache) != 0) { + printk + ("memtrack::cleanup_module: Failed on kmem_cache_destroy !\n"); + } +#else + kmem_cache_destroy(meminfo_cache); +#endif + printk("memtrack::cleanup_module done.\n"); +} + +EXPORT_SYMBOL(memtrack_alloc); +EXPORT_SYMBOL(memtrack_free); + +//module_init(memtrack_init) +//module_exit(memtrack_exit) + diff --git a/sys/ofed/drivers/infiniband/debug/memtrack.h b/sys/ofed/drivers/infiniband/debug/memtrack.h new file mode 100644 index 000000000000..e443a314b9f5 --- /dev/null +++ b/sys/ofed/drivers/infiniband/debug/memtrack.h @@ -0,0 +1,45 @@ +/* + This software is available to you under a choice of one of two + licenses. You may choose to be licensed under the terms of the GNU + General Public License (GPL) Version 2, available at + , or the OpenIB.org BSD + license, available in the LICENSE.TXT file accompanying this + software. These details are also available at + . + + 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. + + Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. +*/ + +#ifndef H_MEMTRACK_H +#define H_MEMTRACK_H + +typedef enum { + MEMTRACK_KMALLOC, + MEMTRACK_VMALLOC, + MEMTRACK_KMEM_OBJ, + MEMTRACK_NUM_OF_MEMTYPES +} memtrack_memtype_t; + +/* Invoke on memory allocation */ +void memtrack_alloc(memtrack_memtype_t memtype, unsigned long addr, + unsigned long size, const char *filename, + const unsigned long line_num, int alloc_flags); + +/* Invoke on memory free */ +void memtrack_free(memtrack_memtype_t memtype, unsigned long addr, + const char *filename, const unsigned long line_num); + +/* Report current allocations status (for all memory types) */ +/* we do not export this function since it is used by cleanup_module only */ +/* void memtrack_report(void); */ + +#endif diff --git a/sys/ofed/drivers/infiniband/debug/mtrack.h b/sys/ofed/drivers/infiniband/debug/mtrack.h new file mode 100644 index 000000000000..337d9c3986a0 --- /dev/null +++ b/sys/ofed/drivers/infiniband/debug/mtrack.h @@ -0,0 +1,138 @@ +#ifndef __mtrack_h_ +#define __mtrack_h_ + +#include + +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) +#define RDMA_KZALLOC_H +#define kzalloc(size, flags) ({ \ + void *__memtrack_kz_addr; \ + \ + __memtrack_kz_addr = kmalloc(size, flags); \ + if ( __memtrack_kz_addr ) { \ + memset( __memtrack_kz_addr, 0, size) ; \ + } \ + __memtrack_kz_addr; \ +}) + +#else +#define kzalloc(size, flags) ({ \ + void *__memtrack_addr; \ + \ + __memtrack_addr = kzalloc(size, flags); \ + if ( __memtrack_addr && (size)) { \ + memtrack_alloc(MEMTRACK_KMALLOC, (unsigned long)(__memtrack_addr), size, __FILE__, __LINE__, flags); \ + } \ + __memtrack_addr; \ +}) + +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +#define kcalloc(n, size, flags) kzalloc((n)*(size), flags) +#else +#define kcalloc(n, size, flags) ({ \ + void *__memtrack_addr; \ + \ + __memtrack_addr = kcalloc(n, size, flags); \ + if ( __memtrack_addr && (size)) { \ + memtrack_alloc(MEMTRACK_KMALLOC, (unsigned long)(__memtrack_addr), (n)*(size), __FILE__, __LINE__, flags); \ + } \ + __memtrack_addr; \ +}) +#endif + + + +#ifdef ZERO_OR_NULL_PTR +#define kmalloc(sz, flgs) ({ \ + void *__memtrack_addr; \ + \ + __memtrack_addr = kmalloc(sz, flgs); \ + if ( !ZERO_OR_NULL_PTR(__memtrack_addr)) { \ + memtrack_alloc(MEMTRACK_KMALLOC, (unsigned long)(__memtrack_addr), sz, __FILE__, __LINE__, flgs); \ + } \ + __memtrack_addr; \ +}) +#else +#define kmalloc(sz, flgs) ({ \ + void *__memtrack_addr; \ + \ + __memtrack_addr = kmalloc(sz, flgs); \ + if ( __memtrack_addr ) { \ + memtrack_alloc(MEMTRACK_KMALLOC, (unsigned long)(__memtrack_addr), sz, __FILE__, __LINE__, flgs); \ + } \ + __memtrack_addr; \ +}) + +#endif + +#ifdef ZERO_OR_NULL_PTR +#define kfree(addr) ({ \ + void *__memtrack_addr = (void *)addr; \ + if ( !ZERO_OR_NULL_PTR(__memtrack_addr) ) { \ + memtrack_free(MEMTRACK_KMALLOC, (unsigned long)(__memtrack_addr), __FILE__, __LINE__); \ + } \ + kfree(__memtrack_addr); \ +}) +#else +#define kfree(addr) ({ \ + void *__memtrack_addr = (void *)addr; \ + if ( __memtrack_addr ) { \ + memtrack_free(MEMTRACK_KMALLOC, (unsigned long)(__memtrack_addr), __FILE__, __LINE__); \ + } \ + kfree(__memtrack_addr); \ +}) +#endif + + + + + + +#define vmalloc(size) ({ \ + void *__memtrack_addr; \ + \ + __memtrack_addr = vmalloc(size); \ + if ( __memtrack_addr ) { \ + memtrack_alloc(MEMTRACK_VMALLOC, (unsigned long)(__memtrack_addr), size, __FILE__, __LINE__, GFP_ATOMIC); \ + } \ + __memtrack_addr; \ +}) + + +#define vfree(addr) ({ \ + void *__memtrack_addr = (void *)addr; \ + if ( __memtrack_addr ) { \ + memtrack_free(MEMTRACK_VMALLOC, (unsigned long)(__memtrack_addr), __FILE__, __LINE__); \ + } \ + vfree(__memtrack_addr); \ +}) + + +#define kmem_cache_alloc(cache, flags) ({ \ + void *__memtrack_addr; \ + \ + __memtrack_addr = kmem_cache_alloc(cache, flags); \ + if ( __memtrack_addr ) { \ + memtrack_alloc(MEMTRACK_KMEM_OBJ, (unsigned long)(__memtrack_addr), 1, __FILE__, __LINE__, flags); \ + } \ + __memtrack_addr; \ +}) + + +#define kmem_cache_free(cache, addr) ({ \ + void *__memtrack_addr = (void *)addr; \ + if ( __memtrack_addr ) { \ + memtrack_free(MEMTRACK_KMEM_OBJ, (unsigned long)(__memtrack_addr), __FILE__, __LINE__); \ + } \ + kmem_cache_free(cache, __memtrack_addr); \ +}) + + +#endif /* __mtrack_h_ */ + diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/Kconfig b/sys/ofed/drivers/infiniband/hw/mlx4/Kconfig new file mode 100644 index 000000000000..4175a4bd0c78 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mlx4/Kconfig @@ -0,0 +1,8 @@ +config MLX4_INFINIBAND + tristate "Mellanox ConnectX HCA support" + select MLX4_CORE + ---help--- + This driver provides low-level InfiniBand support for + Mellanox ConnectX PCI Express host channel adapters (HCAs). + This is required to use InfiniBand protocols such as + IP-over-IB or SRP with these devices. diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/Makefile b/sys/ofed/drivers/infiniband/hw/mlx4/Makefile new file mode 100644 index 000000000000..ce885a855cff --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mlx4/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_MLX4_INFINIBAND) += mlx4_ib.o + +mlx4_ib-y := ah.o cq.o doorbell.o mad.o main.o mr.o qp.o srq.o +mlx4_ib-y += wc.o diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/ah.c b/sys/ofed/drivers/infiniband/hw/mlx4/ah.c new file mode 100644 index 000000000000..26251b473d3d --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mlx4/ah.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4_ib.h" +#include +#include +#include +#include + +int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr, + u8 *mac, int *is_mcast, u8 port) +{ + struct mlx4_ib_iboe *iboe = &dev->iboe; + struct in6_addr in6; + + *is_mcast = 0; + spin_lock(&iboe->lock); + if (!iboe->netdevs[port - 1]) { + spin_unlock(&iboe->lock); + return -EINVAL; + } + spin_unlock(&iboe->lock); + + memcpy(&in6, ah_attr->grh.dgid.raw, sizeof in6); + if (rdma_link_local_addr(&in6)) + rdma_get_ll_mac(&in6, mac); + else if (rdma_is_multicast_addr(&in6)) { + rdma_get_mcast_mac(&in6, mac); + *is_mcast = 1; + } else + return -EINVAL; + + return 0; +} + +static struct ib_ah *create_ib_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, + struct mlx4_ib_ah *ah) +{ + struct mlx4_dev *dev = to_mdev(pd->device)->dev; + + ah->av.ib.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); + ah->av.ib.g_slid = ah_attr->src_path_bits; + if (ah_attr->ah_flags & IB_AH_GRH) { + ah->av.ib.g_slid |= 0x80; + ah->av.ib.gid_index = ah_attr->grh.sgid_index; + ah->av.ib.hop_limit = ah_attr->grh.hop_limit; + ah->av.ib.sl_tclass_flowlabel |= + cpu_to_be32((ah_attr->grh.traffic_class << 20) | + ah_attr->grh.flow_label); + memcpy(ah->av.ib.dgid, ah_attr->grh.dgid.raw, 16); + } + + ah->av.ib.dlid = cpu_to_be16(ah_attr->dlid); + if (ah_attr->static_rate) { + ah->av.ib.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; + while (ah->av.ib.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && + !(1 << ah->av.ib.stat_rate & dev->caps.stat_rate_support)) + --ah->av.ib.stat_rate; + } + ah->av.ib.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); + + return &ah->ibah; +} + +static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, + struct mlx4_ib_ah *ah) +{ + struct mlx4_ib_dev *ibdev = to_mdev(pd->device); + struct mlx4_dev *dev = ibdev->dev; + u8 mac[6]; + int err; + int is_mcast; + u16 vlan_tag; + union ib_gid sgid; + + err = mlx4_ib_resolve_grh(ibdev, ah_attr, mac, &is_mcast, ah_attr->port_num); + if (err) + return ERR_PTR(err); + + memcpy(ah->av.eth.mac, mac, 6); + err = ib_get_cached_gid(pd->device, ah_attr->port_num, ah_attr->grh.sgid_index, &sgid); + if (err) + return ERR_PTR(err); + vlan_tag = rdma_get_vlan_id(&sgid); + if (vlan_tag < 0x1000) + vlan_tag |= (ah_attr->sl & 7) << 13; + ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); + ah->av.eth.gid_index = ah_attr->grh.sgid_index; + ah->av.eth.vlan = cpu_to_be16(vlan_tag); + if (ah_attr->static_rate) { + ah->av.eth.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; + while (ah->av.eth.stat_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && + !(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support)) + --ah->av.eth.stat_rate; + } + + /* + * HW requires multicast LID so we just choose one. + */ + if (is_mcast) + ah->av.ib.dlid = cpu_to_be16(0xc000); + + memcpy(ah->av.eth.dgid, ah_attr->grh.dgid.raw, 16); + ah->av.eth.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); + + return &ah->ibah; +} + +struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) +{ + struct mlx4_ib_ah *ah; + struct ib_ah *ret; + + ah = kzalloc(sizeof *ah, GFP_ATOMIC); + if (!ah) + return ERR_PTR(-ENOMEM); + + if (rdma_port_get_link_layer(pd->device, ah_attr->port_num) == IB_LINK_LAYER_ETHERNET) { + if (!(ah_attr->ah_flags & IB_AH_GRH)) { + ret = ERR_PTR(-EINVAL); + goto out; + } else { + /* TBD: need to handle the case when we get called + in an atomic context and there we might sleep. We + don't expect this currently since we're working with + link local addresses which we can translate without + going to sleep */ + ret = create_iboe_ah(pd, ah_attr, ah); + if (IS_ERR(ret)) + goto out; + else + return ret; + } + } else + return create_ib_ah(pd, ah_attr, ah); /* never fails */ + +out: + kfree(ah); + return ret; +} + +int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) +{ + struct mlx4_ib_ah *ah = to_mah(ibah); + enum rdma_link_layer ll; + + memset(ah_attr, 0, sizeof *ah_attr); + ah_attr->sl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28; + ah_attr->port_num = be32_to_cpu(ah->av.ib.port_pd) >> 24; + ll = rdma_port_get_link_layer(ibah->device, ah_attr->port_num); + ah_attr->dlid = ll == IB_LINK_LAYER_INFINIBAND ? be16_to_cpu(ah->av.ib.dlid) : 0; + if (ah->av.ib.stat_rate) + ah_attr->static_rate = ah->av.ib.stat_rate - MLX4_STAT_RATE_OFFSET; + ah_attr->src_path_bits = ah->av.ib.g_slid & 0x7F; + + if (mlx4_ib_ah_grh_present(ah)) { + ah_attr->ah_flags = IB_AH_GRH; + + ah_attr->grh.traffic_class = + be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20; + ah_attr->grh.flow_label = + be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) & 0xfffff; + ah_attr->grh.hop_limit = ah->av.ib.hop_limit; + ah_attr->grh.sgid_index = ah->av.ib.gid_index; + memcpy(ah_attr->grh.dgid.raw, ah->av.ib.dgid, 16); + } + + return 0; +} + +int mlx4_ib_destroy_ah(struct ib_ah *ah) +{ + kfree(to_mah(ah)); + return 0; +} + diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/cq.c b/sys/ofed/drivers/infiniband/hw/mlx4/cq.c new file mode 100644 index 000000000000..31cd00db8196 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mlx4/cq.c @@ -0,0 +1,861 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "mlx4_ib.h" +#include "user.h" + +/* Which firmware version adds support for Resize CQ */ +#define MLX4_FW_VER_RESIZE_CQ mlx4_fw_ver(2, 5, 0) + +static void mlx4_ib_cq_comp(struct mlx4_cq *cq) +{ + struct ib_cq *ibcq = &to_mibcq(cq)->ibcq; + ibcq->comp_handler(ibcq, ibcq->cq_context); +} + +static void mlx4_ib_cq_event(struct mlx4_cq *cq, enum mlx4_event type) +{ + struct ib_event event; + struct ib_cq *ibcq; + + if (type != MLX4_EVENT_TYPE_CQ_ERROR) { + printk(KERN_WARNING "mlx4_ib: Unexpected event type %d " + "on CQ %06x\n", type, cq->cqn); + return; + } + + ibcq = &to_mibcq(cq)->ibcq; + if (ibcq->event_handler) { + event.device = ibcq->device; + event.event = IB_EVENT_CQ_ERR; + event.element.cq = ibcq; + ibcq->event_handler(&event, ibcq->cq_context); + } +} + +static void *get_cqe_from_buf(struct mlx4_ib_cq_buf *buf, int n) +{ + return mlx4_buf_offset(&buf->buf, n * sizeof (struct mlx4_cqe)); +} + +static void *get_cqe(struct mlx4_ib_cq *cq, int n) +{ + return get_cqe_from_buf(&cq->buf, n); +} + +static void *get_sw_cqe(struct mlx4_ib_cq *cq, int n) +{ + struct mlx4_cqe *cqe = get_cqe(cq, n & cq->ibcq.cqe); + + return (!!(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK) ^ + !!(n & (cq->ibcq.cqe + 1))) ? NULL : cqe; +} + +static struct mlx4_cqe *next_cqe_sw(struct mlx4_ib_cq *cq) +{ + return get_sw_cqe(cq, cq->mcq.cons_index); +} + +int mlx4_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) +{ + struct mlx4_ib_cq *mcq = to_mcq(cq); + struct mlx4_ib_dev *dev = to_mdev(cq->device); + + return mlx4_cq_modify(dev->dev, &mcq->mcq, cq_count, cq_period); +} + +static int mlx4_ib_alloc_cq_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq_buf *buf, int nent) +{ + int err; + + err = mlx4_buf_alloc(dev->dev, nent * sizeof(struct mlx4_cqe), + PAGE_SIZE * 2, &buf->buf); + + if (err) + goto out; + + err = mlx4_mtt_init(dev->dev, buf->buf.npages, buf->buf.page_shift, + &buf->mtt); + if (err) + goto err_buf; + + err = mlx4_buf_write_mtt(dev->dev, &buf->mtt, &buf->buf); + if (err) + goto err_mtt; + + return 0; + +err_mtt: + mlx4_mtt_cleanup(dev->dev, &buf->mtt); + +err_buf: + mlx4_buf_free(dev->dev, nent * sizeof(struct mlx4_cqe), + &buf->buf); + +out: + return err; +} + +static void mlx4_ib_free_cq_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq_buf *buf, int cqe) +{ + mlx4_buf_free(dev->dev, (cqe + 1) * sizeof(struct mlx4_cqe), &buf->buf); +} + +static int mlx4_ib_get_cq_umem(struct mlx4_ib_dev *dev, struct ib_ucontext *context, + struct mlx4_ib_cq_buf *buf, struct ib_umem **umem, + u64 buf_addr, int cqe) +{ + int err; + + *umem = ib_umem_get(context, buf_addr, cqe * sizeof (struct mlx4_cqe), + IB_ACCESS_LOCAL_WRITE, 1); + if (IS_ERR(*umem)) + return PTR_ERR(*umem); + + err = mlx4_mtt_init(dev->dev, ib_umem_page_count(*umem), + ilog2((*umem)->page_size), &buf->mtt); + if (err) + goto err_buf; + + err = mlx4_ib_umem_write_mtt(dev, &buf->mtt, *umem); + if (err) + goto err_mtt; + + return 0; + +err_mtt: + mlx4_mtt_cleanup(dev->dev, &buf->mtt); + +err_buf: + ib_umem_release(*umem); + + return err; +} + +struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(ibdev); + struct mlx4_ib_cq *cq; + struct mlx4_uar *uar; + int err; + + if (entries < 1 || entries > dev->dev->caps.max_cqes) { + mlx4_ib_dbg("invalid num of entries: %d", entries); + return ERR_PTR(-EINVAL); + } + + cq = kzalloc(sizeof *cq, GFP_KERNEL); + if (!cq) + return ERR_PTR(-ENOMEM); + + entries = roundup_pow_of_two(entries + 1); + cq->ibcq.cqe = entries - 1; + mutex_init(&cq->resize_mutex); + spin_lock_init(&cq->lock); + cq->resize_buf = NULL; + cq->resize_umem = NULL; + + if (context) { + struct mlx4_ib_create_cq ucmd; + + if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) { + err = -EFAULT; + goto err_cq; + } + + err = mlx4_ib_get_cq_umem(dev, context, &cq->buf, &cq->umem, + ucmd.buf_addr, entries); + if (err) + goto err_cq; + + err = mlx4_ib_db_map_user(to_mucontext(context), ucmd.db_addr, + &cq->db); + if (err) + goto err_mtt; + + uar = &to_mucontext(context)->uar; + } else { + err = mlx4_db_alloc(dev->dev, &cq->db, 1); + if (err) + goto err_cq; + + cq->mcq.set_ci_db = cq->db.db; + cq->mcq.arm_db = cq->db.db + 1; + *cq->mcq.set_ci_db = 0; + *cq->mcq.arm_db = 0; + + err = mlx4_ib_alloc_cq_buf(dev, &cq->buf, entries); + if (err) + goto err_db; + + uar = &dev->priv_uar; + } + + err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar, + cq->db.dma, &cq->mcq, + vector == IB_CQ_VECTOR_LEAST_ATTACHED ? + MLX4_LEAST_ATTACHED_VECTOR : vector, 0); + if (err) + goto err_dbmap; + + cq->mcq.comp = mlx4_ib_cq_comp; + cq->mcq.event = mlx4_ib_cq_event; + + if (context) + if (ib_copy_to_udata(udata, &cq->mcq.cqn, sizeof (__u32))) { + err = -EFAULT; + goto err_dbmap; + } + + return &cq->ibcq; + +err_dbmap: + if (context) + mlx4_ib_db_unmap_user(to_mucontext(context), &cq->db); + +err_mtt: + mlx4_mtt_cleanup(dev->dev, &cq->buf.mtt); + + if (context) + ib_umem_release(cq->umem); + else + mlx4_ib_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe); + +err_db: + if (!context) + mlx4_db_free(dev->dev, &cq->db); + +err_cq: + kfree(cq); + + return ERR_PTR(err); +} + +static int mlx4_alloc_resize_buf(struct mlx4_ib_dev *dev, struct mlx4_ib_cq *cq, + int entries) +{ + int err; + + if (cq->resize_buf) + return -EBUSY; + + cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC); + if (!cq->resize_buf) + return -ENOMEM; + + err = mlx4_ib_alloc_cq_buf(dev, &cq->resize_buf->buf, entries); + if (err) { + kfree(cq->resize_buf); + cq->resize_buf = NULL; + return err; + } + + cq->resize_buf->cqe = entries - 1; + + return 0; +} + +static int mlx4_alloc_resize_umem(struct mlx4_ib_dev *dev, struct mlx4_ib_cq *cq, + int entries, struct ib_udata *udata) +{ + struct mlx4_ib_resize_cq ucmd; + int err; + + if (cq->resize_umem) + return -EBUSY; + + if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) + return -EFAULT; + + cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC); + if (!cq->resize_buf) + return -ENOMEM; + + err = mlx4_ib_get_cq_umem(dev, cq->umem->context, &cq->resize_buf->buf, + &cq->resize_umem, ucmd.buf_addr, entries); + if (err) { + kfree(cq->resize_buf); + cq->resize_buf = NULL; + return err; + } + + cq->resize_buf->cqe = entries - 1; + + return 0; +} + +static int mlx4_ib_get_outstanding_cqes(struct mlx4_ib_cq *cq) +{ + u32 i; + + i = cq->mcq.cons_index; + while (get_sw_cqe(cq, i & cq->ibcq.cqe)) + ++i; + + return i - cq->mcq.cons_index; +} + +static void mlx4_ib_cq_resize_copy_cqes(struct mlx4_ib_cq *cq) +{ + struct mlx4_cqe *cqe, *new_cqe; + int i; + + i = cq->mcq.cons_index; + cqe = get_cqe(cq, i & cq->ibcq.cqe); + while ((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) != MLX4_CQE_OPCODE_RESIZE) { + new_cqe = get_cqe_from_buf(&cq->resize_buf->buf, + (i + 1) & cq->resize_buf->cqe); + memcpy(new_cqe, get_cqe(cq, i & cq->ibcq.cqe), sizeof(struct mlx4_cqe)); + new_cqe->owner_sr_opcode = (cqe->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK) | + (((i + 1) & (cq->resize_buf->cqe + 1)) ? MLX4_CQE_OWNER_MASK : 0); + cqe = get_cqe(cq, ++i & cq->ibcq.cqe); + } + ++cq->mcq.cons_index; +} + +int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(ibcq->device); + struct mlx4_ib_cq *cq = to_mcq(ibcq); + struct mlx4_mtt mtt; + int outst_cqe; + int err; + + if (dev->dev->caps.fw_ver < MLX4_FW_VER_RESIZE_CQ) + return -ENOSYS; + + mutex_lock(&cq->resize_mutex); + + if (entries < 1 || entries > dev->dev->caps.max_cqes) { + err = -EINVAL; + goto out; + } + + entries = roundup_pow_of_two(entries + 1); + if (entries == ibcq->cqe + 1) { + err = 0; + goto out; + } + + if (ibcq->uobject) { + err = mlx4_alloc_resize_umem(dev, cq, entries, udata); + if (err) + goto out; + } else { + /* Can't be smaller than the number of outstanding CQEs */ + outst_cqe = mlx4_ib_get_outstanding_cqes(cq); + if (entries < outst_cqe + 1) { + err = 0; + goto out; + } + + err = mlx4_alloc_resize_buf(dev, cq, entries); + if (err) + goto out; + } + + mtt = cq->buf.mtt; + + err = mlx4_cq_resize(dev->dev, &cq->mcq, entries, &cq->resize_buf->buf.mtt); + if (err) + goto err_buf; + + mlx4_mtt_cleanup(dev->dev, &mtt); + if (ibcq->uobject) { + cq->buf = cq->resize_buf->buf; + cq->ibcq.cqe = cq->resize_buf->cqe; + ib_umem_release(cq->umem); + cq->umem = cq->resize_umem; + + kfree(cq->resize_buf); + cq->resize_buf = NULL; + cq->resize_umem = NULL; + } else { + struct mlx4_ib_cq_buf tmp_buf; + int tmp_cqe = 0; + + spin_lock_irq(&cq->lock); + if (cq->resize_buf) { + mlx4_ib_cq_resize_copy_cqes(cq); + tmp_buf = cq->buf; + tmp_cqe = cq->ibcq.cqe; + cq->buf = cq->resize_buf->buf; + cq->ibcq.cqe = cq->resize_buf->cqe; + + kfree(cq->resize_buf); + cq->resize_buf = NULL; + } + spin_unlock_irq(&cq->lock); + + if (tmp_cqe) + mlx4_ib_free_cq_buf(dev, &tmp_buf, tmp_cqe); + } + + goto out; + +err_buf: + mlx4_mtt_cleanup(dev->dev, &cq->resize_buf->buf.mtt); + if (!ibcq->uobject) + mlx4_ib_free_cq_buf(dev, &cq->resize_buf->buf, + cq->resize_buf->cqe); + + kfree(cq->resize_buf); + cq->resize_buf = NULL; + + if (cq->resize_umem) { + ib_umem_release(cq->resize_umem); + cq->resize_umem = NULL; + } + +out: + mutex_unlock(&cq->resize_mutex); + return err; +} + +int mlx4_ib_destroy_cq(struct ib_cq *cq) +{ + struct mlx4_ib_dev *dev = to_mdev(cq->device); + struct mlx4_ib_cq *mcq = to_mcq(cq); + + mlx4_cq_free(dev->dev, &mcq->mcq); + mlx4_mtt_cleanup(dev->dev, &mcq->buf.mtt); + + if (cq->uobject) { + mlx4_ib_db_unmap_user(to_mucontext(cq->uobject->context), &mcq->db); + ib_umem_release(mcq->umem); + } else { + mlx4_ib_free_cq_buf(dev, &mcq->buf, cq->cqe); + mlx4_db_free(dev->dev, &mcq->db); + } + + kfree(mcq); + + return 0; +} + +static void dump_cqe(void *cqe) +{ + __be32 *buf = cqe; + + printk(KERN_DEBUG "CQE contents %08x %08x %08x %08x %08x %08x %08x %08x\n", + be32_to_cpu(buf[0]), be32_to_cpu(buf[1]), be32_to_cpu(buf[2]), + be32_to_cpu(buf[3]), be32_to_cpu(buf[4]), be32_to_cpu(buf[5]), + be32_to_cpu(buf[6]), be32_to_cpu(buf[7])); +} + +static void mlx4_ib_handle_error_cqe(struct mlx4_err_cqe *cqe, + struct ib_wc *wc) +{ + if (cqe->syndrome == MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR) { + printk(KERN_DEBUG "local QP operation err " + "(QPN %06x, WQE index %x, vendor syndrome %02x, " + "opcode = %02x)\n", + be32_to_cpu(cqe->my_qpn), be16_to_cpu(cqe->wqe_index), + cqe->vendor_err_syndrome, + cqe->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK); + dump_cqe(cqe); + } + + switch (cqe->syndrome) { + case MLX4_CQE_SYNDROME_LOCAL_LENGTH_ERR: + wc->status = IB_WC_LOC_LEN_ERR; + break; + case MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR: + wc->status = IB_WC_LOC_QP_OP_ERR; + break; + case MLX4_CQE_SYNDROME_LOCAL_PROT_ERR: + wc->status = IB_WC_LOC_PROT_ERR; + break; + case MLX4_CQE_SYNDROME_WR_FLUSH_ERR: + wc->status = IB_WC_WR_FLUSH_ERR; + break; + case MLX4_CQE_SYNDROME_MW_BIND_ERR: + wc->status = IB_WC_MW_BIND_ERR; + break; + case MLX4_CQE_SYNDROME_BAD_RESP_ERR: + wc->status = IB_WC_BAD_RESP_ERR; + break; + case MLX4_CQE_SYNDROME_LOCAL_ACCESS_ERR: + wc->status = IB_WC_LOC_ACCESS_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR: + wc->status = IB_WC_REM_INV_REQ_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_ACCESS_ERR: + wc->status = IB_WC_REM_ACCESS_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_OP_ERR: + wc->status = IB_WC_REM_OP_ERR; + break; + case MLX4_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR: + wc->status = IB_WC_RETRY_EXC_ERR; + break; + case MLX4_CQE_SYNDROME_RNR_RETRY_EXC_ERR: + wc->status = IB_WC_RNR_RETRY_EXC_ERR; + break; + case MLX4_CQE_SYNDROME_REMOTE_ABORTED_ERR: + wc->status = IB_WC_REM_ABORT_ERR; + break; + default: + wc->status = IB_WC_GENERAL_ERR; + break; + } + + wc->vendor_err = cqe->vendor_err_syndrome; +} + +static int mlx4_ib_ipoib_csum_ok(__be16 status, __be16 checksum) +{ + return ((status & cpu_to_be16(MLX4_CQE_STATUS_IPV4 | + MLX4_CQE_STATUS_IPV4F | + MLX4_CQE_STATUS_IPV4OPT | + MLX4_CQE_STATUS_IPV6 | + MLX4_CQE_STATUS_IPOK)) == + cpu_to_be16(MLX4_CQE_STATUS_IPV4 | + MLX4_CQE_STATUS_IPOK)) && + (status & cpu_to_be16(MLX4_CQE_STATUS_UDP | + MLX4_CQE_STATUS_TCP)) && + checksum == cpu_to_be16(0xffff); +} + +static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, + struct mlx4_ib_qp **cur_qp, + struct ib_wc *wc) +{ + struct mlx4_cqe *cqe; + struct mlx4_qp *mqp; + struct mlx4_ib_wq *wq; + struct mlx4_ib_srq *srq; + struct mlx4_srq *msrq; + int is_send; + int is_error; + u32 g_mlpath_rqpn; + int is_xrc_recv = 0; + u16 wqe_ctr; + +repoll: + cqe = next_cqe_sw(cq); + if (!cqe) + return -EAGAIN; + + ++cq->mcq.cons_index; + + /* + * Make sure we read CQ entry contents after we've checked the + * ownership bit. + */ + rmb(); + + is_send = cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK; + is_error = (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == + MLX4_CQE_OPCODE_ERROR; + + if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == MLX4_OPCODE_NOP && + is_send)) { + printk(KERN_WARNING "Completion for NOP opcode detected!\n"); + return -EINVAL; + } + + /* Resize CQ in progress */ + if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == MLX4_CQE_OPCODE_RESIZE)) { + if (cq->resize_buf) { + struct mlx4_ib_dev *dev = to_mdev(cq->ibcq.device); + + mlx4_ib_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe); + cq->buf = cq->resize_buf->buf; + cq->ibcq.cqe = cq->resize_buf->cqe; + + kfree(cq->resize_buf); + cq->resize_buf = NULL; + } + + goto repoll; + } + + if ((be32_to_cpu(cqe->vlan_my_qpn) & (1 << 23)) && !is_send) { + /* + * We do not have to take the XRC SRQ table lock here, + * because CQs will be locked while XRC SRQs are removed + * from the table. + */ + msrq = __mlx4_srq_lookup(to_mdev(cq->ibcq.device)->dev, + be32_to_cpu(cqe->g_mlpath_rqpn) & + 0xffffff); + if (unlikely(!msrq)) { + printk(KERN_WARNING "CQ %06x with entry for unknown " + "XRC SRQ %06x\n", cq->mcq.cqn, + be32_to_cpu(cqe->g_mlpath_rqpn) & 0xffffff); + return -EINVAL; + } + is_xrc_recv = 1; + srq = to_mibsrq(msrq); + } else if (!*cur_qp || + (be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_QPN_MASK) != (*cur_qp)->mqp.qpn) { + /* + * We do not have to take the QP table lock here, + * because CQs will be locked while QPs are removed + * from the table. + */ + mqp = __mlx4_qp_lookup(to_mdev(cq->ibcq.device)->dev, + be32_to_cpu(cqe->vlan_my_qpn)); + if (unlikely(!mqp)) { + printk(KERN_WARNING "CQ %06x with entry for unknown QPN %06x\n", + cq->mcq.cqn, be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_QPN_MASK); + return -EINVAL; + } + + *cur_qp = to_mibqp(mqp); + } + + wc->qp = is_xrc_recv ? NULL: &(*cur_qp)->ibqp; + + if (is_send) { + wq = &(*cur_qp)->sq; + if (!(*cur_qp)->sq_signal_bits) { + wqe_ctr = be16_to_cpu(cqe->wqe_index); + wq->tail += (u16) (wqe_ctr - (u16) wq->tail); + } + wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; + ++wq->tail; + } else if (is_xrc_recv) { + wqe_ctr = be16_to_cpu(cqe->wqe_index); + wc->wr_id = srq->wrid[wqe_ctr]; + mlx4_ib_free_srq_wqe(srq, wqe_ctr); + } else if ((*cur_qp)->ibqp.srq) { + srq = to_msrq((*cur_qp)->ibqp.srq); + wqe_ctr = be16_to_cpu(cqe->wqe_index); + wc->wr_id = srq->wrid[wqe_ctr]; + mlx4_ib_free_srq_wqe(srq, wqe_ctr); + } else { + wq = &(*cur_qp)->rq; + wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)]; + ++wq->tail; + } + + if (unlikely(is_error)) { + mlx4_ib_handle_error_cqe((struct mlx4_err_cqe *) cqe, wc); + return 0; + } + + wc->status = IB_WC_SUCCESS; + + if (is_send) { + wc->wc_flags = 0; + switch (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) { + case MLX4_OPCODE_RDMA_WRITE_IMM: + wc->wc_flags |= IB_WC_WITH_IMM; + case MLX4_OPCODE_RDMA_WRITE: + wc->opcode = IB_WC_RDMA_WRITE; + break; + case MLX4_OPCODE_SEND_IMM: + wc->wc_flags |= IB_WC_WITH_IMM; + case MLX4_OPCODE_SEND: + case MLX4_OPCODE_SEND_INVAL: + wc->opcode = IB_WC_SEND; + break; + case MLX4_OPCODE_RDMA_READ: + wc->opcode = IB_WC_RDMA_READ; + wc->byte_len = be32_to_cpu(cqe->byte_cnt); + break; + case MLX4_OPCODE_ATOMIC_CS: + wc->opcode = IB_WC_COMP_SWAP; + wc->byte_len = 8; + break; + case MLX4_OPCODE_ATOMIC_FA: + wc->opcode = IB_WC_FETCH_ADD; + wc->byte_len = 8; + break; + case MLX4_OPCODE_MASKED_ATOMIC_CS: + wc->opcode = IB_WC_MASKED_COMP_SWAP; + wc->byte_len = 8; + break; + case MLX4_OPCODE_MASKED_ATOMIC_FA: + wc->opcode = IB_WC_MASKED_FETCH_ADD; + wc->byte_len = 8; + break; + case MLX4_OPCODE_BIND_MW: + wc->opcode = IB_WC_BIND_MW; + break; + case MLX4_OPCODE_LSO: + wc->opcode = IB_WC_LSO; + break; + case MLX4_OPCODE_FMR: + wc->opcode = IB_WC_FAST_REG_MR; + break; + case MLX4_OPCODE_LOCAL_INVAL: + wc->opcode = IB_WC_LOCAL_INV; + break; + } + } else { + wc->byte_len = be32_to_cpu(cqe->byte_cnt); + + switch (cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) { + case MLX4_RECV_OPCODE_RDMA_WRITE_IMM: + wc->opcode = IB_WC_RECV_RDMA_WITH_IMM; + wc->wc_flags = IB_WC_WITH_IMM; + wc->ex.imm_data = cqe->immed_rss_invalid; + break; + case MLX4_RECV_OPCODE_SEND_INVAL: + wc->opcode = IB_WC_RECV; + wc->wc_flags = IB_WC_WITH_INVALIDATE; + wc->ex.invalidate_rkey = be32_to_cpu(cqe->immed_rss_invalid); + break; + case MLX4_RECV_OPCODE_SEND: + wc->opcode = IB_WC_RECV; + wc->wc_flags = 0; + break; + case MLX4_RECV_OPCODE_SEND_IMM: + wc->opcode = IB_WC_RECV; + wc->wc_flags = IB_WC_WITH_IMM; + wc->ex.imm_data = cqe->immed_rss_invalid; + break; + } + + wc->slid = be16_to_cpu(cqe->rlid); + wc->sl = be16_to_cpu(cqe->sl_vid) >> 12; + g_mlpath_rqpn = be32_to_cpu(cqe->g_mlpath_rqpn); + wc->src_qp = g_mlpath_rqpn & 0xffffff; + wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f; + wc->wc_flags |= g_mlpath_rqpn & 0x80000000 ? IB_WC_GRH : 0; + wc->pkey_index = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f; + wc->csum_ok = mlx4_ib_ipoib_csum_ok(cqe->status, cqe->checksum); + } + + return 0; +} + +int mlx4_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) +{ + struct mlx4_ib_cq *cq = to_mcq(ibcq); + struct mlx4_ib_qp *cur_qp = NULL; + unsigned long flags; + int npolled; + int err = 0; + + spin_lock_irqsave(&cq->lock, flags); + + for (npolled = 0; npolled < num_entries; ++npolled) { + err = mlx4_ib_poll_one(cq, &cur_qp, wc + npolled); + if (err) + break; + } + + if (npolled) + mlx4_cq_set_ci(&cq->mcq); + + spin_unlock_irqrestore(&cq->lock, flags); + + if (err == 0 || err == -EAGAIN) + return npolled; + else + return err; +} + +int mlx4_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) +{ + mlx4_cq_arm(&to_mcq(ibcq)->mcq, + (flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ? + MLX4_CQ_DB_REQ_NOT_SOL : MLX4_CQ_DB_REQ_NOT, + to_mdev(ibcq->device)->priv_uar.map, + MLX4_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->uar_lock)); + + return 0; +} + +void __mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq) +{ + u32 prod_index; + int nfreed = 0; + struct mlx4_cqe *cqe, *dest; + u8 owner_bit; + int is_xrc_srq = 0; + + if (srq && srq->ibsrq.xrc_cq) + is_xrc_srq = 1; + + /* + * First we need to find the current producer index, so we + * know where to start cleaning from. It doesn't matter if HW + * adds new entries after this loop -- the QP we're worried + * about is already in RESET, so the new entries won't come + * from our QP and therefore don't need to be checked. + */ + for (prod_index = cq->mcq.cons_index; get_sw_cqe(cq, prod_index); ++prod_index) + if (prod_index == cq->mcq.cons_index + cq->ibcq.cqe) + break; + + /* + * Now sweep backwards through the CQ, removing CQ entries + * that match our QP by copying older entries on top of them. + */ + while ((int) --prod_index - (int) cq->mcq.cons_index >= 0) { + cqe = get_cqe(cq, prod_index & cq->ibcq.cqe); + if (((be32_to_cpu(cqe->vlan_my_qpn) & 0xffffff) == qpn) || + (is_xrc_srq && + (be32_to_cpu(cqe->g_mlpath_rqpn) & 0xffffff) == + srq->msrq.srqn)) { + if (srq && !(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK)) + mlx4_ib_free_srq_wqe(srq, be16_to_cpu(cqe->wqe_index)); + ++nfreed; + } else if (nfreed) { + dest = get_cqe(cq, (prod_index + nfreed) & cq->ibcq.cqe); + owner_bit = dest->owner_sr_opcode & MLX4_CQE_OWNER_MASK; + memcpy(dest, cqe, sizeof *cqe); + dest->owner_sr_opcode = owner_bit | + (dest->owner_sr_opcode & ~MLX4_CQE_OWNER_MASK); + } + } + + if (nfreed) { + cq->mcq.cons_index += nfreed; + /* + * Make sure update of buffer contents is done before + * updating consumer index. + */ + wmb(); + mlx4_cq_set_ci(&cq->mcq); + } +} + +void mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq) +{ + spin_lock_irq(&cq->lock); + __mlx4_ib_cq_clean(cq, qpn, srq); + spin_unlock_irq(&cq->lock); +} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/doorbell.c b/sys/ofed/drivers/infiniband/hw/mlx4/doorbell.c new file mode 100644 index 000000000000..8aee4233b388 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mlx4/doorbell.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "mlx4_ib.h" + +struct mlx4_ib_user_db_page { + struct list_head list; + struct ib_umem *umem; + unsigned long user_virt; + int refcnt; +}; + +int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt, + struct mlx4_db *db) +{ + struct mlx4_ib_user_db_page *page; + struct ib_umem_chunk *chunk; + int err = 0; + + mutex_lock(&context->db_page_mutex); + + list_for_each_entry(page, &context->db_page_list, list) + if (page->user_virt == (virt & PAGE_MASK)) + goto found; + + page = kmalloc(sizeof *page, GFP_KERNEL); + if (!page) { + err = -ENOMEM; + goto out; + } + + page->user_virt = (virt & PAGE_MASK); + page->refcnt = 0; + page->umem = ib_umem_get(&context->ibucontext, virt & PAGE_MASK, + PAGE_SIZE, 0, 0); + if (IS_ERR(page->umem)) { + err = PTR_ERR(page->umem); + kfree(page); + goto out; + } + + list_add(&page->list, &context->db_page_list); + +found: + chunk = list_entry(page->umem->chunk_list.next, struct ib_umem_chunk, list); + db->dma = sg_dma_address(chunk->page_list) + (virt & ~PAGE_MASK); + db->u.user_page = page; + ++page->refcnt; + +out: + mutex_unlock(&context->db_page_mutex); + + return err; +} + +void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_db *db) +{ + mutex_lock(&context->db_page_mutex); + + if (!--db->u.user_page->refcnt) { + list_del(&db->u.user_page->list); + ib_umem_release(db->u.user_page->umem); + kfree(db->u.user_page); + } + + mutex_unlock(&context->db_page_mutex); +} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/mad.c b/sys/ofed/drivers/infiniband/hw/mlx4/mad.c new file mode 100644 index 000000000000..2bb87ab7ec50 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mlx4/mad.c @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include + +#include "mlx4_ib.h" + +enum { + MLX4_IB_VENDOR_CLASS1 = 0x9, + MLX4_IB_VENDOR_CLASS2 = 0xa +}; + +int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int ignore_mkey, int ignore_bkey, + int port, struct ib_wc *in_wc, struct ib_grh *in_grh, + void *in_mad, void *response_mad) +{ + struct mlx4_cmd_mailbox *inmailbox, *outmailbox; + void *inbox; + int err; + u32 in_modifier = port; + u8 op_modifier = 0; + + inmailbox = mlx4_alloc_cmd_mailbox(dev->dev); + if (IS_ERR(inmailbox)) + return PTR_ERR(inmailbox); + inbox = inmailbox->buf; + + outmailbox = mlx4_alloc_cmd_mailbox(dev->dev); + if (IS_ERR(outmailbox)) { + mlx4_free_cmd_mailbox(dev->dev, inmailbox); + return PTR_ERR(outmailbox); + } + + memcpy(inbox, in_mad, 256); + + /* + * Key check traps can't be generated unless we have in_wc to + * tell us where to send the trap. + */ + if (ignore_mkey || !in_wc) + op_modifier |= 0x1; + if (ignore_bkey || !in_wc) + op_modifier |= 0x2; + + if (in_wc) { + struct { + __be32 my_qpn; + u32 reserved1; + __be32 rqpn; + u8 sl; + u8 g_path; + u16 reserved2[2]; + __be16 pkey; + u32 reserved3[11]; + u8 grh[40]; + } *ext_info; + + memset(inbox + 256, 0, 256); + ext_info = inbox + 256; + + ext_info->my_qpn = cpu_to_be32(in_wc->qp->qp_num); + ext_info->rqpn = cpu_to_be32(in_wc->src_qp); + ext_info->sl = in_wc->sl << 4; + ext_info->g_path = in_wc->dlid_path_bits | + (in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0); + ext_info->pkey = cpu_to_be16(in_wc->pkey_index); + + if (in_grh) + memcpy(ext_info->grh, in_grh, 40); + + op_modifier |= 0x4; + + in_modifier |= in_wc->slid << 16; + } + + err = mlx4_cmd_box(dev->dev, inmailbox->dma, outmailbox->dma, + in_modifier, op_modifier, + MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C); + + if (!err) + memcpy(response_mad, outmailbox->buf, 256); + + mlx4_free_cmd_mailbox(dev->dev, inmailbox); + mlx4_free_cmd_mailbox(dev->dev, outmailbox); + + return err; +} + +static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl) +{ + struct ib_ah *new_ah; + struct ib_ah_attr ah_attr; + + if (!dev->send_agent[port_num - 1][0]) + return; + + memset(&ah_attr, 0, sizeof ah_attr); + ah_attr.dlid = lid; + ah_attr.sl = sl; + ah_attr.port_num = port_num; + + new_ah = ib_create_ah(dev->send_agent[port_num - 1][0]->qp->pd, + &ah_attr); + if (IS_ERR(new_ah)) + return; + + spin_lock(&dev->sm_lock); + if (dev->sm_ah[port_num - 1]) + ib_destroy_ah(dev->sm_ah[port_num - 1]); + dev->sm_ah[port_num - 1] = new_ah; + spin_unlock(&dev->sm_lock); +} + +/* + * Snoop SM MADs for port info and P_Key table sets, so we can + * synthesize LID change and P_Key change events. + */ +static void smp_snoop(struct ib_device *ibdev, u8 port_num, struct ib_mad *mad, + u16 prev_lid) +{ + struct ib_event event; + + if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || + mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && + mad->mad_hdr.method == IB_MGMT_METHOD_SET) { + if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) { + struct ib_port_info *pinfo = + (struct ib_port_info *) ((struct ib_smp *) mad)->data; + u16 lid = be16_to_cpu(pinfo->lid); + + update_sm_ah(to_mdev(ibdev), port_num, + be16_to_cpu(pinfo->sm_lid), + pinfo->neighbormtu_mastersmsl & 0xf); + + event.device = ibdev; + event.element.port_num = port_num; + + if (pinfo->clientrereg_resv_subnetto & 0x80) { + event.event = IB_EVENT_CLIENT_REREGISTER; + ib_dispatch_event(&event); + } + + if (prev_lid != lid) { + event.event = IB_EVENT_LID_CHANGE; + ib_dispatch_event(&event); + } + } + + if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) { + event.device = ibdev; + event.event = IB_EVENT_PKEY_CHANGE; + event.element.port_num = port_num; + ib_dispatch_event(&event); + } + } +} + +static void node_desc_override(struct ib_device *dev, + struct ib_mad *mad) +{ + if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || + mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && + mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP && + mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) { + spin_lock(&to_mdev(dev)->sm_lock); + memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64); + spin_unlock(&to_mdev(dev)->sm_lock); + } +} + +static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *mad) +{ + int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; + struct ib_mad_send_buf *send_buf; + struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; + int ret; + + if (agent) { + send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, + IB_MGMT_MAD_DATA, GFP_ATOMIC); + /* + * We rely here on the fact that MLX QPs don't use the + * address handle after the send is posted (this is + * wrong following the IB spec strictly, but we know + * it's OK for our devices). + */ + spin_lock(&dev->sm_lock); + memcpy(send_buf->mad, mad, sizeof *mad); + if ((send_buf->ah = dev->sm_ah[port_num - 1])) + ret = ib_post_send_mad(send_buf, NULL); + else + ret = -EINVAL; + spin_unlock(&dev->sm_lock); + + if (ret) + ib_free_send_mad(send_buf); + } +} + +static int is_vendor_id(__be16 attr_id) +{ + return (attr_id & IB_SMP_ATTR_VENDOR_MASK) == IB_SMP_ATTR_VENDOR_MASK; +} + +static int supported_vendor_id(__be16 attr_id) +{ + return 1; +} + +static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, + struct ib_wc *in_wc, struct ib_grh *in_grh, + struct ib_mad *in_mad, struct ib_mad *out_mad) +{ + u16 slid, prev_lid = 0; + int err; + struct ib_port_attr pattr; + + slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE); + + if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0) { + forward_trap(to_mdev(ibdev), port_num, in_mad); + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; + } + + if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || + in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { + if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && + in_mad->mad_hdr.method != IB_MGMT_METHOD_SET && + in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) + return IB_MAD_RESULT_SUCCESS; + + /* + * Don't process SMInfo queries or vendor-specific + * MADs -- the SMA can't handle them. + */ + if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO || + (is_vendor_id(in_mad->mad_hdr.attr_id) && + !supported_vendor_id(in_mad->mad_hdr.attr_id))) + return IB_MAD_RESULT_SUCCESS; + } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || + in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS1 || + in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS2 || + in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_CONG_MGMT) { + if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && + in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) + return IB_MAD_RESULT_SUCCESS; + } else + return IB_MAD_RESULT_SUCCESS; + + if ((in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || + in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && + in_mad->mad_hdr.method == IB_MGMT_METHOD_SET && + in_mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO && + !ib_query_port(ibdev, port_num, &pattr)) + prev_lid = pattr.lid; + + err = mlx4_MAD_IFC(to_mdev(ibdev), + mad_flags & IB_MAD_IGNORE_MKEY, + mad_flags & IB_MAD_IGNORE_BKEY, + port_num, in_wc, in_grh, in_mad, out_mad); + if (err) + return IB_MAD_RESULT_FAILURE; + + if (!out_mad->mad_hdr.status) { + smp_snoop(ibdev, port_num, in_mad, prev_lid); + node_desc_override(ibdev, out_mad); + } + + /* set return bit in status of directed route responses */ + if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) + out_mad->mad_hdr.status |= cpu_to_be16(1 << 15); + + if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) + /* no response for trap repress */ + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; + + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; +} + +static __be32 be64_to_be32(__be64 b64) +{ + return cpu_to_be32(be64_to_cpu(b64) & 0xffffffff); +} + +static void edit_counters(struct mlx4_counters *cnt, void *data) +{ + *(__be32 *)(data + 40 + 24) = be64_to_be32(cnt->tx_bytes); + *(__be32 *)(data + 40 + 28) = be64_to_be32(cnt->rx_bytes); + *(__be32 *)(data + 40 + 32) = be64_to_be32(cnt->tx_frames); + *(__be32 *)(data + 40 + 36) = be64_to_be32(cnt->rx_frames); +} + +static void edit_ext_counters(struct mlx4_counters_ext *cnt, void *data) +{ + *(__be32 *)(data + 40 + 24) = be64_to_be32(cnt->tx_uni_bytes); + *(__be32 *)(data + 40 + 28) = be64_to_be32(cnt->rx_uni_bytes); + *(__be32 *)(data + 40 + 32) = be64_to_be32(cnt->tx_uni_frames); + *(__be32 *)(data + 40 + 36) = be64_to_be32(cnt->rx_uni_frames); + *(__be32 *)(data + 40 + 8) = be64_to_be32(cnt->rx_err_frames); +} + +static int rdmaoe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, + struct ib_wc *in_wc, struct ib_grh *in_grh, + struct ib_mad *in_mad, struct ib_mad *out_mad) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_ib_dev *dev = to_mdev(ibdev); + int err; + u32 inmod = dev->counters[port_num - 1] & 0xffff; + int mode; + + if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT) + return -EINVAL; + + mailbox = mlx4_alloc_cmd_mailbox(dev->dev); + if (IS_ERR(mailbox)) + return IB_MAD_RESULT_FAILURE; + + err = mlx4_cmd_box(dev->dev, 0, mailbox->dma, inmod, 0, + MLX4_CMD_QUERY_IF_STAT, MLX4_CMD_TIME_CLASS_C); + if (err) + err = IB_MAD_RESULT_FAILURE; + else { + memset(out_mad->data, 0, sizeof out_mad->data); + mode = be32_to_cpu(((struct mlx4_counters *)mailbox->buf)->counter_mode) & 0xf; + switch (mode) { + case 0: + edit_counters(mailbox->buf, out_mad->data); + err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; + break; + case 1: + edit_ext_counters(mailbox->buf, out_mad->data); + err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; + break; + default: + err = IB_MAD_RESULT_FAILURE; + } + } + + mlx4_free_cmd_mailbox(dev->dev, mailbox); + + return err; +} + +int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, + struct ib_wc *in_wc, struct ib_grh *in_grh, + struct ib_mad *in_mad, struct ib_mad *out_mad) +{ + switch (rdma_port_get_link_layer(ibdev, port_num)) { + case IB_LINK_LAYER_INFINIBAND: + return ib_process_mad(ibdev, mad_flags, port_num, in_wc, + in_grh, in_mad, out_mad); + case IB_LINK_LAYER_ETHERNET: + return rdmaoe_process_mad(ibdev, mad_flags, port_num, in_wc, + in_grh, in_mad, out_mad); + default: + return -EINVAL; + } +} + +static void send_handler(struct ib_mad_agent *agent, + struct ib_mad_send_wc *mad_send_wc) +{ + ib_free_send_mad(mad_send_wc->send_buf); +} + +int mlx4_ib_mad_init(struct mlx4_ib_dev *dev) +{ + struct ib_mad_agent *agent; + int p, q; + int ret; + enum rdma_link_layer ll; + + for (p = 0; p < dev->num_ports; ++p) { + ll = rdma_port_get_link_layer(&dev->ib_dev, p + 1); + for (q = 0; q <= 1; ++q) { + if (ll == IB_LINK_LAYER_INFINIBAND) { + agent = ib_register_mad_agent(&dev->ib_dev, p + 1, + q ? IB_QPT_GSI : IB_QPT_SMI, + NULL, 0, send_handler, + NULL, NULL); + if (IS_ERR(agent)) { + ret = PTR_ERR(agent); + goto err; + } + dev->send_agent[p][q] = agent; + } else + dev->send_agent[p][q] = NULL; + } + } + + return 0; + +err: + for (p = 0; p < dev->num_ports; ++p) + for (q = 0; q <= 1; ++q) + if (dev->send_agent[p][q]) + ib_unregister_mad_agent(dev->send_agent[p][q]); + + return ret; +} + +void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev) +{ + struct ib_mad_agent *agent; + int p, q; + + for (p = 0; p < dev->num_ports; ++p) { + for (q = 0; q <= 1; ++q) { + agent = dev->send_agent[p][q]; + if (agent) { + dev->send_agent[p][q] = NULL; + ib_unregister_mad_agent(agent); + } + } + + if (dev->sm_ah[p]) + ib_destroy_ah(dev->sm_ah[p]); + } +} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/main.c b/sys/ofed/drivers/infiniband/hw/mlx4/main.c new file mode 100644 index 000000000000..bc99414ce3ba --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mlx4/main.c @@ -0,0 +1,1580 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "mlx4_ib.h" +#include "user.h" +#include "wc.h" + +#define DRV_NAME MLX4_IB_DRV_NAME +#define DRV_VERSION "1.0-ofed1.5.2" +#define DRV_RELDATE "August 4, 2010" + +MODULE_AUTHOR("Roland Dreier"); +MODULE_DESCRIPTION("Mellanox ConnectX HCA InfiniBand driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRV_VERSION); + +#ifdef CONFIG_MLX4_DEBUG + +int mlx4_ib_debug_level = 0; +module_param_named(debug_level, mlx4_ib_debug_level, int, 0644); +MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); + +#endif /* CONFIG_MLX4_DEBUG */ + +static const char mlx4_ib_version[] = + DRV_NAME ": Mellanox ConnectX InfiniBand driver v" + DRV_VERSION " (" DRV_RELDATE ")\n"; + +static void *get_ibdev(struct mlx4_dev *dev, void *ctx, u8 port) +{ + struct mlx4_ib_dev *mlxibdev = ctx; + return &mlxibdev->ib_dev; +} + +struct update_gid_work { + struct work_struct work; + union ib_gid gids[128]; + int port; + struct mlx4_ib_dev *dev; +}; + +static struct workqueue_struct *wq; + +static void init_query_mad(struct ib_smp *mad) +{ + mad->base_version = 1; + mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; + mad->class_version = 1; + mad->method = IB_MGMT_METHOD_GET; +} + +static union ib_gid zgid; + +static int mlx4_ib_query_device(struct ib_device *ibdev, + struct ib_device_attr *props) +{ + struct mlx4_ib_dev *dev = to_mdev(ibdev); + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; + + err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, 1, NULL, NULL, in_mad, out_mad); + if (err) + goto out; + + memset(props, 0, sizeof *props); + + props->fw_ver = dev->dev->caps.fw_ver; + props->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT | + IB_DEVICE_PORT_ACTIVE_EVENT | + IB_DEVICE_SYS_IMAGE_GUID | + IB_DEVICE_RC_RNR_NAK_GEN | + IB_DEVICE_BLOCK_MULTICAST_LOOPBACK; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_BAD_PKEY_CNTR) + props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_BAD_QKEY_CNTR) + props->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_APM) + props->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UD_AV_PORT) + props->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) + props->device_cap_flags |= IB_DEVICE_UD_IP_CSUM; + if (dev->dev->caps.max_gso_sz && dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_BLH) + props->device_cap_flags |= IB_DEVICE_UD_TSO; + if (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_RESERVED_LKEY) + props->device_cap_flags |= IB_DEVICE_LOCAL_DMA_LKEY; + if ((dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_LOCAL_INV) && + (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_REMOTE_INV) && + (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_FAST_REG_WR)) + props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) + props->device_cap_flags |= IB_DEVICE_XRC; + if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_RAW_ETY) + props->max_raw_ethy_qp = dev->ib_dev.phys_port_cnt; + + props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) & + 0xffffff; + props->vendor_part_id = be16_to_cpup((__be16 *) (out_mad->data + 30)); + props->hw_ver = be32_to_cpup((__be32 *) (out_mad->data + 32)); + memcpy(&props->sys_image_guid, out_mad->data + 4, 8); + + props->max_mr_size = ~0ull; + props->page_size_cap = dev->dev->caps.page_size_cap; + props->max_qp = dev->dev->caps.num_qps - dev->dev->caps.reserved_qps; + props->max_qp_wr = dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE; + props->max_sge = min(dev->dev->caps.max_sq_sg, + dev->dev->caps.max_rq_sg); + props->max_cq = dev->dev->caps.num_cqs - dev->dev->caps.reserved_cqs; + props->max_cqe = dev->dev->caps.max_cqes; + props->max_mr = dev->dev->caps.num_mpts - dev->dev->caps.reserved_mrws; + props->max_pd = dev->dev->caps.num_pds - dev->dev->caps.reserved_pds; + props->max_qp_rd_atom = dev->dev->caps.max_qp_dest_rdma; + props->max_qp_init_rd_atom = dev->dev->caps.max_qp_init_rdma; + props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp; + props->max_srq = dev->dev->caps.num_srqs - dev->dev->caps.reserved_srqs; + props->max_srq_wr = dev->dev->caps.max_srq_wqes - 1; + props->max_srq_sge = dev->dev->caps.max_srq_sge; + props->max_fast_reg_page_list_len = MAX_FAST_REG_PAGES; + props->local_ca_ack_delay = dev->dev->caps.local_ca_ack_delay; + props->atomic_cap = dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_ATOMIC ? + IB_ATOMIC_HCA : IB_ATOMIC_NONE; + props->masked_atomic_cap = IB_ATOMIC_HCA; + props->max_pkeys = dev->dev->caps.pkey_table_len[1]; + props->max_mcast_grp = dev->dev->caps.num_mgms + dev->dev->caps.num_amgms; + props->max_mcast_qp_attach = dev->dev->caps.num_qp_per_mgm; + props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * + props->max_mcast_grp; + props->max_map_per_fmr = (1 << (32 - ilog2(dev->dev->caps.num_mpts))) - 1; + +out: + kfree(in_mad); + kfree(out_mad); + + return err; +} + +static enum rdma_link_layer +mlx4_ib_port_link_layer(struct ib_device *device, u8 port_num) +{ + struct mlx4_dev *dev = to_mdev(device)->dev; + + return dev->caps.port_mask[port_num] == MLX4_PORT_TYPE_IB ? + IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET; +} + +static void ib_link_query_port(struct ib_device *ibdev, u8 port, + struct ib_port_attr *props, + struct ib_smp *out_mad) +{ + props->lid = be16_to_cpup((__be16 *) (out_mad->data + 16)); + props->lmc = out_mad->data[34] & 0x7; + props->sm_lid = be16_to_cpup((__be16 *) (out_mad->data + 18)); + props->sm_sl = out_mad->data[36] & 0xf; + props->state = out_mad->data[32] & 0xf; + props->phys_state = out_mad->data[33] >> 4; + props->port_cap_flags = be32_to_cpup((__be32 *) (out_mad->data + 20)); + props->gid_tbl_len = to_mdev(ibdev)->dev->caps.gid_table_len[port]; + props->max_msg_sz = to_mdev(ibdev)->dev->caps.max_msg_sz; + props->pkey_tbl_len = to_mdev(ibdev)->dev->caps.pkey_table_len[port]; + props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46)); + props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48)); + props->active_width = out_mad->data[31] & 0xf; + props->active_speed = out_mad->data[35] >> 4; + props->max_mtu = out_mad->data[41] & 0xf; + props->active_mtu = out_mad->data[36] >> 4; + props->subnet_timeout = out_mad->data[51] & 0x1f; + props->max_vl_num = out_mad->data[37] >> 4; + props->init_type_reply = out_mad->data[41] >> 4; + props->link_layer = IB_LINK_LAYER_INFINIBAND; +} + +#ifdef notyet +static int eth_to_ib_width(int w) +{ + switch (w) { + case 4: + return IB_WIDTH_4X; + case 8: + case 16: + return IB_WIDTH_8X; + case 32: + return IB_WIDTH_12X; + default: + return IB_WIDTH_1X; + } +} + +static int eth_to_ib_speed(int s) +{ + switch (s) { + case 256: + return 1; + case 512: + return 2; + case 1024: + return 4; + default: + return 1; + } +} +#endif + +static u8 state_to_phys_state(enum ib_port_state state) +{ + return state == IB_PORT_ACTIVE ? 5 : 3; +} + +static int eth_link_query_port(struct ib_device *ibdev, u8 port, + struct ib_port_attr *props, + struct ib_smp *out_mad) +{ + struct mlx4_ib_iboe *iboe = &to_mdev(ibdev)->iboe; + struct net_device *ndev; + enum ib_mtu tmp; + + props->active_width = IB_WIDTH_4X; + props->active_speed = 1; + props->port_cap_flags = IB_PORT_CM_SUP; + props->gid_tbl_len = to_mdev(ibdev)->dev->caps.gid_table_len[port]; + props->max_msg_sz = to_mdev(ibdev)->dev->caps.max_msg_sz; + props->pkey_tbl_len = 1; + props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46)); + props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48)); + props->max_mtu = IB_MTU_2048; + props->subnet_timeout = 0; + props->max_vl_num = out_mad->data[37] >> 4; + props->init_type_reply = 0; + props->link_layer = IB_LINK_LAYER_ETHERNET; + props->state = IB_PORT_DOWN; + props->phys_state = state_to_phys_state(props->state); + props->active_mtu = IB_MTU_256; + spin_lock(&iboe->lock); + ndev = iboe->netdevs[port - 1]; + if (!ndev) + goto out; + +#ifdef __linux__ + tmp = iboe_get_mtu(ndev->mtu); +#else + tmp = iboe_get_mtu(ndev->if_mtu); +#endif + props->active_mtu = tmp ? min(props->max_mtu, tmp) : IB_MTU_256; + props->state = netif_carrier_ok(ndev) && netif_oper_up(ndev) ? + IB_PORT_ACTIVE : IB_PORT_DOWN; + props->phys_state = state_to_phys_state(props->state); + +out: + spin_unlock(&iboe->lock); + return 0; +} + +static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port, + struct ib_port_attr *props) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + memset(props, 0, sizeof *props); + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; + in_mad->attr_mod = cpu_to_be32(port); + + err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad); + if (err) + goto out; + + mlx4_ib_port_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND ? + ib_link_query_port(ibdev, port, props, out_mad) : + eth_link_query_port(ibdev, port, props, out_mad); + +out: + kfree(in_mad); + kfree(out_mad); + + return err; +} + +static int __mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index, + union ib_gid *gid) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; + in_mad->attr_mod = cpu_to_be32(port); + + err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad); + if (err) + goto out; + + memcpy(gid->raw, out_mad->data + 8, 8); + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_GUID_INFO; + in_mad->attr_mod = cpu_to_be32(index / 8); + + err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad); + if (err) + goto out; + + memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8); + +out: + kfree(in_mad); + kfree(out_mad); + return err; +} + +static int iboe_query_gid(struct ib_device *ibdev, u8 port, int index, + union ib_gid *gid) +{ + struct mlx4_ib_dev *dev = to_mdev(ibdev); + + *gid = dev->iboe.gid_table[port - 1][index]; + + return 0; +} + +static int mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index, + union ib_gid *gid) +{ + if (rdma_port_get_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND) + return __mlx4_ib_query_gid(ibdev, port, index, gid); + else + return iboe_query_gid(ibdev, port, index, gid); +} + +static int mlx4_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index, + u16 *pkey) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE; + in_mad->attr_mod = cpu_to_be32(index / 32); + + err = mlx4_MAD_IFC(to_mdev(ibdev), 1, 1, port, NULL, NULL, in_mad, out_mad); + if (err) + goto out; + + *pkey = be16_to_cpu(((__be16 *) out_mad->data)[index % 32]); + +out: + kfree(in_mad); + kfree(out_mad); + return err; +} + +static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask, + struct ib_device_modify *props) +{ + struct mlx4_cmd_mailbox *mailbox; + int err; + + if (mask & ~IB_DEVICE_MODIFY_NODE_DESC) + return -EOPNOTSUPP; + + if (!(mask & IB_DEVICE_MODIFY_NODE_DESC)) + return 0; + + spin_lock(&to_mdev(ibdev)->sm_lock); + memcpy(ibdev->node_desc, props->node_desc, 64); + spin_unlock(&to_mdev(ibdev)->sm_lock); + + /* if possible, pass node desc to FW, so it can generate + * a 144 trap. If cmd fails, just ignore. + */ + mailbox = mlx4_alloc_cmd_mailbox(to_mdev(ibdev)->dev); + if (IS_ERR(mailbox)) + return 0; + + memset(mailbox->buf, 0, 256); + memcpy(mailbox->buf, props->node_desc, 64); + err = mlx4_cmd(to_mdev(ibdev)->dev, mailbox->dma, 1, 0, + MLX4_CMD_SET_NODE, MLX4_CMD_TIME_CLASS_A); + if (err) + mlx4_ib_dbg("SET_NODE command failed (%d)", err); + + mlx4_free_cmd_mailbox(to_mdev(ibdev)->dev, mailbox); + + return 0; +} + +static int mlx4_SET_PORT(struct mlx4_ib_dev *dev, u8 port, int reset_qkey_viols, + u32 cap_mask) +{ + struct mlx4_cmd_mailbox *mailbox; + int err; + u8 is_eth = dev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH; + + mailbox = mlx4_alloc_cmd_mailbox(dev->dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + memset(mailbox->buf, 0, 256); + + if (dev->dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { + *(u8 *) mailbox->buf = !!reset_qkey_viols << 6; + ((__be32 *) mailbox->buf)[2] = cpu_to_be32(cap_mask); + } else { + ((u8 *) mailbox->buf)[3] = !!reset_qkey_viols; + ((__be32 *) mailbox->buf)[1] = cpu_to_be32(cap_mask); + } + + err = mlx4_cmd(dev->dev, mailbox->dma, port, is_eth, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B); + + mlx4_free_cmd_mailbox(dev->dev, mailbox); + return err; +} + +static int mlx4_ib_modify_port(struct ib_device *ibdev, u8 port, int mask, + struct ib_port_modify *props) +{ + struct ib_port_attr attr; + u32 cap_mask; + int err; + + mutex_lock(&to_mdev(ibdev)->cap_mask_mutex); + + err = mlx4_ib_query_port(ibdev, port, &attr); + if (err) + goto out; + + cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) & + ~props->clr_port_cap_mask; + + err = mlx4_SET_PORT(to_mdev(ibdev), port, + !!(mask & IB_PORT_RESET_QKEY_CNTR), + cap_mask); + +out: + mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex); + return err; +} + +static struct ib_ucontext *mlx4_ib_alloc_ucontext(struct ib_device *ibdev, + struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(ibdev); + struct mlx4_ib_ucontext *context; + struct mlx4_ib_alloc_ucontext_resp resp; + int err; + + if (!dev->ib_active) + return ERR_PTR(-EAGAIN); + + resp.qp_tab_size = dev->dev->caps.num_qps; + + if (mlx4_wc_enabled()) { + resp.bf_reg_size = dev->dev->caps.bf_reg_size; + resp.bf_regs_per_page = dev->dev->caps.bf_regs_per_page; + } else { + resp.bf_reg_size = 0; + resp.bf_regs_per_page = 0; + } + + context = kzalloc(sizeof *context, GFP_KERNEL); + if (!context) + return ERR_PTR(-ENOMEM); + + err = mlx4_uar_alloc(to_mdev(ibdev)->dev, &context->uar); + if (err) { + kfree(context); + return ERR_PTR(err); + } + + INIT_LIST_HEAD(&context->db_page_list); + mutex_init(&context->db_page_mutex); + + err = ib_copy_to_udata(udata, &resp, sizeof resp); + if (err) { + mlx4_uar_free(to_mdev(ibdev)->dev, &context->uar); + kfree(context); + return ERR_PTR(-EFAULT); + } + + return &context->ibucontext; +} + +static int mlx4_ib_dealloc_ucontext(struct ib_ucontext *ibcontext) +{ + struct mlx4_ib_ucontext *context = to_mucontext(ibcontext); + + mlx4_uar_free(to_mdev(ibcontext->device)->dev, &context->uar); + kfree(context); + + return 0; +} + +static int mlx4_ib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) +{ + struct mlx4_ib_dev *dev = to_mdev(context->device); + + if (vma->vm_end - vma->vm_start != PAGE_SIZE) + return -EINVAL; + + if (vma->vm_pgoff == 0) { + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (io_remap_pfn_range(vma, vma->vm_start, + to_mucontext(context)->uar.pfn, + PAGE_SIZE, vma->vm_page_prot)) + return -EAGAIN; + } else if (vma->vm_pgoff == 1 && dev->dev->caps.bf_reg_size != 0) { + vma->vm_page_prot = pgprot_wc(vma->vm_page_prot); + + if (io_remap_pfn_range(vma, vma->vm_start, + to_mucontext(context)->uar.pfn + + dev->dev->caps.num_uars, + PAGE_SIZE, vma->vm_page_prot)) + return -EAGAIN; + } else + return -EINVAL; + + return 0; +} + +static struct ib_pd *mlx4_ib_alloc_pd(struct ib_device *ibdev, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct mlx4_ib_pd *pd; + int err; + + pd = kzalloc(sizeof *pd, GFP_KERNEL); + if (!pd) + return ERR_PTR(-ENOMEM); + + err = mlx4_pd_alloc(to_mdev(ibdev)->dev, &pd->pdn); + if (err) { + kfree(pd); + return ERR_PTR(err); + } + + if (context) + if (ib_copy_to_udata(udata, &pd->pdn, sizeof (__u32))) { + mlx4_pd_free(to_mdev(ibdev)->dev, pd->pdn); + kfree(pd); + return ERR_PTR(-EFAULT); + } + + return &pd->ibpd; +} + +static int mlx4_ib_dealloc_pd(struct ib_pd *pd) +{ + mlx4_pd_free(to_mdev(pd->device)->dev, to_mpd(pd)->pdn); + kfree(pd); + + return 0; +} + +static int add_gid_entry(struct ib_qp *ibqp, union ib_gid *gid) +{ + struct mlx4_ib_qp *mqp = to_mqp(ibqp); + struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); + struct gid_entry *ge; + + ge = kzalloc(sizeof *ge, GFP_KERNEL); + if (!ge) + return -ENOMEM; + + ge->gid = *gid; + if (mlx4_ib_add_mc(mdev, mqp, gid)) { + ge->port = mqp->port; + ge->added = 1; + } + + mutex_lock(&mqp->mutex); + list_add_tail(&ge->list, &mqp->gid_list); + mutex_unlock(&mqp->mutex); + + return 0; +} + +int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp, + union ib_gid *gid) +{ + u8 mac[6]; + struct net_device *ndev; + int ret = 0; + + if (!mqp->port) + return 0; + spin_lock(&mdev->iboe.lock); + ndev = mdev->iboe.netdevs[mqp->port - 1]; + if (ndev) + dev_hold(ndev); + spin_unlock(&mdev->iboe.lock); + if (ndev) { + rdma_get_mcast_mac((struct in6_addr *)gid, mac); + rtnl_lock(); + dev_mc_add(mdev->iboe.netdevs[mqp->port - 1], mac, 6, 0); + ret = 1; + rtnl_unlock(); + dev_put(ndev); + } + + return ret; +} + +static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) +{ + int err; + struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); + struct mlx4_ib_qp *mqp = to_mqp(ibqp); + + err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, !!(mqp->flags & + MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK), + (ibqp->qp_type == IB_QPT_RAW_ETH) ? + MLX4_MCAST_PROT_EN : MLX4_MCAST_PROT_IB); + if (err) + return err; + + err = add_gid_entry(ibqp, gid); + if (err) + goto err_add; + + return 0; + +err_add: + mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, + (ibqp->qp_type == IB_QPT_RAW_ETH) ? + MLX4_MCAST_PROT_EN : MLX4_MCAST_PROT_IB); + return err; +} + +static struct gid_entry *find_gid_entry(struct mlx4_ib_qp *qp, u8 *raw) +{ + struct gid_entry *ge; + struct gid_entry *tmp; + struct gid_entry *ret = NULL; + + list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) { + if (!memcmp(raw, ge->gid.raw, 16)) { + ret = ge; + break; + } + } + + return ret; +} + +static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) +{ + int err; + struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); + struct mlx4_ib_qp *mqp = to_mqp(ibqp); + u8 mac[6]; + struct net_device *ndev; + struct gid_entry *ge; + + err = mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, + (ibqp->qp_type == IB_QPT_RAW_ETH) ? + MLX4_MCAST_PROT_EN : MLX4_MCAST_PROT_IB); + if (err) + return err; + + mutex_lock(&mqp->mutex); + ge = find_gid_entry(mqp, gid->raw); + if (ge) { + spin_lock(&mdev->iboe.lock); + ndev = ge->added ? mdev->iboe.netdevs[ge->port - 1] : NULL; + if (ndev) + dev_hold(ndev); + spin_unlock(&mdev->iboe.lock); + rdma_get_mcast_mac((struct in6_addr *)gid, mac); + if (ndev) { + rtnl_lock(); + dev_mc_delete(mdev->iboe.netdevs[ge->port - 1], mac, 6, 0); + rtnl_unlock(); + dev_put(ndev); + } + list_del(&ge->list); + kfree(ge); + } else + printk(KERN_WARNING "could not find mgid entry\n"); + + mutex_unlock(&mqp->mutex); + + return 0; +} + +static void mlx4_dummy_comp_handler(struct ib_cq *cq, void *cq_context) +{ +} + +static struct ib_xrcd *mlx4_ib_alloc_xrcd(struct ib_device *ibdev, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct mlx4_ib_xrcd *xrcd; + struct mlx4_ib_dev *mdev = to_mdev(ibdev); + struct ib_pd *pd; + struct ib_cq *cq; + int err; + + if (!(mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC)) + return ERR_PTR(-ENOSYS); + + xrcd = kmalloc(sizeof *xrcd, GFP_KERNEL); + if (!xrcd) + return ERR_PTR(-ENOMEM); + + err = mlx4_xrcd_alloc(mdev->dev, &xrcd->xrcdn); + if (err) + goto err_xrcd; + + pd = mlx4_ib_alloc_pd(ibdev, NULL, NULL); + if (IS_ERR(pd)) { + err = PTR_ERR(pd); + goto err_pd; + } + pd->device = ibdev; + + cq = mlx4_ib_create_cq(ibdev, 1, 0, NULL, NULL); + if (IS_ERR(cq)) { + err = PTR_ERR(cq); + goto err_cq; + } + cq->device = ibdev; + cq->comp_handler = mlx4_dummy_comp_handler; + + if (context) + if (ib_copy_to_udata(udata, &xrcd->xrcdn, sizeof(__u32))) { + err = -EFAULT; + goto err_copy; + } + + xrcd->cq = cq; + xrcd->pd = pd; + return &xrcd->ibxrcd; + +err_copy: + mlx4_ib_destroy_cq(cq); +err_cq: + mlx4_ib_dealloc_pd(pd); +err_pd: + mlx4_xrcd_free(mdev->dev, xrcd->xrcdn); +err_xrcd: + kfree(xrcd); + return ERR_PTR(err); +} + +static int mlx4_ib_dealloc_xrcd(struct ib_xrcd *xrcd) +{ + struct mlx4_ib_xrcd *mxrcd = to_mxrcd(xrcd); + + mlx4_ib_destroy_cq(mxrcd->cq); + mlx4_ib_dealloc_pd(mxrcd->pd); + mlx4_xrcd_free(to_mdev(xrcd->device)->dev, to_mxrcd(xrcd)->xrcdn); + kfree(xrcd); + + return 0; +} + + +static int init_node_data(struct mlx4_ib_dev *dev) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_NODE_DESC; + + err = mlx4_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad); + if (err) + goto out; + + memcpy(dev->ib_dev.node_desc, out_mad->data, 64); + + in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; + + err = mlx4_MAD_IFC(dev, 1, 1, 1, NULL, NULL, in_mad, out_mad); + if (err) + goto out; + + dev->dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32)); + memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8); + +out: + kfree(in_mad); + kfree(out_mad); + return err; +} + +static ssize_t show_hca(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct mlx4_ib_dev *dev = + container_of(device, struct mlx4_ib_dev, ib_dev.dev); + return sprintf(buf, "MT%d\n", dev->dev->pdev->device); +} + +static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct mlx4_ib_dev *dev = + container_of(device, struct mlx4_ib_dev, ib_dev.dev); + return sprintf(buf, "%d.%d.%d\n", (int) (dev->dev->caps.fw_ver >> 32), + (int) (dev->dev->caps.fw_ver >> 16) & 0xffff, + (int) dev->dev->caps.fw_ver & 0xffff); +} + +static ssize_t show_rev(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct mlx4_ib_dev *dev = + container_of(device, struct mlx4_ib_dev, ib_dev.dev); + return sprintf(buf, "%x\n", dev->dev->rev_id); +} + +static ssize_t show_board(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct mlx4_ib_dev *dev = + container_of(device, struct mlx4_ib_dev, ib_dev.dev); + return sprintf(buf, "%.*s\n", MLX4_BOARD_ID_LEN, + dev->dev->board_id); +} + +static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); +static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL); +static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); +static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); + +static struct device_attribute *mlx4_class_attributes[] = { + &dev_attr_hw_rev, + &dev_attr_fw_ver, + &dev_attr_hca_type, + &dev_attr_board_id +}; + +/* + * create show function and a device_attribute struct pointing to + * the function for _name + */ +#define DEVICE_DIAG_RPRT_ATTR(_name, _offset, _op_mod) \ +static ssize_t show_rprt_##_name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf){ \ + return show_diag_rprt(dev, buf, _offset, _op_mod); \ +} \ +static DEVICE_ATTR(_name, S_IRUGO, show_rprt_##_name, NULL); + +#define MLX4_DIAG_RPRT_CLEAR_DIAGS 3 + +static size_t show_diag_rprt(struct device *device, char *buf, + u32 offset, u8 op_modifier) +{ + size_t ret; + u32 counter_offset = offset; + u32 diag_counter = 0; + struct mlx4_ib_dev *dev = container_of(device, struct mlx4_ib_dev, + ib_dev.dev); + + ret = mlx4_query_diag_counters(dev->dev, 1, op_modifier, + &counter_offset, &diag_counter); + if (ret) + return ret; + + return sprintf(buf,"%d\n", diag_counter); +} + +static ssize_t clear_diag_counters(struct device *device, + struct device_attribute *attr, + const char *buf, size_t length) +{ + size_t ret; + struct mlx4_ib_dev *dev = container_of(device, struct mlx4_ib_dev, + ib_dev.dev); + + ret = mlx4_query_diag_counters(dev->dev, 0, MLX4_DIAG_RPRT_CLEAR_DIAGS, + NULL, NULL); + if (ret) + return ret; + + return length; +} + +DEVICE_DIAG_RPRT_ATTR(rq_num_lle , 0x00, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_lle , 0x04, 2); +DEVICE_DIAG_RPRT_ATTR(rq_num_lqpoe , 0x08, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_lqpoe , 0x0C, 2); +DEVICE_DIAG_RPRT_ATTR(rq_num_leeoe , 0x10, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_leeoe , 0x14, 2); +DEVICE_DIAG_RPRT_ATTR(rq_num_lpe , 0x18, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_lpe , 0x1C, 2); +DEVICE_DIAG_RPRT_ATTR(rq_num_wrfe , 0x20, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_wrfe , 0x24, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_mwbe , 0x2C, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_bre , 0x34, 2); +DEVICE_DIAG_RPRT_ATTR(rq_num_lae , 0x38, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_rire , 0x44, 2); +DEVICE_DIAG_RPRT_ATTR(rq_num_rire , 0x48, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_rae , 0x4C, 2); +DEVICE_DIAG_RPRT_ATTR(rq_num_rae , 0x50, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_roe , 0x54, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_tree , 0x5C, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_rree , 0x64, 2); +DEVICE_DIAG_RPRT_ATTR(rq_num_rnr , 0x68, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_rnr , 0x6C, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_rabrte , 0x7C, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_ieecne , 0x84, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_ieecse , 0x8C, 2); +DEVICE_DIAG_RPRT_ATTR(rq_num_oos , 0x100, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_oos , 0x104, 2); +DEVICE_DIAG_RPRT_ATTR(rq_num_mce , 0x108, 2); +DEVICE_DIAG_RPRT_ATTR(rq_num_rsync , 0x110, 2); +DEVICE_DIAG_RPRT_ATTR(sq_num_rsync , 0x114, 2); +DEVICE_DIAG_RPRT_ATTR(rq_num_udsdprd , 0x118, 2); +DEVICE_DIAG_RPRT_ATTR(rq_num_ucsdprd , 0x120, 2); +DEVICE_DIAG_RPRT_ATTR(num_cqovf , 0x1A0, 2); +DEVICE_DIAG_RPRT_ATTR(num_eqovf , 0x1A4, 2); +DEVICE_DIAG_RPRT_ATTR(num_baddb , 0x1A8, 2); + +static DEVICE_ATTR(clear_diag, S_IWUGO, NULL, clear_diag_counters); + +static struct attribute *diag_rprt_attrs[] = { + &dev_attr_rq_num_lle.attr, + &dev_attr_sq_num_lle.attr, + &dev_attr_rq_num_lqpoe.attr, + &dev_attr_sq_num_lqpoe.attr, + &dev_attr_rq_num_leeoe.attr, + &dev_attr_sq_num_leeoe.attr, + &dev_attr_rq_num_lpe.attr, + &dev_attr_sq_num_lpe.attr, + &dev_attr_rq_num_wrfe.attr, + &dev_attr_sq_num_wrfe.attr, + &dev_attr_sq_num_mwbe.attr, + &dev_attr_sq_num_bre.attr, + &dev_attr_rq_num_lae.attr, + &dev_attr_sq_num_rire.attr, + &dev_attr_rq_num_rire.attr, + &dev_attr_sq_num_rae.attr, + &dev_attr_rq_num_rae.attr, + &dev_attr_sq_num_roe.attr, + &dev_attr_sq_num_tree.attr, + &dev_attr_sq_num_rree.attr, + &dev_attr_rq_num_rnr.attr, + &dev_attr_sq_num_rnr.attr, + &dev_attr_sq_num_rabrte.attr, + &dev_attr_sq_num_ieecne.attr, + &dev_attr_sq_num_ieecse.attr, + &dev_attr_rq_num_oos.attr, + &dev_attr_sq_num_oos.attr, + &dev_attr_rq_num_mce.attr, + &dev_attr_rq_num_rsync.attr, + &dev_attr_sq_num_rsync.attr, + &dev_attr_rq_num_udsdprd.attr, + &dev_attr_rq_num_ucsdprd.attr, + &dev_attr_num_cqovf.attr, + &dev_attr_num_eqovf.attr, + &dev_attr_num_baddb.attr, + &dev_attr_clear_diag.attr, + NULL +}; + +struct attribute_group diag_counters_group = { + .name = "diag_counters", + .attrs = diag_rprt_attrs +}; + +static void mlx4_addrconf_ifid_eui48(u8 *eui, u16 vlan_id, struct net_device *dev) +{ +#ifdef __linux__ + memcpy(eui, dev->dev_addr, 3); + memcpy(eui + 5, dev->dev_addr + 3, 3); +#else + memcpy(eui, IF_LLADDR(dev), 3); + memcpy(eui + 5, IF_LLADDR(dev) + 3, 3); +#endif + if (vlan_id < 0x1000) { + eui[3] = vlan_id >> 8; + eui[4] = vlan_id & 0xff; + } else { + eui[3] = 0xff; + eui[4] = 0xfe; + } + eui[0] ^= 2; +} + +static void update_gids_task(struct work_struct *work) +{ + struct update_gid_work *gw = container_of(work, struct update_gid_work, work); + struct mlx4_cmd_mailbox *mailbox; + union ib_gid *gids; + int err; + struct mlx4_dev *dev = gw->dev->dev; + struct ib_event event; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + printk(KERN_WARNING "update gid table failed %ld\n", PTR_ERR(mailbox)); + return; + } + + gids = mailbox->buf; + memcpy(gids, gw->gids, sizeof gw->gids); + + err = mlx4_cmd(dev, mailbox->dma, MLX4_SET_PORT_GID_TABLE << 8 | gw->port, + 1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B); + if (err) + printk(KERN_WARNING "set port command failed\n"); + else { + memcpy(gw->dev->iboe.gid_table[gw->port - 1], gw->gids, sizeof gw->gids); + event.device = &gw->dev->ib_dev; + event.element.port_num = gw->port; + event.event = IB_EVENT_GID_CHANGE; + ib_dispatch_event(&event); + } + + mlx4_free_cmd_mailbox(dev, mailbox); + kfree(gw); +} + +enum { + MLX4_MAX_EFF_VLANS = 128 - MLX4_VLAN_REGULAR, +}; + +static int update_ipv6_gids(struct mlx4_ib_dev *dev, int port, int clear) +{ + struct net_device *ndev = dev->iboe.netdevs[port - 1]; + struct update_gid_work *work; + struct net_device *tmp; + int i; + u8 *hits; + int ret; + union ib_gid gid; + int tofree; + int found; + int need_update = 0; + u16 vid; + + work = kzalloc(sizeof *work, GFP_ATOMIC); + if (!work) + return -ENOMEM; + + hits = kzalloc(MLX4_MAX_EFF_VLANS + 1, GFP_ATOMIC); + if (!hits) { + ret = -ENOMEM; + goto out; + } + +#ifdef __linux__ + read_lock(&dev_base_lock); + for_each_netdev(&init_net, tmp) { +#else + IFNET_RLOCK(); + TAILQ_FOREACH(tmp, &V_ifnet, if_link) { +#endif + if (ndev && (tmp == ndev || rdma_vlan_dev_real_dev(tmp) == ndev)) { + gid.global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL); + vid = rdma_vlan_dev_vlan_id(tmp); + mlx4_addrconf_ifid_eui48(&gid.raw[8], vid, ndev); + found = 0; + tofree = -1; + for (i = 0; i < MLX4_MAX_EFF_VLANS + 1; ++i) { + if (tofree < 0 && + !memcmp(&dev->iboe.gid_table[port - 1][i], &zgid, sizeof zgid)) + tofree = i; + if (!memcmp(&dev->iboe.gid_table[port - 1][i], &gid, sizeof gid)) { + hits[i] = 1; + found = 1; + break; + } + } + + if (!found) { + if (tmp == ndev && (memcmp(&dev->iboe.gid_table[port - 1][0], &gid, sizeof gid) || !memcmp(&dev->iboe.gid_table[port - 1][0], &zgid, sizeof gid))) { + dev->iboe.gid_table[port - 1][0] = gid; + ++need_update; + hits[0] = 1; + } else if (tofree >= 0) { + dev->iboe.gid_table[port - 1][tofree] = gid; + hits[tofree] = 1; + ++need_update; + } + } + } +#ifdef __linux__ + } + read_unlock(&dev_base_lock); +#else + } + IFNET_RUNLOCK(); +#endif + + for (i = 0; i < MLX4_MAX_EFF_VLANS + 1; ++i) + if (!hits[i]) { + if (memcmp(&dev->iboe.gid_table[port - 1][i], &zgid, sizeof zgid)) + ++need_update; + dev->iboe.gid_table[port - 1][i] = zgid; + } + + + if (need_update) { + memcpy(work->gids, dev->iboe.gid_table[port - 1], sizeof work->gids); + INIT_WORK(&work->work, update_gids_task); + work->port = port; + work->dev = dev; + queue_work(wq, &work->work); + } else + kfree(work); + + kfree(hits); + return 0; + +out: + kfree(work); + return ret; +} + +static void handle_en_event(struct mlx4_ib_dev *dev, int port, unsigned long event) +{ + switch (event) { + case NETDEV_UP: +#ifdef __linux__ + case NETDEV_CHANGEADDR: +#endif + update_ipv6_gids(dev, port, 0); + break; + + case NETDEV_DOWN: + update_ipv6_gids(dev, port, 1); + dev->iboe.netdevs[port - 1] = NULL; + } +} + +static void netdev_added(struct mlx4_ib_dev *dev, int port) +{ + update_ipv6_gids(dev, port, 0); +} + +static void netdev_removed(struct mlx4_ib_dev *dev, int port) +{ + update_ipv6_gids(dev, port, 1); +} + +static int mlx4_ib_netdev_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct net_device *dev = ptr; + struct mlx4_ib_dev *ibdev; + struct net_device *oldnd; + struct mlx4_ib_iboe *iboe; + int port; + +#ifdef __linux__ + if (!net_eq(dev_net(dev), &init_net)) + return NOTIFY_DONE; +#endif + + ibdev = container_of(this, struct mlx4_ib_dev, iboe.nb); + iboe = &ibdev->iboe; + + spin_lock(&iboe->lock); + mlx4_foreach_ib_transport_port(port, ibdev->dev) { + oldnd = iboe->netdevs[port - 1]; + iboe->netdevs[port - 1] = mlx4_get_prot_dev(ibdev->dev, MLX4_PROT_EN, port); + if (oldnd != iboe->netdevs[port - 1]) { + if (iboe->netdevs[port - 1]) + netdev_added(ibdev, port); + else + netdev_removed(ibdev, port); + } + } + + if (dev == iboe->netdevs[0] || + (iboe->netdevs[0] && rdma_vlan_dev_real_dev(dev) == iboe->netdevs[0])) + handle_en_event(ibdev, 1, event); + else if (dev == iboe->netdevs[1] + || (iboe->netdevs[1] && rdma_vlan_dev_real_dev(dev) == iboe->netdevs[1])) + handle_en_event(ibdev, 2, event); + + spin_unlock(&iboe->lock); + + return NOTIFY_DONE; +} + +static void *mlx4_ib_add(struct mlx4_dev *dev) +{ + static int mlx4_ib_version_printed; + struct mlx4_ib_dev *ibdev; + int num_ports = 0; + int i; + int err; + struct mlx4_ib_iboe *iboe; + int k; + + if (!mlx4_ib_version_printed) { + printk(KERN_INFO "%s", mlx4_ib_version); + ++mlx4_ib_version_printed; + } + + mlx4_foreach_ib_transport_port(i, dev) + num_ports++; + + /* No point in registering a device with no ports... */ + if (num_ports == 0) + return NULL; + + ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev); + if (!ibdev) { + dev_err(&dev->pdev->dev, "Device struct alloc failed\n"); + return NULL; + } + + iboe = &ibdev->iboe; + + if (mlx4_pd_alloc(dev, &ibdev->priv_pdn)) + goto err_dealloc; + + if (mlx4_uar_alloc(dev, &ibdev->priv_uar)) + goto err_pd; + + ibdev->priv_uar.map = ioremap(ibdev->priv_uar.pfn << PAGE_SHIFT, PAGE_SIZE); + if (!ibdev->priv_uar.map) + goto err_uar; + MLX4_INIT_DOORBELL_LOCK(&ibdev->uar_lock); + + ibdev->dev = dev; + + strlcpy(ibdev->ib_dev.name, "mlx4_%d", IB_DEVICE_NAME_MAX); + ibdev->ib_dev.owner = THIS_MODULE; + ibdev->ib_dev.node_type = RDMA_NODE_IB_CA; + ibdev->ib_dev.local_dma_lkey = dev->caps.reserved_lkey; + ibdev->num_ports = num_ports; + ibdev->ib_dev.phys_port_cnt = ibdev->num_ports; + ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors; + ibdev->ib_dev.dma_device = &dev->pdev->dev; + + ibdev->ib_dev.uverbs_abi_ver = MLX4_IB_UVERBS_ABI_VERSION; + ibdev->ib_dev.uverbs_cmd_mask = + (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | + (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | + (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | + (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_REG_MR) | + (1ull << IB_USER_VERBS_CMD_DEREG_MR) | + (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | + (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | + (1ull << IB_USER_VERBS_CMD_RESIZE_CQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | + (1ull << IB_USER_VERBS_CMD_CREATE_QP) | + (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | + (1ull << IB_USER_VERBS_CMD_QUERY_QP) | + (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | + (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) | + (1ull << IB_USER_VERBS_CMD_DETACH_MCAST) | + (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) | + (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) | + (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ); + + ibdev->ib_dev.query_device = mlx4_ib_query_device; + ibdev->ib_dev.query_port = mlx4_ib_query_port; + ibdev->ib_dev.get_link_layer = mlx4_ib_port_link_layer; + ibdev->ib_dev.query_gid = mlx4_ib_query_gid; + ibdev->ib_dev.query_pkey = mlx4_ib_query_pkey; + ibdev->ib_dev.modify_device = mlx4_ib_modify_device; + ibdev->ib_dev.modify_port = mlx4_ib_modify_port; + ibdev->ib_dev.alloc_ucontext = mlx4_ib_alloc_ucontext; + ibdev->ib_dev.dealloc_ucontext = mlx4_ib_dealloc_ucontext; + ibdev->ib_dev.mmap = mlx4_ib_mmap; + ibdev->ib_dev.alloc_pd = mlx4_ib_alloc_pd; + ibdev->ib_dev.dealloc_pd = mlx4_ib_dealloc_pd; + ibdev->ib_dev.create_ah = mlx4_ib_create_ah; + ibdev->ib_dev.query_ah = mlx4_ib_query_ah; + ibdev->ib_dev.destroy_ah = mlx4_ib_destroy_ah; + ibdev->ib_dev.create_srq = mlx4_ib_create_srq; + ibdev->ib_dev.modify_srq = mlx4_ib_modify_srq; + ibdev->ib_dev.query_srq = mlx4_ib_query_srq; + ibdev->ib_dev.destroy_srq = mlx4_ib_destroy_srq; + ibdev->ib_dev.post_srq_recv = mlx4_ib_post_srq_recv; + ibdev->ib_dev.create_qp = mlx4_ib_create_qp; + ibdev->ib_dev.modify_qp = mlx4_ib_modify_qp; + ibdev->ib_dev.query_qp = mlx4_ib_query_qp; + ibdev->ib_dev.destroy_qp = mlx4_ib_destroy_qp; + ibdev->ib_dev.post_send = mlx4_ib_post_send; + ibdev->ib_dev.post_recv = mlx4_ib_post_recv; + ibdev->ib_dev.create_cq = mlx4_ib_create_cq; + ibdev->ib_dev.modify_cq = mlx4_ib_modify_cq; + ibdev->ib_dev.resize_cq = mlx4_ib_resize_cq; + ibdev->ib_dev.destroy_cq = mlx4_ib_destroy_cq; + ibdev->ib_dev.poll_cq = mlx4_ib_poll_cq; + ibdev->ib_dev.req_notify_cq = mlx4_ib_arm_cq; + ibdev->ib_dev.get_dma_mr = mlx4_ib_get_dma_mr; + ibdev->ib_dev.reg_user_mr = mlx4_ib_reg_user_mr; + ibdev->ib_dev.dereg_mr = mlx4_ib_dereg_mr; + ibdev->ib_dev.alloc_fast_reg_mr = mlx4_ib_alloc_fast_reg_mr; + ibdev->ib_dev.alloc_fast_reg_page_list = mlx4_ib_alloc_fast_reg_page_list; + ibdev->ib_dev.free_fast_reg_page_list = mlx4_ib_free_fast_reg_page_list; + ibdev->ib_dev.attach_mcast = mlx4_ib_mcg_attach; + ibdev->ib_dev.detach_mcast = mlx4_ib_mcg_detach; + ibdev->ib_dev.process_mad = mlx4_ib_process_mad; + + ibdev->ib_dev.alloc_fmr = mlx4_ib_fmr_alloc; + ibdev->ib_dev.map_phys_fmr = mlx4_ib_map_phys_fmr; + ibdev->ib_dev.unmap_fmr = mlx4_ib_unmap_fmr; + ibdev->ib_dev.dealloc_fmr = mlx4_ib_fmr_dealloc; + if (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) { + ibdev->ib_dev.create_xrc_srq = mlx4_ib_create_xrc_srq; + ibdev->ib_dev.alloc_xrcd = mlx4_ib_alloc_xrcd; + ibdev->ib_dev.dealloc_xrcd = mlx4_ib_dealloc_xrcd; + ibdev->ib_dev.create_xrc_rcv_qp = mlx4_ib_create_xrc_rcv_qp; + ibdev->ib_dev.modify_xrc_rcv_qp = mlx4_ib_modify_xrc_rcv_qp; + ibdev->ib_dev.query_xrc_rcv_qp = mlx4_ib_query_xrc_rcv_qp; + ibdev->ib_dev.reg_xrc_rcv_qp = mlx4_ib_reg_xrc_rcv_qp; + ibdev->ib_dev.unreg_xrc_rcv_qp = mlx4_ib_unreg_xrc_rcv_qp; + ibdev->ib_dev.uverbs_cmd_mask |= + (1ull << IB_USER_VERBS_CMD_CREATE_XRC_SRQ) | + (1ull << IB_USER_VERBS_CMD_OPEN_XRC_DOMAIN) | + (1ull << IB_USER_VERBS_CMD_CLOSE_XRC_DOMAIN) | + (1ull << IB_USER_VERBS_CMD_CREATE_XRC_RCV_QP) | + (1ull << IB_USER_VERBS_CMD_MODIFY_XRC_RCV_QP) | + (1ull << IB_USER_VERBS_CMD_QUERY_XRC_RCV_QP) | + (1ull << IB_USER_VERBS_CMD_REG_XRC_RCV_QP) | + (1ull << IB_USER_VERBS_CMD_UNREG_XRC_RCV_QP); + } + + + spin_lock_init(&iboe->lock); + if (init_node_data(ibdev)) + goto err_map; + + for (k = 0; k < ibdev->num_ports; ++k) { + err = mlx4_counter_alloc(ibdev->dev, &ibdev->counters[k]); + if (err) + ibdev->counters[k] = -1; + else + mlx4_set_iboe_counter(dev, ibdev->counters[k], k + 1); + } + + spin_lock_init(&ibdev->sm_lock); + mutex_init(&ibdev->cap_mask_mutex); + mutex_init(&ibdev->xrc_reg_mutex); + + if (ib_register_device(&ibdev->ib_dev)) + goto err_counter; + + if (mlx4_ib_mad_init(ibdev)) + goto err_reg; + if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE && !iboe->nb.notifier_call) { + iboe->nb.notifier_call = mlx4_ib_netdev_event; + err = register_netdevice_notifier(&iboe->nb); + if (err) + goto err_reg; + } + for (i = 0; i < ARRAY_SIZE(mlx4_class_attributes); ++i) { + if (device_create_file(&ibdev->ib_dev.dev, + mlx4_class_attributes[i])) + goto err_notif; + } + + if(sysfs_create_group(&ibdev->ib_dev.dev.kobj, &diag_counters_group)) + goto err_notif; + + ibdev->ib_active = 1; + + return ibdev; + +err_notif: + if (unregister_netdevice_notifier(&ibdev->iboe.nb)) + printk(KERN_WARNING "failure unregistering notifier\n"); + flush_workqueue(wq); + +err_reg: + ib_unregister_device(&ibdev->ib_dev); + +err_counter: + for (; k; --k) + mlx4_counter_free(ibdev->dev, ibdev->counters[k - 1]); + +err_map: + iounmap(ibdev->priv_uar.map); + +err_uar: + mlx4_uar_free(dev, &ibdev->priv_uar); + +err_pd: + mlx4_pd_free(dev, ibdev->priv_pdn); + +err_dealloc: + ib_dealloc_device(&ibdev->ib_dev); + + return NULL; +} + +static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr) +{ + struct mlx4_ib_dev *ibdev = ibdev_ptr; + int p; + int k; + + sysfs_remove_group(&ibdev->ib_dev.dev.kobj, &diag_counters_group); + + mlx4_ib_mad_cleanup(ibdev); + ib_unregister_device(&ibdev->ib_dev); + for (k = 0; k < ibdev->num_ports; ++k) + mlx4_counter_free(ibdev->dev, ibdev->counters[k]); + + if (ibdev->iboe.nb.notifier_call) { + unregister_netdevice_notifier(&ibdev->iboe.nb); + flush_workqueue(wq); + ibdev->iboe.nb.notifier_call = NULL; + } + iounmap(ibdev->priv_uar.map); + + mlx4_foreach_port(p, dev, MLX4_PORT_TYPE_IB) + mlx4_CLOSE_PORT(dev, p); + + mlx4_uar_free(dev, &ibdev->priv_uar); + mlx4_pd_free(dev, ibdev->priv_pdn); + ib_dealloc_device(&ibdev->ib_dev); +} + +static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, + enum mlx4_dev_event event, int port) +{ + struct ib_event ibev; + struct mlx4_ib_dev *ibdev = to_mdev((struct ib_device *) ibdev_ptr); + + if (port > ibdev->num_ports) + return; + + switch (event) { + case MLX4_DEV_EVENT_PORT_UP: + ibev.event = IB_EVENT_PORT_ACTIVE; + break; + + case MLX4_DEV_EVENT_PORT_DOWN: + ibev.event = IB_EVENT_PORT_ERR; + break; + + case MLX4_DEV_EVENT_CATASTROPHIC_ERROR: + ibdev->ib_active = 0; + ibev.event = IB_EVENT_DEVICE_FATAL; + break; + + default: + return; + } + + ibev.device = ibdev_ptr; + ibev.element.port_num = port; + + ib_dispatch_event(&ibev); +} + +static struct mlx4_interface mlx4_ib_interface = { + .add = mlx4_ib_add, + .remove = mlx4_ib_remove, + .event = mlx4_ib_event, + .get_prot_dev = get_ibdev, + .protocol = MLX4_PROT_IB, +}; + +static int __init mlx4_ib_init(void) +{ + int err; + + wq = create_singlethread_workqueue("mlx4_ib"); + if (!wq) + return -ENOMEM; + + err = mlx4_register_interface(&mlx4_ib_interface); + if (err) { + destroy_workqueue(wq); + return err; + } + + return 0; +} + +static void __exit mlx4_ib_cleanup(void) +{ + mlx4_unregister_interface(&mlx4_ib_interface); + destroy_workqueue(wq); +} + +module_init_order(mlx4_ib_init, SI_ORDER_MIDDLE); +module_exit(mlx4_ib_cleanup); + +#undef MODULE_VERSION +#include +static int +mlx4ib_evhand(module_t mod, int event, void *arg) +{ + return (0); +} +static moduledata_t mlx4ib_mod = { + .name = "mlx4ib", + .evhand = mlx4ib_evhand, +}; +DECLARE_MODULE(mlx4ib, mlx4ib_mod, SI_SUB_SMP, SI_ORDER_ANY); +MODULE_DEPEND(mlx4ib, mlx4, 1, 1, 1); diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/mlx4_ib.h b/sys/ofed/drivers/infiniband/hw/mlx4/mlx4_ib.h new file mode 100644 index 000000000000..b8f6996c278a --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems. All rights reserved. + * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_IB_H +#define MLX4_IB_H + +#include +#include +#include + +#include +#include + +#include +#include + + +#define MLX4_IB_DRV_NAME "mlx4_ib" + +#ifdef CONFIG_MLX4_DEBUG +extern int mlx4_ib_debug_level; + +#define mlx4_ib_dbg(format, arg...) \ + do { \ + if (mlx4_ib_debug_level) \ + printk(KERN_DEBUG "<" MLX4_IB_DRV_NAME "> %s: " format "\n",\ + __func__, ## arg); \ + } while (0) + +#else /* CONFIG_MLX4_DEBUG */ + +#define mlx4_ib_dbg(format, arg...) do {} while (0) + +#endif /* CONFIG_MLX4_DEBUG */ + +enum { + MLX4_IB_SQ_MIN_WQE_SHIFT = 6 +}; + +#define MLX4_IB_SQ_HEADROOM(shift) ((2048 >> (shift)) + 1) +#define MLX4_IB_SQ_MAX_SPARE (MLX4_IB_SQ_HEADROOM(MLX4_IB_SQ_MIN_WQE_SHIFT)) + +struct mlx4_ib_ucontext { + struct ib_ucontext ibucontext; + struct mlx4_uar uar; + struct list_head db_page_list; + struct mutex db_page_mutex; +}; + +struct mlx4_ib_pd { + struct ib_pd ibpd; + u32 pdn; +}; + +struct mlx4_ib_xrcd { + struct ib_xrcd ibxrcd; + u32 xrcdn; + struct ib_pd *pd; + struct ib_cq *cq; +}; + +struct mlx4_ib_cq_buf { + struct mlx4_buf buf; + struct mlx4_mtt mtt; +}; + +struct mlx4_ib_cq_resize { + struct mlx4_ib_cq_buf buf; + int cqe; +}; + +struct mlx4_ib_cq { + struct ib_cq ibcq; + struct mlx4_cq mcq; + struct mlx4_ib_cq_buf buf; + struct mlx4_ib_cq_resize *resize_buf; + struct mlx4_db db; + spinlock_t lock; + struct mutex resize_mutex; + struct ib_umem *umem; + struct ib_umem *resize_umem; +}; + +struct mlx4_ib_mr { + struct ib_mr ibmr; + struct mlx4_mr mmr; + struct ib_umem *umem; +}; + +struct mlx4_ib_fast_reg_page_list { + struct ib_fast_reg_page_list ibfrpl; + __be64 *mapped_page_list; + dma_addr_t map; +}; + +struct mlx4_ib_fmr { + struct ib_fmr ibfmr; + struct mlx4_fmr mfmr; +}; + +struct mlx4_ib_wq { + u64 *wrid; + spinlock_t lock; + int wqe_cnt; + int max_post; + int max_gs; + int offset; + int wqe_shift; + unsigned head; + unsigned tail; +}; + +enum mlx4_ib_qp_flags { + MLX4_IB_QP_LSO = 1 << 0, + MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK = 1 << 1, + MLX4_IB_XRC_RCV = 1 << 2, +}; + +struct gid_entry { + struct list_head list; + union ib_gid gid; + int added; + u8 port; +}; + +struct mlx4_ib_qp { + struct ib_qp ibqp; + struct mlx4_qp mqp; + struct mlx4_buf buf; + + struct mlx4_db db; + struct mlx4_ib_wq rq; + + u32 doorbell_qpn; + __be32 sq_signal_bits; + unsigned sq_next_wqe; + int sq_max_wqes_per_wr; + int sq_spare_wqes; + struct mlx4_ib_wq sq; + + struct ib_umem *umem; + struct mlx4_mtt mtt; + int buf_size; + struct mutex mutex; + u32 flags; + struct list_head xrc_reg_list; + spinlock_t xrc_reg_list_lock; + u16 xrcdn; + u8 port; + u8 alt_port; + u8 atomic_rd_en; + u8 resp_depth; + u8 sq_no_prefetch; + u8 state; + int mlx_type; + struct list_head gid_list; + int max_inline_data; + struct mlx4_bf bf; +}; + +struct mlx4_ib_srq { + struct ib_srq ibsrq; + struct mlx4_srq msrq; + struct mlx4_buf buf; + struct mlx4_db db; + u64 *wrid; + spinlock_t lock; + int head; + int tail; + u16 wqe_ctr; + struct ib_umem *umem; + struct mlx4_mtt mtt; + struct mutex mutex; +}; + +struct mlx4_ib_ah { + struct ib_ah ibah; + union mlx4_ext_av av; +}; + +struct mlx4_ib_iboe { + spinlock_t lock; + struct net_device *netdevs[MLX4_MAX_PORTS]; + struct notifier_block nb; + union ib_gid gid_table[MLX4_MAX_PORTS][128]; +}; + +struct mlx4_ib_dev { + struct ib_device ib_dev; + struct mlx4_dev *dev; + int num_ports; + struct mlx4_uar priv_uar; + u32 priv_pdn; + MLX4_DECLARE_DOORBELL_LOCK(uar_lock); + + struct ib_mad_agent *send_agent[MLX4_MAX_PORTS][2]; + struct ib_ah *sm_ah[MLX4_MAX_PORTS]; + spinlock_t sm_lock; + + struct mutex cap_mask_mutex; + struct mutex xrc_reg_mutex; + int ib_active; + struct mlx4_ib_iboe iboe; + int counters[MLX4_MAX_PORTS]; +}; + +static inline struct mlx4_ib_dev *to_mdev(struct ib_device *ibdev) +{ + return container_of(ibdev, struct mlx4_ib_dev, ib_dev); +} + +static inline struct mlx4_ib_ucontext *to_mucontext(struct ib_ucontext *ibucontext) +{ + return container_of(ibucontext, struct mlx4_ib_ucontext, ibucontext); +} + +static inline struct mlx4_ib_pd *to_mpd(struct ib_pd *ibpd) +{ + return container_of(ibpd, struct mlx4_ib_pd, ibpd); +} + +static inline struct mlx4_ib_xrcd *to_mxrcd(struct ib_xrcd *ibxrcd) +{ + return container_of(ibxrcd, struct mlx4_ib_xrcd, ibxrcd); +} + +static inline struct mlx4_ib_cq *to_mcq(struct ib_cq *ibcq) +{ + return container_of(ibcq, struct mlx4_ib_cq, ibcq); +} + +static inline struct mlx4_ib_cq *to_mibcq(struct mlx4_cq *mcq) +{ + return container_of(mcq, struct mlx4_ib_cq, mcq); +} + +static inline struct mlx4_ib_mr *to_mmr(struct ib_mr *ibmr) +{ + return container_of(ibmr, struct mlx4_ib_mr, ibmr); +} + +static inline struct mlx4_ib_fast_reg_page_list *to_mfrpl(struct ib_fast_reg_page_list *ibfrpl) +{ + return container_of(ibfrpl, struct mlx4_ib_fast_reg_page_list, ibfrpl); +} + +static inline struct mlx4_ib_fmr *to_mfmr(struct ib_fmr *ibfmr) +{ + return container_of(ibfmr, struct mlx4_ib_fmr, ibfmr); +} +static inline struct mlx4_ib_qp *to_mqp(struct ib_qp *ibqp) +{ + return container_of(ibqp, struct mlx4_ib_qp, ibqp); +} + +static inline struct mlx4_ib_qp *to_mibqp(struct mlx4_qp *mqp) +{ + return container_of(mqp, struct mlx4_ib_qp, mqp); +} + +static inline struct mlx4_ib_srq *to_msrq(struct ib_srq *ibsrq) +{ + return container_of(ibsrq, struct mlx4_ib_srq, ibsrq); +} + +static inline struct mlx4_ib_srq *to_mibsrq(struct mlx4_srq *msrq) +{ + return container_of(msrq, struct mlx4_ib_srq, msrq); +} + +static inline struct mlx4_ib_ah *to_mah(struct ib_ah *ibah) +{ + return container_of(ibah, struct mlx4_ib_ah, ibah); +} + +int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt, + struct mlx4_db *db); +void mlx4_ib_db_unmap_user(struct mlx4_ib_ucontext *context, struct mlx4_db *db); + +struct ib_mr *mlx4_ib_get_dma_mr(struct ib_pd *pd, int acc); +int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt, + struct ib_umem *umem); +struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, + u64 virt_addr, int access_flags, + struct ib_udata *udata); +int mlx4_ib_dereg_mr(struct ib_mr *mr); +struct ib_mr *mlx4_ib_alloc_fast_reg_mr(struct ib_pd *pd, + int max_page_list_len); +struct ib_fast_reg_page_list *mlx4_ib_alloc_fast_reg_page_list(struct ib_device *ibdev, + int page_list_len); +void mlx4_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list); + +int mlx4_ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period); +int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata); +struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector, + struct ib_ucontext *context, + struct ib_udata *udata); +int mlx4_ib_destroy_cq(struct ib_cq *cq); +int mlx4_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); +int mlx4_ib_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags); +void __mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq); +void mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq); + +struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr); +int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr); +int mlx4_ib_destroy_ah(struct ib_ah *ah); + +struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd, + struct ib_srq_init_attr *init_attr, + struct ib_udata *udata); +struct ib_srq *mlx4_ib_create_xrc_srq(struct ib_pd *pd, + struct ib_cq *xrc_cq, + struct ib_xrcd *xrcd, + struct ib_srq_init_attr *init_attr, + struct ib_udata *udata); +int mlx4_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, + enum ib_srq_attr_mask attr_mask, struct ib_udata *udata); +int mlx4_ib_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr); +int mlx4_ib_destroy_srq(struct ib_srq *srq); +void mlx4_ib_free_srq_wqe(struct mlx4_ib_srq *srq, int wqe_index); +int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr); + +struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata); +int mlx4_ib_destroy_qp(struct ib_qp *qp); +int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_udata *udata); +int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr); +int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr); +int mlx4_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr); + +int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int ignore_mkey, int ignore_bkey, + int port, struct ib_wc *in_wc, struct ib_grh *in_grh, + void *in_mad, void *response_mad); +int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, + struct ib_wc *in_wc, struct ib_grh *in_grh, + struct ib_mad *in_mad, struct ib_mad *out_mad); +int mlx4_ib_mad_init(struct mlx4_ib_dev *dev); +void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev); + +struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int mr_access_flags, + struct ib_fmr_attr *fmr_attr); +int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, int npages, + u64 iova); +int mlx4_ib_unmap_fmr(struct list_head *fmr_list); +int mlx4_ib_fmr_dealloc(struct ib_fmr *fmr); +int mlx4_ib_create_xrc_rcv_qp(struct ib_qp_init_attr *init_attr, + u32 *qp_num); +int mlx4_ib_modify_xrc_rcv_qp(struct ib_xrcd *xrcd, u32 qp_num, + struct ib_qp_attr *attr, int attr_mask); +int mlx4_ib_query_xrc_rcv_qp(struct ib_xrcd *xrcd, u32 qp_num, + struct ib_qp_attr *attr, int attr_mask, + struct ib_qp_init_attr *init_attr); +int mlx4_ib_reg_xrc_rcv_qp(struct ib_xrcd *xrcd, void *context, u32 qp_num); +int mlx4_ib_unreg_xrc_rcv_qp(struct ib_xrcd *xrcd, void *context, u32 qp_num); + + +int mlx4_ib_resolve_grh(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah_attr, + u8 *mac, int *is_mcast, u8 port); + +static inline int mlx4_ib_ah_grh_present(struct mlx4_ib_ah *ah) +{ + u8 port = be32_to_cpu(ah->av.ib.port_pd) >> 24 & 3; + + if (rdma_port_get_link_layer(ah->ibah.device, port) == IB_LINK_LAYER_ETHERNET) + return 1; + + return !!(ah->av.ib.g_slid & 0x80); +} + +int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp, + union ib_gid *gid); + +#endif /* MLX4_IB_H */ diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/mr.c b/sys/ofed/drivers/infiniband/hw/mlx4/mr.c new file mode 100644 index 000000000000..c49b46022278 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mlx4/mr.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4_ib.h" + +static u32 convert_access(int acc) +{ + return (acc & IB_ACCESS_REMOTE_ATOMIC ? MLX4_PERM_ATOMIC : 0) | + (acc & IB_ACCESS_REMOTE_WRITE ? MLX4_PERM_REMOTE_WRITE : 0) | + (acc & IB_ACCESS_REMOTE_READ ? MLX4_PERM_REMOTE_READ : 0) | + (acc & IB_ACCESS_LOCAL_WRITE ? MLX4_PERM_LOCAL_WRITE : 0) | + MLX4_PERM_LOCAL_READ; +} + +struct ib_mr *mlx4_ib_get_dma_mr(struct ib_pd *pd, int acc) +{ + struct mlx4_ib_mr *mr; + int err; + + mr = kmalloc(sizeof *mr, GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + err = mlx4_mr_alloc(to_mdev(pd->device)->dev, to_mpd(pd)->pdn, 0, + ~0ull, convert_access(acc), 0, 0, &mr->mmr); + if (err) + goto err_free; + + err = mlx4_mr_enable(to_mdev(pd->device)->dev, &mr->mmr); + if (err) + goto err_mr; + + mr->ibmr.rkey = mr->ibmr.lkey = mr->mmr.key; + mr->umem = NULL; + + return &mr->ibmr; + +err_mr: + mlx4_mr_free(to_mdev(pd->device)->dev, &mr->mmr); + +err_free: + kfree(mr); + + return ERR_PTR(err); +} + +int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt, + struct ib_umem *umem) +{ + u64 *pages; + struct ib_umem_chunk *chunk; + int i, j, k; + int n; + int len; + int err = 0; + + pages = (u64 *) __get_free_page(GFP_KERNEL); + if (!pages) + return -ENOMEM; + + i = n = 0; + + list_for_each_entry(chunk, &umem->chunk_list, list) + for (j = 0; j < chunk->nmap; ++j) { + len = sg_dma_len(&chunk->page_list[j]) >> mtt->page_shift; + for (k = 0; k < len; ++k) { + pages[i++] = sg_dma_address(&chunk->page_list[j]) + + umem->page_size * k; + /* + * Be friendly to mlx4_write_mtt() and + * pass it chunks of appropriate size. + */ + if (i == PAGE_SIZE / sizeof (u64)) { + err = mlx4_write_mtt(dev->dev, mtt, n, + i, pages); + if (err) + goto out; + n += i; + i = 0; + } + } + } + + if (i) + err = mlx4_write_mtt(dev->dev, mtt, n, i, pages); + +out: + free_page((unsigned long) pages); + return err; +} + +static int handle_hugetlb_user_mr(struct ib_pd *pd, struct mlx4_ib_mr *mr, + u64 start, u64 virt_addr, int access_flags) +{ +#if defined(CONFIG_HUGETLB_PAGE) && !defined(__powerpc__) && !defined(__ia64__) + struct mlx4_ib_dev *dev = to_mdev(pd->device); + struct ib_umem_chunk *chunk; + unsigned dsize; + dma_addr_t daddr; + unsigned cur_size = 0; + dma_addr_t uninitialized_var(cur_addr); + int n; + struct ib_umem *umem = mr->umem; + u64 *arr; + int err = 0; + int i; + int j = 0; + int off = start & (HPAGE_SIZE - 1); + + n = DIV_ROUND_UP(off + umem->length, HPAGE_SIZE); + arr = kmalloc(n * sizeof *arr, GFP_KERNEL); + if (!arr) + return -ENOMEM; + + list_for_each_entry(chunk, &umem->chunk_list, list) + for (i = 0; i < chunk->nmap; ++i) { + daddr = sg_dma_address(&chunk->page_list[i]); + dsize = sg_dma_len(&chunk->page_list[i]); + if (!cur_size) { + cur_addr = daddr; + cur_size = dsize; + } else if (cur_addr + cur_size != daddr) { + err = -EINVAL; + goto out; + } else + cur_size += dsize; + + if (cur_size > HPAGE_SIZE) { + err = -EINVAL; + goto out; + } else if (cur_size == HPAGE_SIZE) { + cur_size = 0; + arr[j++] = cur_addr; + } + } + + if (cur_size) { + arr[j++] = cur_addr; + } + + err = mlx4_mr_alloc(dev->dev, to_mpd(pd)->pdn, virt_addr, umem->length, + convert_access(access_flags), n, HPAGE_SHIFT, &mr->mmr); + if (err) + goto out; + + err = mlx4_write_mtt(dev->dev, &mr->mmr.mtt, 0, n, arr); + +out: + kfree(arr); + return err; +#else + return -ENOSYS; +#endif +} + +struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, + u64 virt_addr, int access_flags, + struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(pd->device); + struct mlx4_ib_mr *mr; + int shift; + int err; + int n; + + mr = kmalloc(sizeof *mr, GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + mr->umem = ib_umem_get(pd->uobject->context, start, length, + access_flags, 0); + if (IS_ERR(mr->umem)) { + err = PTR_ERR(mr->umem); + goto err_free; + } + + if (!mr->umem->hugetlb || + handle_hugetlb_user_mr(pd, mr, start, virt_addr, access_flags)) { + n = ib_umem_page_count(mr->umem); + shift = ilog2(mr->umem->page_size); + + err = mlx4_mr_alloc(dev->dev, to_mpd(pd)->pdn, virt_addr, length, + convert_access(access_flags), n, shift, &mr->mmr); + if (err) + goto err_umem; + + err = mlx4_ib_umem_write_mtt(dev, &mr->mmr.mtt, mr->umem); + if (err) + goto err_mr; + } + + err = mlx4_mr_enable(dev->dev, &mr->mmr); + if (err) + goto err_mr; + + mr->ibmr.rkey = mr->ibmr.lkey = mr->mmr.key; + + return &mr->ibmr; + +err_mr: + mlx4_mr_free(to_mdev(pd->device)->dev, &mr->mmr); + +err_umem: + ib_umem_release(mr->umem); + +err_free: + kfree(mr); + + return ERR_PTR(err); +} + +int mlx4_ib_dereg_mr(struct ib_mr *ibmr) +{ + struct mlx4_ib_mr *mr = to_mmr(ibmr); + + mlx4_mr_free(to_mdev(ibmr->device)->dev, &mr->mmr); + if (mr->umem) + ib_umem_release(mr->umem); + kfree(mr); + + return 0; +} + +struct ib_mr *mlx4_ib_alloc_fast_reg_mr(struct ib_pd *pd, + int max_page_list_len) +{ + struct mlx4_ib_dev *dev = to_mdev(pd->device); + struct mlx4_ib_mr *mr; + int err; + + mr = kmalloc(sizeof *mr, GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + err = mlx4_mr_alloc(dev->dev, to_mpd(pd)->pdn, 0, 0, 0, + max_page_list_len, 0, &mr->mmr); + if (err) + goto err_free; + + err = mlx4_mr_enable(dev->dev, &mr->mmr); + if (err) + goto err_mr; + + mr->ibmr.rkey = mr->ibmr.lkey = mr->mmr.key; + mr->umem = NULL; + + return &mr->ibmr; + +err_mr: + mlx4_mr_free(dev->dev, &mr->mmr); + +err_free: + kfree(mr); + return ERR_PTR(err); +} + +struct ib_fast_reg_page_list *mlx4_ib_alloc_fast_reg_page_list(struct ib_device *ibdev, + int page_list_len) +{ + struct mlx4_ib_dev *dev = to_mdev(ibdev); + struct mlx4_ib_fast_reg_page_list *mfrpl; + int size = page_list_len * sizeof (u64); + + if (page_list_len > MAX_FAST_REG_PAGES) + return ERR_PTR(-EINVAL); + + mfrpl = kmalloc(sizeof *mfrpl, GFP_KERNEL); + if (!mfrpl) + return ERR_PTR(-ENOMEM); + + mfrpl->ibfrpl.page_list = kmalloc(size, GFP_KERNEL); + if (!mfrpl->ibfrpl.page_list) + goto err_free; + + mfrpl->mapped_page_list = dma_alloc_coherent(&dev->dev->pdev->dev, + size, &mfrpl->map, + GFP_KERNEL); + if (!mfrpl->mapped_page_list) + goto err_free; + + WARN_ON(mfrpl->map & 0x3f); + + return &mfrpl->ibfrpl; + +err_free: + kfree(mfrpl->ibfrpl.page_list); + kfree(mfrpl); + return ERR_PTR(-ENOMEM); +} + +void mlx4_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list) +{ + struct mlx4_ib_dev *dev = to_mdev(page_list->device); + struct mlx4_ib_fast_reg_page_list *mfrpl = to_mfrpl(page_list); + int size = page_list->max_page_list_len * sizeof (u64); + + dma_free_coherent(&dev->dev->pdev->dev, size, mfrpl->mapped_page_list, + mfrpl->map); + kfree(mfrpl->ibfrpl.page_list); + kfree(mfrpl); +} + +struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int acc, + struct ib_fmr_attr *fmr_attr) +{ + struct mlx4_ib_dev *dev = to_mdev(pd->device); + struct mlx4_ib_fmr *fmr; + int err = -ENOMEM; + + fmr = kmalloc(sizeof *fmr, GFP_KERNEL); + if (!fmr) + return ERR_PTR(-ENOMEM); + + err = mlx4_fmr_alloc(dev->dev, to_mpd(pd)->pdn, convert_access(acc), + fmr_attr->max_pages, fmr_attr->max_maps, + fmr_attr->page_shift, &fmr->mfmr); + if (err) + goto err_free; + + err = mlx4_fmr_enable(to_mdev(pd->device)->dev, &fmr->mfmr); + if (err) + goto err_mr; + + fmr->ibfmr.rkey = fmr->ibfmr.lkey = fmr->mfmr.mr.key; + + return &fmr->ibfmr; + +err_mr: + mlx4_mr_free(to_mdev(pd->device)->dev, &fmr->mfmr.mr); + +err_free: + kfree(fmr); + + return ERR_PTR(err); +} + +int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, + int npages, u64 iova) +{ + struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); + struct mlx4_ib_dev *dev = to_mdev(ifmr->ibfmr.device); + + return mlx4_map_phys_fmr(dev->dev, &ifmr->mfmr, page_list, npages, iova, + &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey); +} + +int mlx4_ib_unmap_fmr(struct list_head *fmr_list) +{ + struct ib_fmr *ibfmr; + int err; + struct mlx4_dev *mdev = NULL; + + list_for_each_entry(ibfmr, fmr_list, list) { + if (mdev && to_mdev(ibfmr->device)->dev != mdev) + return -EINVAL; + mdev = to_mdev(ibfmr->device)->dev; + } + + if (!mdev) + return 0; + + list_for_each_entry(ibfmr, fmr_list, list) { + struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); + + mlx4_fmr_unmap(mdev, &ifmr->mfmr, &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey); + } + + /* + * Make sure all MPT status updates are visible before issuing + * SYNC_TPT firmware command. + */ + wmb(); + + err = mlx4_SYNC_TPT(mdev); + if (err) + printk(KERN_WARNING "mlx4_ib: SYNC_TPT error %d when " + "unmapping FMRs\n", err); + + return 0; +} + +int mlx4_ib_fmr_dealloc(struct ib_fmr *ibfmr) +{ + struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr); + struct mlx4_ib_dev *dev = to_mdev(ibfmr->device); + int err; + + err = mlx4_fmr_free(dev->dev, &ifmr->mfmr); + + if (!err) + kfree(ifmr); + + return err; +} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/qp.c b/sys/ofed/drivers/infiniband/hw/mlx4/qp.c new file mode 100644 index 000000000000..8958c1ed12b3 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mlx4/qp.c @@ -0,0 +1,2770 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#include "mlx4_ib.h" +#include "user.h" + +enum { + MLX4_IB_ACK_REQ_FREQ = 8, +}; + +enum { + MLX4_IB_DEFAULT_SCHED_QUEUE = 0x83, + MLX4_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f, + MLX4_IB_LINK_TYPE_IB = 0, + MLX4_IB_LINK_TYPE_ETH = 1, +}; + +enum { + /* + * Largest possible UD header: send with GRH and immediate data. + * 4 bytes added to accommodate for eth header instead of lrh + */ + MLX4_IB_UD_HEADER_SIZE = 76, + MLX4_IB_MAX_RAW_ETY_HDR_SIZE = 12 +}; + +enum { + MLX4_IBOE_ETHERTYPE = 0x8915 +}; + +struct mlx4_ib_xrc_reg_entry { + struct list_head list; + void *context; +}; + +struct mlx4_ib_sqp { + struct mlx4_ib_qp qp; + int pkey_index; + u32 qkey; + u32 send_psn; + struct ib_ud_header ud_header; + u8 header_buf[MLX4_IB_UD_HEADER_SIZE]; +}; + +enum { + MLX4_IB_MIN_SQ_STRIDE = 6 +}; + +static const __be32 mlx4_ib_opcode[] = { + [IB_WR_SEND] = cpu_to_be32(MLX4_OPCODE_SEND), + [IB_WR_LSO] = cpu_to_be32(MLX4_OPCODE_LSO), + [IB_WR_SEND_WITH_IMM] = cpu_to_be32(MLX4_OPCODE_SEND_IMM), + [IB_WR_RDMA_WRITE] = cpu_to_be32(MLX4_OPCODE_RDMA_WRITE), + [IB_WR_RDMA_WRITE_WITH_IMM] = cpu_to_be32(MLX4_OPCODE_RDMA_WRITE_IMM), + [IB_WR_RDMA_READ] = cpu_to_be32(MLX4_OPCODE_RDMA_READ), + [IB_WR_ATOMIC_CMP_AND_SWP] = cpu_to_be32(MLX4_OPCODE_ATOMIC_CS), + [IB_WR_ATOMIC_FETCH_AND_ADD] = cpu_to_be32(MLX4_OPCODE_ATOMIC_FA), + [IB_WR_SEND_WITH_INV] = cpu_to_be32(MLX4_OPCODE_SEND_INVAL), + [IB_WR_LOCAL_INV] = cpu_to_be32(MLX4_OPCODE_LOCAL_INVAL), + [IB_WR_FAST_REG_MR] = cpu_to_be32(MLX4_OPCODE_FMR), + [IB_WR_MASKED_ATOMIC_CMP_AND_SWP] = cpu_to_be32(MLX4_OPCODE_MASKED_ATOMIC_CS), + [IB_WR_MASKED_ATOMIC_FETCH_AND_ADD] = cpu_to_be32(MLX4_OPCODE_MASKED_ATOMIC_FA), +}; + +#ifndef wc_wmb + #if defined(__i386__) + #define wc_wmb() __asm volatile("lock; addl $0,0(%%esp) " ::: "memory") + #elif defined(__x86_64__) + #define wc_wmb() __asm volatile("sfence" ::: "memory") + #elif defined(__ia64__) + #define wc_wmb() __asm volatile("fwb" ::: "memory") + #else + #define wc_wmb() wmb() + #endif +#endif + + +static struct mlx4_ib_sqp *to_msqp(struct mlx4_ib_qp *mqp) +{ + return container_of(mqp, struct mlx4_ib_sqp, qp); +} + +static int is_sqp(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) +{ + return qp->mqp.qpn >= dev->dev->caps.sqp_start && + qp->mqp.qpn <= dev->dev->caps.sqp_start + 3; +} + +static int is_qp0(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) +{ + return qp->mqp.qpn >= dev->dev->caps.sqp_start && + qp->mqp.qpn <= dev->dev->caps.sqp_start + 1; +} + +static void *get_wqe(struct mlx4_ib_qp *qp, int offset) +{ + return mlx4_buf_offset(&qp->buf, offset); +} + +static void *get_recv_wqe(struct mlx4_ib_qp *qp, int n) +{ + return get_wqe(qp, qp->rq.offset + (n << qp->rq.wqe_shift)); +} + +static void *get_send_wqe(struct mlx4_ib_qp *qp, int n) +{ + return get_wqe(qp, qp->sq.offset + (n << qp->sq.wqe_shift)); +} + +/* + * Stamp a SQ WQE so that it is invalid if prefetched by marking the + * first four bytes of every 64 byte chunk with + * 0x7FFFFFF | (invalid_ownership_value << 31). + * + * When the max work request size is less than or equal to the WQE + * basic block size, as an optimization, we can stamp all WQEs with + * 0xffffffff, and skip the very first chunk of each WQE. + */ +static void stamp_send_wqe(struct mlx4_ib_qp *qp, int n, int size) +{ + __be32 *wqe; + int i; + int s; + int ind; + void *buf; + __be32 stamp; + struct mlx4_wqe_ctrl_seg *ctrl; + + if (qp->sq_max_wqes_per_wr > 1) { + s = roundup(size, 1U << qp->sq.wqe_shift); + for (i = 0; i < s; i += 64) { + ind = (i >> qp->sq.wqe_shift) + n; + stamp = ind & qp->sq.wqe_cnt ? cpu_to_be32(0x7fffffff) : + cpu_to_be32(0xffffffff); + buf = get_send_wqe(qp, ind & (qp->sq.wqe_cnt - 1)); + wqe = buf + (i & ((1 << qp->sq.wqe_shift) - 1)); + *wqe = stamp; + } + } else { + ctrl = buf = get_send_wqe(qp, n & (qp->sq.wqe_cnt - 1)); + s = (ctrl->fence_size & 0x3f) << 4; + for (i = 64; i < s; i += 64) { + wqe = buf + i; + *wqe = cpu_to_be32(0xffffffff); + } + } +} + +static void post_nop_wqe(struct mlx4_ib_qp *qp, int n, int size) +{ + struct mlx4_wqe_ctrl_seg *ctrl; + struct mlx4_wqe_inline_seg *inl; + void *wqe; + int s; + + ctrl = wqe = get_send_wqe(qp, n & (qp->sq.wqe_cnt - 1)); + s = sizeof(struct mlx4_wqe_ctrl_seg); + + if (qp->ibqp.qp_type == IB_QPT_UD) { + struct mlx4_wqe_datagram_seg *dgram = wqe + sizeof *ctrl; + struct mlx4_av *av = (struct mlx4_av *)dgram->av; + memset(dgram, 0, sizeof *dgram); + av->port_pd = cpu_to_be32((qp->port << 24) | to_mpd(qp->ibqp.pd)->pdn); + s += sizeof(struct mlx4_wqe_datagram_seg); + } + + /* Pad the remainder of the WQE with an inline data segment. */ + if (size > s) { + inl = wqe + s; + inl->byte_count = cpu_to_be32(1 << 31 | (size - s - sizeof *inl)); + } + ctrl->srcrb_flags = 0; + ctrl->fence_size = size / 16; + /* + * Make sure descriptor is fully written before setting ownership bit + * (because HW can start executing as soon as we do). + */ + wmb(); + + ctrl->owner_opcode = cpu_to_be32(MLX4_OPCODE_NOP | MLX4_WQE_CTRL_NEC) | + (n & qp->sq.wqe_cnt ? cpu_to_be32(1 << 31) : 0); + + stamp_send_wqe(qp, n + qp->sq_spare_wqes, size); +} + +/* Post NOP WQE to prevent wrap-around in the middle of WR */ +static inline unsigned pad_wraparound(struct mlx4_ib_qp *qp, int ind) +{ + unsigned s = qp->sq.wqe_cnt - (ind & (qp->sq.wqe_cnt - 1)); + if (unlikely(s < qp->sq_max_wqes_per_wr)) { + post_nop_wqe(qp, ind, s << qp->sq.wqe_shift); + ind += s; + } + return ind; +} + +static void mlx4_ib_qp_event(struct mlx4_qp *qp, enum mlx4_event type) +{ + struct ib_event event; + struct mlx4_ib_qp *mqp = to_mibqp(qp); + struct ib_qp *ibqp = &mqp->ibqp; + struct mlx4_ib_xrc_reg_entry *ctx_entry; + unsigned long flags; + + if (type == MLX4_EVENT_TYPE_PATH_MIG) + to_mibqp(qp)->port = to_mibqp(qp)->alt_port; + + if (ibqp->event_handler) { + event.device = ibqp->device; + switch (type) { + case MLX4_EVENT_TYPE_PATH_MIG: + event.event = IB_EVENT_PATH_MIG; + break; + case MLX4_EVENT_TYPE_COMM_EST: + event.event = IB_EVENT_COMM_EST; + break; + case MLX4_EVENT_TYPE_SQ_DRAINED: + event.event = IB_EVENT_SQ_DRAINED; + break; + case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE: + event.event = IB_EVENT_QP_LAST_WQE_REACHED; + break; + case MLX4_EVENT_TYPE_WQ_CATAS_ERROR: + event.event = IB_EVENT_QP_FATAL; + break; + case MLX4_EVENT_TYPE_PATH_MIG_FAILED: + event.event = IB_EVENT_PATH_MIG_ERR; + break; + case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR: + event.event = IB_EVENT_QP_REQ_ERR; + break; + case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR: + event.event = IB_EVENT_QP_ACCESS_ERR; + break; + default: + printk(KERN_WARNING "mlx4_ib: Unexpected event type %d " + "on QP %06x\n", type, qp->qpn); + return; + } + + if (unlikely(ibqp->qp_type == IB_QPT_XRC && + mqp->flags & MLX4_IB_XRC_RCV)) { + event.event |= IB_XRC_QP_EVENT_FLAG; + event.element.xrc_qp_num = ibqp->qp_num; + spin_lock_irqsave(&mqp->xrc_reg_list_lock, flags); + list_for_each_entry(ctx_entry, &mqp->xrc_reg_list, list) + ibqp->event_handler(&event, ctx_entry->context); + spin_unlock_irqrestore(&mqp->xrc_reg_list_lock, flags); + return; + } + event.element.qp = ibqp; + ibqp->event_handler(&event, ibqp->qp_context); + } +} + +static int send_wqe_overhead(enum ib_qp_type type, u32 flags) +{ + /* + * UD WQEs must have a datagram segment. + * RC and UC WQEs might have a remote address segment. + * MLX WQEs need two extra inline data segments (for the UD + * header and space for the ICRC). + */ + switch (type) { + case IB_QPT_UD: + return sizeof (struct mlx4_wqe_ctrl_seg) + + sizeof (struct mlx4_wqe_datagram_seg) + + ((flags & MLX4_IB_QP_LSO) ? 128 : 0); + case IB_QPT_UC: + return sizeof (struct mlx4_wqe_ctrl_seg) + + sizeof (struct mlx4_wqe_raddr_seg); + case IB_QPT_XRC: + case IB_QPT_RC: + return sizeof (struct mlx4_wqe_ctrl_seg) + + sizeof (struct mlx4_wqe_atomic_seg) + + sizeof (struct mlx4_wqe_raddr_seg); + case IB_QPT_SMI: + case IB_QPT_GSI: + return sizeof (struct mlx4_wqe_ctrl_seg) + + ALIGN(MLX4_IB_UD_HEADER_SIZE + + DIV_ROUND_UP(MLX4_IB_UD_HEADER_SIZE, + MLX4_INLINE_ALIGN) * + sizeof (struct mlx4_wqe_inline_seg), + sizeof (struct mlx4_wqe_data_seg)) + + ALIGN(4 + + sizeof (struct mlx4_wqe_inline_seg), + sizeof (struct mlx4_wqe_data_seg)); + case IB_QPT_RAW_ETY: + return sizeof(struct mlx4_wqe_ctrl_seg) + + ALIGN(MLX4_IB_MAX_RAW_ETY_HDR_SIZE + + sizeof(struct mlx4_wqe_inline_seg), + sizeof(struct mlx4_wqe_data_seg)); + + default: + return sizeof (struct mlx4_wqe_ctrl_seg); + } +} + +static int set_rq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, + int is_user, int has_srq_or_is_xrc, struct mlx4_ib_qp *qp) +{ + /* Sanity check RQ size before proceeding */ + if (cap->max_recv_wr > dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE || + cap->max_recv_sge > + min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg)) { + mlx4_ib_dbg("Requested RQ size (sge or wr) too large"); + return -EINVAL; + } + + if (has_srq_or_is_xrc) { + /* QPs attached to an SRQ should have no RQ */ + if (cap->max_recv_wr) { + mlx4_ib_dbg("non-zero RQ size for QP using SRQ"); + return -EINVAL; + } + + qp->rq.wqe_cnt = qp->rq.max_gs = 0; + } else { + /* HW requires >= 1 RQ entry with >= 1 gather entry */ + if (is_user && (!cap->max_recv_wr || !cap->max_recv_sge)) { + mlx4_ib_dbg("user QP RQ has 0 wr's or 0 sge's " + "(wr: 0x%x, sge: 0x%x)", cap->max_recv_wr, + cap->max_recv_sge); + return -EINVAL; + } + + qp->rq.wqe_cnt = roundup_pow_of_two(max(1U, cap->max_recv_wr)); + qp->rq.max_gs = roundup_pow_of_two(max(1U, cap->max_recv_sge)); + qp->rq.wqe_shift = ilog2(qp->rq.max_gs * sizeof (struct mlx4_wqe_data_seg)); + } + + /* leave userspace return values as they were, so as not to break ABI */ + if (is_user) { + cap->max_recv_wr = qp->rq.max_post = qp->rq.wqe_cnt; + cap->max_recv_sge = qp->rq.max_gs; + } else { + cap->max_recv_wr = qp->rq.max_post = + min(dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE, qp->rq.wqe_cnt); + cap->max_recv_sge = min(qp->rq.max_gs, + min(dev->dev->caps.max_sq_sg, + dev->dev->caps.max_rq_sg)); + } + /* We don't support inline sends for kernel QPs (yet) */ + + + return 0; +} + +static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap, + enum ib_qp_type type, struct mlx4_ib_qp *qp) +{ + int s; + + /* Sanity check SQ size before proceeding */ + if (cap->max_send_wr > (dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE) || + cap->max_send_sge > + min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg) || + cap->max_inline_data + send_wqe_overhead(type, qp->flags) + + sizeof (struct mlx4_wqe_inline_seg) > dev->dev->caps.max_sq_desc_sz) { + mlx4_ib_dbg("Requested SQ resources exceed device maxima"); + return -EINVAL; + } + + /* + * For MLX transport we need 2 extra S/G entries: + * one for the header and one for the checksum at the end + */ + if ((type == IB_QPT_SMI || type == IB_QPT_GSI) && + cap->max_send_sge + 2 > dev->dev->caps.max_sq_sg) { + mlx4_ib_dbg("No space for SQP hdr/csum sge's"); + return -EINVAL; + } + + if (type == IB_QPT_RAW_ETY && + cap->max_send_sge + 1 > dev->dev->caps.max_sq_sg) { + mlx4_ib_dbg("No space for RAW ETY hdr"); + return -EINVAL; + } + + s = max(cap->max_send_sge * sizeof (struct mlx4_wqe_data_seg), + cap->max_inline_data + sizeof (struct mlx4_wqe_inline_seg)) + + send_wqe_overhead(type, qp->flags); + + if (s > dev->dev->caps.max_sq_desc_sz) + return -EINVAL; + + /* + * Hermon supports shrinking WQEs, such that a single work + * request can include multiple units of 1 << wqe_shift. This + * way, work requests can differ in size, and do not have to + * be a power of 2 in size, saving memory and speeding up send + * WR posting. Unfortunately, if we do this then the + * wqe_index field in CQEs can't be used to look up the WR ID + * anymore, so we do this only if selective signaling is off. + * + * Further, on 32-bit platforms, we can't use vmap() to make + * the QP buffer virtually contigious. Thus we have to use + * constant-sized WRs to make sure a WR is always fully within + * a single page-sized chunk. + * + * Finally, we use NOP work requests to pad the end of the + * work queue, to avoid wrap-around in the middle of WR. We + * set NEC bit to avoid getting completions with error for + * these NOP WRs, but since NEC is only supported starting + * with firmware 2.2.232, we use constant-sized WRs for older + * firmware. + * + * And, since MLX QPs only support SEND, we use constant-sized + * WRs in this case. + * + * We look for the smallest value of wqe_shift such that the + * resulting number of wqes does not exceed device + * capabilities. + * + * We set WQE size to at least 64 bytes, this way stamping + * invalidates each WQE. + */ + if (dev->dev->caps.fw_ver >= MLX4_FW_VER_WQE_CTRL_NEC && + qp->sq_signal_bits && BITS_PER_LONG == 64 && + type != IB_QPT_SMI && type != IB_QPT_GSI && type != IB_QPT_RAW_ETY) + qp->sq.wqe_shift = ilog2(64); + else + qp->sq.wqe_shift = ilog2(roundup_pow_of_two(s)); + + for (;;) { + qp->sq_max_wqes_per_wr = DIV_ROUND_UP(s, 1U << qp->sq.wqe_shift); + + /* + * We need to leave 2 KB + 1 WR of headroom in the SQ to + * allow HW to prefetch. + */ + qp->sq_spare_wqes = (2048 >> qp->sq.wqe_shift) + qp->sq_max_wqes_per_wr; + qp->sq.wqe_cnt = roundup_pow_of_two(cap->max_send_wr * + qp->sq_max_wqes_per_wr + + qp->sq_spare_wqes); + + if (qp->sq.wqe_cnt <= dev->dev->caps.max_wqes) + break; + + if (qp->sq_max_wqes_per_wr <= 1) + return -EINVAL; + + ++qp->sq.wqe_shift; + } + + qp->sq.max_gs = (min(dev->dev->caps.max_sq_desc_sz, + (qp->sq_max_wqes_per_wr << qp->sq.wqe_shift)) - + send_wqe_overhead(type, qp->flags)) / + sizeof (struct mlx4_wqe_data_seg); + + qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) + + (qp->sq.wqe_cnt << qp->sq.wqe_shift); + if (qp->rq.wqe_shift > qp->sq.wqe_shift) { + qp->rq.offset = 0; + qp->sq.offset = qp->rq.wqe_cnt << qp->rq.wqe_shift; + } else { + qp->rq.offset = qp->sq.wqe_cnt << qp->sq.wqe_shift; + qp->sq.offset = 0; + } + + cap->max_send_wr = qp->sq.max_post = + (qp->sq.wqe_cnt - qp->sq_spare_wqes) / qp->sq_max_wqes_per_wr; + cap->max_send_sge = min(qp->sq.max_gs, + min(dev->dev->caps.max_sq_sg, + dev->dev->caps.max_rq_sg)); + qp->max_inline_data = cap->max_inline_data; + + return 0; +} + +static int set_user_sq_size(struct mlx4_ib_dev *dev, + struct mlx4_ib_qp *qp, + struct mlx4_ib_create_qp *ucmd) +{ + /* Sanity check SQ size before proceeding */ + if ((1 << ucmd->log_sq_bb_count) > dev->dev->caps.max_wqes || + ucmd->log_sq_stride > + ilog2(roundup_pow_of_two(dev->dev->caps.max_sq_desc_sz)) || + ucmd->log_sq_stride < MLX4_IB_MIN_SQ_STRIDE) { + mlx4_ib_dbg("Requested max wqes or wqe stride exceeds max"); + return -EINVAL; + } + + qp->sq.wqe_cnt = 1 << ucmd->log_sq_bb_count; + qp->sq.wqe_shift = ucmd->log_sq_stride; + + qp->buf_size = (qp->rq.wqe_cnt << qp->rq.wqe_shift) + + (qp->sq.wqe_cnt << qp->sq.wqe_shift); + + return 0; +} + +static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata, int sqpn, struct mlx4_ib_qp *qp) +{ + int qpn; + int err; + + mutex_init(&qp->mutex); + spin_lock_init(&qp->sq.lock); + spin_lock_init(&qp->rq.lock); + spin_lock_init(&qp->xrc_reg_list_lock); + INIT_LIST_HEAD(&qp->gid_list); + + qp->state = IB_QPS_RESET; + if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) + qp->sq_signal_bits = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE); + + err = set_rq_size(dev, &init_attr->cap, !!pd->uobject, + !!init_attr->srq || !!init_attr->xrc_domain , qp); + if (err) + goto err; + + if (pd->uobject) { + struct mlx4_ib_create_qp ucmd; + + if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) { + err = -EFAULT; + goto err; + } + + qp->sq_no_prefetch = ucmd.sq_no_prefetch; + + err = set_user_sq_size(dev, qp, &ucmd); + if (err) + goto err; + + qp->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, + qp->buf_size, 0, 0); + if (IS_ERR(qp->umem)) { + err = PTR_ERR(qp->umem); + mlx4_ib_dbg("ib_umem_get error (%d)", err); + goto err; + } + + err = mlx4_mtt_init(dev->dev, ib_umem_page_count(qp->umem), + ilog2(qp->umem->page_size), &qp->mtt); + if (err) { + mlx4_ib_dbg("mlx4_mtt_init error (%d)", err); + goto err_buf; + } + + err = mlx4_ib_umem_write_mtt(dev, &qp->mtt, qp->umem); + if (err) { + mlx4_ib_dbg("mlx4_ib_umem_write_mtt error (%d)", err); + goto err_mtt; + } + + if (!init_attr->srq && init_attr->qp_type != IB_QPT_XRC) { + err = mlx4_ib_db_map_user(to_mucontext(pd->uobject->context), + ucmd.db_addr, &qp->db); + if (err) { + mlx4_ib_dbg("mlx4_ib_db_map_user error (%d)", err); + goto err_mtt; + } + } + } else { + qp->sq_no_prefetch = 0; + + if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) + qp->flags |= MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK; + + if (init_attr->create_flags & IB_QP_CREATE_IPOIB_UD_LSO) + qp->flags |= MLX4_IB_QP_LSO; + + err = set_kernel_sq_size(dev, &init_attr->cap, init_attr->qp_type, qp); + if (err) + goto err; + + if (!init_attr->srq && init_attr->qp_type != IB_QPT_XRC) { + err = mlx4_db_alloc(dev->dev, &qp->db, 0); + if (err) + goto err; + + *qp->db.db = 0; + } + + if (qp->max_inline_data) { + err = mlx4_bf_alloc(dev->dev, &qp->bf); + if (err) { + mlx4_ib_dbg("failed to allocate blue flame register (%d)", err); + qp->bf.uar = &dev->priv_uar; + } + } else + qp->bf.uar = &dev->priv_uar; + + if (mlx4_buf_alloc(dev->dev, qp->buf_size, PAGE_SIZE * 2, &qp->buf)) { + err = -ENOMEM; + goto err_db; + } + + err = mlx4_mtt_init(dev->dev, qp->buf.npages, qp->buf.page_shift, + &qp->mtt); + if (err) { + mlx4_ib_dbg("kernel qp mlx4_mtt_init error (%d)", err); + goto err_buf; + } + + err = mlx4_buf_write_mtt(dev->dev, &qp->mtt, &qp->buf); + if (err) { + mlx4_ib_dbg("mlx4_buf_write_mtt error (%d)", err); + goto err_mtt; + } + + qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof (u64), GFP_KERNEL); + qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof (u64), GFP_KERNEL); + + if (!qp->sq.wrid || !qp->rq.wrid) { + err = -ENOMEM; + goto err_wrid; + } + } + + if (sqpn) { + qpn = sqpn; + } else { + err = mlx4_qp_reserve_range(dev->dev, 1, 1, &qpn); + if (err) + goto err_wrid; + } + + err = mlx4_qp_alloc(dev->dev, qpn, &qp->mqp); + if (err) + goto err_qpn; + + if (init_attr->qp_type == IB_QPT_XRC) + qp->mqp.qpn |= (1 << 23); + + /* + * Hardware wants QPN written in big-endian order (after + * shifting) for send doorbell. Precompute this value to save + * a little bit when posting sends. + */ + qp->doorbell_qpn = swab32(qp->mqp.qpn << 8); + + qp->mqp.event = mlx4_ib_qp_event; + + return 0; + +err_qpn: + if (!sqpn) + mlx4_qp_release_range(dev->dev, qpn, 1); + +err_wrid: + if (pd->uobject) { + if (!init_attr->srq && init_attr->qp_type != IB_QPT_XRC) + mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), + &qp->db); + } else { + kfree(qp->sq.wrid); + kfree(qp->rq.wrid); + } + +err_mtt: + mlx4_mtt_cleanup(dev->dev, &qp->mtt); + +err_buf: + if (pd->uobject) + ib_umem_release(qp->umem); + else + mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf); + +err_db: + if (!pd->uobject && !init_attr->srq && init_attr->qp_type != IB_QPT_XRC) + mlx4_db_free(dev->dev, &qp->db); + + if (qp->max_inline_data) + mlx4_bf_free(dev->dev, &qp->bf); + +err: + return err; +} + +static enum mlx4_qp_state to_mlx4_state(enum ib_qp_state state) +{ + switch (state) { + case IB_QPS_RESET: return MLX4_QP_STATE_RST; + case IB_QPS_INIT: return MLX4_QP_STATE_INIT; + case IB_QPS_RTR: return MLX4_QP_STATE_RTR; + case IB_QPS_RTS: return MLX4_QP_STATE_RTS; + case IB_QPS_SQD: return MLX4_QP_STATE_SQD; + case IB_QPS_SQE: return MLX4_QP_STATE_SQER; + case IB_QPS_ERR: return MLX4_QP_STATE_ERR; + default: return -1; + } +} + +static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq) +{ + if (send_cq == recv_cq) + spin_lock_irq(&send_cq->lock); + else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { + spin_lock_irq(&send_cq->lock); + spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING); + } else { + spin_lock_irq(&recv_cq->lock); + spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING); + } +} + +static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq) +{ + if (send_cq == recv_cq) + spin_unlock_irq(&send_cq->lock); + else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) { + spin_unlock(&recv_cq->lock); + spin_unlock_irq(&send_cq->lock); + } else { + spin_unlock(&send_cq->lock); + spin_unlock_irq(&recv_cq->lock); + } +} + +static void del_gid_entries(struct mlx4_ib_qp *qp) +{ + struct gid_entry *ge, *tmp; + + list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) { + list_del(&ge->list); + kfree(ge); + } +} + +static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, + int is_user) +{ + struct mlx4_ib_cq *send_cq, *recv_cq; + + if (qp->state != IB_QPS_RESET) + if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state), + MLX4_QP_STATE_RST, NULL, 0, 0, &qp->mqp)) + printk(KERN_WARNING "mlx4_ib: modify QP %06x to RESET failed.\n", + qp->mqp.qpn); + + send_cq = to_mcq(qp->ibqp.send_cq); + recv_cq = to_mcq(qp->ibqp.recv_cq); + + mlx4_ib_lock_cqs(send_cq, recv_cq); + + if (!is_user) { + __mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn, + qp->ibqp.srq ? to_msrq(qp->ibqp.srq): NULL); + if (send_cq != recv_cq) + __mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL); + } + + mlx4_qp_remove(dev->dev, &qp->mqp); + + mlx4_ib_unlock_cqs(send_cq, recv_cq); + + mlx4_qp_free(dev->dev, &qp->mqp); + + if (!is_sqp(dev, qp)) + mlx4_qp_release_range(dev->dev, qp->mqp.qpn, 1); + + mlx4_mtt_cleanup(dev->dev, &qp->mtt); + + if (is_user) { + if (!qp->ibqp.srq && qp->ibqp.qp_type != IB_QPT_XRC) + mlx4_ib_db_unmap_user(to_mucontext(qp->ibqp.uobject->context), + &qp->db); + ib_umem_release(qp->umem); + } else { + kfree(qp->sq.wrid); + kfree(qp->rq.wrid); + mlx4_buf_free(dev->dev, qp->buf_size, &qp->buf); + if (qp->max_inline_data) + mlx4_bf_free(dev->dev, &qp->bf); + if (!qp->ibqp.srq && qp->ibqp.qp_type != IB_QPT_XRC) + mlx4_db_free(dev->dev, &qp->db); + } + + del_gid_entries(qp); +} + +struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(pd->device); + struct mlx4_ib_sqp *sqp; + struct mlx4_ib_qp *qp; + int err; + + /* + * We only support LSO and multicast loopback blocking, and + * only for kernel UD QPs. + */ + if (init_attr->create_flags & ~(IB_QP_CREATE_IPOIB_UD_LSO | + IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK)) + return ERR_PTR(-EINVAL); + + if (init_attr->create_flags && + (pd->uobject || init_attr->qp_type != IB_QPT_UD)) + return ERR_PTR(-EINVAL); + + switch (init_attr->qp_type) { + case IB_QPT_XRC: + if (!(dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC)) + return ERR_PTR(-ENOSYS); + case IB_QPT_RC: + case IB_QPT_UC: + case IB_QPT_UD: + case IB_QPT_RAW_ETH: + { + qp = kzalloc(sizeof *qp, GFP_KERNEL); + if (!qp) + return ERR_PTR(-ENOMEM); + + err = create_qp_common(dev, pd, init_attr, udata, 0, qp); + if (err) { + kfree(qp); + return ERR_PTR(err); + } + + if (init_attr->qp_type == IB_QPT_XRC) + qp->xrcdn = to_mxrcd(init_attr->xrc_domain)->xrcdn; + else + qp->xrcdn = 0; + + qp->ibqp.qp_num = qp->mqp.qpn; + + break; + } + case IB_QPT_RAW_ETY: + if (!(dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_RAW_ETY)) + return ERR_PTR(-ENOSYS); + case IB_QPT_SMI: + case IB_QPT_GSI: + { + /* Userspace is not allowed to create special QPs: */ + if (pd->uobject) { + mlx4_ib_dbg("Userspace is not allowed to create special QPs"); + return ERR_PTR(-EINVAL); + } + + sqp = kzalloc(sizeof *sqp, GFP_KERNEL); + if (!sqp) + return ERR_PTR(-ENOMEM); + + qp = &sqp->qp; + + err = create_qp_common(dev, pd, init_attr, udata, + dev->dev->caps.sqp_start + + (init_attr->qp_type == IB_QPT_RAW_ETY ? 4 : + (init_attr->qp_type == IB_QPT_SMI ? 0 : 2)) + + init_attr->port_num - 1, + qp); + if (err) { + kfree(sqp); + return ERR_PTR(err); + } + + qp->port = init_attr->port_num; + qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1; + + break; + } + default: + mlx4_ib_dbg("Invalid QP type requested for create_qp (%d)", + init_attr->qp_type); + return ERR_PTR(-EINVAL); + } + + return &qp->ibqp; +} + +int mlx4_ib_destroy_qp(struct ib_qp *qp) +{ + struct mlx4_ib_dev *dev = to_mdev(qp->device); + struct mlx4_ib_qp *mqp = to_mqp(qp); + + if (is_qp0(dev, mqp)) + mlx4_CLOSE_PORT(dev->dev, mqp->port); + + destroy_qp_common(dev, mqp, !!qp->pd->uobject); + + if (is_sqp(dev, mqp)) + kfree(to_msqp(mqp)); + else + kfree(mqp); + + return 0; +} + +static int to_mlx4_st(enum ib_qp_type type) +{ + switch (type) { + case IB_QPT_RC: return MLX4_QP_ST_RC; + case IB_QPT_UC: return MLX4_QP_ST_UC; + case IB_QPT_UD: return MLX4_QP_ST_UD; + case IB_QPT_XRC: return MLX4_QP_ST_XRC; + case IB_QPT_RAW_ETY: + case IB_QPT_SMI: + case IB_QPT_GSI: + case IB_QPT_RAW_ETH: return MLX4_QP_ST_MLX; + default: return -1; + } +} + +static __be32 to_mlx4_access_flags(struct mlx4_ib_qp *qp, const struct ib_qp_attr *attr, + int attr_mask) +{ + u8 dest_rd_atomic; + u32 access_flags; + u32 hw_access_flags = 0; + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) + dest_rd_atomic = attr->max_dest_rd_atomic; + else + dest_rd_atomic = qp->resp_depth; + + if (attr_mask & IB_QP_ACCESS_FLAGS) + access_flags = attr->qp_access_flags; + else + access_flags = qp->atomic_rd_en; + + if (!dest_rd_atomic) + access_flags &= IB_ACCESS_REMOTE_WRITE; + + if (access_flags & IB_ACCESS_REMOTE_READ) + hw_access_flags |= MLX4_QP_BIT_RRE; + if (access_flags & IB_ACCESS_REMOTE_ATOMIC) + hw_access_flags |= MLX4_QP_BIT_RAE; + if (access_flags & IB_ACCESS_REMOTE_WRITE) + hw_access_flags |= MLX4_QP_BIT_RWE; + + return cpu_to_be32(hw_access_flags); +} + +static void store_sqp_attrs(struct mlx4_ib_sqp *sqp, const struct ib_qp_attr *attr, + int attr_mask) +{ + if (attr_mask & IB_QP_PKEY_INDEX) + sqp->pkey_index = attr->pkey_index; + if (attr_mask & IB_QP_QKEY) + sqp->qkey = attr->qkey; + if (attr_mask & IB_QP_SQ_PSN) + sqp->send_psn = attr->sq_psn; +} + +static void mlx4_set_sched(struct mlx4_qp_path *path, u8 port) +{ + path->sched_queue = (path->sched_queue & 0xbf) | ((port - 1) << 6); +} + +static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah, + struct mlx4_qp_path *path, u8 port) +{ + int err; + int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port) == + IB_LINK_LAYER_ETHERNET; + u8 mac[6]; + int is_mcast; + u16 vlan_tag; + int vidx; + + path->grh_mylmc = ah->src_path_bits & 0x7f; + path->rlid = cpu_to_be16(ah->dlid); + if (ah->static_rate) { + path->static_rate = ah->static_rate + MLX4_STAT_RATE_OFFSET; + while (path->static_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET && + !(1 << path->static_rate & dev->dev->caps.stat_rate_support)) + --path->static_rate; + } else + path->static_rate = 0; + + if (ah->ah_flags & IB_AH_GRH) { + if (ah->grh.sgid_index >= dev->dev->caps.gid_table_len[port]) { + printk(KERN_ERR "sgid_index (%u) too large. max is %d\n", + ah->grh.sgid_index, dev->dev->caps.gid_table_len[port] - 1); + return -1; + } + + path->grh_mylmc |= 1 << 7; + path->mgid_index = ah->grh.sgid_index; + path->hop_limit = ah->grh.hop_limit; + path->tclass_flowlabel = + cpu_to_be32((ah->grh.traffic_class << 20) | + (ah->grh.flow_label)); + memcpy(path->rgid, ah->grh.dgid.raw, 16); + } + + if (is_eth) { + path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | + ((port - 1) << 6) | ((ah->sl & 0x7) << 3) | ((ah->sl & 8) >> 1); + + if (!(ah->ah_flags & IB_AH_GRH)) + return -1; + + err = mlx4_ib_resolve_grh(dev, ah, mac, &is_mcast, port); + if (err) + return err; + + memcpy(path->dmac, mac, 6); + path->ackto = MLX4_IB_LINK_TYPE_ETH; + /* use index 0 into MAC table for IBoE */ + path->grh_mylmc &= 0x80; + + vlan_tag = rdma_get_vlan_id(&dev->iboe.gid_table[port - 1][ah->grh.sgid_index]); + if (vlan_tag < 0x1000) { + if (mlx4_find_cached_vlan(dev->dev, port, vlan_tag, &vidx)) + return -ENOENT; + + path->vlan_index = vidx; + path->fl = 1 << 6; + } + } else + path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | + ((port - 1) << 6) | ((ah->sl & 0xf) << 2); + + return 0; +} + +static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) +{ + struct gid_entry *ge, *tmp; + + list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) { + if (!ge->added && mlx4_ib_add_mc(dev, qp, &ge->gid)) { + ge->added = 1; + ge->port = qp->port; + } + } +} + +static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, + const struct ib_qp_attr *attr, int attr_mask, + enum ib_qp_state cur_state, enum ib_qp_state new_state) +{ + struct mlx4_ib_dev *dev = to_mdev(ibqp->device); + struct mlx4_ib_qp *qp = to_mqp(ibqp); + struct mlx4_qp_context *context; + enum mlx4_qp_optpar optpar = 0; + int sqd_event; + int err = -EINVAL; + + context = kzalloc(sizeof *context, GFP_KERNEL); + if (!context) + return -ENOMEM; + + context->flags = cpu_to_be32((to_mlx4_state(new_state) << 28) | + (to_mlx4_st(ibqp->qp_type) << 16)); + + if (!(attr_mask & IB_QP_PATH_MIG_STATE)) + context->flags |= cpu_to_be32(MLX4_QP_PM_MIGRATED << 11); + else { + optpar |= MLX4_QP_OPTPAR_PM_STATE; + switch (attr->path_mig_state) { + case IB_MIG_MIGRATED: + context->flags |= cpu_to_be32(MLX4_QP_PM_MIGRATED << 11); + break; + case IB_MIG_REARM: + context->flags |= cpu_to_be32(MLX4_QP_PM_REARM << 11); + break; + case IB_MIG_ARMED: + context->flags |= cpu_to_be32(MLX4_QP_PM_ARMED << 11); + break; + } + } + if (ibqp->qp_type == IB_QPT_RAW_ETH) + context->mtu_msgmax = 0xff; + else if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI || + ibqp->qp_type == IB_QPT_RAW_ETY) + context->mtu_msgmax = (IB_MTU_4096 << 5) | 11; + else if (ibqp->qp_type == IB_QPT_UD) { + if (qp->flags & MLX4_IB_QP_LSO) + context->mtu_msgmax = (IB_MTU_4096 << 5) | + ilog2(dev->dev->caps.max_gso_sz); + else + context->mtu_msgmax = (IB_MTU_4096 << 5) | 12; + } else if (attr_mask & IB_QP_PATH_MTU) { + if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) { + printk(KERN_ERR "path MTU (%u) is invalid\n", + attr->path_mtu); + goto out; + } + context->mtu_msgmax = (attr->path_mtu << 5) | + ilog2(dev->dev->caps.max_msg_sz); + } + + if (qp->rq.wqe_cnt) + context->rq_size_stride = ilog2(qp->rq.wqe_cnt) << 3; + context->rq_size_stride |= qp->rq.wqe_shift - 4; + + if (qp->sq.wqe_cnt) + context->sq_size_stride = ilog2(qp->sq.wqe_cnt) << 3; + context->sq_size_stride |= qp->sq.wqe_shift - 4; + + if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { + context->sq_size_stride |= !!qp->sq_no_prefetch << 7; + if (ibqp->qp_type == IB_QPT_XRC) + context->xrcd = cpu_to_be32((u32) qp->xrcdn); + } + + if (qp->ibqp.uobject) + context->usr_page = cpu_to_be32(to_mucontext(ibqp->uobject->context)->uar.index); + else + context->usr_page = cpu_to_be32(qp->bf.uar->index); + + if (attr_mask & IB_QP_DEST_QPN) + context->remote_qpn = cpu_to_be32(attr->dest_qp_num); + + if (attr_mask & IB_QP_PORT) { + if (cur_state == IB_QPS_SQD && new_state == IB_QPS_SQD && + !(attr_mask & IB_QP_AV)) { + mlx4_set_sched(&context->pri_path, attr->port_num); + optpar |= MLX4_QP_OPTPAR_SCHED_QUEUE; + } + } + + if (cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR && + dev->counters[qp->port - 1] != -1) { + context->pri_path.counter_index = dev->counters[qp->port - 1]; + optpar |= MLX4_QP_OPTPAR_COUNTER_INDEX; + } + + if (attr_mask & IB_QP_PKEY_INDEX) { + context->pri_path.pkey_index = attr->pkey_index; + optpar |= MLX4_QP_OPTPAR_PKEY_INDEX; + } + + if (attr_mask & IB_QP_AV) { + if (mlx4_set_path(dev, &attr->ah_attr, &context->pri_path, + attr_mask & IB_QP_PORT ? attr->port_num : qp->port)) { + mlx4_ib_dbg("qpn 0x%x: could not set pri path params", + ibqp->qp_num); + goto out; + } + + optpar |= (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH | + MLX4_QP_OPTPAR_SCHED_QUEUE); + } + + if (attr_mask & IB_QP_TIMEOUT) { + context->pri_path.ackto |= (attr->timeout << 3); + optpar |= MLX4_QP_OPTPAR_ACK_TIMEOUT; + } + + if (attr_mask & IB_QP_ALT_PATH) { + if (attr->alt_port_num == 0 || + attr->alt_port_num > dev->num_ports) { + mlx4_ib_dbg("qpn 0x%x: invalid alternate port num (%d)", + ibqp->qp_num, attr->alt_port_num); + goto out; + } + + if (attr->alt_pkey_index >= + dev->dev->caps.pkey_table_len[attr->alt_port_num]) { + mlx4_ib_dbg("qpn 0x%x: invalid alt pkey index (0x%x)", + ibqp->qp_num, attr->alt_pkey_index); + goto out; + } + + if (mlx4_set_path(dev, &attr->alt_ah_attr, &context->alt_path, + attr->alt_port_num)) { + mlx4_ib_dbg("qpn 0x%x: could not set alt path params", + ibqp->qp_num); + goto out; + } + + context->alt_path.pkey_index = attr->alt_pkey_index; + context->alt_path.ackto = attr->alt_timeout << 3; + optpar |= MLX4_QP_OPTPAR_ALT_ADDR_PATH; + } + + context->pd = cpu_to_be32(to_mpd(ibqp->pd)->pdn); + context->params1 = cpu_to_be32(MLX4_IB_ACK_REQ_FREQ << 28); + + /* Set "fast registration enabled" for all kernel QPs */ + if (!qp->ibqp.uobject) + context->params1 |= cpu_to_be32(1 << 11); + + if (attr_mask & IB_QP_RNR_RETRY) { + context->params1 |= cpu_to_be32(attr->rnr_retry << 13); + optpar |= MLX4_QP_OPTPAR_RNR_RETRY; + } + + if (attr_mask & IB_QP_RETRY_CNT) { + context->params1 |= cpu_to_be32(attr->retry_cnt << 16); + optpar |= MLX4_QP_OPTPAR_RETRY_COUNT; + } + + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) { + if (attr->max_rd_atomic) + context->params1 |= + cpu_to_be32(fls(attr->max_rd_atomic - 1) << 21); + optpar |= MLX4_QP_OPTPAR_SRA_MAX; + } + + if (attr_mask & IB_QP_SQ_PSN) + context->next_send_psn = cpu_to_be32(attr->sq_psn); + + context->cqn_send = cpu_to_be32(to_mcq(ibqp->send_cq)->mcq.cqn); + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { + if (attr->max_dest_rd_atomic) + context->params2 |= + cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21); + optpar |= MLX4_QP_OPTPAR_RRA_MAX; + } + + if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) { + context->params2 |= to_mlx4_access_flags(qp, attr, attr_mask); + optpar |= MLX4_QP_OPTPAR_RWE | MLX4_QP_OPTPAR_RRE | MLX4_QP_OPTPAR_RAE; + } + + if (ibqp->srq) + context->params2 |= cpu_to_be32(MLX4_QP_BIT_RIC); + + if (attr_mask & IB_QP_MIN_RNR_TIMER) { + context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24); + optpar |= MLX4_QP_OPTPAR_RNR_TIMEOUT; + } + if (attr_mask & IB_QP_RQ_PSN) + context->rnr_nextrecvpsn |= cpu_to_be32(attr->rq_psn); + + context->cqn_recv = cpu_to_be32(to_mcq(ibqp->recv_cq)->mcq.cqn); + + if (attr_mask & IB_QP_QKEY) { + context->qkey = cpu_to_be32(attr->qkey); + optpar |= MLX4_QP_OPTPAR_Q_KEY; + } + + if (ibqp->srq) + context->srqn = cpu_to_be32(1 << 24 | to_msrq(ibqp->srq)->msrq.srqn); + + if (!ibqp->srq && ibqp->qp_type != IB_QPT_XRC && + cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) + context->db_rec_addr = cpu_to_be64(qp->db.dma); + + if (cur_state == IB_QPS_INIT && + new_state == IB_QPS_RTR && + (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI || + ibqp->qp_type == IB_QPT_UD || ibqp->qp_type == IB_QPT_RAW_ETY || + ibqp->qp_type == IB_QPT_RAW_ETH)) { + context->pri_path.sched_queue = (qp->port - 1) << 6; + if (is_qp0(dev, qp)) + context->pri_path.sched_queue |= MLX4_IB_DEFAULT_QP0_SCHED_QUEUE; + else + context->pri_path.sched_queue |= MLX4_IB_DEFAULT_SCHED_QUEUE; + } + + if (cur_state == IB_QPS_RTS && new_state == IB_QPS_SQD && + attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY && attr->en_sqd_async_notify) + sqd_event = 1; + else + sqd_event = 0; + + if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) + context->rlkey |= (1 << 4); + + /* + * Before passing a kernel QP to the HW, make sure that the + * ownership bits of the send queue are set and the SQ + * headroom is stamped so that the hardware doesn't start + * processing stale work requests. + */ + if (!ibqp->uobject && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { + struct mlx4_wqe_ctrl_seg *ctrl; + int i; + + for (i = 0; i < qp->sq.wqe_cnt; ++i) { + ctrl = get_send_wqe(qp, i); + ctrl->owner_opcode = cpu_to_be32(1 << 31); + if (qp->sq_max_wqes_per_wr == 1) + ctrl->fence_size = 1 << (qp->sq.wqe_shift - 4); + + stamp_send_wqe(qp, i, 1 << qp->sq.wqe_shift); + } + } + + err = mlx4_qp_modify(dev->dev, &qp->mtt, to_mlx4_state(cur_state), + to_mlx4_state(new_state), context, optpar, + sqd_event, &qp->mqp); + if (err) + goto out; + + qp->state = new_state; + + if (attr_mask & IB_QP_ACCESS_FLAGS) + qp->atomic_rd_en = attr->qp_access_flags; + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) + qp->resp_depth = attr->max_dest_rd_atomic; + if (attr_mask & IB_QP_PORT) { + qp->port = attr->port_num; + update_mcg_macs(dev, qp); + } + if (attr_mask & IB_QP_ALT_PATH) + qp->alt_port = attr->alt_port_num; + + if (is_sqp(dev, qp)) + store_sqp_attrs(to_msqp(qp), attr, attr_mask); + + /* + * If we moved QP0 to RTR, bring the IB link up; if we moved + * QP0 to RESET or ERROR, bring the link back down. + */ + if (is_qp0(dev, qp)) { + if (cur_state != IB_QPS_RTR && new_state == IB_QPS_RTR) + if (mlx4_INIT_PORT(dev->dev, qp->port)) + printk(KERN_WARNING "INIT_PORT failed for port %d\n", + qp->port); + + if (cur_state != IB_QPS_RESET && cur_state != IB_QPS_ERR && + (new_state == IB_QPS_RESET || new_state == IB_QPS_ERR)) + mlx4_CLOSE_PORT(dev->dev, qp->port); + } + + /* + * If we moved a kernel QP to RESET, clean up all old CQ + * entries and reinitialize the QP. + */ + if (new_state == IB_QPS_RESET && !ibqp->uobject) { + mlx4_ib_cq_clean(to_mcq(ibqp->recv_cq), qp->mqp.qpn, + ibqp->srq ? to_msrq(ibqp->srq): NULL); + if (ibqp->send_cq != ibqp->recv_cq) + mlx4_ib_cq_clean(to_mcq(ibqp->send_cq), qp->mqp.qpn, NULL); + + qp->rq.head = 0; + qp->rq.tail = 0; + qp->sq.head = 0; + qp->sq.tail = 0; + qp->sq_next_wqe = 0; + if (!ibqp->srq && ibqp->qp_type != IB_QPT_XRC) + *qp->db.db = 0; + } + +out: + kfree(context); + return err; +} + +int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(ibqp->device); + struct mlx4_ib_qp *qp = to_mqp(ibqp); + enum ib_qp_state cur_state, new_state; + int err = -EINVAL; + + mutex_lock(&qp->mutex); + + cur_state = attr_mask & IB_QP_CUR_STATE ? attr->cur_qp_state : qp->state; + new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state; + + if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask)) { + mlx4_ib_dbg("qpn 0x%x: invalid attribute mask specified " + "for transition %d to %d. qp_type %d, attr_mask 0x%x", + ibqp->qp_num, cur_state, new_state, + ibqp->qp_type, attr_mask); + goto out; + } + + if ((attr_mask & IB_QP_PORT) && (ibqp->qp_type != IB_QPT_RAW_ETH) && + (attr->port_num == 0 || attr->port_num > dev->num_ports)) { + mlx4_ib_dbg("qpn 0x%x: invalid port number (%d) specified " + "for transition %d to %d. qp_type %d", + ibqp->qp_num, attr->port_num, cur_state, + new_state, ibqp->qp_type); + goto out; + } + + if ((attr_mask & IB_QP_PORT) && (ibqp->qp_type == IB_QPT_RAW_ETH) && + (rdma_port_get_link_layer(&dev->ib_dev, attr->port_num) + != IB_LINK_LAYER_ETHERNET)) { + mlx4_ib_dbg("qpn 0x%x: invalid port (%d) specified (not RDMAoE)" + "for transition %d to %d. qp_type %d", + ibqp->qp_num, attr->port_num, cur_state, + new_state, ibqp->qp_type); + goto out; + } + + if (attr_mask & IB_QP_PKEY_INDEX) { + int p = attr_mask & IB_QP_PORT ? attr->port_num : qp->port; + if (attr->pkey_index >= dev->dev->caps.pkey_table_len[p]) { + mlx4_ib_dbg("qpn 0x%x: invalid pkey index (%d) specified " + "for transition %d to %d. qp_type %d", + ibqp->qp_num, attr->pkey_index, cur_state, + new_state, ibqp->qp_type); + goto out; + } + } + + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && + attr->max_rd_atomic > dev->dev->caps.max_qp_init_rdma) { + mlx4_ib_dbg("qpn 0x%x: max_rd_atomic (%d) too large. " + "Transition %d to %d. qp_type %d", + ibqp->qp_num, attr->max_rd_atomic, cur_state, + new_state, ibqp->qp_type); + goto out; + } + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && + attr->max_dest_rd_atomic > dev->dev->caps.max_qp_dest_rdma) { + mlx4_ib_dbg("qpn 0x%x: max_dest_rd_atomic (%d) too large. " + "Transition %d to %d. qp_type %d", + ibqp->qp_num, attr->max_dest_rd_atomic, cur_state, + new_state, ibqp->qp_type); + goto out; + } + + if (cur_state == new_state && cur_state == IB_QPS_RESET) { + err = 0; + goto out; + } + + err = __mlx4_ib_modify_qp(ibqp, attr, attr_mask, cur_state, new_state); + +out: + mutex_unlock(&qp->mutex); + return err; +} + +static int build_raw_ety_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, + void *wqe, unsigned *mlx_seg_len) +{ + int payload = 0; + int header_size, packet_length; + struct mlx4_wqe_mlx_seg *mlx = wqe; + struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx; + u32 *lrh = wqe + sizeof *mlx + sizeof *inl; + int i; + + /* Only IB_WR_SEND is supported */ + if (wr->opcode != IB_WR_SEND) + return -EINVAL; + + for (i = 0; i < wr->num_sge; ++i) + payload += wr->sg_list[i].length; + + header_size = IB_LRH_BYTES + 4; /* LRH + RAW_HEADER (32 bits) */ + + /* headers + payload and round up */ + packet_length = (header_size + payload + 3) / 4; + + mlx->flags &= cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE); + + mlx->flags |= cpu_to_be32(MLX4_WQE_MLX_ICRC | + (wr->wr.raw_ety.lrh->service_level << 8)); + + mlx->rlid = wr->wr.raw_ety.lrh->destination_lid; + + wr->wr.raw_ety.lrh->packet_length = cpu_to_be16(packet_length); + + ib_lrh_header_pack(wr->wr.raw_ety.lrh, lrh); + lrh += IB_LRH_BYTES / 4; /* LRH size is a dword multiple */ + *lrh = cpu_to_be32(wr->wr.raw_ety.eth_type); + + inl->byte_count = cpu_to_be32(1 << 31 | header_size); + + *mlx_seg_len = + ALIGN(sizeof(struct mlx4_wqe_inline_seg) + header_size, 16); + + return 0; +} + +static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, + void *wqe, unsigned *mlx_seg_len) +{ + struct ib_device *ib_dev = &to_mdev(sqp->qp.ibqp.device)->ib_dev; + struct mlx4_wqe_mlx_seg *mlx = wqe; + struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx; + struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah); + u16 pkey; + int send_size; + int header_size; + int spc; + int i; + union ib_gid sgid; + int is_eth; + int is_grh; + int is_vlan = 0; + int err; + u16 vlan; + + vlan = 0; + send_size = 0; + for (i = 0; i < wr->num_sge; ++i) + send_size += wr->sg_list[i].length; + + is_eth = rdma_port_get_link_layer(sqp->qp.ibqp.device, sqp->qp.port) == IB_LINK_LAYER_ETHERNET; + is_grh = mlx4_ib_ah_grh_present(ah); + err = ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.ib.port_pd) >> 24, + ah->av.ib.gid_index, &sgid); + if (err) + return err; + if (is_eth) { + is_vlan = rdma_get_vlan_id(&sgid) < 0x1000; + vlan = rdma_get_vlan_id(&sgid); + } + + ib_ud_header_init(send_size, !is_eth, is_eth, is_vlan, is_grh, 0, &sqp->ud_header); + if (!is_eth) { + sqp->ud_header.lrh.service_level = + be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28; + sqp->ud_header.lrh.destination_lid = ah->av.ib.dlid; + sqp->ud_header.lrh.source_lid = cpu_to_be16(ah->av.ib.g_slid & 0x7f); + } + + if (is_grh) { + sqp->ud_header.grh.traffic_class = + (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 20) & 0xff; + sqp->ud_header.grh.flow_label = + ah->av.ib.sl_tclass_flowlabel & cpu_to_be32(0xfffff); + sqp->ud_header.grh.hop_limit = ah->av.ib.hop_limit; + ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.ib.port_pd) >> 24, + ah->av.ib.gid_index, &sqp->ud_header.grh.source_gid); + memcpy(sqp->ud_header.grh.destination_gid.raw, + ah->av.ib.dgid, 16); + } + + mlx->flags &= cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE); + + if (!is_eth) { + mlx->flags |= cpu_to_be32((!sqp->qp.ibqp.qp_num ? MLX4_WQE_MLX_VL15 : 0) | + (sqp->ud_header.lrh.destination_lid == + IB_LID_PERMISSIVE ? MLX4_WQE_MLX_SLR : 0) | + (sqp->ud_header.lrh.service_level << 8)); + mlx->rlid = sqp->ud_header.lrh.destination_lid; + } + + switch (wr->opcode) { + case IB_WR_SEND: + sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY; + sqp->ud_header.immediate_present = 0; + break; + case IB_WR_SEND_WITH_IMM: + sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; + sqp->ud_header.immediate_present = 1; + sqp->ud_header.immediate_data = wr->ex.imm_data; + break; + default: + return -EINVAL; + } + + if (is_eth) { + u8 *smac; + + memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6); +#ifdef __linux__ + smac = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1]->dev_addr; /* fixme: cache this value */ +#else + smac = IF_LLADDR(to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1]); /* fixme: cache this value */ +#endif + memcpy(sqp->ud_header.eth.smac_h, smac, 6); + if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6)) + mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK); + if (!is_vlan) + sqp->ud_header.eth.type = cpu_to_be16(MLX4_IBOE_ETHERTYPE); + else { + u16 pcp; + + sqp->ud_header.vlan.type = cpu_to_be16(MLX4_IBOE_ETHERTYPE); + pcp = (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 27 & 3) << 13; + sqp->ud_header.vlan.tag = cpu_to_be16(vlan | pcp); + } + } else { + sqp->ud_header.lrh.virtual_lane = !sqp->qp.ibqp.qp_num ? 15 : 0; + if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE) + sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE; + } + sqp->ud_header.bth.solicited_event = !!(wr->send_flags & IB_SEND_SOLICITED); + if (!sqp->qp.ibqp.qp_num) + ib_get_cached_pkey(ib_dev, sqp->qp.port, sqp->pkey_index, &pkey); + else + ib_get_cached_pkey(ib_dev, sqp->qp.port, wr->wr.ud.pkey_index, &pkey); + sqp->ud_header.bth.pkey = cpu_to_be16(pkey); + sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->wr.ud.remote_qpn); + sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1)); + sqp->ud_header.deth.qkey = cpu_to_be32(wr->wr.ud.remote_qkey & 0x80000000 ? + sqp->qkey : wr->wr.ud.remote_qkey); + sqp->ud_header.deth.source_qpn = cpu_to_be32(sqp->qp.ibqp.qp_num); + + header_size = ib_ud_header_pack(&sqp->ud_header, sqp->header_buf); + + if (0) { + printk(KERN_ERR "built UD header of size %d:\n", header_size); + for (i = 0; i < header_size / 4; ++i) { + if (i % 8 == 0) + printk(" [%02x] ", i * 4); + printk(" %08x", + be32_to_cpu(((__be32 *) sqp->header_buf)[i])); + if ((i + 1) % 8 == 0) + printk("\n"); + } + printk("\n"); + } + + /* + * Inline data segments may not cross a 64 byte boundary. If + * our UD header is bigger than the space available up to the + * next 64 byte boundary in the WQE, use two inline data + * segments to hold the UD header. + */ + spc = MLX4_INLINE_ALIGN - + ((unsigned long) (inl + 1) & (MLX4_INLINE_ALIGN - 1)); + if (header_size <= spc) { + inl->byte_count = cpu_to_be32(1 << 31 | header_size); + memcpy(inl + 1, sqp->header_buf, header_size); + i = 1; + } else { + inl->byte_count = cpu_to_be32(1 << 31 | spc); + memcpy(inl + 1, sqp->header_buf, spc); + + inl = (void *) (inl + 1) + spc; + memcpy(inl + 1, sqp->header_buf + spc, header_size - spc); + /* + * Need a barrier here to make sure all the data is + * visible before the byte_count field is set. + * Otherwise the HCA prefetcher could grab the 64-byte + * chunk with this inline segment and get a valid (!= + * 0xffffffff) byte count but stale data, and end up + * generating a packet with bad headers. + * + * The first inline segment's byte_count field doesn't + * need a barrier, because it comes after a + * control/MLX segment and therefore is at an offset + * of 16 mod 64. + */ + wmb(); + inl->byte_count = cpu_to_be32(1 << 31 | (header_size - spc)); + i = 2; + } + + *mlx_seg_len = + ALIGN(i * sizeof (struct mlx4_wqe_inline_seg) + header_size, 16); + return 0; +} + +static int mlx4_wq_overflow(struct mlx4_ib_wq *wq, int nreq, struct ib_cq *ib_cq) +{ + unsigned cur; + struct mlx4_ib_cq *cq; + + cur = wq->head - wq->tail; + if (likely(cur + nreq < wq->max_post)) + return 0; + + cq = to_mcq(ib_cq); + spin_lock(&cq->lock); + cur = wq->head - wq->tail; + spin_unlock(&cq->lock); + + return cur + nreq >= wq->max_post; +} + +static __be32 convert_access(int acc) +{ + return (acc & IB_ACCESS_REMOTE_ATOMIC ? cpu_to_be32(MLX4_WQE_FMR_PERM_ATOMIC) : 0) | + (acc & IB_ACCESS_REMOTE_WRITE ? cpu_to_be32(MLX4_WQE_FMR_PERM_REMOTE_WRITE) : 0) | + (acc & IB_ACCESS_REMOTE_READ ? cpu_to_be32(MLX4_WQE_FMR_PERM_REMOTE_READ) : 0) | + (acc & IB_ACCESS_LOCAL_WRITE ? cpu_to_be32(MLX4_WQE_FMR_PERM_LOCAL_WRITE) : 0) | + cpu_to_be32(MLX4_WQE_FMR_PERM_LOCAL_READ); +} + +static void set_fmr_seg(struct mlx4_wqe_fmr_seg *fseg, struct ib_send_wr *wr) +{ + struct mlx4_ib_fast_reg_page_list *mfrpl = to_mfrpl(wr->wr.fast_reg.page_list); + int i; + + for (i = 0; i < wr->wr.fast_reg.page_list_len; ++i) + mfrpl->mapped_page_list[i] = + cpu_to_be64(wr->wr.fast_reg.page_list->page_list[i] | + MLX4_MTT_FLAG_PRESENT); + + fseg->flags = convert_access(wr->wr.fast_reg.access_flags); + fseg->mem_key = cpu_to_be32(wr->wr.fast_reg.rkey); + fseg->buf_list = cpu_to_be64(mfrpl->map); + fseg->start_addr = cpu_to_be64(wr->wr.fast_reg.iova_start); + fseg->reg_len = cpu_to_be64(wr->wr.fast_reg.length); + fseg->offset = 0; /* XXX -- is this just for ZBVA? */ + fseg->page_size = cpu_to_be32(wr->wr.fast_reg.page_shift); + fseg->reserved[0] = 0; + fseg->reserved[1] = 0; +} + +static void set_local_inv_seg(struct mlx4_wqe_local_inval_seg *iseg, u32 rkey) +{ + iseg->flags = 0; + iseg->mem_key = cpu_to_be32(rkey); + iseg->guest_id = 0; + iseg->pa = 0; +} + +static __always_inline void set_raddr_seg(struct mlx4_wqe_raddr_seg *rseg, + u64 remote_addr, u32 rkey) +{ + rseg->raddr = cpu_to_be64(remote_addr); + rseg->rkey = cpu_to_be32(rkey); + rseg->reserved = 0; +} + +static void set_atomic_seg(struct mlx4_wqe_atomic_seg *aseg, struct ib_send_wr *wr) +{ + if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) { + aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap); + aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add); + } else if (wr->opcode == IB_WR_MASKED_ATOMIC_FETCH_AND_ADD) { + aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add); + aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add_mask); + } else { + aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add); + aseg->compare = 0; + } + +} + +static void set_masked_atomic_seg(struct mlx4_wqe_masked_atomic_seg *aseg, + struct ib_send_wr *wr) +{ + aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap); + aseg->swap_add_mask = cpu_to_be64(wr->wr.atomic.swap_mask); + aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add); + aseg->compare_mask = cpu_to_be64(wr->wr.atomic.compare_add_mask); +} + +static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg, + struct ib_send_wr *wr, __be16 *vlan) +{ + memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av)); + dseg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn); + dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey); + dseg->vlan = to_mah(wr->wr.ud.ah)->av.eth.vlan; + memcpy(dseg->mac, to_mah(wr->wr.ud.ah)->av.eth.mac, 6); + *vlan = dseg->vlan; +} + +static void set_mlx_icrc_seg(void *dseg) +{ + u32 *t = dseg; + struct mlx4_wqe_inline_seg *iseg = dseg; + + t[1] = 0; + + /* + * Need a barrier here before writing the byte_count field to + * make sure that all the data is visible before the + * byte_count field is set. Otherwise, if the segment begins + * a new cacheline, the HCA prefetcher could grab the 64-byte + * chunk and get a valid (!= * 0xffffffff) byte count but + * stale data, and end up sending the wrong data. + */ + wmb(); + + iseg->byte_count = cpu_to_be32((1 << 31) | 4); +} + +static void set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg) +{ + dseg->lkey = cpu_to_be32(sg->lkey); + dseg->addr = cpu_to_be64(sg->addr); + + /* + * Need a barrier here before writing the byte_count field to + * make sure that all the data is visible before the + * byte_count field is set. Otherwise, if the segment begins + * a new cacheline, the HCA prefetcher could grab the 64-byte + * chunk and get a valid (!= * 0xffffffff) byte count but + * stale data, and end up sending the wrong data. + */ + wmb(); + + dseg->byte_count = cpu_to_be32(sg->length); +} + +static void __set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg) +{ + dseg->byte_count = cpu_to_be32(sg->length); + dseg->lkey = cpu_to_be32(sg->lkey); + dseg->addr = cpu_to_be64(sg->addr); +} + +static int build_lso_seg(struct mlx4_wqe_lso_seg *wqe, struct ib_send_wr *wr, + struct mlx4_ib_qp *qp, unsigned *lso_seg_len, + __be32 *lso_hdr_sz, int *blh) +{ + unsigned halign = ALIGN(sizeof *wqe + wr->wr.ud.hlen, 16); + + *blh = unlikely(halign > 64) ? 1 : 0; + + if (unlikely(!(qp->flags & MLX4_IB_QP_LSO) && + wr->num_sge > qp->sq.max_gs - (halign >> 4))) + return -EINVAL; + + memcpy(wqe->header, wr->wr.ud.header, wr->wr.ud.hlen); + + *lso_hdr_sz = cpu_to_be32((wr->wr.ud.mss - wr->wr.ud.hlen) << 16 | + wr->wr.ud.hlen); + *lso_seg_len = halign; + return 0; +} + +static __be32 send_ieth(struct ib_send_wr *wr) +{ + switch (wr->opcode) { + case IB_WR_SEND_WITH_IMM: + case IB_WR_RDMA_WRITE_WITH_IMM: + return wr->ex.imm_data; + + case IB_WR_SEND_WITH_INV: + return cpu_to_be32(wr->ex.invalidate_rkey); + + default: + return 0; + } +} + +static int lay_inline_data(struct mlx4_ib_qp *qp, struct ib_send_wr *wr, + void *wqe, int *sz) +{ + struct mlx4_wqe_inline_seg *seg; + void *addr; + int len, seg_len; + int num_seg; + int off, to_copy; + int i; + int inl = 0; + + seg = wqe; + wqe += sizeof *seg; + off = ((unsigned long)wqe) & (unsigned long)(MLX4_INLINE_ALIGN - 1); + num_seg = 0; + seg_len = 0; + + for (i = 0; i < wr->num_sge; ++i) { + addr = (void *) (unsigned long)(wr->sg_list[i].addr); + len = wr->sg_list[i].length; + inl += len; + + if (inl > qp->max_inline_data) { + inl = 0; + return -1; + } + + while (len >= MLX4_INLINE_ALIGN - off) { + to_copy = MLX4_INLINE_ALIGN - off; + memcpy(wqe, addr, to_copy); + len -= to_copy; + wqe += to_copy; + addr += to_copy; + seg_len += to_copy; + wmb(); /* see comment below */ + seg->byte_count = htonl(MLX4_INLINE_SEG | seg_len); + seg_len = 0; + seg = wqe; + wqe += sizeof *seg; + off = sizeof *seg; + ++num_seg; + } + + memcpy(wqe, addr, len); + wqe += len; + seg_len += len; + off += len; + } + + if (seg_len) { + ++num_seg; + /* + * Need a barrier here to make sure + * all the data is visible before the + * byte_count field is set. Otherwise + * the HCA prefetcher could grab the + * 64-byte chunk with this inline + * segment and get a valid (!= + * 0xffffffff) byte count but stale + * data, and end up sending the wrong + * data. + */ + wmb(); + seg->byte_count = htonl(MLX4_INLINE_SEG | seg_len); + } + + *sz = (inl + num_seg * sizeof *seg + 15) / 16; + + return 0; +} + +/* + * Avoid using memcpy() to copy to BlueFlame page, since memcpy() + * implementations may use move-string-buffer assembler instructions, + * which do not guarantee order of copying. + */ +static void mlx4_bf_copy(unsigned long *dst, unsigned long *src, unsigned bytecnt) +{ + __iowrite64_copy(dst, src, bytecnt / 8); +} + +int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr) +{ + struct mlx4_ib_qp *qp = to_mqp(ibqp); + void *wqe; + struct mlx4_wqe_ctrl_seg *ctrl; + struct mlx4_wqe_data_seg *dseg; + unsigned long flags; + int nreq; + int err = 0; + unsigned ind; + int uninitialized_var(stamp); + int uninitialized_var(size); + unsigned uninitialized_var(seglen); + __be32 dummy; + __be32 *lso_wqe; + __be32 uninitialized_var(lso_hdr_sz); + int i; + int blh = 0; + __be16 vlan = 0; + int inl = 0; + + ctrl = NULL; + spin_lock_irqsave(&qp->sq.lock, flags); + + ind = qp->sq_next_wqe; + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + lso_wqe = &dummy; + + if (mlx4_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) { + mlx4_ib_dbg("QP 0x%x: WQE overflow", ibqp->qp_num); + err = -ENOMEM; + *bad_wr = wr; + goto out; + } + + if (unlikely(wr->num_sge > qp->sq.max_gs)) { + mlx4_ib_dbg("QP 0x%x: too many sg entries (%d)", + ibqp->qp_num, wr->num_sge); + err = -EINVAL; + *bad_wr = wr; + goto out; + } + + ctrl = wqe = get_send_wqe(qp, ind & (qp->sq.wqe_cnt - 1)); + *((u32 *) (&ctrl->vlan_tag)) = 0; + qp->sq.wrid[(qp->sq.head + nreq) & (qp->sq.wqe_cnt - 1)] = wr->wr_id; + + ctrl->srcrb_flags = + (wr->send_flags & IB_SEND_SIGNALED ? + cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE) : 0) | + (wr->send_flags & IB_SEND_SOLICITED ? + cpu_to_be32(MLX4_WQE_CTRL_SOLICITED) : 0) | + ((wr->send_flags & IB_SEND_IP_CSUM) ? + cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM | + MLX4_WQE_CTRL_TCP_UDP_CSUM) : 0) | + qp->sq_signal_bits; + + ctrl->imm = send_ieth(wr); + + wqe += sizeof *ctrl; + size = sizeof *ctrl / 16; + + switch (ibqp->qp_type) { + case IB_QPT_XRC: + ctrl->srcrb_flags |= + cpu_to_be32(wr->xrc_remote_srq_num << 8); + /* fall thru */ + case IB_QPT_RC: + case IB_QPT_UC: + switch (wr->opcode) { + case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_ATOMIC_FETCH_AND_ADD: + case IB_WR_MASKED_ATOMIC_FETCH_AND_ADD: + set_raddr_seg(wqe, wr->wr.atomic.remote_addr, + wr->wr.atomic.rkey); + wqe += sizeof (struct mlx4_wqe_raddr_seg); + + set_atomic_seg(wqe, wr); + wqe += sizeof (struct mlx4_wqe_atomic_seg); + + size += (sizeof (struct mlx4_wqe_raddr_seg) + + sizeof (struct mlx4_wqe_atomic_seg)) / 16; + + break; + + case IB_WR_MASKED_ATOMIC_CMP_AND_SWP: + set_raddr_seg(wqe, wr->wr.atomic.remote_addr, + wr->wr.atomic.rkey); + wqe += sizeof (struct mlx4_wqe_raddr_seg); + + set_masked_atomic_seg(wqe, wr); + wqe += sizeof (struct mlx4_wqe_masked_atomic_seg); + + size += (sizeof (struct mlx4_wqe_raddr_seg) + + sizeof (struct mlx4_wqe_masked_atomic_seg)) / 16; + + break; + + case IB_WR_RDMA_READ: + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + set_raddr_seg(wqe, wr->wr.rdma.remote_addr, + wr->wr.rdma.rkey); + wqe += sizeof (struct mlx4_wqe_raddr_seg); + size += sizeof (struct mlx4_wqe_raddr_seg) / 16; + break; + + case IB_WR_LOCAL_INV: + ctrl->srcrb_flags |= + cpu_to_be32(MLX4_WQE_CTRL_STRONG_ORDER); + set_local_inv_seg(wqe, wr->ex.invalidate_rkey); + wqe += sizeof (struct mlx4_wqe_local_inval_seg); + size += sizeof (struct mlx4_wqe_local_inval_seg) / 16; + break; + + case IB_WR_FAST_REG_MR: + ctrl->srcrb_flags |= + cpu_to_be32(MLX4_WQE_CTRL_STRONG_ORDER); + set_fmr_seg(wqe, wr); + wqe += sizeof (struct mlx4_wqe_fmr_seg); + size += sizeof (struct mlx4_wqe_fmr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + break; + + case IB_QPT_UD: + set_datagram_seg(wqe, wr, &vlan); + wqe += sizeof (struct mlx4_wqe_datagram_seg); + size += sizeof (struct mlx4_wqe_datagram_seg) / 16; + + if (wr->opcode == IB_WR_LSO) { + err = build_lso_seg(wqe, wr, qp, &seglen, &lso_hdr_sz, &blh); + if (unlikely(err)) { + *bad_wr = wr; + goto out; + } + lso_wqe = (__be32 *) wqe; + wqe += seglen; + size += seglen / 16; + } + break; + + case IB_QPT_SMI: + case IB_QPT_GSI: + err = build_mlx_header(to_msqp(qp), wr, ctrl, &seglen); + if (unlikely(err)) { + *bad_wr = wr; + goto out; + } + wqe += seglen; + size += seglen / 16; + break; + + case IB_QPT_RAW_ETY: + err = build_raw_ety_header(to_msqp(qp), wr, ctrl, + &seglen); + if (unlikely(err)) { + *bad_wr = wr; + goto out; + } + wqe += seglen; + size += seglen / 16; + break; + + default: + break; + } + + /* + * Write data segments in reverse order, so as to + * overwrite cacheline stamp last within each + * cacheline. This avoids issues with WQE + * prefetching. + */ + + dseg = wqe; + dseg += wr->num_sge - 1; + + /* Add one more inline data segment for ICRC for MLX sends */ + if (unlikely(qp->ibqp.qp_type == IB_QPT_SMI || + qp->ibqp.qp_type == IB_QPT_GSI)) { + set_mlx_icrc_seg(dseg + 1); + size += sizeof (struct mlx4_wqe_data_seg) / 16; + } + + if (wr->send_flags & IB_SEND_INLINE && wr->num_sge) { + int sz; + err = lay_inline_data(qp, wr, wqe, &sz); + if (!err) { + inl = 1; + size += sz; + } + } else { + size += wr->num_sge * (sizeof (struct mlx4_wqe_data_seg) / 16); + for (i = wr->num_sge - 1; i >= 0; --i, --dseg) + set_data_seg(dseg, wr->sg_list + i); + } + + /* + * Possibly overwrite stamping in cacheline with LSO + * segment only after making sure all data segments + * are written. + */ + wmb(); + *lso_wqe = lso_hdr_sz; + + ctrl->fence_size = (wr->send_flags & IB_SEND_FENCE ? + MLX4_WQE_CTRL_FENCE : 0) | size; + + if (vlan) { + ctrl->ins_vlan = 1 << 6; + ctrl->vlan_tag = vlan; + } + + /* + * Make sure descriptor is fully written before + * setting ownership bit (because HW can start + * executing as soon as we do). + */ + wmb(); + + if (wr->opcode < 0 || wr->opcode >= ARRAY_SIZE(mlx4_ib_opcode)) { + err = -EINVAL; + goto out; + } + + ctrl->owner_opcode = mlx4_ib_opcode[wr->opcode] | + (ind & qp->sq.wqe_cnt ? cpu_to_be32(1 << 31) : 0) | + (blh ? cpu_to_be32(1 << 6) : 0); + + stamp = ind + qp->sq_spare_wqes; + ind += DIV_ROUND_UP(size * 16, 1U << qp->sq.wqe_shift); + + /* + * We can improve latency by not stamping the last + * send queue WQE until after ringing the doorbell, so + * only stamp here if there are still more WQEs to post. + * + * Same optimization applies to padding with NOP wqe + * in case of WQE shrinking (used to prevent wrap-around + * in the middle of WR). + */ + if (wr->next) { + stamp_send_wqe(qp, stamp, size * 16); + ind = pad_wraparound(qp, ind); + } + } + +out: + if (nreq == 1 && inl && size > 1 && size < qp->bf.buf_size / 16) { + ctrl->owner_opcode |= htonl((qp->sq_next_wqe & 0xffff) << 8); + *(u32 *) (&ctrl->vlan_tag) |= qp->doorbell_qpn; + /* + * Make sure that descriptor is written to memory + * before writing to BlueFlame page. + */ + wmb(); + + ++qp->sq.head; + + mlx4_bf_copy(qp->bf.reg + qp->bf.offset, (unsigned long *) ctrl, + ALIGN(size * 16, 64)); + wc_wmb(); + + qp->bf.offset ^= qp->bf.buf_size; + + } else if (nreq) { + qp->sq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + + writel(qp->doorbell_qpn, qp->bf.uar->map + MLX4_SEND_DOORBELL); + + /* + * Make sure doorbells don't leak out of SQ spinlock + * and reach the HCA out of order. + */ + mmiowb(); + + } + + if (likely(nreq)) { + stamp_send_wqe(qp, stamp, size * 16); + ind = pad_wraparound(qp, ind); + qp->sq_next_wqe = ind; + } + + spin_unlock_irqrestore(&qp->sq.lock, flags); + + return err; +} + +int mlx4_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr) +{ + struct mlx4_ib_qp *qp = to_mqp(ibqp); + struct mlx4_wqe_data_seg *scat; + unsigned long flags; + int err = 0; + int nreq; + int ind; + int i; + + spin_lock_irqsave(&qp->rq.lock, flags); + + ind = qp->rq.head & (qp->rq.wqe_cnt - 1); + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + if (mlx4_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) { + mlx4_ib_dbg("QP 0x%x: WQE overflow", ibqp->qp_num); + err = -ENOMEM; + *bad_wr = wr; + goto out; + } + + if (unlikely(wr->num_sge > qp->rq.max_gs)) { + mlx4_ib_dbg("QP 0x%x: too many sg entries (%d)", + ibqp->qp_num, wr->num_sge); + err = -EINVAL; + *bad_wr = wr; + goto out; + } + + scat = get_recv_wqe(qp, ind); + + for (i = 0; i < wr->num_sge; ++i) + __set_data_seg(scat + i, wr->sg_list + i); + + if (i < qp->rq.max_gs) { + scat[i].byte_count = 0; + scat[i].lkey = cpu_to_be32(MLX4_INVALID_LKEY); + scat[i].addr = 0; + } + + qp->rq.wrid[ind] = wr->wr_id; + + ind = (ind + 1) & (qp->rq.wqe_cnt - 1); + } + +out: + if (likely(nreq)) { + qp->rq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + + *qp->db.db = cpu_to_be32(qp->rq.head & 0xffff); + } + + spin_unlock_irqrestore(&qp->rq.lock, flags); + + return err; +} + +static inline enum ib_qp_state to_ib_qp_state(enum mlx4_qp_state mlx4_state) +{ + switch (mlx4_state) { + case MLX4_QP_STATE_RST: return IB_QPS_RESET; + case MLX4_QP_STATE_INIT: return IB_QPS_INIT; + case MLX4_QP_STATE_RTR: return IB_QPS_RTR; + case MLX4_QP_STATE_RTS: return IB_QPS_RTS; + case MLX4_QP_STATE_SQ_DRAINING: + case MLX4_QP_STATE_SQD: return IB_QPS_SQD; + case MLX4_QP_STATE_SQER: return IB_QPS_SQE; + case MLX4_QP_STATE_ERR: return IB_QPS_ERR; + default: return -1; + } +} + +static inline enum ib_mig_state to_ib_mig_state(int mlx4_mig_state) +{ + switch (mlx4_mig_state) { + case MLX4_QP_PM_ARMED: return IB_MIG_ARMED; + case MLX4_QP_PM_REARM: return IB_MIG_REARM; + case MLX4_QP_PM_MIGRATED: return IB_MIG_MIGRATED; + default: return -1; + } +} + +static int to_ib_qp_access_flags(int mlx4_flags) +{ + int ib_flags = 0; + + if (mlx4_flags & MLX4_QP_BIT_RRE) + ib_flags |= IB_ACCESS_REMOTE_READ; + if (mlx4_flags & MLX4_QP_BIT_RWE) + ib_flags |= IB_ACCESS_REMOTE_WRITE; + if (mlx4_flags & MLX4_QP_BIT_RAE) + ib_flags |= IB_ACCESS_REMOTE_ATOMIC; + + return ib_flags; +} + +static void to_ib_ah_attr(struct mlx4_ib_dev *ib_dev, struct ib_ah_attr *ib_ah_attr, + struct mlx4_qp_path *path) +{ + struct mlx4_dev *dev = ib_dev->dev; + int is_eth; + + memset(ib_ah_attr, 0, sizeof *ib_ah_attr); + ib_ah_attr->port_num = path->sched_queue & 0x40 ? 2 : 1; + + if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports) + return; + + is_eth = rdma_port_get_link_layer(&ib_dev->ib_dev, ib_ah_attr->port_num) == + IB_LINK_LAYER_ETHERNET; + if (is_eth) + ib_ah_attr->sl = ((path->sched_queue >> 3) & 0x7) | + ((path->sched_queue & 4) << 1); + else + ib_ah_attr->sl = (path->sched_queue >> 2) & 0xf; + + ib_ah_attr->dlid = be16_to_cpu(path->rlid); + + ib_ah_attr->src_path_bits = path->grh_mylmc & 0x7f; + ib_ah_attr->static_rate = path->static_rate ? path->static_rate - 5 : 0; + ib_ah_attr->ah_flags = (path->grh_mylmc & (1 << 7)) ? IB_AH_GRH : 0; + if (ib_ah_attr->ah_flags) { + ib_ah_attr->grh.sgid_index = path->mgid_index; + ib_ah_attr->grh.hop_limit = path->hop_limit; + ib_ah_attr->grh.traffic_class = + (be32_to_cpu(path->tclass_flowlabel) >> 20) & 0xff; + ib_ah_attr->grh.flow_label = + be32_to_cpu(path->tclass_flowlabel) & 0xfffff; + memcpy(ib_ah_attr->grh.dgid.raw, + path->rgid, sizeof ib_ah_attr->grh.dgid.raw); + } +} + +int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr) +{ + struct mlx4_ib_dev *dev = to_mdev(ibqp->device); + struct mlx4_ib_qp *qp = to_mqp(ibqp); + struct mlx4_qp_context context; + int mlx4_state; + int err = 0; + + mutex_lock(&qp->mutex); + + if (qp->state == IB_QPS_RESET) { + qp_attr->qp_state = IB_QPS_RESET; + goto done; + } + + err = mlx4_qp_query(dev->dev, &qp->mqp, &context); + if (err) { + err = -EINVAL; + goto out; + } + + mlx4_state = be32_to_cpu(context.flags) >> 28; + + qp->state = to_ib_qp_state(mlx4_state); + qp_attr->qp_state = qp->state; + qp_attr->path_mtu = context.mtu_msgmax >> 5; + qp_attr->path_mig_state = + to_ib_mig_state((be32_to_cpu(context.flags) >> 11) & 0x3); + qp_attr->qkey = be32_to_cpu(context.qkey); + qp_attr->rq_psn = be32_to_cpu(context.rnr_nextrecvpsn) & 0xffffff; + qp_attr->sq_psn = be32_to_cpu(context.next_send_psn) & 0xffffff; + qp_attr->dest_qp_num = be32_to_cpu(context.remote_qpn) & 0xffffff; + qp_attr->qp_access_flags = + to_ib_qp_access_flags(be32_to_cpu(context.params2)); + + if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC || + qp->ibqp.qp_type == IB_QPT_XRC) { + to_ib_ah_attr(dev, &qp_attr->ah_attr, &context.pri_path); + to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context.alt_path); + qp_attr->alt_pkey_index = context.alt_path.pkey_index & 0x7f; + qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num; + } + + qp_attr->pkey_index = context.pri_path.pkey_index & 0x7f; + if (qp_attr->qp_state == IB_QPS_INIT) + qp_attr->port_num = qp->port; + else + qp_attr->port_num = context.pri_path.sched_queue & 0x40 ? 2 : 1; + + /* qp_attr->en_sqd_async_notify is only applicable in modify qp */ + qp_attr->sq_draining = mlx4_state == MLX4_QP_STATE_SQ_DRAINING; + + qp_attr->max_rd_atomic = 1 << ((be32_to_cpu(context.params1) >> 21) & 0x7); + + qp_attr->max_dest_rd_atomic = + 1 << ((be32_to_cpu(context.params2) >> 21) & 0x7); + qp_attr->min_rnr_timer = + (be32_to_cpu(context.rnr_nextrecvpsn) >> 24) & 0x1f; + qp_attr->timeout = context.pri_path.ackto >> 3; + qp_attr->retry_cnt = (be32_to_cpu(context.params1) >> 16) & 0x7; + qp_attr->rnr_retry = (be32_to_cpu(context.params1) >> 13) & 0x7; + qp_attr->alt_timeout = context.alt_path.ackto >> 3; + +done: + qp_attr->cur_qp_state = qp_attr->qp_state; + qp_attr->cap.max_recv_wr = qp->rq.wqe_cnt; + qp_attr->cap.max_recv_sge = qp->rq.max_gs; + + if (!ibqp->uobject) { + qp_attr->cap.max_send_wr = qp->sq.wqe_cnt; + qp_attr->cap.max_send_sge = qp->sq.max_gs; + } else { + qp_attr->cap.max_send_wr = 0; + qp_attr->cap.max_send_sge = 0; + } + + /* + * We don't support inline sends for kernel QPs (yet), and we + * don't know what userspace's value should be. + */ + qp_attr->cap.max_inline_data = 0; + + qp_init_attr->cap = qp_attr->cap; + + qp_init_attr->create_flags = 0; + if (qp->flags & MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK) + qp_init_attr->create_flags |= IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK; + + if (qp->flags & MLX4_IB_QP_LSO) + qp_init_attr->create_flags |= IB_QP_CREATE_IPOIB_UD_LSO; + +out: + mutex_unlock(&qp->mutex); + return err; +} + +int mlx4_ib_create_xrc_rcv_qp(struct ib_qp_init_attr *init_attr, + u32 *qp_num) +{ + struct mlx4_ib_dev *dev = to_mdev(init_attr->xrc_domain->device); + struct mlx4_ib_xrcd *xrcd = to_mxrcd(init_attr->xrc_domain); + struct mlx4_ib_qp *qp; + struct ib_qp *ibqp; + struct mlx4_ib_xrc_reg_entry *ctx_entry; + unsigned long flags; + int err; + + if (!(dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC)) + return -ENOSYS; + + if (init_attr->qp_type != IB_QPT_XRC) + return -EINVAL; + + ctx_entry = kmalloc(sizeof *ctx_entry, GFP_KERNEL); + if (!ctx_entry) + return -ENOMEM; + + qp = kzalloc(sizeof *qp, GFP_KERNEL); + if (!qp) { + kfree(ctx_entry); + return -ENOMEM; + } + mutex_lock(&dev->xrc_reg_mutex); + qp->flags = MLX4_IB_XRC_RCV; + qp->xrcdn = to_mxrcd(init_attr->xrc_domain)->xrcdn; + INIT_LIST_HEAD(&qp->xrc_reg_list); + err = create_qp_common(dev, xrcd->pd, init_attr, NULL, 0, qp); + if (err) { + mutex_unlock(&dev->xrc_reg_mutex); + kfree(ctx_entry); + kfree(qp); + return err; + } + + ibqp = &qp->ibqp; + /* set the ibpq attributes which will be used by the mlx4 module */ + ibqp->qp_num = qp->mqp.qpn; + ibqp->device = init_attr->xrc_domain->device; + ibqp->pd = xrcd->pd; + ibqp->send_cq = ibqp->recv_cq = xrcd->cq; + ibqp->event_handler = init_attr->event_handler; + ibqp->qp_context = init_attr->qp_context; + ibqp->qp_type = init_attr->qp_type; + ibqp->xrcd = init_attr->xrc_domain; + + mutex_lock(&qp->mutex); + ctx_entry->context = init_attr->qp_context; + spin_lock_irqsave(&qp->xrc_reg_list_lock, flags); + list_add_tail(&ctx_entry->list, &qp->xrc_reg_list); + spin_unlock_irqrestore(&qp->xrc_reg_list_lock, flags); + mutex_unlock(&qp->mutex); + mutex_unlock(&dev->xrc_reg_mutex); + *qp_num = qp->mqp.qpn; + return 0; +} + +int mlx4_ib_modify_xrc_rcv_qp(struct ib_xrcd *ibxrcd, u32 qp_num, + struct ib_qp_attr *attr, int attr_mask) +{ + struct mlx4_ib_dev *dev = to_mdev(ibxrcd->device); + struct mlx4_ib_xrcd *xrcd = to_mxrcd(ibxrcd); + struct mlx4_qp *mqp; + struct mlx4_ib_qp *mibqp; + int err = -EINVAL; + + if (!(dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC)) + return -ENOSYS; + + mutex_lock(&dev->xrc_reg_mutex); + mqp = mlx4_qp_lookup_lock(dev->dev, qp_num); + if (unlikely(!mqp)) { + printk(KERN_WARNING "mlx4_ib_reg_xrc_rcv_qp: " + "unknown QPN %06x\n", qp_num); + goto err_out; + } + + mibqp = to_mibqp(mqp); + + if (!(mibqp->flags & MLX4_IB_XRC_RCV) || !mibqp->ibqp.xrcd || + xrcd->xrcdn != to_mxrcd(mibqp->ibqp.xrcd)->xrcdn) + goto err_out; + + err = mlx4_ib_modify_qp(&mibqp->ibqp, attr, attr_mask, NULL); + mutex_unlock(&dev->xrc_reg_mutex); + return err; + +err_out: + mutex_unlock(&dev->xrc_reg_mutex); + return err; +} + +int mlx4_ib_query_xrc_rcv_qp(struct ib_xrcd *ibxrcd, u32 qp_num, + struct ib_qp_attr *qp_attr, int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr) +{ + struct mlx4_ib_dev *dev = to_mdev(ibxrcd->device); + struct mlx4_ib_xrcd *xrcd = to_mxrcd(ibxrcd); + struct mlx4_ib_qp *qp; + struct mlx4_qp *mqp; + struct mlx4_qp_context context; + int mlx4_state; + int err = -EINVAL; + + if (!(dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC)) + return -ENOSYS; + + mutex_lock(&dev->xrc_reg_mutex); + mqp = mlx4_qp_lookup_lock(dev->dev, qp_num); + if (unlikely(!mqp)) { + printk(KERN_WARNING "mlx4_ib_reg_xrc_rcv_qp: " + "unknown QPN %06x\n", qp_num); + goto err_out; + } + + qp = to_mibqp(mqp); + if (!(qp->flags & MLX4_IB_XRC_RCV) || !(qp->ibqp.xrcd) || + xrcd->xrcdn != to_mxrcd(qp->ibqp.xrcd)->xrcdn) + goto err_out; + + if (qp->state == IB_QPS_RESET) { + qp_attr->qp_state = IB_QPS_RESET; + goto done; + } + + err = mlx4_qp_query(dev->dev, mqp, &context); + if (err) + goto err_out; + + mlx4_state = be32_to_cpu(context.flags) >> 28; + + qp_attr->qp_state = to_ib_qp_state(mlx4_state); + qp_attr->path_mtu = context.mtu_msgmax >> 5; + qp_attr->path_mig_state = + to_ib_mig_state((be32_to_cpu(context.flags) >> 11) & 0x3); + qp_attr->qkey = be32_to_cpu(context.qkey); + qp_attr->rq_psn = be32_to_cpu(context.rnr_nextrecvpsn) & 0xffffff; + qp_attr->sq_psn = be32_to_cpu(context.next_send_psn) & 0xffffff; + qp_attr->dest_qp_num = be32_to_cpu(context.remote_qpn) & 0xffffff; + qp_attr->qp_access_flags = + to_ib_qp_access_flags(be32_to_cpu(context.params2)); + + if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC || + qp->ibqp.qp_type == IB_QPT_XRC) { + to_ib_ah_attr(dev, &qp_attr->ah_attr, &context.pri_path); + to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, + &context.alt_path); + qp_attr->alt_pkey_index = context.alt_path.pkey_index & 0x7f; + qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num; + } + + qp_attr->pkey_index = context.pri_path.pkey_index & 0x7f; + if (qp_attr->qp_state == IB_QPS_INIT) + qp_attr->port_num = qp->port; + else + qp_attr->port_num = context.pri_path.sched_queue & 0x40 ? 2 : 1; + + /* qp_attr->en_sqd_async_notify is only applicable in modify qp */ + qp_attr->sq_draining = mlx4_state == MLX4_QP_STATE_SQ_DRAINING; + + qp_attr->max_rd_atomic = + 1 << ((be32_to_cpu(context.params1) >> 21) & 0x7); + + qp_attr->max_dest_rd_atomic = + 1 << ((be32_to_cpu(context.params2) >> 21) & 0x7); + qp_attr->min_rnr_timer = + (be32_to_cpu(context.rnr_nextrecvpsn) >> 24) & 0x1f; + qp_attr->timeout = context.pri_path.ackto >> 3; + qp_attr->retry_cnt = (be32_to_cpu(context.params1) >> 16) & 0x7; + qp_attr->rnr_retry = (be32_to_cpu(context.params1) >> 13) & 0x7; + qp_attr->alt_timeout = context.alt_path.ackto >> 3; + +done: + qp_attr->cur_qp_state = qp_attr->qp_state; + qp_attr->cap.max_recv_wr = 0; + qp_attr->cap.max_recv_sge = 0; + qp_attr->cap.max_send_wr = 0; + qp_attr->cap.max_send_sge = 0; + qp_attr->cap.max_inline_data = 0; + qp_init_attr->cap = qp_attr->cap; + + mutex_unlock(&dev->xrc_reg_mutex); + return 0; + +err_out: + mutex_unlock(&dev->xrc_reg_mutex); + return err; +} + +int mlx4_ib_reg_xrc_rcv_qp(struct ib_xrcd *xrcd, void *context, u32 qp_num) +{ + + struct mlx4_ib_xrcd *mxrcd = to_mxrcd(xrcd); + + struct mlx4_qp *mqp; + struct mlx4_ib_qp *mibqp; + struct mlx4_ib_xrc_reg_entry *ctx_entry, *tmp; + unsigned long flags; + int err = -EINVAL; + + mutex_lock(&to_mdev(xrcd->device)->xrc_reg_mutex); + mqp = mlx4_qp_lookup_lock(to_mdev(xrcd->device)->dev, qp_num); + if (unlikely(!mqp)) { + printk(KERN_WARNING "mlx4_ib_reg_xrc_rcv_qp: " + "unknown QPN %06x\n", qp_num); + goto err_out; + } + + mibqp = to_mibqp(mqp); + + if (!(mibqp->flags & MLX4_IB_XRC_RCV) || !(mibqp->ibqp.xrcd) || + mxrcd->xrcdn != to_mxrcd(mibqp->ibqp.xrcd)->xrcdn) + goto err_out; + + ctx_entry = kmalloc(sizeof *ctx_entry, GFP_KERNEL); + if (!ctx_entry) { + err = -ENOMEM; + goto err_out; + } + + mutex_lock(&mibqp->mutex); + list_for_each_entry(tmp, &mibqp->xrc_reg_list, list) + if (tmp->context == context) { + mutex_unlock(&mibqp->mutex); + kfree(ctx_entry); + mutex_unlock(&to_mdev(xrcd->device)->xrc_reg_mutex); + return 0; + } + + ctx_entry->context = context; + spin_lock_irqsave(&mibqp->xrc_reg_list_lock, flags); + list_add_tail(&ctx_entry->list, &mibqp->xrc_reg_list); + spin_unlock_irqrestore(&mibqp->xrc_reg_list_lock, flags); + mutex_unlock(&mibqp->mutex); + mutex_unlock(&to_mdev(xrcd->device)->xrc_reg_mutex); + return 0; + +err_out: + mutex_unlock(&to_mdev(xrcd->device)->xrc_reg_mutex); + return err; +} + +int mlx4_ib_unreg_xrc_rcv_qp(struct ib_xrcd *xrcd, void *context, u32 qp_num) +{ + + struct mlx4_ib_xrcd *mxrcd = to_mxrcd(xrcd); + + struct mlx4_qp *mqp; + struct mlx4_ib_qp *mibqp; + struct mlx4_ib_xrc_reg_entry *ctx_entry, *tmp; + unsigned long flags; + int found = 0; + int err = -EINVAL; + + mutex_lock(&to_mdev(xrcd->device)->xrc_reg_mutex); + mqp = mlx4_qp_lookup_lock(to_mdev(xrcd->device)->dev, qp_num); + if (unlikely(!mqp)) { + printk(KERN_WARNING "mlx4_ib_unreg_xrc_rcv_qp: " + "unknown QPN %06x\n", qp_num); + goto err_out; + } + + mibqp = to_mibqp(mqp); + + if (!(mibqp->flags & MLX4_IB_XRC_RCV) || + mxrcd->xrcdn != (mibqp->xrcdn & 0xffff)) + goto err_out; + + mutex_lock(&mibqp->mutex); + spin_lock_irqsave(&mibqp->xrc_reg_list_lock, flags); + list_for_each_entry_safe(ctx_entry, tmp, &mibqp->xrc_reg_list, list) + if (ctx_entry->context == context) { + found = 1; + list_del(&ctx_entry->list); + spin_unlock_irqrestore(&mibqp->xrc_reg_list_lock, flags); + kfree(ctx_entry); + break; + } + + if (!found) + spin_unlock_irqrestore(&mibqp->xrc_reg_list_lock, flags); + mutex_unlock(&mibqp->mutex); + if (!found) + goto err_out; + + /* destroy the QP if the registration list is empty */ + if (list_empty(&mibqp->xrc_reg_list)) + mlx4_ib_destroy_qp(&mibqp->ibqp); + + mutex_unlock(&to_mdev(xrcd->device)->xrc_reg_mutex); + return 0; + +err_out: + mutex_unlock(&to_mdev(xrcd->device)->xrc_reg_mutex); + return err; +} + diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/srq.c b/sys/ofed/drivers/infiniband/hw/mlx4/srq.c new file mode 100644 index 000000000000..90918c778d63 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mlx4/srq.c @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "mlx4_ib.h" +#include "user.h" + +static void *get_wqe(struct mlx4_ib_srq *srq, int n) +{ + return mlx4_buf_offset(&srq->buf, n << srq->msrq.wqe_shift); +} + +static void mlx4_ib_srq_event(struct mlx4_srq *srq, enum mlx4_event type) +{ + struct ib_event event; + struct ib_srq *ibsrq = &to_mibsrq(srq)->ibsrq; + + if (ibsrq->event_handler) { + event.device = ibsrq->device; + event.element.srq = ibsrq; + switch (type) { + case MLX4_EVENT_TYPE_SRQ_LIMIT: + event.event = IB_EVENT_SRQ_LIMIT_REACHED; + break; + case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR: + event.event = IB_EVENT_SRQ_ERR; + break; + default: + printk(KERN_WARNING "mlx4_ib: Unexpected event type %d " + "on SRQ %06x\n", type, srq->srqn); + return; + } + + ibsrq->event_handler(&event, ibsrq->srq_context); + } +} + +struct ib_srq *mlx4_ib_create_xrc_srq(struct ib_pd *pd, + struct ib_cq *xrc_cq, + struct ib_xrcd *xrcd, + struct ib_srq_init_attr *init_attr, + struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(pd->device); + struct mlx4_ib_srq *srq; + struct mlx4_wqe_srq_next_seg *next; + u32 cqn; + u16 xrcdn; + int desc_size; + int buf_size; + int err; + int i; + + /* Sanity check SRQ size before proceeding */ + if (init_attr->attr.max_wr >= dev->dev->caps.max_srq_wqes || + init_attr->attr.max_sge > dev->dev->caps.max_srq_sge) { + mlx4_ib_dbg("a size param is out of range. " + "max_wr = 0x%x, max_sge = 0x%x", + init_attr->attr.max_wr, init_attr->attr.max_sge); + return ERR_PTR(-EINVAL); + } + + srq = kzalloc(sizeof *srq, GFP_KERNEL); + if (!srq) + return ERR_PTR(-ENOMEM); + + mutex_init(&srq->mutex); + spin_lock_init(&srq->lock); + srq->msrq.max = roundup_pow_of_two(init_attr->attr.max_wr + 1); + srq->msrq.max_gs = init_attr->attr.max_sge; + + desc_size = max(32UL, + roundup_pow_of_two(sizeof (struct mlx4_wqe_srq_next_seg) + + srq->msrq.max_gs * + sizeof (struct mlx4_wqe_data_seg))); + srq->msrq.wqe_shift = ilog2(desc_size); + + buf_size = srq->msrq.max * desc_size; + + if (pd->uobject) { + struct mlx4_ib_create_srq ucmd; + + if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) { + err = -EFAULT; + goto err_srq; + } + + srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, + buf_size, 0, 0); + if (IS_ERR(srq->umem)) { + err = PTR_ERR(srq->umem); + goto err_srq; + } + + err = mlx4_mtt_init(dev->dev, ib_umem_page_count(srq->umem), + ilog2(srq->umem->page_size), &srq->mtt); + if (err) + goto err_buf; + + err = mlx4_ib_umem_write_mtt(dev, &srq->mtt, srq->umem); + if (err) + goto err_mtt; + + err = mlx4_ib_db_map_user(to_mucontext(pd->uobject->context), + ucmd.db_addr, &srq->db); + if (err) + goto err_mtt; + } else { + struct mlx4_wqe_data_seg *scatter; + + err = mlx4_db_alloc(dev->dev, &srq->db, 0); + if (err) + goto err_srq; + + *srq->db.db = 0; + + if (mlx4_buf_alloc(dev->dev, buf_size, PAGE_SIZE * 2, &srq->buf)) { + err = -ENOMEM; + goto err_db; + } + + srq->head = 0; + srq->tail = srq->msrq.max - 1; + srq->wqe_ctr = 0; + + for (i = 0; i < srq->msrq.max; ++i) { + next = get_wqe(srq, i); + next->next_wqe_index = + cpu_to_be16((i + 1) & (srq->msrq.max - 1)); + + for (scatter = (void *) (next + 1); + (void *) scatter < (void *) next + desc_size; + ++scatter) + scatter->lkey = cpu_to_be32(MLX4_INVALID_LKEY); + } + + err = mlx4_mtt_init(dev->dev, srq->buf.npages, srq->buf.page_shift, + &srq->mtt); + if (err) + goto err_buf; + + err = mlx4_buf_write_mtt(dev->dev, &srq->mtt, &srq->buf); + if (err) + goto err_mtt; + + srq->wrid = kmalloc(srq->msrq.max * sizeof (u64), GFP_KERNEL); + if (!srq->wrid) { + err = -ENOMEM; + goto err_mtt; + } + } + + cqn = xrc_cq ? (u32) (to_mcq(xrc_cq)->mcq.cqn) : 0; + xrcdn = xrcd ? (u16) (to_mxrcd(xrcd)->xrcdn) : + (u16) dev->dev->caps.reserved_xrcds; + + err = mlx4_srq_alloc(dev->dev, to_mpd(pd)->pdn, cqn, xrcdn, &srq->mtt, + srq->db.dma, &srq->msrq); + if (err) + goto err_wrid; + + srq->msrq.event = mlx4_ib_srq_event; + + if (pd->uobject) { + if (ib_copy_to_udata(udata, &srq->msrq.srqn, sizeof (__u32))) { + err = -EFAULT; + goto err_wrid; + } + } else + srq->ibsrq.xrc_srq_num = srq->msrq.srqn; + + init_attr->attr.max_wr = srq->msrq.max - 1; + + return &srq->ibsrq; + +err_wrid: + if (pd->uobject) + mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &srq->db); + else + kfree(srq->wrid); + +err_mtt: + mlx4_mtt_cleanup(dev->dev, &srq->mtt); + +err_buf: + if (pd->uobject) + ib_umem_release(srq->umem); + else + mlx4_buf_free(dev->dev, buf_size, &srq->buf); + +err_db: + if (!pd->uobject) + mlx4_db_free(dev->dev, &srq->db); + +err_srq: + kfree(srq); + + return ERR_PTR(err); +} + +int mlx4_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, + enum ib_srq_attr_mask attr_mask, struct ib_udata *udata) +{ + struct mlx4_ib_dev *dev = to_mdev(ibsrq->device); + struct mlx4_ib_srq *srq = to_msrq(ibsrq); + int ret; + + /* We don't support resizing SRQs (yet?) */ + if (attr_mask & IB_SRQ_MAX_WR) { + mlx4_ib_dbg("resize not yet supported"); + return -EINVAL; + } + + if (attr_mask & IB_SRQ_LIMIT) { + if (attr->srq_limit >= srq->msrq.max){ + mlx4_ib_dbg("limit (0x%x) too high", attr->srq_limit); + return -EINVAL; + } + + mutex_lock(&srq->mutex); + ret = mlx4_srq_arm(dev->dev, &srq->msrq, attr->srq_limit); + mutex_unlock(&srq->mutex); + + if (ret) + return ret; + } + + return 0; +} + +struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd, + struct ib_srq_init_attr *init_attr, + struct ib_udata *udata) +{ + return mlx4_ib_create_xrc_srq(pd, NULL, NULL, init_attr, udata); +} + +int mlx4_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) +{ + struct mlx4_ib_dev *dev = to_mdev(ibsrq->device); + struct mlx4_ib_srq *srq = to_msrq(ibsrq); + int ret; + int limit_watermark; + + ret = mlx4_srq_query(dev->dev, &srq->msrq, &limit_watermark); + if (ret) + return ret; + + srq_attr->srq_limit = limit_watermark; + srq_attr->max_wr = srq->msrq.max - 1; + srq_attr->max_sge = srq->msrq.max_gs; + + return 0; +} + +int mlx4_ib_destroy_srq(struct ib_srq *srq) +{ + struct mlx4_ib_dev *dev = to_mdev(srq->device); + struct mlx4_ib_srq *msrq = to_msrq(srq); + struct mlx4_ib_cq *cq; + + mlx4_srq_invalidate(dev->dev, &msrq->msrq); + + if (srq->xrc_cq && !srq->uobject) { + cq = to_mcq(srq->xrc_cq); + spin_lock_irq(&cq->lock); + __mlx4_ib_cq_clean(cq, -1, msrq); + mlx4_srq_remove(dev->dev, &msrq->msrq); + spin_unlock_irq(&cq->lock); + } else + mlx4_srq_remove(dev->dev, &msrq->msrq); + + mlx4_srq_free(dev->dev, &msrq->msrq); + mlx4_mtt_cleanup(dev->dev, &msrq->mtt); + + if (srq->uobject) { + mlx4_ib_db_unmap_user(to_mucontext(srq->uobject->context), &msrq->db); + ib_umem_release(msrq->umem); + } else { + kfree(msrq->wrid); + mlx4_buf_free(dev->dev, msrq->msrq.max << msrq->msrq.wqe_shift, + &msrq->buf); + mlx4_db_free(dev->dev, &msrq->db); + } + + kfree(msrq); + + return 0; +} + +void mlx4_ib_free_srq_wqe(struct mlx4_ib_srq *srq, int wqe_index) +{ + struct mlx4_wqe_srq_next_seg *next; + + /* always called with interrupts disabled. */ + spin_lock(&srq->lock); + + next = get_wqe(srq, srq->tail); + next->next_wqe_index = cpu_to_be16(wqe_index); + srq->tail = wqe_index; + + spin_unlock(&srq->lock); +} + +int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr) +{ + struct mlx4_ib_srq *srq = to_msrq(ibsrq); + struct mlx4_wqe_srq_next_seg *next; + struct mlx4_wqe_data_seg *scat; + unsigned long flags; + int err = 0; + int nreq; + int i; + + spin_lock_irqsave(&srq->lock, flags); + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + if (unlikely(wr->num_sge > srq->msrq.max_gs)) { + mlx4_ib_dbg("srq num 0x%x: num s/g entries too large (%d)", + srq->msrq.srqn, wr->num_sge); + err = -EINVAL; + *bad_wr = wr; + break; + } + + if (unlikely(srq->head == srq->tail)) { + mlx4_ib_dbg("srq num 0x%x: No entries available to post.", + srq->msrq.srqn); + err = -ENOMEM; + *bad_wr = wr; + break; + } + + srq->wrid[srq->head] = wr->wr_id; + + next = get_wqe(srq, srq->head); + srq->head = be16_to_cpu(next->next_wqe_index); + scat = (struct mlx4_wqe_data_seg *) (next + 1); + + for (i = 0; i < wr->num_sge; ++i) { + scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length); + scat[i].lkey = cpu_to_be32(wr->sg_list[i].lkey); + scat[i].addr = cpu_to_be64(wr->sg_list[i].addr); + } + + if (i < srq->msrq.max_gs) { + scat[i].byte_count = 0; + scat[i].lkey = cpu_to_be32(MLX4_INVALID_LKEY); + scat[i].addr = 0; + } + } + + if (likely(nreq)) { + srq->wqe_ctr += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + + *srq->db.db = cpu_to_be32(srq->wqe_ctr); + } + + spin_unlock_irqrestore(&srq->lock, flags); + + return err; +} diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/user.h b/sys/ofed/drivers/infiniband/hw/mlx4/user.h new file mode 100644 index 000000000000..13beedeeef9f --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mlx4/user.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_IB_USER_H +#define MLX4_IB_USER_H + +#include + +/* + * Increment this value if any changes that break userspace ABI + * compatibility are made. + */ +#define MLX4_IB_UVERBS_ABI_VERSION 3 + +/* + * Make sure that all structs defined in this file remain laid out so + * that they pack the same way on 32-bit and 64-bit architectures (to + * avoid incompatibility between 32-bit userspace and 64-bit kernels). + * In particular do not use pointer types -- pass pointers in __u64 + * instead. + */ + +struct mlx4_ib_alloc_ucontext_resp { + __u32 qp_tab_size; + __u16 bf_reg_size; + __u16 bf_regs_per_page; +}; + +struct mlx4_ib_alloc_pd_resp { + __u32 pdn; + __u32 reserved; +}; + +struct mlx4_ib_create_cq { + __u64 buf_addr; + __u64 db_addr; +}; + +struct mlx4_ib_create_cq_resp { + __u32 cqn; + __u32 reserved; +}; + +struct mlx4_ib_resize_cq { + __u64 buf_addr; +}; + +struct mlx4_ib_create_srq { + __u64 buf_addr; + __u64 db_addr; +}; + +struct mlx4_ib_create_srq_resp { + __u32 srqn; + __u32 reserved; +}; + +struct mlx4_ib_create_qp { + __u64 buf_addr; + __u64 db_addr; + __u8 log_sq_bb_count; + __u8 log_sq_stride; + __u8 sq_no_prefetch; + __u8 reserved[5]; +}; + +#endif /* MLX4_IB_USER_H */ diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/wc.c b/sys/ofed/drivers/infiniband/hw/mlx4/wc.c new file mode 100644 index 000000000000..827de14a068c --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mlx4/wc.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2006-2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "wc.h" + +#if defined(__i386__) || defined(__x86_64__) + +pgprot_t pgprot_wc(pgprot_t _prot) +{ + return pgprot_writecombine(_prot); +} + +int mlx4_wc_enabled(void) +{ + return 1; +} + +#elif defined(CONFIG_PPC64) + +pgprot_t pgprot_wc(pgprot_t _prot) +{ + return __pgprot((pgprot_val(_prot) | _PAGE_NO_CACHE) & + ~(pgprot_t)_PAGE_GUARDED); +} + +int mlx4_wc_enabled(void) +{ + return 1; +} + +#else /* !(defined(__i386__) || defined(__x86_64__)) */ + +pgprot_t pgprot_wc(pgprot_t _prot) +{ + return pgprot_noncached(_prot); +} + +int mlx4_wc_enabled(void) +{ + return 0; +} + +#endif + diff --git a/sys/ofed/drivers/infiniband/hw/mlx4/wc.h b/sys/ofed/drivers/infiniband/hw/mlx4/wc.h new file mode 100644 index 000000000000..f32fe1ee55e7 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mlx4/wc.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2006-2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef mlx4_WC_H +#define mlx4_WC_H + +#include + +int mlx4_wc_enabled(void); +pgprot_t pgprot_wc(pgprot_t _prot); + +#endif diff --git a/sys/ofed/drivers/infiniband/hw/mthca/Kconfig b/sys/ofed/drivers/infiniband/hw/mthca/Kconfig new file mode 100644 index 000000000000..03efc074967e --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/Kconfig @@ -0,0 +1,17 @@ +config INFINIBAND_MTHCA + tristate "Mellanox HCA support" + depends on PCI + ---help--- + This is a low-level driver for Mellanox InfiniHost host + channel adapters (HCAs), including the MT23108 PCI-X HCA + ("Tavor") and the MT25208 PCI Express HCA ("Arbel"). + +config INFINIBAND_MTHCA_DEBUG + bool "Verbose debugging output" if EMBEDDED + depends on INFINIBAND_MTHCA + default y + ---help--- + This option causes debugging code to be compiled into the + mthca driver. The output can be turned on via the + debug_level module parameter (which can also be set after + the driver is loaded through sysfs). diff --git a/sys/ofed/drivers/infiniband/hw/mthca/Makefile b/sys/ofed/drivers/infiniband/hw/mthca/Makefile new file mode 100644 index 000000000000..e388d95d0cf1 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/Makefile @@ -0,0 +1,7 @@ +obj-$(CONFIG_INFINIBAND_MTHCA) += ib_mthca.o + +ib_mthca-y := mthca_main.o mthca_cmd.o mthca_profile.o mthca_reset.o \ + mthca_allocator.o mthca_eq.o mthca_pd.o mthca_cq.o \ + mthca_mr.o mthca_qp.o mthca_av.o mthca_mcg.o mthca_mad.o \ + mthca_provider.o mthca_memfree.o mthca_uar.o mthca_srq.o \ + mthca_catas.o diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_allocator.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_allocator.c new file mode 100644 index 000000000000..c5ccc2daab60 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_allocator.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "mthca_dev.h" + +/* Trivial bitmap-based allocator */ +u32 mthca_alloc(struct mthca_alloc *alloc) +{ + unsigned long flags; + u32 obj; + + spin_lock_irqsave(&alloc->lock, flags); + + obj = find_next_zero_bit(alloc->table, alloc->max, alloc->last); + if (obj >= alloc->max) { + alloc->top = (alloc->top + alloc->max) & alloc->mask; + obj = find_first_zero_bit(alloc->table, alloc->max); + } + + if (obj < alloc->max) { + set_bit(obj, alloc->table); + obj |= alloc->top; + } else + obj = -1; + + spin_unlock_irqrestore(&alloc->lock, flags); + + return obj; +} + +void mthca_free(struct mthca_alloc *alloc, u32 obj) +{ + unsigned long flags; + + obj &= alloc->max - 1; + + spin_lock_irqsave(&alloc->lock, flags); + + clear_bit(obj, alloc->table); + alloc->last = min(alloc->last, obj); + alloc->top = (alloc->top + alloc->max) & alloc->mask; + + spin_unlock_irqrestore(&alloc->lock, flags); +} + +int mthca_alloc_init(struct mthca_alloc *alloc, u32 num, u32 mask, + u32 reserved) +{ + int i; + + /* num must be a power of 2 */ + if (num != 1 << (ffs(num) - 1)) + return -EINVAL; + + alloc->last = 0; + alloc->top = 0; + alloc->max = num; + alloc->mask = mask; + spin_lock_init(&alloc->lock); + alloc->table = kmalloc(BITS_TO_LONGS(num) * sizeof (long), + GFP_KERNEL); + if (!alloc->table) + return -ENOMEM; + + bitmap_zero(alloc->table, num); + for (i = 0; i < reserved; ++i) + set_bit(i, alloc->table); + + return 0; +} + +void mthca_alloc_cleanup(struct mthca_alloc *alloc) +{ + kfree(alloc->table); +} + +/* + * Array of pointers with lazy allocation of leaf pages. Callers of + * _get, _set and _clear methods must use a lock or otherwise + * serialize access to the array. + */ + +#define MTHCA_ARRAY_MASK (PAGE_SIZE / sizeof (void *) - 1) + +void *mthca_array_get(struct mthca_array *array, int index) +{ + int p = (index * sizeof (void *)) >> PAGE_SHIFT; + + if (array->page_list[p].page) + return array->page_list[p].page[index & MTHCA_ARRAY_MASK]; + else + return NULL; +} + +int mthca_array_set(struct mthca_array *array, int index, void *value) +{ + int p = (index * sizeof (void *)) >> PAGE_SHIFT; + + /* Allocate with GFP_ATOMIC because we'll be called with locks held. */ + if (!array->page_list[p].page) + array->page_list[p].page = (void **) get_zeroed_page(GFP_ATOMIC); + + if (!array->page_list[p].page) + return -ENOMEM; + + array->page_list[p].page[index & MTHCA_ARRAY_MASK] = value; + ++array->page_list[p].used; + + return 0; +} + +void mthca_array_clear(struct mthca_array *array, int index) +{ + int p = (index * sizeof (void *)) >> PAGE_SHIFT; + + if (--array->page_list[p].used == 0) { + free_page((unsigned long) array->page_list[p].page); + array->page_list[p].page = NULL; + } else + array->page_list[p].page[index & MTHCA_ARRAY_MASK] = NULL; + + if (array->page_list[p].used < 0) + pr_debug("Array %p index %d page %d with ref count %d < 0\n", + array, index, p, array->page_list[p].used); +} + +int mthca_array_init(struct mthca_array *array, int nent) +{ + int npage = (nent * sizeof (void *) + PAGE_SIZE - 1) / PAGE_SIZE; + int i; + + array->page_list = kmalloc(npage * sizeof *array->page_list, GFP_KERNEL); + if (!array->page_list) + return -ENOMEM; + + for (i = 0; i < npage; ++i) { + array->page_list[i].page = NULL; + array->page_list[i].used = 0; + } + + return 0; +} + +void mthca_array_cleanup(struct mthca_array *array, int nent) +{ + int i; + + for (i = 0; i < (nent * sizeof (void *) + PAGE_SIZE - 1) / PAGE_SIZE; ++i) + free_page((unsigned long) array->page_list[i].page); + + kfree(array->page_list); +} + +/* + * Handling for queue buffers -- we allocate a bunch of memory and + * register it in a memory region at HCA virtual address 0. If the + * requested size is > max_direct, we split the allocation into + * multiple pages, so we don't require too much contiguous memory. + */ + +int mthca_buf_alloc(struct mthca_dev *dev, int size, int max_direct, + union mthca_buf *buf, int *is_direct, struct mthca_pd *pd, + int hca_write, struct mthca_mr *mr) +{ + int err = -ENOMEM; + int npages, shift; + u64 *dma_list = NULL; + dma_addr_t t; + int i; + + if (size <= max_direct) { + *is_direct = 1; + npages = 1; + shift = get_order(size) + PAGE_SHIFT; + + buf->direct.buf = dma_alloc_coherent(&dev->pdev->dev, + size, &t, GFP_KERNEL); + if (!buf->direct.buf) + return -ENOMEM; + + pci_unmap_addr_set(&buf->direct, mapping, t); + + memset(buf->direct.buf, 0, size); + + while (t & ((1 << shift) - 1)) { + --shift; + npages *= 2; + } + + dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL); + if (!dma_list) + goto err_free; + + for (i = 0; i < npages; ++i) + dma_list[i] = t + i * (1 << shift); + } else { + *is_direct = 0; + npages = (size + PAGE_SIZE - 1) / PAGE_SIZE; + shift = PAGE_SHIFT; + + dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL); + if (!dma_list) + return -ENOMEM; + + buf->page_list = kmalloc(npages * sizeof *buf->page_list, + GFP_KERNEL); + if (!buf->page_list) + goto err_out; + + for (i = 0; i < npages; ++i) + buf->page_list[i].buf = NULL; + + for (i = 0; i < npages; ++i) { + buf->page_list[i].buf = + dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, + &t, GFP_KERNEL); + if (!buf->page_list[i].buf) + goto err_free; + + dma_list[i] = t; + pci_unmap_addr_set(&buf->page_list[i], mapping, t); + + clear_page(buf->page_list[i].buf); + } + } + + err = mthca_mr_alloc_phys(dev, pd->pd_num, + dma_list, shift, npages, + 0, size, + MTHCA_MPT_FLAG_LOCAL_READ | + (hca_write ? MTHCA_MPT_FLAG_LOCAL_WRITE : 0), + mr); + if (err) + goto err_free; + + kfree(dma_list); + + return 0; + +err_free: + mthca_buf_free(dev, size, buf, *is_direct, NULL); + +err_out: + kfree(dma_list); + + return err; +} + +void mthca_buf_free(struct mthca_dev *dev, int size, union mthca_buf *buf, + int is_direct, struct mthca_mr *mr) +{ + int i; + + if (mr) + mthca_free_mr(dev, mr); + + if (is_direct) + dma_free_coherent(&dev->pdev->dev, size, buf->direct.buf, + pci_unmap_addr(&buf->direct, mapping)); + else { + for (i = 0; i < (size + PAGE_SIZE - 1) / PAGE_SIZE; ++i) + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + buf->page_list[i].buf, + pci_unmap_addr(&buf->page_list[i], + mapping)); + kfree(buf->page_list); + } +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_av.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_av.c new file mode 100644 index 000000000000..32f6c6315454 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_av.c @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include +#include + +#include "mthca_dev.h" + +enum { + MTHCA_RATE_TAVOR_FULL = 0, + MTHCA_RATE_TAVOR_1X = 1, + MTHCA_RATE_TAVOR_4X = 2, + MTHCA_RATE_TAVOR_1X_DDR = 3 +}; + +enum { + MTHCA_RATE_MEMFREE_FULL = 0, + MTHCA_RATE_MEMFREE_QUARTER = 1, + MTHCA_RATE_MEMFREE_EIGHTH = 2, + MTHCA_RATE_MEMFREE_HALF = 3 +}; + +struct mthca_av { + __be32 port_pd; + u8 reserved1; + u8 g_slid; + __be16 dlid; + u8 reserved2; + u8 gid_index; + u8 msg_sr; + u8 hop_limit; + __be32 sl_tclass_flowlabel; + __be32 dgid[4]; +}; + +static enum ib_rate memfree_rate_to_ib(u8 mthca_rate, u8 port_rate) +{ + switch (mthca_rate) { + case MTHCA_RATE_MEMFREE_EIGHTH: + return mult_to_ib_rate(port_rate >> 3); + case MTHCA_RATE_MEMFREE_QUARTER: + return mult_to_ib_rate(port_rate >> 2); + case MTHCA_RATE_MEMFREE_HALF: + return mult_to_ib_rate(port_rate >> 1); + case MTHCA_RATE_MEMFREE_FULL: + default: + return mult_to_ib_rate(port_rate); + } +} + +static enum ib_rate tavor_rate_to_ib(u8 mthca_rate, u8 port_rate) +{ + switch (mthca_rate) { + case MTHCA_RATE_TAVOR_1X: return IB_RATE_2_5_GBPS; + case MTHCA_RATE_TAVOR_1X_DDR: return IB_RATE_5_GBPS; + case MTHCA_RATE_TAVOR_4X: return IB_RATE_10_GBPS; + default: return mult_to_ib_rate(port_rate); + } +} + +enum ib_rate mthca_rate_to_ib(struct mthca_dev *dev, u8 mthca_rate, u8 port) +{ + if (mthca_is_memfree(dev)) { + /* Handle old Arbel FW */ + if (dev->limits.stat_rate_support == 0x3 && mthca_rate) + return IB_RATE_2_5_GBPS; + + return memfree_rate_to_ib(mthca_rate, dev->rate[port - 1]); + } else + return tavor_rate_to_ib(mthca_rate, dev->rate[port - 1]); +} + +static u8 ib_rate_to_memfree(u8 req_rate, u8 cur_rate) +{ + if (cur_rate <= req_rate) + return 0; + + /* + * Inter-packet delay (IPD) to get from rate X down to a rate + * no more than Y is (X - 1) / Y. + */ + switch ((cur_rate - 1) / req_rate) { + case 0: return MTHCA_RATE_MEMFREE_FULL; + case 1: return MTHCA_RATE_MEMFREE_HALF; + case 2: /* fall through */ + case 3: return MTHCA_RATE_MEMFREE_QUARTER; + default: return MTHCA_RATE_MEMFREE_EIGHTH; + } +} + +static u8 ib_rate_to_tavor(u8 static_rate) +{ + switch (static_rate) { + case IB_RATE_2_5_GBPS: return MTHCA_RATE_TAVOR_1X; + case IB_RATE_5_GBPS: return MTHCA_RATE_TAVOR_1X_DDR; + case IB_RATE_10_GBPS: return MTHCA_RATE_TAVOR_4X; + default: return MTHCA_RATE_TAVOR_FULL; + } +} + +u8 mthca_get_rate(struct mthca_dev *dev, int static_rate, u8 port) +{ + u8 rate; + + if (!static_rate || ib_rate_to_mult(static_rate) >= dev->rate[port - 1]) + return 0; + + if (mthca_is_memfree(dev)) + rate = ib_rate_to_memfree(ib_rate_to_mult(static_rate), + dev->rate[port - 1]); + else + rate = ib_rate_to_tavor(static_rate); + + if (!(dev->limits.stat_rate_support & (1 << rate))) + rate = 1; + + return rate; +} + +int mthca_create_ah(struct mthca_dev *dev, + struct mthca_pd *pd, + struct ib_ah_attr *ah_attr, + struct mthca_ah *ah) +{ + u32 index = -1; + struct mthca_av *av = NULL; + + ah->type = MTHCA_AH_PCI_POOL; + + if (mthca_is_memfree(dev)) { + ah->av = kmalloc(sizeof *ah->av, GFP_ATOMIC); + if (!ah->av) + return -ENOMEM; + + ah->type = MTHCA_AH_KMALLOC; + av = ah->av; + } else if (!atomic_read(&pd->sqp_count) && + !(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) { + index = mthca_alloc(&dev->av_table.alloc); + + /* fall back to allocate in host memory */ + if (index == -1) + goto on_hca_fail; + + av = kmalloc(sizeof *av, GFP_ATOMIC); + if (!av) + goto on_hca_fail; + + ah->type = MTHCA_AH_ON_HCA; + ah->avdma = dev->av_table.ddr_av_base + + index * MTHCA_AV_SIZE; + } + +on_hca_fail: + if (ah->type == MTHCA_AH_PCI_POOL) { + ah->av = pci_pool_alloc(dev->av_table.pool, + GFP_ATOMIC, &ah->avdma); + if (!ah->av) + return -ENOMEM; + + av = ah->av; + } + + ah->key = pd->ntmr.ibmr.lkey; + + memset(av, 0, MTHCA_AV_SIZE); + + av->port_pd = cpu_to_be32(pd->pd_num | (ah_attr->port_num << 24)); + av->g_slid = ah_attr->src_path_bits; + av->dlid = cpu_to_be16(ah_attr->dlid); + av->msg_sr = (3 << 4) | /* 2K message */ + mthca_get_rate(dev, ah_attr->static_rate, ah_attr->port_num); + av->sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); + if (ah_attr->ah_flags & IB_AH_GRH) { + av->g_slid |= 0x80; + av->gid_index = (ah_attr->port_num - 1) * dev->limits.gid_table_len + + ah_attr->grh.sgid_index; + av->hop_limit = ah_attr->grh.hop_limit; + av->sl_tclass_flowlabel |= + cpu_to_be32((ah_attr->grh.traffic_class << 20) | + ah_attr->grh.flow_label); + memcpy(av->dgid, ah_attr->grh.dgid.raw, 16); + } else { + /* Arbel workaround -- low byte of GID must be 2 */ + av->dgid[3] = cpu_to_be32(2); + } + + if (0) { + int j; + + mthca_dbg(dev, "Created UDAV at %p/%08lx:\n", + av, (unsigned long) ah->avdma); + for (j = 0; j < 8; ++j) + printk(KERN_DEBUG " [%2x] %08x\n", + j * 4, be32_to_cpu(((__be32 *) av)[j])); + } + + if (ah->type == MTHCA_AH_ON_HCA) { + memcpy_toio(dev->av_table.av_map + index * MTHCA_AV_SIZE, + av, MTHCA_AV_SIZE); + kfree(av); + } + + return 0; +} + +int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah) +{ + switch (ah->type) { + case MTHCA_AH_ON_HCA: + mthca_free(&dev->av_table.alloc, + (ah->avdma - dev->av_table.ddr_av_base) / + MTHCA_AV_SIZE); + break; + + case MTHCA_AH_PCI_POOL: + pci_pool_free(dev->av_table.pool, ah->av, ah->avdma); + break; + + case MTHCA_AH_KMALLOC: + kfree(ah->av); + break; + } + + return 0; +} + +int mthca_ah_grh_present(struct mthca_ah *ah) +{ + return !!(ah->av->g_slid & 0x80); +} + +int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah, + struct ib_ud_header *header) +{ + if (ah->type == MTHCA_AH_ON_HCA) + return -EINVAL; + + header->lrh.service_level = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28; + header->lrh.destination_lid = ah->av->dlid; + header->lrh.source_lid = cpu_to_be16(ah->av->g_slid & 0x7f); + if (mthca_ah_grh_present(ah)) { + header->grh.traffic_class = + (be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20) & 0xff; + header->grh.flow_label = + ah->av->sl_tclass_flowlabel & cpu_to_be32(0xfffff); + header->grh.hop_limit = ah->av->hop_limit; + ib_get_cached_gid(&dev->ib_dev, + be32_to_cpu(ah->av->port_pd) >> 24, + ah->av->gid_index % dev->limits.gid_table_len, + &header->grh.source_gid); + memcpy(header->grh.destination_gid.raw, + ah->av->dgid, 16); + } + + return 0; +} + +int mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr) +{ + struct mthca_ah *ah = to_mah(ibah); + struct mthca_dev *dev = to_mdev(ibah->device); + + /* Only implement for MAD and memfree ah for now. */ + if (ah->type == MTHCA_AH_ON_HCA) + return -ENOSYS; + + memset(attr, 0, sizeof *attr); + attr->dlid = be16_to_cpu(ah->av->dlid); + attr->sl = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28; + attr->port_num = be32_to_cpu(ah->av->port_pd) >> 24; + attr->static_rate = mthca_rate_to_ib(dev, ah->av->msg_sr & 0x7, + attr->port_num); + attr->src_path_bits = ah->av->g_slid & 0x7F; + attr->ah_flags = mthca_ah_grh_present(ah) ? IB_AH_GRH : 0; + + if (attr->ah_flags) { + attr->grh.traffic_class = + be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20; + attr->grh.flow_label = + be32_to_cpu(ah->av->sl_tclass_flowlabel) & 0xfffff; + attr->grh.hop_limit = ah->av->hop_limit; + attr->grh.sgid_index = ah->av->gid_index & + (dev->limits.gid_table_len - 1); + memcpy(attr->grh.dgid.raw, ah->av->dgid, 16); + } + + return 0; +} + +int mthca_init_av_table(struct mthca_dev *dev) +{ + int err; + + if (mthca_is_memfree(dev)) + return 0; + + err = mthca_alloc_init(&dev->av_table.alloc, + dev->av_table.num_ddr_avs, + dev->av_table.num_ddr_avs - 1, + 0); + if (err) + return err; + + dev->av_table.pool = pci_pool_create("mthca_av", dev->pdev, + MTHCA_AV_SIZE, + MTHCA_AV_SIZE, 0); + if (!dev->av_table.pool) + goto out_free_alloc; + + if (!(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) { + dev->av_table.av_map = ioremap(pci_resource_start(dev->pdev, 4) + + dev->av_table.ddr_av_base - + dev->ddr_start, + dev->av_table.num_ddr_avs * + MTHCA_AV_SIZE); + if (!dev->av_table.av_map) + goto out_free_pool; + } else + dev->av_table.av_map = NULL; + + return 0; + + out_free_pool: + pci_pool_destroy(dev->av_table.pool); + + out_free_alloc: + mthca_alloc_cleanup(&dev->av_table.alloc); + return -ENOMEM; +} + +void mthca_cleanup_av_table(struct mthca_dev *dev) +{ + if (mthca_is_memfree(dev)) + return; + + if (dev->av_table.av_map) + iounmap(dev->av_table.av_map); + pci_pool_destroy(dev->av_table.pool); + mthca_alloc_cleanup(&dev->av_table.alloc); +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_catas.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_catas.c new file mode 100644 index 000000000000..b200170c61e8 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_catas.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "mthca_dev.h" + +enum { + MTHCA_CATAS_TYPE_INTERNAL = 0, + MTHCA_CATAS_TYPE_UPLINK = 3, + MTHCA_CATAS_TYPE_DDR = 4, + MTHCA_CATAS_TYPE_PARITY = 5, +}; + +#define MTHCA_CATAS_POLL_INTERVAL (5 * HZ) + +static DEFINE_SPINLOCK(catas_lock); + +static LIST_HEAD(catas_list); +static struct workqueue_struct *catas_wq; +static struct work_struct catas_work; + +static int catas_reset_disable; +module_param_named(catas_reset_disable, catas_reset_disable, int, 0644); +MODULE_PARM_DESC(catas_reset_disable, "disable reset on catastrophic event if nonzero"); + +static void catas_reset(struct work_struct *work) +{ + struct mthca_dev *dev, *tmpdev; + LIST_HEAD(tlist); + int ret; + + mutex_lock(&mthca_device_mutex); + + spin_lock_irq(&catas_lock); + list_splice_init(&catas_list, &tlist); + spin_unlock_irq(&catas_lock); + + list_for_each_entry_safe(dev, tmpdev, &tlist, catas_err.list) { + struct pci_dev *pdev = dev->pdev; + ret = __mthca_restart_one(dev->pdev); + /* 'dev' now is not valid */ + if (ret) + printk(KERN_ERR "mthca %s: Reset failed (%d)\n", + pci_name(pdev), ret); + else { + struct mthca_dev *d = pci_get_drvdata(pdev); + mthca_dbg(d, "Reset succeeded\n"); + } + } + + mutex_unlock(&mthca_device_mutex); +} + +static void handle_catas(struct mthca_dev *dev) +{ + struct ib_event event; + unsigned long flags; + const char *type; + int i; + + event.device = &dev->ib_dev; + event.event = IB_EVENT_DEVICE_FATAL; + event.element.port_num = 0; + dev->active = 0; + + ib_dispatch_event(&event); + + switch (swab32(readl(dev->catas_err.map)) >> 24) { + case MTHCA_CATAS_TYPE_INTERNAL: + type = "internal error"; + break; + case MTHCA_CATAS_TYPE_UPLINK: + type = "uplink bus error"; + break; + case MTHCA_CATAS_TYPE_DDR: + type = "DDR data error"; + break; + case MTHCA_CATAS_TYPE_PARITY: + type = "internal parity error"; + break; + default: + type = "unknown error"; + break; + } + + mthca_err(dev, "Catastrophic error detected: %s\n", type); + for (i = 0; i < dev->catas_err.size; ++i) + mthca_err(dev, " buf[%02x]: %08x\n", + i, swab32(readl(dev->catas_err.map + i))); + + if (catas_reset_disable) + return; + + spin_lock_irqsave(&catas_lock, flags); + list_add(&dev->catas_err.list, &catas_list); + queue_work(catas_wq, &catas_work); + spin_unlock_irqrestore(&catas_lock, flags); +} + +static void poll_catas(unsigned long dev_ptr) +{ + struct mthca_dev *dev = (struct mthca_dev *) dev_ptr; + int i; + + for (i = 0; i < dev->catas_err.size; ++i) + if (readl(dev->catas_err.map + i)) { + handle_catas(dev); + return; + } + + mod_timer(&dev->catas_err.timer, + round_jiffies(jiffies + MTHCA_CATAS_POLL_INTERVAL)); +} + +void mthca_start_catas_poll(struct mthca_dev *dev) +{ + unsigned long addr; + + init_timer(&dev->catas_err.timer); + dev->catas_err.map = NULL; + + addr = pci_resource_start(dev->pdev, 0) + + ((pci_resource_len(dev->pdev, 0) - 1) & + dev->catas_err.addr); + + dev->catas_err.map = ioremap(addr, dev->catas_err.size * 4); + if (!dev->catas_err.map) { + mthca_warn(dev, "couldn't map catastrophic error region " + "at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4); + return; + } + + dev->catas_err.timer.data = (unsigned long) dev; + dev->catas_err.timer.function = poll_catas; + dev->catas_err.timer.expires = jiffies + MTHCA_CATAS_POLL_INTERVAL; + INIT_LIST_HEAD(&dev->catas_err.list); + add_timer(&dev->catas_err.timer); +} + +void mthca_stop_catas_poll(struct mthca_dev *dev) +{ + del_timer_sync(&dev->catas_err.timer); + + if (dev->catas_err.map) + iounmap(dev->catas_err.map); + + spin_lock_irq(&catas_lock); + list_del(&dev->catas_err.list); + spin_unlock_irq(&catas_lock); +} + +int __init mthca_catas_init(void) +{ + INIT_WORK(&catas_work, catas_reset); + + catas_wq = create_singlethread_workqueue("mthcacatas"); + if (!catas_wq) + return -ENOMEM; + + return 0; +} + +void mthca_catas_cleanup(void) +{ + destroy_workqueue(catas_wq); +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_cmd.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_cmd.c new file mode 100644 index 000000000000..81e28387fac4 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -0,0 +1,1931 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "mthca_dev.h" +#include "mthca_config_reg.h" +#include "mthca_cmd.h" +#include "mthca_memfree.h" + +#define CMD_POLL_TOKEN 0xffff + +enum { + HCR_IN_PARAM_OFFSET = 0x00, + HCR_IN_MODIFIER_OFFSET = 0x08, + HCR_OUT_PARAM_OFFSET = 0x0c, + HCR_TOKEN_OFFSET = 0x14, + HCR_STATUS_OFFSET = 0x18, + + HCR_OPMOD_SHIFT = 12, + HCA_E_BIT = 22, + HCR_GO_BIT = 23 +}; + +enum { + /* initialization and general commands */ + CMD_SYS_EN = 0x1, + CMD_SYS_DIS = 0x2, + CMD_MAP_FA = 0xfff, + CMD_UNMAP_FA = 0xffe, + CMD_RUN_FW = 0xff6, + CMD_MOD_STAT_CFG = 0x34, + CMD_QUERY_DEV_LIM = 0x3, + CMD_QUERY_FW = 0x4, + CMD_ENABLE_LAM = 0xff8, + CMD_DISABLE_LAM = 0xff7, + CMD_QUERY_DDR = 0x5, + CMD_QUERY_ADAPTER = 0x6, + CMD_INIT_HCA = 0x7, + CMD_CLOSE_HCA = 0x8, + CMD_INIT_IB = 0x9, + CMD_CLOSE_IB = 0xa, + CMD_QUERY_HCA = 0xb, + CMD_SET_IB = 0xc, + CMD_ACCESS_DDR = 0x2e, + CMD_MAP_ICM = 0xffa, + CMD_UNMAP_ICM = 0xff9, + CMD_MAP_ICM_AUX = 0xffc, + CMD_UNMAP_ICM_AUX = 0xffb, + CMD_SET_ICM_SIZE = 0xffd, + + /* TPT commands */ + CMD_SW2HW_MPT = 0xd, + CMD_QUERY_MPT = 0xe, + CMD_HW2SW_MPT = 0xf, + CMD_READ_MTT = 0x10, + CMD_WRITE_MTT = 0x11, + CMD_SYNC_TPT = 0x2f, + + /* EQ commands */ + CMD_MAP_EQ = 0x12, + CMD_SW2HW_EQ = 0x13, + CMD_HW2SW_EQ = 0x14, + CMD_QUERY_EQ = 0x15, + + /* CQ commands */ + CMD_SW2HW_CQ = 0x16, + CMD_HW2SW_CQ = 0x17, + CMD_QUERY_CQ = 0x18, + CMD_RESIZE_CQ = 0x2c, + + /* SRQ commands */ + CMD_SW2HW_SRQ = 0x35, + CMD_HW2SW_SRQ = 0x36, + CMD_QUERY_SRQ = 0x37, + CMD_ARM_SRQ = 0x40, + + /* QP/EE commands */ + CMD_RST2INIT_QPEE = 0x19, + CMD_INIT2RTR_QPEE = 0x1a, + CMD_RTR2RTS_QPEE = 0x1b, + CMD_RTS2RTS_QPEE = 0x1c, + CMD_SQERR2RTS_QPEE = 0x1d, + CMD_2ERR_QPEE = 0x1e, + CMD_RTS2SQD_QPEE = 0x1f, + CMD_SQD2SQD_QPEE = 0x38, + CMD_SQD2RTS_QPEE = 0x20, + CMD_ERR2RST_QPEE = 0x21, + CMD_QUERY_QPEE = 0x22, + CMD_INIT2INIT_QPEE = 0x2d, + CMD_SUSPEND_QPEE = 0x32, + CMD_UNSUSPEND_QPEE = 0x33, + /* special QPs and management commands */ + CMD_CONF_SPECIAL_QP = 0x23, + CMD_MAD_IFC = 0x24, + + /* multicast commands */ + CMD_READ_MGM = 0x25, + CMD_WRITE_MGM = 0x26, + CMD_MGID_HASH = 0x27, + + /* miscellaneous commands */ + CMD_DIAG_RPRT = 0x30, + CMD_NOP = 0x31, + + /* debug commands */ + CMD_QUERY_DEBUG_MSG = 0x2a, + CMD_SET_DEBUG_MSG = 0x2b, +}; + +/* + * According to Mellanox code, FW may be starved and never complete + * commands. So we can't use strict timeouts described in PRM -- we + * just arbitrarily select 60 seconds for now. + */ +#if 0 +/* + * Round up and add 1 to make sure we get the full wait time (since we + * will be starting in the middle of a jiffy) + */ +enum { + CMD_TIME_CLASS_A = (HZ + 999) / 1000 + 1, + CMD_TIME_CLASS_B = (HZ + 99) / 100 + 1, + CMD_TIME_CLASS_C = (HZ + 9) / 10 + 1, + CMD_TIME_CLASS_D = 60 * HZ +}; +#else +#define CMD_TIME_CLASS_A (60 * HZ) +#define CMD_TIME_CLASS_B (60 * HZ) +#define CMD_TIME_CLASS_C (60 * HZ) +#define CMD_TIME_CLASS_D (60 * HZ) +#endif + +#define GO_BIT_TIMEOUT (HZ * 10) + +struct mthca_cmd_context { + struct completion done; + int result; + int next; + u64 out_param; + u16 token; + u8 status; +}; + +static int fw_cmd_doorbell = 0; +module_param(fw_cmd_doorbell, int, 0644); +MODULE_PARM_DESC(fw_cmd_doorbell, "post FW commands through doorbell page if nonzero " + "(and supported by FW)"); + +static inline int go_bit(struct mthca_dev *dev) +{ + return readl(dev->hcr + HCR_STATUS_OFFSET) & + swab32(1 << HCR_GO_BIT); +} + +static void mthca_cmd_post_dbell(struct mthca_dev *dev, + u64 in_param, + u64 out_param, + u32 in_modifier, + u8 op_modifier, + u16 op, + u16 token) +{ + void __iomem *ptr = dev->cmd.dbell_map; + u16 *offs = dev->cmd.dbell_offsets; + + __raw_writel((__force u32) cpu_to_be32(in_param >> 32), ptr + offs[0]); + wmb(); + __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), ptr + offs[1]); + wmb(); + __raw_writel((__force u32) cpu_to_be32(in_modifier), ptr + offs[2]); + wmb(); + __raw_writel((__force u32) cpu_to_be32(out_param >> 32), ptr + offs[3]); + wmb(); + __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), ptr + offs[4]); + wmb(); + __raw_writel((__force u32) cpu_to_be32(token << 16), ptr + offs[5]); + wmb(); + __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) | + (1 << HCA_E_BIT) | + (op_modifier << HCR_OPMOD_SHIFT) | + op), ptr + offs[6]); + wmb(); + __raw_writel((__force u32) 0, ptr + offs[7]); + wmb(); +} + +static int mthca_cmd_post_hcr(struct mthca_dev *dev, + u64 in_param, + u64 out_param, + u32 in_modifier, + u8 op_modifier, + u16 op, + u16 token, + int event) +{ + if (event) { + unsigned long end = jiffies + GO_BIT_TIMEOUT; + + while (go_bit(dev) && time_before(jiffies, end)) + sched_yield(); + } + + if (go_bit(dev)) + return -EAGAIN; + + /* + * We use writel (instead of something like memcpy_toio) + * because writes of less than 32 bits to the HCR don't work + * (and some architectures such as ia64 implement memcpy_toio + * in terms of writeb). + */ + __raw_writel((__force u32) cpu_to_be32(in_param >> 32), dev->hcr + 0 * 4); + __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), dev->hcr + 1 * 4); + __raw_writel((__force u32) cpu_to_be32(in_modifier), dev->hcr + 2 * 4); + __raw_writel((__force u32) cpu_to_be32(out_param >> 32), dev->hcr + 3 * 4); + __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), dev->hcr + 4 * 4); + __raw_writel((__force u32) cpu_to_be32(token << 16), dev->hcr + 5 * 4); + + /* __raw_writel may not order writes. */ + wmb(); + + __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) | + (event ? (1 << HCA_E_BIT) : 0) | + (op_modifier << HCR_OPMOD_SHIFT) | + op), dev->hcr + 6 * 4); + + return 0; +} + +static int mthca_cmd_post(struct mthca_dev *dev, + u64 in_param, + u64 out_param, + u32 in_modifier, + u8 op_modifier, + u16 op, + u16 token, + int event) +{ + int err = 0; + + mutex_lock(&dev->cmd.hcr_mutex); + + if (event && dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS && fw_cmd_doorbell) + mthca_cmd_post_dbell(dev, in_param, out_param, in_modifier, + op_modifier, op, token); + else + err = mthca_cmd_post_hcr(dev, in_param, out_param, in_modifier, + op_modifier, op, token, event); + + /* + * Make sure that our HCR writes don't get mixed in with + * writes from another CPU starting a FW command. + */ + mmiowb(); + + mutex_unlock(&dev->cmd.hcr_mutex); + return err; +} + +static int mthca_cmd_poll(struct mthca_dev *dev, + u64 in_param, + u64 *out_param, + int out_is_imm, + u32 in_modifier, + u8 op_modifier, + u16 op, + unsigned long timeout, + u8 *status) +{ + int err = 0; + unsigned long end; + + down(&dev->cmd.poll_sem); + + err = mthca_cmd_post(dev, in_param, + out_param ? *out_param : 0, + in_modifier, op_modifier, + op, CMD_POLL_TOKEN, 0); + if (err) + goto out; + + end = timeout + jiffies; + while (go_bit(dev) && time_before(jiffies, end)) + sched_yield(); + + if (go_bit(dev)) { + err = -EBUSY; + goto out; + } + + if (out_is_imm) + *out_param = + (u64) be32_to_cpu((__force __be32) + __raw_readl(dev->hcr + HCR_OUT_PARAM_OFFSET)) << 32 | + (u64) be32_to_cpu((__force __be32) + __raw_readl(dev->hcr + HCR_OUT_PARAM_OFFSET + 4)); + + *status = be32_to_cpu((__force __be32) __raw_readl(dev->hcr + HCR_STATUS_OFFSET)) >> 24; + +out: + up(&dev->cmd.poll_sem); + return err; +} + +void mthca_cmd_event(struct mthca_dev *dev, + u16 token, + u8 status, + u64 out_param) +{ + struct mthca_cmd_context *context = + &dev->cmd.context[token & dev->cmd.token_mask]; + + /* previously timed out command completing at long last */ + if (token != context->token) + return; + + context->result = 0; + context->status = status; + context->out_param = out_param; + + complete(&context->done); +} + +static int mthca_cmd_wait(struct mthca_dev *dev, + u64 in_param, + u64 *out_param, + int out_is_imm, + u32 in_modifier, + u8 op_modifier, + u16 op, + unsigned long timeout, + u8 *status) +{ + int err = 0; + struct mthca_cmd_context *context; + + down(&dev->cmd.event_sem); + + spin_lock(&dev->cmd.context_lock); + BUG_ON(dev->cmd.free_head < 0); + context = &dev->cmd.context[dev->cmd.free_head]; + context->token += dev->cmd.token_mask + 1; + dev->cmd.free_head = context->next; + spin_unlock(&dev->cmd.context_lock); + + init_completion(&context->done); + + err = mthca_cmd_post(dev, in_param, + out_param ? *out_param : 0, + in_modifier, op_modifier, + op, context->token, 1); + if (err) + goto out; + + if (!wait_for_completion_timeout(&context->done, timeout)) { + err = -EBUSY; + goto out; + } + + err = context->result; + if (err) + goto out; + + *status = context->status; + if (*status) + mthca_dbg(dev, "Command %02x completed with status %02x\n", + op, *status); + + if (out_is_imm) + *out_param = context->out_param; + +out: + spin_lock(&dev->cmd.context_lock); + context->next = dev->cmd.free_head; + dev->cmd.free_head = context - dev->cmd.context; + spin_unlock(&dev->cmd.context_lock); + + up(&dev->cmd.event_sem); + return err; +} + +/* Invoke a command with an output mailbox */ +static int mthca_cmd_box(struct mthca_dev *dev, + u64 in_param, + u64 out_param, + u32 in_modifier, + u8 op_modifier, + u16 op, + unsigned long timeout, + u8 *status) +{ + if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS) + return mthca_cmd_wait(dev, in_param, &out_param, 0, + in_modifier, op_modifier, op, + timeout, status); + else + return mthca_cmd_poll(dev, in_param, &out_param, 0, + in_modifier, op_modifier, op, + timeout, status); +} + +/* Invoke a command with no output parameter */ +static int mthca_cmd(struct mthca_dev *dev, + u64 in_param, + u32 in_modifier, + u8 op_modifier, + u16 op, + unsigned long timeout, + u8 *status) +{ + return mthca_cmd_box(dev, in_param, 0, in_modifier, + op_modifier, op, timeout, status); +} + +/* + * Invoke a command with an immediate output parameter (and copy the + * output into the caller's out_param pointer after the command + * executes). + */ +static int mthca_cmd_imm(struct mthca_dev *dev, + u64 in_param, + u64 *out_param, + u32 in_modifier, + u8 op_modifier, + u16 op, + unsigned long timeout, + u8 *status) +{ + if (dev->cmd.flags & MTHCA_CMD_USE_EVENTS) + return mthca_cmd_wait(dev, in_param, out_param, 1, + in_modifier, op_modifier, op, + timeout, status); + else + return mthca_cmd_poll(dev, in_param, out_param, 1, + in_modifier, op_modifier, op, + timeout, status); +} + +int mthca_cmd_init(struct mthca_dev *dev) +{ + mutex_init(&dev->cmd.hcr_mutex); + sema_init(&dev->cmd.poll_sem, 1); + dev->cmd.flags = 0; + + dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE, + MTHCA_HCR_SIZE); + if (!dev->hcr) { + mthca_err(dev, "Couldn't map command register."); + return -ENOMEM; + } + + dev->cmd.pool = pci_pool_create("mthca_cmd", dev->pdev, + MTHCA_MAILBOX_SIZE, + MTHCA_MAILBOX_SIZE, 0); + if (!dev->cmd.pool) { + iounmap(dev->hcr); + return -ENOMEM; + } + + return 0; +} + +void mthca_cmd_cleanup(struct mthca_dev *dev) +{ + pci_pool_destroy(dev->cmd.pool); + iounmap(dev->hcr); + if (dev->cmd.flags & MTHCA_CMD_POST_DOORBELLS) + iounmap(dev->cmd.dbell_map); +} + +/* + * Switch to using events to issue FW commands (should be called after + * event queue to command events has been initialized). + */ +int mthca_cmd_use_events(struct mthca_dev *dev) +{ + int i; + + dev->cmd.context = kmalloc(dev->cmd.max_cmds * + sizeof (struct mthca_cmd_context), + GFP_KERNEL); + if (!dev->cmd.context) + return -ENOMEM; + + for (i = 0; i < dev->cmd.max_cmds; ++i) { + dev->cmd.context[i].token = i; + dev->cmd.context[i].next = i + 1; + } + + dev->cmd.context[dev->cmd.max_cmds - 1].next = -1; + dev->cmd.free_head = 0; + + sema_init(&dev->cmd.event_sem, dev->cmd.max_cmds); + spin_lock_init(&dev->cmd.context_lock); + + for (dev->cmd.token_mask = 1; + dev->cmd.token_mask < dev->cmd.max_cmds; + dev->cmd.token_mask <<= 1) + ; /* nothing */ + --dev->cmd.token_mask; + + dev->cmd.flags |= MTHCA_CMD_USE_EVENTS; + + down(&dev->cmd.poll_sem); + + return 0; +} + +/* + * Switch back to polling (used when shutting down the device) + */ +void mthca_cmd_use_polling(struct mthca_dev *dev) +{ + int i; + + dev->cmd.flags &= ~MTHCA_CMD_USE_EVENTS; + + for (i = 0; i < dev->cmd.max_cmds; ++i) + down(&dev->cmd.event_sem); + + kfree(dev->cmd.context); + + up(&dev->cmd.poll_sem); +} + +struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev, + gfp_t gfp_mask) +{ + struct mthca_mailbox *mailbox; + + mailbox = kmalloc(sizeof *mailbox, gfp_mask); + if (!mailbox) + return ERR_PTR(-ENOMEM); + + mailbox->buf = pci_pool_alloc(dev->cmd.pool, gfp_mask, &mailbox->dma); + if (!mailbox->buf) { + kfree(mailbox); + return ERR_PTR(-ENOMEM); + } + + return mailbox; +} + +void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox) +{ + if (!mailbox) + return; + + pci_pool_free(dev->cmd.pool, mailbox->buf, mailbox->dma); + kfree(mailbox); +} + +int mthca_SYS_EN(struct mthca_dev *dev, u8 *status) +{ + u64 out; + int ret; + + ret = mthca_cmd_imm(dev, 0, &out, 0, 0, CMD_SYS_EN, CMD_TIME_CLASS_D, status); + + if (*status == MTHCA_CMD_STAT_DDR_MEM_ERR) + mthca_warn(dev, "SYS_EN DDR error: syn=%x, sock=%d, " + "sladdr=%d, SPD source=%s\n", + (int) (out >> 6) & 0xf, (int) (out >> 4) & 3, + (int) (out >> 1) & 7, (int) out & 1 ? "NVMEM" : "DIMM"); + + return ret; +} + +int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status) +{ + return mthca_cmd(dev, 0, 0, 0, CMD_SYS_DIS, CMD_TIME_CLASS_C, status); +} + +static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm, + u64 virt, u8 *status) +{ + struct mthca_mailbox *mailbox; + struct mthca_icm_iter iter; + __be64 *pages; + int lg; + int nent = 0; + int i; + int err = 0; + int ts = 0, tc = 0; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + memset(mailbox->buf, 0, MTHCA_MAILBOX_SIZE); + pages = mailbox->buf; + + for (mthca_icm_first(icm, &iter); + !mthca_icm_last(&iter); + mthca_icm_next(&iter)) { + /* + * We have to pass pages that are aligned to their + * size, so find the least significant 1 in the + * address or size and use that as our log2 size. + */ + lg = ffs(mthca_icm_addr(&iter) | mthca_icm_size(&iter)) - 1; + if (lg < MTHCA_ICM_PAGE_SHIFT) { + mthca_warn(dev, "Got FW area not aligned to %d (%llx/%lx).\n", + MTHCA_ICM_PAGE_SIZE, + (unsigned long long) mthca_icm_addr(&iter), + mthca_icm_size(&iter)); + err = -EINVAL; + goto out; + } + for (i = 0; i < mthca_icm_size(&iter) >> lg; ++i) { + if (virt != -1) { + pages[nent * 2] = cpu_to_be64(virt); + virt += 1 << lg; + } + + pages[nent * 2 + 1] = + cpu_to_be64((mthca_icm_addr(&iter) + (i << lg)) | + (lg - MTHCA_ICM_PAGE_SHIFT)); + ts += 1 << (lg - 10); + ++tc; + + if (++nent == MTHCA_MAILBOX_SIZE / 16) { + err = mthca_cmd(dev, mailbox->dma, nent, 0, op, + CMD_TIME_CLASS_B, status); + if (err || *status) + goto out; + nent = 0; + } + } + } + + if (nent) + err = mthca_cmd(dev, mailbox->dma, nent, 0, op, + CMD_TIME_CLASS_B, status); + + switch (op) { + case CMD_MAP_FA: + mthca_dbg(dev, "Mapped %d chunks/%d KB for FW.\n", tc, ts); + break; + case CMD_MAP_ICM_AUX: + mthca_dbg(dev, "Mapped %d chunks/%d KB for ICM aux.\n", tc, ts); + break; + case CMD_MAP_ICM: + mthca_dbg(dev, "Mapped %d chunks/%d KB at %llx for ICM.\n", + tc, ts, (unsigned long long) virt - (ts << 10)); + break; + } + +out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_MAP_FA(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status) +{ + return mthca_map_cmd(dev, CMD_MAP_FA, icm, -1, status); +} + +int mthca_UNMAP_FA(struct mthca_dev *dev, u8 *status) +{ + return mthca_cmd(dev, 0, 0, 0, CMD_UNMAP_FA, CMD_TIME_CLASS_B, status); +} + +int mthca_RUN_FW(struct mthca_dev *dev, u8 *status) +{ + return mthca_cmd(dev, 0, 0, 0, CMD_RUN_FW, CMD_TIME_CLASS_A, status); +} + +static void mthca_setup_cmd_doorbells(struct mthca_dev *dev, u64 base) +{ + unsigned long addr; + u16 max_off = 0; + int i; + + for (i = 0; i < 8; ++i) + max_off = max(max_off, dev->cmd.dbell_offsets[i]); + + if ((base & PAGE_MASK) != ((base + max_off) & PAGE_MASK)) { + mthca_warn(dev, "Firmware doorbell region at 0x%016llx, " + "length 0x%x crosses a page boundary\n", + (unsigned long long) base, max_off); + return; + } + + addr = pci_resource_start(dev->pdev, 2) + + ((pci_resource_len(dev->pdev, 2) - 1) & base); + dev->cmd.dbell_map = ioremap(addr, max_off + sizeof(u32)); + if (!dev->cmd.dbell_map) + return; + + dev->cmd.flags |= MTHCA_CMD_POST_DOORBELLS; + mthca_dbg(dev, "Mapped doorbell page for posting FW commands\n"); +} + +int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status) +{ + struct mthca_mailbox *mailbox; + u32 *outbox; + u64 base; + u32 tmp; + int err = 0; + u8 lg; + int i; + +#define QUERY_FW_OUT_SIZE 0x100 +#define QUERY_FW_VER_OFFSET 0x00 +#define QUERY_FW_MAX_CMD_OFFSET 0x0f +#define QUERY_FW_ERR_START_OFFSET 0x30 +#define QUERY_FW_ERR_SIZE_OFFSET 0x38 + +#define QUERY_FW_CMD_DB_EN_OFFSET 0x10 +#define QUERY_FW_CMD_DB_OFFSET 0x50 +#define QUERY_FW_CMD_DB_BASE 0x60 + +#define QUERY_FW_START_OFFSET 0x20 +#define QUERY_FW_END_OFFSET 0x28 + +#define QUERY_FW_SIZE_OFFSET 0x00 +#define QUERY_FW_CLR_INT_BASE_OFFSET 0x20 +#define QUERY_FW_EQ_ARM_BASE_OFFSET 0x40 +#define QUERY_FW_EQ_SET_CI_BASE_OFFSET 0x48 + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_FW, + CMD_TIME_CLASS_A, status); + + if (err) + goto out; + + MTHCA_GET(dev->fw_ver, outbox, QUERY_FW_VER_OFFSET); + /* + * FW subminor version is at more significant bits than minor + * version, so swap here. + */ + dev->fw_ver = (dev->fw_ver & 0xffff00000000ull) | + ((dev->fw_ver & 0xffff0000ull) >> 16) | + ((dev->fw_ver & 0x0000ffffull) << 16); + + MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET); + dev->cmd.max_cmds = 1 << lg; + + mthca_dbg(dev, "FW version %012llx, max commands %d\n", + (unsigned long long) dev->fw_ver, dev->cmd.max_cmds); + + MTHCA_GET(dev->catas_err.addr, outbox, QUERY_FW_ERR_START_OFFSET); + MTHCA_GET(dev->catas_err.size, outbox, QUERY_FW_ERR_SIZE_OFFSET); + + mthca_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x\n", + (unsigned long long) dev->catas_err.addr, dev->catas_err.size); + + MTHCA_GET(tmp, outbox, QUERY_FW_CMD_DB_EN_OFFSET); + if (tmp & 0x1) { + mthca_dbg(dev, "FW supports commands through doorbells\n"); + + MTHCA_GET(base, outbox, QUERY_FW_CMD_DB_BASE); + for (i = 0; i < MTHCA_CMD_NUM_DBELL_DWORDS; ++i) + MTHCA_GET(dev->cmd.dbell_offsets[i], outbox, + QUERY_FW_CMD_DB_OFFSET + (i << 1)); + + mthca_setup_cmd_doorbells(dev, base); + } + + if (mthca_is_memfree(dev)) { + MTHCA_GET(dev->fw.arbel.fw_pages, outbox, QUERY_FW_SIZE_OFFSET); + MTHCA_GET(dev->fw.arbel.clr_int_base, outbox, QUERY_FW_CLR_INT_BASE_OFFSET); + MTHCA_GET(dev->fw.arbel.eq_arm_base, outbox, QUERY_FW_EQ_ARM_BASE_OFFSET); + MTHCA_GET(dev->fw.arbel.eq_set_ci_base, outbox, QUERY_FW_EQ_SET_CI_BASE_OFFSET); + mthca_dbg(dev, "FW size %d KB\n", dev->fw.arbel.fw_pages << 2); + + /* + * Round up number of system pages needed in case + * MTHCA_ICM_PAGE_SIZE < PAGE_SIZE. + */ + dev->fw.arbel.fw_pages = + ALIGN(dev->fw.arbel.fw_pages, PAGE_SIZE / MTHCA_ICM_PAGE_SIZE) >> + (PAGE_SHIFT - MTHCA_ICM_PAGE_SHIFT); + + mthca_dbg(dev, "Clear int @ %llx, EQ arm @ %llx, EQ set CI @ %llx\n", + (unsigned long long) dev->fw.arbel.clr_int_base, + (unsigned long long) dev->fw.arbel.eq_arm_base, + (unsigned long long) dev->fw.arbel.eq_set_ci_base); + } else { + MTHCA_GET(dev->fw.tavor.fw_start, outbox, QUERY_FW_START_OFFSET); + MTHCA_GET(dev->fw.tavor.fw_end, outbox, QUERY_FW_END_OFFSET); + + mthca_dbg(dev, "FW size %d KB (start %llx, end %llx)\n", + (int) ((dev->fw.tavor.fw_end - dev->fw.tavor.fw_start) >> 10), + (unsigned long long) dev->fw.tavor.fw_start, + (unsigned long long) dev->fw.tavor.fw_end); + } + +out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status) +{ + struct mthca_mailbox *mailbox; + u8 info; + u32 *outbox; + int err = 0; + +#define ENABLE_LAM_OUT_SIZE 0x100 +#define ENABLE_LAM_START_OFFSET 0x00 +#define ENABLE_LAM_END_OFFSET 0x08 +#define ENABLE_LAM_INFO_OFFSET 0x13 + +#define ENABLE_LAM_INFO_HIDDEN_FLAG (1 << 4) +#define ENABLE_LAM_INFO_ECC_MASK 0x3 + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_ENABLE_LAM, + CMD_TIME_CLASS_C, status); + + if (err) + goto out; + + if (*status == MTHCA_CMD_STAT_LAM_NOT_PRE) + goto out; + + MTHCA_GET(dev->ddr_start, outbox, ENABLE_LAM_START_OFFSET); + MTHCA_GET(dev->ddr_end, outbox, ENABLE_LAM_END_OFFSET); + MTHCA_GET(info, outbox, ENABLE_LAM_INFO_OFFSET); + + if (!!(info & ENABLE_LAM_INFO_HIDDEN_FLAG) != + !!(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) { + mthca_info(dev, "FW reports that HCA-attached memory " + "is %s hidden; does not match PCI config\n", + (info & ENABLE_LAM_INFO_HIDDEN_FLAG) ? + "" : "not"); + } + if (info & ENABLE_LAM_INFO_HIDDEN_FLAG) + mthca_dbg(dev, "HCA-attached memory is hidden.\n"); + + mthca_dbg(dev, "HCA memory size %d KB (start %llx, end %llx)\n", + (int) ((dev->ddr_end - dev->ddr_start) >> 10), + (unsigned long long) dev->ddr_start, + (unsigned long long) dev->ddr_end); + +out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_DISABLE_LAM(struct mthca_dev *dev, u8 *status) +{ + return mthca_cmd(dev, 0, 0, 0, CMD_SYS_DIS, CMD_TIME_CLASS_C, status); +} + +int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status) +{ + struct mthca_mailbox *mailbox; + u8 info; + u32 *outbox; + int err = 0; + +#define QUERY_DDR_OUT_SIZE 0x100 +#define QUERY_DDR_START_OFFSET 0x00 +#define QUERY_DDR_END_OFFSET 0x08 +#define QUERY_DDR_INFO_OFFSET 0x13 + +#define QUERY_DDR_INFO_HIDDEN_FLAG (1 << 4) +#define QUERY_DDR_INFO_ECC_MASK 0x3 + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DDR, + CMD_TIME_CLASS_A, status); + + if (err) + goto out; + + MTHCA_GET(dev->ddr_start, outbox, QUERY_DDR_START_OFFSET); + MTHCA_GET(dev->ddr_end, outbox, QUERY_DDR_END_OFFSET); + MTHCA_GET(info, outbox, QUERY_DDR_INFO_OFFSET); + + if (!!(info & QUERY_DDR_INFO_HIDDEN_FLAG) != + !!(dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) { + mthca_info(dev, "FW reports that HCA-attached memory " + "is %s hidden; does not match PCI config\n", + (info & QUERY_DDR_INFO_HIDDEN_FLAG) ? + "" : "not"); + } + if (info & QUERY_DDR_INFO_HIDDEN_FLAG) + mthca_dbg(dev, "HCA-attached memory is hidden.\n"); + + mthca_dbg(dev, "HCA memory size %d KB (start %llx, end %llx)\n", + (int) ((dev->ddr_end - dev->ddr_start) >> 10), + (unsigned long long) dev->ddr_start, + (unsigned long long) dev->ddr_end); + +out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, + struct mthca_dev_lim *dev_lim, u8 *status) +{ + struct mthca_mailbox *mailbox; + u32 *outbox; + u8 field; + u16 size; + u16 stat_rate; + int err; + +#define QUERY_DEV_LIM_OUT_SIZE 0x100 +#define QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET 0x10 +#define QUERY_DEV_LIM_MAX_QP_SZ_OFFSET 0x11 +#define QUERY_DEV_LIM_RSVD_QP_OFFSET 0x12 +#define QUERY_DEV_LIM_MAX_QP_OFFSET 0x13 +#define QUERY_DEV_LIM_RSVD_SRQ_OFFSET 0x14 +#define QUERY_DEV_LIM_MAX_SRQ_OFFSET 0x15 +#define QUERY_DEV_LIM_RSVD_EEC_OFFSET 0x16 +#define QUERY_DEV_LIM_MAX_EEC_OFFSET 0x17 +#define QUERY_DEV_LIM_MAX_CQ_SZ_OFFSET 0x19 +#define QUERY_DEV_LIM_RSVD_CQ_OFFSET 0x1a +#define QUERY_DEV_LIM_MAX_CQ_OFFSET 0x1b +#define QUERY_DEV_LIM_MAX_MPT_OFFSET 0x1d +#define QUERY_DEV_LIM_RSVD_EQ_OFFSET 0x1e +#define QUERY_DEV_LIM_MAX_EQ_OFFSET 0x1f +#define QUERY_DEV_LIM_RSVD_MTT_OFFSET 0x20 +#define QUERY_DEV_LIM_MAX_MRW_SZ_OFFSET 0x21 +#define QUERY_DEV_LIM_RSVD_MRW_OFFSET 0x22 +#define QUERY_DEV_LIM_MAX_MTT_SEG_OFFSET 0x23 +#define QUERY_DEV_LIM_MAX_AV_OFFSET 0x27 +#define QUERY_DEV_LIM_MAX_REQ_QP_OFFSET 0x29 +#define QUERY_DEV_LIM_MAX_RES_QP_OFFSET 0x2b +#define QUERY_DEV_LIM_MAX_RDMA_OFFSET 0x2f +#define QUERY_DEV_LIM_RSZ_SRQ_OFFSET 0x33 +#define QUERY_DEV_LIM_ACK_DELAY_OFFSET 0x35 +#define QUERY_DEV_LIM_MTU_WIDTH_OFFSET 0x36 +#define QUERY_DEV_LIM_VL_PORT_OFFSET 0x37 +#define QUERY_DEV_LIM_MAX_GID_OFFSET 0x3b +#define QUERY_DEV_LIM_RATE_SUPPORT_OFFSET 0x3c +#define QUERY_DEV_LIM_MAX_PKEY_OFFSET 0x3f +#define QUERY_DEV_LIM_FLAGS_OFFSET 0x44 +#define QUERY_DEV_LIM_RSVD_UAR_OFFSET 0x48 +#define QUERY_DEV_LIM_UAR_SZ_OFFSET 0x49 +#define QUERY_DEV_LIM_PAGE_SZ_OFFSET 0x4b +#define QUERY_DEV_LIM_MAX_SG_OFFSET 0x51 +#define QUERY_DEV_LIM_MAX_DESC_SZ_OFFSET 0x52 +#define QUERY_DEV_LIM_MAX_SG_RQ_OFFSET 0x55 +#define QUERY_DEV_LIM_MAX_DESC_SZ_RQ_OFFSET 0x56 +#define QUERY_DEV_LIM_MAX_QP_MCG_OFFSET 0x61 +#define QUERY_DEV_LIM_RSVD_MCG_OFFSET 0x62 +#define QUERY_DEV_LIM_MAX_MCG_OFFSET 0x63 +#define QUERY_DEV_LIM_RSVD_PD_OFFSET 0x64 +#define QUERY_DEV_LIM_MAX_PD_OFFSET 0x65 +#define QUERY_DEV_LIM_RSVD_RDD_OFFSET 0x66 +#define QUERY_DEV_LIM_MAX_RDD_OFFSET 0x67 +#define QUERY_DEV_LIM_EEC_ENTRY_SZ_OFFSET 0x80 +#define QUERY_DEV_LIM_QPC_ENTRY_SZ_OFFSET 0x82 +#define QUERY_DEV_LIM_EEEC_ENTRY_SZ_OFFSET 0x84 +#define QUERY_DEV_LIM_EQPC_ENTRY_SZ_OFFSET 0x86 +#define QUERY_DEV_LIM_EQC_ENTRY_SZ_OFFSET 0x88 +#define QUERY_DEV_LIM_CQC_ENTRY_SZ_OFFSET 0x8a +#define QUERY_DEV_LIM_SRQ_ENTRY_SZ_OFFSET 0x8c +#define QUERY_DEV_LIM_UAR_ENTRY_SZ_OFFSET 0x8e +#define QUERY_DEV_LIM_MTT_ENTRY_SZ_OFFSET 0x90 +#define QUERY_DEV_LIM_MPT_ENTRY_SZ_OFFSET 0x92 +#define QUERY_DEV_LIM_PBL_SZ_OFFSET 0x96 +#define QUERY_DEV_LIM_BMME_FLAGS_OFFSET 0x97 +#define QUERY_DEV_LIM_RSVD_LKEY_OFFSET 0x98 +#define QUERY_DEV_LIM_LAMR_OFFSET 0x9f +#define QUERY_DEV_LIM_MAX_ICM_SZ_OFFSET 0xa0 + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DEV_LIM, + CMD_TIME_CLASS_A, status); + + if (err) + goto out; + + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_QP_OFFSET); + dev_lim->reserved_qps = 1 << (field & 0xf); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_OFFSET); + dev_lim->max_qps = 1 << (field & 0x1f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_SRQ_OFFSET); + dev_lim->reserved_srqs = 1 << (field >> 4); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_OFFSET); + dev_lim->max_srqs = 1 << (field & 0x1f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_EEC_OFFSET); + dev_lim->reserved_eecs = 1 << (field & 0xf); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_EEC_OFFSET); + dev_lim->max_eecs = 1 << (field & 0x1f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_CQ_SZ_OFFSET); + dev_lim->max_cq_sz = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_CQ_OFFSET); + dev_lim->reserved_cqs = 1 << (field & 0xf); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_CQ_OFFSET); + dev_lim->max_cqs = 1 << (field & 0x1f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MPT_OFFSET); + dev_lim->max_mpts = 1 << (field & 0x3f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_EQ_OFFSET); + dev_lim->reserved_eqs = 1 << (field & 0xf); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_EQ_OFFSET); + dev_lim->max_eqs = 1 << (field & 0x7); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MTT_OFFSET); + if (mthca_is_memfree(dev)) + dev_lim->reserved_mtts = ALIGN((1 << (field >> 4)) * sizeof(u64), + dev->limits.mtt_seg_size) / dev->limits.mtt_seg_size; + else + dev_lim->reserved_mtts = 1 << (field >> 4); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MRW_SZ_OFFSET); + dev_lim->max_mrw_sz = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MRW_OFFSET); + dev_lim->reserved_mrws = 1 << (field & 0xf); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MTT_SEG_OFFSET); + dev_lim->max_mtt_seg = 1 << (field & 0x3f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_REQ_QP_OFFSET); + dev_lim->max_requester_per_qp = 1 << (field & 0x3f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_RES_QP_OFFSET); + dev_lim->max_responder_per_qp = 1 << (field & 0x3f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_RDMA_OFFSET); + dev_lim->max_rdma_global = 1 << (field & 0x3f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_ACK_DELAY_OFFSET); + dev_lim->local_ca_ack_delay = field & 0x1f; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MTU_WIDTH_OFFSET); + dev_lim->max_mtu = field >> 4; + dev_lim->max_port_width = field & 0xf; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_VL_PORT_OFFSET); + dev_lim->max_vl = field >> 4; + dev_lim->num_ports = field & 0xf; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_GID_OFFSET); + dev_lim->max_gids = 1 << (field & 0xf); + MTHCA_GET(stat_rate, outbox, QUERY_DEV_LIM_RATE_SUPPORT_OFFSET); + dev_lim->stat_rate_support = stat_rate; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_PKEY_OFFSET); + dev_lim->max_pkeys = 1 << (field & 0xf); + MTHCA_GET(dev_lim->flags, outbox, QUERY_DEV_LIM_FLAGS_OFFSET); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_UAR_OFFSET); + dev_lim->reserved_uars = field >> 4; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_UAR_SZ_OFFSET); + dev_lim->uar_size = 1 << ((field & 0x3f) + 20); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_PAGE_SZ_OFFSET); + dev_lim->min_page_sz = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SG_OFFSET); + dev_lim->max_sg = field; + + MTHCA_GET(size, outbox, QUERY_DEV_LIM_MAX_DESC_SZ_OFFSET); + dev_lim->max_desc_sz = size; + + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_MCG_OFFSET); + dev_lim->max_qp_per_mcg = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_MCG_OFFSET); + dev_lim->reserved_mgms = field & 0xf; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_MCG_OFFSET); + dev_lim->max_mcgs = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_PD_OFFSET); + dev_lim->reserved_pds = field >> 4; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_PD_OFFSET); + dev_lim->max_pds = 1 << (field & 0x3f); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSVD_RDD_OFFSET); + dev_lim->reserved_rdds = field >> 4; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_RDD_OFFSET); + dev_lim->max_rdds = 1 << (field & 0x3f); + + MTHCA_GET(size, outbox, QUERY_DEV_LIM_EEC_ENTRY_SZ_OFFSET); + dev_lim->eec_entry_sz = size; + MTHCA_GET(size, outbox, QUERY_DEV_LIM_QPC_ENTRY_SZ_OFFSET); + dev_lim->qpc_entry_sz = size; + MTHCA_GET(size, outbox, QUERY_DEV_LIM_EEEC_ENTRY_SZ_OFFSET); + dev_lim->eeec_entry_sz = size; + MTHCA_GET(size, outbox, QUERY_DEV_LIM_EQPC_ENTRY_SZ_OFFSET); + dev_lim->eqpc_entry_sz = size; + MTHCA_GET(size, outbox, QUERY_DEV_LIM_EQC_ENTRY_SZ_OFFSET); + dev_lim->eqc_entry_sz = size; + MTHCA_GET(size, outbox, QUERY_DEV_LIM_CQC_ENTRY_SZ_OFFSET); + dev_lim->cqc_entry_sz = size; + MTHCA_GET(size, outbox, QUERY_DEV_LIM_SRQ_ENTRY_SZ_OFFSET); + dev_lim->srq_entry_sz = size; + MTHCA_GET(size, outbox, QUERY_DEV_LIM_UAR_ENTRY_SZ_OFFSET); + dev_lim->uar_scratch_entry_sz = size; + + if (mthca_is_memfree(dev)) { + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET); + dev_lim->max_srq_sz = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET); + dev_lim->max_qp_sz = 1 << field; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_RSZ_SRQ_OFFSET); + dev_lim->hca.arbel.resize_srq = field & 1; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SG_RQ_OFFSET); + dev_lim->max_sg = min_t(int, field, dev_lim->max_sg); + MTHCA_GET(size, outbox, QUERY_DEV_LIM_MAX_DESC_SZ_RQ_OFFSET); + dev_lim->max_desc_sz = min_t(int, size, dev_lim->max_desc_sz); + MTHCA_GET(size, outbox, QUERY_DEV_LIM_MPT_ENTRY_SZ_OFFSET); + dev_lim->mpt_entry_sz = size; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_PBL_SZ_OFFSET); + dev_lim->hca.arbel.max_pbl_sz = 1 << (field & 0x3f); + MTHCA_GET(dev_lim->hca.arbel.bmme_flags, outbox, + QUERY_DEV_LIM_BMME_FLAGS_OFFSET); + MTHCA_GET(dev_lim->hca.arbel.reserved_lkey, outbox, + QUERY_DEV_LIM_RSVD_LKEY_OFFSET); + MTHCA_GET(field, outbox, QUERY_DEV_LIM_LAMR_OFFSET); + dev_lim->hca.arbel.lam_required = field & 1; + MTHCA_GET(dev_lim->hca.arbel.max_icm_sz, outbox, + QUERY_DEV_LIM_MAX_ICM_SZ_OFFSET); + + if (dev_lim->hca.arbel.bmme_flags & 1) + mthca_dbg(dev, "Base MM extensions: yes " + "(flags %d, max PBL %d, rsvd L_Key %08x)\n", + dev_lim->hca.arbel.bmme_flags, + dev_lim->hca.arbel.max_pbl_sz, + dev_lim->hca.arbel.reserved_lkey); + else + mthca_dbg(dev, "Base MM extensions: no\n"); + + mthca_dbg(dev, "Max ICM size %lld MB\n", + (unsigned long long) dev_lim->hca.arbel.max_icm_sz >> 20); + } else { + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_SRQ_SZ_OFFSET); + dev_lim->max_srq_sz = (1 << field) - 1; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_QP_SZ_OFFSET); + dev_lim->max_qp_sz = (1 << field) - 1; + MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_AV_OFFSET); + dev_lim->hca.tavor.max_avs = 1 << (field & 0x3f); + dev_lim->mpt_entry_sz = MTHCA_MPT_ENTRY_SIZE; + } + + mthca_dbg(dev, "Max QPs: %d, reserved QPs: %d, entry size: %d\n", + dev_lim->max_qps, dev_lim->reserved_qps, dev_lim->qpc_entry_sz); + mthca_dbg(dev, "Max SRQs: %d, reserved SRQs: %d, entry size: %d\n", + dev_lim->max_srqs, dev_lim->reserved_srqs, dev_lim->srq_entry_sz); + mthca_dbg(dev, "Max CQs: %d, reserved CQs: %d, entry size: %d\n", + dev_lim->max_cqs, dev_lim->reserved_cqs, dev_lim->cqc_entry_sz); + mthca_dbg(dev, "Max EQs: %d, reserved EQs: %d, entry size: %d\n", + dev_lim->max_eqs, dev_lim->reserved_eqs, dev_lim->eqc_entry_sz); + mthca_dbg(dev, "reserved MPTs: %d, reserved MTTs: %d\n", + dev_lim->reserved_mrws, dev_lim->reserved_mtts); + mthca_dbg(dev, "Max PDs: %d, reserved PDs: %d, reserved UARs: %d\n", + dev_lim->max_pds, dev_lim->reserved_pds, dev_lim->reserved_uars); + mthca_dbg(dev, "Max QP/MCG: %d, reserved MGMs: %d\n", + dev_lim->max_pds, dev_lim->reserved_mgms); + mthca_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n", + dev_lim->max_cq_sz, dev_lim->max_qp_sz, dev_lim->max_srq_sz); + + mthca_dbg(dev, "Flags: %08x\n", dev_lim->flags); + +out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +static void get_board_id(void *vsd, char *board_id) +{ + int i; + +#define VSD_OFFSET_SIG1 0x00 +#define VSD_OFFSET_SIG2 0xde +#define VSD_OFFSET_MLX_BOARD_ID 0xd0 +#define VSD_OFFSET_TS_BOARD_ID 0x20 + +#define VSD_SIGNATURE_TOPSPIN 0x5ad + + memset(board_id, 0, MTHCA_BOARD_ID_LEN); + + if (be16_to_cpup(vsd + VSD_OFFSET_SIG1) == VSD_SIGNATURE_TOPSPIN && + be16_to_cpup(vsd + VSD_OFFSET_SIG2) == VSD_SIGNATURE_TOPSPIN) { + strlcpy(board_id, vsd + VSD_OFFSET_TS_BOARD_ID, MTHCA_BOARD_ID_LEN); + } else { + /* + * The board ID is a string but the firmware byte + * swaps each 4-byte word before passing it back to + * us. Therefore we need to swab it before printing. + */ + for (i = 0; i < 4; ++i) + ((u32 *) board_id)[i] = + swab32(*(u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4)); + } +} + +int mthca_QUERY_ADAPTER(struct mthca_dev *dev, + struct mthca_adapter *adapter, u8 *status) +{ + struct mthca_mailbox *mailbox; + u32 *outbox; + int err; + +#define QUERY_ADAPTER_OUT_SIZE 0x100 +#define QUERY_ADAPTER_VENDOR_ID_OFFSET 0x00 +#define QUERY_ADAPTER_DEVICE_ID_OFFSET 0x04 +#define QUERY_ADAPTER_REVISION_ID_OFFSET 0x08 +#define QUERY_ADAPTER_INTA_PIN_OFFSET 0x10 +#define QUERY_ADAPTER_VSD_OFFSET 0x20 + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_ADAPTER, + CMD_TIME_CLASS_A, status); + + if (err) + goto out; + + if (!mthca_is_memfree(dev)) { + MTHCA_GET(adapter->vendor_id, outbox, + QUERY_ADAPTER_VENDOR_ID_OFFSET); + MTHCA_GET(adapter->device_id, outbox, + QUERY_ADAPTER_DEVICE_ID_OFFSET); + MTHCA_GET(adapter->revision_id, outbox, + QUERY_ADAPTER_REVISION_ID_OFFSET); + } + MTHCA_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET); + + get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4, + adapter->board_id); + +out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_INIT_HCA(struct mthca_dev *dev, + struct mthca_init_hca_param *param, + u8 *status) +{ + struct mthca_mailbox *mailbox; + __be32 *inbox; + int err; + +#define INIT_HCA_IN_SIZE 0x200 +#define INIT_HCA_FLAGS1_OFFSET 0x00c +#define INIT_HCA_FLAGS2_OFFSET 0x014 +#define INIT_HCA_QPC_OFFSET 0x020 +#define INIT_HCA_QPC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x10) +#define INIT_HCA_LOG_QP_OFFSET (INIT_HCA_QPC_OFFSET + 0x17) +#define INIT_HCA_EEC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x20) +#define INIT_HCA_LOG_EEC_OFFSET (INIT_HCA_QPC_OFFSET + 0x27) +#define INIT_HCA_SRQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x28) +#define INIT_HCA_LOG_SRQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x2f) +#define INIT_HCA_CQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x30) +#define INIT_HCA_LOG_CQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x37) +#define INIT_HCA_EQPC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x40) +#define INIT_HCA_EEEC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x50) +#define INIT_HCA_EQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x60) +#define INIT_HCA_LOG_EQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x67) +#define INIT_HCA_RDB_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x70) +#define INIT_HCA_UDAV_OFFSET 0x0b0 +#define INIT_HCA_UDAV_LKEY_OFFSET (INIT_HCA_UDAV_OFFSET + 0x0) +#define INIT_HCA_UDAV_PD_OFFSET (INIT_HCA_UDAV_OFFSET + 0x4) +#define INIT_HCA_MCAST_OFFSET 0x0c0 +#define INIT_HCA_MC_BASE_OFFSET (INIT_HCA_MCAST_OFFSET + 0x00) +#define INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12) +#define INIT_HCA_MC_HASH_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x16) +#define INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b) +#define INIT_HCA_TPT_OFFSET 0x0f0 +#define INIT_HCA_MPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x00) +#define INIT_HCA_MTT_SEG_SZ_OFFSET (INIT_HCA_TPT_OFFSET + 0x09) +#define INIT_HCA_LOG_MPT_SZ_OFFSET (INIT_HCA_TPT_OFFSET + 0x0b) +#define INIT_HCA_MTT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x10) +#define INIT_HCA_UAR_OFFSET 0x120 +#define INIT_HCA_UAR_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x00) +#define INIT_HCA_UARC_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x09) +#define INIT_HCA_LOG_UAR_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x0a) +#define INIT_HCA_UAR_PAGE_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x0b) +#define INIT_HCA_UAR_SCATCH_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x10) +#define INIT_HCA_UAR_CTX_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x18) + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + memset(inbox, 0, INIT_HCA_IN_SIZE); + + if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT) + MTHCA_PUT(inbox, 0x1, INIT_HCA_FLAGS1_OFFSET); + +#if defined(__LITTLE_ENDIAN) + *(inbox + INIT_HCA_FLAGS2_OFFSET / 4) &= ~cpu_to_be32(1 << 1); +#elif defined(__BIG_ENDIAN) + *(inbox + INIT_HCA_FLAGS2_OFFSET / 4) |= cpu_to_be32(1 << 1); +#else +#error Host endianness not defined +#endif + /* Check port for UD address vector: */ + *(inbox + INIT_HCA_FLAGS2_OFFSET / 4) |= cpu_to_be32(1); + + /* Enable IPoIB checksumming if we can: */ + if (dev->device_cap_flags & IB_DEVICE_UD_IP_CSUM) + *(inbox + INIT_HCA_FLAGS2_OFFSET / 4) |= cpu_to_be32(7 << 3); + + /* We leave wqe_quota, responder_exu, etc as 0 (default) */ + + /* QPC/EEC/CQC/EQC/RDB attributes */ + + MTHCA_PUT(inbox, param->qpc_base, INIT_HCA_QPC_BASE_OFFSET); + MTHCA_PUT(inbox, param->log_num_qps, INIT_HCA_LOG_QP_OFFSET); + MTHCA_PUT(inbox, param->eec_base, INIT_HCA_EEC_BASE_OFFSET); + MTHCA_PUT(inbox, param->log_num_eecs, INIT_HCA_LOG_EEC_OFFSET); + MTHCA_PUT(inbox, param->srqc_base, INIT_HCA_SRQC_BASE_OFFSET); + MTHCA_PUT(inbox, param->log_num_srqs, INIT_HCA_LOG_SRQ_OFFSET); + MTHCA_PUT(inbox, param->cqc_base, INIT_HCA_CQC_BASE_OFFSET); + MTHCA_PUT(inbox, param->log_num_cqs, INIT_HCA_LOG_CQ_OFFSET); + MTHCA_PUT(inbox, param->eqpc_base, INIT_HCA_EQPC_BASE_OFFSET); + MTHCA_PUT(inbox, param->eeec_base, INIT_HCA_EEEC_BASE_OFFSET); + MTHCA_PUT(inbox, param->eqc_base, INIT_HCA_EQC_BASE_OFFSET); + MTHCA_PUT(inbox, param->log_num_eqs, INIT_HCA_LOG_EQ_OFFSET); + MTHCA_PUT(inbox, param->rdb_base, INIT_HCA_RDB_BASE_OFFSET); + + /* UD AV attributes */ + + /* multicast attributes */ + + MTHCA_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET); + MTHCA_PUT(inbox, param->log_mc_entry_sz, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); + MTHCA_PUT(inbox, param->mc_hash_sz, INIT_HCA_MC_HASH_SZ_OFFSET); + MTHCA_PUT(inbox, param->log_mc_table_sz, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); + + /* TPT attributes */ + + MTHCA_PUT(inbox, param->mpt_base, INIT_HCA_MPT_BASE_OFFSET); + if (!mthca_is_memfree(dev)) + MTHCA_PUT(inbox, param->mtt_seg_sz, INIT_HCA_MTT_SEG_SZ_OFFSET); + MTHCA_PUT(inbox, param->log_mpt_sz, INIT_HCA_LOG_MPT_SZ_OFFSET); + MTHCA_PUT(inbox, param->mtt_base, INIT_HCA_MTT_BASE_OFFSET); + + /* UAR attributes */ + { + u8 uar_page_sz = PAGE_SHIFT - 12; + MTHCA_PUT(inbox, uar_page_sz, INIT_HCA_UAR_PAGE_SZ_OFFSET); + } + + MTHCA_PUT(inbox, param->uar_scratch_base, INIT_HCA_UAR_SCATCH_BASE_OFFSET); + + if (mthca_is_memfree(dev)) { + MTHCA_PUT(inbox, param->log_uarc_sz, INIT_HCA_UARC_SZ_OFFSET); + MTHCA_PUT(inbox, param->log_uar_sz, INIT_HCA_LOG_UAR_SZ_OFFSET); + MTHCA_PUT(inbox, param->uarc_base, INIT_HCA_UAR_CTX_BASE_OFFSET); + } + + err = mthca_cmd(dev, mailbox->dma, 0, 0, CMD_INIT_HCA, CMD_TIME_CLASS_D, status); + + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_INIT_IB(struct mthca_dev *dev, + struct mthca_init_ib_param *param, + int port, u8 *status) +{ + struct mthca_mailbox *mailbox; + u32 *inbox; + int err; + u32 flags; + +#define INIT_IB_IN_SIZE 56 +#define INIT_IB_FLAGS_OFFSET 0x00 +#define INIT_IB_FLAG_SIG (1 << 18) +#define INIT_IB_FLAG_NG (1 << 17) +#define INIT_IB_FLAG_G0 (1 << 16) +#define INIT_IB_VL_SHIFT 4 +#define INIT_IB_PORT_WIDTH_SHIFT 8 +#define INIT_IB_MTU_SHIFT 12 +#define INIT_IB_MAX_GID_OFFSET 0x06 +#define INIT_IB_MAX_PKEY_OFFSET 0x0a +#define INIT_IB_GUID0_OFFSET 0x10 +#define INIT_IB_NODE_GUID_OFFSET 0x18 +#define INIT_IB_SI_GUID_OFFSET 0x20 + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + memset(inbox, 0, INIT_IB_IN_SIZE); + + flags = 0; + flags |= param->set_guid0 ? INIT_IB_FLAG_G0 : 0; + flags |= param->set_node_guid ? INIT_IB_FLAG_NG : 0; + flags |= param->set_si_guid ? INIT_IB_FLAG_SIG : 0; + flags |= param->vl_cap << INIT_IB_VL_SHIFT; + flags |= param->port_width << INIT_IB_PORT_WIDTH_SHIFT; + flags |= param->mtu_cap << INIT_IB_MTU_SHIFT; + MTHCA_PUT(inbox, flags, INIT_IB_FLAGS_OFFSET); + + MTHCA_PUT(inbox, param->gid_cap, INIT_IB_MAX_GID_OFFSET); + MTHCA_PUT(inbox, param->pkey_cap, INIT_IB_MAX_PKEY_OFFSET); + MTHCA_PUT(inbox, param->guid0, INIT_IB_GUID0_OFFSET); + MTHCA_PUT(inbox, param->node_guid, INIT_IB_NODE_GUID_OFFSET); + MTHCA_PUT(inbox, param->si_guid, INIT_IB_SI_GUID_OFFSET); + + err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_INIT_IB, + CMD_TIME_CLASS_A, status); + + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_CLOSE_IB(struct mthca_dev *dev, int port, u8 *status) +{ + return mthca_cmd(dev, 0, port, 0, CMD_CLOSE_IB, CMD_TIME_CLASS_A, status); +} + +int mthca_CLOSE_HCA(struct mthca_dev *dev, int panic, u8 *status) +{ + return mthca_cmd(dev, 0, 0, panic, CMD_CLOSE_HCA, CMD_TIME_CLASS_C, status); +} + +int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param, + int port, u8 *status) +{ + struct mthca_mailbox *mailbox; + u32 *inbox; + int err; + u32 flags = 0; + +#define SET_IB_IN_SIZE 0x40 +#define SET_IB_FLAGS_OFFSET 0x00 +#define SET_IB_FLAG_SIG (1 << 18) +#define SET_IB_FLAG_RQK (1 << 0) +#define SET_IB_CAP_MASK_OFFSET 0x04 +#define SET_IB_SI_GUID_OFFSET 0x08 + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + memset(inbox, 0, SET_IB_IN_SIZE); + + flags |= param->set_si_guid ? SET_IB_FLAG_SIG : 0; + flags |= param->reset_qkey_viol ? SET_IB_FLAG_RQK : 0; + MTHCA_PUT(inbox, flags, SET_IB_FLAGS_OFFSET); + + MTHCA_PUT(inbox, param->cap_mask, SET_IB_CAP_MASK_OFFSET); + MTHCA_PUT(inbox, param->si_guid, SET_IB_SI_GUID_OFFSET); + + err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_SET_IB, + CMD_TIME_CLASS_B, status); + + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_MAP_ICM(struct mthca_dev *dev, struct mthca_icm *icm, u64 virt, u8 *status) +{ + return mthca_map_cmd(dev, CMD_MAP_ICM, icm, virt, status); +} + +int mthca_MAP_ICM_page(struct mthca_dev *dev, u64 dma_addr, u64 virt, u8 *status) +{ + struct mthca_mailbox *mailbox; + __be64 *inbox; + int err; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + inbox[0] = cpu_to_be64(virt); + inbox[1] = cpu_to_be64(dma_addr); + + err = mthca_cmd(dev, mailbox->dma, 1, 0, CMD_MAP_ICM, + CMD_TIME_CLASS_B, status); + + mthca_free_mailbox(dev, mailbox); + + if (!err) + mthca_dbg(dev, "Mapped page at %llx to %llx for ICM.\n", + (unsigned long long) dma_addr, (unsigned long long) virt); + + return err; +} + +int mthca_UNMAP_ICM(struct mthca_dev *dev, u64 virt, u32 page_count, u8 *status) +{ + mthca_dbg(dev, "Unmapping %d pages at %llx from ICM.\n", + page_count, (unsigned long long) virt); + + return mthca_cmd(dev, virt, page_count, 0, CMD_UNMAP_ICM, CMD_TIME_CLASS_B, status); +} + +int mthca_MAP_ICM_AUX(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status) +{ + return mthca_map_cmd(dev, CMD_MAP_ICM_AUX, icm, -1, status); +} + +int mthca_UNMAP_ICM_AUX(struct mthca_dev *dev, u8 *status) +{ + return mthca_cmd(dev, 0, 0, 0, CMD_UNMAP_ICM_AUX, CMD_TIME_CLASS_B, status); +} + +int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages, + u8 *status) +{ + int ret = mthca_cmd_imm(dev, icm_size, aux_pages, 0, 0, CMD_SET_ICM_SIZE, + CMD_TIME_CLASS_A, status); + + if (ret || status) + return ret; + + /* + * Round up number of system pages needed in case + * MTHCA_ICM_PAGE_SIZE < PAGE_SIZE. + */ + *aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MTHCA_ICM_PAGE_SIZE) >> + (PAGE_SHIFT - MTHCA_ICM_PAGE_SHIFT); + + return 0; +} + +int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int mpt_index, u8 *status) +{ + return mthca_cmd(dev, mailbox->dma, mpt_index, 0, CMD_SW2HW_MPT, + CMD_TIME_CLASS_B, status); +} + +int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int mpt_index, u8 *status) +{ + return mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index, + !mailbox, CMD_HW2SW_MPT, + CMD_TIME_CLASS_B, status); +} + +int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int num_mtt, u8 *status) +{ + return mthca_cmd(dev, mailbox->dma, num_mtt, 0, CMD_WRITE_MTT, + CMD_TIME_CLASS_B, status); +} + +int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status) +{ + return mthca_cmd(dev, 0, 0, 0, CMD_SYNC_TPT, CMD_TIME_CLASS_B, status); +} + +int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap, + int eq_num, u8 *status) +{ + mthca_dbg(dev, "%s mask %016llx for eqn %d\n", + unmap ? "Clearing" : "Setting", + (unsigned long long) event_mask, eq_num); + return mthca_cmd(dev, event_mask, (unmap << 31) | eq_num, + 0, CMD_MAP_EQ, CMD_TIME_CLASS_B, status); +} + +int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int eq_num, u8 *status) +{ + return mthca_cmd(dev, mailbox->dma, eq_num, 0, CMD_SW2HW_EQ, + CMD_TIME_CLASS_A, status); +} + +int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int eq_num, u8 *status) +{ + return mthca_cmd_box(dev, 0, mailbox->dma, eq_num, 0, + CMD_HW2SW_EQ, + CMD_TIME_CLASS_A, status); +} + +int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int cq_num, u8 *status) +{ + return mthca_cmd(dev, mailbox->dma, cq_num, 0, CMD_SW2HW_CQ, + CMD_TIME_CLASS_A, status); +} + +int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int cq_num, u8 *status) +{ + return mthca_cmd_box(dev, 0, mailbox->dma, cq_num, 0, + CMD_HW2SW_CQ, + CMD_TIME_CLASS_A, status); +} + +int mthca_RESIZE_CQ(struct mthca_dev *dev, int cq_num, u32 lkey, u8 log_size, + u8 *status) +{ + struct mthca_mailbox *mailbox; + __be32 *inbox; + int err; + +#define RESIZE_CQ_IN_SIZE 0x40 +#define RESIZE_CQ_LOG_SIZE_OFFSET 0x0c +#define RESIZE_CQ_LKEY_OFFSET 0x1c + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + memset(inbox, 0, RESIZE_CQ_IN_SIZE); + /* + * Leave start address fields zeroed out -- mthca assumes that + * MRs for CQs always start at virtual address 0. + */ + MTHCA_PUT(inbox, log_size, RESIZE_CQ_LOG_SIZE_OFFSET); + MTHCA_PUT(inbox, lkey, RESIZE_CQ_LKEY_OFFSET); + + err = mthca_cmd(dev, mailbox->dma, cq_num, 1, CMD_RESIZE_CQ, + CMD_TIME_CLASS_B, status); + + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int srq_num, u8 *status) +{ + return mthca_cmd(dev, mailbox->dma, srq_num, 0, CMD_SW2HW_SRQ, + CMD_TIME_CLASS_A, status); +} + +int mthca_HW2SW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int srq_num, u8 *status) +{ + return mthca_cmd_box(dev, 0, mailbox->dma, srq_num, 0, + CMD_HW2SW_SRQ, + CMD_TIME_CLASS_A, status); +} + +int mthca_QUERY_SRQ(struct mthca_dev *dev, u32 num, + struct mthca_mailbox *mailbox, u8 *status) +{ + return mthca_cmd_box(dev, 0, mailbox->dma, num, 0, + CMD_QUERY_SRQ, CMD_TIME_CLASS_A, status); +} + +int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status) +{ + return mthca_cmd(dev, limit, srq_num, 0, CMD_ARM_SRQ, + CMD_TIME_CLASS_B, status); +} + +int mthca_MODIFY_QP(struct mthca_dev *dev, enum ib_qp_state cur, + enum ib_qp_state next, u32 num, int is_ee, + struct mthca_mailbox *mailbox, u32 optmask, + u8 *status) +{ + static const u16 op[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = { + [IB_QPS_RESET] = { + [IB_QPS_RESET] = CMD_ERR2RST_QPEE, + [IB_QPS_ERR] = CMD_2ERR_QPEE, + [IB_QPS_INIT] = CMD_RST2INIT_QPEE, + }, + [IB_QPS_INIT] = { + [IB_QPS_RESET] = CMD_ERR2RST_QPEE, + [IB_QPS_ERR] = CMD_2ERR_QPEE, + [IB_QPS_INIT] = CMD_INIT2INIT_QPEE, + [IB_QPS_RTR] = CMD_INIT2RTR_QPEE, + }, + [IB_QPS_RTR] = { + [IB_QPS_RESET] = CMD_ERR2RST_QPEE, + [IB_QPS_ERR] = CMD_2ERR_QPEE, + [IB_QPS_RTS] = CMD_RTR2RTS_QPEE, + }, + [IB_QPS_RTS] = { + [IB_QPS_RESET] = CMD_ERR2RST_QPEE, + [IB_QPS_ERR] = CMD_2ERR_QPEE, + [IB_QPS_RTS] = CMD_RTS2RTS_QPEE, + [IB_QPS_SQD] = CMD_RTS2SQD_QPEE, + }, + [IB_QPS_SQD] = { + [IB_QPS_RESET] = CMD_ERR2RST_QPEE, + [IB_QPS_ERR] = CMD_2ERR_QPEE, + [IB_QPS_RTS] = CMD_SQD2RTS_QPEE, + [IB_QPS_SQD] = CMD_SQD2SQD_QPEE, + }, + [IB_QPS_SQE] = { + [IB_QPS_RESET] = CMD_ERR2RST_QPEE, + [IB_QPS_ERR] = CMD_2ERR_QPEE, + [IB_QPS_RTS] = CMD_SQERR2RTS_QPEE, + }, + [IB_QPS_ERR] = { + [IB_QPS_RESET] = CMD_ERR2RST_QPEE, + [IB_QPS_ERR] = CMD_2ERR_QPEE, + } + }; + + u8 op_mod = 0; + int my_mailbox = 0; + int err; + + if (op[cur][next] == CMD_ERR2RST_QPEE) { + op_mod = 3; /* don't write outbox, any->reset */ + + /* For debugging */ + if (!mailbox) { + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (!IS_ERR(mailbox)) { + my_mailbox = 1; + op_mod = 2; /* write outbox, any->reset */ + } else + mailbox = NULL; + } + + err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, + (!!is_ee << 24) | num, op_mod, + op[cur][next], CMD_TIME_CLASS_C, status); + + if (0 && mailbox) { + int i; + mthca_dbg(dev, "Dumping QP context:\n"); + printk(" %08x\n", be32_to_cpup(mailbox->buf)); + for (i = 0; i < 0x100 / 4; ++i) { + if (i % 8 == 0) + printk("[%02x] ", i * 4); + printk(" %08x", + be32_to_cpu(((__be32 *) mailbox->buf)[i + 2])); + if ((i + 1) % 8 == 0) + printk("\n"); + } + } + + if (my_mailbox) + mthca_free_mailbox(dev, mailbox); + } else { + if (0) { + int i; + mthca_dbg(dev, "Dumping QP context:\n"); + printk(" opt param mask: %08x\n", be32_to_cpup(mailbox->buf)); + for (i = 0; i < 0x100 / 4; ++i) { + if (i % 8 == 0) + printk(" [%02x] ", i * 4); + printk(" %08x", + be32_to_cpu(((__be32 *) mailbox->buf)[i + 2])); + if ((i + 1) % 8 == 0) + printk("\n"); + } + } + + err = mthca_cmd(dev, mailbox->dma, optmask | (!!is_ee << 24) | num, + op_mod, op[cur][next], CMD_TIME_CLASS_C, status); + } + + return err; +} + +int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee, + struct mthca_mailbox *mailbox, u8 *status) +{ + return mthca_cmd_box(dev, 0, mailbox->dma, (!!is_ee << 24) | num, 0, + CMD_QUERY_QPEE, CMD_TIME_CLASS_A, status); +} + +int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn, + u8 *status) +{ + u8 op_mod; + + switch (type) { + case IB_QPT_SMI: + op_mod = 0; + break; + case IB_QPT_GSI: + op_mod = 1; + break; + case IB_QPT_RAW_IPV6: + op_mod = 2; + break; + case IB_QPT_RAW_ETY: + op_mod = 3; + break; + default: + return -EINVAL; + } + + return mthca_cmd(dev, 0, qpn, op_mod, CMD_CONF_SPECIAL_QP, + CMD_TIME_CLASS_B, status); +} + +int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey, + int port, struct ib_wc *in_wc, struct ib_grh *in_grh, + void *in_mad, void *response_mad, u8 *status) +{ + struct mthca_mailbox *inmailbox, *outmailbox; + void *inbox; + int err; + u32 in_modifier = port; + u8 op_modifier = 0; + +#define MAD_IFC_BOX_SIZE 0x400 +#define MAD_IFC_MY_QPN_OFFSET 0x100 +#define MAD_IFC_RQPN_OFFSET 0x108 +#define MAD_IFC_SL_OFFSET 0x10c +#define MAD_IFC_G_PATH_OFFSET 0x10d +#define MAD_IFC_RLID_OFFSET 0x10e +#define MAD_IFC_PKEY_OFFSET 0x112 +#define MAD_IFC_GRH_OFFSET 0x140 + + inmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(inmailbox)) + return PTR_ERR(inmailbox); + inbox = inmailbox->buf; + + outmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(outmailbox)) { + mthca_free_mailbox(dev, inmailbox); + return PTR_ERR(outmailbox); + } + + memcpy(inbox, in_mad, 256); + + /* + * Key check traps can't be generated unless we have in_wc to + * tell us where to send the trap. + */ + if (ignore_mkey || !in_wc) + op_modifier |= 0x1; + if (ignore_bkey || !in_wc) + op_modifier |= 0x2; + + if (in_wc) { + u8 val; + + memset(inbox + 256, 0, 256); + + MTHCA_PUT(inbox, in_wc->qp->qp_num, MAD_IFC_MY_QPN_OFFSET); + MTHCA_PUT(inbox, in_wc->src_qp, MAD_IFC_RQPN_OFFSET); + + val = in_wc->sl << 4; + MTHCA_PUT(inbox, val, MAD_IFC_SL_OFFSET); + + val = in_wc->dlid_path_bits | + (in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0); + MTHCA_PUT(inbox, val, MAD_IFC_G_PATH_OFFSET); + + MTHCA_PUT(inbox, in_wc->slid, MAD_IFC_RLID_OFFSET); + MTHCA_PUT(inbox, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET); + + if (in_grh) + memcpy(inbox + MAD_IFC_GRH_OFFSET, in_grh, 40); + + op_modifier |= 0x4; + + in_modifier |= in_wc->slid << 16; + } + + err = mthca_cmd_box(dev, inmailbox->dma, outmailbox->dma, + in_modifier, op_modifier, + CMD_MAD_IFC, CMD_TIME_CLASS_C, status); + + if (!err && !*status) + memcpy(response_mad, outmailbox->buf, 256); + + mthca_free_mailbox(dev, inmailbox); + mthca_free_mailbox(dev, outmailbox); + return err; +} + +int mthca_READ_MGM(struct mthca_dev *dev, int index, + struct mthca_mailbox *mailbox, u8 *status) +{ + return mthca_cmd_box(dev, 0, mailbox->dma, index, 0, + CMD_READ_MGM, CMD_TIME_CLASS_A, status); +} + +int mthca_WRITE_MGM(struct mthca_dev *dev, int index, + struct mthca_mailbox *mailbox, u8 *status) +{ + return mthca_cmd(dev, mailbox->dma, index, 0, CMD_WRITE_MGM, + CMD_TIME_CLASS_A, status); +} + +int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + u16 *hash, u8 *status) +{ + u64 imm; + int err; + + err = mthca_cmd_imm(dev, mailbox->dma, &imm, 0, 0, CMD_MGID_HASH, + CMD_TIME_CLASS_A, status); + + *hash = imm; + return err; +} + +int mthca_NOP(struct mthca_dev *dev, u8 *status) +{ + return mthca_cmd(dev, 0, 0x1f, 0, CMD_NOP, msecs_to_jiffies(100), status); +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_cmd.h b/sys/ofed/drivers/infiniband/hw/mthca/mthca_cmd.h new file mode 100644 index 000000000000..6efd3265f248 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_cmd.h @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2006 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MTHCA_CMD_H +#define MTHCA_CMD_H + +#include + +#define MTHCA_MAILBOX_SIZE 4096 + +enum { + /* command completed successfully: */ + MTHCA_CMD_STAT_OK = 0x00, + /* Internal error (such as a bus error) occurred while processing command: */ + MTHCA_CMD_STAT_INTERNAL_ERR = 0x01, + /* Operation/command not supported or opcode modifier not supported: */ + MTHCA_CMD_STAT_BAD_OP = 0x02, + /* Parameter not supported or parameter out of range: */ + MTHCA_CMD_STAT_BAD_PARAM = 0x03, + /* System not enabled or bad system state: */ + MTHCA_CMD_STAT_BAD_SYS_STATE = 0x04, + /* Attempt to access reserved or unallocaterd resource: */ + MTHCA_CMD_STAT_BAD_RESOURCE = 0x05, + /* Requested resource is currently executing a command, or is otherwise busy: */ + MTHCA_CMD_STAT_RESOURCE_BUSY = 0x06, + /* memory error: */ + MTHCA_CMD_STAT_DDR_MEM_ERR = 0x07, + /* Required capability exceeds device limits: */ + MTHCA_CMD_STAT_EXCEED_LIM = 0x08, + /* Resource is not in the appropriate state or ownership: */ + MTHCA_CMD_STAT_BAD_RES_STATE = 0x09, + /* Index out of range: */ + MTHCA_CMD_STAT_BAD_INDEX = 0x0a, + /* FW image corrupted: */ + MTHCA_CMD_STAT_BAD_NVMEM = 0x0b, + /* Attempt to modify a QP/EE which is not in the presumed state: */ + MTHCA_CMD_STAT_BAD_QPEE_STATE = 0x10, + /* Bad segment parameters (Address/Size): */ + MTHCA_CMD_STAT_BAD_SEG_PARAM = 0x20, + /* Memory Region has Memory Windows bound to: */ + MTHCA_CMD_STAT_REG_BOUND = 0x21, + /* HCA local attached memory not present: */ + MTHCA_CMD_STAT_LAM_NOT_PRE = 0x22, + /* Bad management packet (silently discarded): */ + MTHCA_CMD_STAT_BAD_PKT = 0x30, + /* More outstanding CQEs in CQ than new CQ size: */ + MTHCA_CMD_STAT_BAD_SIZE = 0x40 +}; + +enum { + MTHCA_TRANS_INVALID = 0, + MTHCA_TRANS_RST2INIT, + MTHCA_TRANS_INIT2INIT, + MTHCA_TRANS_INIT2RTR, + MTHCA_TRANS_RTR2RTS, + MTHCA_TRANS_RTS2RTS, + MTHCA_TRANS_SQERR2RTS, + MTHCA_TRANS_ANY2ERR, + MTHCA_TRANS_RTS2SQD, + MTHCA_TRANS_SQD2SQD, + MTHCA_TRANS_SQD2RTS, + MTHCA_TRANS_ANY2RST, +}; + +enum { + DEV_LIM_FLAG_RC = 1 << 0, + DEV_LIM_FLAG_UC = 1 << 1, + DEV_LIM_FLAG_UD = 1 << 2, + DEV_LIM_FLAG_RD = 1 << 3, + DEV_LIM_FLAG_RAW_IPV6 = 1 << 4, + DEV_LIM_FLAG_RAW_ETHER = 1 << 5, + DEV_LIM_FLAG_SRQ = 1 << 6, + DEV_LIM_FLAG_IPOIB_CSUM = 1 << 7, + DEV_LIM_FLAG_BAD_PKEY_CNTR = 1 << 8, + DEV_LIM_FLAG_BAD_QKEY_CNTR = 1 << 9, + DEV_LIM_FLAG_MW = 1 << 16, + DEV_LIM_FLAG_AUTO_PATH_MIG = 1 << 17, + DEV_LIM_FLAG_ATOMIC = 1 << 18, + DEV_LIM_FLAG_RAW_MULTI = 1 << 19, + DEV_LIM_FLAG_UD_AV_PORT_ENFORCE = 1 << 20, + DEV_LIM_FLAG_UD_MULTI = 1 << 21, +}; + +struct mthca_mailbox { + dma_addr_t dma; + void *buf; +}; + +struct mthca_dev_lim { + int max_srq_sz; + int max_qp_sz; + int reserved_qps; + int max_qps; + int reserved_srqs; + int max_srqs; + int reserved_eecs; + int max_eecs; + int max_cq_sz; + int reserved_cqs; + int max_cqs; + int max_mpts; + int reserved_eqs; + int max_eqs; + int reserved_mtts; + int max_mrw_sz; + int reserved_mrws; + int max_mtt_seg; + int max_requester_per_qp; + int max_responder_per_qp; + int max_rdma_global; + int local_ca_ack_delay; + int max_mtu; + int max_port_width; + int max_vl; + int num_ports; + int max_gids; + u16 stat_rate_support; + int max_pkeys; + u32 flags; + int reserved_uars; + int uar_size; + int min_page_sz; + int max_sg; + int max_desc_sz; + int max_qp_per_mcg; + int reserved_mgms; + int max_mcgs; + int reserved_pds; + int max_pds; + int reserved_rdds; + int max_rdds; + int eec_entry_sz; + int qpc_entry_sz; + int eeec_entry_sz; + int eqpc_entry_sz; + int eqc_entry_sz; + int cqc_entry_sz; + int srq_entry_sz; + int uar_scratch_entry_sz; + int mpt_entry_sz; + union { + struct { + int max_avs; + } tavor; + struct { + int resize_srq; + int max_pbl_sz; + u8 bmme_flags; + u32 reserved_lkey; + int lam_required; + u64 max_icm_sz; + } arbel; + } hca; +}; + +struct mthca_adapter { + u32 vendor_id; + u32 device_id; + u32 revision_id; + char board_id[MTHCA_BOARD_ID_LEN]; + u8 inta_pin; +}; + +struct mthca_init_hca_param { + u64 qpc_base; + u64 eec_base; + u64 srqc_base; + u64 cqc_base; + u64 eqpc_base; + u64 eeec_base; + u64 eqc_base; + u64 rdb_base; + u64 mc_base; + u64 mpt_base; + u64 mtt_base; + u64 uar_scratch_base; + u64 uarc_base; + u16 log_mc_entry_sz; + u16 mc_hash_sz; + u8 log_num_qps; + u8 log_num_eecs; + u8 log_num_srqs; + u8 log_num_cqs; + u8 log_num_eqs; + u8 log_mc_table_sz; + u8 mtt_seg_sz; + u8 log_mpt_sz; + u8 log_uar_sz; + u8 log_uarc_sz; +}; + +struct mthca_init_ib_param { + int port_width; + int vl_cap; + int mtu_cap; + u16 gid_cap; + u16 pkey_cap; + int set_guid0; + u64 guid0; + int set_node_guid; + u64 node_guid; + int set_si_guid; + u64 si_guid; +}; + +struct mthca_set_ib_param { + int set_si_guid; + int reset_qkey_viol; + u64 si_guid; + u32 cap_mask; +}; + +int mthca_cmd_init(struct mthca_dev *dev); +void mthca_cmd_cleanup(struct mthca_dev *dev); +int mthca_cmd_use_events(struct mthca_dev *dev); +void mthca_cmd_use_polling(struct mthca_dev *dev); +void mthca_cmd_event(struct mthca_dev *dev, u16 token, + u8 status, u64 out_param); + +struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev, + gfp_t gfp_mask); +void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox); + +int mthca_SYS_EN(struct mthca_dev *dev, u8 *status); +int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status); +int mthca_MAP_FA(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status); +int mthca_UNMAP_FA(struct mthca_dev *dev, u8 *status); +int mthca_RUN_FW(struct mthca_dev *dev, u8 *status); +int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status); +int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status); +int mthca_DISABLE_LAM(struct mthca_dev *dev, u8 *status); +int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status); +int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, + struct mthca_dev_lim *dev_lim, u8 *status); +int mthca_QUERY_ADAPTER(struct mthca_dev *dev, + struct mthca_adapter *adapter, u8 *status); +int mthca_INIT_HCA(struct mthca_dev *dev, + struct mthca_init_hca_param *param, + u8 *status); +int mthca_INIT_IB(struct mthca_dev *dev, + struct mthca_init_ib_param *param, + int port, u8 *status); +int mthca_CLOSE_IB(struct mthca_dev *dev, int port, u8 *status); +int mthca_CLOSE_HCA(struct mthca_dev *dev, int panic, u8 *status); +int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param, + int port, u8 *status); +int mthca_MAP_ICM(struct mthca_dev *dev, struct mthca_icm *icm, u64 virt, u8 *status); +int mthca_MAP_ICM_page(struct mthca_dev *dev, u64 dma_addr, u64 virt, u8 *status); +int mthca_UNMAP_ICM(struct mthca_dev *dev, u64 virt, u32 page_count, u8 *status); +int mthca_MAP_ICM_AUX(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status); +int mthca_UNMAP_ICM_AUX(struct mthca_dev *dev, u8 *status); +int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages, + u8 *status); +int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int mpt_index, u8 *status); +int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int mpt_index, u8 *status); +int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int num_mtt, u8 *status); +int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status); +int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap, + int eq_num, u8 *status); +int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int eq_num, u8 *status); +int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int eq_num, u8 *status); +int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int cq_num, u8 *status); +int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int cq_num, u8 *status); +int mthca_RESIZE_CQ(struct mthca_dev *dev, int cq_num, u32 lkey, u8 log_size, + u8 *status); +int mthca_SW2HW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int srq_num, u8 *status); +int mthca_HW2SW_SRQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + int srq_num, u8 *status); +int mthca_QUERY_SRQ(struct mthca_dev *dev, u32 num, + struct mthca_mailbox *mailbox, u8 *status); +int mthca_ARM_SRQ(struct mthca_dev *dev, int srq_num, int limit, u8 *status); +int mthca_MODIFY_QP(struct mthca_dev *dev, enum ib_qp_state cur, + enum ib_qp_state next, u32 num, int is_ee, + struct mthca_mailbox *mailbox, u32 optmask, + u8 *status); +int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee, + struct mthca_mailbox *mailbox, u8 *status); +int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn, + u8 *status); +int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey, + int port, struct ib_wc *in_wc, struct ib_grh *in_grh, + void *in_mad, void *response_mad, u8 *status); +int mthca_READ_MGM(struct mthca_dev *dev, int index, + struct mthca_mailbox *mailbox, u8 *status); +int mthca_WRITE_MGM(struct mthca_dev *dev, int index, + struct mthca_mailbox *mailbox, u8 *status); +int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox, + u16 *hash, u8 *status); +int mthca_NOP(struct mthca_dev *dev, u8 *status); + +#endif /* MTHCA_CMD_H */ diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_config_reg.h b/sys/ofed/drivers/infiniband/hw/mthca/mthca_config_reg.h new file mode 100644 index 000000000000..75671f75cac4 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_config_reg.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MTHCA_CONFIG_REG_H +#define MTHCA_CONFIG_REG_H + +#include + +#define MTHCA_HCR_BASE 0x80680 +#define MTHCA_HCR_SIZE 0x0001c +#define MTHCA_ECR_BASE 0x80700 +#define MTHCA_ECR_SIZE 0x00008 +#define MTHCA_ECR_CLR_BASE 0x80708 +#define MTHCA_ECR_CLR_SIZE 0x00008 +#define MTHCA_MAP_ECR_SIZE (MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE) +#define MTHCA_CLR_INT_BASE 0xf00d8 +#define MTHCA_CLR_INT_SIZE 0x00008 +#define MTHCA_EQ_SET_CI_SIZE (8 * 32) + +#endif /* MTHCA_CONFIG_REG_H */ diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_cq.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_cq.c new file mode 100644 index 000000000000..aa75d26ac9ab --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_cq.c @@ -0,0 +1,992 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include + +#include + +#include "mthca_dev.h" +#include "mthca_cmd.h" +#include "mthca_memfree.h" + +enum { + MTHCA_MAX_DIRECT_CQ_SIZE = 4 * PAGE_SIZE +}; + +enum { + MTHCA_CQ_ENTRY_SIZE = 0x20 +}; + +enum { + MTHCA_ATOMIC_BYTE_LEN = 8 +}; + +/* + * Must be packed because start is 64 bits but only aligned to 32 bits. + */ +struct mthca_cq_context { + __be32 flags; + __be64 start; + __be32 logsize_usrpage; + __be32 error_eqn; /* Tavor only */ + __be32 comp_eqn; + __be32 pd; + __be32 lkey; + __be32 last_notified_index; + __be32 solicit_producer_index; + __be32 consumer_index; + __be32 producer_index; + __be32 cqn; + __be32 ci_db; /* Arbel only */ + __be32 state_db; /* Arbel only */ + u32 reserved; +} __attribute__((packed)); + +#define MTHCA_CQ_STATUS_OK ( 0 << 28) +#define MTHCA_CQ_STATUS_OVERFLOW ( 9 << 28) +#define MTHCA_CQ_STATUS_WRITE_FAIL (10 << 28) +#define MTHCA_CQ_FLAG_TR ( 1 << 18) +#define MTHCA_CQ_FLAG_OI ( 1 << 17) +#define MTHCA_CQ_STATE_DISARMED ( 0 << 8) +#define MTHCA_CQ_STATE_ARMED ( 1 << 8) +#define MTHCA_CQ_STATE_ARMED_SOL ( 4 << 8) +#define MTHCA_EQ_STATE_FIRED (10 << 8) + +enum { + MTHCA_ERROR_CQE_OPCODE_MASK = 0xfe +}; + +enum { + SYNDROME_LOCAL_LENGTH_ERR = 0x01, + SYNDROME_LOCAL_QP_OP_ERR = 0x02, + SYNDROME_LOCAL_EEC_OP_ERR = 0x03, + SYNDROME_LOCAL_PROT_ERR = 0x04, + SYNDROME_WR_FLUSH_ERR = 0x05, + SYNDROME_MW_BIND_ERR = 0x06, + SYNDROME_BAD_RESP_ERR = 0x10, + SYNDROME_LOCAL_ACCESS_ERR = 0x11, + SYNDROME_REMOTE_INVAL_REQ_ERR = 0x12, + SYNDROME_REMOTE_ACCESS_ERR = 0x13, + SYNDROME_REMOTE_OP_ERR = 0x14, + SYNDROME_RETRY_EXC_ERR = 0x15, + SYNDROME_RNR_RETRY_EXC_ERR = 0x16, + SYNDROME_LOCAL_RDD_VIOL_ERR = 0x20, + SYNDROME_REMOTE_INVAL_RD_REQ_ERR = 0x21, + SYNDROME_REMOTE_ABORTED_ERR = 0x22, + SYNDROME_INVAL_EECN_ERR = 0x23, + SYNDROME_INVAL_EEC_STATE_ERR = 0x24 +}; + +struct mthca_cqe { + __be32 my_qpn; + __be32 my_ee; + __be32 rqpn; + u8 sl_ipok; + u8 g_mlpath; + __be16 rlid; + __be32 imm_etype_pkey_eec; + __be32 byte_cnt; + __be32 wqe; + u8 opcode; + u8 is_send; + u8 reserved; + u8 owner; +}; + +struct mthca_err_cqe { + __be32 my_qpn; + u32 reserved1[3]; + u8 syndrome; + u8 vendor_err; + __be16 db_cnt; + u32 reserved2; + __be32 wqe; + u8 opcode; + u8 reserved3[2]; + u8 owner; +}; + +#define MTHCA_CQ_ENTRY_OWNER_SW (0 << 7) +#define MTHCA_CQ_ENTRY_OWNER_HW (1 << 7) + +#define MTHCA_TAVOR_CQ_DB_INC_CI (1 << 24) +#define MTHCA_TAVOR_CQ_DB_REQ_NOT (2 << 24) +#define MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL (3 << 24) +#define MTHCA_TAVOR_CQ_DB_SET_CI (4 << 24) +#define MTHCA_TAVOR_CQ_DB_REQ_NOT_MULT (5 << 24) + +#define MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL (1 << 24) +#define MTHCA_ARBEL_CQ_DB_REQ_NOT (2 << 24) +#define MTHCA_ARBEL_CQ_DB_REQ_NOT_MULT (3 << 24) + +static inline struct mthca_cqe *get_cqe_from_buf(struct mthca_cq_buf *buf, + int entry) +{ + if (buf->is_direct) + return buf->queue.direct.buf + (entry * MTHCA_CQ_ENTRY_SIZE); + else + return buf->queue.page_list[entry * MTHCA_CQ_ENTRY_SIZE / PAGE_SIZE].buf + + (entry * MTHCA_CQ_ENTRY_SIZE) % PAGE_SIZE; +} + +static inline struct mthca_cqe *get_cqe(struct mthca_cq *cq, int entry) +{ + return get_cqe_from_buf(&cq->buf, entry); +} + +static inline struct mthca_cqe *cqe_sw(struct mthca_cqe *cqe) +{ + return MTHCA_CQ_ENTRY_OWNER_HW & cqe->owner ? NULL : cqe; +} + +static inline struct mthca_cqe *next_cqe_sw(struct mthca_cq *cq) +{ + return cqe_sw(get_cqe(cq, cq->cons_index & cq->ibcq.cqe)); +} + +static inline void set_cqe_hw(struct mthca_cqe *cqe) +{ + cqe->owner = MTHCA_CQ_ENTRY_OWNER_HW; +} + +static void dump_cqe(struct mthca_dev *dev, void *cqe_ptr) +{ + __be32 *cqe = cqe_ptr; + + (void) cqe; /* avoid warning if mthca_dbg compiled away... */ + mthca_dbg(dev, "CQE contents %08x %08x %08x %08x %08x %08x %08x %08x\n", + be32_to_cpu(cqe[0]), be32_to_cpu(cqe[1]), be32_to_cpu(cqe[2]), + be32_to_cpu(cqe[3]), be32_to_cpu(cqe[4]), be32_to_cpu(cqe[5]), + be32_to_cpu(cqe[6]), be32_to_cpu(cqe[7])); +} + +/* + * incr is ignored in native Arbel (mem-free) mode, so cq->cons_index + * should be correct before calling update_cons_index(). + */ +static inline void update_cons_index(struct mthca_dev *dev, struct mthca_cq *cq, + int incr) +{ + if (mthca_is_memfree(dev)) { + *cq->set_ci_db = cpu_to_be32(cq->cons_index); + wmb(); + } else { + mthca_write64(MTHCA_TAVOR_CQ_DB_INC_CI | cq->cqn, incr - 1, + dev->kar + MTHCA_CQ_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + /* + * Make sure doorbells don't leak out of CQ spinlock + * and reach the HCA out of order: + */ + mmiowb(); + } +} + +void mthca_cq_completion(struct mthca_dev *dev, u32 cqn) +{ + struct mthca_cq *cq; + + cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1)); + + if (!cq) { + mthca_warn(dev, "Completion event for bogus CQ %08x\n", cqn); + return; + } + + ++cq->arm_sn; + + cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context); +} + +void mthca_cq_event(struct mthca_dev *dev, u32 cqn, + enum ib_event_type event_type) +{ + struct mthca_cq *cq; + struct ib_event event; + + spin_lock(&dev->cq_table.lock); + + cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1)); + if (cq) + ++cq->refcount; + + spin_unlock(&dev->cq_table.lock); + + if (!cq) { + mthca_warn(dev, "Async event for bogus CQ %08x\n", cqn); + return; + } + + event.device = &dev->ib_dev; + event.event = event_type; + event.element.cq = &cq->ibcq; + if (cq->ibcq.event_handler) + cq->ibcq.event_handler(&event, cq->ibcq.cq_context); + + spin_lock(&dev->cq_table.lock); + if (!--cq->refcount) + wake_up(&cq->wait); + spin_unlock(&dev->cq_table.lock); +} + +static inline int is_recv_cqe(struct mthca_cqe *cqe) +{ + if ((cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) == + MTHCA_ERROR_CQE_OPCODE_MASK) + return !(cqe->opcode & 0x01); + else + return !(cqe->is_send & 0x80); +} + +void mthca_cq_clean(struct mthca_dev *dev, struct mthca_cq *cq, u32 qpn, + struct mthca_srq *srq) +{ + struct mthca_cqe *cqe; + u32 prod_index; + int i, nfreed = 0; + + spin_lock_irq(&cq->lock); + + /* + * First we need to find the current producer index, so we + * know where to start cleaning from. It doesn't matter if HW + * adds new entries after this loop -- the QP we're worried + * about is already in RESET, so the new entries won't come + * from our QP and therefore don't need to be checked. + */ + for (prod_index = cq->cons_index; + cqe_sw(get_cqe(cq, prod_index & cq->ibcq.cqe)); + ++prod_index) + if (prod_index == cq->cons_index + cq->ibcq.cqe) + break; + + if (0) + mthca_dbg(dev, "Cleaning QPN %06x from CQN %06x; ci %d, pi %d\n", + qpn, cq->cqn, cq->cons_index, prod_index); + + /* + * Now sweep backwards through the CQ, removing CQ entries + * that match our QP by copying older entries on top of them. + */ + while ((int) --prod_index - (int) cq->cons_index >= 0) { + cqe = get_cqe(cq, prod_index & cq->ibcq.cqe); + if (cqe->my_qpn == cpu_to_be32(qpn)) { + if (srq && is_recv_cqe(cqe)) + mthca_free_srq_wqe(srq, be32_to_cpu(cqe->wqe)); + ++nfreed; + } else if (nfreed) + memcpy(get_cqe(cq, (prod_index + nfreed) & cq->ibcq.cqe), + cqe, MTHCA_CQ_ENTRY_SIZE); + } + + if (nfreed) { + for (i = 0; i < nfreed; ++i) + set_cqe_hw(get_cqe(cq, (cq->cons_index + i) & cq->ibcq.cqe)); + wmb(); + cq->cons_index += nfreed; + update_cons_index(dev, cq, nfreed); + } + + spin_unlock_irq(&cq->lock); +} + +void mthca_cq_resize_copy_cqes(struct mthca_cq *cq) +{ + int i; + + /* + * In Tavor mode, the hardware keeps the consumer and producer + * indices mod the CQ size. Since we might be making the CQ + * bigger, we need to deal with the case where the producer + * index wrapped around before the CQ was resized. + */ + if (!mthca_is_memfree(to_mdev(cq->ibcq.device)) && + cq->ibcq.cqe < cq->resize_buf->cqe) { + cq->cons_index &= cq->ibcq.cqe; + if (cqe_sw(get_cqe(cq, cq->ibcq.cqe))) + cq->cons_index -= cq->ibcq.cqe + 1; + } + + for (i = cq->cons_index; cqe_sw(get_cqe(cq, i & cq->ibcq.cqe)); ++i) + memcpy(get_cqe_from_buf(&cq->resize_buf->buf, + i & cq->resize_buf->cqe), + get_cqe(cq, i & cq->ibcq.cqe), MTHCA_CQ_ENTRY_SIZE); +} + +int mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent) +{ + int ret; + int i; + + ret = mthca_buf_alloc(dev, nent * MTHCA_CQ_ENTRY_SIZE, + MTHCA_MAX_DIRECT_CQ_SIZE, + &buf->queue, &buf->is_direct, + &dev->driver_pd, 1, &buf->mr); + if (ret) + return ret; + + for (i = 0; i < nent; ++i) + set_cqe_hw(get_cqe_from_buf(buf, i)); + + return 0; +} + +void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int cqe) +{ + mthca_buf_free(dev, (cqe + 1) * MTHCA_CQ_ENTRY_SIZE, &buf->queue, + buf->is_direct, &buf->mr); +} + +static void handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq, + struct mthca_qp *qp, int wqe_index, int is_send, + struct mthca_err_cqe *cqe, + struct ib_wc *entry, int *free_cqe) +{ + int dbd; + __be32 new_wqe; + + if (cqe->syndrome == SYNDROME_LOCAL_QP_OP_ERR) { + mthca_dbg(dev, "local QP operation err " + "(QPN %06x, WQE @ %08x, CQN %06x, index %d)\n", + be32_to_cpu(cqe->my_qpn), be32_to_cpu(cqe->wqe), + cq->cqn, cq->cons_index); + dump_cqe(dev, cqe); + } + + /* + * For completions in error, only work request ID, status, vendor error + * (and freed resource count for RD) have to be set. + */ + switch (cqe->syndrome) { + case SYNDROME_LOCAL_LENGTH_ERR: + entry->status = IB_WC_LOC_LEN_ERR; + break; + case SYNDROME_LOCAL_QP_OP_ERR: + entry->status = IB_WC_LOC_QP_OP_ERR; + break; + case SYNDROME_LOCAL_EEC_OP_ERR: + entry->status = IB_WC_LOC_EEC_OP_ERR; + break; + case SYNDROME_LOCAL_PROT_ERR: + entry->status = IB_WC_LOC_PROT_ERR; + break; + case SYNDROME_WR_FLUSH_ERR: + entry->status = IB_WC_WR_FLUSH_ERR; + break; + case SYNDROME_MW_BIND_ERR: + entry->status = IB_WC_MW_BIND_ERR; + break; + case SYNDROME_BAD_RESP_ERR: + entry->status = IB_WC_BAD_RESP_ERR; + break; + case SYNDROME_LOCAL_ACCESS_ERR: + entry->status = IB_WC_LOC_ACCESS_ERR; + break; + case SYNDROME_REMOTE_INVAL_REQ_ERR: + entry->status = IB_WC_REM_INV_REQ_ERR; + break; + case SYNDROME_REMOTE_ACCESS_ERR: + entry->status = IB_WC_REM_ACCESS_ERR; + break; + case SYNDROME_REMOTE_OP_ERR: + entry->status = IB_WC_REM_OP_ERR; + break; + case SYNDROME_RETRY_EXC_ERR: + entry->status = IB_WC_RETRY_EXC_ERR; + break; + case SYNDROME_RNR_RETRY_EXC_ERR: + entry->status = IB_WC_RNR_RETRY_EXC_ERR; + break; + case SYNDROME_LOCAL_RDD_VIOL_ERR: + entry->status = IB_WC_LOC_RDD_VIOL_ERR; + break; + case SYNDROME_REMOTE_INVAL_RD_REQ_ERR: + entry->status = IB_WC_REM_INV_RD_REQ_ERR; + break; + case SYNDROME_REMOTE_ABORTED_ERR: + entry->status = IB_WC_REM_ABORT_ERR; + break; + case SYNDROME_INVAL_EECN_ERR: + entry->status = IB_WC_INV_EECN_ERR; + break; + case SYNDROME_INVAL_EEC_STATE_ERR: + entry->status = IB_WC_INV_EEC_STATE_ERR; + break; + default: + entry->status = IB_WC_GENERAL_ERR; + break; + } + + entry->vendor_err = cqe->vendor_err; + + /* + * Mem-free HCAs always generate one CQE per WQE, even in the + * error case, so we don't have to check the doorbell count, etc. + */ + if (mthca_is_memfree(dev)) + return; + + mthca_free_err_wqe(dev, qp, is_send, wqe_index, &dbd, &new_wqe); + + /* + * If we're at the end of the WQE chain, or we've used up our + * doorbell count, free the CQE. Otherwise just update it for + * the next poll operation. + */ + if (!(new_wqe & cpu_to_be32(0x3f)) || (!cqe->db_cnt && dbd)) + return; + + be16_add_cpu(&cqe->db_cnt, -dbd); + cqe->wqe = new_wqe; + cqe->syndrome = SYNDROME_WR_FLUSH_ERR; + + *free_cqe = 0; +} + +static inline int mthca_poll_one(struct mthca_dev *dev, + struct mthca_cq *cq, + struct mthca_qp **cur_qp, + int *freed, + struct ib_wc *entry) +{ + struct mthca_wq *wq; + struct mthca_cqe *cqe; + int wqe_index; + int is_error; + int is_send; + int free_cqe = 1; + int err = 0; + u16 checksum; + + cqe = next_cqe_sw(cq); + if (!cqe) + return -EAGAIN; + + /* + * Make sure we read CQ entry contents after we've checked the + * ownership bit. + */ + rmb(); + + if (0) { + mthca_dbg(dev, "%x/%d: CQE -> QPN %06x, WQE @ %08x\n", + cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn), + be32_to_cpu(cqe->wqe)); + dump_cqe(dev, cqe); + } + + is_error = (cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) == + MTHCA_ERROR_CQE_OPCODE_MASK; + is_send = is_error ? cqe->opcode & 0x01 : cqe->is_send & 0x80; + + if (!*cur_qp || be32_to_cpu(cqe->my_qpn) != (*cur_qp)->qpn) { + /* + * We do not have to take the QP table lock here, + * because CQs will be locked while QPs are removed + * from the table. + */ + *cur_qp = mthca_array_get(&dev->qp_table.qp, + be32_to_cpu(cqe->my_qpn) & + (dev->limits.num_qps - 1)); + if (!*cur_qp) { + mthca_warn(dev, "CQ entry for unknown QP %06x\n", + be32_to_cpu(cqe->my_qpn) & 0xffffff); + err = -EINVAL; + goto out; + } + } + + entry->qp = &(*cur_qp)->ibqp; + + if (is_send) { + wq = &(*cur_qp)->sq; + wqe_index = ((be32_to_cpu(cqe->wqe) - (*cur_qp)->send_wqe_offset) + >> wq->wqe_shift); + entry->wr_id = (*cur_qp)->wrid[wqe_index]; + } else if ((*cur_qp)->ibqp.srq) { + struct mthca_srq *srq = to_msrq((*cur_qp)->ibqp.srq); + u32 wqe = be32_to_cpu(cqe->wqe); + wq = NULL; + wqe_index = wqe >> srq->wqe_shift; + entry->wr_id = srq->wrid[wqe_index]; + mthca_free_srq_wqe(srq, wqe); + } else { + s32 wqe; + wq = &(*cur_qp)->rq; + wqe = be32_to_cpu(cqe->wqe); + wqe_index = wqe >> wq->wqe_shift; + /* + * WQE addr == base - 1 might be reported in receive completion + * with error instead of (rq size - 1) by Sinai FW 1.0.800 and + * Arbel FW 5.1.400. This bug should be fixed in later FW revs. + */ + if (unlikely(wqe_index < 0)) + wqe_index = wq->max - 1; + entry->wr_id = (*cur_qp)->wrid[wqe_index + (*cur_qp)->sq.max]; + } + + if (wq) { + if (wq->last_comp < wqe_index) + wq->tail += wqe_index - wq->last_comp; + else + wq->tail += wqe_index + wq->max - wq->last_comp; + + wq->last_comp = wqe_index; + } + + if (is_error) { + handle_error_cqe(dev, cq, *cur_qp, wqe_index, is_send, + (struct mthca_err_cqe *) cqe, + entry, &free_cqe); + goto out; + } + + if (is_send) { + entry->wc_flags = 0; + switch (cqe->opcode) { + case MTHCA_OPCODE_RDMA_WRITE: + entry->opcode = IB_WC_RDMA_WRITE; + break; + case MTHCA_OPCODE_RDMA_WRITE_IMM: + entry->opcode = IB_WC_RDMA_WRITE; + entry->wc_flags |= IB_WC_WITH_IMM; + break; + case MTHCA_OPCODE_SEND: + entry->opcode = IB_WC_SEND; + break; + case MTHCA_OPCODE_SEND_IMM: + entry->opcode = IB_WC_SEND; + entry->wc_flags |= IB_WC_WITH_IMM; + break; + case MTHCA_OPCODE_RDMA_READ: + entry->opcode = IB_WC_RDMA_READ; + entry->byte_len = be32_to_cpu(cqe->byte_cnt); + break; + case MTHCA_OPCODE_ATOMIC_CS: + entry->opcode = IB_WC_COMP_SWAP; + entry->byte_len = MTHCA_ATOMIC_BYTE_LEN; + break; + case MTHCA_OPCODE_ATOMIC_FA: + entry->opcode = IB_WC_FETCH_ADD; + entry->byte_len = MTHCA_ATOMIC_BYTE_LEN; + break; + case MTHCA_OPCODE_BIND_MW: + entry->opcode = IB_WC_BIND_MW; + break; + default: + entry->opcode = MTHCA_OPCODE_INVALID; + break; + } + } else { + entry->byte_len = be32_to_cpu(cqe->byte_cnt); + switch (cqe->opcode & 0x1f) { + case IB_OPCODE_SEND_LAST_WITH_IMMEDIATE: + case IB_OPCODE_SEND_ONLY_WITH_IMMEDIATE: + entry->wc_flags = IB_WC_WITH_IMM; + entry->ex.imm_data = cqe->imm_etype_pkey_eec; + entry->opcode = IB_WC_RECV; + break; + case IB_OPCODE_RDMA_WRITE_LAST_WITH_IMMEDIATE: + case IB_OPCODE_RDMA_WRITE_ONLY_WITH_IMMEDIATE: + entry->wc_flags = IB_WC_WITH_IMM; + entry->ex.imm_data = cqe->imm_etype_pkey_eec; + entry->opcode = IB_WC_RECV_RDMA_WITH_IMM; + break; + default: + entry->wc_flags = 0; + entry->opcode = IB_WC_RECV; + break; + } + entry->slid = be16_to_cpu(cqe->rlid); + entry->sl = cqe->sl_ipok >> 4; + entry->src_qp = be32_to_cpu(cqe->rqpn) & 0xffffff; + entry->dlid_path_bits = cqe->g_mlpath & 0x7f; + entry->pkey_index = be32_to_cpu(cqe->imm_etype_pkey_eec) >> 16; + entry->wc_flags |= cqe->g_mlpath & 0x80 ? IB_WC_GRH : 0; + checksum = (be32_to_cpu(cqe->rqpn) >> 24) | + ((be32_to_cpu(cqe->my_ee) >> 16) & 0xff00); + entry->csum_ok = (cqe->sl_ipok & 1 && checksum == 0xffff); + } + + entry->status = IB_WC_SUCCESS; + + out: + if (likely(free_cqe)) { + set_cqe_hw(cqe); + ++(*freed); + ++cq->cons_index; + } + + return err; +} + +int mthca_poll_cq(struct ib_cq *ibcq, int num_entries, + struct ib_wc *entry) +{ + struct mthca_dev *dev = to_mdev(ibcq->device); + struct mthca_cq *cq = to_mcq(ibcq); + struct mthca_qp *qp = NULL; + unsigned long flags; + int err = 0; + int freed = 0; + int npolled; + + spin_lock_irqsave(&cq->lock, flags); + + npolled = 0; +repoll: + while (npolled < num_entries) { + err = mthca_poll_one(dev, cq, &qp, + &freed, entry + npolled); + if (err) + break; + ++npolled; + } + + if (freed) { + wmb(); + update_cons_index(dev, cq, freed); + } + + /* + * If a CQ resize is in progress and we discovered that the + * old buffer is empty, then peek in the new buffer, and if + * it's not empty, switch to the new buffer and continue + * polling there. + */ + if (unlikely(err == -EAGAIN && cq->resize_buf && + cq->resize_buf->state == CQ_RESIZE_READY)) { + /* + * In Tavor mode, the hardware keeps the producer + * index modulo the CQ size. Since we might be making + * the CQ bigger, we need to mask our consumer index + * using the size of the old CQ buffer before looking + * in the new CQ buffer. + */ + if (!mthca_is_memfree(dev)) + cq->cons_index &= cq->ibcq.cqe; + + if (cqe_sw(get_cqe_from_buf(&cq->resize_buf->buf, + cq->cons_index & cq->resize_buf->cqe))) { + struct mthca_cq_buf tbuf; + int tcqe; + + tbuf = cq->buf; + tcqe = cq->ibcq.cqe; + cq->buf = cq->resize_buf->buf; + cq->ibcq.cqe = cq->resize_buf->cqe; + + cq->resize_buf->buf = tbuf; + cq->resize_buf->cqe = tcqe; + cq->resize_buf->state = CQ_RESIZE_SWAPPED; + + goto repoll; + } + } + + spin_unlock_irqrestore(&cq->lock, flags); + + return err == 0 || err == -EAGAIN ? npolled : err; +} + +int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags) +{ + u32 dbhi = ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ? + MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL : + MTHCA_TAVOR_CQ_DB_REQ_NOT) | + to_mcq(cq)->cqn; + + mthca_write64(dbhi, 0xffffffff, to_mdev(cq->device)->kar + MTHCA_CQ_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&to_mdev(cq->device)->doorbell_lock)); + + return 0; +} + +int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) +{ + struct mthca_cq *cq = to_mcq(ibcq); + __be32 db_rec[2]; + u32 dbhi; + u32 sn = cq->arm_sn & 3; + + db_rec[0] = cpu_to_be32(cq->cons_index); + db_rec[1] = cpu_to_be32((cq->cqn << 8) | (2 << 5) | (sn << 3) | + ((flags & IB_CQ_SOLICITED_MASK) == + IB_CQ_SOLICITED ? 1 : 2)); + + mthca_write_db_rec(db_rec, cq->arm_db); + + /* + * Make sure that the doorbell record in host memory is + * written before ringing the doorbell via PCI MMIO. + */ + wmb(); + + dbhi = (sn << 28) | + ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ? + MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL : + MTHCA_ARBEL_CQ_DB_REQ_NOT) | cq->cqn; + + mthca_write64(dbhi, cq->cons_index, + to_mdev(ibcq->device)->kar + MTHCA_CQ_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->doorbell_lock)); + + return 0; +} + +int mthca_init_cq(struct mthca_dev *dev, int nent, + struct mthca_ucontext *ctx, u32 pdn, + struct mthca_cq *cq) +{ + struct mthca_mailbox *mailbox; + struct mthca_cq_context *cq_context; + int err = -ENOMEM; + u8 status; + + cq->ibcq.cqe = nent - 1; + cq->is_kernel = !ctx; + + cq->cqn = mthca_alloc(&dev->cq_table.alloc); + if (cq->cqn == -1) + return -ENOMEM; + + if (mthca_is_memfree(dev)) { + err = mthca_table_get(dev, dev->cq_table.table, cq->cqn); + if (err) + goto err_out; + + if (cq->is_kernel) { + cq->arm_sn = 1; + + err = -ENOMEM; + + cq->set_ci_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, + cq->cqn, &cq->set_ci_db); + if (cq->set_ci_db_index < 0) + goto err_out_icm; + + cq->arm_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_ARM, + cq->cqn, &cq->arm_db); + if (cq->arm_db_index < 0) + goto err_out_ci; + } + } + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + goto err_out_arm; + + cq_context = mailbox->buf; + + if (cq->is_kernel) { + err = mthca_alloc_cq_buf(dev, &cq->buf, nent); + if (err) + goto err_out_mailbox; + } + + spin_lock_init(&cq->lock); + cq->refcount = 1; + init_waitqueue_head(&cq->wait); + mutex_init(&cq->mutex); + + memset(cq_context, 0, sizeof *cq_context); + cq_context->flags = cpu_to_be32(MTHCA_CQ_STATUS_OK | + MTHCA_CQ_STATE_DISARMED | + MTHCA_CQ_FLAG_TR); + cq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24); + if (ctx) + cq_context->logsize_usrpage |= cpu_to_be32(ctx->uar.index); + else + cq_context->logsize_usrpage |= cpu_to_be32(dev->driver_uar.index); + cq_context->error_eqn = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn); + cq_context->comp_eqn = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_COMP].eqn); + cq_context->pd = cpu_to_be32(pdn); + cq_context->lkey = cpu_to_be32(cq->buf.mr.ibmr.lkey); + cq_context->cqn = cpu_to_be32(cq->cqn); + + if (mthca_is_memfree(dev)) { + cq_context->ci_db = cpu_to_be32(cq->set_ci_db_index); + cq_context->state_db = cpu_to_be32(cq->arm_db_index); + } + + err = mthca_SW2HW_CQ(dev, mailbox, cq->cqn, &status); + if (err) { + mthca_warn(dev, "SW2HW_CQ failed (%d)\n", err); + goto err_out_free_mr; + } + + if (status) { + mthca_warn(dev, "SW2HW_CQ returned status 0x%02x\n", + status); + err = -EINVAL; + goto err_out_free_mr; + } + + spin_lock_irq(&dev->cq_table.lock); + if (mthca_array_set(&dev->cq_table.cq, + cq->cqn & (dev->limits.num_cqs - 1), + cq)) { + spin_unlock_irq(&dev->cq_table.lock); + goto err_out_free_mr; + } + spin_unlock_irq(&dev->cq_table.lock); + + cq->cons_index = 0; + + mthca_free_mailbox(dev, mailbox); + + return 0; + +err_out_free_mr: + if (cq->is_kernel) + mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe); + +err_out_mailbox: + mthca_free_mailbox(dev, mailbox); + +err_out_arm: + if (cq->is_kernel && mthca_is_memfree(dev)) + mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index); + +err_out_ci: + if (cq->is_kernel && mthca_is_memfree(dev)) + mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index); + +err_out_icm: + mthca_table_put(dev, dev->cq_table.table, cq->cqn); + +err_out: + mthca_free(&dev->cq_table.alloc, cq->cqn); + + return err; +} + +static inline int get_cq_refcount(struct mthca_dev *dev, struct mthca_cq *cq) +{ + int c; + + spin_lock_irq(&dev->cq_table.lock); + c = cq->refcount; + spin_unlock_irq(&dev->cq_table.lock); + + return c; +} + +void mthca_free_cq(struct mthca_dev *dev, + struct mthca_cq *cq) +{ + struct mthca_mailbox *mailbox; + int err; + u8 status; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) { + mthca_warn(dev, "No memory for mailbox to free CQ.\n"); + return; + } + + err = mthca_HW2SW_CQ(dev, mailbox, cq->cqn, &status); + if (err) + mthca_warn(dev, "HW2SW_CQ failed (%d)\n", err); + else if (status) + mthca_warn(dev, "HW2SW_CQ returned status 0x%02x\n", status); + + if (0) { + __be32 *ctx = mailbox->buf; + int j; + + printk(KERN_ERR "context for CQN %x (cons index %x, next sw %d)\n", + cq->cqn, cq->cons_index, + cq->is_kernel ? !!next_cqe_sw(cq) : 0); + for (j = 0; j < 16; ++j) + printk(KERN_ERR "[%2x] %08x\n", j * 4, be32_to_cpu(ctx[j])); + } + + spin_lock_irq(&dev->cq_table.lock); + mthca_array_clear(&dev->cq_table.cq, + cq->cqn & (dev->limits.num_cqs - 1)); + --cq->refcount; + spin_unlock_irq(&dev->cq_table.lock); + + if (dev->mthca_flags & MTHCA_FLAG_MSI_X) + synchronize_irq(dev->eq_table.eq[MTHCA_EQ_COMP].msi_x_vector); + else + synchronize_irq(dev->pdev->irq); + + wait_event(cq->wait, !get_cq_refcount(dev, cq)); + + if (cq->is_kernel) { + mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe); + if (mthca_is_memfree(dev)) { + mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index); + mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index); + } + } + + mthca_table_put(dev, dev->cq_table.table, cq->cqn); + mthca_free(&dev->cq_table.alloc, cq->cqn); + mthca_free_mailbox(dev, mailbox); +} + +int mthca_init_cq_table(struct mthca_dev *dev) +{ + int err; + + spin_lock_init(&dev->cq_table.lock); + + err = mthca_alloc_init(&dev->cq_table.alloc, + dev->limits.num_cqs, + (1 << 24) - 1, + dev->limits.reserved_cqs); + if (err) + return err; + + err = mthca_array_init(&dev->cq_table.cq, + dev->limits.num_cqs); + if (err) + mthca_alloc_cleanup(&dev->cq_table.alloc); + + return err; +} + +void mthca_cleanup_cq_table(struct mthca_dev *dev) +{ + mthca_array_cleanup(&dev->cq_table.cq, dev->limits.num_cqs); + mthca_alloc_cleanup(&dev->cq_table.alloc); +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_dev.h b/sys/ofed/drivers/infiniband/hw/mthca/mthca_dev.h new file mode 100644 index 000000000000..14e3f6288aa3 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_dev.h @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MTHCA_DEV_H +#define MTHCA_DEV_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mthca_provider.h" +#include "mthca_doorbell.h" + +#define DRV_NAME "ib_mthca" +#define PFX DRV_NAME ": " +#define DRV_VERSION "1.0-ofed1.5.2" +#define DRV_RELDATE "August 4, 2010" + +enum { + MTHCA_FLAG_DDR_HIDDEN = 1 << 1, + MTHCA_FLAG_SRQ = 1 << 2, + MTHCA_FLAG_MSI_X = 1 << 3, + MTHCA_FLAG_NO_LAM = 1 << 4, + MTHCA_FLAG_FMR = 1 << 5, + MTHCA_FLAG_MEMFREE = 1 << 6, + MTHCA_FLAG_PCIE = 1 << 7, + MTHCA_FLAG_SINAI_OPT = 1 << 8 +}; + +enum { + MTHCA_MAX_PORTS = 2 +}; + +enum { + MTHCA_BOARD_ID_LEN = 64 +}; + +enum { + MTHCA_EQ_CONTEXT_SIZE = 0x40, + MTHCA_CQ_CONTEXT_SIZE = 0x40, + MTHCA_QP_CONTEXT_SIZE = 0x200, + MTHCA_RDB_ENTRY_SIZE = 0x20, + MTHCA_AV_SIZE = 0x20, + MTHCA_MGM_ENTRY_SIZE = 0x100, + + /* Arbel FW gives us these, but we need them for Tavor */ + MTHCA_MPT_ENTRY_SIZE = 0x40, + MTHCA_MTT_SEG_SIZE = 0x40, + + MTHCA_QP_PER_MGM = 4 * (MTHCA_MGM_ENTRY_SIZE / 16 - 2) +}; + +enum { + MTHCA_EQ_CMD, + MTHCA_EQ_ASYNC, + MTHCA_EQ_COMP, + MTHCA_NUM_EQ +}; + +enum { + MTHCA_OPCODE_NOP = 0x00, + MTHCA_OPCODE_RDMA_WRITE = 0x08, + MTHCA_OPCODE_RDMA_WRITE_IMM = 0x09, + MTHCA_OPCODE_SEND = 0x0a, + MTHCA_OPCODE_SEND_IMM = 0x0b, + MTHCA_OPCODE_RDMA_READ = 0x10, + MTHCA_OPCODE_ATOMIC_CS = 0x11, + MTHCA_OPCODE_ATOMIC_FA = 0x12, + MTHCA_OPCODE_BIND_MW = 0x18, + MTHCA_OPCODE_INVALID = 0xff +}; + +enum { + MTHCA_CMD_USE_EVENTS = 1 << 0, + MTHCA_CMD_POST_DOORBELLS = 1 << 1 +}; + +enum { + MTHCA_CMD_NUM_DBELL_DWORDS = 8 +}; + +struct mthca_cmd { + struct pci_pool *pool; + struct mutex hcr_mutex; + struct semaphore poll_sem; + struct semaphore event_sem; + int max_cmds; + spinlock_t context_lock; + int free_head; + struct mthca_cmd_context *context; + u16 token_mask; + u32 flags; + void __iomem *dbell_map; + u16 dbell_offsets[MTHCA_CMD_NUM_DBELL_DWORDS]; +}; + +struct mthca_limits { + int num_ports; + int vl_cap; + int mtu_cap; + int gid_table_len; + int pkey_table_len; + int local_ca_ack_delay; + int num_uars; + int max_sg; + int num_qps; + int max_wqes; + int max_desc_sz; + int max_qp_init_rdma; + int reserved_qps; + int num_srqs; + int max_srq_wqes; + int max_srq_sge; + int reserved_srqs; + int num_eecs; + int reserved_eecs; + int num_cqs; + int max_cqes; + int reserved_cqs; + int num_eqs; + int reserved_eqs; + int num_mpts; + int num_mtt_segs; + int mtt_seg_size; + int fmr_reserved_mtts; + int reserved_mtts; + int reserved_mrws; + int reserved_uars; + int num_mgms; + int num_amgms; + int reserved_mcgs; + int num_pds; + int reserved_pds; + u32 page_size_cap; + u32 flags; + u16 stat_rate_support; + u8 port_width_cap; +}; + +struct mthca_alloc { + u32 last; + u32 top; + u32 max; + u32 mask; + spinlock_t lock; + unsigned long *table; +}; + +struct mthca_array { + struct { + void **page; + int used; + } *page_list; +}; + +struct mthca_uar_table { + struct mthca_alloc alloc; + u64 uarc_base; + int uarc_size; +}; + +struct mthca_pd_table { + struct mthca_alloc alloc; +}; + +struct mthca_buddy { + unsigned long **bits; + int *num_free; + int max_order; + spinlock_t lock; +}; + +struct mthca_mr_table { + struct mthca_alloc mpt_alloc; + struct mthca_buddy mtt_buddy; + struct mthca_buddy *fmr_mtt_buddy; + u64 mtt_base; + u64 mpt_base; + struct mthca_icm_table *mtt_table; + struct mthca_icm_table *mpt_table; + struct { + void __iomem *mpt_base; + void __iomem *mtt_base; + struct mthca_buddy mtt_buddy; + } tavor_fmr; +}; + +struct mthca_eq_table { + struct mthca_alloc alloc; + void __iomem *clr_int; + u32 clr_mask; + u32 arm_mask; + struct mthca_eq eq[MTHCA_NUM_EQ]; + u64 icm_virt; + struct page *icm_page; + dma_addr_t icm_dma; + int have_irq; + u8 inta_pin; +}; + +struct mthca_cq_table { + struct mthca_alloc alloc; + spinlock_t lock; + struct mthca_array cq; + struct mthca_icm_table *table; +}; + +struct mthca_srq_table { + struct mthca_alloc alloc; + spinlock_t lock; + struct mthca_array srq; + struct mthca_icm_table *table; +}; + +struct mthca_qp_table { + struct mthca_alloc alloc; + u32 rdb_base; + int rdb_shift; + int sqp_start; + spinlock_t lock; + struct mthca_array qp; + struct mthca_icm_table *qp_table; + struct mthca_icm_table *eqp_table; + struct mthca_icm_table *rdb_table; +}; + +struct mthca_av_table { + struct pci_pool *pool; + int num_ddr_avs; + u64 ddr_av_base; + void __iomem *av_map; + struct mthca_alloc alloc; +}; + +struct mthca_mcg_table { + struct mutex mutex; + struct mthca_alloc alloc; + struct mthca_icm_table *table; +}; + +struct mthca_catas_err { + u64 addr; + u32 __iomem *map; + u32 size; + struct timer_list timer; + struct list_head list; +}; + +extern struct mutex mthca_device_mutex; + +struct mthca_dev { + struct ib_device ib_dev; + struct pci_dev *pdev; + + int hca_type; + unsigned long mthca_flags; + unsigned long device_cap_flags; + + u32 rev_id; + char board_id[MTHCA_BOARD_ID_LEN]; + + /* firmware info */ + u64 fw_ver; + union { + struct { + u64 fw_start; + u64 fw_end; + } tavor; + struct { + u64 clr_int_base; + u64 eq_arm_base; + u64 eq_set_ci_base; + struct mthca_icm *fw_icm; + struct mthca_icm *aux_icm; + u16 fw_pages; + } arbel; + } fw; + + u64 ddr_start; + u64 ddr_end; + + MTHCA_DECLARE_DOORBELL_LOCK(doorbell_lock) + struct mutex cap_mask_mutex; + + void __iomem *hcr; + void __iomem *kar; + void __iomem *clr_base; + union { + struct { + void __iomem *ecr_base; + } tavor; + struct { + void __iomem *eq_arm; + void __iomem *eq_set_ci_base; + } arbel; + } eq_regs; + + struct mthca_cmd cmd; + struct mthca_limits limits; + + struct mthca_uar_table uar_table; + struct mthca_pd_table pd_table; + struct mthca_mr_table mr_table; + struct mthca_eq_table eq_table; + struct mthca_cq_table cq_table; + struct mthca_srq_table srq_table; + struct mthca_qp_table qp_table; + struct mthca_av_table av_table; + struct mthca_mcg_table mcg_table; + + struct mthca_catas_err catas_err; + + struct mthca_uar driver_uar; + struct mthca_db_table *db_tab; + struct mthca_pd driver_pd; + struct mthca_mr driver_mr; + + struct ib_mad_agent *send_agent[MTHCA_MAX_PORTS][2]; + struct ib_ah *sm_ah[MTHCA_MAX_PORTS]; + spinlock_t sm_lock; + u8 rate[MTHCA_MAX_PORTS]; + int active; +}; + +#ifdef CONFIG_INFINIBAND_MTHCA_DEBUG +extern int mthca_debug_level; + +#define mthca_dbg(mdev, format, arg...) \ + do { \ + if (mthca_debug_level) \ + dev_printk(KERN_DEBUG, &mdev->pdev->dev, format, ## arg); \ + } while (0) + +#else /* CONFIG_INFINIBAND_MTHCA_DEBUG */ + +#define mthca_dbg(mdev, format, arg...) do { (void) mdev; } while (0) + +#endif /* CONFIG_INFINIBAND_MTHCA_DEBUG */ + +#define mthca_err(mdev, format, arg...) \ + dev_err(&mdev->pdev->dev, format, ## arg) +#define mthca_info(mdev, format, arg...) \ + dev_info(&mdev->pdev->dev, format, ## arg) +#define mthca_warn(mdev, format, arg...) \ + dev_warn(&mdev->pdev->dev, format, ## arg) + +extern void __buggy_use_of_MTHCA_GET(void); +extern void __buggy_use_of_MTHCA_PUT(void); + +#define MTHCA_GET(dest, source, offset) \ + do { \ + void *__p = (char *) (source) + (offset); \ + switch (sizeof (dest)) { \ + case 1: (dest) = *(u8 *) __p; break; \ + case 2: (dest) = be16_to_cpup(__p); break; \ + case 4: (dest) = be32_to_cpup(__p); break; \ + case 8: (dest) = be64_to_cpup(__p); break; \ + default: __buggy_use_of_MTHCA_GET(); \ + } \ + } while (0) + +#define MTHCA_PUT(dest, source, offset) \ + do { \ + void *__d = ((char *) (dest) + (offset)); \ + switch (sizeof(source)) { \ + case 1: *(u8 *) __d = (source); break; \ + case 2: *(__be16 *) __d = cpu_to_be16(source); break; \ + case 4: *(__be32 *) __d = cpu_to_be32(source); break; \ + case 8: *(__be64 *) __d = cpu_to_be64(source); break; \ + default: __buggy_use_of_MTHCA_PUT(); \ + } \ + } while (0) + +int mthca_reset(struct mthca_dev *mdev); + +u32 mthca_alloc(struct mthca_alloc *alloc); +void mthca_free(struct mthca_alloc *alloc, u32 obj); +int mthca_alloc_init(struct mthca_alloc *alloc, u32 num, u32 mask, + u32 reserved); +void mthca_alloc_cleanup(struct mthca_alloc *alloc); +void *mthca_array_get(struct mthca_array *array, int index); +int mthca_array_set(struct mthca_array *array, int index, void *value); +void mthca_array_clear(struct mthca_array *array, int index); +int mthca_array_init(struct mthca_array *array, int nent); +void mthca_array_cleanup(struct mthca_array *array, int nent); +int mthca_buf_alloc(struct mthca_dev *dev, int size, int max_direct, + union mthca_buf *buf, int *is_direct, struct mthca_pd *pd, + int hca_write, struct mthca_mr *mr); +void mthca_buf_free(struct mthca_dev *dev, int size, union mthca_buf *buf, + int is_direct, struct mthca_mr *mr); + +int mthca_init_uar_table(struct mthca_dev *dev); +int mthca_init_pd_table(struct mthca_dev *dev); +int mthca_init_mr_table(struct mthca_dev *dev); +int mthca_init_eq_table(struct mthca_dev *dev); +int mthca_init_cq_table(struct mthca_dev *dev); +int mthca_init_srq_table(struct mthca_dev *dev); +int mthca_init_qp_table(struct mthca_dev *dev); +int mthca_init_av_table(struct mthca_dev *dev); +int mthca_init_mcg_table(struct mthca_dev *dev); + +void mthca_cleanup_uar_table(struct mthca_dev *dev); +void mthca_cleanup_pd_table(struct mthca_dev *dev); +void mthca_cleanup_mr_table(struct mthca_dev *dev); +void mthca_cleanup_eq_table(struct mthca_dev *dev); +void mthca_cleanup_cq_table(struct mthca_dev *dev); +void mthca_cleanup_srq_table(struct mthca_dev *dev); +void mthca_cleanup_qp_table(struct mthca_dev *dev); +void mthca_cleanup_av_table(struct mthca_dev *dev); +void mthca_cleanup_mcg_table(struct mthca_dev *dev); + +int mthca_register_device(struct mthca_dev *dev); +void mthca_unregister_device(struct mthca_dev *dev); + +void mthca_start_catas_poll(struct mthca_dev *dev); +void mthca_stop_catas_poll(struct mthca_dev *dev); +int __mthca_restart_one(struct pci_dev *pdev); +int mthca_catas_init(void); +void mthca_catas_cleanup(void); + +int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar); +void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar); + +int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd); +void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd); + +int mthca_write_mtt_size(struct mthca_dev *dev); + +struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size); +void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt); +int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, + int start_index, u64 *buffer_list, int list_len); +int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift, + u64 iova, u64 total_size, u32 access, struct mthca_mr *mr); +int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd, + u32 access, struct mthca_mr *mr); +int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd, + u64 *buffer_list, int buffer_size_shift, + int list_len, u64 iova, u64 total_size, + u32 access, struct mthca_mr *mr); +void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr); + +int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd, + u32 access, struct mthca_fmr *fmr); +int mthca_tavor_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, + int list_len, u64 iova); +void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr); +int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, + int list_len, u64 iova); +void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr); +int mthca_free_fmr(struct mthca_dev *dev, struct mthca_fmr *fmr); + +int mthca_map_eq_icm(struct mthca_dev *dev, u64 icm_virt); +void mthca_unmap_eq_icm(struct mthca_dev *dev); + +int mthca_poll_cq(struct ib_cq *ibcq, int num_entries, + struct ib_wc *entry); +int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags); +int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags); +int mthca_init_cq(struct mthca_dev *dev, int nent, + struct mthca_ucontext *ctx, u32 pdn, + struct mthca_cq *cq); +void mthca_free_cq(struct mthca_dev *dev, + struct mthca_cq *cq); +void mthca_cq_completion(struct mthca_dev *dev, u32 cqn); +void mthca_cq_event(struct mthca_dev *dev, u32 cqn, + enum ib_event_type event_type); +void mthca_cq_clean(struct mthca_dev *dev, struct mthca_cq *cq, u32 qpn, + struct mthca_srq *srq); +void mthca_cq_resize_copy_cqes(struct mthca_cq *cq); +int mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent); +void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int cqe); + +int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, + struct ib_srq_attr *attr, struct mthca_srq *srq); +void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq); +int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, + enum ib_srq_attr_mask attr_mask, struct ib_udata *udata); +int mthca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr); +int mthca_max_srq_sge(struct mthca_dev *dev); +void mthca_srq_event(struct mthca_dev *dev, u32 srqn, + enum ib_event_type event_type); +void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr); +int mthca_tavor_post_srq_recv(struct ib_srq *srq, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr); +int mthca_arbel_post_srq_recv(struct ib_srq *srq, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr); + +void mthca_qp_event(struct mthca_dev *dev, u32 qpn, + enum ib_event_type event_type); +int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr); +int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, + struct ib_udata *udata); +int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr); +int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr); +int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr); +int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr); +void mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send, + int index, int *dbd, __be32 *new_wqe); +int mthca_alloc_qp(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_cq *send_cq, + struct mthca_cq *recv_cq, + enum ib_qp_type type, + enum ib_sig_type send_policy, + struct ib_qp_cap *cap, + struct mthca_qp *qp); +int mthca_alloc_sqp(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_cq *send_cq, + struct mthca_cq *recv_cq, + enum ib_sig_type send_policy, + struct ib_qp_cap *cap, + int qpn, + int port, + struct mthca_sqp *sqp); +void mthca_free_qp(struct mthca_dev *dev, struct mthca_qp *qp); +int mthca_create_ah(struct mthca_dev *dev, + struct mthca_pd *pd, + struct ib_ah_attr *ah_attr, + struct mthca_ah *ah); +int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah); +int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah, + struct ib_ud_header *header); +int mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr); +int mthca_ah_grh_present(struct mthca_ah *ah); +u8 mthca_get_rate(struct mthca_dev *dev, int static_rate, u8 port); +enum ib_rate mthca_rate_to_ib(struct mthca_dev *dev, u8 mthca_rate, u8 port); + +int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid); +int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid); + +int mthca_process_mad(struct ib_device *ibdev, + int mad_flags, + u8 port_num, + struct ib_wc *in_wc, + struct ib_grh *in_grh, + struct ib_mad *in_mad, + struct ib_mad *out_mad); +int mthca_create_agents(struct mthca_dev *dev); +void mthca_free_agents(struct mthca_dev *dev); + +static inline struct mthca_dev *to_mdev(struct ib_device *ibdev) +{ + return container_of(ibdev, struct mthca_dev, ib_dev); +} + +static inline int mthca_is_memfree(struct mthca_dev *dev) +{ + return dev->mthca_flags & MTHCA_FLAG_MEMFREE; +} + +#endif /* MTHCA_DEV_H */ diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_doorbell.h b/sys/ofed/drivers/infiniband/hw/mthca/mthca_doorbell.h new file mode 100644 index 000000000000..14f51ef97d7e --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_doorbell.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#define MTHCA_RD_DOORBELL 0x00 +#define MTHCA_SEND_DOORBELL 0x10 +#define MTHCA_RECEIVE_DOORBELL 0x18 +#define MTHCA_CQ_DOORBELL 0x20 +#define MTHCA_EQ_DOORBELL 0x28 + +#if BITS_PER_LONG == 64 +/* + * Assume that we can just write a 64-bit doorbell atomically. s390 + * actually doesn't have writeq() but S/390 systems don't even have + * PCI so we won't worry about it. + */ + +#define MTHCA_DECLARE_DOORBELL_LOCK(name) +#define MTHCA_INIT_DOORBELL_LOCK(ptr) do { } while (0) +#define MTHCA_GET_DOORBELL_LOCK(ptr) (NULL) + +static inline void mthca_write64_raw(__be64 val, void __iomem *dest) +{ + __raw_writeq((__force u64) val, dest); +} + +static inline void mthca_write64(u32 hi, u32 lo, void __iomem *dest, + spinlock_t *doorbell_lock) +{ + __raw_writeq((__force u64) cpu_to_be64((u64) hi << 32 | lo), dest); +} + +static inline void mthca_write_db_rec(__be32 val[2], __be32 *db) +{ + *(u64 *) db = *(u64 *) val; +} + +#else + +/* + * Just fall back to a spinlock to protect the doorbell if + * BITS_PER_LONG is 32 -- there's no portable way to do atomic 64-bit + * MMIO writes. + */ + +#define MTHCA_DECLARE_DOORBELL_LOCK(name) spinlock_t name; +#define MTHCA_INIT_DOORBELL_LOCK(ptr) spin_lock_init(ptr) +#define MTHCA_GET_DOORBELL_LOCK(ptr) (ptr) + +static inline void mthca_write64_raw(__be64 val, void __iomem *dest) +{ + __raw_writel(((__force u32 *) &val)[0], dest); + __raw_writel(((__force u32 *) &val)[1], dest + 4); +} + +static inline void mthca_write64(u32 hi, u32 lo, void __iomem *dest, + spinlock_t *doorbell_lock) +{ + unsigned long flags; + + hi = (__force u32) cpu_to_be32(hi); + lo = (__force u32) cpu_to_be32(lo); + + spin_lock_irqsave(doorbell_lock, flags); + __raw_writel(hi, dest); + __raw_writel(lo, dest + 4); + spin_unlock_irqrestore(doorbell_lock, flags); +} + +static inline void mthca_write_db_rec(__be32 val[2], __be32 *db) +{ + db[0] = val[0]; + wmb(); + db[1] = val[1]; +} + +#endif diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_eq.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_eq.c new file mode 100644 index 000000000000..90e4e450a120 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_eq.c @@ -0,0 +1,920 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "mthca_dev.h" +#include "mthca_cmd.h" +#include "mthca_config_reg.h" + +enum { + MTHCA_NUM_ASYNC_EQE = 0x80, + MTHCA_NUM_CMD_EQE = 0x80, + MTHCA_NUM_SPARE_EQE = 0x80, + MTHCA_EQ_ENTRY_SIZE = 0x20 +}; + +/* + * Must be packed because start is 64 bits but only aligned to 32 bits. + */ +struct mthca_eq_context { + __be32 flags; + __be64 start; + __be32 logsize_usrpage; + __be32 tavor_pd; /* reserved for Arbel */ + u8 reserved1[3]; + u8 intr; + __be32 arbel_pd; /* lost_count for Tavor */ + __be32 lkey; + u32 reserved2[2]; + __be32 consumer_index; + __be32 producer_index; + u32 reserved3[4]; +} __attribute__((packed)); + +#define MTHCA_EQ_STATUS_OK ( 0 << 28) +#define MTHCA_EQ_STATUS_OVERFLOW ( 9 << 28) +#define MTHCA_EQ_STATUS_WRITE_FAIL (10 << 28) +#define MTHCA_EQ_OWNER_SW ( 0 << 24) +#define MTHCA_EQ_OWNER_HW ( 1 << 24) +#define MTHCA_EQ_FLAG_TR ( 1 << 18) +#define MTHCA_EQ_FLAG_OI ( 1 << 17) +#define MTHCA_EQ_STATE_ARMED ( 1 << 8) +#define MTHCA_EQ_STATE_FIRED ( 2 << 8) +#define MTHCA_EQ_STATE_ALWAYS_ARMED ( 3 << 8) +#define MTHCA_EQ_STATE_ARBEL ( 8 << 8) + +enum { + MTHCA_EVENT_TYPE_COMP = 0x00, + MTHCA_EVENT_TYPE_PATH_MIG = 0x01, + MTHCA_EVENT_TYPE_COMM_EST = 0x02, + MTHCA_EVENT_TYPE_SQ_DRAINED = 0x03, + MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE = 0x13, + MTHCA_EVENT_TYPE_SRQ_LIMIT = 0x14, + MTHCA_EVENT_TYPE_CQ_ERROR = 0x04, + MTHCA_EVENT_TYPE_WQ_CATAS_ERROR = 0x05, + MTHCA_EVENT_TYPE_EEC_CATAS_ERROR = 0x06, + MTHCA_EVENT_TYPE_PATH_MIG_FAILED = 0x07, + MTHCA_EVENT_TYPE_WQ_INVAL_REQ_ERROR = 0x10, + MTHCA_EVENT_TYPE_WQ_ACCESS_ERROR = 0x11, + MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR = 0x12, + MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR = 0x08, + MTHCA_EVENT_TYPE_PORT_CHANGE = 0x09, + MTHCA_EVENT_TYPE_EQ_OVERFLOW = 0x0f, + MTHCA_EVENT_TYPE_ECC_DETECT = 0x0e, + MTHCA_EVENT_TYPE_CMD = 0x0a +}; + +#define MTHCA_ASYNC_EVENT_MASK ((1ULL << MTHCA_EVENT_TYPE_PATH_MIG) | \ + (1ULL << MTHCA_EVENT_TYPE_COMM_EST) | \ + (1ULL << MTHCA_EVENT_TYPE_SQ_DRAINED) | \ + (1ULL << MTHCA_EVENT_TYPE_CQ_ERROR) | \ + (1ULL << MTHCA_EVENT_TYPE_WQ_CATAS_ERROR) | \ + (1ULL << MTHCA_EVENT_TYPE_EEC_CATAS_ERROR) | \ + (1ULL << MTHCA_EVENT_TYPE_PATH_MIG_FAILED) | \ + (1ULL << MTHCA_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \ + (1ULL << MTHCA_EVENT_TYPE_WQ_ACCESS_ERROR) | \ + (1ULL << MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR) | \ + (1ULL << MTHCA_EVENT_TYPE_PORT_CHANGE) | \ + (1ULL << MTHCA_EVENT_TYPE_ECC_DETECT)) +#define MTHCA_SRQ_EVENT_MASK ((1ULL << MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR) | \ + (1ULL << MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE) | \ + (1ULL << MTHCA_EVENT_TYPE_SRQ_LIMIT)) +#define MTHCA_CMD_EVENT_MASK (1ULL << MTHCA_EVENT_TYPE_CMD) + +#define MTHCA_EQ_DB_INC_CI (1 << 24) +#define MTHCA_EQ_DB_REQ_NOT (2 << 24) +#define MTHCA_EQ_DB_DISARM_CQ (3 << 24) +#define MTHCA_EQ_DB_SET_CI (4 << 24) +#define MTHCA_EQ_DB_ALWAYS_ARM (5 << 24) + +struct mthca_eqe { + u8 reserved1; + u8 type; + u8 reserved2; + u8 subtype; + union { + u32 raw[6]; + struct { + __be32 cqn; + } __attribute__((packed)) comp; + struct { + u16 reserved1; + __be16 token; + u32 reserved2; + u8 reserved3[3]; + u8 status; + __be64 out_param; + } __attribute__((packed)) cmd; + struct { + __be32 qpn; + } __attribute__((packed)) qp; + struct { + __be32 srqn; + } __attribute__((packed)) srq; + struct { + __be32 cqn; + u32 reserved1; + u8 reserved2[3]; + u8 syndrome; + } __attribute__((packed)) cq_err; + struct { + u32 reserved1[2]; + __be32 port; + } __attribute__((packed)) port_change; + } event; + u8 reserved3[3]; + u8 owner; +} __attribute__((packed)); + +#define MTHCA_EQ_ENTRY_OWNER_SW (0 << 7) +#define MTHCA_EQ_ENTRY_OWNER_HW (1 << 7) + +static inline u64 async_mask(struct mthca_dev *dev) +{ + return dev->mthca_flags & MTHCA_FLAG_SRQ ? + MTHCA_ASYNC_EVENT_MASK | MTHCA_SRQ_EVENT_MASK : + MTHCA_ASYNC_EVENT_MASK; +} + +static inline void tavor_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci) +{ + /* + * This barrier makes sure that all updates to ownership bits + * done by set_eqe_hw() hit memory before the consumer index + * is updated. set_eq_ci() allows the HCA to possibly write + * more EQ entries, and we want to avoid the exceedingly + * unlikely possibility of the HCA writing an entry and then + * having set_eqe_hw() overwrite the owner field. + */ + wmb(); + mthca_write64(MTHCA_EQ_DB_SET_CI | eq->eqn, ci & (eq->nent - 1), + dev->kar + MTHCA_EQ_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); +} + +static inline void arbel_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci) +{ + /* See comment in tavor_set_eq_ci() above. */ + wmb(); + __raw_writel((__force u32) cpu_to_be32(ci), + dev->eq_regs.arbel.eq_set_ci_base + eq->eqn * 8); + /* We still want ordering, just not swabbing, so add a barrier */ + mb(); +} + +static inline void set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci) +{ + if (mthca_is_memfree(dev)) + arbel_set_eq_ci(dev, eq, ci); + else + tavor_set_eq_ci(dev, eq, ci); +} + +static inline void tavor_eq_req_not(struct mthca_dev *dev, int eqn) +{ + mthca_write64(MTHCA_EQ_DB_REQ_NOT | eqn, 0, + dev->kar + MTHCA_EQ_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); +} + +static inline void arbel_eq_req_not(struct mthca_dev *dev, u32 eqn_mask) +{ + writel(eqn_mask, dev->eq_regs.arbel.eq_arm); +} + +static inline void disarm_cq(struct mthca_dev *dev, int eqn, int cqn) +{ + if (!mthca_is_memfree(dev)) { + mthca_write64(MTHCA_EQ_DB_DISARM_CQ | eqn, cqn, + dev->kar + MTHCA_EQ_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + } +} + +static inline struct mthca_eqe *get_eqe(struct mthca_eq *eq, u32 entry) +{ + unsigned long off = (entry & (eq->nent - 1)) * MTHCA_EQ_ENTRY_SIZE; + return eq->page_list[off / PAGE_SIZE].buf + off % PAGE_SIZE; +} + +static inline struct mthca_eqe *next_eqe_sw(struct mthca_eq *eq) +{ + struct mthca_eqe *eqe; + eqe = get_eqe(eq, eq->cons_index); + return (MTHCA_EQ_ENTRY_OWNER_HW & eqe->owner) ? NULL : eqe; +} + +static inline void set_eqe_hw(struct mthca_eqe *eqe) +{ + eqe->owner = MTHCA_EQ_ENTRY_OWNER_HW; +} + +static void port_change(struct mthca_dev *dev, int port, int active) +{ + struct ib_event record; + + mthca_dbg(dev, "Port change to %s for port %d\n", + active ? "active" : "down", port); + + record.device = &dev->ib_dev; + record.event = active ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR; + record.element.port_num = port; + + ib_dispatch_event(&record); +} + +static int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq) +{ + struct mthca_eqe *eqe; + int disarm_cqn; + int eqes_found = 0; + int set_ci = 0; + + while ((eqe = next_eqe_sw(eq))) { + /* + * Make sure we read EQ entry contents after we've + * checked the ownership bit. + */ + rmb(); + + switch (eqe->type) { + case MTHCA_EVENT_TYPE_COMP: + disarm_cqn = be32_to_cpu(eqe->event.comp.cqn) & 0xffffff; + disarm_cq(dev, eq->eqn, disarm_cqn); + mthca_cq_completion(dev, disarm_cqn); + break; + + case MTHCA_EVENT_TYPE_PATH_MIG: + mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_PATH_MIG); + break; + + case MTHCA_EVENT_TYPE_COMM_EST: + mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_COMM_EST); + break; + + case MTHCA_EVENT_TYPE_SQ_DRAINED: + mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_SQ_DRAINED); + break; + + case MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE: + mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_QP_LAST_WQE_REACHED); + break; + + case MTHCA_EVENT_TYPE_SRQ_LIMIT: + mthca_srq_event(dev, be32_to_cpu(eqe->event.srq.srqn) & 0xffffff, + IB_EVENT_SRQ_LIMIT_REACHED); + break; + + case MTHCA_EVENT_TYPE_WQ_CATAS_ERROR: + mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_QP_FATAL); + break; + + case MTHCA_EVENT_TYPE_PATH_MIG_FAILED: + mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_PATH_MIG_ERR); + break; + + case MTHCA_EVENT_TYPE_WQ_INVAL_REQ_ERROR: + mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_QP_REQ_ERR); + break; + + case MTHCA_EVENT_TYPE_WQ_ACCESS_ERROR: + mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, + IB_EVENT_QP_ACCESS_ERR); + break; + + case MTHCA_EVENT_TYPE_CMD: + mthca_cmd_event(dev, + be16_to_cpu(eqe->event.cmd.token), + eqe->event.cmd.status, + be64_to_cpu(eqe->event.cmd.out_param)); + break; + + case MTHCA_EVENT_TYPE_PORT_CHANGE: + port_change(dev, + (be32_to_cpu(eqe->event.port_change.port) >> 28) & 3, + eqe->subtype == 0x4); + break; + + case MTHCA_EVENT_TYPE_CQ_ERROR: + mthca_warn(dev, "CQ %s on CQN %06x\n", + eqe->event.cq_err.syndrome == 1 ? + "overrun" : "access violation", + be32_to_cpu(eqe->event.cq_err.cqn) & 0xffffff); + mthca_cq_event(dev, be32_to_cpu(eqe->event.cq_err.cqn), + IB_EVENT_CQ_ERR); + break; + + case MTHCA_EVENT_TYPE_EQ_OVERFLOW: + mthca_warn(dev, "EQ overrun on EQN %d\n", eq->eqn); + break; + + case MTHCA_EVENT_TYPE_EEC_CATAS_ERROR: + case MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR: + case MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR: + case MTHCA_EVENT_TYPE_ECC_DETECT: + default: + mthca_warn(dev, "Unhandled event %02x(%02x) on EQ %d\n", + eqe->type, eqe->subtype, eq->eqn); + break; + }; + + set_eqe_hw(eqe); + ++eq->cons_index; + eqes_found = 1; + ++set_ci; + + /* + * The HCA will think the queue has overflowed if we + * don't tell it we've been processing events. We + * create our EQs with MTHCA_NUM_SPARE_EQE extra + * entries, so we must update our consumer index at + * least that often. + */ + if (unlikely(set_ci >= MTHCA_NUM_SPARE_EQE)) { + /* + * Conditional on hca_type is OK here because + * this is a rare case, not the fast path. + */ + set_eq_ci(dev, eq, eq->cons_index); + set_ci = 0; + } + } + + /* + * Rely on caller to set consumer index so that we don't have + * to test hca_type in our interrupt handling fast path. + */ + return eqes_found; +} + +static irqreturn_t mthca_tavor_interrupt(int irq, void *dev_ptr) +{ + struct mthca_dev *dev = dev_ptr; + u32 ecr; + int i; + + if (dev->eq_table.clr_mask) + writel(dev->eq_table.clr_mask, dev->eq_table.clr_int); + + ecr = readl(dev->eq_regs.tavor.ecr_base + 4); + if (!ecr) + return IRQ_NONE; + + writel(ecr, dev->eq_regs.tavor.ecr_base + + MTHCA_ECR_CLR_BASE - MTHCA_ECR_BASE + 4); + + for (i = 0; i < MTHCA_NUM_EQ; ++i) + if (ecr & dev->eq_table.eq[i].eqn_mask) { + if (mthca_eq_int(dev, &dev->eq_table.eq[i])) + tavor_set_eq_ci(dev, &dev->eq_table.eq[i], + dev->eq_table.eq[i].cons_index); + tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn); + } + + return IRQ_HANDLED; +} + +static irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr) +{ + struct mthca_eq *eq = eq_ptr; + struct mthca_dev *dev = eq->dev; + + mthca_eq_int(dev, eq); + tavor_set_eq_ci(dev, eq, eq->cons_index); + tavor_eq_req_not(dev, eq->eqn); + + /* MSI-X vectors always belong to us */ + return IRQ_HANDLED; +} + +static irqreturn_t mthca_arbel_interrupt(int irq, void *dev_ptr) +{ + struct mthca_dev *dev = dev_ptr; + int work = 0; + int i; + + if (dev->eq_table.clr_mask) + writel(dev->eq_table.clr_mask, dev->eq_table.clr_int); + + for (i = 0; i < MTHCA_NUM_EQ; ++i) + if (mthca_eq_int(dev, &dev->eq_table.eq[i])) { + work = 1; + arbel_set_eq_ci(dev, &dev->eq_table.eq[i], + dev->eq_table.eq[i].cons_index); + } + + arbel_eq_req_not(dev, dev->eq_table.arm_mask); + + return IRQ_RETVAL(work); +} + +static irqreturn_t mthca_arbel_msi_x_interrupt(int irq, void *eq_ptr) +{ + struct mthca_eq *eq = eq_ptr; + struct mthca_dev *dev = eq->dev; + + mthca_eq_int(dev, eq); + arbel_set_eq_ci(dev, eq, eq->cons_index); + arbel_eq_req_not(dev, eq->eqn_mask); + + /* MSI-X vectors always belong to us */ + return IRQ_HANDLED; +} + +static int mthca_create_eq(struct mthca_dev *dev, + int nent, + u8 intr, + struct mthca_eq *eq) +{ + int npages; + u64 *dma_list = NULL; + dma_addr_t t; + struct mthca_mailbox *mailbox; + struct mthca_eq_context *eq_context; + int err = -ENOMEM; + int i; + u8 status; + + eq->dev = dev; + eq->nent = roundup_pow_of_two(max(nent, 2)); + npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE; + + eq->page_list = kmalloc(npages * sizeof *eq->page_list, + GFP_KERNEL); + if (!eq->page_list) + goto err_out; + + for (i = 0; i < npages; ++i) + eq->page_list[i].buf = NULL; + + dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL); + if (!dma_list) + goto err_out_free; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + goto err_out_free; + eq_context = mailbox->buf; + + for (i = 0; i < npages; ++i) { + eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev, + PAGE_SIZE, &t, GFP_KERNEL); + if (!eq->page_list[i].buf) + goto err_out_free_pages; + + dma_list[i] = t; + pci_unmap_addr_set(&eq->page_list[i], mapping, t); + + clear_page(eq->page_list[i].buf); + } + + for (i = 0; i < eq->nent; ++i) + set_eqe_hw(get_eqe(eq, i)); + + eq->eqn = mthca_alloc(&dev->eq_table.alloc); + if (eq->eqn == -1) + goto err_out_free_pages; + + err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num, + dma_list, PAGE_SHIFT, npages, + 0, npages * PAGE_SIZE, + MTHCA_MPT_FLAG_LOCAL_WRITE | + MTHCA_MPT_FLAG_LOCAL_READ, + &eq->mr); + if (err) + goto err_out_free_eq; + + memset(eq_context, 0, sizeof *eq_context); + eq_context->flags = cpu_to_be32(MTHCA_EQ_STATUS_OK | + MTHCA_EQ_OWNER_HW | + MTHCA_EQ_STATE_ARMED | + MTHCA_EQ_FLAG_TR); + if (mthca_is_memfree(dev)) + eq_context->flags |= cpu_to_be32(MTHCA_EQ_STATE_ARBEL); + + eq_context->logsize_usrpage = cpu_to_be32((ffs(eq->nent) - 1) << 24); + if (mthca_is_memfree(dev)) { + eq_context->arbel_pd = cpu_to_be32(dev->driver_pd.pd_num); + } else { + eq_context->logsize_usrpage |= cpu_to_be32(dev->driver_uar.index); + eq_context->tavor_pd = cpu_to_be32(dev->driver_pd.pd_num); + } + eq_context->intr = intr; + eq_context->lkey = cpu_to_be32(eq->mr.ibmr.lkey); + + err = mthca_SW2HW_EQ(dev, mailbox, eq->eqn, &status); + if (err) { + mthca_warn(dev, "SW2HW_EQ failed (%d)\n", err); + goto err_out_free_mr; + } + if (status) { + mthca_warn(dev, "SW2HW_EQ returned status 0x%02x\n", + status); + err = -EINVAL; + goto err_out_free_mr; + } + + kfree(dma_list); + mthca_free_mailbox(dev, mailbox); + + eq->eqn_mask = swab32(1 << eq->eqn); + eq->cons_index = 0; + + dev->eq_table.arm_mask |= eq->eqn_mask; + + mthca_dbg(dev, "Allocated EQ %d with %d entries\n", + eq->eqn, eq->nent); + + return err; + + err_out_free_mr: + mthca_free_mr(dev, &eq->mr); + + err_out_free_eq: + mthca_free(&dev->eq_table.alloc, eq->eqn); + + err_out_free_pages: + for (i = 0; i < npages; ++i) + if (eq->page_list[i].buf) + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + eq->page_list[i].buf, + pci_unmap_addr(&eq->page_list[i], + mapping)); + + mthca_free_mailbox(dev, mailbox); + + err_out_free: + kfree(eq->page_list); + kfree(dma_list); + + err_out: + return err; +} + +static void mthca_free_eq(struct mthca_dev *dev, + struct mthca_eq *eq) +{ + struct mthca_mailbox *mailbox; + int err; + u8 status; + int npages = (eq->nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) / + PAGE_SIZE; + int i; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return; + + err = mthca_HW2SW_EQ(dev, mailbox, eq->eqn, &status); + if (err) + mthca_warn(dev, "HW2SW_EQ failed (%d)\n", err); + if (status) + mthca_warn(dev, "HW2SW_EQ returned status 0x%02x\n", status); + + dev->eq_table.arm_mask &= ~eq->eqn_mask; + + if (0) { + mthca_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn); + for (i = 0; i < sizeof (struct mthca_eq_context) / 4; ++i) { + if (i % 4 == 0) + printk("[%02x] ", i * 4); + printk(" %08x", be32_to_cpup(mailbox->buf + i * 4)); + if ((i + 1) % 4 == 0) + printk("\n"); + } + } + + mthca_free_mr(dev, &eq->mr); + for (i = 0; i < npages; ++i) + pci_free_consistent(dev->pdev, PAGE_SIZE, + eq->page_list[i].buf, + pci_unmap_addr(&eq->page_list[i], mapping)); + + kfree(eq->page_list); + mthca_free_mailbox(dev, mailbox); +} + +static void mthca_free_irqs(struct mthca_dev *dev) +{ + int i; + + if (dev->eq_table.have_irq) + free_irq(dev->pdev->irq, dev); + for (i = 0; i < MTHCA_NUM_EQ; ++i) + if (dev->eq_table.eq[i].have_irq) { + free_irq(dev->eq_table.eq[i].msi_x_vector, + dev->eq_table.eq + i); + dev->eq_table.eq[i].have_irq = 0; + } +} + +static int mthca_map_reg(struct mthca_dev *dev, + unsigned long offset, unsigned long size, + void __iomem **map) +{ + unsigned long base = pci_resource_start(dev->pdev, 0); + + *map = ioremap(base + offset, size); + if (!*map) + return -ENOMEM; + + return 0; +} + +static int mthca_map_eq_regs(struct mthca_dev *dev) +{ + if (mthca_is_memfree(dev)) { + /* + * We assume that the EQ arm and EQ set CI registers + * fall within the first BAR. We can't trust the + * values firmware gives us, since those addresses are + * valid on the HCA's side of the PCI bus but not + * necessarily the host side. + */ + if (mthca_map_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) & + dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE, + &dev->clr_base)) { + mthca_err(dev, "Couldn't map interrupt clear register, " + "aborting.\n"); + return -ENOMEM; + } + + /* + * Add 4 because we limit ourselves to EQs 0 ... 31, + * so we only need the low word of the register. + */ + if (mthca_map_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) & + dev->fw.arbel.eq_arm_base) + 4, 4, + &dev->eq_regs.arbel.eq_arm)) { + mthca_err(dev, "Couldn't map EQ arm register, aborting.\n"); + iounmap(dev->clr_base); + return -ENOMEM; + } + + if (mthca_map_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) & + dev->fw.arbel.eq_set_ci_base, + MTHCA_EQ_SET_CI_SIZE, + &dev->eq_regs.arbel.eq_set_ci_base)) { + mthca_err(dev, "Couldn't map EQ CI register, aborting.\n"); + iounmap(dev->eq_regs.arbel.eq_arm); + iounmap(dev->clr_base); + return -ENOMEM; + } + } else { + if (mthca_map_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE, + &dev->clr_base)) { + mthca_err(dev, "Couldn't map interrupt clear register, " + "aborting.\n"); + return -ENOMEM; + } + + if (mthca_map_reg(dev, MTHCA_ECR_BASE, + MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE, + &dev->eq_regs.tavor.ecr_base)) { + mthca_err(dev, "Couldn't map ecr register, " + "aborting.\n"); + iounmap(dev->clr_base); + return -ENOMEM; + } + } + + return 0; + +} + +static void mthca_unmap_eq_regs(struct mthca_dev *dev) +{ + if (mthca_is_memfree(dev)) { + iounmap(dev->eq_regs.arbel.eq_set_ci_base); + iounmap(dev->eq_regs.arbel.eq_arm); + iounmap(dev->clr_base); + } else { + iounmap(dev->eq_regs.tavor.ecr_base); + iounmap(dev->clr_base); + } +} + +int mthca_map_eq_icm(struct mthca_dev *dev, u64 icm_virt) +{ + int ret; + u8 status; + + /* + * We assume that mapping one page is enough for the whole EQ + * context table. This is fine with all current HCAs, because + * we only use 32 EQs and each EQ uses 32 bytes of context + * memory, or 1 KB total. + */ + dev->eq_table.icm_virt = icm_virt; + dev->eq_table.icm_page = alloc_page(GFP_HIGHUSER); + if (!dev->eq_table.icm_page) + return -ENOMEM; + dev->eq_table.icm_dma = pci_map_page(dev->pdev, dev->eq_table.icm_page, 0, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(dev->pdev, dev->eq_table.icm_dma)) { + __free_page(dev->eq_table.icm_page); + return -ENOMEM; + } + + ret = mthca_MAP_ICM_page(dev, dev->eq_table.icm_dma, icm_virt, &status); + if (!ret && status) + ret = -EINVAL; + if (ret) { + pci_unmap_page(dev->pdev, dev->eq_table.icm_dma, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); + __free_page(dev->eq_table.icm_page); + } + + return ret; +} + +void mthca_unmap_eq_icm(struct mthca_dev *dev) +{ + u8 status; + + mthca_UNMAP_ICM(dev, dev->eq_table.icm_virt, 1, &status); + pci_unmap_page(dev->pdev, dev->eq_table.icm_dma, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); + __free_page(dev->eq_table.icm_page); +} + +int mthca_init_eq_table(struct mthca_dev *dev) +{ + int err; + u8 status; + u8 intr; + int i; + + err = mthca_alloc_init(&dev->eq_table.alloc, + dev->limits.num_eqs, + dev->limits.num_eqs - 1, + dev->limits.reserved_eqs); + if (err) + return err; + + err = mthca_map_eq_regs(dev); + if (err) + goto err_out_free; + + if (dev->mthca_flags & MTHCA_FLAG_MSI_X) { + dev->eq_table.clr_mask = 0; + } else { + dev->eq_table.clr_mask = + swab32(1 << (dev->eq_table.inta_pin & 31)); + dev->eq_table.clr_int = dev->clr_base + + (dev->eq_table.inta_pin < 32 ? 4 : 0); + } + + dev->eq_table.arm_mask = 0; + + intr = dev->eq_table.inta_pin; + + err = mthca_create_eq(dev, dev->limits.num_cqs + MTHCA_NUM_SPARE_EQE, + (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr, + &dev->eq_table.eq[MTHCA_EQ_COMP]); + if (err) + goto err_out_unmap; + + err = mthca_create_eq(dev, MTHCA_NUM_ASYNC_EQE + MTHCA_NUM_SPARE_EQE, + (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 129 : intr, + &dev->eq_table.eq[MTHCA_EQ_ASYNC]); + if (err) + goto err_out_comp; + + err = mthca_create_eq(dev, MTHCA_NUM_CMD_EQE + MTHCA_NUM_SPARE_EQE, + (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 130 : intr, + &dev->eq_table.eq[MTHCA_EQ_CMD]); + if (err) + goto err_out_async; + + if (dev->mthca_flags & MTHCA_FLAG_MSI_X) { + static const char *eq_name[] = { + [MTHCA_EQ_COMP] = DRV_NAME " (comp)", + [MTHCA_EQ_ASYNC] = DRV_NAME " (async)", + [MTHCA_EQ_CMD] = DRV_NAME " (cmd)" + }; + + for (i = 0; i < MTHCA_NUM_EQ; ++i) { + err = request_irq(dev->eq_table.eq[i].msi_x_vector, + mthca_is_memfree(dev) ? + mthca_arbel_msi_x_interrupt : + mthca_tavor_msi_x_interrupt, + 0, eq_name[i], dev->eq_table.eq + i); + if (err) + goto err_out_cmd; + dev->eq_table.eq[i].have_irq = 1; + } + } else { + err = request_irq(dev->pdev->irq, + mthca_is_memfree(dev) ? + mthca_arbel_interrupt : + mthca_tavor_interrupt, + IRQF_SHARED, DRV_NAME, dev); + if (err) + goto err_out_cmd; + dev->eq_table.have_irq = 1; + } + + err = mthca_MAP_EQ(dev, async_mask(dev), + 0, dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, &status); + if (err) + mthca_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n", + dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, err); + if (status) + mthca_warn(dev, "MAP_EQ for async EQ %d returned status 0x%02x\n", + dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, status); + + err = mthca_MAP_EQ(dev, MTHCA_CMD_EVENT_MASK, + 0, dev->eq_table.eq[MTHCA_EQ_CMD].eqn, &status); + if (err) + mthca_warn(dev, "MAP_EQ for cmd EQ %d failed (%d)\n", + dev->eq_table.eq[MTHCA_EQ_CMD].eqn, err); + if (status) + mthca_warn(dev, "MAP_EQ for cmd EQ %d returned status 0x%02x\n", + dev->eq_table.eq[MTHCA_EQ_CMD].eqn, status); + + for (i = 0; i < MTHCA_NUM_EQ; ++i) + if (mthca_is_memfree(dev)) + arbel_eq_req_not(dev, dev->eq_table.eq[i].eqn_mask); + else + tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn); + + return 0; + +err_out_cmd: + mthca_free_irqs(dev); + mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_CMD]); + +err_out_async: + mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_ASYNC]); + +err_out_comp: + mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_COMP]); + +err_out_unmap: + mthca_unmap_eq_regs(dev); + +err_out_free: + mthca_alloc_cleanup(&dev->eq_table.alloc); + return err; +} + +void mthca_cleanup_eq_table(struct mthca_dev *dev) +{ + u8 status; + int i; + + mthca_free_irqs(dev); + + mthca_MAP_EQ(dev, async_mask(dev), + 1, dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, &status); + mthca_MAP_EQ(dev, MTHCA_CMD_EVENT_MASK, + 1, dev->eq_table.eq[MTHCA_EQ_CMD].eqn, &status); + + for (i = 0; i < MTHCA_NUM_EQ; ++i) + mthca_free_eq(dev, &dev->eq_table.eq[i]); + + mthca_unmap_eq_regs(dev); + + mthca_alloc_cleanup(&dev->eq_table.alloc); +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_mad.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_mad.c new file mode 100644 index 000000000000..5648659ff0b0 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_mad.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include +#include +#include + +#include "mthca_dev.h" +#include "mthca_cmd.h" + +enum { + MTHCA_VENDOR_CLASS1 = 0x9, + MTHCA_VENDOR_CLASS2 = 0xa +}; + +static int mthca_update_rate(struct mthca_dev *dev, u8 port_num) +{ + struct ib_port_attr *tprops = NULL; + int ret; + + tprops = kmalloc(sizeof *tprops, GFP_KERNEL); + if (!tprops) + return -ENOMEM; + + ret = ib_query_port(&dev->ib_dev, port_num, tprops); + if (ret) { + printk(KERN_WARNING "ib_query_port failed (%d) for %s port %d\n", + ret, dev->ib_dev.name, port_num); + goto out; + } + + dev->rate[port_num - 1] = tprops->active_speed * + ib_width_enum_to_int(tprops->active_width); + +out: + kfree(tprops); + return ret; +} + +static void update_sm_ah(struct mthca_dev *dev, + u8 port_num, u16 lid, u8 sl) +{ + struct ib_ah *new_ah; + struct ib_ah_attr ah_attr; + unsigned long flags; + + if (!dev->send_agent[port_num - 1][0]) + return; + + memset(&ah_attr, 0, sizeof ah_attr); + ah_attr.dlid = lid; + ah_attr.sl = sl; + ah_attr.port_num = port_num; + + new_ah = ib_create_ah(dev->send_agent[port_num - 1][0]->qp->pd, + &ah_attr); + if (IS_ERR(new_ah)) + return; + + spin_lock_irqsave(&dev->sm_lock, flags); + if (dev->sm_ah[port_num - 1]) + ib_destroy_ah(dev->sm_ah[port_num - 1]); + dev->sm_ah[port_num - 1] = new_ah; + spin_unlock_irqrestore(&dev->sm_lock, flags); +} + +/* + * Snoop SM MADs for port info and P_Key table sets, so we can + * synthesize LID change and P_Key change events. + */ +static void smp_snoop(struct ib_device *ibdev, + u8 port_num, + struct ib_mad *mad, + u16 prev_lid) +{ + struct ib_event event; + + if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || + mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && + mad->mad_hdr.method == IB_MGMT_METHOD_SET) { + if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) { + struct ib_port_info *pinfo = + (struct ib_port_info *) ((struct ib_smp *) mad)->data; + u16 lid = be16_to_cpu(pinfo->lid); + + mthca_update_rate(to_mdev(ibdev), port_num); + update_sm_ah(to_mdev(ibdev), port_num, + be16_to_cpu(pinfo->sm_lid), + pinfo->neighbormtu_mastersmsl & 0xf); + + event.device = ibdev; + event.element.port_num = port_num; + + if (pinfo->clientrereg_resv_subnetto & 0x80) { + event.event = IB_EVENT_CLIENT_REREGISTER; + ib_dispatch_event(&event); + } + + if (prev_lid != lid) { + event.event = IB_EVENT_LID_CHANGE; + ib_dispatch_event(&event); + } + } + + if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) { + event.device = ibdev; + event.event = IB_EVENT_PKEY_CHANGE; + event.element.port_num = port_num; + ib_dispatch_event(&event); + } + } +} + +static void node_desc_override(struct ib_device *dev, + struct ib_mad *mad) +{ + if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || + mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && + mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP && + mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) { + mutex_lock(&to_mdev(dev)->cap_mask_mutex); + memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64); + mutex_unlock(&to_mdev(dev)->cap_mask_mutex); + } +} + +static void forward_trap(struct mthca_dev *dev, + u8 port_num, + struct ib_mad *mad) +{ + int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; + struct ib_mad_send_buf *send_buf; + struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; + int ret; + unsigned long flags; + + if (agent) { + send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, + IB_MGMT_MAD_DATA, GFP_ATOMIC); + /* + * We rely here on the fact that MLX QPs don't use the + * address handle after the send is posted (this is + * wrong following the IB spec strictly, but we know + * it's OK for our devices). + */ + spin_lock_irqsave(&dev->sm_lock, flags); + memcpy(send_buf->mad, mad, sizeof *mad); + if ((send_buf->ah = dev->sm_ah[port_num - 1])) + ret = ib_post_send_mad(send_buf, NULL); + else + ret = -EINVAL; + spin_unlock_irqrestore(&dev->sm_lock, flags); + + if (ret) + ib_free_send_mad(send_buf); + } +} + +int mthca_process_mad(struct ib_device *ibdev, + int mad_flags, + u8 port_num, + struct ib_wc *in_wc, + struct ib_grh *in_grh, + struct ib_mad *in_mad, + struct ib_mad *out_mad) +{ + int err; + u8 status; + u16 slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE); + u16 prev_lid = 0; + struct ib_port_attr pattr; + + /* Forward locally generated traps to the SM */ + if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && + slid == 0) { + forward_trap(to_mdev(ibdev), port_num, in_mad); + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; + } + + /* + * Only handle SM gets, sets and trap represses for SM class + * + * Only handle PMA and Mellanox vendor-specific class gets and + * sets for other classes. + */ + if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || + in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { + if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && + in_mad->mad_hdr.method != IB_MGMT_METHOD_SET && + in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) + return IB_MAD_RESULT_SUCCESS; + + /* + * Don't process SMInfo queries or vendor-specific + * MADs -- the SMA can't handle them. + */ + if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO || + ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) == + IB_SMP_ATTR_VENDOR_MASK)) + return IB_MAD_RESULT_SUCCESS; + } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || + in_mad->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS1 || + in_mad->mad_hdr.mgmt_class == MTHCA_VENDOR_CLASS2) { + if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && + in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) + return IB_MAD_RESULT_SUCCESS; + } else + return IB_MAD_RESULT_SUCCESS; + if ((in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || + in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && + in_mad->mad_hdr.method == IB_MGMT_METHOD_SET && + in_mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO && + !ib_query_port(ibdev, port_num, &pattr)) + prev_lid = pattr.lid; + + err = mthca_MAD_IFC(to_mdev(ibdev), + mad_flags & IB_MAD_IGNORE_MKEY, + mad_flags & IB_MAD_IGNORE_BKEY, + port_num, in_wc, in_grh, in_mad, out_mad, + &status); + if (err) { + mthca_err(to_mdev(ibdev), "MAD_IFC failed\n"); + return IB_MAD_RESULT_FAILURE; + } + if (status == MTHCA_CMD_STAT_BAD_PKT) + return IB_MAD_RESULT_SUCCESS; + if (status) { + mthca_err(to_mdev(ibdev), "MAD_IFC returned status %02x\n", + status); + return IB_MAD_RESULT_FAILURE; + } + + if (!out_mad->mad_hdr.status) { + smp_snoop(ibdev, port_num, in_mad, prev_lid); + node_desc_override(ibdev, out_mad); + } + + /* set return bit in status of directed route responses */ + if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) + out_mad->mad_hdr.status |= cpu_to_be16(1 << 15); + + if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) + /* no response for trap repress */ + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; + + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; +} + +static void send_handler(struct ib_mad_agent *agent, + struct ib_mad_send_wc *mad_send_wc) +{ + ib_free_send_mad(mad_send_wc->send_buf); +} + +int mthca_create_agents(struct mthca_dev *dev) +{ + struct ib_mad_agent *agent; + int p, q; + int ret; + + spin_lock_init(&dev->sm_lock); + + for (p = 0; p < dev->limits.num_ports; ++p) + for (q = 0; q <= 1; ++q) { + agent = ib_register_mad_agent(&dev->ib_dev, p + 1, + q ? IB_QPT_GSI : IB_QPT_SMI, + NULL, 0, send_handler, + NULL, NULL); + if (IS_ERR(agent)) { + ret = PTR_ERR(agent); + goto err; + } + dev->send_agent[p][q] = agent; + } + + + for (p = 1; p <= dev->limits.num_ports; ++p) { + ret = mthca_update_rate(dev, p); + if (ret) { + mthca_err(dev, "Failed to obtain port %d rate." + " aborting.\n", p); + goto err; + } + } + + return 0; + +err: + for (p = 0; p < dev->limits.num_ports; ++p) + for (q = 0; q <= 1; ++q) + if (dev->send_agent[p][q]) + ib_unregister_mad_agent(dev->send_agent[p][q]); + + return ret; +} + +void mthca_free_agents(struct mthca_dev *dev) +{ + struct ib_mad_agent *agent; + int p, q; + + for (p = 0; p < dev->limits.num_ports; ++p) { + for (q = 0; q <= 1; ++q) { + agent = dev->send_agent[p][q]; + dev->send_agent[p][q] = NULL; + ib_unregister_mad_agent(agent); + } + + if (dev->sm_ah[p]) + ib_destroy_ah(dev->sm_ah[p]); + } +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_main.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_main.c new file mode 100644 index 000000000000..772cf8ce381e --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_main.c @@ -0,0 +1,1360 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "mthca_dev.h" +#include "mthca_config_reg.h" +#include "mthca_cmd.h" +#include "mthca_profile.h" +#include "mthca_memfree.h" +#include "mthca_wqe.h" + +MODULE_AUTHOR("Roland Dreier"); +MODULE_DESCRIPTION("Mellanox InfiniBand HCA low-level driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRV_VERSION); + +#ifdef CONFIG_INFINIBAND_MTHCA_DEBUG + +int mthca_debug_level = 0; +module_param_named(debug_level, mthca_debug_level, int, 0644); +MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); + +#endif /* CONFIG_INFINIBAND_MTHCA_DEBUG */ + +#ifdef CONFIG_PCI_MSI + +static int msi_x = 1; +module_param(msi_x, int, 0444); +MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero"); + +#else /* CONFIG_PCI_MSI */ + +#define msi_x (0) + +#endif /* CONFIG_PCI_MSI */ + +static int tune_pci = 0; +module_param(tune_pci, int, 0444); +MODULE_PARM_DESC(tune_pci, "increase PCI burst from the default set by BIOS if nonzero"); + +DEFINE_MUTEX(mthca_device_mutex); + +#define MTHCA_DEFAULT_NUM_QP (1 << 16) +#define MTHCA_DEFAULT_RDB_PER_QP (1 << 2) +#define MTHCA_DEFAULT_NUM_CQ (1 << 16) +#define MTHCA_DEFAULT_NUM_MCG (1 << 13) +#define MTHCA_DEFAULT_NUM_MPT (1 << 17) +#define MTHCA_DEFAULT_NUM_MTT (1 << 20) +#define MTHCA_DEFAULT_NUM_UDAV (1 << 15) +#define MTHCA_DEFAULT_NUM_RESERVED_MTTS (1 << 18) +#define MTHCA_DEFAULT_NUM_UARC_SIZE (1 << 18) + +static struct mthca_profile hca_profile = { + .num_qp = MTHCA_DEFAULT_NUM_QP, + .rdb_per_qp = MTHCA_DEFAULT_RDB_PER_QP, + .num_cq = MTHCA_DEFAULT_NUM_CQ, + .num_mcg = MTHCA_DEFAULT_NUM_MCG, + .num_mpt = MTHCA_DEFAULT_NUM_MPT, + .num_mtt = MTHCA_DEFAULT_NUM_MTT, + .num_udav = MTHCA_DEFAULT_NUM_UDAV, /* Tavor only */ + .fmr_reserved_mtts = MTHCA_DEFAULT_NUM_RESERVED_MTTS, /* Tavor only */ + .uarc_size = MTHCA_DEFAULT_NUM_UARC_SIZE, /* Arbel only */ +}; + +module_param_named(num_qp, hca_profile.num_qp, int, 0444); +MODULE_PARM_DESC(num_qp, "maximum number of QPs per HCA"); + +module_param_named(rdb_per_qp, hca_profile.rdb_per_qp, int, 0444); +MODULE_PARM_DESC(rdb_per_qp, "number of RDB buffers per QP"); + +module_param_named(num_cq, hca_profile.num_cq, int, 0444); +MODULE_PARM_DESC(num_cq, "maximum number of CQs per HCA"); + +module_param_named(num_mcg, hca_profile.num_mcg, int, 0444); +MODULE_PARM_DESC(num_mcg, "maximum number of multicast groups per HCA"); + +module_param_named(num_mpt, hca_profile.num_mpt, int, 0444); +MODULE_PARM_DESC(num_mpt, + "maximum number of memory protection table entries per HCA"); + +module_param_named(num_mtt, hca_profile.num_mtt, int, 0444); +MODULE_PARM_DESC(num_mtt, + "maximum number of memory translation table segments per HCA"); + +module_param_named(num_udav, hca_profile.num_udav, int, 0444); +MODULE_PARM_DESC(num_udav, "maximum number of UD address vectors per HCA"); + +module_param_named(fmr_reserved_mtts, hca_profile.fmr_reserved_mtts, int, 0444); +MODULE_PARM_DESC(fmr_reserved_mtts, + "number of memory translation table segments reserved for FMR"); + +static int log_mtts_per_seg; +module_param_named(log_mtts_per_seg, log_mtts_per_seg, int, 0444); +MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment (1-5)"); + +static char mthca_version[] __devinitdata = + DRV_NAME ": Mellanox InfiniBand HCA driver v" + DRV_VERSION " (" DRV_RELDATE ")\n"; + +static int mthca_tune_pci(struct mthca_dev *mdev) +{ + if (!tune_pci) + return 0; + + /* First try to max out Read Byte Count */ + if (pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX)) { + if (pcix_set_mmrbc(mdev->pdev, pcix_get_max_mmrbc(mdev->pdev))) { + mthca_err(mdev, "Couldn't set PCI-X max read count, " + "aborting.\n"); + return -ENODEV; + } + } else if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE)) + mthca_info(mdev, "No PCI-X capability, not setting RBC.\n"); + + if (pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP)) { + if (pcie_set_readrq(mdev->pdev, 4096)) { + mthca_err(mdev, "Couldn't write PCI Express read request, " + "aborting.\n"); + return -ENODEV; + } + } else if (mdev->mthca_flags & MTHCA_FLAG_PCIE) + mthca_info(mdev, "No PCI Express capability, " + "not setting Max Read Request Size.\n"); + + return 0; +} + +static int mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim *dev_lim) +{ + int err; + u8 status; + + mdev->limits.mtt_seg_size = (1 << log_mtts_per_seg) * 8; + err = mthca_QUERY_DEV_LIM(mdev, dev_lim, &status); + if (err) { + mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); + return err; + } + if (status) { + mthca_err(mdev, "QUERY_DEV_LIM returned status 0x%02x, " + "aborting.\n", status); + return -EINVAL; + } + if (dev_lim->min_page_sz > PAGE_SIZE) { + mthca_err(mdev, "HCA minimum page size of %d bigger than " + "kernel PAGE_SIZE of %d, aborting.\n", + dev_lim->min_page_sz, PAGE_SIZE); + return -ENODEV; + } + if (dev_lim->num_ports > MTHCA_MAX_PORTS) { + mthca_err(mdev, "HCA has %d ports, but we only support %d, " + "aborting.\n", + dev_lim->num_ports, MTHCA_MAX_PORTS); + return -ENODEV; + } + + if (dev_lim->uar_size > pci_resource_len(mdev->pdev, 2)) { + mthca_err(mdev, "HCA reported UAR size of 0x%x bigger than " + "PCI resource 2 size of 0x%llx, aborting.\n", + dev_lim->uar_size, + (unsigned long long)pci_resource_len(mdev->pdev, 2)); + return -ENODEV; + } + + mdev->limits.num_ports = dev_lim->num_ports; + mdev->limits.vl_cap = dev_lim->max_vl; + mdev->limits.mtu_cap = dev_lim->max_mtu; + mdev->limits.gid_table_len = dev_lim->max_gids; + mdev->limits.pkey_table_len = dev_lim->max_pkeys; + mdev->limits.local_ca_ack_delay = dev_lim->local_ca_ack_delay; + /* + * Need to allow for worst case send WQE overhead and check + * whether max_desc_sz imposes a lower limit than max_sg; UD + * send has the biggest overhead. + */ + mdev->limits.max_sg = min_t(int, dev_lim->max_sg, + (dev_lim->max_desc_sz - + sizeof (struct mthca_next_seg) - + (mthca_is_memfree(mdev) ? + sizeof (struct mthca_arbel_ud_seg) : + sizeof (struct mthca_tavor_ud_seg))) / + sizeof (struct mthca_data_seg)); + mdev->limits.max_wqes = dev_lim->max_qp_sz; + mdev->limits.max_qp_init_rdma = dev_lim->max_requester_per_qp; + mdev->limits.reserved_qps = dev_lim->reserved_qps; + mdev->limits.max_srq_wqes = dev_lim->max_srq_sz; + mdev->limits.reserved_srqs = dev_lim->reserved_srqs; + mdev->limits.reserved_eecs = dev_lim->reserved_eecs; + mdev->limits.max_desc_sz = dev_lim->max_desc_sz; + mdev->limits.max_srq_sge = mthca_max_srq_sge(mdev); + /* + * Subtract 1 from the limit because we need to allocate a + * spare CQE so the HCA HW can tell the difference between an + * empty CQ and a full CQ. + */ + mdev->limits.max_cqes = dev_lim->max_cq_sz - 1; + mdev->limits.reserved_cqs = dev_lim->reserved_cqs; + mdev->limits.reserved_eqs = dev_lim->reserved_eqs; + mdev->limits.reserved_mtts = dev_lim->reserved_mtts; + mdev->limits.reserved_mrws = dev_lim->reserved_mrws; + mdev->limits.reserved_uars = dev_lim->reserved_uars; + mdev->limits.reserved_pds = dev_lim->reserved_pds; + mdev->limits.port_width_cap = dev_lim->max_port_width; + mdev->limits.page_size_cap = ~(u32) (dev_lim->min_page_sz - 1); + mdev->limits.flags = dev_lim->flags; + /* + * For old FW that doesn't return static rate support, use a + * value of 0x3 (only static rate values of 0 or 1 are handled), + * except on Sinai, where even old FW can handle static rate + * values of 2 and 3. + */ + if (dev_lim->stat_rate_support) + mdev->limits.stat_rate_support = dev_lim->stat_rate_support; + else if (mdev->mthca_flags & MTHCA_FLAG_SINAI_OPT) + mdev->limits.stat_rate_support = 0xf; + else + mdev->limits.stat_rate_support = 0x3; + + /* IB_DEVICE_RESIZE_MAX_WR not supported by driver. + May be doable since hardware supports it for SRQ. + + IB_DEVICE_N_NOTIFY_CQ is supported by hardware but not by driver. + + IB_DEVICE_SRQ_RESIZE is supported by hardware but SRQ is not + supported by driver. */ + mdev->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT | + IB_DEVICE_PORT_ACTIVE_EVENT | + IB_DEVICE_SYS_IMAGE_GUID | + IB_DEVICE_RC_RNR_NAK_GEN; + + if (dev_lim->flags & DEV_LIM_FLAG_BAD_PKEY_CNTR) + mdev->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR; + + if (dev_lim->flags & DEV_LIM_FLAG_BAD_QKEY_CNTR) + mdev->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR; + + if (dev_lim->flags & DEV_LIM_FLAG_RAW_MULTI) + mdev->device_cap_flags |= IB_DEVICE_RAW_MULTI; + + if (dev_lim->flags & DEV_LIM_FLAG_AUTO_PATH_MIG) + mdev->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG; + + if (dev_lim->flags & DEV_LIM_FLAG_UD_AV_PORT_ENFORCE) + mdev->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE; + + if (dev_lim->flags & DEV_LIM_FLAG_SRQ) + mdev->mthca_flags |= MTHCA_FLAG_SRQ; + + if (mthca_is_memfree(mdev)) + if (dev_lim->flags & DEV_LIM_FLAG_IPOIB_CSUM) + mdev->device_cap_flags |= IB_DEVICE_UD_IP_CSUM; + + return 0; +} + +static int mthca_init_tavor(struct mthca_dev *mdev) +{ + s64 size; + u8 status; + int err; + struct mthca_dev_lim dev_lim; + struct mthca_profile profile; + struct mthca_init_hca_param init_hca; + + err = mthca_SYS_EN(mdev, &status); + if (err) { + mthca_err(mdev, "SYS_EN command failed, aborting.\n"); + return err; + } + if (status) { + mthca_err(mdev, "SYS_EN returned status 0x%02x, " + "aborting.\n", status); + return -EINVAL; + } + + err = mthca_QUERY_FW(mdev, &status); + if (err) { + mthca_err(mdev, "QUERY_FW command failed, aborting.\n"); + goto err_disable; + } + if (status) { + mthca_err(mdev, "QUERY_FW returned status 0x%02x, " + "aborting.\n", status); + err = -EINVAL; + goto err_disable; + } + err = mthca_QUERY_DDR(mdev, &status); + if (err) { + mthca_err(mdev, "QUERY_DDR command failed, aborting.\n"); + goto err_disable; + } + if (status) { + mthca_err(mdev, "QUERY_DDR returned status 0x%02x, " + "aborting.\n", status); + err = -EINVAL; + goto err_disable; + } + + err = mthca_dev_lim(mdev, &dev_lim); + if (err) { + mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); + goto err_disable; + } + + profile = hca_profile; + profile.num_uar = dev_lim.uar_size / PAGE_SIZE; + profile.uarc_size = 0; + if (mdev->mthca_flags & MTHCA_FLAG_SRQ) + profile.num_srq = dev_lim.max_srqs; + + size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca); + if (size < 0) { + err = size; + goto err_disable; + } + + err = mthca_INIT_HCA(mdev, &init_hca, &status); + if (err) { + mthca_err(mdev, "INIT_HCA command failed, aborting.\n"); + goto err_disable; + } + if (status) { + mthca_err(mdev, "INIT_HCA returned status 0x%02x, " + "aborting.\n", status); + err = -EINVAL; + goto err_disable; + } + + return 0; + +err_disable: + mthca_SYS_DIS(mdev, &status); + + return err; +} + +static int mthca_load_fw(struct mthca_dev *mdev) +{ + u8 status; + int err; + + /* FIXME: use HCA-attached memory for FW if present */ + + mdev->fw.arbel.fw_icm = + mthca_alloc_icm(mdev, mdev->fw.arbel.fw_pages, + GFP_HIGHUSER | __GFP_NOWARN, 0); + if (!mdev->fw.arbel.fw_icm) { + mthca_err(mdev, "Couldn't allocate FW area, aborting.\n"); + return -ENOMEM; + } + + err = mthca_MAP_FA(mdev, mdev->fw.arbel.fw_icm, &status); + if (err) { + mthca_err(mdev, "MAP_FA command failed, aborting.\n"); + goto err_free; + } + if (status) { + mthca_err(mdev, "MAP_FA returned status 0x%02x, aborting.\n", status); + err = -EINVAL; + goto err_free; + } + err = mthca_RUN_FW(mdev, &status); + if (err) { + mthca_err(mdev, "RUN_FW command failed, aborting.\n"); + goto err_unmap_fa; + } + if (status) { + mthca_err(mdev, "RUN_FW returned status 0x%02x, aborting.\n", status); + err = -EINVAL; + goto err_unmap_fa; + } + + return 0; + +err_unmap_fa: + mthca_UNMAP_FA(mdev, &status); + +err_free: + mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); + return err; +} + +static int mthca_init_icm(struct mthca_dev *mdev, + struct mthca_dev_lim *dev_lim, + struct mthca_init_hca_param *init_hca, + u64 icm_size) +{ + u64 aux_pages; + u8 status; + int err; + + err = mthca_SET_ICM_SIZE(mdev, icm_size, &aux_pages, &status); + if (err) { + mthca_err(mdev, "SET_ICM_SIZE command failed, aborting.\n"); + return err; + } + if (status) { + mthca_err(mdev, "SET_ICM_SIZE returned status 0x%02x, " + "aborting.\n", status); + return -EINVAL; + } + + mthca_dbg(mdev, "%lld KB of HCA context requires %lld KB aux memory.\n", + (unsigned long long) icm_size >> 10, + (unsigned long long) aux_pages << 2); + + mdev->fw.arbel.aux_icm = mthca_alloc_icm(mdev, aux_pages, + GFP_HIGHUSER | __GFP_NOWARN, 0); + if (!mdev->fw.arbel.aux_icm) { + mthca_err(mdev, "Couldn't allocate aux memory, aborting.\n"); + return -ENOMEM; + } + + err = mthca_MAP_ICM_AUX(mdev, mdev->fw.arbel.aux_icm, &status); + if (err) { + mthca_err(mdev, "MAP_ICM_AUX command failed, aborting.\n"); + goto err_free_aux; + } + if (status) { + mthca_err(mdev, "MAP_ICM_AUX returned status 0x%02x, aborting.\n", status); + err = -EINVAL; + goto err_free_aux; + } + + err = mthca_map_eq_icm(mdev, init_hca->eqc_base); + if (err) { + mthca_err(mdev, "Failed to map EQ context memory, aborting.\n"); + goto err_unmap_aux; + } + + /* CPU writes to non-reserved MTTs, while HCA might DMA to reserved mtts */ + mdev->limits.reserved_mtts = ALIGN(mdev->limits.reserved_mtts * mdev->limits.mtt_seg_size, + dma_get_cache_alignment()) / mdev->limits.mtt_seg_size; + + mdev->mr_table.mtt_table = mthca_alloc_icm_table(mdev, init_hca->mtt_base, + mdev->limits.mtt_seg_size, + mdev->limits.num_mtt_segs, + mdev->limits.reserved_mtts, + 1, 0); + if (!mdev->mr_table.mtt_table) { + mthca_err(mdev, "Failed to map MTT context memory, aborting.\n"); + err = -ENOMEM; + goto err_unmap_eq; + } + + mdev->mr_table.mpt_table = mthca_alloc_icm_table(mdev, init_hca->mpt_base, + dev_lim->mpt_entry_sz, + mdev->limits.num_mpts, + mdev->limits.reserved_mrws, + 1, 1); + if (!mdev->mr_table.mpt_table) { + mthca_err(mdev, "Failed to map MPT context memory, aborting.\n"); + err = -ENOMEM; + goto err_unmap_mtt; + } + + mdev->qp_table.qp_table = mthca_alloc_icm_table(mdev, init_hca->qpc_base, + dev_lim->qpc_entry_sz, + mdev->limits.num_qps, + mdev->limits.reserved_qps, + 0, 0); + if (!mdev->qp_table.qp_table) { + mthca_err(mdev, "Failed to map QP context memory, aborting.\n"); + err = -ENOMEM; + goto err_unmap_mpt; + } + + mdev->qp_table.eqp_table = mthca_alloc_icm_table(mdev, init_hca->eqpc_base, + dev_lim->eqpc_entry_sz, + mdev->limits.num_qps, + mdev->limits.reserved_qps, + 0, 0); + if (!mdev->qp_table.eqp_table) { + mthca_err(mdev, "Failed to map EQP context memory, aborting.\n"); + err = -ENOMEM; + goto err_unmap_qp; + } + + mdev->qp_table.rdb_table = mthca_alloc_icm_table(mdev, init_hca->rdb_base, + MTHCA_RDB_ENTRY_SIZE, + mdev->limits.num_qps << + mdev->qp_table.rdb_shift, 0, + 0, 0); + if (!mdev->qp_table.rdb_table) { + mthca_err(mdev, "Failed to map RDB context memory, aborting\n"); + err = -ENOMEM; + goto err_unmap_eqp; + } + + mdev->cq_table.table = mthca_alloc_icm_table(mdev, init_hca->cqc_base, + dev_lim->cqc_entry_sz, + mdev->limits.num_cqs, + mdev->limits.reserved_cqs, + 0, 0); + if (!mdev->cq_table.table) { + mthca_err(mdev, "Failed to map CQ context memory, aborting.\n"); + err = -ENOMEM; + goto err_unmap_rdb; + } + + if (mdev->mthca_flags & MTHCA_FLAG_SRQ) { + mdev->srq_table.table = + mthca_alloc_icm_table(mdev, init_hca->srqc_base, + dev_lim->srq_entry_sz, + mdev->limits.num_srqs, + mdev->limits.reserved_srqs, + 0, 0); + if (!mdev->srq_table.table) { + mthca_err(mdev, "Failed to map SRQ context memory, " + "aborting.\n"); + err = -ENOMEM; + goto err_unmap_cq; + } + } + + /* + * It's not strictly required, but for simplicity just map the + * whole multicast group table now. The table isn't very big + * and it's a lot easier than trying to track ref counts. + */ + mdev->mcg_table.table = mthca_alloc_icm_table(mdev, init_hca->mc_base, + MTHCA_MGM_ENTRY_SIZE, + mdev->limits.num_mgms + + mdev->limits.num_amgms, + mdev->limits.num_mgms + + mdev->limits.num_amgms, + 0, 0); + if (!mdev->mcg_table.table) { + mthca_err(mdev, "Failed to map MCG context memory, aborting.\n"); + err = -ENOMEM; + goto err_unmap_srq; + } + + return 0; + +err_unmap_srq: + if (mdev->mthca_flags & MTHCA_FLAG_SRQ) + mthca_free_icm_table(mdev, mdev->srq_table.table); + +err_unmap_cq: + mthca_free_icm_table(mdev, mdev->cq_table.table); + +err_unmap_rdb: + mthca_free_icm_table(mdev, mdev->qp_table.rdb_table); + +err_unmap_eqp: + mthca_free_icm_table(mdev, mdev->qp_table.eqp_table); + +err_unmap_qp: + mthca_free_icm_table(mdev, mdev->qp_table.qp_table); + +err_unmap_mpt: + mthca_free_icm_table(mdev, mdev->mr_table.mpt_table); + +err_unmap_mtt: + mthca_free_icm_table(mdev, mdev->mr_table.mtt_table); + +err_unmap_eq: + mthca_unmap_eq_icm(mdev); + +err_unmap_aux: + mthca_UNMAP_ICM_AUX(mdev, &status); + +err_free_aux: + mthca_free_icm(mdev, mdev->fw.arbel.aux_icm, 0); + + return err; +} + +static void mthca_free_icms(struct mthca_dev *mdev) +{ + u8 status; + + mthca_free_icm_table(mdev, mdev->mcg_table.table); + if (mdev->mthca_flags & MTHCA_FLAG_SRQ) + mthca_free_icm_table(mdev, mdev->srq_table.table); + mthca_free_icm_table(mdev, mdev->cq_table.table); + mthca_free_icm_table(mdev, mdev->qp_table.rdb_table); + mthca_free_icm_table(mdev, mdev->qp_table.eqp_table); + mthca_free_icm_table(mdev, mdev->qp_table.qp_table); + mthca_free_icm_table(mdev, mdev->mr_table.mpt_table); + mthca_free_icm_table(mdev, mdev->mr_table.mtt_table); + mthca_unmap_eq_icm(mdev); + + mthca_UNMAP_ICM_AUX(mdev, &status); + mthca_free_icm(mdev, mdev->fw.arbel.aux_icm, 0); +} + +static int mthca_init_arbel(struct mthca_dev *mdev) +{ + struct mthca_dev_lim dev_lim; + struct mthca_profile profile; + struct mthca_init_hca_param init_hca; + s64 icm_size; + u8 status; + int err; + + err = mthca_QUERY_FW(mdev, &status); + if (err) { + mthca_err(mdev, "QUERY_FW command failed, aborting.\n"); + return err; + } + if (status) { + mthca_err(mdev, "QUERY_FW returned status 0x%02x, " + "aborting.\n", status); + return -EINVAL; + } + + err = mthca_ENABLE_LAM(mdev, &status); + if (err) { + mthca_err(mdev, "ENABLE_LAM command failed, aborting.\n"); + return err; + } + if (status == MTHCA_CMD_STAT_LAM_NOT_PRE) { + mthca_dbg(mdev, "No HCA-attached memory (running in MemFree mode)\n"); + mdev->mthca_flags |= MTHCA_FLAG_NO_LAM; + } else if (status) { + mthca_err(mdev, "ENABLE_LAM returned status 0x%02x, " + "aborting.\n", status); + return -EINVAL; + } + + err = mthca_load_fw(mdev); + if (err) { + mthca_err(mdev, "Failed to start FW, aborting.\n"); + goto err_disable; + } + + err = mthca_dev_lim(mdev, &dev_lim); + if (err) { + mthca_err(mdev, "QUERY_DEV_LIM command failed, aborting.\n"); + goto err_stop_fw; + } + + profile = hca_profile; + profile.num_uar = dev_lim.uar_size / PAGE_SIZE; + profile.num_udav = 0; + if (mdev->mthca_flags & MTHCA_FLAG_SRQ) + profile.num_srq = dev_lim.max_srqs; + + icm_size = mthca_make_profile(mdev, &profile, &dev_lim, &init_hca); + if (icm_size < 0) { + err = icm_size; + goto err_stop_fw; + } + + err = mthca_init_icm(mdev, &dev_lim, &init_hca, icm_size); + if (err) + goto err_stop_fw; + + err = mthca_INIT_HCA(mdev, &init_hca, &status); + if (err) { + mthca_err(mdev, "INIT_HCA command failed, aborting.\n"); + goto err_free_icm; + } + if (status) { + mthca_err(mdev, "INIT_HCA returned status 0x%02x, " + "aborting.\n", status); + err = -EINVAL; + goto err_free_icm; + } + + return 0; + +err_free_icm: + mthca_free_icms(mdev); + +err_stop_fw: + mthca_UNMAP_FA(mdev, &status); + mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); + +err_disable: + if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) + mthca_DISABLE_LAM(mdev, &status); + + return err; +} + +static void mthca_close_hca(struct mthca_dev *mdev) +{ + u8 status; + + mthca_CLOSE_HCA(mdev, 0, &status); + + if (mthca_is_memfree(mdev)) { + mthca_free_icms(mdev); + + mthca_UNMAP_FA(mdev, &status); + mthca_free_icm(mdev, mdev->fw.arbel.fw_icm, 0); + + if (!(mdev->mthca_flags & MTHCA_FLAG_NO_LAM)) + mthca_DISABLE_LAM(mdev, &status); + } else + mthca_SYS_DIS(mdev, &status); +} + +static int mthca_init_hca(struct mthca_dev *mdev) +{ + u8 status; + int err; + struct mthca_adapter adapter; + + if (mthca_is_memfree(mdev)) + err = mthca_init_arbel(mdev); + else + err = mthca_init_tavor(mdev); + + if (err) + return err; + + err = mthca_QUERY_ADAPTER(mdev, &adapter, &status); + if (err) { + mthca_err(mdev, "QUERY_ADAPTER command failed, aborting.\n"); + goto err_close; + } + if (status) { + mthca_err(mdev, "QUERY_ADAPTER returned status 0x%02x, " + "aborting.\n", status); + err = -EINVAL; + goto err_close; + } + + mdev->eq_table.inta_pin = adapter.inta_pin; + if (!mthca_is_memfree(mdev)) + mdev->rev_id = adapter.revision_id; + memcpy(mdev->board_id, adapter.board_id, sizeof mdev->board_id); + + return 0; + +err_close: + mthca_close_hca(mdev); + return err; +} + +static int mthca_setup_hca(struct mthca_dev *dev) +{ + int err; + u8 status; + + MTHCA_INIT_DOORBELL_LOCK(&dev->doorbell_lock); + + err = mthca_init_uar_table(dev); + if (err) { + mthca_err(dev, "Failed to initialize " + "user access region table, aborting.\n"); + return err; + } + + err = mthca_uar_alloc(dev, &dev->driver_uar); + if (err) { + mthca_err(dev, "Failed to allocate driver access region, " + "aborting.\n"); + goto err_uar_table_free; + } + + dev->kar = ioremap(dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); + if (!dev->kar) { + mthca_err(dev, "Couldn't map kernel access region, " + "aborting.\n"); + err = -ENOMEM; + goto err_uar_free; + } + + err = mthca_init_pd_table(dev); + if (err) { + mthca_err(dev, "Failed to initialize " + "protection domain table, aborting.\n"); + goto err_kar_unmap; + } + + err = mthca_init_mr_table(dev); + if (err) { + mthca_err(dev, "Failed to initialize " + "memory region table, aborting.\n"); + goto err_pd_table_free; + } + + err = mthca_pd_alloc(dev, 1, &dev->driver_pd); + if (err) { + mthca_err(dev, "Failed to create driver PD, " + "aborting.\n"); + goto err_mr_table_free; + } + + err = mthca_init_eq_table(dev); + if (err) { + mthca_err(dev, "Failed to initialize " + "event queue table, aborting.\n"); + goto err_pd_free; + } + + err = mthca_cmd_use_events(dev); + if (err) { + mthca_err(dev, "Failed to switch to event-driven " + "firmware commands, aborting.\n"); + goto err_eq_table_free; + } + + err = mthca_NOP(dev, &status); + if (err || status) { + if (dev->mthca_flags & MTHCA_FLAG_MSI_X) { + mthca_warn(dev, "NOP command failed to generate interrupt " + "(IRQ %d).\n", + dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector); + mthca_warn(dev, "Trying again with MSI-X disabled.\n"); + } else { + mthca_err(dev, "NOP command failed to generate interrupt " + "(IRQ %d), aborting.\n", + dev->pdev->irq); + mthca_err(dev, "BIOS or ACPI interrupt routing problem?\n"); + } + + goto err_cmd_poll; + } + + mthca_dbg(dev, "NOP command IRQ test passed\n"); + + err = mthca_init_cq_table(dev); + if (err) { + mthca_err(dev, "Failed to initialize " + "completion queue table, aborting.\n"); + goto err_cmd_poll; + } + + err = mthca_init_srq_table(dev); + if (err) { + mthca_err(dev, "Failed to initialize " + "shared receive queue table, aborting.\n"); + goto err_cq_table_free; + } + + err = mthca_init_qp_table(dev); + if (err) { + mthca_err(dev, "Failed to initialize " + "queue pair table, aborting.\n"); + goto err_srq_table_free; + } + + err = mthca_init_av_table(dev); + if (err) { + mthca_err(dev, "Failed to initialize " + "address vector table, aborting.\n"); + goto err_qp_table_free; + } + + err = mthca_init_mcg_table(dev); + if (err) { + mthca_err(dev, "Failed to initialize " + "multicast group table, aborting.\n"); + goto err_av_table_free; + } + + return 0; + +err_av_table_free: + mthca_cleanup_av_table(dev); + +err_qp_table_free: + mthca_cleanup_qp_table(dev); + +err_srq_table_free: + mthca_cleanup_srq_table(dev); + +err_cq_table_free: + mthca_cleanup_cq_table(dev); + +err_cmd_poll: + mthca_cmd_use_polling(dev); + +err_eq_table_free: + mthca_cleanup_eq_table(dev); + +err_pd_free: + mthca_pd_free(dev, &dev->driver_pd); + +err_mr_table_free: + mthca_cleanup_mr_table(dev); + +err_pd_table_free: + mthca_cleanup_pd_table(dev); + +err_kar_unmap: + iounmap(dev->kar); + +err_uar_free: + mthca_uar_free(dev, &dev->driver_uar); + +err_uar_table_free: + mthca_cleanup_uar_table(dev); + return err; +} + +static int mthca_enable_msi_x(struct mthca_dev *mdev) +{ + struct msix_entry entries[3]; + int err; + + entries[0].entry = 0; + entries[1].entry = 1; + entries[2].entry = 2; + + err = pci_enable_msix(mdev->pdev, entries, ARRAY_SIZE(entries)); + if (err) { + if (err > 0) + mthca_info(mdev, "Only %d MSI-X vectors available, " + "not using MSI-X\n", err); + return err; + } + + mdev->eq_table.eq[MTHCA_EQ_COMP ].msi_x_vector = entries[0].vector; + mdev->eq_table.eq[MTHCA_EQ_ASYNC].msi_x_vector = entries[1].vector; + mdev->eq_table.eq[MTHCA_EQ_CMD ].msi_x_vector = entries[2].vector; + + return 0; +} + +/* Types of supported HCA */ +enum { + TAVOR, /* MT23108 */ + ARBEL_COMPAT, /* MT25208 in Tavor compat mode */ + ARBEL_NATIVE, /* MT25208 with extended features */ + SINAI /* MT25204 */ +}; + +#define MTHCA_FW_VER(major, minor, subminor) \ + (((u64) (major) << 32) | ((u64) (minor) << 16) | (u64) (subminor)) + +static struct { + u64 latest_fw; + u32 flags; +} mthca_hca_table[] = { + [TAVOR] = { .latest_fw = MTHCA_FW_VER(3, 5, 0), + .flags = 0 }, + [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 8, 200), + .flags = MTHCA_FLAG_PCIE }, + [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 3, 0), + .flags = MTHCA_FLAG_MEMFREE | + MTHCA_FLAG_PCIE }, + [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 2, 0), + .flags = MTHCA_FLAG_MEMFREE | + MTHCA_FLAG_PCIE | + MTHCA_FLAG_SINAI_OPT } +}; + +static int __mthca_init_one(struct pci_dev *pdev, int hca_type) +{ + int ddr_hidden = 0; + int err; + struct mthca_dev *mdev; + + printk(KERN_INFO PFX "Initializing %s\n", + pci_name(pdev)); + + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Cannot enable PCI device, " + "aborting.\n"); + return err; + } + + /* + * Check for BARs. We expect 0: 1MB, 2: 8MB, 4: DDR (may not + * be present) + */ + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || + pci_resource_len(pdev, 0) != 1 << 20) { + dev_err(&pdev->dev, "Missing DCS, aborting.\n"); + err = -ENODEV; + goto err_disable_pdev; + } + if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { + dev_err(&pdev->dev, "Missing UAR, aborting.\n"); + err = -ENODEV; + goto err_disable_pdev; + } + if (!(pci_resource_flags(pdev, 4) & IORESOURCE_MEM)) + ddr_hidden = 1; + + err = pci_request_regions(pdev, DRV_NAME); + if (err) { + dev_err(&pdev->dev, "Cannot obtain PCI resources, " + "aborting.\n"); + goto err_disable_pdev; + } + + pci_set_master(pdev); + + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (err) { + dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n"); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err) { + dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n"); + goto err_free_res; + } + } + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (err) { + dev_warn(&pdev->dev, "Warning: couldn't set 64-bit " + "consistent PCI DMA mask.\n"); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err) { + dev_err(&pdev->dev, "Can't set consistent PCI DMA mask, " + "aborting.\n"); + goto err_free_res; + } + } + + mdev = (struct mthca_dev *) ib_alloc_device(sizeof *mdev); + if (!mdev) { + dev_err(&pdev->dev, "Device struct alloc failed, " + "aborting.\n"); + err = -ENOMEM; + goto err_free_res; + } + + mdev->pdev = pdev; + + mdev->mthca_flags = mthca_hca_table[hca_type].flags; + if (ddr_hidden) + mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN; + + /* + * Now reset the HCA before we touch the PCI capabilities or + * attempt a firmware command, since a boot ROM may have left + * the HCA in an undefined state. + */ + err = mthca_reset(mdev); + if (err) { + mthca_err(mdev, "Failed to reset HCA, aborting.\n"); + goto err_free_dev; + } + + if (mthca_cmd_init(mdev)) { + mthca_err(mdev, "Failed to init command interface, aborting.\n"); + goto err_free_dev; + } + + err = mthca_tune_pci(mdev); + if (err) + goto err_cmd; + + err = mthca_init_hca(mdev); + if (err) + goto err_cmd; + + if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) { + mthca_warn(mdev, "HCA FW version %d.%d.%03d is old (%d.%d.%03d is current).\n", + (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff, + (int) (mdev->fw_ver & 0xffff), + (int) (mthca_hca_table[hca_type].latest_fw >> 32), + (int) (mthca_hca_table[hca_type].latest_fw >> 16) & 0xffff, + (int) (mthca_hca_table[hca_type].latest_fw & 0xffff)); + mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n"); + } + + if (msi_x && !mthca_enable_msi_x(mdev)) + mdev->mthca_flags |= MTHCA_FLAG_MSI_X; + + err = mthca_setup_hca(mdev); + if (err == -EBUSY && (mdev->mthca_flags & MTHCA_FLAG_MSI_X)) { + if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) + pci_disable_msix(pdev); + mdev->mthca_flags &= ~MTHCA_FLAG_MSI_X; + + err = mthca_setup_hca(mdev); + } + + if (err) + goto err_close; + + err = mthca_register_device(mdev); + if (err) + goto err_cleanup; + + err = mthca_create_agents(mdev); + if (err) + goto err_unregister; + + pci_set_drvdata(pdev, mdev); + mdev->hca_type = hca_type; + + mdev->active = 1; + + return 0; + +err_unregister: + mthca_unregister_device(mdev); + +err_cleanup: + mthca_cleanup_mcg_table(mdev); + mthca_cleanup_av_table(mdev); + mthca_cleanup_qp_table(mdev); + mthca_cleanup_srq_table(mdev); + mthca_cleanup_cq_table(mdev); + mthca_cmd_use_polling(mdev); + mthca_cleanup_eq_table(mdev); + + mthca_pd_free(mdev, &mdev->driver_pd); + + mthca_cleanup_mr_table(mdev); + mthca_cleanup_pd_table(mdev); + mthca_cleanup_uar_table(mdev); + +err_close: + if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) + pci_disable_msix(pdev); + + mthca_close_hca(mdev); + +err_cmd: + mthca_cmd_cleanup(mdev); + +err_free_dev: + ib_dealloc_device(&mdev->ib_dev); + +err_free_res: + pci_release_regions(pdev); + +err_disable_pdev: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + return err; +} + +static void __mthca_remove_one(struct pci_dev *pdev) +{ + struct mthca_dev *mdev = pci_get_drvdata(pdev); + u8 status; + int p; + + if (mdev) { + mthca_free_agents(mdev); + mthca_unregister_device(mdev); + + for (p = 1; p <= mdev->limits.num_ports; ++p) + mthca_CLOSE_IB(mdev, p, &status); + + mthca_cleanup_mcg_table(mdev); + mthca_cleanup_av_table(mdev); + mthca_cleanup_qp_table(mdev); + mthca_cleanup_srq_table(mdev); + mthca_cleanup_cq_table(mdev); + mthca_cmd_use_polling(mdev); + mthca_cleanup_eq_table(mdev); + + mthca_pd_free(mdev, &mdev->driver_pd); + + mthca_cleanup_mr_table(mdev); + mthca_cleanup_pd_table(mdev); + + iounmap(mdev->kar); + mthca_uar_free(mdev, &mdev->driver_uar); + mthca_cleanup_uar_table(mdev); + mthca_close_hca(mdev); + mthca_cmd_cleanup(mdev); + + if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) + pci_disable_msix(pdev); + + ib_dealloc_device(&mdev->ib_dev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } +} + +int __mthca_restart_one(struct pci_dev *pdev) +{ + struct mthca_dev *mdev; + int hca_type; + + mdev = pci_get_drvdata(pdev); + if (!mdev) + return -ENODEV; + hca_type = mdev->hca_type; + __mthca_remove_one(pdev); + return __mthca_init_one(pdev, hca_type); +} + +static int __devinit mthca_init_one(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + static int mthca_version_printed = 0; + int ret; + + mutex_lock(&mthca_device_mutex); + + if (!mthca_version_printed) { + printk(KERN_INFO "%s", mthca_version); + ++mthca_version_printed; + } + + if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) { + printk(KERN_ERR PFX "%s has invalid driver data %lx\n", + pci_name(pdev), id->driver_data); + mutex_unlock(&mthca_device_mutex); + return -ENODEV; + } + + ret = __mthca_init_one(pdev, id->driver_data); + + mutex_unlock(&mthca_device_mutex); + + return ret; +} + +static void __devexit mthca_remove_one(struct pci_dev *pdev) +{ + mutex_lock(&mthca_device_mutex); + __mthca_remove_one(pdev); + mutex_unlock(&mthca_device_mutex); +} + +static struct pci_device_id mthca_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_TAVOR), + .driver_data = TAVOR }, + { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_TAVOR), + .driver_data = TAVOR }, + { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT), + .driver_data = ARBEL_COMPAT }, + { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT), + .driver_data = ARBEL_COMPAT }, + { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_ARBEL), + .driver_data = ARBEL_NATIVE }, + { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_ARBEL), + .driver_data = ARBEL_NATIVE }, + { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_SINAI), + .driver_data = SINAI }, + { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_SINAI), + .driver_data = SINAI }, + { PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_SINAI_OLD), + .driver_data = SINAI }, + { PCI_DEVICE(PCI_VENDOR_ID_TOPSPIN, PCI_DEVICE_ID_MELLANOX_SINAI_OLD), + .driver_data = SINAI }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, mthca_pci_table); + +static struct pci_driver mthca_driver = { + .name = DRV_NAME, + .id_table = mthca_pci_table, + .probe = mthca_init_one, + .remove = __devexit_p(mthca_remove_one) +}; + +static void __init __mthca_check_profile_val(const char *name, int *pval, + int pval_default) +{ + /* value must be positive and power of 2 */ + int old_pval = *pval; + + if (old_pval <= 0) + *pval = pval_default; + else + *pval = roundup_pow_of_two(old_pval); + + if (old_pval != *pval) { + printk(KERN_WARNING PFX "Invalid value %d for %s in module parameter.\n", + old_pval, name); + printk(KERN_WARNING PFX "Corrected %s to %d.\n", name, *pval); + } +} + +#define mthca_check_profile_val(name, default) \ + __mthca_check_profile_val(#name, &hca_profile.name, default) + +static void __init mthca_validate_profile(void) +{ + mthca_check_profile_val(num_qp, MTHCA_DEFAULT_NUM_QP); + mthca_check_profile_val(rdb_per_qp, MTHCA_DEFAULT_RDB_PER_QP); + mthca_check_profile_val(num_cq, MTHCA_DEFAULT_NUM_CQ); + mthca_check_profile_val(num_mcg, MTHCA_DEFAULT_NUM_MCG); + mthca_check_profile_val(num_mpt, MTHCA_DEFAULT_NUM_MPT); + mthca_check_profile_val(num_mtt, MTHCA_DEFAULT_NUM_MTT); + mthca_check_profile_val(num_udav, MTHCA_DEFAULT_NUM_UDAV); + mthca_check_profile_val(fmr_reserved_mtts, MTHCA_DEFAULT_NUM_RESERVED_MTTS); + + if (hca_profile.fmr_reserved_mtts >= hca_profile.num_mtt) { + printk(KERN_WARNING PFX "Invalid fmr_reserved_mtts module parameter %d.\n", + hca_profile.fmr_reserved_mtts); + printk(KERN_WARNING PFX "(Must be smaller than num_mtt %d)\n", + hca_profile.num_mtt); + hca_profile.fmr_reserved_mtts = hca_profile.num_mtt / 2; + printk(KERN_WARNING PFX "Corrected fmr_reserved_mtts to %d.\n", + hca_profile.fmr_reserved_mtts); + } + if (log_mtts_per_seg == 0) + log_mtts_per_seg = ilog2(MTHCA_MTT_SEG_SIZE / 8); + if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 5)) { + printk(KERN_WARNING PFX "bad log_mtts_per_seg (%d). Using default - %ld\n", + log_mtts_per_seg, ilog2(MTHCA_MTT_SEG_SIZE / 8)); + log_mtts_per_seg = ilog2(MTHCA_MTT_SEG_SIZE / 8); + } +} + +static int __init mthca_init(void) +{ + int ret; + + mthca_validate_profile(); + + ret = mthca_catas_init(); + if (ret) + return ret; + + ret = pci_register_driver(&mthca_driver); + if (ret < 0) { + mthca_catas_cleanup(); + return ret; + } + + return 0; +} + +static void __exit mthca_cleanup(void) +{ + pci_unregister_driver(&mthca_driver); + mthca_catas_cleanup(); +} + +module_init_order(mthca_init, SI_ORDER_MIDDLE); +module_exit(mthca_cleanup); diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_mcg.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_mcg.c new file mode 100644 index 000000000000..d4c81053e439 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_mcg.c @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "mthca_dev.h" +#include "mthca_cmd.h" + +struct mthca_mgm { + __be32 next_gid_index; + u32 reserved[3]; + u8 gid[16]; + __be32 qp[MTHCA_QP_PER_MGM]; +}; + +static const u8 zero_gid[16]; /* automatically initialized to 0 */ + +/* + * Caller must hold MCG table semaphore. gid and mgm parameters must + * be properly aligned for command interface. + * + * Returns 0 unless a firmware command error occurs. + * + * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 + * and *mgm holds MGM entry. + * + * if GID is found in AMGM, *index = index in AMGM, *prev = index of + * previous entry in hash chain and *mgm holds AMGM entry. + * + * If no AMGM exists for given gid, *index = -1, *prev = index of last + * entry in hash chain and *mgm holds end of hash chain. + */ +static int find_mgm(struct mthca_dev *dev, + u8 *gid, struct mthca_mailbox *mgm_mailbox, + u16 *hash, int *prev, int *index) +{ + struct mthca_mailbox *mailbox; + struct mthca_mgm *mgm = mgm_mailbox->buf; + u8 *mgid; + int err; + u8 status; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return -ENOMEM; + mgid = mailbox->buf; + + memcpy(mgid, gid, 16); + + err = mthca_MGID_HASH(dev, mailbox, hash, &status); + if (err) + goto out; + if (status) { + mthca_err(dev, "MGID_HASH returned status %02x\n", status); + err = -EINVAL; + goto out; + } + + if (0) + mthca_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash); + + *index = *hash; + *prev = -1; + + do { + err = mthca_READ_MGM(dev, *index, mgm_mailbox, &status); + if (err) + goto out; + if (status) { + mthca_err(dev, "READ_MGM returned status %02x\n", status); + err = -EINVAL; + goto out; + } + + if (!memcmp(mgm->gid, zero_gid, 16)) { + if (*index != *hash) { + mthca_err(dev, "Found zero MGID in AMGM.\n"); + err = -EINVAL; + } + goto out; + } + + if (!memcmp(mgm->gid, gid, 16)) + goto out; + + *prev = *index; + *index = be32_to_cpu(mgm->next_gid_index) >> 6; + } while (*index); + + *index = -1; + + out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_mailbox *mailbox; + struct mthca_mgm *mgm; + u16 hash; + int index, prev; + int link = 0; + int i; + int err; + u8 status; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + mgm = mailbox->buf; + + mutex_lock(&dev->mcg_table.mutex); + + err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); + if (err) + goto out; + + if (index != -1) { + if (!memcmp(mgm->gid, zero_gid, 16)) + memcpy(mgm->gid, gid->raw, 16); + } else { + link = 1; + + index = mthca_alloc(&dev->mcg_table.alloc); + if (index == -1) { + mthca_err(dev, "No AMGM entries left\n"); + err = -ENOMEM; + goto out; + } + + err = mthca_READ_MGM(dev, index, mailbox, &status); + if (err) + goto out; + if (status) { + mthca_err(dev, "READ_MGM returned status %02x\n", status); + err = -EINVAL; + goto out; + } + memset(mgm, 0, sizeof *mgm); + memcpy(mgm->gid, gid->raw, 16); + } + + for (i = 0; i < MTHCA_QP_PER_MGM; ++i) + if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) { + mthca_dbg(dev, "QP %06x already a member of MGM\n", + ibqp->qp_num); + err = 0; + goto out; + } else if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) { + mgm->qp[i] = cpu_to_be32(ibqp->qp_num | (1 << 31)); + break; + } + + if (i == MTHCA_QP_PER_MGM) { + mthca_err(dev, "MGM at index %x is full.\n", index); + err = -ENOMEM; + goto out; + } + + err = mthca_WRITE_MGM(dev, index, mailbox, &status); + if (err) + goto out; + if (status) { + mthca_err(dev, "WRITE_MGM returned status %02x\n", status); + err = -EINVAL; + goto out; + } + + if (!link) + goto out; + + err = mthca_READ_MGM(dev, prev, mailbox, &status); + if (err) + goto out; + if (status) { + mthca_err(dev, "READ_MGM returned status %02x\n", status); + err = -EINVAL; + goto out; + } + + mgm->next_gid_index = cpu_to_be32(index << 6); + + err = mthca_WRITE_MGM(dev, prev, mailbox, &status); + if (err) + goto out; + if (status) { + mthca_err(dev, "WRITE_MGM returned status %02x\n", status); + err = -EINVAL; + } + + out: + if (err && link && index != -1) { + BUG_ON(index < dev->limits.num_mgms); + mthca_free(&dev->mcg_table.alloc, index); + } + mutex_unlock(&dev->mcg_table.mutex); + + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_mailbox *mailbox; + struct mthca_mgm *mgm; + u16 hash; + int prev, index; + int i, loc; + int err; + u8 status; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + mgm = mailbox->buf; + + mutex_lock(&dev->mcg_table.mutex); + + err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index); + if (err) + goto out; + + if (index == -1) { + mthca_err(dev, "MGID %pI6 not found\n", gid->raw); + err = -EINVAL; + goto out; + } + + for (loc = -1, i = 0; i < MTHCA_QP_PER_MGM; ++i) { + if (mgm->qp[i] == cpu_to_be32(ibqp->qp_num | (1 << 31))) + loc = i; + if (!(mgm->qp[i] & cpu_to_be32(1 << 31))) + break; + } + + if (loc == -1) { + mthca_err(dev, "QP %06x not found in MGM\n", ibqp->qp_num); + err = -EINVAL; + goto out; + } + + mgm->qp[loc] = mgm->qp[i - 1]; + mgm->qp[i - 1] = 0; + + err = mthca_WRITE_MGM(dev, index, mailbox, &status); + if (err) + goto out; + if (status) { + mthca_err(dev, "WRITE_MGM returned status %02x\n", status); + err = -EINVAL; + goto out; + } + + if (i != 1) + goto out; + + if (prev == -1) { + /* Remove entry from MGM */ + int amgm_index_to_free = be32_to_cpu(mgm->next_gid_index) >> 6; + if (amgm_index_to_free) { + err = mthca_READ_MGM(dev, amgm_index_to_free, + mailbox, &status); + if (err) + goto out; + if (status) { + mthca_err(dev, "READ_MGM returned status %02x\n", + status); + err = -EINVAL; + goto out; + } + } else + memset(mgm->gid, 0, 16); + + err = mthca_WRITE_MGM(dev, index, mailbox, &status); + if (err) + goto out; + if (status) { + mthca_err(dev, "WRITE_MGM returned status %02x\n", status); + err = -EINVAL; + goto out; + } + if (amgm_index_to_free) { + BUG_ON(amgm_index_to_free < dev->limits.num_mgms); + mthca_free(&dev->mcg_table.alloc, amgm_index_to_free); + } + } else { + /* Remove entry from AMGM */ + int curr_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; + err = mthca_READ_MGM(dev, prev, mailbox, &status); + if (err) + goto out; + if (status) { + mthca_err(dev, "READ_MGM returned status %02x\n", status); + err = -EINVAL; + goto out; + } + + mgm->next_gid_index = cpu_to_be32(curr_next_index << 6); + + err = mthca_WRITE_MGM(dev, prev, mailbox, &status); + if (err) + goto out; + if (status) { + mthca_err(dev, "WRITE_MGM returned status %02x\n", status); + err = -EINVAL; + goto out; + } + BUG_ON(index < dev->limits.num_mgms); + mthca_free(&dev->mcg_table.alloc, index); + } + + out: + mutex_unlock(&dev->mcg_table.mutex); + + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_init_mcg_table(struct mthca_dev *dev) +{ + int err; + int table_size = dev->limits.num_mgms + dev->limits.num_amgms; + + err = mthca_alloc_init(&dev->mcg_table.alloc, + table_size, + table_size - 1, + dev->limits.num_mgms); + if (err) + return err; + + mutex_init(&dev->mcg_table.mutex); + + return 0; +} + +void mthca_cleanup_mcg_table(struct mthca_dev *dev) +{ + mthca_alloc_cleanup(&dev->mcg_table.alloc); +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_memfree.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_memfree.c new file mode 100644 index 000000000000..783da4bec5d0 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -0,0 +1,879 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include + +#include "mthca_memfree.h" +#include "mthca_dev.h" +#include "mthca_cmd.h" + +/* + * We allocate in as big chunks as we can, up to a maximum of 256 KB + * per chunk. + */ +enum { + MTHCA_ICM_ALLOC_SIZE = 1 << 18, + MTHCA_TABLE_CHUNK_SIZE = 1 << 18 +}; + +struct mthca_user_db_table { + struct mutex mutex; + struct { + u64 uvirt; + struct scatterlist mem; + int refcount; + } page[0]; +}; + +static void mthca_free_icm_pages(struct mthca_dev *dev, struct mthca_icm_chunk *chunk) +{ + int i; + + if (chunk->nsg > 0) + pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages, + PCI_DMA_BIDIRECTIONAL); + + for (i = 0; i < chunk->npages; ++i) + __free_pages(sg_page(&chunk->mem[i]), + get_order(chunk->mem[i].length)); +} + +static void mthca_free_icm_coherent(struct mthca_dev *dev, struct mthca_icm_chunk *chunk) +{ + int i; + + for (i = 0; i < chunk->npages; ++i) { + dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length, + lowmem_page_address(sg_page(&chunk->mem[i])), + sg_dma_address(&chunk->mem[i])); + } +} + +void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm, int coherent) +{ + struct mthca_icm_chunk *chunk, *tmp; + + if (!icm) + return; + + list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) { + if (coherent) + mthca_free_icm_coherent(dev, chunk); + else + mthca_free_icm_pages(dev, chunk); + + kfree(chunk); + } + + kfree(icm); +} + +static int mthca_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask) +{ + struct page *page; + + /* + * Use __GFP_ZERO because buggy firmware assumes ICM pages are + * cleared, and subtle failures are seen if they aren't. + */ + page = alloc_pages(gfp_mask | __GFP_ZERO, order); + if (!page) + return -ENOMEM; + + sg_set_page(mem, page, PAGE_SIZE << order, 0); + return 0; +} + +static int mthca_alloc_icm_coherent(struct device *dev, struct scatterlist *mem, + int order, gfp_t gfp_mask) +{ + void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order, &sg_dma_address(mem), + gfp_mask); + if (!buf) + return -ENOMEM; + + sg_set_buf(mem, buf, PAGE_SIZE << order); + BUG_ON(mem->offset); + sg_dma_len(mem) = PAGE_SIZE << order; + return 0; +} + +struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, + gfp_t gfp_mask, int coherent) +{ + struct mthca_icm *icm; + struct mthca_icm_chunk *chunk = NULL; + int cur_order; + int ret; + + /* We use sg_set_buf for coherent allocs, which assumes low memory */ + BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM)); + + icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); + if (!icm) + return icm; + + icm->refcount = 0; + INIT_LIST_HEAD(&icm->chunk_list); + + cur_order = get_order(MTHCA_ICM_ALLOC_SIZE); + + while (npages > 0) { + if (!chunk) { + chunk = kmalloc(sizeof *chunk, + gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); + if (!chunk) + goto fail; + + sg_init_table(chunk->mem, MTHCA_ICM_CHUNK_LEN); + chunk->npages = 0; + chunk->nsg = 0; + list_add_tail(&chunk->list, &icm->chunk_list); + } + + while (1 << cur_order > npages) + --cur_order; + + if (coherent) + ret = mthca_alloc_icm_coherent(&dev->pdev->dev, + &chunk->mem[chunk->npages], + cur_order, gfp_mask); + else + ret = mthca_alloc_icm_pages(&chunk->mem[chunk->npages], + cur_order, gfp_mask); + + if (!ret) { + ++chunk->npages; + + if (coherent) + ++chunk->nsg; + else if (chunk->npages == MTHCA_ICM_CHUNK_LEN) { + chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, + chunk->npages, + PCI_DMA_BIDIRECTIONAL); + + if (chunk->nsg <= 0) + goto fail; + } + + if (chunk->npages == MTHCA_ICM_CHUNK_LEN) + chunk = NULL; + + npages -= 1 << cur_order; + } else { + --cur_order; + if (cur_order < 0) + goto fail; + } + } + + if (!coherent && chunk) { + chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, + chunk->npages, + PCI_DMA_BIDIRECTIONAL); + + if (chunk->nsg <= 0) + goto fail; + } + + return icm; + +fail: + mthca_free_icm(dev, icm, coherent); + return NULL; +} + +int mthca_table_get(struct mthca_dev *dev, struct mthca_icm_table *table, int obj) +{ + int i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE; + int ret = 0; + u8 status; + + mutex_lock(&table->mutex); + + if (table->icm[i]) { + ++table->icm[i]->refcount; + goto out; + } + + table->icm[i] = mthca_alloc_icm(dev, MTHCA_TABLE_CHUNK_SIZE >> PAGE_SHIFT, + (table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) | + __GFP_NOWARN, table->coherent); + if (!table->icm[i]) { + ret = -ENOMEM; + goto out; + } + + if (mthca_MAP_ICM(dev, table->icm[i], table->virt + i * MTHCA_TABLE_CHUNK_SIZE, + &status) || status) { + mthca_free_icm(dev, table->icm[i], table->coherent); + table->icm[i] = NULL; + ret = -ENOMEM; + goto out; + } + + ++table->icm[i]->refcount; + +out: + mutex_unlock(&table->mutex); + return ret; +} + +void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj) +{ + int i; + u8 status; + + if (!mthca_is_memfree(dev)) + return; + + i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE; + + mutex_lock(&table->mutex); + + if (--table->icm[i]->refcount == 0) { + mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE, + MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE, + &status); + mthca_free_icm(dev, table->icm[i], table->coherent); + table->icm[i] = NULL; + } + + mutex_unlock(&table->mutex); +} + +void *mthca_table_find(struct mthca_icm_table *table, int obj, dma_addr_t *dma_handle) +{ + int idx, offset, dma_offset, i; + struct mthca_icm_chunk *chunk; + struct mthca_icm *icm; + struct page *page = NULL; + + if (!table->lowmem) + return NULL; + + mutex_lock(&table->mutex); + + idx = (obj & (table->num_obj - 1)) * table->obj_size; + icm = table->icm[idx / MTHCA_TABLE_CHUNK_SIZE]; + dma_offset = offset = idx % MTHCA_TABLE_CHUNK_SIZE; + + if (!icm) + goto out; + + list_for_each_entry(chunk, &icm->chunk_list, list) { + for (i = 0; i < chunk->npages; ++i) { + if (dma_handle && dma_offset >= 0) { + if (sg_dma_len(&chunk->mem[i]) > dma_offset) + *dma_handle = sg_dma_address(&chunk->mem[i]) + + dma_offset; + dma_offset -= sg_dma_len(&chunk->mem[i]); + } + /* DMA mapping can merge pages but not split them, + * so if we found the page, dma_handle has already + * been assigned to. */ + if (chunk->mem[i].length > offset) { + page = sg_page(&chunk->mem[i]); + goto out; + } + offset -= chunk->mem[i].length; + } + } + +out: + mutex_unlock(&table->mutex); + return page ? lowmem_page_address(page) + offset : NULL; +} + +int mthca_table_get_range(struct mthca_dev *dev, struct mthca_icm_table *table, + int start, int end) +{ + int inc = MTHCA_TABLE_CHUNK_SIZE / table->obj_size; + int i, err; + + for (i = start; i <= end; i += inc) { + err = mthca_table_get(dev, table, i); + if (err) + goto fail; + } + + return 0; + +fail: + while (i > start) { + i -= inc; + mthca_table_put(dev, table, i); + } + + return err; +} + +void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table, + int start, int end) +{ + int i; + + if (!mthca_is_memfree(dev)) + return; + + for (i = start; i <= end; i += MTHCA_TABLE_CHUNK_SIZE / table->obj_size) + mthca_table_put(dev, table, i); +} + +struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev, + u64 virt, int obj_size, + int nobj, int reserved, + int use_lowmem, int use_coherent) +{ + struct mthca_icm_table *table; + int obj_per_chunk; + int num_icm; + unsigned chunk_size; + int i; + u8 status; + + obj_per_chunk = MTHCA_TABLE_CHUNK_SIZE / obj_size; + num_icm = DIV_ROUND_UP(nobj, obj_per_chunk); + + table = kmalloc(sizeof *table + num_icm * sizeof *table->icm, GFP_KERNEL); + if (!table) + return NULL; + + table->virt = virt; + table->num_icm = num_icm; + table->num_obj = nobj; + table->obj_size = obj_size; + table->lowmem = use_lowmem; + table->coherent = use_coherent; + mutex_init(&table->mutex); + + for (i = 0; i < num_icm; ++i) + table->icm[i] = NULL; + + for (i = 0; i * MTHCA_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) { + chunk_size = MTHCA_TABLE_CHUNK_SIZE; + if ((i + 1) * MTHCA_TABLE_CHUNK_SIZE > nobj * obj_size) + chunk_size = nobj * obj_size - i * MTHCA_TABLE_CHUNK_SIZE; + + table->icm[i] = mthca_alloc_icm(dev, chunk_size >> PAGE_SHIFT, + (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) | + __GFP_NOWARN, use_coherent); + if (!table->icm[i]) + goto err; + if (mthca_MAP_ICM(dev, table->icm[i], virt + i * MTHCA_TABLE_CHUNK_SIZE, + &status) || status) { + mthca_free_icm(dev, table->icm[i], table->coherent); + table->icm[i] = NULL; + goto err; + } + + /* + * Add a reference to this ICM chunk so that it never + * gets freed (since it contains reserved firmware objects). + */ + ++table->icm[i]->refcount; + } + + return table; + +err: + for (i = 0; i < num_icm; ++i) + if (table->icm[i]) { + mthca_UNMAP_ICM(dev, virt + i * MTHCA_TABLE_CHUNK_SIZE, + MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE, + &status); + mthca_free_icm(dev, table->icm[i], table->coherent); + } + + kfree(table); + + return NULL; +} + +void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table) +{ + int i; + u8 status; + + for (i = 0; i < table->num_icm; ++i) + if (table->icm[i]) { + mthca_UNMAP_ICM(dev, table->virt + i * MTHCA_TABLE_CHUNK_SIZE, + MTHCA_TABLE_CHUNK_SIZE / MTHCA_ICM_PAGE_SIZE, + &status); + mthca_free_icm(dev, table->icm[i], table->coherent); + } + + kfree(table); +} + +static u64 mthca_uarc_virt(struct mthca_dev *dev, struct mthca_uar *uar, int page) +{ + return dev->uar_table.uarc_base + + uar->index * dev->uar_table.uarc_size + + page * MTHCA_ICM_PAGE_SIZE; +} + +#include +#include +#include + +#include +#include + +int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab, int index, u64 uaddr) +{ +#ifdef __linux__ + struct page *pages[1]; + int ret = 0; + u8 status; + int i; + + if (!mthca_is_memfree(dev)) + return 0; + + if (index < 0 || index > dev->uar_table.uarc_size / 8) + return -EINVAL; + + mutex_lock(&db_tab->mutex); + + i = index / MTHCA_DB_REC_PER_PAGE; + + if ((db_tab->page[i].refcount >= MTHCA_DB_REC_PER_PAGE) || + (db_tab->page[i].uvirt && db_tab->page[i].uvirt != uaddr) || + (uaddr & 4095)) { + ret = -EINVAL; + goto out; + } + + if (db_tab->page[i].refcount) { + ++db_tab->page[i].refcount; + goto out; + } + + ret = get_user_pages(current, current->mm, uaddr & PAGE_MASK, 1, 1, 0, + pages, NULL); + if (ret < 0) + goto out; + + sg_set_page(&db_tab->page[i].mem, pages[0], MTHCA_ICM_PAGE_SIZE, + uaddr & ~PAGE_MASK); + + ret = pci_map_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE); + if (ret < 0) { + put_page(pages[0]); + goto out; + } + + ret = mthca_MAP_ICM_page(dev, sg_dma_address(&db_tab->page[i].mem), + mthca_uarc_virt(dev, uar, i), &status); + if (!ret && status) + ret = -EINVAL; + if (ret) { + pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE); + put_page(sg_page(&db_tab->page[i].mem)); + goto out; + } + + db_tab->page[i].uvirt = uaddr; + db_tab->page[i].refcount = 1; + +out: + mutex_unlock(&db_tab->mutex); + return ret; +#else + struct proc *proc; + vm_offset_t start; + vm_paddr_t paddr; + pmap_t pmap; + vm_page_t m; + int ret = 0; + u8 status; + int i; + + if (!mthca_is_memfree(dev)) + return 0; + + if (index < 0 || index > dev->uar_table.uarc_size / 8) + return -EINVAL; + + mutex_lock(&db_tab->mutex); + + i = index / MTHCA_DB_REC_PER_PAGE; + start = 0; + + if ((db_tab->page[i].refcount >= MTHCA_DB_REC_PER_PAGE) || + (db_tab->page[i].uvirt && db_tab->page[i].uvirt != uaddr) || + (uaddr & 4095)) { + ret = -EINVAL; + goto out; + } + + if (db_tab->page[i].refcount) { + ++db_tab->page[i].refcount; + goto out; + } + + proc = curproc; + pmap = vm_map_pmap(&proc->p_vmspace->vm_map); + PROC_LOCK(proc); + if (ptoa(pmap_wired_count(pmap) + 1) > lim_cur(proc, RLIMIT_MEMLOCK)) { + PROC_UNLOCK(proc); + ret = -ENOMEM; + goto out; + } + PROC_UNLOCK(proc); + if (cnt.v_wire_count + 1 > vm_page_max_wired) { + ret = -EAGAIN; + goto out; + } + start = uaddr & PAGE_MASK; + ret = vm_map_wire(&proc->p_vmspace->vm_map, start, start + PAGE_SIZE, + VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES | VM_MAP_WIRE_WRITE); + if (ret != KERN_SUCCESS) { + start = 0; + ret = -ENOMEM; + goto out; + } + paddr = pmap_extract(pmap, uaddr); + if (paddr == 0) { + ret = -EFAULT; + goto out; + } + m = PHYS_TO_VM_PAGE(paddr); + + sg_set_page(&db_tab->page[i].mem, m, MTHCA_ICM_PAGE_SIZE, + uaddr & ~PAGE_MASK); + + ret = pci_map_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE); + if (ret < 0) + goto out; + + ret = mthca_MAP_ICM_page(dev, sg_dma_address(&db_tab->page[i].mem), + mthca_uarc_virt(dev, uar, i), &status); + if (!ret && status) + ret = -EINVAL; + if (ret) { + pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE); + goto out; + } + + db_tab->page[i].uvirt = uaddr; + db_tab->page[i].refcount = 1; + +out: + if (ret < 0 && start) + vm_map_unwire(&curthread->td_proc->p_vmspace->vm_map, + start, start + PAGE_SIZE, + VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); + mutex_unlock(&db_tab->mutex); + return ret; +#endif +} + +void mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab, int index) +{ + if (!mthca_is_memfree(dev)) + return; + + /* + * To make our bookkeeping simpler, we don't unmap DB + * pages until we clean up the whole db table. + */ + + mutex_lock(&db_tab->mutex); + + --db_tab->page[index / MTHCA_DB_REC_PER_PAGE].refcount; + + mutex_unlock(&db_tab->mutex); +} + +struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev) +{ + struct mthca_user_db_table *db_tab; + int npages; + int i; + + if (!mthca_is_memfree(dev)) + return NULL; + + npages = dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE; + db_tab = kmalloc(sizeof *db_tab + npages * sizeof *db_tab->page, GFP_KERNEL); + if (!db_tab) + return ERR_PTR(-ENOMEM); + + mutex_init(&db_tab->mutex); + for (i = 0; i < npages; ++i) { + db_tab->page[i].refcount = 0; + db_tab->page[i].uvirt = 0; + sg_init_table(&db_tab->page[i].mem, 1); + } + + return db_tab; +} + +void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab) +{ + int i; + u8 status; + + if (!mthca_is_memfree(dev)) + return; + + for (i = 0; i < dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE; ++i) { + if (db_tab->page[i].uvirt) { + mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1, &status); + pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE); +#ifdef __linux__ + put_page(sg_page(&db_tab->page[i].mem)); +#else + vm_offset_t start; + + start = db_tab->page[i].uvirt & PAGE_MASK; + vm_map_unwire(&curthread->td_proc->p_vmspace->vm_map, + start, start + PAGE_SIZE, + VM_MAP_WIRE_USER | VM_MAP_WIRE_NOHOLES); +#endif + } + } + + kfree(db_tab); +} + +int mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type, + u32 qn, __be32 **db) +{ + int group; + int start, end, dir; + int i, j; + struct mthca_db_page *page; + int ret = 0; + u8 status; + + mutex_lock(&dev->db_tab->mutex); + + switch (type) { + case MTHCA_DB_TYPE_CQ_ARM: + case MTHCA_DB_TYPE_SQ: + group = 0; + start = 0; + end = dev->db_tab->max_group1; + dir = 1; + break; + + case MTHCA_DB_TYPE_CQ_SET_CI: + case MTHCA_DB_TYPE_RQ: + case MTHCA_DB_TYPE_SRQ: + group = 1; + start = dev->db_tab->npages - 1; + end = dev->db_tab->min_group2; + dir = -1; + break; + + default: + ret = -EINVAL; + goto out; + } + + for (i = start; i != end; i += dir) + if (dev->db_tab->page[i].db_rec && + !bitmap_full(dev->db_tab->page[i].used, + MTHCA_DB_REC_PER_PAGE)) { + page = dev->db_tab->page + i; + goto found; + } + + for (i = start; i != end; i += dir) + if (!dev->db_tab->page[i].db_rec) { + page = dev->db_tab->page + i; + goto alloc; + } + + if (dev->db_tab->max_group1 >= dev->db_tab->min_group2 - 1) { + ret = -ENOMEM; + goto out; + } + + if (group == 0) + ++dev->db_tab->max_group1; + else + --dev->db_tab->min_group2; + + page = dev->db_tab->page + end; + +alloc: + page->db_rec = dma_alloc_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE, + &page->mapping, GFP_KERNEL); + if (!page->db_rec) { + ret = -ENOMEM; + goto out; + } + memset(page->db_rec, 0, MTHCA_ICM_PAGE_SIZE); + + ret = mthca_MAP_ICM_page(dev, page->mapping, + mthca_uarc_virt(dev, &dev->driver_uar, i), &status); + if (!ret && status) + ret = -EINVAL; + if (ret) { + dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE, + page->db_rec, page->mapping); + goto out; + } + + bitmap_zero(page->used, MTHCA_DB_REC_PER_PAGE); + +found: + j = find_first_zero_bit(page->used, MTHCA_DB_REC_PER_PAGE); + set_bit(j, page->used); + + if (group == 1) + j = MTHCA_DB_REC_PER_PAGE - 1 - j; + + ret = i * MTHCA_DB_REC_PER_PAGE + j; + + page->db_rec[j] = cpu_to_be64((qn << 8) | (type << 5)); + + *db = (__be32 *) &page->db_rec[j]; + +out: + mutex_unlock(&dev->db_tab->mutex); + + return ret; +} + +void mthca_free_db(struct mthca_dev *dev, int type, int db_index) +{ + int i, j; + struct mthca_db_page *page; + u8 status; + + i = db_index / MTHCA_DB_REC_PER_PAGE; + j = db_index % MTHCA_DB_REC_PER_PAGE; + + page = dev->db_tab->page + i; + + mutex_lock(&dev->db_tab->mutex); + + page->db_rec[j] = 0; + if (i >= dev->db_tab->min_group2) + j = MTHCA_DB_REC_PER_PAGE - 1 - j; + clear_bit(j, page->used); + + if (bitmap_empty(page->used, MTHCA_DB_REC_PER_PAGE) && + i >= dev->db_tab->max_group1 - 1) { + mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status); + + dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE, + page->db_rec, page->mapping); + page->db_rec = NULL; + + if (i == dev->db_tab->max_group1) { + --dev->db_tab->max_group1; + /* XXX may be able to unmap more pages now */ + } + if (i == dev->db_tab->min_group2) + ++dev->db_tab->min_group2; + } + + mutex_unlock(&dev->db_tab->mutex); +} + +int mthca_init_db_tab(struct mthca_dev *dev) +{ + int i; + + if (!mthca_is_memfree(dev)) + return 0; + + dev->db_tab = kmalloc(sizeof *dev->db_tab, GFP_KERNEL); + if (!dev->db_tab) + return -ENOMEM; + + mutex_init(&dev->db_tab->mutex); + + dev->db_tab->npages = dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE; + dev->db_tab->max_group1 = 0; + dev->db_tab->min_group2 = dev->db_tab->npages - 1; + + dev->db_tab->page = kmalloc(dev->db_tab->npages * + sizeof *dev->db_tab->page, + GFP_KERNEL); + if (!dev->db_tab->page) { + kfree(dev->db_tab); + return -ENOMEM; + } + + for (i = 0; i < dev->db_tab->npages; ++i) + dev->db_tab->page[i].db_rec = NULL; + + return 0; +} + +void mthca_cleanup_db_tab(struct mthca_dev *dev) +{ + int i; + u8 status; + + if (!mthca_is_memfree(dev)) + return; + + /* + * Because we don't always free our UARC pages when they + * become empty to make mthca_free_db() simpler we need to + * make a sweep through the doorbell pages and free any + * leftover pages now. + */ + for (i = 0; i < dev->db_tab->npages; ++i) { + if (!dev->db_tab->page[i].db_rec) + continue; + + if (!bitmap_empty(dev->db_tab->page[i].used, MTHCA_DB_REC_PER_PAGE)) + mthca_warn(dev, "Kernel UARC page %d not empty\n", i); + + mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status); + + dma_free_coherent(&dev->pdev->dev, MTHCA_ICM_PAGE_SIZE, + dev->db_tab->page[i].db_rec, + dev->db_tab->page[i].mapping); + } + + kfree(dev->db_tab->page); + kfree(dev->db_tab); +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_memfree.h b/sys/ofed/drivers/infiniband/hw/mthca/mthca_memfree.h new file mode 100644 index 000000000000..da9b8f9b884f --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_memfree.h @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MTHCA_MEMFREE_H +#define MTHCA_MEMFREE_H + +#include +#include + +#define MTHCA_ICM_CHUNK_LEN \ + ((256 - sizeof (struct list_head) - 2 * sizeof (int)) / \ + (sizeof (struct scatterlist))) + +enum { + MTHCA_ICM_PAGE_SHIFT = 12, + MTHCA_ICM_PAGE_SIZE = 1 << MTHCA_ICM_PAGE_SHIFT, + MTHCA_DB_REC_PER_PAGE = MTHCA_ICM_PAGE_SIZE / 8 +}; + +struct mthca_icm_chunk { + struct list_head list; + int npages; + int nsg; + struct scatterlist mem[MTHCA_ICM_CHUNK_LEN]; +}; + +struct mthca_icm { + struct list_head chunk_list; + int refcount; +}; + +struct mthca_icm_table { + u64 virt; + int num_icm; + int num_obj; + int obj_size; + int lowmem; + int coherent; + struct mutex mutex; + struct mthca_icm *icm[0]; +}; + +struct mthca_icm_iter { + struct mthca_icm *icm; + struct mthca_icm_chunk *chunk; + int page_idx; +}; + +struct mthca_dev; + +struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages, + gfp_t gfp_mask, int coherent); +void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm, int coherent); + +struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev, + u64 virt, int obj_size, + int nobj, int reserved, + int use_lowmem, int use_coherent); +void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table); +int mthca_table_get(struct mthca_dev *dev, struct mthca_icm_table *table, int obj); +void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj); +void *mthca_table_find(struct mthca_icm_table *table, int obj, dma_addr_t *dma_handle); +int mthca_table_get_range(struct mthca_dev *dev, struct mthca_icm_table *table, + int start, int end); +void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table, + int start, int end); + +static inline void mthca_icm_first(struct mthca_icm *icm, + struct mthca_icm_iter *iter) +{ + iter->icm = icm; + iter->chunk = list_empty(&icm->chunk_list) ? + NULL : list_entry(icm->chunk_list.next, + struct mthca_icm_chunk, list); + iter->page_idx = 0; +} + +static inline int mthca_icm_last(struct mthca_icm_iter *iter) +{ + return !iter->chunk; +} + +static inline void mthca_icm_next(struct mthca_icm_iter *iter) +{ + if (++iter->page_idx >= iter->chunk->nsg) { + if (iter->chunk->list.next == &iter->icm->chunk_list) { + iter->chunk = NULL; + return; + } + + iter->chunk = list_entry(iter->chunk->list.next, + struct mthca_icm_chunk, list); + iter->page_idx = 0; + } +} + +static inline dma_addr_t mthca_icm_addr(struct mthca_icm_iter *iter) +{ + return sg_dma_address(&iter->chunk->mem[iter->page_idx]); +} + +static inline unsigned long mthca_icm_size(struct mthca_icm_iter *iter) +{ + return sg_dma_len(&iter->chunk->mem[iter->page_idx]); +} + +struct mthca_db_page { + DECLARE_BITMAP(used, MTHCA_DB_REC_PER_PAGE); + __be64 *db_rec; + dma_addr_t mapping; +}; + +struct mthca_db_table { + int npages; + int max_group1; + int min_group2; + struct mthca_db_page *page; + struct mutex mutex; +}; + +enum mthca_db_type { + MTHCA_DB_TYPE_INVALID = 0x0, + MTHCA_DB_TYPE_CQ_SET_CI = 0x1, + MTHCA_DB_TYPE_CQ_ARM = 0x2, + MTHCA_DB_TYPE_SQ = 0x3, + MTHCA_DB_TYPE_RQ = 0x4, + MTHCA_DB_TYPE_SRQ = 0x5, + MTHCA_DB_TYPE_GROUP_SEP = 0x7 +}; + +struct mthca_user_db_table; +struct mthca_uar; + +int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab, int index, u64 uaddr); +void mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab, int index); +struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev); +void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar, + struct mthca_user_db_table *db_tab); + +int mthca_init_db_tab(struct mthca_dev *dev); +void mthca_cleanup_db_tab(struct mthca_dev *dev); +int mthca_alloc_db(struct mthca_dev *dev, enum mthca_db_type type, + u32 qn, __be32 **db); +void mthca_free_db(struct mthca_dev *dev, int type, int db_index); + +#endif /* MTHCA_MEMFREE_H */ diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_mr.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_mr.c new file mode 100644 index 000000000000..d606edf10858 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_mr.c @@ -0,0 +1,985 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "mthca_dev.h" +#include "mthca_cmd.h" +#include "mthca_memfree.h" + +struct mthca_mtt { + struct mthca_buddy *buddy; + int order; + u32 first_seg; +}; + +/* + * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits. + */ +struct mthca_mpt_entry { + __be32 flags; + __be32 page_size; + __be32 key; + __be32 pd; + __be64 start; + __be64 length; + __be32 lkey; + __be32 window_count; + __be32 window_count_limit; + __be64 mtt_seg; + __be32 mtt_sz; /* Arbel only */ + u32 reserved[2]; +} __attribute__((packed)); + +#define MTHCA_MPT_FLAG_SW_OWNS (0xfUL << 28) +#define MTHCA_MPT_FLAG_MIO (1 << 17) +#define MTHCA_MPT_FLAG_BIND_ENABLE (1 << 15) +#define MTHCA_MPT_FLAG_PHYSICAL (1 << 9) +#define MTHCA_MPT_FLAG_REGION (1 << 8) + +#define MTHCA_MTT_FLAG_PRESENT 1 + +#define MTHCA_MPT_STATUS_SW 0xF0 +#define MTHCA_MPT_STATUS_HW 0x00 + +#define SINAI_FMR_KEY_INC 0x1000000 + +/* + * Buddy allocator for MTT segments (currently not very efficient + * since it doesn't keep a free list and just searches linearly + * through the bitmaps) + */ + +static u32 mthca_buddy_alloc(struct mthca_buddy *buddy, int order) +{ + int o; + int m; + u32 seg; + + spin_lock(&buddy->lock); + + for (o = order; o <= buddy->max_order; ++o) + if (buddy->num_free[o]) { + m = 1 << (buddy->max_order - o); + seg = find_first_bit(buddy->bits[o], m); + if (seg < m) + goto found; + } + + spin_unlock(&buddy->lock); + return -1; + + found: + clear_bit(seg, buddy->bits[o]); + --buddy->num_free[o]; + + while (o > order) { + --o; + seg <<= 1; + set_bit(seg ^ 1, buddy->bits[o]); + ++buddy->num_free[o]; + } + + spin_unlock(&buddy->lock); + + seg <<= order; + + return seg; +} + +static void mthca_buddy_free(struct mthca_buddy *buddy, u32 seg, int order) +{ + seg >>= order; + + spin_lock(&buddy->lock); + + while (test_bit(seg ^ 1, buddy->bits[order])) { + clear_bit(seg ^ 1, buddy->bits[order]); + --buddy->num_free[order]; + seg >>= 1; + ++order; + } + + set_bit(seg, buddy->bits[order]); + ++buddy->num_free[order]; + + spin_unlock(&buddy->lock); +} + +static int mthca_buddy_init(struct mthca_buddy *buddy, int max_order) +{ + int i, s; + + buddy->max_order = max_order; + spin_lock_init(&buddy->lock); + + buddy->bits = kzalloc((buddy->max_order + 1) * sizeof (long *), + GFP_KERNEL); + buddy->num_free = kzalloc((buddy->max_order + 1) * sizeof (int *), + GFP_KERNEL); + if (!buddy->bits || !buddy->num_free) + goto err_out; + + for (i = 0; i <= buddy->max_order; ++i) { + s = BITS_TO_LONGS(1 << (buddy->max_order - i)); + buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL); + if (!buddy->bits[i]) + goto err_out_free; + bitmap_zero(buddy->bits[i], + 1 << (buddy->max_order - i)); + } + + set_bit(0, buddy->bits[buddy->max_order]); + buddy->num_free[buddy->max_order] = 1; + + return 0; + +err_out_free: + for (i = 0; i <= buddy->max_order; ++i) + kfree(buddy->bits[i]); + +err_out: + kfree(buddy->bits); + kfree(buddy->num_free); + + return -ENOMEM; +} + +static void mthca_buddy_cleanup(struct mthca_buddy *buddy) +{ + int i; + + for (i = 0; i <= buddy->max_order; ++i) + kfree(buddy->bits[i]); + + kfree(buddy->bits); + kfree(buddy->num_free); +} + +static u32 mthca_alloc_mtt_range(struct mthca_dev *dev, int order, + struct mthca_buddy *buddy) +{ + u32 seg = mthca_buddy_alloc(buddy, order); + + if (seg == -1) + return -1; + + if (mthca_is_memfree(dev)) + if (mthca_table_get_range(dev, dev->mr_table.mtt_table, seg, + seg + (1 << order) - 1)) { + mthca_buddy_free(buddy, seg, order); + seg = -1; + } + + return seg; +} + +static struct mthca_mtt *__mthca_alloc_mtt(struct mthca_dev *dev, int size, + struct mthca_buddy *buddy) +{ + struct mthca_mtt *mtt; + int i; + + if (size <= 0) + return ERR_PTR(-EINVAL); + + mtt = kmalloc(sizeof *mtt, GFP_KERNEL); + if (!mtt) + return ERR_PTR(-ENOMEM); + + mtt->buddy = buddy; + mtt->order = 0; + for (i = dev->limits.mtt_seg_size / 8; i < size; i <<= 1) + ++mtt->order; + + mtt->first_seg = mthca_alloc_mtt_range(dev, mtt->order, buddy); + if (mtt->first_seg == -1) { + kfree(mtt); + return ERR_PTR(-ENOMEM); + } + + return mtt; +} + +struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size) +{ + return __mthca_alloc_mtt(dev, size, &dev->mr_table.mtt_buddy); +} + +void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt) +{ + if (!mtt) + return; + + mthca_buddy_free(mtt->buddy, mtt->first_seg, mtt->order); + + mthca_table_put_range(dev, dev->mr_table.mtt_table, + mtt->first_seg, + mtt->first_seg + (1 << mtt->order) - 1); + + kfree(mtt); +} + +static int __mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, + int start_index, u64 *buffer_list, int list_len) +{ + struct mthca_mailbox *mailbox; + __be64 *mtt_entry; + int err = 0; + u8 status; + int i; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + mtt_entry = mailbox->buf; + + while (list_len > 0) { + mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base + + mtt->first_seg * dev->limits.mtt_seg_size + + start_index * 8); + mtt_entry[1] = 0; + for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; ++i) + mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] | + MTHCA_MTT_FLAG_PRESENT); + + /* + * If we have an odd number of entries to write, add + * one more dummy entry for firmware efficiency. + */ + if (i & 1) + mtt_entry[i + 2] = 0; + + err = mthca_WRITE_MTT(dev, mailbox, (i + 1) & ~1, &status); + if (err) { + mthca_warn(dev, "WRITE_MTT failed (%d)\n", err); + goto out; + } + if (status) { + mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n", + status); + err = -EINVAL; + goto out; + } + + list_len -= i; + start_index += i; + buffer_list += i; + } + +out: + mthca_free_mailbox(dev, mailbox); + return err; +} + +int mthca_write_mtt_size(struct mthca_dev *dev) +{ + if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy || + !(dev->mthca_flags & MTHCA_FLAG_FMR)) + /* + * Be friendly to WRITE_MTT command + * and leave two empty slots for the + * index and reserved fields of the + * mailbox. + */ + return PAGE_SIZE / sizeof (u64) - 2; + + /* For Arbel, all MTTs must fit in the same page. */ + return mthca_is_memfree(dev) ? (PAGE_SIZE / sizeof (u64)) : 0x7ffffff; +} + +static void mthca_tavor_write_mtt_seg(struct mthca_dev *dev, + struct mthca_mtt *mtt, int start_index, + u64 *buffer_list, int list_len) +{ + u64 __iomem *mtts; + int i; + + mtts = dev->mr_table.tavor_fmr.mtt_base + mtt->first_seg * dev->limits.mtt_seg_size + + start_index * sizeof (u64); + for (i = 0; i < list_len; ++i) + mthca_write64_raw(cpu_to_be64(buffer_list[i] | MTHCA_MTT_FLAG_PRESENT), + mtts + i); +} + +static void mthca_arbel_write_mtt_seg(struct mthca_dev *dev, + struct mthca_mtt *mtt, int start_index, + u64 *buffer_list, int list_len) +{ + __be64 *mtts; + dma_addr_t dma_handle; + int i; + int s = start_index * sizeof (u64); + + /* For Arbel, all MTTs must fit in the same page. */ + BUG_ON(s / PAGE_SIZE != (s + list_len * sizeof(u64) - 1) / PAGE_SIZE); + /* Require full segments */ + BUG_ON(s % dev->limits.mtt_seg_size); + + mtts = mthca_table_find(dev->mr_table.mtt_table, mtt->first_seg + + s / dev->limits.mtt_seg_size, &dma_handle); + + BUG_ON(!mtts); + + for (i = 0; i < list_len; ++i) + mtts[i] = cpu_to_be64(buffer_list[i] | MTHCA_MTT_FLAG_PRESENT); + + dma_sync_single(&dev->pdev->dev, dma_handle, list_len * sizeof (u64), DMA_TO_DEVICE); +} + +int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt, + int start_index, u64 *buffer_list, int list_len) +{ + int size = mthca_write_mtt_size(dev); + int chunk; + + if (dev->mr_table.fmr_mtt_buddy != &dev->mr_table.mtt_buddy || + !(dev->mthca_flags & MTHCA_FLAG_FMR)) + return __mthca_write_mtt(dev, mtt, start_index, buffer_list, list_len); + + while (list_len > 0) { + chunk = min(size, list_len); + if (mthca_is_memfree(dev)) + mthca_arbel_write_mtt_seg(dev, mtt, start_index, + buffer_list, chunk); + else + mthca_tavor_write_mtt_seg(dev, mtt, start_index, + buffer_list, chunk); + + list_len -= chunk; + start_index += chunk; + buffer_list += chunk; + } + + return 0; +} + +static inline u32 tavor_hw_index_to_key(u32 ind) +{ + return ind; +} + +static inline u32 tavor_key_to_hw_index(u32 key) +{ + return key; +} + +static inline u32 arbel_hw_index_to_key(u32 ind) +{ + return (ind >> 24) | (ind << 8); +} + +static inline u32 arbel_key_to_hw_index(u32 key) +{ + return (key << 24) | (key >> 8); +} + +static inline u32 hw_index_to_key(struct mthca_dev *dev, u32 ind) +{ + if (mthca_is_memfree(dev)) + return arbel_hw_index_to_key(ind); + else + return tavor_hw_index_to_key(ind); +} + +static inline u32 key_to_hw_index(struct mthca_dev *dev, u32 key) +{ + if (mthca_is_memfree(dev)) + return arbel_key_to_hw_index(key); + else + return tavor_key_to_hw_index(key); +} + +static inline u32 adjust_key(struct mthca_dev *dev, u32 key) +{ + if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT) + return ((key << 20) & 0x800000) | (key & 0x7fffff); + else + return key; +} + +int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift, + u64 iova, u64 total_size, u32 access, struct mthca_mr *mr) +{ + struct mthca_mailbox *mailbox; + struct mthca_mpt_entry *mpt_entry; + u32 key; + int i; + int err; + u8 status; + + WARN_ON(buffer_size_shift >= 32); + + key = mthca_alloc(&dev->mr_table.mpt_alloc); + if (key == -1) + return -ENOMEM; + key = adjust_key(dev, key); + mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key); + + if (mthca_is_memfree(dev)) { + err = mthca_table_get(dev, dev->mr_table.mpt_table, key); + if (err) + goto err_out_mpt_free; + } + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto err_out_table; + } + mpt_entry = mailbox->buf; + + mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS | + MTHCA_MPT_FLAG_MIO | + MTHCA_MPT_FLAG_REGION | + access); + if (!mr->mtt) + mpt_entry->flags |= cpu_to_be32(MTHCA_MPT_FLAG_PHYSICAL); + + mpt_entry->page_size = cpu_to_be32(buffer_size_shift - 12); + mpt_entry->key = cpu_to_be32(key); + mpt_entry->pd = cpu_to_be32(pd); + mpt_entry->start = cpu_to_be64(iova); + mpt_entry->length = cpu_to_be64(total_size); + + memset(&mpt_entry->lkey, 0, + sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey)); + + if (mr->mtt) + mpt_entry->mtt_seg = + cpu_to_be64(dev->mr_table.mtt_base + + mr->mtt->first_seg * dev->limits.mtt_seg_size); + + if (0) { + mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey); + for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; ++i) { + if (i % 4 == 0) + printk("[%02x] ", i * 4); + printk(" %08x", be32_to_cpu(((__be32 *) mpt_entry)[i])); + if ((i + 1) % 4 == 0) + printk("\n"); + } + } + + err = mthca_SW2HW_MPT(dev, mailbox, + key & (dev->limits.num_mpts - 1), + &status); + if (err) { + mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err); + goto err_out_mailbox; + } else if (status) { + mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n", + status); + err = -EINVAL; + goto err_out_mailbox; + } + + mthca_free_mailbox(dev, mailbox); + return err; + +err_out_mailbox: + mthca_free_mailbox(dev, mailbox); + +err_out_table: + mthca_table_put(dev, dev->mr_table.mpt_table, key); + +err_out_mpt_free: + mthca_free(&dev->mr_table.mpt_alloc, key); + return err; +} + +int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd, + u32 access, struct mthca_mr *mr) +{ + mr->mtt = NULL; + return mthca_mr_alloc(dev, pd, 12, 0, ~0ULL, access, mr); +} + +int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd, + u64 *buffer_list, int buffer_size_shift, + int list_len, u64 iova, u64 total_size, + u32 access, struct mthca_mr *mr) +{ + int err; + + mr->mtt = mthca_alloc_mtt(dev, list_len); + if (IS_ERR(mr->mtt)) + return PTR_ERR(mr->mtt); + + err = mthca_write_mtt(dev, mr->mtt, 0, buffer_list, list_len); + if (err) { + mthca_free_mtt(dev, mr->mtt); + return err; + } + + err = mthca_mr_alloc(dev, pd, buffer_size_shift, iova, + total_size, access, mr); + if (err) + mthca_free_mtt(dev, mr->mtt); + + return err; +} + +/* Free mr or fmr */ +static void mthca_free_region(struct mthca_dev *dev, u32 lkey) +{ + mthca_table_put(dev, dev->mr_table.mpt_table, + key_to_hw_index(dev, lkey)); + + mthca_free(&dev->mr_table.mpt_alloc, key_to_hw_index(dev, lkey)); +} + +void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr) +{ + int err; + u8 status; + + err = mthca_HW2SW_MPT(dev, NULL, + key_to_hw_index(dev, mr->ibmr.lkey) & + (dev->limits.num_mpts - 1), + &status); + if (err) + mthca_warn(dev, "HW2SW_MPT failed (%d)\n", err); + else if (status) + mthca_warn(dev, "HW2SW_MPT returned status 0x%02x\n", + status); + + mthca_free_region(dev, mr->ibmr.lkey); + mthca_free_mtt(dev, mr->mtt); +} + +int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd, + u32 access, struct mthca_fmr *mr) +{ + struct mthca_mpt_entry *mpt_entry; + struct mthca_mailbox *mailbox; + u64 mtt_seg; + u32 key, idx; + u8 status; + int list_len = mr->attr.max_pages; + int err = -ENOMEM; + int i; + + if (mr->attr.page_shift < 12 || mr->attr.page_shift >= 32) + return -EINVAL; + + /* For Arbel, all MTTs must fit in the same page. */ + if (mthca_is_memfree(dev) && + mr->attr.max_pages * sizeof *mr->mem.arbel.mtts > PAGE_SIZE) + return -EINVAL; + + mr->maps = 0; + + key = mthca_alloc(&dev->mr_table.mpt_alloc); + if (key == -1) + return -ENOMEM; + key = adjust_key(dev, key); + + idx = key & (dev->limits.num_mpts - 1); + mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key); + + if (mthca_is_memfree(dev)) { + err = mthca_table_get(dev, dev->mr_table.mpt_table, key); + if (err) + goto err_out_mpt_free; + + mr->mem.arbel.mpt = mthca_table_find(dev->mr_table.mpt_table, key, NULL); + BUG_ON(!mr->mem.arbel.mpt); + } else + mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base + + sizeof *(mr->mem.tavor.mpt) * idx; + + mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy); + if (IS_ERR(mr->mtt)) { + err = PTR_ERR(mr->mtt); + goto err_out_table; + } + + mtt_seg = mr->mtt->first_seg * dev->limits.mtt_seg_size; + + if (mthca_is_memfree(dev)) { + mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table, + mr->mtt->first_seg, + &mr->mem.arbel.dma_handle); + BUG_ON(!mr->mem.arbel.mtts); + } else + mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto err_out_free_mtt; + } + + mpt_entry = mailbox->buf; + + mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS | + MTHCA_MPT_FLAG_MIO | + MTHCA_MPT_FLAG_REGION | + access); + + mpt_entry->page_size = cpu_to_be32(mr->attr.page_shift - 12); + mpt_entry->key = cpu_to_be32(key); + mpt_entry->pd = cpu_to_be32(pd); + memset(&mpt_entry->start, 0, + sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, start)); + mpt_entry->mtt_seg = cpu_to_be64(dev->mr_table.mtt_base + mtt_seg); + + if (0) { + mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey); + for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; ++i) { + if (i % 4 == 0) + printk("[%02x] ", i * 4); + printk(" %08x", be32_to_cpu(((__be32 *) mpt_entry)[i])); + if ((i + 1) % 4 == 0) + printk("\n"); + } + } + + err = mthca_SW2HW_MPT(dev, mailbox, + key & (dev->limits.num_mpts - 1), + &status); + if (err) { + mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err); + goto err_out_mailbox_free; + } + if (status) { + mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n", + status); + err = -EINVAL; + goto err_out_mailbox_free; + } + + mthca_free_mailbox(dev, mailbox); + return 0; + +err_out_mailbox_free: + mthca_free_mailbox(dev, mailbox); + +err_out_free_mtt: + mthca_free_mtt(dev, mr->mtt); + +err_out_table: + mthca_table_put(dev, dev->mr_table.mpt_table, key); + +err_out_mpt_free: + mthca_free(&dev->mr_table.mpt_alloc, key); + return err; +} + +int mthca_free_fmr(struct mthca_dev *dev, struct mthca_fmr *fmr) +{ + if (fmr->maps) + return -EBUSY; + + mthca_free_region(dev, fmr->ibmr.lkey); + mthca_free_mtt(dev, fmr->mtt); + + return 0; +} + +static inline int mthca_check_fmr(struct mthca_fmr *fmr, u64 *page_list, + int list_len, u64 iova) +{ + int i, page_mask; + + if (list_len > fmr->attr.max_pages) + return -EINVAL; + + page_mask = (1 << fmr->attr.page_shift) - 1; + + /* We are getting page lists, so va must be page aligned. */ + if (iova & page_mask) + return -EINVAL; + + /* Trust the user not to pass misaligned data in page_list */ + if (0) + for (i = 0; i < list_len; ++i) { + if (page_list[i] & ~page_mask) + return -EINVAL; + } + + if (fmr->maps >= fmr->attr.max_maps) + return -EINVAL; + + return 0; +} + + +int mthca_tavor_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, + int list_len, u64 iova) +{ + struct mthca_fmr *fmr = to_mfmr(ibfmr); + struct mthca_dev *dev = to_mdev(ibfmr->device); + struct mthca_mpt_entry mpt_entry; + u32 key; + int i, err; + + err = mthca_check_fmr(fmr, page_list, list_len, iova); + if (err) + return err; + + ++fmr->maps; + + key = tavor_key_to_hw_index(fmr->ibmr.lkey); + key += dev->limits.num_mpts; + fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key); + + writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt); + + for (i = 0; i < list_len; ++i) { + __be64 mtt_entry = cpu_to_be64(page_list[i] | + MTHCA_MTT_FLAG_PRESENT); + mthca_write64_raw(mtt_entry, fmr->mem.tavor.mtts + i); + } + + mpt_entry.lkey = cpu_to_be32(key); + mpt_entry.length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift)); + mpt_entry.start = cpu_to_be64(iova); + + __raw_writel((__force u32) mpt_entry.lkey, &fmr->mem.tavor.mpt->key); + memcpy_toio(&fmr->mem.tavor.mpt->start, &mpt_entry.start, + offsetof(struct mthca_mpt_entry, window_count) - + offsetof(struct mthca_mpt_entry, start)); + + writeb(MTHCA_MPT_STATUS_HW, fmr->mem.tavor.mpt); + + return 0; +} + +int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, + int list_len, u64 iova) +{ + struct mthca_fmr *fmr = to_mfmr(ibfmr); + struct mthca_dev *dev = to_mdev(ibfmr->device); + u32 key; + int i, err; + + err = mthca_check_fmr(fmr, page_list, list_len, iova); + if (err) + return err; + + ++fmr->maps; + + key = arbel_key_to_hw_index(fmr->ibmr.lkey); + if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT) + key += SINAI_FMR_KEY_INC; + else + key += dev->limits.num_mpts; + fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key); + + *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW; + + wmb(); + + for (i = 0; i < list_len; ++i) + fmr->mem.arbel.mtts[i] = cpu_to_be64(page_list[i] | + MTHCA_MTT_FLAG_PRESENT); + + dma_sync_single(&dev->pdev->dev, fmr->mem.arbel.dma_handle, + list_len * sizeof(u64), DMA_TO_DEVICE); + + fmr->mem.arbel.mpt->key = cpu_to_be32(key); + fmr->mem.arbel.mpt->lkey = cpu_to_be32(key); + fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift)); + fmr->mem.arbel.mpt->start = cpu_to_be64(iova); + + wmb(); + + *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_HW; + + wmb(); + + return 0; +} + +void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) +{ + if (!fmr->maps) + return; + + fmr->maps = 0; + + writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt); +} + +void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) +{ + if (!fmr->maps) + return; + + fmr->maps = 0; + + *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW; +} + +int mthca_init_mr_table(struct mthca_dev *dev) +{ + unsigned long addr; + int mpts, mtts, err, i; + + err = mthca_alloc_init(&dev->mr_table.mpt_alloc, + dev->limits.num_mpts, + ~0, dev->limits.reserved_mrws); + if (err) + return err; + + if (!mthca_is_memfree(dev) && + (dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN)) + dev->limits.fmr_reserved_mtts = 0; + else + dev->mthca_flags |= MTHCA_FLAG_FMR; + + if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT) + mthca_dbg(dev, "Memory key throughput optimization activated.\n"); + + err = mthca_buddy_init(&dev->mr_table.mtt_buddy, + fls(dev->limits.num_mtt_segs - 1)); + + if (err) + goto err_mtt_buddy; + + dev->mr_table.tavor_fmr.mpt_base = NULL; + dev->mr_table.tavor_fmr.mtt_base = NULL; + + if (dev->limits.fmr_reserved_mtts) { + i = fls(dev->limits.fmr_reserved_mtts - 1); + + if (i >= 31) { + mthca_warn(dev, "Unable to reserve 2^31 FMR MTTs.\n"); + err = -EINVAL; + goto err_fmr_mpt; + } + mpts = mtts = 1 << i; + } else { + mtts = dev->limits.num_mtt_segs; + mpts = dev->limits.num_mpts; + } + + if (!mthca_is_memfree(dev) && + (dev->mthca_flags & MTHCA_FLAG_FMR)) { + + addr = pci_resource_start(dev->pdev, 4) + + ((pci_resource_len(dev->pdev, 4) - 1) & + dev->mr_table.mpt_base); + + dev->mr_table.tavor_fmr.mpt_base = + ioremap(addr, mpts * sizeof(struct mthca_mpt_entry)); + + if (!dev->mr_table.tavor_fmr.mpt_base) { + mthca_warn(dev, "MPT ioremap for FMR failed.\n"); + err = -ENOMEM; + goto err_fmr_mpt; + } + + addr = pci_resource_start(dev->pdev, 4) + + ((pci_resource_len(dev->pdev, 4) - 1) & + dev->mr_table.mtt_base); + + dev->mr_table.tavor_fmr.mtt_base = + ioremap(addr, mtts * dev->limits.mtt_seg_size); + if (!dev->mr_table.tavor_fmr.mtt_base) { + mthca_warn(dev, "MTT ioremap for FMR failed.\n"); + err = -ENOMEM; + goto err_fmr_mtt; + } + } + + if (dev->limits.fmr_reserved_mtts) { + err = mthca_buddy_init(&dev->mr_table.tavor_fmr.mtt_buddy, fls(mtts - 1)); + if (err) + goto err_fmr_mtt_buddy; + + /* Prevent regular MRs from using FMR keys */ + err = mthca_buddy_alloc(&dev->mr_table.mtt_buddy, fls(mtts - 1)); + if (err) + goto err_reserve_fmr; + + dev->mr_table.fmr_mtt_buddy = + &dev->mr_table.tavor_fmr.mtt_buddy; + } else + dev->mr_table.fmr_mtt_buddy = &dev->mr_table.mtt_buddy; + + /* FMR table is always the first, take reserved MTTs out of there */ + if (dev->limits.reserved_mtts) { + i = fls(dev->limits.reserved_mtts - 1); + + if (mthca_alloc_mtt_range(dev, i, + dev->mr_table.fmr_mtt_buddy) == -1) { + mthca_warn(dev, "MTT table of order %d is too small.\n", + dev->mr_table.fmr_mtt_buddy->max_order); + err = -ENOMEM; + goto err_reserve_mtts; + } + } + + return 0; + +err_reserve_mtts: +err_reserve_fmr: + if (dev->limits.fmr_reserved_mtts) + mthca_buddy_cleanup(&dev->mr_table.tavor_fmr.mtt_buddy); + +err_fmr_mtt_buddy: + if (dev->mr_table.tavor_fmr.mtt_base) + iounmap(dev->mr_table.tavor_fmr.mtt_base); + +err_fmr_mtt: + if (dev->mr_table.tavor_fmr.mpt_base) + iounmap(dev->mr_table.tavor_fmr.mpt_base); + +err_fmr_mpt: + mthca_buddy_cleanup(&dev->mr_table.mtt_buddy); + +err_mtt_buddy: + mthca_alloc_cleanup(&dev->mr_table.mpt_alloc); + + return err; +} + +void mthca_cleanup_mr_table(struct mthca_dev *dev) +{ + /* XXX check if any MRs are still allocated? */ + if (dev->limits.fmr_reserved_mtts) + mthca_buddy_cleanup(&dev->mr_table.tavor_fmr.mtt_buddy); + + mthca_buddy_cleanup(&dev->mr_table.mtt_buddy); + + if (dev->mr_table.tavor_fmr.mtt_base) + iounmap(dev->mr_table.tavor_fmr.mtt_base); + if (dev->mr_table.tavor_fmr.mpt_base) + iounmap(dev->mr_table.tavor_fmr.mpt_base); + + mthca_alloc_cleanup(&dev->mr_table.mpt_alloc); +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_pd.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_pd.c new file mode 100644 index 000000000000..266f14e47406 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_pd.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "mthca_dev.h" + +int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd) +{ + int err = 0; + + pd->privileged = privileged; + + atomic_set(&pd->sqp_count, 0); + pd->pd_num = mthca_alloc(&dev->pd_table.alloc); + if (pd->pd_num == -1) + return -ENOMEM; + + if (privileged) { + err = mthca_mr_alloc_notrans(dev, pd->pd_num, + MTHCA_MPT_FLAG_LOCAL_READ | + MTHCA_MPT_FLAG_LOCAL_WRITE, + &pd->ntmr); + if (err) + mthca_free(&dev->pd_table.alloc, pd->pd_num); + } + + return err; +} + +void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd) +{ + if (pd->privileged) + mthca_free_mr(dev, &pd->ntmr); + mthca_free(&dev->pd_table.alloc, pd->pd_num); +} + +int mthca_init_pd_table(struct mthca_dev *dev) +{ + return mthca_alloc_init(&dev->pd_table.alloc, + dev->limits.num_pds, + (1 << 24) - 1, + dev->limits.reserved_pds); +} + +void mthca_cleanup_pd_table(struct mthca_dev *dev) +{ + /* XXX check if any PDs are still allocated? */ + mthca_alloc_cleanup(&dev->pd_table.alloc); +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_profile.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_profile.c new file mode 100644 index 000000000000..8edb28a9a0e7 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_profile.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +#include "mthca_profile.h" + +enum { + MTHCA_RES_QP, + MTHCA_RES_EEC, + MTHCA_RES_SRQ, + MTHCA_RES_CQ, + MTHCA_RES_EQP, + MTHCA_RES_EEEC, + MTHCA_RES_EQ, + MTHCA_RES_RDB, + MTHCA_RES_MCG, + MTHCA_RES_MPT, + MTHCA_RES_MTT, + MTHCA_RES_UAR, + MTHCA_RES_UDAV, + MTHCA_RES_UARC, + MTHCA_RES_NUM +}; + +enum { + MTHCA_NUM_EQS = 32, + MTHCA_NUM_PDS = 1 << 15 +}; + +s64 mthca_make_profile(struct mthca_dev *dev, + struct mthca_profile *request, + struct mthca_dev_lim *dev_lim, + struct mthca_init_hca_param *init_hca) +{ + struct mthca_resource { + u64 size; + u64 start; + int type; + int num; + int log_num; + }; + + u64 mem_base, mem_avail; + s64 total_size = 0; + struct mthca_resource *profile; + struct mthca_resource tmp; + int i, j; + + profile = kzalloc(MTHCA_RES_NUM * sizeof *profile, GFP_KERNEL); + if (!profile) + return -ENOMEM; + + profile[MTHCA_RES_QP].size = dev_lim->qpc_entry_sz; + profile[MTHCA_RES_EEC].size = dev_lim->eec_entry_sz; + profile[MTHCA_RES_SRQ].size = dev_lim->srq_entry_sz; + profile[MTHCA_RES_CQ].size = dev_lim->cqc_entry_sz; + profile[MTHCA_RES_EQP].size = dev_lim->eqpc_entry_sz; + profile[MTHCA_RES_EEEC].size = dev_lim->eeec_entry_sz; + profile[MTHCA_RES_EQ].size = dev_lim->eqc_entry_sz; + profile[MTHCA_RES_RDB].size = MTHCA_RDB_ENTRY_SIZE; + profile[MTHCA_RES_MCG].size = MTHCA_MGM_ENTRY_SIZE; + profile[MTHCA_RES_MPT].size = dev_lim->mpt_entry_sz; + profile[MTHCA_RES_MTT].size = dev->limits.mtt_seg_size; + profile[MTHCA_RES_UAR].size = dev_lim->uar_scratch_entry_sz; + profile[MTHCA_RES_UDAV].size = MTHCA_AV_SIZE; + profile[MTHCA_RES_UARC].size = request->uarc_size; + + profile[MTHCA_RES_QP].num = request->num_qp; + profile[MTHCA_RES_SRQ].num = request->num_srq; + profile[MTHCA_RES_EQP].num = request->num_qp; + profile[MTHCA_RES_RDB].num = request->num_qp * request->rdb_per_qp; + profile[MTHCA_RES_CQ].num = request->num_cq; + profile[MTHCA_RES_EQ].num = MTHCA_NUM_EQS; + profile[MTHCA_RES_MCG].num = request->num_mcg; + profile[MTHCA_RES_MPT].num = request->num_mpt; + profile[MTHCA_RES_MTT].num = request->num_mtt; + profile[MTHCA_RES_UAR].num = request->num_uar; + profile[MTHCA_RES_UARC].num = request->num_uar; + profile[MTHCA_RES_UDAV].num = request->num_udav; + + for (i = 0; i < MTHCA_RES_NUM; ++i) { + profile[i].type = i; + profile[i].log_num = max(ffs(profile[i].num) - 1, 0); + profile[i].size *= profile[i].num; + if (mthca_is_memfree(dev)) + profile[i].size = max(profile[i].size, (u64) PAGE_SIZE); + } + + if (mthca_is_memfree(dev)) { + mem_base = 0; + mem_avail = dev_lim->hca.arbel.max_icm_sz; + } else { + mem_base = dev->ddr_start; + mem_avail = dev->fw.tavor.fw_start - dev->ddr_start; + } + + /* + * Sort the resources in decreasing order of size. Since they + * all have sizes that are powers of 2, we'll be able to keep + * resources aligned to their size and pack them without gaps + * using the sorted order. + */ + for (i = MTHCA_RES_NUM; i > 0; --i) + for (j = 1; j < i; ++j) { + if (profile[j].size > profile[j - 1].size) { + tmp = profile[j]; + profile[j] = profile[j - 1]; + profile[j - 1] = tmp; + } + } + + for (i = 0; i < MTHCA_RES_NUM; ++i) { + if (profile[i].size) { + profile[i].start = mem_base + total_size; + total_size += profile[i].size; + } + if (total_size > mem_avail) { + mthca_err(dev, "Profile requires 0x%llx bytes; " + "won't fit in 0x%llx bytes of context memory.\n", + (unsigned long long) total_size, + (unsigned long long) mem_avail); + kfree(profile); + return -ENOMEM; + } + + if (profile[i].size) + mthca_dbg(dev, "profile[%2d]--%2d/%2d @ 0x%16llx " + "(size 0x%8llx)\n", + i, profile[i].type, profile[i].log_num, + (unsigned long long) profile[i].start, + (unsigned long long) profile[i].size); + } + + if (mthca_is_memfree(dev)) + mthca_dbg(dev, "HCA context memory: reserving %d KB\n", + (int) (total_size >> 10)); + else + mthca_dbg(dev, "HCA memory: allocated %d KB/%d KB (%d KB free)\n", + (int) (total_size >> 10), (int) (mem_avail >> 10), + (int) ((mem_avail - total_size) >> 10)); + + for (i = 0; i < MTHCA_RES_NUM; ++i) { + switch (profile[i].type) { + case MTHCA_RES_QP: + dev->limits.num_qps = profile[i].num; + init_hca->qpc_base = profile[i].start; + init_hca->log_num_qps = profile[i].log_num; + break; + case MTHCA_RES_EEC: + dev->limits.num_eecs = profile[i].num; + init_hca->eec_base = profile[i].start; + init_hca->log_num_eecs = profile[i].log_num; + break; + case MTHCA_RES_SRQ: + dev->limits.num_srqs = profile[i].num; + init_hca->srqc_base = profile[i].start; + init_hca->log_num_srqs = profile[i].log_num; + break; + case MTHCA_RES_CQ: + dev->limits.num_cqs = profile[i].num; + init_hca->cqc_base = profile[i].start; + init_hca->log_num_cqs = profile[i].log_num; + break; + case MTHCA_RES_EQP: + init_hca->eqpc_base = profile[i].start; + break; + case MTHCA_RES_EEEC: + init_hca->eeec_base = profile[i].start; + break; + case MTHCA_RES_EQ: + dev->limits.num_eqs = profile[i].num; + init_hca->eqc_base = profile[i].start; + init_hca->log_num_eqs = profile[i].log_num; + break; + case MTHCA_RES_RDB: + for (dev->qp_table.rdb_shift = 0; + request->num_qp << dev->qp_table.rdb_shift < profile[i].num; + ++dev->qp_table.rdb_shift) + ; /* nothing */ + dev->qp_table.rdb_base = (u32) profile[i].start; + init_hca->rdb_base = profile[i].start; + break; + case MTHCA_RES_MCG: + dev->limits.num_mgms = profile[i].num >> 1; + dev->limits.num_amgms = profile[i].num >> 1; + init_hca->mc_base = profile[i].start; + init_hca->log_mc_entry_sz = ffs(MTHCA_MGM_ENTRY_SIZE) - 1; + init_hca->log_mc_table_sz = profile[i].log_num; + init_hca->mc_hash_sz = 1 << (profile[i].log_num - 1); + break; + case MTHCA_RES_MPT: + dev->limits.num_mpts = profile[i].num; + dev->mr_table.mpt_base = profile[i].start; + init_hca->mpt_base = profile[i].start; + init_hca->log_mpt_sz = profile[i].log_num; + break; + case MTHCA_RES_MTT: + dev->limits.num_mtt_segs = profile[i].num; + dev->mr_table.mtt_base = profile[i].start; + init_hca->mtt_base = profile[i].start; + init_hca->mtt_seg_sz = ffs(dev->limits.mtt_seg_size) - 7; + break; + case MTHCA_RES_UAR: + dev->limits.num_uars = profile[i].num; + init_hca->uar_scratch_base = profile[i].start; + break; + case MTHCA_RES_UDAV: + dev->av_table.ddr_av_base = profile[i].start; + dev->av_table.num_ddr_avs = profile[i].num; + break; + case MTHCA_RES_UARC: + dev->uar_table.uarc_size = request->uarc_size; + dev->uar_table.uarc_base = profile[i].start; + init_hca->uarc_base = profile[i].start; + init_hca->log_uarc_sz = ffs(request->uarc_size) - 13; + init_hca->log_uar_sz = ffs(request->num_uar) - 1; + break; + default: + break; + } + } + + /* + * PDs don't take any HCA memory, but we assign them as part + * of the HCA profile anyway. + */ + dev->limits.num_pds = MTHCA_NUM_PDS; + + if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT && + init_hca->log_mpt_sz > 23) { + mthca_warn(dev, "MPT table too large (requested size 2^%d >= 2^24)\n", + init_hca->log_mpt_sz); + mthca_warn(dev, "Disabling memory key throughput optimization.\n"); + dev->mthca_flags &= ~MTHCA_FLAG_SINAI_OPT; + } + + /* + * For Tavor, FMRs use ioremapped PCI memory. For 32 bit + * systems it may use too much vmalloc space to map all MTT + * memory, so we reserve some MTTs for FMR access, taking them + * out of the MR pool. They don't use additional memory, but + * we assign them as part of the HCA profile anyway. + */ + if (mthca_is_memfree(dev) || BITS_PER_LONG == 64) + dev->limits.fmr_reserved_mtts = 0; + else + dev->limits.fmr_reserved_mtts = request->fmr_reserved_mtts; + + kfree(profile); + return total_size; +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_profile.h b/sys/ofed/drivers/infiniband/hw/mthca/mthca_profile.h new file mode 100644 index 000000000000..62b009cc8730 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_profile.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MTHCA_PROFILE_H +#define MTHCA_PROFILE_H + +#include "mthca_dev.h" +#include "mthca_cmd.h" + +struct mthca_profile { + int num_qp; + int rdb_per_qp; + int num_srq; + int num_cq; + int num_mcg; + int num_mpt; + int num_mtt; + int num_udav; + int num_uar; + int uarc_size; + int fmr_reserved_mtts; +}; + +s64 mthca_make_profile(struct mthca_dev *mdev, + struct mthca_profile *request, + struct mthca_dev_lim *dev_lim, + struct mthca_init_hca_param *init_hca); + +#endif /* MTHCA_PROFILE_H */ diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_provider.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_provider.c new file mode 100644 index 000000000000..e54773976d6e --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_provider.c @@ -0,0 +1,1427 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include +#include + +#include "mthca_dev.h" +#include "mthca_cmd.h" +#include "mthca_user.h" +#include "mthca_memfree.h" + +static void init_query_mad(struct ib_smp *mad) +{ + mad->base_version = 1; + mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; + mad->class_version = 1; + mad->method = IB_MGMT_METHOD_GET; +} + +static int mthca_query_device(struct ib_device *ibdev, + struct ib_device_attr *props) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + struct mthca_dev *mdev = to_mdev(ibdev); + + u8 status; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + memset(props, 0, sizeof *props); + + props->fw_ver = mdev->fw_ver; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; + + err = mthca_MAD_IFC(mdev, 1, 1, + 1, NULL, NULL, in_mad, out_mad, + &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + + props->device_cap_flags = mdev->device_cap_flags; + props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) & + 0xffffff; + props->vendor_part_id = be16_to_cpup((__be16 *) (out_mad->data + 30)); + props->hw_ver = be32_to_cpup((__be32 *) (out_mad->data + 32)); + memcpy(&props->sys_image_guid, out_mad->data + 4, 8); + + props->max_mr_size = ~0ull; + props->page_size_cap = mdev->limits.page_size_cap; + props->max_qp = mdev->limits.num_qps - mdev->limits.reserved_qps; + props->max_qp_wr = mdev->limits.max_wqes; + props->max_sge = mdev->limits.max_sg; + props->max_cq = mdev->limits.num_cqs - mdev->limits.reserved_cqs; + props->max_cqe = mdev->limits.max_cqes; + props->max_mr = mdev->limits.num_mpts - mdev->limits.reserved_mrws; + props->max_pd = mdev->limits.num_pds - mdev->limits.reserved_pds; + props->max_qp_rd_atom = 1 << mdev->qp_table.rdb_shift; + props->max_qp_init_rd_atom = mdev->limits.max_qp_init_rdma; + props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp; + props->max_srq = mdev->limits.num_srqs - mdev->limits.reserved_srqs; + props->max_srq_wr = mdev->limits.max_srq_wqes; + props->max_srq_sge = mdev->limits.max_srq_sge; + props->local_ca_ack_delay = mdev->limits.local_ca_ack_delay; + props->atomic_cap = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ? + IB_ATOMIC_HCA : IB_ATOMIC_NONE; + props->max_pkeys = mdev->limits.pkey_table_len; + props->max_mcast_grp = mdev->limits.num_mgms + mdev->limits.num_amgms; + props->max_mcast_qp_attach = MTHCA_QP_PER_MGM; + props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * + props->max_mcast_grp; + /* + * If Sinai memory key optimization is being used, then only + * the 8-bit key portion will change. For other HCAs, the + * unused index bits will also be used for FMR remapping. + */ + if (mdev->mthca_flags & MTHCA_FLAG_SINAI_OPT) + props->max_map_per_fmr = 255; + else + props->max_map_per_fmr = + (1 << (32 - ilog2(mdev->limits.num_mpts))) - 1; + + err = 0; + out: + kfree(in_mad); + kfree(out_mad); + return err; +} + +static int mthca_query_port(struct ib_device *ibdev, + u8 port, struct ib_port_attr *props) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + u8 status; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + memset(props, 0, sizeof *props); + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; + in_mad->attr_mod = cpu_to_be32(port); + + err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, + port, NULL, NULL, in_mad, out_mad, + &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + + props->lid = be16_to_cpup((__be16 *) (out_mad->data + 16)); + props->lmc = out_mad->data[34] & 0x7; + props->sm_lid = be16_to_cpup((__be16 *) (out_mad->data + 18)); + props->sm_sl = out_mad->data[36] & 0xf; + props->state = out_mad->data[32] & 0xf; + props->phys_state = out_mad->data[33] >> 4; + props->port_cap_flags = be32_to_cpup((__be32 *) (out_mad->data + 20)); + props->gid_tbl_len = to_mdev(ibdev)->limits.gid_table_len; + props->max_msg_sz = 0x80000000; + props->pkey_tbl_len = to_mdev(ibdev)->limits.pkey_table_len; + props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46)); + props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48)); + props->active_width = out_mad->data[31] & 0xf; + props->active_speed = out_mad->data[35] >> 4; + props->max_mtu = out_mad->data[41] & 0xf; + props->active_mtu = out_mad->data[36] >> 4; + props->subnet_timeout = out_mad->data[51] & 0x1f; + props->max_vl_num = out_mad->data[37] >> 4; + props->init_type_reply = out_mad->data[41] >> 4; + + out: + kfree(in_mad); + kfree(out_mad); + return err; +} + +static int mthca_modify_device(struct ib_device *ibdev, + int mask, + struct ib_device_modify *props) +{ + if (mask & ~IB_DEVICE_MODIFY_NODE_DESC) + return -EOPNOTSUPP; + + if (mask & IB_DEVICE_MODIFY_NODE_DESC) { + if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex)) + return -ERESTARTSYS; + memcpy(ibdev->node_desc, props->node_desc, 64); + mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex); + } + + return 0; +} + +static int mthca_modify_port(struct ib_device *ibdev, + u8 port, int port_modify_mask, + struct ib_port_modify *props) +{ + struct mthca_set_ib_param set_ib; + struct ib_port_attr attr; + int err; + u8 status; + + if (mutex_lock_interruptible(&to_mdev(ibdev)->cap_mask_mutex)) + return -ERESTARTSYS; + + err = mthca_query_port(ibdev, port, &attr); + if (err) + goto out; + + set_ib.set_si_guid = 0; + set_ib.reset_qkey_viol = !!(port_modify_mask & IB_PORT_RESET_QKEY_CNTR); + + set_ib.cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) & + ~props->clr_port_cap_mask; + + err = mthca_SET_IB(to_mdev(ibdev), &set_ib, port, &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + +out: + mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex); + return err; +} + +static int mthca_query_pkey(struct ib_device *ibdev, + u8 port, u16 index, u16 *pkey) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + u8 status; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_PKEY_TABLE; + in_mad->attr_mod = cpu_to_be32(index / 32); + + err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, + port, NULL, NULL, in_mad, out_mad, + &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + + *pkey = be16_to_cpu(((__be16 *) out_mad->data)[index % 32]); + + out: + kfree(in_mad); + kfree(out_mad); + return err; +} + +static int mthca_query_gid(struct ib_device *ibdev, u8 port, + int index, union ib_gid *gid) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + u8 status; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_PORT_INFO; + in_mad->attr_mod = cpu_to_be32(port); + + err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, + port, NULL, NULL, in_mad, out_mad, + &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + + memcpy(gid->raw, out_mad->data + 8, 8); + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_GUID_INFO; + in_mad->attr_mod = cpu_to_be32(index / 8); + + err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1, + port, NULL, NULL, in_mad, out_mad, + &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + + memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8); + + out: + kfree(in_mad); + kfree(out_mad); + return err; +} + +static struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev, + struct ib_udata *udata) +{ + struct mthca_alloc_ucontext_resp uresp; + struct mthca_ucontext *context; + int err; + + if (!(to_mdev(ibdev)->active)) + return ERR_PTR(-EAGAIN); + + memset(&uresp, 0, sizeof uresp); + + uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps; + if (mthca_is_memfree(to_mdev(ibdev))) + uresp.uarc_size = to_mdev(ibdev)->uar_table.uarc_size; + else + uresp.uarc_size = 0; + + context = kmalloc(sizeof *context, GFP_KERNEL); + if (!context) + return ERR_PTR(-ENOMEM); + + err = mthca_uar_alloc(to_mdev(ibdev), &context->uar); + if (err) { + kfree(context); + return ERR_PTR(err); + } + + context->db_tab = mthca_init_user_db_tab(to_mdev(ibdev)); + if (IS_ERR(context->db_tab)) { + err = PTR_ERR(context->db_tab); + mthca_uar_free(to_mdev(ibdev), &context->uar); + kfree(context); + return ERR_PTR(err); + } + + if (ib_copy_to_udata(udata, &uresp, sizeof uresp)) { + mthca_cleanup_user_db_tab(to_mdev(ibdev), &context->uar, context->db_tab); + mthca_uar_free(to_mdev(ibdev), &context->uar); + kfree(context); + return ERR_PTR(-EFAULT); + } + + context->reg_mr_warned = 0; + + return &context->ibucontext; +} + +static int mthca_dealloc_ucontext(struct ib_ucontext *context) +{ + mthca_cleanup_user_db_tab(to_mdev(context->device), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab); + mthca_uar_free(to_mdev(context->device), &to_mucontext(context)->uar); + kfree(to_mucontext(context)); + + return 0; +} + +static int mthca_mmap_uar(struct ib_ucontext *context, + struct vm_area_struct *vma) +{ + if (vma->vm_end - vma->vm_start != PAGE_SIZE) + return -EINVAL; + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (io_remap_pfn_range(vma, vma->vm_start, + to_mucontext(context)->uar.pfn, + PAGE_SIZE, vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + +static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct mthca_pd *pd; + int err; + + pd = kmalloc(sizeof *pd, GFP_KERNEL); + if (!pd) + return ERR_PTR(-ENOMEM); + + err = mthca_pd_alloc(to_mdev(ibdev), !context, pd); + if (err) { + kfree(pd); + return ERR_PTR(err); + } + + if (context) { + if (ib_copy_to_udata(udata, &pd->pd_num, sizeof (__u32))) { + mthca_pd_free(to_mdev(ibdev), pd); + kfree(pd); + return ERR_PTR(-EFAULT); + } + } + + return &pd->ibpd; +} + +static int mthca_dealloc_pd(struct ib_pd *pd) +{ + mthca_pd_free(to_mdev(pd->device), to_mpd(pd)); + kfree(pd); + + return 0; +} + +static struct ib_ah *mthca_ah_create(struct ib_pd *pd, + struct ib_ah_attr *ah_attr) +{ + int err; + struct mthca_ah *ah; + + ah = kmalloc(sizeof *ah, GFP_ATOMIC); + if (!ah) + return ERR_PTR(-ENOMEM); + + err = mthca_create_ah(to_mdev(pd->device), to_mpd(pd), ah_attr, ah); + if (err) { + kfree(ah); + return ERR_PTR(err); + } + + return &ah->ibah; +} + +static int mthca_ah_destroy(struct ib_ah *ah) +{ + mthca_destroy_ah(to_mdev(ah->device), to_mah(ah)); + kfree(ah); + + return 0; +} + +static struct ib_srq *mthca_create_srq(struct ib_pd *pd, + struct ib_srq_init_attr *init_attr, + struct ib_udata *udata) +{ + struct mthca_create_srq ucmd; + struct mthca_ucontext *context = NULL; + struct mthca_srq *srq; + int err; + + srq = kmalloc(sizeof *srq, GFP_KERNEL); + if (!srq) + return ERR_PTR(-ENOMEM); + + if (pd->uobject) { + context = to_mucontext(pd->uobject->context); + + if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) { + err = -EFAULT; + goto err_free; + } + + err = mthca_map_user_db(to_mdev(pd->device), &context->uar, + context->db_tab, ucmd.db_index, + ucmd.db_page); + + if (err) + goto err_free; + + srq->mr.ibmr.lkey = ucmd.lkey; + srq->db_index = ucmd.db_index; + } + + err = mthca_alloc_srq(to_mdev(pd->device), to_mpd(pd), + &init_attr->attr, srq); + + if (err && pd->uobject) + mthca_unmap_user_db(to_mdev(pd->device), &context->uar, + context->db_tab, ucmd.db_index); + + if (err) + goto err_free; + + if (context && ib_copy_to_udata(udata, &srq->srqn, sizeof (__u32))) { + mthca_free_srq(to_mdev(pd->device), srq); + err = -EFAULT; + goto err_free; + } + + return &srq->ibsrq; + +err_free: + kfree(srq); + + return ERR_PTR(err); +} + +static int mthca_destroy_srq(struct ib_srq *srq) +{ + struct mthca_ucontext *context; + + if (srq->uobject) { + context = to_mucontext(srq->uobject->context); + + mthca_unmap_user_db(to_mdev(srq->device), &context->uar, + context->db_tab, to_msrq(srq)->db_index); + } + + mthca_free_srq(to_mdev(srq->device), to_msrq(srq)); + kfree(srq); + + return 0; +} + +static struct ib_qp *mthca_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata) +{ + struct mthca_create_qp ucmd; + struct mthca_qp *qp; + int err; + + if (init_attr->create_flags) + return ERR_PTR(-EINVAL); + + switch (init_attr->qp_type) { + case IB_QPT_RC: + case IB_QPT_UC: + case IB_QPT_UD: + { + struct mthca_ucontext *context; + + qp = kmalloc(sizeof *qp, GFP_KERNEL); + if (!qp) + return ERR_PTR(-ENOMEM); + + if (pd->uobject) { + context = to_mucontext(pd->uobject->context); + + if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) { + kfree(qp); + return ERR_PTR(-EFAULT); + } + + err = mthca_map_user_db(to_mdev(pd->device), &context->uar, + context->db_tab, + ucmd.sq_db_index, ucmd.sq_db_page); + if (err) { + kfree(qp); + return ERR_PTR(err); + } + + err = mthca_map_user_db(to_mdev(pd->device), &context->uar, + context->db_tab, + ucmd.rq_db_index, ucmd.rq_db_page); + if (err) { + mthca_unmap_user_db(to_mdev(pd->device), + &context->uar, + context->db_tab, + ucmd.sq_db_index); + kfree(qp); + return ERR_PTR(err); + } + + qp->mr.ibmr.lkey = ucmd.lkey; + qp->sq.db_index = ucmd.sq_db_index; + qp->rq.db_index = ucmd.rq_db_index; + } + + err = mthca_alloc_qp(to_mdev(pd->device), to_mpd(pd), + to_mcq(init_attr->send_cq), + to_mcq(init_attr->recv_cq), + init_attr->qp_type, init_attr->sq_sig_type, + &init_attr->cap, qp); + + if (err && pd->uobject) { + context = to_mucontext(pd->uobject->context); + + mthca_unmap_user_db(to_mdev(pd->device), + &context->uar, + context->db_tab, + ucmd.sq_db_index); + mthca_unmap_user_db(to_mdev(pd->device), + &context->uar, + context->db_tab, + ucmd.rq_db_index); + } + + qp->ibqp.qp_num = qp->qpn; + break; + } + case IB_QPT_SMI: + case IB_QPT_GSI: + { + /* Don't allow userspace to create special QPs */ + if (pd->uobject) + return ERR_PTR(-EINVAL); + + qp = kmalloc(sizeof (struct mthca_sqp), GFP_KERNEL); + if (!qp) + return ERR_PTR(-ENOMEM); + + qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1; + + err = mthca_alloc_sqp(to_mdev(pd->device), to_mpd(pd), + to_mcq(init_attr->send_cq), + to_mcq(init_attr->recv_cq), + init_attr->sq_sig_type, &init_attr->cap, + qp->ibqp.qp_num, init_attr->port_num, + to_msqp(qp)); + break; + } + default: + /* Don't support raw QPs */ + return ERR_PTR(-ENOSYS); + } + + if (err) { + kfree(qp); + return ERR_PTR(err); + } + + init_attr->cap.max_send_wr = qp->sq.max; + init_attr->cap.max_recv_wr = qp->rq.max; + init_attr->cap.max_send_sge = qp->sq.max_gs; + init_attr->cap.max_recv_sge = qp->rq.max_gs; + init_attr->cap.max_inline_data = qp->max_inline_data; + + return &qp->ibqp; +} + +static int mthca_destroy_qp(struct ib_qp *qp) +{ + if (qp->uobject) { + mthca_unmap_user_db(to_mdev(qp->device), + &to_mucontext(qp->uobject->context)->uar, + to_mucontext(qp->uobject->context)->db_tab, + to_mqp(qp)->sq.db_index); + mthca_unmap_user_db(to_mdev(qp->device), + &to_mucontext(qp->uobject->context)->uar, + to_mucontext(qp->uobject->context)->db_tab, + to_mqp(qp)->rq.db_index); + } + mthca_free_qp(to_mdev(qp->device), to_mqp(qp)); + kfree(qp); + return 0; +} + +static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries, + int comp_vector, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct mthca_create_cq ucmd; + struct mthca_cq *cq; + int nent; + int err; + + if (entries < 1 || entries > to_mdev(ibdev)->limits.max_cqes) + return ERR_PTR(-EINVAL); + + if (context) { + if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) + return ERR_PTR(-EFAULT); + + err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab, + ucmd.set_db_index, ucmd.set_db_page); + if (err) + return ERR_PTR(err); + + err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab, + ucmd.arm_db_index, ucmd.arm_db_page); + if (err) + goto err_unmap_set; + } + + cq = kmalloc(sizeof *cq, GFP_KERNEL); + if (!cq) { + err = -ENOMEM; + goto err_unmap_arm; + } + + if (context) { + cq->buf.mr.ibmr.lkey = ucmd.lkey; + cq->set_ci_db_index = ucmd.set_db_index; + cq->arm_db_index = ucmd.arm_db_index; + } + + for (nent = 1; nent <= entries; nent <<= 1) + ; /* nothing */ + + err = mthca_init_cq(to_mdev(ibdev), nent, + context ? to_mucontext(context) : NULL, + context ? ucmd.pdn : to_mdev(ibdev)->driver_pd.pd_num, + cq); + if (err) + goto err_free; + + if (context && ib_copy_to_udata(udata, &cq->cqn, sizeof (__u32))) { + mthca_free_cq(to_mdev(ibdev), cq); + goto err_free; + } + + cq->resize_buf = NULL; + + return &cq->ibcq; + +err_free: + kfree(cq); + +err_unmap_arm: + if (context) + mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab, ucmd.arm_db_index); + +err_unmap_set: + if (context) + mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar, + to_mucontext(context)->db_tab, ucmd.set_db_index); + + return ERR_PTR(err); +} + +static int mthca_alloc_resize_buf(struct mthca_dev *dev, struct mthca_cq *cq, + int entries) +{ + int ret; + + spin_lock_irq(&cq->lock); + if (cq->resize_buf) { + ret = -EBUSY; + goto unlock; + } + + cq->resize_buf = kmalloc(sizeof *cq->resize_buf, GFP_ATOMIC); + if (!cq->resize_buf) { + ret = -ENOMEM; + goto unlock; + } + + cq->resize_buf->state = CQ_RESIZE_ALLOC; + + ret = 0; + +unlock: + spin_unlock_irq(&cq->lock); + + if (ret) + return ret; + + ret = mthca_alloc_cq_buf(dev, &cq->resize_buf->buf, entries); + if (ret) { + spin_lock_irq(&cq->lock); + kfree(cq->resize_buf); + cq->resize_buf = NULL; + spin_unlock_irq(&cq->lock); + return ret; + } + + cq->resize_buf->cqe = entries - 1; + + spin_lock_irq(&cq->lock); + cq->resize_buf->state = CQ_RESIZE_READY; + spin_unlock_irq(&cq->lock); + + return 0; +} + +static int mthca_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) +{ + struct mthca_dev *dev = to_mdev(ibcq->device); + struct mthca_cq *cq = to_mcq(ibcq); + struct mthca_resize_cq ucmd; + u32 lkey; + u8 status; + int ret; + + if (entries < 1 || entries > dev->limits.max_cqes) + return -EINVAL; + + mutex_lock(&cq->mutex); + + entries = roundup_pow_of_two(entries + 1); + if (entries == ibcq->cqe + 1) { + ret = 0; + goto out; + } + + if (cq->is_kernel) { + ret = mthca_alloc_resize_buf(dev, cq, entries); + if (ret) + goto out; + lkey = cq->resize_buf->buf.mr.ibmr.lkey; + } else { + if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) { + ret = -EFAULT; + goto out; + } + lkey = ucmd.lkey; + } + + ret = mthca_RESIZE_CQ(dev, cq->cqn, lkey, ilog2(entries), &status); + if (status) + ret = -EINVAL; + + if (ret) { + if (cq->resize_buf) { + mthca_free_cq_buf(dev, &cq->resize_buf->buf, + cq->resize_buf->cqe); + kfree(cq->resize_buf); + spin_lock_irq(&cq->lock); + cq->resize_buf = NULL; + spin_unlock_irq(&cq->lock); + } + goto out; + } + + if (cq->is_kernel) { + struct mthca_cq_buf tbuf; + int tcqe; + + spin_lock_irq(&cq->lock); + if (cq->resize_buf->state == CQ_RESIZE_READY) { + mthca_cq_resize_copy_cqes(cq); + tbuf = cq->buf; + tcqe = cq->ibcq.cqe; + cq->buf = cq->resize_buf->buf; + cq->ibcq.cqe = cq->resize_buf->cqe; + } else { + tbuf = cq->resize_buf->buf; + tcqe = cq->resize_buf->cqe; + } + + kfree(cq->resize_buf); + cq->resize_buf = NULL; + spin_unlock_irq(&cq->lock); + + mthca_free_cq_buf(dev, &tbuf, tcqe); + } else + ibcq->cqe = entries - 1; + +out: + mutex_unlock(&cq->mutex); + + return ret; +} + +static int mthca_destroy_cq(struct ib_cq *cq) +{ + if (cq->uobject) { + mthca_unmap_user_db(to_mdev(cq->device), + &to_mucontext(cq->uobject->context)->uar, + to_mucontext(cq->uobject->context)->db_tab, + to_mcq(cq)->arm_db_index); + mthca_unmap_user_db(to_mdev(cq->device), + &to_mucontext(cq->uobject->context)->uar, + to_mucontext(cq->uobject->context)->db_tab, + to_mcq(cq)->set_ci_db_index); + } + mthca_free_cq(to_mdev(cq->device), to_mcq(cq)); + kfree(cq); + + return 0; +} + +static inline u32 convert_access(int acc) +{ + return (acc & IB_ACCESS_REMOTE_ATOMIC ? MTHCA_MPT_FLAG_ATOMIC : 0) | + (acc & IB_ACCESS_REMOTE_WRITE ? MTHCA_MPT_FLAG_REMOTE_WRITE : 0) | + (acc & IB_ACCESS_REMOTE_READ ? MTHCA_MPT_FLAG_REMOTE_READ : 0) | + (acc & IB_ACCESS_LOCAL_WRITE ? MTHCA_MPT_FLAG_LOCAL_WRITE : 0) | + MTHCA_MPT_FLAG_LOCAL_READ; +} + +static struct ib_mr *mthca_get_dma_mr(struct ib_pd *pd, int acc) +{ + struct mthca_mr *mr; + int err; + + mr = kmalloc(sizeof *mr, GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + err = mthca_mr_alloc_notrans(to_mdev(pd->device), + to_mpd(pd)->pd_num, + convert_access(acc), mr); + + if (err) { + kfree(mr); + return ERR_PTR(err); + } + + mr->umem = NULL; + + return &mr->ibmr; +} + +static struct ib_mr *mthca_reg_phys_mr(struct ib_pd *pd, + struct ib_phys_buf *buffer_list, + int num_phys_buf, + int acc, + u64 *iova_start) +{ + struct mthca_mr *mr; + u64 *page_list; + u64 total_size; + unsigned long mask; + int shift; + int npages; + int err; + int i, j, n; + + mask = buffer_list[0].addr ^ *iova_start; + total_size = 0; + for (i = 0; i < num_phys_buf; ++i) { + if (i != 0) + mask |= buffer_list[i].addr; + if (i != num_phys_buf - 1) + mask |= buffer_list[i].addr + buffer_list[i].size; + + total_size += buffer_list[i].size; + } + + if (mask & ~PAGE_MASK) + return ERR_PTR(-EINVAL); + + shift = __ffs(mask | 1 << 31); + + buffer_list[0].size += buffer_list[0].addr & ((1ULL << shift) - 1); + buffer_list[0].addr &= ~0ull << shift; + + mr = kmalloc(sizeof *mr, GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + npages = 0; + for (i = 0; i < num_phys_buf; ++i) + npages += (buffer_list[i].size + (1ULL << shift) - 1) >> shift; + + if (!npages) + return &mr->ibmr; + + page_list = kmalloc(npages * sizeof *page_list, GFP_KERNEL); + if (!page_list) { + kfree(mr); + return ERR_PTR(-ENOMEM); + } + + n = 0; + for (i = 0; i < num_phys_buf; ++i) + for (j = 0; + j < (buffer_list[i].size + (1ULL << shift) - 1) >> shift; + ++j) + page_list[n++] = buffer_list[i].addr + ((u64) j << shift); + + mthca_dbg(to_mdev(pd->device), "Registering memory at %llx (iova %llx) " + "in PD %x; shift %d, npages %d.\n", + (unsigned long long) buffer_list[0].addr, + (unsigned long long) *iova_start, + to_mpd(pd)->pd_num, + shift, npages); + + err = mthca_mr_alloc_phys(to_mdev(pd->device), + to_mpd(pd)->pd_num, + page_list, shift, npages, + *iova_start, total_size, + convert_access(acc), mr); + + if (err) { + kfree(page_list); + kfree(mr); + return ERR_PTR(err); + } + + kfree(page_list); + mr->umem = NULL; + + return &mr->ibmr; +} + +static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, + u64 virt, int acc, struct ib_udata *udata) +{ + struct mthca_dev *dev = to_mdev(pd->device); + struct ib_umem_chunk *chunk; + struct mthca_mr *mr; + struct mthca_reg_mr ucmd; + u64 *pages; + int shift, n, len; + int i, j, k; + int err = 0; + int write_mtt_size; + + if (udata->inlen - sizeof (struct ib_uverbs_cmd_hdr) < sizeof ucmd) { + if (!to_mucontext(pd->uobject->context)->reg_mr_warned) { + mthca_warn(dev, "Process '%s' did not pass in MR attrs.\n", + curproc->p_comm); + mthca_warn(dev, " Update libmthca to fix this.\n"); + } + ++to_mucontext(pd->uobject->context)->reg_mr_warned; + ucmd.mr_attrs = 0; + } else if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) + return ERR_PTR(-EFAULT); + + mr = kmalloc(sizeof *mr, GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + mr->umem = ib_umem_get(pd->uobject->context, start, length, acc, + ucmd.mr_attrs & MTHCA_MR_DMASYNC); + + if (IS_ERR(mr->umem)) { + err = PTR_ERR(mr->umem); + goto err; + } + + shift = ffs(mr->umem->page_size) - 1; + + n = 0; + list_for_each_entry(chunk, &mr->umem->chunk_list, list) + n += chunk->nents; + + mr->mtt = mthca_alloc_mtt(dev, n); + if (IS_ERR(mr->mtt)) { + err = PTR_ERR(mr->mtt); + goto err_umem; + } + + pages = (u64 *) __get_free_page(GFP_KERNEL); + if (!pages) { + err = -ENOMEM; + goto err_mtt; + } + + i = n = 0; + + write_mtt_size = min(mthca_write_mtt_size(dev), (int) (PAGE_SIZE / sizeof *pages)); + + list_for_each_entry(chunk, &mr->umem->chunk_list, list) + for (j = 0; j < chunk->nmap; ++j) { + len = sg_dma_len(&chunk->page_list[j]) >> shift; + for (k = 0; k < len; ++k) { + pages[i++] = sg_dma_address(&chunk->page_list[j]) + + mr->umem->page_size * k; + /* + * Be friendly to write_mtt and pass it chunks + * of appropriate size. + */ + if (i == write_mtt_size) { + err = mthca_write_mtt(dev, mr->mtt, n, pages, i); + if (err) + goto mtt_done; + n += i; + i = 0; + } + } + } + + if (i) + err = mthca_write_mtt(dev, mr->mtt, n, pages, i); +mtt_done: + free_page((unsigned long) pages); + if (err) + goto err_mtt; + + err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, shift, virt, length, + convert_access(acc), mr); + + if (err) + goto err_mtt; + + return &mr->ibmr; + +err_mtt: + mthca_free_mtt(dev, mr->mtt); + +err_umem: + ib_umem_release(mr->umem); + +err: + kfree(mr); + return ERR_PTR(err); +} + +static int mthca_dereg_mr(struct ib_mr *mr) +{ + struct mthca_mr *mmr = to_mmr(mr); + + mthca_free_mr(to_mdev(mr->device), mmr); + if (mmr->umem) + ib_umem_release(mmr->umem); + kfree(mmr); + + return 0; +} + +static struct ib_fmr *mthca_alloc_fmr(struct ib_pd *pd, int mr_access_flags, + struct ib_fmr_attr *fmr_attr) +{ + struct mthca_fmr *fmr; + int err; + + fmr = kmalloc(sizeof *fmr, GFP_KERNEL); + if (!fmr) + return ERR_PTR(-ENOMEM); + + memcpy(&fmr->attr, fmr_attr, sizeof *fmr_attr); + err = mthca_fmr_alloc(to_mdev(pd->device), to_mpd(pd)->pd_num, + convert_access(mr_access_flags), fmr); + + if (err) { + kfree(fmr); + return ERR_PTR(err); + } + + return &fmr->ibmr; +} + +static int mthca_dealloc_fmr(struct ib_fmr *fmr) +{ + struct mthca_fmr *mfmr = to_mfmr(fmr); + int err; + + err = mthca_free_fmr(to_mdev(fmr->device), mfmr); + if (err) + return err; + + kfree(mfmr); + return 0; +} + +static int mthca_unmap_fmr(struct list_head *fmr_list) +{ + struct ib_fmr *fmr; + int err; + u8 status; + struct mthca_dev *mdev = NULL; + + list_for_each_entry(fmr, fmr_list, list) { + if (mdev && to_mdev(fmr->device) != mdev) + return -EINVAL; + mdev = to_mdev(fmr->device); + } + + if (!mdev) + return 0; + + if (mthca_is_memfree(mdev)) { + list_for_each_entry(fmr, fmr_list, list) + mthca_arbel_fmr_unmap(mdev, to_mfmr(fmr)); + + wmb(); + } else + list_for_each_entry(fmr, fmr_list, list) + mthca_tavor_fmr_unmap(mdev, to_mfmr(fmr)); + + err = mthca_SYNC_TPT(mdev, &status); + if (err) + return err; + if (status) + return -EINVAL; + return 0; +} + +static ssize_t show_rev(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct mthca_dev *dev = + container_of(device, struct mthca_dev, ib_dev.dev); + return sprintf(buf, "%x\n", dev->rev_id); +} + +static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct mthca_dev *dev = + container_of(device, struct mthca_dev, ib_dev.dev); + return sprintf(buf, "%d.%d.%d\n", (int) (dev->fw_ver >> 32), + (int) (dev->fw_ver >> 16) & 0xffff, + (int) dev->fw_ver & 0xffff); +} + +static ssize_t show_hca(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct mthca_dev *dev = + container_of(device, struct mthca_dev, ib_dev.dev); + switch (dev->pdev->device) { + case PCI_DEVICE_ID_MELLANOX_TAVOR: + return sprintf(buf, "MT23108\n"); + case PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT: + return sprintf(buf, "MT25208 (MT23108 compat mode)\n"); + case PCI_DEVICE_ID_MELLANOX_ARBEL: + return sprintf(buf, "MT25208\n"); + case PCI_DEVICE_ID_MELLANOX_SINAI: + case PCI_DEVICE_ID_MELLANOX_SINAI_OLD: + return sprintf(buf, "MT25204\n"); + default: + return sprintf(buf, "unknown\n"); + } +} + +static ssize_t show_board(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct mthca_dev *dev = + container_of(device, struct mthca_dev, ib_dev.dev); + return sprintf(buf, "%.*s\n", MTHCA_BOARD_ID_LEN, dev->board_id); +} + +static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); +static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL); +static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); +static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); + +static struct device_attribute *mthca_dev_attributes[] = { + &dev_attr_hw_rev, + &dev_attr_fw_ver, + &dev_attr_hca_type, + &dev_attr_board_id +}; + +static int mthca_init_node_data(struct mthca_dev *dev) +{ + struct ib_smp *in_mad = NULL; + struct ib_smp *out_mad = NULL; + int err = -ENOMEM; + u8 status; + + in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); + out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + if (!in_mad || !out_mad) + goto out; + + init_query_mad(in_mad); + in_mad->attr_id = IB_SMP_ATTR_NODE_DESC; + + err = mthca_MAD_IFC(dev, 1, 1, + 1, NULL, NULL, in_mad, out_mad, + &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + + memcpy(dev->ib_dev.node_desc, out_mad->data, 64); + + in_mad->attr_id = IB_SMP_ATTR_NODE_INFO; + + err = mthca_MAD_IFC(dev, 1, 1, + 1, NULL, NULL, in_mad, out_mad, + &status); + if (err) + goto out; + if (status) { + err = -EINVAL; + goto out; + } + + if (mthca_is_memfree(dev)) + dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32)); + memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8); + +out: + kfree(in_mad); + kfree(out_mad); + return err; +} + +int mthca_register_device(struct mthca_dev *dev) +{ + int ret; + int i; + + ret = mthca_init_node_data(dev); + if (ret) + return ret; + + strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX); + dev->ib_dev.owner = THIS_MODULE; + + dev->ib_dev.uverbs_abi_ver = MTHCA_UVERBS_ABI_VERSION; + dev->ib_dev.uverbs_cmd_mask = + (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | + (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | + (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | + (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_REG_MR) | + (1ull << IB_USER_VERBS_CMD_DEREG_MR) | + (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | + (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | + (1ull << IB_USER_VERBS_CMD_RESIZE_CQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | + (1ull << IB_USER_VERBS_CMD_CREATE_QP) | + (1ull << IB_USER_VERBS_CMD_QUERY_QP) | + (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | + (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | + (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) | + (1ull << IB_USER_VERBS_CMD_DETACH_MCAST); + dev->ib_dev.node_type = RDMA_NODE_IB_CA; + dev->ib_dev.phys_port_cnt = dev->limits.num_ports; + dev->ib_dev.num_comp_vectors = 1; + dev->ib_dev.dma_device = &dev->pdev->dev; + dev->ib_dev.query_device = mthca_query_device; + dev->ib_dev.query_port = mthca_query_port; + dev->ib_dev.modify_device = mthca_modify_device; + dev->ib_dev.modify_port = mthca_modify_port; + dev->ib_dev.query_pkey = mthca_query_pkey; + dev->ib_dev.query_gid = mthca_query_gid; + dev->ib_dev.alloc_ucontext = mthca_alloc_ucontext; + dev->ib_dev.dealloc_ucontext = mthca_dealloc_ucontext; + dev->ib_dev.mmap = mthca_mmap_uar; + dev->ib_dev.alloc_pd = mthca_alloc_pd; + dev->ib_dev.dealloc_pd = mthca_dealloc_pd; + dev->ib_dev.create_ah = mthca_ah_create; + dev->ib_dev.query_ah = mthca_ah_query; + dev->ib_dev.destroy_ah = mthca_ah_destroy; + + if (dev->mthca_flags & MTHCA_FLAG_SRQ) { + dev->ib_dev.create_srq = mthca_create_srq; + dev->ib_dev.modify_srq = mthca_modify_srq; + dev->ib_dev.query_srq = mthca_query_srq; + dev->ib_dev.destroy_srq = mthca_destroy_srq; + dev->ib_dev.uverbs_cmd_mask |= + (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) | + (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) | + (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ); + + if (mthca_is_memfree(dev)) + dev->ib_dev.post_srq_recv = mthca_arbel_post_srq_recv; + else + dev->ib_dev.post_srq_recv = mthca_tavor_post_srq_recv; + } + + dev->ib_dev.create_qp = mthca_create_qp; + dev->ib_dev.modify_qp = mthca_modify_qp; + dev->ib_dev.query_qp = mthca_query_qp; + dev->ib_dev.destroy_qp = mthca_destroy_qp; + dev->ib_dev.create_cq = mthca_create_cq; + dev->ib_dev.resize_cq = mthca_resize_cq; + dev->ib_dev.destroy_cq = mthca_destroy_cq; + dev->ib_dev.poll_cq = mthca_poll_cq; + dev->ib_dev.get_dma_mr = mthca_get_dma_mr; + dev->ib_dev.reg_phys_mr = mthca_reg_phys_mr; + dev->ib_dev.reg_user_mr = mthca_reg_user_mr; + dev->ib_dev.dereg_mr = mthca_dereg_mr; + + if (dev->mthca_flags & MTHCA_FLAG_FMR) { + dev->ib_dev.alloc_fmr = mthca_alloc_fmr; + dev->ib_dev.unmap_fmr = mthca_unmap_fmr; + dev->ib_dev.dealloc_fmr = mthca_dealloc_fmr; + if (mthca_is_memfree(dev)) + dev->ib_dev.map_phys_fmr = mthca_arbel_map_phys_fmr; + else + dev->ib_dev.map_phys_fmr = mthca_tavor_map_phys_fmr; + } + + dev->ib_dev.attach_mcast = mthca_multicast_attach; + dev->ib_dev.detach_mcast = mthca_multicast_detach; + dev->ib_dev.process_mad = mthca_process_mad; + + if (mthca_is_memfree(dev)) { + dev->ib_dev.req_notify_cq = mthca_arbel_arm_cq; + dev->ib_dev.post_send = mthca_arbel_post_send; + dev->ib_dev.post_recv = mthca_arbel_post_receive; + } else { + dev->ib_dev.req_notify_cq = mthca_tavor_arm_cq; + dev->ib_dev.post_send = mthca_tavor_post_send; + dev->ib_dev.post_recv = mthca_tavor_post_receive; + } + + mutex_init(&dev->cap_mask_mutex); + + ret = ib_register_device(&dev->ib_dev); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(mthca_dev_attributes); ++i) { + ret = device_create_file(&dev->ib_dev.dev, + mthca_dev_attributes[i]); + if (ret) { + ib_unregister_device(&dev->ib_dev); + return ret; + } + } + + mthca_start_catas_poll(dev); + + return 0; +} + +void mthca_unregister_device(struct mthca_dev *dev) +{ + mthca_stop_catas_poll(dev); + ib_unregister_device(&dev->ib_dev); +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_provider.h b/sys/ofed/drivers/infiniband/hw/mthca/mthca_provider.h new file mode 100644 index 000000000000..c621f8794b88 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_provider.h @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MTHCA_PROVIDER_H +#define MTHCA_PROVIDER_H + +#include +#include + +#define MTHCA_MPT_FLAG_ATOMIC (1 << 14) +#define MTHCA_MPT_FLAG_REMOTE_WRITE (1 << 13) +#define MTHCA_MPT_FLAG_REMOTE_READ (1 << 12) +#define MTHCA_MPT_FLAG_LOCAL_WRITE (1 << 11) +#define MTHCA_MPT_FLAG_LOCAL_READ (1 << 10) + +struct mthca_buf_list { + void *buf; + DECLARE_PCI_UNMAP_ADDR(mapping) +}; + +union mthca_buf { + struct mthca_buf_list direct; + struct mthca_buf_list *page_list; +}; + +struct mthca_uar { + unsigned long pfn; + int index; +}; + +struct mthca_user_db_table; + +struct mthca_ucontext { + struct ib_ucontext ibucontext; + struct mthca_uar uar; + struct mthca_user_db_table *db_tab; + int reg_mr_warned; +}; + +struct mthca_mtt; + +struct mthca_mr { + struct ib_mr ibmr; + struct ib_umem *umem; + struct mthca_mtt *mtt; +}; + +struct mthca_fmr { + struct ib_fmr ibmr; + struct ib_fmr_attr attr; + struct mthca_mtt *mtt; + int maps; + union { + struct { + struct mthca_mpt_entry __iomem *mpt; + u64 __iomem *mtts; + } tavor; + struct { + struct mthca_mpt_entry *mpt; + __be64 *mtts; + dma_addr_t dma_handle; + } arbel; + } mem; +}; + +struct mthca_pd { + struct ib_pd ibpd; + u32 pd_num; + atomic_t sqp_count; + struct mthca_mr ntmr; + int privileged; +}; + +struct mthca_eq { + struct mthca_dev *dev; + int eqn; + u32 eqn_mask; + u32 cons_index; + u16 msi_x_vector; + u16 msi_x_entry; + int have_irq; + int nent; + struct mthca_buf_list *page_list; + struct mthca_mr mr; +}; + +struct mthca_av; + +enum mthca_ah_type { + MTHCA_AH_ON_HCA, + MTHCA_AH_PCI_POOL, + MTHCA_AH_KMALLOC +}; + +struct mthca_ah { + struct ib_ah ibah; + enum mthca_ah_type type; + u32 key; + struct mthca_av *av; + dma_addr_t avdma; +}; + +/* + * Quick description of our CQ/QP locking scheme: + * + * We have one global lock that protects dev->cq/qp_table. Each + * struct mthca_cq/qp also has its own lock. An individual qp lock + * may be taken inside of an individual cq lock. Both cqs attached to + * a qp may be locked, with the cq with the lower cqn locked first. + * No other nesting should be done. + * + * Each struct mthca_cq/qp also has an ref count, protected by the + * corresponding table lock. The pointer from the cq/qp_table to the + * struct counts as one reference. This reference also is good for + * access through the consumer API, so modifying the CQ/QP etc doesn't + * need to take another reference. Access to a QP because of a + * completion being polled does not need a reference either. + * + * Finally, each struct mthca_cq/qp has a wait_queue_head_t for the + * destroy function to sleep on. + * + * This means that access from the consumer API requires nothing but + * taking the struct's lock. + * + * Access because of a completion event should go as follows: + * - lock cq/qp_table and look up struct + * - increment ref count in struct + * - drop cq/qp_table lock + * - lock struct, do your thing, and unlock struct + * - decrement ref count; if zero, wake up waiters + * + * To destroy a CQ/QP, we can do the following: + * - lock cq/qp_table + * - remove pointer and decrement ref count + * - unlock cq/qp_table lock + * - wait_event until ref count is zero + * + * It is the consumer's responsibilty to make sure that no QP + * operations (WQE posting or state modification) are pending when a + * QP is destroyed. Also, the consumer must make sure that calls to + * qp_modify are serialized. Similarly, the consumer is responsible + * for ensuring that no CQ resize operations are pending when a CQ + * is destroyed. + * + * Possible optimizations (wait for profile data to see if/where we + * have locks bouncing between CPUs): + * - split cq/qp table lock into n separate (cache-aligned) locks, + * indexed (say) by the page in the table + * - split QP struct lock into three (one for common info, one for the + * send queue and one for the receive queue) + */ + +struct mthca_cq_buf { + union mthca_buf queue; + struct mthca_mr mr; + int is_direct; +}; + +struct mthca_cq_resize { + struct mthca_cq_buf buf; + int cqe; + enum { + CQ_RESIZE_ALLOC, + CQ_RESIZE_READY, + CQ_RESIZE_SWAPPED + } state; +}; + +struct mthca_cq { + struct ib_cq ibcq; + spinlock_t lock; + int refcount; + int cqn; + u32 cons_index; + struct mthca_cq_buf buf; + struct mthca_cq_resize *resize_buf; + int is_kernel; + + /* Next fields are Arbel only */ + int set_ci_db_index; + __be32 *set_ci_db; + int arm_db_index; + __be32 *arm_db; + int arm_sn; + + wait_queue_head_t wait; + struct mutex mutex; +}; + +struct mthca_srq { + struct ib_srq ibsrq; + spinlock_t lock; + int refcount; + int srqn; + int max; + int max_gs; + int wqe_shift; + int first_free; + int last_free; + u16 counter; /* Arbel only */ + int db_index; /* Arbel only */ + __be32 *db; /* Arbel only */ + void *last; + + int is_direct; + u64 *wrid; + union mthca_buf queue; + struct mthca_mr mr; + + wait_queue_head_t wait; + struct mutex mutex; +}; + +struct mthca_wq { + spinlock_t lock; + int max; + unsigned next_ind; + unsigned last_comp; + unsigned head; + unsigned tail; + void *last; + int max_gs; + int wqe_shift; + + int db_index; /* Arbel only */ + __be32 *db; +}; + +struct mthca_qp { + struct ib_qp ibqp; + int refcount; + u32 qpn; + int is_direct; + u8 port; /* for SQP and memfree use only */ + u8 alt_port; /* for memfree use only */ + u8 transport; + u8 state; + u8 atomic_rd_en; + u8 resp_depth; + + struct mthca_mr mr; + + struct mthca_wq rq; + struct mthca_wq sq; + enum ib_sig_type sq_policy; + int send_wqe_offset; + int max_inline_data; + + u64 *wrid; + union mthca_buf queue; + + wait_queue_head_t wait; + struct mutex mutex; +}; + +struct mthca_sqp { + struct mthca_qp qp; + int pkey_index; + u32 qkey; + u32 send_psn; + struct ib_ud_header ud_header; + int header_buf_size; + void *header_buf; + dma_addr_t header_dma; +}; + +static inline struct mthca_ucontext *to_mucontext(struct ib_ucontext *ibucontext) +{ + return container_of(ibucontext, struct mthca_ucontext, ibucontext); +} + +static inline struct mthca_fmr *to_mfmr(struct ib_fmr *ibmr) +{ + return container_of(ibmr, struct mthca_fmr, ibmr); +} + +static inline struct mthca_mr *to_mmr(struct ib_mr *ibmr) +{ + return container_of(ibmr, struct mthca_mr, ibmr); +} + +static inline struct mthca_pd *to_mpd(struct ib_pd *ibpd) +{ + return container_of(ibpd, struct mthca_pd, ibpd); +} + +static inline struct mthca_ah *to_mah(struct ib_ah *ibah) +{ + return container_of(ibah, struct mthca_ah, ibah); +} + +static inline struct mthca_cq *to_mcq(struct ib_cq *ibcq) +{ + return container_of(ibcq, struct mthca_cq, ibcq); +} + +static inline struct mthca_srq *to_msrq(struct ib_srq *ibsrq) +{ + return container_of(ibsrq, struct mthca_srq, ibsrq); +} + +static inline struct mthca_qp *to_mqp(struct ib_qp *ibqp) +{ + return container_of(ibqp, struct mthca_qp, ibqp); +} + +static inline struct mthca_sqp *to_msqp(struct mthca_qp *qp) +{ + return container_of(qp, struct mthca_sqp, qp); +} + +#endif /* MTHCA_PROVIDER_H */ diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_qp.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_qp.c new file mode 100644 index 000000000000..4a4d1334a174 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_qp.c @@ -0,0 +1,2332 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include + +#include +#include +#include + +#include "mthca_dev.h" +#include "mthca_cmd.h" +#include "mthca_memfree.h" +#include "mthca_wqe.h" + +enum { + MTHCA_MAX_DIRECT_QP_SIZE = 4 * PAGE_SIZE, + MTHCA_ACK_REQ_FREQ = 10, + MTHCA_FLIGHT_LIMIT = 9, + MTHCA_UD_HEADER_SIZE = 72, /* largest UD header possible */ + MTHCA_INLINE_HEADER_SIZE = 4, /* data segment overhead for inline */ + MTHCA_INLINE_CHUNK_SIZE = 16 /* inline data segment chunk */ +}; + +enum { + MTHCA_QP_STATE_RST = 0, + MTHCA_QP_STATE_INIT = 1, + MTHCA_QP_STATE_RTR = 2, + MTHCA_QP_STATE_RTS = 3, + MTHCA_QP_STATE_SQE = 4, + MTHCA_QP_STATE_SQD = 5, + MTHCA_QP_STATE_ERR = 6, + MTHCA_QP_STATE_DRAINING = 7 +}; + +enum { + MTHCA_QP_ST_RC = 0x0, + MTHCA_QP_ST_UC = 0x1, + MTHCA_QP_ST_RD = 0x2, + MTHCA_QP_ST_UD = 0x3, + MTHCA_QP_ST_MLX = 0x7 +}; + +enum { + MTHCA_QP_PM_MIGRATED = 0x3, + MTHCA_QP_PM_ARMED = 0x0, + MTHCA_QP_PM_REARM = 0x1 +}; + +enum { + /* qp_context flags */ + MTHCA_QP_BIT_DE = 1 << 8, + /* params1 */ + MTHCA_QP_BIT_SRE = 1 << 15, + MTHCA_QP_BIT_SWE = 1 << 14, + MTHCA_QP_BIT_SAE = 1 << 13, + MTHCA_QP_BIT_SIC = 1 << 4, + MTHCA_QP_BIT_SSC = 1 << 3, + /* params2 */ + MTHCA_QP_BIT_RRE = 1 << 15, + MTHCA_QP_BIT_RWE = 1 << 14, + MTHCA_QP_BIT_RAE = 1 << 13, + MTHCA_QP_BIT_RIC = 1 << 4, + MTHCA_QP_BIT_RSC = 1 << 3 +}; + +enum { + MTHCA_SEND_DOORBELL_FENCE = 1 << 5 +}; + +struct mthca_qp_path { + __be32 port_pkey; + u8 rnr_retry; + u8 g_mylmc; + __be16 rlid; + u8 ackto; + u8 mgid_index; + u8 static_rate; + u8 hop_limit; + __be32 sl_tclass_flowlabel; + u8 rgid[16]; +} __attribute__((packed)); + +struct mthca_qp_context { + __be32 flags; + __be32 tavor_sched_queue; /* Reserved on Arbel */ + u8 mtu_msgmax; + u8 rq_size_stride; /* Reserved on Tavor */ + u8 sq_size_stride; /* Reserved on Tavor */ + u8 rlkey_arbel_sched_queue; /* Reserved on Tavor */ + __be32 usr_page; + __be32 local_qpn; + __be32 remote_qpn; + u32 reserved1[2]; + struct mthca_qp_path pri_path; + struct mthca_qp_path alt_path; + __be32 rdd; + __be32 pd; + __be32 wqe_base; + __be32 wqe_lkey; + __be32 params1; + __be32 reserved2; + __be32 next_send_psn; + __be32 cqn_snd; + __be32 snd_wqe_base_l; /* Next send WQE on Tavor */ + __be32 snd_db_index; /* (debugging only entries) */ + __be32 last_acked_psn; + __be32 ssn; + __be32 params2; + __be32 rnr_nextrecvpsn; + __be32 ra_buff_indx; + __be32 cqn_rcv; + __be32 rcv_wqe_base_l; /* Next recv WQE on Tavor */ + __be32 rcv_db_index; /* (debugging only entries) */ + __be32 qkey; + __be32 srqn; + __be32 rmsn; + __be16 rq_wqe_counter; /* reserved on Tavor */ + __be16 sq_wqe_counter; /* reserved on Tavor */ + u32 reserved3[18]; +} __attribute__((packed)); + +struct mthca_qp_param { + __be32 opt_param_mask; + u32 reserved1; + struct mthca_qp_context context; + u32 reserved2[62]; +} __attribute__((packed)); + +enum { + MTHCA_QP_OPTPAR_ALT_ADDR_PATH = 1 << 0, + MTHCA_QP_OPTPAR_RRE = 1 << 1, + MTHCA_QP_OPTPAR_RAE = 1 << 2, + MTHCA_QP_OPTPAR_RWE = 1 << 3, + MTHCA_QP_OPTPAR_PKEY_INDEX = 1 << 4, + MTHCA_QP_OPTPAR_Q_KEY = 1 << 5, + MTHCA_QP_OPTPAR_RNR_TIMEOUT = 1 << 6, + MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH = 1 << 7, + MTHCA_QP_OPTPAR_SRA_MAX = 1 << 8, + MTHCA_QP_OPTPAR_RRA_MAX = 1 << 9, + MTHCA_QP_OPTPAR_PM_STATE = 1 << 10, + MTHCA_QP_OPTPAR_PORT_NUM = 1 << 11, + MTHCA_QP_OPTPAR_RETRY_COUNT = 1 << 12, + MTHCA_QP_OPTPAR_ALT_RNR_RETRY = 1 << 13, + MTHCA_QP_OPTPAR_ACK_TIMEOUT = 1 << 14, + MTHCA_QP_OPTPAR_RNR_RETRY = 1 << 15, + MTHCA_QP_OPTPAR_SCHED_QUEUE = 1 << 16 +}; + +static const u8 mthca_opcode[] = { + [IB_WR_SEND] = MTHCA_OPCODE_SEND, + [IB_WR_SEND_WITH_IMM] = MTHCA_OPCODE_SEND_IMM, + [IB_WR_RDMA_WRITE] = MTHCA_OPCODE_RDMA_WRITE, + [IB_WR_RDMA_WRITE_WITH_IMM] = MTHCA_OPCODE_RDMA_WRITE_IMM, + [IB_WR_RDMA_READ] = MTHCA_OPCODE_RDMA_READ, + [IB_WR_ATOMIC_CMP_AND_SWP] = MTHCA_OPCODE_ATOMIC_CS, + [IB_WR_ATOMIC_FETCH_AND_ADD] = MTHCA_OPCODE_ATOMIC_FA, +}; + +static int is_sqp(struct mthca_dev *dev, struct mthca_qp *qp) +{ + return qp->qpn >= dev->qp_table.sqp_start && + qp->qpn <= dev->qp_table.sqp_start + 3; +} + +static int is_qp0(struct mthca_dev *dev, struct mthca_qp *qp) +{ + return qp->qpn >= dev->qp_table.sqp_start && + qp->qpn <= dev->qp_table.sqp_start + 1; +} + +static void *get_recv_wqe(struct mthca_qp *qp, int n) +{ + if (qp->is_direct) + return qp->queue.direct.buf + (n << qp->rq.wqe_shift); + else + return qp->queue.page_list[(n << qp->rq.wqe_shift) >> PAGE_SHIFT].buf + + ((n << qp->rq.wqe_shift) & (PAGE_SIZE - 1)); +} + +static void *get_send_wqe(struct mthca_qp *qp, int n) +{ + if (qp->is_direct) + return qp->queue.direct.buf + qp->send_wqe_offset + + (n << qp->sq.wqe_shift); + else + return qp->queue.page_list[(qp->send_wqe_offset + + (n << qp->sq.wqe_shift)) >> + PAGE_SHIFT].buf + + ((qp->send_wqe_offset + (n << qp->sq.wqe_shift)) & + (PAGE_SIZE - 1)); +} + +static void mthca_wq_reset(struct mthca_wq *wq) +{ + wq->next_ind = 0; + wq->last_comp = wq->max - 1; + wq->head = 0; + wq->tail = 0; +} + +void mthca_qp_event(struct mthca_dev *dev, u32 qpn, + enum ib_event_type event_type) +{ + struct mthca_qp *qp; + struct ib_event event; + + spin_lock(&dev->qp_table.lock); + qp = mthca_array_get(&dev->qp_table.qp, qpn & (dev->limits.num_qps - 1)); + if (qp) + ++qp->refcount; + spin_unlock(&dev->qp_table.lock); + + if (!qp) { + mthca_warn(dev, "Async event %d for bogus QP %08x\n", + (int) event_type, qpn); + return; + } + + if (event_type == IB_EVENT_PATH_MIG) + qp->port = qp->alt_port; + + event.device = &dev->ib_dev; + event.event = event_type; + event.element.qp = &qp->ibqp; + if (qp->ibqp.event_handler) + qp->ibqp.event_handler(&event, qp->ibqp.qp_context); + + spin_lock(&dev->qp_table.lock); + if (!--qp->refcount) + wake_up(&qp->wait); + spin_unlock(&dev->qp_table.lock); +} + +static int to_mthca_state(enum ib_qp_state ib_state) +{ + switch (ib_state) { + case IB_QPS_RESET: return MTHCA_QP_STATE_RST; + case IB_QPS_INIT: return MTHCA_QP_STATE_INIT; + case IB_QPS_RTR: return MTHCA_QP_STATE_RTR; + case IB_QPS_RTS: return MTHCA_QP_STATE_RTS; + case IB_QPS_SQD: return MTHCA_QP_STATE_SQD; + case IB_QPS_SQE: return MTHCA_QP_STATE_SQE; + case IB_QPS_ERR: return MTHCA_QP_STATE_ERR; + default: return -1; + } +} + +enum { RC, UC, UD, RD, RDEE, MLX, NUM_TRANS }; + +static int to_mthca_st(int transport) +{ + switch (transport) { + case RC: return MTHCA_QP_ST_RC; + case UC: return MTHCA_QP_ST_UC; + case UD: return MTHCA_QP_ST_UD; + case RD: return MTHCA_QP_ST_RD; + case MLX: return MTHCA_QP_ST_MLX; + default: return -1; + } +} + +static void store_attrs(struct mthca_sqp *sqp, const struct ib_qp_attr *attr, + int attr_mask) +{ + if (attr_mask & IB_QP_PKEY_INDEX) + sqp->pkey_index = attr->pkey_index; + if (attr_mask & IB_QP_QKEY) + sqp->qkey = attr->qkey; + if (attr_mask & IB_QP_SQ_PSN) + sqp->send_psn = attr->sq_psn; +} + +static void init_port(struct mthca_dev *dev, int port) +{ + int err; + u8 status; + struct mthca_init_ib_param param; + + memset(¶m, 0, sizeof param); + + param.port_width = dev->limits.port_width_cap; + param.vl_cap = dev->limits.vl_cap; + param.mtu_cap = dev->limits.mtu_cap; + param.gid_cap = dev->limits.gid_table_len; + param.pkey_cap = dev->limits.pkey_table_len; + + err = mthca_INIT_IB(dev, ¶m, port, &status); + if (err) + mthca_warn(dev, "INIT_IB failed, return code %d.\n", err); + if (status) + mthca_warn(dev, "INIT_IB returned status %02x.\n", status); +} + +static __be32 get_hw_access_flags(struct mthca_qp *qp, const struct ib_qp_attr *attr, + int attr_mask) +{ + u8 dest_rd_atomic; + u32 access_flags; + u32 hw_access_flags = 0; + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) + dest_rd_atomic = attr->max_dest_rd_atomic; + else + dest_rd_atomic = qp->resp_depth; + + if (attr_mask & IB_QP_ACCESS_FLAGS) + access_flags = attr->qp_access_flags; + else + access_flags = qp->atomic_rd_en; + + if (!dest_rd_atomic) + access_flags &= IB_ACCESS_REMOTE_WRITE; + + if (access_flags & IB_ACCESS_REMOTE_READ) + hw_access_flags |= MTHCA_QP_BIT_RRE; + if (access_flags & IB_ACCESS_REMOTE_ATOMIC) + hw_access_flags |= MTHCA_QP_BIT_RAE; + if (access_flags & IB_ACCESS_REMOTE_WRITE) + hw_access_flags |= MTHCA_QP_BIT_RWE; + + return cpu_to_be32(hw_access_flags); +} + +static inline enum ib_qp_state to_ib_qp_state(int mthca_state) +{ + switch (mthca_state) { + case MTHCA_QP_STATE_RST: return IB_QPS_RESET; + case MTHCA_QP_STATE_INIT: return IB_QPS_INIT; + case MTHCA_QP_STATE_RTR: return IB_QPS_RTR; + case MTHCA_QP_STATE_RTS: return IB_QPS_RTS; + case MTHCA_QP_STATE_DRAINING: + case MTHCA_QP_STATE_SQD: return IB_QPS_SQD; + case MTHCA_QP_STATE_SQE: return IB_QPS_SQE; + case MTHCA_QP_STATE_ERR: return IB_QPS_ERR; + default: return -1; + } +} + +static inline enum ib_mig_state to_ib_mig_state(int mthca_mig_state) +{ + switch (mthca_mig_state) { + case 0: return IB_MIG_ARMED; + case 1: return IB_MIG_REARM; + case 3: return IB_MIG_MIGRATED; + default: return -1; + } +} + +static int to_ib_qp_access_flags(int mthca_flags) +{ + int ib_flags = 0; + + if (mthca_flags & MTHCA_QP_BIT_RRE) + ib_flags |= IB_ACCESS_REMOTE_READ; + if (mthca_flags & MTHCA_QP_BIT_RWE) + ib_flags |= IB_ACCESS_REMOTE_WRITE; + if (mthca_flags & MTHCA_QP_BIT_RAE) + ib_flags |= IB_ACCESS_REMOTE_ATOMIC; + + return ib_flags; +} + +static void to_ib_ah_attr(struct mthca_dev *dev, struct ib_ah_attr *ib_ah_attr, + struct mthca_qp_path *path) +{ + memset(ib_ah_attr, 0, sizeof *ib_ah_attr); + ib_ah_attr->port_num = (be32_to_cpu(path->port_pkey) >> 24) & 0x3; + + if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->limits.num_ports) + return; + + ib_ah_attr->dlid = be16_to_cpu(path->rlid); + ib_ah_attr->sl = be32_to_cpu(path->sl_tclass_flowlabel) >> 28; + ib_ah_attr->src_path_bits = path->g_mylmc & 0x7f; + ib_ah_attr->static_rate = mthca_rate_to_ib(dev, + path->static_rate & 0xf, + ib_ah_attr->port_num); + ib_ah_attr->ah_flags = (path->g_mylmc & (1 << 7)) ? IB_AH_GRH : 0; + if (ib_ah_attr->ah_flags) { + ib_ah_attr->grh.sgid_index = path->mgid_index & (dev->limits.gid_table_len - 1); + ib_ah_attr->grh.hop_limit = path->hop_limit; + ib_ah_attr->grh.traffic_class = + (be32_to_cpu(path->sl_tclass_flowlabel) >> 20) & 0xff; + ib_ah_attr->grh.flow_label = + be32_to_cpu(path->sl_tclass_flowlabel) & 0xfffff; + memcpy(ib_ah_attr->grh.dgid.raw, + path->rgid, sizeof ib_ah_attr->grh.dgid.raw); + } +} + +int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_qp *qp = to_mqp(ibqp); + int err = 0; + struct mthca_mailbox *mailbox = NULL; + struct mthca_qp_param *qp_param; + struct mthca_qp_context *context; + int mthca_state; + u8 status; + + mutex_lock(&qp->mutex); + + if (qp->state == IB_QPS_RESET) { + qp_attr->qp_state = IB_QPS_RESET; + goto done; + } + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto out; + } + + err = mthca_QUERY_QP(dev, qp->qpn, 0, mailbox, &status); + if (err) + goto out_mailbox; + if (status) { + mthca_warn(dev, "QUERY_QP returned status %02x\n", status); + err = -EINVAL; + goto out_mailbox; + } + + qp_param = mailbox->buf; + context = &qp_param->context; + mthca_state = be32_to_cpu(context->flags) >> 28; + + qp->state = to_ib_qp_state(mthca_state); + qp_attr->qp_state = qp->state; + qp_attr->path_mtu = context->mtu_msgmax >> 5; + qp_attr->path_mig_state = + to_ib_mig_state((be32_to_cpu(context->flags) >> 11) & 0x3); + qp_attr->qkey = be32_to_cpu(context->qkey); + qp_attr->rq_psn = be32_to_cpu(context->rnr_nextrecvpsn) & 0xffffff; + qp_attr->sq_psn = be32_to_cpu(context->next_send_psn) & 0xffffff; + qp_attr->dest_qp_num = be32_to_cpu(context->remote_qpn) & 0xffffff; + qp_attr->qp_access_flags = + to_ib_qp_access_flags(be32_to_cpu(context->params2)); + + if (qp->transport == RC || qp->transport == UC) { + to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path); + to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path); + qp_attr->alt_pkey_index = + be32_to_cpu(context->alt_path.port_pkey) & 0x7f; + qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num; + } + + qp_attr->pkey_index = be32_to_cpu(context->pri_path.port_pkey) & 0x7f; + qp_attr->port_num = + (be32_to_cpu(context->pri_path.port_pkey) >> 24) & 0x3; + + /* qp_attr->en_sqd_async_notify is only applicable in modify qp */ + qp_attr->sq_draining = mthca_state == MTHCA_QP_STATE_DRAINING; + + qp_attr->max_rd_atomic = 1 << ((be32_to_cpu(context->params1) >> 21) & 0x7); + + qp_attr->max_dest_rd_atomic = + 1 << ((be32_to_cpu(context->params2) >> 21) & 0x7); + qp_attr->min_rnr_timer = + (be32_to_cpu(context->rnr_nextrecvpsn) >> 24) & 0x1f; + qp_attr->timeout = context->pri_path.ackto >> 3; + qp_attr->retry_cnt = (be32_to_cpu(context->params1) >> 16) & 0x7; + qp_attr->rnr_retry = context->pri_path.rnr_retry >> 5; + qp_attr->alt_timeout = context->alt_path.ackto >> 3; + +done: + qp_attr->cur_qp_state = qp_attr->qp_state; + qp_attr->cap.max_send_wr = qp->sq.max; + qp_attr->cap.max_recv_wr = qp->rq.max; + qp_attr->cap.max_send_sge = qp->sq.max_gs; + qp_attr->cap.max_recv_sge = qp->rq.max_gs; + qp_attr->cap.max_inline_data = qp->max_inline_data; + + qp_init_attr->cap = qp_attr->cap; + +out_mailbox: + mthca_free_mailbox(dev, mailbox); + +out: + mutex_unlock(&qp->mutex); + return err; +} + +static int mthca_path_set(struct mthca_dev *dev, const struct ib_ah_attr *ah, + struct mthca_qp_path *path, u8 port) +{ + path->g_mylmc = ah->src_path_bits & 0x7f; + path->rlid = cpu_to_be16(ah->dlid); + path->static_rate = mthca_get_rate(dev, ah->static_rate, port); + + if (ah->ah_flags & IB_AH_GRH) { + if (ah->grh.sgid_index >= dev->limits.gid_table_len) { + mthca_dbg(dev, "sgid_index (%u) too large. max is %d\n", + ah->grh.sgid_index, dev->limits.gid_table_len-1); + return -1; + } + + path->g_mylmc |= 1 << 7; + path->mgid_index = ah->grh.sgid_index; + path->hop_limit = ah->grh.hop_limit; + path->sl_tclass_flowlabel = + cpu_to_be32((ah->sl << 28) | + (ah->grh.traffic_class << 20) | + (ah->grh.flow_label)); + memcpy(path->rgid, ah->grh.dgid.raw, 16); + } else + path->sl_tclass_flowlabel = cpu_to_be32(ah->sl << 28); + + return 0; +} + +static int __mthca_modify_qp(struct ib_qp *ibqp, + const struct ib_qp_attr *attr, int attr_mask, + enum ib_qp_state cur_state, enum ib_qp_state new_state) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_qp *qp = to_mqp(ibqp); + struct mthca_mailbox *mailbox; + struct mthca_qp_param *qp_param; + struct mthca_qp_context *qp_context; + u32 sqd_event = 0; + u8 status; + int err = -EINVAL; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto out; + } + qp_param = mailbox->buf; + qp_context = &qp_param->context; + memset(qp_param, 0, sizeof *qp_param); + + qp_context->flags = cpu_to_be32((to_mthca_state(new_state) << 28) | + (to_mthca_st(qp->transport) << 16)); + qp_context->flags |= cpu_to_be32(MTHCA_QP_BIT_DE); + if (!(attr_mask & IB_QP_PATH_MIG_STATE)) + qp_context->flags |= cpu_to_be32(MTHCA_QP_PM_MIGRATED << 11); + else { + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PM_STATE); + switch (attr->path_mig_state) { + case IB_MIG_MIGRATED: + qp_context->flags |= cpu_to_be32(MTHCA_QP_PM_MIGRATED << 11); + break; + case IB_MIG_REARM: + qp_context->flags |= cpu_to_be32(MTHCA_QP_PM_REARM << 11); + break; + case IB_MIG_ARMED: + qp_context->flags |= cpu_to_be32(MTHCA_QP_PM_ARMED << 11); + break; + } + } + + /* leave tavor_sched_queue as 0 */ + + if (qp->transport == MLX || qp->transport == UD) + qp_context->mtu_msgmax = (IB_MTU_2048 << 5) | 11; + else if (attr_mask & IB_QP_PATH_MTU) { + if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_2048) { + mthca_dbg(dev, "path MTU (%u) is invalid\n", + attr->path_mtu); + goto out_mailbox; + } + qp_context->mtu_msgmax = (attr->path_mtu << 5) | 31; + } + + if (mthca_is_memfree(dev)) { + if (qp->rq.max) + qp_context->rq_size_stride = ilog2(qp->rq.max) << 3; + qp_context->rq_size_stride |= qp->rq.wqe_shift - 4; + + if (qp->sq.max) + qp_context->sq_size_stride = ilog2(qp->sq.max) << 3; + qp_context->sq_size_stride |= qp->sq.wqe_shift - 4; + } + + /* leave arbel_sched_queue as 0 */ + + if (qp->ibqp.uobject) + qp_context->usr_page = + cpu_to_be32(to_mucontext(qp->ibqp.uobject->context)->uar.index); + else + qp_context->usr_page = cpu_to_be32(dev->driver_uar.index); + qp_context->local_qpn = cpu_to_be32(qp->qpn); + if (attr_mask & IB_QP_DEST_QPN) { + qp_context->remote_qpn = cpu_to_be32(attr->dest_qp_num); + } + + if (qp->transport == MLX) + qp_context->pri_path.port_pkey |= + cpu_to_be32(qp->port << 24); + else { + if (attr_mask & IB_QP_PORT) { + qp_context->pri_path.port_pkey |= + cpu_to_be32(attr->port_num << 24); + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PORT_NUM); + } + } + + if (attr_mask & IB_QP_PKEY_INDEX) { + qp_context->pri_path.port_pkey |= + cpu_to_be32(attr->pkey_index); + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PKEY_INDEX); + } + + if (attr_mask & IB_QP_RNR_RETRY) { + qp_context->alt_path.rnr_retry = qp_context->pri_path.rnr_retry = + attr->rnr_retry << 5; + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_RETRY | + MTHCA_QP_OPTPAR_ALT_RNR_RETRY); + } + + if (attr_mask & IB_QP_AV) { + if (mthca_path_set(dev, &attr->ah_attr, &qp_context->pri_path, + attr_mask & IB_QP_PORT ? attr->port_num : qp->port)) + goto out_mailbox; + + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH); + } + + if (ibqp->qp_type == IB_QPT_RC && + cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) { + u8 sched_queue = ibqp->uobject ? 0x2 : 0x1; + + if (mthca_is_memfree(dev)) + qp_context->rlkey_arbel_sched_queue |= sched_queue; + else + qp_context->tavor_sched_queue |= cpu_to_be32(sched_queue); + + qp_param->opt_param_mask |= + cpu_to_be32(MTHCA_QP_OPTPAR_SCHED_QUEUE); + } + + if (attr_mask & IB_QP_TIMEOUT) { + qp_context->pri_path.ackto = attr->timeout << 3; + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ACK_TIMEOUT); + } + + if (attr_mask & IB_QP_ALT_PATH) { + if (attr->alt_pkey_index >= dev->limits.pkey_table_len) { + mthca_dbg(dev, "Alternate P_Key index (%u) too large. max is %d\n", + attr->alt_pkey_index, dev->limits.pkey_table_len-1); + goto out_mailbox; + } + + if (attr->alt_port_num == 0 || attr->alt_port_num > dev->limits.num_ports) { + mthca_dbg(dev, "Alternate port number (%u) is invalid\n", + attr->alt_port_num); + goto out_mailbox; + } + + if (mthca_path_set(dev, &attr->alt_ah_attr, &qp_context->alt_path, + attr->alt_ah_attr.port_num)) + goto out_mailbox; + + qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index | + attr->alt_port_num << 24); + qp_context->alt_path.ackto = attr->alt_timeout << 3; + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ALT_ADDR_PATH); + } + + /* leave rdd as 0 */ + qp_context->pd = cpu_to_be32(to_mpd(ibqp->pd)->pd_num); + /* leave wqe_base as 0 (we always create an MR based at 0 for WQs) */ + qp_context->wqe_lkey = cpu_to_be32(qp->mr.ibmr.lkey); + qp_context->params1 = cpu_to_be32((MTHCA_ACK_REQ_FREQ << 28) | + (MTHCA_FLIGHT_LIMIT << 24) | + MTHCA_QP_BIT_SWE); + if (qp->sq_policy == IB_SIGNAL_ALL_WR) + qp_context->params1 |= cpu_to_be32(MTHCA_QP_BIT_SSC); + if (attr_mask & IB_QP_RETRY_CNT) { + qp_context->params1 |= cpu_to_be32(attr->retry_cnt << 16); + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RETRY_COUNT); + } + + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) { + if (attr->max_rd_atomic) { + qp_context->params1 |= + cpu_to_be32(MTHCA_QP_BIT_SRE | + MTHCA_QP_BIT_SAE); + qp_context->params1 |= + cpu_to_be32(fls(attr->max_rd_atomic - 1) << 21); + } + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_SRA_MAX); + } + + if (attr_mask & IB_QP_SQ_PSN) + qp_context->next_send_psn = cpu_to_be32(attr->sq_psn); + qp_context->cqn_snd = cpu_to_be32(to_mcq(ibqp->send_cq)->cqn); + + if (mthca_is_memfree(dev)) { + qp_context->snd_wqe_base_l = cpu_to_be32(qp->send_wqe_offset); + qp_context->snd_db_index = cpu_to_be32(qp->sq.db_index); + } + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) { + if (attr->max_dest_rd_atomic) + qp_context->params2 |= + cpu_to_be32(fls(attr->max_dest_rd_atomic - 1) << 21); + + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRA_MAX); + } + + if (attr_mask & (IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC)) { + qp_context->params2 |= get_hw_access_flags(qp, attr, attr_mask); + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RWE | + MTHCA_QP_OPTPAR_RRE | + MTHCA_QP_OPTPAR_RAE); + } + + qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC); + + if (ibqp->srq) + qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RIC); + + if (attr_mask & IB_QP_MIN_RNR_TIMER) { + qp_context->rnr_nextrecvpsn |= cpu_to_be32(attr->min_rnr_timer << 24); + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RNR_TIMEOUT); + } + if (attr_mask & IB_QP_RQ_PSN) + qp_context->rnr_nextrecvpsn |= cpu_to_be32(attr->rq_psn); + + qp_context->ra_buff_indx = + cpu_to_be32(dev->qp_table.rdb_base + + ((qp->qpn & (dev->limits.num_qps - 1)) * MTHCA_RDB_ENTRY_SIZE << + dev->qp_table.rdb_shift)); + + qp_context->cqn_rcv = cpu_to_be32(to_mcq(ibqp->recv_cq)->cqn); + + if (mthca_is_memfree(dev)) + qp_context->rcv_db_index = cpu_to_be32(qp->rq.db_index); + + if (attr_mask & IB_QP_QKEY) { + qp_context->qkey = cpu_to_be32(attr->qkey); + qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_Q_KEY); + } + + if (ibqp->srq) + qp_context->srqn = cpu_to_be32(1 << 24 | + to_msrq(ibqp->srq)->srqn); + + if (cur_state == IB_QPS_RTS && new_state == IB_QPS_SQD && + attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY && + attr->en_sqd_async_notify) + sqd_event = 1 << 31; + + err = mthca_MODIFY_QP(dev, cur_state, new_state, qp->qpn, 0, + mailbox, sqd_event, &status); + if (err) + goto out_mailbox; + if (status) { + mthca_warn(dev, "modify QP %d->%d returned status %02x.\n", + cur_state, new_state, status); + err = -EINVAL; + goto out_mailbox; + } + + qp->state = new_state; + if (attr_mask & IB_QP_ACCESS_FLAGS) + qp->atomic_rd_en = attr->qp_access_flags; + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) + qp->resp_depth = attr->max_dest_rd_atomic; + if (attr_mask & IB_QP_PORT) + qp->port = attr->port_num; + if (attr_mask & IB_QP_ALT_PATH) + qp->alt_port = attr->alt_port_num; + + if (is_sqp(dev, qp)) + store_attrs(to_msqp(qp), attr, attr_mask); + + /* + * If we moved QP0 to RTR, bring the IB link up; if we moved + * QP0 to RESET or ERROR, bring the link back down. + */ + if (is_qp0(dev, qp)) { + if (cur_state != IB_QPS_RTR && + new_state == IB_QPS_RTR) + init_port(dev, qp->port); + + if (cur_state != IB_QPS_RESET && + cur_state != IB_QPS_ERR && + (new_state == IB_QPS_RESET || + new_state == IB_QPS_ERR)) + mthca_CLOSE_IB(dev, qp->port, &status); + } + + /* + * If we moved a kernel QP to RESET, clean up all old CQ + * entries and reinitialize the QP. + */ + if (new_state == IB_QPS_RESET && !qp->ibqp.uobject) { + mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn, + qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); + if (qp->ibqp.send_cq != qp->ibqp.recv_cq) + mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn, NULL); + + mthca_wq_reset(&qp->sq); + qp->sq.last = get_send_wqe(qp, qp->sq.max - 1); + + mthca_wq_reset(&qp->rq); + qp->rq.last = get_recv_wqe(qp, qp->rq.max - 1); + + if (mthca_is_memfree(dev)) { + *qp->sq.db = 0; + *qp->rq.db = 0; + } + } + +out_mailbox: + mthca_free_mailbox(dev, mailbox); +out: + return err; +} + +int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, + struct ib_udata *udata) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_qp *qp = to_mqp(ibqp); + enum ib_qp_state cur_state, new_state; + int err = -EINVAL; + + mutex_lock(&qp->mutex); + if (attr_mask & IB_QP_CUR_STATE) { + cur_state = attr->cur_qp_state; + } else { + spin_lock_irq(&qp->sq.lock); + spin_lock(&qp->rq.lock); + cur_state = qp->state; + spin_unlock(&qp->rq.lock); + spin_unlock_irq(&qp->sq.lock); + } + + new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state; + + if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, attr_mask)) { + mthca_dbg(dev, "Bad QP transition (transport %d) " + "%d->%d with attr 0x%08x\n", + qp->transport, cur_state, new_state, + attr_mask); + goto out; + } + + if ((attr_mask & IB_QP_PKEY_INDEX) && + attr->pkey_index >= dev->limits.pkey_table_len) { + mthca_dbg(dev, "P_Key index (%u) too large. max is %d\n", + attr->pkey_index, dev->limits.pkey_table_len-1); + goto out; + } + + if ((attr_mask & IB_QP_PORT) && + (attr->port_num == 0 || attr->port_num > dev->limits.num_ports)) { + mthca_dbg(dev, "Port number (%u) is invalid\n", attr->port_num); + goto out; + } + + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && + attr->max_rd_atomic > dev->limits.max_qp_init_rdma) { + mthca_dbg(dev, "Max rdma_atomic as initiator %u too large (max is %d)\n", + attr->max_rd_atomic, dev->limits.max_qp_init_rdma); + goto out; + } + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && + attr->max_dest_rd_atomic > 1 << dev->qp_table.rdb_shift) { + mthca_dbg(dev, "Max rdma_atomic as responder %u too large (max %d)\n", + attr->max_dest_rd_atomic, 1 << dev->qp_table.rdb_shift); + goto out; + } + + if (cur_state == new_state && cur_state == IB_QPS_RESET) { + err = 0; + goto out; + } + + err = __mthca_modify_qp(ibqp, attr, attr_mask, cur_state, new_state); + +out: + mutex_unlock(&qp->mutex); + return err; +} + +static int mthca_max_data_size(struct mthca_dev *dev, struct mthca_qp *qp, int desc_sz) +{ + /* + * Calculate the maximum size of WQE s/g segments, excluding + * the next segment and other non-data segments. + */ + int max_data_size = desc_sz - sizeof (struct mthca_next_seg); + + switch (qp->transport) { + case MLX: + max_data_size -= 2 * sizeof (struct mthca_data_seg); + break; + + case UD: + if (mthca_is_memfree(dev)) + max_data_size -= sizeof (struct mthca_arbel_ud_seg); + else + max_data_size -= sizeof (struct mthca_tavor_ud_seg); + break; + + default: + max_data_size -= sizeof (struct mthca_raddr_seg); + break; + } + + return max_data_size; +} + +static inline int mthca_max_inline_data(struct mthca_pd *pd, int max_data_size) +{ + /* We don't support inline data for kernel QPs (yet). */ + return pd->ibpd.uobject ? max_data_size - MTHCA_INLINE_HEADER_SIZE : 0; +} + +static void mthca_adjust_qp_caps(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_qp *qp) +{ + int max_data_size = mthca_max_data_size(dev, qp, + min(dev->limits.max_desc_sz, + 1 << qp->sq.wqe_shift)); + + qp->max_inline_data = mthca_max_inline_data(pd, max_data_size); + + qp->sq.max_gs = min_t(int, dev->limits.max_sg, + max_data_size / sizeof (struct mthca_data_seg)); + qp->rq.max_gs = min_t(int, dev->limits.max_sg, + (min(dev->limits.max_desc_sz, 1 << qp->rq.wqe_shift) - + sizeof (struct mthca_next_seg)) / + sizeof (struct mthca_data_seg)); +} + +/* + * Allocate and register buffer for WQEs. qp->rq.max, sq.max, + * rq.max_gs and sq.max_gs must all be assigned. + * mthca_alloc_wqe_buf will calculate rq.wqe_shift and + * sq.wqe_shift (as well as send_wqe_offset, is_direct, and + * queue) + */ +static int mthca_alloc_wqe_buf(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_qp *qp) +{ + int size; + int err = -ENOMEM; + + size = sizeof (struct mthca_next_seg) + + qp->rq.max_gs * sizeof (struct mthca_data_seg); + + if (size > dev->limits.max_desc_sz) + return -EINVAL; + + for (qp->rq.wqe_shift = 6; 1 << qp->rq.wqe_shift < size; + qp->rq.wqe_shift++) + ; /* nothing */ + + size = qp->sq.max_gs * sizeof (struct mthca_data_seg); + switch (qp->transport) { + case MLX: + size += 2 * sizeof (struct mthca_data_seg); + break; + + case UD: + size += mthca_is_memfree(dev) ? + sizeof (struct mthca_arbel_ud_seg) : + sizeof (struct mthca_tavor_ud_seg); + break; + + case UC: + size += sizeof (struct mthca_raddr_seg); + break; + + case RC: + size += sizeof (struct mthca_raddr_seg); + /* + * An atomic op will require an atomic segment, a + * remote address segment and one scatter entry. + */ + size = max_t(int, size, + sizeof (struct mthca_atomic_seg) + + sizeof (struct mthca_raddr_seg) + + sizeof (struct mthca_data_seg)); + break; + + default: + break; + } + + /* Make sure that we have enough space for a bind request */ + size = max_t(int, size, sizeof (struct mthca_bind_seg)); + + size += sizeof (struct mthca_next_seg); + + if (size > dev->limits.max_desc_sz) + return -EINVAL; + + for (qp->sq.wqe_shift = 6; 1 << qp->sq.wqe_shift < size; + qp->sq.wqe_shift++) + ; /* nothing */ + + qp->send_wqe_offset = ALIGN(qp->rq.max << qp->rq.wqe_shift, + 1 << qp->sq.wqe_shift); + + /* + * If this is a userspace QP, we don't actually have to + * allocate anything. All we need is to calculate the WQE + * sizes and the send_wqe_offset, so we're done now. + */ + if (pd->ibpd.uobject) + return 0; + + size = PAGE_ALIGN(qp->send_wqe_offset + + (qp->sq.max << qp->sq.wqe_shift)); + + qp->wrid = kmalloc((qp->rq.max + qp->sq.max) * sizeof (u64), + GFP_KERNEL); + if (!qp->wrid) + goto err_out; + + err = mthca_buf_alloc(dev, size, MTHCA_MAX_DIRECT_QP_SIZE, + &qp->queue, &qp->is_direct, pd, 0, &qp->mr); + if (err) + goto err_out; + + return 0; + +err_out: + kfree(qp->wrid); + return err; +} + +static void mthca_free_wqe_buf(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + mthca_buf_free(dev, PAGE_ALIGN(qp->send_wqe_offset + + (qp->sq.max << qp->sq.wqe_shift)), + &qp->queue, qp->is_direct, &qp->mr); + kfree(qp->wrid); +} + +static int mthca_map_memfree(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + int ret; + + if (mthca_is_memfree(dev)) { + ret = mthca_table_get(dev, dev->qp_table.qp_table, qp->qpn); + if (ret) + return ret; + + ret = mthca_table_get(dev, dev->qp_table.eqp_table, qp->qpn); + if (ret) + goto err_qpc; + + ret = mthca_table_get(dev, dev->qp_table.rdb_table, + qp->qpn << dev->qp_table.rdb_shift); + if (ret) + goto err_eqpc; + + } + + return 0; + +err_eqpc: + mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn); + +err_qpc: + mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn); + + return ret; +} + +static void mthca_unmap_memfree(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + mthca_table_put(dev, dev->qp_table.rdb_table, + qp->qpn << dev->qp_table.rdb_shift); + mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn); + mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn); +} + +static int mthca_alloc_memfree(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + if (mthca_is_memfree(dev)) { + qp->rq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_RQ, + qp->qpn, &qp->rq.db); + if (qp->rq.db_index < 0) + return -ENOMEM; + + qp->sq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SQ, + qp->qpn, &qp->sq.db); + if (qp->sq.db_index < 0) { + mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index); + return -ENOMEM; + } + } + + return 0; +} + +static void mthca_free_memfree(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + if (mthca_is_memfree(dev)) { + mthca_free_db(dev, MTHCA_DB_TYPE_SQ, qp->sq.db_index); + mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index); + } +} + +static int mthca_alloc_qp_common(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_cq *send_cq, + struct mthca_cq *recv_cq, + enum ib_sig_type send_policy, + struct mthca_qp *qp) +{ + int ret; + int i; + struct mthca_next_seg *next; + + qp->refcount = 1; + init_waitqueue_head(&qp->wait); + mutex_init(&qp->mutex); + qp->state = IB_QPS_RESET; + qp->atomic_rd_en = 0; + qp->resp_depth = 0; + qp->sq_policy = send_policy; + mthca_wq_reset(&qp->sq); + mthca_wq_reset(&qp->rq); + + spin_lock_init(&qp->sq.lock); + spin_lock_init(&qp->rq.lock); + + ret = mthca_map_memfree(dev, qp); + if (ret) + return ret; + + ret = mthca_alloc_wqe_buf(dev, pd, qp); + if (ret) { + mthca_unmap_memfree(dev, qp); + return ret; + } + + mthca_adjust_qp_caps(dev, pd, qp); + + /* + * If this is a userspace QP, we're done now. The doorbells + * will be allocated and buffers will be initialized in + * userspace. + */ + if (pd->ibpd.uobject) + return 0; + + ret = mthca_alloc_memfree(dev, qp); + if (ret) { + mthca_free_wqe_buf(dev, qp); + mthca_unmap_memfree(dev, qp); + return ret; + } + + if (mthca_is_memfree(dev)) { + struct mthca_data_seg *scatter; + int size = (sizeof (struct mthca_next_seg) + + qp->rq.max_gs * sizeof (struct mthca_data_seg)) / 16; + + for (i = 0; i < qp->rq.max; ++i) { + next = get_recv_wqe(qp, i); + next->nda_op = cpu_to_be32(((i + 1) & (qp->rq.max - 1)) << + qp->rq.wqe_shift); + next->ee_nds = cpu_to_be32(size); + + for (scatter = (void *) (next + 1); + (void *) scatter < (void *) next + (1 << qp->rq.wqe_shift); + ++scatter) + scatter->lkey = cpu_to_be32(MTHCA_INVAL_LKEY); + } + + for (i = 0; i < qp->sq.max; ++i) { + next = get_send_wqe(qp, i); + next->nda_op = cpu_to_be32((((i + 1) & (qp->sq.max - 1)) << + qp->sq.wqe_shift) + + qp->send_wqe_offset); + } + } else { + for (i = 0; i < qp->rq.max; ++i) { + next = get_recv_wqe(qp, i); + next->nda_op = htonl((((i + 1) % qp->rq.max) << + qp->rq.wqe_shift) | 1); + } + + } + + qp->sq.last = get_send_wqe(qp, qp->sq.max - 1); + qp->rq.last = get_recv_wqe(qp, qp->rq.max - 1); + + return 0; +} + +static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap, + struct mthca_pd *pd, struct mthca_qp *qp) +{ + int max_data_size = mthca_max_data_size(dev, qp, dev->limits.max_desc_sz); + u32 max_inline_data; + + /* Sanity check QP size before proceeding */ + if (cap->max_send_wr > dev->limits.max_wqes || + cap->max_recv_wr > dev->limits.max_wqes || + cap->max_send_sge > dev->limits.max_sg || + cap->max_recv_sge > dev->limits.max_sg) + return -EINVAL; + + if (pd->ibpd.uobject && + cap->max_inline_data > mthca_max_inline_data(pd, max_data_size)) + return -EINVAL; + + max_inline_data = pd->ibpd.uobject ? cap->max_inline_data : 0; + + /* + * For MLX transport we need 2 extra send gather entries: + * one for the header and one for the checksum at the end + */ + if (qp->transport == MLX && cap->max_send_sge + 2 > dev->limits.max_sg) + return -EINVAL; + + if (mthca_is_memfree(dev)) { + qp->rq.max = cap->max_recv_wr ? + roundup_pow_of_two(cap->max_recv_wr) : 0; + qp->sq.max = cap->max_send_wr ? + roundup_pow_of_two(cap->max_send_wr) : 0; + } else { + qp->rq.max = cap->max_recv_wr; + qp->sq.max = cap->max_send_wr; + } + + qp->rq.max_gs = cap->max_recv_sge; + qp->sq.max_gs = max_t(int, cap->max_send_sge, + ALIGN(max_inline_data + MTHCA_INLINE_HEADER_SIZE, + MTHCA_INLINE_CHUNK_SIZE) / + sizeof (struct mthca_data_seg)); + + return 0; +} + +int mthca_alloc_qp(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_cq *send_cq, + struct mthca_cq *recv_cq, + enum ib_qp_type type, + enum ib_sig_type send_policy, + struct ib_qp_cap *cap, + struct mthca_qp *qp) +{ + int err; + + switch (type) { + case IB_QPT_RC: qp->transport = RC; break; + case IB_QPT_UC: qp->transport = UC; break; + case IB_QPT_UD: qp->transport = UD; break; + default: return -EINVAL; + } + + err = mthca_set_qp_size(dev, cap, pd, qp); + if (err) + return err; + + qp->qpn = mthca_alloc(&dev->qp_table.alloc); + if (qp->qpn == -1) + return -ENOMEM; + + /* initialize port to zero for error-catching. */ + qp->port = 0; + + err = mthca_alloc_qp_common(dev, pd, send_cq, recv_cq, + send_policy, qp); + if (err) { + mthca_free(&dev->qp_table.alloc, qp->qpn); + return err; + } + + spin_lock_irq(&dev->qp_table.lock); + mthca_array_set(&dev->qp_table.qp, + qp->qpn & (dev->limits.num_qps - 1), qp); + spin_unlock_irq(&dev->qp_table.lock); + + return 0; +} + +static void mthca_lock_cqs(struct mthca_cq *send_cq, struct mthca_cq *recv_cq) +{ + if (send_cq == recv_cq) + spin_lock_irq(&send_cq->lock); + else if (send_cq->cqn < recv_cq->cqn) { + spin_lock_irq(&send_cq->lock); + spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING); + } else { + spin_lock_irq(&recv_cq->lock); + spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING); + } +} + +static void mthca_unlock_cqs(struct mthca_cq *send_cq, struct mthca_cq *recv_cq) +{ + if (send_cq == recv_cq) + spin_unlock_irq(&send_cq->lock); + else if (send_cq->cqn < recv_cq->cqn) { + spin_unlock(&recv_cq->lock); + spin_unlock_irq(&send_cq->lock); + } else { + spin_unlock(&send_cq->lock); + spin_unlock_irq(&recv_cq->lock); + } +} + +int mthca_alloc_sqp(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_cq *send_cq, + struct mthca_cq *recv_cq, + enum ib_sig_type send_policy, + struct ib_qp_cap *cap, + int qpn, + int port, + struct mthca_sqp *sqp) +{ + u32 mqpn = qpn * 2 + dev->qp_table.sqp_start + port - 1; + int err; + + sqp->qp.transport = MLX; + err = mthca_set_qp_size(dev, cap, pd, &sqp->qp); + if (err) + return err; + + sqp->header_buf_size = sqp->qp.sq.max * MTHCA_UD_HEADER_SIZE; + sqp->header_buf = dma_alloc_coherent(&dev->pdev->dev, sqp->header_buf_size, + &sqp->header_dma, GFP_KERNEL); + if (!sqp->header_buf) + return -ENOMEM; + + spin_lock_irq(&dev->qp_table.lock); + if (mthca_array_get(&dev->qp_table.qp, mqpn)) + err = -EBUSY; + else + mthca_array_set(&dev->qp_table.qp, mqpn, sqp); + spin_unlock_irq(&dev->qp_table.lock); + + if (err) + goto err_out; + + sqp->qp.port = port; + sqp->qp.qpn = mqpn; + sqp->qp.transport = MLX; + + err = mthca_alloc_qp_common(dev, pd, send_cq, recv_cq, + send_policy, &sqp->qp); + if (err) + goto err_out_free; + + atomic_inc(&pd->sqp_count); + + return 0; + + err_out_free: + /* + * Lock CQs here, so that CQ polling code can do QP lookup + * without taking a lock. + */ + mthca_lock_cqs(send_cq, recv_cq); + + spin_lock(&dev->qp_table.lock); + mthca_array_clear(&dev->qp_table.qp, mqpn); + spin_unlock(&dev->qp_table.lock); + + mthca_unlock_cqs(send_cq, recv_cq); + + err_out: + dma_free_coherent(&dev->pdev->dev, sqp->header_buf_size, + sqp->header_buf, sqp->header_dma); + + return err; +} + +static inline int get_qp_refcount(struct mthca_dev *dev, struct mthca_qp *qp) +{ + int c; + + spin_lock_irq(&dev->qp_table.lock); + c = qp->refcount; + spin_unlock_irq(&dev->qp_table.lock); + + return c; +} + +void mthca_free_qp(struct mthca_dev *dev, + struct mthca_qp *qp) +{ + u8 status; + struct mthca_cq *send_cq; + struct mthca_cq *recv_cq; + + send_cq = to_mcq(qp->ibqp.send_cq); + recv_cq = to_mcq(qp->ibqp.recv_cq); + + /* + * Lock CQs here, so that CQ polling code can do QP lookup + * without taking a lock. + */ + mthca_lock_cqs(send_cq, recv_cq); + + spin_lock(&dev->qp_table.lock); + mthca_array_clear(&dev->qp_table.qp, + qp->qpn & (dev->limits.num_qps - 1)); + --qp->refcount; + spin_unlock(&dev->qp_table.lock); + + mthca_unlock_cqs(send_cq, recv_cq); + + wait_event(qp->wait, !get_qp_refcount(dev, qp)); + + if (qp->state != IB_QPS_RESET) + mthca_MODIFY_QP(dev, qp->state, IB_QPS_RESET, qp->qpn, 0, + NULL, 0, &status); + + /* + * If this is a userspace QP, the buffers, MR, CQs and so on + * will be cleaned up in userspace, so all we have to do is + * unref the mem-free tables and free the QPN in our table. + */ + if (!qp->ibqp.uobject) { + mthca_cq_clean(dev, recv_cq, qp->qpn, + qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL); + if (send_cq != recv_cq) + mthca_cq_clean(dev, send_cq, qp->qpn, NULL); + + mthca_free_memfree(dev, qp); + mthca_free_wqe_buf(dev, qp); + } + + mthca_unmap_memfree(dev, qp); + + if (is_sqp(dev, qp)) { + atomic_dec(&(to_mpd(qp->ibqp.pd)->sqp_count)); + dma_free_coherent(&dev->pdev->dev, + to_msqp(qp)->header_buf_size, + to_msqp(qp)->header_buf, + to_msqp(qp)->header_dma); + } else + mthca_free(&dev->qp_table.alloc, qp->qpn); +} + +/* Create UD header for an MLX send and build a data segment for it */ +static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp, + int ind, struct ib_send_wr *wr, + struct mthca_mlx_seg *mlx, + struct mthca_data_seg *data) +{ + int header_size; + int err; + u16 pkey; + + ib_ud_header_init(256, /* assume a MAD */ + 1, 0, 0, + mthca_ah_grh_present(to_mah(wr->wr.ud.ah)), + 0, + &sqp->ud_header); + + err = mthca_read_ah(dev, to_mah(wr->wr.ud.ah), &sqp->ud_header); + if (err) + return err; + mlx->flags &= ~cpu_to_be32(MTHCA_NEXT_SOLICIT | 1); + mlx->flags |= cpu_to_be32((!sqp->qp.ibqp.qp_num ? MTHCA_MLX_VL15 : 0) | + (sqp->ud_header.lrh.destination_lid == + IB_LID_PERMISSIVE ? MTHCA_MLX_SLR : 0) | + (sqp->ud_header.lrh.service_level << 8)); + mlx->rlid = sqp->ud_header.lrh.destination_lid; + mlx->vcrc = 0; + + switch (wr->opcode) { + case IB_WR_SEND: + sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY; + sqp->ud_header.immediate_present = 0; + break; + case IB_WR_SEND_WITH_IMM: + sqp->ud_header.bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE; + sqp->ud_header.immediate_present = 1; + sqp->ud_header.immediate_data = wr->ex.imm_data; + break; + default: + return -EINVAL; + } + + sqp->ud_header.lrh.virtual_lane = !sqp->qp.ibqp.qp_num ? 15 : 0; + if (sqp->ud_header.lrh.destination_lid == IB_LID_PERMISSIVE) + sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE; + sqp->ud_header.bth.solicited_event = !!(wr->send_flags & IB_SEND_SOLICITED); + if (!sqp->qp.ibqp.qp_num) + ib_get_cached_pkey(&dev->ib_dev, sqp->qp.port, + sqp->pkey_index, &pkey); + else + ib_get_cached_pkey(&dev->ib_dev, sqp->qp.port, + wr->wr.ud.pkey_index, &pkey); + sqp->ud_header.bth.pkey = cpu_to_be16(pkey); + sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->wr.ud.remote_qpn); + sqp->ud_header.bth.psn = cpu_to_be32((sqp->send_psn++) & ((1 << 24) - 1)); + sqp->ud_header.deth.qkey = cpu_to_be32(wr->wr.ud.remote_qkey & 0x80000000 ? + sqp->qkey : wr->wr.ud.remote_qkey); + sqp->ud_header.deth.source_qpn = cpu_to_be32(sqp->qp.ibqp.qp_num); + + header_size = ib_ud_header_pack(&sqp->ud_header, + sqp->header_buf + + ind * MTHCA_UD_HEADER_SIZE); + + data->byte_count = cpu_to_be32(header_size); + data->lkey = cpu_to_be32(to_mpd(sqp->qp.ibqp.pd)->ntmr.ibmr.lkey); + data->addr = cpu_to_be64(sqp->header_dma + + ind * MTHCA_UD_HEADER_SIZE); + + return 0; +} + +static inline int mthca_wq_overflow(struct mthca_wq *wq, int nreq, + struct ib_cq *ib_cq) +{ + unsigned cur; + struct mthca_cq *cq; + + cur = wq->head - wq->tail; + if (likely(cur + nreq < wq->max)) + return 0; + + cq = to_mcq(ib_cq); + spin_lock(&cq->lock); + cur = wq->head - wq->tail; + spin_unlock(&cq->lock); + + return cur + nreq >= wq->max; +} + +static __always_inline void set_raddr_seg(struct mthca_raddr_seg *rseg, + u64 remote_addr, u32 rkey) +{ + rseg->raddr = cpu_to_be64(remote_addr); + rseg->rkey = cpu_to_be32(rkey); + rseg->reserved = 0; +} + +static __always_inline void set_atomic_seg(struct mthca_atomic_seg *aseg, + struct ib_send_wr *wr) +{ + if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) { + aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap); + aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add); + } else { + aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add); + aseg->compare = 0; + } + +} + +static void set_tavor_ud_seg(struct mthca_tavor_ud_seg *useg, + struct ib_send_wr *wr) +{ + useg->lkey = cpu_to_be32(to_mah(wr->wr.ud.ah)->key); + useg->av_addr = cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma); + useg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn); + useg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey); + +} + +static void set_arbel_ud_seg(struct mthca_arbel_ud_seg *useg, + struct ib_send_wr *wr) +{ + memcpy(useg->av, to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE); + useg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn); + useg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey); +} + +int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_qp *qp = to_mqp(ibqp); + void *wqe; + void *prev_wqe; + unsigned long flags; + int err = 0; + int nreq; + int i; + int size; + /* + * f0 and size0 are only used if nreq != 0, and they will + * always be initialized the first time through the main loop + * before nreq is incremented. So nreq cannot become non-zero + * without initializing f0 and size0, and they are in fact + * never used uninitialized. + */ + int uninitialized_var(size0); + u32 uninitialized_var(f0); + int ind; + u8 op0 = 0; + + spin_lock_irqsave(&qp->sq.lock, flags); + + /* XXX check that state is OK to post send */ + + ind = qp->sq.next_ind; + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + if (mthca_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) { + mthca_err(dev, "SQ %06x full (%u head, %u tail," + " %d max, %d nreq)\n", qp->qpn, + qp->sq.head, qp->sq.tail, + qp->sq.max, nreq); + err = -ENOMEM; + *bad_wr = wr; + goto out; + } + + wqe = get_send_wqe(qp, ind); + prev_wqe = qp->sq.last; + qp->sq.last = wqe; + + ((struct mthca_next_seg *) wqe)->nda_op = 0; + ((struct mthca_next_seg *) wqe)->ee_nds = 0; + ((struct mthca_next_seg *) wqe)->flags = + ((wr->send_flags & IB_SEND_SIGNALED) ? + cpu_to_be32(MTHCA_NEXT_CQ_UPDATE) : 0) | + ((wr->send_flags & IB_SEND_SOLICITED) ? + cpu_to_be32(MTHCA_NEXT_SOLICIT) : 0) | + cpu_to_be32(1); + if (wr->opcode == IB_WR_SEND_WITH_IMM || + wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) + ((struct mthca_next_seg *) wqe)->imm = wr->ex.imm_data; + + wqe += sizeof (struct mthca_next_seg); + size = sizeof (struct mthca_next_seg) / 16; + + switch (qp->transport) { + case RC: + switch (wr->opcode) { + case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_ATOMIC_FETCH_AND_ADD: + set_raddr_seg(wqe, wr->wr.atomic.remote_addr, + wr->wr.atomic.rkey); + wqe += sizeof (struct mthca_raddr_seg); + + set_atomic_seg(wqe, wr); + wqe += sizeof (struct mthca_atomic_seg); + size += (sizeof (struct mthca_raddr_seg) + + sizeof (struct mthca_atomic_seg)) / 16; + break; + + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + case IB_WR_RDMA_READ: + set_raddr_seg(wqe, wr->wr.rdma.remote_addr, + wr->wr.rdma.rkey); + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case UC: + switch (wr->opcode) { + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + set_raddr_seg(wqe, wr->wr.rdma.remote_addr, + wr->wr.rdma.rkey); + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case UD: + set_tavor_ud_seg(wqe, wr); + wqe += sizeof (struct mthca_tavor_ud_seg); + size += sizeof (struct mthca_tavor_ud_seg) / 16; + break; + + case MLX: + err = build_mlx_header(dev, to_msqp(qp), ind, wr, + wqe - sizeof (struct mthca_next_seg), + wqe); + if (err) { + *bad_wr = wr; + goto out; + } + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + break; + } + + if (wr->num_sge > qp->sq.max_gs) { + mthca_err(dev, "too many gathers\n"); + err = -EINVAL; + *bad_wr = wr; + goto out; + } + + for (i = 0; i < wr->num_sge; ++i) { + mthca_set_data_seg(wqe, wr->sg_list + i); + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + } + + /* Add one more inline data segment for ICRC */ + if (qp->transport == MLX) { + ((struct mthca_data_seg *) wqe)->byte_count = + cpu_to_be32((1 << 31) | 4); + ((u32 *) wqe)[1] = 0; + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + } + + qp->wrid[ind] = wr->wr_id; + + if (wr->opcode >= ARRAY_SIZE(mthca_opcode)) { + mthca_err(dev, "opcode invalid\n"); + err = -EINVAL; + *bad_wr = wr; + goto out; + } + + ((struct mthca_next_seg *) prev_wqe)->nda_op = + cpu_to_be32(((ind << qp->sq.wqe_shift) + + qp->send_wqe_offset) | + mthca_opcode[wr->opcode]); + wmb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cpu_to_be32((nreq ? 0 : MTHCA_NEXT_DBD) | size | + ((wr->send_flags & IB_SEND_FENCE) ? + MTHCA_NEXT_FENCE : 0)); + + if (!nreq) { + size0 = size; + op0 = mthca_opcode[wr->opcode]; + f0 = wr->send_flags & IB_SEND_FENCE ? + MTHCA_SEND_DOORBELL_FENCE : 0; + } + + ++ind; + if (unlikely(ind >= qp->sq.max)) + ind -= qp->sq.max; + } + +out: + if (likely(nreq)) { + wmb(); + + mthca_write64(((qp->sq.next_ind << qp->sq.wqe_shift) + + qp->send_wqe_offset) | f0 | op0, + (qp->qpn << 8) | size0, + dev->kar + MTHCA_SEND_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + /* + * Make sure doorbells don't leak out of SQ spinlock + * and reach the HCA out of order: + */ + mmiowb(); + } + + qp->sq.next_ind = ind; + qp->sq.head += nreq; + + spin_unlock_irqrestore(&qp->sq.lock, flags); + return err; +} + +int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_qp *qp = to_mqp(ibqp); + unsigned long flags; + int err = 0; + int nreq; + int i; + int size; + /* + * size0 is only used if nreq != 0, and it will always be + * initialized the first time through the main loop before + * nreq is incremented. So nreq cannot become non-zero + * without initializing size0, and it is in fact never used + * uninitialized. + */ + int uninitialized_var(size0); + int ind; + void *wqe; + void *prev_wqe; + + spin_lock_irqsave(&qp->rq.lock, flags); + + /* XXX check that state is OK to post receive */ + + ind = qp->rq.next_ind; + + for (nreq = 0; wr; wr = wr->next) { + if (mthca_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) { + mthca_err(dev, "RQ %06x full (%u head, %u tail," + " %d max, %d nreq)\n", qp->qpn, + qp->rq.head, qp->rq.tail, + qp->rq.max, nreq); + err = -ENOMEM; + *bad_wr = wr; + goto out; + } + + wqe = get_recv_wqe(qp, ind); + prev_wqe = qp->rq.last; + qp->rq.last = wqe; + + ((struct mthca_next_seg *) wqe)->ee_nds = + cpu_to_be32(MTHCA_NEXT_DBD); + ((struct mthca_next_seg *) wqe)->flags = 0; + + wqe += sizeof (struct mthca_next_seg); + size = sizeof (struct mthca_next_seg) / 16; + + if (unlikely(wr->num_sge > qp->rq.max_gs)) { + err = -EINVAL; + *bad_wr = wr; + goto out; + } + + for (i = 0; i < wr->num_sge; ++i) { + mthca_set_data_seg(wqe, wr->sg_list + i); + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + } + + qp->wrid[ind + qp->sq.max] = wr->wr_id; + + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cpu_to_be32(MTHCA_NEXT_DBD | size); + + if (!nreq) + size0 = size; + + ++ind; + if (unlikely(ind >= qp->rq.max)) + ind -= qp->rq.max; + + ++nreq; + if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) { + nreq = 0; + + wmb(); + + mthca_write64((qp->rq.next_ind << qp->rq.wqe_shift) | size0, + qp->qpn << 8, dev->kar + MTHCA_RECEIVE_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + + qp->rq.next_ind = ind; + qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB; + } + } + +out: + if (likely(nreq)) { + wmb(); + + mthca_write64((qp->rq.next_ind << qp->rq.wqe_shift) | size0, + qp->qpn << 8 | nreq, dev->kar + MTHCA_RECEIVE_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + } + + qp->rq.next_ind = ind; + qp->rq.head += nreq; + + /* + * Make sure doorbells don't leak out of RQ spinlock and reach + * the HCA out of order: + */ + mmiowb(); + + spin_unlock_irqrestore(&qp->rq.lock, flags); + return err; +} + +int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_qp *qp = to_mqp(ibqp); + u32 dbhi; + void *wqe; + void *prev_wqe; + unsigned long flags; + int err = 0; + int nreq; + int i; + int size; + /* + * f0 and size0 are only used if nreq != 0, and they will + * always be initialized the first time through the main loop + * before nreq is incremented. So nreq cannot become non-zero + * without initializing f0 and size0, and they are in fact + * never used uninitialized. + */ + int uninitialized_var(size0); + u32 uninitialized_var(f0); + int ind; + u8 op0 = 0; + + spin_lock_irqsave(&qp->sq.lock, flags); + + /* XXX check that state is OK to post send */ + + ind = qp->sq.head & (qp->sq.max - 1); + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + if (unlikely(nreq == MTHCA_ARBEL_MAX_WQES_PER_SEND_DB)) { + nreq = 0; + + dbhi = (MTHCA_ARBEL_MAX_WQES_PER_SEND_DB << 24) | + ((qp->sq.head & 0xffff) << 8) | f0 | op0; + + qp->sq.head += MTHCA_ARBEL_MAX_WQES_PER_SEND_DB; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + *qp->sq.db = cpu_to_be32(qp->sq.head & 0xffff); + + /* + * Make sure doorbell record is written before we + * write MMIO send doorbell. + */ + wmb(); + + mthca_write64(dbhi, (qp->qpn << 8) | size0, + dev->kar + MTHCA_SEND_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + } + + if (mthca_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) { + mthca_err(dev, "SQ %06x full (%u head, %u tail," + " %d max, %d nreq)\n", qp->qpn, + qp->sq.head, qp->sq.tail, + qp->sq.max, nreq); + err = -ENOMEM; + *bad_wr = wr; + goto out; + } + + wqe = get_send_wqe(qp, ind); + prev_wqe = qp->sq.last; + qp->sq.last = wqe; + + ((struct mthca_next_seg *) wqe)->flags = + ((wr->send_flags & IB_SEND_SIGNALED) ? + cpu_to_be32(MTHCA_NEXT_CQ_UPDATE) : 0) | + ((wr->send_flags & IB_SEND_SOLICITED) ? + cpu_to_be32(MTHCA_NEXT_SOLICIT) : 0) | + ((wr->send_flags & IB_SEND_IP_CSUM) ? + cpu_to_be32(MTHCA_NEXT_IP_CSUM | MTHCA_NEXT_TCP_UDP_CSUM) : 0) | + cpu_to_be32(1); + if (wr->opcode == IB_WR_SEND_WITH_IMM || + wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) + ((struct mthca_next_seg *) wqe)->imm = wr->ex.imm_data; + + wqe += sizeof (struct mthca_next_seg); + size = sizeof (struct mthca_next_seg) / 16; + + switch (qp->transport) { + case RC: + switch (wr->opcode) { + case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_ATOMIC_FETCH_AND_ADD: + set_raddr_seg(wqe, wr->wr.atomic.remote_addr, + wr->wr.atomic.rkey); + wqe += sizeof (struct mthca_raddr_seg); + + set_atomic_seg(wqe, wr); + wqe += sizeof (struct mthca_atomic_seg); + size += (sizeof (struct mthca_raddr_seg) + + sizeof (struct mthca_atomic_seg)) / 16; + break; + + case IB_WR_RDMA_READ: + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + set_raddr_seg(wqe, wr->wr.rdma.remote_addr, + wr->wr.rdma.rkey); + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case UC: + switch (wr->opcode) { + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + set_raddr_seg(wqe, wr->wr.rdma.remote_addr, + wr->wr.rdma.rkey); + wqe += sizeof (struct mthca_raddr_seg); + size += sizeof (struct mthca_raddr_seg) / 16; + break; + + default: + /* No extra segments required for sends */ + break; + } + + break; + + case UD: + set_arbel_ud_seg(wqe, wr); + wqe += sizeof (struct mthca_arbel_ud_seg); + size += sizeof (struct mthca_arbel_ud_seg) / 16; + break; + + case MLX: + err = build_mlx_header(dev, to_msqp(qp), ind, wr, + wqe - sizeof (struct mthca_next_seg), + wqe); + if (err) { + *bad_wr = wr; + goto out; + } + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + break; + } + + if (wr->num_sge > qp->sq.max_gs) { + mthca_err(dev, "too many gathers\n"); + err = -EINVAL; + *bad_wr = wr; + goto out; + } + + for (i = 0; i < wr->num_sge; ++i) { + mthca_set_data_seg(wqe, wr->sg_list + i); + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + } + + /* Add one more inline data segment for ICRC */ + if (qp->transport == MLX) { + ((struct mthca_data_seg *) wqe)->byte_count = + cpu_to_be32((1 << 31) | 4); + ((u32 *) wqe)[1] = 0; + wqe += sizeof (struct mthca_data_seg); + size += sizeof (struct mthca_data_seg) / 16; + } + + qp->wrid[ind] = wr->wr_id; + + if (wr->opcode >= ARRAY_SIZE(mthca_opcode)) { + mthca_err(dev, "opcode invalid\n"); + err = -EINVAL; + *bad_wr = wr; + goto out; + } + + ((struct mthca_next_seg *) prev_wqe)->nda_op = + cpu_to_be32(((ind << qp->sq.wqe_shift) + + qp->send_wqe_offset) | + mthca_opcode[wr->opcode]); + wmb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cpu_to_be32(MTHCA_NEXT_DBD | size | + ((wr->send_flags & IB_SEND_FENCE) ? + MTHCA_NEXT_FENCE : 0)); + + if (!nreq) { + size0 = size; + op0 = mthca_opcode[wr->opcode]; + f0 = wr->send_flags & IB_SEND_FENCE ? + MTHCA_SEND_DOORBELL_FENCE : 0; + } + + ++ind; + if (unlikely(ind >= qp->sq.max)) + ind -= qp->sq.max; + } + +out: + if (likely(nreq)) { + dbhi = (nreq << 24) | ((qp->sq.head & 0xffff) << 8) | f0 | op0; + + qp->sq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + *qp->sq.db = cpu_to_be32(qp->sq.head & 0xffff); + + /* + * Make sure doorbell record is written before we + * write MMIO send doorbell. + */ + wmb(); + + mthca_write64(dbhi, (qp->qpn << 8) | size0, dev->kar + MTHCA_SEND_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + } + + /* + * Make sure doorbells don't leak out of SQ spinlock and reach + * the HCA out of order: + */ + mmiowb(); + + spin_unlock_irqrestore(&qp->sq.lock, flags); + return err; +} + +int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr) +{ + struct mthca_dev *dev = to_mdev(ibqp->device); + struct mthca_qp *qp = to_mqp(ibqp); + unsigned long flags; + int err = 0; + int nreq; + int ind; + int i; + void *wqe; + + spin_lock_irqsave(&qp->rq.lock, flags); + + /* XXX check that state is OK to post receive */ + + ind = qp->rq.head & (qp->rq.max - 1); + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + if (mthca_wq_overflow(&qp->rq, nreq, qp->ibqp.recv_cq)) { + mthca_err(dev, "RQ %06x full (%u head, %u tail," + " %d max, %d nreq)\n", qp->qpn, + qp->rq.head, qp->rq.tail, + qp->rq.max, nreq); + err = -ENOMEM; + *bad_wr = wr; + goto out; + } + + wqe = get_recv_wqe(qp, ind); + + ((struct mthca_next_seg *) wqe)->flags = 0; + + wqe += sizeof (struct mthca_next_seg); + + if (unlikely(wr->num_sge > qp->rq.max_gs)) { + err = -EINVAL; + *bad_wr = wr; + goto out; + } + + for (i = 0; i < wr->num_sge; ++i) { + mthca_set_data_seg(wqe, wr->sg_list + i); + wqe += sizeof (struct mthca_data_seg); + } + + if (i < qp->rq.max_gs) + mthca_set_data_seg_inval(wqe); + + qp->wrid[ind + qp->sq.max] = wr->wr_id; + + ++ind; + if (unlikely(ind >= qp->rq.max)) + ind -= qp->rq.max; + } +out: + if (likely(nreq)) { + qp->rq.head += nreq; + + /* + * Make sure that descriptors are written before + * doorbell record. + */ + wmb(); + *qp->rq.db = cpu_to_be32(qp->rq.head & 0xffff); + } + + spin_unlock_irqrestore(&qp->rq.lock, flags); + return err; +} + +void mthca_free_err_wqe(struct mthca_dev *dev, struct mthca_qp *qp, int is_send, + int index, int *dbd, __be32 *new_wqe) +{ + struct mthca_next_seg *next; + + /* + * For SRQs, all receive WQEs generate a CQE, so we're always + * at the end of the doorbell chain. + */ + if (qp->ibqp.srq && !is_send) { + *new_wqe = 0; + return; + } + + if (is_send) + next = get_send_wqe(qp, index); + else + next = get_recv_wqe(qp, index); + + *dbd = !!(next->ee_nds & cpu_to_be32(MTHCA_NEXT_DBD)); + if (next->ee_nds & cpu_to_be32(0x3f)) + *new_wqe = (next->nda_op & cpu_to_be32(~0x3f)) | + (next->ee_nds & cpu_to_be32(0x3f)); + else + *new_wqe = 0; +} + +int mthca_init_qp_table(struct mthca_dev *dev) +{ + int err; + u8 status; + int i; + + spin_lock_init(&dev->qp_table.lock); + + /* + * We reserve 2 extra QPs per port for the special QPs. The + * special QP for port 1 has to be even, so round up. + */ + dev->qp_table.sqp_start = (dev->limits.reserved_qps + 1) & ~1UL; + err = mthca_alloc_init(&dev->qp_table.alloc, + dev->limits.num_qps, + (1 << 24) - 1, + dev->qp_table.sqp_start + + MTHCA_MAX_PORTS * 2); + if (err) + return err; + + err = mthca_array_init(&dev->qp_table.qp, + dev->limits.num_qps); + if (err) { + mthca_alloc_cleanup(&dev->qp_table.alloc); + return err; + } + + for (i = 0; i < 2; ++i) { + err = mthca_CONF_SPECIAL_QP(dev, i ? IB_QPT_GSI : IB_QPT_SMI, + dev->qp_table.sqp_start + i * 2, + &status); + if (err) + goto err_out; + if (status) { + mthca_warn(dev, "CONF_SPECIAL_QP returned " + "status %02x, aborting.\n", + status); + err = -EINVAL; + goto err_out; + } + } + return 0; + + err_out: + for (i = 0; i < 2; ++i) + mthca_CONF_SPECIAL_QP(dev, i, 0, &status); + + mthca_array_cleanup(&dev->qp_table.qp, dev->limits.num_qps); + mthca_alloc_cleanup(&dev->qp_table.alloc); + + return err; +} + +void mthca_cleanup_qp_table(struct mthca_dev *dev) +{ + int i; + u8 status; + + for (i = 0; i < 2; ++i) + mthca_CONF_SPECIAL_QP(dev, i, 0, &status); + + mthca_array_cleanup(&dev->qp_table.qp, dev->limits.num_qps); + mthca_alloc_cleanup(&dev->qp_table.alloc); +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_reset.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_reset.c new file mode 100644 index 000000000000..3c124611c03d --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_reset.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "mthca_dev.h" +#include "mthca_cmd.h" + +int mthca_reset(struct mthca_dev *mdev) +{ + int i; + int err = 0; + u32 *hca_header = NULL; + u32 *bridge_header = NULL; + struct pci_dev *bridge = NULL; + int bridge_pcix_cap = 0; + int hca_pcie_cap = 0; + int hca_pcix_cap = 0; + + u16 devctl; + u16 linkctl; + +#define MTHCA_RESET_OFFSET 0xf0010 +#define MTHCA_RESET_VALUE swab32(1) + + /* + * Reset the chip. This is somewhat ugly because we have to + * save off the PCI header before reset and then restore it + * after the chip reboots. We skip config space offsets 22 + * and 23 since those have a special meaning. + * + * To make matters worse, for Tavor (PCI-X HCA) we have to + * find the associated bridge device and save off its PCI + * header as well. + */ + + if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE)) { + /* Look for the bridge -- its device ID will be 2 more + than HCA's device ID. */ +#ifdef __linux__ + while ((bridge = pci_get_device(mdev->pdev->vendor, + mdev->pdev->device + 2, + bridge)) != NULL) { + if (bridge->hdr_type == PCI_HEADER_TYPE_BRIDGE && + bridge->subordinate == mdev->pdev->bus) { + mthca_dbg(mdev, "Found bridge: %s\n", + pci_name(bridge)); + break; + } + } + + if (!bridge) { + /* + * Didn't find a bridge for a Tavor device -- + * assume we're in no-bridge mode and hope for + * the best. + */ + mthca_warn(mdev, "No bridge found for %s\n", + pci_name(mdev->pdev)); + } +#else + mthca_warn(mdev, "Reset on PCI-X is not supported.\n"); + goto out; + +#endif + } + + /* For Arbel do we need to save off the full 4K PCI Express header?? */ + hca_header = kmalloc(256, GFP_KERNEL); + if (!hca_header) { + err = -ENOMEM; + mthca_err(mdev, "Couldn't allocate memory to save HCA " + "PCI header, aborting.\n"); + goto out; + } + + for (i = 0; i < 64; ++i) { + if (i == 22 || i == 23) + continue; + if (pci_read_config_dword(mdev->pdev, i * 4, hca_header + i)) { + err = -ENODEV; + mthca_err(mdev, "Couldn't save HCA " + "PCI header, aborting.\n"); + goto out; + } + } + + hca_pcix_cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX); + hca_pcie_cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP); + +#ifdef __linux__ + if (bridge) { + bridge_header = kmalloc(256, GFP_KERNEL); + if (!bridge_header) { + err = -ENOMEM; + mthca_err(mdev, "Couldn't allocate memory to save HCA " + "bridge PCI header, aborting.\n"); + goto out; + } + + for (i = 0; i < 64; ++i) { + if (i == 22 || i == 23) + continue; + if (pci_read_config_dword(bridge, i * 4, bridge_header + i)) { + err = -ENODEV; + mthca_err(mdev, "Couldn't save HCA bridge " + "PCI header, aborting.\n"); + goto out; + } + } + bridge_pcix_cap = pci_find_capability(bridge, PCI_CAP_ID_PCIX); + if (!bridge_pcix_cap) { + err = -ENODEV; + mthca_err(mdev, "Couldn't locate HCA bridge " + "PCI-X capability, aborting.\n"); + goto out; + } + } +#endif + + /* actually hit reset */ + { + void __iomem *reset = ioremap(pci_resource_start(mdev->pdev, 0) + + MTHCA_RESET_OFFSET, 4); + + if (!reset) { + err = -ENOMEM; + mthca_err(mdev, "Couldn't map HCA reset register, " + "aborting.\n"); + goto out; + } + + writel(MTHCA_RESET_VALUE, reset); + iounmap(reset); + } + + /* Docs say to wait one second before accessing device */ + msleep(1000); + + /* Now wait for PCI device to start responding again */ + { + u32 v; + int c = 0; + + for (c = 0; c < 100; ++c) { + if (pci_read_config_dword(bridge ? bridge : mdev->pdev, 0, &v)) { + err = -ENODEV; + mthca_err(mdev, "Couldn't access HCA after reset, " + "aborting.\n"); + goto out; + } + + if (v != 0xffffffff) + goto good; + + msleep(100); + } + + err = -ENODEV; + mthca_err(mdev, "PCI device did not come back after reset, " + "aborting.\n"); + goto out; + } + +good: + /* Now restore the PCI headers */ + if (bridge) { + if (pci_write_config_dword(bridge, bridge_pcix_cap + 0x8, + bridge_header[(bridge_pcix_cap + 0x8) / 4])) { + err = -ENODEV; + mthca_err(mdev, "Couldn't restore HCA bridge Upstream " + "split transaction control, aborting.\n"); + goto out; + } + if (pci_write_config_dword(bridge, bridge_pcix_cap + 0xc, + bridge_header[(bridge_pcix_cap + 0xc) / 4])) { + err = -ENODEV; + mthca_err(mdev, "Couldn't restore HCA bridge Downstream " + "split transaction control, aborting.\n"); + goto out; + } + /* + * Bridge control register is at 0x3e, so we'll + * naturally restore it last in this loop. + */ + for (i = 0; i < 16; ++i) { + if (i * 4 == PCI_COMMAND) + continue; + + if (pci_write_config_dword(bridge, i * 4, bridge_header[i])) { + err = -ENODEV; + mthca_err(mdev, "Couldn't restore HCA bridge reg %x, " + "aborting.\n", i); + goto out; + } + } + + if (pci_write_config_dword(bridge, PCI_COMMAND, + bridge_header[PCI_COMMAND / 4])) { + err = -ENODEV; + mthca_err(mdev, "Couldn't restore HCA bridge COMMAND, " + "aborting.\n"); + goto out; + } + } + + if (hca_pcix_cap) { + if (pci_write_config_dword(mdev->pdev, hca_pcix_cap, + hca_header[hca_pcix_cap / 4])) { + err = -ENODEV; + mthca_err(mdev, "Couldn't restore HCA PCI-X " + "command register, aborting.\n"); + goto out; + } + } + + if (hca_pcie_cap) { + devctl = hca_header[(hca_pcie_cap + PCI_EXP_DEVCTL) / 4]; + if (pci_write_config_word(mdev->pdev, hca_pcie_cap + PCI_EXP_DEVCTL, + devctl)) { + err = -ENODEV; + mthca_err(mdev, "Couldn't restore HCA PCI Express " + "Device Control register, aborting.\n"); + goto out; + } + linkctl = hca_header[(hca_pcie_cap + PCI_EXP_LNKCTL) / 4]; + if (pci_write_config_word(mdev->pdev, hca_pcie_cap + PCI_EXP_LNKCTL, + linkctl)) { + err = -ENODEV; + mthca_err(mdev, "Couldn't restore HCA PCI Express " + "Link control register, aborting.\n"); + goto out; + } + } + + for (i = 0; i < 16; ++i) { + if (i * 4 == PCI_COMMAND) + continue; + + if (pci_write_config_dword(mdev->pdev, i * 4, hca_header[i])) { + err = -ENODEV; + mthca_err(mdev, "Couldn't restore HCA reg %x, " + "aborting.\n", i); + goto out; + } + } + + if (pci_write_config_dword(mdev->pdev, PCI_COMMAND, + hca_header[PCI_COMMAND / 4])) { + err = -ENODEV; + mthca_err(mdev, "Couldn't restore HCA COMMAND, " + "aborting.\n"); + goto out; + } + +out: +#ifdef __linux__ + if (bridge) + pci_dev_put(bridge); +#endif + kfree(bridge_header); + kfree(hca_header); + + return err; +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_srq.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_srq.c new file mode 100644 index 000000000000..4fabe62aab8a --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_srq.c @@ -0,0 +1,715 @@ +/* + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include + +#include "mthca_dev.h" +#include "mthca_cmd.h" +#include "mthca_memfree.h" +#include "mthca_wqe.h" + +enum { + MTHCA_MAX_DIRECT_SRQ_SIZE = 4 * PAGE_SIZE +}; + +struct mthca_tavor_srq_context { + __be64 wqe_base_ds; /* low 6 bits is descriptor size */ + __be32 state_pd; + __be32 lkey; + __be32 uar; + __be16 limit_watermark; + __be16 wqe_cnt; + u32 reserved[2]; +}; + +struct mthca_arbel_srq_context { + __be32 state_logsize_srqn; + __be32 lkey; + __be32 db_index; + __be32 logstride_usrpage; + __be64 wqe_base; + __be32 eq_pd; + __be16 limit_watermark; + __be16 wqe_cnt; + u16 reserved1; + __be16 wqe_counter; + u32 reserved2[3]; +}; + +static void *get_wqe(struct mthca_srq *srq, int n) +{ + if (srq->is_direct) + return srq->queue.direct.buf + (n << srq->wqe_shift); + else + return srq->queue.page_list[(n << srq->wqe_shift) >> PAGE_SHIFT].buf + + ((n << srq->wqe_shift) & (PAGE_SIZE - 1)); +} + +/* + * Return a pointer to the location within a WQE that we're using as a + * link when the WQE is in the free list. We use the imm field + * because in the Tavor case, posting a WQE may overwrite the next + * segment of the previous WQE, but a receive WQE will never touch the + * imm field. This avoids corrupting our free list if the previous + * WQE has already completed and been put on the free list when we + * post the next WQE. + */ +static inline int *wqe_to_link(void *wqe) +{ + return (int *) (wqe + offsetof(struct mthca_next_seg, imm)); +} + +static void mthca_tavor_init_srq_context(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_srq *srq, + struct mthca_tavor_srq_context *context) +{ + memset(context, 0, sizeof *context); + + context->wqe_base_ds = cpu_to_be64(1 << (srq->wqe_shift - 4)); + context->state_pd = cpu_to_be32(pd->pd_num); + context->lkey = cpu_to_be32(srq->mr.ibmr.lkey); + + if (pd->ibpd.uobject) + context->uar = + cpu_to_be32(to_mucontext(pd->ibpd.uobject->context)->uar.index); + else + context->uar = cpu_to_be32(dev->driver_uar.index); +} + +static void mthca_arbel_init_srq_context(struct mthca_dev *dev, + struct mthca_pd *pd, + struct mthca_srq *srq, + struct mthca_arbel_srq_context *context) +{ + int logsize, max; + + memset(context, 0, sizeof *context); + + /* + * Put max in a temporary variable to work around gcc bug + * triggered by ilog2() on sparc64. + */ + max = srq->max; + logsize = ilog2(max); + context->state_logsize_srqn = cpu_to_be32(logsize << 24 | srq->srqn); + context->lkey = cpu_to_be32(srq->mr.ibmr.lkey); + context->db_index = cpu_to_be32(srq->db_index); + context->logstride_usrpage = cpu_to_be32((srq->wqe_shift - 4) << 29); + if (pd->ibpd.uobject) + context->logstride_usrpage |= + cpu_to_be32(to_mucontext(pd->ibpd.uobject->context)->uar.index); + else + context->logstride_usrpage |= cpu_to_be32(dev->driver_uar.index); + context->eq_pd = cpu_to_be32(MTHCA_EQ_ASYNC << 24 | pd->pd_num); +} + +static void mthca_free_srq_buf(struct mthca_dev *dev, struct mthca_srq *srq) +{ + mthca_buf_free(dev, srq->max << srq->wqe_shift, &srq->queue, + srq->is_direct, &srq->mr); + kfree(srq->wrid); +} + +static int mthca_alloc_srq_buf(struct mthca_dev *dev, struct mthca_pd *pd, + struct mthca_srq *srq) +{ + struct mthca_data_seg *scatter; + void *wqe; + int err; + int i; + + if (pd->ibpd.uobject) + return 0; + + srq->wrid = kmalloc(srq->max * sizeof (u64), GFP_KERNEL); + if (!srq->wrid) + return -ENOMEM; + + err = mthca_buf_alloc(dev, srq->max << srq->wqe_shift, + MTHCA_MAX_DIRECT_SRQ_SIZE, + &srq->queue, &srq->is_direct, pd, 1, &srq->mr); + if (err) { + kfree(srq->wrid); + return err; + } + + /* + * Now initialize the SRQ buffer so that all of the WQEs are + * linked into the list of free WQEs. In addition, set the + * scatter list L_Keys to the sentry value of 0x100. + */ + for (i = 0; i < srq->max; ++i) { + struct mthca_next_seg *next; + + next = wqe = get_wqe(srq, i); + + if (i < srq->max - 1) { + *wqe_to_link(wqe) = i + 1; + next->nda_op = htonl(((i + 1) << srq->wqe_shift) | 1); + } else { + *wqe_to_link(wqe) = -1; + next->nda_op = 0; + } + + for (scatter = wqe + sizeof (struct mthca_next_seg); + (void *) scatter < wqe + (1 << srq->wqe_shift); + ++scatter) + scatter->lkey = cpu_to_be32(MTHCA_INVAL_LKEY); + } + + srq->last = get_wqe(srq, srq->max - 1); + + return 0; +} + +int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, + struct ib_srq_attr *attr, struct mthca_srq *srq) +{ + struct mthca_mailbox *mailbox; + u8 status; + int ds; + int err; + + /* Sanity check SRQ size before proceeding */ + if (attr->max_wr > dev->limits.max_srq_wqes || + attr->max_sge > dev->limits.max_srq_sge) + return -EINVAL; + + srq->max = attr->max_wr; + srq->max_gs = attr->max_sge; + srq->counter = 0; + + if (mthca_is_memfree(dev)) + srq->max = roundup_pow_of_two(srq->max + 1); + else + srq->max = srq->max + 1; + + ds = max(64UL, + roundup_pow_of_two(sizeof (struct mthca_next_seg) + + srq->max_gs * sizeof (struct mthca_data_seg))); + + if (!mthca_is_memfree(dev) && (ds > dev->limits.max_desc_sz)) + return -EINVAL; + + srq->wqe_shift = ilog2(ds); + + srq->srqn = mthca_alloc(&dev->srq_table.alloc); + if (srq->srqn == -1) + return -ENOMEM; + + if (mthca_is_memfree(dev)) { + err = mthca_table_get(dev, dev->srq_table.table, srq->srqn); + if (err) + goto err_out; + + if (!pd->ibpd.uobject) { + srq->db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SRQ, + srq->srqn, &srq->db); + if (srq->db_index < 0) { + err = -ENOMEM; + goto err_out_icm; + } + } + } + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto err_out_db; + } + + err = mthca_alloc_srq_buf(dev, pd, srq); + if (err) + goto err_out_mailbox; + + spin_lock_init(&srq->lock); + srq->refcount = 1; + init_waitqueue_head(&srq->wait); + mutex_init(&srq->mutex); + + if (mthca_is_memfree(dev)) + mthca_arbel_init_srq_context(dev, pd, srq, mailbox->buf); + else + mthca_tavor_init_srq_context(dev, pd, srq, mailbox->buf); + + err = mthca_SW2HW_SRQ(dev, mailbox, srq->srqn, &status); + + if (err) { + mthca_warn(dev, "SW2HW_SRQ failed (%d)\n", err); + goto err_out_free_buf; + } + if (status) { + mthca_warn(dev, "SW2HW_SRQ returned status 0x%02x\n", + status); + err = -EINVAL; + goto err_out_free_buf; + } + + spin_lock_irq(&dev->srq_table.lock); + if (mthca_array_set(&dev->srq_table.srq, + srq->srqn & (dev->limits.num_srqs - 1), + srq)) { + spin_unlock_irq(&dev->srq_table.lock); + goto err_out_free_srq; + } + spin_unlock_irq(&dev->srq_table.lock); + + mthca_free_mailbox(dev, mailbox); + + srq->first_free = 0; + srq->last_free = srq->max - 1; + + attr->max_wr = srq->max - 1; + attr->max_sge = srq->max_gs; + + return 0; + +err_out_free_srq: + err = mthca_HW2SW_SRQ(dev, mailbox, srq->srqn, &status); + if (err) + mthca_warn(dev, "HW2SW_SRQ failed (%d)\n", err); + else if (status) + mthca_warn(dev, "HW2SW_SRQ returned status 0x%02x\n", status); + +err_out_free_buf: + if (!pd->ibpd.uobject) + mthca_free_srq_buf(dev, srq); + +err_out_mailbox: + mthca_free_mailbox(dev, mailbox); + +err_out_db: + if (!pd->ibpd.uobject && mthca_is_memfree(dev)) + mthca_free_db(dev, MTHCA_DB_TYPE_SRQ, srq->db_index); + +err_out_icm: + mthca_table_put(dev, dev->srq_table.table, srq->srqn); + +err_out: + mthca_free(&dev->srq_table.alloc, srq->srqn); + + return err; +} + +static inline int get_srq_refcount(struct mthca_dev *dev, struct mthca_srq *srq) +{ + int c; + + spin_lock_irq(&dev->srq_table.lock); + c = srq->refcount; + spin_unlock_irq(&dev->srq_table.lock); + + return c; +} + +void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq) +{ + struct mthca_mailbox *mailbox; + int err; + u8 status; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) { + mthca_warn(dev, "No memory for mailbox to free SRQ.\n"); + return; + } + + err = mthca_HW2SW_SRQ(dev, mailbox, srq->srqn, &status); + if (err) + mthca_warn(dev, "HW2SW_SRQ failed (%d)\n", err); + else if (status) + mthca_warn(dev, "HW2SW_SRQ returned status 0x%02x\n", status); + + spin_lock_irq(&dev->srq_table.lock); + mthca_array_clear(&dev->srq_table.srq, + srq->srqn & (dev->limits.num_srqs - 1)); + --srq->refcount; + spin_unlock_irq(&dev->srq_table.lock); + + wait_event(srq->wait, !get_srq_refcount(dev, srq)); + + if (!srq->ibsrq.uobject) { + mthca_free_srq_buf(dev, srq); + if (mthca_is_memfree(dev)) + mthca_free_db(dev, MTHCA_DB_TYPE_SRQ, srq->db_index); + } + + mthca_table_put(dev, dev->srq_table.table, srq->srqn); + mthca_free(&dev->srq_table.alloc, srq->srqn); + mthca_free_mailbox(dev, mailbox); +} + +int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, + enum ib_srq_attr_mask attr_mask, struct ib_udata *udata) +{ + struct mthca_dev *dev = to_mdev(ibsrq->device); + struct mthca_srq *srq = to_msrq(ibsrq); + int ret; + u8 status; + + /* We don't support resizing SRQs (yet?) */ + if (attr_mask & IB_SRQ_MAX_WR) + return -EINVAL; + + if (attr_mask & IB_SRQ_LIMIT) { + u32 max_wr = mthca_is_memfree(dev) ? srq->max - 1 : srq->max; + if (attr->srq_limit > max_wr) + return -EINVAL; + + mutex_lock(&srq->mutex); + ret = mthca_ARM_SRQ(dev, srq->srqn, attr->srq_limit, &status); + mutex_unlock(&srq->mutex); + + if (ret) + return ret; + if (status) + return -EINVAL; + } + + return 0; +} + +int mthca_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr) +{ + struct mthca_dev *dev = to_mdev(ibsrq->device); + struct mthca_srq *srq = to_msrq(ibsrq); + struct mthca_mailbox *mailbox; + struct mthca_arbel_srq_context *arbel_ctx; + struct mthca_tavor_srq_context *tavor_ctx; + u8 status; + int err; + + mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + err = mthca_QUERY_SRQ(dev, srq->srqn, mailbox, &status); + if (err) + goto out; + + if (mthca_is_memfree(dev)) { + arbel_ctx = mailbox->buf; + srq_attr->srq_limit = be16_to_cpu(arbel_ctx->limit_watermark); + } else { + tavor_ctx = mailbox->buf; + srq_attr->srq_limit = be16_to_cpu(tavor_ctx->limit_watermark); + } + + srq_attr->max_wr = srq->max - 1; + srq_attr->max_sge = srq->max_gs; + +out: + mthca_free_mailbox(dev, mailbox); + + return err; +} + +void mthca_srq_event(struct mthca_dev *dev, u32 srqn, + enum ib_event_type event_type) +{ + struct mthca_srq *srq; + struct ib_event event; + + spin_lock(&dev->srq_table.lock); + srq = mthca_array_get(&dev->srq_table.srq, srqn & (dev->limits.num_srqs - 1)); + if (srq) + ++srq->refcount; + spin_unlock(&dev->srq_table.lock); + + if (!srq) { + mthca_warn(dev, "Async event for bogus SRQ %08x\n", srqn); + return; + } + + if (!srq->ibsrq.event_handler) + goto out; + + event.device = &dev->ib_dev; + event.event = event_type; + event.element.srq = &srq->ibsrq; + srq->ibsrq.event_handler(&event, srq->ibsrq.srq_context); + +out: + spin_lock(&dev->srq_table.lock); + if (!--srq->refcount) + wake_up(&srq->wait); + spin_unlock(&dev->srq_table.lock); +} + +/* + * This function must be called with IRQs disabled. + */ +void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr) +{ + int ind; + struct mthca_next_seg *last_free; + + ind = wqe_addr >> srq->wqe_shift; + + spin_lock(&srq->lock); + + last_free = get_wqe(srq, srq->last_free); + *wqe_to_link(last_free) = ind; + last_free->nda_op = htonl((ind << srq->wqe_shift) | 1); + *wqe_to_link(get_wqe(srq, ind)) = -1; + srq->last_free = ind; + + spin_unlock(&srq->lock); +} + +int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr) +{ + struct mthca_dev *dev = to_mdev(ibsrq->device); + struct mthca_srq *srq = to_msrq(ibsrq); + unsigned long flags; + int err = 0; + int first_ind; + int ind; + int next_ind; + int nreq; + int i; + void *wqe; + void *prev_wqe; + + spin_lock_irqsave(&srq->lock, flags); + + first_ind = srq->first_free; + + for (nreq = 0; wr; wr = wr->next) { + ind = srq->first_free; + wqe = get_wqe(srq, ind); + next_ind = *wqe_to_link(wqe); + + if (unlikely(next_ind < 0)) { + mthca_err(dev, "SRQ %06x full\n", srq->srqn); + err = -ENOMEM; + *bad_wr = wr; + break; + } + + prev_wqe = srq->last; + srq->last = wqe; + + ((struct mthca_next_seg *) wqe)->ee_nds = 0; + /* flags field will always remain 0 */ + + wqe += sizeof (struct mthca_next_seg); + + if (unlikely(wr->num_sge > srq->max_gs)) { + err = -EINVAL; + *bad_wr = wr; + srq->last = prev_wqe; + break; + } + + for (i = 0; i < wr->num_sge; ++i) { + mthca_set_data_seg(wqe, wr->sg_list + i); + wqe += sizeof (struct mthca_data_seg); + } + + if (i < srq->max_gs) + mthca_set_data_seg_inval(wqe); + + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cpu_to_be32(MTHCA_NEXT_DBD); + + srq->wrid[ind] = wr->wr_id; + srq->first_free = next_ind; + + ++nreq; + if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) { + nreq = 0; + + /* + * Make sure that descriptors are written + * before doorbell is rung. + */ + wmb(); + + mthca_write64(first_ind << srq->wqe_shift, srq->srqn << 8, + dev->kar + MTHCA_RECEIVE_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + + first_ind = srq->first_free; + } + } + + if (likely(nreq)) { + /* + * Make sure that descriptors are written before + * doorbell is rung. + */ + wmb(); + + mthca_write64(first_ind << srq->wqe_shift, (srq->srqn << 8) | nreq, + dev->kar + MTHCA_RECEIVE_DOORBELL, + MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock)); + } + + /* + * Make sure doorbells don't leak out of SRQ spinlock and + * reach the HCA out of order: + */ + mmiowb(); + + spin_unlock_irqrestore(&srq->lock, flags); + return err; +} + +int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr) +{ + struct mthca_dev *dev = to_mdev(ibsrq->device); + struct mthca_srq *srq = to_msrq(ibsrq); + unsigned long flags; + int err = 0; + int ind; + int next_ind; + int nreq; + int i; + void *wqe; + + spin_lock_irqsave(&srq->lock, flags); + + for (nreq = 0; wr; ++nreq, wr = wr->next) { + ind = srq->first_free; + wqe = get_wqe(srq, ind); + next_ind = *wqe_to_link(wqe); + + if (unlikely(next_ind < 0)) { + mthca_err(dev, "SRQ %06x full\n", srq->srqn); + err = -ENOMEM; + *bad_wr = wr; + break; + } + + ((struct mthca_next_seg *) wqe)->ee_nds = 0; + /* flags field will always remain 0 */ + + wqe += sizeof (struct mthca_next_seg); + + if (unlikely(wr->num_sge > srq->max_gs)) { + err = -EINVAL; + *bad_wr = wr; + break; + } + + for (i = 0; i < wr->num_sge; ++i) { + mthca_set_data_seg(wqe, wr->sg_list + i); + wqe += sizeof (struct mthca_data_seg); + } + + if (i < srq->max_gs) + mthca_set_data_seg_inval(wqe); + + srq->wrid[ind] = wr->wr_id; + srq->first_free = next_ind; + } + + if (likely(nreq)) { + srq->counter += nreq; + + /* + * Make sure that descriptors are written before + * we write doorbell record. + */ + wmb(); + *srq->db = cpu_to_be32(srq->counter); + } + + spin_unlock_irqrestore(&srq->lock, flags); + return err; +} + +int mthca_max_srq_sge(struct mthca_dev *dev) +{ + if (mthca_is_memfree(dev)) + return dev->limits.max_sg; + + /* + * SRQ allocations are based on powers of 2 for Tavor, + * (although they only need to be multiples of 16 bytes). + * + * Therefore, we need to base the max number of sg entries on + * the largest power of 2 descriptor size that is <= to the + * actual max WQE descriptor size, rather than return the + * max_sg value given by the firmware (which is based on WQE + * sizes as multiples of 16, not powers of 2). + * + * If SRQ implementation is changed for Tavor to be based on + * multiples of 16, the calculation below can be deleted and + * the FW max_sg value returned. + */ + return min_t(int, dev->limits.max_sg, + ((1 << (fls(dev->limits.max_desc_sz) - 1)) - + sizeof (struct mthca_next_seg)) / + sizeof (struct mthca_data_seg)); +} + +int mthca_init_srq_table(struct mthca_dev *dev) +{ + int err; + + if (!(dev->mthca_flags & MTHCA_FLAG_SRQ)) + return 0; + + spin_lock_init(&dev->srq_table.lock); + + err = mthca_alloc_init(&dev->srq_table.alloc, + dev->limits.num_srqs, + dev->limits.num_srqs - 1, + dev->limits.reserved_srqs); + if (err) + return err; + + err = mthca_array_init(&dev->srq_table.srq, + dev->limits.num_srqs); + if (err) + mthca_alloc_cleanup(&dev->srq_table.alloc); + + return err; +} + +void mthca_cleanup_srq_table(struct mthca_dev *dev) +{ + if (!(dev->mthca_flags & MTHCA_FLAG_SRQ)) + return; + + mthca_array_cleanup(&dev->srq_table.srq, dev->limits.num_srqs); + mthca_alloc_cleanup(&dev->srq_table.alloc); +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_uar.c b/sys/ofed/drivers/infiniband/hw/mthca/mthca_uar.c new file mode 100644 index 000000000000..ca5900c96fcf --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_uar.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include /* PAGE_SHIFT */ + +#include "mthca_dev.h" +#include "mthca_memfree.h" + +int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar) +{ + uar->index = mthca_alloc(&dev->uar_table.alloc); + if (uar->index == -1) + return -ENOMEM; + + uar->pfn = (pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + uar->index; + + return 0; +} + +void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar) +{ + mthca_free(&dev->uar_table.alloc, uar->index); +} + +int mthca_init_uar_table(struct mthca_dev *dev) +{ + int ret; + + ret = mthca_alloc_init(&dev->uar_table.alloc, + dev->limits.num_uars, + dev->limits.num_uars - 1, + dev->limits.reserved_uars + 1); + if (ret) + return ret; + + ret = mthca_init_db_tab(dev); + if (ret) + mthca_alloc_cleanup(&dev->uar_table.alloc); + + return ret; +} + +void mthca_cleanup_uar_table(struct mthca_dev *dev) +{ + mthca_cleanup_db_tab(dev); + + /* XXX check if any UARs are still allocated? */ + mthca_alloc_cleanup(&dev->uar_table.alloc); +} diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_user.h b/sys/ofed/drivers/infiniband/hw/mthca/mthca_user.h new file mode 100644 index 000000000000..5fe56e810739 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_user.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MTHCA_USER_H +#define MTHCA_USER_H + +#include + +/* + * Increment this value if any changes that break userspace ABI + * compatibility are made. + */ +#define MTHCA_UVERBS_ABI_VERSION 1 + +/* + * Make sure that all structs defined in this file remain laid out so + * that they pack the same way on 32-bit and 64-bit architectures (to + * avoid incompatibility between 32-bit userspace and 64-bit kernels). + * In particular do not use pointer types -- pass pointers in __u64 + * instead. + */ + +struct mthca_alloc_ucontext_resp { + __u32 qp_tab_size; + __u32 uarc_size; +}; + +struct mthca_alloc_pd_resp { + __u32 pdn; + __u32 reserved; +}; + +struct mthca_reg_mr { +/* + * Mark the memory region with a DMA attribute that causes + * in-flight DMA to be flushed when the region is written to: + */ +#define MTHCA_MR_DMASYNC 0x1 + __u32 mr_attrs; + __u32 reserved; +}; + +struct mthca_create_cq { + __u32 lkey; + __u32 pdn; + __u64 arm_db_page; + __u64 set_db_page; + __u32 arm_db_index; + __u32 set_db_index; +}; + +struct mthca_create_cq_resp { + __u32 cqn; + __u32 reserved; +}; + +struct mthca_resize_cq { + __u32 lkey; + __u32 reserved; +}; + +struct mthca_create_srq { + __u32 lkey; + __u32 db_index; + __u64 db_page; +}; + +struct mthca_create_srq_resp { + __u32 srqn; + __u32 reserved; +}; + +struct mthca_create_qp { + __u32 lkey; + __u32 reserved; + __u64 sq_db_page; + __u64 rq_db_page; + __u32 sq_db_index; + __u32 rq_db_index; +}; + +#endif /* MTHCA_USER_H */ diff --git a/sys/ofed/drivers/infiniband/hw/mthca/mthca_wqe.h b/sys/ofed/drivers/infiniband/hw/mthca/mthca_wqe.h new file mode 100644 index 000000000000..341a5ae881c1 --- /dev/null +++ b/sys/ofed/drivers/infiniband/hw/mthca/mthca_wqe.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2005 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MTHCA_WQE_H +#define MTHCA_WQE_H + +#include + +enum { + MTHCA_NEXT_DBD = 1 << 7, + MTHCA_NEXT_FENCE = 1 << 6, + MTHCA_NEXT_CQ_UPDATE = 1 << 3, + MTHCA_NEXT_EVENT_GEN = 1 << 2, + MTHCA_NEXT_SOLICIT = 1 << 1, + MTHCA_NEXT_IP_CSUM = 1 << 4, + MTHCA_NEXT_TCP_UDP_CSUM = 1 << 5, + + MTHCA_MLX_VL15 = 1 << 17, + MTHCA_MLX_SLR = 1 << 16 +}; + +enum { + MTHCA_INVAL_LKEY = 0x100, + MTHCA_TAVOR_MAX_WQES_PER_RECV_DB = 256, + MTHCA_ARBEL_MAX_WQES_PER_SEND_DB = 255 +}; + +struct mthca_next_seg { + __be32 nda_op; /* [31:6] next WQE [4:0] next opcode */ + __be32 ee_nds; /* [31:8] next EE [7] DBD [6] F [5:0] next WQE size */ + __be32 flags; /* [3] CQ [2] Event [1] Solicit */ + __be32 imm; /* immediate data */ +}; + +struct mthca_tavor_ud_seg { + u32 reserved1; + __be32 lkey; + __be64 av_addr; + u32 reserved2[4]; + __be32 dqpn; + __be32 qkey; + u32 reserved3[2]; +}; + +struct mthca_arbel_ud_seg { + __be32 av[8]; + __be32 dqpn; + __be32 qkey; + u32 reserved[2]; +}; + +struct mthca_bind_seg { + __be32 flags; /* [31] Atomic [30] rem write [29] rem read */ + u32 reserved; + __be32 new_rkey; + __be32 lkey; + __be64 addr; + __be64 length; +}; + +struct mthca_raddr_seg { + __be64 raddr; + __be32 rkey; + u32 reserved; +}; + +struct mthca_atomic_seg { + __be64 swap_add; + __be64 compare; +}; + +struct mthca_data_seg { + __be32 byte_count; + __be32 lkey; + __be64 addr; +}; + +struct mthca_mlx_seg { + __be32 nda_op; + __be32 nds; + __be32 flags; /* [17] VL15 [16] SLR [14:12] static rate + [11:8] SL [3] C [2] E */ + __be16 rlid; + __be16 vcrc; +}; + +static __always_inline void mthca_set_data_seg(struct mthca_data_seg *dseg, + struct ib_sge *sg) +{ + dseg->byte_count = cpu_to_be32(sg->length); + dseg->lkey = cpu_to_be32(sg->lkey); + dseg->addr = cpu_to_be64(sg->addr); +} + +static __always_inline void mthca_set_data_seg_inval(struct mthca_data_seg *dseg) +{ + dseg->byte_count = 0; + dseg->lkey = cpu_to_be32(MTHCA_INVAL_LKEY); + dseg->addr = 0; +} + +#endif /* MTHCA_WQE_H */ diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/Kconfig b/sys/ofed/drivers/infiniband/ulp/ipoib/Kconfig new file mode 100644 index 000000000000..9d9a9dc51f18 --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/ipoib/Kconfig @@ -0,0 +1,50 @@ +config INFINIBAND_IPOIB + tristate "IP-over-InfiniBand" + depends on NETDEVICES && INET && (IPV6 || IPV6=n) + select INET_LRO + ---help--- + Support for the IP-over-InfiniBand protocol (IPoIB). This + transports IP packets over InfiniBand so you can use your IB + device as a fancy NIC. + + See Documentation/infiniband/ipoib.txt for more information + +config INFINIBAND_IPOIB_CM + bool "IP-over-InfiniBand Connected Mode support" + depends on INFINIBAND_IPOIB + default n + ---help--- + This option enables support for IPoIB connected mode. After + enabling this option, you need to switch to connected mode + through /sys/class/net/ibXXX/mode to actually create + connections, and then increase the interface MTU with + e.g. ifconfig ib0 mtu 65520. + + WARNING: Enabling connected mode will trigger some packet + drops for multicast and UD mode traffic from this interface, + unless you limit mtu for these destinations to 2044. + +config INFINIBAND_IPOIB_DEBUG + bool "IP-over-InfiniBand debugging" if EMBEDDED + depends on INFINIBAND_IPOIB + default y + ---help--- + This option causes debugging code to be compiled into the + IPoIB driver. The output can be turned on via the + debug_level and mcast_debug_level module parameters (which + can also be set after the driver is loaded through sysfs). + + This option also creates a directory tree under ipoib/ in + debugfs, which contains files that expose debugging + information about IB multicast groups used by the IPoIB + driver. + +config INFINIBAND_IPOIB_DEBUG_DATA + bool "IP-over-InfiniBand data path debugging" + depends on INFINIBAND_IPOIB_DEBUG + ---help--- + This option compiles debugging code into the data path + of the IPoIB driver. The output can be turned on via the + data_debug_level module parameter; however, even with output + turned off, this debugging code will have some performance + impact. diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/Makefile b/sys/ofed/drivers/infiniband/ulp/ipoib/Makefile new file mode 100644 index 000000000000..3090100f0de7 --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/ipoib/Makefile @@ -0,0 +1,11 @@ +obj-$(CONFIG_INFINIBAND_IPOIB) += ib_ipoib.o + +ib_ipoib-y := ipoib_main.o \ + ipoib_ib.o \ + ipoib_multicast.o \ + ipoib_verbs.o \ + ipoib_vlan.o \ + ipoib_ethtool.o +ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_CM) += ipoib_cm.o +ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_DEBUG) += ipoib_fs.o + diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib.h b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib.h new file mode 100644 index 000000000000..1d6ae845d1ae --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib.h @@ -0,0 +1,757 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _IPOIB_H +#define _IPOIB_H + +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_ofed.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(INET) || defined(INET6) +#include +#include +#include +#include +#include +#include +#endif +#ifdef INET6 +#include +#endif + +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +/* constants */ + +#define INFINIBAND_ALEN 20 /* Octets in IPoIB HW addr */ + +#ifdef IPOIB_CM +#define CONFIG_INFINIBAND_IPOIB_CM +#endif + +#ifdef IPOIB_DEBUG +#define CONFIG_INFINIBAND_IPOIB_DEBUG +#define CONFIG_INFINIBAND_IPOIB_DEBUG_DATA +#endif + +enum ipoib_flush_level { + IPOIB_FLUSH_LIGHT, + IPOIB_FLUSH_NORMAL, + IPOIB_FLUSH_HEAVY +}; + +enum { + IPOIB_ENCAP_LEN = 4, + IPOIB_HEADER_LEN = IPOIB_ENCAP_LEN + INFINIBAND_ALEN, + IPOIB_UD_MAX_MTU = 4 * 1024, + IPOIB_UD_RX_SG = (IPOIB_UD_MAX_MTU / MJUMPAGESIZE), + IPOIB_UD_TX_SG = (IPOIB_UD_MAX_MTU / MCLBYTES) + 2, + IPOIB_CM_MAX_MTU = (64 * 1024), + IPOIB_CM_TX_SG = (IPOIB_CM_MAX_MTU / MCLBYTES) + 2, + IPOIB_CM_RX_SG = (IPOIB_CM_MAX_MTU / MJUMPAGESIZE), + IPOIB_RX_RING_SIZE = 256, + IPOIB_TX_RING_SIZE = 128, + IPOIB_MAX_RX_SG = MAX(IPOIB_CM_RX_SG, IPOIB_UD_RX_SG), + IPOIB_MAX_TX_SG = MAX(IPOIB_CM_TX_SG, IPOIB_UD_TX_SG), + IPOIB_MAX_QUEUE_SIZE = 8192, + IPOIB_MIN_QUEUE_SIZE = 2, + IPOIB_CM_MAX_CONN_QP = 4096, + + IPOIB_NUM_WC = 4, + + IPOIB_MAX_PATH_REC_QUEUE = 3, + IPOIB_MAX_MCAST_QUEUE = 3, + + IPOIB_FLAG_OPER_UP = 0, + IPOIB_FLAG_INITIALIZED = 1, + IPOIB_FLAG_ADMIN_UP = 2, + IPOIB_PKEY_ASSIGNED = 3, + IPOIB_PKEY_STOP = 4, + IPOIB_FLAG_SUBINTERFACE = 5, + IPOIB_MCAST_RUN = 6, + IPOIB_STOP_REAPER = 7, + IPOIB_FLAG_UMCAST = 10, + IPOIB_FLAG_CSUM = 11, + + IPOIB_MAX_BACKOFF_SECONDS = 16, + + IPOIB_MCAST_FLAG_FOUND = 0, /* used in set_multicast_list */ + IPOIB_MCAST_FLAG_SENDONLY = 1, + IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */ + IPOIB_MCAST_FLAG_ATTACHED = 3, + + IPOIB_MAX_LRO_DESCRIPTORS = 8, + IPOIB_LRO_MAX_AGGR = 64, + + MAX_SEND_CQE = 16, + IPOIB_CM_COPYBREAK = 256, +}; + +#define IPOIB_OP_RECV (1ul << 31) +#ifdef CONFIG_INFINIBAND_IPOIB_CM +#define IPOIB_OP_CM (1ul << 30) +#else +#define IPOIB_OP_CM (0) +#endif + +/* structs */ + +struct ipoib_header { + u8 hwaddr[INFINIBAND_ALEN]; + __be16 proto; + u16 reserved; +}; + +struct ipoib_pseudoheader { + u8 hwaddr[INFINIBAND_ALEN]; +}; + +/* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */ +struct ipoib_mcast { + struct ib_sa_mcmember_rec mcmember; + struct ib_sa_multicast *mc; + struct ipoib_ah *ah; + + struct rb_node rb_node; + struct list_head list; + + unsigned long created; + unsigned long backoff; + + unsigned long flags; + unsigned char logcount; + + struct ifqueue pkt_queue; + + struct ipoib_dev_priv *priv; +}; + +struct ipoib_cm_rx_buf { + struct mbuf *mb; + u64 mapping[IPOIB_CM_RX_SG]; +}; + +struct ipoib_cm_tx_buf { + struct mbuf *mb; + u64 mapping[IPOIB_CM_TX_SG]; +}; + +struct ipoib_rx_buf { + struct mbuf *mb; + u64 mapping[IPOIB_UD_RX_SG]; +}; + +struct ipoib_tx_buf { + struct mbuf *mb; + u64 mapping[IPOIB_UD_TX_SG]; +}; + +struct ib_cm_id; + +struct ipoib_cm_data { + __be32 qpn; /* High byte MUST be ignored on receive */ + __be32 mtu; +}; + +/* + * Quoting 10.3.1 Queue Pair and EE Context States: + * + * Note, for QPs that are associated with an SRQ, the Consumer should take the + * QP through the Error State before invoking a Destroy QP or a Modify QP to the + * Reset State. The Consumer may invoke the Destroy QP without first performing + * a Modify QP to the Error State and waiting for the Affiliated Asynchronous + * Last WQE Reached Event. However, if the Consumer does not wait for the + * Affiliated Asynchronous Last WQE Reached Event, then WQE and Data Segment + * leakage may occur. Therefore, it is good programming practice to tear down a + * QP that is associated with an SRQ by using the following process: + * + * - Put the QP in the Error State + * - Wait for the Affiliated Asynchronous Last WQE Reached Event; + * - either: + * drain the CQ by invoking the Poll CQ verb and either wait for CQ + * to be empty or the number of Poll CQ operations has exceeded + * CQ capacity size; + * - or + * post another WR that completes on the same CQ and wait for this + * WR to return as a WC; + * - and then invoke a Destroy QP or Reset QP. + * + * We use the second option and wait for a completion on the + * same CQ before destroying QPs attached to our SRQ. + */ + +enum ipoib_cm_state { + IPOIB_CM_RX_LIVE, + IPOIB_CM_RX_ERROR, /* Ignored by stale task */ + IPOIB_CM_RX_FLUSH /* Last WQE Reached event observed */ +}; + +struct ipoib_cm_rx { + struct ib_cm_id *id; + struct ib_qp *qp; + struct ipoib_cm_rx_buf *rx_ring; + struct list_head list; + struct ipoib_dev_priv *priv; + unsigned long jiffies; + enum ipoib_cm_state state; + int recv_count; +}; + +struct ipoib_cm_tx { + struct ib_cm_id *id; + struct ib_qp *qp; + struct list_head list; + struct ipoib_dev_priv *priv; + struct ipoib_path *path; + struct ipoib_cm_tx_buf *tx_ring; + unsigned tx_head; + unsigned tx_tail; + unsigned long flags; + u32 mtu; /* remote specified mtu, with grh. */ +}; + +struct ipoib_cm_dev_priv { + struct ib_srq *srq; + struct ipoib_cm_rx_buf *srq_ring; + struct ib_cm_id *id; + struct list_head passive_ids; /* state: LIVE */ + struct list_head rx_error_list; /* state: ERROR */ + struct list_head rx_flush_list; /* state: FLUSH, drain not started */ + struct list_head rx_drain_list; /* state: FLUSH, drain started */ + struct list_head rx_reap_list; /* state: FLUSH, drain done */ + struct work_struct start_task; + struct work_struct reap_task; + struct work_struct mb_task; + struct work_struct rx_reap_task; + struct delayed_work stale_task; + struct ifqueue mb_queue; + struct list_head start_list; + struct list_head reap_list; + struct ib_sge rx_sge[IPOIB_CM_RX_SG]; + struct ib_recv_wr rx_wr; + int nonsrq_conn_qp; + int max_cm_mtu; /* Actual buf size. */ + int num_frags; +}; + +struct ipoib_ethtool_st { + u16 coalesce_usecs; + u16 max_coalesced_frames; +}; + +/* + * Device private locking: network stack tx_lock protects members used + * in TX fast path, lock protects everything else. lock nests inside + * of tx_lock (ie tx_lock must be acquired first if needed). + */ +struct ipoib_dev_priv { + spinlock_t lock; + + struct ifnet *dev; + + u8 broadcastaddr[INFINIBAND_ALEN]; + + unsigned long flags; + + struct mutex vlan_mutex; + + struct rb_root path_tree; + struct list_head path_list; + + struct ipoib_mcast *broadcast; + struct list_head multicast_list; + struct rb_root multicast_tree; + + struct delayed_work pkey_poll_task; + struct delayed_work mcast_task; + struct work_struct carrier_on_task; + struct work_struct flush_light; + struct work_struct flush_normal; + struct work_struct flush_heavy; + struct work_struct restart_task; + struct delayed_work ah_reap_task; + + struct ib_device *ca; + u8 port; + u16 pkey; + u16 pkey_index; + struct ib_pd *pd; + struct ib_mr *mr; + struct ib_cq *recv_cq; + struct ib_cq *send_cq; + struct ib_qp *qp; + u32 qkey; + + union ib_gid local_gid; + u16 local_lid; + + unsigned int admin_mtu; /* User selected MTU, no GRH. */ + unsigned int mcast_mtu; /* Minus GRH bytes, from mcast group. */ + unsigned int max_ib_mtu; /* Without header, actual buf size. */ + + struct ipoib_rx_buf *rx_ring; + + struct ipoib_tx_buf *tx_ring; + unsigned tx_head; + unsigned tx_tail; + struct ib_sge tx_sge[IPOIB_MAX_TX_SG]; + struct ib_send_wr tx_wr; + unsigned tx_outstanding; + struct ib_wc send_wc[MAX_SEND_CQE]; + + struct ib_recv_wr rx_wr; + struct ib_sge rx_sge[IPOIB_MAX_RX_SG]; + + struct ib_wc ibwc[IPOIB_NUM_WC]; + + struct list_head dead_ahs; + + struct ib_event_handler event_handler; + + struct ifnet *parent; + struct list_head child_intfs; + struct list_head list; + +#ifdef CONFIG_INFINIBAND_IPOIB_CM + struct ipoib_cm_dev_priv cm; +#endif + +#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG + struct list_head fs_list; + struct dentry *mcg_dentry; + struct dentry *path_dentry; +#endif + int hca_caps; + struct ipoib_ethtool_st ethtool; + struct timer_list poll_timer; +}; + +struct ipoib_ah { + struct ipoib_dev_priv *priv; + struct ib_ah *ah; + struct list_head list; + struct kref ref; + unsigned last_send; +}; + +struct ipoib_path { + struct ipoib_dev_priv *priv; + struct rb_node rb_node; + struct list_head list; +#ifdef CONFIG_INFINIBAND_IPOIB_CM + uint8_t hwaddr[INFINIBAND_ALEN]; + struct ipoib_cm_tx *cm; +#endif + struct ipoib_ah *ah; + struct ib_sa_path_rec pathrec; + struct ifqueue queue; + + int query_id; + struct ib_sa_query *query; + struct completion done; + + int valid; +}; + +/* UD Only transmits encap len but we want the two sizes to be symmetrical. */ +#define IPOIB_UD_MTU(ib_mtu) (ib_mtu - IPOIB_ENCAP_LEN) +#define IPOIB_CM_MTU(ib_mtu) (ib_mtu - 0x10) + +#define IPOIB_IS_MULTICAST(addr) ((addr)[4] == 0xff) + +extern struct workqueue_struct *ipoib_workqueue; + +#define IPOIB_MTAP_PROTO(_ifp, _m, _proto) \ +do { \ + if (bpf_peers_present((_ifp)->if_bpf)) { \ + M_ASSERTVALID(_m); \ + ipoib_mtap_proto((_ifp), (_m), (_proto)); \ + } \ +} while (0) + +/* functions */ +void ipoib_mtap_proto(struct ifnet *ifp, struct mbuf *mb, uint16_t proto); +void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr); +void ipoib_send_comp_handler(struct ib_cq *cq, void *dev_ptr); + +struct ipoib_ah *ipoib_create_ah(struct ipoib_dev_priv *, + struct ib_pd *pd, struct ib_ah_attr *attr); +void ipoib_free_ah(struct kref *kref); +static inline void ipoib_put_ah(struct ipoib_ah *ah) +{ + kref_put(&ah->ref, ipoib_free_ah); +} + +int ipoib_open(struct ipoib_dev_priv *priv); +int ipoib_add_pkey_attr(struct ipoib_dev_priv *priv); +int ipoib_add_umcast_attr(struct ipoib_dev_priv *priv); + +void ipoib_demux(struct ifnet *ifp, struct mbuf *m, u_short proto); + +void ipoib_send(struct ipoib_dev_priv *priv, struct mbuf *mb, + struct ipoib_ah *address, u32 qpn); +void ipoib_reap_ah(struct work_struct *work); + +void ipoib_mark_paths_invalid(struct ipoib_dev_priv *priv); +void ipoib_flush_paths(struct ipoib_dev_priv *priv); +struct ipoib_dev_priv *ipoib_intf_alloc(const char *format); + +int ipoib_ib_dev_init(struct ipoib_dev_priv *priv, struct ib_device *ca, + int port); +void ipoib_ib_dev_flush_light(struct work_struct *work); +void ipoib_ib_dev_flush_normal(struct work_struct *work); +void ipoib_ib_dev_flush_heavy(struct work_struct *work); +void ipoib_pkey_event(struct work_struct *work); +void ipoib_ib_dev_cleanup(struct ipoib_dev_priv *priv); + +int ipoib_ib_dev_open(struct ipoib_dev_priv *priv); +int ipoib_ib_dev_up(struct ipoib_dev_priv *priv); +int ipoib_ib_dev_down(struct ipoib_dev_priv *priv, int flush); +int ipoib_ib_dev_stop(struct ipoib_dev_priv *priv, int flush); + +int ipoib_dev_init(struct ipoib_dev_priv *priv, struct ib_device *ca, int port); +void ipoib_dev_cleanup(struct ipoib_dev_priv *priv); + +void ipoib_mcast_join_task(struct work_struct *work); +void ipoib_mcast_carrier_on_task(struct work_struct *work); +void ipoib_mcast_send(struct ipoib_dev_priv *priv, void *mgid, struct mbuf *mb); + +void ipoib_mcast_restart_task(struct work_struct *work); +void ipoib_mcast_restart(struct ipoib_dev_priv *); +int ipoib_mcast_start_thread(struct ipoib_dev_priv *priv); +int ipoib_mcast_stop_thread(struct ipoib_dev_priv *priv, int flush); + +void ipoib_mcast_dev_down(struct ipoib_dev_priv *priv); +void ipoib_mcast_dev_flush(struct ipoib_dev_priv *priv); + +void ipoib_path_free(struct ipoib_dev_priv *priv, struct ipoib_path *path); +#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG +struct ipoib_mcast_iter *ipoib_mcast_iter_init(struct ipoib_dev_priv *priv); +int ipoib_mcast_iter_next(struct ipoib_mcast_iter *iter); +void ipoib_mcast_iter_read(struct ipoib_mcast_iter *iter, + union ib_gid *gid, + unsigned long *created, + unsigned int *queuelen, + unsigned int *complete, + unsigned int *send_only); + +struct ipoib_path_iter *ipoib_path_iter_init(struct ipoib_dev_priv *priv); +int ipoib_path_iter_next(struct ipoib_path_iter *iter); +void ipoib_path_iter_read(struct ipoib_path_iter *iter, + struct ipoib_path *path); +#endif + +int ipoib_change_mtu(struct ipoib_dev_priv *priv, int new_mtu); + +int ipoib_mcast_attach(struct ipoib_dev_priv *priv, u16 mlid, + union ib_gid *mgid, int set_qkey); + +int ipoib_init_qp(struct ipoib_dev_priv *priv); +int ipoib_transport_dev_init(struct ipoib_dev_priv *priv, struct ib_device *ca); +void ipoib_transport_dev_cleanup(struct ipoib_dev_priv *priv); + +void ipoib_event(struct ib_event_handler *handler, + struct ib_event *record); + +void ipoib_pkey_poll(struct work_struct *work); +int ipoib_pkey_dev_delay_open(struct ipoib_dev_priv *priv); +void ipoib_drain_cq(struct ipoib_dev_priv *priv); + +int ipoib_dma_map_tx(struct ib_device *ca, struct ipoib_tx_buf *tx_req, int max); +void ipoib_dma_unmap_tx(struct ib_device *ca, struct ipoib_tx_buf *tx_req); +int ipoib_poll_tx(struct ipoib_dev_priv *priv); + +void ipoib_dma_unmap_rx(struct ipoib_dev_priv *priv, struct ipoib_rx_buf *rx_req); +void ipoib_dma_mb(struct ipoib_dev_priv *priv, struct mbuf *mb, unsigned int length); +struct mbuf *ipoib_alloc_map_mb(struct ipoib_dev_priv *priv, struct ipoib_rx_buf *rx_req, int size); + + +void ipoib_set_ethtool_ops(struct ifnet *dev); +int ipoib_set_dev_features(struct ipoib_dev_priv *priv, struct ib_device *hca); + +#ifdef CONFIG_INFINIBAND_IPOIB_CM + +#define IPOIB_FLAGS_RC 0x80 +#define IPOIB_FLAGS_UC 0x40 + +/* We don't support UC connections at the moment */ +#define IPOIB_CM_SUPPORTED(ha) (ha[0] & (IPOIB_FLAGS_RC)) + +extern int ipoib_max_conn_qp; + +static inline int ipoib_cm_admin_enabled(struct ipoib_dev_priv *priv) +{ + return IPOIB_CM_SUPPORTED(IF_LLADDR(priv->dev)); +} + +static inline int ipoib_cm_enabled(struct ipoib_dev_priv *priv, uint8_t *hwaddr) +{ + return IPOIB_CM_SUPPORTED(hwaddr); +} + +static inline int ipoib_cm_up(struct ipoib_path *path) + +{ + return test_bit(IPOIB_FLAG_OPER_UP, &path->cm->flags); +} + +static inline struct ipoib_cm_tx *ipoib_cm_get(struct ipoib_path *path) +{ + return path->cm; +} + +static inline void ipoib_cm_set(struct ipoib_path *path, struct ipoib_cm_tx *tx) +{ + path->cm = tx; +} + +static inline int ipoib_cm_has_srq(struct ipoib_dev_priv *priv) +{ + return !!priv->cm.srq; +} + +static inline unsigned int ipoib_cm_max_mtu(struct ipoib_dev_priv *priv) +{ + return priv->cm.max_cm_mtu; +} + +void ipoib_cm_send(struct ipoib_dev_priv *priv, struct mbuf *mb, struct ipoib_cm_tx *tx); +int ipoib_cm_dev_open(struct ipoib_dev_priv *priv); +void ipoib_cm_dev_stop(struct ipoib_dev_priv *priv); +int ipoib_cm_dev_init(struct ipoib_dev_priv *priv); +int ipoib_cm_add_mode_attr(struct ipoib_dev_priv *priv); +void ipoib_cm_dev_cleanup(struct ipoib_dev_priv *priv); +struct ipoib_cm_tx *ipoib_cm_create_tx(struct ipoib_dev_priv *priv, + struct ipoib_path *path); +void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx); +void ipoib_cm_mb_too_long(struct ipoib_dev_priv *priv, struct mbuf *mb, + unsigned int mtu); +void ipoib_cm_handle_rx_wc(struct ipoib_dev_priv *priv, struct ib_wc *wc); +void ipoib_cm_handle_tx_wc(struct ipoib_dev_priv *priv, struct ib_wc *wc); +#else + +struct ipoib_cm_tx; + +#define ipoib_max_conn_qp 0 + +static inline int ipoib_cm_admin_enabled(struct ipoib_dev_priv *priv) +{ + return 0; +} +static inline int ipoib_cm_enabled(struct ipoib_dev_priv *priv, uint8_t *hwaddr) + +{ + return 0; +} + +static inline int ipoib_cm_up(struct ipoib_path *path) + +{ + return 0; +} + +static inline struct ipoib_cm_tx *ipoib_cm_get(struct ipoib_path *path) +{ + return NULL; +} + +static inline void ipoib_cm_set(struct ipoib_path *path, struct ipoib_cm_tx *tx) +{ +} + +static inline int ipoib_cm_has_srq(struct ipoib_dev_priv *priv) +{ + return 0; +} + +static inline unsigned int ipoib_cm_max_mtu(struct ipoib_dev_priv *priv) +{ + return 0; +} + +static inline +void ipoib_cm_send(struct ipoib_dev_priv *priv, struct mbuf *mb, struct ipoib_cm_tx *tx) +{ + return; +} + +static inline +int ipoib_cm_dev_open(struct ipoib_dev_priv *priv) +{ + return 0; +} + +static inline +void ipoib_cm_dev_stop(struct ipoib_dev_priv *priv) +{ + return; +} + +static inline +int ipoib_cm_dev_init(struct ipoib_dev_priv *priv) +{ + return -ENOSYS; +} + +static inline +void ipoib_cm_dev_cleanup(struct ipoib_dev_priv *priv) +{ + return; +} + +static inline +struct ipoib_cm_tx *ipoib_cm_create_tx(struct ipoib_dev_priv *priv, struct ipoib_path *path) +{ + return NULL; +} + +static inline +void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx) +{ + return; +} + +static inline +int ipoib_cm_add_mode_attr(struct ipoib_dev_priv *priv) +{ + return 0; +} + +static inline void ipoib_cm_mb_too_long(struct ipoib_dev_priv *priv, struct mbuf *mb, + unsigned int mtu) +{ + m_freem(mb); +} + +static inline void ipoib_cm_handle_rx_wc(struct ipoib_dev_priv *priv, struct ib_wc *wc) +{ +} + +static inline void ipoib_cm_handle_tx_wc(struct ipoib_dev_priv *priv, struct ib_wc *wc) +{ +} +#endif + +#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG +void ipoib_create_debug_files(struct ipoib_dev_priv *priv); +void ipoib_delete_debug_files(struct ipoib_dev_priv *priv); +int ipoib_register_debugfs(void); +void ipoib_unregister_debugfs(void); +#else +static inline void ipoib_create_debug_files(struct ipoib_dev_priv *priv) { } +static inline void ipoib_delete_debug_files(struct ipoib_dev_priv *priv) { } +static inline int ipoib_register_debugfs(void) { return 0; } +static inline void ipoib_unregister_debugfs(void) { } +#endif + +#define ipoib_printk(level, priv, format, arg...) \ + printk(level "%s: " format, if_name(((struct ipoib_dev_priv *) priv)->dev), ## arg) +#define ipoib_warn(priv, format, arg...) \ + ipoib_printk(KERN_WARNING, priv, format , ## arg) + +extern int ipoib_sendq_size; +extern int ipoib_recvq_size; + +extern struct ib_sa_client ipoib_sa_client; + +#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG +extern int ipoib_debug_level; + +#define ipoib_dbg(priv, format, arg...) \ + do { \ + if (ipoib_debug_level > 0) \ + ipoib_printk(KERN_DEBUG, priv, format , ## arg); \ + } while (0) +#define ipoib_dbg_mcast(priv, format, arg...) \ + do { \ + if (mcast_debug_level > 0) \ + ipoib_printk(KERN_DEBUG, priv, format , ## arg); \ + } while (0) +#else /* CONFIG_INFINIBAND_IPOIB_DEBUG */ +#define ipoib_dbg(priv, format, arg...) \ + do { (void) (priv); } while (0) +#define ipoib_dbg_mcast(priv, format, arg...) \ + do { (void) (priv); } while (0) +#endif /* CONFIG_INFINIBAND_IPOIB_DEBUG */ + +#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA +#define ipoib_dbg_data(priv, format, arg...) \ + do { \ + if (data_debug_level > 0) \ + ipoib_printk(KERN_DEBUG, priv, format , ## arg); \ + } while (0) +#else /* CONFIG_INFINIBAND_IPOIB_DEBUG_DATA */ +#define ipoib_dbg_data(priv, format, arg...) \ + do { (void) (priv); } while (0) +#endif /* CONFIG_INFINIBAND_IPOIB_DEBUG_DATA */ + +#define IPOIB_QPN(ha) (be32_to_cpup((__be32 *) ha) & 0xffffff) + +#endif /* _IPOIB_H */ diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_cm.c new file mode 100644 index 000000000000..2d0fd61a43ed --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -0,0 +1,1445 @@ +/* + * Copyright (c) 2006 Mellanox Technologies. All rights reserved + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "ipoib.h" + +#ifdef CONFIG_INFINIBAND_IPOIB_CM + +#include +#include +#include + +#include +#include +#include + +int ipoib_max_conn_qp = 128; + +module_param_named(max_nonsrq_conn_qp, ipoib_max_conn_qp, int, 0444); +MODULE_PARM_DESC(max_nonsrq_conn_qp, + "Max number of connected-mode QPs per interface " + "(applied only if shared receive queue is not available)"); + +#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA +static int data_debug_level; + +module_param_named(cm_data_debug_level, data_debug_level, int, 0644); +MODULE_PARM_DESC(cm_data_debug_level, + "Enable data path debug tracing for connected mode if > 0"); +#endif + +#define IPOIB_CM_IETF_ID 0x1000000000000000ULL + +#define IPOIB_CM_RX_UPDATE_TIME (256 * HZ) +#define IPOIB_CM_RX_TIMEOUT (2 * 256 * HZ) +#define IPOIB_CM_RX_DELAY (3 * 256 * HZ) +#define IPOIB_CM_RX_UPDATE_MASK (0x3) + +static struct ib_qp_attr ipoib_cm_err_attr = { + .qp_state = IB_QPS_ERR +}; + +#define IPOIB_CM_RX_DRAIN_WRID 0xffffffff + +static struct ib_send_wr ipoib_cm_rx_drain_wr = { + .wr_id = IPOIB_CM_RX_DRAIN_WRID, + .opcode = IB_WR_SEND, +}; + +static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id, + struct ib_cm_event *event); + +static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv, struct ipoib_cm_rx_buf *rx_req) +{ + + ipoib_dma_unmap_rx(priv, (struct ipoib_rx_buf *)rx_req); + +} + +static int ipoib_cm_post_receive_srq(struct ipoib_dev_priv *priv, int id) +{ + struct ib_recv_wr *bad_wr; + struct ipoib_rx_buf *rx_req; + struct mbuf *m; + int ret; + int i; + + rx_req = (struct ipoib_rx_buf *)&priv->cm.srq_ring[id]; + for (m = rx_req->mb, i = 0; m != NULL; m = m->m_next, i++) { + priv->cm.rx_sge[i].addr = rx_req->mapping[i]; + priv->cm.rx_sge[i].length = m->m_len; + } + + priv->cm.rx_wr.num_sge = i; + priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV; + + ret = ib_post_srq_recv(priv->cm.srq, &priv->cm.rx_wr, &bad_wr); + if (unlikely(ret)) { + ipoib_warn(priv, "post srq failed for buf %d (%d)\n", id, ret); + ipoib_dma_unmap_rx(priv, rx_req); + m_freem(priv->cm.srq_ring[id].mb); + priv->cm.srq_ring[id].mb = NULL; + } + + return ret; +} + +static int ipoib_cm_post_receive_nonsrq(struct ipoib_dev_priv *priv, + struct ipoib_cm_rx *rx, + struct ib_recv_wr *wr, + struct ib_sge *sge, int id) +{ + struct ipoib_rx_buf *rx_req; + struct ib_recv_wr *bad_wr; + struct mbuf *m; + int ret; + int i; + + rx_req = (struct ipoib_rx_buf *)&rx->rx_ring[id]; + for (m = rx_req->mb, i = 0; m != NULL; m = m->m_next, i++) { + sge[i].addr = rx_req->mapping[i]; + sge[i].length = m->m_len; + } + + wr->num_sge = i; + wr->wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV; + + ret = ib_post_recv(rx->qp, wr, &bad_wr); + if (unlikely(ret)) { + ipoib_warn(priv, "post recv failed for buf %d (%d)\n", id, ret); + ipoib_dma_unmap_rx(priv, rx_req); + m_freem(rx->rx_ring[id].mb); + rx->rx_ring[id].mb = NULL; + } + + return ret; +} + +static struct mbuf * +ipoib_cm_alloc_rx_mb(struct ipoib_dev_priv *priv, struct ipoib_cm_rx_buf *rx_req) +{ + return ipoib_alloc_map_mb(priv, (struct ipoib_rx_buf *)rx_req, + priv->cm.max_cm_mtu); +} + +static void ipoib_cm_free_rx_ring(struct ipoib_dev_priv *priv, + struct ipoib_cm_rx_buf *rx_ring) +{ + int i; + + for (i = 0; i < ipoib_recvq_size; ++i) + if (rx_ring[i].mb) { + ipoib_cm_dma_unmap_rx(priv, &rx_ring[i]); + m_freem(rx_ring[i].mb); + } + + kfree(rx_ring); +} + +static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv *priv) +{ + struct ib_send_wr *bad_wr; + struct ipoib_cm_rx *p; + + /* We only reserved 1 extra slot in CQ for drain WRs, so + * make sure we have at most 1 outstanding WR. */ + if (list_empty(&priv->cm.rx_flush_list) || + !list_empty(&priv->cm.rx_drain_list)) + return; + + /* + * QPs on flush list are error state. This way, a "flush + * error" WC will be immediately generated for each WR we post. + */ + p = list_entry(priv->cm.rx_flush_list.next, typeof(*p), list); + if (ib_post_send(p->qp, &ipoib_cm_rx_drain_wr, &bad_wr)) + ipoib_warn(priv, "failed to post drain wr\n"); + + list_splice_init(&priv->cm.rx_flush_list, &priv->cm.rx_drain_list); +} + +static void ipoib_cm_rx_event_handler(struct ib_event *event, void *ctx) +{ + struct ipoib_cm_rx *p = ctx; + struct ipoib_dev_priv *priv = p->priv; + unsigned long flags; + + if (event->event != IB_EVENT_QP_LAST_WQE_REACHED) + return; + + spin_lock_irqsave(&priv->lock, flags); + list_move(&p->list, &priv->cm.rx_flush_list); + p->state = IPOIB_CM_RX_FLUSH; + ipoib_cm_start_rx_drain(priv); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static struct ib_qp *ipoib_cm_create_rx_qp(struct ipoib_dev_priv *priv, + struct ipoib_cm_rx *p) +{ + struct ib_qp_init_attr attr = { + .event_handler = ipoib_cm_rx_event_handler, + .send_cq = priv->recv_cq, /* For drain WR */ + .recv_cq = priv->recv_cq, + .srq = priv->cm.srq, + .cap.max_send_wr = 1, /* For drain WR */ + .cap.max_send_sge = 1, + .sq_sig_type = IB_SIGNAL_ALL_WR, + .qp_type = IB_QPT_RC, + .qp_context = p, + }; + + if (!ipoib_cm_has_srq(priv)) { + attr.cap.max_recv_wr = ipoib_recvq_size; + attr.cap.max_recv_sge = priv->cm.num_frags; + } + + return ib_create_qp(priv->pd, &attr); +} + +static int ipoib_cm_modify_rx_qp(struct ipoib_dev_priv *priv, + struct ib_cm_id *cm_id, struct ib_qp *qp, + unsigned psn) +{ + struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; + + qp_attr.qp_state = IB_QPS_INIT; + ret = ib_cm_init_qp_attr(cm_id, &qp_attr, &qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to init QP attr for INIT: %d\n", ret); + return ret; + } + ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to modify QP to INIT: %d\n", ret); + return ret; + } + qp_attr.qp_state = IB_QPS_RTR; + ret = ib_cm_init_qp_attr(cm_id, &qp_attr, &qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to init QP attr for RTR: %d\n", ret); + return ret; + } + qp_attr.rq_psn = psn; + ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to modify QP to RTR: %d\n", ret); + return ret; + } + + /* + * Current Mellanox HCA firmware won't generate completions + * with error for drain WRs unless the QP has been moved to + * RTS first. This work-around leaves a window where a QP has + * moved to error asynchronously, but this will eventually get + * fixed in firmware, so let's not error out if modify QP + * fails. + */ + qp_attr.qp_state = IB_QPS_RTS; + ret = ib_cm_init_qp_attr(cm_id, &qp_attr, &qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to init QP attr for RTS: %d\n", ret); + return 0; + } + ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to modify QP to RTS: %d\n", ret); + return 0; + } + + return 0; +} + +static void ipoib_cm_init_rx_wr(struct ipoib_dev_priv *priv, + struct ib_recv_wr *wr, + struct ib_sge *sge) +{ + int i; + + for (i = 0; i < IPOIB_CM_RX_SG; i++) + sge[i].lkey = priv->mr->lkey; + + wr->next = NULL; + wr->sg_list = sge; + wr->num_sge = 1; +} + +static int ipoib_cm_nonsrq_init_rx(struct ipoib_dev_priv *priv, + struct ib_cm_id *cm_id, struct ipoib_cm_rx *rx) +{ + struct { + struct ib_recv_wr wr; + struct ib_sge sge[IPOIB_CM_RX_SG]; + } *t; + int ret; + int i; + + rx->rx_ring = kzalloc(ipoib_recvq_size * sizeof *rx->rx_ring, GFP_KERNEL); + if (!rx->rx_ring) { + printk(KERN_WARNING "%s: failed to allocate CM non-SRQ ring (%d entries)\n", + priv->ca->name, ipoib_recvq_size); + return -ENOMEM; + } + + memset(rx->rx_ring, 0, ipoib_recvq_size * sizeof *rx->rx_ring); + + t = kmalloc(sizeof *t, GFP_KERNEL); + if (!t) { + ret = -ENOMEM; + goto err_free; + } + + ipoib_cm_init_rx_wr(priv, &t->wr, t->sge); + + spin_lock_irq(&priv->lock); + + if (priv->cm.nonsrq_conn_qp >= ipoib_max_conn_qp) { + spin_unlock_irq(&priv->lock); + ib_send_cm_rej(cm_id, IB_CM_REJ_NO_QP, NULL, 0, NULL, 0); + ret = -EINVAL; + goto err_free; + } else + ++priv->cm.nonsrq_conn_qp; + + spin_unlock_irq(&priv->lock); + + for (i = 0; i < ipoib_recvq_size; ++i) { + if (!ipoib_cm_alloc_rx_mb(priv, &rx->rx_ring[i])) { + ipoib_warn(priv, "failed to allocate receive buffer %d\n", i); + ret = -ENOMEM; + goto err_count; + } + ret = ipoib_cm_post_receive_nonsrq(priv, rx, &t->wr, t->sge, i); + if (ret) { + ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq " + "failed for buf %d\n", i); + ret = -EIO; + goto err_count; + } + } + + rx->recv_count = ipoib_recvq_size; + + kfree(t); + + return 0; + +err_count: + spin_lock_irq(&priv->lock); + --priv->cm.nonsrq_conn_qp; + spin_unlock_irq(&priv->lock); + +err_free: + kfree(t); + ipoib_cm_free_rx_ring(priv, rx->rx_ring); + + return ret; +} + +static int ipoib_cm_send_rep(struct ipoib_dev_priv *priv, struct ib_cm_id *cm_id, + struct ib_qp *qp, struct ib_cm_req_event_param *req, + unsigned psn) +{ + struct ipoib_cm_data data = {}; + struct ib_cm_rep_param rep = {}; + + data.qpn = cpu_to_be32(priv->qp->qp_num); + data.mtu = cpu_to_be32(priv->cm.max_cm_mtu); + + rep.private_data = &data; + rep.private_data_len = sizeof data; + rep.flow_control = 0; + rep.rnr_retry_count = req->rnr_retry_count; + rep.srq = ipoib_cm_has_srq(priv); + rep.qp_num = qp->qp_num; + rep.starting_psn = psn; + return ib_send_cm_rep(cm_id, &rep); +} + +static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) +{ + struct ipoib_dev_priv *priv = cm_id->context; + struct ipoib_cm_rx *p; + unsigned psn; + int ret; + + ipoib_dbg(priv, "REQ arrived\n"); + p = kzalloc(sizeof *p, GFP_KERNEL); + if (!p) + return -ENOMEM; + p->priv = priv; + p->id = cm_id; + cm_id->context = p; + p->state = IPOIB_CM_RX_LIVE; + p->jiffies = jiffies; + INIT_LIST_HEAD(&p->list); + + p->qp = ipoib_cm_create_rx_qp(priv, p); + if (IS_ERR(p->qp)) { + ret = PTR_ERR(p->qp); + goto err_qp; + } + + psn = random() & 0xffffff; + ret = ipoib_cm_modify_rx_qp(priv, cm_id, p->qp, psn); + if (ret) + goto err_modify; + + if (!ipoib_cm_has_srq(priv)) { + ret = ipoib_cm_nonsrq_init_rx(priv, cm_id, p); + if (ret) + goto err_modify; + } + + spin_lock_irq(&priv->lock); + queue_delayed_work(ipoib_workqueue, + &priv->cm.stale_task, IPOIB_CM_RX_DELAY); + /* Add this entry to passive ids list head, but do not re-add it + * if IB_EVENT_QP_LAST_WQE_REACHED has moved it to flush list. */ + p->jiffies = jiffies; + if (p->state == IPOIB_CM_RX_LIVE) + list_move(&p->list, &priv->cm.passive_ids); + spin_unlock_irq(&priv->lock); + + ret = ipoib_cm_send_rep(priv, cm_id, p->qp, &event->param.req_rcvd, psn); + if (ret) { + ipoib_warn(priv, "failed to send REP: %d\n", ret); + if (ib_modify_qp(p->qp, &ipoib_cm_err_attr, IB_QP_STATE)) + ipoib_warn(priv, "unable to move qp to error state\n"); + } + return 0; + +err_modify: + ib_destroy_qp(p->qp); +err_qp: + kfree(p); + return ret; +} + +static int ipoib_cm_rx_handler(struct ib_cm_id *cm_id, + struct ib_cm_event *event) +{ + struct ipoib_cm_rx *p; + struct ipoib_dev_priv *priv; + + switch (event->event) { + case IB_CM_REQ_RECEIVED: + return ipoib_cm_req_handler(cm_id, event); + case IB_CM_DREQ_RECEIVED: + p = cm_id->context; + ib_send_cm_drep(cm_id, NULL, 0); + /* Fall through */ + case IB_CM_REJ_RECEIVED: + p = cm_id->context; + priv = p->priv; + if (ib_modify_qp(p->qp, &ipoib_cm_err_attr, IB_QP_STATE)) + ipoib_warn(priv, "unable to move qp to error state\n"); + /* Fall through */ + default: + return 0; + } +} + +void ipoib_cm_handle_rx_wc(struct ipoib_dev_priv *priv, struct ib_wc *wc) +{ + struct ipoib_cm_rx_buf saverx; + struct ipoib_cm_rx_buf *rx_ring; + unsigned int wr_id = wc->wr_id & ~(IPOIB_OP_CM | IPOIB_OP_RECV); + struct ifnet *dev = priv->dev; + struct mbuf *mb, *newmb; + struct ipoib_cm_rx *p; + int has_srq; + u_short proto; + + ipoib_dbg_data(priv, "cm recv completion: id %d, status: %d\n", + wr_id, wc->status); + + if (unlikely(wr_id >= ipoib_recvq_size)) { + if (wr_id == (IPOIB_CM_RX_DRAIN_WRID & ~(IPOIB_OP_CM | IPOIB_OP_RECV))) { + spin_lock(&priv->lock); + list_splice_init(&priv->cm.rx_drain_list, &priv->cm.rx_reap_list); + ipoib_cm_start_rx_drain(priv); + if (priv->cm.id != NULL) + queue_work(ipoib_workqueue, + &priv->cm.rx_reap_task); + spin_unlock(&priv->lock); + } else + ipoib_warn(priv, "cm recv completion event with wrid %d (> %d)\n", + wr_id, ipoib_recvq_size); + return; + } + + p = wc->qp->qp_context; + + has_srq = ipoib_cm_has_srq(priv); + rx_ring = has_srq ? priv->cm.srq_ring : p->rx_ring; + + mb = rx_ring[wr_id].mb; + + if (unlikely(wc->status != IB_WC_SUCCESS)) { + ipoib_dbg(priv, "cm recv error " + "(status=%d, wrid=%d vend_err %x)\n", + wc->status, wr_id, wc->vendor_err); + ++dev->if_ierrors; + if (has_srq) + goto repost; + else { + if (!--p->recv_count) { + spin_lock(&priv->lock); + list_move(&p->list, &priv->cm.rx_reap_list); + queue_work(ipoib_workqueue, &priv->cm.rx_reap_task); + spin_unlock(&priv->lock); + } + return; + } + } + + if (unlikely(!(wr_id & IPOIB_CM_RX_UPDATE_MASK))) { + if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) { + p->jiffies = jiffies; + /* Move this entry to list head, but do not re-add it + * if it has been moved out of list. */ + if (p->state == IPOIB_CM_RX_LIVE) + list_move(&p->list, &priv->cm.passive_ids); + } + } + + memcpy(&saverx, &rx_ring[wr_id], sizeof(saverx)); + newmb = ipoib_cm_alloc_rx_mb(priv, &rx_ring[wr_id]); + if (unlikely(!newmb)) { + /* + * If we can't allocate a new RX buffer, dump + * this packet and reuse the old buffer. + */ + ipoib_dbg(priv, "failed to allocate receive buffer %d\n", wr_id); + ++dev->if_ierrors; + memcpy(&rx_ring[wr_id], &saverx, sizeof(saverx)); + goto repost; + } + + ipoib_cm_dma_unmap_rx(priv, &saverx); + + ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n", + wc->byte_len, wc->slid); + + ipoib_dma_mb(priv, mb, wc->byte_len); + + ++dev->if_opackets; + dev->if_obytes += mb->m_pkthdr.len; + + mb->m_pkthdr.rcvif = dev; + proto = *mtod(mb, uint16_t *); + m_adj(mb, IPOIB_ENCAP_LEN); + + IPOIB_MTAP_PROTO(dev, mb, proto); + ipoib_demux(dev, mb, ntohs(proto)); + +repost: + if (has_srq) { + if (unlikely(ipoib_cm_post_receive_srq(priv, wr_id))) + ipoib_warn(priv, "ipoib_cm_post_receive_srq failed " + "for buf %d\n", wr_id); + } else { + if (unlikely(ipoib_cm_post_receive_nonsrq(priv, p, + &priv->cm.rx_wr, + priv->cm.rx_sge, + wr_id))) { + --p->recv_count; + ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq failed " + "for buf %d\n", wr_id); + } + } +} + +static inline int post_send(struct ipoib_dev_priv *priv, + struct ipoib_cm_tx *tx, + struct ipoib_cm_tx_buf *tx_req, + unsigned int wr_id) +{ + struct ib_send_wr *bad_wr; + struct mbuf *mb = tx_req->mb; + u64 *mapping = tx_req->mapping; + struct mbuf *m; + int i; + + for (m = mb, i = 0; m != NULL; m = m->m_next, i++) { + priv->tx_sge[i].addr = mapping[i]; + priv->tx_sge[i].length = m->m_len; + } + priv->tx_wr.num_sge = i; + priv->tx_wr.wr_id = wr_id | IPOIB_OP_CM; + priv->tx_wr.opcode = IB_WR_SEND; + + return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr); +} + +void ipoib_cm_send(struct ipoib_dev_priv *priv, struct mbuf *mb, struct ipoib_cm_tx *tx) +{ + struct ipoib_cm_tx_buf *tx_req; + struct ifnet *dev = priv->dev; + + if (unlikely(priv->tx_outstanding > MAX_SEND_CQE)) + while (ipoib_poll_tx(priv)); /* nothing */ + + m_adj(mb, sizeof(struct ipoib_pseudoheader)); + if (unlikely(mb->m_pkthdr.len > tx->mtu)) { + ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n", + mb->m_pkthdr.len, tx->mtu); + ++dev->if_oerrors; + ipoib_cm_mb_too_long(priv, mb, IPOIB_CM_MTU(tx->mtu)); + return; + } + + ipoib_dbg_data(priv, "sending packet: head 0x%x length %d connection 0x%x\n", + tx->tx_head, mb->m_pkthdr.len, tx->qp->qp_num); + + + /* + * We put the mb into the tx_ring _before_ we call post_send() + * because it's entirely possible that the completion handler will + * run before we execute anything after the post_send(). That + * means we have to make sure everything is properly recorded and + * our state is consistent before we call post_send(). + */ + tx_req = &tx->tx_ring[tx->tx_head & (ipoib_sendq_size - 1)]; + tx_req->mb = mb; + if (unlikely(ipoib_dma_map_tx(priv->ca, (struct ipoib_tx_buf *)tx_req, + priv->cm.num_frags))) { + ++dev->if_oerrors; + if (tx_req->mb) + m_freem(tx_req->mb); + return; + } + + if (unlikely(post_send(priv, tx, tx_req, tx->tx_head & (ipoib_sendq_size - 1)))) { + ipoib_warn(priv, "post_send failed\n"); + ++dev->if_oerrors; + ipoib_dma_unmap_tx(priv->ca, (struct ipoib_tx_buf *)tx_req); + m_freem(mb); + } else { + ++tx->tx_head; + + if (++priv->tx_outstanding == ipoib_sendq_size) { + ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n", + tx->qp->qp_num); + if (ib_req_notify_cq(priv->send_cq, IB_CQ_NEXT_COMP)) + ipoib_warn(priv, "request notify on send CQ failed\n"); + dev->if_drv_flags |= IFF_DRV_OACTIVE; + } + } + +} + +void ipoib_cm_handle_tx_wc(struct ipoib_dev_priv *priv, struct ib_wc *wc) +{ + struct ipoib_cm_tx *tx = wc->qp->qp_context; + unsigned int wr_id = wc->wr_id & ~IPOIB_OP_CM; + struct ifnet *dev = priv->dev; + struct ipoib_cm_tx_buf *tx_req; + + ipoib_dbg_data(priv, "cm send completion: id %d, status: %d\n", + wr_id, wc->status); + + if (unlikely(wr_id >= ipoib_sendq_size)) { + ipoib_warn(priv, "cm send completion event with wrid %d (> %d)\n", + wr_id, ipoib_sendq_size); + return; + } + + tx_req = &tx->tx_ring[wr_id]; + + ipoib_dma_unmap_tx(priv->ca, (struct ipoib_tx_buf *)tx_req); + + /* FIXME: is this right? Shouldn't we only increment on success? */ + ++dev->if_opackets; + dev->if_obytes += tx_req->mb->m_pkthdr.len; + + m_freem(tx_req->mb); + + ++tx->tx_tail; + if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) && + (dev->if_drv_flags & IFF_DRV_OACTIVE) != 0 && + test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) + dev->if_drv_flags &= ~IFF_DRV_OACTIVE; + + if (wc->status != IB_WC_SUCCESS && + wc->status != IB_WC_WR_FLUSH_ERR) { + struct ipoib_path *path; + + ipoib_dbg(priv, "failed cm send event " + "(status=%d, wrid=%d vend_err %x)\n", + wc->status, wr_id, wc->vendor_err); + + path = tx->path; + + if (path) { + path->cm = NULL; + rb_erase(&path->rb_node, &priv->path_tree); + list_del(&path->list); + } + + if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) { + list_move(&tx->list, &priv->cm.reap_list); + queue_work(ipoib_workqueue, &priv->cm.reap_task); + } + + clear_bit(IPOIB_FLAG_OPER_UP, &tx->flags); + } + +} + +int ipoib_cm_dev_open(struct ipoib_dev_priv *priv) +{ + int ret; + + if (!IPOIB_CM_SUPPORTED(IF_LLADDR(priv->dev))) + return 0; + + priv->cm.id = ib_create_cm_id(priv->ca, ipoib_cm_rx_handler, priv); + if (IS_ERR(priv->cm.id)) { + printk(KERN_WARNING "%s: failed to create CM ID\n", priv->ca->name); + ret = PTR_ERR(priv->cm.id); + goto err_cm; + } + + ret = ib_cm_listen(priv->cm.id, cpu_to_be64(IPOIB_CM_IETF_ID | priv->qp->qp_num), + 0, NULL); + if (ret) { + printk(KERN_WARNING "%s: failed to listen on ID 0x%llx\n", priv->ca->name, + IPOIB_CM_IETF_ID | priv->qp->qp_num); + goto err_listen; + } + + return 0; + +err_listen: + ib_destroy_cm_id(priv->cm.id); +err_cm: + priv->cm.id = NULL; + return ret; +} + +static void ipoib_cm_free_rx_reap_list(struct ipoib_dev_priv *priv) +{ + struct ipoib_cm_rx *rx, *n; + LIST_HEAD(list); + + spin_lock_irq(&priv->lock); + list_splice_init(&priv->cm.rx_reap_list, &list); + spin_unlock_irq(&priv->lock); + + list_for_each_entry_safe(rx, n, &list, list) { + ib_destroy_cm_id(rx->id); + ib_destroy_qp(rx->qp); + if (!ipoib_cm_has_srq(priv)) { + ipoib_cm_free_rx_ring(priv, rx->rx_ring); + spin_lock_irq(&priv->lock); + --priv->cm.nonsrq_conn_qp; + spin_unlock_irq(&priv->lock); + } + kfree(rx); + } +} + +void ipoib_cm_dev_stop(struct ipoib_dev_priv *priv) +{ + struct ipoib_cm_rx *p; + unsigned long begin; + int ret; + + if (!IPOIB_CM_SUPPORTED(IF_LLADDR(priv->dev)) || !priv->cm.id) + return; + + ib_destroy_cm_id(priv->cm.id); + priv->cm.id = NULL; + + cancel_work_sync(&priv->cm.rx_reap_task); + + spin_lock_irq(&priv->lock); + while (!list_empty(&priv->cm.passive_ids)) { + p = list_entry(priv->cm.passive_ids.next, typeof(*p), list); + list_move(&p->list, &priv->cm.rx_error_list); + p->state = IPOIB_CM_RX_ERROR; + spin_unlock_irq(&priv->lock); + ret = ib_modify_qp(p->qp, &ipoib_cm_err_attr, IB_QP_STATE); + if (ret) + ipoib_warn(priv, "unable to move qp to error state: %d\n", ret); + spin_lock_irq(&priv->lock); + } + + /* Wait for all RX to be drained */ + begin = jiffies; + + while (!list_empty(&priv->cm.rx_error_list) || + !list_empty(&priv->cm.rx_flush_list) || + !list_empty(&priv->cm.rx_drain_list)) { + if (time_after(jiffies, begin + 5 * HZ)) { + ipoib_warn(priv, "RX drain timing out\n"); + + /* + * assume the HW is wedged and just free up everything. + */ + list_splice_init(&priv->cm.rx_flush_list, + &priv->cm.rx_reap_list); + list_splice_init(&priv->cm.rx_error_list, + &priv->cm.rx_reap_list); + list_splice_init(&priv->cm.rx_drain_list, + &priv->cm.rx_reap_list); + break; + } + spin_unlock_irq(&priv->lock); + msleep(1); + ipoib_drain_cq(priv); + spin_lock_irq(&priv->lock); + } + + spin_unlock_irq(&priv->lock); + + ipoib_cm_free_rx_reap_list(priv); + + cancel_delayed_work(&priv->cm.stale_task); +} + +static int ipoib_cm_rep_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) +{ + struct ipoib_cm_tx *p = cm_id->context; + struct ipoib_dev_priv *priv = p->priv; + struct ipoib_cm_data *data = event->private_data; + struct ifqueue mbqueue; + struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; + struct mbuf *mb; + + ipoib_dbg(priv, "cm rep handler\n"); + p->mtu = be32_to_cpu(data->mtu); + + if (p->mtu <= IPOIB_ENCAP_LEN) { + ipoib_warn(priv, "Rejecting connection: mtu %d <= %d\n", + p->mtu, IPOIB_ENCAP_LEN); + return -EINVAL; + } + + qp_attr.qp_state = IB_QPS_RTR; + ret = ib_cm_init_qp_attr(cm_id, &qp_attr, &qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to init QP attr for RTR: %d\n", ret); + return ret; + } + + qp_attr.rq_psn = 0 /* FIXME */; + ret = ib_modify_qp(p->qp, &qp_attr, qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to modify QP to RTR: %d\n", ret); + return ret; + } + + qp_attr.qp_state = IB_QPS_RTS; + ret = ib_cm_init_qp_attr(cm_id, &qp_attr, &qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to init QP attr for RTS: %d\n", ret); + return ret; + } + ret = ib_modify_qp(p->qp, &qp_attr, qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to modify QP to RTS: %d\n", ret); + return ret; + } + + bzero(&mbqueue, sizeof(mbqueue)); + + spin_lock_irq(&priv->lock); + set_bit(IPOIB_FLAG_OPER_UP, &p->flags); + if (p->path) + for (;;) { + _IF_DEQUEUE(&p->path->queue, mb); + if (mb == NULL) + break; + _IF_ENQUEUE(&mbqueue, mb); + } + spin_unlock_irq(&priv->lock); + + for (;;) { + struct ifnet *dev = p->priv->dev; + _IF_DEQUEUE(&mbqueue, mb); + if (mb == NULL) + break; + mb->m_pkthdr.rcvif = dev; + if (dev->if_transmit(dev, mb)) + ipoib_warn(priv, "dev_queue_xmit failed " + "to requeue packet\n"); + } + + ret = ib_send_cm_rtu(cm_id, NULL, 0); + if (ret) { + ipoib_warn(priv, "failed to send RTU: %d\n", ret); + return ret; + } + return 0; +} + +static struct ib_qp *ipoib_cm_create_tx_qp(struct ipoib_dev_priv *priv, + struct ipoib_cm_tx *tx) +{ + struct ib_qp_init_attr attr = { + .send_cq = priv->send_cq, + .recv_cq = priv->recv_cq, + .srq = priv->cm.srq, + .cap.max_send_wr = ipoib_sendq_size, + .cap.max_send_sge = priv->cm.num_frags, + .sq_sig_type = IB_SIGNAL_ALL_WR, + .qp_type = IB_QPT_RC, + .qp_context = tx + }; + + return ib_create_qp(priv->pd, &attr); +} + +static int ipoib_cm_send_req(struct ipoib_dev_priv *priv, + struct ib_cm_id *id, struct ib_qp *qp, + u32 qpn, + struct ib_sa_path_rec *pathrec) +{ + struct ipoib_cm_data data = {}; + struct ib_cm_req_param req = {}; + + ipoib_dbg(priv, "cm send req\n"); + + data.qpn = cpu_to_be32(priv->qp->qp_num); + data.mtu = cpu_to_be32(priv->cm.max_cm_mtu); + + req.primary_path = pathrec; + req.alternate_path = NULL; + req.service_id = cpu_to_be64(IPOIB_CM_IETF_ID | qpn); + req.qp_num = qp->qp_num; + req.qp_type = qp->qp_type; + req.private_data = &data; + req.private_data_len = sizeof data; + req.flow_control = 0; + + req.starting_psn = 0; /* FIXME */ + + /* + * Pick some arbitrary defaults here; we could make these + * module parameters if anyone cared about setting them. + */ + req.responder_resources = 4; + req.remote_cm_response_timeout = 20; + req.local_cm_response_timeout = 20; + req.retry_count = 0; /* RFC draft warns against retries */ + req.rnr_retry_count = 0; /* RFC draft warns against retries */ + req.max_cm_retries = 15; + req.srq = ipoib_cm_has_srq(priv); + return ib_send_cm_req(id, &req); +} + +static int ipoib_cm_modify_tx_init(struct ipoib_dev_priv *priv, + struct ib_cm_id *cm_id, struct ib_qp *qp) +{ + struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; + ret = ib_find_pkey(priv->ca, priv->port, priv->pkey, &qp_attr.pkey_index); + if (ret) { + ipoib_warn(priv, "pkey 0x%x not found: %d\n", priv->pkey, ret); + return ret; + } + + qp_attr.qp_state = IB_QPS_INIT; + qp_attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE; + qp_attr.port_num = priv->port; + qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX | IB_QP_PORT; + + ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); + if (ret) { + ipoib_warn(priv, "failed to modify tx QP to INIT: %d\n", ret); + return ret; + } + return 0; +} + +static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn, + struct ib_sa_path_rec *pathrec) +{ + struct ipoib_dev_priv *priv = p->priv; + int ret; + + p->tx_ring = kzalloc(ipoib_sendq_size * sizeof *p->tx_ring, GFP_KERNEL); + if (!p->tx_ring) { + ipoib_warn(priv, "failed to allocate tx ring\n"); + ret = -ENOMEM; + goto err_tx; + } + memset(p->tx_ring, 0, ipoib_sendq_size * sizeof *p->tx_ring); + + p->qp = ipoib_cm_create_tx_qp(p->priv, p); + if (IS_ERR(p->qp)) { + ret = PTR_ERR(p->qp); + ipoib_warn(priv, "failed to allocate tx qp: %d\n", ret); + goto err_qp; + } + + p->id = ib_create_cm_id(priv->ca, ipoib_cm_tx_handler, p); + if (IS_ERR(p->id)) { + ret = PTR_ERR(p->id); + ipoib_warn(priv, "failed to create tx cm id: %d\n", ret); + goto err_id; + } + + ret = ipoib_cm_modify_tx_init(p->priv, p->id, p->qp); + if (ret) { + ipoib_warn(priv, "failed to modify tx qp to rtr: %d\n", ret); + goto err_modify; + } + + ret = ipoib_cm_send_req(p->priv, p->id, p->qp, qpn, pathrec); + if (ret) { + ipoib_warn(priv, "failed to send cm req: %d\n", ret); + goto err_send_cm; + } + + ipoib_dbg(priv, "Request connection 0x%x for gid %pI6 qpn 0x%x\n", + p->qp->qp_num, pathrec->dgid.raw, qpn); + + return 0; + +err_send_cm: +err_modify: + ib_destroy_cm_id(p->id); +err_id: + p->id = NULL; + ib_destroy_qp(p->qp); +err_qp: + p->qp = NULL; + kfree(p->tx_ring); +err_tx: + return ret; +} + +static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p) +{ + struct ipoib_dev_priv *priv = p->priv; + struct ifnet *dev = priv->dev; + struct ipoib_cm_tx_buf *tx_req; + unsigned long begin; + + ipoib_dbg(priv, "Destroy active connection 0x%x head 0x%x tail 0x%x\n", + p->qp ? p->qp->qp_num : 0, p->tx_head, p->tx_tail); + + if (p->path) + ipoib_path_free(priv, p->path); + + if (p->id) + ib_destroy_cm_id(p->id); + + if (p->tx_ring) { + /* Wait for all sends to complete */ + begin = jiffies; + while ((int) p->tx_tail - (int) p->tx_head < 0) { + if (time_after(jiffies, begin + 5 * HZ)) { + ipoib_warn(priv, "timing out; %d sends not completed\n", + p->tx_head - p->tx_tail); + goto timeout; + } + + msleep(1); + } + } + +timeout: + + while ((int) p->tx_tail - (int) p->tx_head < 0) { + tx_req = &p->tx_ring[p->tx_tail & (ipoib_sendq_size - 1)]; + ipoib_dma_unmap_tx(priv->ca, (struct ipoib_tx_buf *)tx_req); + m_freem(tx_req->mb); + ++p->tx_tail; + if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) && + (dev->if_drv_flags & IFF_DRV_OACTIVE) != 0 && + test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) + dev->if_drv_flags &= ~IFF_DRV_OACTIVE; + } + + if (p->qp) + ib_destroy_qp(p->qp); + + kfree(p->tx_ring); + kfree(p); +} + +static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id, + struct ib_cm_event *event) +{ + struct ipoib_cm_tx *tx = cm_id->context; + struct ipoib_dev_priv *priv = tx->priv; + struct ipoib_path *path; + unsigned long flags; + int ret; + + switch (event->event) { + case IB_CM_DREQ_RECEIVED: + ipoib_dbg(priv, "DREQ received.\n"); + ib_send_cm_drep(cm_id, NULL, 0); + break; + case IB_CM_REP_RECEIVED: + ipoib_dbg(priv, "REP received.\n"); + ret = ipoib_cm_rep_handler(cm_id, event); + if (ret) + ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED, + NULL, 0, NULL, 0); + break; + case IB_CM_REQ_ERROR: + case IB_CM_REJ_RECEIVED: + case IB_CM_TIMEWAIT_EXIT: + ipoib_dbg(priv, "CM error %d.\n", event->event); + spin_lock_irqsave(&priv->lock, flags); + path = tx->path; + + if (path) { + path->cm = NULL; + tx->path = NULL; + rb_erase(&path->rb_node, &priv->path_tree); + list_del(&path->list); + } + + if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) { + list_move(&tx->list, &priv->cm.reap_list); + queue_work(ipoib_workqueue, &priv->cm.reap_task); + } + + spin_unlock_irqrestore(&priv->lock, flags); + if (path) + ipoib_path_free(tx->priv, path); + break; + default: + break; + } + + return 0; +} + +struct ipoib_cm_tx *ipoib_cm_create_tx(struct ipoib_dev_priv *priv, + struct ipoib_path *path) +{ + struct ipoib_cm_tx *tx; + + tx = kzalloc(sizeof *tx, GFP_ATOMIC); + if (!tx) + return NULL; + + ipoib_dbg(priv, "Creating cm tx\n"); + path->cm = tx; + tx->path = path; + tx->priv = priv; + list_add(&tx->list, &priv->cm.start_list); + set_bit(IPOIB_FLAG_INITIALIZED, &tx->flags); + queue_work(ipoib_workqueue, &priv->cm.start_task); + return tx; +} + +void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx) +{ + struct ipoib_dev_priv *priv = tx->priv; + if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) { + spin_lock(&priv->lock); + list_move(&tx->list, &priv->cm.reap_list); + spin_unlock(&priv->lock); + queue_work(ipoib_workqueue, &priv->cm.reap_task); + ipoib_dbg(priv, "Reap connection for gid %pI6\n", + tx->path->pathrec.dgid.raw); + tx->path = NULL; + } +} + +static void ipoib_cm_tx_start(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, + cm.start_task); + struct ipoib_path *path; + struct ipoib_cm_tx *p; + unsigned long flags; + int ret; + + struct ib_sa_path_rec pathrec; + u32 qpn; + + ipoib_dbg(priv, "cm start task\n"); + spin_lock_irqsave(&priv->lock, flags); + + while (!list_empty(&priv->cm.start_list)) { + p = list_entry(priv->cm.start_list.next, typeof(*p), list); + list_del_init(&p->list); + path = p->path; + qpn = IPOIB_QPN(path->hwaddr); + memcpy(&pathrec, &p->path->pathrec, sizeof pathrec); + + spin_unlock_irqrestore(&priv->lock, flags); + + ret = ipoib_cm_tx_init(p, qpn, &pathrec); + + spin_lock_irqsave(&priv->lock, flags); + + if (ret) { + path = p->path; + if (path) { + path->cm = NULL; + rb_erase(&path->rb_node, &priv->path_tree); + list_del(&path->list); + ipoib_path_free(priv, path); + } + list_del(&p->list); + kfree(p); + } + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void ipoib_cm_tx_reap(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, + cm.reap_task); + struct ipoib_cm_tx *p; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + while (!list_empty(&priv->cm.reap_list)) { + p = list_entry(priv->cm.reap_list.next, typeof(*p), list); + list_del(&p->list); + spin_unlock_irqrestore(&priv->lock, flags); + ipoib_cm_tx_destroy(p); + spin_lock_irqsave(&priv->lock, flags); + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void ipoib_cm_mb_reap(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, + cm.mb_task); + struct mbuf *mb; + unsigned long flags; + unsigned mtu = priv->mcast_mtu; + uint16_t proto; + + spin_lock_irqsave(&priv->lock, flags); + + for (;;) { + IF_DEQUEUE(&priv->cm.mb_queue, mb); + if (mb == NULL) + break; + spin_unlock_irqrestore(&priv->lock, flags); + + proto = htons(*mtod(mb, uint16_t *)); + m_adj(mb, IPOIB_ENCAP_LEN); + if (proto == ETHERTYPE_IP) + icmp_error(mb, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0, mtu); +#if defined(INET6) + else if (proto == ETHERTYPE_IPV6) + icmp6_error(mb, ICMP6_PACKET_TOO_BIG, 0, mtu); +#endif + else + m_freem(mb); + + spin_lock_irqsave(&priv->lock, flags); + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +void +ipoib_cm_mb_too_long(struct ipoib_dev_priv *priv, struct mbuf *mb, unsigned int mtu) +{ + int e = priv->cm.mb_queue.ifq_len; + + IF_ENQUEUE(&priv->cm.mb_queue, mb); + if (e == 0) + queue_work(ipoib_workqueue, &priv->cm.mb_task); +} + +static void ipoib_cm_rx_reap(struct work_struct *work) +{ + ipoib_cm_free_rx_reap_list(container_of(work, struct ipoib_dev_priv, + cm.rx_reap_task)); +} + +static void ipoib_cm_stale_task(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, + cm.stale_task.work); + struct ipoib_cm_rx *p; + int ret; + + spin_lock_irq(&priv->lock); + while (!list_empty(&priv->cm.passive_ids)) { + /* List is sorted by LRU, start from tail, + * stop when we see a recently used entry */ + p = list_entry(priv->cm.passive_ids.prev, typeof(*p), list); + if (time_before_eq(jiffies, p->jiffies + IPOIB_CM_RX_TIMEOUT)) + break; + list_move(&p->list, &priv->cm.rx_error_list); + p->state = IPOIB_CM_RX_ERROR; + spin_unlock_irq(&priv->lock); + ret = ib_modify_qp(p->qp, &ipoib_cm_err_attr, IB_QP_STATE); + if (ret) + ipoib_warn(priv, "unable to move qp to error state: %d\n", ret); + spin_lock_irq(&priv->lock); + } + + if (!list_empty(&priv->cm.passive_ids)) + queue_delayed_work(ipoib_workqueue, + &priv->cm.stale_task, IPOIB_CM_RX_DELAY); + spin_unlock_irq(&priv->lock); +} + + +static void ipoib_cm_create_srq(struct ipoib_dev_priv *priv, int max_sge) +{ + struct ib_srq_init_attr srq_init_attr = { + .attr = { + .max_wr = ipoib_recvq_size, + .max_sge = max_sge + } + }; + + priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr); + if (IS_ERR(priv->cm.srq)) { + if (PTR_ERR(priv->cm.srq) != -ENOSYS) + printk(KERN_WARNING "%s: failed to allocate SRQ, error %ld\n", + priv->ca->name, PTR_ERR(priv->cm.srq)); + priv->cm.srq = NULL; + return; + } + + priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring, GFP_KERNEL); + if (!priv->cm.srq_ring) { + printk(KERN_WARNING "%s: failed to allocate CM SRQ ring (%d entries)\n", + priv->ca->name, ipoib_recvq_size); + ib_destroy_srq(priv->cm.srq); + priv->cm.srq = NULL; + return; + } + + memset(priv->cm.srq_ring, 0, ipoib_recvq_size * sizeof *priv->cm.srq_ring); +} + +int ipoib_cm_dev_init(struct ipoib_dev_priv *priv) +{ + struct ifnet *dev = priv->dev; + int i, ret; + struct ib_device_attr attr; + + INIT_LIST_HEAD(&priv->cm.passive_ids); + INIT_LIST_HEAD(&priv->cm.reap_list); + INIT_LIST_HEAD(&priv->cm.start_list); + INIT_LIST_HEAD(&priv->cm.rx_error_list); + INIT_LIST_HEAD(&priv->cm.rx_flush_list); + INIT_LIST_HEAD(&priv->cm.rx_drain_list); + INIT_LIST_HEAD(&priv->cm.rx_reap_list); + INIT_WORK(&priv->cm.start_task, ipoib_cm_tx_start); + INIT_WORK(&priv->cm.reap_task, ipoib_cm_tx_reap); + INIT_WORK(&priv->cm.mb_task, ipoib_cm_mb_reap); + INIT_WORK(&priv->cm.rx_reap_task, ipoib_cm_rx_reap); + INIT_DELAYED_WORK(&priv->cm.stale_task, ipoib_cm_stale_task); + + bzero(&priv->cm.mb_queue, sizeof(priv->cm.mb_queue)); + mtx_init(&priv->cm.mb_queue.ifq_mtx, + dev->if_xname, "if send queue", MTX_DEF); + + ret = ib_query_device(priv->ca, &attr); + if (ret) { + printk(KERN_WARNING "ib_query_device() failed with %d\n", ret); + return ret; + } + + ipoib_dbg(priv, "max_srq_sge=%d\n", attr.max_srq_sge); + + attr.max_srq_sge = min_t(int, IPOIB_CM_RX_SG, attr.max_srq_sge); + ipoib_cm_create_srq(priv, attr.max_srq_sge); + if (ipoib_cm_has_srq(priv)) { + priv->cm.max_cm_mtu = attr.max_srq_sge * MJUMPAGESIZE; + priv->cm.num_frags = attr.max_srq_sge; + ipoib_dbg(priv, "max_cm_mtu = 0x%x, num_frags=%d\n", + priv->cm.max_cm_mtu, priv->cm.num_frags); + } else { + priv->cm.max_cm_mtu = IPOIB_CM_MAX_MTU; + priv->cm.num_frags = IPOIB_CM_RX_SG; + } + + ipoib_cm_init_rx_wr(priv, &priv->cm.rx_wr, priv->cm.rx_sge); + + if (ipoib_cm_has_srq(priv)) { + for (i = 0; i < ipoib_recvq_size; ++i) { + if (!ipoib_cm_alloc_rx_mb(priv, &priv->cm.srq_ring[i])) { + ipoib_warn(priv, "failed to allocate " + "receive buffer %d\n", i); + ipoib_cm_dev_cleanup(priv); + return -ENOMEM; + } + + if (ipoib_cm_post_receive_srq(priv, i)) { + ipoib_warn(priv, "ipoib_cm_post_receive_srq " + "failed for buf %d\n", i); + ipoib_cm_dev_cleanup(priv); + return -EIO; + } + } + } + + IF_LLADDR(priv->dev)[0] = IPOIB_FLAGS_RC; + return 0; +} + +void ipoib_cm_dev_cleanup(struct ipoib_dev_priv *priv) +{ + int ret; + + if (!priv->cm.srq) + return; + + ipoib_dbg(priv, "Cleanup ipoib connected mode.\n"); + + ret = ib_destroy_srq(priv->cm.srq); + if (ret) + ipoib_warn(priv, "ib_destroy_srq failed: %d\n", ret); + + priv->cm.srq = NULL; + if (!priv->cm.srq_ring) + return; + + ipoib_cm_free_rx_ring(priv, priv->cm.srq_ring); + priv->cm.srq_ring = NULL; + + mtx_destroy(&priv->cm.mb_queue.ifq_mtx); +} + +#endif /* CONFIG_INFINIBAND_IPOIB_CM */ diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c new file mode 100644 index 000000000000..ec52712db235 --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "ipoib.h" + +static void ipoib_get_drvinfo(struct ifnet *netdev, + struct ethtool_drvinfo *drvinfo) +{ + strncpy(drvinfo->driver, "ipoib", sizeof(drvinfo->driver) - 1); +} + +static u32 ipoib_get_rx_csum(struct ifnet *dev) +{ + struct ipoib_dev_priv *priv = dev->if_softc; + return test_bit(IPOIB_FLAG_CSUM, &priv->flags) && + !test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); +} + +static int ipoib_get_coalesce(struct ifnet *dev, + struct ethtool_coalesce *coal) +{ + struct ipoib_dev_priv *priv = dev->if_softc; + + coal->rx_coalesce_usecs = priv->ethtool.coalesce_usecs; + coal->tx_coalesce_usecs = priv->ethtool.coalesce_usecs; + coal->rx_max_coalesced_frames = priv->ethtool.max_coalesced_frames; + coal->tx_max_coalesced_frames = priv->ethtool.max_coalesced_frames; + + return 0; +} + +static int ipoib_set_coalesce(struct ifnet *dev, + struct ethtool_coalesce *coal) +{ + struct ipoib_dev_priv *priv = dev->if_softc; + int ret; + + /* + * Since IPoIB uses a single CQ for both rx and tx, we assume + * that rx params dictate the configuration. These values are + * saved in the private data and returned when ipoib_get_coalesce() + * is called. + */ + if (coal->rx_coalesce_usecs > 0xffff || + coal->rx_max_coalesced_frames > 0xffff) + return -EINVAL; + + if (coal->rx_max_coalesced_frames | coal->rx_coalesce_usecs) { + if (!coal->rx_max_coalesced_frames) + coal->rx_max_coalesced_frames = 0xffff; + else if (!coal->rx_coalesce_usecs) + coal->rx_coalesce_usecs = 0xffff; + } + + ret = ib_modify_cq(priv->recv_cq, coal->rx_max_coalesced_frames, + coal->rx_coalesce_usecs); + if (ret && ret != -ENOSYS) { + ipoib_warn(priv, "failed modifying CQ (%d)\n", ret); + return ret; + } + + coal->tx_coalesce_usecs = coal->rx_coalesce_usecs; + coal->tx_max_coalesced_frames = coal->rx_max_coalesced_frames; + priv->ethtool.coalesce_usecs = coal->rx_coalesce_usecs; + priv->ethtool.max_coalesced_frames = coal->rx_max_coalesced_frames; + + return 0; +} + +static const char ipoib_stats_keys[][ETH_GSTRING_LEN] = { + "LRO aggregated", "LRO flushed", + "LRO avg aggr", "LRO no desc" +}; + +static void ipoib_get_strings(struct ifnet *netdev, u32 stringset, u8 *data) +{ + switch (stringset) { + case ETH_SS_STATS: + memcpy(data, *ipoib_stats_keys, sizeof(ipoib_stats_keys)); + break; + } +} + +static int ipoib_get_sset_count(struct ifnet *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(ipoib_stats_keys); + default: + return -EOPNOTSUPP; + } +} + +static void ipoib_get_ethtool_stats(struct ifnet *dev, + struct ethtool_stats *stats, uint64_t *data) +{ + struct ipoib_dev_priv *priv = dev->if_softc; + int index = 0; + + /* Get LRO statistics */ + data[index++] = priv->lro.lro_mgr.stats.aggregated; + data[index++] = priv->lro.lro_mgr.stats.flushed; + if (priv->lro.lro_mgr.stats.flushed) + data[index++] = priv->lro.lro_mgr.stats.aggregated / + priv->lro.lro_mgr.stats.flushed; + else + data[index++] = 0; + data[index++] = priv->lro.lro_mgr.stats.no_desc; +} + +static const struct ethtool_ops ipoib_ethtool_ops = { + .get_drvinfo = ipoib_get_drvinfo, + .get_rx_csum = ipoib_get_rx_csum, + .get_coalesce = ipoib_get_coalesce, + .set_coalesce = ipoib_set_coalesce, + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_set_flags, + .get_strings = ipoib_get_strings, + .get_sset_count = ipoib_get_sset_count, + .get_ethtool_stats = ipoib_get_ethtool_stats, +}; + +void ipoib_set_ethtool_ops(struct ifnet *dev) +{ + SET_ETHTOOL_OPS(dev, &ipoib_ethtool_ops); +} diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_fs.c new file mode 100644 index 000000000000..0f85f2842dbb --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_fs.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +struct file_operations; + +#include + +#include "ipoib.h" + +static struct dentry *ipoib_root; + +static void format_gid(union ib_gid *gid, char *buf) +{ + int i, n; + + for (n = 0, i = 0; i < 8; ++i) { + n += sprintf(buf + n, "%x", + be16_to_cpu(((__be16 *) gid->raw)[i])); + if (i < 7) + buf[n++] = ':'; + } +} + +static void *ipoib_mcg_seq_start(struct seq_file *file, loff_t *pos) +{ + struct ipoib_mcast_iter *iter; + loff_t n = *pos; + + iter = ipoib_mcast_iter_init(file->private); + if (!iter) + return NULL; + + while (n--) { + if (ipoib_mcast_iter_next(iter)) { + kfree(iter); + return NULL; + } + } + + return iter; +} + +static void *ipoib_mcg_seq_next(struct seq_file *file, void *iter_ptr, + loff_t *pos) +{ + struct ipoib_mcast_iter *iter = iter_ptr; + + (*pos)++; + + if (ipoib_mcast_iter_next(iter)) { + kfree(iter); + return NULL; + } + + return iter; +} + +static void ipoib_mcg_seq_stop(struct seq_file *file, void *iter_ptr) +{ + /* nothing for now */ +} + +static int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr) +{ + struct ipoib_mcast_iter *iter = iter_ptr; + char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; + union ib_gid mgid; + unsigned long created; + unsigned int queuelen, complete, send_only; + + if (!iter) + return 0; + + ipoib_mcast_iter_read(iter, &mgid, &created, &queuelen, + &complete, &send_only); + + format_gid(&mgid, gid_buf); + + seq_printf(file, + "GID: %s\n" + " created: %10ld\n" + " queuelen: %9d\n" + " complete: %9s\n" + " send_only: %8s\n" + "\n", + gid_buf, created, queuelen, + complete ? "yes" : "no", + send_only ? "yes" : "no"); + + return 0; +} + +static const struct seq_operations ipoib_mcg_seq_ops = { + .start = ipoib_mcg_seq_start, + .next = ipoib_mcg_seq_next, + .stop = ipoib_mcg_seq_stop, + .show = ipoib_mcg_seq_show, +}; + +static int ipoib_mcg_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int ret; + + ret = seq_open(file, &ipoib_mcg_seq_ops); + if (ret) + return ret; + + seq = file->private_data; + seq->private = inode->i_private; + + return 0; +} + +static const struct file_operations ipoib_mcg_fops = { + .owner = THIS_MODULE, + .open = ipoib_mcg_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +static void *ipoib_path_seq_start(struct seq_file *file, loff_t *pos) +{ + struct ipoib_path_iter *iter; + loff_t n = *pos; + + iter = ipoib_path_iter_init(file->private); + if (!iter) + return NULL; + + while (n--) { + if (ipoib_path_iter_next(iter)) { + kfree(iter); + return NULL; + } + } + + return iter; +} + +static void *ipoib_path_seq_next(struct seq_file *file, void *iter_ptr, + loff_t *pos) +{ + struct ipoib_path_iter *iter = iter_ptr; + + (*pos)++; + + if (ipoib_path_iter_next(iter)) { + kfree(iter); + return NULL; + } + + return iter; +} + +static void ipoib_path_seq_stop(struct seq_file *file, void *iter_ptr) +{ + /* nothing for now */ +} + +static int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr) +{ + struct ipoib_path_iter *iter = iter_ptr; + char gid_buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; + struct ipoib_path path; + int rate; + + if (!iter) + return 0; + + ipoib_path_iter_read(iter, &path); + + format_gid(&path.pathrec.dgid, gid_buf); + + seq_printf(file, + "GID: %s\n" + " complete: %6s\n", + gid_buf, path.pathrec.dlid ? "yes" : "no"); + + if (path.pathrec.dlid) { + rate = ib_rate_to_mult(path.pathrec.rate) * 25; + + seq_printf(file, + " DLID: 0x%04x\n" + " SL: %12d\n" + " rate: %*d%s Gb/sec\n", + be16_to_cpu(path.pathrec.dlid), + path.pathrec.sl, + 10 - ((rate % 10) ? 2 : 0), + rate / 10, rate % 10 ? ".5" : ""); + } + + seq_putc(file, '\n'); + + return 0; +} + +static const struct seq_operations ipoib_path_seq_ops = { + .start = ipoib_path_seq_start, + .next = ipoib_path_seq_next, + .stop = ipoib_path_seq_stop, + .show = ipoib_path_seq_show, +}; + +static int ipoib_path_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int ret; + + ret = seq_open(file, &ipoib_path_seq_ops); + if (ret) + return ret; + + seq = file->private_data; + seq->private = inode->i_private; + + return 0; +} + +static const struct file_operations ipoib_path_fops = { + .owner = THIS_MODULE, + .open = ipoib_path_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +void ipoib_create_debug_files(struct ifnet *dev) +{ + struct ipoib_dev_priv *priv = dev->if_softc; + char name[IFNAMSIZ + sizeof "_path"]; + + snprintf(name, sizeof name, "%s_mcg", if_name(dev)); + priv->mcg_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO, + ipoib_root, dev, &ipoib_mcg_fops); + if (!priv->mcg_dentry) + ipoib_warn(priv, "failed to create mcg debug file\n"); + + snprintf(name, sizeof name, "%s_path", if_name(dev)); + priv->path_dentry = debugfs_create_file(name, S_IFREG | S_IRUGO, + ipoib_root, dev, &ipoib_path_fops); + if (!priv->path_dentry) + ipoib_warn(priv, "failed to create path debug file\n"); +} + +void ipoib_delete_debug_files(struct ifnet *dev) +{ + struct ipoib_dev_priv *priv = dev->if_softc; + + if (priv->mcg_dentry) + debugfs_remove(priv->mcg_dentry); + if (priv->path_dentry) + debugfs_remove(priv->path_dentry); +} + +int ipoib_register_debugfs(void) +{ + ipoib_root = debugfs_create_dir("ipoib", NULL); + return ipoib_root ? 0 : -ENOMEM; +} + +void ipoib_unregister_debugfs(void) +{ + debugfs_remove(ipoib_root); +} diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_ib.c new file mode 100644 index 000000000000..d3b68bcf49d0 --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -0,0 +1,997 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "ipoib.h" + +#include + +#include + +#include +#include + +#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA +static int data_debug_level; + +module_param(data_debug_level, int, 0644); +MODULE_PARM_DESC(data_debug_level, + "Enable data path debug tracing if > 0"); +#endif + +static DEFINE_MUTEX(pkey_mutex); + +struct ipoib_ah *ipoib_create_ah(struct ipoib_dev_priv *priv, + struct ib_pd *pd, struct ib_ah_attr *attr) +{ + struct ipoib_ah *ah; + + ah = kmalloc(sizeof *ah, GFP_KERNEL); + if (!ah) + return NULL; + + ah->priv = priv; + ah->last_send = 0; + kref_init(&ah->ref); + + ah->ah = ib_create_ah(pd, attr); + if (IS_ERR(ah->ah)) { + kfree(ah); + ah = NULL; + } else + ipoib_dbg(priv, "Created ah %p\n", ah->ah); + + return ah; +} + +void ipoib_free_ah(struct kref *kref) +{ + struct ipoib_ah *ah = container_of(kref, struct ipoib_ah, ref); + struct ipoib_dev_priv *priv = ah->priv; + + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + list_add_tail(&ah->list, &priv->dead_ahs); + spin_unlock_irqrestore(&priv->lock, flags); +} + +void +ipoib_dma_unmap_rx(struct ipoib_dev_priv *priv, struct ipoib_rx_buf *rx_req) +{ + struct mbuf *m; + int i; + + for (i = 0, m = rx_req->mb; m != NULL; m = m->m_next, i++) + ib_dma_unmap_single(priv->ca, rx_req->mapping[i], m->m_len, + DMA_FROM_DEVICE); +} + +void +ipoib_dma_mb(struct ipoib_dev_priv *priv, struct mbuf *mb, unsigned int length) +{ + + m_adj(mb, -(mb->m_pkthdr.len - length)); +} + +struct mbuf * +ipoib_alloc_map_mb(struct ipoib_dev_priv *priv, struct ipoib_rx_buf *rx_req, + int size) +{ + struct mbuf *mb, *m; + int i, j; + + rx_req->mb = NULL; + mb = m_getm2(NULL, size, M_NOWAIT, MT_DATA, M_PKTHDR); + if (mb == NULL) + return (NULL); + for (i = 0, m = mb; m != NULL; m = m->m_next, i++) { + m->m_len = (m->m_flags & M_EXT) ? m->m_ext.ext_size : + ((m->m_flags & M_PKTHDR) ? MHLEN : MLEN); + mb->m_pkthdr.len += m->m_len; + rx_req->mapping[i] = ib_dma_map_single(priv->ca, + mtod(m, void *), m->m_len, DMA_FROM_DEVICE); + if (unlikely(ib_dma_mapping_error(priv->ca, + rx_req->mapping[i]))) + goto error; + + } + rx_req->mb = mb; + return (mb); +error: + for (j = 0, m = mb; j < i; m = m->m_next, j++) + ib_dma_unmap_single(priv->ca, rx_req->mapping[j], m->m_len, + DMA_FROM_DEVICE); + m_freem(mb); + return (NULL); + +} + +static int ipoib_ib_post_receive(struct ipoib_dev_priv *priv, int id) +{ + struct ipoib_rx_buf *rx_req; + struct ib_recv_wr *bad_wr; + struct mbuf *m; + int ret; + int i; + + rx_req = &priv->rx_ring[id]; + for (m = rx_req->mb, i = 0; m != NULL; m = m->m_next, i++) { + priv->rx_sge[i].addr = rx_req->mapping[i]; + priv->rx_sge[i].length = m->m_len; + } + priv->rx_wr.num_sge = i; + priv->rx_wr.wr_id = id | IPOIB_OP_RECV; + + ret = ib_post_recv(priv->qp, &priv->rx_wr, &bad_wr); + if (unlikely(ret)) { + ipoib_warn(priv, "receive failed for buf %d (%d)\n", id, ret); + ipoib_dma_unmap_rx(priv, &priv->rx_ring[id]); + m_freem(priv->rx_ring[id].mb); + priv->rx_ring[id].mb = NULL; + } + + return ret; +} + +static struct mbuf * +ipoib_alloc_rx_mb(struct ipoib_dev_priv *priv, int id) +{ + + return ipoib_alloc_map_mb(priv, &priv->rx_ring[id], + priv->max_ib_mtu + IB_GRH_BYTES); +} + +static int ipoib_ib_post_receives(struct ipoib_dev_priv *priv) +{ + int i; + + for (i = 0; i < ipoib_recvq_size; ++i) { + if (!ipoib_alloc_rx_mb(priv, i)) { + ipoib_warn(priv, "failed to allocate receive buffer %d\n", i); + return -ENOMEM; + } + if (ipoib_ib_post_receive(priv, i)) { + ipoib_warn(priv, "ipoib_ib_post_receive failed for buf %d\n", i); + return -EIO; + } + } + + return 0; +} + +static void +ipoib_ib_handle_rx_wc(struct ipoib_dev_priv *priv, struct ib_wc *wc) +{ + struct ipoib_rx_buf saverx; + unsigned int wr_id = wc->wr_id & ~IPOIB_OP_RECV; + struct ifnet *dev = priv->dev; + struct ipoib_header *eh; + struct mbuf *mb; + + ipoib_dbg_data(priv, "recv completion: id %d, status: %d\n", + wr_id, wc->status); + + if (unlikely(wr_id >= ipoib_recvq_size)) { + ipoib_warn(priv, "recv completion event with wrid %d (> %d)\n", + wr_id, ipoib_recvq_size); + return; + } + + mb = priv->rx_ring[wr_id].mb; + + if (unlikely(wc->status != IB_WC_SUCCESS)) { + if (wc->status != IB_WC_WR_FLUSH_ERR) { + ipoib_warn(priv, "failed recv event " + "(status=%d, wrid=%d vend_err %x)\n", + wc->status, wr_id, wc->vendor_err); + goto repost; + } + if (mb) { + ipoib_dma_unmap_rx(priv, &priv->rx_ring[wr_id]); + m_freem(mb); + priv->rx_ring[wr_id].mb = NULL; + } + return; + } + + /* + * Drop packets that this interface sent, ie multicast packets + * that the HCA has replicated. + */ + if (wc->slid == priv->local_lid && wc->src_qp == priv->qp->qp_num) + goto repost; + + memcpy(&saverx, &priv->rx_ring[wr_id], sizeof(saverx)); + /* + * If we can't allocate a new RX buffer, dump + * this packet and reuse the old buffer. + */ + if (unlikely(!ipoib_alloc_rx_mb(priv, wr_id))) { + memcpy(&priv->rx_ring[wr_id], &saverx, sizeof(saverx)); + dev->if_iqdrops++; + goto repost; + } + + ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n", + wc->byte_len, wc->slid); + + ipoib_dma_unmap_rx(priv, &saverx); + ipoib_dma_mb(priv, mb, wc->byte_len); + + ++dev->if_ipackets; + dev->if_ibytes += mb->m_pkthdr.len; + mb->m_pkthdr.rcvif = dev; + m_adj(mb, sizeof(struct ib_grh) - INFINIBAND_ALEN); + eh = mtod(mb, struct ipoib_header *); + bzero(eh->hwaddr, 4); /* Zero the queue pair, only dgid is in grh */ + + if (test_bit(IPOIB_FLAG_CSUM, &priv->flags) && likely(wc->csum_ok)) + mb->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID; + + dev->if_input(dev, mb); + +repost: + if (unlikely(ipoib_ib_post_receive(priv, wr_id))) + ipoib_warn(priv, "ipoib_ib_post_receive failed " + "for buf %d\n", wr_id); +} + +int ipoib_dma_map_tx(struct ib_device *ca, struct ipoib_tx_buf *tx_req, int max) +{ + struct mbuf *mb = tx_req->mb; + u64 *mapping = tx_req->mapping; + struct mbuf *m, *p; + int error; + int i; + + for (m = mb, p = NULL, i = 0; m != NULL; p = m, m = m->m_next, i++) { + if (m->m_len != 0) + continue; + if (p == NULL) + panic("ipoib_dma_map_tx: First mbuf empty\n"); + p->m_next = m_free(m); + m = p; + i--; + } + i--; + if (i >= max) { + tx_req->mb = mb = m_defrag(mb, M_DONTWAIT); + if (mb == NULL) + return -EIO; + for (m = mb, i = 0; m != NULL; m = m->m_next, i++); + if (i >= max) + return -EIO; + } + error = 0; + for (m = mb, i = 0; m != NULL; m = m->m_next, i++) { + mapping[i] = ib_dma_map_single(ca, mtod(m, void *), + m->m_len, DMA_TO_DEVICE); + if (unlikely(ib_dma_mapping_error(ca, mapping[i]))) { + error = -EIO; + break; + } + } + if (error) { + int end; + + end = i; + for (m = mb, i = 0; i < end; m = m->m_next, i++) + ib_dma_unmap_single(ca, mapping[i], m->m_len, + DMA_TO_DEVICE); + } + return error; +} + +void ipoib_dma_unmap_tx(struct ib_device *ca, struct ipoib_tx_buf *tx_req) +{ + struct mbuf *mb = tx_req->mb; + u64 *mapping = tx_req->mapping; + struct mbuf *m; + int i; + + for (m = mb, i = 0; m != NULL; m = m->m_next, i++) + ib_dma_unmap_single(ca, mapping[i], m->m_len, DMA_TO_DEVICE); +} + +static void ipoib_ib_handle_tx_wc(struct ipoib_dev_priv *priv, struct ib_wc *wc) +{ + struct ifnet *dev = priv->dev; + unsigned int wr_id = wc->wr_id; + struct ipoib_tx_buf *tx_req; + + ipoib_dbg_data(priv, "send completion: id %d, status: %d\n", + wr_id, wc->status); + + if (unlikely(wr_id >= ipoib_sendq_size)) { + ipoib_warn(priv, "send completion event with wrid %d (> %d)\n", + wr_id, ipoib_sendq_size); + return; + } + + tx_req = &priv->tx_ring[wr_id]; + + ipoib_dma_unmap_tx(priv->ca, tx_req); + + ++dev->if_opackets; + dev->if_obytes += tx_req->mb->m_pkthdr.len; + + m_freem(tx_req->mb); + + ++priv->tx_tail; + if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) && + (dev->if_drv_flags & IFF_DRV_OACTIVE) && + test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) + dev->if_drv_flags &= ~IFF_DRV_OACTIVE; + + if (wc->status != IB_WC_SUCCESS && + wc->status != IB_WC_WR_FLUSH_ERR) + ipoib_warn(priv, "failed send event " + "(status=%d, wrid=%d vend_err %x)\n", + wc->status, wr_id, wc->vendor_err); +} + +int +ipoib_poll_tx(struct ipoib_dev_priv *priv) +{ + int n, i; + + n = ib_poll_cq(priv->send_cq, MAX_SEND_CQE, priv->send_wc); + for (i = 0; i < n; ++i) { + struct ib_wc *wc = priv->send_wc + i; + if (wc->wr_id & IPOIB_OP_CM) + ipoib_cm_handle_tx_wc(priv, wc); + else + ipoib_ib_handle_tx_wc(priv, wc); + } + + return n == MAX_SEND_CQE; +} + +static void +ipoib_poll(struct ipoib_dev_priv *priv) +{ + int n, i; + +poll_more: + for (;;) { + n = ib_poll_cq(priv->recv_cq, IPOIB_NUM_WC, priv->ibwc); + + for (i = 0; i < n; i++) { + struct ib_wc *wc = priv->ibwc + i; + + if ((wc->wr_id & IPOIB_OP_RECV) == 0) + panic("ipoib_poll: Bad wr_id 0x%jX\n", + (intmax_t)wc->wr_id); + if (wc->wr_id & IPOIB_OP_CM) + ipoib_cm_handle_rx_wc(priv, wc); + else + ipoib_ib_handle_rx_wc(priv, wc); + } + + if (n != IPOIB_NUM_WC) + break; + } + + if (ib_req_notify_cq(priv->recv_cq, + IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS)) + goto poll_more; +} + +void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr) +{ + struct ipoib_dev_priv *priv = dev_ptr; + + ipoib_poll(priv); +} + +static void drain_tx_cq(struct ipoib_dev_priv *priv) +{ + struct ifnet *dev = priv->dev; + + spin_lock(&priv->lock); + while (ipoib_poll_tx(priv)) + ; /* nothing */ + + if (dev->if_drv_flags & IFF_DRV_OACTIVE) + mod_timer(&priv->poll_timer, jiffies + 1); + + spin_unlock(&priv->lock); +} + +void ipoib_send_comp_handler(struct ib_cq *cq, void *dev_ptr) +{ + struct ipoib_dev_priv *priv = dev_ptr; + + mod_timer(&priv->poll_timer, jiffies); +} + +static inline int +post_send(struct ipoib_dev_priv *priv, unsigned int wr_id, + struct ib_ah *address, u32 qpn, struct ipoib_tx_buf *tx_req, void *head, + int hlen) +{ + struct ib_send_wr *bad_wr; + struct mbuf *mb = tx_req->mb; + u64 *mapping = tx_req->mapping; + struct mbuf *m; + int i; + + for (m = mb, i = 0; m != NULL; m = m->m_next, i++) { + priv->tx_sge[i].addr = mapping[i]; + priv->tx_sge[i].length = m->m_len; + } + priv->tx_wr.num_sge = i; + priv->tx_wr.wr_id = wr_id; + priv->tx_wr.wr.ud.remote_qpn = qpn; + priv->tx_wr.wr.ud.ah = address; + + + if (head) { + priv->tx_wr.wr.ud.mss = 0; /* XXX mb_shinfo(mb)->gso_size; */ + priv->tx_wr.wr.ud.header = head; + priv->tx_wr.wr.ud.hlen = hlen; + priv->tx_wr.opcode = IB_WR_LSO; + } else + priv->tx_wr.opcode = IB_WR_SEND; + + return ib_post_send(priv->qp, &priv->tx_wr, &bad_wr); +} + +void +ipoib_send(struct ipoib_dev_priv *priv, struct mbuf *mb, + struct ipoib_ah *address, u32 qpn) +{ + struct ifnet *dev = priv->dev; + struct ipoib_tx_buf *tx_req; + int hlen; + void *phead; + + if (unlikely(priv->tx_outstanding > MAX_SEND_CQE)) + while (ipoib_poll_tx(priv)) + ; /* nothing */ + + m_adj(mb, sizeof (struct ipoib_pseudoheader)); + if (0 /* XXX segment offload mb_is_gso(mb) */) { + /* XXX hlen = mb_transport_offset(mb) + tcp_hdrlen(mb); */ + phead = mtod(mb, void *); + if (mb->m_len < hlen) { + ipoib_warn(priv, "linear data too small\n"); + ++dev->if_oerrors; + m_freem(mb); + return; + } + m_adj(mb, hlen); + } else { + if (unlikely(mb->m_pkthdr.len - IPOIB_ENCAP_LEN > priv->mcast_mtu)) { + ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n", + mb->m_pkthdr.len, priv->mcast_mtu); + ++dev->if_oerrors; + ipoib_cm_mb_too_long(priv, mb, priv->mcast_mtu); + return; + } + phead = NULL; + hlen = 0; + } + + ipoib_dbg_data(priv, "sending packet, length=%d address=%p qpn=0x%06x\n", + mb->m_pkthdr.len, address, qpn); + + /* + * We put the mb into the tx_ring _before_ we call post_send() + * because it's entirely possible that the completion handler will + * run before we execute anything after the post_send(). That + * means we have to make sure everything is properly recorded and + * our state is consistent before we call post_send(). + */ + tx_req = &priv->tx_ring[priv->tx_head & (ipoib_sendq_size - 1)]; + tx_req->mb = mb; + if (unlikely(ipoib_dma_map_tx(priv->ca, tx_req, IPOIB_UD_TX_SG))) { + ++dev->if_oerrors; + if (tx_req->mb) + m_freem(tx_req->mb); + return; + } + + if (mb->m_pkthdr.csum_flags & (CSUM_IP|CSUM_TCP|CSUM_UDP)) + priv->tx_wr.send_flags |= IB_SEND_IP_CSUM; + else + priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM; + + if (++priv->tx_outstanding == ipoib_sendq_size) { + ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n"); + if (ib_req_notify_cq(priv->send_cq, IB_CQ_NEXT_COMP)) + ipoib_warn(priv, "request notify on send CQ failed\n"); + dev->if_drv_flags |= IFF_DRV_OACTIVE; + } + + if (unlikely(post_send(priv, + priv->tx_head & (ipoib_sendq_size - 1), address->ah, qpn, + tx_req, phead, hlen))) { + ipoib_warn(priv, "post_send failed\n"); + ++dev->if_oerrors; + --priv->tx_outstanding; + ipoib_dma_unmap_tx(priv->ca, tx_req); + m_freem(mb); + if (dev->if_drv_flags & IFF_DRV_OACTIVE) + dev->if_drv_flags &= ~IFF_DRV_OACTIVE; + } else { + address->last_send = priv->tx_head; + ++priv->tx_head; + } +} + +static void __ipoib_reap_ah(struct ipoib_dev_priv *priv) +{ + struct ipoib_ah *ah, *tah; + LIST_HEAD(remove_list); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list) + if ((int) priv->tx_tail - (int) ah->last_send >= 0) { + list_del(&ah->list); + ib_destroy_ah(ah->ah); + kfree(ah); + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +void ipoib_reap_ah(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, ah_reap_task.work); + + __ipoib_reap_ah(priv); + + if (!test_bit(IPOIB_STOP_REAPER, &priv->flags)) + queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task, + HZ); +} + +static void ipoib_ah_dev_cleanup(struct ipoib_dev_priv *priv) +{ + unsigned long begin; + + begin = jiffies; + + while (!list_empty(&priv->dead_ahs)) { + __ipoib_reap_ah(priv); + + if (time_after(jiffies, begin + HZ)) { + ipoib_warn(priv, "timing out; will leak address handles\n"); + break; + } + + msleep(1); + } +} + +static void ipoib_ib_tx_timer_func(unsigned long ctx) +{ + drain_tx_cq((struct ipoib_dev_priv *)ctx); +} + +int ipoib_ib_dev_open(struct ipoib_dev_priv *priv) +{ + int ret; + + if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &priv->pkey_index)) { + ipoib_warn(priv, "P_Key 0x%04x not found\n", priv->pkey); + clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); + return -1; + } + set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); + + ret = ipoib_init_qp(priv); + if (ret) { + ipoib_warn(priv, "ipoib_init_qp returned %d\n", ret); + return -1; + } + + ret = ipoib_ib_post_receives(priv); + if (ret) { + ipoib_warn(priv, "ipoib_ib_post_receives returned %d\n", ret); + ipoib_ib_dev_stop(priv, 1); + return -1; + } + + ret = ipoib_cm_dev_open(priv); + if (ret) { + ipoib_warn(priv, "ipoib_cm_dev_open returned %d\n", ret); + ipoib_ib_dev_stop(priv, 1); + return -1; + } + + clear_bit(IPOIB_STOP_REAPER, &priv->flags); + queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task, HZ); + + return 0; +} + +static void ipoib_pkey_dev_check_presence(struct ipoib_dev_priv *priv) +{ + u16 pkey_index = 0; + + if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &pkey_index)) + clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); + else + set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); +} + +int ipoib_ib_dev_up(struct ipoib_dev_priv *priv) +{ + + ipoib_pkey_dev_check_presence(priv); + + if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) { + ipoib_dbg(priv, "PKEY is not assigned.\n"); + return 0; + } + + set_bit(IPOIB_FLAG_OPER_UP, &priv->flags); + + return ipoib_mcast_start_thread(priv); +} + +int ipoib_ib_dev_down(struct ipoib_dev_priv *priv, int flush) +{ + + ipoib_dbg(priv, "downing ib_dev\n"); + + clear_bit(IPOIB_FLAG_OPER_UP, &priv->flags); + if_link_state_change(priv->dev, LINK_STATE_DOWN); + + /* Shutdown the P_Key thread if still active */ + if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) { + mutex_lock(&pkey_mutex); + set_bit(IPOIB_PKEY_STOP, &priv->flags); + cancel_delayed_work(&priv->pkey_poll_task); + mutex_unlock(&pkey_mutex); + if (flush) + flush_workqueue(ipoib_workqueue); + } + + ipoib_mcast_stop_thread(priv, flush); + ipoib_mcast_dev_flush(priv); + + ipoib_flush_paths(priv); + + return 0; +} + +static int recvs_pending(struct ipoib_dev_priv *priv) +{ + int pending = 0; + int i; + + for (i = 0; i < ipoib_recvq_size; ++i) + if (priv->rx_ring[i].mb) + ++pending; + + return pending; +} + +void ipoib_drain_cq(struct ipoib_dev_priv *priv) +{ + int i, n; + + do { + n = ib_poll_cq(priv->recv_cq, IPOIB_NUM_WC, priv->ibwc); + for (i = 0; i < n; ++i) { + /* + * Convert any successful completions to flush + * errors to avoid passing packets up the + * stack after bringing the device down. + */ + if (priv->ibwc[i].status == IB_WC_SUCCESS) + priv->ibwc[i].status = IB_WC_WR_FLUSH_ERR; + + if ((priv->ibwc[i].wr_id & IPOIB_OP_RECV) == 0) + panic("ipoib_drain_cq: Bad wrid 0x%jX\n", + (intmax_t)priv->ibwc[i].wr_id); + if (priv->ibwc[i].wr_id & IPOIB_OP_CM) + ipoib_cm_handle_rx_wc(priv, priv->ibwc + i); + else + ipoib_ib_handle_rx_wc(priv, priv->ibwc + i); + } + } while (n == IPOIB_NUM_WC); + + spin_lock(&priv->lock); + while (ipoib_poll_tx(priv)) + ; /* nothing */ + + spin_unlock(&priv->lock); +} + +int ipoib_ib_dev_stop(struct ipoib_dev_priv *priv, int flush) +{ + struct ib_qp_attr qp_attr; + unsigned long begin; + struct ipoib_tx_buf *tx_req; + int i; + + ipoib_cm_dev_stop(priv); + + /* + * Move our QP to the error state and then reinitialize in + * when all work requests have completed or have been flushed. + */ + qp_attr.qp_state = IB_QPS_ERR; + if (ib_modify_qp(priv->qp, &qp_attr, IB_QP_STATE)) + ipoib_warn(priv, "Failed to modify QP to ERROR state\n"); + + /* Wait for all sends and receives to complete */ + begin = jiffies; + + while (priv->tx_head != priv->tx_tail || recvs_pending(priv)) { + if (time_after(jiffies, begin + 5 * HZ)) { + ipoib_warn(priv, "timing out; %d sends %d receives not completed\n", + priv->tx_head - priv->tx_tail, recvs_pending(priv)); + + /* + * assume the HW is wedged and just free up + * all our pending work requests. + */ + while ((int) priv->tx_tail - (int) priv->tx_head < 0) { + tx_req = &priv->tx_ring[priv->tx_tail & + (ipoib_sendq_size - 1)]; + ipoib_dma_unmap_tx(priv->ca, tx_req); + m_freem(tx_req->mb); + ++priv->tx_tail; + --priv->tx_outstanding; + } + + for (i = 0; i < ipoib_recvq_size; ++i) { + struct ipoib_rx_buf *rx_req; + + rx_req = &priv->rx_ring[i]; + if (!rx_req->mb) + continue; + ipoib_dma_unmap_rx(priv, &priv->rx_ring[i]); + m_freem(rx_req->mb); + rx_req->mb = NULL; + } + + goto timeout; + } + + ipoib_drain_cq(priv); + + msleep(1); + } + + ipoib_dbg(priv, "All sends and receives done.\n"); + +timeout: + del_timer_sync(&priv->poll_timer); + qp_attr.qp_state = IB_QPS_RESET; + if (ib_modify_qp(priv->qp, &qp_attr, IB_QP_STATE)) + ipoib_warn(priv, "Failed to modify QP to RESET state\n"); + + /* Wait for all AHs to be reaped */ + set_bit(IPOIB_STOP_REAPER, &priv->flags); + cancel_delayed_work(&priv->ah_reap_task); + if (flush) + flush_workqueue(ipoib_workqueue); + + ipoib_ah_dev_cleanup(priv); + + ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP); + + return 0; +} + +int ipoib_ib_dev_init(struct ipoib_dev_priv *priv, struct ib_device *ca, int port) +{ + struct ifnet *dev = priv->dev; + + priv->ca = ca; + priv->port = port; + priv->qp = NULL; + + if (ipoib_transport_dev_init(priv, ca)) { + printk(KERN_WARNING "%s: ipoib_transport_dev_init failed\n", ca->name); + return -ENODEV; + } + + setup_timer(&priv->poll_timer, ipoib_ib_tx_timer_func, + (unsigned long) priv); + + if (dev->if_flags & IFF_UP) { + if (ipoib_ib_dev_open(priv)) { + ipoib_transport_dev_cleanup(priv); + return -ENODEV; + } + } + + return 0; +} + +static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, + enum ipoib_flush_level level) +{ + struct ipoib_dev_priv *cpriv; + u16 new_index; + + mutex_lock(&priv->vlan_mutex); + + /* + * Flush any child interfaces too -- they might be up even if + * the parent is down. + */ + list_for_each_entry(cpriv, &priv->child_intfs, list) + __ipoib_ib_dev_flush(cpriv, level); + + mutex_unlock(&priv->vlan_mutex); + + if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) { + ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n"); + return; + } + + if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) { + ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_ADMIN_UP not set.\n"); + return; + } + + if (level == IPOIB_FLUSH_HEAVY) { + if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) { + clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); + ipoib_ib_dev_down(priv, 0); + ipoib_ib_dev_stop(priv, 0); + if (ipoib_pkey_dev_delay_open(priv)) + return; + } + + /* restart QP only if P_Key index is changed */ + if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) && + new_index == priv->pkey_index) { + ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n"); + return; + } + priv->pkey_index = new_index; + } + + if (level == IPOIB_FLUSH_LIGHT) { + ipoib_mark_paths_invalid(priv); + ipoib_mcast_dev_flush(priv); + } + + if (level >= IPOIB_FLUSH_NORMAL) + ipoib_ib_dev_down(priv, 0); + + if (level == IPOIB_FLUSH_HEAVY) { + ipoib_ib_dev_stop(priv, 0); + ipoib_ib_dev_open(priv); + } + + /* + * The device could have been brought down between the start and when + * we get here, don't bring it back up if it's not configured up + */ + if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) { + if (level >= IPOIB_FLUSH_NORMAL) + ipoib_ib_dev_up(priv); + ipoib_mcast_restart_task(&priv->restart_task); + } +} + +void ipoib_ib_dev_flush_light(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, flush_light); + + __ipoib_ib_dev_flush(priv, IPOIB_FLUSH_LIGHT); +} + +void ipoib_ib_dev_flush_normal(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, flush_normal); + + __ipoib_ib_dev_flush(priv, IPOIB_FLUSH_NORMAL); +} + +void ipoib_ib_dev_flush_heavy(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, flush_heavy); + + __ipoib_ib_dev_flush(priv, IPOIB_FLUSH_HEAVY); +} + +void ipoib_ib_dev_cleanup(struct ipoib_dev_priv *priv) +{ + + ipoib_dbg(priv, "cleaning up ib_dev\n"); + + ipoib_mcast_stop_thread(priv, 1); + ipoib_mcast_dev_flush(priv); + + ipoib_ah_dev_cleanup(priv); + ipoib_transport_dev_cleanup(priv); +} + +/* + * Delayed P_Key Assigment Interim Support + * + * The following is initial implementation of delayed P_Key assigment + * mechanism. It is using the same approach implemented for the multicast + * group join. The single goal of this implementation is to quickly address + * Bug #2507. This implementation will probably be removed when the P_Key + * change async notification is available. + */ + +void ipoib_pkey_poll(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, pkey_poll_task.work); + + ipoib_pkey_dev_check_presence(priv); + + if (test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) + ipoib_open(priv); + else { + mutex_lock(&pkey_mutex); + if (!test_bit(IPOIB_PKEY_STOP, &priv->flags)) + queue_delayed_work(ipoib_workqueue, + &priv->pkey_poll_task, + HZ); + mutex_unlock(&pkey_mutex); + } +} + +int ipoib_pkey_dev_delay_open(struct ipoib_dev_priv *priv) +{ + + /* Look for the interface pkey value in the IB Port P_Key table and */ + /* set the interface pkey assigment flag */ + ipoib_pkey_dev_check_presence(priv); + + /* P_Key value not assigned yet - start polling */ + if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) { + mutex_lock(&pkey_mutex); + clear_bit(IPOIB_PKEY_STOP, &priv->flags); + queue_delayed_work(ipoib_workqueue, + &priv->pkey_poll_task, + HZ); + mutex_unlock(&pkey_mutex); + return 1; + } + + return 0; +} diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c new file mode 100644 index 000000000000..99c9cc2ce697 --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -0,0 +1,1537 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "ipoib.h" + +static int ipoib_resolvemulti(struct ifnet *, struct sockaddr **, + struct sockaddr *); + + +#include + +#include +#include +#include +#include + +#include /* For ARPHRD_xxx */ +#include +#include +#include + +MODULE_AUTHOR("Roland Dreier"); +MODULE_DESCRIPTION("IP-over-InfiniBand net driver"); +MODULE_LICENSE("Dual BSD/GPL"); + +int ipoib_sendq_size = IPOIB_TX_RING_SIZE; +int ipoib_recvq_size = IPOIB_RX_RING_SIZE; + +module_param_named(send_queue_size, ipoib_sendq_size, int, 0444); +MODULE_PARM_DESC(send_queue_size, "Number of descriptors in send queue"); +module_param_named(recv_queue_size, ipoib_recvq_size, int, 0444); +MODULE_PARM_DESC(recv_queue_size, "Number of descriptors in receive queue"); + +#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG +int ipoib_debug_level = 1; + +module_param_named(debug_level, ipoib_debug_level, int, 0644); +MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); +#endif + +struct ipoib_path_iter { + struct ipoib_dev_priv *priv; + struct ipoib_path path; +}; + +static const u8 ipv4_bcast_addr[] = { + 0x00, 0xff, 0xff, 0xff, + 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff +}; + +struct workqueue_struct *ipoib_workqueue; + +struct ib_sa_client ipoib_sa_client; + +static void ipoib_add_one(struct ib_device *device); +static void ipoib_remove_one(struct ib_device *device); +static void ipoib_start(struct ifnet *dev); +static int ipoib_output(struct ifnet *ifp, struct mbuf *m, + struct sockaddr *dst, struct route *ro); +static int ipoib_ioctl(struct ifnet *ifp, u_long command, caddr_t data); +static void ipoib_input(struct ifnet *ifp, struct mbuf *m); + +#define IPOIB_MTAP(_ifp, _m) \ +do { \ + if (bpf_peers_present((_ifp)->if_bpf)) { \ + M_ASSERTVALID(_m); \ + ipoib_mtap_mb((_ifp), (_m)); \ + } \ +} while (0) + +/* + * This is for clients that have an ipoib_header in the mbuf. + */ +static void +ipoib_mtap_mb(struct ifnet *ifp, struct mbuf *mb) +{ + struct ipoib_header *ih; + struct ether_header eh; + + ih = mtod(mb, struct ipoib_header *); + eh.ether_type = ih->proto; + bcopy(ih->hwaddr, &eh.ether_dhost, ETHER_ADDR_LEN); + bzero(&eh.ether_shost, ETHER_ADDR_LEN); + mb->m_data += sizeof(struct ipoib_header); + mb->m_len -= sizeof(struct ipoib_header); + bpf_mtap2(ifp->if_bpf, &eh, sizeof(eh), mb); + mb->m_data -= sizeof(struct ipoib_header); + mb->m_len += sizeof(struct ipoib_header); +} + +void +ipoib_mtap_proto(struct ifnet *ifp, struct mbuf *mb, uint16_t proto) +{ + struct ether_header eh; + + eh.ether_type = proto; + bzero(&eh.ether_shost, ETHER_ADDR_LEN); + bzero(&eh.ether_dhost, ETHER_ADDR_LEN); + bpf_mtap2(ifp->if_bpf, &eh, sizeof(eh), mb); +} + +static struct ib_client ipoib_client = { + .name = "ipoib", + .add = ipoib_add_one, + .remove = ipoib_remove_one +}; + +int +ipoib_open(struct ipoib_dev_priv *priv) +{ + struct ifnet *dev = priv->dev; + + ipoib_dbg(priv, "bringing up interface\n"); + + set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); + + if (ipoib_pkey_dev_delay_open(priv)) + return 0; + + if (ipoib_ib_dev_open(priv)) + goto err_disable; + + if (ipoib_ib_dev_up(priv)) + goto err_stop; + + if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { + struct ipoib_dev_priv *cpriv; + + /* Bring up any child interfaces too */ + mutex_lock(&priv->vlan_mutex); + list_for_each_entry(cpriv, &priv->child_intfs, list) + if ((cpriv->dev->if_drv_flags & IFF_DRV_RUNNING) == 0) + ipoib_open(cpriv); + mutex_unlock(&priv->vlan_mutex); + } + dev->if_drv_flags |= IFF_DRV_RUNNING; + dev->if_drv_flags &= ~IFF_DRV_OACTIVE; + + return 0; + +err_stop: + ipoib_ib_dev_stop(priv, 1); + +err_disable: + clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); + + return -EINVAL; +} + +static void +ipoib_init(void *arg) +{ + struct ifnet *dev; + struct ipoib_dev_priv *priv; + + priv = arg; + dev = priv->dev; + if ((dev->if_drv_flags & IFF_DRV_RUNNING) == 0) + ipoib_open(priv); + queue_work(ipoib_workqueue, &priv->flush_light); +} + + +static int +ipoib_stop(struct ipoib_dev_priv *priv) +{ + struct ifnet *dev = priv->dev; + + ipoib_dbg(priv, "stopping interface\n"); + + clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); + + dev->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + + ipoib_ib_dev_down(priv, 0); + ipoib_ib_dev_stop(priv, 0); + + if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { + struct ipoib_dev_priv *cpriv; + + /* Bring down any child interfaces too */ + mutex_lock(&priv->vlan_mutex); + list_for_each_entry(cpriv, &priv->child_intfs, list) + if ((cpriv->dev->if_drv_flags & IFF_DRV_RUNNING) != 0) + ipoib_stop(cpriv); + mutex_unlock(&priv->vlan_mutex); + } + + return 0; +} + +int +ipoib_change_mtu(struct ipoib_dev_priv *priv, int new_mtu) +{ + struct ifnet *dev = priv->dev; + + /* dev->if_mtu > 2K ==> connected mode */ + if (ipoib_cm_admin_enabled(priv)) { + if (new_mtu > IPOIB_CM_MTU(ipoib_cm_max_mtu(priv))) + return -EINVAL; + + if (new_mtu > priv->mcast_mtu) + ipoib_warn(priv, "mtu > %d will cause multicast packet drops.\n", + priv->mcast_mtu); + + dev->if_mtu = new_mtu; + return 0; + } + + if (new_mtu > IPOIB_UD_MTU(priv->max_ib_mtu)) + return -EINVAL; + + priv->admin_mtu = new_mtu; + + dev->if_mtu = min(priv->mcast_mtu, priv->admin_mtu); + + queue_work(ipoib_workqueue, &priv->flush_light); + + return 0; +} + +static int +ipoib_ioctl(struct ifnet *ifp, u_long command, caddr_t data) +{ + struct ipoib_dev_priv *priv = ifp->if_softc; + struct ifaddr *ifa = (struct ifaddr *) data; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0; + + switch (command) { + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + error = -ipoib_open(priv); + } else + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ipoib_stop(priv); + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + queue_work(ipoib_workqueue, &priv->restart_task); + break; + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + ifp->if_init(ifp->if_softc); /* before arpwhohas */ + arp_ifinit(ifp, ifa); + break; +#endif + default: + ifp->if_init(ifp->if_softc); + break; + } + break; + + case SIOCGIFADDR: + { + struct sockaddr *sa; + + sa = (struct sockaddr *) & ifr->ifr_data; + bcopy(IF_LLADDR(ifp), + (caddr_t) sa->sa_data, INFINIBAND_ALEN); + } + break; + + case SIOCSIFMTU: + /* + * Set the interface MTU. + */ + error = -ipoib_change_mtu(priv, ifr->ifr_mtu); + break; + default: + error = EINVAL; + break; + } + return (error); +} + + +static struct ipoib_path * +__path_find(struct ipoib_dev_priv *priv, void *gid) +{ + struct rb_node *n = priv->path_tree.rb_node; + struct ipoib_path *path; + int ret; + + while (n) { + path = rb_entry(n, struct ipoib_path, rb_node); + + ret = memcmp(gid, path->pathrec.dgid.raw, + sizeof (union ib_gid)); + + if (ret < 0) + n = n->rb_left; + else if (ret > 0) + n = n->rb_right; + else + return path; + } + + return NULL; +} + +static int +__path_add(struct ipoib_dev_priv *priv, struct ipoib_path *path) +{ + struct rb_node **n = &priv->path_tree.rb_node; + struct rb_node *pn = NULL; + struct ipoib_path *tpath; + int ret; + + while (*n) { + pn = *n; + tpath = rb_entry(pn, struct ipoib_path, rb_node); + + ret = memcmp(path->pathrec.dgid.raw, tpath->pathrec.dgid.raw, + sizeof (union ib_gid)); + if (ret < 0) + n = &pn->rb_left; + else if (ret > 0) + n = &pn->rb_right; + else + return -EEXIST; + } + + rb_link_node(&path->rb_node, pn, n); + rb_insert_color(&path->rb_node, &priv->path_tree); + + list_add_tail(&path->list, &priv->path_list); + + return 0; +} + +void +ipoib_path_free(struct ipoib_dev_priv *priv, struct ipoib_path *path) +{ + + _IF_DRAIN(&path->queue); + + if (path->ah) + ipoib_put_ah(path->ah); + if (ipoib_cm_get(path)) + ipoib_cm_destroy_tx(ipoib_cm_get(path)); + + kfree(path); +} + +#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG + +struct ipoib_path_iter * +ipoib_path_iter_init(struct ipoib_dev_priv *priv) +{ + struct ipoib_path_iter *iter; + + iter = kmalloc(sizeof *iter, GFP_KERNEL); + if (!iter) + return NULL; + + iter->priv = priv; + memset(iter->path.pathrec.dgid.raw, 0, 16); + + if (ipoib_path_iter_next(iter)) { + kfree(iter); + return NULL; + } + + return iter; +} + +int +ipoib_path_iter_next(struct ipoib_path_iter *iter) +{ + struct ipoib_dev_priv *priv = iter->priv; + struct rb_node *n; + struct ipoib_path *path; + int ret = 1; + + spin_lock_irq(&priv->lock); + + n = rb_first(&priv->path_tree); + + while (n) { + path = rb_entry(n, struct ipoib_path, rb_node); + + if (memcmp(iter->path.pathrec.dgid.raw, path->pathrec.dgid.raw, + sizeof (union ib_gid)) < 0) { + iter->path = *path; + ret = 0; + break; + } + + n = rb_next(n); + } + + spin_unlock_irq(&priv->lock); + + return ret; +} + +void +ipoib_path_iter_read(struct ipoib_path_iter *iter, struct ipoib_path *path) +{ + *path = iter->path; +} + +#endif /* CONFIG_INFINIBAND_IPOIB_DEBUG */ + +void +ipoib_mark_paths_invalid(struct ipoib_dev_priv *priv) +{ + struct ipoib_path *path, *tp; + + spin_lock_irq(&priv->lock); + + list_for_each_entry_safe(path, tp, &priv->path_list, list) { + ipoib_dbg(priv, "mark path LID 0x%04x GID %16D invalid\n", + be16_to_cpu(path->pathrec.dlid), + path->pathrec.dgid.raw, ":"); + path->valid = 0; + } + + spin_unlock_irq(&priv->lock); +} + +void +ipoib_flush_paths(struct ipoib_dev_priv *priv) +{ + struct ipoib_path *path, *tp; + LIST_HEAD(remove_list); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + list_splice_init(&priv->path_list, &remove_list); + + list_for_each_entry(path, &remove_list, list) + rb_erase(&path->rb_node, &priv->path_tree); + + list_for_each_entry_safe(path, tp, &remove_list, list) { + if (path->query) + ib_sa_cancel_query(path->query_id, path->query); + spin_unlock_irqrestore(&priv->lock, flags); + wait_for_completion(&path->done); + ipoib_path_free(priv, path); + spin_lock_irqsave(&priv->lock, flags); + } + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void +path_rec_completion(int status, struct ib_sa_path_rec *pathrec, void *path_ptr) +{ + struct ipoib_path *path = path_ptr; + struct ipoib_dev_priv *priv = path->priv; + struct ifnet *dev = priv->dev; + struct ipoib_ah *ah = NULL; + struct ipoib_ah *old_ah = NULL; + struct ifqueue mbqueue; + struct mbuf *mb; + unsigned long flags; + + if (!status) + ipoib_dbg(priv, "PathRec LID 0x%04x for GID %16D\n", + be16_to_cpu(pathrec->dlid), pathrec->dgid.raw, ":"); + else + ipoib_dbg(priv, "PathRec status %d for GID %16D\n", + status, path->pathrec.dgid.raw, ":"); + + bzero(&mbqueue, sizeof(mbqueue)); + + if (!status) { + struct ib_ah_attr av; + + if (!ib_init_ah_from_path(priv->ca, priv->port, pathrec, &av)) + ah = ipoib_create_ah(priv, priv->pd, &av); + } + + spin_lock_irqsave(&priv->lock, flags); + + if (ah) { + path->pathrec = *pathrec; + + old_ah = path->ah; + path->ah = ah; + + ipoib_dbg(priv, "created address handle %p for LID 0x%04x, SL %d\n", + ah, be16_to_cpu(pathrec->dlid), pathrec->sl); + + for (;;) { + _IF_DEQUEUE(&path->queue, mb); + if (mb == NULL) + break; + _IF_ENQUEUE(&mbqueue, mb); + } + +#ifdef CONFIG_INFINIBAND_IPOIB_CM + if (ipoib_cm_enabled(priv, path->hwaddr) && !ipoib_cm_get(path)) + ipoib_cm_set(path, ipoib_cm_create_tx(priv, path)); +#endif + + path->valid = 1; + } + + path->query = NULL; + complete(&path->done); + + spin_unlock_irqrestore(&priv->lock, flags); + + if (old_ah) + ipoib_put_ah(old_ah); + + for (;;) { + _IF_DEQUEUE(&mbqueue, mb); + if (mb == NULL) + break; + mb->m_pkthdr.rcvif = dev; + if (dev->if_transmit(dev, mb)) + ipoib_warn(priv, "dev_queue_xmit failed " + "to requeue packet\n"); + } +} + +static struct ipoib_path * +path_rec_create(struct ipoib_dev_priv *priv, uint8_t *hwaddr) +{ + struct ipoib_path *path; + + if (!priv->broadcast) + return NULL; + + path = kzalloc(sizeof *path, GFP_ATOMIC); + if (!path) + return NULL; + + path->priv = priv; + + bzero(&path->queue, sizeof(path->queue)); + +#ifdef CONFIG_INFINIBAND_IPOIB_CM + memcpy(&path->hwaddr, hwaddr, INFINIBAND_ALEN); +#endif + memcpy(path->pathrec.dgid.raw, &hwaddr[4], sizeof (union ib_gid)); + path->pathrec.sgid = priv->local_gid; + path->pathrec.pkey = cpu_to_be16(priv->pkey); + path->pathrec.numb_path = 1; + path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class; + + return path; +} + +static int +path_rec_start(struct ipoib_dev_priv *priv, struct ipoib_path *path) +{ + struct ifnet *dev = priv->dev; + + ib_sa_comp_mask comp_mask = IB_SA_PATH_REC_MTU_SELECTOR | IB_SA_PATH_REC_MTU; + struct ib_sa_path_rec p_rec; + + p_rec = path->pathrec; + p_rec.mtu_selector = IB_SA_GT; + + switch (roundup_pow_of_two(dev->if_mtu + IPOIB_ENCAP_LEN)) { + case 512: + p_rec.mtu = IB_MTU_256; + break; + case 1024: + p_rec.mtu = IB_MTU_512; + break; + case 2048: + p_rec.mtu = IB_MTU_1024; + break; + case 4096: + p_rec.mtu = IB_MTU_2048; + break; + default: + /* Wildcard everything */ + comp_mask = 0; + p_rec.mtu = 0; + p_rec.mtu_selector = 0; + } + + ipoib_dbg(priv, "Start path record lookup for %16D MTU > %d\n", + p_rec.dgid.raw, ":", + comp_mask ? ib_mtu_enum_to_int(p_rec.mtu) : 0); + + init_completion(&path->done); + + path->query_id = + ib_sa_path_rec_get(&ipoib_sa_client, priv->ca, priv->port, + &p_rec, comp_mask | + IB_SA_PATH_REC_DGID | + IB_SA_PATH_REC_SGID | + IB_SA_PATH_REC_NUMB_PATH | + IB_SA_PATH_REC_TRAFFIC_CLASS | + IB_SA_PATH_REC_PKEY, + 1000, GFP_ATOMIC, + path_rec_completion, + path, &path->query); + if (path->query_id < 0) { + ipoib_warn(priv, "ib_sa_path_rec_get failed: %d\n", path->query_id); + path->query = NULL; + complete(&path->done); + return path->query_id; + } + + return 0; +} + +static void +ipoib_unicast_send(struct mbuf *mb, struct ipoib_dev_priv *priv, struct ipoib_header *eh) +{ + struct ipoib_path *path; + + path = __path_find(priv, eh->hwaddr + 4); + if (!path || !path->valid) { + int new_path = 0; + + if (!path) { + path = path_rec_create(priv, eh->hwaddr); + new_path = 1; + } + if (path) { + _IF_ENQUEUE(&path->queue, mb); + if (!path->query && path_rec_start(priv, path)) { + spin_unlock_irqrestore(&priv->lock, flags); + if (new_path) + ipoib_path_free(priv, path); + return; + } else + __path_add(priv, path); + } else { + ++priv->dev->if_oerrors; + m_freem(mb); + } + + return; + } + + if (ipoib_cm_get(path) && ipoib_cm_up(path)) { + ipoib_cm_send(priv, mb, ipoib_cm_get(path)); + } else if (path->ah) { + ipoib_send(priv, mb, path->ah, IPOIB_QPN(eh->hwaddr)); + } else if ((path->query || !path_rec_start(priv, path)) && + path->queue.ifq_len < IPOIB_MAX_PATH_REC_QUEUE) { + _IF_ENQUEUE(&path->queue, mb); + } else { + ++priv->dev->if_oerrors; + m_freem(mb); + } +} + +static int +ipoib_send_one(struct ipoib_dev_priv *priv, struct mbuf *mb) +{ + struct ipoib_header *eh; + + eh = mtod(mb, struct ipoib_header *); + if (IPOIB_IS_MULTICAST(eh->hwaddr)) { + /* Add in the P_Key for multicast*/ + eh->hwaddr[8] = (priv->pkey >> 8) & 0xff; + eh->hwaddr[9] = priv->pkey & 0xff; + + ipoib_mcast_send(priv, eh->hwaddr + 4, mb); + } else + ipoib_unicast_send(mb, priv, eh); + + return 0; +} + + +static void +_ipoib_start(struct ifnet *dev, struct ipoib_dev_priv *priv) +{ + struct mbuf *mb; + + if ((dev->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING) + return; + + spin_lock(&priv->lock); + while (!IFQ_DRV_IS_EMPTY(&dev->if_snd) && + (dev->if_drv_flags & IFF_DRV_OACTIVE) == 0) { + IFQ_DRV_DEQUEUE(&dev->if_snd, mb); + if (mb == NULL) + break; + IPOIB_MTAP(dev, mb); + ipoib_send_one(priv, mb); + } + spin_unlock(&priv->lock); +} + +static void +ipoib_start(struct ifnet *dev) +{ + _ipoib_start(dev, dev->if_softc); +} + +static void +ipoib_vlan_start(struct ifnet *dev) +{ + struct ipoib_dev_priv *priv; + struct mbuf *mb; + + priv = VLAN_COOKIE(dev); + if (priv != NULL) + return _ipoib_start(dev, priv); + while (!IFQ_DRV_IS_EMPTY(&dev->if_snd)) { + IFQ_DRV_DEQUEUE(&dev->if_snd, mb); + if (mb == NULL) + break; + m_freem(mb); + dev->if_oerrors++; + } +} + +int +ipoib_dev_init(struct ipoib_dev_priv *priv, struct ib_device *ca, int port) +{ + + /* Allocate RX/TX "rings" to hold queued mbs */ + priv->rx_ring = kzalloc(ipoib_recvq_size * sizeof *priv->rx_ring, + GFP_KERNEL); + if (!priv->rx_ring) { + printk(KERN_WARNING "%s: failed to allocate RX ring (%d entries)\n", + ca->name, ipoib_recvq_size); + goto out; + } + + priv->tx_ring = kzalloc(ipoib_sendq_size * sizeof *priv->tx_ring, GFP_KERNEL); + if (!priv->tx_ring) { + printk(KERN_WARNING "%s: failed to allocate TX ring (%d entries)\n", + ca->name, ipoib_sendq_size); + goto out_rx_ring_cleanup; + } + memset(priv->tx_ring, 0, ipoib_sendq_size * sizeof *priv->tx_ring); + + /* priv->tx_head, tx_tail & tx_outstanding are already 0 */ + + if (ipoib_ib_dev_init(priv, ca, port)) + goto out_tx_ring_cleanup; + + return 0; + +out_tx_ring_cleanup: + kfree(priv->tx_ring); + +out_rx_ring_cleanup: + kfree(priv->rx_ring); + +out: + return -ENOMEM; +} + +static void +ipoib_detach(struct ipoib_dev_priv *priv) +{ + struct ifnet *dev; + + dev = priv->dev; + if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { + bpfdetach(dev); + if_detach(dev); + if_free(dev); + } else + VLAN_SETCOOKIE(priv->dev, NULL); + + free(priv, M_TEMP); +} + +void +ipoib_dev_cleanup(struct ipoib_dev_priv *priv) +{ + struct ipoib_dev_priv *cpriv, *tcpriv; + + /* Delete any child interfaces first */ + list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) { + ipoib_dev_cleanup(cpriv); + ipoib_detach(cpriv); + } + + ipoib_ib_dev_cleanup(priv); + + kfree(priv->rx_ring); + kfree(priv->tx_ring); + + priv->rx_ring = NULL; + priv->tx_ring = NULL; +} + +static volatile int ipoib_unit; + +static struct ipoib_dev_priv * +ipoib_priv_alloc(void) +{ + struct ipoib_dev_priv *priv; + + priv = malloc(sizeof(struct ipoib_dev_priv), M_TEMP, M_ZERO|M_WAITOK); + spin_lock_init(&priv->lock); + mutex_init(&priv->vlan_mutex); + INIT_LIST_HEAD(&priv->path_list); + INIT_LIST_HEAD(&priv->child_intfs); + INIT_LIST_HEAD(&priv->dead_ahs); + INIT_LIST_HEAD(&priv->multicast_list); + INIT_DELAYED_WORK(&priv->pkey_poll_task, ipoib_pkey_poll); + INIT_DELAYED_WORK(&priv->mcast_task, ipoib_mcast_join_task); + INIT_WORK(&priv->carrier_on_task, ipoib_mcast_carrier_on_task); + INIT_WORK(&priv->flush_light, ipoib_ib_dev_flush_light); + INIT_WORK(&priv->flush_normal, ipoib_ib_dev_flush_normal); + INIT_WORK(&priv->flush_heavy, ipoib_ib_dev_flush_heavy); + INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task); + INIT_DELAYED_WORK(&priv->ah_reap_task, ipoib_reap_ah); + memcpy(priv->broadcastaddr, ipv4_bcast_addr, INFINIBAND_ALEN); + + return (priv); +} + +struct ipoib_dev_priv * +ipoib_intf_alloc(const char *name) +{ + struct ipoib_dev_priv *priv; + struct sockaddr_dl *sdl; + struct ifnet *dev; + + priv = ipoib_priv_alloc(); + dev = priv->dev = if_alloc(IFT_INFINIBAND); + if (!dev) { + free(priv, M_TEMP); + return NULL; + } + dev->if_softc = priv; + if_initname(dev, name, atomic_fetchadd_int(&ipoib_unit, 1)); + dev->if_flags = IFF_BROADCAST | IFF_MULTICAST; + dev->if_addrlen = INFINIBAND_ALEN; + dev->if_hdrlen = IPOIB_HEADER_LEN; + if_attach(dev); + dev->if_init = ipoib_init; + dev->if_ioctl = ipoib_ioctl; + dev->if_start = ipoib_start; + dev->if_output = ipoib_output; + dev->if_input = ipoib_input; + dev->if_resolvemulti = ipoib_resolvemulti; + dev->if_baudrate = IF_Gbps(10LL); + dev->if_broadcastaddr = priv->broadcastaddr; + dev->if_snd.ifq_maxlen = ipoib_sendq_size * 2; + sdl = (struct sockaddr_dl *)dev->if_addr->ifa_addr; + sdl->sdl_type = IFT_INFINIBAND; + sdl->sdl_alen = dev->if_addrlen; + priv->dev = dev; + if_link_state_change(dev, LINK_STATE_DOWN); + bpfattach(dev, DLT_EN10MB, ETHER_HDR_LEN); + + return dev->if_softc; +} + +int +ipoib_set_dev_features(struct ipoib_dev_priv *priv, struct ib_device *hca) +{ + struct ib_device_attr *device_attr; + int result = -ENOMEM; + + device_attr = kmalloc(sizeof *device_attr, GFP_KERNEL); + if (!device_attr) { + printk(KERN_WARNING "%s: allocation of %zu bytes failed\n", + hca->name, sizeof *device_attr); + return result; + } + + result = ib_query_device(hca, device_attr); + if (result) { + printk(KERN_WARNING "%s: ib_query_device failed (ret = %d)\n", + hca->name, result); + kfree(device_attr); + return result; + } + priv->hca_caps = device_attr->device_cap_flags; + + kfree(device_attr); + + priv->dev->if_hwassist = 0; + priv->dev->if_capabilities = 0; + +#ifndef CONFIG_INFINIBAND_IPOIB_CM + if (priv->hca_caps & IB_DEVICE_UD_IP_CSUM) { + set_bit(IPOIB_FLAG_CSUM, &priv->flags); + priv->dev->if_hwassist = CSUM_IP | CSUM_TCP | CSUM_UDP; + priv->dev->if_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM; + } + +#if 0 + if (priv->dev->features & NETIF_F_SG && priv->hca_caps & IB_DEVICE_UD_TSO) + priv->dev->if_capabilities |= IFCAP_TSO4 | CSUM_TSO; +#endif +#endif + priv->dev->if_capabilities |= + IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_LINKSTATE; + priv->dev->if_capenable = priv->dev->if_capabilities; + + return 0; +} + + +static struct ifnet * +ipoib_add_port(const char *format, struct ib_device *hca, u8 port) +{ + struct ipoib_dev_priv *priv; + struct ib_port_attr attr; + int result = -ENOMEM; + + priv = ipoib_intf_alloc(format); + if (!priv) + goto alloc_mem_failed; + + if (!ib_query_port(hca, port, &attr)) + priv->max_ib_mtu = ib_mtu_enum_to_int(attr.max_mtu); + else { + printk(KERN_WARNING "%s: ib_query_port %d failed\n", + hca->name, port); + goto device_init_failed; + } + + /* MTU will be reset when mcast join happens */ + priv->dev->if_mtu = IPOIB_UD_MTU(priv->max_ib_mtu); + priv->mcast_mtu = priv->admin_mtu = priv->dev->if_mtu; + + result = ib_query_pkey(hca, port, 0, &priv->pkey); + if (result) { + printk(KERN_WARNING "%s: ib_query_pkey port %d failed (ret = %d)\n", + hca->name, port, result); + goto device_init_failed; + } + + if (ipoib_set_dev_features(priv, hca)) + goto device_init_failed; + + /* + * Set the full membership bit, so that we join the right + * broadcast group, etc. + */ + priv->pkey |= 0x8000; + + priv->broadcastaddr[8] = priv->pkey >> 8; + priv->broadcastaddr[9] = priv->pkey & 0xff; + + result = ib_query_gid(hca, port, 0, &priv->local_gid); + if (result) { + printk(KERN_WARNING "%s: ib_query_gid port %d failed (ret = %d)\n", + hca->name, port, result); + goto device_init_failed; + } + memcpy(IF_LLADDR(priv->dev) + 4, priv->local_gid.raw, sizeof (union ib_gid)); + + result = ipoib_dev_init(priv, hca, port); + if (result < 0) { + printk(KERN_WARNING "%s: failed to initialize port %d (ret = %d)\n", + hca->name, port, result); + goto device_init_failed; + } + if (ipoib_cm_admin_enabled(priv)) + priv->dev->if_mtu = IPOIB_CM_MTU(ipoib_cm_max_mtu(priv)); + + INIT_IB_EVENT_HANDLER(&priv->event_handler, + priv->ca, ipoib_event); + result = ib_register_event_handler(&priv->event_handler); + if (result < 0) { + printk(KERN_WARNING "%s: ib_register_event_handler failed for " + "port %d (ret = %d)\n", + hca->name, port, result); + goto event_failed; + } + if_printf(priv->dev, "Attached to %s port %d\n", hca->name, port); + + return priv->dev; + +event_failed: + ipoib_dev_cleanup(priv); + +device_init_failed: + ipoib_detach(priv); + +alloc_mem_failed: + return ERR_PTR(result); +} + +static void +ipoib_add_one(struct ib_device *device) +{ + struct list_head *dev_list; + struct ifnet *dev; + struct ipoib_dev_priv *priv; + int s, e, p; + + if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) + return; + + dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL); + if (!dev_list) + return; + + INIT_LIST_HEAD(dev_list); + + if (device->node_type == RDMA_NODE_IB_SWITCH) { + s = 0; + e = 0; + } else { + s = 1; + e = device->phys_port_cnt; + } + + for (p = s; p <= e; ++p) { + if (rdma_port_get_link_layer(device, p) != IB_LINK_LAYER_INFINIBAND) + continue; + dev = ipoib_add_port("ib", device, p); + if (!IS_ERR(dev)) { + priv = dev->if_softc; + list_add_tail(&priv->list, dev_list); + } + } + + ib_set_client_data(device, &ipoib_client, dev_list); +} + +static void +ipoib_remove_one(struct ib_device *device) +{ + struct ipoib_dev_priv *priv, *tmp; + struct list_head *dev_list; + + if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) + return; + + dev_list = ib_get_client_data(device, &ipoib_client); + + list_for_each_entry_safe(priv, tmp, dev_list, list) { + if (rdma_port_get_link_layer(device, priv->port) != IB_LINK_LAYER_INFINIBAND) + continue; + + ib_unregister_event_handler(&priv->event_handler); + + /* dev_change_flags(priv->dev, priv->dev->flags & ~IFF_UP); */ + + flush_workqueue(ipoib_workqueue); + + ipoib_dev_cleanup(priv); + ipoib_detach(priv); + } + + kfree(dev_list); +} + +static void +ipoib_config_vlan(void *arg, struct ifnet *ifp, u_int16_t vtag) +{ + struct ipoib_dev_priv *parent; + struct ipoib_dev_priv *priv; + struct ifnet *dev; + uint16_t pkey; + int error; + + if (ifp->if_type != IFT_INFINIBAND) + return; + dev = VLAN_DEVAT(ifp, vtag); + if (dev == NULL) + return; + priv = NULL; + error = 0; + parent = ifp->if_softc; + /* We only support 15 bits of pkey. */ + if (vtag & 0x8000) + return; + pkey = vtag | 0x8000; /* Set full membership bit. */ + if (pkey == parent->pkey) + return; + /* Check for dups */ + mutex_lock(&parent->vlan_mutex); + list_for_each_entry(priv, &parent->child_intfs, list) { + if (priv->pkey == pkey) { + priv = NULL; + error = EBUSY; + goto out; + } + } + priv = ipoib_priv_alloc(); + priv->dev = dev; + priv->max_ib_mtu = parent->max_ib_mtu; + priv->mcast_mtu = priv->admin_mtu = parent->dev->if_mtu; + set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags); + error = ipoib_set_dev_features(priv, parent->ca); + if (error) + goto out; + priv->pkey = pkey; + priv->broadcastaddr[8] = pkey >> 8; + priv->broadcastaddr[9] = pkey & 0xff; + dev->if_broadcastaddr = priv->broadcastaddr; + error = ipoib_dev_init(priv, parent->ca, parent->port); + if (error) + goto out; + priv->parent = parent->dev; + list_add_tail(&priv->list, &parent->child_intfs); + VLAN_SETCOOKIE(dev, priv); + dev->if_start = ipoib_vlan_start; + dev->if_drv_flags &= ~IFF_DRV_RUNNING; + dev->if_hdrlen = IPOIB_HEADER_LEN; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ipoib_open(priv); + mutex_unlock(&parent->vlan_mutex); + return; +out: + mutex_unlock(&parent->vlan_mutex); + if (priv) + free(priv, M_TEMP); + if (error) + ipoib_warn(parent, + "failed to initialize subinterface: device %s, port %d vtag 0x%X", + parent->ca->name, parent->port, vtag); + return; +} + +static void +ipoib_unconfig_vlan(void *arg, struct ifnet *ifp, u_int16_t vtag) +{ + struct ipoib_dev_priv *parent; + struct ipoib_dev_priv *priv; + struct ifnet *dev; + uint16_t pkey; + + if (ifp->if_type != IFT_INFINIBAND) + return; + + dev = VLAN_DEVAT(ifp, vtag); + if (dev) + VLAN_SETCOOKIE(dev, NULL); + pkey = vtag | 0x8000; + parent = ifp->if_softc; + mutex_lock(&parent->vlan_mutex); + list_for_each_entry(priv, &parent->child_intfs, list) { + if (priv->pkey == pkey) { + ipoib_dev_cleanup(priv); + list_del(&priv->list); + break; + } + } + mutex_unlock(&parent->vlan_mutex); +} + +eventhandler_tag ipoib_vlan_attach; +eventhandler_tag ipoib_vlan_detach; + +static int __init +ipoib_init_module(void) +{ + int ret; + + ipoib_recvq_size = roundup_pow_of_two(ipoib_recvq_size); + ipoib_recvq_size = min(ipoib_recvq_size, IPOIB_MAX_QUEUE_SIZE); + ipoib_recvq_size = max(ipoib_recvq_size, IPOIB_MIN_QUEUE_SIZE); + + ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size); + ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE); + ipoib_sendq_size = max(ipoib_sendq_size, max(2 * MAX_SEND_CQE, + IPOIB_MIN_QUEUE_SIZE)); +#ifdef CONFIG_INFINIBAND_IPOIB_CM + ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP); +#endif + + ipoib_vlan_attach = EVENTHANDLER_REGISTER(vlan_config, + ipoib_config_vlan, NULL, EVENTHANDLER_PRI_FIRST); + ipoib_vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, + ipoib_unconfig_vlan, NULL, EVENTHANDLER_PRI_FIRST); + + /* + * We create our own workqueue mainly because we want to be + * able to flush it when devices are being removed. We can't + * use schedule_work()/flush_scheduled_work() because both + * unregister_netdev() and linkwatch_event take the rtnl lock, + * so flush_scheduled_work() can deadlock during device + * removal. + */ + ipoib_workqueue = create_singlethread_workqueue("ipoib"); + if (!ipoib_workqueue) { + ret = -ENOMEM; + goto err_fs; + } + + ib_sa_register_client(&ipoib_sa_client); + + ret = ib_register_client(&ipoib_client); + if (ret) + goto err_sa; + + return 0; + +err_sa: + ib_sa_unregister_client(&ipoib_sa_client); + destroy_workqueue(ipoib_workqueue); + +err_fs: + return ret; +} + +static void __exit +ipoib_cleanup_module(void) +{ + + EVENTHANDLER_DEREGISTER(vlan_config, ipoib_vlan_attach); + EVENTHANDLER_DEREGISTER(vlan_unconfig, ipoib_vlan_detach); + ib_unregister_client(&ipoib_client); + ib_sa_unregister_client(&ipoib_sa_client); + destroy_workqueue(ipoib_workqueue); +} + +/* + * Infiniband output routine. + */ +static int +ipoib_output(struct ifnet *ifp, struct mbuf *m, + struct sockaddr *dst, struct route *ro) +{ + u_char edst[INFINIBAND_ALEN]; + struct llentry *lle = NULL; + struct rtentry *rt0 = NULL; + struct ipoib_header *eh; + int error = 0; + short type; + + if (ro != NULL) { + if (!(m->m_flags & (M_BCAST | M_MCAST))) + lle = ro->ro_lle; + rt0 = ro->ro_rt; + } +#ifdef MAC + error = mac_ifnet_check_transmit(ifp, m); + if (error) + goto bad; +#endif + + M_PROFILE(m); + if (ifp->if_flags & IFF_MONITOR) { + error = ENETDOWN; + goto bad; + } + if (!((ifp->if_flags & IFF_UP) && + (ifp->if_drv_flags & IFF_DRV_RUNNING))) { + error = ENETDOWN; + goto bad; + } + + switch (dst->sa_family) { +#ifdef INET + case AF_INET: + if (lle != NULL && (lle->la_flags & LLE_VALID)) + memcpy(edst, &lle->ll_addr.mac8, sizeof(edst)); + else if (m->m_flags & M_MCAST) + ip_ib_mc_map(((struct sockaddr_in *)dst)->sin_addr.s_addr, ifp->if_broadcastaddr, edst); + else + error = arpresolve(ifp, rt0, m, dst, edst, &lle); + if (error) + return (error == EWOULDBLOCK ? 0 : error); + type = htons(ETHERTYPE_IP); + break; + case AF_ARP: + { + struct arphdr *ah; + ah = mtod(m, struct arphdr *); + ah->ar_hrd = htons(ARPHRD_INFINIBAND); + + switch(ntohs(ah->ar_op)) { + case ARPOP_REVREQUEST: + case ARPOP_REVREPLY: + type = htons(ETHERTYPE_REVARP); + break; + case ARPOP_REQUEST: + case ARPOP_REPLY: + default: + type = htons(ETHERTYPE_ARP); + break; + } + + if (m->m_flags & M_BCAST) + bcopy(ifp->if_broadcastaddr, edst, INFINIBAND_ALEN); + else + bcopy(ar_tha(ah), edst, INFINIBAND_ALEN); + + } + break; +#endif +#ifdef INET6 + case AF_INET6: + if (lle != NULL && (lle->la_flags & LLE_VALID)) + memcpy(edst, &lle->ll_addr.mac8, sizeof(edst)); + else if (m->m_flags & M_MCAST) + ipv6_ib_mc_map(&((struct sockaddr_in6 *)dst)->sin6_addr, ifp->if_broadcastaddr, edst); + else + error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle); + if (error) + return error; + type = htons(ETHERTYPE_IPV6); + break; +#endif + + default: + if_printf(ifp, "can't handle af%d\n", dst->sa_family); + error = EAFNOSUPPORT; + goto bad; + } + + /* + * Add local net header. If no space in first mbuf, + * allocate another. + */ + M_PREPEND(m, IPOIB_HEADER_LEN, M_DONTWAIT); + if (m == NULL) { + error = ENOBUFS; + goto bad; + } + eh = mtod(m, struct ipoib_header *); + (void)memcpy(&eh->proto, &type, sizeof(eh->proto)); + (void)memcpy(&eh->hwaddr, edst, sizeof (edst)); + + /* + * Queue message on interface, update output statistics if + * successful, and start output if interface not yet active. + */ + return ((ifp->if_transmit)(ifp, m)); +bad: + if (m != NULL) + m_freem(m); + return (error); +} + +/* + * Upper layer processing for a received Infiniband packet. + */ +void +ipoib_demux(struct ifnet *ifp, struct mbuf *m, u_short proto) +{ + int isr; + +#ifdef MAC + /* + * Tag the mbuf with an appropriate MAC label before any other + * consumers can get to it. + */ + mac_ifnet_create_mbuf(ifp, m); +#endif + /* Allow monitor mode to claim this frame, after stats are updated. */ + if (ifp->if_flags & IFF_MONITOR) { + if_printf(ifp, "discard frame at IFF_MONITOR\n"); + m_freem(m); + return; + } + /* + * Dispatch frame to upper layer. + */ + switch (proto) { +#ifdef INET + case ETHERTYPE_IP: + isr = NETISR_IP; + break; + + case ETHERTYPE_ARP: + if (ifp->if_flags & IFF_NOARP) { + /* Discard packet if ARP is disabled on interface */ + m_freem(m); + return; + } + isr = NETISR_ARP; + break; +#endif +#ifdef INET6 + case ETHERTYPE_IPV6: + isr = NETISR_IPV6; + break; +#endif + default: + goto discard; + } + netisr_dispatch(isr, m); + return; + +discard: + m_freem(m); +} + +/* + * Process a received Infiniband packet. + */ +static void +ipoib_input(struct ifnet *ifp, struct mbuf *m) +{ + struct ipoib_header *eh; + + if ((ifp->if_flags & IFF_UP) == 0) { + m_freem(m); + return; + } + CURVNET_SET_QUIET(ifp->if_vnet); + + /* Let BPF have it before we strip the header. */ + IPOIB_MTAP(ifp, m); + eh = mtod(m, struct ipoib_header *); + /* + * Reset layer specific mbuf flags to avoid confusing upper layers. + * Strip off Infiniband header. + */ + m->m_flags &= ~M_VLANTAG; + m->m_flags &= ~(M_PROTOFLAGS); + m_adj(m, IPOIB_HEADER_LEN); + + if (IPOIB_IS_MULTICAST(eh->hwaddr)) { + if (memcmp(eh->hwaddr, ifp->if_broadcastaddr, + ifp->if_addrlen) == 0) + m->m_flags |= M_BCAST; + else + m->m_flags |= M_MCAST; + ifp->if_imcasts++; + } + + ipoib_demux(ifp, m, ntohs(eh->proto)); + CURVNET_RESTORE(); +} + +static int +ipoib_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, + struct sockaddr *sa) +{ + struct sockaddr_dl *sdl; +#ifdef INET + struct sockaddr_in *sin; +#endif +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + u_char *e_addr; + + switch(sa->sa_family) { + case AF_LINK: + /* + * No mapping needed. Just check that it's a valid MC address. + */ + sdl = (struct sockaddr_dl *)sa; + e_addr = LLADDR(sdl); + if (!IPOIB_IS_MULTICAST(e_addr)) + return EADDRNOTAVAIL; + *llsa = 0; + return 0; + +#ifdef INET + case AF_INET: + sin = (struct sockaddr_in *)sa; + if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) + return EADDRNOTAVAIL; + sdl = malloc(sizeof *sdl, M_IFMADDR, + M_NOWAIT|M_ZERO); + if (sdl == NULL) + return ENOMEM; + sdl->sdl_len = sizeof *sdl; + sdl->sdl_family = AF_LINK; + sdl->sdl_index = ifp->if_index; + sdl->sdl_type = IFT_INFINIBAND; + sdl->sdl_alen = INFINIBAND_ALEN; + e_addr = LLADDR(sdl); + ip_ib_mc_map(sin->sin_addr.s_addr, ifp->if_broadcastaddr, + e_addr); + *llsa = (struct sockaddr *)sdl; + return 0; +#endif +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *)sa; + /* + * An IP6 address of 0 means listen to all + * of the multicast address used for IP6. + * This has no meaning in ipoib. + */ + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) + return EADDRNOTAVAIL; + if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) + return EADDRNOTAVAIL; + sdl = malloc(sizeof *sdl, M_IFMADDR, + M_NOWAIT|M_ZERO); + if (sdl == NULL) + return (ENOMEM); + sdl->sdl_len = sizeof *sdl; + sdl->sdl_family = AF_LINK; + sdl->sdl_index = ifp->if_index; + sdl->sdl_type = IFT_INFINIBAND; + sdl->sdl_alen = INFINIBAND_ALEN; + e_addr = LLADDR(sdl); + ipv6_ib_mc_map(&sin6->sin6_addr, ifp->if_broadcastaddr, e_addr); + *llsa = (struct sockaddr *)sdl; + return 0; +#endif + + default: + return EAFNOSUPPORT; + } +} + +module_init(ipoib_init_module); +module_exit(ipoib_cleanup_module); diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_multicast.c new file mode 100644 index 000000000000..a5746e426b27 --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "ipoib.h" + +#include +#include + +#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG +static int mcast_debug_level = 1; + +module_param(mcast_debug_level, int, 0644); +MODULE_PARM_DESC(mcast_debug_level, + "Enable multicast debug tracing if > 0"); +#endif + +static DEFINE_MUTEX(mcast_mutex); + +struct ipoib_mcast_iter { + struct ipoib_dev_priv *priv; + union ib_gid mgid; + unsigned long created; + unsigned int queuelen; + unsigned int complete; + unsigned int send_only; +}; + +static void ipoib_mcast_free(struct ipoib_mcast *mcast) +{ + struct ifnet *dev = mcast->priv->dev; + int tx_dropped = 0; + + ipoib_dbg_mcast(mcast->priv, "deleting multicast group %16D\n", + mcast->mcmember.mgid.raw, ":"); + + if (mcast->ah) + ipoib_put_ah(mcast->ah); + + tx_dropped = mcast->pkt_queue.ifq_len; + _IF_DRAIN(&mcast->pkt_queue); /* XXX Locking. */ + + dev->if_oerrors += tx_dropped; + + kfree(mcast); +} + +static struct ipoib_mcast *ipoib_mcast_alloc(struct ipoib_dev_priv *priv, + int can_sleep) +{ + struct ipoib_mcast *mcast; + + mcast = kzalloc(sizeof *mcast, can_sleep ? GFP_KERNEL : GFP_ATOMIC); + if (!mcast) + return NULL; + + mcast->priv = priv; + mcast->created = jiffies; + mcast->backoff = 1; + + INIT_LIST_HEAD(&mcast->list); + bzero(&mcast->pkt_queue, sizeof(mcast->pkt_queue)); + + return mcast; +} + +static struct ipoib_mcast *__ipoib_mcast_find(struct ipoib_dev_priv *priv, + void *mgid) +{ + struct rb_node *n = priv->multicast_tree.rb_node; + + while (n) { + struct ipoib_mcast *mcast; + int ret; + + mcast = rb_entry(n, struct ipoib_mcast, rb_node); + + ret = memcmp(mgid, mcast->mcmember.mgid.raw, + sizeof (union ib_gid)); + if (ret < 0) + n = n->rb_left; + else if (ret > 0) + n = n->rb_right; + else + return mcast; + } + + return NULL; +} + +static int __ipoib_mcast_add(struct ipoib_dev_priv *priv, + struct ipoib_mcast *mcast) +{ + struct rb_node **n = &priv->multicast_tree.rb_node, *pn = NULL; + + while (*n) { + struct ipoib_mcast *tmcast; + int ret; + + pn = *n; + tmcast = rb_entry(pn, struct ipoib_mcast, rb_node); + + ret = memcmp(mcast->mcmember.mgid.raw, tmcast->mcmember.mgid.raw, + sizeof (union ib_gid)); + if (ret < 0) + n = &pn->rb_left; + else if (ret > 0) + n = &pn->rb_right; + else + return -EEXIST; + } + + rb_link_node(&mcast->rb_node, pn, n); + rb_insert_color(&mcast->rb_node, &priv->multicast_tree); + + return 0; +} + +static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, + struct ib_sa_mcmember_rec *mcmember) +{ + struct ipoib_dev_priv *priv = mcast->priv; + struct ifnet *dev = priv->dev; + struct ipoib_ah *ah; + int ret; + int set_qkey = 0; + + mcast->mcmember = *mcmember; + + /* Set the cached Q_Key before we attach if it's the broadcast group */ + if (!memcmp(mcast->mcmember.mgid.raw, dev->if_broadcastaddr + 4, + sizeof (union ib_gid))) { + spin_lock_irq(&priv->lock); + if (!priv->broadcast) { + spin_unlock_irq(&priv->lock); + return -EAGAIN; + } + priv->qkey = be32_to_cpu(priv->broadcast->mcmember.qkey); + spin_unlock_irq(&priv->lock); + priv->tx_wr.wr.ud.remote_qkey = priv->qkey; + set_qkey = 1; + } + + if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { + if (test_and_set_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { + ipoib_warn(priv, "multicast group %16D already attached\n", + mcast->mcmember.mgid.raw, ":"); + + return 0; + } + + ret = ipoib_mcast_attach(priv, be16_to_cpu(mcast->mcmember.mlid), + &mcast->mcmember.mgid, set_qkey); + if (ret < 0) { + ipoib_warn(priv, "couldn't attach QP to multicast group %16D\n", + mcast->mcmember.mgid.raw, ":"); + + clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags); + return ret; + } + } + + { + struct ib_ah_attr av = { + .dlid = be16_to_cpu(mcast->mcmember.mlid), + .port_num = priv->port, + .sl = mcast->mcmember.sl, + .ah_flags = IB_AH_GRH, + .static_rate = mcast->mcmember.rate, + .grh = { + .flow_label = be32_to_cpu(mcast->mcmember.flow_label), + .hop_limit = mcast->mcmember.hop_limit, + .sgid_index = 0, + .traffic_class = mcast->mcmember.traffic_class + } + }; + av.grh.dgid = mcast->mcmember.mgid; + + ah = ipoib_create_ah(priv, priv->pd, &av); + if (!ah) { + ipoib_warn(priv, "ib_address_create failed\n"); + } else { + spin_lock_irq(&priv->lock); + mcast->ah = ah; + spin_unlock_irq(&priv->lock); + + ipoib_dbg_mcast(priv, "MGID %16D AV %p, LID 0x%04x, SL %d\n", + mcast->mcmember.mgid.raw, ":", + mcast->ah->ah, + be16_to_cpu(mcast->mcmember.mlid), + mcast->mcmember.sl); + } + } + + /* actually send any queued packets */ + while (mcast->pkt_queue.ifq_len) { + struct mbuf *mb; + _IF_DEQUEUE(&mcast->pkt_queue, mb); + mb->m_pkthdr.rcvif = dev; + + if (dev->if_transmit(dev, mb)) + ipoib_warn(priv, "dev_queue_xmit failed to requeue packet\n"); + } + + return 0; +} + +static int +ipoib_mcast_sendonly_join_complete(int status, + struct ib_sa_multicast *multicast) +{ + struct ipoib_mcast *mcast = multicast->context; + struct ipoib_dev_priv *priv = mcast->priv; + + /* We trap for port events ourselves. */ + if (status == -ENETRESET) + return 0; + + if (!status) + status = ipoib_mcast_join_finish(mcast, &multicast->rec); + + if (status) { + if (mcast->logcount++ < 20) + ipoib_dbg_mcast(priv, "multicast join failed for %16D, status %d\n", + mcast->mcmember.mgid.raw, ":", status); + + /* Flush out any queued packets */ + priv->dev->if_oerrors += mcast->pkt_queue.ifq_len; + _IF_DRAIN(&mcast->pkt_queue); + + /* Clear the busy flag so we try again */ + status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, + &mcast->flags); + } + return status; +} + +static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) +{ + struct ipoib_dev_priv *priv = mcast->priv; + struct ib_sa_mcmember_rec rec = { +#if 0 /* Some SMs don't support send-only yet */ + .join_state = 4 +#else + .join_state = 1 +#endif + }; + int ret = 0; + + if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) { + ipoib_dbg_mcast(priv, "device shutting down, no multicast joins\n"); + return -ENODEV; + } + + if (test_and_set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) { + ipoib_dbg_mcast(priv, "multicast entry busy, skipping\n"); + return -EBUSY; + } + + rec.mgid = mcast->mcmember.mgid; + rec.port_gid = priv->local_gid; + rec.pkey = cpu_to_be16(priv->pkey); + + mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, + priv->port, &rec, + IB_SA_MCMEMBER_REC_MGID | + IB_SA_MCMEMBER_REC_PORT_GID | + IB_SA_MCMEMBER_REC_PKEY | + IB_SA_MCMEMBER_REC_JOIN_STATE, + GFP_ATOMIC, + ipoib_mcast_sendonly_join_complete, + mcast); + if (IS_ERR(mcast->mc)) { + ret = PTR_ERR(mcast->mc); + clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + ipoib_warn(priv, "ib_sa_join_multicast failed (ret = %d)\n", + ret); + } else { + ipoib_dbg_mcast(priv, "no multicast record for %16D, starting join\n", + mcast->mcmember.mgid.raw, ":"); + } + + return ret; +} + +void ipoib_mcast_carrier_on_task(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, + carrier_on_task); + struct ib_port_attr attr; + + /* + * Take rtnl_lock to avoid racing with ipoib_stop() and + * turning the carrier back on while a device is being + * removed. + */ + if (ib_query_port(priv->ca, priv->port, &attr) || + attr.state != IB_PORT_ACTIVE) { + ipoib_dbg(priv, "Keeping carrier off until IB port is active\n"); + return; + } + if_link_state_change(priv->dev, LINK_STATE_UP); +} + +static int ipoib_mcast_join_complete(int status, + struct ib_sa_multicast *multicast) +{ + struct ipoib_mcast *mcast = multicast->context; + struct ipoib_dev_priv *priv = mcast->priv; + + ipoib_dbg_mcast(priv, "join completion for %16D (status %d)\n", + mcast->mcmember.mgid.raw, ":", status); + + /* We trap for port events ourselves. */ + if (status == -ENETRESET) + return 0; + + if (!status) + status = ipoib_mcast_join_finish(mcast, &multicast->rec); + + if (!status) { + mcast->backoff = 1; + mutex_lock(&mcast_mutex); + if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) + queue_delayed_work(ipoib_workqueue, + &priv->mcast_task, 0); + mutex_unlock(&mcast_mutex); + + /* + * Defer carrier on work to ipoib_workqueue to avoid a + * deadlock on rtnl_lock here. + */ + if (mcast == priv->broadcast) + queue_work(ipoib_workqueue, &priv->carrier_on_task); + + return 0; + } + + if (mcast->logcount++ < 20) { + if (status == -ETIMEDOUT || status == -EAGAIN) { + ipoib_dbg_mcast(priv, "multicast join failed for %16D, status %d\n", + mcast->mcmember.mgid.raw, ":", status); + } else { + ipoib_warn(priv, "multicast join failed for %16D, status %d\n", + mcast->mcmember.mgid.raw, ":", status); + } + } + + mcast->backoff *= 2; + if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) + mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS; + + /* Clear the busy flag so we try again */ + status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + + mutex_lock(&mcast_mutex); + spin_lock_irq(&priv->lock); + if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) + queue_delayed_work(ipoib_workqueue, &priv->mcast_task, + mcast->backoff * HZ); + spin_unlock_irq(&priv->lock); + mutex_unlock(&mcast_mutex); + + return status; +} + +static void ipoib_mcast_join(struct ipoib_dev_priv *priv, + struct ipoib_mcast *mcast, int create) +{ + struct ib_sa_mcmember_rec rec = { + .join_state = 1 + }; + ib_sa_comp_mask comp_mask; + int ret = 0; + + ipoib_dbg_mcast(priv, "joining MGID %16D\n", + mcast->mcmember.mgid.raw, ":"); + + rec.mgid = mcast->mcmember.mgid; + rec.port_gid = priv->local_gid; + rec.pkey = cpu_to_be16(priv->pkey); + + comp_mask = + IB_SA_MCMEMBER_REC_MGID | + IB_SA_MCMEMBER_REC_PORT_GID | + IB_SA_MCMEMBER_REC_PKEY | + IB_SA_MCMEMBER_REC_JOIN_STATE; + + if (create) { + comp_mask |= + IB_SA_MCMEMBER_REC_QKEY | + IB_SA_MCMEMBER_REC_MTU_SELECTOR | + IB_SA_MCMEMBER_REC_MTU | + IB_SA_MCMEMBER_REC_TRAFFIC_CLASS | + IB_SA_MCMEMBER_REC_RATE_SELECTOR | + IB_SA_MCMEMBER_REC_RATE | + IB_SA_MCMEMBER_REC_SL | + IB_SA_MCMEMBER_REC_FLOW_LABEL | + IB_SA_MCMEMBER_REC_HOP_LIMIT; + + rec.qkey = priv->broadcast->mcmember.qkey; + rec.mtu_selector = IB_SA_EQ; + rec.mtu = priv->broadcast->mcmember.mtu; + rec.traffic_class = priv->broadcast->mcmember.traffic_class; + rec.rate_selector = IB_SA_EQ; + rec.rate = priv->broadcast->mcmember.rate; + rec.sl = priv->broadcast->mcmember.sl; + rec.flow_label = priv->broadcast->mcmember.flow_label; + rec.hop_limit = priv->broadcast->mcmember.hop_limit; + } + + set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port, + &rec, comp_mask, GFP_KERNEL, + ipoib_mcast_join_complete, mcast); + if (IS_ERR(mcast->mc)) { + clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + ret = PTR_ERR(mcast->mc); + ipoib_warn(priv, "ib_sa_join_multicast failed, status %d\n", ret); + + mcast->backoff *= 2; + if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) + mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS; + + mutex_lock(&mcast_mutex); + if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) + queue_delayed_work(ipoib_workqueue, + &priv->mcast_task, + mcast->backoff * HZ); + mutex_unlock(&mcast_mutex); + } +} + +void ipoib_mcast_join_task(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, mcast_task.work); + struct ifnet *dev = priv->dev; + + ipoib_dbg_mcast(priv, "Running join task. flags 0x%lX\n", priv->flags); + + if (!test_bit(IPOIB_MCAST_RUN, &priv->flags)) + return; + + if (ib_query_gid(priv->ca, priv->port, 0, &priv->local_gid)) + ipoib_warn(priv, "ib_query_gid() failed\n"); + else + memcpy(IF_LLADDR(dev) + 4, priv->local_gid.raw, sizeof (union ib_gid)); + + { + struct ib_port_attr attr; + + if (!ib_query_port(priv->ca, priv->port, &attr)) + priv->local_lid = attr.lid; + else + ipoib_warn(priv, "ib_query_port failed\n"); + } + + if (!priv->broadcast) { + struct ipoib_mcast *broadcast; + + if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) + return; + + broadcast = ipoib_mcast_alloc(priv, 1); + if (!broadcast) { + ipoib_warn(priv, "failed to allocate broadcast group\n"); + mutex_lock(&mcast_mutex); + if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) + queue_delayed_work(ipoib_workqueue, + &priv->mcast_task, HZ); + mutex_unlock(&mcast_mutex); + return; + } + + spin_lock_irq(&priv->lock); + memcpy(broadcast->mcmember.mgid.raw, dev->if_broadcastaddr + 4, + sizeof (union ib_gid)); + priv->broadcast = broadcast; + + __ipoib_mcast_add(priv, priv->broadcast); + spin_unlock_irq(&priv->lock); + } + + if (priv->broadcast && + !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { + if (priv->broadcast && + !test_bit(IPOIB_MCAST_FLAG_BUSY, &priv->broadcast->flags)) + ipoib_mcast_join(priv, priv->broadcast, 0); + return; + } + + while (1) { + struct ipoib_mcast *mcast = NULL; + + spin_lock_irq(&priv->lock); + list_for_each_entry(mcast, &priv->multicast_list, list) { + if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags) + && !test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags) + && !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { + /* Found the next unjoined group */ + break; + } + } + spin_unlock_irq(&priv->lock); + + if (&mcast->list == &priv->multicast_list) { + /* All done */ + break; + } + + ipoib_mcast_join(priv, mcast, 1); + return; + } + + spin_lock_irq(&priv->lock); + if (priv->broadcast) + priv->mcast_mtu = IPOIB_UD_MTU(ib_mtu_enum_to_int(priv->broadcast->mcmember.mtu)); + else + priv->mcast_mtu = priv->admin_mtu; + spin_unlock_irq(&priv->lock); + + if (!ipoib_cm_admin_enabled(priv)) + ipoib_change_mtu(priv, min(priv->mcast_mtu, priv->admin_mtu)); + + ipoib_dbg_mcast(priv, "successfully joined all multicast groups\n"); + + clear_bit(IPOIB_MCAST_RUN, &priv->flags); +} + +int ipoib_mcast_start_thread(struct ipoib_dev_priv *priv) +{ + ipoib_dbg_mcast(priv, "starting multicast thread flags 0x%lX\n", + priv->flags); + + mutex_lock(&mcast_mutex); + if (!test_and_set_bit(IPOIB_MCAST_RUN, &priv->flags)) + queue_delayed_work(ipoib_workqueue, &priv->mcast_task, 0); + mutex_unlock(&mcast_mutex); + + return 0; +} + +int ipoib_mcast_stop_thread(struct ipoib_dev_priv *priv, int flush) +{ + + ipoib_dbg_mcast(priv, "stopping multicast thread\n"); + + mutex_lock(&mcast_mutex); + clear_bit(IPOIB_MCAST_RUN, &priv->flags); + cancel_delayed_work(&priv->mcast_task); + mutex_unlock(&mcast_mutex); + + if (flush) + flush_workqueue(ipoib_workqueue); + + return 0; +} + +static int ipoib_mcast_leave(struct ipoib_dev_priv *priv, struct ipoib_mcast *mcast) +{ + int ret = 0; + + if (test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) + ib_sa_free_multicast(mcast->mc); + + if (test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { + ipoib_dbg_mcast(priv, "leaving MGID %16D\n", + mcast->mcmember.mgid.raw, ":"); + + /* Remove ourselves from the multicast group */ + ret = ib_detach_mcast(priv->qp, &mcast->mcmember.mgid, + be16_to_cpu(mcast->mcmember.mlid)); + if (ret) + ipoib_warn(priv, "ib_detach_mcast failed (result = %d)\n", ret); + } + + return 0; +} + +void +ipoib_mcast_send(struct ipoib_dev_priv *priv, void *mgid, struct mbuf *mb) +{ + struct ifnet *dev = priv->dev; + struct ipoib_mcast *mcast; + + if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags) || + !priv->broadcast || + !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { + ++dev->if_oerrors; + m_freem(mb); + return; + } + + mcast = __ipoib_mcast_find(priv, mgid); + if (!mcast) { + /* Let's create a new send only group now */ + ipoib_dbg_mcast(priv, "setting up send only multicast group for %16D\n", + mgid, ":"); + + mcast = ipoib_mcast_alloc(priv, 0); + if (!mcast) { + ipoib_warn(priv, "unable to allocate memory for " + "multicast structure\n"); + ++dev->if_oerrors; + m_freem(mb); + goto out; + } + + set_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags); + memcpy(mcast->mcmember.mgid.raw, mgid, sizeof (union ib_gid)); + __ipoib_mcast_add(priv, mcast); + list_add_tail(&mcast->list, &priv->multicast_list); + } + + if (!mcast->ah) { + if (mcast->pkt_queue.ifq_len < IPOIB_MAX_MCAST_QUEUE) { + _IF_ENQUEUE(&mcast->pkt_queue, mb); + } else { + ++dev->if_oerrors; + m_freem(mb); + } + + if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) + ipoib_dbg_mcast(priv, "no address vector, " + "but multicast join already started\n"); + else if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) + ipoib_mcast_sendonly_join(mcast); + + /* + * If lookup completes between here and out:, don't + * want to send packet twice. + */ + mcast = NULL; + } + +out: + if (mcast && mcast->ah) + ipoib_send(priv, mb, mcast->ah, IB_MULTICAST_QPN); +} + +void ipoib_mcast_dev_flush(struct ipoib_dev_priv *priv) +{ + LIST_HEAD(remove_list); + struct ipoib_mcast *mcast, *tmcast; + unsigned long flags; + + ipoib_dbg_mcast(priv, "flushing multicast list\n"); + + spin_lock_irqsave(&priv->lock, flags); + + list_for_each_entry_safe(mcast, tmcast, &priv->multicast_list, list) { + list_del(&mcast->list); + rb_erase(&mcast->rb_node, &priv->multicast_tree); + list_add_tail(&mcast->list, &remove_list); + } + + if (priv->broadcast) { + rb_erase(&priv->broadcast->rb_node, &priv->multicast_tree); + list_add_tail(&priv->broadcast->list, &remove_list); + priv->broadcast = NULL; + } + + spin_unlock_irqrestore(&priv->lock, flags); + + list_for_each_entry_safe(mcast, tmcast, &remove_list, list) { + ipoib_mcast_leave(priv, mcast); + ipoib_mcast_free(mcast); + } +} + +static int ipoib_mcast_addr_is_valid(const u8 *addr, unsigned int addrlen, + const u8 *broadcast) +{ + if (addrlen != INFINIBAND_ALEN) + return 0; + /* reserved QPN, prefix, scope */ + if (memcmp(addr, broadcast, 6)) + return 0; + /* signature lower, pkey */ + if (memcmp(addr + 7, broadcast + 7, 3)) + return 0; + return 1; +} + +void ipoib_mcast_restart_task(struct work_struct *work) +{ + struct ipoib_dev_priv *priv = + container_of(work, struct ipoib_dev_priv, restart_task); + ipoib_mcast_restart(priv); +} + +void ipoib_mcast_restart(struct ipoib_dev_priv *priv) +{ + struct ifnet *dev = priv->dev; + struct ifmultiaddr *ifma;; + struct ipoib_mcast *mcast, *tmcast; + LIST_HEAD(remove_list); + struct ib_sa_mcmember_rec rec; + int addrlen; + + ipoib_dbg_mcast(priv, "restarting multicast task flags 0x%lX\n", + priv->flags); + + ipoib_mcast_stop_thread(priv, 0); + + if_maddr_rlock(dev); + spin_lock(&priv->lock); + + /* + * Unfortunately, the networking core only gives us a list of all of + * the multicast hardware addresses. We need to figure out which ones + * are new and which ones have been removed + */ + + /* Clear out the found flag */ + list_for_each_entry(mcast, &priv->multicast_list, list) + clear_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags); + + /* Mark all of the entries that are found or don't exist */ + + + TAILQ_FOREACH(ifma, &dev->if_multiaddrs, ifma_link) { + union ib_gid mgid; + uint8_t *addr; + + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + addr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); + addrlen = ((struct sockaddr_dl *)ifma->ifma_addr)->sdl_alen; + if (!ipoib_mcast_addr_is_valid(addr, addrlen, + dev->if_broadcastaddr)) + continue; + + memcpy(mgid.raw, addr + 4, sizeof mgid); + + mcast = __ipoib_mcast_find(priv, &mgid); + if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { + struct ipoib_mcast *nmcast; + + /* ignore group which is directly joined by userspace */ + if (test_bit(IPOIB_FLAG_UMCAST, &priv->flags) && + !ib_sa_get_mcmember_rec(priv->ca, priv->port, &mgid, &rec)) { + ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid %16D\n", + mgid.raw, ":"); + continue; + } + + /* Not found or send-only group, let's add a new entry */ + ipoib_dbg_mcast(priv, "adding multicast entry for mgid %16D\n", + mgid.raw, ":"); + + nmcast = ipoib_mcast_alloc(priv, 0); + if (!nmcast) { + ipoib_warn(priv, "unable to allocate memory for multicast structure\n"); + continue; + } + + set_bit(IPOIB_MCAST_FLAG_FOUND, &nmcast->flags); + + nmcast->mcmember.mgid = mgid; + + if (mcast) { + /* Destroy the send only entry */ + list_move_tail(&mcast->list, &remove_list); + + rb_replace_node(&mcast->rb_node, + &nmcast->rb_node, + &priv->multicast_tree); + } else + __ipoib_mcast_add(priv, nmcast); + + list_add_tail(&nmcast->list, &priv->multicast_list); + } + + if (mcast) + set_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags); + } + + /* Remove all of the entries don't exist anymore */ + list_for_each_entry_safe(mcast, tmcast, &priv->multicast_list, list) { + if (!test_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags) && + !test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { + ipoib_dbg_mcast(priv, "deleting multicast group %16D\n", + mcast->mcmember.mgid.raw, ":"); + + rb_erase(&mcast->rb_node, &priv->multicast_tree); + + /* Move to the remove list */ + list_move_tail(&mcast->list, &remove_list); + } + } + + spin_unlock(&priv->lock); + if_maddr_runlock(dev); + + /* We have to cancel outside of the spinlock */ + list_for_each_entry_safe(mcast, tmcast, &remove_list, list) { + ipoib_mcast_leave(mcast->priv, mcast); + ipoib_mcast_free(mcast); + } + + if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) + ipoib_mcast_start_thread(priv); +} + +#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG + +struct ipoib_mcast_iter *ipoib_mcast_iter_init(struct ipoib_dev_priv *priv) +{ + struct ipoib_mcast_iter *iter; + + iter = kmalloc(sizeof *iter, GFP_KERNEL); + if (!iter) + return NULL; + + iter->priv = priv; + memset(iter->mgid.raw, 0, 16); + + if (ipoib_mcast_iter_next(iter)) { + kfree(iter); + return NULL; + } + + return iter; +} + +int ipoib_mcast_iter_next(struct ipoib_mcast_iter *iter) +{ + struct ipoib_dev_priv *priv = iter->priv; + struct rb_node *n; + struct ipoib_mcast *mcast; + int ret = 1; + + spin_lock_irq(&priv->lock); + + n = rb_first(&priv->multicast_tree); + + while (n) { + mcast = rb_entry(n, struct ipoib_mcast, rb_node); + + if (memcmp(iter->mgid.raw, mcast->mcmember.mgid.raw, + sizeof (union ib_gid)) < 0) { + iter->mgid = mcast->mcmember.mgid; + iter->created = mcast->created; + iter->queuelen = mcast->pkt_queue.ifq_len; + iter->complete = !!mcast->ah; + iter->send_only = !!(mcast->flags & (1 << IPOIB_MCAST_FLAG_SENDONLY)); + + ret = 0; + + break; + } + + n = rb_next(n); + } + + spin_unlock_irq(&priv->lock); + + return ret; +} + +void ipoib_mcast_iter_read(struct ipoib_mcast_iter *iter, + union ib_gid *mgid, + unsigned long *created, + unsigned int *queuelen, + unsigned int *complete, + unsigned int *send_only) +{ + *mgid = iter->mgid; + *created = iter->created; + *queuelen = iter->queuelen; + *complete = iter->complete; + *send_only = iter->send_only; +} + +#endif /* CONFIG_INFINIBAND_IPOIB_DEBUG */ diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_verbs.c new file mode 100644 index 000000000000..fb9a27abbbcc --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "ipoib.h" +#include + +int ipoib_mcast_attach(struct ipoib_dev_priv *priv, u16 mlid, union ib_gid *mgid, int set_qkey) +{ + struct ib_qp_attr *qp_attr = NULL; + int ret; + u16 pkey_index; + + if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &pkey_index)) { + clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); + ret = -ENXIO; + goto out; + } + set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); + + if (set_qkey) { + ret = -ENOMEM; + qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL); + if (!qp_attr) + goto out; + + /* set correct QKey for QP */ + qp_attr->qkey = priv->qkey; + ret = ib_modify_qp(priv->qp, qp_attr, IB_QP_QKEY); + if (ret) { + ipoib_warn(priv, "failed to modify QP, ret = %d\n", ret); + goto out; + } + } + + /* attach QP to multicast group */ + ret = ib_attach_mcast(priv->qp, mgid, mlid); + if (ret) + ipoib_warn(priv, "failed to attach to multicast group, ret = %d\n", ret); + +out: + kfree(qp_attr); + return ret; +} + +int ipoib_init_qp(struct ipoib_dev_priv *priv) +{ + int ret; + struct ib_qp_attr qp_attr; + int attr_mask; + + if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) + return -1; + + qp_attr.qp_state = IB_QPS_INIT; + qp_attr.qkey = 0; + qp_attr.port_num = priv->port; + qp_attr.pkey_index = priv->pkey_index; + attr_mask = + IB_QP_QKEY | + IB_QP_PORT | + IB_QP_PKEY_INDEX | + IB_QP_STATE; + ret = ib_modify_qp(priv->qp, &qp_attr, attr_mask); + if (ret) { + ipoib_warn(priv, "failed to modify QP to init, ret = %d\n", ret); + goto out_fail; + } + + qp_attr.qp_state = IB_QPS_RTR; + /* Can't set this in a INIT->RTR transition */ + attr_mask &= ~IB_QP_PORT; + ret = ib_modify_qp(priv->qp, &qp_attr, attr_mask); + if (ret) { + ipoib_warn(priv, "failed to modify QP to RTR, ret = %d\n", ret); + goto out_fail; + } + + qp_attr.qp_state = IB_QPS_RTS; + qp_attr.sq_psn = 0; + attr_mask |= IB_QP_SQ_PSN; + attr_mask &= ~IB_QP_PKEY_INDEX; + ret = ib_modify_qp(priv->qp, &qp_attr, attr_mask); + if (ret) { + ipoib_warn(priv, "failed to modify QP to RTS, ret = %d\n", ret); + goto out_fail; + } + + return 0; + +out_fail: + qp_attr.qp_state = IB_QPS_RESET; + if (ib_modify_qp(priv->qp, &qp_attr, IB_QP_STATE)) + ipoib_warn(priv, "Failed to modify QP to RESET state\n"); + + return ret; +} + +int ipoib_transport_dev_init(struct ipoib_dev_priv *priv, struct ib_device *ca) +{ + struct ib_qp_init_attr init_attr = { + .cap = { + .max_send_wr = ipoib_sendq_size, + .max_recv_wr = ipoib_recvq_size, + .max_send_sge = 1, + .max_recv_sge = IPOIB_UD_RX_SG + }, + .sq_sig_type = IB_SIGNAL_ALL_WR, + .qp_type = IB_QPT_UD + }; + + int ret, size; + int i; + /* XXX struct ethtool_coalesce *coal; */ + + priv->pd = ib_alloc_pd(priv->ca); + if (IS_ERR(priv->pd)) { + printk(KERN_WARNING "%s: failed to allocate PD\n", ca->name); + return -ENODEV; + } + + priv->mr = ib_get_dma_mr(priv->pd, IB_ACCESS_LOCAL_WRITE); + if (IS_ERR(priv->mr)) { + printk(KERN_WARNING "%s: ib_get_dma_mr failed\n", ca->name); + goto out_free_pd; + } + + size = ipoib_recvq_size + 1; + ret = ipoib_cm_dev_init(priv); + if (!ret) { + size += ipoib_sendq_size; + if (ipoib_cm_has_srq(priv)) + size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */ + else + size += ipoib_recvq_size * ipoib_max_conn_qp; + } + + priv->recv_cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, priv, size, 0); + if (IS_ERR(priv->recv_cq)) { + printk(KERN_WARNING "%s: failed to create receive CQ\n", ca->name); + goto out_free_mr; + } + + priv->send_cq = ib_create_cq(priv->ca, ipoib_send_comp_handler, NULL, + priv, ipoib_sendq_size, 0); + if (IS_ERR(priv->send_cq)) { + printk(KERN_WARNING "%s: failed to create send CQ\n", ca->name); + goto out_free_recv_cq; + } + + if (ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP)) + goto out_free_send_cq; + +#if 0 + /* XXX */ + coal = kzalloc(sizeof *coal, GFP_KERNEL); + if (coal) { + coal->rx_coalesce_usecs = 10; + coal->tx_coalesce_usecs = 10; + coal->rx_max_coalesced_frames = 16; + coal->tx_max_coalesced_frames = 16; + dev->ethtool_ops->set_coalesce(dev, coal); + kfree(coal); + } +#endif + + init_attr.send_cq = priv->send_cq; + init_attr.recv_cq = priv->recv_cq; + + if (priv->hca_caps & IB_DEVICE_UD_TSO) + init_attr.create_flags |= IB_QP_CREATE_IPOIB_UD_LSO; + + if (priv->hca_caps & IB_DEVICE_BLOCK_MULTICAST_LOOPBACK) + init_attr.create_flags |= IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK; + + init_attr.cap.max_send_sge = IPOIB_UD_TX_SG; + + priv->qp = ib_create_qp(priv->pd, &init_attr); + if (IS_ERR(priv->qp)) { + printk(KERN_WARNING "%s: failed to create QP\n", ca->name); + goto out_free_send_cq; + } + + IF_LLADDR(priv->dev)[1] = (priv->qp->qp_num >> 16) & 0xff; + IF_LLADDR(priv->dev)[2] = (priv->qp->qp_num >> 8) & 0xff; + IF_LLADDR(priv->dev)[3] = (priv->qp->qp_num ) & 0xff; + + for (i = 0; i < IPOIB_MAX_TX_SG; ++i) + priv->tx_sge[i].lkey = priv->mr->lkey; + + priv->tx_wr.opcode = IB_WR_SEND; + priv->tx_wr.sg_list = priv->tx_sge; + priv->tx_wr.send_flags = IB_SEND_SIGNALED; + + for (i = 0; i < IPOIB_UD_RX_SG; ++i) + priv->rx_sge[i].lkey = priv->mr->lkey; + priv->rx_wr.next = NULL; + priv->rx_wr.sg_list = priv->rx_sge; + + return 0; + +out_free_send_cq: + ib_destroy_cq(priv->send_cq); + +out_free_recv_cq: + ib_destroy_cq(priv->recv_cq); + +out_free_mr: + ib_dereg_mr(priv->mr); + ipoib_cm_dev_cleanup(priv); + +out_free_pd: + ib_dealloc_pd(priv->pd); + return -ENODEV; +} + +void ipoib_transport_dev_cleanup(struct ipoib_dev_priv *priv) +{ + + if (priv->qp) { + if (ib_destroy_qp(priv->qp)) + ipoib_warn(priv, "ib_qp_destroy failed\n"); + + priv->qp = NULL; + clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); + } + + if (ib_destroy_cq(priv->send_cq)) + ipoib_warn(priv, "ib_cq_destroy (send) failed\n"); + + if (ib_destroy_cq(priv->recv_cq)) + ipoib_warn(priv, "ib_cq_destroy (recv) failed\n"); + + ipoib_cm_dev_cleanup(priv); + + if (ib_dereg_mr(priv->mr)) + ipoib_warn(priv, "ib_dereg_mr failed\n"); + + if (ib_dealloc_pd(priv->pd)) + ipoib_warn(priv, "ib_dealloc_pd failed\n"); +} + +void ipoib_event(struct ib_event_handler *handler, + struct ib_event *record) +{ + struct ipoib_dev_priv *priv = + container_of(handler, struct ipoib_dev_priv, event_handler); + + if (record->element.port_num != priv->port) + return; + + ipoib_dbg(priv, "Event %d on device %s port %d\n", record->event, + record->device->name, record->element.port_num); + + if (record->event == IB_EVENT_SM_CHANGE || + record->event == IB_EVENT_CLIENT_REREGISTER) { + queue_work(ipoib_workqueue, &priv->flush_light); + } else if (record->event == IB_EVENT_PORT_ERR || + record->event == IB_EVENT_PORT_ACTIVE || + record->event == IB_EVENT_LID_CHANGE) { + queue_work(ipoib_workqueue, &priv->flush_normal); + } else if (record->event == IB_EVENT_PKEY_CHANGE) { + queue_work(ipoib_workqueue, &priv->flush_heavy); + } +} diff --git a/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_vlan.c new file mode 100644 index 000000000000..18c761fdcbcc --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include +#include +#include + +#include + +#include "ipoib.h" + +static ssize_t show_parent(struct device *d, struct device_attribute *attr, + char *buf) +{ + struct ifnet *dev = to_net_dev(d); + struct ipoib_dev_priv *priv = dev->if_softc; + + return sprintf(buf, "%s\n", priv->parent->name); +} +static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); + +int ipoib_vlan_add(struct ifnet *pdev, unsigned short pkey) +{ + struct ipoib_dev_priv *ppriv, *priv; + char intf_name[IFNAMSIZ]; + int result; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + ppriv = pdev->if_softc; + + rtnl_lock(); + mutex_lock(&ppriv->vlan_mutex); + + /* + * First ensure this isn't a duplicate. We check the parent device and + * then all of the child interfaces to make sure the Pkey doesn't match. + */ + if (ppriv->pkey == pkey) { + result = -ENOTUNIQ; + priv = NULL; + goto err; + } + + list_for_each_entry(priv, &ppriv->child_intfs, list) { + if (priv->pkey == pkey) { + result = -ENOTUNIQ; + priv = NULL; + goto err; + } + } + + snprintf(intf_name, sizeof intf_name, "%s.%04x", + ppriv->dev->name, pkey); + priv = ipoib_intf_alloc(intf_name); + if (!priv) { + result = -ENOMEM; + goto err; + } + + priv->max_ib_mtu = ppriv->max_ib_mtu; + /* MTU will be reset when mcast join happens */ + priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu); + priv->mcast_mtu = priv->admin_mtu = priv->dev->mtu; + set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags); + + result = ipoib_set_dev_features(priv, ppriv->ca); + if (result) + goto err; + + priv->pkey = pkey; + + memcpy(IF_LLADDR(priv->dev), ppriv->dev->dev_addr, INFINIBAND_ALEN); + priv->broadcastaddr[8] = pkey >> 8; + priv->broadcastaddr[9] = pkey & 0xff; + + result = ipoib_dev_init(priv->dev, ppriv->ca, ppriv->port); + if (result < 0) { + ipoib_warn(ppriv, "failed to initialize subinterface: " + "device %s, port %d", + ppriv->ca->name, ppriv->port); + goto err; + } + + result = register_netdevice(priv->dev); + if (result) { + ipoib_warn(priv, "failed to initialize; error %i", result); + goto register_failed; + } + + priv->parent = ppriv->dev; + + ipoib_create_debug_files(priv->dev); + + if (ipoib_cm_add_mode_attr(priv->dev)) + goto sysfs_failed; + if (ipoib_add_pkey_attr(priv->dev)) + goto sysfs_failed; + if (ipoib_add_umcast_attr(priv->dev)) + goto sysfs_failed; + + if (device_create_file(&priv->dev->dev, &dev_attr_parent)) + goto sysfs_failed; + + list_add_tail(&priv->list, &ppriv->child_intfs); + + mutex_unlock(&ppriv->vlan_mutex); + rtnl_unlock(); + + return 0; + +sysfs_failed: + ipoib_delete_debug_files(priv->dev); + unregister_netdevice(priv->dev); + +register_failed: + ipoib_dev_cleanup(priv->dev); + +err: + mutex_unlock(&ppriv->vlan_mutex); + rtnl_unlock(); + if (priv) + free_netdev(priv->dev); + + return result; +} + +int ipoib_vlan_delete(struct ifnet *pdev, unsigned short pkey) +{ + struct ipoib_dev_priv *ppriv, *priv, *tpriv; + struct ifnet *dev = NULL; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + ppriv = pdev->if_softc; + + rtnl_lock(); + mutex_lock(&ppriv->vlan_mutex); + list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) { + if (priv->pkey == pkey) { + unregister_netdevice(priv->dev); + ipoib_dev_cleanup(priv->dev); + list_del(&priv->list); + dev = priv->dev; + break; + } + } + mutex_unlock(&ppriv->vlan_mutex); + rtnl_unlock(); + + if (dev) { + free_netdev(dev); + return 0; + } + + return -ENODEV; +} diff --git a/sys/ofed/drivers/infiniband/ulp/sdp/Kconfig b/sys/ofed/drivers/infiniband/ulp/sdp/Kconfig new file mode 100644 index 000000000000..b5fadf4452c3 --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/sdp/Kconfig @@ -0,0 +1,28 @@ +config INFINIBAND_SDP + tristate "Sockets Direct Protocol" + depends on INFINIBAND && INFINIBAND_IPOIB + ---help--- + Support for Sockets Direct Protocol (SDP). This provides + sockets semantics over InfiniBand via address family + AF_INET_SDP (address family 27). You can also LD_PRELOAD the + libsdp library from to have standard + sockets applications use SDP. + +config INFINIBAND_SDP_DEBUG + bool "Sockets Direct Protocol debugging" + depends on INFINIBAND_SDP + ---help--- + This option causes debugging code to be compiled into the + SDP driver. The output can be turned on via the debug_level + module parameter (which can also be set through sysfs after the + driver is loaded). + +config INFINIBAND_SDP_DEBUG_DATA + bool "Sockets Direct Protocol data path debugging" + depends on INFINIBAND_SDP_DEBUG + ---help--- + This option compiles debugging code into the the data path + of the SDP driver. The output can be turned on via the + data_debug_level module parameter; however, even with output + turned off, this debugging code will have some performance + impact. diff --git a/sys/ofed/drivers/infiniband/ulp/sdp/Makefile b/sys/ofed/drivers/infiniband/ulp/sdp/Makefile new file mode 100644 index 000000000000..5c250e9d9dac --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/sdp/Makefile @@ -0,0 +1,6 @@ +EXTRA_CFLAGS += -Idrivers/infiniband/include +EXTRA_CFLAGS += -ggdb + +obj-$(CONFIG_INFINIBAND_SDP) += ib_sdp.o + +ib_sdp-objs := sdp_main.o sdp_cma.o sdp_bcopy.o sdp_proc.o sdp_tx.o sdp_rx.o sdp_zcopy.o diff --git a/sys/ofed/drivers/infiniband/ulp/sdp/sdp.h b/sys/ofed/drivers/infiniband/ulp/sdp/sdp.h new file mode 100644 index 000000000000..a1ccdff0f957 --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/sdp/sdp.h @@ -0,0 +1,721 @@ +#ifndef _SDP_H_ +#define _SDP_H_ + +#include "opt_ddb.h" +#include "opt_inet.h" +#include "opt_ofed.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef DDB +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef SDP_DEBUG +#define CONFIG_INFINIBAND_SDP_DEBUG +#endif + +#include "sdp_dbg.h" + +#undef LIST_HEAD +/* From sys/queue.h */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +/* Interval between sucessive polls in the Tx routine when polling is used + instead of interrupts (in per-core Tx rings) - should be power of 2 */ +#define SDP_TX_POLL_MODER 16 +#define SDP_TX_POLL_TIMEOUT (HZ / 20) +#define SDP_NAGLE_TIMEOUT (HZ / 10) + +#define SDP_SRCAVAIL_CANCEL_TIMEOUT (HZ * 5) +#define SDP_SRCAVAIL_ADV_TIMEOUT (1 * HZ) +#define SDP_SRCAVAIL_PAYLOAD_LEN 1 + +#define SDP_RESOLVE_TIMEOUT 1000 +#define SDP_ROUTE_TIMEOUT 1000 +#define SDP_RETRY_COUNT 5 +#define SDP_KEEPALIVE_TIME (120 * 60 * HZ) +#define SDP_FIN_WAIT_TIMEOUT (60 * HZ) /* like TCP_FIN_TIMEOUT */ + +#define SDP_TX_SIZE 0x40 +#define SDP_RX_SIZE 0x40 + +#define SDP_FMR_SIZE (MIN(0x1000, PAGE_SIZE) / sizeof(u64)) +#define SDP_FMR_POOL_SIZE 1024 +#define SDP_FMR_DIRTY_SIZE ( SDP_FMR_POOL_SIZE / 4 ) + +#define SDP_MAX_RDMA_READ_LEN (PAGE_SIZE * (SDP_FMR_SIZE - 2)) + +/* mb inlined data len - rest will be rx'ed into frags */ +#define SDP_HEAD_SIZE (sizeof(struct sdp_bsdh)) + +/* limit tx payload len, if the sink supports bigger buffers than the source + * can handle. + * or rx fragment size (limited by sge->length size) */ +#define SDP_MAX_PACKET (1 << 16) +#define SDP_MAX_PAYLOAD (SDP_MAX_PACKET - SDP_HEAD_SIZE) + +#define SDP_MAX_RECV_SGES (SDP_MAX_PACKET / MCLBYTES) +#define SDP_MAX_SEND_SGES (SDP_MAX_PACKET / MCLBYTES) + 2 + +#define SDP_NUM_WC 4 + +#define SDP_DEF_ZCOPY_THRESH 64*1024 +#define SDP_MIN_ZCOPY_THRESH PAGE_SIZE +#define SDP_MAX_ZCOPY_THRESH 1048576 + +#define SDP_OP_RECV 0x800000000LL +#define SDP_OP_SEND 0x400000000LL +#define SDP_OP_RDMA 0x200000000LL +#define SDP_OP_NOP 0x100000000LL + +/* how long (in jiffies) to block sender till tx completion*/ +#define SDP_BZCOPY_POLL_TIMEOUT (HZ / 10) + +#define SDP_AUTO_CONF 0xffff +#define AUTO_MOD_DELAY (HZ / 4) + +struct sdp_mb_cb { + __u32 seq; /* Starting sequence number */ + struct bzcopy_state *bz; + struct rx_srcavail_state *rx_sa; + struct tx_srcavail_state *tx_sa; +}; + +#define M_PUSH M_PROTO1 /* Do a 'push'. */ +#define M_URG M_PROTO2 /* Mark as urgent (oob). */ + +#define SDP_SKB_CB(__mb) ((struct sdp_mb_cb *)&((__mb)->cb[0])) +#define BZCOPY_STATE(mb) (SDP_SKB_CB(mb)->bz) +#define RX_SRCAVAIL_STATE(mb) (SDP_SKB_CB(mb)->rx_sa) +#define TX_SRCAVAIL_STATE(mb) (SDP_SKB_CB(mb)->tx_sa) + +#ifndef MIN +#define MIN(a, b) (a < b ? a : b) +#endif + +#define ring_head(ring) (atomic_read(&(ring).head)) +#define ring_tail(ring) (atomic_read(&(ring).tail)) +#define ring_posted(ring) (ring_head(ring) - ring_tail(ring)) + +#define rx_ring_posted(ssk) ring_posted(ssk->rx_ring) +#ifdef SDP_ZCOPY +#define tx_ring_posted(ssk) (ring_posted(ssk->tx_ring) + \ + (ssk->tx_ring.rdma_inflight ? ssk->tx_ring.rdma_inflight->busy : 0)) +#else +#define tx_ring_posted(ssk) ring_posted(ssk->tx_ring) +#endif + +extern int sdp_zcopy_thresh; +extern int rcvbuf_initial_size; +extern struct workqueue_struct *rx_comp_wq; +extern struct ib_client sdp_client; + +enum sdp_mid { + SDP_MID_HELLO = 0x0, + SDP_MID_HELLO_ACK = 0x1, + SDP_MID_DISCONN = 0x2, + SDP_MID_ABORT = 0x3, + SDP_MID_SENDSM = 0x4, + SDP_MID_RDMARDCOMPL = 0x6, + SDP_MID_SRCAVAIL_CANCEL = 0x8, + SDP_MID_CHRCVBUF = 0xB, + SDP_MID_CHRCVBUF_ACK = 0xC, + SDP_MID_SINKAVAIL = 0xFD, + SDP_MID_SRCAVAIL = 0xFE, + SDP_MID_DATA = 0xFF, +}; + +enum sdp_flags { + SDP_OOB_PRES = 1 << 0, + SDP_OOB_PEND = 1 << 1, +}; + +enum { + SDP_MIN_TX_CREDITS = 2 +}; + +enum { + SDP_ERR_ERROR = -4, + SDP_ERR_FAULT = -3, + SDP_NEW_SEG = -2, + SDP_DO_WAIT_MEM = -1 +}; + +struct sdp_bsdh { + u8 mid; + u8 flags; + __u16 bufs; + __u32 len; + __u32 mseq; + __u32 mseq_ack; +} __attribute__((__packed__)); + +union cma_ip_addr { + struct in6_addr ip6; + struct { + __u32 pad[3]; + __u32 addr; + } ip4; +} __attribute__((__packed__)); + +/* TODO: too much? Can I avoid having the src/dst and port here? */ +struct sdp_hh { + struct sdp_bsdh bsdh; + u8 majv_minv; + u8 ipv_cap; + u8 rsvd1; + u8 max_adverts; + __u32 desremrcvsz; + __u32 localrcvsz; + __u16 port; + __u16 rsvd2; + union cma_ip_addr src_addr; + union cma_ip_addr dst_addr; + u8 rsvd3[IB_CM_REQ_PRIVATE_DATA_SIZE - sizeof(struct sdp_bsdh) - 48]; +} __attribute__((__packed__)); + +struct sdp_hah { + struct sdp_bsdh bsdh; + u8 majv_minv; + u8 ipv_cap; + u8 rsvd1; + u8 ext_max_adverts; + __u32 actrcvsz; + u8 rsvd2[IB_CM_REP_PRIVATE_DATA_SIZE - sizeof(struct sdp_bsdh) - 8]; +} __attribute__((__packed__)); + +struct sdp_rrch { + __u32 len; +} __attribute__((__packed__)); + +struct sdp_srcah { + __u32 len; + __u32 rkey; + __u64 vaddr; +} __attribute__((__packed__)); + +struct sdp_buf { + struct mbuf *mb; + u64 mapping[SDP_MAX_SEND_SGES]; +} __attribute__((__packed__)); + +struct sdp_chrecvbuf { + u32 size; +} __attribute__((__packed__)); + +/* Context used for synchronous zero copy bcopy (BZCOPY) */ +struct bzcopy_state { + unsigned char __user *u_base; + int u_len; + int left; + int page_cnt; + int cur_page; + int cur_offset; + int busy; + struct sdp_sock *ssk; + struct page **pages; +}; + +enum rx_sa_flag { + RX_SA_ABORTED = 2, +}; + +enum tx_sa_flag { + TX_SA_SENDSM = 0x01, + TX_SA_CROSS_SEND = 0x02, + TX_SA_INTRRUPTED = 0x04, + TX_SA_TIMEDOUT = 0x08, + TX_SA_ERROR = 0x10, +}; + +struct rx_srcavail_state { + /* Advertised buffer stuff */ + u32 mseq; + u32 used; + u32 reported; + u32 len; + u32 rkey; + u64 vaddr; + + /* Dest buff info */ + struct ib_umem *umem; + struct ib_pool_fmr *fmr; + + /* Utility */ + u8 busy; + enum rx_sa_flag flags; +}; + +struct tx_srcavail_state { + /* Data below 'busy' will be reset */ + u8 busy; + + struct ib_umem *umem; + struct ib_pool_fmr *fmr; + + u32 bytes_sent; + u32 bytes_acked; + + enum tx_sa_flag abort_flags; + u8 posted; + + u32 mseq; +}; + +struct sdp_tx_ring { +#ifdef SDP_ZCOPY + struct rx_srcavail_state *rdma_inflight; +#endif + struct sdp_buf *buffer; + atomic_t head; + atomic_t tail; + struct ib_cq *cq; + + atomic_t credits; +#define tx_credits(ssk) (atomic_read(&ssk->tx_ring.credits)) + + struct callout timer; + u16 poll_cnt; +}; + +struct sdp_rx_ring { + struct sdp_buf *buffer; + atomic_t head; + atomic_t tail; + struct ib_cq *cq; + + int destroyed; + struct rwlock destroyed_lock; +}; + +struct sdp_device { + struct ib_pd *pd; + struct ib_mr *mr; + struct ib_fmr_pool *fmr_pool; +}; + +struct sdp_moderation { + unsigned long last_moder_packets; + unsigned long last_moder_tx_packets; + unsigned long last_moder_bytes; + unsigned long last_moder_jiffies; + int last_moder_time; + u16 rx_usecs; + u16 rx_frames; + u16 tx_usecs; + u32 pkt_rate_low; + u16 rx_usecs_low; + u32 pkt_rate_high; + u16 rx_usecs_high; + u16 sample_interval; + u16 adaptive_rx_coal; + u32 msg_enable; + + int moder_cnt; + int moder_time; +}; + +/* These are flags fields. */ +#define SDP_TIMEWAIT 0x0001 /* In ssk timewait state. */ +#define SDP_DROPPED 0x0002 /* Socket has been dropped. */ +#define SDP_SOCKREF 0x0004 /* Holding a sockref for close. */ +#define SDP_NODELAY 0x0008 /* Disble nagle. */ +#define SDP_NEEDFIN 0x0010 /* Send a fin on the next tx. */ +#define SDP_DREQWAIT 0x0020 /* Waiting on DREQ. */ +#define SDP_DESTROY 0x0040 /* Being destroyed. */ +#define SDP_DISCON 0x0080 /* rdma_disconnect is owed. */ + +/* These are oobflags */ +#define SDP_HADOOB 0x0001 /* Had OOB data. */ +#define SDP_HAVEOOB 0x0002 /* Have OOB data. */ + +struct sdp_sock { + LIST_ENTRY(sdp_sock) list; + struct socket *socket; + struct rdma_cm_id *id; + struct ib_device *ib_device; + struct sdp_device *sdp_dev; + struct ib_qp *qp; + struct ucred *cred; + struct callout keep2msl; /* 2msl and keepalive timer. */ + struct callout nagle_timer; /* timeout waiting for ack */ + struct ib_ucontext context; + in_port_t lport; + in_addr_t laddr; + in_port_t fport; + in_addr_t faddr; + int flags; + int oobflags; /* protected by rx lock. */ + int state; + int softerror; + int recv_bytes; /* Bytes per recv. buf including header */ + int xmit_size_goal; + char iobc; + + struct sdp_rx_ring rx_ring; + struct sdp_tx_ring tx_ring; + struct rwlock lock; + struct mbuf *rx_ctl_q; + struct mbuf *rx_ctl_tail; + + int qp_active; /* XXX Flag. */ + int max_sge; + struct work_struct rx_comp_work; +#define rcv_nxt(ssk) atomic_read(&(ssk->rcv_nxt)) + atomic_t rcv_nxt; + + /* SDP specific */ + atomic_t mseq_ack; +#define mseq_ack(ssk) (atomic_read(&ssk->mseq_ack)) + unsigned max_bufs; /* Initial buffers offered by other side */ + unsigned min_bufs; /* Low water mark to wake senders */ + + unsigned long nagle_last_unacked; /* mseq of lastest unacked packet */ + + atomic_t remote_credits; +#define remote_credits(ssk) (atomic_read(&ssk->remote_credits)) + int poll_cq; + + /* SDP slow start */ + int recv_request_head; /* mark the rx_head when the resize request + was recieved */ + int recv_request; /* XXX flag if request to resize was recieved */ + + unsigned long tx_packets; + unsigned long rx_packets; + unsigned long tx_bytes; + unsigned long rx_bytes; + struct sdp_moderation auto_mod; + struct task shutdown_task; +#ifdef SDP_ZCOPY + struct tx_srcavail_state *tx_sa; + struct rx_srcavail_state *rx_sa; + spinlock_t tx_sa_lock; + struct delayed_work srcavail_cancel_work; + int srcavail_cancel_mseq; + /* ZCOPY data: -1:use global; 0:disable zcopy; >0: zcopy threshold */ + int zcopy_thresh; +#endif +}; + +#define sdp_sk(so) ((struct sdp_sock *)(so->so_pcb)) + +#define SDP_RLOCK(ssk) rw_rlock(&(ssk)->lock) +#define SDP_WLOCK(ssk) rw_wlock(&(ssk)->lock) +#define SDP_RUNLOCK(ssk) rw_runlock(&(ssk)->lock) +#define SDP_WUNLOCK(ssk) rw_wunlock(&(ssk)->lock) +#define SDP_WLOCK_ASSERT(ssk) rw_assert(&(ssk)->lock, RA_WLOCKED) +#define SDP_RLOCK_ASSERT(ssk) rw_assert(&(ssk)->lock, RA_RLOCKED) +#define SDP_LOCK_ASSERT(ssk) rw_assert(&(ssk)->lock, RA_LOCKED) + +static inline void tx_sa_reset(struct tx_srcavail_state *tx_sa) +{ + memset((void *)&tx_sa->busy, 0, + sizeof(*tx_sa) - offsetof(typeof(*tx_sa), busy)); +} + +static inline void rx_ring_unlock(struct sdp_rx_ring *rx_ring) +{ + rw_runlock(&rx_ring->destroyed_lock); +} + +static inline int rx_ring_trylock(struct sdp_rx_ring *rx_ring) +{ + rw_rlock(&rx_ring->destroyed_lock); + if (rx_ring->destroyed) { + rx_ring_unlock(rx_ring); + return 0; + } + return 1; +} + +static inline void rx_ring_destroy_lock(struct sdp_rx_ring *rx_ring) +{ + rw_wlock(&rx_ring->destroyed_lock); + rx_ring->destroyed = 1; + rw_wunlock(&rx_ring->destroyed_lock); +} + +static inline void sdp_arm_rx_cq(struct sdp_sock *ssk) +{ + sdp_prf(ssk->socket, NULL, "Arming RX cq"); + sdp_dbg_data(ssk->socket, "Arming RX cq\n"); + + ib_req_notify_cq(ssk->rx_ring.cq, IB_CQ_NEXT_COMP); +} + +static inline void sdp_arm_tx_cq(struct sdp_sock *ssk) +{ + sdp_prf(ssk->socket, NULL, "Arming TX cq"); + sdp_dbg_data(ssk->socket, "Arming TX cq. credits: %d, posted: %d\n", + tx_credits(ssk), tx_ring_posted(ssk)); + + ib_req_notify_cq(ssk->tx_ring.cq, IB_CQ_NEXT_COMP); +} + +/* return the min of: + * - tx credits + * - free slots in tx_ring (not including SDP_MIN_TX_CREDITS + */ +static inline int tx_slots_free(struct sdp_sock *ssk) +{ + int min_free; + + min_free = MIN(tx_credits(ssk), + SDP_TX_SIZE - tx_ring_posted(ssk)); + if (min_free < SDP_MIN_TX_CREDITS) + return 0; + + return min_free - SDP_MIN_TX_CREDITS; +}; + +/* utilities */ +static inline char *mid2str(int mid) +{ +#define ENUM2STR(e) [e] = #e + static char *mid2str[] = { + ENUM2STR(SDP_MID_HELLO), + ENUM2STR(SDP_MID_HELLO_ACK), + ENUM2STR(SDP_MID_ABORT), + ENUM2STR(SDP_MID_DISCONN), + ENUM2STR(SDP_MID_SENDSM), + ENUM2STR(SDP_MID_RDMARDCOMPL), + ENUM2STR(SDP_MID_SRCAVAIL_CANCEL), + ENUM2STR(SDP_MID_CHRCVBUF), + ENUM2STR(SDP_MID_CHRCVBUF_ACK), + ENUM2STR(SDP_MID_DATA), + ENUM2STR(SDP_MID_SRCAVAIL), + ENUM2STR(SDP_MID_SINKAVAIL), + }; + + if (mid >= ARRAY_SIZE(mid2str)) + return NULL; + + return mid2str[mid]; +} + +static inline struct mbuf * +sdp_alloc_mb(struct socket *sk, u8 mid, int size, int wait) +{ + struct sdp_bsdh *h; + struct mbuf *mb; + + MGETHDR(mb, wait, MT_DATA); + if (mb == NULL) + return (NULL); + mb->m_pkthdr.len = mb->m_len = sizeof(struct sdp_bsdh); + h = mtod(mb, struct sdp_bsdh *); + h->mid = mid; + + return mb; +} +static inline struct mbuf * +sdp_alloc_mb_data(struct socket *sk, int wait) +{ + return sdp_alloc_mb(sk, SDP_MID_DATA, 0, wait); +} + +static inline struct mbuf * +sdp_alloc_mb_disconnect(struct socket *sk, int wait) +{ + return sdp_alloc_mb(sk, SDP_MID_DISCONN, 0, wait); +} + +static inline void * +mb_put(struct mbuf *mb, int len) +{ + uint8_t *data; + + data = mb->m_data; + data += mb->m_len; + mb->m_len += len; + return (void *)data; +} + +static inline struct mbuf * +sdp_alloc_mb_chrcvbuf_ack(struct socket *sk, int size, int wait) +{ + struct mbuf *mb; + struct sdp_chrecvbuf *resp_size; + + mb = sdp_alloc_mb(sk, SDP_MID_CHRCVBUF_ACK, sizeof(*resp_size), wait); + if (mb == NULL) + return (NULL); + resp_size = (struct sdp_chrecvbuf *)mb_put(mb, sizeof *resp_size); + resp_size->size = htonl(size); + + return mb; +} + +static inline struct mbuf * +sdp_alloc_mb_srcavail(struct socket *sk, u32 len, u32 rkey, u64 vaddr, int wait) +{ + struct mbuf *mb; + struct sdp_srcah *srcah; + + mb = sdp_alloc_mb(sk, SDP_MID_SRCAVAIL, sizeof(*srcah), wait); + if (mb == NULL) + return (NULL); + srcah = (struct sdp_srcah *)mb_put(mb, sizeof(*srcah)); + srcah->len = htonl(len); + srcah->rkey = htonl(rkey); + srcah->vaddr = cpu_to_be64(vaddr); + + return mb; +} + +static inline struct mbuf * +sdp_alloc_mb_srcavail_cancel(struct socket *sk, int wait) +{ + return sdp_alloc_mb(sk, SDP_MID_SRCAVAIL_CANCEL, 0, wait); +} + +static inline struct mbuf * +sdp_alloc_mb_rdmardcompl(struct socket *sk, u32 len, int wait) +{ + struct mbuf *mb; + struct sdp_rrch *rrch; + + mb = sdp_alloc_mb(sk, SDP_MID_RDMARDCOMPL, sizeof(*rrch), wait); + if (mb == NULL) + return (NULL); + rrch = (struct sdp_rrch *)mb_put(mb, sizeof(*rrch)); + rrch->len = htonl(len); + + return mb; +} + +static inline struct mbuf * +sdp_alloc_mb_sendsm(struct socket *sk, int wait) +{ + return sdp_alloc_mb(sk, SDP_MID_SENDSM, 0, wait); +} +static inline int sdp_tx_ring_slots_left(struct sdp_sock *ssk) +{ + return SDP_TX_SIZE - tx_ring_posted(ssk); +} + +static inline int credit_update_needed(struct sdp_sock *ssk) +{ + int c; + + c = remote_credits(ssk); + if (likely(c > SDP_MIN_TX_CREDITS)) + c += c/2; + return unlikely(c < rx_ring_posted(ssk)) && + likely(tx_credits(ssk) > 0) && + likely(sdp_tx_ring_slots_left(ssk)); +} + + +#define SDPSTATS_COUNTER_INC(stat) +#define SDPSTATS_COUNTER_ADD(stat, val) +#define SDPSTATS_COUNTER_MID_INC(stat, mid) +#define SDPSTATS_HIST_LINEAR(stat, size) +#define SDPSTATS_HIST(stat, size) + +static inline void +sdp_cleanup_sdp_buf(struct sdp_sock *ssk, struct sdp_buf *sbuf, + enum dma_data_direction dir) +{ + struct ib_device *dev; + struct mbuf *mb; + int i; + + dev = ssk->ib_device; + for (i = 0, mb = sbuf->mb; mb != NULL; mb = mb->m_next, i++) + ib_dma_unmap_single(dev, sbuf->mapping[i], mb->m_len, dir); +} + +/* sdp_main.c */ +void sdp_set_default_moderation(struct sdp_sock *ssk); +void sdp_start_keepalive_timer(struct socket *sk); +void sdp_urg(struct sdp_sock *ssk, struct mbuf *mb); +void sdp_cancel_dreq_wait_timeout(struct sdp_sock *ssk); +void sdp_abort(struct socket *sk); +struct sdp_sock *sdp_notify(struct sdp_sock *ssk, int error); + + +/* sdp_cma.c */ +int sdp_cma_handler(struct rdma_cm_id *, struct rdma_cm_event *); + +/* sdp_tx.c */ +int sdp_tx_ring_create(struct sdp_sock *ssk, struct ib_device *device); +void sdp_tx_ring_destroy(struct sdp_sock *ssk); +int sdp_xmit_poll(struct sdp_sock *ssk, int force); +void sdp_post_send(struct sdp_sock *ssk, struct mbuf *mb); +void sdp_post_sends(struct sdp_sock *ssk, int wait); +void sdp_post_keepalive(struct sdp_sock *ssk); + +/* sdp_rx.c */ +void sdp_rx_ring_init(struct sdp_sock *ssk); +int sdp_rx_ring_create(struct sdp_sock *ssk, struct ib_device *device); +void sdp_rx_ring_destroy(struct sdp_sock *ssk); +int sdp_resize_buffers(struct sdp_sock *ssk, u32 new_size); +int sdp_init_buffers(struct sdp_sock *ssk, u32 new_size); +void sdp_do_posts(struct sdp_sock *ssk); +void sdp_rx_comp_full(struct sdp_sock *ssk); + +/* sdp_zcopy.c */ +int sdp_sendmsg_zcopy(struct kiocb *iocb, struct socket *sk, struct iovec *iov); +int sdp_handle_srcavail(struct sdp_sock *ssk, struct sdp_srcah *srcah); +void sdp_handle_sendsm(struct sdp_sock *ssk, u32 mseq_ack); +void sdp_handle_rdma_read_compl(struct sdp_sock *ssk, u32 mseq_ack, + u32 bytes_completed); +int sdp_handle_rdma_read_cqe(struct sdp_sock *ssk); +int sdp_rdma_to_iovec(struct socket *sk, struct iovec *iov, struct mbuf *mb, + unsigned long *used); +int sdp_post_rdma_rd_compl(struct sdp_sock *ssk, + struct rx_srcavail_state *rx_sa); +int sdp_post_sendsm(struct socket *sk); +void srcavail_cancel_timeout(struct work_struct *work); +void sdp_abort_srcavail(struct socket *sk); +void sdp_abort_rdma_read(struct socket *sk); +int sdp_process_rx(struct sdp_sock *ssk); + +#endif diff --git a/sys/ofed/drivers/infiniband/ulp/sdp/sdp_bcopy.c b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_bcopy.c new file mode 100644 index 000000000000..d0688528f1ff --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_bcopy.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2006 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ +#include "sdp.h" + +static void sdp_nagle_timeout(void *data); + +#ifdef CONFIG_INFINIBAND_SDP_DEBUG_DATA +void _dump_packet(const char *func, int line, struct socket *sk, char *str, + struct mbuf *mb, const struct sdp_bsdh *h) +{ + struct sdp_hh *hh; + struct sdp_hah *hah; + struct sdp_chrecvbuf *req_size; + struct sdp_rrch *rrch; + struct sdp_srcah *srcah; + int len = 0; + char buf[256]; + len += snprintf(buf, 255-len, "%s mb: %p mid: %2x:%-20s flags: 0x%x " + "bufs: 0x%x len: 0x%x mseq: 0x%x mseq_ack: 0x%x | ", + str, mb, h->mid, mid2str(h->mid), h->flags, + ntohs(h->bufs), ntohl(h->len), ntohl(h->mseq), + ntohl(h->mseq_ack)); + + switch (h->mid) { + case SDP_MID_HELLO: + hh = (struct sdp_hh *)h; + len += snprintf(buf + len, 255-len, + "max_adverts: %d majv_minv: 0x%x " + "localrcvsz: 0x%x desremrcvsz: 0x%x |", + hh->max_adverts, hh->majv_minv, + ntohl(hh->localrcvsz), + ntohl(hh->desremrcvsz)); + break; + case SDP_MID_HELLO_ACK: + hah = (struct sdp_hah *)h; + len += snprintf(buf + len, 255-len, "actrcvz: 0x%x |", + ntohl(hah->actrcvsz)); + break; + case SDP_MID_CHRCVBUF: + case SDP_MID_CHRCVBUF_ACK: + req_size = (struct sdp_chrecvbuf *)(h+1); + len += snprintf(buf + len, 255-len, "req_size: 0x%x |", + ntohl(req_size->size)); + break; + case SDP_MID_DATA: + len += snprintf(buf + len, 255-len, "data_len: 0x%lx |", + ntohl(h->len) - sizeof(struct sdp_bsdh)); + break; + case SDP_MID_RDMARDCOMPL: + rrch = (struct sdp_rrch *)(h+1); + + len += snprintf(buf + len, 255-len, " | len: 0x%x |", + ntohl(rrch->len)); + break; + case SDP_MID_SRCAVAIL: + srcah = (struct sdp_srcah *)(h+1); + + len += snprintf(buf + len, 255-len, " | payload: 0x%lx, " + "len: 0x%x, rkey: 0x%x, vaddr: 0x%jx |", + ntohl(h->len) - sizeof(struct sdp_bsdh) - + sizeof(struct sdp_srcah), + ntohl(srcah->len), ntohl(srcah->rkey), + be64_to_cpu(srcah->vaddr)); + break; + default: + break; + } + buf[len] = 0; + _sdp_printk(func, line, KERN_WARNING, sk, "%s: %s\n", str, buf); +} +#endif + +static inline int +sdp_nagle_off(struct sdp_sock *ssk, struct mbuf *mb) +{ + + struct sdp_bsdh *h; + + h = mtod(mb, struct sdp_bsdh *); + int send_now = +#ifdef SDP_ZCOPY + BZCOPY_STATE(mb) || +#endif + unlikely(h->mid != SDP_MID_DATA) || + (ssk->flags & SDP_NODELAY) || + !ssk->nagle_last_unacked || + mb->m_pkthdr.len >= ssk->xmit_size_goal / 4 || + (mb->m_flags & M_PUSH); + + if (send_now) { + unsigned long mseq = ring_head(ssk->tx_ring); + ssk->nagle_last_unacked = mseq; + } else { + if (!callout_pending(&ssk->nagle_timer)) { + callout_reset(&ssk->nagle_timer, SDP_NAGLE_TIMEOUT, + sdp_nagle_timeout, ssk); + sdp_dbg_data(ssk->socket, "Starting nagle timer\n"); + } + } + sdp_dbg_data(ssk->socket, "send_now = %d last_unacked = %ld\n", + send_now, ssk->nagle_last_unacked); + + return send_now; +} + +static void +sdp_nagle_timeout(void *data) +{ + struct sdp_sock *ssk = (struct sdp_sock *)data; + struct socket *sk = ssk->socket; + + sdp_dbg_data(sk, "last_unacked = %ld\n", ssk->nagle_last_unacked); + + if (!callout_active(&ssk->nagle_timer)) + return; + callout_deactivate(&ssk->nagle_timer); + + if (!ssk->nagle_last_unacked) + goto out; + if (ssk->state == TCPS_CLOSED) + return; + ssk->nagle_last_unacked = 0; + sdp_post_sends(ssk, M_DONTWAIT); + + sowwakeup(ssk->socket); +out: + if (sk->so_snd.sb_sndptr) + callout_reset(&ssk->nagle_timer, SDP_NAGLE_TIMEOUT, + sdp_nagle_timeout, ssk); +} + +void +sdp_post_sends(struct sdp_sock *ssk, int wait) +{ + struct mbuf *mb; + int post_count = 0; + struct socket *sk; + int low; + + sk = ssk->socket; + if (unlikely(!ssk->id)) { + if (sk->so_snd.sb_sndptr) { + sdp_dbg(ssk->socket, + "Send on socket without cmid ECONNRESET.\n"); + sdp_notify(ssk, ECONNRESET); + } + return; + } +again: + if (sdp_tx_ring_slots_left(ssk) < SDP_TX_SIZE / 2) + sdp_xmit_poll(ssk, 1); + + if (ssk->recv_request && + ring_tail(ssk->rx_ring) >= ssk->recv_request_head && + tx_credits(ssk) >= SDP_MIN_TX_CREDITS && + sdp_tx_ring_slots_left(ssk)) { + mb = sdp_alloc_mb_chrcvbuf_ack(sk, + ssk->recv_bytes - SDP_HEAD_SIZE, wait); + if (mb == NULL) + goto allocfail; + ssk->recv_request = 0; + sdp_post_send(ssk, mb); + post_count++; + } + + if (tx_credits(ssk) <= SDP_MIN_TX_CREDITS && + sdp_tx_ring_slots_left(ssk) && sk->so_snd.sb_sndptr && + sdp_nagle_off(ssk, sk->so_snd.sb_sndptr)) { + SDPSTATS_COUNTER_INC(send_miss_no_credits); + } + + while (tx_credits(ssk) > SDP_MIN_TX_CREDITS && + sdp_tx_ring_slots_left(ssk) && (mb = sk->so_snd.sb_sndptr) && + sdp_nagle_off(ssk, mb)) { + struct mbuf *n; + + SOCKBUF_LOCK(&sk->so_snd); + sk->so_snd.sb_sndptr = mb->m_nextpkt; + sk->so_snd.sb_mb = mb->m_nextpkt; + mb->m_nextpkt = NULL; + SB_EMPTY_FIXUP(&sk->so_snd); + for (n = mb; n != NULL; n = n->m_next) + sbfree(&sk->so_snd, n); + SOCKBUF_UNLOCK(&sk->so_snd); + sdp_post_send(ssk, mb); + post_count++; + } + + if (credit_update_needed(ssk) && ssk->state >= TCPS_ESTABLISHED && + ssk->state < TCPS_FIN_WAIT_2) { + mb = sdp_alloc_mb_data(ssk->socket, wait); + if (mb == NULL) + goto allocfail; + sdp_post_send(ssk, mb); + + SDPSTATS_COUNTER_INC(post_send_credits); + post_count++; + } + + /* send DisConn if needed + * Do not send DisConn if there is only 1 credit. Compliance with CA4-82 + * If one credit is available, an implementation shall only send SDP + * messages that provide additional credits and also do not contain ULP + * payload. */ + if ((ssk->flags & SDP_NEEDFIN) && !sk->so_snd.sb_sndptr && + tx_credits(ssk) > 1) { + mb = sdp_alloc_mb_disconnect(sk, wait); + if (mb == NULL) + goto allocfail; + ssk->flags &= ~SDP_NEEDFIN; + sdp_post_send(ssk, mb); + post_count++; + } + low = (sdp_tx_ring_slots_left(ssk) <= SDP_MIN_TX_CREDITS); + if (post_count || low) { + if (low) + sdp_arm_tx_cq(ssk); + if (sdp_xmit_poll(ssk, low)) + goto again; + } + return; + +allocfail: + ssk->nagle_last_unacked = -1; + callout_reset(&ssk->nagle_timer, 1, sdp_nagle_timeout, ssk); + return; +} diff --git a/sys/ofed/drivers/infiniband/ulp/sdp/sdp_cma.c b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_cma.c new file mode 100644 index 000000000000..9350609a78ac --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_cma.c @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2006 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ +#include "sdp.h" + +#define SDP_MAJV_MINV 0x22 + +SDP_MODPARAM_SINT(sdp_link_layer_ib_only, 1, "Support only link layer of " + "type Infiniband"); + +enum { + SDP_HH_SIZE = 76, + SDP_HAH_SIZE = 180, +}; + +static void +sdp_qp_event_handler(struct ib_event *event, void *data) +{ +} + +static int +sdp_get_max_dev_sge(struct ib_device *dev) +{ + struct ib_device_attr attr; + static int max_sges = -1; + + if (max_sges > 0) + goto out; + + ib_query_device(dev, &attr); + + max_sges = attr.max_sge; + +out: + return max_sges; +} + +static int +sdp_init_qp(struct socket *sk, struct rdma_cm_id *id) +{ + struct ib_qp_init_attr qp_init_attr = { + .event_handler = sdp_qp_event_handler, + .cap.max_send_wr = SDP_TX_SIZE, + .cap.max_recv_wr = SDP_RX_SIZE, + .sq_sig_type = IB_SIGNAL_REQ_WR, + .qp_type = IB_QPT_RC, + }; + struct ib_device *device = id->device; + struct sdp_sock *ssk; + int rc; + + sdp_dbg(sk, "%s\n", __func__); + + ssk = sdp_sk(sk); + ssk->max_sge = sdp_get_max_dev_sge(device); + sdp_dbg(sk, "Max sges: %d\n", ssk->max_sge); + + qp_init_attr.cap.max_send_sge = MIN(ssk->max_sge, SDP_MAX_SEND_SGES); + sdp_dbg(sk, "Setting max send sge to: %d\n", + qp_init_attr.cap.max_send_sge); + + qp_init_attr.cap.max_recv_sge = MIN(ssk->max_sge, SDP_MAX_RECV_SGES); + sdp_dbg(sk, "Setting max recv sge to: %d\n", + qp_init_attr.cap.max_recv_sge); + + ssk->sdp_dev = ib_get_client_data(device, &sdp_client); + if (!ssk->sdp_dev) { + sdp_warn(sk, "SDP not available on device %s\n", device->name); + rc = -ENODEV; + goto err_rx; + } + + rc = sdp_rx_ring_create(ssk, device); + if (rc) + goto err_rx; + + rc = sdp_tx_ring_create(ssk, device); + if (rc) + goto err_tx; + + qp_init_attr.recv_cq = ssk->rx_ring.cq; + qp_init_attr.send_cq = ssk->tx_ring.cq; + + rc = rdma_create_qp(id, ssk->sdp_dev->pd, &qp_init_attr); + if (rc) { + sdp_warn(sk, "Unable to create QP: %d.\n", rc); + goto err_qp; + } + ssk->qp = id->qp; + ssk->ib_device = device; + ssk->qp_active = 1; + ssk->context.device = device; + + sdp_dbg(sk, "%s done\n", __func__); + return 0; + +err_qp: + sdp_tx_ring_destroy(ssk); +err_tx: + sdp_rx_ring_destroy(ssk); +err_rx: + return rc; +} + +static int +sdp_connect_handler(struct socket *sk, struct rdma_cm_id *id, + struct rdma_cm_event *event) +{ + struct sockaddr_in *src_addr; + struct sockaddr_in *dst_addr; + struct socket *child; + const struct sdp_hh *h; + struct sdp_sock *ssk; + int rc; + + sdp_dbg(sk, "%s %p -> %p\n", __func__, sdp_sk(sk)->id, id); + + h = event->param.conn.private_data; + SDP_DUMP_PACKET(sk, "RX", NULL, &h->bsdh); + + if (!h->max_adverts) + return -EINVAL; + + child = sonewconn(sk, SS_ISCONNECTED); + if (!child) + return -ENOMEM; + + ssk = sdp_sk(child); + rc = sdp_init_qp(child, id); + if (rc) + return rc; + SDP_WLOCK(ssk); + id->context = ssk; + ssk->id = id; + ssk->socket = child; + ssk->cred = crhold(child->so_cred); + dst_addr = (struct sockaddr_in *)&id->route.addr.dst_addr; + src_addr = (struct sockaddr_in *)&id->route.addr.src_addr; + ssk->fport = dst_addr->sin_port; + ssk->faddr = dst_addr->sin_addr.s_addr; + ssk->lport = src_addr->sin_port; + ssk->max_bufs = ntohs(h->bsdh.bufs); + atomic_set(&ssk->tx_ring.credits, ssk->max_bufs); + ssk->min_bufs = tx_credits(ssk) / 4; + ssk->xmit_size_goal = ntohl(h->localrcvsz) - sizeof(struct sdp_bsdh); + sdp_init_buffers(ssk, rcvbuf_initial_size); + ssk->state = TCPS_SYN_RECEIVED; + SDP_WUNLOCK(ssk); + + return 0; +} + +static int +sdp_response_handler(struct socket *sk, struct rdma_cm_id *id, + struct rdma_cm_event *event) +{ + const struct sdp_hah *h; + struct sockaddr_in *dst_addr; + struct sdp_sock *ssk; + sdp_dbg(sk, "%s\n", __func__); + + ssk = sdp_sk(sk); + SDP_WLOCK(ssk); + ssk->state = TCPS_ESTABLISHED; + sdp_set_default_moderation(ssk); + if (ssk->flags & SDP_DROPPED) { + SDP_WUNLOCK(ssk); + return 0; + } + if (sk->so_options & SO_KEEPALIVE) + sdp_start_keepalive_timer(sk); + h = event->param.conn.private_data; + SDP_DUMP_PACKET(sk, "RX", NULL, &h->bsdh); + ssk->max_bufs = ntohs(h->bsdh.bufs); + atomic_set(&ssk->tx_ring.credits, ssk->max_bufs); + ssk->min_bufs = tx_credits(ssk) / 4; + ssk->xmit_size_goal = + ntohl(h->actrcvsz) - sizeof(struct sdp_bsdh); + ssk->poll_cq = 1; + + dst_addr = (struct sockaddr_in *)&id->route.addr.dst_addr; + ssk->fport = dst_addr->sin_port; + ssk->faddr = dst_addr->sin_addr.s_addr; + soisconnected(sk); + SDP_WUNLOCK(ssk); + + return 0; +} + +static int +sdp_connected_handler(struct socket *sk, struct rdma_cm_event *event) +{ + struct sdp_sock *ssk; + + sdp_dbg(sk, "%s\n", __func__); + + ssk = sdp_sk(sk); + SDP_WLOCK(ssk); + ssk->state = TCPS_ESTABLISHED; + + sdp_set_default_moderation(ssk); + + if (sk->so_options & SO_KEEPALIVE) + sdp_start_keepalive_timer(sk); + + if ((ssk->flags & SDP_DROPPED) == 0) + soisconnected(sk); + SDP_WUNLOCK(ssk); + return 0; +} + +static int +sdp_disconnected_handler(struct socket *sk) +{ + struct sdp_sock *ssk; + + ssk = sdp_sk(sk); + sdp_dbg(sk, "%s\n", __func__); + + SDP_WLOCK_ASSERT(ssk); + if (sdp_sk(sk)->state == TCPS_SYN_RECEIVED) { + sdp_connected_handler(sk, NULL); + + if (rcv_nxt(ssk)) + return 0; + } + + return -ECONNRESET; +} + +int +sdp_cma_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) +{ + struct rdma_conn_param conn_param; + struct socket *sk; + struct sdp_sock *ssk; + struct sdp_hah hah; + struct sdp_hh hh; + + int rc = 0; + + ssk = id->context; + sk = NULL; + if (ssk) + sk = ssk->socket; + if (!ssk || !sk || !ssk->id) { + sdp_dbg(sk, + "cm_id is being torn down, event %d, ssk %p, sk %p, id %p\n", + event->event, ssk, sk, id); + return event->event == RDMA_CM_EVENT_CONNECT_REQUEST ? + -EINVAL : 0; + } + + sdp_dbg(sk, "%s event %d id %p\n", __func__, event->event, id); + switch (event->event) { + case RDMA_CM_EVENT_ADDR_RESOLVED: + sdp_dbg(sk, "RDMA_CM_EVENT_ADDR_RESOLVED\n"); + + if (sdp_link_layer_ib_only && + rdma_node_get_transport(id->device->node_type) == + RDMA_TRANSPORT_IB && + rdma_port_get_link_layer(id->device, id->port_num) != + IB_LINK_LAYER_INFINIBAND) { + sdp_dbg(sk, "Link layer is: %d. Only IB link layer " + "is allowed\n", + rdma_port_get_link_layer(id->device, id->port_num)); + rc = -ENETUNREACH; + break; + } + + rc = rdma_resolve_route(id, SDP_ROUTE_TIMEOUT); + break; + case RDMA_CM_EVENT_ADDR_ERROR: + sdp_dbg(sk, "RDMA_CM_EVENT_ADDR_ERROR\n"); + rc = -ENETUNREACH; + break; + case RDMA_CM_EVENT_ROUTE_RESOLVED: + sdp_dbg(sk, "RDMA_CM_EVENT_ROUTE_RESOLVED : %p\n", id); + rc = sdp_init_qp(sk, id); + if (rc) + break; + atomic_set(&sdp_sk(sk)->remote_credits, + rx_ring_posted(sdp_sk(sk))); + memset(&hh, 0, sizeof hh); + hh.bsdh.mid = SDP_MID_HELLO; + hh.bsdh.len = htonl(sizeof(struct sdp_hh)); + hh.max_adverts = 1; + hh.ipv_cap = 0x40; + hh.majv_minv = SDP_MAJV_MINV; + sdp_init_buffers(sdp_sk(sk), rcvbuf_initial_size); + hh.bsdh.bufs = htons(rx_ring_posted(sdp_sk(sk))); + hh.localrcvsz = hh.desremrcvsz = htonl(sdp_sk(sk)->recv_bytes); + hh.max_adverts = 0x1; + sdp_sk(sk)->laddr = + ((struct sockaddr_in *)&id->route.addr.src_addr)->sin_addr.s_addr; + memset(&conn_param, 0, sizeof conn_param); + conn_param.private_data_len = sizeof hh; + conn_param.private_data = &hh; + conn_param.responder_resources = 4 /* TODO */; + conn_param.initiator_depth = 4 /* TODO */; + conn_param.retry_count = SDP_RETRY_COUNT; + SDP_DUMP_PACKET(NULL, "TX", NULL, &hh.bsdh); + rc = rdma_connect(id, &conn_param); + break; + case RDMA_CM_EVENT_ROUTE_ERROR: + sdp_dbg(sk, "RDMA_CM_EVENT_ROUTE_ERROR : %p\n", id); + rc = -ETIMEDOUT; + break; + case RDMA_CM_EVENT_CONNECT_REQUEST: + sdp_dbg(sk, "RDMA_CM_EVENT_CONNECT_REQUEST\n"); + rc = sdp_connect_handler(sk, id, event); + if (rc) { + sdp_dbg(sk, "Destroying qp\n"); + rdma_reject(id, NULL, 0); + break; + } + ssk = id->context; + atomic_set(&ssk->remote_credits, rx_ring_posted(ssk)); + memset(&hah, 0, sizeof hah); + hah.bsdh.mid = SDP_MID_HELLO_ACK; + hah.bsdh.bufs = htons(rx_ring_posted(ssk)); + hah.bsdh.len = htonl(sizeof(struct sdp_hah)); + hah.majv_minv = SDP_MAJV_MINV; + hah.ext_max_adverts = 1; /* Doesn't seem to be mandated by spec, + but just in case */ + hah.actrcvsz = htonl(ssk->recv_bytes); + memset(&conn_param, 0, sizeof conn_param); + conn_param.private_data_len = sizeof hah; + conn_param.private_data = &hah; + conn_param.responder_resources = 4 /* TODO */; + conn_param.initiator_depth = 4 /* TODO */; + conn_param.retry_count = SDP_RETRY_COUNT; + SDP_DUMP_PACKET(sk, "TX", NULL, &hah.bsdh); + rc = rdma_accept(id, &conn_param); + if (rc) { + ssk->id = NULL; + id->qp = NULL; + id->context = NULL; + } + break; + case RDMA_CM_EVENT_CONNECT_RESPONSE: + sdp_dbg(sk, "RDMA_CM_EVENT_CONNECT_RESPONSE\n"); + rc = sdp_response_handler(sk, id, event); + if (rc) { + sdp_dbg(sk, "Destroying qp\n"); + rdma_reject(id, NULL, 0); + } else + rc = rdma_accept(id, NULL); + break; + case RDMA_CM_EVENT_CONNECT_ERROR: + sdp_dbg(sk, "RDMA_CM_EVENT_CONNECT_ERROR\n"); + rc = -ETIMEDOUT; + break; + case RDMA_CM_EVENT_UNREACHABLE: + sdp_dbg(sk, "RDMA_CM_EVENT_UNREACHABLE\n"); + rc = -ENETUNREACH; + break; + case RDMA_CM_EVENT_REJECTED: + sdp_dbg(sk, "RDMA_CM_EVENT_REJECTED\n"); + rc = -ECONNREFUSED; + break; + case RDMA_CM_EVENT_ESTABLISHED: + sdp_dbg(sk, "RDMA_CM_EVENT_ESTABLISHED\n"); + sdp_sk(sk)->laddr = + ((struct sockaddr_in *)&id->route.addr.src_addr)->sin_addr.s_addr; + rc = sdp_connected_handler(sk, event); + break; + case RDMA_CM_EVENT_DISCONNECTED: /* This means DREQ/DREP received */ + sdp_dbg(sk, "RDMA_CM_EVENT_DISCONNECTED\n"); + + SDP_WLOCK(ssk); + if (ssk->state == TCPS_LAST_ACK) { + sdp_cancel_dreq_wait_timeout(ssk); + + sdp_dbg(sk, "%s: waiting for Infiniband tear down\n", + __func__); + } + ssk->qp_active = 0; + SDP_WUNLOCK(ssk); + rdma_disconnect(id); + SDP_WLOCK(ssk); + if (ssk->state != TCPS_TIME_WAIT) { + if (ssk->state == TCPS_CLOSE_WAIT) { + sdp_dbg(sk, "IB teardown while in " + "TCPS_CLOSE_WAIT taking reference to " + "let close() finish the work\n"); + } + rc = sdp_disconnected_handler(sk); + if (rc) + rc = -EPIPE; + } + SDP_WUNLOCK(ssk); + break; + case RDMA_CM_EVENT_TIMEWAIT_EXIT: + sdp_dbg(sk, "RDMA_CM_EVENT_TIMEWAIT_EXIT\n"); + SDP_WLOCK(ssk); + rc = sdp_disconnected_handler(sk); + SDP_WUNLOCK(ssk); + break; + case RDMA_CM_EVENT_DEVICE_REMOVAL: + sdp_dbg(sk, "RDMA_CM_EVENT_DEVICE_REMOVAL\n"); + rc = -ENETRESET; + break; + default: + printk(KERN_ERR "SDP: Unexpected CMA event: %d\n", + event->event); + rc = -ECONNABORTED; + break; + } + + sdp_dbg(sk, "event %d done. status %d\n", event->event, rc); + + if (rc) { + SDP_WLOCK(ssk); + if (ssk->id == id) { + ssk->id = NULL; + id->qp = NULL; + id->context = NULL; + if (sdp_notify(ssk, -rc)) + SDP_WUNLOCK(ssk); + } else + SDP_WUNLOCK(ssk); + } + + return rc; +} diff --git a/sys/ofed/drivers/infiniband/ulp/sdp/sdp_dbg.h b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_dbg.h new file mode 100644 index 000000000000..188b58bf3413 --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_dbg.h @@ -0,0 +1,167 @@ +#ifndef _SDP_DBG_H_ +#define _SDP_DBG_H_ + +#define SDPSTATS_ON + +//#define GETNSTIMEODAY_SUPPORTED + +#define _sdp_printk(func, line, level, sk, format, arg...) \ +do { \ + printk(level "%s:%d %p sdp_sock(%d:%d %d:%d): " format "\n", \ + func, line, sk ? sdp_sk(sk) : NULL, \ + curproc->p_pid, PCPU_GET(cpuid), \ + (sk) && sdp_sk(sk) ? ntohs(sdp_sk(sk)->lport) : -1, \ + (sk) && sdp_sk(sk) ? ntohs(sdp_sk(sk)->fport) : -1, ## arg); \ +} while (0) +#define sdp_printk(level, sk, format, arg...) \ + _sdp_printk(__func__, __LINE__, level, sk, format, ## arg) +#define sdp_warn(sk, format, arg...) \ + sdp_printk(KERN_WARNING, sk, format , ## arg) + +#define SDP_MODPARAM_SINT(var, def_val, msg) \ + static int var = def_val; \ + module_param_named(var, var, int, 0644); \ + MODULE_PARM_DESC(var, msg " [" #def_val "]"); \ + +#define SDP_MODPARAM_INT(var, def_val, msg) \ + int var = def_val; \ + module_param_named(var, var, int, 0644); \ + MODULE_PARM_DESC(var, msg " [" #def_val "]"); \ + +#ifdef SDP_PROFILING +struct mbuf; +struct sdpprf_log { + int idx; + int pid; + int cpu; + int sk_num; + int sk_dport; + struct mbuf *mb; + char msg[256]; + + unsigned long long time; + + const char *func; + int line; +}; + +#define SDPPRF_LOG_SIZE 0x20000 /* must be a power of 2 */ + +extern struct sdpprf_log sdpprf_log[SDPPRF_LOG_SIZE]; +extern int sdpprf_log_count; + +#ifdef GETNSTIMEODAY_SUPPORTED +static inline unsigned long long current_nsec(void) +{ + struct timespec tv; + getnstimeofday(&tv); + return tv.tv_sec * NSEC_PER_SEC + tv.tv_nsec; +} +#else +#define current_nsec() jiffies_to_usecs(jiffies) +#endif + +#define sdp_prf1(sk, s, format, arg...) ({ \ + struct sdpprf_log *l = \ + &sdpprf_log[sdpprf_log_count++ & (SDPPRF_LOG_SIZE - 1)]; \ + preempt_disable(); \ + l->idx = sdpprf_log_count - 1; \ + l->pid = current->pid; \ + l->sk_num = (sk) ? inet_sk(sk)->num : -1; \ + l->sk_dport = (sk) ? ntohs(inet_sk(sk)->dport) : -1; \ + l->cpu = smp_processor_id(); \ + l->mb = s; \ + snprintf(l->msg, sizeof(l->msg) - 1, format, ## arg); \ + l->time = current_nsec(); \ + l->func = __func__; \ + l->line = __LINE__; \ + preempt_enable(); \ + 1; \ +}) +//#define sdp_prf(sk, s, format, arg...) +#define sdp_prf(sk, s, format, arg...) sdp_prf1(sk, s, format, ## arg) + +#else +#define sdp_prf1(sk, s, format, arg...) +#define sdp_prf(sk, s, format, arg...) +#endif + +#ifdef CONFIG_INFINIBAND_SDP_DEBUG +extern int sdp_debug_level; + +#define sdp_dbg(sk, format, arg...) \ + do { \ + if (sdp_debug_level > 0) \ + sdp_printk(KERN_WARNING, sk, format , ## arg); \ + } while (0) + +#else /* CONFIG_INFINIBAND_SDP_DEBUG */ +#define sdp_dbg(priv, format, arg...) \ + do { (void) (priv); } while (0) +#define sock_ref(sk, msg, sock_op) sock_op(sk) +#endif /* CONFIG_INFINIBAND_SDP_DEBUG */ + +#ifdef CONFIG_INFINIBAND_SDP_DEBUG_DATA + +extern int sdp_data_debug_level; +#define sdp_dbg_data(sk, format, arg...) \ + do { \ + if (sdp_data_debug_level & 0x2) \ + sdp_printk(KERN_WARNING, sk, format , ## arg); \ + } while (0) +#define SDP_DUMP_PACKET(sk, str, mb, h) \ + do { \ + if (sdp_data_debug_level & 0x1) \ + dump_packet(sk, str, mb, h); \ + } while (0) +#else +#define sdp_dbg_data(priv, format, arg...) +#define SDP_DUMP_PACKET(sk, str, mb, h) +#endif + +#define SOCK_REF_RESET "RESET" +#define SOCK_REF_ALIVE "ALIVE" /* sock_alloc -> destruct_sock */ +#define SOCK_REF_CLONE "CLONE" +#define SOCK_REF_CMA "CMA" /* sdp_cma_handler() is expected to be invoked */ +#define SOCK_REF_SEQ "SEQ" /* during proc read */ +#define SOCK_REF_DREQ_TO "DREQ_TO" /* dreq timeout is pending */ +#define SOCK_REF_ZCOPY "ZCOPY" /* zcopy send in process */ +#define SOCK_REF_RDMA_RD "RDMA_RD" /* RDMA read in process */ + +#define sock_hold(sk, msg) sock_ref(sk, msg, sock_hold) +#define sock_put(sk, msg) sock_ref(sk, msg, sock_put) +#define __sock_put(sk, msg) sock_ref(sk, msg, __sock_put) + +#define ENUM2STR(e) [e] = #e + +static inline char *sdp_state_str(int state) +{ + static char *state2str[] = { + ENUM2STR(TCPS_ESTABLISHED), + ENUM2STR(TCPS_SYN_SENT), + ENUM2STR(TCPS_SYN_RECEIVED), + ENUM2STR(TCPS_FIN_WAIT_1), + ENUM2STR(TCPS_FIN_WAIT_2), + ENUM2STR(TCPS_TIME_WAIT), + ENUM2STR(TCPS_CLOSED), + ENUM2STR(TCPS_CLOSE_WAIT), + ENUM2STR(TCPS_LAST_ACK), + ENUM2STR(TCPS_LISTEN), + ENUM2STR(TCPS_CLOSING), + }; + + if (state < 0 || state >= ARRAY_SIZE(state2str)) + return "unknown"; + + return state2str[state]; +} + +struct sdp_bsdh; +#ifdef CONFIG_INFINIBAND_SDP_DEBUG_DATA +void _dump_packet(const char *func, int line, struct socket *sk, char *str, + struct mbuf *mb, const struct sdp_bsdh *h); +#define dump_packet(sk, str, mb, h) \ + _dump_packet(__func__, __LINE__, sk, str, mb, h) +#endif + +#endif diff --git a/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c new file mode 100644 index 000000000000..fe747af77a85 --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c @@ -0,0 +1,1962 @@ + +/*- + * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 2004 The FreeBSD Foundation. All rights reserved. + * Copyright (c) 2004-2008 Robert N. M. Watson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Excerpts taken from tcp_subr.c, tcp_usrreq.c, uipc_socket.c + */ + +/* + * + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +__FBSDID("$FreeBSD$"); + +#include "sdp.h" + +#include +#include +#include + +uma_zone_t sdp_zone; +struct rwlock sdp_lock; +LIST_HEAD(, sdp_sock) sdp_list; + +struct workqueue_struct *rx_comp_wq; + +RW_SYSINIT(sdplockinit, &sdp_lock, "SDP lock"); +#define SDP_LIST_WLOCK() rw_wlock(&sdp_lock) +#define SDP_LIST_RLOCK() rw_rlock(&sdp_lock) +#define SDP_LIST_WUNLOCK() rw_wunlock(&sdp_lock) +#define SDP_LIST_RUNLOCK() rw_runlock(&sdp_lock) +#define SDP_LIST_WLOCK_ASSERT() rw_assert(&sdp_lock, RW_WLOCKED) +#define SDP_LIST_RLOCK_ASSERT() rw_assert(&sdp_lock, RW_RLOCKED) +#define SDP_LIST_LOCK_ASSERT() rw_assert(&sdp_lock, RW_LOCKED) + +MALLOC_DEFINE(M_SDP, "sdp", "Socket Direct Protocol"); + +static void sdp_stop_keepalive_timer(struct socket *so); + +/* + * SDP protocol interface to socket abstraction. + */ +/* + * sdp_sendspace and sdp_recvspace are the default send and receive window + * sizes, respectively. + */ +u_long sdp_sendspace = 1024*32; +u_long sdp_recvspace = 1024*64; + +static int sdp_count; + +/* + * Disable async. CMA events for sockets which are being torn down. + */ +static void +sdp_destroy_cma(struct sdp_sock *ssk) +{ + + if (ssk->id == NULL) + return; + rdma_destroy_id(ssk->id); + ssk->id = NULL; +} + +static int +sdp_pcbbind(struct sdp_sock *ssk, struct sockaddr *nam, struct ucred *cred) +{ + struct sockaddr_in *sin; + struct sockaddr_in null; + int error; + + SDP_WLOCK_ASSERT(ssk); + + if (ssk->lport != 0 || ssk->laddr != INADDR_ANY) + return (EINVAL); + /* rdma_bind_addr handles bind races. */ + SDP_WUNLOCK(ssk); + if (ssk->id == NULL) + ssk->id = rdma_create_id(sdp_cma_handler, ssk, RDMA_PS_SDP); + if (ssk->id == NULL) { + SDP_WLOCK(ssk); + return (ENOMEM); + } + if (nam == NULL) { + null.sin_family = AF_INET; + null.sin_len = sizeof(null); + null.sin_addr.s_addr = INADDR_ANY; + null.sin_port = 0; + bzero(&null.sin_zero, sizeof(null.sin_zero)); + nam = (struct sockaddr *)&null; + } + error = -rdma_bind_addr(ssk->id, nam); + SDP_WLOCK(ssk); + if (error == 0) { + sin = (struct sockaddr_in *)&ssk->id->route.addr.src_addr; + ssk->laddr = sin->sin_addr.s_addr; + ssk->lport = sin->sin_port; + } else + sdp_destroy_cma(ssk); + return (error); +} + +static void +sdp_pcbfree(struct sdp_sock *ssk) +{ + KASSERT(ssk->socket == NULL, ("ssk %p socket still attached", ssk)); + + sdp_dbg(ssk->socket, "Freeing pcb"); + SDP_WLOCK_ASSERT(ssk); + ssk->flags |= SDP_DESTROY; + SDP_WUNLOCK(ssk); + SDP_LIST_WLOCK(); + sdp_count--; + LIST_REMOVE(ssk, list); + SDP_LIST_WUNLOCK(); + crfree(ssk->cred); + sdp_destroy_cma(ssk); + ssk->qp_active = 0; + if (ssk->qp) { + ib_destroy_qp(ssk->qp); + ssk->qp = NULL; + } + sdp_tx_ring_destroy(ssk); + sdp_rx_ring_destroy(ssk); + rw_destroy(&ssk->rx_ring.destroyed_lock); + uma_zfree(sdp_zone, ssk); + rw_destroy(&ssk->lock); +} + +/* + * Common routines to return a socket address. + */ +static struct sockaddr * +sdp_sockaddr(in_port_t port, struct in_addr *addr_p) +{ + struct sockaddr_in *sin; + + sin = malloc(sizeof *sin, M_SONAME, + M_WAITOK | M_ZERO); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); + sin->sin_addr = *addr_p; + sin->sin_port = port; + + return (struct sockaddr *)sin; +} + +static int +sdp_getsockaddr(struct socket *so, struct sockaddr **nam) +{ + struct sdp_sock *ssk; + struct in_addr addr; + in_port_t port; + + ssk = sdp_sk(so); + SDP_RLOCK(ssk); + port = ssk->lport; + addr.s_addr = ssk->laddr; + SDP_RUNLOCK(ssk); + + *nam = sdp_sockaddr(port, &addr); + return 0; +} + +static int +sdp_getpeeraddr(struct socket *so, struct sockaddr **nam) +{ + struct sdp_sock *ssk; + struct in_addr addr; + in_port_t port; + + ssk = sdp_sk(so); + SDP_RLOCK(ssk); + port = ssk->fport; + addr.s_addr = ssk->faddr; + SDP_RUNLOCK(ssk); + + *nam = sdp_sockaddr(port, &addr); + return 0; +} + +static void +sdp_pcbnotifyall(struct in_addr faddr, int errno, + struct sdp_sock *(*notify)(struct sdp_sock *, int)) +{ + struct sdp_sock *ssk, *ssk_temp; + + SDP_LIST_WLOCK(); + LIST_FOREACH_SAFE(ssk, &sdp_list, list, ssk_temp) { + SDP_WLOCK(ssk); + if (ssk->faddr != faddr.s_addr || ssk->socket == NULL) { + SDP_WUNLOCK(ssk); + continue; + } + if ((ssk->flags & SDP_DESTROY) == 0) + if ((*notify)(ssk, errno)) + SDP_WUNLOCK(ssk); + } + SDP_LIST_WUNLOCK(); +} + +#if 0 +static void +sdp_apply_all(void (*func)(struct sdp_sock *, void *), void *arg) +{ + struct sdp_sock *ssk; + + SDP_LIST_RLOCK(); + LIST_FOREACH(ssk, &sdp_list, list) { + SDP_WLOCK(ssk); + func(ssk, arg); + SDP_WUNLOCK(ssk); + } + SDP_LIST_RUNLOCK(); +} +#endif + +static void +sdp_output_reset(struct sdp_sock *ssk) +{ + struct rdma_cm_id *id; + + SDP_WLOCK_ASSERT(ssk); + if (ssk->id) { + id = ssk->id; + ssk->qp_active = 0; + SDP_WUNLOCK(ssk); + rdma_disconnect(id); + SDP_WLOCK(ssk); + } + ssk->state = TCPS_CLOSED; +} + +/* + * Attempt to close a SDP socket, marking it as dropped, and freeing + * the socket if we hold the only reference. + */ +static struct sdp_sock * +sdp_closed(struct sdp_sock *ssk) +{ + struct socket *so; + + SDP_WLOCK_ASSERT(ssk); + + ssk->flags |= SDP_DROPPED; + so = ssk->socket; + soisdisconnected(so); + if (ssk->flags & SDP_SOCKREF) { + KASSERT(so->so_state & SS_PROTOREF, + ("sdp_closed: !SS_PROTOREF")); + ssk->flags &= ~SDP_SOCKREF; + SDP_WUNLOCK(ssk); + ACCEPT_LOCK(); + SOCK_LOCK(so); + so->so_state &= ~SS_PROTOREF; + sofree(so); + return (NULL); + } + return (ssk); +} + +/* + * Perform timer based shutdowns which can not operate in + * callout context. + */ +static void +sdp_shutdown_task(void *data, int pending) +{ + struct sdp_sock *ssk; + + ssk = data; + SDP_WLOCK(ssk); + /* + * I don't think this can race with another call to pcbfree() + * because SDP_TIMEWAIT protects it. SDP_DESTROY may be redundant. + */ + if (ssk->flags & SDP_DESTROY) + panic("sdp_shutdown_task: Racing with pcbfree for ssk %p", + ssk); + if (ssk->flags & SDP_DISCON) + sdp_output_reset(ssk); + /* We have to clear this so sdp_detach() will call pcbfree(). */ + ssk->flags &= ~(SDP_TIMEWAIT | SDP_DREQWAIT); + if ((ssk->flags & SDP_DROPPED) == 0 && + sdp_closed(ssk) == NULL) + return; + if (ssk->socket == NULL) { + sdp_pcbfree(ssk); + return; + } + SDP_WUNLOCK(ssk); +} + +/* + * 2msl has expired, schedule the shutdown task. + */ +static void +sdp_2msl_timeout(void *data) +{ + struct sdp_sock *ssk; + + ssk = data; + /* Callout canceled. */ + if (!callout_active(&ssk->keep2msl)) + goto out; + callout_deactivate(&ssk->keep2msl); + /* Should be impossible, defensive programming. */ + if ((ssk->flags & SDP_TIMEWAIT) == 0) + goto out; + taskqueue_enqueue(taskqueue_thread, &ssk->shutdown_task); +out: + SDP_WUNLOCK(ssk); + return; +} + +/* + * Schedule the 2msl wait timer. + */ +static void +sdp_2msl_wait(struct sdp_sock *ssk) +{ + + SDP_WLOCK_ASSERT(ssk); + ssk->flags |= SDP_TIMEWAIT; + ssk->state = TCPS_TIME_WAIT; + soisdisconnected(ssk->socket); + callout_reset(&ssk->keep2msl, TCPTV_MSL, sdp_2msl_timeout, ssk); +} + +/* + * Timed out waiting for the final fin/ack from rdma_disconnect(). + */ +static void +sdp_dreq_timeout(void *data) +{ + struct sdp_sock *ssk; + + ssk = data; + /* Callout canceled. */ + if (!callout_active(&ssk->keep2msl)) + goto out; + /* Callout rescheduled, probably as a different timer. */ + if (callout_pending(&ssk->keep2msl)) + goto out; + callout_deactivate(&ssk->keep2msl); + if (ssk->state != TCPS_FIN_WAIT_1 && ssk->state != TCPS_LAST_ACK) + goto out; + if ((ssk->flags & SDP_DREQWAIT) == 0) + goto out; + ssk->flags &= ~SDP_DREQWAIT; + ssk->flags |= SDP_DISCON; + sdp_2msl_wait(ssk); + ssk->qp_active = 0; +out: + SDP_WUNLOCK(ssk); +} + +/* + * Received the final fin/ack. Cancel the 2msl. + */ +void +sdp_cancel_dreq_wait_timeout(struct sdp_sock *ssk) +{ + sdp_dbg(ssk->socket, "cancelling dreq wait timeout\n"); + ssk->flags &= ~SDP_DREQWAIT; + sdp_2msl_wait(ssk); +} + +static int +sdp_init_sock(struct socket *sk) +{ + struct sdp_sock *ssk = sdp_sk(sk); + + sdp_dbg(sk, "%s\n", __func__); + + callout_init_rw(&ssk->keep2msl, &ssk->lock, CALLOUT_RETURNUNLOCKED); + TASK_INIT(&ssk->shutdown_task, 0, sdp_shutdown_task, ssk); +#ifdef SDP_ZCOPY + INIT_DELAYED_WORK(&ssk->srcavail_cancel_work, srcavail_cancel_timeout); + ssk->zcopy_thresh = -1; /* use global sdp_zcopy_thresh */ + ssk->tx_ring.rdma_inflight = NULL; +#endif + atomic_set(&ssk->mseq_ack, 0); + sdp_rx_ring_init(ssk); + ssk->tx_ring.buffer = NULL; + + return 0; +} + +/* + * Allocate an sdp_sock for the socket and reserve socket buffer space. + */ +static int +sdp_attach(struct socket *so, int proto, struct thread *td) +{ + struct sdp_sock *ssk; + int error; + + ssk = sdp_sk(so); + KASSERT(ssk == NULL, ("sdp_attach: ssk already set on so %p", so)); + if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { + error = soreserve(so, sdp_sendspace, sdp_recvspace); + if (error) + return (error); + } + so->so_rcv.sb_flags |= SB_AUTOSIZE; + so->so_snd.sb_flags |= SB_AUTOSIZE; + ssk = uma_zalloc(sdp_zone, M_NOWAIT | M_ZERO); + if (ssk == NULL) + return (ENOBUFS); + rw_init(&ssk->lock, "sdpsock"); + ssk->socket = so; + ssk->cred = crhold(so->so_cred); + so->so_pcb = (caddr_t)ssk; + sdp_init_sock(so); + ssk->flags = 0; + ssk->qp_active = 0; + ssk->state = TCPS_CLOSED; + SDP_LIST_WLOCK(); + LIST_INSERT_HEAD(&sdp_list, ssk, list); + sdp_count++; + SDP_LIST_WUNLOCK(); + if ((so->so_options & SO_LINGER) && so->so_linger == 0) + so->so_linger = TCP_LINGERTIME; + + return (0); +} + +/* + * Detach SDP from the socket, potentially leaving it around for the + * timewait to expire. + */ +static void +sdp_detach(struct socket *so) +{ + struct sdp_sock *ssk; + + ssk = sdp_sk(so); + SDP_WLOCK(ssk); + KASSERT(ssk->socket != NULL, ("sdp_detach: socket is NULL")); + ssk->socket->so_pcb = NULL; + ssk->socket = NULL; + if (ssk->flags & (SDP_TIMEWAIT | SDP_DREQWAIT)) + SDP_WUNLOCK(ssk); + else if (ssk->flags & SDP_DROPPED || ssk->state < TCPS_SYN_SENT) + sdp_pcbfree(ssk); + else + panic("sdp_detach: Unexpected state, ssk %p.\n", ssk); +} + +/* + * Allocate a local address for the socket. + */ +static int +sdp_bind(struct socket *so, struct sockaddr *nam, struct thread *td) +{ + int error = 0; + struct sdp_sock *ssk; + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *)nam; + if (nam->sa_len != sizeof (*sin)) + return (EINVAL); + if (sin->sin_family != AF_INET) + return (EINVAL); + if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) + return (EAFNOSUPPORT); + + ssk = sdp_sk(so); + SDP_WLOCK(ssk); + if (ssk->flags & (SDP_TIMEWAIT | SDP_DROPPED)) { + error = EINVAL; + goto out; + } + error = sdp_pcbbind(ssk, nam, td->td_ucred); +out: + SDP_WUNLOCK(ssk); + + return (error); +} + +/* + * Prepare to accept connections. + */ +static int +sdp_listen(struct socket *so, int backlog, struct thread *td) +{ + int error = 0; + struct sdp_sock *ssk; + + ssk = sdp_sk(so); + SDP_WLOCK(ssk); + if (ssk->flags & (SDP_TIMEWAIT | SDP_DROPPED)) { + error = EINVAL; + goto out; + } + if (error == 0 && ssk->lport == 0) + error = sdp_pcbbind(ssk, (struct sockaddr *)0, td->td_ucred); + SOCK_LOCK(so); + if (error == 0) + error = solisten_proto_check(so); + if (error == 0) { + solisten_proto(so, backlog); + ssk->state = TCPS_LISTEN; + } + SOCK_UNLOCK(so); + +out: + SDP_WUNLOCK(ssk); + if (error == 0) + error = -rdma_listen(ssk->id, backlog); + return (error); +} + +/* + * Initiate a SDP connection to nam. + */ +static int +sdp_start_connect(struct sdp_sock *ssk, struct sockaddr *nam, struct thread *td) +{ + struct sockaddr_in src; + struct socket *so; + int error; + + so = ssk->socket; + + SDP_WLOCK_ASSERT(ssk); + if (ssk->lport == 0) { + error = sdp_pcbbind(ssk, (struct sockaddr *)0, td->td_ucred); + if (error) + return error; + } + src.sin_family = AF_INET; + src.sin_len = sizeof(src); + bzero(&src.sin_zero, sizeof(src.sin_zero)); + src.sin_port = ssk->lport; + src.sin_addr.s_addr = ssk->laddr; + soisconnecting(so); + SDP_WUNLOCK(ssk); + error = -rdma_resolve_addr(ssk->id, (struct sockaddr *)&src, nam, + SDP_RESOLVE_TIMEOUT); + SDP_WLOCK(ssk); + if (error == 0) + ssk->state = TCPS_SYN_SENT; + + return 0; +} + +/* + * Initiate SDP connection. + */ +static int +sdp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) +{ + int error = 0; + struct sdp_sock *ssk; + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *)nam; + if (nam->sa_len != sizeof (*sin)) + return (EINVAL); + if (sin->sin_family != AF_INET) + return (EINVAL); + if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) + return (EAFNOSUPPORT); + if ((error = prison_remote_ip4(td->td_ucred, &sin->sin_addr)) != 0) + return (error); + ssk = sdp_sk(so); + SDP_WLOCK(ssk); + if (ssk->flags & (SDP_TIMEWAIT | SDP_DROPPED)) + error = EINVAL; + else + error = sdp_start_connect(ssk, nam, td); + SDP_WUNLOCK(ssk); + return (error); +} + +/* + * Drop a SDP socket, reporting + * the specified error. If connection is synchronized, + * then send a RST to peer. + */ +static struct sdp_sock * +sdp_drop(struct sdp_sock *ssk, int errno) +{ + struct socket *so; + + SDP_WLOCK_ASSERT(ssk); + so = ssk->socket; + if (TCPS_HAVERCVDSYN(ssk->state)) + sdp_output_reset(ssk); + if (errno == ETIMEDOUT && ssk->softerror) + errno = ssk->softerror; + so->so_error = errno; + return (sdp_closed(ssk)); +} + +/* + * User issued close, and wish to trail through shutdown states: + * if never received SYN, just forget it. If got a SYN from peer, + * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. + * If already got a FIN from peer, then almost done; go to LAST_ACK + * state. In all other cases, have already sent FIN to peer (e.g. + * after PRU_SHUTDOWN), and just have to play tedious game waiting + * for peer to send FIN or not respond to keep-alives, etc. + * We can let the user exit from the close as soon as the FIN is acked. + */ +static void +sdp_usrclosed(struct sdp_sock *ssk) +{ + + SDP_WLOCK_ASSERT(ssk); + + switch (ssk->state) { + case TCPS_LISTEN: + ssk->state = TCPS_CLOSED; + SDP_WUNLOCK(ssk); + sdp_destroy_cma(ssk); + SDP_WLOCK(ssk); + /* FALLTHROUGH */ + case TCPS_CLOSED: + ssk = sdp_closed(ssk); + /* + * sdp_closed() should never return NULL here as the socket is + * still open. + */ + KASSERT(ssk != NULL, + ("sdp_usrclosed: sdp_closed() returned NULL")); + break; + + case TCPS_SYN_SENT: + /* FALLTHROUGH */ + case TCPS_SYN_RECEIVED: + ssk->flags |= SDP_NEEDFIN; + break; + + case TCPS_ESTABLISHED: + ssk->flags |= SDP_NEEDFIN; + ssk->state = TCPS_FIN_WAIT_1; + break; + + case TCPS_CLOSE_WAIT: + ssk->state = TCPS_LAST_ACK; + break; + } + if (ssk->state >= TCPS_FIN_WAIT_2) { + /* Prevent the connection hanging in FIN_WAIT_2 forever. */ + if (ssk->state == TCPS_FIN_WAIT_2) + sdp_2msl_wait(ssk); + else + soisdisconnected(ssk->socket); + } +} + +static void +sdp_output_disconnect(struct sdp_sock *ssk) +{ + + SDP_WLOCK_ASSERT(ssk); + callout_reset(&ssk->keep2msl, SDP_FIN_WAIT_TIMEOUT, + sdp_dreq_timeout, ssk); + ssk->flags |= SDP_NEEDFIN | SDP_DREQWAIT; + sdp_post_sends(ssk, M_NOWAIT); +} + +/* + * Initiate or continue a disconnect. + * If embryonic state, just send reset (once). + * If in ``let data drain'' option and linger null, just drop. + * Otherwise (hard), mark socket disconnecting and drop + * current input data; switch states based on user close, and + * send segment to peer (with FIN). + */ +static void +sdp_start_disconnect(struct sdp_sock *ssk) +{ + struct socket *so; + int unread; + + so = ssk->socket; + SDP_WLOCK_ASSERT(ssk); + sdp_stop_keepalive_timer(so); + /* + * Neither sdp_closed() nor sdp_drop() should return NULL, as the + * socket is still open. + */ + if (ssk->state < TCPS_ESTABLISHED) { + ssk = sdp_closed(ssk); + KASSERT(ssk != NULL, + ("sdp_start_disconnect: sdp_close() returned NULL")); + } else if ((so->so_options & SO_LINGER) && so->so_linger == 0) { + ssk = sdp_drop(ssk, 0); + KASSERT(ssk != NULL, + ("sdp_start_disconnect: sdp_drop() returned NULL")); + } else { + soisdisconnecting(so); + unread = so->so_rcv.sb_cc; + sbflush(&so->so_rcv); + sdp_usrclosed(ssk); + if (!(ssk->flags & SDP_DROPPED)) { + if (unread) + sdp_output_reset(ssk); + else + sdp_output_disconnect(ssk); + } + } +} + +/* + * User initiated disconnect. + */ +static int +sdp_disconnect(struct socket *so) +{ + struct sdp_sock *ssk; + int error = 0; + + ssk = sdp_sk(so); + SDP_WLOCK(ssk); + if (ssk->flags & (SDP_TIMEWAIT | SDP_DROPPED)) { + error = ECONNRESET; + goto out; + } + sdp_start_disconnect(ssk); +out: + SDP_WUNLOCK(ssk); + return (error); +} + +/* + * Accept a connection. Essentially all the work is done at higher levels; + * just return the address of the peer, storing through addr. + * + * + * XXX This is broken XXX + * + * The rationale for acquiring the sdp lock here is somewhat complicated, + * and is described in detail in the commit log entry for r175612. Acquiring + * it delays an accept(2) racing with sonewconn(), which inserts the socket + * before the address/port fields are initialized. A better fix would + * prevent the socket from being placed in the listen queue until all fields + * are fully initialized. + */ +static int +sdp_accept(struct socket *so, struct sockaddr **nam) +{ + struct sdp_sock *ssk = NULL; + struct in_addr addr; + in_port_t port; + int error; + + if (so->so_state & SS_ISDISCONNECTED) + return (ECONNABORTED); + + port = 0; + addr.s_addr = 0; + error = 0; + ssk = sdp_sk(so); + SDP_WLOCK(ssk); + if (ssk->flags & (SDP_TIMEWAIT | SDP_DROPPED)) { + error = ECONNABORTED; + goto out; + } + port = ssk->fport; + addr.s_addr = ssk->faddr; +out: + SDP_WUNLOCK(ssk); + if (error == 0) + *nam = sdp_sockaddr(port, &addr); + return error; +} + +/* + * Mark the connection as being incapable of further output. + */ +static int +sdp_shutdown(struct socket *so) +{ + int error = 0; + struct sdp_sock *ssk; + + ssk = sdp_sk(so); + SDP_WLOCK(ssk); + if (ssk->flags & (SDP_TIMEWAIT | SDP_DROPPED)) { + error = ECONNRESET; + goto out; + } + socantsendmore(so); + sdp_usrclosed(ssk); + if (!(ssk->flags & SDP_DROPPED)) + sdp_output_disconnect(ssk); + +out: + SDP_WUNLOCK(ssk); + + return (error); +} + +static void +sdp_append(struct sdp_sock *ssk, struct sockbuf *sb, struct mbuf *mb, int cnt) +{ + struct mbuf *n; + int ncnt; + + SOCKBUF_LOCK_ASSERT(sb); + SBLASTRECORDCHK(sb) + KASSERT(mb->m_flags & M_PKTHDR, + ("sdp_append: %p Missing packet header.\n", mb)); + n = sb->sb_lastrecord; + /* + * If the queue is empty just set all pointers and proceed. + */ + if (n == NULL) { + sb->sb_lastrecord = sb->sb_mb = sb->sb_sndptr = mb; + for (; mb; mb = mb->m_next) { + sb->sb_mbtail = mb; + sballoc(sb, mb); + } + return; + } + /* + * Count the number of mbufs in the current tail. + */ + for (ncnt = 0; n->m_next; n = n->m_next) + ncnt++; + n = sb->sb_lastrecord; + /* + * If the two chains can fit in a single sdp packet and + * the last record has not been sent yet (WRITABLE) coalesce + * them. The lastrecord remains the same but we must strip the + * packet header and then let sbcompress do the hard part. + */ + if (M_WRITABLE(n) && ncnt + cnt < SDP_MAX_SEND_SGES && + n->m_pkthdr.len + mb->m_pkthdr.len - SDP_HEAD_SIZE < + ssk->xmit_size_goal) { + m_adj(mb, SDP_HEAD_SIZE); + n->m_pkthdr.len += mb->m_pkthdr.len; + n->m_flags |= mb->m_flags & (M_PUSH | M_URG); + m_demote(mb, 1); + sbcompress(sb, mb, sb->sb_mbtail); + return; + } + /* + * Not compressible, just append to the end and adjust counters. + */ + sb->sb_lastrecord->m_flags |= M_PUSH; + sb->sb_lastrecord->m_nextpkt = mb; + sb->sb_lastrecord = mb; + if (sb->sb_sndptr == NULL) + sb->sb_sndptr = mb; + for (; mb; mb = mb->m_next) { + sb->sb_mbtail = mb; + sballoc(sb, mb); + } +} + +/* + * Do a send by putting data in output queue and updating urgent + * marker if URG set. Possibly send more data. Unlike the other + * pru_*() routines, the mbuf chains are our responsibility. We + * must either enqueue them or free them. The other pru_* routines + * generally are caller-frees. + * + * This comes from sendfile, normal sends will come from sdp_sosend(). + */ +static int +sdp_send(struct socket *so, int flags, struct mbuf *m, + struct sockaddr *nam, struct mbuf *control, struct thread *td) +{ + struct sdp_sock *ssk; + struct mbuf *n; + int error; + int cnt; + + error = 0; + ssk = sdp_sk(so); + KASSERT(m->m_flags & M_PKTHDR, + ("sdp_send: %p no packet header", m)); + M_PREPEND(m, SDP_HEAD_SIZE, M_WAIT); + mtod(m, struct sdp_bsdh *)->mid = SDP_MID_DATA; + for (n = m, cnt = 0; n->m_next; n = n->m_next) + cnt++; + if (cnt > SDP_MAX_SEND_SGES) { + n = m_collapse(m, M_WAIT, SDP_MAX_SEND_SGES); + if (n == NULL) { + m_freem(m); + return (EMSGSIZE); + } + m = n; + for (cnt = 0; n->m_next; n = n->m_next) + cnt++; + } + SDP_WLOCK(ssk); + if (ssk->flags & (SDP_TIMEWAIT | SDP_DROPPED)) { + if (control) + m_freem(control); + if (m) + m_freem(m); + error = ECONNRESET; + goto out; + } + if (control) { + /* SDP doesn't support control messages. */ + if (control->m_len) { + m_freem(control); + if (m) + m_freem(m); + error = EINVAL; + goto out; + } + m_freem(control); /* empty control, just free it */ + } + if (!(flags & PRUS_OOB)) { + SOCKBUF_LOCK(&so->so_snd); + sdp_append(ssk, &so->so_snd, m, cnt); + SOCKBUF_UNLOCK(&so->so_snd); + if (nam && ssk->state < TCPS_SYN_SENT) { + /* + * Do implied connect if not yet connected. + */ + error = sdp_start_connect(ssk, nam, td); + if (error) + goto out; + } + if (flags & PRUS_EOF) { + /* + * Close the send side of the connection after + * the data is sent. + */ + socantsendmore(so); + sdp_usrclosed(ssk); + if (!(ssk->flags & SDP_DROPPED)) + sdp_output_disconnect(ssk); + } else if (!(ssk->flags & SDP_DROPPED) && + !(flags & PRUS_MORETOCOME)) + sdp_post_sends(ssk, M_NOWAIT); + SDP_WUNLOCK(ssk); + return (0); + } else { + SOCKBUF_LOCK(&so->so_snd); + if (sbspace(&so->so_snd) < -512) { + SOCKBUF_UNLOCK(&so->so_snd); + m_freem(m); + error = ENOBUFS; + goto out; + } + /* + * According to RFC961 (Assigned Protocols), + * the urgent pointer points to the last octet + * of urgent data. We continue, however, + * to consider it to indicate the first octet + * of data past the urgent section. + * Otherwise, snd_up should be one lower. + */ + m->m_flags |= M_URG | M_PUSH; + sdp_append(ssk, &so->so_snd, m, cnt); + SOCKBUF_UNLOCK(&so->so_snd); + if (nam && ssk->state < TCPS_SYN_SENT) { + /* + * Do implied connect if not yet connected. + */ + error = sdp_start_connect(ssk, nam, td); + if (error) + goto out; + } + sdp_post_sends(ssk, M_NOWAIT); + SDP_WUNLOCK(ssk); + return (0); + } +out: + SDP_WUNLOCK(ssk); + return (error); +} + +#define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? 0 : SBL_WAIT) + +/* + * Send on a socket. If send must go all at once and message is larger than + * send buffering, then hard error. Lock against other senders. If must go + * all at once and not enough room now, then inform user that this would + * block and do nothing. Otherwise, if nonblocking, send as much as + * possible. The data to be sent is described by "uio" if nonzero, otherwise + * by the mbuf chain "top" (which must be null if uio is not). Data provided + * in mbuf chain must be small enough to send all at once. + * + * Returns nonzero on error, timeout or signal; callers must check for short + * counts if EINTR/ERESTART are returned. Data and control buffers are freed + * on return. + */ +static int +sdp_sosend(struct socket *so, struct sockaddr *addr, struct uio *uio, + struct mbuf *top, struct mbuf *control, int flags, struct thread *td) +{ + struct sdp_sock *ssk; + long space, resid; + int atomic; + int error; + int copy; + + if (uio != NULL) + resid = uio->uio_resid; + else + resid = top->m_pkthdr.len; + atomic = top != NULL; + if (control != NULL) { + if (control->m_len) { + m_freem(control); + if (top) + m_freem(top); + return (EINVAL); + } + m_freem(control); + control = NULL; + } + /* + * In theory resid should be unsigned. However, space must be + * signed, as it might be less than 0 if we over-committed, and we + * must use a signed comparison of space and resid. On the other + * hand, a negative resid causes us to loop sending 0-length + * segments to the protocol. + * + * Also check to make sure that MSG_EOR isn't used on SOCK_STREAM + * type sockets since that's an error. + */ + if (resid < 0 || (so->so_type == SOCK_STREAM && (flags & MSG_EOR))) { + error = EINVAL; + goto out; + } + if (td != NULL) + td->td_ru.ru_msgsnd++; + + ssk = sdp_sk(so); + error = sblock(&so->so_snd, SBLOCKWAIT(flags)); + if (error) + goto out; + +restart: + do { + SOCKBUF_LOCK(&so->so_snd); + if (so->so_snd.sb_state & SBS_CANTSENDMORE) { + SOCKBUF_UNLOCK(&so->so_snd); + error = EPIPE; + goto release; + } + if (so->so_error) { + error = so->so_error; + so->so_error = 0; + SOCKBUF_UNLOCK(&so->so_snd); + goto release; + } + if ((so->so_state & SS_ISCONNECTED) == 0 && addr == NULL) { + SOCKBUF_UNLOCK(&so->so_snd); + error = ENOTCONN; + goto release; + } + space = sbspace(&so->so_snd); + if (flags & MSG_OOB) + space += 1024; + if (atomic && resid > ssk->xmit_size_goal - SDP_HEAD_SIZE) { + SOCKBUF_UNLOCK(&so->so_snd); + error = EMSGSIZE; + goto release; + } + if (space < resid && + (atomic || space < so->so_snd.sb_lowat)) { + if ((so->so_state & SS_NBIO) || (flags & MSG_NBIO)) { + SOCKBUF_UNLOCK(&so->so_snd); + error = EWOULDBLOCK; + goto release; + } + error = sbwait(&so->so_snd); + SOCKBUF_UNLOCK(&so->so_snd); + if (error) + goto release; + goto restart; + } + SOCKBUF_UNLOCK(&so->so_snd); + do { + if (uio == NULL) { + resid = 0; + if (flags & MSG_EOR) + top->m_flags |= M_EOR; + } else { + /* + * Copy the data from userland into a mbuf + * chain. If no data is to be copied in, + * a single empty mbuf is returned. + */ + copy = min(space, + ssk->xmit_size_goal - SDP_HEAD_SIZE); + top = m_uiotombuf(uio, M_WAITOK, copy, + 0, M_PKTHDR | + ((flags & MSG_EOR) ? M_EOR : 0)); + if (top == NULL) { + /* only possible error */ + error = EFAULT; + goto release; + } + space -= resid - uio->uio_resid; + resid = uio->uio_resid; + } + /* + * XXX all the SBS_CANTSENDMORE checks previously + * done could be out of date after dropping the + * socket lock. + */ + error = sdp_send(so, (flags & MSG_OOB) ? PRUS_OOB : + /* + * Set EOF on the last send if the user specified + * MSG_EOF. + */ + ((flags & MSG_EOF) && (resid <= 0)) ? PRUS_EOF : + /* If there is more to send set PRUS_MORETOCOME. */ + (resid > 0 && space > 0) ? PRUS_MORETOCOME : 0, + top, addr, NULL, td); + top = NULL; + if (error) + goto release; + } while (resid && space > 0); + } while (resid); + +release: + sbunlock(&so->so_snd); +out: + if (top != NULL) + m_freem(top); + return (error); +} + +/* + * The part of soreceive() that implements reading non-inline out-of-band + * data from a socket. For more complete comments, see soreceive(), from + * which this code originated. + * + * Note that soreceive_rcvoob(), unlike the remainder of soreceive(), is + * unable to return an mbuf chain to the caller. + */ +static int +soreceive_rcvoob(struct socket *so, struct uio *uio, int flags) +{ + struct protosw *pr = so->so_proto; + struct mbuf *m; + int error; + + KASSERT(flags & MSG_OOB, ("soreceive_rcvoob: (flags & MSG_OOB) == 0")); + + m = m_get(M_WAIT, MT_DATA); + error = (*pr->pr_usrreqs->pru_rcvoob)(so, m, flags & MSG_PEEK); + if (error) + goto bad; + do { + error = uiomove(mtod(m, void *), + (int) min(uio->uio_resid, m->m_len), uio); + m = m_free(m); + } while (uio->uio_resid && error == 0 && m); +bad: + if (m != NULL) + m_freem(m); + return (error); +} + +/* + * Optimized version of soreceive() for stream (TCP) sockets. + */ +static int +sdp_sorecv(struct socket *so, struct sockaddr **psa, struct uio *uio, + struct mbuf **mp0, struct mbuf **controlp, int *flagsp) +{ + int len = 0, error = 0, flags, oresid; + struct sockbuf *sb; + struct mbuf *m, *n = NULL; + struct sdp_sock *ssk; + + /* We only do stream sockets. */ + if (so->so_type != SOCK_STREAM) + return (EINVAL); + if (psa != NULL) + *psa = NULL; + if (controlp != NULL) + return (EINVAL); + if (flagsp != NULL) + flags = *flagsp &~ MSG_EOR; + else + flags = 0; + if (flags & MSG_OOB) + return (soreceive_rcvoob(so, uio, flags)); + if (mp0 != NULL) + *mp0 = NULL; + + sb = &so->so_rcv; + ssk = sdp_sk(so); + + /* Prevent other readers from entering the socket. */ + error = sblock(sb, SBLOCKWAIT(flags)); + if (error) + goto out; + SOCKBUF_LOCK(sb); + + /* Easy one, no space to copyout anything. */ + if (uio->uio_resid == 0) { + error = EINVAL; + goto out; + } + oresid = uio->uio_resid; + + /* We will never ever get anything unless we are connected. */ + if (!(so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED))) { + /* When disconnecting there may be still some data left. */ + if (sb->sb_cc > 0) + goto deliver; + if (!(so->so_state & SS_ISDISCONNECTED)) + error = ENOTCONN; + goto out; + } + + /* Socket buffer is empty and we shall not block. */ + if (sb->sb_cc == 0 && + ((sb->sb_flags & SS_NBIO) || (flags & (MSG_DONTWAIT|MSG_NBIO)))) { + error = EAGAIN; + goto out; + } + +restart: + SOCKBUF_LOCK_ASSERT(&so->so_rcv); + + /* Abort if socket has reported problems. */ + if (so->so_error) { + if (sb->sb_cc > 0) + goto deliver; + if (oresid > uio->uio_resid) + goto out; + error = so->so_error; + if (!(flags & MSG_PEEK)) + so->so_error = 0; + goto out; + } + + /* Door is closed. Deliver what is left, if any. */ + if (sb->sb_state & SBS_CANTRCVMORE) { + if (sb->sb_cc > 0) + goto deliver; + else + goto out; + } + + /* Socket buffer got some data that we shall deliver now. */ + if (sb->sb_cc > 0 && !(flags & MSG_WAITALL) && + ((sb->sb_flags & SS_NBIO) || + (flags & (MSG_DONTWAIT|MSG_NBIO)) || + sb->sb_cc >= sb->sb_lowat || + sb->sb_cc >= uio->uio_resid || + sb->sb_cc >= sb->sb_hiwat) ) { + goto deliver; + } + + /* On MSG_WAITALL we must wait until all data or error arrives. */ + if ((flags & MSG_WAITALL) && + (sb->sb_cc >= uio->uio_resid || sb->sb_cc >= sb->sb_lowat)) + goto deliver; + + /* + * Wait and block until (more) data comes in. + * NB: Drops the sockbuf lock during wait. + */ + error = sbwait(sb); + if (error) + goto out; + goto restart; + +deliver: + SOCKBUF_LOCK_ASSERT(&so->so_rcv); + KASSERT(sb->sb_cc > 0, ("%s: sockbuf empty", __func__)); + KASSERT(sb->sb_mb != NULL, ("%s: sb_mb == NULL", __func__)); + + /* Statistics. */ + if (uio->uio_td) + uio->uio_td->td_ru.ru_msgrcv++; + + /* Fill uio until full or current end of socket buffer is reached. */ + len = min(uio->uio_resid, sb->sb_cc); + if (mp0 != NULL) { + /* Dequeue as many mbufs as possible. */ + if (!(flags & MSG_PEEK) && len >= sb->sb_mb->m_len) { + for (*mp0 = m = sb->sb_mb; + m != NULL && m->m_len <= len; + m = m->m_next) { + len -= m->m_len; + uio->uio_resid -= m->m_len; + sbfree(sb, m); + n = m; + } + sb->sb_mb = m; + if (sb->sb_mb == NULL) + SB_EMPTY_FIXUP(sb); + n->m_next = NULL; + } + /* Copy the remainder. */ + if (len > 0) { + KASSERT(sb->sb_mb != NULL, + ("%s: len > 0 && sb->sb_mb empty", __func__)); + + m = m_copym(sb->sb_mb, 0, len, M_DONTWAIT); + if (m == NULL) + len = 0; /* Don't flush data from sockbuf. */ + else + uio->uio_resid -= m->m_len; + if (*mp0 != NULL) + n->m_next = m; + else + *mp0 = m; + if (*mp0 == NULL) { + error = ENOBUFS; + goto out; + } + } + } else { + /* NB: Must unlock socket buffer as uiomove may sleep. */ + SOCKBUF_UNLOCK(sb); + error = m_mbuftouio(uio, sb->sb_mb, len); + SOCKBUF_LOCK(sb); + if (error) + goto out; + } + SBLASTRECORDCHK(sb); + SBLASTMBUFCHK(sb); + + /* + * Remove the delivered data from the socket buffer unless we + * were only peeking. + */ + if (!(flags & MSG_PEEK)) { + if (len > 0) + sbdrop_locked(sb, len); + + /* Notify protocol that we drained some data. */ + SOCKBUF_UNLOCK(sb); + SDP_WLOCK(ssk); + sdp_do_posts(ssk); + SDP_WUNLOCK(ssk); + SOCKBUF_LOCK(sb); + } + + /* + * For MSG_WAITALL we may have to loop again and wait for + * more data to come in. + */ + if ((flags & MSG_WAITALL) && uio->uio_resid > 0) + goto restart; +out: + SOCKBUF_LOCK_ASSERT(sb); + SBLASTRECORDCHK(sb); + SBLASTMBUFCHK(sb); + SOCKBUF_UNLOCK(sb); + sbunlock(sb); + return (error); +} + +/* + * Abort is used to teardown a connection typically while sitting in + * the accept queue. + */ +void +sdp_abort(struct socket *so) +{ + struct sdp_sock *ssk; + + ssk = sdp_sk(so); + SDP_WLOCK(ssk); + /* + * If we have not yet dropped, do it now. + */ + if (!(ssk->flags & SDP_TIMEWAIT) && + !(ssk->flags & SDP_DROPPED)) + sdp_drop(ssk, ECONNABORTED); + KASSERT(ssk->flags & SDP_DROPPED, ("sdp_abort: %p not dropped 0x%X", + ssk, ssk->flags)); + SDP_WUNLOCK(ssk); +} + +/* + * Close a SDP socket and initiate a friendly disconnect. + */ +static void +sdp_close(struct socket *so) +{ + struct sdp_sock *ssk; + + ssk = sdp_sk(so); + SDP_WLOCK(ssk); + /* + * If we have not yet dropped, do it now. + */ + if (!(ssk->flags & SDP_TIMEWAIT) && + !(ssk->flags & SDP_DROPPED)) + sdp_start_disconnect(ssk); + + /* + * If we've still not dropped let the socket layer know we're + * holding on to the socket and pcb for a while. + */ + if (!(ssk->flags & SDP_DROPPED)) { + SOCK_LOCK(so); + so->so_state |= SS_PROTOREF; + SOCK_UNLOCK(so); + ssk->flags |= SDP_SOCKREF; + } + SDP_WUNLOCK(ssk); +} + +/* + * User requests out-of-band data. + */ +static int +sdp_rcvoob(struct socket *so, struct mbuf *m, int flags) +{ + int error = 0; + struct sdp_sock *ssk; + + ssk = sdp_sk(so); + SDP_WLOCK(ssk); + if (!rx_ring_trylock(&ssk->rx_ring)) { + SDP_WUNLOCK(ssk); + return (ECONNRESET); + } + if (ssk->flags & (SDP_TIMEWAIT | SDP_DROPPED)) { + error = ECONNRESET; + goto out; + } + if ((so->so_oobmark == 0 && + (so->so_rcv.sb_state & SBS_RCVATMARK) == 0) || + so->so_options & SO_OOBINLINE || + ssk->oobflags & SDP_HADOOB) { + error = EINVAL; + goto out; + } + if ((ssk->oobflags & SDP_HAVEOOB) == 0) { + error = EWOULDBLOCK; + goto out; + } + m->m_len = 1; + *mtod(m, caddr_t) = ssk->iobc; + if ((flags & MSG_PEEK) == 0) + ssk->oobflags ^= (SDP_HAVEOOB | SDP_HADOOB); +out: + rx_ring_unlock(&ssk->rx_ring); + SDP_WUNLOCK(ssk); + return (error); +} + +void +sdp_urg(struct sdp_sock *ssk, struct mbuf *mb) +{ + struct mbuf *m; + struct socket *so; + + so = ssk->socket; + if (so == NULL) + return; + + so->so_oobmark = so->so_rcv.sb_cc + mb->m_pkthdr.len - 1; + sohasoutofband(so); + ssk->oobflags &= ~(SDP_HAVEOOB | SDP_HADOOB); + if (!(so->so_options & SO_OOBINLINE)) { + for (m = mb; m->m_next != NULL; m = m->m_next); + ssk->iobc = *(mtod(m, char *) + m->m_len - 1); + ssk->oobflags |= SDP_HAVEOOB; + m->m_len--; + mb->m_pkthdr.len--; + } +} + +/* + * Notify a sdp socket of an asynchronous error. + * + * Do not wake up user since there currently is no mechanism for + * reporting soft errors (yet - a kqueue filter may be added). + */ +struct sdp_sock * +sdp_notify(struct sdp_sock *ssk, int error) +{ + + SDP_WLOCK_ASSERT(ssk); + + if ((ssk->flags & SDP_TIMEWAIT) || + (ssk->flags & SDP_DROPPED)) + return (ssk); + + /* + * Ignore some errors if we are hooked up. + */ + if (ssk->state == TCPS_ESTABLISHED && + (error == EHOSTUNREACH || error == ENETUNREACH || + error == EHOSTDOWN)) + return (ssk); + ssk->softerror = error; + return sdp_drop(ssk, error); +} + +static void +sdp_ctlinput(int cmd, struct sockaddr *sa, void *vip) +{ + struct in_addr faddr; + + faddr = ((struct sockaddr_in *)sa)->sin_addr; + if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY) + return; + + sdp_pcbnotifyall(faddr, inetctlerrmap[cmd], sdp_notify); +} + +static int +sdp_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, + struct thread *td) +{ + return (EOPNOTSUPP); +} + +static void +sdp_keepalive_timeout(void *data) +{ + struct sdp_sock *ssk; + + ssk = data; + /* Callout canceled. */ + if (!callout_active(&ssk->keep2msl)) + return; + /* Callout rescheduled as a different kind of timer. */ + if (callout_pending(&ssk->keep2msl)) + goto out; + callout_deactivate(&ssk->keep2msl); + if (ssk->flags & SDP_DROPPED || + (ssk->socket->so_options & SO_KEEPALIVE) == 0) + goto out; + sdp_post_keepalive(ssk); + callout_reset(&ssk->keep2msl, SDP_KEEPALIVE_TIME, + sdp_keepalive_timeout, ssk); +out: + SDP_WUNLOCK(ssk); +} + + +void +sdp_start_keepalive_timer(struct socket *so) +{ + struct sdp_sock *ssk; + + ssk = sdp_sk(so); + if (!callout_pending(&ssk->keep2msl)) + callout_reset(&ssk->keep2msl, SDP_KEEPALIVE_TIME, + sdp_keepalive_timeout, ssk); +} + +static void +sdp_stop_keepalive_timer(struct socket *so) +{ + struct sdp_sock *ssk; + + ssk = sdp_sk(so); + callout_stop(&ssk->keep2msl); +} + +/* + * sdp_ctloutput() must drop the inpcb lock before performing copyin on + * socket option arguments. When it re-acquires the lock after the copy, it + * has to revalidate that the connection is still valid for the socket + * option. + */ +#define SDP_WLOCK_RECHECK(inp) do { \ + SDP_WLOCK(ssk); \ + if (ssk->flags & (SDP_TIMEWAIT | SDP_DROPPED)) { \ + SDP_WUNLOCK(ssk); \ + return (ECONNRESET); \ + } \ +} while(0) + +static int +sdp_ctloutput(struct socket *so, struct sockopt *sopt) +{ + int error, opt, optval; + struct sdp_sock *ssk; + + error = 0; + ssk = sdp_sk(so); + if (sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_KEEPALIVE) { + SDP_WLOCK(ssk); + if (so->so_options & SO_KEEPALIVE) + sdp_start_keepalive_timer(so); + else + sdp_stop_keepalive_timer(so); + SDP_WUNLOCK(ssk); + } + if (sopt->sopt_level != IPPROTO_TCP) + return (error); + + SDP_WLOCK(ssk); + if (ssk->flags & (SDP_TIMEWAIT | SDP_DROPPED)) { + SDP_WUNLOCK(ssk); + return (ECONNRESET); + } + + switch (sopt->sopt_dir) { + case SOPT_SET: + switch (sopt->sopt_name) { + case TCP_NODELAY: + SDP_WUNLOCK(ssk); + error = sooptcopyin(sopt, &optval, sizeof optval, + sizeof optval); + if (error) + return (error); + + SDP_WLOCK_RECHECK(ssk); + opt = SDP_NODELAY; + if (optval) + ssk->flags |= opt; + else + ssk->flags &= ~opt; + sdp_do_posts(ssk); + SDP_WUNLOCK(ssk); + break; + + default: + SDP_WUNLOCK(ssk); + error = ENOPROTOOPT; + break; + } + break; + + case SOPT_GET: + switch (sopt->sopt_name) { + case TCP_NODELAY: + optval = ssk->flags & SDP_NODELAY; + SDP_WUNLOCK(ssk); + error = sooptcopyout(sopt, &optval, sizeof optval); + break; + default: + SDP_WUNLOCK(ssk); + error = ENOPROTOOPT; + break; + } + break; + } + return (error); +} +#undef SDP_WLOCK_RECHECK + +int sdp_mod_count = 0; +int sdp_mod_usec = 0; + +void +sdp_set_default_moderation(struct sdp_sock *ssk) +{ + if (sdp_mod_count <= 0 || sdp_mod_usec <= 0) + return; + ib_modify_cq(ssk->rx_ring.cq, sdp_mod_count, sdp_mod_usec); +} + + +static void +sdp_dev_add(struct ib_device *device) +{ + struct ib_fmr_pool_param param; + struct sdp_device *sdp_dev; + + sdp_dev = malloc(sizeof(*sdp_dev), M_SDP, M_WAITOK | M_ZERO); + sdp_dev->pd = ib_alloc_pd(device); + if (IS_ERR(sdp_dev->pd)) + goto out_pd; + sdp_dev->mr = ib_get_dma_mr(sdp_dev->pd, IB_ACCESS_LOCAL_WRITE); + if (IS_ERR(sdp_dev->mr)) + goto out_mr; + memset(¶m, 0, sizeof param); + param.max_pages_per_fmr = SDP_FMR_SIZE; + param.page_shift = PAGE_SHIFT; + param.access = (IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_READ); + param.pool_size = SDP_FMR_POOL_SIZE; + param.dirty_watermark = SDP_FMR_DIRTY_SIZE; + param.cache = 1; + sdp_dev->fmr_pool = ib_create_fmr_pool(sdp_dev->pd, ¶m); + if (IS_ERR(sdp_dev->fmr_pool)) + goto out_fmr; + ib_set_client_data(device, &sdp_client, sdp_dev); + return; + +out_fmr: + ib_dereg_mr(sdp_dev->mr); +out_mr: + ib_dealloc_pd(sdp_dev->pd); +out_pd: + free(sdp_dev, M_SDP); +} + +static void +sdp_dev_rem(struct ib_device *device) +{ + struct sdp_device *sdp_dev; + struct sdp_sock *ssk; + + SDP_LIST_WLOCK(); + LIST_FOREACH(ssk, &sdp_list, list) { + if (ssk->ib_device != device) + continue; + SDP_WLOCK(ssk); + if ((ssk->flags & SDP_DESTROY) == 0) + ssk = sdp_notify(ssk, ECONNRESET); + if (ssk) + SDP_WUNLOCK(ssk); + } + SDP_LIST_WUNLOCK(); + /* + * XXX Do I need to wait between these two? + */ + sdp_dev = ib_get_client_data(device, &sdp_client); + if (!sdp_dev) + return; + ib_flush_fmr_pool(sdp_dev->fmr_pool); + ib_destroy_fmr_pool(sdp_dev->fmr_pool); + ib_dereg_mr(sdp_dev->mr); + ib_dealloc_pd(sdp_dev->pd); + free(sdp_dev, M_SDP); +} + +struct ib_client sdp_client = + { .name = "sdp", .add = sdp_dev_add, .remove = sdp_dev_rem }; + + +static int +sdp_pcblist(SYSCTL_HANDLER_ARGS) +{ + int error, n, i; + struct sdp_sock *ssk; + struct xinpgen xig; + + /* + * The process of preparing the TCB list is too time-consuming and + * resource-intensive to repeat twice on every request. + */ + if (req->oldptr == NULL) { + n = sdp_count; + n += imax(n / 8, 10); + req->oldidx = 2 * (sizeof xig) + n * sizeof(struct xtcpcb); + return (0); + } + + if (req->newptr != NULL) + return (EPERM); + + /* + * OK, now we're committed to doing something. + */ + SDP_LIST_RLOCK(); + n = sdp_count; + SDP_LIST_RUNLOCK(); + + error = sysctl_wire_old_buffer(req, 2 * (sizeof xig) + + n * sizeof(struct xtcpcb)); + if (error != 0) + return (error); + + xig.xig_len = sizeof xig; + xig.xig_count = n; + xig.xig_gen = 0; + xig.xig_sogen = so_gencnt; + error = SYSCTL_OUT(req, &xig, sizeof xig); + if (error) + return (error); + + SDP_LIST_RLOCK(); + for (ssk = LIST_FIRST(&sdp_list), i = 0; + ssk != NULL && i < n; ssk = LIST_NEXT(ssk, list)) { + struct xtcpcb xt; + + SDP_RLOCK(ssk); + if (ssk->flags & SDP_TIMEWAIT) { + if (ssk->cred != NULL) + error = cr_cansee(req->td->td_ucred, + ssk->cred); + else + error = EINVAL; /* Skip this inp. */ + } else if (ssk->socket) + error = cr_canseesocket(req->td->td_ucred, + ssk->socket); + else + error = EINVAL; + if (error) { + error = 0; + goto next; + } + + bzero(&xt, sizeof(xt)); + xt.xt_len = sizeof xt; + xt.xt_inp.inp_gencnt = 0; + xt.xt_inp.inp_vflag = INP_IPV4; + memcpy(&xt.xt_inp.inp_laddr, &ssk->laddr, sizeof(ssk->laddr)); + xt.xt_inp.inp_lport = ssk->lport; + memcpy(&xt.xt_inp.inp_faddr, &ssk->faddr, sizeof(ssk->faddr)); + xt.xt_inp.inp_fport = ssk->fport; + xt.xt_tp.t_state = ssk->state; + if (ssk->socket != NULL) + sotoxsocket(ssk->socket, &xt.xt_socket); + else + bzero(&xt.xt_socket, sizeof xt.xt_socket); + xt.xt_socket.xso_protocol = IPPROTO_TCP; + SDP_RUNLOCK(ssk); + error = SYSCTL_OUT(req, &xt, sizeof xt); + if (error) + break; + i++; + continue; +next: + SDP_RUNLOCK(ssk); + } + if (!error) { + /* + * Give the user an updated idea of our state. + * If the generation differs from what we told + * her before, she knows that something happened + * while we were processing this request, and it + * might be necessary to retry. + */ + xig.xig_gen = 0; + xig.xig_sogen = so_gencnt; + xig.xig_count = sdp_count; + error = SYSCTL_OUT(req, &xig, sizeof xig); + } + SDP_LIST_RUNLOCK(); + return (error); +} + +SYSCTL_NODE(_net_inet, -1, sdp, CTLFLAG_RW, 0, "SDP"); + +SYSCTL_PROC(_net_inet_sdp, TCPCTL_PCBLIST, pcblist, + CTLFLAG_RD | CTLTYPE_STRUCT, 0, 0, sdp_pcblist, "S,xtcpcb", + "List of active SDP connections"); + +static void +sdp_zone_change(void *tag) +{ + + uma_zone_set_max(sdp_zone, maxsockets); +} + +static void +sdp_init(void) +{ + + LIST_INIT(&sdp_list); + sdp_zone = uma_zcreate("sdp_sock", sizeof(struct sdp_sock), + NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); + uma_zone_set_max(sdp_zone, maxsockets); + EVENTHANDLER_REGISTER(maxsockets_change, sdp_zone_change, NULL, + EVENTHANDLER_PRI_ANY); + rx_comp_wq = create_singlethread_workqueue("rx_comp_wq"); + ib_register_client(&sdp_client); +} + +extern struct domain sdpdomain; + +struct pr_usrreqs sdp_usrreqs = { + .pru_abort = sdp_abort, + .pru_accept = sdp_accept, + .pru_attach = sdp_attach, + .pru_bind = sdp_bind, + .pru_connect = sdp_connect, + .pru_control = sdp_control, + .pru_detach = sdp_detach, + .pru_disconnect = sdp_disconnect, + .pru_listen = sdp_listen, + .pru_peeraddr = sdp_getpeeraddr, + .pru_rcvoob = sdp_rcvoob, + .pru_send = sdp_send, + .pru_sosend = sdp_sosend, + .pru_soreceive = sdp_sorecv, + .pru_shutdown = sdp_shutdown, + .pru_sockaddr = sdp_getsockaddr, + .pru_close = sdp_close, +}; + +struct protosw sdpsw[] = { +{ + .pr_type = SOCK_STREAM, + .pr_domain = &sdpdomain, + .pr_protocol = IPPROTO_IP, + .pr_flags = PR_CONNREQUIRED|PR_IMPLOPCL|PR_WANTRCVD, + .pr_ctlinput = sdp_ctlinput, + .pr_ctloutput = sdp_ctloutput, + .pr_usrreqs = &sdp_usrreqs +}, +{ + .pr_type = SOCK_STREAM, + .pr_domain = &sdpdomain, + .pr_protocol = IPPROTO_TCP, + .pr_flags = PR_CONNREQUIRED|PR_IMPLOPCL|PR_WANTRCVD, + .pr_ctlinput = sdp_ctlinput, + .pr_ctloutput = sdp_ctloutput, + .pr_usrreqs = &sdp_usrreqs +}, +}; + +struct domain sdpdomain = { + .dom_family = AF_INET_SDP, + .dom_name = "SDP", + .dom_init = sdp_init, + .dom_protosw = sdpsw, + .dom_protoswNPROTOSW = &sdpsw[sizeof(sdpsw)/sizeof(sdpsw[0])], +}; + +DOMAIN_SET(sdp); + +int sdp_debug_level = 1; +int sdp_data_debug_level = 0; diff --git a/sys/ofed/drivers/infiniband/ulp/sdp/sdp_proc.c b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_proc.c new file mode 100644 index 000000000000..74bc04a052ef --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_proc.c @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2008 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include "sdp.h" + +#ifdef CONFIG_PROC_FS + +#define PROC_SDP_STATS "sdpstats" +#define PROC_SDP_PERF "sdpprf" + +/* just like TCP fs */ +struct sdp_seq_afinfo { + struct module *owner; + char *name; + sa_family_t family; + int (*seq_show) (struct seq_file *m, void *v); + struct file_operations *seq_fops; +}; + +struct sdp_iter_state { + sa_family_t family; + int num; + struct seq_operations seq_ops; +}; + +static void *sdp_get_idx(struct seq_file *seq, loff_t pos) +{ + int i = 0; + struct sdp_sock *ssk; + + if (!list_empty(&sock_list)) + list_for_each_entry(ssk, &sock_list, sock_list) { + if (i == pos) + return ssk; + i++; + } + + return NULL; +} + +static void *sdp_seq_start(struct seq_file *seq, loff_t *pos) +{ + void *start = NULL; + struct sdp_iter_state *st = seq->private; + + st->num = 0; + + if (!*pos) + return SEQ_START_TOKEN; + + spin_lock_irq(&sock_list_lock); + start = sdp_get_idx(seq, *pos - 1); + if (start) + sock_hold((struct socket *)start, SOCK_REF_SEQ); + spin_unlock_irq(&sock_list_lock); + + return start; +} + +static void *sdp_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct sdp_iter_state *st = seq->private; + void *next = NULL; + + spin_lock_irq(&sock_list_lock); + if (v == SEQ_START_TOKEN) + next = sdp_get_idx(seq, 0); + else + next = sdp_get_idx(seq, *pos); + if (next) + sock_hold((struct socket *)next, SOCK_REF_SEQ); + spin_unlock_irq(&sock_list_lock); + + *pos += 1; + st->num++; + + return next; +} + +static void sdp_seq_stop(struct seq_file *seq, void *v) +{ +} + +#define TMPSZ 150 + +static int sdp_seq_show(struct seq_file *seq, void *v) +{ + struct sdp_iter_state *st; + struct socket *sk = v; + char tmpbuf[TMPSZ + 1]; + unsigned int dest; + unsigned int src; + int uid; + unsigned long inode; + __u16 destp; + __u16 srcp; + __u32 rx_queue, tx_queue; + + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "%-*s\n", TMPSZ - 1, + " sl local_address rem_address " + "uid inode rx_queue tx_queue state"); + goto out; + } + + st = seq->private; + + dest = inet_sk(sk)->daddr; + src = inet_sk(sk)->rcv_saddr; + destp = ntohs(inet_sk(sk)->dport); + srcp = ntohs(inet_sk(sk)->sport); + uid = sock_i_uid(sk); + inode = sock_i_ino(sk); + rx_queue = rcv_nxt(sdp_sk(sk)) - sdp_sk(sk)->copied_seq; + tx_queue = sdp_sk(sk)->write_seq - sdp_sk(sk)->tx_ring.una_seq; + + sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %5d %lu %08X:%08X %X", + st->num, src, srcp, dest, destp, uid, inode, + rx_queue, tx_queue, sk->sk_state); + + seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf); + + sock_put(sk, SOCK_REF_SEQ); +out: + return 0; +} + +static int sdp_seq_open(struct inode *inode, struct file *file) +{ + struct sdp_seq_afinfo *afinfo = PDE(inode)->data; + struct seq_file *seq; + struct sdp_iter_state *s; + int rc; + + if (unlikely(afinfo == NULL)) + return -EINVAL; + +/* Workaround bogus warning by memtrack */ +#define _kzalloc(size,flags) kzalloc(size,flags) +#undef kzalloc + s = kzalloc(sizeof(*s), GFP_KERNEL); +#define kzalloc(s,f) _kzalloc(s,f) + if (!s) + return -ENOMEM; + s->family = afinfo->family; + s->seq_ops.start = sdp_seq_start; + s->seq_ops.next = sdp_seq_next; + s->seq_ops.show = afinfo->seq_show; + s->seq_ops.stop = sdp_seq_stop; + + rc = seq_open(file, &s->seq_ops); + if (rc) + goto out_kfree; + seq = file->private_data; + seq->private = s; +out: + return rc; +out_kfree: + kfree(s); + goto out; +} + + +static struct file_operations sdp_seq_fops; +static struct sdp_seq_afinfo sdp_seq_afinfo = { + .owner = THIS_MODULE, + .name = "sdp", + .family = AF_INET_SDP, + .seq_show = sdp_seq_show, + .seq_fops = &sdp_seq_fops, +}; + +#ifdef SDPSTATS_ON +DEFINE_PER_CPU(struct sdpstats, sdpstats); + +static void sdpstats_seq_hist(struct seq_file *seq, char *str, u32 *h, int n, + int is_log) +{ + int i; + u32 max = 0; + + seq_printf(seq, "%s:\n", str); + + for (i = 0; i < n; i++) { + if (h[i] > max) + max = h[i]; + } + + if (max == 0) { + seq_printf(seq, " - all values are 0\n"); + return; + } + + for (i = 0; i < n; i++) { + char s[51]; + int j = 50 * h[i] / max; + int val = is_log ? (i == n-1 ? 0 : 1<time - start_t; + nsec_rem = do_div(t, 1000000000); + + seq_printf(m, "%-6d: [%5lu.%06lu] %-50s - [%d{%d} %d:%d] " + "mb: %p %s:%d\n", + l->idx, (unsigned long)t, nsec_rem/1000, + l->msg, l->pid, l->cpu, l->sk_num, l->sk_dport, + l->mb, l->func, l->line); +out: + return 0; +} + +static void *sdpprf_start(struct seq_file *p, loff_t *pos) +{ + int idx = *pos; + + if (!*pos) { + if (!sdpprf_log_count) + return SEQ_START_TOKEN; + } + + if (*pos >= MIN(sdpprf_log_count, SDPPRF_LOG_SIZE - 1)) + return NULL; + + if (sdpprf_log_count >= SDPPRF_LOG_SIZE - 1) { + int off = sdpprf_log_count & (SDPPRF_LOG_SIZE - 1); + idx = (idx + off) & (SDPPRF_LOG_SIZE - 1); + + } + + if (!start_t) + start_t = sdpprf_log[idx].time; + return &sdpprf_log[idx]; +} + +static void *sdpprf_next(struct seq_file *p, void *v, loff_t *pos) +{ + struct sdpprf_log *l = v; + + if (++*pos >= MIN(sdpprf_log_count, SDPPRF_LOG_SIZE - 1)) + return NULL; + + ++l; + if (l - &sdpprf_log[0] >= SDPPRF_LOG_SIZE - 1) + return &sdpprf_log[0]; + + return l; +} + +static void sdpprf_stop(struct seq_file *p, void *v) +{ +} + +static struct seq_operations sdpprf_ops = { + .start = sdpprf_start, + .stop = sdpprf_stop, + .next = sdpprf_next, + .show = sdpprf_show, +}; + +static int sdpprf_open(struct inode *inode, struct file *file) +{ + int res; + + res = seq_open(file, &sdpprf_ops); + + return res; +} + +static ssize_t sdpprf_write(struct file *file, const char __user *buf, + size_t count, loff_t *offs) +{ + sdpprf_log_count = 0; + printk(KERN_INFO "Cleared sdpprf statistics\n"); + + return count; +} + +static struct file_operations sdpprf_fops = { + .open = sdpprf_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, + .write = sdpprf_write, +}; +#endif /* SDP_PROFILING */ + +int __init sdp_proc_init(void) +{ + struct proc_dir_entry *p = NULL; +#ifdef SDPSTATS_ON + struct proc_dir_entry *stats = NULL; +#endif +#ifdef SDP_PROFILING + struct proc_dir_entry *prof = NULL; +#endif + + sdp_seq_afinfo.seq_fops->owner = sdp_seq_afinfo.owner; + sdp_seq_afinfo.seq_fops->open = sdp_seq_open; + sdp_seq_afinfo.seq_fops->read = seq_read; + sdp_seq_afinfo.seq_fops->llseek = seq_lseek; + sdp_seq_afinfo.seq_fops->release = seq_release_private; + + p = proc_net_fops_create(&init_net, sdp_seq_afinfo.name, S_IRUGO, + sdp_seq_afinfo.seq_fops); + if (p) + p->data = &sdp_seq_afinfo; + else + goto no_mem; + +#ifdef SDPSTATS_ON + + stats = proc_net_fops_create(&init_net, PROC_SDP_STATS, + S_IRUGO | S_IWUGO, &sdpstats_fops); + if (!stats) + goto no_mem_stats; + +#endif + +#ifdef SDP_PROFILING + prof = proc_net_fops_create(&init_net, PROC_SDP_PERF, + S_IRUGO | S_IWUGO, &sdpprf_fops); + if (!prof) + goto no_mem_prof; +#endif + + return 0; + +#ifdef SDP_PROFILING +no_mem_prof: +#endif + +#ifdef SDPSTATS_ON + proc_net_remove(&init_net, PROC_SDP_STATS); + +no_mem_stats: +#endif + proc_net_remove(&init_net, sdp_seq_afinfo.name); + +no_mem: + return -ENOMEM; +} + +void sdp_proc_unregister(void) +{ + proc_net_remove(&init_net, sdp_seq_afinfo.name); + memset(sdp_seq_afinfo.seq_fops, 0, sizeof(*sdp_seq_afinfo.seq_fops)); + +#ifdef SDPSTATS_ON + proc_net_remove(&init_net, PROC_SDP_STATS); +#endif +#ifdef SDP_PROFILING + proc_net_remove(&init_net, PROC_SDP_PERF); +#endif +} + +#else /* CONFIG_PROC_FS */ + +int __init sdp_proc_init(void) +{ + return 0; +} + +void sdp_proc_unregister(void) +{ + +} +#endif /* CONFIG_PROC_FS */ diff --git a/sys/ofed/drivers/infiniband/ulp/sdp/sdp_rx.c b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_rx.c new file mode 100644 index 000000000000..de4b80be68db --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_rx.c @@ -0,0 +1,783 @@ +/* + * Copyright (c) 2009 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "sdp.h" + +SDP_MODPARAM_INT(rcvbuf_initial_size, 32 * 1024, + "Receive buffer initial size in bytes."); +SDP_MODPARAM_SINT(rcvbuf_scale, 0x8, + "Receive buffer size scale factor."); + +/* Like tcp_fin - called when SDP_MID_DISCONNECT is received */ +static void +sdp_handle_disconn(struct sdp_sock *ssk) +{ + + sdp_dbg(ssk->socket, "%s\n", __func__); + + SDP_WLOCK_ASSERT(ssk); + if (TCPS_HAVERCVDFIN(ssk->state) == 0) + socantrcvmore(ssk->socket); + + switch (ssk->state) { + case TCPS_SYN_RECEIVED: + case TCPS_ESTABLISHED: + ssk->state = TCPS_CLOSE_WAIT; + break; + + case TCPS_FIN_WAIT_1: + /* Received a reply FIN - start Infiniband tear down */ + sdp_dbg(ssk->socket, + "%s: Starting Infiniband tear down sending DREQ\n", + __func__); + + sdp_cancel_dreq_wait_timeout(ssk); + ssk->qp_active = 0; + if (ssk->id) { + struct rdma_cm_id *id; + + id = ssk->id; + SDP_WUNLOCK(ssk); + rdma_disconnect(id); + SDP_WLOCK(ssk); + } else { + sdp_warn(ssk->socket, + "%s: ssk->id is NULL\n", __func__); + return; + } + break; + case TCPS_TIME_WAIT: + /* This is a mutual close situation and we've got the DREQ from + the peer before the SDP_MID_DISCONNECT */ + break; + case TCPS_CLOSED: + /* FIN arrived after IB teardown started - do nothing */ + sdp_dbg(ssk->socket, "%s: fin in state %s\n", + __func__, sdp_state_str(ssk->state)); + return; + default: + sdp_warn(ssk->socket, + "%s: FIN in unexpected state. state=%d\n", + __func__, ssk->state); + break; + } +} + +static int +sdp_post_recv(struct sdp_sock *ssk) +{ + struct sdp_buf *rx_req; + int i, rc; + u64 addr; + struct ib_device *dev; + struct ib_recv_wr rx_wr = { NULL }; + struct ib_sge ibsge[SDP_MAX_RECV_SGES]; + struct ib_sge *sge = ibsge; + struct ib_recv_wr *bad_wr; + struct mbuf *mb, *m; + struct sdp_bsdh *h; + int id = ring_head(ssk->rx_ring); + + /* Now, allocate and repost recv */ + sdp_prf(ssk->socket, mb, "Posting mb"); + mb = m_getm2(NULL, ssk->recv_bytes, M_NOWAIT, MT_DATA, M_PKTHDR); + if (mb == NULL) { + /* Retry so we can't stall out with no memory. */ + if (!rx_ring_posted(ssk)) + queue_work(rx_comp_wq, &ssk->rx_comp_work); + return -1; + } + for (m = mb; m != NULL; m = m->m_next) { + m->m_len = (m->m_flags & M_EXT) ? m->m_ext.ext_size : + ((m->m_flags & M_PKTHDR) ? MHLEN : MLEN); + mb->m_pkthdr.len += m->m_len; + } + h = mtod(mb, struct sdp_bsdh *); + rx_req = ssk->rx_ring.buffer + (id & (SDP_RX_SIZE - 1)); + rx_req->mb = mb; + dev = ssk->ib_device; + for (i = 0; mb != NULL; i++, mb = mb->m_next, sge++) { + addr = ib_dma_map_single(dev, mb->m_data, mb->m_len, + DMA_TO_DEVICE); + /* TODO: proper error handling */ + BUG_ON(ib_dma_mapping_error(dev, addr)); + BUG_ON(i >= SDP_MAX_RECV_SGES); + rx_req->mapping[i] = addr; + sge->addr = addr; + sge->length = mb->m_len; + sge->lkey = ssk->sdp_dev->mr->lkey; + } + + rx_wr.next = NULL; + rx_wr.wr_id = id | SDP_OP_RECV; + rx_wr.sg_list = ibsge; + rx_wr.num_sge = i; + rc = ib_post_recv(ssk->qp, &rx_wr, &bad_wr); + if (unlikely(rc)) { + sdp_warn(ssk->socket, "ib_post_recv failed. status %d\n", rc); + + sdp_cleanup_sdp_buf(ssk, rx_req, DMA_FROM_DEVICE); + m_freem(mb); + + sdp_notify(ssk, ECONNRESET); + + return -1; + } + + atomic_inc(&ssk->rx_ring.head); + SDPSTATS_COUNTER_INC(post_recv); + + return 0; +} + +static inline int +sdp_post_recvs_needed(struct sdp_sock *ssk) +{ + unsigned long bytes_in_process; + unsigned long max_bytes; + int buffer_size; + int posted; + + if (!ssk->qp_active || !ssk->socket) + return 0; + + posted = rx_ring_posted(ssk); + if (posted >= SDP_RX_SIZE) + return 0; + if (posted < SDP_MIN_TX_CREDITS) + return 1; + + buffer_size = ssk->recv_bytes; + max_bytes = max(ssk->socket->so_snd.sb_hiwat, + (1 + SDP_MIN_TX_CREDITS) * buffer_size); + max_bytes *= rcvbuf_scale; + /* + * Compute bytes in the receive queue and socket buffer. + */ + bytes_in_process = (posted - SDP_MIN_TX_CREDITS) * buffer_size; + bytes_in_process += ssk->socket->so_rcv.sb_cc; + + return bytes_in_process < max_bytes; +} + +static inline void +sdp_post_recvs(struct sdp_sock *ssk) +{ + + while (sdp_post_recvs_needed(ssk)) + if (sdp_post_recv(ssk)) + return; +} + +static inline struct mbuf * +sdp_sock_queue_rcv_mb(struct socket *sk, struct mbuf *mb) +{ + struct sdp_sock *ssk = sdp_sk(sk); + struct sdp_bsdh *h; + + h = mtod(mb, struct sdp_bsdh *); + +#ifdef SDP_ZCOPY + SDP_SKB_CB(mb)->seq = rcv_nxt(ssk); + if (h->mid == SDP_MID_SRCAVAIL) { + struct sdp_srcah *srcah = (struct sdp_srcah *)(h+1); + struct rx_srcavail_state *rx_sa; + + ssk->srcavail_cancel_mseq = 0; + + ssk->rx_sa = rx_sa = RX_SRCAVAIL_STATE(mb) = kzalloc( + sizeof(struct rx_srcavail_state), M_NOWAIT); + + rx_sa->mseq = ntohl(h->mseq); + rx_sa->used = 0; + rx_sa->len = mb_len = ntohl(srcah->len); + rx_sa->rkey = ntohl(srcah->rkey); + rx_sa->vaddr = be64_to_cpu(srcah->vaddr); + rx_sa->flags = 0; + + if (ssk->tx_sa) { + sdp_dbg_data(ssk->socket, "got RX SrcAvail while waiting " + "for TX SrcAvail. waking up TX SrcAvail" + "to be aborted\n"); + wake_up(sk->sk_sleep); + } + + atomic_add(mb->len, &ssk->rcv_nxt); + sdp_dbg_data(sk, "queueing SrcAvail. mb_len = %d vaddr = %lld\n", + mb_len, rx_sa->vaddr); + } else +#endif + { + atomic_add(mb->m_pkthdr.len, &ssk->rcv_nxt); + } + + m_adj(mb, SDP_HEAD_SIZE); + SOCKBUF_LOCK(&sk->so_rcv); + if (unlikely(h->flags & SDP_OOB_PRES)) + sdp_urg(ssk, mb); + sbappend_locked(&sk->so_rcv, mb); + sorwakeup_locked(sk); + return mb; +} + +static int +sdp_get_recv_bytes(struct sdp_sock *ssk, u32 new_size) +{ + + return MIN(new_size, SDP_MAX_PACKET); +} + +int +sdp_init_buffers(struct sdp_sock *ssk, u32 new_size) +{ + + ssk->recv_bytes = sdp_get_recv_bytes(ssk, new_size); + sdp_post_recvs(ssk); + + return 0; +} + +int +sdp_resize_buffers(struct sdp_sock *ssk, u32 new_size) +{ + u32 curr_size = ssk->recv_bytes; + u32 max_size = SDP_MAX_PACKET; + + if (new_size > curr_size && new_size <= max_size) { + ssk->recv_bytes = sdp_get_recv_bytes(ssk, new_size); + return 0; + } + return -1; +} + +static void +sdp_handle_resize_request(struct sdp_sock *ssk, struct sdp_chrecvbuf *buf) +{ + if (sdp_resize_buffers(ssk, ntohl(buf->size)) == 0) + ssk->recv_request_head = ring_head(ssk->rx_ring) + 1; + else + ssk->recv_request_head = ring_tail(ssk->rx_ring); + ssk->recv_request = 1; +} + +static void +sdp_handle_resize_ack(struct sdp_sock *ssk, struct sdp_chrecvbuf *buf) +{ + u32 new_size = ntohl(buf->size); + + if (new_size > ssk->xmit_size_goal) + ssk->xmit_size_goal = new_size; +} + +static struct mbuf * +sdp_recv_completion(struct sdp_sock *ssk, int id) +{ + struct sdp_buf *rx_req; + struct ib_device *dev; + struct mbuf *mb; + + if (unlikely(id != ring_tail(ssk->rx_ring))) { + printk(KERN_WARNING "Bogus recv completion id %d tail %d\n", + id, ring_tail(ssk->rx_ring)); + return NULL; + } + + dev = ssk->ib_device; + rx_req = &ssk->rx_ring.buffer[id & (SDP_RX_SIZE - 1)]; + mb = rx_req->mb; + sdp_cleanup_sdp_buf(ssk, rx_req, DMA_FROM_DEVICE); + + atomic_inc(&ssk->rx_ring.tail); + atomic_dec(&ssk->remote_credits); + return mb; +} + +/* socket lock should be taken before calling this */ +static int +sdp_process_rx_ctl_mb(struct sdp_sock *ssk, struct mbuf *mb) +{ + struct sdp_bsdh *h; + struct socket *sk; + + SDP_WLOCK_ASSERT(ssk); + sk = ssk->socket; + h = mtod(mb, struct sdp_bsdh *); + switch (h->mid) { + case SDP_MID_DATA: + case SDP_MID_SRCAVAIL: + sdp_dbg(sk, "DATA after socket rcv was shutdown\n"); + + /* got data in RCV_SHUTDOWN */ + if (ssk->state == TCPS_FIN_WAIT_1) { + sdp_dbg(sk, "RX data when state = FIN_WAIT1\n"); + sdp_notify(ssk, ECONNRESET); + } + m_freem(mb); + + break; +#ifdef SDP_ZCOPY + case SDP_MID_RDMARDCOMPL: + m_freem(mb); + break; + case SDP_MID_SENDSM: + sdp_handle_sendsm(ssk, ntohl(h->mseq_ack)); + m_freem(mb); + break; + case SDP_MID_SRCAVAIL_CANCEL: + sdp_dbg_data(sk, "Handling SrcAvailCancel\n"); + sdp_prf(sk, NULL, "Handling SrcAvailCancel"); + if (ssk->rx_sa) { + ssk->srcavail_cancel_mseq = ntohl(h->mseq); + ssk->rx_sa->flags |= RX_SA_ABORTED; + ssk->rx_sa = NULL; /* TODO: change it into SDP_MID_DATA and get + the dirty logic from recvmsg */ + } else { + sdp_dbg(sk, "Got SrcAvailCancel - " + "but no SrcAvail in process\n"); + } + m_freem(mb); + break; + case SDP_MID_SINKAVAIL: + sdp_dbg_data(sk, "Got SinkAvail - not supported: ignored\n"); + sdp_prf(sk, NULL, "Got SinkAvail - not supported: ignored"); + /* FALLTHROUGH */ +#endif + case SDP_MID_ABORT: + sdp_dbg_data(sk, "Handling ABORT\n"); + sdp_prf(sk, NULL, "Handling ABORT"); + sdp_notify(ssk, ECONNRESET); + m_freem(mb); + break; + case SDP_MID_DISCONN: + sdp_dbg_data(sk, "Handling DISCONN\n"); + sdp_prf(sk, NULL, "Handling DISCONN"); + sdp_handle_disconn(ssk); + break; + case SDP_MID_CHRCVBUF: + sdp_dbg_data(sk, "Handling RX CHRCVBUF\n"); + sdp_handle_resize_request(ssk, (struct sdp_chrecvbuf *)(h+1)); + m_freem(mb); + break; + case SDP_MID_CHRCVBUF_ACK: + sdp_dbg_data(sk, "Handling RX CHRCVBUF_ACK\n"); + sdp_handle_resize_ack(ssk, (struct sdp_chrecvbuf *)(h+1)); + m_freem(mb); + break; + default: + /* TODO: Handle other messages */ + sdp_warn(sk, "SDP: FIXME MID %d\n", h->mid); + m_freem(mb); + } + + return 0; +} + +static int +sdp_process_rx_mb(struct sdp_sock *ssk, struct mbuf *mb) +{ + struct socket *sk; + struct sdp_bsdh *h; + unsigned long mseq_ack; + int credits_before; + + h = mtod(mb, struct sdp_bsdh *); + sk = ssk->socket; + /* + * If another thread is in so_pcbfree this may be partially torn + * down but no further synchronization is required as the destroying + * thread will wait for receive to shutdown before discarding the + * socket. + */ + if (sk == NULL) { + m_freem(mb); + return 0; + } + + SDPSTATS_HIST_LINEAR(credits_before_update, tx_credits(ssk)); + + mseq_ack = ntohl(h->mseq_ack); + credits_before = tx_credits(ssk); + atomic_set(&ssk->tx_ring.credits, mseq_ack - ring_head(ssk->tx_ring) + + 1 + ntohs(h->bufs)); + if (mseq_ack >= ssk->nagle_last_unacked) + ssk->nagle_last_unacked = 0; + + sdp_prf1(ssk->socket, mb, "RX %s +%d c:%d->%d mseq:%d ack:%d\n", + mid2str(h->mid), ntohs(h->bufs), credits_before, + tx_credits(ssk), ntohl(h->mseq), ntohl(h->mseq_ack)); + + if (unlikely(h->mid == SDP_MID_DATA && + mb->m_pkthdr.len == SDP_HEAD_SIZE)) { + /* Credit update is valid even after RCV_SHUTDOWN */ + m_freem(mb); + return 0; + } + + if ((h->mid != SDP_MID_DATA && h->mid != SDP_MID_SRCAVAIL) || + TCPS_HAVERCVDFIN(ssk->state)) { + sdp_prf(sk, NULL, "Control mb - queing to control queue"); +#ifdef SDP_ZCOPY + if (h->mid == SDP_MID_SRCAVAIL_CANCEL) { + sdp_dbg_data(sk, "Got SrcAvailCancel. " + "seq: 0x%d seq_ack: 0x%d\n", + ntohl(h->mseq), ntohl(h->mseq_ack)); + ssk->srcavail_cancel_mseq = ntohl(h->mseq); + } + + + if (h->mid == SDP_MID_RDMARDCOMPL) { + struct sdp_rrch *rrch = (struct sdp_rrch *)(h+1); + sdp_dbg_data(sk, "RdmaRdCompl message arrived\n"); + sdp_handle_rdma_read_compl(ssk, ntohl(h->mseq_ack), + ntohl(rrch->len)); + } +#endif + mb->m_nextpkt = NULL; + if (ssk->rx_ctl_tail) + ssk->rx_ctl_tail->m_nextpkt = mb; + else + ssk->rx_ctl_q = mb; + ssk->rx_ctl_tail = mb; + + return 0; + } + + sdp_prf1(sk, NULL, "queueing %s mb\n", mid2str(h->mid)); + mb = sdp_sock_queue_rcv_mb(sk, mb); + + + return 0; +} + +/* called only from irq */ +static struct mbuf * +sdp_process_rx_wc(struct sdp_sock *ssk, struct ib_wc *wc) +{ + struct mbuf *mb; + struct sdp_bsdh *h; + struct socket *sk = ssk->socket; + int mseq; + + mb = sdp_recv_completion(ssk, wc->wr_id); + if (unlikely(!mb)) + return NULL; + + if (unlikely(wc->status)) { + if (ssk->qp_active && sk) { + sdp_dbg(sk, "Recv completion with error. " + "Status %d, vendor: %d\n", + wc->status, wc->vendor_err); + sdp_abort(sk); + ssk->qp_active = 0; + } + m_freem(mb); + return NULL; + } + + sdp_dbg_data(sk, "Recv completion. ID %d Length %d\n", + (int)wc->wr_id, wc->byte_len); + if (unlikely(wc->byte_len < sizeof(struct sdp_bsdh))) { + sdp_warn(sk, "SDP BUG! byte_len %d < %zd\n", + wc->byte_len, sizeof(struct sdp_bsdh)); + m_freem(mb); + return NULL; + } + /* Use m_adj to trim the tail of data we didn't use. */ + m_adj(mb, -(mb->m_pkthdr.len - wc->byte_len)); + h = mtod(mb, struct sdp_bsdh *); + + SDP_DUMP_PACKET(ssk->socket, "RX", mb, h); + + ssk->rx_packets++; + ssk->rx_bytes += mb->m_pkthdr.len; + + mseq = ntohl(h->mseq); + atomic_set(&ssk->mseq_ack, mseq); + if (mseq != (int)wc->wr_id) + sdp_warn(sk, "SDP BUG! mseq %d != wrid %d\n", + mseq, (int)wc->wr_id); + + return mb; +} + +/* Wakeup writers if we now have credits. */ +static void +sdp_bzcopy_write_space(struct sdp_sock *ssk) +{ + struct socket *sk = ssk->socket; + + if (tx_credits(ssk) >= ssk->min_bufs && sk) + sowwakeup(sk); +} + +/* only from interrupt. */ +static int +sdp_poll_rx_cq(struct sdp_sock *ssk) +{ + struct ib_cq *cq = ssk->rx_ring.cq; + struct ib_wc ibwc[SDP_NUM_WC]; + int n, i; + int wc_processed = 0; + struct mbuf *mb; + + do { + n = ib_poll_cq(cq, SDP_NUM_WC, ibwc); + for (i = 0; i < n; ++i) { + struct ib_wc *wc = &ibwc[i]; + + BUG_ON(!(wc->wr_id & SDP_OP_RECV)); + mb = sdp_process_rx_wc(ssk, wc); + if (!mb) + continue; + + sdp_process_rx_mb(ssk, mb); + wc_processed++; + } + } while (n == SDP_NUM_WC); + + if (wc_processed) + sdp_bzcopy_write_space(ssk); + + return wc_processed; +} + +static void +sdp_rx_comp_work(struct work_struct *work) +{ + struct sdp_sock *ssk = container_of(work, struct sdp_sock, + rx_comp_work); + + sdp_prf(ssk->socket, NULL, "%s", __func__); + + SDP_WLOCK(ssk); + if (unlikely(!ssk->qp)) { + sdp_prf(ssk->socket, NULL, "qp was destroyed"); + goto out; + } + if (unlikely(!ssk->rx_ring.cq)) { + sdp_prf(ssk->socket, NULL, "rx_ring.cq is NULL"); + goto out; + } + + if (unlikely(!ssk->poll_cq)) { + struct rdma_cm_id *id = ssk->id; + if (id && id->qp) + rdma_notify(id, RDMA_CM_EVENT_ESTABLISHED); + goto out; + } + + sdp_do_posts(ssk); +out: + SDP_WUNLOCK(ssk); +} + +void +sdp_do_posts(struct sdp_sock *ssk) +{ + struct socket *sk = ssk->socket; + int xmit_poll_force; + struct mbuf *mb; + + SDP_WLOCK_ASSERT(ssk); + if (!ssk->qp_active) { + sdp_dbg(sk, "QP is deactivated\n"); + return; + } + + while ((mb = ssk->rx_ctl_q)) { + ssk->rx_ctl_q = mb->m_nextpkt; + mb->m_nextpkt = NULL; + sdp_process_rx_ctl_mb(ssk, mb); + } + + if (ssk->state == TCPS_TIME_WAIT) + return; + + if (!ssk->rx_ring.cq || !ssk->tx_ring.cq) + return; + + sdp_post_recvs(ssk); + + if (tx_ring_posted(ssk)) + sdp_xmit_poll(ssk, 1); + + sdp_post_sends(ssk, M_NOWAIT); + + xmit_poll_force = tx_credits(ssk) < SDP_MIN_TX_CREDITS; + + if (credit_update_needed(ssk) || xmit_poll_force) { + /* if has pending tx because run out of tx_credits - xmit it */ + sdp_prf(sk, NULL, "Processing to free pending sends"); + sdp_xmit_poll(ssk, xmit_poll_force); + sdp_prf(sk, NULL, "Sending credit update"); + sdp_post_sends(ssk, M_NOWAIT); + } + +} + +int +sdp_process_rx(struct sdp_sock *ssk) +{ + int wc_processed = 0; + int credits_before; + + if (!rx_ring_trylock(&ssk->rx_ring)) { + sdp_dbg(ssk->socket, "ring destroyed. not polling it\n"); + return 0; + } + + credits_before = tx_credits(ssk); + + wc_processed = sdp_poll_rx_cq(ssk); + sdp_prf(ssk->socket, NULL, "processed %d", wc_processed); + + if (wc_processed) { + sdp_prf(ssk->socket, NULL, "credits: %d -> %d", + credits_before, tx_credits(ssk)); + queue_work(rx_comp_wq, &ssk->rx_comp_work); + } + sdp_arm_rx_cq(ssk); + + rx_ring_unlock(&ssk->rx_ring); + + return (wc_processed); +} + +static void +sdp_rx_irq(struct ib_cq *cq, void *cq_context) +{ + struct socket *sk = cq_context; + struct sdp_sock *ssk = sdp_sk(sk); + + if (cq != ssk->rx_ring.cq) { + sdp_dbg(sk, "cq = %p, ssk->cq = %p\n", cq, ssk->rx_ring.cq); + return; + } + + SDPSTATS_COUNTER_INC(rx_int_count); + + sdp_prf(sk, NULL, "rx irq"); + + sdp_process_rx(ssk); +} + +static +void sdp_rx_ring_purge(struct sdp_sock *ssk) +{ + while (rx_ring_posted(ssk) > 0) { + struct mbuf *mb; + mb = sdp_recv_completion(ssk, ring_tail(ssk->rx_ring)); + if (!mb) + break; + m_freem(mb); + } +} + +void +sdp_rx_ring_init(struct sdp_sock *ssk) +{ + ssk->rx_ring.buffer = NULL; + ssk->rx_ring.destroyed = 0; + rw_init(&ssk->rx_ring.destroyed_lock, "sdp rx lock"); +} + +static void +sdp_rx_cq_event_handler(struct ib_event *event, void *data) +{ +} + +int +sdp_rx_ring_create(struct sdp_sock *ssk, struct ib_device *device) +{ + struct ib_cq *rx_cq; + int rc = 0; + + + sdp_dbg(ssk->socket, "rx ring created"); + INIT_WORK(&ssk->rx_comp_work, sdp_rx_comp_work); + atomic_set(&ssk->rx_ring.head, 1); + atomic_set(&ssk->rx_ring.tail, 1); + + ssk->rx_ring.buffer = kmalloc( + sizeof *ssk->rx_ring.buffer * SDP_RX_SIZE, GFP_KERNEL); + if (!ssk->rx_ring.buffer) { + sdp_warn(ssk->socket, + "Unable to allocate RX Ring size %zd.\n", + sizeof(*ssk->rx_ring.buffer) * SDP_RX_SIZE); + + return -ENOMEM; + } + + rx_cq = ib_create_cq(device, sdp_rx_irq, sdp_rx_cq_event_handler, + ssk->socket, SDP_RX_SIZE, IB_CQ_VECTOR_LEAST_ATTACHED); + + if (IS_ERR(rx_cq)) { + rc = PTR_ERR(rx_cq); + sdp_warn(ssk->socket, "Unable to allocate RX CQ: %d.\n", rc); + goto err_cq; + } + + sdp_sk(ssk->socket)->rx_ring.cq = rx_cq; + sdp_arm_rx_cq(ssk); + + return 0; + +err_cq: + kfree(ssk->rx_ring.buffer); + ssk->rx_ring.buffer = NULL; + return rc; +} + +void +sdp_rx_ring_destroy(struct sdp_sock *ssk) +{ + + cancel_work_sync(&ssk->rx_comp_work); + rx_ring_destroy_lock(&ssk->rx_ring); + + if (ssk->rx_ring.buffer) { + sdp_rx_ring_purge(ssk); + + kfree(ssk->rx_ring.buffer); + ssk->rx_ring.buffer = NULL; + } + + if (ssk->rx_ring.cq) { + if (ib_destroy_cq(ssk->rx_ring.cq)) { + sdp_warn(ssk->socket, "destroy cq(%p) failed\n", + ssk->rx_ring.cq); + } else { + ssk->rx_ring.cq = NULL; + } + } + + WARN_ON(ring_head(ssk->rx_ring) != ring_tail(ssk->rx_ring)); +} diff --git a/sys/ofed/drivers/infiniband/ulp/sdp/sdp_tx.c b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_tx.c new file mode 100644 index 000000000000..b0c37e554e13 --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_tx.c @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2009 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "sdp.h" + +#define sdp_cnt(var) do { (var)++; } while (0) + +SDP_MODPARAM_SINT(sdp_keepalive_probes_sent, 0, + "Total number of keepalive probes sent."); + +static int sdp_process_tx_cq(struct sdp_sock *ssk); +static void sdp_poll_tx_timeout(void *data); + +int +sdp_xmit_poll(struct sdp_sock *ssk, int force) +{ + int wc_processed = 0; + + SDP_WLOCK_ASSERT(ssk); + sdp_prf(ssk->socket, NULL, "%s", __func__); + + /* If we don't have a pending timer, set one up to catch our recent + post in case the interface becomes idle */ + if (!callout_pending(&ssk->tx_ring.timer)) + callout_reset(&ssk->tx_ring.timer, SDP_TX_POLL_TIMEOUT, + sdp_poll_tx_timeout, ssk); + + /* Poll the CQ every SDP_TX_POLL_MODER packets */ + if (force || (++ssk->tx_ring.poll_cnt & (SDP_TX_POLL_MODER - 1)) == 0) + wc_processed = sdp_process_tx_cq(ssk); + + return wc_processed; +} + +void +sdp_post_send(struct sdp_sock *ssk, struct mbuf *mb) +{ + struct sdp_buf *tx_req; + struct sdp_bsdh *h; + unsigned long mseq; + struct ib_device *dev; + struct ib_send_wr *bad_wr; + struct ib_sge ibsge[SDP_MAX_SEND_SGES]; + struct ib_sge *sge; + struct ib_send_wr tx_wr = { NULL }; + int i, rc; + u64 addr; + + SDPSTATS_COUNTER_MID_INC(post_send, h->mid); + SDPSTATS_HIST(send_size, mb->len); + + if (!ssk->qp_active) { + m_freem(mb); + return; + } + + mseq = ring_head(ssk->tx_ring); + h = mtod(mb, struct sdp_bsdh *); + ssk->tx_packets++; + ssk->tx_bytes += mb->m_pkthdr.len; + +#ifdef SDP_ZCOPY + if (unlikely(h->mid == SDP_MID_SRCAVAIL)) { + struct tx_srcavail_state *tx_sa = TX_SRCAVAIL_STATE(mb); + if (ssk->tx_sa != tx_sa) { + sdp_dbg_data(ssk->socket, "SrcAvail cancelled " + "before being sent!\n"); + WARN_ON(1); + m_freem(mb); + return; + } + TX_SRCAVAIL_STATE(mb)->mseq = mseq; + } +#endif + + if (unlikely(mb->m_flags & M_URG)) + h->flags = SDP_OOB_PRES | SDP_OOB_PEND; + else + h->flags = 0; + + mb->m_flags |= M_RDONLY; /* Don't allow compression once sent. */ + h->bufs = htons(rx_ring_posted(ssk)); + h->len = htonl(mb->m_pkthdr.len); + h->mseq = htonl(mseq); + h->mseq_ack = htonl(mseq_ack(ssk)); + + sdp_prf1(ssk->socket, mb, "TX: %s bufs: %d mseq:%ld ack:%d", + mid2str(h->mid), rx_ring_posted(ssk), mseq, + ntohl(h->mseq_ack)); + + SDP_DUMP_PACKET(ssk->socket, "TX", mb, h); + + tx_req = &ssk->tx_ring.buffer[mseq & (SDP_TX_SIZE - 1)]; + tx_req->mb = mb; + dev = ssk->ib_device; + sge = &ibsge[0]; + for (i = 0; mb != NULL; i++, mb = mb->m_next, sge++) { + addr = ib_dma_map_single(dev, mb->m_data, mb->m_len, + DMA_TO_DEVICE); + /* TODO: proper error handling */ + BUG_ON(ib_dma_mapping_error(dev, addr)); + BUG_ON(i >= SDP_MAX_SEND_SGES); + tx_req->mapping[i] = addr; + sge->addr = addr; + sge->length = mb->m_len; + sge->lkey = ssk->sdp_dev->mr->lkey; + } + tx_wr.next = NULL; + tx_wr.wr_id = mseq | SDP_OP_SEND; + tx_wr.sg_list = ibsge; + tx_wr.num_sge = i; + tx_wr.opcode = IB_WR_SEND; + tx_wr.send_flags = IB_SEND_SIGNALED; + if (unlikely(tx_req->mb->m_flags & M_URG)) + tx_wr.send_flags |= IB_SEND_SOLICITED; + + rc = ib_post_send(ssk->qp, &tx_wr, &bad_wr); + if (unlikely(rc)) { + sdp_dbg(ssk->socket, + "ib_post_send failed with status %d.\n", rc); + + sdp_cleanup_sdp_buf(ssk, tx_req, DMA_TO_DEVICE); + + sdp_notify(ssk, ECONNRESET); + m_freem(tx_req->mb); + return; + } + + atomic_inc(&ssk->tx_ring.head); + atomic_dec(&ssk->tx_ring.credits); + atomic_set(&ssk->remote_credits, rx_ring_posted(ssk)); + + return; +} + +static struct mbuf * +sdp_send_completion(struct sdp_sock *ssk, int mseq) +{ + struct ib_device *dev; + struct sdp_buf *tx_req; + struct mbuf *mb = NULL; + struct sdp_tx_ring *tx_ring = &ssk->tx_ring; + + if (unlikely(mseq != ring_tail(*tx_ring))) { + printk(KERN_WARNING "Bogus send completion id %d tail %d\n", + mseq, ring_tail(*tx_ring)); + goto out; + } + + dev = ssk->ib_device; + tx_req = &tx_ring->buffer[mseq & (SDP_TX_SIZE - 1)]; + mb = tx_req->mb; + sdp_cleanup_sdp_buf(ssk, tx_req, DMA_TO_DEVICE); + +#ifdef SDP_ZCOPY + /* TODO: AIO and real zcopy code; add their context support here */ + if (BZCOPY_STATE(mb)) + BZCOPY_STATE(mb)->busy--; +#endif + + atomic_inc(&tx_ring->tail); + +out: + return mb; +} + +static int +sdp_handle_send_comp(struct sdp_sock *ssk, struct ib_wc *wc) +{ + struct mbuf *mb = NULL; + struct sdp_bsdh *h; + + if (unlikely(wc->status)) { + if (wc->status != IB_WC_WR_FLUSH_ERR) { + sdp_prf(ssk->socket, mb, "Send completion with error. " + "Status %d", wc->status); + sdp_dbg_data(ssk->socket, "Send completion with error. " + "Status %d\n", wc->status); + sdp_notify(ssk, ECONNRESET); + } + } + + mb = sdp_send_completion(ssk, wc->wr_id); + if (unlikely(!mb)) + return -1; + + h = mtod(mb, struct sdp_bsdh *); + sdp_prf1(ssk->socket, mb, "tx completion. mseq:%d", ntohl(h->mseq)); + sdp_dbg(ssk->socket, "tx completion. %p %d mseq:%d", + mb, mb->m_pkthdr.len, ntohl(h->mseq)); + m_freem(mb); + + return 0; +} + +static inline void +sdp_process_tx_wc(struct sdp_sock *ssk, struct ib_wc *wc) +{ + + if (likely(wc->wr_id & SDP_OP_SEND)) { + sdp_handle_send_comp(ssk, wc); + return; + } + +#ifdef SDP_ZCOPY + if (wc->wr_id & SDP_OP_RDMA) { + /* TODO: handle failed RDMA read cqe */ + + sdp_dbg_data(ssk->socket, + "TX comp: RDMA read. status: %d\n", wc->status); + sdp_prf1(sk, NULL, "TX comp: RDMA read"); + + if (!ssk->tx_ring.rdma_inflight) { + sdp_warn(ssk->socket, "ERROR: unexpected RDMA read\n"); + return; + } + + if (!ssk->tx_ring.rdma_inflight->busy) { + sdp_warn(ssk->socket, + "ERROR: too many RDMA read completions\n"); + return; + } + + /* Only last RDMA read WR is signalled. Order is guaranteed - + * therefore if Last RDMA read WR is completed - all other + * have, too */ + ssk->tx_ring.rdma_inflight->busy = 0; + sowwakeup(ssk->socket); + sdp_dbg_data(ssk->socket, "woke up sleepers\n"); + return; + } +#endif + + /* Keepalive probe sent cleanup */ + sdp_cnt(sdp_keepalive_probes_sent); + + if (likely(!wc->status)) + return; + + sdp_dbg(ssk->socket, " %s consumes KEEPALIVE status %d\n", + __func__, wc->status); + + if (wc->status == IB_WC_WR_FLUSH_ERR) + return; + + sdp_notify(ssk, ECONNRESET); +} + +static int +sdp_process_tx_cq(struct sdp_sock *ssk) +{ + struct ib_wc ibwc[SDP_NUM_WC]; + int n, i; + int wc_processed = 0; + + SDP_WLOCK_ASSERT(ssk); + + if (!ssk->tx_ring.cq) { + sdp_dbg(ssk->socket, "tx irq on destroyed tx_cq\n"); + return 0; + } + + do { + n = ib_poll_cq(ssk->tx_ring.cq, SDP_NUM_WC, ibwc); + for (i = 0; i < n; ++i) { + sdp_process_tx_wc(ssk, ibwc + i); + wc_processed++; + } + } while (n == SDP_NUM_WC); + + if (wc_processed) { + sdp_post_sends(ssk, M_DONTWAIT); + sdp_prf1(sk, NULL, "Waking sendmsg. inflight=%d", + (u32) tx_ring_posted(ssk)); + sowwakeup(ssk->socket); + } + + return wc_processed; +} + +static void +sdp_poll_tx(struct sdp_sock *ssk) +{ + struct socket *sk = ssk->socket; + u32 inflight, wc_processed; + + sdp_prf1(ssk->socket, NULL, "TX timeout: inflight=%d, head=%d tail=%d", + (u32) tx_ring_posted(ssk), + ring_head(ssk->tx_ring), ring_tail(ssk->tx_ring)); + + if (unlikely(ssk->state == TCPS_CLOSED)) { + sdp_warn(sk, "Socket is closed\n"); + goto out; + } + + wc_processed = sdp_process_tx_cq(ssk); + if (!wc_processed) + SDPSTATS_COUNTER_INC(tx_poll_miss); + else + SDPSTATS_COUNTER_INC(tx_poll_hit); + + inflight = (u32) tx_ring_posted(ssk); + sdp_prf1(ssk->socket, NULL, "finished tx proccessing. inflight = %d", + inflight); + + /* If there are still packets in flight and the timer has not already + * been scheduled by the Tx routine then schedule it here to guarantee + * completion processing of these packets */ + if (inflight) + callout_reset(&ssk->tx_ring.timer, SDP_TX_POLL_TIMEOUT, + sdp_poll_tx_timeout, ssk); +out: +#ifdef SDP_ZCOPY + if (ssk->tx_ring.rdma_inflight && ssk->tx_ring.rdma_inflight->busy) { + sdp_prf1(sk, NULL, "RDMA is inflight - arming irq"); + sdp_arm_tx_cq(ssk); + } +#endif + return; +} + +static void +sdp_poll_tx_timeout(void *data) +{ + struct sdp_sock *ssk = (struct sdp_sock *)data; + + if (!callout_active(&ssk->tx_ring.timer)) + return; + callout_deactivate(&ssk->tx_ring.timer); + sdp_poll_tx(ssk); +} + +static void +sdp_tx_irq(struct ib_cq *cq, void *cq_context) +{ + struct sdp_sock *ssk; + + ssk = cq_context; + sdp_prf1(ssk->socket, NULL, "tx irq"); + sdp_dbg_data(ssk->socket, "Got tx comp interrupt\n"); + SDPSTATS_COUNTER_INC(tx_int_count); + SDP_WLOCK(ssk); + sdp_poll_tx(ssk); + SDP_WUNLOCK(ssk); +} + +static +void sdp_tx_ring_purge(struct sdp_sock *ssk) +{ + while (tx_ring_posted(ssk)) { + struct mbuf *mb; + mb = sdp_send_completion(ssk, ring_tail(ssk->tx_ring)); + if (!mb) + break; + m_freem(mb); + } +} + +void +sdp_post_keepalive(struct sdp_sock *ssk) +{ + int rc; + struct ib_send_wr wr, *bad_wr; + + sdp_dbg(ssk->socket, "%s\n", __func__); + + memset(&wr, 0, sizeof(wr)); + + wr.next = NULL; + wr.wr_id = 0; + wr.sg_list = NULL; + wr.num_sge = 0; + wr.opcode = IB_WR_RDMA_WRITE; + + rc = ib_post_send(ssk->qp, &wr, &bad_wr); + if (rc) { + sdp_dbg(ssk->socket, + "ib_post_keepalive failed with status %d.\n", rc); + sdp_notify(ssk, ECONNRESET); + } + + sdp_cnt(sdp_keepalive_probes_sent); +} + +static void +sdp_tx_cq_event_handler(struct ib_event *event, void *data) +{ +} + +int +sdp_tx_ring_create(struct sdp_sock *ssk, struct ib_device *device) +{ + struct ib_cq *tx_cq; + int rc = 0; + + sdp_dbg(ssk->socket, "tx ring create\n"); + callout_init_rw(&ssk->tx_ring.timer, &ssk->lock, 0); + callout_init_rw(&ssk->nagle_timer, &ssk->lock, 0); + atomic_set(&ssk->tx_ring.head, 1); + atomic_set(&ssk->tx_ring.tail, 1); + + ssk->tx_ring.buffer = kzalloc( + sizeof *ssk->tx_ring.buffer * SDP_TX_SIZE, GFP_KERNEL); + if (!ssk->tx_ring.buffer) { + rc = -ENOMEM; + sdp_warn(ssk->socket, "Can't allocate TX Ring size %zd.\n", + sizeof(*ssk->tx_ring.buffer) * SDP_TX_SIZE); + + goto out; + } + + tx_cq = ib_create_cq(device, sdp_tx_irq, sdp_tx_cq_event_handler, + ssk, SDP_TX_SIZE, IB_CQ_VECTOR_LEAST_ATTACHED); + + if (IS_ERR(tx_cq)) { + rc = PTR_ERR(tx_cq); + sdp_warn(ssk->socket, "Unable to allocate TX CQ: %d.\n", rc); + goto err_cq; + } + ssk->tx_ring.cq = tx_cq; + ssk->tx_ring.poll_cnt = 0; + sdp_arm_tx_cq(ssk); + + return 0; + +err_cq: + kfree(ssk->tx_ring.buffer); + ssk->tx_ring.buffer = NULL; +out: + return rc; +} + +void +sdp_tx_ring_destroy(struct sdp_sock *ssk) +{ + + sdp_dbg(ssk->socket, "tx ring destroy\n"); + SDP_WLOCK(ssk); + callout_stop(&ssk->tx_ring.timer); + callout_stop(&ssk->nagle_timer); + SDP_WUNLOCK(ssk); + callout_drain(&ssk->tx_ring.timer); + callout_drain(&ssk->nagle_timer); + + if (ssk->tx_ring.buffer) { + sdp_tx_ring_purge(ssk); + + kfree(ssk->tx_ring.buffer); + ssk->tx_ring.buffer = NULL; + } + + if (ssk->tx_ring.cq) { + if (ib_destroy_cq(ssk->tx_ring.cq)) { + sdp_warn(ssk->socket, "destroy cq(%p) failed\n", + ssk->tx_ring.cq); + } else { + ssk->tx_ring.cq = NULL; + } + } + + WARN_ON(ring_head(ssk->tx_ring) != ring_tail(ssk->tx_ring)); +} diff --git a/sys/ofed/drivers/infiniband/ulp/sdp/sdp_zcopy.c b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_zcopy.c new file mode 100644 index 000000000000..0425f8e98bbc --- /dev/null +++ b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_zcopy.c @@ -0,0 +1,804 @@ +/* + * Copyright (c) 2006 Mellanox Technologies Ltd. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for memcpy_toiovec */ +#include +#include +#include +#include "sdp.h" + +static int sdp_post_srcavail(struct socket *sk, struct tx_srcavail_state *tx_sa) +{ + struct sdp_sock *ssk = sdp_sk(sk); + struct mbuf *mb; + int payload_len; + struct page *payload_pg; + int off, len; + struct ib_umem_chunk *chunk; + + WARN_ON(ssk->tx_sa); + + BUG_ON(!tx_sa); + BUG_ON(!tx_sa->fmr || !tx_sa->fmr->fmr->lkey); + BUG_ON(!tx_sa->umem); + BUG_ON(!tx_sa->umem->chunk_list.next); + + chunk = list_entry(tx_sa->umem->chunk_list.next, struct ib_umem_chunk, list); + BUG_ON(!chunk->nmap); + + off = tx_sa->umem->offset; + len = tx_sa->umem->length; + + tx_sa->bytes_sent = tx_sa->bytes_acked = 0; + + mb = sdp_alloc_mb_srcavail(sk, len, tx_sa->fmr->fmr->lkey, off, 0); + if (!mb) { + return -ENOMEM; + } + sdp_dbg_data(sk, "sending SrcAvail\n"); + + TX_SRCAVAIL_STATE(mb) = tx_sa; /* tx_sa is hanged on the mb + * but continue to live after mb is freed */ + ssk->tx_sa = tx_sa; + + /* must have payload inlined in SrcAvail packet in combined mode */ + payload_len = MIN(tx_sa->umem->page_size - off, len); + payload_len = MIN(payload_len, ssk->xmit_size_goal - sizeof(struct sdp_srcah)); + payload_pg = sg_page(&chunk->page_list[0]); + get_page(payload_pg); + + sdp_dbg_data(sk, "payload: off: 0x%x, pg: %p, len: 0x%x\n", + off, payload_pg, payload_len); + + mb_fill_page_desc(mb, mb_shinfo(mb)->nr_frags, + payload_pg, off, payload_len); + + mb->len += payload_len; + mb->data_len = payload_len; + mb->truesize += payload_len; +// sk->sk_wmem_queued += payload_len; +// sk->sk_forward_alloc -= payload_len; + + mb_entail(sk, ssk, mb); + + ssk->write_seq += payload_len; + SDP_SKB_CB(mb)->end_seq += payload_len; + + tx_sa->bytes_sent = tx_sa->umem->length; + tx_sa->bytes_acked = payload_len; + + /* TODO: pushing the mb into the tx_queue should be enough */ + + return 0; +} + +static int sdp_post_srcavail_cancel(struct socket *sk) +{ + struct sdp_sock *ssk = sdp_sk(sk); + struct mbuf *mb; + + sdp_dbg_data(ssk->socket, "Posting srcavail cancel\n"); + + mb = sdp_alloc_mb_srcavail_cancel(sk, 0); + mb_entail(sk, ssk, mb); + + sdp_post_sends(ssk, 0); + + schedule_delayed_work(&ssk->srcavail_cancel_work, + SDP_SRCAVAIL_CANCEL_TIMEOUT); + + return 0; +} + +void srcavail_cancel_timeout(struct work_struct *work) +{ + struct sdp_sock *ssk = + container_of(work, struct sdp_sock, srcavail_cancel_work.work); + struct socket *sk = ssk->socket; + + lock_sock(sk); + + sdp_dbg_data(sk, "both SrcAvail and SrcAvailCancel timedout." + " closing connection\n"); + sdp_set_error(sk, -ECONNRESET); + wake_up(&ssk->wq); + + release_sock(sk); +} + +static int sdp_wait_rdmardcompl(struct sdp_sock *ssk, long *timeo_p, + int ignore_signals) +{ + struct socket *sk = ssk->socket; + int err = 0; + long vm_wait = 0; + long current_timeo = *timeo_p; + struct tx_srcavail_state *tx_sa = ssk->tx_sa; + DEFINE_WAIT(wait); + + sdp_dbg_data(sk, "sleep till RdmaRdCompl. timeo = %ld.\n", *timeo_p); + sdp_prf1(sk, NULL, "Going to sleep"); + while (ssk->qp_active) { + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); + + if (unlikely(!*timeo_p)) { + err = -ETIME; + tx_sa->abort_flags |= TX_SA_TIMEDOUT; + sdp_prf1(sk, NULL, "timeout"); + SDPSTATS_COUNTER_INC(zcopy_tx_timeout); + break; + } + + else if (tx_sa->bytes_acked > tx_sa->bytes_sent) { + err = -EINVAL; + sdp_dbg_data(sk, "acked bytes > sent bytes\n"); + tx_sa->abort_flags |= TX_SA_ERROR; + break; + } + + if (tx_sa->abort_flags & TX_SA_SENDSM) { + sdp_prf1(sk, NULL, "Aborting SrcAvail sending"); + SDPSTATS_COUNTER_INC(zcopy_tx_aborted); + err = -EAGAIN; + break ; + } + + if (!ignore_signals) { + if (signal_pending(current)) { + err = -EINTR; + sdp_prf1(sk, NULL, "signalled"); + tx_sa->abort_flags |= TX_SA_INTRRUPTED; + break; + } + + if (ssk->rx_sa && (tx_sa->bytes_acked < tx_sa->bytes_sent)) { + sdp_dbg_data(sk, "Crossing SrcAvail - aborting this\n"); + tx_sa->abort_flags |= TX_SA_CROSS_SEND; + SDPSTATS_COUNTER_INC(zcopy_cross_send); + err = -ETIME; + break ; + } + } + + posts_handler_put(ssk); + + sk_wait_event(sk, ¤t_timeo, + tx_sa->abort_flags && + ssk->rx_sa && + (tx_sa->bytes_acked < tx_sa->bytes_sent) && + vm_wait); + sdp_dbg_data(ssk->socket, "woke up sleepers\n"); + + posts_handler_get(ssk); + + if (tx_sa->bytes_acked == tx_sa->bytes_sent) + break; + + if (vm_wait) { + vm_wait -= current_timeo; + current_timeo = *timeo_p; + if (current_timeo != MAX_SCHEDULE_TIMEOUT && + (current_timeo -= vm_wait) < 0) + current_timeo = 0; + vm_wait = 0; + } + *timeo_p = current_timeo; + } + + finish_wait(sk->sk_sleep, &wait); + + sdp_dbg_data(sk, "Finished waiting - RdmaRdCompl: %d/%d bytes, flags: 0x%x\n", + tx_sa->bytes_acked, tx_sa->bytes_sent, tx_sa->abort_flags); + + if (!ssk->qp_active) { + sdp_dbg(sk, "QP destroyed while waiting\n"); + return -EINVAL; + } + return err; +} + +static void sdp_wait_rdma_wr_finished(struct sdp_sock *ssk) +{ + struct socket *sk = ssk->socket; + long timeo = HZ * 5; /* Timeout for for RDMA read */ + DEFINE_WAIT(wait); + + sdp_dbg_data(sk, "Sleep till RDMA wr finished.\n"); + while (1) { + prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE); + + if (!ssk->tx_ring.rdma_inflight->busy) { + sdp_dbg_data(sk, "got rdma cqe\n"); + break; + } + + if (!ssk->qp_active) { + sdp_dbg_data(sk, "QP destroyed\n"); + break; + } + + if (!timeo) { + sdp_warn(sk, "Panic: Timed out waiting for RDMA read\n"); + WARN_ON(1); + break; + } + + posts_handler_put(ssk); + + sdp_prf1(sk, NULL, "Going to sleep"); + sk_wait_event(sk, &timeo, + !ssk->tx_ring.rdma_inflight->busy); + sdp_prf1(sk, NULL, "Woke up"); + sdp_dbg_data(ssk->socket, "woke up sleepers\n"); + + posts_handler_get(ssk); + } + + finish_wait(sk->sk_sleep, &wait); + + sdp_dbg_data(sk, "Finished waiting\n"); +} + +int sdp_post_rdma_rd_compl(struct sdp_sock *ssk, + struct rx_srcavail_state *rx_sa) +{ + struct mbuf *mb; + int copied = rx_sa->used - rx_sa->reported; + + if (rx_sa->used <= rx_sa->reported) + return 0; + + mb = sdp_alloc_mb_rdmardcompl(ssk->socket, copied, 0); + + rx_sa->reported += copied; + + /* TODO: What if no tx_credits available? */ + sdp_post_send(ssk, mb); + + return 0; +} + +int sdp_post_sendsm(struct socket *sk) +{ + struct mbuf *mb = sdp_alloc_mb_sendsm(sk, 0); + + sdp_post_send(sdp_sk(sk), mb); + + return 0; +} + +static int sdp_update_iov_used(struct socket *sk, struct iovec *iov, int len) +{ + sdp_dbg_data(sk, "updating consumed 0x%x bytes from iov\n", len); + while (len > 0) { + if (iov->iov_len) { + int copy = min_t(unsigned int, iov->iov_len, len); + len -= copy; + iov->iov_len -= copy; + iov->iov_base += copy; + } + iov++; + } + + return 0; +} + +static inline int sge_bytes(struct ib_sge *sge, int sge_cnt) +{ + int bytes = 0; + + while (sge_cnt > 0) { + bytes += sge->length; + sge++; + sge_cnt--; + } + + return bytes; +} +void sdp_handle_sendsm(struct sdp_sock *ssk, u32 mseq_ack) +{ + struct socket *sk = ssk->socket; + unsigned long flags; + + spin_lock_irqsave(&ssk->tx_sa_lock, flags); + + if (!ssk->tx_sa) { + sdp_prf1(sk, NULL, "SendSM for cancelled/finished SrcAvail"); + goto out; + } + + if (ssk->tx_sa->mseq > mseq_ack) { + sdp_dbg_data(sk, "SendSM arrived for old SrcAvail. " + "SendSM mseq_ack: 0x%x, SrcAvail mseq: 0x%x\n", + mseq_ack, ssk->tx_sa->mseq); + goto out; + } + + sdp_dbg_data(sk, "Got SendSM - aborting SrcAvail\n"); + + ssk->tx_sa->abort_flags |= TX_SA_SENDSM; + cancel_delayed_work(&ssk->srcavail_cancel_work); + + wake_up(sk->sk_sleep); + sdp_dbg_data(sk, "woke up sleepers\n"); + +out: + spin_unlock_irqrestore(&ssk->tx_sa_lock, flags); +} + +void sdp_handle_rdma_read_compl(struct sdp_sock *ssk, u32 mseq_ack, + u32 bytes_completed) +{ + struct socket *sk = ssk->socket; + unsigned long flags; + + sdp_prf1(sk, NULL, "RdmaRdCompl ssk=%p tx_sa=%p", ssk, ssk->tx_sa); + sdp_dbg_data(sk, "RdmaRdCompl ssk=%p tx_sa=%p\n", ssk, ssk->tx_sa); + + spin_lock_irqsave(&ssk->tx_sa_lock, flags); + + BUG_ON(!ssk); + + if (!ssk->tx_sa) { + sdp_dbg_data(sk, "Got RdmaRdCompl for aborted SrcAvail\n"); + goto out; + } + + if (ssk->tx_sa->mseq > mseq_ack) { + sdp_dbg_data(sk, "RdmaRdCompl arrived for old SrcAvail. " + "SendSM mseq_ack: 0x%x, SrcAvail mseq: 0x%x\n", + mseq_ack, ssk->tx_sa->mseq); + goto out; + } + + ssk->tx_sa->bytes_acked += bytes_completed; + + wake_up(sk->sk_sleep); + sdp_dbg_data(sk, "woke up sleepers\n"); + +out: + spin_unlock_irqrestore(&ssk->tx_sa_lock, flags); + return; +} + +static unsigned long sdp_get_max_memlockable_bytes(unsigned long offset) +{ + unsigned long avail; + unsigned long lock_limit; + + if (capable(CAP_IPC_LOCK)) + return ULONG_MAX; + + lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; + avail = lock_limit - (current->mm->locked_vm << PAGE_SHIFT); + + return avail - offset; +} + +static int sdp_alloc_fmr(struct socket *sk, void *uaddr, size_t len, + struct ib_pool_fmr **_fmr, struct ib_umem **_umem) +{ + struct ib_pool_fmr *fmr; + struct ib_umem *umem; + struct ib_device *dev; + u64 *pages; + struct ib_umem_chunk *chunk; + int n, j, k; + int rc = 0; + unsigned long max_lockable_bytes; + + if (unlikely(len > SDP_MAX_RDMA_READ_LEN)) { + sdp_dbg_data(sk, "len:0x%lx > FMR_SIZE: 0x%lx\n", + len, SDP_MAX_RDMA_READ_LEN); + len = SDP_MAX_RDMA_READ_LEN; + } + + max_lockable_bytes = sdp_get_max_memlockable_bytes((unsigned long)uaddr & ~PAGE_MASK); + if (unlikely(len > max_lockable_bytes)) { + sdp_dbg_data(sk, "len:0x%lx > RLIMIT_MEMLOCK available: 0x%lx\n", + len, max_lockable_bytes); + len = max_lockable_bytes; + } + + sdp_dbg_data(sk, "user buf: %p, len:0x%lx max_lockable_bytes: 0x%lx\n", + uaddr, len, max_lockable_bytes); + + umem = ib_umem_get(&sdp_sk(sk)->context, (unsigned long)uaddr, len, + IB_ACCESS_REMOTE_WRITE, 0); + + if (IS_ERR(umem)) { + rc = PTR_ERR(umem); + sdp_warn(sk, "Error doing umem_get 0x%lx bytes: %d\n", len, rc); + sdp_warn(sk, "RLIMIT_MEMLOCK: 0x%lx[cur] 0x%lx[max] CAP_IPC_LOCK: %d\n", + current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur, + current->signal->rlim[RLIMIT_MEMLOCK].rlim_max, + capable(CAP_IPC_LOCK)); + goto err_umem_get; + } + + sdp_dbg_data(sk, "umem->offset = 0x%x, length = 0x%lx\n", + umem->offset, umem->length); + + pages = (u64 *) __get_free_page(GFP_KERNEL); + if (!pages) + goto err_pages_alloc; + + n = 0; + + dev = sdp_sk(sk)->ib_device; + list_for_each_entry(chunk, &umem->chunk_list, list) { + for (j = 0; j < chunk->nmap; ++j) { + len = ib_sg_dma_len(dev, + &chunk->page_list[j]) >> PAGE_SHIFT; + + for (k = 0; k < len; ++k) { + pages[n++] = ib_sg_dma_address(dev, + &chunk->page_list[j]) + + umem->page_size * k; + + } + } + } + + fmr = ib_fmr_pool_map_phys(sdp_sk(sk)->sdp_dev->fmr_pool, pages, n, 0); + if (IS_ERR(fmr)) { + sdp_warn(sk, "Error allocating fmr: %ld\n", PTR_ERR(fmr)); + goto err_fmr_alloc; + } + + free_page((unsigned long) pages); + + *_umem = umem; + *_fmr = fmr; + + return 0; + +err_fmr_alloc: + free_page((unsigned long) pages); + +err_pages_alloc: + ib_umem_release(umem); + +err_umem_get: + + return rc; +} + +void sdp_free_fmr(struct socket *sk, struct ib_pool_fmr **_fmr, struct ib_umem **_umem) +{ + if (!sdp_sk(sk)->qp_active) + return; + + ib_fmr_pool_unmap(*_fmr); + *_fmr = NULL; + + ib_umem_release(*_umem); + *_umem = NULL; +} + +static int sdp_post_rdma_read(struct socket *sk, struct rx_srcavail_state *rx_sa) +{ + struct sdp_sock *ssk = sdp_sk(sk); + struct ib_send_wr *bad_wr; + struct ib_send_wr wr = { NULL }; + struct ib_sge sge; + + wr.opcode = IB_WR_RDMA_READ; + wr.next = NULL; + wr.wr_id = SDP_OP_RDMA; + wr.wr.rdma.rkey = rx_sa->rkey; + wr.send_flags = 0; + + ssk->tx_ring.rdma_inflight = rx_sa; + + sge.addr = rx_sa->umem->offset; + sge.length = rx_sa->umem->length; + sge.lkey = rx_sa->fmr->fmr->lkey; + + wr.wr.rdma.remote_addr = rx_sa->vaddr + rx_sa->used; + wr.num_sge = 1; + wr.sg_list = &sge; + rx_sa->busy++; + + wr.send_flags = IB_SEND_SIGNALED; + + return ib_post_send(ssk->qp, &wr, &bad_wr); +} + +int sdp_rdma_to_iovec(struct socket *sk, struct iovec *iov, struct mbuf *mb, + unsigned long *used) +{ + struct sdp_sock *ssk = sdp_sk(sk); + struct rx_srcavail_state *rx_sa = RX_SRCAVAIL_STATE(mb); + int got_srcavail_cancel; + int rc = 0; + int len = *used; + int copied; + + sdp_dbg_data(ssk->socket, "preparing RDMA read." + " len: 0x%x. buffer len: 0x%lx\n", len, iov->iov_len); + + sock_hold(sk, SOCK_REF_RDMA_RD); + + if (len > rx_sa->len) { + sdp_warn(sk, "len:0x%x > rx_sa->len: 0x%x\n", len, rx_sa->len); + WARN_ON(1); + len = rx_sa->len; + } + + rc = sdp_alloc_fmr(sk, iov->iov_base, len, &rx_sa->fmr, &rx_sa->umem); + if (rc) { + sdp_warn(sk, "Error allocating fmr: %d\n", rc); + goto err_alloc_fmr; + } + + rc = sdp_post_rdma_read(sk, rx_sa); + if (unlikely(rc)) { + sdp_warn(sk, "ib_post_send failed with status %d.\n", rc); + sdp_set_error(ssk->socket, -ECONNRESET); + wake_up(&ssk->wq); + goto err_post_send; + } + + sdp_prf(sk, mb, "Finished posting(rc=%d), now to wait", rc); + + got_srcavail_cancel = ssk->srcavail_cancel_mseq > rx_sa->mseq; + + sdp_arm_tx_cq(sk); + + sdp_wait_rdma_wr_finished(ssk); + + sdp_prf(sk, mb, "Finished waiting(rc=%d)", rc); + if (!ssk->qp_active) { + sdp_dbg_data(sk, "QP destroyed during RDMA read\n"); + rc = -EPIPE; + goto err_post_send; + } + + copied = rx_sa->umem->length; + + sdp_update_iov_used(sk, iov, copied); + rx_sa->used += copied; + atomic_add(copied, &ssk->rcv_nxt); + *used = copied; + + ssk->tx_ring.rdma_inflight = NULL; + +err_post_send: + sdp_free_fmr(sk, &rx_sa->fmr, &rx_sa->umem); + +err_alloc_fmr: + if (rc && ssk->qp_active) { + sdp_warn(sk, "Couldn't do RDMA - post sendsm\n"); + rx_sa->flags |= RX_SA_ABORTED; + } + + sock_put(sk, SOCK_REF_RDMA_RD); + + return rc; +} + +static inline int wait_for_sndbuf(struct socket *sk, long *timeo_p) +{ + struct sdp_sock *ssk = sdp_sk(sk); + int ret = 0; + int credits_needed = 1; + + sdp_dbg_data(sk, "Wait for mem\n"); + + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); + + SDPSTATS_COUNTER_INC(send_wait_for_mem); + + sdp_do_posts(ssk); + + sdp_xmit_poll(ssk, 1); + + ret = sdp_tx_wait_memory(ssk, timeo_p, &credits_needed); + + return ret; +} + +static int do_sdp_sendmsg_zcopy(struct socket *sk, struct tx_srcavail_state *tx_sa, + struct iovec *iov, long *timeo) +{ + struct sdp_sock *ssk = sdp_sk(sk); + int rc = 0; + unsigned long lock_flags; + + rc = sdp_alloc_fmr(sk, iov->iov_base, iov->iov_len, + &tx_sa->fmr, &tx_sa->umem); + if (rc) { + sdp_warn(sk, "Error allocating fmr: %d\n", rc); + goto err_alloc_fmr; + } + + if (tx_slots_free(ssk) == 0) { + rc = wait_for_sndbuf(sk, timeo); + if (rc) { + sdp_warn(sk, "Couldn't get send buffer\n"); + goto err_no_tx_slots; + } + } + + rc = sdp_post_srcavail(sk, tx_sa); + if (rc) { + sdp_dbg(sk, "Error posting SrcAvail\n"); + goto err_abort_send; + } + + rc = sdp_wait_rdmardcompl(ssk, timeo, 0); + if (unlikely(rc)) { + enum tx_sa_flag f = tx_sa->abort_flags; + + if (f & TX_SA_SENDSM) { + sdp_dbg_data(sk, "Got SendSM. use SEND verb.\n"); + } else if (f & TX_SA_ERROR) { + sdp_dbg_data(sk, "SrcAvail error completion\n"); + sdp_reset(sk); + SDPSTATS_COUNTER_INC(zcopy_tx_error); + } else if (ssk->qp_active) { + sdp_post_srcavail_cancel(sk); + + /* Wait for RdmaRdCompl/SendSM to + * finish the transaction */ + *timeo = 2 * HZ; + sdp_dbg_data(sk, "Waiting for SendSM\n"); + sdp_wait_rdmardcompl(ssk, timeo, 1); + sdp_dbg_data(sk, "finished waiting\n"); + + cancel_delayed_work(&ssk->srcavail_cancel_work); + } else { + sdp_dbg_data(sk, "QP was destroyed while waiting\n"); + } + } else { + sdp_dbg_data(sk, "got RdmaRdCompl\n"); + } + + spin_lock_irqsave(&ssk->tx_sa_lock, lock_flags); + ssk->tx_sa = NULL; + spin_unlock_irqrestore(&ssk->tx_sa_lock, lock_flags); + +err_abort_send: + sdp_update_iov_used(sk, iov, tx_sa->bytes_acked); + +err_no_tx_slots: + sdp_free_fmr(sk, &tx_sa->fmr, &tx_sa->umem); + +err_alloc_fmr: + return rc; +} + +int sdp_sendmsg_zcopy(struct kiocb *iocb, struct socket *sk, struct iovec *iov) +{ + struct sdp_sock *ssk = sdp_sk(sk); + int rc = 0; + long timeo; + struct tx_srcavail_state *tx_sa; + int offset; + size_t bytes_to_copy = 0; + int copied = 0; + + sdp_dbg_data(sk, "Sending iov: %p, iov_len: 0x%lx\n", + iov->iov_base, iov->iov_len); + sdp_prf1(sk, NULL, "sdp_sendmsg_zcopy start"); + if (ssk->rx_sa) { + sdp_dbg_data(sk, "Deadlock prevent: crossing SrcAvail\n"); + return 0; + } + + sock_hold(ssk->socket, SOCK_REF_ZCOPY); + + SDPSTATS_COUNTER_INC(sendmsg_zcopy_segment); + + timeo = SDP_SRCAVAIL_ADV_TIMEOUT ; + + /* Ok commence sending. */ + offset = (unsigned long)iov->iov_base & (PAGE_SIZE - 1); + + tx_sa = kmalloc(sizeof(struct tx_srcavail_state), GFP_KERNEL); + if (!tx_sa) { + sdp_warn(sk, "Error allocating zcopy context\n"); + rc = -EAGAIN; /* Buffer too big - fallback to bcopy */ + goto err_alloc_tx_sa; + } + + bytes_to_copy = iov->iov_len; + do { + tx_sa_reset(tx_sa); + + rc = do_sdp_sendmsg_zcopy(sk, tx_sa, iov, &timeo); + + if (iov->iov_len && iov->iov_len < sdp_zcopy_thresh) { + sdp_dbg_data(sk, "0x%lx bytes left, switching to bcopy\n", + iov->iov_len); + break; + } + } while (!rc && iov->iov_len > 0 && !tx_sa->abort_flags); + + kfree(tx_sa); +err_alloc_tx_sa: + copied = bytes_to_copy - iov->iov_len; + + sdp_prf1(sk, NULL, "sdp_sendmsg_zcopy end rc: %d copied: %d", rc, copied); + + sock_put(ssk->socket, SOCK_REF_ZCOPY); + + if (rc < 0 && rc != -EAGAIN && rc != -ETIME) + return rc; + + return copied; +} + +void sdp_abort_srcavail(struct socket *sk) +{ + struct sdp_sock *ssk = sdp_sk(sk); + struct tx_srcavail_state *tx_sa = ssk->tx_sa; + unsigned long flags; + + if (!tx_sa) + return; + + cancel_delayed_work(&ssk->srcavail_cancel_work); + flush_scheduled_work(); + + spin_lock_irqsave(&ssk->tx_sa_lock, flags); + + sdp_free_fmr(sk, &tx_sa->fmr, &tx_sa->umem); + + ssk->tx_sa = NULL; + + spin_unlock_irqrestore(&ssk->tx_sa_lock, flags); +} + +void sdp_abort_rdma_read(struct socket *sk) +{ + struct sdp_sock *ssk = sdp_sk(sk); + struct rx_srcavail_state *rx_sa = ssk->rx_sa; + + if (!rx_sa) + return; + + sdp_free_fmr(sk, &rx_sa->fmr, &rx_sa->umem); + + ssk->rx_sa = NULL; +} diff --git a/sys/ofed/drivers/infiniband/util/Kconfig b/sys/ofed/drivers/infiniband/util/Kconfig new file mode 100644 index 000000000000..5e98eaa9c6a6 --- /dev/null +++ b/sys/ofed/drivers/infiniband/util/Kconfig @@ -0,0 +1,6 @@ +config INFINIBAND_MADEYE + tristate "MAD debug viewer for InfiniBand" + depends on INFINIBAND + ---help--- + Prints sent and received MADs on QP 0/1 for debugging. + diff --git a/sys/ofed/drivers/infiniband/util/Makefile b/sys/ofed/drivers/infiniband/util/Makefile new file mode 100644 index 000000000000..caf947153767 --- /dev/null +++ b/sys/ofed/drivers/infiniband/util/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_INFINIBAND_MADEYE) += ib_madeye.o + +ib_madeye-y := madeye.o diff --git a/sys/ofed/drivers/infiniband/util/madeye.c b/sys/ofed/drivers/infiniband/util/madeye.c new file mode 100644 index 000000000000..2c650a33a69c --- /dev/null +++ b/sys/ofed/drivers/infiniband/util/madeye.c @@ -0,0 +1,593 @@ +/* + * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2005, 2006 Voltaire Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directorY of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * $Id$ + */ +#include +#include +#include + +#include +#include +#include + +MODULE_AUTHOR("Sean Hefty"); +MODULE_DESCRIPTION("InfiniBand MAD viewer"); +MODULE_LICENSE("Dual BSD/GPL"); + +static void madeye_remove_one(struct ib_device *device); +static void madeye_add_one(struct ib_device *device); + +static struct ib_client madeye_client = { + .name = "madeye", + .add = madeye_add_one, + .remove = madeye_remove_one +}; + +struct madeye_port { + struct ib_mad_agent *smi_agent; + struct ib_mad_agent *gsi_agent; +}; + +static int smp = 1; +static int gmp = 1; +static int mgmt_class = 0; +static int attr_id = 0; +static int data = 0; + +module_param(smp, int, 0444); +module_param(gmp, int, 0444); +module_param(mgmt_class, int, 0444); +module_param(attr_id, int, 0444); +module_param(data, int, 0444); + +MODULE_PARM_DESC(smp, "Display all SMPs (default=1)"); +MODULE_PARM_DESC(gmp, "Display all GMPs (default=1)"); +MODULE_PARM_DESC(mgmt_class, "Display all MADs of specified class (default=0)"); +MODULE_PARM_DESC(attr_id, "Display add MADs of specified attribute ID (default=0)"); +MODULE_PARM_DESC(data, "Display data area of MADs (default=0)"); + +static char * get_class_name(u8 mgmt_class) +{ + switch(mgmt_class) { + case IB_MGMT_CLASS_SUBN_LID_ROUTED: + return "LID routed SMP"; + case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: + return "Directed route SMP"; + case IB_MGMT_CLASS_SUBN_ADM: + return "Subnet admin."; + case IB_MGMT_CLASS_PERF_MGMT: + return "Perf. mgmt."; + case IB_MGMT_CLASS_BM: + return "Baseboard mgmt."; + case IB_MGMT_CLASS_DEVICE_MGMT: + return "Device mgmt."; + case IB_MGMT_CLASS_CM: + return "Comm. mgmt."; + case IB_MGMT_CLASS_SNMP: + return "SNMP"; + default: + return "Unknown vendor/application"; + } +} + +static char * get_method_name(u8 mgmt_class, u8 method) +{ + switch(method) { + case IB_MGMT_METHOD_GET: + return "Get"; + case IB_MGMT_METHOD_SET: + return "Set"; + case IB_MGMT_METHOD_GET_RESP: + return "Get response"; + case IB_MGMT_METHOD_SEND: + return "Send"; + case IB_MGMT_METHOD_SEND | IB_MGMT_METHOD_RESP: + return "Send response"; + case IB_MGMT_METHOD_TRAP: + return "Trap"; + case IB_MGMT_METHOD_REPORT: + return "Report"; + case IB_MGMT_METHOD_REPORT_RESP: + return "Report response"; + case IB_MGMT_METHOD_TRAP_REPRESS: + return "Trap repress"; + default: + break; + } + + switch (mgmt_class) { + case IB_MGMT_CLASS_SUBN_ADM: + switch (method) { + case IB_SA_METHOD_GET_TABLE: + return "Get table"; + case IB_SA_METHOD_GET_TABLE_RESP: + return "Get table response"; + case IB_SA_METHOD_DELETE: + return "Delete"; + case IB_SA_METHOD_DELETE_RESP: + return "Delete response"; + case IB_SA_METHOD_GET_MULTI: + return "Get Multi"; + case IB_SA_METHOD_GET_MULTI_RESP: + return "Get Multi response"; + case IB_SA_METHOD_GET_TRACE_TBL: + return "Get Trace Table response"; + default: + break; + } + default: + break; + } + + return "Unknown"; +} + +static void print_status_details(u16 status) +{ + if (status & 0x0001) + printk(" busy\n"); + if (status & 0x0002) + printk(" redirection required\n"); + switch((status & 0x001C) >> 2) { + case 1: + printk(" bad version\n"); + break; + case 2: + printk(" method not supported\n"); + break; + case 3: + printk(" method/attribute combo not supported\n"); + break; + case 7: + printk(" invalid attribute/modifier value\n"); + break; + } +} + +static char * get_sa_attr(__be16 attr) +{ + switch(attr) { + case IB_SA_ATTR_CLASS_PORTINFO: + return "Class Port Info"; + case IB_SA_ATTR_NOTICE: + return "Notice"; + case IB_SA_ATTR_INFORM_INFO: + return "Inform Info"; + case IB_SA_ATTR_NODE_REC: + return "Node Record"; + case IB_SA_ATTR_PORT_INFO_REC: + return "PortInfo Record"; + case IB_SA_ATTR_SL2VL_REC: + return "SL to VL Record"; + case IB_SA_ATTR_SWITCH_REC: + return "Switch Record"; + case IB_SA_ATTR_LINEAR_FDB_REC: + return "Linear FDB Record"; + case IB_SA_ATTR_RANDOM_FDB_REC: + return "Random FDB Record"; + case IB_SA_ATTR_MCAST_FDB_REC: + return "Multicast FDB Record"; + case IB_SA_ATTR_SM_INFO_REC: + return "SM Info Record"; + case IB_SA_ATTR_LINK_REC: + return "Link Record"; + case IB_SA_ATTR_GUID_INFO_REC: + return "Guid Info Record"; + case IB_SA_ATTR_SERVICE_REC: + return "Service Record"; + case IB_SA_ATTR_PARTITION_REC: + return "Partition Record"; + case IB_SA_ATTR_PATH_REC: + return "Path Record"; + case IB_SA_ATTR_VL_ARB_REC: + return "VL Arb Record"; + case IB_SA_ATTR_MC_MEMBER_REC: + return "MC Member Record"; + case IB_SA_ATTR_TRACE_REC: + return "Trace Record"; + case IB_SA_ATTR_MULTI_PATH_REC: + return "Multi Path Record"; + case IB_SA_ATTR_SERVICE_ASSOC_REC: + return "Service Assoc Record"; + case IB_SA_ATTR_INFORM_INFO_REC: + return "Inform Info Record"; + default: + return ""; + } +} + +static void print_mad_hdr(struct ib_mad_hdr *mad_hdr) +{ + printk("MAD version....0x%01x\n", mad_hdr->base_version); + printk("Class..........0x%01x (%s)\n", mad_hdr->mgmt_class, + get_class_name(mad_hdr->mgmt_class)); + printk("Class version..0x%01x\n", mad_hdr->class_version); + printk("Method.........0x%01x (%s)\n", mad_hdr->method, + get_method_name(mad_hdr->mgmt_class, mad_hdr->method)); + printk("Status.........0x%02x\n", be16_to_cpu(mad_hdr->status)); + if (mad_hdr->status) + print_status_details(be16_to_cpu(mad_hdr->status)); + printk("Class specific.0x%02x\n", be16_to_cpu(mad_hdr->class_specific)); + printk("Trans ID.......0x%llx\n", + (unsigned long long)be64_to_cpu(mad_hdr->tid)); + if (mad_hdr->mgmt_class == IB_MGMT_CLASS_SUBN_ADM) + printk("Attr ID........0x%02x (%s)\n", + be16_to_cpu(mad_hdr->attr_id), + get_sa_attr(be16_to_cpu(mad_hdr->attr_id))); + else + printk("Attr ID........0x%02x\n", + be16_to_cpu(mad_hdr->attr_id)); + printk("Attr modifier..0x%04x\n", be32_to_cpu(mad_hdr->attr_mod)); +} + +static char * get_rmpp_type(u8 rmpp_type) +{ + switch (rmpp_type) { + case IB_MGMT_RMPP_TYPE_DATA: + return "Data"; + case IB_MGMT_RMPP_TYPE_ACK: + return "Ack"; + case IB_MGMT_RMPP_TYPE_STOP: + return "Stop"; + case IB_MGMT_RMPP_TYPE_ABORT: + return "Abort"; + default: + return "Unknown"; + } +} + +static char * get_rmpp_flags(u8 rmpp_flags) +{ + if (rmpp_flags & IB_MGMT_RMPP_FLAG_ACTIVE) + if (rmpp_flags & IB_MGMT_RMPP_FLAG_FIRST) + if (rmpp_flags & IB_MGMT_RMPP_FLAG_LAST) + return "Active - First & Last"; + else + return "Active - First"; + else + if (rmpp_flags & IB_MGMT_RMPP_FLAG_LAST) + return "Active - Last"; + else + return "Active"; + else + return "Inactive"; +} + +static void print_rmpp_hdr(struct ib_rmpp_hdr *rmpp_hdr) +{ + printk("RMPP version...0x%01x\n", rmpp_hdr->rmpp_version); + printk("RMPP type......0x%01x (%s)\n", rmpp_hdr->rmpp_type, + get_rmpp_type(rmpp_hdr->rmpp_type)); + printk("RMPP RRespTime.0x%01x\n", ib_get_rmpp_resptime(rmpp_hdr)); + printk("RMPP flags.....0x%01x (%s)\n", ib_get_rmpp_flags(rmpp_hdr), + get_rmpp_flags(ib_get_rmpp_flags(rmpp_hdr))); + printk("RMPP status....0x%01x\n", rmpp_hdr->rmpp_status); + printk("Seg number.....0x%04x\n", be32_to_cpu(rmpp_hdr->seg_num)); + switch (rmpp_hdr->rmpp_type) { + case IB_MGMT_RMPP_TYPE_DATA: + printk("Payload len....0x%04x\n", + be32_to_cpu(rmpp_hdr->paylen_newwin)); + break; + case IB_MGMT_RMPP_TYPE_ACK: + printk("New window.....0x%04x\n", + be32_to_cpu(rmpp_hdr->paylen_newwin)); + break; + default: + printk("Data 2.........0x%04x\n", + be32_to_cpu(rmpp_hdr->paylen_newwin)); + break; + } +} + +static char * get_smp_attr(__be16 attr) +{ + switch (attr) { + case IB_SMP_ATTR_NOTICE: + return "notice"; + case IB_SMP_ATTR_NODE_DESC: + return "node description"; + case IB_SMP_ATTR_NODE_INFO: + return "node info"; + case IB_SMP_ATTR_SWITCH_INFO: + return "switch info"; + case IB_SMP_ATTR_GUID_INFO: + return "GUID info"; + case IB_SMP_ATTR_PORT_INFO: + return "port info"; + case IB_SMP_ATTR_PKEY_TABLE: + return "pkey table"; + case IB_SMP_ATTR_SL_TO_VL_TABLE: + return "SL to VL table"; + case IB_SMP_ATTR_VL_ARB_TABLE: + return "VL arbitration table"; + case IB_SMP_ATTR_LINEAR_FORWARD_TABLE: + return "linear forwarding table"; + case IB_SMP_ATTR_RANDOM_FORWARD_TABLE: + return "random forward table"; + case IB_SMP_ATTR_MCAST_FORWARD_TABLE: + return "multicast forward table"; + case IB_SMP_ATTR_SM_INFO: + return "SM info"; + case IB_SMP_ATTR_VENDOR_DIAG: + return "vendor diags"; + case IB_SMP_ATTR_LED_INFO: + return "LED info"; + default: + return ""; + } +} + +static void print_smp(struct ib_smp *smp) +{ + int i; + + printk("MAD version....0x%01x\n", smp->base_version); + printk("Class..........0x%01x (%s)\n", smp->mgmt_class, + get_class_name(smp->mgmt_class)); + printk("Class version..0x%01x\n", smp->class_version); + printk("Method.........0x%01x (%s)\n", smp->method, + get_method_name(smp->mgmt_class, smp->method)); + printk("Status.........0x%02x\n", be16_to_cpu(smp->status)); + if (smp->status) + print_status_details(be16_to_cpu(smp->status)); + printk("Hop pointer....0x%01x\n", smp->hop_ptr); + printk("Hop counter....0x%01x\n", smp->hop_cnt); + printk("Trans ID.......0x%llx\n", + (unsigned long long)be64_to_cpu(smp->tid)); + printk("Attr ID........0x%02x (%s)\n", be16_to_cpu(smp->attr_id), + get_smp_attr(smp->attr_id)); + printk("Attr modifier..0x%04x\n", be32_to_cpu(smp->attr_mod)); + + printk("Mkey...........0x%llx\n", + (unsigned long long)be64_to_cpu(smp->mkey)); + printk("DR SLID........0x%02x\n", be16_to_cpu(smp->dr_slid)); + printk("DR DLID........0x%02x", be16_to_cpu(smp->dr_dlid)); + + if (data) { + for (i = 0; i < IB_SMP_DATA_SIZE; i++) { + if (i % 16 == 0) + printk("\nSMP Data......."); + printk("%01x ", smp->data[i]); + } + for (i = 0; i < IB_SMP_MAX_PATH_HOPS; i++) { + if (i % 16 == 0) + printk("\nInitial path..."); + printk("%01x ", smp->initial_path[i]); + } + for (i = 0; i < IB_SMP_MAX_PATH_HOPS; i++) { + if (i % 16 == 0) + printk("\nReturn path...."); + printk("%01x ", smp->return_path[i]); + } + } + printk("\n"); +} + +static void snoop_smi_handler(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf, + struct ib_mad_send_wc *mad_send_wc) +{ + struct ib_mad_hdr *hdr = send_buf->mad; + + if (!smp && hdr->mgmt_class != mgmt_class) + return; + if (attr_id && be16_to_cpu(hdr->attr_id) != attr_id) + return; + + printk("Madeye:sent SMP\n"); + print_smp(send_buf->mad); +} + +static void recv_smi_handler(struct ib_mad_agent *mad_agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + if (!smp && mad_recv_wc->recv_buf.mad->mad_hdr.mgmt_class != mgmt_class) + return; + if (attr_id && be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) != attr_id) + return; + + printk("Madeye:recv SMP\n"); + print_smp((struct ib_smp *)&mad_recv_wc->recv_buf.mad->mad_hdr); +} + +static int is_rmpp_mad(struct ib_mad_hdr *mad_hdr) +{ + if (mad_hdr->mgmt_class == IB_MGMT_CLASS_SUBN_ADM) { + switch (mad_hdr->method) { + case IB_SA_METHOD_GET_TABLE: + case IB_SA_METHOD_GET_TABLE_RESP: + case IB_SA_METHOD_GET_MULTI_RESP: + return 1; + default: + break; + } + } else if ((mad_hdr->mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && + (mad_hdr->mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) + return 1; + + return 0; +} + +static void snoop_gsi_handler(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf, + struct ib_mad_send_wc *mad_send_wc) +{ + struct ib_mad_hdr *hdr = send_buf->mad; + + if (!gmp && hdr->mgmt_class != mgmt_class) + return; + if (attr_id && be16_to_cpu(hdr->attr_id) != attr_id) + return; + + printk("Madeye:sent GMP\n"); + print_mad_hdr(hdr); + + if (is_rmpp_mad(hdr)) + print_rmpp_hdr(&((struct ib_rmpp_mad *) hdr)->rmpp_hdr); +} + +static void recv_gsi_handler(struct ib_mad_agent *mad_agent, + struct ib_mad_recv_wc *mad_recv_wc) +{ + struct ib_mad_hdr *hdr = &mad_recv_wc->recv_buf.mad->mad_hdr; + struct ib_rmpp_mad *mad = NULL; + struct ib_sa_mad *sa_mad; + struct ib_vendor_mad *vendor_mad; + u8 *mad_data; + int i, j; + + if (!gmp && hdr->mgmt_class != mgmt_class) + return; + if (attr_id && be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) != attr_id) + return; + + printk("Madeye:recv GMP\n"); + print_mad_hdr(hdr); + + if (is_rmpp_mad(hdr)) { + mad = (struct ib_rmpp_mad *) hdr; + print_rmpp_hdr(&mad->rmpp_hdr); + } + + if (data) { + if (hdr->mgmt_class == IB_MGMT_CLASS_SUBN_ADM) { + j = IB_MGMT_SA_DATA; + /* Display SA header */ + if (is_rmpp_mad(hdr) && + mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) + return; + sa_mad = (struct ib_sa_mad *) + &mad_recv_wc->recv_buf.mad; + mad_data = sa_mad->data; + } else { + if (is_rmpp_mad(hdr)) { + j = IB_MGMT_VENDOR_DATA; + /* Display OUI */ + vendor_mad = (struct ib_vendor_mad *) + &mad_recv_wc->recv_buf.mad; + printk("Vendor OUI......%01x %01x %01x\n", + vendor_mad->oui[0], + vendor_mad->oui[1], + vendor_mad->oui[2]); + mad_data = vendor_mad->data; + } else { + j = IB_MGMT_MAD_DATA; + mad_data = mad_recv_wc->recv_buf.mad->data; + } + } + for (i = 0; i < j; i++) { + if (i % 16 == 0) + printk("\nData..........."); + printk("%01x ", mad_data[i]); + } + printk("\n"); + } +} + +static void madeye_add_one(struct ib_device *device) +{ + struct madeye_port *port; + int reg_flags; + u8 i, s, e; + + if (device->node_type == RDMA_NODE_IB_SWITCH) { + s = 0; + e = 0; + } else { + s = 1; + e = device->phys_port_cnt; + } + + port = kmalloc(sizeof *port * (e - s + 1), GFP_KERNEL); + if (!port) + goto out; + + reg_flags = IB_MAD_SNOOP_SEND_COMPLETIONS | IB_MAD_SNOOP_RECVS; + for (i = 0; i <= e - s; i++) { + port[i].smi_agent = ib_register_mad_snoop(device, i + s, + IB_QPT_SMI, + reg_flags, + snoop_smi_handler, + recv_smi_handler, + &port[i]); + port[i].gsi_agent = ib_register_mad_snoop(device, i + s, + IB_QPT_GSI, + reg_flags, + snoop_gsi_handler, + recv_gsi_handler, + &port[i]); + } + +out: + ib_set_client_data(device, &madeye_client, port); +} + +static void madeye_remove_one(struct ib_device *device) +{ + struct madeye_port *port; + int i, s, e; + + port = (struct madeye_port *) + ib_get_client_data(device, &madeye_client); + if (!port) + return; + + if (device->node_type == RDMA_NODE_IB_SWITCH) { + s = 0; + e = 0; + } else { + s = 1; + e = device->phys_port_cnt; + } + + for (i = 0; i <= e - s; i++) { + if (!IS_ERR(port[i].smi_agent)) + ib_unregister_mad_agent(port[i].smi_agent); + if (!IS_ERR(port[i].gsi_agent)) + ib_unregister_mad_agent(port[i].gsi_agent); + } + kfree(port); +} + +static int __init ib_madeye_init(void) +{ + return ib_register_client(&madeye_client); +} + +static void __exit ib_madeye_cleanup(void) +{ + ib_unregister_client(&madeye_client); +} + +module_init(ib_madeye_init); +module_exit(ib_madeye_cleanup); diff --git a/sys/ofed/drivers/net/mlx4/Makefile b/sys/ofed/drivers/net/mlx4/Makefile new file mode 100644 index 000000000000..b9d2e7eaa68c --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/Makefile @@ -0,0 +1,9 @@ +obj-$(CONFIG_MLX4_CORE) += mlx4_core.o + +mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \ + mr.o pd.o port.o profile.o qp.o reset.o sense.o srq.o xrcd.o + +obj-$(CONFIG_MLX4_EN) += mlx4_en.o + +mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \ + en_resources.o en_netdev.o en_frag.o en_selftest.o diff --git a/sys/ofed/drivers/net/mlx4/alloc.c b/sys/ofed/drivers/net/mlx4/alloc.c new file mode 100644 index 000000000000..c22791a4d981 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/alloc.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "mlx4.h" + +u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap) +{ + u32 obj; + + spin_lock(&bitmap->lock); + + obj = find_next_zero_bit(bitmap->table, bitmap->max, bitmap->last); + if (obj >= bitmap->max) { + bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) + & bitmap->mask; + obj = find_first_zero_bit(bitmap->table, bitmap->max); + } + + if (obj < bitmap->max) { + set_bit(obj, bitmap->table); + bitmap->last = (obj + 1); + if (bitmap->last == bitmap->max) + bitmap->last = 0; + obj |= bitmap->top; + } else + obj = -1; + + if (obj != -1) + --bitmap->avail; + + spin_unlock(&bitmap->lock); + + return obj; +} + +void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj) +{ + mlx4_bitmap_free_range(bitmap, obj, 1); +} + +static unsigned long find_aligned_range(unsigned long *bitmap, + u32 start, u32 nbits, + int len, int align) +{ + unsigned long end, i; + +again: + start = ALIGN(start, align); + + while ((start < nbits) && test_bit(start, bitmap)) + start += align; + + if (start >= nbits) + return -1; + + end = start+len; + if (end > nbits) + return -1; + + for (i = start + 1; i < end; i++) { + if (test_bit(i, bitmap)) { + start = i + 1; + goto again; + } + } + + return start; +} + +u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) +{ + u32 obj, i; + + if (likely(cnt == 1 && align == 1)) + return mlx4_bitmap_alloc(bitmap); + + spin_lock(&bitmap->lock); + + obj = find_aligned_range(bitmap->table, bitmap->last, + bitmap->max, cnt, align); + if (obj >= bitmap->max) { + bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) + & bitmap->mask; + obj = find_aligned_range(bitmap->table, 0, bitmap->max, + cnt, align); + } + + if (obj < bitmap->max) { + for (i = 0; i < cnt; i++) + set_bit(obj + i, bitmap->table); + if (obj == bitmap->last) { + bitmap->last = (obj + cnt); + if (bitmap->last >= bitmap->max) + bitmap->last = 0; + } + obj |= bitmap->top; + } else + obj = -1; + + if (obj != -1) + bitmap->avail -= cnt; + + spin_unlock(&bitmap->lock); + + return obj; +} + +u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap) +{ + return bitmap->avail; +} + +void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) +{ + u32 i; + + obj &= bitmap->max + bitmap->reserved_top - 1; + + spin_lock(&bitmap->lock); + for (i = 0; i < cnt; i++) + clear_bit(obj + i, bitmap->table); + bitmap->last = min(bitmap->last, obj); + bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) + & bitmap->mask; + bitmap->avail += cnt; + spin_unlock(&bitmap->lock); +} + +int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, + u32 reserved_bot, u32 reserved_top) +{ + int i; + + /* num must be a power of 2 */ + if (num != roundup_pow_of_two(num)) + return -EINVAL; + + bitmap->last = 0; + bitmap->top = 0; + bitmap->max = num - reserved_top; + bitmap->mask = mask; + bitmap->reserved_top = reserved_top; + bitmap->avail = num - reserved_top - reserved_bot; + spin_lock_init(&bitmap->lock); + bitmap->table = kzalloc(BITS_TO_LONGS(bitmap->max) * + sizeof (long), GFP_KERNEL); + if (!bitmap->table) + return -ENOMEM; + + for (i = 0; i < reserved_bot; ++i) + set_bit(i, bitmap->table); + + return 0; +} + +void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap) +{ + kfree(bitmap->table); +} + +/* + * Handling for queue buffers -- we allocate a bunch of memory and + * register it in a memory region at HCA virtual address 0. If the + * requested size is > max_direct, we split the allocation into + * multiple pages, so we don't require too much contiguous memory. + */ + +int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, + struct mlx4_buf *buf) +{ + dma_addr_t t; + + buf->direct.buf = NULL; + if (size <= max_direct) { + buf->nbufs = 1; + buf->npages = 1; + buf->page_shift = get_order(size) + PAGE_SHIFT; + buf->direct.buf = dma_alloc_coherent(&dev->pdev->dev, + size, &t, GFP_KERNEL); + if (!buf->direct.buf) + return -ENOMEM; + + buf->direct.map = t; + + while (t & ((1 << buf->page_shift) - 1)) { + --buf->page_shift; + buf->npages *= 2; + } + + memset(buf->direct.buf, 0, size); + } else { + int i; + + buf->direct.buf = NULL; + buf->direct.map = 0; + buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE; + buf->npages = buf->nbufs; + buf->page_shift = PAGE_SHIFT; + buf->page_list = kzalloc(buf->nbufs * sizeof *buf->page_list, + GFP_KERNEL); + if (!buf->page_list) + return -ENOMEM; + + for (i = 0; i < buf->nbufs; ++i) { + buf->page_list[i].buf = + dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, + &t, GFP_KERNEL); + if (!buf->page_list[i].buf) + goto err_free; + + buf->page_list[i].map = t; + + memset(buf->page_list[i].buf, 0, PAGE_SIZE); + } + + if (BITS_PER_LONG == 64) { + struct page **pages; + pages = kmalloc(sizeof *pages * buf->nbufs, GFP_KERNEL); + if (!pages) + goto err_free; + for (i = 0; i < buf->nbufs; ++i) + pages[i] = virt_to_page(buf->page_list[i].buf); + buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL); + kfree(pages); + if (!buf->direct.buf) + goto err_free; + } + } + + return 0; + +err_free: + mlx4_buf_free(dev, size, buf); + + return -ENOMEM; +} +EXPORT_SYMBOL_GPL(mlx4_buf_alloc); + +void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf) +{ + int i; + + if (buf->nbufs == 1) + dma_free_coherent(&dev->pdev->dev, size, buf->direct.buf, + buf->direct.map); + else { + if (BITS_PER_LONG == 64 && buf->direct.buf) + vunmap(buf->direct.buf); + + for (i = 0; i < buf->nbufs; ++i) + if (buf->page_list[i].buf) + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + buf->page_list[i].buf, + buf->page_list[i].map); + kfree(buf->page_list); + } + buf->direct.buf = NULL; +} +EXPORT_SYMBOL_GPL(mlx4_buf_free); + +static struct mlx4_db_pgdir *mlx4_alloc_db_pgdir(struct device *dma_device) +{ + struct mlx4_db_pgdir *pgdir; + + pgdir = kzalloc(sizeof *pgdir, GFP_KERNEL); + if (!pgdir) + return NULL; + + bitmap_fill(pgdir->order1, MLX4_DB_PER_PAGE / 2); + pgdir->bits[0] = pgdir->order0; + pgdir->bits[1] = pgdir->order1; + pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE, + &pgdir->db_dma, GFP_KERNEL); + if (!pgdir->db_page) { + kfree(pgdir); + return NULL; + } + + return pgdir; +} + +static int mlx4_alloc_db_from_pgdir(struct mlx4_db_pgdir *pgdir, + struct mlx4_db *db, int order) +{ + int o; + int i; + + for (o = order; o <= 1; ++o) { + i = find_first_bit(pgdir->bits[o], MLX4_DB_PER_PAGE >> o); + if (i < MLX4_DB_PER_PAGE >> o) + goto found; + } + + return -ENOMEM; + +found: + clear_bit(i, pgdir->bits[o]); + + i <<= o; + + if (o > order) + set_bit(i ^ 1, pgdir->bits[order]); + + db->u.pgdir = pgdir; + db->index = i; + db->db = pgdir->db_page + db->index; + db->dma = pgdir->db_dma + db->index * 4; + db->order = order; + + return 0; +} + +int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_db_pgdir *pgdir; + int ret = 0; + + mutex_lock(&priv->pgdir_mutex); + + list_for_each_entry(pgdir, &priv->pgdir_list, list) + if (!mlx4_alloc_db_from_pgdir(pgdir, db, order)) + goto out; + + pgdir = mlx4_alloc_db_pgdir(&(dev->pdev->dev)); + if (!pgdir) { + ret = -ENOMEM; + goto out; + } + + list_add(&pgdir->list, &priv->pgdir_list); + + /* This should never fail -- we just allocated an empty page: */ + WARN_ON(mlx4_alloc_db_from_pgdir(pgdir, db, order)); + +out: + mutex_unlock(&priv->pgdir_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(mlx4_db_alloc); + +void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int o; + int i; + + mutex_lock(&priv->pgdir_mutex); + + o = db->order; + i = db->index; + + if (db->order == 0 && test_bit(i ^ 1, db->u.pgdir->order0)) { + clear_bit(i ^ 1, db->u.pgdir->order0); + ++o; + } + i >>= o; + set_bit(i, db->u.pgdir->bits[o]); + + if (bitmap_full(db->u.pgdir->order1, MLX4_DB_PER_PAGE / 2)) { + dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE, + db->u.pgdir->db_page, db->u.pgdir->db_dma); + list_del(&db->u.pgdir->list); + kfree(db->u.pgdir); + } + + mutex_unlock(&priv->pgdir_mutex); +} +EXPORT_SYMBOL_GPL(mlx4_db_free); + +int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, + int size, int max_direct) +{ + int err; + + err = mlx4_db_alloc(dev, &wqres->db, 1); + if (err) + return err; + + *wqres->db.db = 0; + + err = mlx4_buf_alloc(dev, size, max_direct, &wqres->buf); + if (err) + goto err_db; + + err = mlx4_mtt_init(dev, wqres->buf.npages, wqres->buf.page_shift, + &wqres->mtt); + if (err) + goto err_buf; + + err = mlx4_buf_write_mtt(dev, &wqres->mtt, &wqres->buf); + if (err) + goto err_mtt; + + return 0; + +err_mtt: + mlx4_mtt_cleanup(dev, &wqres->mtt); +err_buf: + mlx4_buf_free(dev, size, &wqres->buf); +err_db: + mlx4_db_free(dev, &wqres->db); + + return err; +} +EXPORT_SYMBOL_GPL(mlx4_alloc_hwq_res); + +void mlx4_free_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, + int size) +{ + mlx4_mtt_cleanup(dev, &wqres->mtt); + mlx4_buf_free(dev, size, &wqres->buf); + mlx4_db_free(dev, &wqres->db); +} +EXPORT_SYMBOL_GPL(mlx4_free_hwq_res); diff --git a/sys/ofed/drivers/net/mlx4/catas.c b/sys/ofed/drivers/net/mlx4/catas.c new file mode 100644 index 000000000000..334aad927501 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/catas.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "mlx4.h" + +#define MLX4_CATAS_POLL_INTERVAL (5 * HZ) + +static DEFINE_SPINLOCK(catas_lock); + +static LIST_HEAD(catas_list); +static struct work_struct catas_work; + +static int internal_err_reset = 1; +module_param(internal_err_reset, int, 0644); +MODULE_PARM_DESC(internal_err_reset, + "Reset device on internal errors if non-zero (default 1)"); + +static void dump_err_buf(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + int i; + + mlx4_err(dev, "Internal error detected:\n"); + for (i = 0; i < priv->fw.catas_size; ++i) + mlx4_err(dev, " buf[%02x]: %08x\n", + i, swab32(readl(priv->catas_err.map + i))); +} + +static void poll_catas(unsigned long dev_ptr) +{ + struct mlx4_dev *dev = (struct mlx4_dev *) dev_ptr; + struct mlx4_priv *priv = mlx4_priv(dev); + + if (readl(priv->catas_err.map)) { + dump_err_buf(dev); + + mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0); + + if (internal_err_reset) { + spin_lock(&catas_lock); + list_add(&priv->catas_err.list, &catas_list); + spin_unlock(&catas_lock); + + queue_work(mlx4_wq, &catas_work); + } + } else + mod_timer(&priv->catas_err.timer, + round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL)); +} + +static void catas_reset(struct work_struct *work) +{ + struct mlx4_priv *priv, *tmppriv; + struct mlx4_dev *dev; + + LIST_HEAD(tlist); + int ret; + + if (!mutex_trylock(&drv_mutex)) + return; + + spin_lock_irq(&catas_lock); + list_splice_init(&catas_list, &tlist); + spin_unlock_irq(&catas_lock); + + list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) { + struct pci_dev *pdev = priv->dev.pdev; + + ret = mlx4_restart_one(priv->dev.pdev); + /* 'priv' now is not valid */ + if (ret) + printk(KERN_ERR "mlx4 %s: Reset failed (%d)\n", + pci_name(pdev), ret); + else { + dev = pci_get_drvdata(pdev); + mlx4_dbg(dev, "Reset succeeded\n"); + } + } + mutex_unlock(&drv_mutex); +} + +void mlx4_start_catas_poll(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + unsigned long addr; + + INIT_LIST_HEAD(&priv->catas_err.list); + init_timer(&priv->catas_err.timer); + priv->catas_err.map = NULL; + + addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) + + priv->fw.catas_offset; + + priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4); + if (!priv->catas_err.map) { + mlx4_warn(dev, "Failed to map internal error buffer at 0x%lx\n", + addr); + return; + } + + priv->catas_err.timer.data = (unsigned long) dev; + priv->catas_err.timer.function = poll_catas; + priv->catas_err.timer.expires = + round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL); + add_timer(&priv->catas_err.timer); +} + +void mlx4_stop_catas_poll(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + del_timer_sync(&priv->catas_err.timer); + + if (priv->catas_err.map) + iounmap(priv->catas_err.map); + + spin_lock_irq(&catas_lock); + list_del(&priv->catas_err.list); + spin_unlock_irq(&catas_lock); +} + +void __init mlx4_catas_init(void) +{ + INIT_WORK(&catas_work, catas_reset); +} diff --git a/sys/ofed/drivers/net/mlx4/cmd.c b/sys/ofed/drivers/net/mlx4/cmd.c new file mode 100644 index 000000000000..bc4a618cb00f --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/cmd.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include + +#include + +#include "mlx4.h" + +#define CMD_POLL_TOKEN 0xffff + +enum { + /* command completed successfully: */ + CMD_STAT_OK = 0x00, + /* Internal error (such as a bus error) occurred while processing command: */ + CMD_STAT_INTERNAL_ERR = 0x01, + /* Operation/command not supported or opcode modifier not supported: */ + CMD_STAT_BAD_OP = 0x02, + /* Parameter not supported or parameter out of range: */ + CMD_STAT_BAD_PARAM = 0x03, + /* System not enabled or bad system state: */ + CMD_STAT_BAD_SYS_STATE = 0x04, + /* Attempt to access reserved or unallocaterd resource: */ + CMD_STAT_BAD_RESOURCE = 0x05, + /* Requested resource is currently executing a command, or is otherwise busy: */ + CMD_STAT_RESOURCE_BUSY = 0x06, + /* Required capability exceeds device limits: */ + CMD_STAT_EXCEED_LIM = 0x08, + /* Resource is not in the appropriate state or ownership: */ + CMD_STAT_BAD_RES_STATE = 0x09, + /* Index out of range: */ + CMD_STAT_BAD_INDEX = 0x0a, + /* FW image corrupted: */ + CMD_STAT_BAD_NVMEM = 0x0b, + /* Error in ICM mapping (e.g. not enough auxiliary ICM pages to execute command): */ + CMD_STAT_ICM_ERROR = 0x0c, + /* Attempt to modify a QP/EE which is not in the presumed state: */ + CMD_STAT_BAD_QP_STATE = 0x10, + /* Bad segment parameters (Address/Size): */ + CMD_STAT_BAD_SEG_PARAM = 0x20, + /* Memory Region has Memory Windows bound to: */ + CMD_STAT_REG_BOUND = 0x21, + /* HCA local attached memory not present: */ + CMD_STAT_LAM_NOT_PRE = 0x22, + /* Bad management packet (silently discarded): */ + CMD_STAT_BAD_PKT = 0x30, + /* More outstanding CQEs in CQ than new CQ size: */ + CMD_STAT_BAD_SIZE = 0x40, + /* Multi Function device support required: */ + CMD_STAT_MULTI_FUNC_REQ = 0x50, +}; + +enum { + HCR_IN_PARAM_OFFSET = 0x00, + HCR_IN_MODIFIER_OFFSET = 0x08, + HCR_OUT_PARAM_OFFSET = 0x0c, + HCR_TOKEN_OFFSET = 0x14, + HCR_STATUS_OFFSET = 0x18, + + HCR_OPMOD_SHIFT = 12, + HCR_T_BIT = 21, + HCR_E_BIT = 22, + HCR_GO_BIT = 23 +}; + +enum { + GO_BIT_TIMEOUT_MSECS = 10000 +}; + +struct mlx4_cmd_context { + struct completion done; + int result; + int next; + u64 out_param; + u16 token; + u8 fw_status; +}; + +static int mlx4_status_to_errno(u8 status) +{ + static const int trans_table[] = { + [CMD_STAT_INTERNAL_ERR] = -EIO, + [CMD_STAT_BAD_OP] = -EPERM, + [CMD_STAT_BAD_PARAM] = -EINVAL, + [CMD_STAT_BAD_SYS_STATE] = -ENXIO, + [CMD_STAT_BAD_RESOURCE] = -EBADF, + [CMD_STAT_RESOURCE_BUSY] = -EBUSY, + [CMD_STAT_EXCEED_LIM] = -ENOMEM, + [CMD_STAT_BAD_RES_STATE] = -EBADF, + [CMD_STAT_BAD_INDEX] = -EBADF, + [CMD_STAT_BAD_NVMEM] = -EFAULT, + [CMD_STAT_ICM_ERROR] = -ENFILE, + [CMD_STAT_BAD_QP_STATE] = -EINVAL, + [CMD_STAT_BAD_SEG_PARAM] = -EFAULT, + [CMD_STAT_REG_BOUND] = -EBUSY, + [CMD_STAT_LAM_NOT_PRE] = -EAGAIN, + [CMD_STAT_BAD_PKT] = -EINVAL, + [CMD_STAT_BAD_SIZE] = -ENOMEM, + [CMD_STAT_MULTI_FUNC_REQ] = -EACCES, + }; + + if (status >= ARRAY_SIZE(trans_table) || + (status != CMD_STAT_OK && trans_table[status] == 0)) + return -EIO; + + return trans_table[status]; +} + +static int cmd_pending(struct mlx4_dev *dev) +{ + u32 status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); + + return (status & swab32(1 << HCR_GO_BIT)) || + (mlx4_priv(dev)->cmd.toggle == + !!(status & swab32(1 << HCR_T_BIT))); +} + +static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, + u32 in_modifier, u8 op_modifier, u16 op, u16 token, + int event) +{ + struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; + u32 __iomem *hcr = cmd->hcr; + int ret = -EAGAIN; + unsigned long end; + + mutex_lock(&cmd->hcr_mutex); + + end = jiffies; + if (event) + end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); + + while (cmd_pending(dev)) { + if (time_after_eq(jiffies, end)) + goto out; + cond_resched(); + } + + /* + * We use writel (instead of something like memcpy_toio) + * because writes of less than 32 bits to the HCR don't work + * (and some architectures such as ia64 implement memcpy_toio + * in terms of writeb). + */ + __raw_writel((__force u32) cpu_to_be32(in_param >> 32), hcr + 0); + __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), hcr + 1); + __raw_writel((__force u32) cpu_to_be32(in_modifier), hcr + 2); + __raw_writel((__force u32) cpu_to_be32(out_param >> 32), hcr + 3); + __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4); + __raw_writel((__force u32) cpu_to_be32(token << 16), hcr + 5); + + /* __raw_writel may not order writes. */ + wmb(); + + __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) | + (cmd->toggle << HCR_T_BIT) | + (event ? (1 << HCR_E_BIT) : 0) | + (op_modifier << HCR_OPMOD_SHIFT) | + op), hcr + 6); + + /* + * Make sure that our HCR writes don't get mixed in with + * writes from another CPU starting a FW command. + */ + mmiowb(); + + cmd->toggle = cmd->toggle ^ 1; + + ret = 0; + +out: + mutex_unlock(&cmd->hcr_mutex); + return ret; +} + +static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, + int out_is_imm, u32 in_modifier, u8 op_modifier, + u16 op, unsigned long timeout) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + void __iomem *hcr = priv->cmd.hcr; + int err = 0; + unsigned long end; + u32 stat; + + down(&priv->cmd.poll_sem); + + err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, + in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); + if (err) + goto out; + + end = msecs_to_jiffies(timeout) + jiffies; + while (cmd_pending(dev) && time_before(jiffies, end)) + cond_resched(); + + if (cmd_pending(dev)) { + err = -ETIMEDOUT; + goto out; + } + + if (out_is_imm) + *out_param = + (u64) be32_to_cpu((__force __be32) + __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 | + (u64) be32_to_cpu((__force __be32) + __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4)); + stat = be32_to_cpu((__force __be32) __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24; + err = mlx4_status_to_errno(stat); + if (err) { + if (op != MLX4_CMD_SET_NODE || stat != CMD_STAT_BAD_OP) + mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", + op, stat); + } + +out: + up(&priv->cmd.poll_sem); + return err; +} + +void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cmd_context *context = + &priv->cmd.context[token & priv->cmd.token_mask]; + + /* previously timed out command completing at long last */ + if (token != context->token) + return; + + context->fw_status = status; + context->result = mlx4_status_to_errno(status); + context->out_param = out_param; + + complete(&context->done); +} + +static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, + int out_is_imm, u32 in_modifier, u8 op_modifier, + u16 op, unsigned long timeout) +{ + struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; + struct mlx4_cmd_context *context; + int err = 0; + + down(&cmd->event_sem); + + spin_lock(&cmd->context_lock); + BUG_ON(cmd->free_head < 0); + context = &cmd->context[cmd->free_head]; + context->token += cmd->token_mask + 1; + cmd->free_head = context->next; + spin_unlock(&cmd->context_lock); + + init_completion(&context->done); + + mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, + in_modifier, op_modifier, op, context->token, 1); + + if (!wait_for_completion_timeout(&context->done, msecs_to_jiffies(timeout))) { + err = -EBUSY; + goto out; + } + + err = context->result; + if (err) { + if (op != MLX4_CMD_SET_NODE || context->fw_status != CMD_STAT_BAD_OP) + mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n", + op, context->fw_status); + goto out; + } + + if (out_is_imm) + *out_param = context->out_param; + +out: + spin_lock(&cmd->context_lock); + context->next = cmd->free_head; + cmd->free_head = context - cmd->context; + spin_unlock(&cmd->context_lock); + + up(&cmd->event_sem); + return err; +} + +int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, + int out_is_imm, u32 in_modifier, u8 op_modifier, + u16 op, unsigned long timeout) +{ + if (mlx4_priv(dev)->cmd.use_events && !cold) + return mlx4_cmd_wait(dev, in_param, out_param, out_is_imm, + in_modifier, op_modifier, op, timeout); + else + return mlx4_cmd_poll(dev, in_param, out_param, out_is_imm, + in_modifier, op_modifier, op, timeout); +} +EXPORT_SYMBOL_GPL(__mlx4_cmd); + +int mlx4_cmd_init(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + mutex_init(&priv->cmd.hcr_mutex); + sema_init(&priv->cmd.poll_sem, 1); + priv->cmd.use_events = 0; + priv->cmd.toggle = 1; + + priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_HCR_BASE, + MLX4_HCR_SIZE); + if (!priv->cmd.hcr) { + mlx4_err(dev, "Couldn't map command register."); + return -ENOMEM; + } + + priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev, + MLX4_MAILBOX_SIZE, + MLX4_MAILBOX_SIZE, 0); + if (!priv->cmd.pool) { + iounmap(priv->cmd.hcr); + return -ENOMEM; + } + + return 0; +} + +void mlx4_cmd_cleanup(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + pci_pool_destroy(priv->cmd.pool); + iounmap(priv->cmd.hcr); +} + +/* + * Switch to using events to issue FW commands (can only be called + * after event queue for command events has been initialized). + */ +int mlx4_cmd_use_events(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int i; + + priv->cmd.context = kmalloc(priv->cmd.max_cmds * + sizeof (struct mlx4_cmd_context), + GFP_KERNEL); + if (!priv->cmd.context) + return -ENOMEM; + + for (i = 0; i < priv->cmd.max_cmds; ++i) { + priv->cmd.context[i].token = i; + priv->cmd.context[i].next = i + 1; + } + + priv->cmd.context[priv->cmd.max_cmds - 1].next = -1; + priv->cmd.free_head = 0; + + sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds); + spin_lock_init(&priv->cmd.context_lock); + + for (priv->cmd.token_mask = 1; + priv->cmd.token_mask < priv->cmd.max_cmds; + priv->cmd.token_mask <<= 1) + ; /* nothing */ + --priv->cmd.token_mask; + + priv->cmd.use_events = 1; + + down(&priv->cmd.poll_sem); + + return 0; +} + +/* + * Switch back to polling (used when shutting down the device) + */ +void mlx4_cmd_use_polling(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int i; + + priv->cmd.use_events = 0; + + for (i = 0; i < priv->cmd.max_cmds; ++i) + down(&priv->cmd.event_sem); + + kfree(priv->cmd.context); + + up(&priv->cmd.poll_sem); +} + +struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev) +{ + struct mlx4_cmd_mailbox *mailbox; + + mailbox = kmalloc(sizeof *mailbox, GFP_KERNEL); + if (!mailbox) + return ERR_PTR(-ENOMEM); + + mailbox->buf = pci_pool_alloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL, + &mailbox->dma); + if (!mailbox->buf) { + kfree(mailbox); + return ERR_PTR(-ENOMEM); + } + + return mailbox; +} +EXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox); + +void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox) +{ + if (!mailbox) + return; + + pci_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma); + kfree(mailbox); +} +EXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox); diff --git a/sys/ofed/drivers/net/mlx4/cq.c b/sys/ofed/drivers/net/mlx4/cq.c new file mode 100644 index 000000000000..076c602acb00 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/cq.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include +#include + +#include "mlx4.h" +#include "icm.h" + +struct mlx4_cq_context { + __be32 flags; + u16 reserved1[3]; + __be16 page_offset; + __be32 logsize_usrpage; + __be16 cq_period; + __be16 cq_max_count; + u8 reserved2[3]; + u8 comp_eqn; + u8 log_page_size; + u8 reserved3[2]; + u8 mtt_base_addr_h; + __be32 mtt_base_addr_l; + __be32 last_notified_index; + __be32 solicit_producer_index; + __be32 consumer_index; + __be32 producer_index; + u32 reserved4[2]; + __be64 db_rec_addr; +}; + +#define MLX4_CQ_STATUS_OK ( 0 << 28) +#define MLX4_CQ_STATUS_OVERFLOW ( 9 << 28) +#define MLX4_CQ_STATUS_WRITE_FAIL (10 << 28) +#define MLX4_CQ_FLAG_CC ( 1 << 18) +#define MLX4_CQ_FLAG_OI ( 1 << 17) +#define MLX4_CQ_STATE_ARMED ( 9 << 8) +#define MLX4_CQ_STATE_ARMED_SOL ( 6 << 8) +#define MLX4_EQ_STATE_FIRED (10 << 8) + +void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn) +{ + struct mlx4_cq *cq; + + cq = radix_tree_lookup(&mlx4_priv(dev)->cq_table.tree, + cqn & (dev->caps.num_cqs - 1)); + if (!cq) { + mlx4_dbg(dev, "Completion event for bogus CQ %08x\n", cqn); + return; + } + + ++cq->arm_sn; + + cq->comp(cq); +} + +void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type) +{ + struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table; + struct mlx4_cq *cq; + + spin_lock(&cq_table->lock); + + cq = radix_tree_lookup(&cq_table->tree, cqn & (dev->caps.num_cqs - 1)); + if (cq) + atomic_inc(&cq->refcount); + + spin_unlock(&cq_table->lock); + + if (!cq) { + mlx4_warn(dev, "Async event for bogus CQ %08x\n", cqn); + return; + } + + cq->event(cq, event_type); + + if (atomic_dec_and_test(&cq->refcount)) + complete(&cq->free); +} + +static int mlx4_SW2HW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int cq_num) +{ + return mlx4_cmd(dev, mailbox->dma, cq_num, 0, MLX4_CMD_SW2HW_CQ, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_MODIFY_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int cq_num, u32 opmod) +{ + return mlx4_cmd(dev, mailbox->dma, cq_num, opmod, MLX4_CMD_MODIFY_CQ, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_HW2SW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int cq_num) +{ + return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, cq_num, + mailbox ? 0 : 1, MLX4_CMD_HW2SW_CQ, + MLX4_CMD_TIME_CLASS_A); +} + +int mlx4_cq_modify(struct mlx4_dev *dev, struct mlx4_cq *cq, + u16 count, u16 period) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_cq_context *cq_context; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + cq_context = mailbox->buf; + memset(cq_context, 0, sizeof *cq_context); + + cq_context->cq_max_count = cpu_to_be16(count); + cq_context->cq_period = cpu_to_be16(period); + + err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, 1); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_cq_modify); + +int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq, + int entries, struct mlx4_mtt *mtt) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_cq_context *cq_context; + u64 mtt_addr; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + cq_context = mailbox->buf; + memset(cq_context, 0, sizeof *cq_context); + + cq_context->logsize_usrpage = cpu_to_be32(ilog2(entries) << 24); + cq_context->log_page_size = mtt->page_shift - 12; + mtt_addr = mlx4_mtt_addr(dev, mtt); + cq_context->mtt_base_addr_h = mtt_addr >> 32; + cq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); + + err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, 0); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_cq_resize); + +static int mlx4_find_least_loaded_vector(struct mlx4_priv *priv) +{ + int i; + int index = 0; + int min = priv->eq_table.eq[0].load; + + for (i = 1; i < priv->dev.caps.num_comp_vectors; i++) { + if (priv->eq_table.eq[i].load < min) { + index = i; + min = priv->eq_table.eq[i].load; + } + } + + return index; +} + +int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, + struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq, + unsigned vector, int collapsed) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cq_table *cq_table = &priv->cq_table; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_cq_context *cq_context; + u64 mtt_addr; + int err; + + cq->vector = (vector == MLX4_LEAST_ATTACHED_VECTOR) ? + mlx4_find_least_loaded_vector(priv) : vector; + + if (cq->vector >= dev->caps.num_comp_vectors) + return -EINVAL; + + cq->cqn = mlx4_bitmap_alloc(&cq_table->bitmap); + if (cq->cqn == -1) + return -ENOMEM; + + err = mlx4_table_get(dev, &cq_table->table, cq->cqn); + if (err) + goto err_out; + + err = mlx4_table_get(dev, &cq_table->cmpt_table, cq->cqn); + if (err) + goto err_put; + + spin_lock_irq(&cq_table->lock); + err = radix_tree_insert(&cq_table->tree, cq->cqn, cq); + spin_unlock_irq(&cq_table->lock); + if (err) + goto err_cmpt_put; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto err_radix; + } + + cq_context = mailbox->buf; + memset(cq_context, 0, sizeof *cq_context); + + cq_context->flags = cpu_to_be32(!!collapsed << 18); + cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index); + cq_context->comp_eqn = priv->eq_table.eq[cq->vector].eqn; + cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; + + mtt_addr = mlx4_mtt_addr(dev, mtt); + cq_context->mtt_base_addr_h = mtt_addr >> 32; + cq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); + cq_context->db_rec_addr = cpu_to_be64(db_rec); + + err = mlx4_SW2HW_CQ(dev, mailbox, cq->cqn); + mlx4_free_cmd_mailbox(dev, mailbox); + if (err) + goto err_radix; + + priv->eq_table.eq[cq->vector].load++; + cq->cons_index = 0; + cq->arm_sn = 1; + cq->uar = uar; + atomic_set(&cq->refcount, 1); + init_completion(&cq->free); + + return 0; + +err_radix: + spin_lock_irq(&cq_table->lock); + radix_tree_delete(&cq_table->tree, cq->cqn); + spin_unlock_irq(&cq_table->lock); + +err_cmpt_put: + mlx4_table_put(dev, &cq_table->cmpt_table, cq->cqn); + +err_put: + mlx4_table_put(dev, &cq_table->table, cq->cqn); + +err_out: + mlx4_bitmap_free(&cq_table->bitmap, cq->cqn); + + return err; +} +EXPORT_SYMBOL_GPL(mlx4_cq_alloc); + +void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cq_table *cq_table = &priv->cq_table; + int err; + + err = mlx4_HW2SW_CQ(dev, NULL, cq->cqn); + if (err) + mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn); + + synchronize_irq(priv->eq_table.eq[cq->vector].irq); + priv->eq_table.eq[cq->vector].load--; + + spin_lock_irq(&cq_table->lock); + radix_tree_delete(&cq_table->tree, cq->cqn); + spin_unlock_irq(&cq_table->lock); + + if (atomic_dec_and_test(&cq->refcount)) + complete(&cq->free); + wait_for_completion(&cq->free); + + mlx4_table_put(dev, &cq_table->table, cq->cqn); + mlx4_bitmap_free(&cq_table->bitmap, cq->cqn); +} +EXPORT_SYMBOL_GPL(mlx4_cq_free); + +int mlx4_init_cq_table(struct mlx4_dev *dev) +{ + struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table; + int err; + + spin_lock_init(&cq_table->lock); + INIT_RADIX_TREE(&cq_table->tree, GFP_ATOMIC); + + err = mlx4_bitmap_init(&cq_table->bitmap, dev->caps.num_cqs, + dev->caps.num_cqs - 1, dev->caps.reserved_cqs, 0); + if (err) + return err; + + return 0; +} + +void mlx4_cleanup_cq_table(struct mlx4_dev *dev) +{ + /* Nothing to do to clean up radix_tree */ + mlx4_bitmap_cleanup(&mlx4_priv(dev)->cq_table.bitmap); +} diff --git a/sys/ofed/drivers/net/mlx4/en_cq.c b/sys/ofed/drivers/net/mlx4/en_cq.c new file mode 100644 index 000000000000..9f475fff2e08 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/en_cq.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include "mlx4_en.h" + +#include +#include +#include + +static void mlx4_en_cq_event(struct mlx4_cq *cq, enum mlx4_event event) +{ + return; +} + + +int mlx4_en_create_cq(struct mlx4_en_priv *priv, + struct mlx4_en_cq *cq, + int entries, int ring, enum cq_type mode) +{ + struct mlx4_en_dev *mdev = priv->mdev; + int err; + + cq->size = entries; + if (mode == RX) { + cq->buf_size = cq->size * sizeof(struct mlx4_cqe); + cq->vector = (ring + priv->port) % + mdev->dev->caps.num_comp_vectors; + TASK_INIT(&cq->cq_task, 0, mlx4_en_rx_que, cq); + } else { + cq->buf_size = sizeof(struct mlx4_cqe); + cq->vector = MLX4_LEAST_ATTACHED_VECTOR; + TASK_INIT(&cq->cq_task, 0, mlx4_en_tx_que, cq); + } + + cq->tq = taskqueue_create_fast("mlx4_en_que", M_NOWAIT, + taskqueue_thread_enqueue, &cq->tq); + taskqueue_start_threads(&cq->tq, 1, PI_NET, "%s cq", + if_name(priv->dev)); + cq->ring = ring; + cq->is_tx = mode; + mtx_init(&cq->lock.m, "mlx4 cq", NULL, MTX_DEF); + + err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres, + cq->buf_size, 2 * PAGE_SIZE); + if (err) + return err; + + err = mlx4_en_map_buffer(&cq->wqres.buf); + if (err) + mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); + else + cq->buf = (struct mlx4_cqe *) cq->wqres.buf.direct.buf; + + return err; +} + +int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) +{ + struct mlx4_en_dev *mdev = priv->mdev; + int err; + + cq->dev = mdev->pndev[priv->port]; + cq->mcq.set_ci_db = cq->wqres.db.db; + cq->mcq.arm_db = cq->wqres.db.db + 1; + *cq->mcq.set_ci_db = 0; + *cq->mcq.arm_db = 0; + memset(cq->buf, 0, cq->buf_size); + + if (!cq->is_tx) + cq->size = priv->rx_ring[cq->ring].actual_size; + + err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar, + cq->wqres.db.dma, &cq->mcq, cq->vector, cq->is_tx); + if (err) + return err; + + cq->mcq.comp = cq->is_tx ? mlx4_en_tx_irq : mlx4_en_rx_irq; + cq->mcq.event = mlx4_en_cq_event; + + if (cq->is_tx) { + init_timer(&cq->timer); + cq->timer.function = mlx4_en_poll_tx_cq; + cq->timer.data = (unsigned long) cq; + } + + return 0; +} + +void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) +{ + struct mlx4_en_dev *mdev = priv->mdev; + + taskqueue_drain(cq->tq, &cq->cq_task); + taskqueue_free(cq->tq); + mlx4_en_unmap_buffer(&cq->wqres.buf); + mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); + cq->buf_size = 0; + cq->buf = NULL; + mtx_destroy(&cq->lock.m); +} + +void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) +{ + struct mlx4_en_dev *mdev = priv->mdev; + + taskqueue_drain(cq->tq, &cq->cq_task); + if (cq->is_tx) + del_timer(&cq->timer); + + mlx4_cq_free(mdev->dev, &cq->mcq); +} + +/* Set rx cq moderation parameters */ +int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) +{ + return mlx4_cq_modify(priv->mdev->dev, &cq->mcq, + cq->moder_cnt, cq->moder_time); +} + +int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) +{ + mlx4_cq_arm(&cq->mcq, MLX4_CQ_DB_REQ_NOT, priv->mdev->uar_map, + &priv->mdev->uar_lock); + + return 0; +} + + diff --git a/sys/ofed/drivers/net/mlx4/en_ethtool.c b/sys/ofed/drivers/net/mlx4/en_ethtool.c new file mode 100644 index 000000000000..9587fb325178 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/en_ethtool.c @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include +#include +#include + +#include "mlx4_en.h" +#include "en_port.h" + + +static void mlx4_en_update_lro_stats(struct mlx4_en_priv *priv) +{ + int i; + + priv->port_stats.lro_aggregated = 0; + priv->port_stats.lro_flushed = 0; + priv->port_stats.lro_no_desc = 0; + + for (i = 0; i < priv->rx_ring_num; i++) { + priv->port_stats.lro_aggregated += priv->rx_ring[i].lro.stats.aggregated; + priv->port_stats.lro_flushed += priv->rx_ring[i].lro.stats.flushed; + priv->port_stats.lro_no_desc += priv->rx_ring[i].lro.stats.no_desc; + } +} + +static void +mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + + sprintf(drvinfo->driver, DRV_NAME " (%s)", mdev->dev->board_id); + strncpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", 32); + sprintf(drvinfo->fw_version, "%d.%d.%d", + (u16) (mdev->dev->caps.fw_ver >> 32), + (u16) ((mdev->dev->caps.fw_ver >> 16) & 0xffff), + (u16) (mdev->dev->caps.fw_ver & 0xffff)); + strncpy(drvinfo->bus_info, pci_name(mdev->dev->pdev), 32); + drvinfo->n_stats = 0; + drvinfo->regdump_len = 0; + drvinfo->eedump_len = 0; +} + +static u32 mlx4_en_get_tso(struct net_device *dev) +{ + return (dev->features & NETIF_F_TSO) != 0; +} + +static int mlx4_en_set_tso(struct net_device *dev, u32 data) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + if (data) { + if (!priv->mdev->LSO_support) + return -EPERM; + dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); +#ifdef HAVE_NETDEV_VLAN_FEATURES + dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6); +#else + if (priv->vlgrp) { + int i; + struct net_device *vdev; + for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { + vdev = vlan_group_get_device(priv->vlgrp, i); + if (vdev) { + vdev->features |= (NETIF_F_TSO | NETIF_F_TSO6); + vlan_group_set_device(priv->vlgrp, i, vdev); + } + } + } +#endif + } else { + dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); +#ifdef HAVE_NETDEV_VLAN_FEATURES + dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_TSO6); +#else + if (priv->vlgrp) { + int i; + struct net_device *vdev; + for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { + vdev = vlan_group_get_device(priv->vlgrp, i); + if (vdev) { + vdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + vlan_group_set_device(priv->vlgrp, i, vdev); + } + } + } +#endif + } + return 0; +} + +static u32 mlx4_en_get_rx_csum(struct net_device *dev) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + return priv->rx_csum; +} + +static int mlx4_en_set_rx_csum(struct net_device *dev, u32 data) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + priv->rx_csum = (data != 0); + return 0; +} + +static const char main_strings[][ETH_GSTRING_LEN] = { + "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", + "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", + "rx_length_errors", "rx_over_errors", "rx_crc_errors", + "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", + "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", + "tx_heartbeat_errors", "tx_window_errors", + + /* port statistics */ + "lro_aggregated", "lro_flushed", "lro_no_desc", "tso_packets", + "queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed", + "rx_csum_good", "rx_csum_none", "tx_chksum_offload", + + /* packet statistics */ + "broadcast", "rx_prio_0", "rx_prio_1", "rx_prio_2", "rx_prio_3", + "rx_prio_4", "rx_prio_5", "rx_prio_6", "rx_prio_7", "tx_prio_0", + "tx_prio_1", "tx_prio_2", "tx_prio_3", "tx_prio_4", "tx_prio_5", + "tx_prio_6", "tx_prio_7", +}; +#define NUM_MAIN_STATS 21 +#define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS) + +static const char mlx4_en_test_names[][ETH_GSTRING_LEN]= { + "Interupt Test", + "Link Test", + "Speed Test", + "Register Test", + "Loopback Test", +}; + +static u32 mlx4_en_get_msglevel(struct net_device *dev) +{ + return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable; +} + +static void mlx4_en_set_msglevel(struct net_device *dev, u32 val) +{ + ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable = val; +} + +static void mlx4_en_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + wol->supported = 0; + wol->wolopts = 0; + + return; +} + +static int mlx4_en_get_sset_count(struct net_device *dev, int sset) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + switch (sset) { + case ETH_SS_STATS: + return NUM_ALL_STATS + + (priv->tx_ring_num + priv->rx_ring_num) * 2; + case ETH_SS_TEST: + return MLX4_EN_NUM_SELF_TEST - !(priv->mdev->dev->caps.loopback_support) * 2; + default: + return -EOPNOTSUPP; + } +} + +static void mlx4_en_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, uint64_t *data) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int index = 0; + int i; + + spin_lock_bh(&priv->stats_lock); + + mlx4_en_update_lro_stats(priv); + + for (i = 0; i < NUM_MAIN_STATS; i++) + data[index++] = ((unsigned long *) &priv->stats)[i]; + for (i = 0; i < NUM_PORT_STATS; i++) + data[index++] = ((unsigned long *) &priv->port_stats)[i]; + for (i = 0; i < priv->tx_ring_num; i++) { + data[index++] = priv->tx_ring[i].packets; + data[index++] = priv->tx_ring[i].bytes; + } + for (i = 0; i < priv->rx_ring_num; i++) { + data[index++] = priv->rx_ring[i].packets; + data[index++] = priv->rx_ring[i].bytes; + } + for (i = 0; i < NUM_PKT_STATS; i++) + data[index++] = ((unsigned long *) &priv->pkstats)[i]; + spin_unlock_bh(&priv->stats_lock); + +} + +static void mlx4_en_self_test(struct net_device *dev, + struct ethtool_test *etest, u64 *buf) +{ + mlx4_en_ex_selftest(dev, &etest->flags, buf); +} + +static void mlx4_en_get_strings(struct net_device *dev, + uint32_t stringset, uint8_t *data) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int index = 0; + int i; + + switch (stringset) { + case ETH_SS_TEST: + for (i = 0; i < MLX4_EN_NUM_SELF_TEST - 2; i++) + strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]); + if (priv->mdev->dev->caps.loopback_support) + for (; i < MLX4_EN_NUM_SELF_TEST; i++) + strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]); + break; + + case ETH_SS_STATS: + /* Add main counters */ + for (i = 0; i < NUM_MAIN_STATS; i++) + strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]); + for (i = 0; i< NUM_PORT_STATS; i++) + strcpy(data + (index++) * ETH_GSTRING_LEN, + main_strings[i + NUM_MAIN_STATS]); + for (i = 0; i < priv->tx_ring_num; i++) { + sprintf(data + (index++) * ETH_GSTRING_LEN, + "tx%d_packets", i); + sprintf(data + (index++) * ETH_GSTRING_LEN, + "tx%d_bytes", i); + } + for (i = 0; i < priv->rx_ring_num; i++) { + sprintf(data + (index++) * ETH_GSTRING_LEN, + "rx%d_packets", i); + sprintf(data + (index++) * ETH_GSTRING_LEN, + "rx%d_bytes", i); + } + for (i = 0; i< NUM_PKT_STATS; i++) + strcpy(data + (index++) * ETH_GSTRING_LEN, + main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]); + break; + } +} + +static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int trans_type; + + cmd->autoneg = AUTONEG_DISABLE; + cmd->supported = SUPPORTED_10000baseT_Full; + cmd->advertising = ADVERTISED_10000baseT_Full; + + if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) + return -ENOMEM; + + trans_type = priv->port_state.transciver; + if (netif_carrier_ok(dev)) { + cmd->speed = priv->port_state.link_speed; + cmd->duplex = DUPLEX_FULL; + } else { + cmd->speed = -1; + cmd->duplex = -1; + } + + if (trans_type > 0 && trans_type <= 0xC) { + cmd->port = PORT_FIBRE; + cmd->transceiver = XCVR_EXTERNAL; + cmd->supported |= SUPPORTED_FIBRE; + cmd->advertising |= ADVERTISED_FIBRE; + } else if (trans_type == 0x80 || trans_type == 0) { + cmd->port = PORT_TP; + cmd->transceiver = XCVR_INTERNAL; + cmd->supported |= SUPPORTED_TP; + cmd->advertising |= ADVERTISED_TP; + } else { + cmd->port = -1; + cmd->transceiver = -1; + } + return 0; +} + +static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + if ((cmd->autoneg == AUTONEG_ENABLE) || + (cmd->speed != SPEED_10000) || (cmd->duplex != DUPLEX_FULL)) + return -EINVAL; + + /* Nothing to change */ + return 0; +} + +static int mlx4_en_get_coalesce(struct net_device *dev, + struct ethtool_coalesce *coal) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + coal->tx_coalesce_usecs = 0; + coal->tx_max_coalesced_frames = 0; + coal->rx_coalesce_usecs = priv->rx_usecs; + coal->rx_max_coalesced_frames = priv->rx_frames; + + coal->pkt_rate_low = priv->pkt_rate_low; + coal->rx_coalesce_usecs_low = priv->rx_usecs_low; + coal->pkt_rate_high = priv->pkt_rate_high; + coal->rx_coalesce_usecs_high = priv->rx_usecs_high; + coal->rate_sample_interval = priv->sample_interval; + coal->use_adaptive_rx_coalesce = priv->adaptive_rx_coal; + return 0; +} + +static int mlx4_en_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *coal) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int err, i; + + priv->rx_frames = (coal->rx_max_coalesced_frames == + MLX4_EN_AUTO_CONF) ? + MLX4_EN_RX_COAL_TARGET / + priv->dev->mtu + 1 : + coal->rx_max_coalesced_frames; + priv->rx_usecs = (coal->rx_coalesce_usecs == + MLX4_EN_AUTO_CONF) ? + MLX4_EN_RX_COAL_TIME : + coal->rx_coalesce_usecs; + + /* Set adaptive coalescing params */ + priv->pkt_rate_low = coal->pkt_rate_low; + priv->rx_usecs_low = coal->rx_coalesce_usecs_low; + priv->pkt_rate_high = coal->pkt_rate_high; + priv->rx_usecs_high = coal->rx_coalesce_usecs_high; + priv->sample_interval = coal->rate_sample_interval; + priv->adaptive_rx_coal = coal->use_adaptive_rx_coalesce; + priv->last_moder_time = MLX4_EN_AUTO_CONF; + if (priv->adaptive_rx_coal) + return 0; + + for (i = 0; i < priv->rx_ring_num; i++) { + priv->rx_cq[i].moder_cnt = priv->rx_frames; + priv->rx_cq[i].moder_time = priv->rx_usecs; + err = mlx4_en_set_cq_moder(priv, &priv->rx_cq[i]); + if (err) + return err; + } + return 0; +} + +static int mlx4_en_set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + int err; + + priv->prof->tx_pause = pause->tx_pause != 0; + priv->prof->rx_pause = pause->rx_pause != 0; + err = mlx4_SET_PORT_general(mdev->dev, priv->port, + priv->rx_mb_size + ETH_FCS_LEN, + priv->prof->tx_pause, + priv->prof->tx_ppp, + priv->prof->rx_pause, + priv->prof->rx_ppp); + if (err) + en_err(priv, "Failed setting pause params\n"); + + return err; +} + +static void mlx4_en_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + pause->tx_pause = priv->prof->tx_pause; + pause->rx_pause = priv->prof->rx_pause; +} + +static int mlx4_en_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *param) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + u32 rx_size, tx_size; + int port_up = 0; + int err = 0; + + if (param->rx_jumbo_pending || param->rx_mini_pending) + return -EINVAL; + + rx_size = roundup_pow_of_two(param->rx_pending); + rx_size = max_t(u32, rx_size, MLX4_EN_MIN_RX_SIZE); + rx_size = min_t(u32, rx_size, MLX4_EN_MAX_RX_SIZE); + tx_size = roundup_pow_of_two(param->tx_pending); + tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE); + tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE); + + if (rx_size == (priv->port_up ? priv->rx_ring[0].actual_size : + priv->rx_ring[0].size) && + tx_size == priv->tx_ring[0].size) + return 0; + + mutex_lock(&mdev->state_lock); + if (priv->port_up) { + port_up = 1; + mlx4_en_stop_port(dev); + } + + mlx4_en_free_resources(priv); + + priv->prof->tx_ring_size = tx_size; + priv->prof->rx_ring_size = rx_size; + + err = mlx4_en_alloc_resources(priv); + if (err) { + en_err(priv, "Failed reallocating port resources\n"); + goto out; + } + if (port_up) { + err = mlx4_en_start_port(dev); + if (err) + en_err(priv, "Failed starting port\n"); + } + +out: + mutex_unlock(&mdev->state_lock); + return err; +} + +static void mlx4_en_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *param) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + memset(param, 0, sizeof(*param)); + param->rx_max_pending = MLX4_EN_MAX_RX_SIZE; + param->tx_max_pending = MLX4_EN_MAX_TX_SIZE; + param->rx_pending = priv->port_up ? + priv->rx_ring[0].actual_size : priv->rx_ring[0].size; + param->tx_pending = priv->tx_ring[0].size; +} + +const struct ethtool_ops mlx4_en_ethtool_ops = { + .get_drvinfo = mlx4_en_get_drvinfo, + .get_settings = mlx4_en_get_settings, + .set_settings = mlx4_en_set_settings, +#ifdef NETIF_F_TSO + .get_tso = mlx4_en_get_tso, + .set_tso = mlx4_en_set_tso, +#endif + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_link = ethtool_op_get_link, + .get_rx_csum = mlx4_en_get_rx_csum, + .set_rx_csum = mlx4_en_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_ipv6_csum, + .get_strings = mlx4_en_get_strings, + .get_sset_count = mlx4_en_get_sset_count, + .get_ethtool_stats = mlx4_en_get_ethtool_stats, + .self_test = mlx4_en_self_test, + .get_wol = mlx4_en_get_wol, + .get_msglevel = mlx4_en_get_msglevel, + .set_msglevel = mlx4_en_set_msglevel, + .get_coalesce = mlx4_en_get_coalesce, + .set_coalesce = mlx4_en_set_coalesce, + .get_pauseparam = mlx4_en_get_pauseparam, + .set_pauseparam = mlx4_en_set_pauseparam, + .get_ringparam = mlx4_en_get_ringparam, + .set_ringparam = mlx4_en_set_ringparam, + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_set_flags, +}; + + + + + diff --git a/sys/ofed/drivers/net/mlx4/en_frag.c b/sys/ofed/drivers/net/mlx4/en_frag.c new file mode 100644 index 000000000000..6c6bac4a9a25 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/en_frag.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include "mlx4_en.h" + +#include +#include +#include + +static struct mlx4_en_ipfrag *find_session(struct mlx4_en_rx_ring *ring, + struct ip *iph) +{ + struct mlx4_en_ipfrag *session; + int i; + + for (i = 0; i < MLX4_EN_NUM_IPFRAG_SESSIONS; i++) { + session = &ring->ipfrag[i]; + if (session->fragments == NULL) + continue; + if (session->daddr == iph->ip_dst.s_addr && + session->saddr == iph->ip_src.s_addr && + session->id == iph->ip_id && + session->protocol == iph->ip_p) { + return session; + } + } + return NULL; +} + +static struct mlx4_en_ipfrag *start_session(struct mlx4_en_rx_ring *ring, + struct ip *iph) +{ + struct mlx4_en_ipfrag *session; + int index = -1; + int i; + + for (i = 0; i < MLX4_EN_NUM_IPFRAG_SESSIONS; i++) { + if (ring->ipfrag[i].fragments == NULL) { + index = i; + break; + } + } + if (index < 0) + return NULL; + + session = &ring->ipfrag[index]; + + return session; +} + + +static void flush_session(struct mlx4_en_priv *priv, + struct mlx4_en_ipfrag *session, + u16 more) +{ + struct mbuf *mb = session->fragments; + struct ip *iph = mb->m_pkthdr.header; + struct net_device *dev = mb->m_pkthdr.rcvif; + + /* Update IP length and checksum */ + iph->ip_len = htons(session->total_len); + iph->ip_off = htons(more | (session->offset >> 3)); + iph->ip_sum = 0; + iph->ip_sum = in_cksum_skip(mb, iph->ip_hl * 4, + (char *)iph - mb->m_data); + + dev->if_input(dev, mb); + session->fragments = NULL; + session->last = NULL; +} + + +static inline void frag_append(struct mlx4_en_priv *priv, + struct mlx4_en_ipfrag *session, + struct mbuf *mb, + unsigned int data_len) +{ + struct mbuf *parent = session->fragments; + + /* Update mb bookkeeping */ + parent->m_pkthdr.len += data_len; + session->total_len += data_len; + + m_adj(mb, mb->m_pkthdr.len - data_len); + + session->last->m_next = mb; + for (; mb->m_next != NULL; mb = mb->m_next); + session->last = mb; +} + +int mlx4_en_rx_frags(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring *ring, + struct mbuf *mb, struct mlx4_cqe *cqe) +{ + struct mlx4_en_ipfrag *session; + struct ip *iph; + u16 ip_len; + u16 ip_hlen; + int data_len; + u16 offset; + + iph = (struct ip *)(mtod(mb, char *) + ETHER_HDR_LEN); + mb->m_pkthdr.header = iph; + ip_len = ntohs(iph->ip_len); + ip_hlen = iph->ip_hl * 4; + data_len = ip_len - ip_hlen; + offset = ntohs(iph->ip_off); + offset &= IP_OFFMASK; + offset <<= 3; + + session = find_session(ring, iph); + if (unlikely(in_cksum_skip(mb, ip_hlen, (char *)iph - mb->m_data))) { + if (session) + flush_session(priv, session, IP_MF); + return -EINVAL; + } + if (session) { + if (unlikely(session->offset + session->total_len != + offset + ip_hlen || + session->total_len + mb->m_pkthdr.len > 65536)) { + flush_session(priv, session, IP_MF); + goto new_session; + } + frag_append(priv, session, mb, data_len); + } else { +new_session: + session = start_session(ring, iph); + if (unlikely(!session)) + return -ENOSPC; + + session->fragments = mb; + session->daddr = iph->ip_dst.s_addr; + session->saddr = iph->ip_src.s_addr; + session->id = iph->ip_id; + session->protocol = iph->ip_p; + session->total_len = ip_len; + session->offset = offset; + for (; mb->m_next != NULL; mb = mb->m_next); + session->last = mb; + } + if (!(ntohs(iph->ip_off) & IP_MF)) + flush_session(priv, session, 0); + + return 0; +} + + +void mlx4_en_flush_frags(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring) +{ + struct mlx4_en_ipfrag *session; + int i; + + for (i = 0; i < MLX4_EN_NUM_IPFRAG_SESSIONS; i++) { + session = &ring->ipfrag[i]; + if (session->fragments) + flush_session(priv, session, IP_MF); + } +} diff --git a/sys/ofed/drivers/net/mlx4/en_main.c b/sys/ofed/drivers/net/mlx4/en_main.c new file mode 100644 index 000000000000..4d75a10f8efb --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/en_main.c @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include +#include + +#include +#include +#include + +#include "mlx4_en.h" + +MODULE_AUTHOR("Liran Liss, Yevgeny Petrilin"); +MODULE_DESCRIPTION("Mellanox ConnectX HCA Ethernet driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRV_VERSION " ("DRV_RELDATE")"); + +static const char mlx4_en_version[] = + DRV_NAME ": Mellanox ConnectX HCA Ethernet driver v" + DRV_VERSION " (" DRV_RELDATE ")\n"; + +#define MLX4_EN_PARM_INT(X, def_val, desc) \ + static unsigned int X = def_val;\ + module_param(X , uint, 0444); \ + MODULE_PARM_DESC(X, desc); + + +/* + * Device scope module parameters + */ + + +/* Enable RSS TCP traffic */ +MLX4_EN_PARM_INT(tcp_rss, 1, + "Enable RSS for incomming TCP traffic or disabled (0)"); +/* Enable RSS UDP traffic */ +MLX4_EN_PARM_INT(udp_rss, 1, + "Enable RSS for incomming UDP traffic or disabled (0)"); + +/* Number of LRO sessions per Rx ring (rounded up to a power of two) */ +MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS, + "Number of LRO sessions per ring or disabled (0)"); + +/* Allow reassembly of fragmented IP packets */ +MLX4_EN_PARM_INT(ip_reasm, 1, "Allow reassembly of fragmented IP packets (!0)"); + +/* Priority pausing */ +MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]." + " Per priority bit mask"); +MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]." + " Per priority bit mask"); + +static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) +{ + struct mlx4_en_profile *params = &mdev->profile; + int i; + + params->tcp_rss = tcp_rss; + params->udp_rss = udp_rss; + if (params->udp_rss && !mdev->dev->caps.udp_rss) { + mlx4_warn(mdev, "UDP RSS is not supported on this device.\n"); + params->udp_rss = 0; + } + params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS); + params->ip_reasm = ip_reasm; + for (i = 1; i <= MLX4_MAX_PORTS; i++) { + params->prof[i].rx_pause = 1; + params->prof[i].rx_ppp = pfcrx; + params->prof[i].tx_pause = 1; + params->prof[i].tx_ppp = pfctx; + params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; + params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; + params->prof[i].tx_ring_num = MLX4_EN_NUM_HASH_RINGS + 1 + + (!!pfcrx) * MLX4_EN_NUM_PPP_RINGS; + } + + return 0; +} + +static void *get_netdev(struct mlx4_dev *dev, void *ctx, u8 port) +{ + struct mlx4_en_dev *endev = ctx; + + return endev->pndev[port]; +} + +static void mlx4_en_event(struct mlx4_dev *dev, void *endev_ptr, + enum mlx4_dev_event event, int port) +{ + struct mlx4_en_dev *mdev = (struct mlx4_en_dev *) endev_ptr; + struct mlx4_en_priv *priv; + + if (!mdev->pndev[port]) + return; + + priv = netdev_priv(mdev->pndev[port]); + switch (event) { + case MLX4_DEV_EVENT_PORT_UP: + case MLX4_DEV_EVENT_PORT_DOWN: + /* To prevent races, we poll the link state in a separate + task rather than changing it here */ + priv->link_state = event; + queue_work(mdev->workqueue, &priv->linkstate_task); + break; + + case MLX4_DEV_EVENT_CATASTROPHIC_ERROR: + mlx4_err(mdev, "Internal error detected, restarting device\n"); + break; + + default: + mlx4_warn(mdev, "Unhandled event: %d\n", event); + } +} + +static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr) +{ + struct mlx4_en_dev *mdev = endev_ptr; + int i; + + mutex_lock(&mdev->state_lock); + mdev->device_up = false; + mutex_unlock(&mdev->state_lock); + + mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) + if (mdev->pndev[i]) + mlx4_en_destroy_netdev(mdev->pndev[i]); + + flush_workqueue(mdev->workqueue); + destroy_workqueue(mdev->workqueue); + mlx4_mr_free(dev, &mdev->mr); + mlx4_uar_free(dev, &mdev->priv_uar); + mlx4_pd_free(dev, mdev->priv_pdn); + sx_destroy(&mdev->state_lock.sx); + mtx_destroy(&mdev->uar_lock.m); + kfree(mdev); +} + +static void *mlx4_en_add(struct mlx4_dev *dev) +{ + static int mlx4_en_version_printed; + struct mlx4_en_dev *mdev; + int i; + int err; + + if (!mlx4_en_version_printed) { + printk(KERN_INFO "%s", mlx4_en_version); + mlx4_en_version_printed++; + } + + mdev = kzalloc(sizeof *mdev, GFP_KERNEL); + if (!mdev) { + dev_err(&dev->pdev->dev, "Device struct alloc failed, " + "aborting.\n"); + err = -ENOMEM; + goto err_free_res; + } + + if (mlx4_pd_alloc(dev, &mdev->priv_pdn)) + goto err_free_dev; + + if (mlx4_uar_alloc(dev, &mdev->priv_uar)) + goto err_pd; + + mtx_init(&mdev->uar_lock.m, "mlx4 uar", NULL, MTX_DEF); + mdev->uar_map = ioremap(mdev->priv_uar.pfn << PAGE_SHIFT, PAGE_SIZE); + if (!mdev->uar_map) + goto err_uar; + + mdev->dev = dev; + mdev->dma_device = &(dev->pdev->dev); + mdev->pdev = dev->pdev; + mdev->device_up = false; + + mdev->LSO_support = !!(dev->caps.flags & (1 << 15)); + if (!mdev->LSO_support) + mlx4_warn(mdev, "LSO not supported, please upgrade to later " + "FW version to enable LSO\n"); + + if (mlx4_mr_alloc(mdev->dev, mdev->priv_pdn, 0, ~0ull, + MLX4_PERM_LOCAL_WRITE | MLX4_PERM_LOCAL_READ, + 0, 0, &mdev->mr)) { + mlx4_err(mdev, "Failed allocating memory region\n"); + goto err_uar; + } + if (mlx4_mr_enable(mdev->dev, &mdev->mr)) { + mlx4_err(mdev, "Failed enabling memory region\n"); + goto err_mr; + } + + /* Build device profile according to supplied module parameters */ + err = mlx4_en_get_profile(mdev); + if (err) { + mlx4_err(mdev, "Bad module parameters, aborting.\n"); + goto err_mr; + } + + /* Configure wich ports to start according to module parameters */ + mdev->port_cnt = 0; + mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) + mdev->port_cnt++; + + /* If we did not receive an explicit number of Rx rings, default to + * the number of completion vectors populated by the mlx4_core */ + mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { + mlx4_info(mdev, "Using %d tx rings for port:%d\n", + mdev->profile.prof[i].tx_ring_num, i); + mdev->profile.prof[i].rx_ring_num = rounddown_pow_of_two( + min_t(int, dev->caps.num_comp_vectors, MAX_RX_RINGS/2)) + + (mdev->profile.udp_rss ? rounddown_pow_of_two( + min_t(int, dev->caps.num_comp_vectors, MAX_RX_RINGS/2)) : 1); + mlx4_info(mdev, "Defaulting to %d rx rings for port:%d\n", + mdev->profile.prof[i].rx_ring_num, i); + } + + /* Create our own workqueue for reset/multicast tasks + * Note: we cannot use the shared workqueue because of deadlocks caused + * by the rtnl lock */ + mdev->workqueue = create_singlethread_workqueue("mlx4_en"); + if (!mdev->workqueue) { + err = -ENOMEM; + goto err_mr; + } + + /* At this stage all non-port specific tasks are complete: + * mark the card state as up */ + sx_init(&mdev->state_lock.sx, "mlxen state"); + mdev->device_up = true; + + /* Setup ports */ + + /* Create a netdev for each port */ + mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { + mlx4_info(mdev, "Activating port:%d\n", i); + if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) { + mdev->pndev[i] = NULL; + goto err_free_netdev; + } + } + return mdev; + + +err_free_netdev: + mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { + if (mdev->pndev[i]) + mlx4_en_destroy_netdev(mdev->pndev[i]); + } + + mutex_lock(&mdev->state_lock); + mdev->device_up = false; + mutex_unlock(&mdev->state_lock); + flush_workqueue(mdev->workqueue); + + /* Stop event queue before we drop down to release shared SW state */ + destroy_workqueue(mdev->workqueue); + +err_mr: + mlx4_mr_free(dev, &mdev->mr); +err_uar: + mtx_destroy(&mdev->uar_lock.m); + mlx4_uar_free(dev, &mdev->priv_uar); +err_pd: + mlx4_pd_free(dev, mdev->priv_pdn); +err_free_dev: + kfree(mdev); +err_free_res: + return NULL; +} + +enum mlx4_query_reply mlx4_en_query(void *endev_ptr, void *int_dev) +{ + struct mlx4_en_dev *mdev = endev_ptr; + struct net_device *netdev = int_dev; + int p; + + for (p = 1; p <= MLX4_MAX_PORTS; ++p) + if (mdev->pndev[p] == netdev) + return p; + + return MLX4_QUERY_NOT_MINE; +} + +#if 0 +static struct pci_device_id mlx4_en_pci_table[] = { + { PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */ + { PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */ + { PCI_VDEVICE(MELLANOX, 0x6354) }, /* MT25408 "Hermon" QDR */ + { PCI_VDEVICE(MELLANOX, 0x6732) }, /* MT25408 "Hermon" DDR PCIe gen2 */ + { PCI_VDEVICE(MELLANOX, 0x673c) }, /* MT25408 "Hermon" QDR PCIe gen2 */ + { PCI_VDEVICE(MELLANOX, 0x6368) }, /* MT25408 "Hermon" EN 10GigE */ + { PCI_VDEVICE(MELLANOX, 0x6750) }, /* MT25408 "Hermon" EN 10GigE PCIe gen2 */ + { PCI_VDEVICE(MELLANOX, 0x6372) }, /* MT25458 ConnectX EN 10GBASE-T 10GigE */ + { PCI_VDEVICE(MELLANOX, 0x675a) }, /* MT25458 ConnectX EN 10GBASE-T+Gen2 10GigE */ + { PCI_VDEVICE(MELLANOX, 0x6764) }, /* MT26468 ConnectX EN 10GigE PCIe gen2 */ + { PCI_VDEVICE(MELLANOX, 0x6746) }, /* MT26438 ConnectX VPI PCIe 2.0 5GT/s - IB QDR / 10GigE Virt+ */ + { PCI_VDEVICE(MELLANOX, 0x676e) }, /* MT26478 ConnectX EN 40GigE PCIe 2.0 5GT/s */ + { PCI_VDEVICE(MELLANOX, 0x6778) }, /* MT26488 ConnectX VPI PCIe 2.0 5GT/s - IB DDR / 10GigE Virt+ */ + { PCI_VDEVICE(MELLANOX, 0x1000) }, + { PCI_VDEVICE(MELLANOX, 0x1001) }, + { PCI_VDEVICE(MELLANOX, 0x1002) }, + { PCI_VDEVICE(MELLANOX, 0x1003) }, + { PCI_VDEVICE(MELLANOX, 0x1004) }, + { PCI_VDEVICE(MELLANOX, 0x1005) }, + { PCI_VDEVICE(MELLANOX, 0x1006) }, + { PCI_VDEVICE(MELLANOX, 0x1007) }, + { PCI_VDEVICE(MELLANOX, 0x1008) }, + { PCI_VDEVICE(MELLANOX, 0x1009) }, + { PCI_VDEVICE(MELLANOX, 0x100a) }, + { PCI_VDEVICE(MELLANOX, 0x100b) }, + { PCI_VDEVICE(MELLANOX, 0x100c) }, + { PCI_VDEVICE(MELLANOX, 0x100d) }, + { PCI_VDEVICE(MELLANOX, 0x100e) }, + { PCI_VDEVICE(MELLANOX, 0x100f) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, mlx4_en_pci_table); +#endif + +static struct mlx4_interface mlx4_en_interface = { + .add = mlx4_en_add, + .remove = mlx4_en_remove, + .event = mlx4_en_event, + .query = mlx4_en_query, + .get_prot_dev = get_netdev, + .protocol = MLX4_PROT_EN, +}; + +static int __init mlx4_en_init(void) +{ + return mlx4_register_interface(&mlx4_en_interface); +} + +static void __exit mlx4_en_cleanup(void) +{ + mlx4_unregister_interface(&mlx4_en_interface); +} + +module_init(mlx4_en_init); +module_exit(mlx4_en_cleanup); + +#undef MODULE_VERSION +#include +static int +mlxen_evhand(module_t mod, int event, void *arg) +{ + return (0); +} +static moduledata_t mlxen_mod = { + .name = "mlxen", + .evhand = mlxen_evhand, +}; +DECLARE_MODULE(mlxen, mlxen_mod, SI_SUB_SMP, SI_ORDER_ANY); +MODULE_DEPEND(mlxen, mlx4, 1, 1, 1); diff --git a/sys/ofed/drivers/net/mlx4/en_netdev.c b/sys/ofed/drivers/net/mlx4/en_netdev.c new file mode 100644 index 000000000000..531f46f00db3 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/en_netdev.c @@ -0,0 +1,1511 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include "mlx4_en.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv); + +static void mlx4_en_vlan_rx_add_vid(void *arg, struct net_device *dev, u16 vid) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int idx; + u8 field; + + if ((vid == 0) || (vid > 4095)) /* Invalid */ + return; + + en_dbg(HW, priv, "adding VLAN:%d\n", vid); + + spin_lock(&priv->vlan_lock); + priv->vlgrp_modified = true; + idx = vid >> 5; + field = 1 << (vid & 0x1f); + if (priv->vlan_unregister[idx] & field) + priv->vlan_unregister[idx] &= ~field; + else + priv->vlan_register[idx] |= field; + priv->vlans[idx] |= field; + spin_unlock(&priv->vlan_lock); +} + +static void mlx4_en_vlan_rx_kill_vid(void *arg, struct net_device *dev, u16 vid) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int idx; + u8 field; + + if ((vid == 0) || (vid > 4095)) /* Invalid */ + return; + en_dbg(HW, priv, "Killing VID:%d\n", vid); + spin_lock(&priv->vlan_lock); + priv->vlgrp_modified = true; + idx = vid >> 5; + field = 1 << (vid & 0x1f); + if (priv->vlan_register[idx] & field) + priv->vlan_register[idx] &= ~field; + else + priv->vlan_unregister[idx] |= field; + priv->vlans[idx] &= ~field; + spin_unlock(&priv->vlan_lock); +} + +u64 mlx4_en_mac_to_u64(u8 *addr) +{ + u64 mac = 0; + int i; + + for (i = 0; i < ETHER_ADDR_LEN; i++) { + mac <<= 8; + mac |= addr[i]; + } + return mac; +} + +static int mlx4_en_cache_mclist(struct net_device *dev, u64 **mcaddrp) +{ + struct ifmultiaddr *ifma;; + u64 *mcaddr; + int cnt; + int i; + + *mcaddrp = NULL; +restart: + cnt = 0; + if_maddr_rlock(dev); + TAILQ_FOREACH(ifma, &dev->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + if (((struct sockaddr_dl *)ifma->ifma_addr)->sdl_alen != + ETHER_ADDR_LEN) + continue; + cnt++; + } + if_maddr_runlock(dev); + if (cnt == 0) + return (0); + mcaddr = kmalloc(sizeof(u64) * cnt, GFP_KERNEL); + if (mcaddr == NULL) + return (0); + i = 0; + if_maddr_rlock(dev); + TAILQ_FOREACH(ifma, &dev->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + if (((struct sockaddr_dl *)ifma->ifma_addr)->sdl_alen != + ETHER_ADDR_LEN) + continue; + /* Make sure the list didn't grow. */ + if (i == cnt) { + if_maddr_runlock(dev); + kfree(mcaddr); + goto restart; + } + mcaddr[i++] = mlx4_en_mac_to_u64( + LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); + } + if_maddr_runlock(dev); + *mcaddrp = mcaddr; + return (i); +} + + +static void mlx4_en_set_multicast(struct net_device *dev) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + + if (!priv->port_up) + return; + + queue_work(priv->mdev->workqueue, &priv->mcast_task); +} + +static void mlx4_en_do_set_multicast(struct work_struct *work) +{ + struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, + mcast_task); + struct net_device *dev = priv->dev; + struct mlx4_en_dev *mdev = priv->mdev; + int err; + + mutex_lock(&mdev->state_lock); + if (!mdev->device_up) { + en_dbg(HW, priv, "Card is not up, " + "ignoring multicast change.\n"); + goto out; + } + if (!priv->port_up) { + en_dbg(HW, priv, "Port is down, " + "ignoring multicast change.\n"); + goto out; + } + + /* + * Promsicuous mode: disable all filters + */ + + if (dev->if_flags & IFF_PROMISC) { + if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) { + priv->flags |= MLX4_EN_FLAG_PROMISC; + + /* Enable promiscouos mode */ + err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, + priv->base_qpn, 1); + if (err) + en_err(priv, "Failed enabling " + "promiscous mode\n"); + + /* Disable port multicast filter (unconditionally) */ + err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, + 0, MLX4_MCAST_DISABLE); + if (err) + en_err(priv, "Failed disabling " + "multicast filter\n"); + + /* Disable port VLAN filter */ + err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, NULL); + if (err) + en_err(priv, "Failed disabling VLAN filter\n"); + } + goto out; + } + + /* + * Not in promiscous mode + */ + + if (priv->flags & MLX4_EN_FLAG_PROMISC) { + priv->flags &= ~MLX4_EN_FLAG_PROMISC; + + /* Disable promiscouos mode */ + err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, + priv->base_qpn, 0); + if (err) + en_err(priv, "Failed disabling promiscous mode\n"); + + /* Enable port VLAN filter */ + err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlans); + if (err) + en_err(priv, "Failed enabling VLAN filter\n"); + } + + /* Enable/disable the multicast filter according to IFF_ALLMULTI */ + if (dev->if_flags & IFF_ALLMULTI) { + err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, + 0, MLX4_MCAST_DISABLE); + if (err) + en_err(priv, "Failed disabling multicast filter\n"); + } else { + u64 *mcaddr; + int mccount; + int i; + + err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, + 0, MLX4_MCAST_DISABLE); + if (err) + en_err(priv, "Failed disabling multicast filter\n"); + + /* Flush mcast filter and init it with broadcast address */ + mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, + 1, MLX4_MCAST_CONFIG); + + /* Update multicast list - we cache all addresses so they won't + * change while HW is updated holding the command semaphor */ + mccount = mlx4_en_cache_mclist(dev, &mcaddr); + for (i = 0; i < mccount; i++) + mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, + mcaddr[i], 0, MLX4_MCAST_CONFIG); + err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, + 0, MLX4_MCAST_ENABLE); + if (err) + en_err(priv, "Failed enabling multicast filter\n"); + + kfree(mcaddr); + } +out: + mutex_unlock(&mdev->state_lock); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void mlx4_en_netpoll(struct net_device *dev) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_cq *cq; + unsigned long flags; + int i; + + for (i = 0; i < priv->rx_ring_num; i++) { + cq = &priv->rx_cq[i]; + spin_lock_irqsave(&cq->lock, flags); + napi_synchronize(&cq->napi); + if (priv->rx_ring[i].use_frags) + mlx4_en_process_rx_cq(dev, cq, 0); + else + mlx4_en_process_rx_cq_mb(dev, cq, 0); + spin_unlock_irqrestore(&cq->lock, flags); + } +} +#endif + +static void mlx4_en_watchdog_timeout(void *arg) +{ + struct mlx4_en_priv *priv = arg; + struct mlx4_en_dev *mdev = priv->mdev; + + en_dbg(DRV, priv, "Scheduling watchdog\n"); + queue_work(mdev->workqueue, &priv->watchdog_task); + if (priv->port_up) + callout_reset(&priv->watchdog_timer, MLX4_EN_WATCHDOG_TIMEOUT, + mlx4_en_watchdog_timeout, priv); +} + + +/* XXX This clears user settings in too many cases. */ +static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) +{ + struct mlx4_en_cq *cq; + int i; + + /* If we haven't received a specific coalescing setting + * (module param), we set the moderation paramters as follows: + * - moder_cnt is set to the number of mtu sized packets to + * satisfy our coelsing target. + * - moder_time is set to a fixed value. + */ + priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->if_mtu + 1; + priv->rx_usecs = MLX4_EN_RX_COAL_TIME; + en_dbg(INTR, priv, "Default coalesing params for mtu:%ld - " + "rx_frames:%d rx_usecs:%d\n", + priv->dev->if_mtu, priv->rx_frames, priv->rx_usecs); + + /* Setup cq moderation params */ + for (i = 0; i < priv->rx_ring_num; i++) { + cq = &priv->rx_cq[i]; + cq->moder_cnt = priv->rx_frames; + cq->moder_time = priv->rx_usecs; + } + + for (i = 0; i < priv->tx_ring_num; i++) { + cq = &priv->tx_cq[i]; + cq->moder_cnt = MLX4_EN_TX_COAL_PKTS; + cq->moder_time = MLX4_EN_TX_COAL_TIME; + } + + /* Reset auto-moderation params */ + priv->pkt_rate_low = MLX4_EN_RX_RATE_LOW; + priv->rx_usecs_low = MLX4_EN_RX_COAL_TIME_LOW; + priv->pkt_rate_high = MLX4_EN_RX_RATE_HIGH; + priv->rx_usecs_high = MLX4_EN_RX_COAL_TIME_HIGH; + priv->sample_interval = MLX4_EN_SAMPLE_INTERVAL; + priv->adaptive_rx_coal = 1; + priv->last_moder_time = MLX4_EN_AUTO_CONF; + priv->last_moder_jiffies = 0; + priv->last_moder_packets = 0; + priv->last_moder_tx_packets = 0; + priv->last_moder_bytes = 0; +} + +static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) +{ + unsigned long period = (unsigned long) (jiffies - priv->last_moder_jiffies); + struct mlx4_en_cq *cq; + unsigned long packets; + unsigned long rate; + unsigned long avg_pkt_size; + unsigned long rx_packets; + unsigned long rx_bytes; + unsigned long tx_packets; + unsigned long tx_pkt_diff; + unsigned long rx_pkt_diff; + int moder_time; + int i, err; + + if (!priv->adaptive_rx_coal || period < priv->sample_interval * HZ) + return; + + spin_lock(&priv->stats_lock); + rx_packets = priv->dev->if_ipackets; + rx_bytes = priv->dev->if_ibytes; + tx_packets = priv->dev->if_opackets; + spin_unlock(&priv->stats_lock); + + if (!priv->last_moder_jiffies || !period) + goto out; + + tx_pkt_diff = ((unsigned long) (tx_packets - + priv->last_moder_tx_packets)); + rx_pkt_diff = ((unsigned long) (rx_packets - + priv->last_moder_packets)); + packets = max(tx_pkt_diff, rx_pkt_diff); + rate = packets * HZ / period; + avg_pkt_size = packets ? ((unsigned long) (rx_bytes - + priv->last_moder_bytes)) / packets : 0; + + /* Apply auto-moderation only when packet rate exceeds a rate that + * it matters */ + if (rate > MLX4_EN_RX_RATE_THRESH) { + /* If tx and rx packet rates are not balanced, assume that + * traffic is mainly BW bound and apply maximum moderation. + * Otherwise, moderate according to packet rate */ + if (2 * tx_pkt_diff > 3 * rx_pkt_diff || + 2 * rx_pkt_diff > 3 * tx_pkt_diff) { + moder_time = priv->rx_usecs_high; + } else { + if (rate < priv->pkt_rate_low || + avg_pkt_size < MLX4_EN_AVG_PKT_SMALL) + moder_time = priv->rx_usecs_low; + else if (rate > priv->pkt_rate_high) + moder_time = priv->rx_usecs_high; + else + moder_time = (rate - priv->pkt_rate_low) * + (priv->rx_usecs_high - priv->rx_usecs_low) / + (priv->pkt_rate_high - priv->pkt_rate_low) + + priv->rx_usecs_low; + } + } else { + /* When packet rate is low, use default moderation rather than + * 0 to prevent interrupt storms if traffic suddenly increases */ + moder_time = priv->rx_usecs; + } + + en_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n", + tx_pkt_diff * HZ / period, rx_pkt_diff * HZ / period); + + en_dbg(INTR, priv, "Rx moder_time changed from:%d to %d period:%lu " + "[jiff] packets:%lu avg_pkt_size:%lu rate:%lu [p/s])\n", + priv->last_moder_time, moder_time, period, packets, + avg_pkt_size, rate); + + if (moder_time != priv->last_moder_time) { + priv->last_moder_time = moder_time; + for (i = 0; i < priv->rx_ring_num; i++) { + cq = &priv->rx_cq[i]; + cq->moder_time = moder_time; + err = mlx4_en_set_cq_moder(priv, cq); + if (err) { + en_err(priv, "Failed modifying moderation for cq:%d\n", i); + break; + } + } + } + +out: + priv->last_moder_packets = rx_packets; + priv->last_moder_tx_packets = tx_packets; + priv->last_moder_bytes = rx_bytes; + priv->last_moder_jiffies = jiffies; +} + +static void mlx4_en_handle_vlans(struct mlx4_en_priv *priv) +{ + u8 vlan_register[VLAN_FLTR_SIZE]; + u8 vlan_unregister[VLAN_FLTR_SIZE]; + int i, j, idx; + u16 vid; + + /* cache the vlan data for processing + * done under lock to avoid changes during work */ + spin_lock(&priv->vlan_lock); + for (i = 0; i < VLAN_FLTR_SIZE; i++) { + vlan_register[i] = priv->vlan_register[i]; + priv->vlan_register[i] = 0; + vlan_unregister[i] = priv->vlan_unregister[i]; + priv->vlan_unregister[i] = 0; + } + priv->vlgrp_modified = false; + spin_unlock(&priv->vlan_lock); + + /* Configure the vlan filter + * The vlgrp is updated with all the vids that need to be allowed */ + if (mlx4_SET_VLAN_FLTR(priv->mdev->dev, priv->port, priv->vlans)) + en_err(priv, "Failed configuring VLAN filter\n"); + + /* Configure the VLAN table */ + for (i = 0; i < VLAN_FLTR_SIZE; i++) { + for (j = 0; j < 32; j++) { + vid = (i << 5) + j; + if (vlan_register[i] & (1 << j)) + if (mlx4_register_vlan(priv->mdev->dev, priv->port, vid, &idx)) + en_dbg(HW, priv, "failed registering vlan %d\n", vid); + if (vlan_unregister[i] & (1 << j)) { + if (!mlx4_find_cached_vlan(priv->mdev->dev, priv->port, vid, &idx)) + mlx4_unregister_vlan(priv->mdev->dev, priv->port, idx); + else + en_dbg(HW, priv, "could not find vid %d in cache\n", vid); + } + } + } +} + +static void mlx4_en_do_get_stats(struct work_struct *work) +{ + struct delayed_work *delay = to_delayed_work(work); + struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, + stats_task); + struct mlx4_en_dev *mdev = priv->mdev; + int err; + + err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0); + if (err) + en_dbg(HW, priv, "Could not update stats \n"); + + + mutex_lock(&mdev->state_lock); + if (mdev->device_up) { + if (priv->port_up) { + if (priv->vlgrp_modified) + mlx4_en_handle_vlans(priv); + + mlx4_en_auto_moderation(priv); + } + + queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); + } + if (mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port]) { + panic("mlx4_en_do_get_stats: Unexpected mac removed for %d\n", + priv->port); + mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port] = 0; + } + mutex_unlock(&mdev->state_lock); +} + +static void mlx4_en_linkstate(struct work_struct *work) +{ + struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, + linkstate_task); + struct mlx4_en_dev *mdev = priv->mdev; + int linkstate = priv->link_state; + + mutex_lock(&mdev->state_lock); + /* If observable port state changed set carrier state and + * report to system log */ + if (priv->last_link_state != linkstate) { + if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) { + if_link_state_change(priv->dev, LINK_STATE_DOWN); + } else { + en_info(priv, "Link Up\n"); + if_link_state_change(priv->dev, LINK_STATE_UP); + } + } + priv->last_link_state = linkstate; + mutex_unlock(&mdev->state_lock); +} + + +int mlx4_en_start_port(struct net_device *dev) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + struct mlx4_en_cq *cq; + struct mlx4_en_tx_ring *tx_ring; + int rx_index = 0; + int tx_index = 0; + int err = 0; + int i; + int j; + + if (priv->port_up) { + en_dbg(DRV, priv, "start port called while port already up\n"); + return 0; + } + + /* Calculate Rx buf size */ + dev->if_mtu = min(dev->if_mtu, priv->max_mtu); + mlx4_en_calc_rx_buf(dev); + en_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_mb_size); + + /* Configure rx cq's and rings */ + err = mlx4_en_activate_rx_rings(priv); + if (err) { + en_err(priv, "Failed to activate RX rings\n"); + return err; + } + + for (i = 0; i < priv->rx_ring_num; i++) { + cq = &priv->rx_cq[i]; + + err = mlx4_en_activate_cq(priv, cq); + if (err) { + en_err(priv, "Failed activating Rx CQ\n"); + goto cq_err; + } + for (j = 0; j < cq->size; j++) + cq->buf[j].owner_sr_opcode = MLX4_CQE_OWNER_MASK; + err = mlx4_en_set_cq_moder(priv, cq); + if (err) { + en_err(priv, "Failed setting cq moderation parameters"); + mlx4_en_deactivate_cq(priv, cq); + goto cq_err; + } + mlx4_en_arm_cq(priv, cq); + priv->rx_ring[i].cqn = cq->mcq.cqn; + ++rx_index; + } + + err = mlx4_en_config_rss_steer(priv); + if (err) { + en_err(priv, "Failed configuring rss steering\n"); + goto cq_err; + } + + /* Configure tx cq's and rings */ + for (i = 0; i < priv->tx_ring_num; i++) { + /* Configure cq */ + cq = &priv->tx_cq[i]; + err = mlx4_en_activate_cq(priv, cq); + if (err) { + en_err(priv, "Failed allocating Tx CQ\n"); + goto tx_err; + } + err = mlx4_en_set_cq_moder(priv, cq); + if (err) { + en_err(priv, "Failed setting cq moderation parameters"); + mlx4_en_deactivate_cq(priv, cq); + goto tx_err; + } + en_dbg(DRV, priv, "Resetting index of collapsed CQ:%d to -1\n", i); + cq->buf->wqe_index = cpu_to_be16(0xffff); + + /* Configure ring */ + tx_ring = &priv->tx_ring[i]; + err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn); + if (err) { + en_err(priv, "Failed allocating Tx ring\n"); + mlx4_en_deactivate_cq(priv, cq); + goto tx_err; + } + /* Set initial ownership of all Tx TXBBs to SW (1) */ + for (j = 0; j < tx_ring->buf_size; j += STAMP_STRIDE) + *((u32 *) (tx_ring->buf + j)) = 0xffffffff; + ++tx_index; + } + + /* Configure port */ + err = mlx4_SET_PORT_general(mdev->dev, priv->port, + priv->rx_mb_size + ETHER_CRC_LEN, + priv->prof->tx_pause, + priv->prof->tx_ppp, + priv->prof->rx_pause, + priv->prof->rx_ppp); + if (err) { + en_err(priv, "Failed setting port general configurations " + "for port %d, with error %d\n", priv->port, err); + goto tx_err; + } + /* Set default qp number */ + err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0); + if (err) { + en_err(priv, "Failed setting default qp numbers\n"); + goto tx_err; + } + /* Set port mac number */ + en_dbg(DRV, priv, "Setting mac for port %d\n", priv->port); + err = mlx4_register_mac(mdev->dev, priv->port, + mlx4_en_mac_to_u64(IF_LLADDR(dev)), + &priv->mac_index); + if (err) { + en_err(priv, "Failed setting port mac\n"); + goto tx_err; + } + mdev->mac_removed[priv->port] = 0; + + /* Init port */ + en_dbg(HW, priv, "Initializing port\n"); + err = mlx4_INIT_PORT(mdev->dev, priv->port); + if (err) { + en_err(priv, "Failed Initializing port\n"); + goto mac_err; + } + + /* Set the various hardware offload abilities */ + dev->if_hwassist = 0; + if (dev->if_capenable & IFCAP_TSO4) + dev->if_hwassist |= CSUM_TSO; + if (dev->if_capenable & IFCAP_TXCSUM) + dev->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP); + if (dev->if_capenable & IFCAP_RXCSUM) + priv->rx_csum = 1; + else + priv->rx_csum = 0; + + priv->port_up = true; + + /* Populate multicast list */ + mlx4_en_set_multicast(dev); + + /* Enable the queues. */ + atomic_clear_int(&dev->if_drv_flags, IFF_DRV_OACTIVE); + atomic_set_int(&dev->if_drv_flags, IFF_DRV_RUNNING); + + callout_reset(&priv->watchdog_timer, MLX4_EN_WATCHDOG_TIMEOUT, + mlx4_en_watchdog_timeout, priv); + + return 0; + +mac_err: + mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index); +tx_err: + while (tx_index--) { + mlx4_en_deactivate_tx_ring(priv, &priv->tx_ring[tx_index]); + mlx4_en_deactivate_cq(priv, &priv->tx_cq[tx_index]); + } + + mlx4_en_release_rss_steer(priv); +cq_err: + while (rx_index--) + mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]); + for (i = 0; i < priv->rx_ring_num; i++) + mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]); + + return err; /* need to close devices */ +} + + +void mlx4_en_stop_port(struct net_device *dev) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + int i; + + if (!priv->port_up) { + en_dbg(DRV, priv, "stop port called while port already down\n"); + return; + } + + /* Set port as not active */ + priv->port_up = false; + + /* Unregister Mac address for the port */ + mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index); + mdev->mac_removed[priv->port] = 1; + + /* Free TX Rings */ + for (i = 0; i < priv->tx_ring_num; i++) { + mlx4_en_deactivate_tx_ring(priv, &priv->tx_ring[i]); + mlx4_en_deactivate_cq(priv, &priv->tx_cq[i]); + } + msleep(10); + + for (i = 0; i < priv->tx_ring_num; i++) + mlx4_en_free_tx_buf(dev, &priv->tx_ring[i]); + + /* Free RSS qps */ + mlx4_en_release_rss_steer(priv); + + /* Free RX Rings */ + for (i = 0; i < priv->rx_ring_num; i++) { + mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]); + mlx4_en_deactivate_cq(priv, &priv->rx_cq[i]); + } + + /* close port*/ + mlx4_CLOSE_PORT(mdev->dev, priv->port); + + callout_stop(&priv->watchdog_timer); + + atomic_clear_int(&dev->if_drv_flags, IFF_DRV_RUNNING); +} + +static void mlx4_en_restart(struct work_struct *work) +{ + struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, + watchdog_task); + struct mlx4_en_dev *mdev = priv->mdev; + struct net_device *dev = priv->dev; + struct mlx4_en_tx_ring *ring; + int i; + + if (priv->blocked == 0 || priv->port_up == 0) + return; + for (i = 0; i < priv->tx_ring_num; i++) { + ring = &priv->tx_ring[i]; + if (ring->blocked && + ring->watchdog_time + MLX4_EN_WATCHDOG_TIMEOUT < ticks) + goto reset; + } + return; + +reset: + priv->port_stats.tx_timeout++; + en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port); + + mutex_lock(&mdev->state_lock); + if (priv->port_up) { + mlx4_en_stop_port(dev); + if (mlx4_en_start_port(dev)) + en_err(priv, "Failed restarting port %d\n", priv->port); + } + mutex_unlock(&mdev->state_lock); +} + + +static void +mlx4_en_init(void *arg) +{ + struct mlx4_en_priv *priv; + struct mlx4_en_dev *mdev; + struct ifnet *dev; + int i; + + priv = arg; + dev = priv->dev; + mdev = priv->mdev; + mutex_lock(&mdev->state_lock); + if (dev->if_drv_flags & IFF_DRV_RUNNING) + mlx4_en_stop_port(dev); + + if (!mdev->device_up) { + en_err(priv, "Cannot open - device down/disabled\n"); + goto out; + } + + /* Reset HW statistics and performance counters */ + if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1)) + en_dbg(HW, priv, "Failed dumping statistics\n"); + + memset(&priv->pstats, 0, sizeof(priv->pstats)); + + for (i = 0; i < priv->tx_ring_num; i++) { + priv->tx_ring[i].bytes = 0; + priv->tx_ring[i].packets = 0; + } + for (i = 0; i < priv->rx_ring_num; i++) { + priv->rx_ring[i].bytes = 0; + priv->rx_ring[i].packets = 0; + } + + mlx4_en_set_default_moderation(priv); + if (mlx4_en_start_port(dev)) + en_err(priv, "Failed starting port:%d\n", priv->port); + +out: + mutex_unlock(&mdev->state_lock); +} + +void mlx4_en_free_resources(struct mlx4_en_priv *priv) +{ + int i; + + for (i = 0; i < priv->tx_ring_num; i++) { + if (priv->tx_ring[i].tx_info) + mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]); + if (priv->tx_cq[i].buf) + mlx4_en_destroy_cq(priv, &priv->tx_cq[i]); + } + + for (i = 0; i < priv->rx_ring_num; i++) { + if (priv->rx_ring[i].rx_info) + mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i]); + if (priv->rx_cq[i].buf) + mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); + } + /* Free the stats tree when we resize the rings. */ + if (priv->sysctl) + sysctl_ctx_free(&priv->stat_ctx); + +} + +int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) +{ + struct mlx4_en_port_profile *prof = priv->prof; + int i; + + /* Create tx Rings */ + for (i = 0; i < priv->tx_ring_num; i++) { + if (mlx4_en_create_cq(priv, &priv->tx_cq[i], + prof->tx_ring_size, i, TX)) + goto err; + + if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i], + prof->tx_ring_size, TXBB_SIZE)) + goto err; + } + + /* Create rx Rings */ + for (i = 0; i < priv->rx_ring_num; i++) { + if (mlx4_en_create_cq(priv, &priv->rx_cq[i], + prof->rx_ring_size, i, RX)) + goto err; + + if (i > priv->rx_ring_num - priv->udp_rings - 1) + priv->rx_ring[i].use_frags = 0; + else + priv->rx_ring[i].use_frags = 1; + if (mlx4_en_create_rx_ring(priv, &priv->rx_ring[i], + prof->rx_ring_size)) + goto err; + } + + /* Re-create stat sysctls in case the number of rings changed. */ + mlx4_en_sysctl_stat(priv); + + /* Populate Tx priority mappings */ + mlx4_en_set_prio_map(priv, priv->tx_prio_map, + prof->tx_ring_num - MLX4_EN_NUM_HASH_RINGS); + + return 0; + +err: + en_err(priv, "Failed to allocate NIC resources\n"); + return -ENOMEM; +} + + +void mlx4_en_destroy_netdev(struct net_device *dev) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + + en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port); + + if (priv->vlan_attach != NULL) + EVENTHANDLER_DEREGISTER(vlan_config, priv->vlan_attach); + if (priv->vlan_detach != NULL) + EVENTHANDLER_DEREGISTER(vlan_unconfig, priv->vlan_detach); + + /* Unregister device - this will close the port if it was up */ + if (priv->registered) + ether_ifdetach(dev); + + if (priv->allocated) + mlx4_free_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE); + + if (priv->sysctl) + sysctl_ctx_free(&priv->conf_ctx); + + cancel_delayed_work(&priv->stats_task); + /* flush any pending task for this netdev */ + flush_workqueue(mdev->workqueue); + + /* Detach the netdev so tasks would not attempt to access it */ + mutex_lock(&mdev->state_lock); + mdev->pndev[priv->port] = NULL; + mutex_unlock(&mdev->state_lock); + + mlx4_en_free_resources(priv); + mtx_destroy(&priv->stats_lock.m); + mtx_destroy(&priv->vlan_lock.m); + kfree(priv); + if_free(dev); +} + +static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + int err = 0; + + en_dbg(DRV, priv, "Change MTU called - current:%ld new:%d\n", + dev->if_mtu, new_mtu); + + if ((new_mtu < MLX4_EN_MIN_MTU) || (new_mtu > priv->max_mtu)) { + en_err(priv, "Bad MTU size:%d.\n", new_mtu); + return -EPERM; + } + mutex_lock(&mdev->state_lock); + dev->if_mtu = new_mtu; + if (dev->if_drv_flags & IFF_DRV_RUNNING) { + if (!mdev->device_up) { + /* NIC is probably restarting - let watchdog task reset + * the port */ + en_dbg(DRV, priv, "Change MTU called with card down!?\n"); + } else { + mlx4_en_stop_port(dev); + mlx4_en_set_default_moderation(priv); + err = mlx4_en_start_port(dev); + if (err) { + en_err(priv, "Failed restarting port:%d\n", + priv->port); + queue_work(mdev->workqueue, &priv->watchdog_task); + } + } + } + mutex_unlock(&mdev->state_lock); + return 0; +} + +static int mlx4_en_calc_media(struct mlx4_en_priv *priv) +{ + int trans_type; + int active; + + active = IFM_ETHER; + if (priv->last_link_state == MLX4_DEV_EVENT_PORT_DOWN) + return (active); + if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) + return (active); + active |= IFM_FDX; + trans_type = priv->port_state.transciver; + /* XXX I don't know all of the transceiver values. */ + if (priv->port_state.link_speed == 1000) + active |= IFM_1000_T; + else if (trans_type > 0 && trans_type <= 0xC) + active |= IFM_10G_SR; + else if (trans_type == 0x80 || trans_type == 0) + active |= IFM_10G_CX4; + if (priv->prof->tx_pause) + active |= IFM_ETH_TXPAUSE; + if (priv->prof->rx_pause) + active |= IFM_ETH_RXPAUSE; + + return (active); +} + + +static void mlx4_en_media_status(struct ifnet *dev, struct ifmediareq *ifmr) +{ + struct mlx4_en_priv *priv; + + priv = dev->if_softc; + ifmr->ifm_status = IFM_AVALID; + if (priv->last_link_state != MLX4_DEV_EVENT_PORT_DOWN) + ifmr->ifm_status |= IFM_ACTIVE; + ifmr->ifm_active = mlx4_en_calc_media(priv); + + return; +} + +static int mlx4_en_media_change(struct ifnet *dev) +{ + struct mlx4_en_priv *priv; + struct ifmedia *ifm; + int rxpause; + int txpause; + int error; + + priv = dev->if_softc; + ifm = &priv->media; + rxpause = txpause = 0; + error = 0; + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return (EINVAL); + switch (IFM_SUBTYPE(ifm->ifm_media)) { + case IFM_AUTO: + break; + case IFM_10G_SR: + case IFM_10G_CX4: + case IFM_1000_T: + if (IFM_SUBTYPE(ifm->ifm_media) == + IFM_SUBTYPE(mlx4_en_calc_media(priv)) && + (ifm->ifm_media & IFM_FDX)) + break; + /* Fallthrough */ + default: + printf("%s: Only auto media type\n", if_name(dev)); + return (EINVAL); + } + /* Allow user to set/clear pause */ + if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_RXPAUSE) + rxpause = 1; + if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_TXPAUSE) + txpause = 1; + if (priv->prof->tx_pause != txpause || priv->prof->rx_pause != rxpause) { + priv->prof->tx_pause = txpause; + priv->prof->rx_pause = rxpause; + error = -mlx4_SET_PORT_general(priv->mdev->dev, priv->port, + priv->rx_mb_size + ETHER_CRC_LEN, priv->prof->tx_pause, + priv->prof->tx_ppp, priv->prof->rx_pause, + priv->prof->rx_ppp); + } + return (error); +} + +static int mlx4_en_ioctl(struct ifnet *dev, u_long command, caddr_t data) +{ + struct mlx4_en_priv *priv; + struct mlx4_en_dev *mdev; + struct ifreq *ifr; + int error; + int mask; + + error = 0; + mask = 0; + priv = dev->if_softc; + mdev = priv->mdev; + ifr = (struct ifreq *) data; + switch (command) { + case SIOCSIFMTU: + error = -mlx4_en_change_mtu(dev, ifr->ifr_mtu); + break; + case SIOCSIFFLAGS: + if (dev->if_flags & IFF_UP) { + if ((dev->if_drv_flags & IFF_DRV_RUNNING) == 0) { + mutex_lock(&mdev->state_lock); + mlx4_en_start_port(dev); + mutex_unlock(&mdev->state_lock); + } else + mlx4_en_set_multicast(dev); + } else { + mutex_lock(&mdev->state_lock); + if (dev->if_drv_flags & IFF_DRV_RUNNING) { + mlx4_en_stop_port(dev); + if_link_state_change(dev, LINK_STATE_DOWN); + } + mutex_unlock(&mdev->state_lock); + } + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + mlx4_en_set_multicast(dev); + break; + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + error = ifmedia_ioctl(dev, ifr, &priv->media, command); + break; + case SIOCSIFCAP: + mask = ifr->ifr_reqcap ^ dev->if_capenable; + if (mask & IFCAP_HWCSUM) + dev->if_capenable ^= IFCAP_HWCSUM; + if (mask & IFCAP_TSO4) + dev->if_capenable ^= IFCAP_TSO4; + if (mask & IFCAP_LRO) + dev->if_capenable ^= IFCAP_LRO; + if (mask & IFCAP_VLAN_HWTAGGING) + dev->if_capenable ^= IFCAP_VLAN_HWTAGGING; + if (mask & IFCAP_VLAN_HWFILTER) + dev->if_capenable ^= IFCAP_VLAN_HWFILTER; + if (dev->if_drv_flags & IFF_DRV_RUNNING) + mlx4_en_init(priv); + VLAN_CAPABILITIES(dev); + break; + default: + error = ether_ioctl(dev, command, data); + break; + } + + return (error); +} + +static int mlx4_en_set_ring_size(struct net_device *dev, + int rx_size, int tx_size) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + int port_up = 0; + int err = 0; + + rx_size = roundup_pow_of_two(rx_size); + rx_size = max_t(u32, rx_size, MLX4_EN_MIN_RX_SIZE); + rx_size = min_t(u32, rx_size, MLX4_EN_MAX_RX_SIZE); + tx_size = roundup_pow_of_two(tx_size); + tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE); + tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE); + + if (rx_size == (priv->port_up ? + priv->rx_ring[0].actual_size : priv->rx_ring[0].size) && + tx_size == priv->tx_ring[0].size) + return 0; + + mutex_lock(&mdev->state_lock); + if (priv->port_up) { + port_up = 1; + mlx4_en_stop_port(dev); + } + mlx4_en_free_resources(priv); + priv->prof->tx_ring_size = tx_size; + priv->prof->rx_ring_size = rx_size; + err = mlx4_en_alloc_resources(priv); + if (err) { + en_err(priv, "Failed reallocating port resources\n"); + goto out; + } + if (port_up) { + err = mlx4_en_start_port(dev); + if (err) + en_err(priv, "Failed starting port\n"); + } +out: + mutex_unlock(&mdev->state_lock); + return err; +} + +static int mlx4_en_set_rx_ring_size(SYSCTL_HANDLER_ARGS) +{ + struct mlx4_en_priv *priv; + int size; + int error; + + priv = arg1; + size = priv->prof->rx_ring_size; + error = sysctl_handle_int(oidp, &size, 0, req); + if (error || !req->newptr) + return (error); + error = -mlx4_en_set_ring_size(priv->dev, size, + priv->prof->tx_ring_size); + + return (error); +} + +static int mlx4_en_set_tx_ring_size(SYSCTL_HANDLER_ARGS) +{ + struct mlx4_en_priv *priv; + int size; + int error; + + priv = arg1; + size = priv->prof->tx_ring_size; + error = sysctl_handle_int(oidp, &size, 0, req); + if (error || !req->newptr) + return (error); + error = -mlx4_en_set_ring_size(priv->dev, priv->prof->rx_ring_size, + size); + + return (error); +} + +static void mlx4_en_sysctl_conf(struct mlx4_en_priv *priv) +{ + struct net_device *dev; + struct sysctl_ctx_list *ctx; + struct sysctl_oid *node; + struct sysctl_oid_list *node_list; + struct sysctl_oid *coal; + struct sysctl_oid_list *coal_list; + + dev = priv->dev; + ctx = &priv->conf_ctx; + + sysctl_ctx_init(ctx); + priv->sysctl = SYSCTL_ADD_NODE(ctx, SYSCTL_STATIC_CHILDREN(_hw), + OID_AUTO, dev->if_xname, CTLFLAG_RD, 0, "mlx4 10gig ethernet"); + node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->sysctl), OID_AUTO, + "conf", CTLFLAG_RD, NULL, "Configuration"); + node_list = SYSCTL_CHILDREN(node); + + SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "msg_enable", + CTLFLAG_RW, &priv->msg_enable, 0, + "Driver message enable bitfield"); + SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "rx_rings", + CTLTYPE_INT | CTLFLAG_RD, &priv->rx_ring_num, 0, + "Number of receive rings"); + SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_rings", + CTLTYPE_INT | CTLFLAG_RD, &priv->tx_ring_num, 0, + "Number of transmit rings"); + SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "rx_size", + CTLTYPE_INT | CTLFLAG_RW, priv, 0, mlx4_en_set_rx_ring_size, "I", + "Receive ring size"); + SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "tx_size", + CTLTYPE_INT | CTLFLAG_RW, priv, 0, mlx4_en_set_tx_ring_size, "I", + "Transmit ring size"); + SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "ip_reasm", + CTLFLAG_RD, &priv->mdev->profile.ip_reasm, 0, + "Allow reassembly of IP fragments."); + + /* Add coalescer configuration. */ + coal = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, + "coalesce", CTLFLAG_RD, NULL, "Interrupt coalesce configuration"); + coal_list = SYSCTL_CHILDREN(node); + SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "pkt_rate_low", + CTLFLAG_RW, &priv->pkt_rate_low, 0, + "Packets per-second for minimum delay"); + SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "rx_usecs_low", + CTLFLAG_RW, &priv->rx_usecs_low, 0, + "Minimum RX delay in micro-seconds"); + SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "pkt_rate_high", + CTLFLAG_RW, &priv->pkt_rate_high, 0, + "Packets per-second for maximum delay"); + SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "rx_usecs_high", + CTLFLAG_RW, &priv->rx_usecs_high, 0, + "Maximum RX delay in micro-seconds"); + SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "sample_interval", + CTLFLAG_RW, &priv->sample_interval, 0, + "adaptive frequency in units of HZ ticks"); + SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "adaptive_rx_coal", + CTLFLAG_RW, &priv->adaptive_rx_coal, 0, + "Enable adaptive rx coalescing"); +} + +static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv) +{ + struct net_device *dev; + struct sysctl_ctx_list *ctx; + struct sysctl_oid *node; + struct sysctl_oid_list *node_list; + struct sysctl_oid *ring_node; + struct sysctl_oid_list *ring_list; + struct mlx4_en_tx_ring *tx_ring; + struct mlx4_en_rx_ring *rx_ring; + char namebuf[128]; + int i; + + dev = priv->dev; + + ctx = &priv->stat_ctx; + sysctl_ctx_init(ctx); + node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->sysctl), OID_AUTO, + "stat", CTLFLAG_RD, NULL, "Statistics"); + node_list = SYSCTL_CHILDREN(node); + +#ifdef MLX4_EN_PERF_STAT + SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_poll", CTLFLAG_RD, + &priv->pstats.tx_poll, "TX Poll calls"); + SYSCTL_ADD_QUAD(ctx, node_list, OID_AUTO, "tx_pktsz_avg", CTLFLAG_RD, + &priv->pstats.tx_pktsz_avg, "TX average packet size"); + SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "inflight_avg", CTLFLAG_RD, + &priv->pstats.inflight_avg, "TX average packets in-flight"); + SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_coal_avg", CTLFLAG_RD, + &priv->pstats.tx_coal_avg, "TX average coalesced completions"); + SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "rx_coal_avg", CTLFLAG_RD, + &priv->pstats.rx_coal_avg, "RX average coalesced completions"); +#endif + + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tso_packets", CTLFLAG_RD, + &priv->port_stats.tso_packets, "TSO packets sent"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "queue_stopped", CTLFLAG_RD, + &priv->port_stats.queue_stopped, "Queue full"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "wake_queue", CTLFLAG_RD, + &priv->port_stats.wake_queue, "Queue resumed after full"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_timeout", CTLFLAG_RD, + &priv->port_stats.tx_timeout, "Transmit timeouts"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_alloc_failed", CTLFLAG_RD, + &priv->port_stats.rx_alloc_failed, "RX failed to allocate mbuf"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_chksum_good", CTLFLAG_RD, + &priv->port_stats.rx_chksum_good, "RX checksum offload success"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_chksum_none", CTLFLAG_RD, + &priv->port_stats.rx_chksum_none, "RX without checksum offload"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_chksum_offload", + CTLFLAG_RD, &priv->port_stats.tx_chksum_offload, + "TX checksum offloads"); + + /* Could strdup the names and add in a loop. This is simpler. */ + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "broadcast", CTLFLAG_RD, + &priv->pkstats.broadcast, "Broadcast packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_prio0", CTLFLAG_RD, + &priv->pkstats.tx_prio[0], "TX Priority 0 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_prio1", CTLFLAG_RD, + &priv->pkstats.tx_prio[1], "TX Priority 1 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_prio2", CTLFLAG_RD, + &priv->pkstats.tx_prio[2], "TX Priority 2 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_prio3", CTLFLAG_RD, + &priv->pkstats.tx_prio[3], "TX Priority 3 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_prio4", CTLFLAG_RD, + &priv->pkstats.tx_prio[4], "TX Priority 4 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_prio5", CTLFLAG_RD, + &priv->pkstats.tx_prio[5], "TX Priority 5 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_prio6", CTLFLAG_RD, + &priv->pkstats.tx_prio[6], "TX Priority 6 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_prio7", CTLFLAG_RD, + &priv->pkstats.tx_prio[7], "TX Priority 7 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_prio0", CTLFLAG_RD, + &priv->pkstats.rx_prio[0], "RX Priority 0 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_prio1", CTLFLAG_RD, + &priv->pkstats.rx_prio[1], "RX Priority 1 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_prio2", CTLFLAG_RD, + &priv->pkstats.rx_prio[2], "RX Priority 2 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_prio3", CTLFLAG_RD, + &priv->pkstats.rx_prio[3], "RX Priority 3 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_prio4", CTLFLAG_RD, + &priv->pkstats.rx_prio[4], "RX Priority 4 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_prio5", CTLFLAG_RD, + &priv->pkstats.rx_prio[5], "RX Priority 5 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_prio6", CTLFLAG_RD, + &priv->pkstats.rx_prio[6], "RX Priority 6 packets"); + SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_prio7", CTLFLAG_RD, + &priv->pkstats.rx_prio[7], "RX Priority 7 packets"); + + for (i = 0; i < priv->tx_ring_num; i++) { + tx_ring = &priv->tx_ring[i]; + snprintf(namebuf, sizeof(namebuf), "tx_ring%d", i); + ring_node = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, namebuf, + CTLFLAG_RD, NULL, "TX Ring"); + ring_list = SYSCTL_CHILDREN(ring_node); + SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "packets", + CTLFLAG_RD, &tx_ring->packets, "TX packets"); + SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "bytes", + CTLFLAG_RD, &tx_ring->bytes, "TX bytes"); + SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "error", + CTLFLAG_RD, &tx_ring->errors, "TX soft errors"); + + } + for (i = 0; i < priv->rx_ring_num; i++) { + rx_ring = &priv->rx_ring[i]; + snprintf(namebuf, sizeof(namebuf), "rx_ring%d", i); + ring_node = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, namebuf, + CTLFLAG_RD, NULL, "RX Ring"); + ring_list = SYSCTL_CHILDREN(ring_node); + SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "packets", + CTLFLAG_RD, &rx_ring->packets, "RX packets"); + SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "bytes", + CTLFLAG_RD, &rx_ring->bytes, "RX bytes"); + SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "error", + CTLFLAG_RD, &rx_ring->errors, "RX soft errors"); + SYSCTL_ADD_UINT(ctx, ring_list, OID_AUTO, "lro_queued", + CTLFLAG_RD, &rx_ring->lro.lro_queued, 0, "LRO Queued"); + SYSCTL_ADD_UINT(ctx, ring_list, OID_AUTO, "lro_flushed", + CTLFLAG_RD, &rx_ring->lro.lro_flushed, 0, "LRO Flushed"); + } +} + +int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, + struct mlx4_en_port_profile *prof) +{ + static volatile int mlx4_en_unit; + struct net_device *dev; + struct mlx4_en_priv *priv; + uint8_t dev_addr[ETHER_ADDR_LEN]; + int err; + int i; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + dev = priv->dev = if_alloc(IFT_ETHER); + if (dev == NULL) { + mlx4_err(mdev, "Net device allocation failed\n"); + kfree(priv); + return -ENOMEM; + } + dev->if_softc = priv; + if_initname(dev, "mlxen", atomic_fetchadd_int(&mlx4_en_unit, 1)); + dev->if_mtu = ETHERMTU; + dev->if_baudrate = 1000000000; + dev->if_init = mlx4_en_init; + dev->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + dev->if_ioctl = mlx4_en_ioctl; + dev->if_transmit = mlx4_en_transmit; + dev->if_qflush = mlx4_en_qflush; + dev->if_snd.ifq_maxlen = prof->tx_ring_size; + + /* + * Initialize driver private data + */ + priv->dev = dev; + priv->mdev = mdev; + priv->prof = prof; + priv->port = port; + priv->port_up = false; + priv->rx_csum = 1; + priv->flags = prof->flags; + priv->tx_ring_num = prof->tx_ring_num; + priv->rx_ring_num = prof->rx_ring_num; + priv->udp_rings = mdev->profile.udp_rss ? prof->rx_ring_num / 2 : 1; + priv->mac_index = -1; + priv->msg_enable = MLX4_EN_MSG_LEVEL; + mtx_init(&priv->stats_lock.m, "mlx4 stats", NULL, MTX_DEF); + mtx_init(&priv->vlan_lock.m, "mlx4 vlan", NULL, MTX_DEF); + INIT_WORK(&priv->mcast_task, mlx4_en_do_set_multicast); + INIT_WORK(&priv->watchdog_task, mlx4_en_restart); + INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate); + INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); + callout_init(&priv->watchdog_timer, 1); + + /* Query for default mac and max mtu */ + priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; + priv->mac = mdev->dev->caps.def_mac[priv->port]; + + if (ILLEGAL_MAC(priv->mac)) { + en_err(priv, "Port: %d, invalid mac burned: 0x%llx, quiting\n", + priv->port, priv->mac); + err = -EINVAL; + goto out; + } + + mlx4_en_sysctl_conf(priv); + + err = mlx4_en_alloc_resources(priv); + if (err) + goto out; + + /* Allocate page for receive rings */ + err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, + MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE); + if (err) { + en_err(priv, "Failed to allocate page for rx qps\n"); + goto out; + } + priv->allocated = 1; + + /* + * Set driver features + */ + dev->if_capabilities |= IFCAP_RXCSUM | IFCAP_TXCSUM; + dev->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING; + dev->if_capabilities |= IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWFILTER; + dev->if_capabilities |= IFCAP_LINKSTATE | IFCAP_JUMBO_MTU; +#if 0 /* Not yet */ + dev->if_capabilities |= IFCAP_WOL; +#endif + if (mdev->LSO_support) + dev->if_capabilities |= IFCAP_TSO | IFCAP_VLAN_HWTSO; + + /* Don't enable LOR unless the user requests. */ + dev->if_capenable = dev->if_capabilities; + + if (mdev->profile.num_lro) + dev->if_capabilities |= IFCAP_LRO; + + /* Register for VLAN events */ + priv->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, + mlx4_en_vlan_rx_add_vid, priv, EVENTHANDLER_PRI_FIRST); + priv->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, + mlx4_en_vlan_rx_kill_vid, priv, EVENTHANDLER_PRI_FIRST); + + mdev->pndev[priv->port] = dev; + + priv->last_link_state = MLX4_DEV_EVENT_PORT_DOWN; + if_link_state_change(dev, LINK_STATE_DOWN); + + /* Set default MAC */ + for (i = 0; i < ETHER_ADDR_LEN; i++) + dev_addr[ETHER_ADDR_LEN - 1 - i] = (u8) (priv->mac >> (8 * i)); + + ether_ifattach(dev, dev_addr); + ifmedia_init(&priv->media, IFM_IMASK | IFM_ETH_FMASK, + mlx4_en_media_change, mlx4_en_media_status); + ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_1000_T, 0, NULL); + ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_10G_SR, 0, NULL); + ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_10G_CX4, 0, NULL); + ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL); + ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO); + + en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); + en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); + + priv->registered = 1; + queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); + + return 0; + +out: + mlx4_en_destroy_netdev(dev); + return err; +} + diff --git a/sys/ofed/drivers/net/mlx4/en_params.c b/sys/ofed/drivers/net/mlx4/en_params.c new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/sys/ofed/drivers/net/mlx4/en_port.c b/sys/ofed/drivers/net/mlx4/en_port.c new file mode 100644 index 000000000000..36a53d36081e --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/en_port.c @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + + +#include "mlx4_en.h" + +#include + +#include +#include + + +int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, + u64 mac, u64 clear, u8 mode) +{ + return mlx4_cmd(dev, (mac | (clear << 63)), port, mode, + MLX4_CMD_SET_MCAST_FLTR, MLX4_CMD_TIME_CLASS_B); +} + +int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, u8 port, u32 *vlans) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_set_vlan_fltr_mbox *filter; + int i; + int err = 0; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + filter = mailbox->buf; + memset(filter, 0, sizeof *filter); + if (vlans) + for (i = 0; i < VLAN_FLTR_SIZE; i ++) + filter->entry[i] = cpu_to_be32(vlans[i]); + err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_VLAN_FLTR, + MLX4_CMD_TIME_CLASS_B); + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + + +int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, + u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_set_port_general_context *context; + int err; + u32 in_mod; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + context = mailbox->buf; + memset(context, 0, sizeof *context); + + context->flags = SET_PORT_GEN_ALL_VALID; + context->mtu = cpu_to_be16(mtu); + context->pptx = (pptx * (!pfctx)) << 7; + context->pfctx = pfctx; + context->pprx = (pprx * (!pfcrx)) << 7; + context->pfcrx = pfcrx; + + in_mod = MLX4_SET_PORT_GENERAL << 8 | port; + err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, + u8 promisc) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_set_port_rqp_calc_context *context; + int err; + u32 in_mod; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + context = mailbox->buf; + memset(context, 0, sizeof *context); + + context->base_qpn = cpu_to_be32(base_qpn); + context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_EN_SHIFT | base_qpn); + context->mcast = cpu_to_be32((dev->caps.mc_promisc_mode << + SET_PORT_PROMISC_MODE_SHIFT) | base_qpn); + context->intra_no_vlan = 0; + context->no_vlan = MLX4_NO_VLAN_IDX; + context->intra_vlan_miss = 0; + context->vlan_miss = MLX4_VLAN_MISS_IDX; + + in_mod = MLX4_SET_PORT_RQP_CALC << 8 | port; + err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port) +{ + struct mlx4_en_query_port_context *qport_context; + struct mlx4_en_priv *priv = netdev_priv(mdev->pndev[port]); + struct mlx4_en_port_state *state = &priv->port_state; + struct mlx4_cmd_mailbox *mailbox; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(mdev->dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + memset(mailbox->buf, 0, sizeof(*qport_context)); + err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, port, 0, + MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B); + if (err) + goto out; + qport_context = mailbox->buf; + + /* This command is always accessed from Ethtool context + * already synchronized, no need in locking */ + state->link_state = !!(qport_context->link_up & MLX4_EN_LINK_UP_MASK); + if ((qport_context->link_speed & MLX4_EN_SPEED_MASK) == + MLX4_EN_1G_SPEED) + state->link_speed = 1000; + else + state->link_speed = 10000; + state->transciver = qport_context->transceiver; + if (be32_to_cpu(qport_context->transceiver_code_hi) & 0x400) + state->transciver = 0x80; + +out: + mlx4_free_cmd_mailbox(mdev->dev, mailbox); + return err; +} + +static int read_iboe_counters(struct mlx4_dev *dev, int index, u64 counters[]) +{ + struct mlx4_cmd_mailbox *mailbox; + int err; + int mode; + struct mlx4_counters_ext *ext; + struct mlx4_counters *reg; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return -ENOMEM; + + err = mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, + MLX4_CMD_QUERY_IF_STAT, MLX4_CMD_TIME_CLASS_C); + if (err) + goto out; + + mode = be32_to_cpu(((struct mlx4_counters *)mailbox->buf)->counter_mode) & 0xf; + switch (mode) { + case 0: + reg = mailbox->buf; + counters[0] = be64_to_cpu(reg->rx_frames); + counters[1] = be64_to_cpu(reg->tx_frames); + counters[2] = be64_to_cpu(reg->rx_bytes); + counters[3] = be64_to_cpu(reg->tx_bytes); + break; + case 1: + ext = mailbox->buf; + counters[0] = be64_to_cpu(ext->rx_uni_frames); + counters[1] = be64_to_cpu(ext->tx_uni_frames); + counters[2] = be64_to_cpu(ext->rx_uni_bytes); + counters[3] = be64_to_cpu(ext->tx_uni_bytes); + break; + default: + err = -EINVAL; + } + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) +{ + struct mlx4_en_stat_out_mbox *mlx4_en_stats; + struct net_device *dev; + struct mlx4_en_priv *priv; + struct mlx4_cmd_mailbox *mailbox; + u64 in_mod = reset << 8 | port; + unsigned long oerror; + unsigned long ierror; + int err; + int i; + int counter; + u64 counters[4]; + + dev = mdev->pndev[port]; + priv = netdev_priv(dev); + memset(counters, 0, sizeof counters); + counter = mlx4_get_iboe_counter(priv->mdev->dev, port); + if (counter >= 0) + err = read_iboe_counters(priv->mdev->dev, counter, counters); + + mailbox = mlx4_alloc_cmd_mailbox(mdev->dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + memset(mailbox->buf, 0, sizeof(*mlx4_en_stats)); + err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, in_mod, 0, + MLX4_CMD_DUMP_ETH_STATS, MLX4_CMD_TIME_CLASS_B); + if (err) + goto out; + + mlx4_en_stats = mailbox->buf; + + spin_lock(&priv->stats_lock); + + oerror = ierror = 0; + dev->if_ipackets = counters[0]; + dev->if_ibytes = counters[2]; + for (i = 0; i < priv->rx_ring_num; i++) { + dev->if_ipackets += priv->rx_ring[i].packets; + dev->if_ibytes += priv->rx_ring[i].bytes; + ierror += priv->rx_ring[i].errors; + } + dev->if_opackets = counters[1]; + dev->if_obytes = counters[3]; + for (i = 0; i <= priv->tx_ring_num; i++) { + dev->if_opackets += priv->tx_ring[i].packets; + dev->if_obytes += priv->tx_ring[i].bytes; + oerror += priv->tx_ring[i].errors; + } + + dev->if_ierrors = be32_to_cpu(mlx4_en_stats->RDROP) + ierror; + dev->if_oerrors = be32_to_cpu(mlx4_en_stats->TDROP) + oerror; + dev->if_imcasts = be64_to_cpu(mlx4_en_stats->MCAST_prio_0) + + be64_to_cpu(mlx4_en_stats->MCAST_prio_1) + + be64_to_cpu(mlx4_en_stats->MCAST_prio_2) + + be64_to_cpu(mlx4_en_stats->MCAST_prio_3) + + be64_to_cpu(mlx4_en_stats->MCAST_prio_4) + + be64_to_cpu(mlx4_en_stats->MCAST_prio_5) + + be64_to_cpu(mlx4_en_stats->MCAST_prio_6) + + be64_to_cpu(mlx4_en_stats->MCAST_prio_7) + + be64_to_cpu(mlx4_en_stats->MCAST_novlan); + dev->if_omcasts = be64_to_cpu(mlx4_en_stats->TMCAST_prio_0) + + be64_to_cpu(mlx4_en_stats->TMCAST_prio_1) + + be64_to_cpu(mlx4_en_stats->TMCAST_prio_2) + + be64_to_cpu(mlx4_en_stats->TMCAST_prio_3) + + be64_to_cpu(mlx4_en_stats->TMCAST_prio_4) + + be64_to_cpu(mlx4_en_stats->TMCAST_prio_5) + + be64_to_cpu(mlx4_en_stats->TMCAST_prio_6) + + be64_to_cpu(mlx4_en_stats->TMCAST_prio_7) + + be64_to_cpu(mlx4_en_stats->TMCAST_novlan); + dev->if_collisions = 0; + + priv->pkstats.broadcast = + be64_to_cpu(mlx4_en_stats->RBCAST_prio_0) + + be64_to_cpu(mlx4_en_stats->RBCAST_prio_1) + + be64_to_cpu(mlx4_en_stats->RBCAST_prio_2) + + be64_to_cpu(mlx4_en_stats->RBCAST_prio_3) + + be64_to_cpu(mlx4_en_stats->RBCAST_prio_4) + + be64_to_cpu(mlx4_en_stats->RBCAST_prio_5) + + be64_to_cpu(mlx4_en_stats->RBCAST_prio_6) + + be64_to_cpu(mlx4_en_stats->RBCAST_prio_7) + + be64_to_cpu(mlx4_en_stats->RBCAST_novlan); + priv->pkstats.rx_prio[0] = be64_to_cpu(mlx4_en_stats->RTOT_prio_0); + priv->pkstats.rx_prio[1] = be64_to_cpu(mlx4_en_stats->RTOT_prio_1); + priv->pkstats.rx_prio[2] = be64_to_cpu(mlx4_en_stats->RTOT_prio_2); + priv->pkstats.rx_prio[3] = be64_to_cpu(mlx4_en_stats->RTOT_prio_3); + priv->pkstats.rx_prio[4] = be64_to_cpu(mlx4_en_stats->RTOT_prio_4); + priv->pkstats.rx_prio[5] = be64_to_cpu(mlx4_en_stats->RTOT_prio_5); + priv->pkstats.rx_prio[6] = be64_to_cpu(mlx4_en_stats->RTOT_prio_6); + priv->pkstats.rx_prio[7] = be64_to_cpu(mlx4_en_stats->RTOT_prio_7); + priv->pkstats.tx_prio[0] = be64_to_cpu(mlx4_en_stats->TTOT_prio_0); + priv->pkstats.tx_prio[1] = be64_to_cpu(mlx4_en_stats->TTOT_prio_1); + priv->pkstats.tx_prio[2] = be64_to_cpu(mlx4_en_stats->TTOT_prio_2); + priv->pkstats.tx_prio[3] = be64_to_cpu(mlx4_en_stats->TTOT_prio_3); + priv->pkstats.tx_prio[4] = be64_to_cpu(mlx4_en_stats->TTOT_prio_4); + priv->pkstats.tx_prio[5] = be64_to_cpu(mlx4_en_stats->TTOT_prio_5); + priv->pkstats.tx_prio[6] = be64_to_cpu(mlx4_en_stats->TTOT_prio_6); + priv->pkstats.tx_prio[7] = be64_to_cpu(mlx4_en_stats->TTOT_prio_7); + spin_unlock(&priv->stats_lock); + +out: + mlx4_free_cmd_mailbox(mdev->dev, mailbox); + return err; +} + diff --git a/sys/ofed/drivers/net/mlx4/en_port.h b/sys/ofed/drivers/net/mlx4/en_port.h new file mode 100644 index 000000000000..96551d358ee1 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/en_port.h @@ -0,0 +1,591 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _MLX4_EN_PORT_H_ +#define _MLX4_EN_PORT_H_ + + +#define SET_PORT_GEN_ALL_VALID 0x7 +#define SET_PORT_PROMISC_EN_SHIFT 31 +#define SET_PORT_PROMISC_MODE_SHIFT 30 + +enum { + MLX4_CMD_SET_VLAN_FLTR = 0x47, + MLX4_CMD_SET_MCAST_FLTR = 0x48, + MLX4_CMD_DUMP_ETH_STATS = 0x49, +}; + +struct mlx4_set_port_general_context { + u8 reserved[3]; + u8 flags; + u16 reserved2; + __be16 mtu; + u8 pptx; + u8 pfctx; + u16 reserved3; + u8 pprx; + u8 pfcrx; + u16 reserved4; +}; + +struct mlx4_set_port_rqp_calc_context { + __be32 base_qpn; + __be32 flags; + u8 reserved[3]; + u8 mac_miss; + u8 intra_no_vlan; + u8 no_vlan; + u8 intra_vlan_miss; + u8 vlan_miss; + u8 reserved2[3]; + u8 no_vlan_prio; + __be32 promisc; + __be32 mcast; +}; + +#define VLAN_FLTR_SIZE 128 +struct mlx4_set_vlan_fltr_mbox { + __be32 entry[VLAN_FLTR_SIZE]; +}; + + +enum { + MLX4_MCAST_CONFIG = 0, + MLX4_MCAST_DISABLE = 1, + MLX4_MCAST_ENABLE = 2, +}; + +struct mlx4_en_query_port_context { + u8 link_up; +#define MLX4_EN_LINK_UP_MASK 0x80 + u8 reserved; + __be16 mtu; + u8 reserved2; + u8 link_speed; +#define MLX4_EN_SPEED_MASK 0x3 +#define MLX4_EN_1G_SPEED 0x2 + u16 reserved3[5]; + __be64 mac; + u8 transceiver; + u8 reserved4[3]; + __be32 wavelenth; + u32 reserved5; + __be32 transceiver_code_hi; + __be32 transceiver_code_low; +}; + + +struct mlx4_en_stat_out_mbox { + /* Received frames with a length of 64 octets */ + __be64 R64_prio_0; + __be64 R64_prio_1; + __be64 R64_prio_2; + __be64 R64_prio_3; + __be64 R64_prio_4; + __be64 R64_prio_5; + __be64 R64_prio_6; + __be64 R64_prio_7; + __be64 R64_novlan; + /* Received frames with a length of 127 octets */ + __be64 R127_prio_0; + __be64 R127_prio_1; + __be64 R127_prio_2; + __be64 R127_prio_3; + __be64 R127_prio_4; + __be64 R127_prio_5; + __be64 R127_prio_6; + __be64 R127_prio_7; + __be64 R127_novlan; + /* Received frames with a length of 255 octets */ + __be64 R255_prio_0; + __be64 R255_prio_1; + __be64 R255_prio_2; + __be64 R255_prio_3; + __be64 R255_prio_4; + __be64 R255_prio_5; + __be64 R255_prio_6; + __be64 R255_prio_7; + __be64 R255_novlan; + /* Received frames with a length of 511 octets */ + __be64 R511_prio_0; + __be64 R511_prio_1; + __be64 R511_prio_2; + __be64 R511_prio_3; + __be64 R511_prio_4; + __be64 R511_prio_5; + __be64 R511_prio_6; + __be64 R511_prio_7; + __be64 R511_novlan; + /* Received frames with a length of 1023 octets */ + __be64 R1023_prio_0; + __be64 R1023_prio_1; + __be64 R1023_prio_2; + __be64 R1023_prio_3; + __be64 R1023_prio_4; + __be64 R1023_prio_5; + __be64 R1023_prio_6; + __be64 R1023_prio_7; + __be64 R1023_novlan; + /* Received frames with a length of 1518 octets */ + __be64 R1518_prio_0; + __be64 R1518_prio_1; + __be64 R1518_prio_2; + __be64 R1518_prio_3; + __be64 R1518_prio_4; + __be64 R1518_prio_5; + __be64 R1518_prio_6; + __be64 R1518_prio_7; + __be64 R1518_novlan; + /* Received frames with a length of 1522 octets */ + __be64 R1522_prio_0; + __be64 R1522_prio_1; + __be64 R1522_prio_2; + __be64 R1522_prio_3; + __be64 R1522_prio_4; + __be64 R1522_prio_5; + __be64 R1522_prio_6; + __be64 R1522_prio_7; + __be64 R1522_novlan; + /* Received frames with a length of 1548 octets */ + __be64 R1548_prio_0; + __be64 R1548_prio_1; + __be64 R1548_prio_2; + __be64 R1548_prio_3; + __be64 R1548_prio_4; + __be64 R1548_prio_5; + __be64 R1548_prio_6; + __be64 R1548_prio_7; + __be64 R1548_novlan; + /* Received frames with a length of 1548 < octets < MTU */ + __be64 R2MTU_prio_0; + __be64 R2MTU_prio_1; + __be64 R2MTU_prio_2; + __be64 R2MTU_prio_3; + __be64 R2MTU_prio_4; + __be64 R2MTU_prio_5; + __be64 R2MTU_prio_6; + __be64 R2MTU_prio_7; + __be64 R2MTU_novlan; + /* Received frames with a length of MTU< octets and good CRC */ + __be64 RGIANT_prio_0; + __be64 RGIANT_prio_1; + __be64 RGIANT_prio_2; + __be64 RGIANT_prio_3; + __be64 RGIANT_prio_4; + __be64 RGIANT_prio_5; + __be64 RGIANT_prio_6; + __be64 RGIANT_prio_7; + __be64 RGIANT_novlan; + /* Received broadcast frames with good CRC */ + __be64 RBCAST_prio_0; + __be64 RBCAST_prio_1; + __be64 RBCAST_prio_2; + __be64 RBCAST_prio_3; + __be64 RBCAST_prio_4; + __be64 RBCAST_prio_5; + __be64 RBCAST_prio_6; + __be64 RBCAST_prio_7; + __be64 RBCAST_novlan; + /* Received multicast frames with good CRC */ + __be64 MCAST_prio_0; + __be64 MCAST_prio_1; + __be64 MCAST_prio_2; + __be64 MCAST_prio_3; + __be64 MCAST_prio_4; + __be64 MCAST_prio_5; + __be64 MCAST_prio_6; + __be64 MCAST_prio_7; + __be64 MCAST_novlan; + /* Received unicast not short or GIANT frames with good CRC */ + __be64 RTOTG_prio_0; + __be64 RTOTG_prio_1; + __be64 RTOTG_prio_2; + __be64 RTOTG_prio_3; + __be64 RTOTG_prio_4; + __be64 RTOTG_prio_5; + __be64 RTOTG_prio_6; + __be64 RTOTG_prio_7; + __be64 RTOTG_novlan; + + /* Count of total octets of received frames, includes framing characters */ + __be64 RTTLOCT_prio_0; + /* Count of total octets of received frames, not including framing + characters */ + __be64 RTTLOCT_NOFRM_prio_0; + /* Count of Total number of octets received + (only for frames without errors) */ + __be64 ROCT_prio_0; + + __be64 RTTLOCT_prio_1; + __be64 RTTLOCT_NOFRM_prio_1; + __be64 ROCT_prio_1; + + __be64 RTTLOCT_prio_2; + __be64 RTTLOCT_NOFRM_prio_2; + __be64 ROCT_prio_2; + + __be64 RTTLOCT_prio_3; + __be64 RTTLOCT_NOFRM_prio_3; + __be64 ROCT_prio_3; + + __be64 RTTLOCT_prio_4; + __be64 RTTLOCT_NOFRM_prio_4; + __be64 ROCT_prio_4; + + __be64 RTTLOCT_prio_5; + __be64 RTTLOCT_NOFRM_prio_5; + __be64 ROCT_prio_5; + + __be64 RTTLOCT_prio_6; + __be64 RTTLOCT_NOFRM_prio_6; + __be64 ROCT_prio_6; + + __be64 RTTLOCT_prio_7; + __be64 RTTLOCT_NOFRM_prio_7; + __be64 ROCT_prio_7; + + __be64 RTTLOCT_novlan; + __be64 RTTLOCT_NOFRM_novlan; + __be64 ROCT_novlan; + + /* Count of Total received frames including bad frames */ + __be64 RTOT_prio_0; + /* Count of Total number of received frames with 802.1Q encapsulation */ + __be64 R1Q_prio_0; + __be64 reserved1; + + __be64 RTOT_prio_1; + __be64 R1Q_prio_1; + __be64 reserved2; + + __be64 RTOT_prio_2; + __be64 R1Q_prio_2; + __be64 reserved3; + + __be64 RTOT_prio_3; + __be64 R1Q_prio_3; + __be64 reserved4; + + __be64 RTOT_prio_4; + __be64 R1Q_prio_4; + __be64 reserved5; + + __be64 RTOT_prio_5; + __be64 R1Q_prio_5; + __be64 reserved6; + + __be64 RTOT_prio_6; + __be64 R1Q_prio_6; + __be64 reserved7; + + __be64 RTOT_prio_7; + __be64 R1Q_prio_7; + __be64 reserved8; + + __be64 RTOT_novlan; + __be64 R1Q_novlan; + __be64 reserved9; + + /* Total number of Successfully Received Control Frames */ + __be64 RCNTL; + __be64 reserved10; + __be64 reserved11; + __be64 reserved12; + /* Count of received frames with a length/type field value between 46 + (42 for VLANtagged frames) and 1500 (also 1500 for VLAN-tagged frames), + inclusive */ + __be64 RInRangeLengthErr; + /* Count of received frames with length/type field between 1501 and 1535 + decimal, inclusive */ + __be64 ROutRangeLengthErr; + /* Count of received frames that are longer than max allowed size for + 802.3 frames (1518/1522) */ + __be64 RFrmTooLong; + /* Count frames received with PCS error */ + __be64 PCS; + + /* Transmit frames with a length of 64 octets */ + __be64 T64_prio_0; + __be64 T64_prio_1; + __be64 T64_prio_2; + __be64 T64_prio_3; + __be64 T64_prio_4; + __be64 T64_prio_5; + __be64 T64_prio_6; + __be64 T64_prio_7; + __be64 T64_novlan; + __be64 T64_loopbk; + /* Transmit frames with a length of 65 to 127 octets. */ + __be64 T127_prio_0; + __be64 T127_prio_1; + __be64 T127_prio_2; + __be64 T127_prio_3; + __be64 T127_prio_4; + __be64 T127_prio_5; + __be64 T127_prio_6; + __be64 T127_prio_7; + __be64 T127_novlan; + __be64 T127_loopbk; + /* Transmit frames with a length of 128 to 255 octets */ + __be64 T255_prio_0; + __be64 T255_prio_1; + __be64 T255_prio_2; + __be64 T255_prio_3; + __be64 T255_prio_4; + __be64 T255_prio_5; + __be64 T255_prio_6; + __be64 T255_prio_7; + __be64 T255_novlan; + __be64 T255_loopbk; + /* Transmit frames with a length of 256 to 511 octets */ + __be64 T511_prio_0; + __be64 T511_prio_1; + __be64 T511_prio_2; + __be64 T511_prio_3; + __be64 T511_prio_4; + __be64 T511_prio_5; + __be64 T511_prio_6; + __be64 T511_prio_7; + __be64 T511_novlan; + __be64 T511_loopbk; + /* Transmit frames with a length of 512 to 1023 octets */ + __be64 T1023_prio_0; + __be64 T1023_prio_1; + __be64 T1023_prio_2; + __be64 T1023_prio_3; + __be64 T1023_prio_4; + __be64 T1023_prio_5; + __be64 T1023_prio_6; + __be64 T1023_prio_7; + __be64 T1023_novlan; + __be64 T1023_loopbk; + /* Transmit frames with a length of 1024 to 1518 octets */ + __be64 T1518_prio_0; + __be64 T1518_prio_1; + __be64 T1518_prio_2; + __be64 T1518_prio_3; + __be64 T1518_prio_4; + __be64 T1518_prio_5; + __be64 T1518_prio_6; + __be64 T1518_prio_7; + __be64 T1518_novlan; + __be64 T1518_loopbk; + /* Counts transmit frames with a length of 1519 to 1522 bytes */ + __be64 T1522_prio_0; + __be64 T1522_prio_1; + __be64 T1522_prio_2; + __be64 T1522_prio_3; + __be64 T1522_prio_4; + __be64 T1522_prio_5; + __be64 T1522_prio_6; + __be64 T1522_prio_7; + __be64 T1522_novlan; + __be64 T1522_loopbk; + /* Transmit frames with a length of 1523 to 1548 octets */ + __be64 T1548_prio_0; + __be64 T1548_prio_1; + __be64 T1548_prio_2; + __be64 T1548_prio_3; + __be64 T1548_prio_4; + __be64 T1548_prio_5; + __be64 T1548_prio_6; + __be64 T1548_prio_7; + __be64 T1548_novlan; + __be64 T1548_loopbk; + /* Counts transmit frames with a length of 1549 to MTU bytes */ + __be64 T2MTU_prio_0; + __be64 T2MTU_prio_1; + __be64 T2MTU_prio_2; + __be64 T2MTU_prio_3; + __be64 T2MTU_prio_4; + __be64 T2MTU_prio_5; + __be64 T2MTU_prio_6; + __be64 T2MTU_prio_7; + __be64 T2MTU_novlan; + __be64 T2MTU_loopbk; + /* Transmit frames with a length greater than MTU octets and a good CRC. */ + __be64 TGIANT_prio_0; + __be64 TGIANT_prio_1; + __be64 TGIANT_prio_2; + __be64 TGIANT_prio_3; + __be64 TGIANT_prio_4; + __be64 TGIANT_prio_5; + __be64 TGIANT_prio_6; + __be64 TGIANT_prio_7; + __be64 TGIANT_novlan; + __be64 TGIANT_loopbk; + /* Transmit broadcast frames with a good CRC */ + __be64 TBCAST_prio_0; + __be64 TBCAST_prio_1; + __be64 TBCAST_prio_2; + __be64 TBCAST_prio_3; + __be64 TBCAST_prio_4; + __be64 TBCAST_prio_5; + __be64 TBCAST_prio_6; + __be64 TBCAST_prio_7; + __be64 TBCAST_novlan; + __be64 TBCAST_loopbk; + /* Transmit multicast frames with a good CRC */ + __be64 TMCAST_prio_0; + __be64 TMCAST_prio_1; + __be64 TMCAST_prio_2; + __be64 TMCAST_prio_3; + __be64 TMCAST_prio_4; + __be64 TMCAST_prio_5; + __be64 TMCAST_prio_6; + __be64 TMCAST_prio_7; + __be64 TMCAST_novlan; + __be64 TMCAST_loopbk; + /* Transmit good frames that are neither broadcast nor multicast */ + __be64 TTOTG_prio_0; + __be64 TTOTG_prio_1; + __be64 TTOTG_prio_2; + __be64 TTOTG_prio_3; + __be64 TTOTG_prio_4; + __be64 TTOTG_prio_5; + __be64 TTOTG_prio_6; + __be64 TTOTG_prio_7; + __be64 TTOTG_novlan; + __be64 TTOTG_loopbk; + + /* total octets of transmitted frames, including framing characters */ + __be64 TTTLOCT_prio_0; + /* total octets of transmitted frames, not including framing characters */ + __be64 TTTLOCT_NOFRM_prio_0; + /* ifOutOctets */ + __be64 TOCT_prio_0; + + __be64 TTTLOCT_prio_1; + __be64 TTTLOCT_NOFRM_prio_1; + __be64 TOCT_prio_1; + + __be64 TTTLOCT_prio_2; + __be64 TTTLOCT_NOFRM_prio_2; + __be64 TOCT_prio_2; + + __be64 TTTLOCT_prio_3; + __be64 TTTLOCT_NOFRM_prio_3; + __be64 TOCT_prio_3; + + __be64 TTTLOCT_prio_4; + __be64 TTTLOCT_NOFRM_prio_4; + __be64 TOCT_prio_4; + + __be64 TTTLOCT_prio_5; + __be64 TTTLOCT_NOFRM_prio_5; + __be64 TOCT_prio_5; + + __be64 TTTLOCT_prio_6; + __be64 TTTLOCT_NOFRM_prio_6; + __be64 TOCT_prio_6; + + __be64 TTTLOCT_prio_7; + __be64 TTTLOCT_NOFRM_prio_7; + __be64 TOCT_prio_7; + + __be64 TTTLOCT_novlan; + __be64 TTTLOCT_NOFRM_novlan; + __be64 TOCT_novlan; + + __be64 TTTLOCT_loopbk; + __be64 TTTLOCT_NOFRM_loopbk; + __be64 TOCT_loopbk; + + /* Total frames transmitted with a good CRC that are not aborted */ + __be64 TTOT_prio_0; + /* Total number of frames transmitted with 802.1Q encapsulation */ + __be64 T1Q_prio_0; + __be64 reserved13; + + __be64 TTOT_prio_1; + __be64 T1Q_prio_1; + __be64 reserved14; + + __be64 TTOT_prio_2; + __be64 T1Q_prio_2; + __be64 reserved15; + + __be64 TTOT_prio_3; + __be64 T1Q_prio_3; + __be64 reserved16; + + __be64 TTOT_prio_4; + __be64 T1Q_prio_4; + __be64 reserved17; + + __be64 TTOT_prio_5; + __be64 T1Q_prio_5; + __be64 reserved18; + + __be64 TTOT_prio_6; + __be64 T1Q_prio_6; + __be64 reserved19; + + __be64 TTOT_prio_7; + __be64 T1Q_prio_7; + __be64 reserved20; + + __be64 TTOT_novlan; + __be64 T1Q_novlan; + __be64 reserved21; + + __be64 TTOT_loopbk; + __be64 T1Q_loopbk; + __be64 reserved22; + + /* Received frames with a length greater than MTU octets and a bad CRC */ + __be32 RJBBR; + /* Received frames with a bad CRC that are not runts, jabbers, + or alignment errors */ + __be32 RCRC; + /* Received frames with SFD with a length of less than 64 octets and a + bad CRC */ + __be32 RRUNT; + /* Received frames with a length less than 64 octets and a good CRC */ + __be32 RSHORT; + /* Total Number of Received Packets Dropped */ + __be32 RDROP; + /* Drop due to overflow */ + __be32 RdropOvflw; + /* Drop due to overflow */ + __be32 RdropLength; + /* Total of good frames. Does not include frames received with + frame-too-long, FCS, or length errors */ + __be32 RTOTFRMS; + /* Total dropped Xmited packets */ + __be32 TDROP; +}; + +enum mlx4_query_reply mlx4_en_query(void *endev_ptr, void *int_dev); + +#endif diff --git a/sys/ofed/drivers/net/mlx4/en_resources.c b/sys/ofed/drivers/net/mlx4/en_resources.c new file mode 100644 index 000000000000..a147153803fd --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/en_resources.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include + +#include "mlx4_en.h" + +void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, + int is_tx, int rss, int qpn, int cqn, + struct mlx4_qp_context *context) +{ + struct mlx4_en_dev *mdev = priv->mdev; + + memset(context, 0, sizeof *context); + context->flags = cpu_to_be32(7 << 16 | rss << 13); + context->pd = cpu_to_be32(mdev->priv_pdn); + context->mtu_msgmax = 0xff; + if (!is_tx && !rss) { + context->rq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4); + } + if (is_tx) + context->sq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4); + else + context->sq_size_stride = ilog2(TXBB_SIZE) - 4; + context->usr_page = cpu_to_be32(mdev->priv_uar.index); + context->local_qpn = cpu_to_be32(qpn); + context->pri_path.ackto = 1 & 0x07; + context->pri_path.sched_queue = 0x83 | (priv->port - 1) << 6; + context->pri_path.counter_index = 0xff; + context->cqn_send = cpu_to_be32(cqn); + context->cqn_recv = cpu_to_be32(cqn); + context->db_rec_addr = cpu_to_be64(priv->res.db.dma << 2); +} + + +int mlx4_en_map_buffer(struct mlx4_buf *buf) +{ + struct page **pages; + int i; + + if (buf->direct.buf != NULL || buf->nbufs == 1) + return 0; + + pages = kmalloc(sizeof *pages * buf->nbufs, GFP_KERNEL); + if (!pages) + return -ENOMEM; + + for (i = 0; i < buf->nbufs; ++i) + pages[i] = virt_to_page(buf->page_list[i].buf); + + buf->direct.buf = vmap(pages, buf->nbufs, VM_MAP, PAGE_KERNEL); + kfree(pages); + if (!buf->direct.buf) + return -ENOMEM; + + return 0; +} + +void mlx4_en_unmap_buffer(struct mlx4_buf *buf) +{ + if (buf->direct.buf != NULL || buf->nbufs == 1) + return; + + vunmap(buf->direct.buf); + buf->direct.buf = NULL; +} + +void mlx4_en_sqp_event(struct mlx4_qp *qp, enum mlx4_event event) +{ + return; +} + diff --git a/sys/ofed/drivers/net/mlx4/en_rx.c b/sys/ofed/drivers/net/mlx4/en_rx.c new file mode 100644 index 000000000000..fc4345f7f16c --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/en_rx.c @@ -0,0 +1,1006 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include "mlx4_en.h" + +#include +#include + +#include +#include +#include + +enum { + MIN_RX_ARM = 1024, +}; + +static int mlx4_en_alloc_buf(struct mlx4_en_priv *priv, + struct mlx4_en_rx_desc *rx_desc, + struct mbuf **mb_list, + int i) +{ + struct mlx4_en_dev *mdev = priv->mdev; + struct mlx4_en_frag_info *frag_info = &priv->frag_info[i]; + struct mbuf *mb; + dma_addr_t dma; + + if (i == 0) + mb = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, frag_info->frag_size); + else + mb = m_getjcl(M_NOWAIT, MT_DATA, 0, frag_info->frag_size); + if (mb == NULL) { + priv->port_stats.rx_alloc_failed++; + return -ENOMEM; + } + dma = pci_map_single(mdev->pdev, mb->m_data, frag_info->frag_size, + PCI_DMA_FROMDEVICE); + rx_desc->data[i].addr = cpu_to_be64(dma); + mb_list[i] = mb; + return 0; +} + +static void +mlx4_en_init_rx_desc_mb(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring, int index) +{ + struct mlx4_en_rx_desc *rx_desc = ring->buf + ring->stride * index; + + rx_desc->data->byte_count = cpu_to_be32(priv->rx_mb_size); + rx_desc->data->lkey = cpu_to_be32(priv->mdev->mr.key); +} + +static void mlx4_en_init_rx_desc(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring, int index) +{ + struct mlx4_en_rx_desc *rx_desc = ring->buf + ring->stride * index; + int possible_frags; + int i; + + /* Set size and memtype fields */ + for (i = 0; i < priv->num_frags; i++) { + rx_desc->data[i].byte_count = + cpu_to_be32(priv->frag_info[i].frag_size); + rx_desc->data[i].lkey = cpu_to_be32(priv->mdev->mr.key); + } + + /* If the number of used fragments does not fill up the ring stride, + * remaining (unused) fragments must be padded with null address/size + * and a special memory key */ + possible_frags = (ring->stride - sizeof(struct mlx4_en_rx_desc)) / DS_SIZE; + for (i = priv->num_frags; i < possible_frags; i++) { + rx_desc->data[i].byte_count = 0; + rx_desc->data[i].lkey = cpu_to_be32(MLX4_EN_MEMTYPE_PAD); + rx_desc->data[i].addr = 0; + } +} + +static int +mlx4_en_alloc_rx_mb(struct mlx4_en_priv *priv, + struct mlx4_en_rx_desc *rx_desc, + struct mbuf **pmb, int unmap) +{ + struct mlx4_en_dev *mdev = priv->mdev; + dma_addr_t dma; + int size = priv->rx_mb_size; + struct mbuf *new_mb; + + new_mb = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, size); + if (unlikely(new_mb == NULL)) { + priv->port_stats.rx_alloc_failed++; + return -ENOMEM; + } + + if (unmap) + pci_unmap_single(mdev->pdev, be64_to_cpu(rx_desc->data->addr), + be32_to_cpu(rx_desc->data->byte_count), + PCI_DMA_FROMDEVICE); + dma = pci_map_single(priv->mdev->pdev, new_mb->m_data, size, DMA_FROM_DEVICE); + *pmb = new_mb; + rx_desc->data->addr = cpu_to_be64(dma); + return 0; +} + +static int +mlx4_en_prepare_rx_desc_mb(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring, int index) +{ + struct mlx4_en_rx_desc *rx_desc = ring->buf + (index * ring->stride); + struct mbuf **pmb = (struct mbuf **) ring->rx_info + index; + + return mlx4_en_alloc_rx_mb(priv, rx_desc, pmb, 0); +} + +static int mlx4_en_prepare_rx_desc(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring, int index) +{ + struct mlx4_en_rx_desc *rx_desc = ring->buf + (index * ring->stride); + struct mbuf **mb_list = ring->rx_info + (index << priv->log_rx_info); + int i; + + for (i = 0; i < priv->num_frags; i++) + if (mlx4_en_alloc_buf(priv, rx_desc, mb_list, i)) + goto err; + + return 0; + +err: + while (i--) + m_free(mb_list[i]); + return -ENOMEM; +} + +static inline void mlx4_en_update_rx_prod_db(struct mlx4_en_rx_ring *ring) +{ + *ring->wqres.db.db = cpu_to_be32(ring->prod & 0xffff); +} + +static void mlx4_en_free_rx_desc(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring, + int index) +{ + struct mlx4_en_frag_info *frag_info; + struct mlx4_en_dev *mdev = priv->mdev; + struct mbuf **mb_list; + struct mbuf *mb; + struct mlx4_en_rx_desc *rx_desc = ring->buf + (index << ring->log_stride); + dma_addr_t dma; + int nr; + + if (ring->use_frags) { + mb_list = ring->rx_info + (index << priv->log_rx_info); + for (nr = 0; nr < priv->num_frags; nr++) { + en_dbg(DRV, priv, "Freeing fragment:%d\n", nr); + frag_info = &priv->frag_info[nr]; + dma = be64_to_cpu(rx_desc->data[nr].addr); + + en_dbg(DRV, priv, "Unmaping buffer at dma:0x%llx\n", (u64) dma); + pci_unmap_single(mdev->pdev, dma, frag_info->frag_size, + PCI_DMA_FROMDEVICE); + m_free(mb_list[nr]); + } + } else { + mb = *((struct mbuf **) ring->rx_info + index); + dma = be64_to_cpu(rx_desc->data->addr); + pci_unmap_single(mdev->pdev, dma, + priv->rx_mb_size, + PCI_DMA_FROMDEVICE); + m_free(mb); + } +} + +static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv) +{ + struct mlx4_en_rx_ring *ring; + int ring_ind; + int buf_ind; + int new_size; + int err; + + for (buf_ind = 0; buf_ind < priv->prof->rx_ring_size; buf_ind++) { + for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { + ring = &priv->rx_ring[ring_ind]; + + if (ring->use_frags) + err = mlx4_en_prepare_rx_desc(priv, ring, + ring->actual_size); + else + err = mlx4_en_prepare_rx_desc_mb(priv, ring, + ring->actual_size); + if (err) { + if (ring->actual_size == 0) { + en_err(priv, "Failed to allocate " + "enough rx buffers\n"); + return -ENOMEM; + } else { + new_size = rounddown_pow_of_two(ring->actual_size); + en_warn(priv, "Only %d buffers allocated " + "reducing ring size to %d\n", + ring->actual_size, new_size); + goto reduce_rings; + } + } + ring->actual_size++; + ring->prod++; + } + } + return 0; + +reduce_rings: + for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { + ring = &priv->rx_ring[ring_ind]; + while (ring->actual_size > new_size) { + ring->actual_size--; + ring->prod--; + mlx4_en_free_rx_desc(priv, ring, ring->actual_size); + } + } + + return 0; +} + +static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring) +{ + int index; + + en_dbg(DRV, priv, "Freeing Rx buf - cons:%d prod:%d\n", + ring->cons, ring->prod); + + /* Unmap and free Rx buffers */ + BUG_ON((u32) (ring->prod - ring->cons) > ring->actual_size); + while (ring->cons != ring->prod) { + index = ring->cons & ring->size_mask; + en_dbg(DRV, priv, "Processing descriptor:%d\n", index); + mlx4_en_free_rx_desc(priv, ring, index); + ++ring->cons; + } +} + + +int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring, u32 size) +{ + struct mlx4_en_dev *mdev = priv->mdev; + int err; + int tmp; + + + ring->prod = 0; + ring->cons = 0; + ring->size = size; + ring->size_mask = size - 1; + ring->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + + DS_SIZE * (ring->use_frags ? + MLX4_EN_MAX_RX_FRAGS : 1)); + ring->log_stride = ffs(ring->stride) - 1; + ring->buf_size = ring->size * ring->stride + TXBB_SIZE; + + if (ring->use_frags) + tmp = size * roundup_pow_of_two(MLX4_EN_MAX_RX_FRAGS * + sizeof(struct mbuf *)); + else + tmp = size * sizeof(struct mbuf *); + + ring->rx_info = kmalloc(tmp, GFP_KERNEL); + if (!ring->rx_info) { + en_err(priv, "Failed allocating rx_info ring\n"); + return -ENOMEM; + } + en_dbg(DRV, priv, "Allocated rx_info ring at addr:%p size:%d stride:%d (%d)\n", + ring->rx_info, tmp, ring->stride, ring->log_stride); + + err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, + ring->buf_size, 2 * PAGE_SIZE); + if (err) + goto err_ring; + + err = mlx4_en_map_buffer(&ring->wqres.buf); + if (err) { + en_err(priv, "Failed to map RX buffer\n"); + goto err_hwq; + } + ring->buf = ring->wqres.buf.direct.buf; + + return 0; + + mlx4_en_unmap_buffer(&ring->wqres.buf); +err_hwq: + mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); +err_ring: + kfree(ring->rx_info); + ring->rx_info = NULL; + return err; +} + +int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) +{ + struct mlx4_en_rx_ring *ring; + int i; + int ring_ind; + int err; + int stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + + DS_SIZE * priv->num_frags); + + for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { + ring = &priv->rx_ring[ring_ind]; + + ring->prod = 0; + ring->cons = 0; + ring->actual_size = 0; + ring->cqn = priv->rx_cq[ring_ind].mcq.cqn; + + if (ring->use_frags) + ring->stride = stride; + if (ring->stride <= TXBB_SIZE) + ring->buf += TXBB_SIZE; + + ring->log_stride = ffs(ring->stride) - 1; + ring->buf_size = ring->size * ring->stride; + + memset(ring->buf, 0, ring->buf_size); + mlx4_en_update_rx_prod_db(ring); + + if (ring->use_frags) { + /* Initailize all descriptors */ + for (i = 0; i < ring->size; i++) + mlx4_en_init_rx_desc(priv, ring, i); + } else { + for (i = 0; i < ring->size; i++) + mlx4_en_init_rx_desc_mb(priv, ring, i); + } + /* Configure lro mngr */ + if (priv->dev->if_capenable & IFCAP_LRO) { + if (tcp_lro_init(&ring->lro)) + priv->dev->if_capenable &= ~IFCAP_LRO; + else + ring->lro.ifp = priv->dev; + } + } + err = mlx4_en_fill_rx_buffers(priv); + if (err) + goto err_buffers; + + for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { + ring = &priv->rx_ring[ring_ind]; + + ring->size_mask = ring->actual_size - 1; + mlx4_en_update_rx_prod_db(ring); + } + + + return 0; + +err_buffers: + for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) + mlx4_en_free_rx_buf(priv, &priv->rx_ring[ring_ind]); + + ring_ind = priv->rx_ring_num - 1; + return err; +} + +void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring) +{ + struct mlx4_en_dev *mdev = priv->mdev; + + mlx4_en_unmap_buffer(&ring->wqres.buf); + mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size + TXBB_SIZE); + kfree(ring->rx_info); + ring->rx_info = NULL; +} + +void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring) +{ + tcp_lro_free(&ring->lro); + mlx4_en_free_rx_buf(priv, ring); + if (ring->stride <= TXBB_SIZE) + ring->buf -= TXBB_SIZE; +} + + +/* Unmap a completed descriptor and free unused pages */ +static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv, + struct mlx4_en_rx_desc *rx_desc, + struct mbuf **mb_list, + int length) +{ + struct mlx4_en_dev *mdev = priv->mdev; + struct mlx4_en_frag_info *frag_info; + dma_addr_t dma; + struct mbuf *mb; + int nr; + + mb = mb_list[0]; + mb->m_pkthdr.len = length; + /* Collect used fragments while replacing them in the HW descirptors */ + for (nr = 0; nr < priv->num_frags; nr++) { + frag_info = &priv->frag_info[nr]; + if (length <= frag_info->frag_prefix_size) + break; + if (nr) + mb->m_next = mb_list[nr]; + mb = mb_list[nr]; + mb->m_len = frag_info[nr].frag_size; + dma = be64_to_cpu(rx_desc->data[nr].addr); + + /* Allocate a replacement page */ + if (mlx4_en_alloc_buf(priv, rx_desc, mb_list, nr)) + goto fail; + + /* Unmap buffer */ + pci_unmap_single(mdev->pdev, dma, frag_info[nr].frag_size, + PCI_DMA_FROMDEVICE); + } + /* Adjust size of last fragment to match actual length */ + mb->m_len = length - priv->frag_info[nr - 1].frag_prefix_size; + mb->m_next = NULL; + return 0; + +fail: + /* Drop all accumulated fragments (which have already been replaced in + * the descriptor) of this packet; remaining fragments are reused... */ + while (nr > 0) { + nr--; + m_free(mb_list[nr]); + } + return -ENOMEM; +} + + +static struct mbuf *mlx4_en_rx_mb(struct mlx4_en_priv *priv, + struct mlx4_en_rx_desc *rx_desc, + struct mbuf **mb_list, + unsigned int length) +{ + struct mbuf *mb; + + mb = mb_list[0]; + /* Move relevant fragments to mb */ + if (unlikely(mlx4_en_complete_rx_desc(priv, rx_desc, mb_list, length))) + return NULL; + + return mb; +} + +static inline int invalid_cqe(struct mlx4_en_priv *priv, + struct mlx4_cqe *cqe) +{ + /* Drop packet on bad receive or bad checksum */ + if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == + MLX4_CQE_OPCODE_ERROR)) { + en_err(priv, "CQE completed in error - vendor " + "syndrom:%d syndrom:%d\n", + ((struct mlx4_err_cqe *) cqe)->vendor_err_syndrome, + ((struct mlx4_err_cqe *) cqe)->syndrome); + return 1; + } + if (unlikely(cqe->badfcs_enc & MLX4_CQE_BAD_FCS)) { + en_dbg(RX_ERR, priv, "Accepted frame with bad FCS\n"); + return 1;; + } + + return 0; +} + +static struct mbuf * +mlx4_en_get_rx_mb(struct mlx4_en_priv *priv, + struct mlx4_en_rx_desc *rx_desc, + struct mbuf **pmb, + unsigned int length) +{ + struct mlx4_en_dev *mdev = priv->mdev; + struct mbuf *mb; + dma_addr_t dma; + + if (length <= SMALL_PACKET_SIZE) { + mb = m_gethdr(M_WAITOK, MT_DATA); + if (unlikely(mb == NULL)) + return NULL; + /* We are copying all relevant data to the mb - temporarily + * synch buffers for the copy */ + dma = be64_to_cpu(rx_desc->data->addr); + dma_sync_single_range_for_cpu(&mdev->pdev->dev, dma, 0, + length, DMA_FROM_DEVICE); + memcpy(mb->m_data, (*pmb)->m_data, length); + dma_sync_single_range_for_device(&mdev->pdev->dev, dma, 0, + length, DMA_FROM_DEVICE); + + } else { + mb = *pmb; + if (unlikely(mlx4_en_alloc_rx_mb(priv, rx_desc, pmb, 1))) + return NULL; + } + + mb->m_len = length; + mb->m_pkthdr.len = length; + return mb; +} + +static void validate_loopback(struct mlx4_en_priv *priv, struct mbuf *mb) +{ + int i; + int offset = ETHER_HDR_LEN; + + for (i = 0; i < MLX4_LOOPBACK_TEST_PAYLOAD; i++, offset++) { + if (*(mb->m_data + offset) != (unsigned char) (i & 0xff)) + goto out_loopback; + } + /* Loopback found */ + priv->loopback_ok = 1; + +out_loopback: + m_freem(mb); +} + +int mlx4_en_process_rx_cq_mb(struct net_device *dev, + struct mlx4_en_cq *cq, int budget) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_cqe *cqe; + struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring]; + struct mlx4_en_rx_desc *rx_desc; + struct mbuf **pmb; + struct mbuf *mb; + int index; + unsigned int length; + int polled = 0; + + if (!priv->port_up) + return 0; + + /* We assume a 1:1 mapping between CQEs and Rx descriptors, so Rx + * descriptor offset can be deduced from the CQE index instead of + * reading 'cqe->index' */ + index = cq->mcq.cons_index & ring->size_mask; + cqe = &cq->buf[index]; + + /* Process all completed CQEs */ + while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK, + cq->mcq.cons_index & cq->size)) { + + pmb = (struct mbuf **) ring->rx_info + index; + rx_desc = ring->buf + (index << ring->log_stride); + + /* + * make sure we read the CQE after we read the ownership bit + */ + rmb(); + + if (invalid_cqe(priv, cqe)) + goto next; + + /* + * Packet is OK - process it. + */ + length = be32_to_cpu(cqe->byte_cnt); + + mb = mlx4_en_get_rx_mb(priv, rx_desc, pmb, length); + if (unlikely(!mb)){ + ring->errors++; + goto next; + } + + ring->bytes += length; + ring->packets++; + + if (unlikely(priv->validate_loopback)) { + validate_loopback(priv, mb); + goto next; + } + mb->m_pkthdr.flowid = cq->ring; + mb->m_flags |= M_FLOWID; + mb->m_pkthdr.rcvif = dev; + if (be32_to_cpu(cqe->vlan_my_qpn) & + MLX4_CQE_VLAN_PRESENT_MASK) { + mb->m_pkthdr.ether_vtag = be16_to_cpu(cqe->sl_vid); + mb->m_flags |= M_VLANTAG; + } + + if (likely(priv->rx_csum && cqe->checksum == 0xffff)) { + priv->port_stats.rx_chksum_good++; + mb->m_pkthdr.csum_flags = + CSUM_IP_CHECKED | CSUM_IP_VALID | + CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + mb->m_pkthdr.csum_data = htons(0xffff); + } else { + priv->port_stats.rx_chksum_none++; + mb->m_pkthdr.csum_flags = 0; + if (priv->mdev->profile.ip_reasm && + cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4) && + !mlx4_en_rx_frags(priv, ring, mb, cqe)) + goto next; + } + /* Push it up the stack */ + dev->if_input(dev, mb); + +next: + ++cq->mcq.cons_index; + index = (cq->mcq.cons_index) & ring->size_mask; + cqe = &cq->buf[index]; + if (++polled == budget) + break; + } + + /* If CQ is empty, flush all pending IP reassembly sessions */ + mlx4_en_flush_frags(priv, ring); + + AVG_PERF_COUNTER(priv->pstats.rx_coal_avg, polled); + mlx4_cq_set_ci(&cq->mcq); + wmb(); /* ensure HW sees CQ consumer before we post new buffers */ + ring->cons = cq->mcq.cons_index; + ring->prod += polled; /* Polled descriptors were realocated in place */ + mlx4_en_update_rx_prod_db(ring); + return polled; +} + +int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_cqe *cqe; + struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring]; + struct mbuf **mb_list; + struct mlx4_en_rx_desc *rx_desc; + struct mbuf *mb; + struct lro_entry *queued; + int index; + unsigned int length; + int polled = 0; + + if (!priv->port_up) + return 0; + + /* We assume a 1:1 mapping between CQEs and Rx descriptors, so Rx + * descriptor offset can be deduced from the CQE index instead of + * reading 'cqe->index' */ + index = cq->mcq.cons_index & ring->size_mask; + cqe = &cq->buf[index]; + + /* Process all completed CQEs */ + while (XNOR(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK, + cq->mcq.cons_index & cq->size)) { + + mb_list = ring->rx_info + (index << priv->log_rx_info); + rx_desc = ring->buf + (index << ring->log_stride); + + /* + * make sure we read the CQE after we read the ownership bit + */ + rmb(); + + if (invalid_cqe(priv, cqe)) + goto next; + + /* + * Packet is OK - process it. + */ + length = be32_to_cpu(cqe->byte_cnt); + mb = mlx4_en_rx_mb(priv, rx_desc, mb_list, length); + if (!mb) { + ring->errors++; + goto next; + } + + ring->bytes += length; + ring->packets++; + + if (unlikely(priv->validate_loopback)) { + validate_loopback(priv, mb); + goto next; + } + + mb->m_pkthdr.flowid = cq->ring; + mb->m_flags |= M_FLOWID; + mb->m_pkthdr.rcvif = dev; + if (be32_to_cpu(cqe->vlan_my_qpn) & + MLX4_CQE_VLAN_PRESENT_MASK) { + mb->m_pkthdr.ether_vtag = be16_to_cpu(cqe->sl_vid); + mb->m_flags |= M_VLANTAG; + } + if (likely(priv->rx_csum) && + (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) && + (cqe->checksum == cpu_to_be16(0xffff))) { + priv->port_stats.rx_chksum_good++; + mb->m_pkthdr.csum_flags = + CSUM_IP_CHECKED | CSUM_IP_VALID | + CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + mb->m_pkthdr.csum_data = htons(0xffff); + /* This packet is eligible for LRO if it is: + * - DIX Ethernet (type interpretation) + * - TCP/IP (v4) + * - without IP options + * - not an IP fragment + */ + if (mlx4_en_can_lro(cqe->status) && + (dev->if_capenable & IFCAP_LRO)) { + if (ring->lro.lro_cnt != 0 && + tcp_lro_rx(&ring->lro, mb, 0) == 0) + goto next; + } + + /* LRO not possible, complete processing here */ + INC_PERF_COUNTER(priv->pstats.lro_misses); + } else { + mb->m_pkthdr.csum_flags = 0; + priv->port_stats.rx_chksum_none++; + } + + /* Push it up the stack */ + dev->if_input(dev, mb); + +next: + ++cq->mcq.cons_index; + index = (cq->mcq.cons_index) & ring->size_mask; + cqe = &cq->buf[index]; + if (++polled == budget) + break; + } + while ((queued = SLIST_FIRST(&ring->lro.lro_active)) != NULL) { + SLIST_REMOVE_HEAD(&ring->lro.lro_active, next); + tcp_lro_flush(&ring->lro, queued); + } + AVG_PERF_COUNTER(priv->pstats.rx_coal_avg, polled); + mlx4_cq_set_ci(&cq->mcq); + wmb(); /* ensure HW sees CQ consumer before we post new buffers */ + ring->cons = cq->mcq.cons_index; + ring->prod += polled; /* Polled descriptors were realocated in place */ + mlx4_en_update_rx_prod_db(ring); + return polled; +} + + +/* Rx CQ polling - called by NAPI */ +static int mlx4_en_poll_rx_cq(struct mlx4_en_cq *cq, int budget) +{ + struct net_device *dev = cq->dev; + struct mlx4_en_priv *priv = netdev_priv(dev); + int done; + + if (priv->rx_ring[cq->ring].use_frags) + done = mlx4_en_process_rx_cq(dev, cq, budget); + else + done = mlx4_en_process_rx_cq_mb(dev, cq, budget); + + cq->tot_rx += done; + + return done; +} + +void mlx4_en_rx_que(void *context, int pending) +{ + struct mlx4_en_cq *cq; + + cq = context; + while (mlx4_en_poll_rx_cq(cq, MLX4_EN_MAX_RX_POLL) + == MLX4_EN_MAX_RX_POLL); + mlx4_en_arm_cq(cq->dev->if_softc, cq); +} + +void mlx4_en_rx_irq(struct mlx4_cq *mcq) +{ + struct mlx4_en_cq *cq = container_of(mcq, struct mlx4_en_cq, mcq); + struct mlx4_en_priv *priv = netdev_priv(cq->dev); + int done; + + done = mlx4_en_poll_rx_cq(cq, MLX4_EN_MAX_RX_POLL); + if (done == MLX4_EN_MAX_RX_POLL) + taskqueue_enqueue(cq->tq, &cq->cq_task); + else + mlx4_en_arm_cq(priv, cq); +} + + +#if MLX4_EN_MAX_RX_FRAGS == 3 +static int frag_sizes[] = { + FRAG_SZ0, + FRAG_SZ1, + FRAG_SZ2, +}; +#elif MLX4_EN_MAX_RX_FRAGS == 2 +static int frag_sizes[] = { + FRAG_SZ0, + FRAG_SZ1, +}; +#else +#error "Unknown MAX_RX_FRAGS" +#endif + +void mlx4_en_calc_rx_buf(struct net_device *dev) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int eff_mtu = dev->if_mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETH_LLC_SNAP_SIZE; + int buf_size = 0; + int i, frag; + + for (i = 0, frag = 0; buf_size < eff_mtu; frag++, i++) { + /* + * Allocate small to large but only as much as is needed for + * the tail. + */ + while (i > 0 && eff_mtu - buf_size <= frag_sizes[i - 1]) + i--; + priv->frag_info[frag].frag_size = frag_sizes[i]; + priv->frag_info[frag].frag_prefix_size = buf_size; + buf_size += priv->frag_info[frag].frag_size; + } + + priv->num_frags = frag; + /* + * For use_frags == 0 calculate the size extbuf we require. + */ + if (eff_mtu <= MCLBYTES) + priv->rx_mb_size = MCLBYTES; + else if (eff_mtu <= MJUMPAGESIZE) + priv->rx_mb_size = MJUMPAGESIZE; + else if (eff_mtu <= MJUM9BYTES) + priv->rx_mb_size = MJUM9BYTES; + else + priv->rx_mb_size = MJUM16BYTES; + priv->log_rx_info = + ROUNDUP_LOG2(priv->num_frags * sizeof(struct mbuf *)); + + en_dbg(DRV, priv, "Rx buffer scatter-list (effective-mtu:%d " + "num_frags:%d):\n", eff_mtu, priv->num_frags); + for (i = 0; i < priv->num_frags; i++) { + en_dbg(DRV, priv, " frag:%d - size:%d prefix:%d\n", i, + priv->frag_info[i].frag_size, + priv->frag_info[i].frag_prefix_size) + } +} + +/* RSS related functions */ + +static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn, + struct mlx4_en_rx_ring *ring, + enum mlx4_qp_state *state, + struct mlx4_qp *qp) +{ + struct mlx4_en_dev *mdev = priv->mdev; + struct mlx4_qp_context *context; + int err = 0; + + context = kmalloc(sizeof *context , GFP_KERNEL); + if (!context) { + en_err(priv, "Failed to allocate qp context\n"); + return -ENOMEM; + } + + err = mlx4_qp_alloc(mdev->dev, qpn, qp); + if (err) { + en_err(priv, "Failed to allocate qp #%x\n", qpn); + goto out; + } + qp->event = mlx4_en_sqp_event; + + memset(context, 0, sizeof *context); + mlx4_en_fill_qp_context(priv, ring->actual_size, ring->stride, 0, 0, + qpn, ring->cqn, context); + context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma); + + err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, context, qp, state); + if (err) { + mlx4_qp_remove(mdev->dev, qp); + mlx4_qp_free(mdev->dev, qp); + } + mlx4_en_update_rx_prod_db(ring); +out: + kfree(context); + return err; +} + +/* Allocate rx qp's and configure them according to rss map */ +int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) +{ + struct mlx4_en_dev *mdev = priv->mdev; + struct mlx4_en_rss_map *rss_map = &priv->rss_map; + struct mlx4_qp_context context; + struct mlx4_en_rss_context *rss_context; + void *ptr; + u8 rss_mask = (priv->udp_rings > 1) ? 0x3f : 0x14; + int i, qpn; + int err = 0; + int good_qps = 0; + + en_dbg(DRV, priv, "Configuring rss steering\n"); + err = mlx4_qp_reserve_range(mdev->dev, priv->rx_ring_num, + roundup_pow_of_two(priv->rx_ring_num), + &rss_map->base_qpn); + if (err) { + en_err(priv, "Failed reserving %d qps\n", priv->rx_ring_num); + return err; + } + + for (i = 0; i < priv->rx_ring_num; i++) { + qpn = rss_map->base_qpn + i; + err = mlx4_en_config_rss_qp(priv, qpn, + &priv->rx_ring[i], + &rss_map->state[i], + &rss_map->qps[i]); + if (err) + goto rss_err; + + ++good_qps; + } + + /* Configure RSS indirection qp */ + err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &priv->base_qpn); + if (err) { + en_err(priv, "Failed to reserve range for RSS " + "indirection qp\n"); + goto rss_err; + } + err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp); + if (err) { + en_err(priv, "Failed to allocate RSS indirection QP\n"); + goto reserve_err; + } + rss_map->indir_qp.event = mlx4_en_sqp_event; + mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn, + priv->rx_ring[0].cqn, &context); + + ptr = ((void *) &context) + 0x3c; + rss_context = (struct mlx4_en_rss_context *) ptr; + rss_context->base_qpn = cpu_to_be32(ilog2(priv->rx_ring_num - priv->udp_rings) << 24 | + (rss_map->base_qpn)); + rss_context->default_qpn = cpu_to_be32(rss_map->base_qpn + + priv->rx_ring_num - + priv->udp_rings); + rss_context->flags = rss_mask; + if (priv->udp_rings > 1) + rss_context->base_qpn_udp = rss_context->default_qpn; + + err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context, + &rss_map->indir_qp, &rss_map->indir_state); + if (err) + goto indir_err; + + return 0; + +indir_err: + mlx4_qp_modify(mdev->dev, NULL, rss_map->indir_state, + MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); + mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); + mlx4_qp_free(mdev->dev, &rss_map->indir_qp); +reserve_err: + mlx4_qp_release_range(mdev->dev, priv->base_qpn, 1); +rss_err: + for (i = 0; i < good_qps; i++) { + mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], + MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->qps[i]); + mlx4_qp_remove(mdev->dev, &rss_map->qps[i]); + mlx4_qp_free(mdev->dev, &rss_map->qps[i]); + } + mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, priv->rx_ring_num); + return err; +} + +void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv) +{ + struct mlx4_en_dev *mdev = priv->mdev; + struct mlx4_en_rss_map *rss_map = &priv->rss_map; + int i; + + mlx4_qp_modify(mdev->dev, NULL, rss_map->indir_state, + MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); + mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); + mlx4_qp_free(mdev->dev, &rss_map->indir_qp); + mlx4_qp_release_range(mdev->dev, priv->base_qpn, 1); + + for (i = 0; i < priv->rx_ring_num; i++) { + mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], + MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->qps[i]); + mlx4_qp_remove(mdev->dev, &rss_map->qps[i]); + mlx4_qp_free(mdev->dev, &rss_map->qps[i]); + } + mlx4_qp_release_range(mdev->dev, rss_map->base_qpn, priv->rx_ring_num); +} diff --git a/sys/ofed/drivers/net/mlx4/en_selftest.c b/sys/ofed/drivers/net/mlx4/en_selftest.c new file mode 100644 index 000000000000..0e62027321c7 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/en_selftest.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include "mlx4_en.h" + +#include +#include +#include +#include +#include + + +static int mlx4_en_test_registers(struct mlx4_en_priv *priv) +{ + return mlx4_cmd(priv->mdev->dev, 0, 0, 0, MLX4_CMD_HW_HEALTH_CHECK, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_en_test_loopback_xmit(struct mlx4_en_priv *priv) +{ + struct mbuf *mb; + struct ethhdr *ethh; + unsigned char *packet; + unsigned int packet_size = MLX4_LOOPBACK_TEST_PAYLOAD; + unsigned int i; + int err; + + + /* build the pkt before xmit */ + mb = netdev_alloc_mb(priv->dev, MLX4_LOOPBACK_TEST_PAYLOAD + ETH_HLEN + NET_IP_ALIGN); + if (!mb) { + en_err(priv, "-LOOPBACK_TEST_XMIT- failed to create mb for xmit\n"); + return -ENOMEM; + } + mb_reserve(mb, NET_IP_ALIGN); + + ethh = (struct ethhdr *)mb_put(mb, sizeof(struct ethhdr)); + packet = (unsigned char *)mb_put(mb, packet_size); + memcpy(ethh->h_dest, priv->dev->dev_addr, ETH_ALEN); + memset(ethh->h_source, 0, ETH_ALEN); + ethh->h_proto = htons(ETH_P_ARP); + mb_set_mac_header(mb, 0); + for (i = 0; i < packet_size; ++i) /* fill our packet */ + packet[i] = (unsigned char)(i & 0xff); + + /* xmit the pkt */ + err = mlx4_en_xmit(mb, priv->dev); + return err; +} + +static int mlx4_en_test_loopback(struct mlx4_en_priv *priv) +{ + u32 loopback_ok = 0; + int i; + + + priv->loopback_ok = 0; + priv->validate_loopback = 1; + + /* xmit */ + if (mlx4_en_test_loopback_xmit(priv)) { + en_err(priv, "Transmitting loopback packet failed\n"); + goto mlx4_en_test_loopback_exit; + } + + /* polling for result */ + for (i = 0; i < MLX4_EN_LOOPBACK_RETRIES; ++i) { + msleep(MLX4_EN_LOOPBACK_TIMEOUT); + if (priv->loopback_ok) { + loopback_ok = 1; + break; + } + } + if (!loopback_ok) + en_err(priv, "Loopback packet didn't arrive\n"); + +mlx4_en_test_loopback_exit: + + priv->validate_loopback = 0; + return (!loopback_ok); +} + + +static int mlx4_en_test_link(struct mlx4_en_priv *priv) +{ + if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) + return -ENOMEM; + if (priv->port_state.link_state == 1) + return 0; + else + return 1; +} + +static int mlx4_en_test_speed(struct mlx4_en_priv *priv) +{ + + if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) + return -ENOMEM; + + /* The device currently only supports 10G speed */ + if (priv->port_state.link_speed != SPEED_10000) + return priv->port_state.link_speed; + return 0; +} + + +void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + struct mlx4_en_tx_ring *tx_ring; + int i, carrier_ok; + + memset(buf, 0, sizeof(u64) * MLX4_EN_NUM_SELF_TEST); + + if (*flags & ETH_TEST_FL_OFFLINE) { + /* disable the interface */ + carrier_ok = netif_carrier_ok(dev); + + netif_carrier_off(dev); +retry_tx: + /* Wait untill all tx queues are empty. + * there should not be any additional incoming traffic + * since we turned the carrier off */ + msleep(200); + for (i = 0; i < priv->tx_ring_num && carrier_ok; i++) { + tx_ring = &priv->tx_ring[i]; + if (tx_ring->prod != (tx_ring->cons + tx_ring->last_nr_txbb)) + goto retry_tx; + } + + if (priv->mdev->dev->caps.loopback_support){ + buf[3] = mlx4_en_test_registers(priv); + buf[4] = mlx4_en_test_loopback(priv); + } + + if (carrier_ok) + netif_carrier_on(dev); + + } + buf[0] = mlx4_test_interrupts(mdev->dev); + buf[1] = mlx4_en_test_link(priv); + buf[2] = mlx4_en_test_speed(priv); + + for (i = 0; i < MLX4_EN_NUM_SELF_TEST; i++) { + if (buf[i]) + *flags |= ETH_TEST_FL_FAILED; + } +} diff --git a/sys/ofed/drivers/net/mlx4/en_tx.c b/sys/ofed/drivers/net/mlx4/en_tx.c new file mode 100644 index 000000000000..cd45f9dc0ac7 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/en_tx.c @@ -0,0 +1,1035 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include "mlx4_en.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */ + MAX_BF = 256, +}; + +static int inline_thold = MAX_INLINE; + +module_param_named(inline_thold, inline_thold, int, 0444); +MODULE_PARM_DESC(inline_thold, "treshold for using inline data"); + +int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, + struct mlx4_en_tx_ring *ring, u32 size, + u16 stride) +{ + struct mlx4_en_dev *mdev = priv->mdev; + int tmp; + int err; + + ring->size = size; + ring->size_mask = size - 1; + ring->stride = stride; + + inline_thold = min(inline_thold, MAX_INLINE); + + mtx_init(&ring->tx_lock.m, "mlx4 tx", NULL, MTX_DEF); + mtx_init(&ring->comp_lock.m, "mlx4 comp", NULL, MTX_DEF); + + /* Allocate the buf ring */ + ring->br = buf_ring_alloc(MLX4_EN_DEF_TX_QUEUE_SIZE, M_DEVBUF, + M_WAITOK, &ring->tx_lock.m); + if (ring->br == NULL) { + en_err(priv, "Failed allocating tx_info ring\n"); + return -ENOMEM; + } + + tmp = size * sizeof(struct mlx4_en_tx_info); + ring->tx_info = kmalloc(tmp, GFP_KERNEL); + if (!ring->tx_info) { + en_err(priv, "Failed allocating tx_info ring\n"); + err = -ENOMEM; + goto err_tx; + } + en_dbg(DRV, priv, "Allocated tx_info ring at addr:%p size:%d\n", + ring->tx_info, tmp); + + ring->bounce_buf = kmalloc(MAX_DESC_SIZE, GFP_KERNEL); + if (!ring->bounce_buf) { + en_err(priv, "Failed allocating bounce buffer\n"); + err = -ENOMEM; + goto err_tx; + } + ring->buf_size = ALIGN(size * ring->stride, MLX4_EN_PAGE_SIZE); + + err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, ring->buf_size, + 2 * PAGE_SIZE); + if (err) { + en_err(priv, "Failed allocating hwq resources\n"); + goto err_bounce; + } + + err = mlx4_en_map_buffer(&ring->wqres.buf); + if (err) { + en_err(priv, "Failed to map TX buffer\n"); + goto err_hwq_res; + } + + ring->buf = ring->wqres.buf.direct.buf; + + en_dbg(DRV, priv, "Allocated TX ring (addr:%p) - buf:%p size:%d " + "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size, + ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map); + + err = mlx4_qp_reserve_range(mdev->dev, 1, 256, &ring->qpn); + if (err) { + en_err(priv, "Failed reserving qp for tx ring.\n"); + goto err_map; + } + + err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp); + if (err) { + en_err(priv, "Failed allocating qp %d\n", ring->qpn); + goto err_reserve; + } + ring->qp.event = mlx4_en_sqp_event; + + err = mlx4_bf_alloc(mdev->dev, &ring->bf); + if (err) { + ring->bf.uar = &mdev->priv_uar; + ring->bf.uar->map = mdev->uar_map; + ring->bf_enabled = false; + } else + ring->bf_enabled = true; + + return 0; + +err_reserve: + mlx4_qp_release_range(mdev->dev, ring->qpn, 1); +err_map: + mlx4_en_unmap_buffer(&ring->wqres.buf); +err_hwq_res: + mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); +err_bounce: + kfree(ring->bounce_buf); + ring->bounce_buf = NULL; +err_tx: + buf_ring_free(ring->br, M_DEVBUF); + kfree(ring->tx_info); + ring->tx_info = NULL; + return err; +} + +void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, + struct mlx4_en_tx_ring *ring) +{ + struct mlx4_en_dev *mdev = priv->mdev; + en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); + + buf_ring_free(ring->br, M_DEVBUF); + if (ring->bf_enabled) + mlx4_bf_free(mdev->dev, &ring->bf); + mlx4_qp_remove(mdev->dev, &ring->qp); + mlx4_qp_free(mdev->dev, &ring->qp); + mlx4_qp_release_range(mdev->dev, ring->qpn, 1); + mlx4_en_unmap_buffer(&ring->wqres.buf); + mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); + kfree(ring->bounce_buf); + ring->bounce_buf = NULL; + kfree(ring->tx_info); + ring->tx_info = NULL; + mtx_destroy(&ring->tx_lock.m); + mtx_destroy(&ring->comp_lock.m); +} + +int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, + struct mlx4_en_tx_ring *ring, + int cq) +{ + struct mlx4_en_dev *mdev = priv->mdev; + int err; + + ring->cqn = cq; + ring->prod = 0; + ring->cons = 0xffffffff; + ring->last_nr_txbb = 1; + ring->poll_cnt = 0; + ring->blocked = 0; + memset(ring->tx_info, 0, ring->size * sizeof(struct mlx4_en_tx_info)); + memset(ring->buf, 0, ring->buf_size); + + ring->qp_state = MLX4_QP_STATE_RST; + ring->doorbell_qpn = swab32(ring->qp.qpn << 8); + + mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn, + ring->cqn, &ring->context); + if (ring->bf_enabled) + ring->context.usr_page = cpu_to_be32(ring->bf.uar->index); + + err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context, + &ring->qp, &ring->qp_state); + + return err; +} + +void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, + struct mlx4_en_tx_ring *ring) +{ + struct mlx4_en_dev *mdev = priv->mdev; + + mlx4_qp_modify(mdev->dev, NULL, ring->qp_state, + MLX4_QP_STATE_RST, NULL, 0, 0, &ring->qp); +} + + +static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, + struct mlx4_en_tx_ring *ring, + int index, u8 owner) +{ + struct mlx4_en_dev *mdev = priv->mdev; + struct mlx4_en_tx_info *tx_info = &ring->tx_info[index]; + struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE; + struct mlx4_wqe_data_seg *data = (void *) tx_desc + tx_info->data_offset; + struct mbuf *mb = tx_info->mb; + void *end = ring->buf + ring->buf_size; + int frags = tx_info->nr_segs; + int i; + __be32 *ptr = (__be32 *)tx_desc; + __be32 stamp = cpu_to_be32(STAMP_VAL | (!!owner << STAMP_SHIFT)); + + /* Optimize the common case when there are no wraparounds */ + if (likely((void *) tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) { + if (!tx_info->inl) { + for (i = 0; i < frags; i++) { + pci_unmap_single(mdev->pdev, + (dma_addr_t) be64_to_cpu(data[i].addr), + data[i].byte_count, PCI_DMA_TODEVICE); + } + } + /* Stamp the freed descriptor */ + for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) { + *ptr = stamp; + ptr += STAMP_DWORDS; + } + + } else { + if (!tx_info->inl) { + for (i = 0; i < frags; i++) { + /* Check for wraparound before unmapping */ + if ((void *) data >= end) + data = (struct mlx4_wqe_data_seg *) ring->buf; + pci_unmap_single(mdev->pdev, + (dma_addr_t) be64_to_cpu(data->addr), + data->byte_count, PCI_DMA_TODEVICE); + ++data; + } + } + /* Stamp the freed descriptor */ + for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) { + *ptr = stamp; + ptr += STAMP_DWORDS; + if ((void *) ptr >= end) { + ptr = ring->buf; + stamp ^= cpu_to_be32(0x80000000); + } + } + + } + m_freem(mb); + return tx_info->nr_txbb; +} + + +int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + int cnt = 0; + + /* Skip last polled descriptor */ + ring->cons += ring->last_nr_txbb; + en_dbg(DRV, priv, "Freeing Tx buf - cons:0x%x prod:0x%x\n", + ring->cons, ring->prod); + + if ((u32) (ring->prod - ring->cons) > ring->size) { + en_warn(priv, "Tx consumer passed producer!\n"); + return 0; + } + + while (ring->cons != ring->prod) { + ring->last_nr_txbb = mlx4_en_free_tx_desc(priv, ring, + ring->cons & ring->size_mask, + !!(ring->cons & ring->size)); + ring->cons += ring->last_nr_txbb; + cnt++; + } + + if (cnt) + en_dbg(DRV, priv, "Freed %d uncompleted tx descriptors\n", cnt); + + return cnt; +} + +void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num) +{ + int block = 8 / ring_num; + int extra = 8 - (block * ring_num); + int num = 0; + u16 ring = 1; + int prio; + + if (ring_num == 1) { + for (prio = 0; prio < 8; prio++) + prio_map[prio] = 0; + return; + } + + for (prio = 0; prio < 8; prio++) { + if (extra && (num == block + 1)) { + ring++; + num = 0; + extra--; + } else if (!extra && (num == block)) { + ring++; + num = 0; + } + prio_map[prio] = ring; + en_dbg(DRV, priv, " prio:%d --> ring:%d\n", prio, ring); + num++; + } +} + +static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_cq *mcq = &cq->mcq; + struct mlx4_en_tx_ring *ring = &priv->tx_ring[cq->ring]; + struct mlx4_cqe *cqe = cq->buf; + u16 index; + u16 new_index; + u32 txbbs_skipped = 0; + u32 cq_last_sav; + + /* index always points to the first TXBB of the last polled descriptor */ + index = ring->cons & ring->size_mask; + new_index = be16_to_cpu(cqe->wqe_index) & ring->size_mask; + if (index == new_index) + return; + + if (!priv->port_up) + return; + + /* + * We use a two-stage loop: + * - the first samples the HW-updated CQE + * - the second frees TXBBs until the last sample + * This lets us amortize CQE cache misses, while still polling the CQ + * until is quiescent. + */ + cq_last_sav = mcq->cons_index; + do { + do { + /* Skip over last polled CQE */ + index = (index + ring->last_nr_txbb) & ring->size_mask; + txbbs_skipped += ring->last_nr_txbb; + + /* Poll next CQE */ + ring->last_nr_txbb = mlx4_en_free_tx_desc( + priv, ring, index, + !!((ring->cons + txbbs_skipped) & + ring->size)); + ++mcq->cons_index; + + } while (index != new_index); + + new_index = be16_to_cpu(cqe->wqe_index) & ring->size_mask; + } while (index != new_index); + AVG_PERF_COUNTER(priv->pstats.tx_coal_avg, + (u32) (mcq->cons_index - cq_last_sav)); + + /* + * To prevent CQ overflow we first update CQ consumer and only then + * the ring consumer. + */ + mlx4_cq_set_ci(mcq); + wmb(); + ring->cons += txbbs_skipped; + + /* Wakeup Tx queue if this ring stopped it */ + if (unlikely(ring->blocked)) { + if ((u32) (ring->prod - ring->cons) <= + ring->size - HEADROOM - MAX_DESC_TXBBS) { + ring->blocked = 0; + if (atomic_fetchadd_int(&priv->blocked, -1) == 1) + atomic_clear_int(&dev->if_drv_flags, + IFF_DRV_OACTIVE); + priv->port_stats.wake_queue++; + } + } +} + +void mlx4_en_tx_irq(struct mlx4_cq *mcq) +{ + struct mlx4_en_cq *cq = container_of(mcq, struct mlx4_en_cq, mcq); + struct mlx4_en_priv *priv = netdev_priv(cq->dev); + struct mlx4_en_tx_ring *ring = &priv->tx_ring[cq->ring]; + + if (!spin_trylock(&ring->comp_lock)) + return; + mlx4_en_process_tx_cq(cq->dev, cq); + mod_timer(&cq->timer, jiffies + 1); + spin_unlock(&ring->comp_lock); +} + + +void mlx4_en_poll_tx_cq(unsigned long data) +{ + struct mlx4_en_cq *cq = (struct mlx4_en_cq *) data; + struct mlx4_en_priv *priv = netdev_priv(cq->dev); + struct mlx4_en_tx_ring *ring = &priv->tx_ring[cq->ring]; + u32 inflight; + + INC_PERF_COUNTER(priv->pstats.tx_poll); + + if (!spin_trylock(&ring->comp_lock)) { + mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); + return; + } + mlx4_en_process_tx_cq(cq->dev, cq); + inflight = (u32) (ring->prod - ring->cons - ring->last_nr_txbb); + + /* If there are still packets in flight and the timer has not already + * been scheduled by the Tx routine then schedule it here to guarantee + * completion processing of these packets */ + if (inflight && priv->port_up) + mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); + + spin_unlock(&ring->comp_lock); +} + +static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv, + struct mlx4_en_tx_ring *ring, + u32 index, + unsigned int desc_size) +{ + u32 copy = (ring->size - index) * TXBB_SIZE; + int i; + + for (i = desc_size - copy - 4; i >= 0; i -= 4) { + if ((i & (TXBB_SIZE - 1)) == 0) + wmb(); + + *((u32 *) (ring->buf + i)) = + *((u32 *) (ring->bounce_buf + copy + i)); + } + + for (i = copy - 4; i >= 4 ; i -= 4) { + if ((i & (TXBB_SIZE - 1)) == 0) + wmb(); + + *((u32 *) (ring->buf + index * TXBB_SIZE + i)) = + *((u32 *) (ring->bounce_buf + i)); + } + + /* Return real descriptor location */ + return ring->buf + index * TXBB_SIZE; +} + +static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind) +{ + struct mlx4_en_cq *cq = &priv->tx_cq[tx_ind]; + struct mlx4_en_tx_ring *ring = &priv->tx_ring[tx_ind]; + + /* If we don't have a pending timer, set one up to catch our recent + post in case the interface becomes idle */ + if (!timer_pending(&cq->timer)) + mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); + + /* Poll the CQ every mlx4_en_TX_MODER_POLL packets */ + if ((++ring->poll_cnt & (MLX4_EN_TX_POLL_MODER - 1)) == 0) + if (spin_trylock(&ring->comp_lock)) { + mlx4_en_process_tx_cq(priv->dev, cq); + spin_unlock(&ring->comp_lock); + } +} + +static int is_inline(struct mbuf *mb) +{ + + if (inline_thold && mb->m_pkthdr.len <= inline_thold && + (mb->m_pkthdr.csum_flags & CSUM_TSO) == 0) + return 1; + + return 0; +} + +static int inline_size(struct mbuf *mb) +{ + int len; + + len = mb->m_pkthdr.len; + if (len + CTRL_SIZE + sizeof(struct mlx4_wqe_inline_seg) + <= MLX4_INLINE_ALIGN) + return ALIGN(len + CTRL_SIZE + + sizeof(struct mlx4_wqe_inline_seg), 16); + else + return ALIGN(len + CTRL_SIZE + 2 * + sizeof(struct mlx4_wqe_inline_seg), 16); +} + +static int get_head_size(struct mbuf *mb) +{ + struct tcphdr *th; + struct ip *ip; + int ip_hlen, tcp_hlen; + int len; + + len = ETHER_HDR_LEN; + if (mb->m_len < len + sizeof(struct ip)) + return (0); + ip = (struct ip *)(mtod(mb, char *) + len); + if (ip->ip_p != IPPROTO_TCP) + return (0); + ip_hlen = ip->ip_hl << 2; + len += ip_hlen; + if (mb->m_len < len + sizeof(struct tcphdr)) + return (0); + th = (struct tcphdr *)(mtod(mb, char *) + len); + tcp_hlen = th->th_off << 2; + len += tcp_hlen; + if (mb->m_len < len) + return (0); + return (len); +} + +static int get_real_size(struct mbuf *mb, struct net_device *dev, int *segsp, + int *lso_header_size) +{ + struct mbuf *m; + int nr_segs; + + nr_segs = 0; + for (m = mb; m != NULL; m = m->m_next) + if (m->m_len) + nr_segs++; + + if (mb->m_pkthdr.csum_flags & CSUM_TSO) { + *lso_header_size = get_head_size(mb); + if (*lso_header_size) { + if (mb->m_len == *lso_header_size) + nr_segs--; + *segsp = nr_segs; + return CTRL_SIZE + nr_segs * DS_SIZE + + ALIGN(*lso_header_size + 4, DS_SIZE); + } + } else + *lso_header_size = 0; + *segsp = nr_segs; + if (is_inline(mb)) + return inline_size(mb); + return (CTRL_SIZE + nr_segs * DS_SIZE); +} + +static struct mbuf *mb_copy(struct mbuf *mb, int *offp, char *data, int len) +{ + int bytes; + int off; + + off = *offp; + while (len) { + bytes = min(mb->m_len - off, len); + if (bytes) + memcpy(data, mb->m_data + off, bytes); + len -= bytes; + data += bytes; + off += bytes; + if (off == mb->m_len) { + off = 0; + mb = mb->m_next; + } + } + *offp = off; + return (mb); +} + +static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct mbuf *mb, + int real_size, u16 *vlan_tag, int tx_ind) +{ + struct mlx4_wqe_inline_seg *inl = &tx_desc->inl; + int spc = MLX4_INLINE_ALIGN - CTRL_SIZE - sizeof *inl; + int len; + int off; + + off = 0; + len = mb->m_pkthdr.len; + if (len <= spc) { + inl->byte_count = cpu_to_be32(1 << 31 | len); + mb_copy(mb, &off, (void *)(inl + 1), len); + } else { + inl->byte_count = cpu_to_be32(1 << 31 | spc); + mb = mb_copy(mb, &off, (void *)(inl + 1), spc); + inl = (void *) (inl + 1) + spc; + mb_copy(mb, &off, (void *)(inl + 1), len - spc); + wmb(); + inl->byte_count = cpu_to_be32(1 << 31 | (len - spc)); + } + tx_desc->ctrl.vlan_tag = cpu_to_be16(*vlan_tag); + tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN * !!(*vlan_tag); + tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f; +} + +u16 mlx4_en_select_queue(struct net_device *dev, struct mbuf *mb) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_tx_hash_entry *entry; + struct ether_header *eth; + struct tcphdr *th; + struct ip *iph; + u32 hash_index; + int tx_ind = 0; + u16 vlan_tag = 0; + int len; + + /* Obtain VLAN information if present */ + if (mb->m_flags & M_VLANTAG) { + vlan_tag = mb->m_pkthdr.ether_vtag; + /* Set the Tx ring to use according to vlan priority */ + tx_ind = priv->tx_prio_map[vlan_tag >> 13]; + if (tx_ind) + return tx_ind; + } + if (mb->m_len < + ETHER_HDR_LEN + sizeof(struct ip) + sizeof(struct tcphdr)) + return MLX4_EN_NUM_HASH_RINGS; + eth = mtod(mb, struct ether_header *); + /* Hashing is only done for TCP/IP or UDP/IP packets */ + if (be16_to_cpu(eth->ether_type) != ETHERTYPE_IP) + return MLX4_EN_NUM_HASH_RINGS; + len = ETHER_HDR_LEN; + iph = (struct ip *)(mtod(mb, char *) + len); + len += iph->ip_hl << 2; + th = (struct tcphdr *)(mtod(mb, char *) + len); + hash_index = be32_to_cpu(iph->ip_dst.s_addr) & MLX4_EN_TX_HASH_MASK; + switch(iph->ip_p) { + case IPPROTO_UDP: + break; + case IPPROTO_TCP: + if (mb->m_len < len + sizeof(struct tcphdr)) + return MLX4_EN_NUM_HASH_RINGS; + hash_index = + (hash_index ^ be16_to_cpu(th->th_dport ^ th->th_sport)) & + MLX4_EN_TX_HASH_MASK; + break; + default: + return MLX4_EN_NUM_HASH_RINGS; + } + + entry = &priv->tx_hash[hash_index]; + if(unlikely(!entry->cnt)) { + tx_ind = hash_index & (MLX4_EN_NUM_HASH_RINGS / 2 - 1); + if (2 * entry->small_pkts > entry->big_pkts) + tx_ind += MLX4_EN_NUM_HASH_RINGS / 2; + entry->small_pkts = entry->big_pkts = 0; + entry->ring = tx_ind; + } + + entry->cnt++; + if (mb->m_pkthdr.len > MLX4_EN_SMALL_PKT_SIZE) + entry->big_pkts++; + else + entry->small_pkts++; + return entry->ring; +} + +static void mlx4_bf_copy(unsigned long *dst, unsigned long *src, unsigned bytecnt) +{ + __iowrite64_copy(dst, src, bytecnt / 8); +} + +static int mlx4_en_xmit(struct net_device *dev, int tx_ind, struct mbuf **mbp) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; + struct mlx4_en_tx_ring *ring; + struct mlx4_en_cq *cq; + struct mlx4_en_tx_desc *tx_desc; + struct mlx4_wqe_data_seg *data; + struct mlx4_en_tx_info *tx_info; + struct mbuf *m; + int nr_txbb; + int nr_segs; + int desc_size; + int real_size; + dma_addr_t dma; + u32 index, bf_index; + __be32 op_own; + u16 vlan_tag = 0; + int i; + int lso_header_size; + bool bounce = false; + struct mbuf *mb; + int defrag = 1; + + ring = &priv->tx_ring[tx_ind]; + mb = *mbp; + if (!priv->port_up) + goto tx_drop; + +retry: + real_size = get_real_size(mb, dev, &nr_segs, &lso_header_size); + if (unlikely(!real_size)) + goto tx_drop; + + /* Allign descriptor to TXBB size */ + desc_size = ALIGN(real_size, TXBB_SIZE); + nr_txbb = desc_size / TXBB_SIZE; + if (unlikely(nr_txbb > MAX_DESC_TXBBS)) { + if (defrag) { + mb = m_defrag(*mbp, M_DONTWAIT); + if (mb == NULL) { + mb = *mbp; + goto tx_drop; + } + *mbp = mb; + defrag = 0; + goto retry; + } + goto tx_drop; + } + + /* Check available TXBBs And 2K spare for prefetch */ + if (unlikely(((int)(ring->prod - ring->cons)) > + ring->size - HEADROOM - MAX_DESC_TXBBS)) { + /* every full Tx ring stops queue */ + if (ring->blocked == 0) + atomic_add_int(&priv->blocked, 1); + atomic_set_int(&dev->if_drv_flags, IFF_DRV_OACTIVE); + ring->blocked = 1; + priv->port_stats.queue_stopped++; + + /* Use interrupts to find out when queue opened */ + cq = &priv->tx_cq[tx_ind]; + mlx4_en_arm_cq(priv, cq); + return EBUSY; + } + + /* Track current inflight packets for performance analysis */ + AVG_PERF_COUNTER(priv->pstats.inflight_avg, + (u32) (ring->prod - ring->cons - 1)); + + /* Packet is good - grab an index and transmit it */ + index = ring->prod & ring->size_mask; + bf_index = ring->prod; + + /* See if we have enough space for whole descriptor TXBB for setting + * SW ownership on next descriptor; if not, use a bounce buffer. */ + if (likely(index + nr_txbb <= ring->size)) + tx_desc = ring->buf + index * TXBB_SIZE; + else { + tx_desc = (struct mlx4_en_tx_desc *) ring->bounce_buf; + bounce = true; + } + + /* Prepare ctrl segement apart opcode+ownership, which depends on + * whether LSO is used */ + if (mb->m_flags & M_VLANTAG) + vlan_tag = mb->m_pkthdr.ether_vtag; + tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag); + tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN * !!vlan_tag; + tx_desc->ctrl.fence_size = (real_size / 16) & 0x3f; + tx_desc->ctrl.srcrb_flags = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE | + MLX4_WQE_CTRL_SOLICITED); + if (mb->m_pkthdr.csum_flags & (CSUM_IP|CSUM_TCP|CSUM_UDP)) { + tx_desc->ctrl.srcrb_flags |= cpu_to_be32(MLX4_WQE_CTRL_IP_CSUM | + MLX4_WQE_CTRL_TCP_UDP_CSUM); + priv->port_stats.tx_chksum_offload++; + } + + if (unlikely(priv->validate_loopback)) { + /* Copy dst mac address to wqe */ + struct ether_header *ethh; + u64 mac; + u32 mac_l, mac_h; + + ethh = mtod(mb, struct ether_header *); + mac = mlx4_en_mac_to_u64(ethh->ether_dhost); + if (mac) { + mac_h = (u32) ((mac & 0xffff00000000ULL) >> 16); + mac_l = (u32) (mac & 0xffffffff); + tx_desc->ctrl.srcrb_flags |= cpu_to_be32(mac_h); + tx_desc->ctrl.imm = cpu_to_be32(mac_l); + } + } + + /* Handle LSO (TSO) packets */ + if (lso_header_size) { + int segsz; + + /* Mark opcode as LSO */ + op_own = cpu_to_be32(MLX4_OPCODE_LSO | (1 << 6)) | + ((ring->prod & ring->size) ? + cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0); + + /* Fill in the LSO prefix */ + tx_desc->lso.mss_hdr_size = cpu_to_be32( + mb->m_pkthdr.tso_segsz << 16 | lso_header_size); + + /* Copy headers; + * note that we already verified that it is linear */ + memcpy(tx_desc->lso.header, mb->m_data, lso_header_size); + data = ((void *) &tx_desc->lso + + ALIGN(lso_header_size + 4, DS_SIZE)); + + priv->port_stats.tso_packets++; + segsz = mb->m_pkthdr.tso_segsz; + i = ((mb->m_pkthdr.len - lso_header_size) / segsz) + + !!((mb->m_pkthdr.len - lso_header_size) % segsz); + ring->bytes += mb->m_pkthdr.len + (i - 1) * lso_header_size; + ring->packets += i; + mb->m_data += lso_header_size; + mb->m_len -= lso_header_size; + } else { + /* Normal (Non LSO) packet */ + op_own = cpu_to_be32(MLX4_OPCODE_SEND) | + ((ring->prod & ring->size) ? + cpu_to_be32(MLX4_EN_BIT_DESC_OWN) : 0); + data = &tx_desc->data; + ring->bytes += max(mb->m_pkthdr.len, + (unsigned int)ETHER_MIN_LEN - ETHER_CRC_LEN); + ring->packets++; + + } + AVG_PERF_COUNTER(priv->pstats.tx_pktsz_avg, mb->m_pkthdr.len); + + /* Save mb in tx_info ring */ + tx_info = &ring->tx_info[index]; + tx_info->mb = mb; + tx_info->nr_txbb = nr_txbb; + tx_info->nr_segs = nr_segs; + /* valid only for non inline segments */ + tx_info->data_offset = (void *) data - (void *) tx_desc; + + if (!is_inline(mb)) { + for (i = 0, m = mb; i < nr_segs; i++, m = m->m_next) { + if (m->m_len == 0) { + i--; + continue; + } + dma = pci_map_single(mdev->dev->pdev, m->m_data, + m->m_len, PCI_DMA_TODEVICE); + data->addr = cpu_to_be64(dma); + data->lkey = cpu_to_be32(mdev->mr.key); + wmb(); + data->byte_count = cpu_to_be32(m->m_len); + data++; + } + if (lso_header_size) { + mb->m_data -= lso_header_size; + mb->m_len += lso_header_size; + } + tx_info->inl = 0; + } else { + build_inline_wqe(tx_desc, mb, real_size, &vlan_tag, tx_ind); + tx_info->inl = 1; + } + + ring->prod += nr_txbb; + + /* If we used a bounce buffer then copy descriptor back into place */ + if (bounce) + tx_desc = mlx4_en_bounce_to_desc(priv, ring, index, desc_size); + + if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && !vlan_tag) { + *(u32 *) (&tx_desc->ctrl.vlan_tag) |= ring->doorbell_qpn; + op_own |= htonl((bf_index & 0xffff) << 8); + /* Ensure new descirptor hits memory + * before setting ownership of this descriptor to HW */ + wmb(); + tx_desc->ctrl.owner_opcode = op_own; + + wmb(); + + mlx4_bf_copy(ring->bf.reg + ring->bf.offset, (unsigned long *) &tx_desc->ctrl, + desc_size); + + wmb(); + + ring->bf.offset ^= ring->bf.buf_size; + } else { + /* Ensure new descirptor hits memory + * before setting ownership of this descriptor to HW */ + wmb(); + tx_desc->ctrl.owner_opcode = op_own; + wmb(); + writel(ring->doorbell_qpn, ring->bf.uar->map + MLX4_SEND_DOORBELL); + } + + return 0; + +tx_drop: + *mbp = NULL; + m_freem(mb); + ring->errors++; + return EINVAL; +} + + +static int +mlx4_en_transmit_locked(struct ifnet *dev, int tx_ind, struct mbuf *m) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_tx_ring *ring; + struct mbuf *next; + int enqueued, err = 0; + + ring = &priv->tx_ring[tx_ind]; + if ((dev->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING || priv->port_up == 0) { + if (m != NULL) + err = drbr_enqueue(dev, ring->br, m); + return (err); + } + + enqueued = 0; + if (m == NULL) { + next = drbr_dequeue(dev, ring->br); + } else if (drbr_needs_enqueue(dev, ring->br)) { + if ((err = drbr_enqueue(dev, ring->br, m)) != 0) + return (err); + next = drbr_dequeue(dev, ring->br); + } else + next = m; + + /* Process the queue */ + while (next != NULL) { + if ((err = mlx4_en_xmit(dev, tx_ind, &next)) != 0) { + if (next != NULL) + err = drbr_enqueue(dev, ring->br, next); + break; + } + enqueued++; + drbr_stats_update(dev, next->m_pkthdr.len, next->m_flags); + /* Send a copy of the frame to the BPF listener */ + ETHER_BPF_MTAP(dev, next); + if ((dev->if_drv_flags & IFF_DRV_RUNNING) == 0) + break; + next = drbr_dequeue(dev, ring->br); + } + + if (enqueued > 0) + ring->watchdog_time = ticks; + + return (err); +} + +void +mlx4_en_tx_que(void *context, int pending) +{ + struct mlx4_en_tx_ring *ring; + struct mlx4_en_priv *priv; + struct net_device *dev; + struct mlx4_en_cq *cq; + int tx_ind; + + cq = context; + dev = cq->dev; + priv = dev->if_softc; + tx_ind = cq->ring; + ring = &priv->tx_ring[tx_ind]; + if (dev->if_drv_flags & IFF_DRV_RUNNING) { + mlx4_en_xmit_poll(priv, tx_ind); + spin_lock(&ring->tx_lock); + if (!drbr_empty(dev, ring->br)) + mlx4_en_transmit_locked(dev, tx_ind, NULL); + spin_unlock(&ring->tx_lock); + } +} + +int +mlx4_en_transmit(struct ifnet *dev, struct mbuf *m) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_tx_ring *ring; + struct mlx4_en_cq *cq; + int i = 0, err = 0; + + /* Which queue to use */ + if ((m->m_flags & (M_FLOWID | M_VLANTAG)) == M_FLOWID) + i = m->m_pkthdr.flowid % (MLX4_EN_NUM_HASH_RINGS - 1); + else + i = mlx4_en_select_queue(dev, m); + + ring = &priv->tx_ring[i]; + + if (spin_trylock(&ring->tx_lock)) { + err = mlx4_en_transmit_locked(dev, i, m); + spin_unlock(&ring->tx_lock); + /* Poll CQ here */ + mlx4_en_xmit_poll(priv, i); + } else { + err = drbr_enqueue(dev, ring->br, m); + cq = &priv->tx_cq[i]; + taskqueue_enqueue(cq->tq, &cq->cq_task); + } + + return (err); +} + +/* + * Flush ring buffers. + */ +void +mlx4_en_qflush(struct ifnet *dev) +{ + struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_tx_ring *ring = priv->tx_ring; + struct mbuf *m; + + for (int i = 0; i < priv->tx_ring_num; i++, ring++) { + spin_lock(&ring->tx_lock); + while ((m = buf_ring_dequeue_sc(ring->br)) != NULL) + m_freem(m); + spin_unlock(&ring->tx_lock); + } + if_qflush(dev); +} diff --git a/sys/ofed/drivers/net/mlx4/eq.c b/sys/ofed/drivers/net/mlx4/eq.c new file mode 100644 index 000000000000..42885c76e230 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/eq.c @@ -0,0 +1,727 @@ +/* + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +#include + +#include "mlx4.h" +#include "fw.h" + +enum { + MLX4_NUM_ASYNC_EQE = 0x100, + MLX4_NUM_SPARE_EQE = 0x80, + MLX4_EQ_ENTRY_SIZE = 0x20 +}; + +/* + * Must be packed because start is 64 bits but only aligned to 32 bits. + */ +struct mlx4_eq_context { + __be32 flags; + u16 reserved1[3]; + __be16 page_offset; + u8 log_eq_size; + u8 reserved2[4]; + u8 eq_period; + u8 reserved3; + u8 eq_max_count; + u8 reserved4[3]; + u8 intr; + u8 log_page_size; + u8 reserved5[2]; + u8 mtt_base_addr_h; + __be32 mtt_base_addr_l; + u32 reserved6[2]; + __be32 consumer_index; + __be32 producer_index; + u32 reserved7[4]; +}; + +#define MLX4_EQ_STATUS_OK ( 0 << 28) +#define MLX4_EQ_STATUS_WRITE_FAIL (10 << 28) +#define MLX4_EQ_OWNER_SW ( 0 << 24) +#define MLX4_EQ_OWNER_HW ( 1 << 24) +#define MLX4_EQ_FLAG_EC ( 1 << 18) +#define MLX4_EQ_FLAG_OI ( 1 << 17) +#define MLX4_EQ_STATE_ARMED ( 9 << 8) +#define MLX4_EQ_STATE_FIRED (10 << 8) +#define MLX4_EQ_STATE_ALWAYS_ARMED (11 << 8) + +#define MLX4_ASYNC_EVENT_MASK ((1ull << MLX4_EVENT_TYPE_PATH_MIG) | \ + (1ull << MLX4_EVENT_TYPE_COMM_EST) | \ + (1ull << MLX4_EVENT_TYPE_SQ_DRAINED) | \ + (1ull << MLX4_EVENT_TYPE_CQ_ERROR) | \ + (1ull << MLX4_EVENT_TYPE_WQ_CATAS_ERROR) | \ + (1ull << MLX4_EVENT_TYPE_EEC_CATAS_ERROR) | \ + (1ull << MLX4_EVENT_TYPE_PATH_MIG_FAILED) | \ + (1ull << MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \ + (1ull << MLX4_EVENT_TYPE_WQ_ACCESS_ERROR) | \ + (1ull << MLX4_EVENT_TYPE_PORT_CHANGE) | \ + (1ull << MLX4_EVENT_TYPE_ECC_DETECT) | \ + (1ull << MLX4_EVENT_TYPE_SRQ_CATAS_ERROR) | \ + (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE) | \ + (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT) | \ + (1ull << MLX4_EVENT_TYPE_CMD)) + +struct mlx4_eqe { + u8 reserved1; + u8 type; + u8 reserved2; + u8 subtype; + union { + u32 raw[6]; + struct { + __be32 cqn; + } __attribute__((packed)) comp; + struct { + u16 reserved1; + __be16 token; + u32 reserved2; + u8 reserved3[3]; + u8 status; + __be64 out_param; + } __attribute__((packed)) cmd; + struct { + __be32 qpn; + } __attribute__((packed)) qp; + struct { + __be32 srqn; + } __attribute__((packed)) srq; + struct { + __be32 cqn; + u32 reserved1; + u8 reserved2[3]; + u8 syndrome; + } __attribute__((packed)) cq_err; + struct { + u32 reserved1[2]; + __be32 port; + } __attribute__((packed)) port_change; + } event; + u8 reserved3[3]; + u8 owner; +} __attribute__((packed)); + +static void eq_set_ci(struct mlx4_eq *eq, int req_not) +{ + __raw_writel((__force u32) cpu_to_be32((eq->cons_index & 0xffffff) | + req_not << 31), + eq->doorbell); + /* We still want ordering, just not swabbing, so add a barrier */ + mb(); +} + +static struct mlx4_eqe *get_eqe(struct mlx4_eq *eq, u32 entry) +{ + unsigned long off = (entry & (eq->nent - 1)) * MLX4_EQ_ENTRY_SIZE; + return eq->page_list[off / PAGE_SIZE].buf + off % PAGE_SIZE; +} + +static struct mlx4_eqe *next_eqe_sw(struct mlx4_eq *eq) +{ + struct mlx4_eqe *eqe = get_eqe(eq, eq->cons_index); + return !!(eqe->owner & 0x80) ^ !!(eq->cons_index & eq->nent) ? NULL : eqe; +} + +static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) +{ + struct mlx4_eqe *eqe; + int cqn; + int eqes_found = 0; + int set_ci = 0; + int port; + + while ((eqe = next_eqe_sw(eq))) { + /* + * Make sure we read EQ entry contents after we've + * checked the ownership bit. + */ + rmb(); + + switch (eqe->type) { + case MLX4_EVENT_TYPE_COMP: + cqn = be32_to_cpu(eqe->event.comp.cqn) & 0xffffff; + mlx4_cq_completion(dev, cqn); + break; + + case MLX4_EVENT_TYPE_PATH_MIG: + case MLX4_EVENT_TYPE_COMM_EST: + case MLX4_EVENT_TYPE_SQ_DRAINED: + case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE: + case MLX4_EVENT_TYPE_WQ_CATAS_ERROR: + case MLX4_EVENT_TYPE_PATH_MIG_FAILED: + case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR: + case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR: + mlx4_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, + eqe->type); + break; + + case MLX4_EVENT_TYPE_SRQ_LIMIT: + case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR: + mlx4_srq_event(dev, be32_to_cpu(eqe->event.srq.srqn) & 0xffffff, + eqe->type); + break; + + case MLX4_EVENT_TYPE_CMD: + mlx4_cmd_event(dev, + be16_to_cpu(eqe->event.cmd.token), + eqe->event.cmd.status, + be64_to_cpu(eqe->event.cmd.out_param)); + break; + + case MLX4_EVENT_TYPE_PORT_CHANGE: + port = be32_to_cpu(eqe->event.port_change.port) >> 28; + if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) { + mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_DOWN, + port); + mlx4_priv(dev)->sense.do_sense_port[port] = 1; + } else { + mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_UP, + port); + mlx4_priv(dev)->sense.do_sense_port[port] = 0; + } + break; + + case MLX4_EVENT_TYPE_CQ_ERROR: + mlx4_warn(dev, "CQ %s on CQN %06x\n", + eqe->event.cq_err.syndrome == 1 ? + "overrun" : "access violation", + be32_to_cpu(eqe->event.cq_err.cqn) & 0xffffff); + mlx4_cq_event(dev, be32_to_cpu(eqe->event.cq_err.cqn), + eqe->type); + break; + + case MLX4_EVENT_TYPE_EQ_OVERFLOW: + mlx4_warn(dev, "EQ overrun on EQN %d\n", eq->eqn); + break; + + case MLX4_EVENT_TYPE_EEC_CATAS_ERROR: + case MLX4_EVENT_TYPE_ECC_DETECT: + default: + mlx4_warn(dev, "Unhandled event %02x(%02x) on EQ %d at index %u\n", + eqe->type, eqe->subtype, eq->eqn, eq->cons_index); + break; + }; + + ++eq->cons_index; + eqes_found = 1; + ++set_ci; + + /* + * The HCA will think the queue has overflowed if we + * don't tell it we've been processing events. We + * create our EQs with MLX4_NUM_SPARE_EQE extra + * entries, so we must update our consumer index at + * least that often. + */ + if (unlikely(set_ci >= MLX4_NUM_SPARE_EQE)) { + eq_set_ci(eq, 0); + set_ci = 0; + } + } + + eq_set_ci(eq, 1); + + return eqes_found; +} + +static irqreturn_t mlx4_interrupt(int irq, void *dev_ptr) +{ + struct mlx4_dev *dev = dev_ptr; + struct mlx4_priv *priv = mlx4_priv(dev); + int work = 0; + int i; + + writel(priv->eq_table.clr_mask, priv->eq_table.clr_int); + + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) + work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]); + + return IRQ_RETVAL(work); +} + +static irqreturn_t mlx4_msi_x_interrupt(int irq, void *eq_ptr) +{ + struct mlx4_eq *eq = eq_ptr; + struct mlx4_dev *dev = eq->dev; + + mlx4_eq_int(dev, eq); + + /* MSI-X vectors always belong to us */ + return IRQ_HANDLED; +} + +static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap, + int eq_num) +{ + return mlx4_cmd(dev, event_mask, (unmap << 31) | eq_num, + 0, MLX4_CMD_MAP_EQ, MLX4_CMD_TIME_CLASS_B); +} + +static int mlx4_SW2HW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int eq_num) +{ + return mlx4_cmd(dev, mailbox->dma, eq_num, 0, MLX4_CMD_SW2HW_EQ, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int eq_num) +{ + return mlx4_cmd_box(dev, 0, mailbox->dma, eq_num, 0, MLX4_CMD_HW2SW_EQ, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_num_eq_uar(struct mlx4_dev *dev) +{ + /* + * Each UAR holds 4 EQ doorbells. To figure out how many UARs + * we need to map, take the difference of highest index and + * the lowest index we'll use and add 1. + */ + return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs) / 4 - + dev->caps.reserved_eqs / 4 + 1; +} + +static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int index; + + index = eq->eqn / 4 - dev->caps.reserved_eqs / 4; + + if (!priv->eq_table.uar_map[index]) { + priv->eq_table.uar_map[index] = + ioremap(pci_resource_start(dev->pdev, 2) + + ((eq->eqn / 4) << PAGE_SHIFT), + PAGE_SIZE); + if (!priv->eq_table.uar_map[index]) { + mlx4_err(dev, "Couldn't map EQ doorbell for EQN 0x%06x\n", + eq->eqn); + return NULL; + } + } + + return priv->eq_table.uar_map[index] + 0x800 + 8 * (eq->eqn % 4); +} + +static int mlx4_create_eq(struct mlx4_dev *dev, int nent, + u8 intr, struct mlx4_eq *eq) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_eq_context *eq_context; + int npages; + u64 *dma_list = NULL; + dma_addr_t t; + u64 mtt_addr; + int err = -ENOMEM; + int i; + + eq->dev = dev; + eq->nent = roundup_pow_of_two(max(nent, 2)); + npages = PAGE_ALIGN(eq->nent * MLX4_EQ_ENTRY_SIZE) / PAGE_SIZE; + + eq->page_list = kmalloc(npages * sizeof *eq->page_list, + GFP_KERNEL); + if (!eq->page_list) + goto err_out; + + for (i = 0; i < npages; ++i) + eq->page_list[i].buf = NULL; + + dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL); + if (!dma_list) + goto err_out_free; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + goto err_out_free; + eq_context = mailbox->buf; + + for (i = 0; i < npages; ++i) { + eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev, + PAGE_SIZE, &t, GFP_KERNEL); + if (!eq->page_list[i].buf) + goto err_out_free_pages; + + dma_list[i] = t; + eq->page_list[i].map = t; + + memset(eq->page_list[i].buf, 0, PAGE_SIZE); + } + + eq->eqn = mlx4_bitmap_alloc(&priv->eq_table.bitmap); + if (eq->eqn == -1) + goto err_out_free_pages; + + eq->doorbell = mlx4_get_eq_uar(dev, eq); + if (!eq->doorbell) { + err = -ENOMEM; + goto err_out_free_eq; + } + + err = mlx4_mtt_init(dev, npages, PAGE_SHIFT, &eq->mtt); + if (err) + goto err_out_free_eq; + + err = mlx4_write_mtt(dev, &eq->mtt, 0, npages, dma_list); + if (err) + goto err_out_free_mtt; + + memset(eq_context, 0, sizeof *eq_context); + eq_context->flags = cpu_to_be32(MLX4_EQ_STATUS_OK | + MLX4_EQ_STATE_ARMED); + eq_context->log_eq_size = ilog2(eq->nent); + eq_context->intr = intr; + eq_context->log_page_size = PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT; + + mtt_addr = mlx4_mtt_addr(dev, &eq->mtt); + eq_context->mtt_base_addr_h = mtt_addr >> 32; + eq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); + + err = mlx4_SW2HW_EQ(dev, mailbox, eq->eqn); + if (err) { + mlx4_warn(dev, "SW2HW_EQ failed (%d)\n", err); + goto err_out_free_mtt; + } + + kfree(dma_list); + mlx4_free_cmd_mailbox(dev, mailbox); + + eq->cons_index = 0; + + return err; + +err_out_free_mtt: + mlx4_mtt_cleanup(dev, &eq->mtt); + +err_out_free_eq: + mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn); + +err_out_free_pages: + for (i = 0; i < npages; ++i) + if (eq->page_list[i].buf) + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + eq->page_list[i].buf, + eq->page_list[i].map); + + mlx4_free_cmd_mailbox(dev, mailbox); + +err_out_free: + kfree(eq->page_list); + kfree(dma_list); + +err_out: + return err; +} + +static void mlx4_free_eq(struct mlx4_dev *dev, + struct mlx4_eq *eq) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cmd_mailbox *mailbox; + int err; + int npages = PAGE_ALIGN(MLX4_EQ_ENTRY_SIZE * eq->nent) / PAGE_SIZE; + int i; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return; + + err = mlx4_HW2SW_EQ(dev, mailbox, eq->eqn); + if (err) + mlx4_warn(dev, "HW2SW_EQ failed (%d)\n", err); + + if (0) { + mlx4_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn); + for (i = 0; i < sizeof (struct mlx4_eq_context) / 4; ++i) { + if (i % 4 == 0) + printk("[%02x] ", i * 4); + printk(" %08x", be32_to_cpup(mailbox->buf + i * 4)); + if ((i + 1) % 4 == 0) + printk("\n"); + } + } + + mlx4_mtt_cleanup(dev, &eq->mtt); + for (i = 0; i < npages; ++i) + pci_free_consistent(dev->pdev, PAGE_SIZE, + eq->page_list[i].buf, + eq->page_list[i].map); + + kfree(eq->page_list); + mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn); + mlx4_free_cmd_mailbox(dev, mailbox); +} + +static void mlx4_free_irqs(struct mlx4_dev *dev) +{ + struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table; + int i; + + if (eq_table->have_irq) + free_irq(dev->pdev->irq, dev); + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) + if (eq_table->eq[i].have_irq) { + free_irq(eq_table->eq[i].irq, eq_table->eq + i); + eq_table->eq[i].have_irq = 0; + } + + kfree(eq_table->irq_names); +} + +static int mlx4_map_clr_int(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + priv->clr_base = ioremap(pci_resource_start(dev->pdev, priv->fw.clr_int_bar) + + priv->fw.clr_int_base, MLX4_CLR_INT_SIZE); + if (!priv->clr_base) { + mlx4_err(dev, "Couldn't map interrupt clear register, aborting.\n"); + return -ENOMEM; + } + + return 0; +} + +static void mlx4_unmap_clr_int(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + iounmap(priv->clr_base); +} + +int mlx4_alloc_eq_table(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + priv->eq_table.eq = kcalloc(dev->caps.num_eqs - dev->caps.reserved_eqs, + sizeof *priv->eq_table.eq, GFP_KERNEL); + if (!priv->eq_table.eq) + return -ENOMEM; + + return 0; +} + +void mlx4_free_eq_table(struct mlx4_dev *dev) +{ + kfree(mlx4_priv(dev)->eq_table.eq); +} + +int mlx4_init_eq_table(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + int i; + + priv->eq_table.uar_map = kcalloc(sizeof *priv->eq_table.uar_map, + mlx4_num_eq_uar(dev), GFP_KERNEL); + if (!priv->eq_table.uar_map) { + err = -ENOMEM; + goto err_out_free; + } + + err = mlx4_bitmap_init(&priv->eq_table.bitmap, dev->caps.num_eqs, + dev->caps.num_eqs - 1, dev->caps.reserved_eqs, 0); + if (err) + goto err_out_free; + + for (i = 0; i < mlx4_num_eq_uar(dev); ++i) + priv->eq_table.uar_map[i] = NULL; + + err = mlx4_map_clr_int(dev); + if (err) + goto err_out_bitmap; + + priv->eq_table.clr_mask = + swab32(1 << (priv->eq_table.inta_pin & 31)); + priv->eq_table.clr_int = priv->clr_base + + (priv->eq_table.inta_pin < 32 ? 4 : 0); + + priv->eq_table.irq_names = kmalloc(16 * dev->caps.num_comp_vectors, GFP_KERNEL); + if (!priv->eq_table.irq_names) { + err = -ENOMEM; + goto err_out_bitmap; + } + + for (i = 0; i < dev->caps.num_comp_vectors; ++i) { + err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE, + (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, + &priv->eq_table.eq[i]); + if (err) { + --i; + goto err_out_unmap; + } + } + + err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE, + (dev->flags & MLX4_FLAG_MSI_X) ? dev->caps.num_comp_vectors : 0, + &priv->eq_table.eq[dev->caps.num_comp_vectors]); + if (err) + goto err_out_comp; + + if (dev->flags & MLX4_FLAG_MSI_X) { + static const char async_eq_name[] = DRV_NAME "(async)"; + const char *eq_name; + + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) { + if (i < dev->caps.num_comp_vectors) { + snprintf(priv->eq_table.irq_names + i * 16, 16, + "eth-mlx4-%d", i); + eq_name = priv->eq_table.irq_names + i * 16; + } else + eq_name = async_eq_name; + + err = request_irq(priv->eq_table.eq[i].irq, + mlx4_msi_x_interrupt, 0, eq_name, + priv->eq_table.eq + i); + if (err) + goto err_out_async; + + priv->eq_table.eq[i].have_irq = 1; + } + } else { + err = request_irq(dev->pdev->irq, mlx4_interrupt, + IRQF_SHARED, DRV_NAME, dev); + if (err) + goto err_out_async; + + priv->eq_table.have_irq = 1; + } + + err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0, + priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); + if (err) + mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n", + priv->eq_table.eq[dev->caps.num_comp_vectors].eqn, err); + + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) + eq_set_ci(&priv->eq_table.eq[i], 1); + + return 0; + +err_out_async: + mlx4_free_eq(dev, &priv->eq_table.eq[dev->caps.num_comp_vectors]); + +err_out_comp: + i = dev->caps.num_comp_vectors - 1; + +err_out_unmap: + while (i >= 0) { + mlx4_free_eq(dev, &priv->eq_table.eq[i]); + --i; + } + mlx4_unmap_clr_int(dev); + mlx4_free_irqs(dev); + +err_out_bitmap: + mlx4_bitmap_cleanup(&priv->eq_table.bitmap); + +err_out_free: + kfree(priv->eq_table.uar_map); + + return err; +} + +void mlx4_cleanup_eq_table(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int i; + + mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1, + priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); + + mlx4_free_irqs(dev); + + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) + mlx4_free_eq(dev, &priv->eq_table.eq[i]); + + mlx4_unmap_clr_int(dev); + + for (i = 0; i < mlx4_num_eq_uar(dev); ++i) + if (priv->eq_table.uar_map[i]) + iounmap(priv->eq_table.uar_map[i]); + + mlx4_bitmap_cleanup(&priv->eq_table.bitmap); + + kfree(priv->eq_table.uar_map); +} + +/* A test that verifies that we can accept interrupts on all + * the irq vectors of the device. + * Interrupts are checked using the NOP command. + */ +int mlx4_test_interrupts(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int i; + int err; + + err = mlx4_NOP(dev); + /* When not in MSI_X, there is only one irq to check */ + if (!(dev->flags & MLX4_FLAG_MSI_X)) + return err; + + /* A loop over all completion vectors, for each vector we will check + * whether it works by mapping command completions to that vector + * and performing a NOP command + */ + for(i = 0; !err && (i < dev->caps.num_comp_vectors); ++i) { + /* Temporary use polling for command completions */ + mlx4_cmd_use_polling(dev); + + /* Map the new eq to handle all asyncronous events */ + err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0, + priv->eq_table.eq[i].eqn); + if (err) { + mlx4_warn(dev, "Failed mapping eq for interrupt test\n"); + mlx4_cmd_use_events(dev); + break; + } + + /* Go back to using events */ + mlx4_cmd_use_events(dev); + err = mlx4_NOP(dev); + } + + /* Return to default */ + mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0, + priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); + return err; +} +EXPORT_SYMBOL(mlx4_test_interrupts); diff --git a/sys/ofed/drivers/net/mlx4/fw.c b/sys/ofed/drivers/net/mlx4/fw.c new file mode 100644 index 000000000000..774d26122e64 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/fw.c @@ -0,0 +1,1010 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "fw.h" +#include "icm.h" + +enum { + MLX4_COMMAND_INTERFACE_MIN_REV = 2, + MLX4_COMMAND_INTERFACE_MAX_REV = 3, + MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS = 3, +}; + +extern void __buggy_use_of_MLX4_GET(void); +extern void __buggy_use_of_MLX4_PUT(void); + +static int enable_qos; +module_param(enable_qos, bool, 0444); +MODULE_PARM_DESC(enable_qos, "Enable Quality of Service support in the HCA (default: off)"); + +static int mlx4_pre_t11_mode = 0; +module_param_named(enable_pre_t11_mode, mlx4_pre_t11_mode, int, 0644); +MODULE_PARM_DESC(enable_pre_t11_mode, "For FCoXX, enable pre-t11 mode if non-zero (default: 0)"); + +#define MLX4_GET(dest, source, offset) \ + do { \ + void *__p = (char *) (source) + (offset); \ + switch (sizeof (dest)) { \ + case 1: (dest) = *(u8 *) __p; break; \ + case 2: (dest) = be16_to_cpup(__p); break; \ + case 4: (dest) = be32_to_cpup(__p); break; \ + case 8: (dest) = be64_to_cpup(__p); break; \ + default: __buggy_use_of_MLX4_GET(); \ + } \ + } while (0) + +#define MLX4_PUT(dest, source, offset) \ + do { \ + void *__d = ((char *) (dest) + (offset)); \ + switch (sizeof(source)) { \ + case 1: *(u8 *) __d = (source); break; \ + case 2: *(__be16 *) __d = cpu_to_be16(source); break; \ + case 4: *(__be32 *) __d = cpu_to_be32(source); break; \ + case 8: *(__be64 *) __d = cpu_to_be64(source); break; \ + default: __buggy_use_of_MLX4_PUT(); \ + } \ + } while (0) + +static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags) +{ + static const char *fname[] = { + [ 0] = "RC transport", + [ 1] = "UC transport", + [ 2] = "UD transport", + [ 3] = "XRC transport", + [ 4] = "reliable multicast", + [ 5] = "FCoIB support", + [ 6] = "SRQ support", + [ 7] = "IPoIB checksum offload", + [ 8] = "P_Key violation counter", + [ 9] = "Q_Key violation counter", + [10] = "VMM", + [12] = "DPDP", + [16] = "MW support", + [17] = "APM support", + [18] = "Atomic ops support", + [19] = "Raw multicast support", + [20] = "Address vector port checking support", + [21] = "UD multicast support", + [24] = "Demand paging support", + [25] = "Router support", + [30] = "IBoE support", + [48] = "Basic counters support", + [49] = "Extended counters support", + }; + int i; + + mlx4_dbg(dev, "DEV_CAP flags:\n"); + for (i = 0; i < ARRAY_SIZE(fname); ++i) + if (fname[i] && (flags & (1LL << i))) + mlx4_dbg(dev, " %s\n", fname[i]); +} + +int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg) +{ + struct mlx4_cmd_mailbox *mailbox; + u32 *inbox; + int err = 0; + +#define MOD_STAT_CFG_IN_SIZE 0x100 + +#define MOD_STAT_CFG_PG_SZ_M_OFFSET 0x002 +#define MOD_STAT_CFG_PG_SZ_OFFSET 0x003 + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + memset(inbox, 0, MOD_STAT_CFG_IN_SIZE); + + MLX4_PUT(inbox, cfg->log_pg_sz, MOD_STAT_CFG_PG_SZ_OFFSET); + MLX4_PUT(inbox, cfg->log_pg_sz_m, MOD_STAT_CFG_PG_SZ_M_OFFSET); + + err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_MOD_STAT_CFG, + MLX4_CMD_TIME_CLASS_A); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) +{ + struct mlx4_cmd_mailbox *mailbox; + u32 *outbox; + u8 field; + u32 field32; + u16 size; + u16 stat_rate; + int err; + int i; + u32 in_modifier; + u64 out_param; + u32 tmp1, tmp2; + +#define QUERY_DEV_CAP_OUT_SIZE 0x100 +#define QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET 0x10 +#define QUERY_DEV_CAP_MAX_QP_SZ_OFFSET 0x11 +#define QUERY_DEV_CAP_RSVD_QP_OFFSET 0x12 +#define QUERY_DEV_CAP_MAX_QP_OFFSET 0x13 +#define QUERY_DEV_CAP_RSVD_SRQ_OFFSET 0x14 +#define QUERY_DEV_CAP_MAX_SRQ_OFFSET 0x15 +#define QUERY_DEV_CAP_RSVD_EEC_OFFSET 0x16 +#define QUERY_DEV_CAP_MAX_EEC_OFFSET 0x17 +#define QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET 0x19 +#define QUERY_DEV_CAP_RSVD_CQ_OFFSET 0x1a +#define QUERY_DEV_CAP_MAX_CQ_OFFSET 0x1b +#define QUERY_DEV_CAP_MAX_MPT_OFFSET 0x1d +#define QUERY_DEV_CAP_RSVD_EQ_OFFSET 0x1e +#define QUERY_DEV_CAP_MAX_EQ_OFFSET 0x1f +#define QUERY_DEV_CAP_RSVD_MTT_OFFSET 0x20 +#define QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET 0x21 +#define QUERY_DEV_CAP_RSVD_MRW_OFFSET 0x22 +#define QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET 0x23 +#define QUERY_DEV_CAP_MAX_AV_OFFSET 0x27 +#define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET 0x29 +#define QUERY_DEV_CAP_MAX_RES_QP_OFFSET 0x2b +#define QUERY_DEV_CAP_MAX_GSO_OFFSET 0x2d +#define QUERY_DEV_CAP_MAX_RDMA_OFFSET 0x2f +#define QUERY_DEV_CAP_STAT_CFG_INL_OFFSET 0x31 +#define QUERY_DEV_CAP_RSZ_SRQ_OFFSET 0x33 +#define QUERY_DEV_CAP_ACK_DELAY_OFFSET 0x35 +#define QUERY_DEV_CAP_MTU_WIDTH_OFFSET 0x36 +#define QUERY_DEV_CAP_VL_PORT_OFFSET 0x37 +#define QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET 0x38 +#define QUERY_DEV_CAP_MAX_GID_OFFSET 0x3b +#define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET 0x3c +#define QUERY_DEV_CAP_MAX_PKEY_OFFSET 0x3f +#define QUERY_DEV_CAP_EXT_FLAGS_OFFSET 0x40 +#define QUERY_DEV_CAP_UDP_RSS_OFFSET 0x42 +#define QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET 0x43 +#define QUERY_DEV_CAP_FLAGS_OFFSET 0x44 +#define QUERY_DEV_CAP_RSVD_UAR_OFFSET 0x48 +#define QUERY_DEV_CAP_UAR_SZ_OFFSET 0x49 +#define QUERY_DEV_CAP_PAGE_SZ_OFFSET 0x4b +#define QUERY_DEV_CAP_BF_OFFSET 0x4c +#define QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET 0x4d +#define QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET 0x4e +#define QUERY_DEV_CAP_LOG_MAX_BF_PAGES_OFFSET 0x4f +#define QUERY_DEV_CAP_MAX_SG_SQ_OFFSET 0x51 +#define QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET 0x52 +#define QUERY_DEV_CAP_MAX_SG_RQ_OFFSET 0x55 +#define QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET 0x56 +#define QUERY_DEV_CAP_MAX_QP_MCG_OFFSET 0x61 +#define QUERY_DEV_CAP_RSVD_MCG_OFFSET 0x62 +#define QUERY_DEV_CAP_MAX_MCG_OFFSET 0x63 +#define QUERY_DEV_CAP_RSVD_PD_OFFSET 0x64 +#define QUERY_DEV_CAP_MAX_PD_OFFSET 0x65 +#define QUERY_DEV_CAP_RSVD_XRC_OFFSET 0x66 +#define QUERY_DEV_CAP_MAX_XRC_OFFSET 0x67 +#define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET 0x80 +#define QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET 0x82 +#define QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET 0x84 +#define QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET 0x86 +#define QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET 0x88 +#define QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET 0x8a +#define QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET 0x8c +#define QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET 0x8e +#define QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET 0x90 +#define QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET 0x92 +#define QUERY_DEV_CAP_BMME_FLAGS_OFFSET 0x94 +#define QUERY_DEV_CAP_RSVD_LKEY_OFFSET 0x98 +#define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET 0xa0 +#define QUERY_DEV_CAP_MAX_BASIC_CNT_OFFSET 0x68 +#define QUERY_DEV_CAP_MAX_EXT_CNT_OFFSET 0x6c + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP, + MLX4_CMD_TIME_CLASS_A); + if (err) + goto out; + + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_QP_OFFSET); + dev_cap->reserved_qps = 1 << (field & 0xf); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_OFFSET); + dev_cap->max_qps = 1 << (field & 0x1f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_SRQ_OFFSET); + dev_cap->reserved_srqs = 1 << (field >> 4); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_OFFSET); + dev_cap->max_srqs = 1 << (field & 0x1f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_SZ_OFFSET); + dev_cap->max_cq_sz = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_CQ_OFFSET); + dev_cap->reserved_cqs = 1 << (field & 0xf); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_CQ_OFFSET); + dev_cap->max_cqs = 1 << (field & 0x1f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MPT_OFFSET); + dev_cap->max_mpts = 1 << (field & 0x3f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET); + dev_cap->reserved_eqs = 1 << (field & 0xf); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET); + dev_cap->max_eqs = 1 << (field & 0xf); + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET); + dev_cap->reserved_mtts = 1 << (field >> 4); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET); + dev_cap->max_mrw_sz = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MRW_OFFSET); + dev_cap->reserved_mrws = 1 << (field & 0xf); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MTT_SEG_OFFSET); + dev_cap->max_mtt_seg = 1 << (field & 0x3f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_REQ_QP_OFFSET); + dev_cap->max_requester_per_qp = 1 << (field & 0x3f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RES_QP_OFFSET); + dev_cap->max_responder_per_qp = 1 << (field & 0x3f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GSO_OFFSET); + field &= 0x1f; + if (!field) + dev_cap->max_gso_sz = 0; + else + dev_cap->max_gso_sz = 1 << field; + + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RDMA_OFFSET); + dev_cap->max_rdma_global = 1 << (field & 0x3f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET); + dev_cap->local_ca_ack_delay = field & 0x1f; + MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET); + dev_cap->num_ports = field & 0xf; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET); + dev_cap->max_msg_sz = 1 << (field & 0x1f); + MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET); + dev_cap->stat_rate_support = stat_rate; + MLX4_GET(field, outbox, QUERY_DEV_CAP_UDP_RSS_OFFSET); + dev_cap->udp_rss = field & 0x1; + MLX4_GET(field, outbox, QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET); + dev_cap->loopback_support = field & 0x1; + MLX4_GET(tmp1, outbox, QUERY_DEV_CAP_EXT_FLAGS_OFFSET); + MLX4_GET(tmp2, outbox, QUERY_DEV_CAP_FLAGS_OFFSET); + dev_cap->flags = tmp2 | (u64)tmp1 << 32; + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET); + dev_cap->reserved_uars = field >> 4; + MLX4_GET(field, outbox, QUERY_DEV_CAP_UAR_SZ_OFFSET); + dev_cap->uar_size = 1 << ((field & 0x3f) + 20); + MLX4_GET(field, outbox, QUERY_DEV_CAP_PAGE_SZ_OFFSET); + dev_cap->min_page_sz = 1 << field; + + MLX4_GET(field, outbox, QUERY_DEV_CAP_BF_OFFSET); + if (field & 0x80) { + MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_BF_REG_SZ_OFFSET); + dev_cap->bf_reg_size = 1 << (field & 0x1f); + MLX4_GET(field, outbox, QUERY_DEV_CAP_LOG_MAX_BF_REGS_PER_PAGE_OFFSET); + if ((1 << (field & 0x3f)) > (PAGE_SIZE / dev_cap->bf_reg_size)) { + mlx4_dbg(dev, "log blue flame is invalid (%d), forcing 3\n", field & 0x1f); + field = 3; + } + dev_cap->bf_regs_per_page = 1 << (field & 0x3f); + mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n", + dev_cap->bf_reg_size, dev_cap->bf_regs_per_page); + } else { + dev_cap->bf_reg_size = 0; + mlx4_dbg(dev, "BlueFlame not available\n"); + } + + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_SQ_OFFSET); + dev_cap->max_sq_sg = field; + MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_SQ_OFFSET); + dev_cap->max_sq_desc_sz = size; + + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_MCG_OFFSET); + dev_cap->max_qp_per_mcg = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MCG_OFFSET); + dev_cap->reserved_mgms = field & 0xf; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MCG_OFFSET); + dev_cap->max_mcgs = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_PD_OFFSET); + dev_cap->reserved_pds = field >> 4; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PD_OFFSET); + dev_cap->max_pds = 1 << (field & 0x3f); + + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_XRC_OFFSET); + dev_cap->reserved_xrcds = field >> 4; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_XRC_OFFSET); + dev_cap->max_xrcds = 1 << (field & 0x1f); + + MLX4_GET(size, outbox, QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET); + dev_cap->rdmarc_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_QPC_ENTRY_SZ_OFFSET); + dev_cap->qpc_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_AUX_ENTRY_SZ_OFFSET); + dev_cap->aux_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_ALTC_ENTRY_SZ_OFFSET); + dev_cap->altc_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_EQC_ENTRY_SZ_OFFSET); + dev_cap->eqc_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_CQC_ENTRY_SZ_OFFSET); + dev_cap->cqc_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_SRQ_ENTRY_SZ_OFFSET); + dev_cap->srq_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_C_MPT_ENTRY_SZ_OFFSET); + dev_cap->cmpt_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_MTT_ENTRY_SZ_OFFSET); + dev_cap->mtt_entry_sz = size; + MLX4_GET(size, outbox, QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET); + dev_cap->dmpt_entry_sz = size; + + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SRQ_SZ_OFFSET); + dev_cap->max_srq_sz = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_QP_SZ_OFFSET); + dev_cap->max_qp_sz = 1 << field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_STAT_CFG_INL_OFFSET); + dev_cap->inline_cfg = field & 1; + MLX4_GET(field, outbox, QUERY_DEV_CAP_RSZ_SRQ_OFFSET); + dev_cap->resize_srq = field & 1; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_RQ_OFFSET); + dev_cap->max_rq_sg = field; + MLX4_GET(size, outbox, QUERY_DEV_CAP_MAX_DESC_SZ_RQ_OFFSET); + dev_cap->max_rq_desc_sz = size; + + MLX4_GET(dev_cap->bmme_flags, outbox, + QUERY_DEV_CAP_BMME_FLAGS_OFFSET); + MLX4_GET(dev_cap->reserved_lkey, outbox, + QUERY_DEV_CAP_RSVD_LKEY_OFFSET); + MLX4_GET(dev_cap->max_icm_sz, outbox, + QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET); + MLX4_GET(dev_cap->max_basic_counters, outbox, + QUERY_DEV_CAP_MAX_BASIC_CNT_OFFSET); + MLX4_GET(dev_cap->max_ext_counters, outbox, + QUERY_DEV_CAP_MAX_EXT_CNT_OFFSET); + + if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { + for (i = 1; i <= dev_cap->num_ports; ++i) { + MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET); + dev_cap->max_vl[i] = field >> 4; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET); + dev_cap->ib_mtu[i] = field >> 4; + dev_cap->max_port_width[i] = field & 0xf; + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_GID_OFFSET); + dev_cap->max_gids[i] = 1 << (field & 0xf); + MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_PKEY_OFFSET); + dev_cap->max_pkeys[i] = 1 << (field & 0xf); + } + } else { +#define QUERY_PORT_SUPPORTED_TYPE_OFFSET 0x00 +#define QUERY_PORT_MTU_OFFSET 0x01 +#define QUERY_PORT_ETH_MTU_OFFSET 0x02 +#define QUERY_PORT_WIDTH_OFFSET 0x06 +#define QUERY_PORT_MAX_GID_PKEY_OFFSET 0x07 +#define QUERY_PORT_MAX_MACVLAN_OFFSET 0x0a +#define QUERY_PORT_MAX_VL_OFFSET 0x0b +#define QUERY_PORT_MAC_OFFSET 0x10 +#define QUERY_PORT_TRANS_VENDOR_OFFSET 0x18 +#define QUERY_PORT_WAVELENGTH_OFFSET 0x1c +#define QUERY_PORT_TRANS_CODE_OFFSET 0x20 + +#define STAT_CFG_PORT_MODE (1 << 28) +#define STAT_CFG_PORT_OFFSET 0x8 +#define STAT_CFG_PORT_MASK (1 << 20) +#define STAT_CFG_MOD_INLINE 0x3 + + for (i = 1; i <= dev_cap->num_ports; ++i) { + err = mlx4_cmd_box(dev, 0, mailbox->dma, i, 0, MLX4_CMD_QUERY_PORT, + MLX4_CMD_TIME_CLASS_B); + if (err) + goto out; + + MLX4_GET(field, outbox, QUERY_PORT_SUPPORTED_TYPE_OFFSET); + dev_cap->supported_port_types[i] = field & 3; + MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET); + dev_cap->ib_mtu[i] = field & 0xf; + MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET); + dev_cap->max_port_width[i] = field & 0xf; + MLX4_GET(field, outbox, QUERY_PORT_MAX_GID_PKEY_OFFSET); + dev_cap->max_gids[i] = 1 << (field >> 4); + dev_cap->max_pkeys[i] = 1 << (field & 0xf); + MLX4_GET(field, outbox, QUERY_PORT_MAX_VL_OFFSET); + dev_cap->max_vl[i] = field & 0xf; + MLX4_GET(field, outbox, QUERY_PORT_MAX_MACVLAN_OFFSET); + dev_cap->log_max_macs[i] = field & 0xf; + dev_cap->log_max_vlans[i] = field >> 4; + MLX4_GET(dev_cap->eth_mtu[i], outbox, QUERY_PORT_ETH_MTU_OFFSET); + MLX4_GET(dev_cap->def_mac[i], outbox, QUERY_PORT_MAC_OFFSET); + MLX4_GET(field32, outbox, QUERY_PORT_TRANS_VENDOR_OFFSET); + dev_cap->trans_type[i] = field32 >> 24; + dev_cap->vendor_oui[i] = field32 & 0xffffff; + MLX4_GET(dev_cap->wavelength[i], outbox, QUERY_PORT_WAVELENGTH_OFFSET); + MLX4_GET(dev_cap->trans_code[i], outbox, QUERY_PORT_TRANS_CODE_OFFSET); + + /* Query stat cfg for port enablement */ + if (dev_cap->inline_cfg) { + in_modifier = STAT_CFG_PORT_MODE | i << 8 | + STAT_CFG_PORT_OFFSET; + err = mlx4_cmd_imm(dev, 0, &out_param, + in_modifier, + STAT_CFG_MOD_INLINE, + MLX4_CMD_MOD_STAT_CFG, + MLX4_CMD_TIME_CLASS_B); + if (!err) + if (!(out_param & STAT_CFG_PORT_MASK)) + dev_cap->supported_port_types[i] = 0; + } + } + } + + mlx4_dbg(dev, "Base MM extensions: flags %08x, rsvd L_Key %08x\n", + dev_cap->bmme_flags, dev_cap->reserved_lkey); + + /* + * Each UAR has 4 EQ doorbells; so if a UAR is reserved, then + * we can't use any EQs whose doorbell falls on that page, + * even if the EQ itself isn't reserved. + */ + dev_cap->reserved_eqs = max(dev_cap->reserved_uars * 4, + dev_cap->reserved_eqs); + + mlx4_dbg(dev, "Max ICM size %lld MB\n", + (unsigned long long) dev_cap->max_icm_sz >> 20); + mlx4_dbg(dev, "Max QPs: %d, reserved QPs: %d, entry size: %d\n", + dev_cap->max_qps, dev_cap->reserved_qps, dev_cap->qpc_entry_sz); + mlx4_dbg(dev, "Max SRQs: %d, reserved SRQs: %d, entry size: %d\n", + dev_cap->max_srqs, dev_cap->reserved_srqs, dev_cap->srq_entry_sz); + mlx4_dbg(dev, "Max CQs: %d, reserved CQs: %d, entry size: %d\n", + dev_cap->max_cqs, dev_cap->reserved_cqs, dev_cap->cqc_entry_sz); + mlx4_dbg(dev, "Max EQs: %d, reserved EQs: %d, entry size: %d\n", + dev_cap->max_eqs, dev_cap->reserved_eqs, dev_cap->eqc_entry_sz); + mlx4_dbg(dev, "reserved MPTs: %d, reserved MTTs: %d\n", + dev_cap->reserved_mrws, dev_cap->reserved_mtts); + mlx4_dbg(dev, "Max PDs: %d, reserved PDs: %d, reserved UARs: %d\n", + dev_cap->max_pds, dev_cap->reserved_pds, dev_cap->reserved_uars); + mlx4_dbg(dev, "Max QP/MCG: %d, reserved MGMs: %d\n", + dev_cap->max_pds, dev_cap->reserved_mgms); + mlx4_dbg(dev, "Max CQEs: %d, max WQEs: %d, max SRQ WQEs: %d\n", + dev_cap->max_cq_sz, dev_cap->max_qp_sz, dev_cap->max_srq_sz); + mlx4_dbg(dev, "Local CA ACK delay: %d, max MTU: %d, port width cap: %d\n", + dev_cap->local_ca_ack_delay, 128 << dev_cap->ib_mtu[1], + dev_cap->max_port_width[1]); + mlx4_dbg(dev, "Max SQ desc size: %d, max SQ S/G: %d\n", + dev_cap->max_sq_desc_sz, dev_cap->max_sq_sg); + mlx4_dbg(dev, "Max RQ desc size: %d, max RQ S/G: %d\n", + dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg); + mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz); + + dump_dev_cap_flags(dev, dev_cap->flags); + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_icm_iter iter; + __be64 *pages; + int lg; + int nent = 0; + int i; + int err = 0; + int ts = 0, tc = 0; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE); + pages = mailbox->buf; + + for (mlx4_icm_first(icm, &iter); + !mlx4_icm_last(&iter); + mlx4_icm_next(&iter)) { + /* + * We have to pass pages that are aligned to their + * size, so find the least significant 1 in the + * address or size and use that as our log2 size. + */ + lg = ffs(mlx4_icm_addr(&iter) | mlx4_icm_size(&iter)) - 1; + if (lg < MLX4_ICM_PAGE_SHIFT) { + mlx4_warn(dev, "Got FW area not aligned to %d (%llx/%lx).\n", + MLX4_ICM_PAGE_SIZE, + (unsigned long long) mlx4_icm_addr(&iter), + mlx4_icm_size(&iter)); + err = -EINVAL; + goto out; + } + + for (i = 0; i < mlx4_icm_size(&iter) >> lg; ++i) { + if (virt != -1) { + pages[nent * 2] = cpu_to_be64(virt); + virt += 1 << lg; + } + + pages[nent * 2 + 1] = + cpu_to_be64((mlx4_icm_addr(&iter) + (i << lg)) | + (lg - MLX4_ICM_PAGE_SHIFT)); + ts += 1 << (lg - 10); + ++tc; + + if (++nent == MLX4_MAILBOX_SIZE / 16) { + err = mlx4_cmd(dev, mailbox->dma, nent, 0, op, + MLX4_CMD_TIME_CLASS_B); + if (err) + goto out; + nent = 0; + } + } + } + + if (nent) + err = mlx4_cmd(dev, mailbox->dma, nent, 0, op, MLX4_CMD_TIME_CLASS_B); + if (err) + goto out; + + switch (op) { + case MLX4_CMD_MAP_FA: + mlx4_dbg(dev, "Mapped %d chunks/%d KB for FW.\n", tc, ts); + break; + case MLX4_CMD_MAP_ICM_AUX: + mlx4_dbg(dev, "Mapped %d chunks/%d KB for ICM aux.\n", tc, ts); + break; + case MLX4_CMD_MAP_ICM: + mlx4_dbg(dev, "Mapped %d chunks/%d KB at %llx for ICM.\n", + tc, ts, (unsigned long long) virt - (ts << 10)); + break; + } + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm) +{ + return mlx4_map_cmd(dev, MLX4_CMD_MAP_FA, icm, -1); +} + +int mlx4_UNMAP_FA(struct mlx4_dev *dev) +{ + return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_UNMAP_FA, MLX4_CMD_TIME_CLASS_B); +} + + +int mlx4_RUN_FW(struct mlx4_dev *dev) +{ + return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_RUN_FW, MLX4_CMD_TIME_CLASS_A); +} + +int mlx4_QUERY_FW(struct mlx4_dev *dev) +{ + struct mlx4_fw *fw = &mlx4_priv(dev)->fw; + struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; + struct mlx4_cmd_mailbox *mailbox; + u32 *outbox; + int err = 0; + u64 fw_ver; + u16 cmd_if_rev; + u8 lg; + +#define QUERY_FW_OUT_SIZE 0x100 +#define QUERY_FW_VER_OFFSET 0x00 +#define MC_PROMISC_VER 0x2000702bcull +#define QUERY_FW_CMD_IF_REV_OFFSET 0x0a +#define QUERY_FW_MAX_CMD_OFFSET 0x0f +#define QUERY_FW_ERR_START_OFFSET 0x30 +#define QUERY_FW_ERR_SIZE_OFFSET 0x38 +#define QUERY_FW_ERR_BAR_OFFSET 0x3c + +#define QUERY_FW_SIZE_OFFSET 0x00 +#define QUERY_FW_CLR_INT_BASE_OFFSET 0x20 +#define QUERY_FW_CLR_INT_BAR_OFFSET 0x28 + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_FW, + MLX4_CMD_TIME_CLASS_A); + if (err) + goto out; + + MLX4_GET(fw_ver, outbox, QUERY_FW_VER_OFFSET); + /* + * FW subminor version is at more significant bits than minor + * version, so swap here. + */ + dev->caps.fw_ver = (fw_ver & 0xffff00000000ull) | + ((fw_ver & 0xffff0000ull) >> 16) | + ((fw_ver & 0x0000ffffull) << 16); + if (dev->caps.fw_ver < MC_PROMISC_VER) + dev->caps.mc_promisc_mode = 2; + else + dev->caps.mc_promisc_mode = 1; + + MLX4_GET(cmd_if_rev, outbox, QUERY_FW_CMD_IF_REV_OFFSET); + if (cmd_if_rev < MLX4_COMMAND_INTERFACE_MIN_REV || + cmd_if_rev > MLX4_COMMAND_INTERFACE_MAX_REV) { + mlx4_err(dev, "Installed FW has unsupported " + "command interface revision %d.\n", + cmd_if_rev); + mlx4_err(dev, "(Installed FW version is %d.%d.%03d)\n", + (int) (dev->caps.fw_ver >> 32), + (int) (dev->caps.fw_ver >> 16) & 0xffff, + (int) dev->caps.fw_ver & 0xffff); + mlx4_err(dev, "This driver version supports only revisions %d to %d.\n", + MLX4_COMMAND_INTERFACE_MIN_REV, MLX4_COMMAND_INTERFACE_MAX_REV); + err = -ENODEV; + goto out; + } + + if (cmd_if_rev < MLX4_COMMAND_INTERFACE_NEW_PORT_CMDS) + dev->flags |= MLX4_FLAG_OLD_PORT_CMDS; + + MLX4_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET); + cmd->max_cmds = 1 << lg; + + mlx4_dbg(dev, "FW version %d.%d.%03d (cmd intf rev %d), max commands %d\n", + (int) (dev->caps.fw_ver >> 32), + (int) (dev->caps.fw_ver >> 16) & 0xffff, + (int) dev->caps.fw_ver & 0xffff, + cmd_if_rev, cmd->max_cmds); + + MLX4_GET(fw->catas_offset, outbox, QUERY_FW_ERR_START_OFFSET); + MLX4_GET(fw->catas_size, outbox, QUERY_FW_ERR_SIZE_OFFSET); + MLX4_GET(fw->catas_bar, outbox, QUERY_FW_ERR_BAR_OFFSET); + fw->catas_bar = (fw->catas_bar >> 6) * 2; + + mlx4_dbg(dev, "Catastrophic error buffer at 0x%llx, size 0x%x, BAR %d\n", + (unsigned long long) fw->catas_offset, fw->catas_size, fw->catas_bar); + + MLX4_GET(fw->fw_pages, outbox, QUERY_FW_SIZE_OFFSET); + MLX4_GET(fw->clr_int_base, outbox, QUERY_FW_CLR_INT_BASE_OFFSET); + MLX4_GET(fw->clr_int_bar, outbox, QUERY_FW_CLR_INT_BAR_OFFSET); + fw->clr_int_bar = (fw->clr_int_bar >> 6) * 2; + + mlx4_dbg(dev, "FW size %d KB\n", fw->fw_pages >> 2); + + /* + * Round up number of system pages needed in case + * MLX4_ICM_PAGE_SIZE < PAGE_SIZE. + */ + fw->fw_pages = + ALIGN(fw->fw_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >> + (PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT); + + mlx4_dbg(dev, "Clear int @ %llx, BAR %d\n", + (unsigned long long) fw->clr_int_base, fw->clr_int_bar); + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +static void get_board_id(void *vsd, char *board_id) +{ + int i; + +#define VSD_OFFSET_SIG1 0x00 +#define VSD_OFFSET_SIG2 0xde +#define VSD_OFFSET_MLX_BOARD_ID 0xd0 +#define VSD_OFFSET_TS_BOARD_ID 0x20 + +#define VSD_SIGNATURE_TOPSPIN 0x5ad + + memset(board_id, 0, MLX4_BOARD_ID_LEN); + + if (be16_to_cpup(vsd + VSD_OFFSET_SIG1) == VSD_SIGNATURE_TOPSPIN && + be16_to_cpup(vsd + VSD_OFFSET_SIG2) == VSD_SIGNATURE_TOPSPIN) { + strlcpy(board_id, vsd + VSD_OFFSET_TS_BOARD_ID, MLX4_BOARD_ID_LEN); + } else { + /* + * The board ID is a string but the firmware byte + * swaps each 4-byte word before passing it back to + * us. Therefore we need to swab it before printing. + */ + for (i = 0; i < 4; ++i) + ((u32 *) board_id)[i] = + swab32(*(u32 *) (vsd + VSD_OFFSET_MLX_BOARD_ID + i * 4)); + } +} + +int mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter) +{ + struct mlx4_cmd_mailbox *mailbox; + u32 *outbox; + int err; + +#define QUERY_ADAPTER_OUT_SIZE 0x100 +#define QUERY_ADAPTER_INTA_PIN_OFFSET 0x10 +#define QUERY_ADAPTER_VSD_OFFSET 0x20 + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0, MLX4_CMD_QUERY_ADAPTER, + MLX4_CMD_TIME_CLASS_A); + if (err) + goto out; + + MLX4_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET); + + get_board_id(outbox + QUERY_ADAPTER_VSD_OFFSET / 4, + adapter->board_id); + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) +{ + struct mlx4_cmd_mailbox *mailbox; + __be32 *inbox; + int err; + +#define INIT_HCA_IN_SIZE 0x200 +#define INIT_HCA_VERSION_OFFSET 0x000 +#define INIT_HCA_VERSION 2 +#define INIT_HCA_CACHELINE_SZ_OFFSET 0x0e +#define INIT_HCA_X86_64_BYTE_CACHELINE_SZ 0x40 +#define INIT_HCA_FLAGS_OFFSET 0x014 +#define INIT_HCA_QPC_OFFSET 0x020 +#define INIT_HCA_QPC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x10) +#define INIT_HCA_LOG_QP_OFFSET (INIT_HCA_QPC_OFFSET + 0x17) +#define INIT_HCA_SRQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x28) +#define INIT_HCA_LOG_SRQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x2f) +#define INIT_HCA_CQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x30) +#define INIT_HCA_LOG_CQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x37) +#define INIT_HCA_ALTC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x40) +#define INIT_HCA_AUXC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x50) +#define INIT_HCA_EQC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x60) +#define INIT_HCA_LOG_EQ_OFFSET (INIT_HCA_QPC_OFFSET + 0x67) +#define INIT_HCA_RDMARC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x70) +#define INIT_HCA_LOG_RD_OFFSET (INIT_HCA_QPC_OFFSET + 0x77) +#define INIT_HCA_MCAST_OFFSET 0x0c0 +#define INIT_HCA_MC_BASE_OFFSET (INIT_HCA_MCAST_OFFSET + 0x00) +#define INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12) +#define INIT_HCA_LOG_MC_HASH_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x16) +#define INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b) +#define INIT_HCA_TPT_OFFSET 0x0f0 +#define INIT_HCA_DMPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x00) +#define INIT_HCA_LOG_MPT_SZ_OFFSET (INIT_HCA_TPT_OFFSET + 0x0b) +#define INIT_HCA_MTT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x10) +#define INIT_HCA_CMPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x18) +#define INIT_HCA_UAR_OFFSET 0x120 +#define INIT_HCA_LOG_UAR_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x0a) +#define INIT_HCA_UAR_PAGE_SZ_OFFSET (INIT_HCA_UAR_OFFSET + 0x0b) + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + memset(inbox, 0, INIT_HCA_IN_SIZE); + + *((u8 *) mailbox->buf + INIT_HCA_VERSION_OFFSET) = INIT_HCA_VERSION; +#if defined(__x86_64__) || defined(__PPC64__) + *((u8 *) mailbox->buf + INIT_HCA_CACHELINE_SZ_OFFSET) = INIT_HCA_X86_64_BYTE_CACHELINE_SZ; +#endif + +#if defined(__LITTLE_ENDIAN) + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) &= ~cpu_to_be32(1 << 1); +#elif defined(__BIG_ENDIAN) + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 1); +#else +#error Host endianness not defined +#endif + /* Check port for UD address vector: */ + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1); + + /* Enable IPoIB checksumming if we can: */ + if (dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM) + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 3); + + /* Enable QoS support if module parameter set */ + if (enable_qos) + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 2); + + /* counters mode */ + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= + cpu_to_be32(dev->caps.counters_mode << 4); + + /* QPC/EEC/CQC/EQC/RDMARC attributes */ + + MLX4_PUT(inbox, param->qpc_base, INIT_HCA_QPC_BASE_OFFSET); + MLX4_PUT(inbox, param->log_num_qps, INIT_HCA_LOG_QP_OFFSET); + MLX4_PUT(inbox, param->srqc_base, INIT_HCA_SRQC_BASE_OFFSET); + MLX4_PUT(inbox, param->log_num_srqs, INIT_HCA_LOG_SRQ_OFFSET); + MLX4_PUT(inbox, param->cqc_base, INIT_HCA_CQC_BASE_OFFSET); + MLX4_PUT(inbox, param->log_num_cqs, INIT_HCA_LOG_CQ_OFFSET); + MLX4_PUT(inbox, param->altc_base, INIT_HCA_ALTC_BASE_OFFSET); + MLX4_PUT(inbox, param->auxc_base, INIT_HCA_AUXC_BASE_OFFSET); + MLX4_PUT(inbox, param->eqc_base, INIT_HCA_EQC_BASE_OFFSET); + MLX4_PUT(inbox, param->log_num_eqs, INIT_HCA_LOG_EQ_OFFSET); + MLX4_PUT(inbox, param->rdmarc_base, INIT_HCA_RDMARC_BASE_OFFSET); + MLX4_PUT(inbox, param->log_rd_per_qp, INIT_HCA_LOG_RD_OFFSET); + + /* multicast attributes */ + + MLX4_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET); + MLX4_PUT(inbox, param->log_mc_entry_sz, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); + MLX4_PUT(inbox, param->log_mc_hash_sz, INIT_HCA_LOG_MC_HASH_SZ_OFFSET); + MLX4_PUT(inbox, param->log_mc_table_sz, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); + + /* TPT attributes */ + + MLX4_PUT(inbox, param->dmpt_base, INIT_HCA_DMPT_BASE_OFFSET); + MLX4_PUT(inbox, param->log_mpt_sz, INIT_HCA_LOG_MPT_SZ_OFFSET); + MLX4_PUT(inbox, param->mtt_base, INIT_HCA_MTT_BASE_OFFSET); + MLX4_PUT(inbox, param->cmpt_base, INIT_HCA_CMPT_BASE_OFFSET); + + /* UAR attributes */ + + MLX4_PUT(inbox, (u8) (PAGE_SHIFT - 12), INIT_HCA_UAR_PAGE_SZ_OFFSET); + MLX4_PUT(inbox, param->log_uar_sz, INIT_HCA_LOG_UAR_SZ_OFFSET); + if (!mlx4_pre_t11_mode && dev->caps.flags & (u32) MLX4_DEV_CAP_FLAG_FC_T11) + *(inbox + INIT_HCA_FLAGS_OFFSET / 4) |= cpu_to_be32(1 << 10); + + + err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 10000); + + if (err) + mlx4_err(dev, "INIT_HCA returns %d\n", err); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int mlx4_INIT_PORT(struct mlx4_dev *dev, int port) +{ + struct mlx4_cmd_mailbox *mailbox; + u32 *inbox; + int err; + u32 flags; + u16 field; + + if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) { +#define INIT_PORT_IN_SIZE 256 +#define INIT_PORT_FLAGS_OFFSET 0x00 +#define INIT_PORT_FLAG_SIG (1 << 18) +#define INIT_PORT_FLAG_NG (1 << 17) +#define INIT_PORT_FLAG_G0 (1 << 16) +#define INIT_PORT_VL_SHIFT 4 +#define INIT_PORT_PORT_WIDTH_SHIFT 8 +#define INIT_PORT_MTU_OFFSET 0x04 +#define INIT_PORT_MAX_GID_OFFSET 0x06 +#define INIT_PORT_MAX_PKEY_OFFSET 0x0a +#define INIT_PORT_GUID0_OFFSET 0x10 +#define INIT_PORT_NODE_GUID_OFFSET 0x18 +#define INIT_PORT_SI_GUID_OFFSET 0x20 + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + memset(inbox, 0, INIT_PORT_IN_SIZE); + + flags = 0; + flags |= (dev->caps.vl_cap[port] & 0xf) << INIT_PORT_VL_SHIFT; + flags |= (dev->caps.port_width_cap[port] & 0xf) << INIT_PORT_PORT_WIDTH_SHIFT; + MLX4_PUT(inbox, flags, INIT_PORT_FLAGS_OFFSET); + + field = 128 << dev->caps.ib_mtu_cap[port]; + MLX4_PUT(inbox, field, INIT_PORT_MTU_OFFSET); + field = dev->caps.gid_table_len[port]; + MLX4_PUT(inbox, field, INIT_PORT_MAX_GID_OFFSET); + field = dev->caps.pkey_table_len[port]; + MLX4_PUT(inbox, field, INIT_PORT_MAX_PKEY_OFFSET); + + err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_INIT_PORT, + MLX4_CMD_TIME_CLASS_A); + + mlx4_free_cmd_mailbox(dev, mailbox); + } else + err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT, + MLX4_CMD_TIME_CLASS_A); + + return err; +} +EXPORT_SYMBOL_GPL(mlx4_INIT_PORT); + +int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port) +{ + return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, 1000); +} +EXPORT_SYMBOL_GPL(mlx4_CLOSE_PORT); + +int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic) +{ + return mlx4_cmd(dev, 0, 0, panic, MLX4_CMD_CLOSE_HCA, 1000); +} + +int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages) +{ + int ret = mlx4_cmd_imm(dev, icm_size, aux_pages, 0, 0, + MLX4_CMD_SET_ICM_SIZE, + MLX4_CMD_TIME_CLASS_A); + if (ret) + return ret; + + /* + * Round up number of system pages needed in case + * MLX4_ICM_PAGE_SIZE < PAGE_SIZE. + */ + *aux_pages = ALIGN(*aux_pages, PAGE_SIZE / MLX4_ICM_PAGE_SIZE) >> + (PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT); + + return 0; +} + +int mlx4_NOP(struct mlx4_dev *dev) +{ + /* Input modifier of 0x1f means "finish as soon as possible." */ + return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100); +} + +int mlx4_query_diag_counters(struct mlx4_dev *dev, int array_length, + u8 op_modifier, u32 in_offset[], u32 counter_out[]) +{ + struct mlx4_cmd_mailbox *mailbox; + u32 *outbox; + int ret; + int i; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + ret = mlx4_cmd_box(dev, 0, mailbox->dma, 0, op_modifier, + MLX4_CMD_DIAG_RPRT, MLX4_CMD_TIME_CLASS_A); + if (ret) + goto out; + + for (i=0; i < array_length; i++) { + if (in_offset[i] > MLX4_MAILBOX_SIZE) { + ret = -EINVAL; + goto out; + } + + MLX4_GET(counter_out[i], outbox, in_offset[i]); + } + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + return ret; +} +EXPORT_SYMBOL_GPL(mlx4_query_diag_counters); + +void mlx4_get_fc_t11_settings(struct mlx4_dev *dev, int *enable_pre_t11, int *t11_supported) +{ + *enable_pre_t11 = !!mlx4_pre_t11_mode; + *t11_supported = !!(dev->caps.flags & MLX4_DEV_CAP_FLAG_FC_T11); +} +EXPORT_SYMBOL_GPL(mlx4_get_fc_t11_settings); diff --git a/sys/ofed/drivers/net/mlx4/fw.h b/sys/ofed/drivers/net/mlx4/fw.h new file mode 100644 index 000000000000..fbdd95e26c3f --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/fw.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_FW_H +#define MLX4_FW_H + +#include "mlx4.h" +#include "icm.h" + +struct mlx4_mod_stat_cfg { + u8 log_pg_sz; + u8 log_pg_sz_m; +}; + +struct mlx4_dev_cap { + int max_srq_sz; + int max_qp_sz; + int reserved_qps; + int max_qps; + int reserved_srqs; + int max_srqs; + int max_cq_sz; + int reserved_cqs; + int max_cqs; + int max_mpts; + int reserved_eqs; + int max_eqs; + int reserved_mtts; + int max_mrw_sz; + int reserved_mrws; + int max_mtt_seg; + int max_requester_per_qp; + int max_responder_per_qp; + int max_rdma_global; + int local_ca_ack_delay; + int num_ports; + u32 max_msg_sz; + int ib_mtu[MLX4_MAX_PORTS + 1]; + int max_port_width[MLX4_MAX_PORTS + 1]; + int max_vl[MLX4_MAX_PORTS + 1]; + int max_gids[MLX4_MAX_PORTS + 1]; + int max_pkeys[MLX4_MAX_PORTS + 1]; + u64 def_mac[MLX4_MAX_PORTS + 1]; + u16 eth_mtu[MLX4_MAX_PORTS + 1]; + int trans_type[MLX4_MAX_PORTS + 1]; + int vendor_oui[MLX4_MAX_PORTS + 1]; + u16 wavelength[MLX4_MAX_PORTS + 1]; + u64 trans_code[MLX4_MAX_PORTS + 1]; + u16 stat_rate_support; + int udp_rss; + int loopback_support; + u64 flags; + int reserved_uars; + int uar_size; + int min_page_sz; + int bf_reg_size; + int bf_regs_per_page; + int max_sq_sg; + int max_sq_desc_sz; + int max_rq_sg; + int max_rq_desc_sz; + int max_qp_per_mcg; + int reserved_mgms; + int max_mcgs; + int reserved_pds; + int max_pds; + int reserved_xrcds; + int max_xrcds; + int qpc_entry_sz; + int rdmarc_entry_sz; + int altc_entry_sz; + int aux_entry_sz; + int srq_entry_sz; + int cqc_entry_sz; + int eqc_entry_sz; + int dmpt_entry_sz; + int cmpt_entry_sz; + int mtt_entry_sz; + int inline_cfg; + int resize_srq; + u32 bmme_flags; + u32 reserved_lkey; + u64 max_icm_sz; + int max_gso_sz; + u8 supported_port_types[MLX4_MAX_PORTS + 1]; + u8 log_max_macs[MLX4_MAX_PORTS + 1]; + u8 log_max_vlans[MLX4_MAX_PORTS + 1]; + u32 max_basic_counters; + u32 max_ext_counters; +}; + +struct mlx4_adapter { + char board_id[MLX4_BOARD_ID_LEN]; + u8 inta_pin; +}; + +struct mlx4_init_hca_param { + u64 qpc_base; + u64 rdmarc_base; + u64 auxc_base; + u64 altc_base; + u64 srqc_base; + u64 cqc_base; + u64 eqc_base; + u64 mc_base; + u64 dmpt_base; + u64 cmpt_base; + u64 mtt_base; + u16 log_mc_entry_sz; + u16 log_mc_hash_sz; + u8 log_num_qps; + u8 log_num_srqs; + u8 log_num_cqs; + u8 log_num_eqs; + u8 log_rd_per_qp; + u8 log_mc_table_sz; + u8 log_mpt_sz; + u8 log_uar_sz; +}; + +struct mlx4_init_ib_param { + int port_width; + int vl_cap; + int mtu_cap; + u16 gid_cap; + u16 pkey_cap; + int set_guid0; + u64 guid0; + int set_node_guid; + u64 node_guid; + int set_si_guid; + u64 si_guid; +}; + +struct mlx4_set_ib_param { + int set_si_guid; + int reset_qkey_viol; + u64 si_guid; + u32 cap_mask; +}; + +int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap); +int mlx4_MAP_FA(struct mlx4_dev *dev, struct mlx4_icm *icm); +int mlx4_UNMAP_FA(struct mlx4_dev *dev); +int mlx4_RUN_FW(struct mlx4_dev *dev); +int mlx4_QUERY_FW(struct mlx4_dev *dev); +int mlx4_QUERY_ADAPTER(struct mlx4_dev *dev, struct mlx4_adapter *adapter); +int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param); +int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic); +int mlx4_map_cmd(struct mlx4_dev *dev, u16 op, struct mlx4_icm *icm, u64 virt); +int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages); +int mlx4_NOP(struct mlx4_dev *dev); +int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg); + +#endif /* MLX4_FW_H */ diff --git a/sys/ofed/drivers/net/mlx4/icm.c b/sys/ofed/drivers/net/mlx4/icm.c new file mode 100644 index 000000000000..3a14d6b6b1b7 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/icm.c @@ -0,0 +1,455 @@ +/* + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +#include + +#include "mlx4.h" +#include "icm.h" +#include "fw.h" + +/* + * We allocate in as big chunks as we can, up to a maximum of 256 KB + * per chunk. + */ +enum { + MLX4_ICM_ALLOC_SIZE = 1 << 18, + MLX4_TABLE_CHUNK_SIZE = 1 << 18 +}; + +static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk) +{ + int i; + + if (chunk->nsg > 0) + pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages, + PCI_DMA_BIDIRECTIONAL); + + for (i = 0; i < chunk->npages; ++i) + __free_pages(sg_page(&chunk->mem[i]), + get_order(chunk->mem[i].length)); +} + +static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk) +{ + int i; + + for (i = 0; i < chunk->npages; ++i) + dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length, + lowmem_page_address(sg_page(&chunk->mem[i])), + sg_dma_address(&chunk->mem[i])); +} + +void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent) +{ + struct mlx4_icm_chunk *chunk, *tmp; + + if (!icm) + return; + + list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) { + if (coherent) + mlx4_free_icm_coherent(dev, chunk); + else + mlx4_free_icm_pages(dev, chunk); + + kfree(chunk); + } + + kfree(icm); +} + +static int mlx4_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask) +{ + struct page *page; + + page = alloc_pages(gfp_mask, order); + if (!page) + return -ENOMEM; + + sg_set_page(mem, page, PAGE_SIZE << order, 0); + return 0; +} + +static int mlx4_alloc_icm_coherent(struct device *dev, struct scatterlist *mem, + int order, gfp_t gfp_mask) +{ + void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order, + &sg_dma_address(mem), gfp_mask); + if (!buf) + return -ENOMEM; + + sg_set_buf(mem, buf, PAGE_SIZE << order); + BUG_ON(mem->offset); + sg_dma_len(mem) = PAGE_SIZE << order; + return 0; +} + +struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, + gfp_t gfp_mask, int coherent) +{ + struct mlx4_icm *icm; + struct mlx4_icm_chunk *chunk = NULL; + int cur_order; + int ret; + + /* We use sg_set_buf for coherent allocs, which assumes low memory */ + BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM)); + + icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); + if (!icm) + return NULL; + + icm->refcount = 0; + INIT_LIST_HEAD(&icm->chunk_list); + + cur_order = get_order(MLX4_ICM_ALLOC_SIZE); + + while (npages > 0) { + if (!chunk) { + chunk = kmalloc(sizeof *chunk, + gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); + if (!chunk) + goto fail; + + sg_init_table(chunk->mem, MLX4_ICM_CHUNK_LEN); + chunk->npages = 0; + chunk->nsg = 0; + list_add_tail(&chunk->list, &icm->chunk_list); + } + + while (1 << cur_order > npages) + --cur_order; + + if (coherent) + ret = mlx4_alloc_icm_coherent(&dev->pdev->dev, + &chunk->mem[chunk->npages], + cur_order, gfp_mask); + else + ret = mlx4_alloc_icm_pages(&chunk->mem[chunk->npages], + cur_order, gfp_mask); + + if (!ret) { + ++chunk->npages; + + if (coherent) + ++chunk->nsg; + else if (chunk->npages == MLX4_ICM_CHUNK_LEN) { + chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, + chunk->npages, + PCI_DMA_BIDIRECTIONAL); + + if (chunk->nsg <= 0) + goto fail; + } + + if (chunk->npages == MLX4_ICM_CHUNK_LEN) + chunk = NULL; + + npages -= 1 << cur_order; + } else { + --cur_order; + if (cur_order < 0) + goto fail; + } + } + + if (!coherent && chunk) { + chunk->nsg = pci_map_sg(dev->pdev, chunk->mem, + chunk->npages, + PCI_DMA_BIDIRECTIONAL); + + if (chunk->nsg <= 0) + goto fail; + } + + return icm; + +fail: + mlx4_free_icm(dev, icm, coherent); + return NULL; +} + +static int mlx4_MAP_ICM(struct mlx4_dev *dev, struct mlx4_icm *icm, u64 virt) +{ + return mlx4_map_cmd(dev, MLX4_CMD_MAP_ICM, icm, virt); +} + +int mlx4_UNMAP_ICM(struct mlx4_dev *dev, u64 virt, u32 page_count) +{ + return mlx4_cmd(dev, virt, page_count, 0, MLX4_CMD_UNMAP_ICM, + MLX4_CMD_TIME_CLASS_B); +} + +int mlx4_MAP_ICM_page(struct mlx4_dev *dev, u64 dma_addr, u64 virt) +{ + struct mlx4_cmd_mailbox *mailbox; + __be64 *inbox; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + inbox = mailbox->buf; + + inbox[0] = cpu_to_be64(virt); + inbox[1] = cpu_to_be64(dma_addr); + + err = mlx4_cmd(dev, mailbox->dma, 1, 0, MLX4_CMD_MAP_ICM, + MLX4_CMD_TIME_CLASS_B); + + mlx4_free_cmd_mailbox(dev, mailbox); + + if (!err) + mlx4_dbg(dev, "Mapped page at %llx to %llx for ICM.\n", + (unsigned long long) dma_addr, (unsigned long long) virt); + + return err; +} + +int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm) +{ + return mlx4_map_cmd(dev, MLX4_CMD_MAP_ICM_AUX, icm, -1); +} + +int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev) +{ + return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_UNMAP_ICM_AUX, MLX4_CMD_TIME_CLASS_B); +} + +int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) +{ + int i = (obj & (table->num_obj - 1)) / (MLX4_TABLE_CHUNK_SIZE / table->obj_size); + int ret = 0; + + mutex_lock(&table->mutex); + + if (table->icm[i]) { + ++table->icm[i]->refcount; + goto out; + } + + table->icm[i] = mlx4_alloc_icm(dev, MLX4_TABLE_CHUNK_SIZE >> PAGE_SHIFT, + (table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) | + __GFP_NOWARN, table->coherent); + if (!table->icm[i]) { + ret = -ENOMEM; + goto out; + } + + if (mlx4_MAP_ICM(dev, table->icm[i], table->virt + + (u64) i * MLX4_TABLE_CHUNK_SIZE)) { + mlx4_free_icm(dev, table->icm[i], table->coherent); + table->icm[i] = NULL; + ret = -ENOMEM; + goto out; + } + + ++table->icm[i]->refcount; + +out: + mutex_unlock(&table->mutex); + return ret; +} + +void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj) +{ + int i; + + i = (obj & (table->num_obj - 1)) / (MLX4_TABLE_CHUNK_SIZE / table->obj_size); + + mutex_lock(&table->mutex); + + if (--table->icm[i]->refcount == 0) { + mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE, + MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); + mlx4_free_icm(dev, table->icm[i], table->coherent); + table->icm[i] = NULL; + } + + mutex_unlock(&table->mutex); +} + +void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle) +{ + int idx, offset, dma_offset, i; + struct mlx4_icm_chunk *chunk; + struct mlx4_icm *icm; + struct page *page = NULL; + + if (!table->lowmem) + return NULL; + + mutex_lock(&table->mutex); + + idx = (obj & (table->num_obj - 1)) * table->obj_size; + icm = table->icm[idx / MLX4_TABLE_CHUNK_SIZE]; + dma_offset = offset = idx % MLX4_TABLE_CHUNK_SIZE; + + if (!icm) + goto out; + + list_for_each_entry(chunk, &icm->chunk_list, list) { + for (i = 0; i < chunk->npages; ++i) { + if (dma_handle && dma_offset >= 0) { + if (sg_dma_len(&chunk->mem[i]) > dma_offset) + *dma_handle = sg_dma_address(&chunk->mem[i]) + + dma_offset; + dma_offset -= sg_dma_len(&chunk->mem[i]); + } + /* + * DMA mapping can merge pages but not split them, + * so if we found the page, dma_handle has already + * been assigned to. + */ + if (chunk->mem[i].length > offset) { + page = sg_page(&chunk->mem[i]); + goto out; + } + offset -= chunk->mem[i].length; + } + } + +out: + mutex_unlock(&table->mutex); + return page ? lowmem_page_address(page) + offset : NULL; +} + +int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, + int start, int end) +{ + int inc = MLX4_TABLE_CHUNK_SIZE / table->obj_size; + int i, err; + + for (i = start; i <= end; i += inc) { + err = mlx4_table_get(dev, table, i); + if (err) + goto fail; + } + + return 0; + +fail: + while (i > start) { + i -= inc; + mlx4_table_put(dev, table, i); + } + + return err; +} + +void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, + int start, int end) +{ + int i; + + for (i = start; i <= end; i += MLX4_TABLE_CHUNK_SIZE / table->obj_size) + mlx4_table_put(dev, table, i); +} + +int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, + u64 virt, int obj_size, int nobj, int reserved, + int use_lowmem, int use_coherent) +{ + int obj_per_chunk; + int num_icm; + unsigned chunk_size; + int i; + + obj_per_chunk = MLX4_TABLE_CHUNK_SIZE / obj_size; + num_icm = (nobj + obj_per_chunk - 1) / obj_per_chunk; + + table->icm = kcalloc(num_icm, sizeof *table->icm, GFP_KERNEL); + if (!table->icm) + return -ENOMEM; + table->virt = virt; + table->num_icm = num_icm; + table->num_obj = nobj; + table->obj_size = obj_size; + table->lowmem = use_lowmem; + table->coherent = use_coherent; + mutex_init(&table->mutex); + + for (i = 0; i * MLX4_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) { + chunk_size = MLX4_TABLE_CHUNK_SIZE; + if ((i + 1) * MLX4_TABLE_CHUNK_SIZE > nobj * obj_size) + chunk_size = PAGE_ALIGN(nobj * obj_size - i * MLX4_TABLE_CHUNK_SIZE); + + table->icm[i] = mlx4_alloc_icm(dev, chunk_size >> PAGE_SHIFT, + (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) | + __GFP_NOWARN, use_coherent); + if (!table->icm[i]) + goto err; + if (mlx4_MAP_ICM(dev, table->icm[i], virt + i * MLX4_TABLE_CHUNK_SIZE)) { + mlx4_free_icm(dev, table->icm[i], use_coherent); + table->icm[i] = NULL; + goto err; + } + + /* + * Add a reference to this ICM chunk so that it never + * gets freed (since it contains reserved firmware objects). + */ + ++table->icm[i]->refcount; + } + + return 0; + +err: + for (i = 0; i < num_icm; ++i) + if (table->icm[i]) { + mlx4_UNMAP_ICM(dev, virt + i * MLX4_TABLE_CHUNK_SIZE, + MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); + mlx4_free_icm(dev, table->icm[i], use_coherent); + } + + return -ENOMEM; +} + +void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table) +{ + int i; + + for (i = 0; i < table->num_icm; ++i) + if (table->icm[i]) { + mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE, + MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE); + mlx4_free_icm(dev, table->icm[i], table->coherent); + } + + kfree(table->icm); +} diff --git a/sys/ofed/drivers/net/mlx4/icm.h b/sys/ofed/drivers/net/mlx4/icm.h new file mode 100644 index 000000000000..b87f7261c567 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/icm.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_ICM_H +#define MLX4_ICM_H + +#include +#include +#include + +#define MLX4_ICM_CHUNK_LEN \ + ((256 - sizeof (struct list_head) - 2 * sizeof (int)) / \ + (sizeof (struct scatterlist))) + +enum { + MLX4_ICM_PAGE_SHIFT = 12, + MLX4_ICM_PAGE_SIZE = 1 << MLX4_ICM_PAGE_SHIFT, +}; + +struct mlx4_icm_chunk { + struct list_head list; + int npages; + int nsg; + struct scatterlist mem[MLX4_ICM_CHUNK_LEN]; +}; + +struct mlx4_icm { + struct list_head chunk_list; + int refcount; +}; + +struct mlx4_icm_iter { + struct mlx4_icm *icm; + struct mlx4_icm_chunk *chunk; + int page_idx; +}; + +struct mlx4_dev; + +struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, + gfp_t gfp_mask, int coherent); +void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent); + +int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table, + u64 virt, int obj_size, int nobj, int reserved, + int use_lowmem, int use_coherent); +void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table); +int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); +void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj); +void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle); +int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, + int start, int end); +void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table, + int start, int end); + +static inline void mlx4_icm_first(struct mlx4_icm *icm, + struct mlx4_icm_iter *iter) +{ + iter->icm = icm; + iter->chunk = list_empty(&icm->chunk_list) ? + NULL : list_entry(icm->chunk_list.next, + struct mlx4_icm_chunk, list); + iter->page_idx = 0; +} + +static inline int mlx4_icm_last(struct mlx4_icm_iter *iter) +{ + return !iter->chunk; +} + +static inline void mlx4_icm_next(struct mlx4_icm_iter *iter) +{ + if (++iter->page_idx >= iter->chunk->nsg) { + if (iter->chunk->list.next == &iter->icm->chunk_list) { + iter->chunk = NULL; + return; + } + + iter->chunk = list_entry(iter->chunk->list.next, + struct mlx4_icm_chunk, list); + iter->page_idx = 0; + } +} + +static inline dma_addr_t mlx4_icm_addr(struct mlx4_icm_iter *iter) +{ + return sg_dma_address(&iter->chunk->mem[iter->page_idx]); +} + +static inline unsigned long mlx4_icm_size(struct mlx4_icm_iter *iter) +{ + return sg_dma_len(&iter->chunk->mem[iter->page_idx]); +} + +int mlx4_UNMAP_ICM(struct mlx4_dev *dev, u64 virt, u32 page_count); +int mlx4_MAP_ICM_page(struct mlx4_dev *dev, u64 dma_addr, u64 virt); +int mlx4_MAP_ICM_AUX(struct mlx4_dev *dev, struct mlx4_icm *icm); +int mlx4_UNMAP_ICM_AUX(struct mlx4_dev *dev); + +#endif /* MLX4_ICM_H */ diff --git a/sys/ofed/drivers/net/mlx4/intf.c b/sys/ofed/drivers/net/mlx4/intf.c new file mode 100644 index 000000000000..bdf7e7d02a11 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/intf.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "mlx4.h" + +struct mlx4_device_context { + struct list_head list; + struct mlx4_interface *intf; + void *context; +}; + +static LIST_HEAD(intf_list); +static LIST_HEAD(dev_list); +static DEFINE_MUTEX(intf_mutex); + +static void mlx4_add_device(struct mlx4_interface *intf, struct mlx4_priv *priv) +{ + struct mlx4_device_context *dev_ctx; + + dev_ctx = kmalloc(sizeof *dev_ctx, GFP_KERNEL); + if (!dev_ctx) + return; + + dev_ctx->intf = intf; + dev_ctx->context = intf->add(&priv->dev); + + if (dev_ctx->context) { + spin_lock_irq(&priv->ctx_lock); + list_add_tail(&dev_ctx->list, &priv->ctx_list); + spin_unlock_irq(&priv->ctx_lock); + } else + kfree(dev_ctx); +} + +static void mlx4_remove_device(struct mlx4_interface *intf, struct mlx4_priv *priv) +{ + struct mlx4_device_context *dev_ctx; + + list_for_each_entry(dev_ctx, &priv->ctx_list, list) + if (dev_ctx->intf == intf) { + spin_lock_irq(&priv->ctx_lock); + list_del(&dev_ctx->list); + spin_unlock_irq(&priv->ctx_lock); + + intf->remove(&priv->dev, dev_ctx->context); + kfree(dev_ctx); + return; + } +} + +int mlx4_register_interface(struct mlx4_interface *intf) +{ + struct mlx4_priv *priv; + + if (!intf->add || !intf->remove) + return -EINVAL; + + mutex_lock(&intf_mutex); + + list_add_tail(&intf->list, &intf_list); + list_for_each_entry(priv, &dev_list, dev_list) + mlx4_add_device(intf, priv); + + mutex_unlock(&intf_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_register_interface); + +void mlx4_unregister_interface(struct mlx4_interface *intf) +{ + struct mlx4_priv *priv; + + mutex_lock(&intf_mutex); + + list_for_each_entry(priv, &dev_list, dev_list) + mlx4_remove_device(intf, priv); + + list_del(&intf->list); + + mutex_unlock(&intf_mutex); +} +EXPORT_SYMBOL_GPL(mlx4_unregister_interface); + +struct mlx4_dev *mlx4_query_interface(void *int_dev, int *port) +{ + struct mlx4_priv *priv; + struct mlx4_device_context *dev_ctx; + enum mlx4_query_reply r; + unsigned long flags; + + mutex_lock(&intf_mutex); + + list_for_each_entry(priv, &dev_list, dev_list) { + spin_lock_irqsave(&priv->ctx_lock, flags); + list_for_each_entry(dev_ctx, &priv->ctx_list, list) { + if (!dev_ctx->intf->query) + continue; + r = dev_ctx->intf->query(dev_ctx->context, int_dev); + if (r != MLX4_QUERY_NOT_MINE) { + *port = r; + spin_unlock_irqrestore(&priv->ctx_lock, flags); + mutex_unlock(&intf_mutex); + return &priv->dev; + } + } + spin_unlock_irqrestore(&priv->ctx_lock, flags); + } + + mutex_unlock(&intf_mutex); + return NULL; +} +EXPORT_SYMBOL_GPL(mlx4_query_interface); + +void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type, int port) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_device_context *dev_ctx; + unsigned long flags; + + spin_lock_irqsave(&priv->ctx_lock, flags); + + list_for_each_entry(dev_ctx, &priv->ctx_list, list) + if (dev_ctx->intf->event) + dev_ctx->intf->event(dev, dev_ctx->context, type, port); + + spin_unlock_irqrestore(&priv->ctx_lock, flags); +} + +int mlx4_register_device(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_interface *intf; + + mutex_lock(&intf_mutex); + + list_add_tail(&priv->dev_list, &dev_list); + list_for_each_entry(intf, &intf_list, list) + mlx4_add_device(intf, priv); + + mutex_unlock(&intf_mutex); + mlx4_start_catas_poll(dev); + + return 0; +} + +void mlx4_unregister_device(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_interface *intf; + + mlx4_stop_catas_poll(dev); + mutex_lock(&intf_mutex); + + list_for_each_entry(intf, &intf_list, list) + mlx4_remove_device(intf, priv); + + list_del(&priv->dev_list); + + mutex_unlock(&intf_mutex); +} + +void *mlx4_find_get_prot_dev(struct mlx4_dev *dev, enum mlx4_prot proto, int port) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_device_context *dev_ctx; + unsigned long flags; + void *result = NULL; + + spin_lock_irqsave(&priv->ctx_lock, flags); + + list_for_each_entry(dev_ctx, &priv->ctx_list, list) + if (dev_ctx->intf->protocol == proto && dev_ctx->intf->get_prot_dev) { + result = dev_ctx->intf->get_prot_dev(dev, dev_ctx->context, port); + break; + } + + spin_unlock_irqrestore(&priv->ctx_lock, flags); + + return result; +} + diff --git a/sys/ofed/drivers/net/mlx4/main.c b/sys/ofed/drivers/net/mlx4/main.c new file mode 100644 index 000000000000..44aec4637ca8 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/main.c @@ -0,0 +1,1704 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mlx4.h" +#include "fw.h" +#include "icm.h" + +MODULE_AUTHOR("Roland Dreier"); +MODULE_DESCRIPTION("Mellanox ConnectX HCA low-level driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRV_VERSION); + +struct workqueue_struct *mlx4_wq; + +#ifdef CONFIG_MLX4_DEBUG + +int mlx4_debug_level = 0; +module_param_named(debug_level, mlx4_debug_level, int, 0644); +MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); + +#endif /* CONFIG_MLX4_DEBUG */ + +int mlx4_blck_lb=1; +module_param_named(block_loopback, mlx4_blck_lb, int, 0644); +MODULE_PARM_DESC(block_loopback, "Block multicast loopback packets if > 0"); + +#ifdef CONFIG_PCI_MSI + +static int msi_x = 1; +module_param(msi_x, int, 0444); +MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero"); + +#else /* CONFIG_PCI_MSI */ + +#define msi_x (0) + +#endif /* CONFIG_PCI_MSI */ + +static char mlx4_version[] __devinitdata = + DRV_NAME ": Mellanox ConnectX core driver v" + DRV_VERSION " (" DRV_RELDATE ")\n"; + +struct mutex drv_mutex; + +static struct mlx4_profile default_profile = { + .num_qp = 1 << 18, + .num_srq = 1 << 16, + .rdmarc_per_qp = 1 << 4, + .num_cq = 1 << 16, + .num_mcg = 1 << 13, + .num_mpt = 1 << 19, + .num_mtt = 1 << 20, +}; + +static int log_num_mac = 2; +module_param_named(log_num_mac, log_num_mac, int, 0444); +MODULE_PARM_DESC(log_num_mac, "Log2 max number of MACs per ETH port (1-7)"); + +static int use_prio; +module_param_named(use_prio, use_prio, bool, 0444); +MODULE_PARM_DESC(use_prio, "Enable steering by VLAN priority on ETH ports " + "(0/1, default 0)"); + +static struct mlx4_profile mod_param_profile = { 0 }; + +module_param_named(log_num_qp, mod_param_profile.num_qp, int, 0444); +MODULE_PARM_DESC(log_num_qp, "log maximum number of QPs per HCA"); + +module_param_named(log_num_srq, mod_param_profile.num_srq, int, 0444); +MODULE_PARM_DESC(log_num_srq, "log maximum number of SRQs per HCA"); + +module_param_named(log_rdmarc_per_qp, mod_param_profile.rdmarc_per_qp, int, 0444); +MODULE_PARM_DESC(log_rdmarc_per_qp, "log number of RDMARC buffers per QP"); + +module_param_named(log_num_cq, mod_param_profile.num_cq, int, 0444); +MODULE_PARM_DESC(log_num_cq, "log maximum number of CQs per HCA"); + +module_param_named(log_num_mcg, mod_param_profile.num_mcg, int, 0444); +MODULE_PARM_DESC(log_num_mcg, "log maximum number of multicast groups per HCA"); + +module_param_named(log_num_mpt, mod_param_profile.num_mpt, int, 0444); +MODULE_PARM_DESC(log_num_mpt, + "log maximum number of memory protection table entries per HCA"); + +module_param_named(log_num_mtt, mod_param_profile.num_mtt, int, 0444); +MODULE_PARM_DESC(log_num_mtt, + "log maximum number of memory translation table segments per HCA"); + +static int log_mtts_per_seg = 0; +module_param_named(log_mtts_per_seg, log_mtts_per_seg, int, 0444); +MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment (1-7)"); + +static void process_mod_param_profile(void) +{ + default_profile.num_qp = (mod_param_profile.num_qp ? + 1 << mod_param_profile.num_qp : + default_profile.num_qp); + default_profile.num_srq = (mod_param_profile.num_srq ? + 1 << mod_param_profile.num_srq : + default_profile.num_srq); + default_profile.rdmarc_per_qp = (mod_param_profile.rdmarc_per_qp ? + 1 << mod_param_profile.rdmarc_per_qp : + default_profile.rdmarc_per_qp); + default_profile.num_cq = (mod_param_profile.num_cq ? + 1 << mod_param_profile.num_cq : + default_profile.num_cq); + default_profile.num_mcg = (mod_param_profile.num_mcg ? + 1 << mod_param_profile.num_mcg : + default_profile.num_mcg); + default_profile.num_mpt = (mod_param_profile.num_mpt ? + 1 << mod_param_profile.num_mpt : + default_profile.num_mpt); + default_profile.num_mtt = (mod_param_profile.num_mtt ? + 1 << mod_param_profile.num_mtt : + default_profile.num_mtt); +} + +struct mlx4_port_config +{ + struct list_head list; + enum mlx4_port_type port_type[MLX4_MAX_PORTS + 1]; + struct pci_dev *pdev; +}; +static LIST_HEAD(config_list); + +static void mlx4_config_cleanup(void) +{ + struct mlx4_port_config *config, *tmp; + + list_for_each_entry_safe(config, tmp, &config_list, list) { + list_del(&config->list); + kfree(config); + } +} + +void *mlx4_get_prot_dev(struct mlx4_dev *dev, enum mlx4_prot proto, int port) +{ + return mlx4_find_get_prot_dev(dev, proto, port); +} +EXPORT_SYMBOL(mlx4_get_prot_dev); + +void mlx4_set_iboe_counter(struct mlx4_dev *dev, int index, u8 port) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + priv->iboe_counter_index[port - 1] = index; +} +EXPORT_SYMBOL(mlx4_set_iboe_counter); + +int mlx4_get_iboe_counter(struct mlx4_dev *dev, u8 port) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + return priv->iboe_counter_index[port - 1]; +} +EXPORT_SYMBOL(mlx4_get_iboe_counter); + +int mlx4_check_port_params(struct mlx4_dev *dev, + enum mlx4_port_type *port_type) +{ + int i; + + for (i = 0; i < dev->caps.num_ports - 1; i++) { + if (port_type[i] != port_type[i + 1]) { + if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) { + mlx4_err(dev, "Only same port types supported " + "on this HCA, aborting.\n"); + return -EINVAL; + } + if (port_type[i] == MLX4_PORT_TYPE_ETH && + port_type[i + 1] == MLX4_PORT_TYPE_IB) + return -EINVAL; + } + } + + for (i = 0; i < dev->caps.num_ports; i++) { + if (!(port_type[i] & dev->caps.supported_type[i+1])) { + mlx4_err(dev, "Requested port type for port %d is not " + "supported on this HCA\n", i + 1); + return -EINVAL; + } + } + return 0; +} + +static void mlx4_set_port_mask(struct mlx4_dev *dev) +{ + int i; + + for (i = 1; i <= dev->caps.num_ports; ++i) + dev->caps.port_mask[i] = dev->caps.port_type[i]; +} + +static u8 get_counters_mode(u64 flags) +{ + switch (flags >> 48 & 3) { + case 2: + case 3: + return MLX4_CUNTERS_EXT; + case 1: + return MLX4_CUNTERS_BASIC; + default: + return MLX4_CUNTERS_DISABLED; + } +} + +static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) +{ + int err; + int i; + + err = mlx4_QUERY_DEV_CAP(dev, dev_cap); + if (err) { + mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n"); + return err; + } + + if (dev_cap->min_page_sz > PAGE_SIZE) { + mlx4_err(dev, "HCA minimum page size of %d bigger than " + "kernel PAGE_SIZE of %d, aborting.\n", + dev_cap->min_page_sz, PAGE_SIZE); + return -ENODEV; + } + if (dev_cap->num_ports > MLX4_MAX_PORTS) { + mlx4_err(dev, "HCA has %d ports, but we only support %d, " + "aborting.\n", + dev_cap->num_ports, MLX4_MAX_PORTS); + return -ENODEV; + } + + if (dev_cap->uar_size > pci_resource_len(dev->pdev, 2)) { + mlx4_err(dev, "HCA reported UAR size of 0x%x bigger than " + "PCI resource 2 size of 0x%llx, aborting.\n", + dev_cap->uar_size, + (unsigned long long) pci_resource_len(dev->pdev, 2)); + return -ENODEV; + } + + dev->caps.num_ports = dev_cap->num_ports; + for (i = 1; i <= dev->caps.num_ports; ++i) { + dev->caps.vl_cap[i] = dev_cap->max_vl[i]; + dev->caps.ib_mtu_cap[i] = dev_cap->ib_mtu[i]; + dev->caps.gid_table_len[i] = dev_cap->max_gids[i]; + dev->caps.pkey_table_len[i] = dev_cap->max_pkeys[i]; + dev->caps.port_width_cap[i] = dev_cap->max_port_width[i]; + dev->caps.eth_mtu_cap[i] = dev_cap->eth_mtu[i]; + dev->caps.def_mac[i] = dev_cap->def_mac[i]; + dev->caps.supported_type[i] = dev_cap->supported_port_types[i]; + dev->caps.trans_type[i] = dev_cap->trans_type[i]; + dev->caps.vendor_oui[i] = dev_cap->vendor_oui[i]; + dev->caps.wavelength[i] = dev_cap->wavelength[i]; + dev->caps.trans_code[i] = dev_cap->trans_code[i]; + } + + dev->caps.num_uars = dev_cap->uar_size / PAGE_SIZE; + dev->caps.local_ca_ack_delay = dev_cap->local_ca_ack_delay; + dev->caps.bf_reg_size = dev_cap->bf_reg_size; + dev->caps.bf_regs_per_page = dev_cap->bf_regs_per_page; + dev->caps.max_sq_sg = dev_cap->max_sq_sg; + dev->caps.max_rq_sg = dev_cap->max_rq_sg; + dev->caps.max_wqes = dev_cap->max_qp_sz; + dev->caps.max_qp_init_rdma = dev_cap->max_requester_per_qp; + dev->caps.max_srq_wqes = dev_cap->max_srq_sz; + dev->caps.max_srq_sge = dev_cap->max_rq_sg - 1; + dev->caps.reserved_srqs = dev_cap->reserved_srqs; + dev->caps.max_sq_desc_sz = dev_cap->max_sq_desc_sz; + dev->caps.max_rq_desc_sz = dev_cap->max_rq_desc_sz; + dev->caps.num_qp_per_mgm = MLX4_QP_PER_MGM; + /* + * Subtract 1 from the limit because we need to allocate a + * spare CQE so the HCA HW can tell the difference between an + * empty CQ and a full CQ. + */ + dev->caps.max_cqes = dev_cap->max_cq_sz - 1; + dev->caps.reserved_cqs = dev_cap->reserved_cqs; + dev->caps.reserved_eqs = dev_cap->reserved_eqs; + dev->caps.mtts_per_seg = 1 << log_mtts_per_seg; + dev->caps.reserved_mtts = DIV_ROUND_UP(dev_cap->reserved_mtts, + dev->caps.mtts_per_seg); + dev->caps.reserved_mrws = dev_cap->reserved_mrws; + dev->caps.reserved_uars = dev_cap->reserved_uars; + dev->caps.reserved_pds = dev_cap->reserved_pds; + dev->caps.mtt_entry_sz = dev->caps.mtts_per_seg * dev_cap->mtt_entry_sz; + dev->caps.max_msg_sz = dev_cap->max_msg_sz; + dev->caps.page_size_cap = ~(u32) (dev_cap->min_page_sz - 1); + dev->caps.flags = dev_cap->flags; + dev->caps.bmme_flags = dev_cap->bmme_flags; + dev->caps.reserved_lkey = dev_cap->reserved_lkey; + dev->caps.stat_rate_support = dev_cap->stat_rate_support; + dev->caps.udp_rss = dev_cap->udp_rss; + dev->caps.loopback_support = dev_cap->loopback_support; + dev->caps.max_gso_sz = dev_cap->max_gso_sz; + dev->caps.reserved_xrcds = (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) ? + dev_cap->reserved_xrcds : 0; + dev->caps.max_xrcds = (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) ? + dev_cap->max_xrcds : 0; + + dev->caps.log_num_macs = log_num_mac; + dev->caps.log_num_prios = use_prio ? 3 : 0; + + for (i = 1; i <= dev->caps.num_ports; ++i) { + dev->caps.port_type[i] = MLX4_PORT_TYPE_NONE; + if (dev->caps.supported_type[i]) { + if (dev->caps.supported_type[i] != MLX4_PORT_TYPE_ETH) + dev->caps.port_type[i] = MLX4_PORT_TYPE_IB; + else + dev->caps.port_type[i] = MLX4_PORT_TYPE_ETH; + } + dev->caps.possible_type[i] = dev->caps.port_type[i]; + mlx4_priv(dev)->sense.sense_allowed[i] = + dev->caps.supported_type[i] == MLX4_PORT_TYPE_AUTO; + + if (dev->caps.log_num_macs > dev_cap->log_max_macs[i]) { + dev->caps.log_num_macs = dev_cap->log_max_macs[i]; + mlx4_warn(dev, "Requested number of MACs is too much " + "for port %d, reducing to %d.\n", + i, 1 << dev->caps.log_num_macs); + } + dev->caps.log_num_vlans = dev_cap->log_max_vlans[i]; + } + + dev->caps.counters_mode = get_counters_mode(dev_cap->flags); + dev->caps.max_basic_counters = 1 << ilog2(dev_cap->max_basic_counters); + dev->caps.max_ext_counters = 1 << ilog2(dev_cap->max_ext_counters); + + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] = dev_cap->reserved_qps; + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] = + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] = + (1 << dev->caps.log_num_macs) * + (1 << dev->caps.log_num_vlans) * + (1 << dev->caps.log_num_prios) * + dev->caps.num_ports; + + dev->caps.reserved_qps = dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] + + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] + + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR]; + + return 0; +} + +static int mlx4_save_config(struct mlx4_dev *dev) +{ + struct mlx4_port_config *config; + int i; + + list_for_each_entry(config, &config_list, list) { + if (config->pdev == dev->pdev) { + for (i = 1; i <= dev->caps.num_ports; i++) + config->port_type[i] = dev->caps.possible_type[i]; + return 0; + } + } + + config = kmalloc(sizeof(struct mlx4_port_config), GFP_KERNEL); + if (!config) + return -ENOMEM; + + config->pdev = dev->pdev; + for (i = 1; i <= dev->caps.num_ports; i++) + config->port_type[i] = dev->caps.possible_type[i]; + + list_add_tail(&config->list, &config_list); + + return 0; +} + +/* + * Change the port configuration of the device. + * Every user of this function must hold the port mutex. + */ +int mlx4_change_port_types(struct mlx4_dev *dev, + enum mlx4_port_type *port_types) +{ + int err = 0; + int change = 0; + int port; + + for (port = 0; port < dev->caps.num_ports; port++) { + /* Change the port type only if the new type is different + * from the current, and not set to Auto */ + if (port_types[port] != dev->caps.port_type[port + 1]) { + change = 1; + dev->caps.port_type[port + 1] = port_types[port]; + } + } + if (change) { + mlx4_unregister_device(dev); + for (port = 1; port <= dev->caps.num_ports; port++) { + mlx4_CLOSE_PORT(dev, port); + err = mlx4_SET_PORT(dev, port); + if (err) { + mlx4_err(dev, "Failed to set port %d, " + "aborting\n", port); + goto out; + } + } + mlx4_set_port_mask(dev); + mlx4_save_config(dev); + err = mlx4_register_device(dev); + } + +out: + return err; +} + +static ssize_t show_port_type(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info, + port_attr); + struct mlx4_dev *mdev = info->dev; + char type[8]; + + sprintf(type, "%s", + (mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_IB) ? + "ib" : "eth"); + if (mdev->caps.possible_type[info->port] == MLX4_PORT_TYPE_AUTO) + sprintf(buf, "auto (%s)\n", type); + else + sprintf(buf, "%s\n", type); + + return strlen(buf); +} + +static ssize_t set_port_type(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info, + port_attr); + struct mlx4_dev *mdev = info->dev; + struct mlx4_priv *priv = mlx4_priv(mdev); + enum mlx4_port_type types[MLX4_MAX_PORTS]; + enum mlx4_port_type new_types[MLX4_MAX_PORTS]; + int i; + int err = 0; + + if (!strcmp(buf, "ib\n")) + info->tmp_type = MLX4_PORT_TYPE_IB; + else if (!strcmp(buf, "eth\n")) + info->tmp_type = MLX4_PORT_TYPE_ETH; + else if (!strcmp(buf, "auto\n")) + info->tmp_type = MLX4_PORT_TYPE_AUTO; + else { + mlx4_err(mdev, "%s is not supported port type\n", buf); + return -EINVAL; + } + + mlx4_stop_sense(mdev); + mutex_lock(&priv->port_mutex); + /* Possible type is always the one that was delivered */ + mdev->caps.possible_type[info->port] = info->tmp_type; + + for (i = 0; i < mdev->caps.num_ports; i++) { + types[i] = priv->port[i+1].tmp_type ? priv->port[i+1].tmp_type : + mdev->caps.possible_type[i+1]; + if (types[i] == MLX4_PORT_TYPE_AUTO) + types[i] = mdev->caps.port_type[i+1]; + } + + if (priv->trig) { + if (++priv->changed_ports < mdev->caps.num_ports) + goto out; + else + priv->trig = priv->changed_ports = 0; + } + + if (!(mdev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) { + for (i = 1; i <= mdev->caps.num_ports; i++) { + if (mdev->caps.possible_type[i] == MLX4_PORT_TYPE_AUTO) { + mdev->caps.possible_type[i] = mdev->caps.port_type[i]; + err = -EINVAL; + } + } + } + if (err) { + mlx4_err(mdev, "Auto sensing is not supported on this HCA. " + "Set only 'eth' or 'ib' for both ports " + "(should be the same)\n"); + goto out; + } + + mlx4_do_sense_ports(mdev, new_types, types); + + err = mlx4_check_port_params(mdev, new_types); + if (err) + goto out; + + /* We are about to apply the changes after the configuration + * was verified, no need to remember the temporary types + * any more */ + for (i = 0; i < mdev->caps.num_ports; i++) + priv->port[i + 1].tmp_type = 0; + + err = mlx4_change_port_types(mdev, new_types); + +out: + mlx4_start_sense(mdev); + mutex_unlock(&priv->port_mutex); + return err ? err : count; +} + +static ssize_t trigger_port(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct mlx4_dev *mdev = pci_get_drvdata(pdev); + struct mlx4_priv *priv = container_of(mdev, struct mlx4_priv, dev); + + if (!priv) + return -ENODEV; + + mutex_lock(&priv->port_mutex); + priv->trig = 1; + mutex_unlock(&priv->port_mutex); + return count; +} +DEVICE_ATTR(port_trigger, S_IWUGO, NULL, trigger_port); + +static int mlx4_load_fw(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + + priv->fw.fw_icm = mlx4_alloc_icm(dev, priv->fw.fw_pages, + GFP_HIGHUSER | __GFP_NOWARN, 0); + if (!priv->fw.fw_icm) { + mlx4_err(dev, "Couldn't allocate FW area, aborting.\n"); + return -ENOMEM; + } + + err = mlx4_MAP_FA(dev, priv->fw.fw_icm); + if (err) { + mlx4_err(dev, "MAP_FA command failed, aborting.\n"); + goto err_free; + } + + err = mlx4_RUN_FW(dev); + if (err) { + mlx4_err(dev, "RUN_FW command failed, aborting.\n"); + goto err_unmap_fa; + } + + return 0; + +err_unmap_fa: + mlx4_UNMAP_FA(dev); + +err_free: + mlx4_free_icm(dev, priv->fw.fw_icm, 0); + return err; +} + +static int mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base, + int cmpt_entry_sz) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + + err = mlx4_init_icm_table(dev, &priv->qp_table.cmpt_table, + cmpt_base + + ((u64) (MLX4_CMPT_TYPE_QP * + cmpt_entry_sz) << MLX4_CMPT_SHIFT), + cmpt_entry_sz, dev->caps.num_qps, + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], + 0, 0); + if (err) + goto err; + + err = mlx4_init_icm_table(dev, &priv->srq_table.cmpt_table, + cmpt_base + + ((u64) (MLX4_CMPT_TYPE_SRQ * + cmpt_entry_sz) << MLX4_CMPT_SHIFT), + cmpt_entry_sz, dev->caps.num_srqs, + dev->caps.reserved_srqs, 0, 0); + if (err) + goto err_qp; + + err = mlx4_init_icm_table(dev, &priv->cq_table.cmpt_table, + cmpt_base + + ((u64) (MLX4_CMPT_TYPE_CQ * + cmpt_entry_sz) << MLX4_CMPT_SHIFT), + cmpt_entry_sz, dev->caps.num_cqs, + dev->caps.reserved_cqs, 0, 0); + if (err) + goto err_srq; + + err = mlx4_init_icm_table(dev, &priv->eq_table.cmpt_table, + cmpt_base + + ((u64) (MLX4_CMPT_TYPE_EQ * + cmpt_entry_sz) << MLX4_CMPT_SHIFT), + cmpt_entry_sz, + dev->caps.num_eqs, dev->caps.num_eqs, 0, 0); + if (err) + goto err_cq; + + return 0; + +err_cq: + mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table); + +err_srq: + mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table); + +err_qp: + mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table); + +err: + return err; +} + +static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap, + struct mlx4_init_hca_param *init_hca, u64 icm_size) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + u64 aux_pages; + int err; + + err = mlx4_SET_ICM_SIZE(dev, icm_size, &aux_pages); + if (err) { + mlx4_err(dev, "SET_ICM_SIZE command failed, aborting.\n"); + return err; + } + + mlx4_dbg(dev, "%lld KB of HCA context requires %lld KB aux memory.\n", + (unsigned long long) icm_size >> 10, + (unsigned long long) aux_pages << 2); + + priv->fw.aux_icm = mlx4_alloc_icm(dev, aux_pages, + GFP_HIGHUSER | __GFP_NOWARN, 0); + if (!priv->fw.aux_icm) { + mlx4_err(dev, "Couldn't allocate aux memory, aborting.\n"); + return -ENOMEM; + } + + err = mlx4_MAP_ICM_AUX(dev, priv->fw.aux_icm); + if (err) { + mlx4_err(dev, "MAP_ICM_AUX command failed, aborting.\n"); + goto err_free_aux; + } + + err = mlx4_init_cmpt_table(dev, init_hca->cmpt_base, dev_cap->cmpt_entry_sz); + if (err) { + mlx4_err(dev, "Failed to map cMPT context memory, aborting.\n"); + goto err_unmap_aux; + } + + err = mlx4_init_icm_table(dev, &priv->eq_table.table, + init_hca->eqc_base, dev_cap->eqc_entry_sz, + dev->caps.num_eqs, dev->caps.num_eqs, + 0, 0); + if (err) { + mlx4_err(dev, "Failed to map EQ context memory, aborting.\n"); + goto err_unmap_cmpt; + } + + /* + * Reserved MTT entries must be aligned up to a cacheline + * boundary, since the FW will write to them, while the driver + * writes to all other MTT entries. (The variable + * dev->caps.mtt_entry_sz below is really the MTT segment + * size, not the raw entry size) + */ + dev->caps.reserved_mtts = + ALIGN(dev->caps.reserved_mtts * dev->caps.mtt_entry_sz, + dma_get_cache_alignment()) / dev->caps.mtt_entry_sz; + + err = mlx4_init_icm_table(dev, &priv->mr_table.mtt_table, + init_hca->mtt_base, + dev->caps.mtt_entry_sz, + dev->caps.num_mtt_segs, + dev->caps.reserved_mtts, 1, 0); + if (err) { + mlx4_err(dev, "Failed to map MTT context memory, aborting.\n"); + goto err_unmap_eq; + } + + err = mlx4_init_icm_table(dev, &priv->mr_table.dmpt_table, + init_hca->dmpt_base, + dev_cap->dmpt_entry_sz, + dev->caps.num_mpts, + dev->caps.reserved_mrws, 1, 1); + if (err) { + mlx4_err(dev, "Failed to map dMPT context memory, aborting.\n"); + goto err_unmap_mtt; + } + + err = mlx4_init_icm_table(dev, &priv->qp_table.qp_table, + init_hca->qpc_base, + dev_cap->qpc_entry_sz, + dev->caps.num_qps, + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], + 0, 0); + if (err) { + mlx4_err(dev, "Failed to map QP context memory, aborting.\n"); + goto err_unmap_dmpt; + } + + err = mlx4_init_icm_table(dev, &priv->qp_table.auxc_table, + init_hca->auxc_base, + dev_cap->aux_entry_sz, + dev->caps.num_qps, + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], + 0, 0); + if (err) { + mlx4_err(dev, "Failed to map AUXC context memory, aborting.\n"); + goto err_unmap_qp; + } + + err = mlx4_init_icm_table(dev, &priv->qp_table.altc_table, + init_hca->altc_base, + dev_cap->altc_entry_sz, + dev->caps.num_qps, + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], + 0, 0); + if (err) { + mlx4_err(dev, "Failed to map ALTC context memory, aborting.\n"); + goto err_unmap_auxc; + } + + err = mlx4_init_icm_table(dev, &priv->qp_table.rdmarc_table, + init_hca->rdmarc_base, + dev_cap->rdmarc_entry_sz << priv->qp_table.rdmarc_shift, + dev->caps.num_qps, + dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], + 0, 0); + if (err) { + mlx4_err(dev, "Failed to map RDMARC context memory, aborting\n"); + goto err_unmap_altc; + } + + err = mlx4_init_icm_table(dev, &priv->cq_table.table, + init_hca->cqc_base, + dev_cap->cqc_entry_sz, + dev->caps.num_cqs, + dev->caps.reserved_cqs, 0, 0); + if (err) { + mlx4_err(dev, "Failed to map CQ context memory, aborting.\n"); + goto err_unmap_rdmarc; + } + + err = mlx4_init_icm_table(dev, &priv->srq_table.table, + init_hca->srqc_base, + dev_cap->srq_entry_sz, + dev->caps.num_srqs, + dev->caps.reserved_srqs, 0, 0); + if (err) { + mlx4_err(dev, "Failed to map SRQ context memory, aborting.\n"); + goto err_unmap_cq; + } + + /* + * It's not strictly required, but for simplicity just map the + * whole multicast group table now. The table isn't very big + * and it's a lot easier than trying to track ref counts. + */ + err = mlx4_init_icm_table(dev, &priv->mcg_table.table, + init_hca->mc_base, MLX4_MGM_ENTRY_SIZE, + dev->caps.num_mgms + dev->caps.num_amgms, + dev->caps.num_mgms + dev->caps.num_amgms, + 0, 0); + if (err) { + mlx4_err(dev, "Failed to map MCG context memory, aborting.\n"); + goto err_unmap_srq; + } + + return 0; + +err_unmap_srq: + mlx4_cleanup_icm_table(dev, &priv->srq_table.table); + +err_unmap_cq: + mlx4_cleanup_icm_table(dev, &priv->cq_table.table); + +err_unmap_rdmarc: + mlx4_cleanup_icm_table(dev, &priv->qp_table.rdmarc_table); + +err_unmap_altc: + mlx4_cleanup_icm_table(dev, &priv->qp_table.altc_table); + +err_unmap_auxc: + mlx4_cleanup_icm_table(dev, &priv->qp_table.auxc_table); + +err_unmap_qp: + mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table); + +err_unmap_dmpt: + mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table); + +err_unmap_mtt: + mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table); + +err_unmap_eq: + mlx4_cleanup_icm_table(dev, &priv->eq_table.table); + +err_unmap_cmpt: + mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table); + mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table); + mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table); + mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table); + +err_unmap_aux: + mlx4_UNMAP_ICM_AUX(dev); + +err_free_aux: + mlx4_free_icm(dev, priv->fw.aux_icm, 0); + + return err; +} + +static void mlx4_free_icms(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + mlx4_cleanup_icm_table(dev, &priv->mcg_table.table); + mlx4_cleanup_icm_table(dev, &priv->srq_table.table); + mlx4_cleanup_icm_table(dev, &priv->cq_table.table); + mlx4_cleanup_icm_table(dev, &priv->qp_table.rdmarc_table); + mlx4_cleanup_icm_table(dev, &priv->qp_table.altc_table); + mlx4_cleanup_icm_table(dev, &priv->qp_table.auxc_table); + mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table); + mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table); + mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table); + mlx4_cleanup_icm_table(dev, &priv->eq_table.table); + mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table); + mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table); + mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table); + mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table); + + mlx4_UNMAP_ICM_AUX(dev); + mlx4_free_icm(dev, priv->fw.aux_icm, 0); +} + +static int map_bf_area(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + resource_size_t bf_start; + resource_size_t bf_len; + int err = 0; + + bf_start = pci_resource_start(dev->pdev, 2) + (dev->caps.num_uars << PAGE_SHIFT); + bf_len = pci_resource_len(dev->pdev, 2) - (dev->caps.num_uars << PAGE_SHIFT); + priv->bf_mapping = io_mapping_create_wc(bf_start, bf_len); + if (!priv->bf_mapping) + err = -ENOMEM; + + return err; +} + +static void unmap_bf_area(struct mlx4_dev *dev) +{ + if (mlx4_priv(dev)->bf_mapping) + io_mapping_free(mlx4_priv(dev)->bf_mapping); +} + +static void mlx4_close_hca(struct mlx4_dev *dev) +{ + unmap_bf_area(dev); + mlx4_CLOSE_HCA(dev, 0); + mlx4_free_icms(dev); + mlx4_UNMAP_FA(dev); + mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm, 0); +} + +static int mlx4_init_hca(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_adapter adapter; + struct mlx4_dev_cap dev_cap; + struct mlx4_mod_stat_cfg mlx4_cfg; + struct mlx4_profile profile; + struct mlx4_init_hca_param init_hca; + struct mlx4_port_config *config; + u64 icm_size; + int err; + int i; + + err = mlx4_QUERY_FW(dev); + if (err) { + if (err == -EACCES) + mlx4_info(dev, "non-primary physical function, skipping.\n"); + else + mlx4_err(dev, "QUERY_FW command failed, aborting.\n"); + return err; + } + + err = mlx4_load_fw(dev); + if (err) { + mlx4_err(dev, "Failed to start FW, aborting.\n"); + return err; + } + + mlx4_cfg.log_pg_sz_m = 1; + mlx4_cfg.log_pg_sz = 0; + err = mlx4_MOD_STAT_CFG(dev, &mlx4_cfg); + if (err) + mlx4_warn(dev, "Failed to override log_pg_sz parameter\n"); + + err = mlx4_dev_cap(dev, &dev_cap); + if (err) { + mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting.\n"); + goto err_stop_fw; + } + + process_mod_param_profile(); + profile = default_profile; + + list_for_each_entry(config, &config_list, list) { + if (config->pdev == dev->pdev) { + for (i = 1; i <= dev->caps.num_ports; i++) { + dev->caps.possible_type[i] = config->port_type[i]; + if (config->port_type[i] != MLX4_PORT_TYPE_AUTO) + dev->caps.port_type[i] = config->port_type[i]; + } + } + } + + mlx4_set_port_mask(dev); + icm_size = mlx4_make_profile(dev, &profile, &dev_cap, &init_hca); + if ((long long) icm_size < 0) { + err = icm_size; + goto err_stop_fw; + } + + if (map_bf_area(dev)) + mlx4_dbg(dev, "Kernel support for blue flame is not available for kernels < 2.6.28\n"); + + init_hca.log_uar_sz = ilog2(dev->caps.num_uars); + + err = mlx4_init_icm(dev, &dev_cap, &init_hca, icm_size); + if (err) + goto err_stop_fw; + + err = mlx4_INIT_HCA(dev, &init_hca); + if (err) { + mlx4_err(dev, "INIT_HCA command failed, aborting.\n"); + goto err_free_icm; + } + + err = mlx4_QUERY_ADAPTER(dev, &adapter); + if (err) { + mlx4_err(dev, "QUERY_ADAPTER command failed, aborting.\n"); + goto err_close; + } + + priv->eq_table.inta_pin = adapter.inta_pin; + memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id); + + return 0; + +err_close: + mlx4_CLOSE_HCA(dev, 0); + +err_free_icm: + mlx4_free_icms(dev); + +err_stop_fw: + unmap_bf_area(dev); + mlx4_UNMAP_FA(dev); + mlx4_free_icm(dev, priv->fw.fw_icm, 0); + + return err; +} + +static int mlx4_init_counters_table(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + int nent; + + switch (dev->caps.counters_mode) { + case MLX4_CUNTERS_BASIC: + nent = dev->caps.max_basic_counters; + break; + case MLX4_CUNTERS_EXT: + nent = dev->caps.max_ext_counters; + break; + default: + return -ENOENT; + } + err = mlx4_bitmap_init(&priv->counters_bitmap, nent, nent - 1, 0, 0); + if (err) + return err; + + return 0; +} + +static void mlx4_cleanup_counters_table(struct mlx4_dev *dev) +{ + switch (dev->caps.counters_mode) { + case MLX4_CUNTERS_BASIC: + case MLX4_CUNTERS_EXT: + mlx4_bitmap_cleanup(&mlx4_priv(dev)->counters_bitmap); + break; + default: + break; + } +} + +int mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + switch (dev->caps.counters_mode) { + case MLX4_CUNTERS_BASIC: + case MLX4_CUNTERS_EXT: + *idx = mlx4_bitmap_alloc(&priv->counters_bitmap); + if (*idx == -1) + return -ENOMEM; + return 0; + default: + return -ENOMEM; + } +} +EXPORT_SYMBOL_GPL(mlx4_counter_alloc); + +void mlx4_counter_free(struct mlx4_dev *dev, u32 idx) +{ + switch (dev->caps.counters_mode) { + case MLX4_CUNTERS_BASIC: + case MLX4_CUNTERS_EXT: + mlx4_bitmap_free(&mlx4_priv(dev)->counters_bitmap, idx); + return; + default: + return; + } +} +EXPORT_SYMBOL_GPL(mlx4_counter_free); + +static int mlx4_setup_hca(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + int port; + __be32 ib_port_default_caps; + + err = mlx4_init_uar_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "user access region table, aborting.\n"); + return err; + } + + err = mlx4_uar_alloc(dev, &priv->driver_uar); + if (err) { + mlx4_err(dev, "Failed to allocate driver access region, " + "aborting.\n"); + goto err_uar_table_free; + } + + priv->kar = ioremap(priv->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); + if (!priv->kar) { + mlx4_err(dev, "Couldn't map kernel access region, " + "aborting.\n"); + err = -ENOMEM; + goto err_uar_free; + } + + err = mlx4_init_pd_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "protection domain table, aborting.\n"); + goto err_kar_unmap; + } + + err = mlx4_init_xrcd_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize extended " + "reliably connected domain table, aborting.\n"); + goto err_pd_table_free; + } + + err = mlx4_init_mr_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "memory region table, aborting.\n"); + goto err_xrcd_table_free; + } + + err = mlx4_init_eq_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "event queue table, aborting.\n"); + goto err_mr_table_free; + } + + err = mlx4_cmd_use_events(dev); + if (err) { + mlx4_err(dev, "Failed to switch to event-driven " + "firmware commands, aborting.\n"); + goto err_eq_table_free; + } + + err = mlx4_NOP(dev); + if (err) { + if (dev->flags & MLX4_FLAG_MSI_X) { + mlx4_warn(dev, "NOP command failed to generate MSI-X " + "interrupt IRQ %d).\n", + priv->eq_table.eq[dev->caps.num_comp_vectors].irq); + mlx4_warn(dev, "Trying again without MSI-X.\n"); + } else { + mlx4_err(dev, "NOP command failed to generate interrupt " + "(IRQ %d), aborting.\n", + priv->eq_table.eq[dev->caps.num_comp_vectors].irq); + mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n"); + } + + goto err_cmd_poll; + } + + mlx4_dbg(dev, "NOP command IRQ test passed\n"); + + err = mlx4_init_cq_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "completion queue table, aborting.\n"); + goto err_cmd_poll; + } + + err = mlx4_init_srq_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "shared receive queue table, aborting.\n"); + goto err_cq_table_free; + } + + err = mlx4_init_qp_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "queue pair table, aborting.\n"); + goto err_srq_table_free; + } + + err = mlx4_init_mcg_table(dev); + if (err) { + mlx4_err(dev, "Failed to initialize " + "multicast group table, aborting.\n"); + goto err_qp_table_free; + } + + err = mlx4_init_counters_table(dev); + if (err && err != -ENOENT) { + mlx4_err(dev, "Failed to initialize counters table, aborting.\n"); + goto err_mcg_table_free; + } + + for (port = 1; port <= dev->caps.num_ports; port++) { + ib_port_default_caps = 0; + err = mlx4_get_port_ib_caps(dev, port, &ib_port_default_caps); + if (err) + mlx4_warn(dev, "failed to get port %d default " + "ib capabilities (%d). Continuing with " + "caps = 0\n", port, err); + dev->caps.ib_port_def_cap[port] = ib_port_default_caps; + err = mlx4_SET_PORT(dev, port); + if (err) { + mlx4_err(dev, "Failed to set port %d, aborting\n", + port); + goto err_counters_table_free; + } + } + + return 0; + +err_counters_table_free: + mlx4_cleanup_counters_table(dev); + +err_mcg_table_free: + mlx4_cleanup_mcg_table(dev); + +err_qp_table_free: + mlx4_cleanup_qp_table(dev); + +err_srq_table_free: + mlx4_cleanup_srq_table(dev); + +err_cq_table_free: + mlx4_cleanup_cq_table(dev); + +err_cmd_poll: + mlx4_cmd_use_polling(dev); + +err_eq_table_free: + mlx4_cleanup_eq_table(dev); + +err_mr_table_free: + mlx4_cleanup_mr_table(dev); + +err_xrcd_table_free: + mlx4_cleanup_xrcd_table(dev); + +err_pd_table_free: + mlx4_cleanup_pd_table(dev); + +err_kar_unmap: + iounmap(priv->kar); + +err_uar_free: + mlx4_uar_free(dev, &priv->driver_uar); + +err_uar_table_free: + mlx4_cleanup_uar_table(dev); + return err; +} + +static void mlx4_enable_msi_x(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct msix_entry *entries; + int nreq; + int err; + int i; + + if (msi_x) { + nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, + num_possible_cpus() + 1); + entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); + if (!entries) + goto no_msi; + + for (i = 0; i < nreq; ++i) + entries[i].entry = i; + + retry: + err = pci_enable_msix(dev->pdev, entries, nreq); + if (err) { + /* Try again if at least 2 vectors are available */ + if (err > 1) { + mlx4_info(dev, "Requested %d vectors, " + "but only %d MSI-X vectors available, " + "trying again\n", nreq, err); + nreq = err; + goto retry; + } + kfree(entries); + goto no_msi; + } + + dev->caps.num_comp_vectors = nreq - 1; + for (i = 0; i < nreq; ++i) + priv->eq_table.eq[i].irq = entries[i].vector; + + dev->flags |= MLX4_FLAG_MSI_X; + + kfree(entries); + return; + } + +no_msi: + dev->caps.num_comp_vectors = 1; + + for (i = 0; i < 2; ++i) + priv->eq_table.eq[i].irq = dev->pdev->irq; +} + +static int mlx4_init_port_info(struct mlx4_dev *dev, int port) +{ + struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; + int err = 0; + + info->dev = dev; + info->port = port; + mlx4_init_mac_table(dev, &info->mac_table); + mlx4_init_vlan_table(dev, &info->vlan_table); + + sprintf(info->dev_name, "mlx4_port%d", port); + info->port_attr.attr.name = info->dev_name; + info->port_attr.attr.mode = S_IRUGO | S_IWUSR; + info->port_attr.show = show_port_type; + info->port_attr.store = set_port_type; + + err = device_create_file(&dev->pdev->dev, &info->port_attr); + if (err) { + mlx4_err(dev, "Failed to create file for port %d\n", port); + info->port = -1; + } + + return err; +} + +static void mlx4_cleanup_port_info(struct mlx4_port_info *info) +{ + if (info->port < 0) + return; + + device_remove_file(&info->dev->pdev->dev, &info->port_attr); +} + +static int mlx4_init_trigger(struct mlx4_priv *priv) +{ + memcpy(&priv->trigger_attr, &dev_attr_port_trigger, + sizeof(struct device_attribute)); + return device_create_file(&priv->dev.pdev->dev, &priv->trigger_attr); +} + +static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct mlx4_priv *priv; + struct mlx4_dev *dev; + int err; + int port; + int i; + + printk(KERN_INFO PFX "Initializing %s\n", + pci_name(pdev)); + + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "Cannot enable PCI device, " + "aborting.\n"); + return err; + } + + /* + * Check for BARs. We expect 0: 1MB + */ + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || + pci_resource_len(pdev, 0) != 1 << 20) { + dev_err(&pdev->dev, "Missing DCS, aborting.\n"); + err = -ENODEV; + goto err_disable_pdev; + } + if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { + dev_err(&pdev->dev, "Missing UAR, aborting.\n"); + err = -ENODEV; + goto err_disable_pdev; + } + + err = pci_request_region(pdev, 0, DRV_NAME); + if (err) { + dev_err(&pdev->dev, "Cannot request control region, aborting.\n"); + goto err_disable_pdev; + } + + err = pci_request_region(pdev, 2, DRV_NAME); + if (err) { + dev_err(&pdev->dev, "Cannot request UAR region, aborting.\n"); + goto err_release_bar0; + } + + pci_set_master(pdev); + + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (err) { + dev_warn(&pdev->dev, "Warning: couldn't set 64-bit PCI DMA mask.\n"); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err) { + dev_err(&pdev->dev, "Can't set PCI DMA mask, aborting.\n"); + goto err_release_bar2; + } + } + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (err) { + dev_warn(&pdev->dev, "Warning: couldn't set 64-bit " + "consistent PCI DMA mask.\n"); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err) { + dev_err(&pdev->dev, "Can't set consistent PCI DMA mask, " + "aborting.\n"); + goto err_release_bar2; + } + } + + priv = kzalloc(sizeof *priv, GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "Device struct alloc failed, " + "aborting.\n"); + err = -ENOMEM; + goto err_release_bar2; + } + + dev = &priv->dev; + dev->pdev = pdev; + INIT_LIST_HEAD(&priv->ctx_list); + spin_lock_init(&priv->ctx_lock); + + mutex_init(&priv->port_mutex); + + INIT_LIST_HEAD(&priv->pgdir_list); + mutex_init(&priv->pgdir_mutex); + for (i = 0; i < MLX4_MAX_PORTS; ++i) + priv->iboe_counter_index[i] = -1; + + INIT_LIST_HEAD(&priv->bf_list); + mutex_init(&priv->bf_mutex); + + /* + * Now reset the HCA before we touch the PCI capabilities or + * attempt a firmware command, since a boot ROM may have left + * the HCA in an undefined state. + */ + err = mlx4_reset(dev); + if (err) { + mlx4_err(dev, "Failed to reset HCA, aborting.\n"); + goto err_free_dev; + } + + if (mlx4_cmd_init(dev)) { + mlx4_err(dev, "Failed to init command interface, aborting.\n"); + goto err_free_dev; + } + + err = mlx4_init_hca(dev); + if (err) + goto err_cmd; + + err = mlx4_alloc_eq_table(dev); + if (err) + goto err_close; + + mlx4_enable_msi_x(dev); + + err = mlx4_setup_hca(dev); + if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X)) { + dev->flags &= ~MLX4_FLAG_MSI_X; + pci_disable_msix(pdev); + err = mlx4_setup_hca(dev); + } + + if (err) + goto err_free_eq; + + for (port = 1; port <= dev->caps.num_ports; port++) { + err = mlx4_init_port_info(dev, port); + if (err) + goto err_port; + } + + err = mlx4_register_device(dev); + if (err) + goto err_port; + + err = mlx4_init_trigger(priv); + if (err) + goto err_register; + + err = mlx4_sense_init(dev); + if (err) + goto err_trigger; + + mlx4_start_sense(dev); + + pci_set_drvdata(pdev, dev); + + return 0; + +err_trigger: + device_remove_file(&dev->pdev->dev, &priv->trigger_attr); +err_register: + mlx4_unregister_device(dev); +err_port: + for (--port; port >= 1; --port) + mlx4_cleanup_port_info(&priv->port[port]); + + mlx4_cleanup_counters_table(dev); + mlx4_cleanup_mcg_table(dev); + mlx4_cleanup_qp_table(dev); + mlx4_cleanup_srq_table(dev); + mlx4_cleanup_cq_table(dev); + mlx4_cmd_use_polling(dev); + mlx4_cleanup_eq_table(dev); + mlx4_cleanup_mr_table(dev); + mlx4_cleanup_xrcd_table(dev); + mlx4_cleanup_pd_table(dev); + mlx4_cleanup_uar_table(dev); + +err_free_eq: + mlx4_free_eq_table(dev); + +err_close: + if (dev->flags & MLX4_FLAG_MSI_X) + pci_disable_msix(pdev); + + mlx4_close_hca(dev); + +err_cmd: + mlx4_cmd_cleanup(dev); + +err_free_dev: + kfree(priv); + +err_release_bar2: + pci_release_region(pdev, 2); + +err_release_bar0: + pci_release_region(pdev, 0); + +err_disable_pdev: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + return err; +} + +static int __devinit mlx4_init_one(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + static int mlx4_version_printed; + + if (!mlx4_version_printed) { + printk(KERN_INFO "%s", mlx4_version); + ++mlx4_version_printed; + } + + return __mlx4_init_one(pdev, id); +} + +static void mlx4_remove_one(struct pci_dev *pdev) +{ + struct mlx4_dev *dev = pci_get_drvdata(pdev); + struct mlx4_priv *priv = mlx4_priv(dev); + int p; + + if (dev) { + mlx4_sense_cleanup(dev); + mlx4_unregister_device(dev); + device_remove_file(&dev->pdev->dev, &priv->trigger_attr); + + for (p = 1; p <= dev->caps.num_ports; p++) { + mlx4_cleanup_port_info(&priv->port[p]); + mlx4_CLOSE_PORT(dev, p); + } + + mlx4_cleanup_counters_table(dev); + mlx4_cleanup_mcg_table(dev); + mlx4_cleanup_qp_table(dev); + mlx4_cleanup_srq_table(dev); + mlx4_cleanup_cq_table(dev); + mlx4_cmd_use_polling(dev); + mlx4_cleanup_eq_table(dev); + mlx4_cleanup_mr_table(dev); + mlx4_cleanup_xrcd_table(dev); + mlx4_cleanup_pd_table(dev); + + iounmap(priv->kar); + mlx4_uar_free(dev, &priv->driver_uar); + mlx4_cleanup_uar_table(dev); + mlx4_free_eq_table(dev); + mlx4_close_hca(dev); + mlx4_cmd_cleanup(dev); + + if (dev->flags & MLX4_FLAG_MSI_X) + pci_disable_msix(pdev); + + kfree(priv); + pci_release_region(pdev, 2); + pci_release_region(pdev, 0); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } +} + +int mlx4_restart_one(struct pci_dev *pdev) +{ + mlx4_remove_one(pdev); + return __mlx4_init_one(pdev, NULL); +} + +static struct pci_device_id mlx4_pci_table[] = { + { PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */ + { PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */ + { PCI_VDEVICE(MELLANOX, 0x6354) }, /* MT25408 "Hermon" QDR */ + { PCI_VDEVICE(MELLANOX, 0x6732) }, /* MT25408 "Hermon" DDR PCIe gen2 */ + { PCI_VDEVICE(MELLANOX, 0x673c) }, /* MT25408 "Hermon" QDR PCIe gen2 */ + { PCI_VDEVICE(MELLANOX, 0x6368) }, /* MT25408 "Hermon" EN 10GigE */ + { PCI_VDEVICE(MELLANOX, 0x6750) }, /* MT25408 "Hermon" EN 10GigE PCIe gen2 */ + { PCI_VDEVICE(MELLANOX, 0x6372) }, /* MT25458 ConnectX EN 10GBASE-T 10GigE */ + { PCI_VDEVICE(MELLANOX, 0x675a) }, /* MT25458 ConnectX EN 10GBASE-T+Gen2 10GigE */ + { PCI_VDEVICE(MELLANOX, 0x6764) }, /* MT26468 ConnectX EN 10GigE PCIe gen2 */ + { PCI_VDEVICE(MELLANOX, 0x6746) }, /* MT26438 ConnectX VPI PCIe 2.0 5GT/s - IB QDR / 10GigE Virt+ */ + { PCI_VDEVICE(MELLANOX, 0x676e) }, /* MT26478 ConnectX EN 40GigE PCIe 2.0 5GT/s */ + { PCI_VDEVICE(MELLANOX, 0x6778) }, /* MT26488 ConnectX VPI PCIe 2.0 5GT/s - IB DDR / 10GigE Virt+ */ + { PCI_VDEVICE(MELLANOX, 0x1000) }, + { PCI_VDEVICE(MELLANOX, 0x1001) }, + { PCI_VDEVICE(MELLANOX, 0x1002) }, + { PCI_VDEVICE(MELLANOX, 0x1003) }, + { PCI_VDEVICE(MELLANOX, 0x1004) }, + { PCI_VDEVICE(MELLANOX, 0x1005) }, + { PCI_VDEVICE(MELLANOX, 0x1006) }, + { PCI_VDEVICE(MELLANOX, 0x1007) }, + { PCI_VDEVICE(MELLANOX, 0x1008) }, + { PCI_VDEVICE(MELLANOX, 0x1009) }, + { PCI_VDEVICE(MELLANOX, 0x100a) }, + { PCI_VDEVICE(MELLANOX, 0x100b) }, + { PCI_VDEVICE(MELLANOX, 0x100c) }, + { PCI_VDEVICE(MELLANOX, 0x100d) }, + { PCI_VDEVICE(MELLANOX, 0x100e) }, + { PCI_VDEVICE(MELLANOX, 0x100f) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, mlx4_pci_table); + +static struct pci_driver mlx4_driver = { + .name = DRV_NAME, + .id_table = mlx4_pci_table, + .probe = mlx4_init_one, + .remove = __devexit_p(mlx4_remove_one) +}; + +static int __init mlx4_verify_params(void) +{ + if ((log_num_mac < 0) || (log_num_mac > 7)) { + printk(KERN_WARNING "mlx4_core: bad num_mac: %d\n", log_num_mac); + return -1; + } + + if (log_mtts_per_seg == 0) + log_mtts_per_seg = ilog2(MLX4_MTT_ENTRY_PER_SEG); + if ((log_mtts_per_seg < 1) || (log_mtts_per_seg > 7)) { + printk(KERN_WARNING "mlx4_core: bad log_mtts_per_seg: %d\n", log_mtts_per_seg); + return -1; + } + + return 0; +} + +static int __init mlx4_init(void) +{ + int ret; + + mutex_init(&drv_mutex); + + if (mlx4_verify_params()) + return -EINVAL; + + mlx4_catas_init(); + + mlx4_wq = create_singlethread_workqueue("mlx4"); + if (!mlx4_wq) + return -ENOMEM; + + ret = pci_register_driver(&mlx4_driver); + return ret < 0 ? ret : 0; +} + +static void __exit mlx4_cleanup(void) +{ + mutex_lock(&drv_mutex); + mlx4_config_cleanup(); + pci_unregister_driver(&mlx4_driver); + mutex_unlock(&drv_mutex); + destroy_workqueue(mlx4_wq); +} + +module_init_order(mlx4_init, SI_ORDER_MIDDLE); +module_exit(mlx4_cleanup); + +#undef MODULE_VERSION +#include +static int +mlx4_evhand(module_t mod, int event, void *arg) +{ + return (0); +} + +static moduledata_t mlx4_mod = { + .name = "mlx4", + .evhand = mlx4_evhand, +}; +MODULE_VERSION(mlx4, 1); +DECLARE_MODULE(mlx4, mlx4_mod, SI_SUB_SMP, SI_ORDER_ANY); diff --git a/sys/ofed/drivers/net/mlx4/mcg.c b/sys/ofed/drivers/net/mlx4/mcg.c new file mode 100644 index 000000000000..70493e3ae398 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/mcg.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include +#include + +#include "mlx4.h" + +#define MGM_QPN_MASK 0x00FFFFFF +#define MGM_BLCK_LB_BIT 30 + +struct mlx4_mgm { + __be32 next_gid_index; + __be32 members_count; + u32 reserved[2]; + u8 gid[16]; + __be32 qp[MLX4_QP_PER_MGM]; +}; + +static const u8 zero_gid[16]; /* automatically initialized to 0 */ + +static int mlx4_READ_MCG(struct mlx4_dev *dev, int index, + struct mlx4_cmd_mailbox *mailbox) +{ + return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_WRITE_MCG(struct mlx4_dev *dev, int index, + struct mlx4_cmd_mailbox *mailbox) +{ + return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + u16 *hash) +{ + u64 imm; + int err; + + err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, 0, MLX4_CMD_MGID_HASH, + MLX4_CMD_TIME_CLASS_A); + + if (!err) + *hash = imm; + + return err; +} + +/* + * Caller must hold MCG table semaphore. gid and mgm parameters must + * be properly aligned for command interface. + * + * Returns 0 unless a firmware command error occurs. + * + * If GID is found in MGM or MGM is empty, *index = *hash, *prev = -1 + * and *mgm holds MGM entry. + * + * if GID is found in AMGM, *index = index in AMGM, *prev = index of + * previous entry in hash chain and *mgm holds AMGM entry. + * + * If no AMGM exists for given gid, *index = -1, *prev = index of last + * entry in hash chain and *mgm holds end of hash chain. + */ +static int find_mgm(struct mlx4_dev *dev, + u8 *gid, enum mlx4_mcast_prot prot, + struct mlx4_cmd_mailbox *mgm_mailbox, + u16 *hash, int *prev, int *index) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mgm *mgm = mgm_mailbox->buf; + u8 *mgid; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return -ENOMEM; + mgid = mailbox->buf; + + memcpy(mgid, gid, 16); + + err = mlx4_MGID_HASH(dev, mailbox, hash); + mlx4_free_cmd_mailbox(dev, mailbox); + if (err) + return err; + + if (0) + mlx4_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash); + + *index = *hash; + *prev = -1; + + do { + err = mlx4_READ_MCG(dev, *index, mgm_mailbox); + if (err) + return err; + + if (!memcmp(mgm->gid, zero_gid, 16)) { + if (*index != *hash) { + mlx4_err(dev, "Found zero MGID in AMGM.\n"); + err = -EINVAL; + } + return err; + } + + if (!memcmp(mgm->gid, gid, 16) && + (prot == be32_to_cpu(mgm->members_count) >> 30)) + return err; + + *prev = *index; + *index = be32_to_cpu(mgm->next_gid_index) >> 6; + } while (*index); + + *index = -1; + return err; +} + +int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + int block_mcast_loopback, enum mlx4_mcast_prot prot) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mgm *mgm; + u32 members_count; + u16 hash; + int index, prev; + int link = 0; + int i; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + mgm = mailbox->buf; + + mutex_lock(&priv->mcg_table.mutex); + + err = find_mgm(dev, gid, prot, mailbox, &hash, &prev, &index); + if (err) + goto out; + + if (index != -1) { + if (!memcmp(mgm->gid, zero_gid, 16)) + memcpy(mgm->gid, gid, 16); + } else { + link = 1; + + index = mlx4_bitmap_alloc(&priv->mcg_table.bitmap); + if (index == -1) { + mlx4_err(dev, "No AMGM entries left\n"); + err = -ENOMEM; + goto out; + } + index += dev->caps.num_mgms; + + memset(mgm, 0, sizeof *mgm); + memcpy(mgm->gid, gid, 16); + } + + members_count = be32_to_cpu(mgm->members_count) & 0xffffff; + if (members_count == MLX4_QP_PER_MGM) { + mlx4_err(dev, "MGM at index %x is full.\n", index); + err = -ENOMEM; + goto out; + } + + for (i = 0; i < members_count; ++i) + if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) { + mlx4_dbg(dev, "QP %06x already a member of MGM\n", qp->qpn); + err = 0; + goto out; + } + + mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) | + (!!mlx4_blck_lb << MGM_BLCK_LB_BIT)); + + mgm->members_count = cpu_to_be32(members_count | ((u32) prot << 30)); + + err = mlx4_WRITE_MCG(dev, index, mailbox); + if (err) + goto out; + + if (!link) + goto out; + + err = mlx4_READ_MCG(dev, prev, mailbox); + if (err) + goto out; + + mgm->next_gid_index = cpu_to_be32(index << 6); + + err = mlx4_WRITE_MCG(dev, prev, mailbox); + if (err) + goto out; + +out: + if (err && link && index != -1) { + if (index < dev->caps.num_mgms) + mlx4_warn(dev, "Got AMGM index %d < %d", + index, dev->caps.num_mgms); + else + mlx4_bitmap_free(&priv->mcg_table.bitmap, + index - dev->caps.num_mgms); + } + mutex_unlock(&priv->mcg_table.mutex); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_multicast_attach); + +int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + enum mlx4_mcast_prot prot) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mgm *mgm; + u32 members_count; + u16 hash; + int prev, index; + int i, loc; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + mgm = mailbox->buf; + + mutex_lock(&priv->mcg_table.mutex); + + err = find_mgm(dev, gid, prot, mailbox, &hash, &prev, &index); + if (err) + goto out; + + if (index == -1) { + mlx4_err(dev, "MGID %pI6 not found\n", gid); + err = -EINVAL; + goto out; + } + + members_count = be32_to_cpu(mgm->members_count) & 0xffffff; + for (loc = -1, i = 0; i < members_count; ++i) + if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) + loc = i; + + if (loc == -1) { + mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn); + err = -EINVAL; + goto out; + } + + + mgm->members_count = cpu_to_be32(--members_count | ((u32) prot << 30)); + mgm->qp[loc] = mgm->qp[i - 1]; + mgm->qp[i - 1] = 0; + + if (i != 1) { + err = mlx4_WRITE_MCG(dev, index, mailbox); + goto out; + } + + if (prev == -1) { + /* Remove entry from MGM */ + int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; + if (amgm_index) { + err = mlx4_READ_MCG(dev, amgm_index, mailbox); + if (err) + goto out; + } else + memset(mgm->gid, 0, 16); + + err = mlx4_WRITE_MCG(dev, index, mailbox); + if (err) + goto out; + + if (amgm_index) { + if (amgm_index < dev->caps.num_mgms) + mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d", + index, amgm_index, dev->caps.num_mgms); + else + mlx4_bitmap_free(&priv->mcg_table.bitmap, + amgm_index - dev->caps.num_mgms); + } + } else { + /* Remove entry from AMGM */ + int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; + err = mlx4_READ_MCG(dev, prev, mailbox); + if (err) + goto out; + + mgm->next_gid_index = cpu_to_be32(cur_next_index << 6); + + err = mlx4_WRITE_MCG(dev, prev, mailbox); + if (err) + goto out; + + if (index < dev->caps.num_mgms) + mlx4_warn(dev, "entry %d had next AMGM index %d < %d", + prev, index, dev->caps.num_mgms); + else + mlx4_bitmap_free(&priv->mcg_table.bitmap, + index - dev->caps.num_mgms); + } + +out: + mutex_unlock(&priv->mcg_table.mutex); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_multicast_detach); + +int mlx4_init_mcg_table(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + + err = mlx4_bitmap_init(&priv->mcg_table.bitmap, dev->caps.num_amgms, + dev->caps.num_amgms - 1, 0, 0); + if (err) + return err; + + mutex_init(&priv->mcg_table.mutex); + + return 0; +} + +void mlx4_cleanup_mcg_table(struct mlx4_dev *dev) +{ + mlx4_bitmap_cleanup(&mlx4_priv(dev)->mcg_table.bitmap); +} diff --git a/sys/ofed/drivers/net/mlx4/mlx4.h b/sys/ofed/drivers/net/mlx4/mlx4.h new file mode 100644 index 000000000000..d5d3da9a4ff3 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/mlx4.h @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved. + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_H +#define MLX4_H + +#include +#include +#include +#include + +#include +#include +#include + +#define DRV_NAME "mlx4_core" +#define PFX DRV_NAME ": " +#define DRV_VERSION "1.0-ofed1.5.2" +#define DRV_RELDATE "August 4, 2010" + +enum { + MLX4_HCR_BASE = 0x80680, + MLX4_HCR_SIZE = 0x0001c, + MLX4_CLR_INT_SIZE = 0x00008 +}; + +enum { + MLX4_MGM_ENTRY_SIZE = 0x100, + MLX4_QP_PER_MGM = 4 * (MLX4_MGM_ENTRY_SIZE / 16 - 2), + MLX4_MTT_ENTRY_PER_SEG = 8 +}; + +enum { + MLX4_NUM_PDS = 1 << 15 +}; + +enum { + MLX4_CMPT_TYPE_QP = 0, + MLX4_CMPT_TYPE_SRQ = 1, + MLX4_CMPT_TYPE_CQ = 2, + MLX4_CMPT_TYPE_EQ = 3, + MLX4_CMPT_NUM_TYPE +}; + +enum { + MLX4_CMPT_SHIFT = 24, + MLX4_NUM_CMPTS = MLX4_CMPT_NUM_TYPE << MLX4_CMPT_SHIFT +}; + +#ifdef CONFIG_MLX4_DEBUG +extern int mlx4_debug_level; +#else /* CONFIG_MLX4_DEBUG */ +#define mlx4_debug_level (0) +#endif /* CONFIG_MLX4_DEBUG */ + +#define mlx4_dbg(mdev, format, arg...) \ + do { \ + if (mlx4_debug_level) \ + dev_printk(KERN_DEBUG, &mdev->pdev->dev, format, ## arg); \ + } while (0) + +#define mlx4_err(mdev, format, arg...) \ + dev_err(&mdev->pdev->dev, format, ## arg) +#define mlx4_info(mdev, format, arg...) \ + dev_info(&mdev->pdev->dev, format, ## arg) +#define mlx4_warn(mdev, format, arg...) \ + dev_warn(&mdev->pdev->dev, format, ## arg) + +extern int mlx4_blck_lb; + +struct mlx4_bitmap { + u32 last; + u32 top; + u32 max; + u32 reserved_top; + u32 mask; + u32 avail; + spinlock_t lock; + unsigned long *table; +}; + +struct mlx4_buddy { + unsigned long **bits; + unsigned int *num_free; + int max_order; + spinlock_t lock; +}; + +struct mlx4_icm; + +struct mlx4_icm_table { + u64 virt; + int num_icm; + int num_obj; + int obj_size; + int lowmem; + int coherent; + struct mutex mutex; + struct mlx4_icm **icm; +}; + +struct mlx4_eq { + struct mlx4_dev *dev; + void __iomem *doorbell; + int eqn; + u32 cons_index; + u16 irq; + u16 have_irq; + int nent; + int load; + struct mlx4_buf_list *page_list; + struct mlx4_mtt mtt; +}; + +struct mlx4_profile { + int num_qp; + int rdmarc_per_qp; + int num_srq; + int num_cq; + int num_mcg; + int num_mpt; + int num_mtt; +}; + +struct mlx4_fw { + u64 clr_int_base; + u64 catas_offset; + struct mlx4_icm *fw_icm; + struct mlx4_icm *aux_icm; + u32 catas_size; + u16 fw_pages; + u8 clr_int_bar; + u8 catas_bar; +}; + +struct mlx4_cmd { + struct pci_pool *pool; + void __iomem *hcr; + struct mutex hcr_mutex; + struct semaphore poll_sem; + struct semaphore event_sem; + int max_cmds; + spinlock_t context_lock; + int free_head; + struct mlx4_cmd_context *context; + u16 token_mask; + u8 use_events; + u8 toggle; +}; + +struct mlx4_uar_table { + struct mlx4_bitmap bitmap; +}; + +struct mlx4_mr_table { + struct mlx4_bitmap mpt_bitmap; + struct mlx4_buddy mtt_buddy; + u64 mtt_base; + u64 mpt_base; + struct mlx4_icm_table mtt_table; + struct mlx4_icm_table dmpt_table; +}; + +struct mlx4_cq_table { + struct mlx4_bitmap bitmap; + spinlock_t lock; + struct radix_tree_root tree; + struct mlx4_icm_table table; + struct mlx4_icm_table cmpt_table; +}; + +struct mlx4_eq_table { + struct mlx4_bitmap bitmap; + char *irq_names; + void __iomem *clr_int; + void __iomem **uar_map; + u32 clr_mask; + struct mlx4_eq *eq; + struct mlx4_icm_table table; + struct mlx4_icm_table cmpt_table; + int have_irq; + u8 inta_pin; +}; + +struct mlx4_srq_table { + struct mlx4_bitmap bitmap; + spinlock_t lock; + struct mlx4_icm_table table; + struct mlx4_icm_table cmpt_table; +}; + +struct mlx4_qp_table { + struct mlx4_bitmap bitmap; + u32 rdmarc_base; + int rdmarc_shift; + spinlock_t lock; + struct mlx4_icm_table qp_table; + struct mlx4_icm_table auxc_table; + struct mlx4_icm_table altc_table; + struct mlx4_icm_table rdmarc_table; + struct mlx4_icm_table cmpt_table; +}; + +struct mlx4_mcg_table { + struct mutex mutex; + struct mlx4_bitmap bitmap; + struct mlx4_icm_table table; +}; + +struct mlx4_catas_err { + u32 __iomem *map; + struct timer_list timer; + struct list_head list; +}; + +#define MLX4_MAX_MAC_NUM 128 +#define MLX4_MAC_TABLE_SIZE (MLX4_MAX_MAC_NUM << 3) + +struct mlx4_mac_table { + __be64 entries[MLX4_MAX_MAC_NUM]; + int refs[MLX4_MAX_MAC_NUM]; + struct mutex mutex; + int total; + int max; +}; + +#define MLX4_MAX_VLAN_NUM 128 +#define MLX4_VLAN_TABLE_SIZE (MLX4_MAX_VLAN_NUM << 2) + +struct mlx4_vlan_table { + __be32 entries[MLX4_MAX_VLAN_NUM]; + int refs[MLX4_MAX_VLAN_NUM]; + struct mutex mutex; + int total; + int max; +}; + +struct mlx4_port_info { + struct mlx4_dev *dev; + int port; + char dev_name[16]; + struct device_attribute port_attr; + enum mlx4_port_type tmp_type; + struct mlx4_mac_table mac_table; + struct mlx4_vlan_table vlan_table; +}; + +struct mlx4_sense { + struct mlx4_dev *dev; + u8 do_sense_port[MLX4_MAX_PORTS + 1]; + u8 sense_allowed[MLX4_MAX_PORTS + 1]; + struct delayed_work sense_poll; + struct workqueue_struct *sense_wq; + u32 resched; +}; + +extern struct mutex drv_mutex; + +struct mlx4_priv { + struct mlx4_dev dev; + + struct list_head dev_list; + struct list_head ctx_list; + spinlock_t ctx_lock; + + struct list_head pgdir_list; + struct mutex pgdir_mutex; + + struct mlx4_fw fw; + struct mlx4_cmd cmd; + + struct mlx4_bitmap pd_bitmap; + struct mlx4_bitmap xrcd_bitmap; + struct mlx4_uar_table uar_table; + struct mlx4_mr_table mr_table; + struct mlx4_cq_table cq_table; + struct mlx4_eq_table eq_table; + struct mlx4_srq_table srq_table; + struct mlx4_qp_table qp_table; + struct mlx4_mcg_table mcg_table; + struct mlx4_bitmap counters_bitmap; + struct list_head bf_list; + struct mutex bf_mutex; + + struct mlx4_catas_err catas_err; + + void __iomem *clr_base; + + struct mlx4_uar driver_uar; + void __iomem *kar; + struct mlx4_port_info port[MLX4_MAX_PORTS + 1]; + struct device_attribute trigger_attr; + int trig; + int changed_ports; + struct mlx4_sense sense; + struct mutex port_mutex; + int iboe_counter_index[MLX4_MAX_PORTS]; + struct io_mapping *bf_mapping; +}; + +static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) +{ + return container_of(dev, struct mlx4_priv, dev); +} + +#define MLX4_SENSE_RANGE (HZ * 3) + +extern struct workqueue_struct *mlx4_wq; + +u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap); +void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj); +u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align); +void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt); +u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap); +int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, + u32 reserved_bot, u32 resetrved_top); +void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap); + +int mlx4_reset(struct mlx4_dev *dev); + +int mlx4_alloc_eq_table(struct mlx4_dev *dev); +void mlx4_free_eq_table(struct mlx4_dev *dev); + +int mlx4_init_pd_table(struct mlx4_dev *dev); +int mlx4_init_xrcd_table(struct mlx4_dev *dev); +int mlx4_init_uar_table(struct mlx4_dev *dev); +int mlx4_init_mr_table(struct mlx4_dev *dev); +int mlx4_init_eq_table(struct mlx4_dev *dev); +int mlx4_init_cq_table(struct mlx4_dev *dev); +int mlx4_init_qp_table(struct mlx4_dev *dev); +int mlx4_init_srq_table(struct mlx4_dev *dev); +int mlx4_init_mcg_table(struct mlx4_dev *dev); + +void mlx4_cleanup_pd_table(struct mlx4_dev *dev); +void mlx4_cleanup_uar_table(struct mlx4_dev *dev); +void mlx4_cleanup_mr_table(struct mlx4_dev *dev); +void mlx4_cleanup_eq_table(struct mlx4_dev *dev); +void mlx4_cleanup_cq_table(struct mlx4_dev *dev); +void mlx4_cleanup_qp_table(struct mlx4_dev *dev); +void mlx4_cleanup_srq_table(struct mlx4_dev *dev); +void mlx4_cleanup_mcg_table(struct mlx4_dev *dev); +void mlx4_cleanup_xrcd_table(struct mlx4_dev *dev); + +void mlx4_start_catas_poll(struct mlx4_dev *dev); +void mlx4_stop_catas_poll(struct mlx4_dev *dev); +void mlx4_catas_init(void); +int mlx4_restart_one(struct pci_dev *pdev); +int mlx4_register_device(struct mlx4_dev *dev); +void mlx4_unregister_device(struct mlx4_dev *dev); +void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type, int port); +void *mlx4_find_get_prot_dev(struct mlx4_dev *dev, enum mlx4_prot proto, int port); + +struct mlx4_dev_cap; +struct mlx4_init_hca_param; + +u64 mlx4_make_profile(struct mlx4_dev *dev, + struct mlx4_profile *request, + struct mlx4_dev_cap *dev_cap, + struct mlx4_init_hca_param *init_hca); + +int mlx4_cmd_init(struct mlx4_dev *dev); +void mlx4_cmd_cleanup(struct mlx4_dev *dev); +void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param); +int mlx4_cmd_use_events(struct mlx4_dev *dev); +void mlx4_cmd_use_polling(struct mlx4_dev *dev); + +void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn); +void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type); + +void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type); + +void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type); + +void mlx4_handle_catas_err(struct mlx4_dev *dev); + +void mlx4_do_sense_ports(struct mlx4_dev *dev, + enum mlx4_port_type *stype, + enum mlx4_port_type *defaults); +void mlx4_start_sense(struct mlx4_dev *dev); +void mlx4_stop_sense(struct mlx4_dev *dev); +int mlx4_sense_init(struct mlx4_dev *dev); +void mlx4_sense_cleanup(struct mlx4_dev *dev); +int mlx4_check_port_params(struct mlx4_dev *dev, + enum mlx4_port_type *port_type); +int mlx4_change_port_types(struct mlx4_dev *dev, + enum mlx4_port_type *port_types); + +void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table); +void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table); + +int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port); +int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps); + +#endif /* MLX4_H */ diff --git a/sys/ofed/drivers/net/mlx4/mlx4_en.h b/sys/ofed/drivers/net/mlx4/mlx4_en.h new file mode 100644 index 000000000000..6ab258e16ab0 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/mlx4_en.h @@ -0,0 +1,651 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _MLX4_EN_H_ +#define _MLX4_EN_H_ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "en_port.h" + +#define DRV_NAME "mlx4_en" +#define DRV_VERSION "1.5.2" +#define DRV_RELDATE "July 2010" + +/* XXX */ +#define NETIF_MSG_LINK 0x1 +#define NETIF_MSG_IFDOWN 0x2 +#define NETIF_MSG_HW 0x4 +#define NETIF_MSG_DRV 0x8 +#define NETIF_MSG_INTR 0x10 +#define NETIF_MSG_RX_ERR 0x20 + +#define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) + +#define en_print(level, priv, format, arg...) \ + { \ + if ((priv)->registered) \ + printk(level "%s: %s: " format, DRV_NAME, \ + (priv->dev)->if_xname, ## arg); \ + else \ + printk(level "%s: %s: Port %d: " format, \ + DRV_NAME, dev_name(&priv->mdev->pdev->dev), \ + (priv)->port, ## arg); \ + } + +#define en_dbg(mlevel, priv, format, arg...) \ + if (NETIF_MSG_##mlevel & priv->msg_enable) \ + en_print(KERN_DEBUG, priv, format, ## arg) +#define en_warn(priv, format, arg...) \ + en_print(KERN_WARNING, priv, format, ## arg) +#define en_err(priv, format, arg...) \ + en_print(KERN_ERR, priv, format, ## arg) +#define en_info(priv, format, arg...) \ + en_print(KERN_INFO, priv, format, ## arg) + +#define mlx4_err(mdev, format, arg...) \ + printk(KERN_ERR "%s %s: " format , DRV_NAME ,\ + dev_name(&mdev->pdev->dev) , ## arg) +#define mlx4_info(mdev, format, arg...) \ + printk(KERN_INFO "%s %s: " format , DRV_NAME ,\ + dev_name(&mdev->pdev->dev) , ## arg) +#define mlx4_warn(mdev, format, arg...) \ + printk(KERN_WARNING "%s %s: " format , DRV_NAME ,\ + dev_name(&mdev->pdev->dev) , ## arg) + +/* + * Device constants + */ + + +#define MLX4_EN_PAGE_SHIFT 12 +#define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT) +#define MAX_TX_RINGS (MLX4_EN_NUM_HASH_RINGS + 1 + MLX4_EN_NUM_PPP_RINGS) +#define MAX_RX_RINGS 16 +#define TXBB_SIZE 64 +#define HEADROOM (2048 / TXBB_SIZE + 1) +#define STAMP_STRIDE 64 +#define STAMP_DWORDS (STAMP_STRIDE / 4) +#define STAMP_SHIFT 31 +#define STAMP_VAL 0x7fffffff +#define STATS_DELAY (HZ / 4) + +/* Typical TSO descriptor with 16 gather entries is 352 bytes... */ +#define MAX_DESC_SIZE 512 +#define MAX_DESC_TXBBS (MAX_DESC_SIZE / TXBB_SIZE) + +/* + * OS related constants and tunables + */ + +#define MLX4_EN_WATCHDOG_TIMEOUT (15 * HZ) + +#define MLX4_EN_MAX_LRO_DESCRIPTORS 32 +#define MLX4_EN_NUM_IPFRAG_SESSIONS 16 + +/* Receive fragment sizes; we use at most 3 fragments (for 9600 byte MTU + * and 4K allocations) */ +#if MJUMPAGESIZE == 4096 +enum { + FRAG_SZ0 = MCLBYTES, + FRAG_SZ1 = MJUMPAGESIZE, + FRAG_SZ2 = MJUMPAGESIZE, +}; +#define MLX4_EN_MAX_RX_FRAGS 3 +#elif MJUMPAGESIZE == 8192 +enum { + FRAG_SZ0 = MCLBYTES, + FRAG_SZ1 = MJUMPAGESIZE, +}; +#define MLX4_EN_MAX_RX_FRAGS 2 +#elif MJUMPAGESIZE == 8192 +#else +#error "Unknown PAGE_SIZE" +#endif + +/* Maximum ring sizes */ +#define MLX4_EN_MAX_TX_SIZE 8192 +#define MLX4_EN_MAX_RX_SIZE 8192 + +#define MLX4_EN_MIN_RX_SIZE (128) +#define MLX4_EN_MIN_TX_SIZE (4096 / TXBB_SIZE) + +#define MLX4_EN_SMALL_PKT_SIZE 64 +#define MLX4_EN_TX_HASH_SIZE 256 +#define MLX4_EN_TX_HASH_MASK (MLX4_EN_TX_HASH_SIZE - 1) +#define MLX4_EN_NUM_HASH_RINGS 4 +#define MLX4_EN_NUM_PPP_RINGS 8 +#define MLX4_EN_DEF_TX_RING_SIZE 512 +#define MLX4_EN_DEF_TX_QUEUE_SIZE 4096 +#define MLX4_EN_DEF_RX_RING_SIZE 1024 +#define MLX4_EN_MAX_RX_POLL 16 + +/* Target number of bytes to coalesce with interrupt moderation */ +#define MLX4_EN_RX_COAL_TARGET 0x20000 +#define MLX4_EN_RX_COAL_TIME 0x10 + +#define MLX4_EN_TX_COAL_PKTS 5 +#define MLX4_EN_TX_COAL_TIME 0x80 + +#define MLX4_EN_RX_RATE_LOW 400000 +#define MLX4_EN_RX_COAL_TIME_LOW 0 +#define MLX4_EN_RX_RATE_HIGH 450000 +#define MLX4_EN_RX_COAL_TIME_HIGH 128 +#define MLX4_EN_RX_SIZE_THRESH 1024 +#define MLX4_EN_RX_RATE_THRESH (1000000 / MLX4_EN_RX_COAL_TIME_HIGH) +#define MLX4_EN_SAMPLE_INTERVAL 0 +#define MLX4_EN_AVG_PKT_SMALL 256 + +#define MLX4_EN_AUTO_CONF 0xffff + +#define MLX4_EN_DEF_RX_PAUSE 1 +#define MLX4_EN_DEF_TX_PAUSE 1 + +/* Interval between sucessive polls in the Tx routine when polling is used + instead of interrupts (in per-core Tx rings) - should be power of 2 */ +#define MLX4_EN_TX_POLL_MODER 16 +#define MLX4_EN_TX_POLL_TIMEOUT (HZ / 4) + +#define ETH_LLC_SNAP_SIZE 8 + +#define SMALL_PACKET_SIZE (MHLEN) +#define HEADER_COPY_SIZE (128) +#define MLX4_LOOPBACK_TEST_PAYLOAD (HEADER_COPY_SIZE - ETHER_HDR_LEN) + +#define MLX4_EN_MIN_MTU 46 +#define ETH_BCAST 0xffffffffffffULL + +#define MLX4_EN_LOOPBACK_RETRIES 5 +#define MLX4_EN_LOOPBACK_TIMEOUT 100 + +#ifdef MLX4_EN_PERF_STAT +/* Number of samples to 'average' */ +#define AVG_SIZE 128 +#define AVG_FACTOR 1024 +#define NUM_PERF_STATS NUM_PERF_COUNTERS + +#define INC_PERF_COUNTER(cnt) (++(cnt)) +#define ADD_PERF_COUNTER(cnt, add) ((cnt) += (add)) +#define AVG_PERF_COUNTER(cnt, sample) \ + ((cnt) = ((cnt) * (AVG_SIZE - 1) + (sample) * AVG_FACTOR) / AVG_SIZE) +#define GET_PERF_COUNTER(cnt) (cnt) +#define GET_AVG_PERF_COUNTER(cnt) ((cnt) / AVG_FACTOR) + +#else + +#define NUM_PERF_STATS 0 +#define INC_PERF_COUNTER(cnt) do {} while (0) +#define ADD_PERF_COUNTER(cnt, add) do {} while (0) +#define AVG_PERF_COUNTER(cnt, sample) do {} while (0) +#define GET_PERF_COUNTER(cnt) (0) +#define GET_AVG_PERF_COUNTER(cnt) (0) +#endif /* MLX4_EN_PERF_STAT */ + +/* + * Configurables + */ + +enum cq_type { + RX = 0, + TX = 1, +}; + + +/* + * Useful macros + */ +#define ROUNDUP_LOG2(x) ilog2(roundup_pow_of_two(x)) +#define XNOR(x, y) (!(x) == !(y)) +#define ILLEGAL_MAC(addr) (addr == 0xffffffffffffULL || addr == 0x0) + + +struct mlx4_en_tx_info { + struct mbuf *mb; + u32 nr_txbb; + u8 nr_segs; + u8 data_offset; + u8 inl; +}; + + +#define MLX4_EN_BIT_DESC_OWN 0x80000000 +#define CTRL_SIZE sizeof(struct mlx4_wqe_ctrl_seg) +#define MLX4_EN_MEMTYPE_PAD 0x100 +#define DS_SIZE sizeof(struct mlx4_wqe_data_seg) + + +struct mlx4_en_tx_desc { + struct mlx4_wqe_ctrl_seg ctrl; + union { + struct mlx4_wqe_data_seg data; /* at least one data segment */ + struct mlx4_wqe_lso_seg lso; + struct mlx4_wqe_inline_seg inl; + }; +}; + +#define MLX4_EN_USE_SRQ 0x01000000 + +struct mlx4_en_tx_ring { + spinlock_t tx_lock; + struct mlx4_hwq_resources wqres; + u32 size ; /* number of TXBBs */ + u32 size_mask; + u16 stride; + u16 cqn; /* index of port CQ associated with this ring */ + u32 prod; + u32 cons; + u32 buf_size; + u32 doorbell_qpn; + void *buf; + u16 poll_cnt; + int blocked; + struct buf_ring *br; + struct mlx4_en_tx_info *tx_info; + u8 *bounce_buf; + u32 last_nr_txbb; + struct mlx4_qp qp; + struct mlx4_qp_context context; + int qpn; + enum mlx4_qp_state qp_state; + struct mlx4_srq dummy; + unsigned long bytes; + unsigned long packets; + unsigned long errors; + spinlock_t comp_lock; + struct mlx4_bf bf; + bool bf_enabled; + u64 watchdog_time; +}; + +struct mlx4_en_ipfrag { + struct mbuf *fragments; + struct mbuf *last; + __be32 saddr; + __be32 daddr; + __be16 id; + u8 protocol; + int total_len; + u16 offset; +}; + +struct mlx4_en_rx_desc { + /* actual number of entries depends on rx ring stride */ + struct mlx4_wqe_data_seg data[0]; +}; + +struct mlx4_en_rx_ring { + struct mlx4_hwq_resources wqres; + u32 size ; /* number of Rx descs*/ + u32 actual_size; + u32 size_mask; + u16 stride; + u16 log_stride; + u16 cqn; /* index of port CQ associated with this ring */ + u32 prod; + u32 cons; + u32 buf_size; + void *buf; + void *rx_info; + unsigned long bytes; + unsigned long packets; + unsigned long errors; + unsigned int use_frags; + struct lro_ctrl lro; + struct mlx4_en_ipfrag ipfrag[MLX4_EN_NUM_IPFRAG_SESSIONS]; +}; + + +static inline int mlx4_en_can_lro(__be16 status) +{ + return (status & cpu_to_be16(MLX4_CQE_STATUS_IPV4 | + MLX4_CQE_STATUS_IPV4F | + MLX4_CQE_STATUS_IPV6 | + MLX4_CQE_STATUS_IPV4OPT | + MLX4_CQE_STATUS_TCP | + MLX4_CQE_STATUS_UDP | + MLX4_CQE_STATUS_IPOK)) == + cpu_to_be16(MLX4_CQE_STATUS_IPV4 | + MLX4_CQE_STATUS_IPOK | + MLX4_CQE_STATUS_TCP); +} + +struct mlx4_en_cq { + struct mlx4_cq mcq; + struct mlx4_hwq_resources wqres; + int ring; + spinlock_t lock; + struct net_device *dev; + /* Per-core Tx cq processing support */ + struct timer_list timer; + int size; + int buf_size; + unsigned vector; + enum cq_type is_tx; + u16 moder_time; + u16 moder_cnt; + struct mlx4_cqe *buf; + struct task cq_task; + struct taskqueue *tq; +#define MLX4_EN_OPCODE_ERROR 0x1e + u32 tot_rx; +}; + +struct mlx4_en_port_profile { + u32 flags; + u32 tx_ring_num; + u32 rx_ring_num; + u32 tx_ring_size; + u32 rx_ring_size; + u8 rx_pause; + u8 rx_ppp; + u8 tx_pause; + u8 tx_ppp; +}; + +struct mlx4_en_profile { + int rss_xor; + int num_lro; + int ip_reasm; + int tcp_rss; + int udp_rss; + u8 rss_mask; + u32 active_ports; + u32 small_pkt_int; + u8 no_reset; + struct mlx4_en_port_profile prof[MLX4_MAX_PORTS + 1]; +}; + +struct mlx4_en_dev { + struct mlx4_dev *dev; + struct pci_dev *pdev; + struct mutex state_lock; + struct net_device *pndev[MLX4_MAX_PORTS + 1]; + u32 port_cnt; + bool device_up; + struct mlx4_en_profile profile; + u32 LSO_support; + struct workqueue_struct *workqueue; + struct device *dma_device; + void __iomem *uar_map; + struct mlx4_uar priv_uar; + struct mlx4_mr mr; + u32 priv_pdn; + spinlock_t uar_lock; + u8 mac_removed[MLX4_MAX_PORTS + 1]; +}; + + +struct mlx4_en_rss_map { + int base_qpn; + struct mlx4_qp qps[MAX_RX_RINGS]; + enum mlx4_qp_state state[MAX_RX_RINGS]; + struct mlx4_qp indir_qp; + enum mlx4_qp_state indir_state; +}; + +struct mlx4_en_rss_context { + __be32 base_qpn; + __be32 default_qpn; + u16 reserved; + u8 hash_fn; + u8 flags; + __be32 rss_key[10]; + __be32 base_qpn_udp; +}; + +struct mlx4_en_port_state { + int link_state; + int link_speed; + int transciver; +}; + +struct mlx4_en_pkt_stats { + unsigned long broadcast; + unsigned long rx_prio[8]; + unsigned long tx_prio[8]; +#define NUM_PKT_STATS 17 +}; + +struct mlx4_en_port_stats { + unsigned long tso_packets; + unsigned long queue_stopped; + unsigned long wake_queue; + unsigned long tx_timeout; + unsigned long rx_alloc_failed; + unsigned long rx_chksum_good; + unsigned long rx_chksum_none; + unsigned long tx_chksum_offload; +}; + +struct mlx4_en_perf_stats { + u32 tx_poll; + u64 tx_pktsz_avg; + u32 inflight_avg; + u32 tx_coal_avg; + u32 rx_coal_avg; +}; + +struct mlx4_en_frag_info { + u16 frag_size; + u16 frag_prefix_size; +}; + +struct mlx4_en_tx_hash_entry { + u8 cnt; + unsigned int small_pkts; + unsigned int big_pkts; + unsigned int ring; +}; + +struct mlx4_en_priv { + struct mlx4_en_dev *mdev; + struct mlx4_en_port_profile *prof; + struct net_device *dev; + bool vlgrp_modified; + u32 vlan_register[VLAN_FLTR_SIZE]; + u32 vlan_unregister[VLAN_FLTR_SIZE]; + u32 vlans[VLAN_FLTR_SIZE]; + spinlock_t vlan_lock; + struct mlx4_en_port_state port_state; + spinlock_t stats_lock; + + unsigned long last_moder_packets; + unsigned long last_moder_tx_packets; + unsigned long last_moder_bytes; + unsigned long last_moder_jiffies; + int last_moder_time; + u16 rx_usecs; + u16 rx_frames; + u16 tx_usecs; + u16 tx_frames; + u32 pkt_rate_low; + u16 rx_usecs_low; + u32 pkt_rate_high; + u16 rx_usecs_high; + u16 sample_interval; + u16 adaptive_rx_coal; + u32 msg_enable; + u32 loopback_ok; + u32 validate_loopback; + + struct mlx4_hwq_resources res; + int link_state; + int last_link_state; + bool port_up; + int port; + int registered; + int allocated; + int rx_csum; + u64 mac; + int mac_index; + unsigned max_mtu; + int base_qpn; + + struct mlx4_en_rss_map rss_map; + u16 tx_prio_map[8]; + u32 flags; +#define MLX4_EN_FLAG_PROMISC 0x1 + u32 tx_ring_num; + u32 rx_ring_num; + u32 udp_rings; + u32 rx_mb_size; + struct mlx4_en_frag_info frag_info[MLX4_EN_MAX_RX_FRAGS]; + u16 num_frags; + u16 log_rx_info; + + struct mlx4_en_tx_ring tx_ring[MAX_TX_RINGS]; + struct mlx4_en_rx_ring rx_ring[MAX_RX_RINGS]; + struct mlx4_en_cq tx_cq[MAX_TX_RINGS]; + struct mlx4_en_cq rx_cq[MAX_RX_RINGS]; + struct mlx4_en_tx_hash_entry tx_hash[MLX4_EN_TX_HASH_SIZE]; + struct work_struct mcast_task; + struct work_struct watchdog_task; + struct work_struct linkstate_task; + struct delayed_work stats_task; + struct mlx4_en_perf_stats pstats; + struct mlx4_en_pkt_stats pkstats; + struct mlx4_en_port_stats port_stats; + struct mlx4_en_stat_out_mbox hw_stats; + struct ifmedia media; + eventhandler_tag vlan_attach; + eventhandler_tag vlan_detach; + struct callout watchdog_timer; + volatile int blocked; + struct sysctl_oid *sysctl; + struct sysctl_ctx_list conf_ctx; + struct sysctl_ctx_list stat_ctx; +}; + + +int mlx4_en_transmit(struct net_device *dev, struct mbuf *mb); +void mlx4_en_qflush(struct net_device *dev); + +int mlx4_en_rx_frags(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring *ring, + struct mbuf *mb, struct mlx4_cqe *cqe); +void mlx4_en_flush_frags(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring); +void mlx4_en_destroy_netdev(struct net_device *dev); +int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, + struct mlx4_en_port_profile *prof); + +int mlx4_en_start_port(struct net_device *dev); +void mlx4_en_stop_port(struct net_device *dev); + +void mlx4_en_free_resources(struct mlx4_en_priv *priv); +int mlx4_en_alloc_resources(struct mlx4_en_priv *priv); + +int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, + int entries, int ring, enum cq_type mode); +void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); +int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); +void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); +int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); +int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); + +void mlx4_en_poll_tx_cq(unsigned long data); +void mlx4_en_tx_irq(struct mlx4_cq *mcq); +u16 mlx4_en_select_queue(struct net_device *dev, struct mbuf *mb); + +int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, + u32 size, u16 stride); +void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring); +int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, + struct mlx4_en_tx_ring *ring, + int cq); +void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, + struct mlx4_en_tx_ring *ring); + +int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring, u32 size); +void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring); +int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv); +void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv, + struct mlx4_en_rx_ring *ring); +int mlx4_en_process_rx_cq(struct net_device *dev, + struct mlx4_en_cq *cq, + int budget); +int mlx4_en_process_rx_cq_mb(struct net_device *dev, + struct mlx4_en_cq *cq, + int budget); +void mlx4_en_tx_que(void *context, int pending); +void mlx4_en_rx_que(void *context, int pending); +void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride, + int is_tx, int rss, int qpn, int cqn, + struct mlx4_qp_context *context); +void mlx4_en_sqp_event(struct mlx4_qp *qp, enum mlx4_event event); +int mlx4_en_map_buffer(struct mlx4_buf *buf); +void mlx4_en_unmap_buffer(struct mlx4_buf *buf); + +void mlx4_en_calc_rx_buf(struct net_device *dev); +void mlx4_en_set_prio_map(struct mlx4_en_priv *priv, u16 *prio_map, u32 ring_num); +int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv); +void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv); +int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring); +void mlx4_en_rx_irq(struct mlx4_cq *mcq); + +int mlx4_SET_MCAST_FLTR(struct mlx4_dev *dev, u8 port, u64 mac, u64 clear, u8 mode); +int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, u8 port, u32 *vlans); +int mlx4_SET_PORT_general(struct mlx4_dev *dev, u8 port, int mtu, + u8 pptx, u8 pfctx, u8 pprx, u8 pfcrx); +int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, + u8 promisc); + +int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset); +int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port); + +#define MLX4_EN_NUM_SELF_TEST 5 +void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf); +u64 mlx4_en_mac_to_u64(u8 *addr); + +/* + * Globals + */ +extern const struct ethtool_ops mlx4_en_ethtool_ops; +#endif diff --git a/sys/ofed/drivers/net/mlx4/mr.c b/sys/ofed/drivers/net/mlx4/mr.c new file mode 100644 index 000000000000..9ed610aa4cfb --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/mr.c @@ -0,0 +1,773 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include + +#include "mlx4.h" +#include "icm.h" + +/* + * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits. + */ +struct mlx4_mpt_entry { + __be32 flags; + __be32 qpn; + __be32 key; + __be32 pd_flags; + __be64 start; + __be64 length; + __be32 lkey; + __be32 win_cnt; + u8 reserved1; + u8 flags2; + u8 reserved2; + u8 mtt_rep; + __be64 mtt_seg; + __be32 mtt_sz; + __be32 entity_size; + __be32 first_byte_offset; +} __attribute__((packed)); + +#define MLX4_MPT_FLAG_SW_OWNS (0xfUL << 28) +#define MLX4_MPT_FLAG_FREE (0x3UL << 28) +#define MLX4_MPT_FLAG_MIO (1 << 17) +#define MLX4_MPT_FLAG_BIND_ENABLE (1 << 15) +#define MLX4_MPT_FLAG_PHYSICAL (1 << 9) +#define MLX4_MPT_FLAG_REGION (1 << 8) + +#define MLX4_MPT_PD_FLAG_FAST_REG (1 << 27) +#define MLX4_MPT_PD_FLAG_RAE (1 << 28) +#define MLX4_MPT_PD_FLAG_EN_INV (3 << 24) + +#define MLX4_MPT_FLAG2_FBO_EN (1 << 7) + +#define MLX4_MPT_STATUS_SW 0xF0 +#define MLX4_MPT_STATUS_HW 0x00 + +static u32 mlx4_buddy_alloc(struct mlx4_buddy *buddy, int order) +{ + int o; + int m; + u32 seg; + + spin_lock(&buddy->lock); + + for (o = order; o <= buddy->max_order; ++o) + if (buddy->num_free[o]) { + m = 1 << (buddy->max_order - o); + seg = find_first_bit(buddy->bits[o], m); + if (seg < m) + goto found; + } + + spin_unlock(&buddy->lock); + return -1; + + found: + clear_bit(seg, buddy->bits[o]); + --buddy->num_free[o]; + + while (o > order) { + --o; + seg <<= 1; + set_bit(seg ^ 1, buddy->bits[o]); + ++buddy->num_free[o]; + } + + spin_unlock(&buddy->lock); + + seg <<= order; + + return seg; +} + +static void mlx4_buddy_free(struct mlx4_buddy *buddy, u32 seg, int order) +{ + seg >>= order; + + spin_lock(&buddy->lock); + + while (test_bit(seg ^ 1, buddy->bits[order])) { + clear_bit(seg ^ 1, buddy->bits[order]); + --buddy->num_free[order]; + seg >>= 1; + ++order; + } + + set_bit(seg, buddy->bits[order]); + ++buddy->num_free[order]; + + spin_unlock(&buddy->lock); +} + +static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order) +{ + int i, s; + + buddy->max_order = max_order; + spin_lock_init(&buddy->lock); + + buddy->bits = kzalloc((buddy->max_order + 1) * sizeof (long *), + GFP_KERNEL); + buddy->num_free = kzalloc((buddy->max_order + 1) * sizeof (int *), + GFP_KERNEL); + if (!buddy->bits || !buddy->num_free) + goto err_out; + + for (i = 0; i <= buddy->max_order; ++i) { + s = BITS_TO_LONGS(1 << (buddy->max_order - i)); + buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL); + if (!buddy->bits[i]) + goto err_out_free; + bitmap_zero(buddy->bits[i], 1 << (buddy->max_order - i)); + } + + set_bit(0, buddy->bits[buddy->max_order]); + buddy->num_free[buddy->max_order] = 1; + + return 0; + +err_out_free: + for (i = 0; i <= buddy->max_order; ++i) + kfree(buddy->bits[i]); + +err_out: + kfree(buddy->bits); + kfree(buddy->num_free); + + return -ENOMEM; +} + +static void mlx4_buddy_cleanup(struct mlx4_buddy *buddy) +{ + int i; + + for (i = 0; i <= buddy->max_order; ++i) + kfree(buddy->bits[i]); + + kfree(buddy->bits); + kfree(buddy->num_free); +} + +static u32 mlx4_alloc_mtt_range(struct mlx4_dev *dev, int order) +{ + struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; + u32 seg; + + seg = mlx4_buddy_alloc(&mr_table->mtt_buddy, order); + if (seg == -1) + return -1; + + if (mlx4_table_get_range(dev, &mr_table->mtt_table, seg, + seg + (1 << order) - 1)) { + mlx4_buddy_free(&mr_table->mtt_buddy, seg, order); + return -1; + } + + return seg; +} + +int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift, + struct mlx4_mtt *mtt) +{ + int i; + + if (!npages) { + mtt->order = -1; + mtt->page_shift = MLX4_ICM_PAGE_SHIFT; + return 0; + } else + mtt->page_shift = page_shift; + + for (mtt->order = 0, i = dev->caps.mtts_per_seg; i < npages; i <<= 1) + ++mtt->order; + + mtt->first_seg = mlx4_alloc_mtt_range(dev, mtt->order); + if (mtt->first_seg == -1) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_mtt_init); + +void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt) +{ + struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; + + if (mtt->order < 0) + return; + + mlx4_buddy_free(&mr_table->mtt_buddy, mtt->first_seg, mtt->order); + mlx4_table_put_range(dev, &mr_table->mtt_table, mtt->first_seg, + mtt->first_seg + (1 << mtt->order) - 1); +} +EXPORT_SYMBOL_GPL(mlx4_mtt_cleanup); + +u64 mlx4_mtt_addr(struct mlx4_dev *dev, struct mlx4_mtt *mtt) +{ + return (u64) mtt->first_seg * dev->caps.mtt_entry_sz; +} +EXPORT_SYMBOL_GPL(mlx4_mtt_addr); + +static u32 hw_index_to_key(u32 ind) +{ + return (ind >> 24) | (ind << 8); +} + +static u32 key_to_hw_index(u32 key) +{ + return (key << 24) | (key >> 8); +} + +static int mlx4_SW2HW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int mpt_index) +{ + return mlx4_cmd(dev, mailbox->dma, mpt_index, 0, MLX4_CMD_SW2HW_MPT, + MLX4_CMD_TIME_CLASS_B); +} + +static int mlx4_HW2SW_MPT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int mpt_index) +{ + return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index, + !mailbox, MLX4_CMD_HW2SW_MPT, MLX4_CMD_TIME_CLASS_B); +} + +int mlx4_mr_reserve_range(struct mlx4_dev *dev, int cnt, int align, u32 *base_mridx) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + u32 mridx; + + mridx = mlx4_bitmap_alloc_range(&priv->mr_table.mpt_bitmap, cnt, align); + if (mridx == -1) + return -ENOMEM; + + *base_mridx = mridx; + return 0; + +} +EXPORT_SYMBOL_GPL(mlx4_mr_reserve_range); + +void mlx4_mr_release_range(struct mlx4_dev *dev, u32 base_mridx, int cnt) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + mlx4_bitmap_free_range(&priv->mr_table.mpt_bitmap, base_mridx, cnt); +} +EXPORT_SYMBOL_GPL(mlx4_mr_release_range); + +int mlx4_mr_alloc_reserved(struct mlx4_dev *dev, u32 mridx, u32 pd, + u64 iova, u64 size, u32 access, int npages, + int page_shift, struct mlx4_mr *mr) +{ + mr->iova = iova; + mr->size = size; + mr->pd = pd; + mr->access = access; + mr->enabled = 0; + mr->key = hw_index_to_key(mridx); + + return mlx4_mtt_init(dev, npages, page_shift, &mr->mtt); +} +EXPORT_SYMBOL_GPL(mlx4_mr_alloc_reserved); + +int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access, + int npages, int page_shift, struct mlx4_mr *mr) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + u32 index; + int err; + + index = mlx4_bitmap_alloc(&priv->mr_table.mpt_bitmap); + if (index == -1) + return -ENOMEM; + + err = mlx4_mr_alloc_reserved(dev, index, pd, iova, size, + access, npages, page_shift, mr); + if (err) + mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index); + + return err; +} +EXPORT_SYMBOL_GPL(mlx4_mr_alloc); + +void mlx4_mr_free_reserved(struct mlx4_dev *dev, struct mlx4_mr *mr) +{ + int err; + + if (mr->enabled) { + err = mlx4_HW2SW_MPT(dev, NULL, + key_to_hw_index(mr->key) & + (dev->caps.num_mpts - 1)); + if (err) + mlx4_warn(dev, "HW2SW_MPT failed (%d)\n", err); + } + + mlx4_mtt_cleanup(dev, &mr->mtt); +} +EXPORT_SYMBOL_GPL(mlx4_mr_free_reserved); + +void mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + mlx4_mr_free_reserved(dev, mr); + mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, key_to_hw_index(mr->key)); +} +EXPORT_SYMBOL_GPL(mlx4_mr_free); + +int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr) +{ + struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mpt_entry *mpt_entry; + int err; + + err = mlx4_table_get(dev, &mr_table->dmpt_table, key_to_hw_index(mr->key)); + if (err) + return err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto err_table; + } + mpt_entry = mailbox->buf; + + memset(mpt_entry, 0, sizeof *mpt_entry); + + mpt_entry->flags = cpu_to_be32(MLX4_MPT_FLAG_MIO | + MLX4_MPT_FLAG_REGION | + mr->access); + + mpt_entry->key = cpu_to_be32(key_to_hw_index(mr->key)); + mpt_entry->pd_flags = cpu_to_be32(mr->pd | MLX4_MPT_PD_FLAG_EN_INV); + mpt_entry->start = cpu_to_be64(mr->iova); + mpt_entry->length = cpu_to_be64(mr->size); + mpt_entry->entity_size = cpu_to_be32(mr->mtt.page_shift); + + if (mr->mtt.order < 0) { + mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_PHYSICAL); + mpt_entry->mtt_seg = 0; + } else { + mpt_entry->mtt_seg = cpu_to_be64(mlx4_mtt_addr(dev, &mr->mtt)); + } + + if (mr->mtt.order >= 0 && mr->mtt.page_shift == 0) { + /* fast register MR in free state */ + mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_FREE); + mpt_entry->pd_flags |= cpu_to_be32(MLX4_MPT_PD_FLAG_FAST_REG | + MLX4_MPT_PD_FLAG_RAE); + mpt_entry->mtt_sz = cpu_to_be32((1 << mr->mtt.order) * + dev->caps.mtts_per_seg); + } else { + mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_SW_OWNS); + } + + err = mlx4_SW2HW_MPT(dev, mailbox, + key_to_hw_index(mr->key) & (dev->caps.num_mpts - 1)); + if (err) { + mlx4_warn(dev, "SW2HW_MPT failed (%d)\n", err); + goto err_cmd; + } + + mr->enabled = 1; + + mlx4_free_cmd_mailbox(dev, mailbox); + + return 0; + +err_cmd: + mlx4_free_cmd_mailbox(dev, mailbox); + +err_table: + mlx4_table_put(dev, &mr_table->dmpt_table, key_to_hw_index(mr->key)); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_mr_enable); + +static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + int start_index, int npages, u64 *page_list) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + __be64 *mtts; + dma_addr_t dma_handle; + int i; + int s = start_index * sizeof (u64); + + /* All MTTs must fit in the same page */ + if (start_index / (PAGE_SIZE / sizeof (u64)) != + (start_index + npages - 1) / (PAGE_SIZE / sizeof (u64))) + return -EINVAL; + + if (start_index & (dev->caps.mtts_per_seg - 1)) + return -EINVAL; + + mtts = mlx4_table_find(&priv->mr_table.mtt_table, mtt->first_seg + + s / dev->caps.mtt_entry_sz, &dma_handle); + if (!mtts) + return -ENOMEM; + + for (i = 0; i < npages; ++i) + mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); + + dma_sync_single(&dev->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE); + + return 0; +} + +int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + int start_index, int npages, u64 *page_list) +{ + int chunk; + int err; + + if (mtt->order < 0) + return -EINVAL; + + while (npages > 0) { + chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages); + err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list); + if (err) + return err; + + npages -= chunk; + start_index += chunk; + page_list += chunk; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_write_mtt); + +int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + struct mlx4_buf *buf) +{ + u64 *page_list; + int err; + int i; + + page_list = kmalloc(buf->npages * sizeof *page_list, GFP_KERNEL); + if (!page_list) + return -ENOMEM; + + for (i = 0; i < buf->npages; ++i) + if (buf->direct.map) + page_list[i] = buf->direct.map + (i << buf->page_shift); + else + page_list[i] = buf->page_list[i].map; + + err = mlx4_write_mtt(dev, mtt, 0, buf->npages, page_list); + + kfree(page_list); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_buf_write_mtt); + +int mlx4_init_mr_table(struct mlx4_dev *dev) +{ + struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; + int err; + + if (!is_power_of_2(dev->caps.num_mpts)) + return -EINVAL; + + err = mlx4_bitmap_init(&mr_table->mpt_bitmap, dev->caps.num_mpts, + ~0, dev->caps.reserved_mrws, 0); + if (err) + return err; + + err = mlx4_buddy_init(&mr_table->mtt_buddy, + ilog2(dev->caps.num_mtt_segs)); + if (err) + goto err_buddy; + + if (dev->caps.reserved_mtts) { + if (mlx4_alloc_mtt_range(dev, fls(dev->caps.reserved_mtts - 1)) == -1) { + mlx4_warn(dev, "MTT table of order %d is too small.\n", + mr_table->mtt_buddy.max_order); + err = -ENOMEM; + goto err_reserve_mtts; + } + } + + return 0; + +err_reserve_mtts: + mlx4_buddy_cleanup(&mr_table->mtt_buddy); + +err_buddy: + mlx4_bitmap_cleanup(&mr_table->mpt_bitmap); + + return err; +} + +void mlx4_cleanup_mr_table(struct mlx4_dev *dev) +{ + struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table; + + mlx4_buddy_cleanup(&mr_table->mtt_buddy); + mlx4_bitmap_cleanup(&mr_table->mpt_bitmap); +} + +static inline int mlx4_check_fmr(struct mlx4_fmr *fmr, u64 *page_list, + int npages, u64 iova) +{ + int i, page_mask; + + if (npages > fmr->max_pages) + return -EINVAL; + + page_mask = (1 << fmr->page_shift) - 1; + + /* We are getting page lists, so va must be page aligned. */ + if (iova & page_mask) + return -EINVAL; + + /* Trust the user not to pass misaligned data in page_list */ + if (0) + for (i = 0; i < npages; ++i) { + if (page_list[i] & ~page_mask) + return -EINVAL; + } + + if (fmr->maps >= fmr->max_maps) + return -EINVAL; + + return 0; +} + +int mlx4_map_phys_fmr_fbo(struct mlx4_dev *dev, struct mlx4_fmr *fmr, + u64 *page_list, int npages, u64 iova, u32 fbo, + u32 len, u32 *lkey, u32 *rkey, int same_key) +{ + u32 key; + int i, err; + + err = mlx4_check_fmr(fmr, page_list, npages, iova); + if (err) + return err; + + ++fmr->maps; + + key = key_to_hw_index(fmr->mr.key); + if (!same_key) + key += dev->caps.num_mpts; + *lkey = *rkey = fmr->mr.key = hw_index_to_key(key); + + *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; + + /* Make sure MPT status is visible before writing MTT entries */ + wmb(); + + for (i = 0; i < npages; ++i) + fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT); + + dma_sync_single(&dev->pdev->dev, fmr->dma_handle, + npages * sizeof(u64), DMA_TO_DEVICE); + + fmr->mpt->key = cpu_to_be32(key); + fmr->mpt->lkey = cpu_to_be32(key); + fmr->mpt->length = cpu_to_be64(len); + fmr->mpt->start = cpu_to_be64(iova); + fmr->mpt->first_byte_offset = cpu_to_be32(fbo & 0x001fffff); + fmr->mpt->flags2 = (fbo ? MLX4_MPT_FLAG2_FBO_EN : 0); + + /* Make MTT entries are visible before setting MPT status */ + wmb(); + + *(u8 *) fmr->mpt = MLX4_MPT_STATUS_HW; + + /* Make sure MPT status is visible before consumer can use FMR */ + wmb(); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_map_phys_fmr_fbo); + +int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list, + int npages, u64 iova, u32 *lkey, u32 *rkey) +{ + u32 len = npages * (1ull << fmr->page_shift); + + return mlx4_map_phys_fmr_fbo(dev, fmr, page_list, npages, iova, 0, + len, lkey, rkey, 0); +} +EXPORT_SYMBOL_GPL(mlx4_map_phys_fmr); + +int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, + int max_maps, u8 page_shift, struct mlx4_fmr *fmr) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + u64 mtt_seg; + int err = -ENOMEM; + + if (page_shift < (ffs(dev->caps.page_size_cap) - 1) || page_shift >= 32) + return -EINVAL; + + /* All MTTs must fit in the same page */ + if (max_pages * sizeof *fmr->mtts > PAGE_SIZE) + return -EINVAL; + + fmr->page_shift = page_shift; + fmr->max_pages = max_pages; + fmr->max_maps = max_maps; + fmr->maps = 0; + + err = mlx4_mr_alloc(dev, pd, 0, 0, access, max_pages, + page_shift, &fmr->mr); + if (err) + return err; + + mtt_seg = fmr->mr.mtt.first_seg * dev->caps.mtt_entry_sz; + + fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table, + fmr->mr.mtt.first_seg, + &fmr->dma_handle); + if (!fmr->mtts) { + err = -ENOMEM; + goto err_free; + } + + return 0; + +err_free: + mlx4_mr_free(dev, &fmr->mr); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_alloc); + +int mlx4_fmr_alloc_reserved(struct mlx4_dev *dev, u32 mridx, + u32 pd, u32 access, int max_pages, + int max_maps, u8 page_shift, struct mlx4_fmr *fmr) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + u64 mtt_seg; + int err = -ENOMEM; + + if (page_shift < (ffs(dev->caps.page_size_cap) - 1) || page_shift >= 32) + return -EINVAL; + + /* All MTTs must fit in the same page */ + if (max_pages * sizeof *fmr->mtts > PAGE_SIZE) + return -EINVAL; + + fmr->page_shift = page_shift; + fmr->max_pages = max_pages; + fmr->max_maps = max_maps; + fmr->maps = 0; + + err = mlx4_mr_alloc_reserved(dev, mridx, pd, 0, 0, access, max_pages, + page_shift, &fmr->mr); + if (err) + return err; + + mtt_seg = fmr->mr.mtt.first_seg * dev->caps.mtt_entry_sz; + + fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table, + fmr->mr.mtt.first_seg, + &fmr->dma_handle); + if (!fmr->mtts) { + err = -ENOMEM; + goto err_free; + } + + return 0; + +err_free: + mlx4_mr_free_reserved(dev, &fmr->mr); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_alloc_reserved); + +int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + + err = mlx4_mr_enable(dev, &fmr->mr); + if (err) + return err; + + fmr->mpt = mlx4_table_find(&priv->mr_table.dmpt_table, + key_to_hw_index(fmr->mr.key), NULL); + if (!fmr->mpt) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_enable); + +void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, + u32 *lkey, u32 *rkey) +{ + if (!fmr->maps) + return; + + fmr->maps = 0; + + *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_unmap); + +int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr) +{ + if (fmr->maps) + return -EBUSY; + + fmr->mr.enabled = 0; + mlx4_mr_free(dev, &fmr->mr); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_free); + +int mlx4_fmr_free_reserved(struct mlx4_dev *dev, struct mlx4_fmr *fmr) +{ + if (fmr->maps) + return -EBUSY; + + fmr->mr.enabled = 0; + mlx4_mr_free_reserved(dev, &fmr->mr); + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_fmr_free_reserved); + +int mlx4_SYNC_TPT(struct mlx4_dev *dev) +{ + return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000); +} +EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT); diff --git a/sys/ofed/drivers/net/mlx4/pd.c b/sys/ofed/drivers/net/mlx4/pd.c new file mode 100644 index 000000000000..cce922671273 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/pd.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include + +#include "mlx4.h" +#include "icm.h" + +enum { + MLX4_NUM_RESERVED_UARS = 8 +}; + +int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + *pdn = mlx4_bitmap_alloc(&priv->pd_bitmap); + if (*pdn == -1) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_pd_alloc); + +void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn) +{ + mlx4_bitmap_free(&mlx4_priv(dev)->pd_bitmap, pdn); +} +EXPORT_SYMBOL_GPL(mlx4_pd_free); + +int mlx4_init_pd_table(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + return mlx4_bitmap_init(&priv->pd_bitmap, dev->caps.num_pds, + (1 << 24) - 1, dev->caps.reserved_pds, 0); +} + +void mlx4_cleanup_pd_table(struct mlx4_dev *dev) +{ + mlx4_bitmap_cleanup(&mlx4_priv(dev)->pd_bitmap); +} + + +int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar) +{ + uar->index = mlx4_bitmap_alloc(&mlx4_priv(dev)->uar_table.bitmap); + if (uar->index == -1) + return -ENOMEM; + + uar->pfn = (pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + uar->index; + uar->map = NULL; + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_uar_alloc); + +void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar) +{ + mlx4_bitmap_free(&mlx4_priv(dev)->uar_table.bitmap, uar->index); +} +EXPORT_SYMBOL_GPL(mlx4_uar_free); + +int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_uar *uar; + int err = 0; + int idx; + + if (!priv->bf_mapping) + return -ENOMEM; + + mutex_lock(&priv->bf_mutex); + if (!list_empty(&priv->bf_list)) + uar = list_entry(priv->bf_list.next, struct mlx4_uar, bf_list); + else { + if (mlx4_bitmap_avail(&priv->uar_table.bitmap) < MLX4_NUM_RESERVED_UARS) { + err = -ENOMEM; + goto out; + } + uar = kmalloc(sizeof *uar, GFP_KERNEL); + if (!uar) { + err = -ENOMEM; + goto out; + } + err = mlx4_uar_alloc(dev, uar); + if (err) + goto free_kmalloc; + + uar->map = ioremap(uar->pfn << PAGE_SHIFT, PAGE_SIZE); + if (!uar->map) { + err = -ENOMEM; + goto free_uar; + } + + uar->bf_map = io_mapping_map_wc(priv->bf_mapping, uar->index << PAGE_SHIFT); + if (!uar->bf_map) { + err = -ENOMEM; + goto unamp_uar; + } + uar->free_bf_bmap = 0; + list_add(&uar->bf_list, &priv->bf_list); + } + + bf->uar = uar; + idx = ffz(uar->free_bf_bmap); + uar->free_bf_bmap |= 1 << idx; + bf->uar = uar; + bf->offset = 0; + bf->buf_size = dev->caps.bf_reg_size / 2; + bf->reg = uar->bf_map + idx * dev->caps.bf_reg_size; + if (uar->free_bf_bmap == (1 << dev->caps.bf_regs_per_page) - 1) + list_del_init(&uar->bf_list); + + goto out; + +unamp_uar: + bf->uar = NULL; + iounmap(uar->map); + +free_uar: + mlx4_uar_free(dev, uar); + +free_kmalloc: + kfree(uar); + +out: + mutex_unlock(&priv->bf_mutex); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_bf_alloc); + +void mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int idx; + + if (!bf->uar || !bf->uar->bf_map) + return; + + mutex_lock(&priv->bf_mutex); + idx = (bf->reg - bf->uar->bf_map) / dev->caps.bf_reg_size; + bf->uar->free_bf_bmap &= ~(1 << idx); + if (!bf->uar->free_bf_bmap) { + if (!list_empty(&bf->uar->bf_list)) + list_del(&bf->uar->bf_list); + + io_mapping_unmap(bf->uar->bf_map); + iounmap(bf->uar->map); + mlx4_uar_free(dev, bf->uar); + kfree(bf->uar); + } else if (list_empty(&bf->uar->bf_list)) + list_add(&bf->uar->bf_list, &priv->bf_list); + + mutex_unlock(&priv->bf_mutex); +} +EXPORT_SYMBOL_GPL(mlx4_bf_free); + +int mlx4_init_uar_table(struct mlx4_dev *dev) +{ + if (dev->caps.num_uars <= 128) { + mlx4_err(dev, "Only %d UAR pages (need more than 128)\n", + dev->caps.num_uars); + mlx4_err(dev, "Increase firmware log2_uar_bar_megabytes?\n"); + return -ENODEV; + } + + return mlx4_bitmap_init(&mlx4_priv(dev)->uar_table.bitmap, + dev->caps.num_uars, dev->caps.num_uars - 1, + max(128, dev->caps.reserved_uars), 0); +} + +void mlx4_cleanup_uar_table(struct mlx4_dev *dev) +{ + mlx4_bitmap_cleanup(&mlx4_priv(dev)->uar_table.bitmap); +} diff --git a/sys/ofed/drivers/net/mlx4/port.c b/sys/ofed/drivers/net/mlx4/port.c new file mode 100644 index 000000000000..c8df375a41ae --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/port.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include + +#include "mlx4.h" + +int mlx4_ib_set_4k_mtu = 0; +module_param_named(set_4k_mtu, mlx4_ib_set_4k_mtu, int, 0444); +MODULE_PARM_DESC(set_4k_mtu, "attempt to set 4K MTU to all ConnectX ports"); + +#define MLX4_MAC_VALID (1ull << 63) +#define MLX4_MAC_MASK 0xffffffffffffULL + +#define MLX4_VLAN_VALID (1u << 31) +#define MLX4_VLAN_MASK 0xfff + +void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table) +{ + int i; + + mutex_init(&table->mutex); + for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { + table->entries[i] = 0; + table->refs[i] = 0; + } + table->max = 1 << dev->caps.log_num_macs; + table->total = 0; +} + +void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table) +{ + int i; + + mutex_init(&table->mutex); + for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) { + table->entries[i] = 0; + table->refs[i] = 0; + } + table->max = 1 << dev->caps.log_num_vlans; + table->total = 0; +} + +static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, + __be64 *entries) +{ + struct mlx4_cmd_mailbox *mailbox; + u32 in_mod; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + memcpy(mailbox->buf, entries, MLX4_MAC_TABLE_SIZE); + + in_mod = MLX4_SET_PORT_MAC_TABLE << 8 | port; + err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index) +{ + struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table; + int i, err = 0; + int free = -1; + + mlx4_dbg(dev, "Registering MAC: 0x%llx\n", (unsigned long long) mac); + mutex_lock(&table->mutex); + for (i = 0; i < MLX4_MAX_MAC_NUM - 1; i++) { + if (free < 0 && !table->refs[i]) { + free = i; + continue; + } + + if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { + /* MAC already registered, increase refernce count */ + *index = i; + ++table->refs[i]; + goto out; + } + } + + if (free < 0) { + err = -ENOMEM; + goto out; + } + + mlx4_dbg(dev, "Free MAC index is %d\n", free); + + if (table->total == table->max) { + /* No free mac entries */ + err = -ENOSPC; + goto out; + } + + /* Register new MAC */ + table->refs[free] = 1; + table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID); + + err = mlx4_set_port_mac_table(dev, port, table->entries); + if (unlikely(err)) { + mlx4_err(dev, "Failed adding MAC: 0x%llx\n", (unsigned long long) mac); + table->refs[free] = 0; + table->entries[free] = 0; + goto out; + } + + *index = free; + ++table->total; +out: + mutex_unlock(&table->mutex); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_register_mac); + +void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index) +{ + struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table; + + mutex_lock(&table->mutex); + if (!table->refs[index]) { + mlx4_warn(dev, "No MAC entry for index %d\n", index); + goto out; + } + if (--table->refs[index]) { + mlx4_warn(dev, "Have more references for index %d," + "no need to modify MAC table\n", index); + goto out; + } + table->entries[index] = 0; + mlx4_set_port_mac_table(dev, port, table->entries); + --table->total; +out: + mutex_unlock(&table->mutex); +} +EXPORT_SYMBOL_GPL(mlx4_unregister_mac); + +static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, + __be32 *entries) +{ + struct mlx4_cmd_mailbox *mailbox; + u32 in_mod; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE); + in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port; + err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B); + + mlx4_free_cmd_mailbox(dev, mailbox); + + return err; +} + +int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx) +{ + struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; + int i; + + for (i = 0; i < MLX4_MAX_VLAN_NUM; ++i) { + if (table->refs[i] && + (vid == (MLX4_VLAN_MASK & + be32_to_cpu(table->entries[i])))) { + /* Vlan already registered, increase refernce count */ + *idx = i; + return 0; + } + } + + return -ENOENT; +} +EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan); + +int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) +{ + struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; + int i, err = 0; + int free = -1; + + mutex_lock(&table->mutex); + for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) { + if (free < 0 && (table->refs[i] == 0)) { + free = i; + continue; + } + + if (table->refs[i] && + (vlan == (MLX4_VLAN_MASK & + be32_to_cpu(table->entries[i])))) { + /* Vlan already registered, increase refernce count */ + *index = i; + ++table->refs[i]; + goto out; + } + } + + if (free < 0) { + err = -ENOMEM; + goto out; + } + + if (table->total == table->max) { + /* No free vlan entries */ + err = -ENOSPC; + goto out; + } + + /* Register new MAC */ + table->refs[free] = 1; + table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID); + + err = mlx4_set_port_vlan_table(dev, port, table->entries); + if (unlikely(err)) { + mlx4_warn(dev, "Failed adding vlan: %u\n", vlan); + table->refs[free] = 0; + table->entries[free] = 0; + goto out; + } + + *index = free; + ++table->total; +out: + mutex_unlock(&table->mutex); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_register_vlan); + +void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index) +{ + struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table; + + if (index < MLX4_VLAN_REGULAR) { + mlx4_warn(dev, "Trying to free special vlan index %d\n", index); + return; + } + + mutex_lock(&table->mutex); + if (!table->refs[index]) { + mlx4_warn(dev, "No vlan entry for index %d\n", index); + goto out; + } + if (--table->refs[index]) { + mlx4_dbg(dev, "Have more references for index %d," + "no need to modify vlan table\n", index); + goto out; + } + table->entries[index] = 0; + mlx4_set_port_vlan_table(dev, port, table->entries); + --table->total; +out: + mutex_unlock(&table->mutex); +} +EXPORT_SYMBOL_GPL(mlx4_unregister_vlan); + +int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) +{ + struct mlx4_cmd_mailbox *inmailbox, *outmailbox; + u8 *inbuf, *outbuf; + int err; + + inmailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(inmailbox)) + return PTR_ERR(inmailbox); + + outmailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(outmailbox)) { + mlx4_free_cmd_mailbox(dev, inmailbox); + return PTR_ERR(outmailbox); + } + + inbuf = inmailbox->buf; + outbuf = outmailbox->buf; + memset(inbuf, 0, 256); + memset(outbuf, 0, 256); + inbuf[0] = 1; + inbuf[1] = 1; + inbuf[2] = 1; + inbuf[3] = 1; + *(__be16 *) (&inbuf[16]) = cpu_to_be16(0x0015); + *(__be32 *) (&inbuf[20]) = cpu_to_be32(port); + + err = mlx4_cmd_box(dev, inmailbox->dma, outmailbox->dma, port, 3, + MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C); + if (!err) + *caps = *(__be32 *) (outbuf + 84); + mlx4_free_cmd_mailbox(dev, inmailbox); + mlx4_free_cmd_mailbox(dev, outmailbox); + return err; +} + +int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port) +{ + struct mlx4_cmd_mailbox *mailbox; + int err; + + if (dev->caps.port_type[port] != MLX4_PORT_TYPE_IB) + return 0; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + memset(mailbox->buf, 0, 256); + + if (mlx4_ib_set_4k_mtu) + ((__be32 *) mailbox->buf)[0] |= cpu_to_be32((1 << 22) | (1 << 21) | (5 << 12) | (2 << 4)); + + ((__be32 *) mailbox->buf)[1] = dev->caps.ib_port_def_cap[port]; + err = mlx4_cmd(dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} diff --git a/sys/ofed/drivers/net/mlx4/profile.c b/sys/ofed/drivers/net/mlx4/profile.c new file mode 100644 index 000000000000..bd22df95adf9 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/profile.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "mlx4.h" +#include "fw.h" + +enum { + MLX4_RES_QP, + MLX4_RES_RDMARC, + MLX4_RES_ALTC, + MLX4_RES_AUXC, + MLX4_RES_SRQ, + MLX4_RES_CQ, + MLX4_RES_EQ, + MLX4_RES_DMPT, + MLX4_RES_CMPT, + MLX4_RES_MTT, + MLX4_RES_MCG, + MLX4_RES_NUM +}; + +static const char *res_name[] = { + [MLX4_RES_QP] = "QP", + [MLX4_RES_RDMARC] = "RDMARC", + [MLX4_RES_ALTC] = "ALTC", + [MLX4_RES_AUXC] = "AUXC", + [MLX4_RES_SRQ] = "SRQ", + [MLX4_RES_CQ] = "CQ", + [MLX4_RES_EQ] = "EQ", + [MLX4_RES_DMPT] = "DMPT", + [MLX4_RES_CMPT] = "CMPT", + [MLX4_RES_MTT] = "MTT", + [MLX4_RES_MCG] = "MCG", +}; + +u64 mlx4_make_profile(struct mlx4_dev *dev, + struct mlx4_profile *request, + struct mlx4_dev_cap *dev_cap, + struct mlx4_init_hca_param *init_hca) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_resource { + u64 size; + u64 start; + int type; + int num; + int log_num; + }; + + u64 total_size = 0; + struct mlx4_resource *profile; + struct mlx4_resource tmp; + int i, j; + + profile = kzalloc(MLX4_RES_NUM * sizeof *profile, GFP_KERNEL); + if (!profile) + return -ENOMEM; + + profile[MLX4_RES_QP].size = dev_cap->qpc_entry_sz; + profile[MLX4_RES_RDMARC].size = dev_cap->rdmarc_entry_sz; + profile[MLX4_RES_ALTC].size = dev_cap->altc_entry_sz; + profile[MLX4_RES_AUXC].size = dev_cap->aux_entry_sz; + profile[MLX4_RES_SRQ].size = dev_cap->srq_entry_sz; + profile[MLX4_RES_CQ].size = dev_cap->cqc_entry_sz; + profile[MLX4_RES_EQ].size = dev_cap->eqc_entry_sz; + profile[MLX4_RES_DMPT].size = dev_cap->dmpt_entry_sz; + profile[MLX4_RES_CMPT].size = dev_cap->cmpt_entry_sz; + profile[MLX4_RES_MTT].size = dev->caps.mtts_per_seg * dev_cap->mtt_entry_sz; + profile[MLX4_RES_MCG].size = MLX4_MGM_ENTRY_SIZE; + + profile[MLX4_RES_QP].num = request->num_qp; + profile[MLX4_RES_RDMARC].num = request->num_qp * request->rdmarc_per_qp; + profile[MLX4_RES_ALTC].num = request->num_qp; + profile[MLX4_RES_AUXC].num = request->num_qp; + profile[MLX4_RES_SRQ].num = request->num_srq; + profile[MLX4_RES_CQ].num = request->num_cq; + profile[MLX4_RES_EQ].num = min_t(unsigned, dev_cap->max_eqs, + dev_cap->reserved_eqs + + num_possible_cpus() + 1); + profile[MLX4_RES_DMPT].num = request->num_mpt; + profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS; + profile[MLX4_RES_MTT].num = request->num_mtt; + profile[MLX4_RES_MCG].num = request->num_mcg; + + for (i = 0; i < MLX4_RES_NUM; ++i) { + profile[i].type = i; + profile[i].num = roundup_pow_of_two(profile[i].num); + profile[i].log_num = ilog2(profile[i].num); + profile[i].size *= profile[i].num; + profile[i].size = max(profile[i].size, (u64) PAGE_SIZE); + } + + /* + * Sort the resources in decreasing order of size. Since they + * all have sizes that are powers of 2, we'll be able to keep + * resources aligned to their size and pack them without gaps + * using the sorted order. + */ + for (i = MLX4_RES_NUM; i > 0; --i) + for (j = 1; j < i; ++j) { + if (profile[j].size > profile[j - 1].size) { + tmp = profile[j]; + profile[j] = profile[j - 1]; + profile[j - 1] = tmp; + } + } + + for (i = 0; i < MLX4_RES_NUM; ++i) { + if (profile[i].size) { + profile[i].start = total_size; + total_size += profile[i].size; + } + + if (total_size > dev_cap->max_icm_sz) { + mlx4_err(dev, "Profile requires 0x%llx bytes; " + "won't fit in 0x%llx bytes of context memory.\n", + (unsigned long long) total_size, + (unsigned long long) dev_cap->max_icm_sz); + kfree(profile); + return -ENOMEM; + } + + if (profile[i].size) + mlx4_dbg(dev, " profile[%2d] (%6s): 2^%02d entries @ 0x%10llx, " + "size 0x%10llx\n", + i, res_name[profile[i].type], profile[i].log_num, + (unsigned long long) profile[i].start, + (unsigned long long) profile[i].size); + } + + mlx4_dbg(dev, "HCA context memory: reserving %d KB\n", + (int) (total_size >> 10)); + + for (i = 0; i < MLX4_RES_NUM; ++i) { + switch (profile[i].type) { + case MLX4_RES_QP: + dev->caps.num_qps = profile[i].num; + init_hca->qpc_base = profile[i].start; + init_hca->log_num_qps = profile[i].log_num; + break; + case MLX4_RES_RDMARC: + for (priv->qp_table.rdmarc_shift = 0; + request->num_qp << priv->qp_table.rdmarc_shift < profile[i].num; + ++priv->qp_table.rdmarc_shift) + ; /* nothing */ + dev->caps.max_qp_dest_rdma = 1 << priv->qp_table.rdmarc_shift; + priv->qp_table.rdmarc_base = (u32) profile[i].start; + init_hca->rdmarc_base = profile[i].start; + init_hca->log_rd_per_qp = priv->qp_table.rdmarc_shift; + break; + case MLX4_RES_ALTC: + init_hca->altc_base = profile[i].start; + break; + case MLX4_RES_AUXC: + init_hca->auxc_base = profile[i].start; + break; + case MLX4_RES_SRQ: + dev->caps.num_srqs = profile[i].num; + init_hca->srqc_base = profile[i].start; + init_hca->log_num_srqs = profile[i].log_num; + break; + case MLX4_RES_CQ: + dev->caps.num_cqs = profile[i].num; + init_hca->cqc_base = profile[i].start; + init_hca->log_num_cqs = profile[i].log_num; + break; + case MLX4_RES_EQ: + dev->caps.num_eqs = profile[i].num; + init_hca->eqc_base = profile[i].start; + init_hca->log_num_eqs = profile[i].log_num; + break; + case MLX4_RES_DMPT: + dev->caps.num_mpts = profile[i].num; + priv->mr_table.mpt_base = profile[i].start; + init_hca->dmpt_base = profile[i].start; + init_hca->log_mpt_sz = profile[i].log_num; + break; + case MLX4_RES_CMPT: + init_hca->cmpt_base = profile[i].start; + break; + case MLX4_RES_MTT: + dev->caps.num_mtt_segs = profile[i].num; + priv->mr_table.mtt_base = profile[i].start; + init_hca->mtt_base = profile[i].start; + break; + case MLX4_RES_MCG: + dev->caps.num_mgms = profile[i].num >> 1; + dev->caps.num_amgms = profile[i].num >> 1; + init_hca->mc_base = profile[i].start; + init_hca->log_mc_entry_sz = ilog2(MLX4_MGM_ENTRY_SIZE); + init_hca->log_mc_table_sz = profile[i].log_num; + init_hca->log_mc_hash_sz = profile[i].log_num - 1; + break; + default: + break; + } + } + + /* + * PDs don't take any HCA memory, but we assign them as part + * of the HCA profile anyway. + */ + dev->caps.num_pds = MLX4_NUM_PDS; + + kfree(profile); + return total_size; +} diff --git a/sys/ofed/drivers/net/mlx4/qp.c b/sys/ofed/drivers/net/mlx4/qp.c new file mode 100644 index 000000000000..bf1c117db4de --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/qp.c @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. + * Copyright (c) 2004 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include +#include + +#include "mlx4.h" +#include "icm.h" + +void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type) +{ + struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; + struct mlx4_qp *qp; + + spin_lock(&qp_table->lock); + + qp = __mlx4_qp_lookup(dev, qpn); + if (qp) + atomic_inc(&qp->refcount); + + spin_unlock(&qp_table->lock); + + if (!qp) { + mlx4_warn(dev, "Async event for bogus QP %08x\n", qpn); + return; + } + + qp->event(qp, event_type); + + if (atomic_dec_and_test(&qp->refcount)) + complete(&qp->free); +} + +int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state, + struct mlx4_qp_context *context, enum mlx4_qp_optpar optpar, + int sqd_event, struct mlx4_qp *qp) +{ + static const u16 op[MLX4_QP_NUM_STATE][MLX4_QP_NUM_STATE] = { + [MLX4_QP_STATE_RST] = { + [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, + [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, + [MLX4_QP_STATE_INIT] = MLX4_CMD_RST2INIT_QP, + }, + [MLX4_QP_STATE_INIT] = { + [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, + [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, + [MLX4_QP_STATE_INIT] = MLX4_CMD_INIT2INIT_QP, + [MLX4_QP_STATE_RTR] = MLX4_CMD_INIT2RTR_QP, + }, + [MLX4_QP_STATE_RTR] = { + [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, + [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, + [MLX4_QP_STATE_RTS] = MLX4_CMD_RTR2RTS_QP, + }, + [MLX4_QP_STATE_RTS] = { + [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, + [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, + [MLX4_QP_STATE_RTS] = MLX4_CMD_RTS2RTS_QP, + [MLX4_QP_STATE_SQD] = MLX4_CMD_RTS2SQD_QP, + }, + [MLX4_QP_STATE_SQD] = { + [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, + [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, + [MLX4_QP_STATE_RTS] = MLX4_CMD_SQD2RTS_QP, + [MLX4_QP_STATE_SQD] = MLX4_CMD_SQD2SQD_QP, + }, + [MLX4_QP_STATE_SQER] = { + [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, + [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, + [MLX4_QP_STATE_RTS] = MLX4_CMD_SQERR2RTS_QP, + }, + [MLX4_QP_STATE_ERR] = { + [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, + [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, + } + }; + + struct mlx4_cmd_mailbox *mailbox; + int ret = 0; + + if (cur_state >= MLX4_QP_NUM_STATE || new_state >= MLX4_QP_NUM_STATE || + !op[cur_state][new_state]) + return -EINVAL; + + if (op[cur_state][new_state] == MLX4_CMD_2RST_QP) + return mlx4_cmd(dev, 0, qp->qpn, 2, + MLX4_CMD_2RST_QP, MLX4_CMD_TIME_CLASS_A); + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + if (cur_state == MLX4_QP_STATE_RST && new_state == MLX4_QP_STATE_INIT) { + u64 mtt_addr = mlx4_mtt_addr(dev, mtt); + context->mtt_base_addr_h = mtt_addr >> 32; + context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); + context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; + } + + *(__be32 *) mailbox->buf = cpu_to_be32(optpar); + memcpy(mailbox->buf + 8, context, sizeof *context); + + ((struct mlx4_qp_context *) (mailbox->buf + 8))->local_qpn = + cpu_to_be32(qp->qpn); + + ret = mlx4_cmd(dev, mailbox->dma, qp->qpn | (!!sqd_event << 31), + new_state == MLX4_QP_STATE_RST ? 2 : 0, + op[cur_state][new_state], MLX4_CMD_TIME_CLASS_C); + + mlx4_free_cmd_mailbox(dev, mailbox); + return ret; +} +EXPORT_SYMBOL_GPL(mlx4_qp_modify); + +int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_qp_table *qp_table = &priv->qp_table; + int qpn; + + qpn = mlx4_bitmap_alloc_range(&qp_table->bitmap, cnt, align); + if (qpn == -1) + return -ENOMEM; + + *base = qpn; + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_qp_reserve_range); + +void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_qp_table *qp_table = &priv->qp_table; + if (base_qpn < dev->caps.sqp_start + 8) + return; + + mlx4_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt); +} +EXPORT_SYMBOL_GPL(mlx4_qp_release_range); + +int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_qp_table *qp_table = &priv->qp_table; + int err; + + if (!qpn) + return -EINVAL; + + qp->qpn = qpn; + + err = mlx4_table_get(dev, &qp_table->qp_table, qp->qpn); + if (err) + goto err_out; + + err = mlx4_table_get(dev, &qp_table->auxc_table, qp->qpn); + if (err) + goto err_put_qp; + + err = mlx4_table_get(dev, &qp_table->altc_table, qp->qpn); + if (err) + goto err_put_auxc; + + err = mlx4_table_get(dev, &qp_table->rdmarc_table, qp->qpn); + if (err) + goto err_put_altc; + + err = mlx4_table_get(dev, &qp_table->cmpt_table, qp->qpn); + if (err) + goto err_put_rdmarc; + + spin_lock_irq(&qp_table->lock); + err = radix_tree_insert(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1), qp); + spin_unlock_irq(&qp_table->lock); + if (err) + goto err_put_cmpt; + + atomic_set(&qp->refcount, 1); + init_completion(&qp->free); + + return 0; + +err_put_cmpt: + mlx4_table_put(dev, &qp_table->cmpt_table, qp->qpn); + +err_put_rdmarc: + mlx4_table_put(dev, &qp_table->rdmarc_table, qp->qpn); + +err_put_altc: + mlx4_table_put(dev, &qp_table->altc_table, qp->qpn); + +err_put_auxc: + mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn); + +err_put_qp: + mlx4_table_put(dev, &qp_table->qp_table, qp->qpn); + +err_out: + return err; +} +EXPORT_SYMBOL_GPL(mlx4_qp_alloc); + +struct mlx4_qp *mlx4_qp_lookup_lock(struct mlx4_dev *dev, u32 qpn) +{ + struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; + unsigned long flags; + struct mlx4_qp *qp; + + spin_lock_irqsave(&qp_table->lock, flags); + qp = radix_tree_lookup(&dev->qp_table_tree, qpn & (dev->caps.num_qps - 1)); + spin_unlock_irqrestore(&qp_table->lock, flags); + return qp; +} +EXPORT_SYMBOL_GPL(mlx4_qp_lookup_lock); + +void mlx4_qp_remove(struct mlx4_dev *dev, struct mlx4_qp *qp) +{ + struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; + unsigned long flags; + + spin_lock_irqsave(&qp_table->lock, flags); + radix_tree_delete(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1)); + spin_unlock_irqrestore(&qp_table->lock, flags); +} +EXPORT_SYMBOL_GPL(mlx4_qp_remove); + +void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp) +{ + struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; + + if (atomic_dec_and_test(&qp->refcount)) + complete(&qp->free); + wait_for_completion(&qp->free); + + mlx4_table_put(dev, &qp_table->cmpt_table, qp->qpn); + mlx4_table_put(dev, &qp_table->rdmarc_table, qp->qpn); + mlx4_table_put(dev, &qp_table->altc_table, qp->qpn); + mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn); + mlx4_table_put(dev, &qp_table->qp_table, qp->qpn); +} +EXPORT_SYMBOL_GPL(mlx4_qp_free); + +static int mlx4_CONF_SPECIAL_QP(struct mlx4_dev *dev, u32 base_qpn) +{ + return mlx4_cmd(dev, 0, base_qpn, + (dev->caps.flags & MLX4_DEV_CAP_FLAG_RAW_ETY) ? 4 : 0, + MLX4_CMD_CONF_SPECIAL_QP, MLX4_CMD_TIME_CLASS_B); +} + +int mlx4_init_qp_table(struct mlx4_dev *dev) +{ + struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; + int err; + int reserved_from_top = 0; + + spin_lock_init(&qp_table->lock); + INIT_RADIX_TREE(&dev->qp_table_tree, GFP_ATOMIC); + + /* + * We reserve 2 extra QPs per port for the special QPs. The + * block of special QPs must be aligned to a multiple of 8, so + * round up. + * We also reserve the MSB of the 24-bit QP number to indicate + * an XRC qp. + */ + dev->caps.sqp_start = + ALIGN(dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], 8); + + { + int sort[MLX4_NUM_QP_REGION]; + int i, j, tmp; + int last_base = dev->caps.num_qps; + + for (i = 1; i < MLX4_NUM_QP_REGION; ++i) + sort[i] = i; + + for (i = MLX4_NUM_QP_REGION; i > 0; --i) { + for (j = 2; j < i; ++j) { + if (dev->caps.reserved_qps_cnt[sort[j]] > + dev->caps.reserved_qps_cnt[sort[j - 1]]) { + tmp = sort[j]; + sort[j] = sort[j - 1]; + sort[j - 1] = tmp; + } + } + } + + for (i = 1; i < MLX4_NUM_QP_REGION; ++i) { + last_base -= dev->caps.reserved_qps_cnt[sort[i]]; + dev->caps.reserved_qps_base[sort[i]] = last_base; + reserved_from_top += + dev->caps.reserved_qps_cnt[sort[i]]; + } + + } + + err = mlx4_bitmap_init(&qp_table->bitmap, dev->caps.num_qps, + (1 << 23) - 1, dev->caps.sqp_start + 8, + reserved_from_top); + if (err) + return err; + + return mlx4_CONF_SPECIAL_QP(dev, dev->caps.sqp_start); +} + +void mlx4_cleanup_qp_table(struct mlx4_dev *dev) +{ + mlx4_CONF_SPECIAL_QP(dev, 0); + mlx4_bitmap_cleanup(&mlx4_priv(dev)->qp_table.bitmap); +} + +int mlx4_qp_get_region(struct mlx4_dev *dev, enum mlx4_qp_region region, + int *base_qpn, int *cnt) +{ + if ((region < 0) || (region >= MLX4_NUM_QP_REGION)) + return -EINVAL; + + *base_qpn = dev->caps.reserved_qps_base[region]; + *cnt = dev->caps.reserved_qps_cnt[region]; + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_qp_get_region); + +int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp, + struct mlx4_qp_context *context) +{ + struct mlx4_cmd_mailbox *mailbox; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + err = mlx4_cmd_box(dev, 0, mailbox->dma, qp->qpn, 0, + MLX4_CMD_QUERY_QP, MLX4_CMD_TIME_CLASS_A); + if (!err) + memcpy(context, mailbox->buf + 8, sizeof *context); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_qp_query); + +int mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + struct mlx4_qp_context *context, + struct mlx4_qp *qp, enum mlx4_qp_state *qp_state) +{ + int err; + int i; + enum mlx4_qp_state states[] = { + MLX4_QP_STATE_RST, + MLX4_QP_STATE_INIT, + MLX4_QP_STATE_RTR, + MLX4_QP_STATE_RTS + }; + + for (i = 0; i < ARRAY_SIZE(states) - 1; i++) { + context->flags &= cpu_to_be32(~(0xf << 28)); + context->flags |= cpu_to_be32(states[i + 1] << 28); + err = mlx4_qp_modify(dev, mtt, states[i], states[i + 1], + context, 0, 0, qp); + if (err) { + mlx4_err(dev, "Failed to bring QP to state: " + "%d with error: %d\n", + states[i + 1], err); + return err; + } + + *qp_state = states[i + 1]; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_qp_to_ready); diff --git a/sys/ofed/drivers/net/mlx4/reset.c b/sys/ofed/drivers/net/mlx4/reset.c new file mode 100644 index 000000000000..3951b884c0fb --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/reset.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "mlx4.h" + +int mlx4_reset(struct mlx4_dev *dev) +{ + void __iomem *reset; + u32 *hca_header = NULL; + int pcie_cap; + u16 devctl; + u16 linkctl; + u16 vendor; + unsigned long end; + u32 sem; + int i; + int err = 0; + +#define MLX4_RESET_BASE 0xf0000 +#define MLX4_RESET_SIZE 0x400 +#define MLX4_SEM_OFFSET 0x3fc +#define MLX4_RESET_OFFSET 0x10 +#define MLX4_RESET_VALUE swab32(1) + +#define MLX4_SEM_TIMEOUT_JIFFIES (10 * HZ) +#define MLX4_RESET_TIMEOUT_JIFFIES (2 * HZ) + + /* + * Reset the chip. This is somewhat ugly because we have to + * save off the PCI header before reset and then restore it + * after the chip reboots. We skip config space offsets 22 + * and 23 since those have a special meaning. + */ + + /* Do we need to save off the full 4K PCI Express header?? */ + hca_header = kmalloc(256, GFP_KERNEL); + if (!hca_header) { + err = -ENOMEM; + mlx4_err(dev, "Couldn't allocate memory to save HCA " + "PCI header, aborting.\n"); + goto out; + } + + pcie_cap = pci_find_capability(dev->pdev, PCI_CAP_ID_EXP); + + for (i = 0; i < 64; ++i) { + if (i == 22 || i == 23) + continue; + if (pci_read_config_dword(dev->pdev, i * 4, hca_header + i)) { + err = -ENODEV; + mlx4_err(dev, "Couldn't save HCA " + "PCI header, aborting.\n"); + goto out; + } + } + + reset = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_RESET_BASE, + MLX4_RESET_SIZE); + if (!reset) { + err = -ENOMEM; + mlx4_err(dev, "Couldn't map HCA reset register, aborting.\n"); + goto out; + } + + /* grab HW semaphore to lock out flash updates */ + end = jiffies + MLX4_SEM_TIMEOUT_JIFFIES; + do { + sem = readl(reset + MLX4_SEM_OFFSET); + if (!sem) + break; + + msleep(1); + } while (time_before(jiffies, end)); + + if (sem) { + mlx4_err(dev, "Failed to obtain HW semaphore, aborting\n"); + err = -EAGAIN; + iounmap(reset); + goto out; + } + + /* actually hit reset */ + writel(MLX4_RESET_VALUE, reset + MLX4_RESET_OFFSET); + iounmap(reset); + + /* Docs say to wait one second before accessing device */ + msleep(1000); + + end = jiffies + MLX4_RESET_TIMEOUT_JIFFIES; + do { + if (!pci_read_config_word(dev->pdev, PCI_VENDOR_ID, &vendor) && + vendor != 0xffff) + break; + + msleep(1); + } while (time_before(jiffies, end)); + + if (vendor == 0xffff) { + err = -ENODEV; + mlx4_err(dev, "PCI device did not come back after reset, " + "aborting.\n"); + goto out; + } + + /* Now restore the PCI headers */ + if (pcie_cap) { + devctl = hca_header[(pcie_cap + PCI_EXP_DEVCTL) / 4]; + if (pci_write_config_word(dev->pdev, pcie_cap + PCI_EXP_DEVCTL, + devctl)) { + err = -ENODEV; + mlx4_err(dev, "Couldn't restore HCA PCI Express " + "Device Control register, aborting.\n"); + goto out; + } + linkctl = hca_header[(pcie_cap + PCI_EXP_LNKCTL) / 4]; + if (pci_write_config_word(dev->pdev, pcie_cap + PCI_EXP_LNKCTL, + linkctl)) { + err = -ENODEV; + mlx4_err(dev, "Couldn't restore HCA PCI Express " + "Link control register, aborting.\n"); + goto out; + } + } + + for (i = 0; i < 16; ++i) { + if (i * 4 == PCI_COMMAND) + continue; + + if (pci_write_config_dword(dev->pdev, i * 4, hca_header[i])) { + err = -ENODEV; + mlx4_err(dev, "Couldn't restore HCA reg %x, " + "aborting.\n", i); + goto out; + } + } + + if (pci_write_config_dword(dev->pdev, PCI_COMMAND, + hca_header[PCI_COMMAND / 4])) { + err = -ENODEV; + mlx4_err(dev, "Couldn't restore HCA COMMAND, " + "aborting.\n"); + goto out; + } + +out: + kfree(hca_header); + + return err; +} diff --git a/sys/ofed/drivers/net/mlx4/sense.c b/sys/ofed/drivers/net/mlx4/sense.c new file mode 100644 index 000000000000..0fcf025e36b5 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/sense.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#include +#include + +#include + +#include "mlx4.h" + +static int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, + enum mlx4_port_type *type) +{ + u64 out_param; + int err = 0; + + err = mlx4_cmd_imm(dev, 0, &out_param, port, 0, + MLX4_CMD_SENSE_PORT, MLX4_CMD_TIME_CLASS_B); + if (err) { + mlx4_err(dev, "Sense command failed for port: %d\n", port); + return err; + } + + if (out_param > 2) { + mlx4_err(dev, "Sense returned illegal value: 0x%llx\n", out_param); + return EINVAL; + } + + *type = out_param; + return 0; +} + +void mlx4_do_sense_ports(struct mlx4_dev *dev, + enum mlx4_port_type *stype, + enum mlx4_port_type *defaults) +{ + struct mlx4_sense *sense = &mlx4_priv(dev)->sense; + int err; + int i; + + for (i = 1; i <= dev->caps.num_ports; i++) { + stype[i - 1] = 0; + if (sense->do_sense_port[i] && sense->sense_allowed[i] && + dev->caps.possible_type[i] == MLX4_PORT_TYPE_AUTO) { + err = mlx4_SENSE_PORT(dev, i, &stype[i - 1]); + if (err) + stype[i - 1] = defaults[i - 1]; + } else + stype[i - 1] = defaults[i - 1]; + } + + /* + * Adjust port configuration: + * If port 1 sensed nothing and port 2 is IB, set both as IB + * If port 2 sensed nothing and port 1 is Eth, set both as Eth + */ + if (stype[0] == MLX4_PORT_TYPE_ETH) { + for (i = 1; i < dev->caps.num_ports; i++) + stype[i] = stype[i] ? stype[i] : MLX4_PORT_TYPE_ETH; + } + if (stype[dev->caps.num_ports - 1] == MLX4_PORT_TYPE_IB) { + for (i = 0; i < dev->caps.num_ports - 1; i++) + stype[i] = stype[i] ? stype[i] : MLX4_PORT_TYPE_IB; + } + + /* + * If sensed nothing, remain in current configuration. + */ + for (i = 0; i < dev->caps.num_ports; i++) + stype[i] = stype[i] ? stype[i] : defaults[i]; + +} + +static void mlx4_sense_port(struct work_struct *work) +{ + struct delayed_work *delay = to_delayed_work(work); + struct mlx4_sense *sense = container_of(delay, struct mlx4_sense, + sense_poll); + struct mlx4_dev *dev = sense->dev; + struct mlx4_priv *priv = mlx4_priv(dev); + enum mlx4_port_type stype[MLX4_MAX_PORTS]; + + mutex_lock(&priv->port_mutex); + mlx4_do_sense_ports(dev, stype, &dev->caps.port_type[1]); + + if (mlx4_check_port_params(dev, stype)) + goto sense_again; + + if (mlx4_change_port_types(dev, stype)) + mlx4_err(dev, "Failed to change port_types\n"); + +sense_again: + mutex_unlock(&priv->port_mutex); + if (sense->resched) + queue_delayed_work(sense->sense_wq , &sense->sense_poll, + round_jiffies(MLX4_SENSE_RANGE)); +} + +void mlx4_start_sense(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_sense *sense = &priv->sense; + + if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) + return; + + sense->resched = 1; + queue_delayed_work(sense->sense_wq , &sense->sense_poll, + round_jiffies(MLX4_SENSE_RANGE)); +} + + +void mlx4_stop_sense(struct mlx4_dev *dev) +{ + mlx4_priv(dev)->sense.resched = 0; +} + +int mlx4_sense_init(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_sense *sense = &priv->sense; + int port; + + sense->dev = dev; + sense->sense_wq = create_singlethread_workqueue("mlx4_sense"); + if (!sense->sense_wq) + return -ENOMEM; + + for (port = 1; port <= dev->caps.num_ports; port++) + sense->do_sense_port[port] = 1; + + INIT_DELAYED_WORK_DEFERRABLE(&sense->sense_poll, mlx4_sense_port); + return 0; +} + +void mlx4_sense_cleanup(struct mlx4_dev *dev) +{ + mlx4_stop_sense(dev); + cancel_delayed_work(&mlx4_priv(dev)->sense.sense_poll); + destroy_workqueue(mlx4_priv(dev)->sense.sense_wq); +} + diff --git a/sys/ofed/drivers/net/mlx4/srq.c b/sys/ofed/drivers/net/mlx4/srq.c new file mode 100644 index 000000000000..f856b8ddb66e --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/srq.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include +#include + +#include "mlx4.h" +#include "icm.h" + +struct mlx4_srq_context { + __be32 state_logsize_srqn; + u8 logstride; + u8 reserved1; + __be16 xrc_domain; + __be32 pg_offset_cqn; + u32 reserved2; + u8 log_page_size; + u8 reserved3[2]; + u8 mtt_base_addr_h; + __be32 mtt_base_addr_l; + __be32 pd; + __be16 limit_watermark; + __be16 wqe_cnt; + u16 reserved4; + __be16 wqe_counter; + u32 reserved5; + __be64 db_rec_addr; +}; + +void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type) +{ + struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; + struct mlx4_srq *srq; + + spin_lock(&srq_table->lock); + + srq = radix_tree_lookup(&dev->srq_table_tree, + srqn & (dev->caps.num_srqs - 1)); + if (srq) + atomic_inc(&srq->refcount); + + spin_unlock(&srq_table->lock); + + if (!srq) { + mlx4_warn(dev, "Async event for bogus SRQ %08x\n", srqn); + return; + } + + srq->event(srq, event_type); + + if (atomic_dec_and_test(&srq->refcount)) + complete(&srq->free); +} + +static int mlx4_SW2HW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int srq_num) +{ + return mlx4_cmd(dev, mailbox->dma, srq_num, 0, MLX4_CMD_SW2HW_SRQ, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_HW2SW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int srq_num) +{ + return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, srq_num, + mailbox ? 0 : 1, MLX4_CMD_HW2SW_SRQ, + MLX4_CMD_TIME_CLASS_A); +} + +static int mlx4_ARM_SRQ(struct mlx4_dev *dev, int srq_num, int limit_watermark) +{ + return mlx4_cmd(dev, limit_watermark, srq_num, 0, MLX4_CMD_ARM_SRQ, + MLX4_CMD_TIME_CLASS_B); +} + +static int mlx4_QUERY_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + int srq_num) +{ + return mlx4_cmd_box(dev, 0, mailbox->dma, srq_num, 0, MLX4_CMD_QUERY_SRQ, + MLX4_CMD_TIME_CLASS_A); +} + +int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd, + struct mlx4_mtt *mtt, u64 db_rec, struct mlx4_srq *srq) +{ + struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_srq_context *srq_context; + u64 mtt_addr; + int err; + + srq->srqn = mlx4_bitmap_alloc(&srq_table->bitmap); + if (srq->srqn == -1) + return -ENOMEM; + + err = mlx4_table_get(dev, &srq_table->table, srq->srqn); + if (err) + goto err_out; + + err = mlx4_table_get(dev, &srq_table->cmpt_table, srq->srqn); + if (err) + goto err_put; + + spin_lock_irq(&srq_table->lock); + err = radix_tree_insert(&dev->srq_table_tree, srq->srqn, srq); + spin_unlock_irq(&srq_table->lock); + if (err) + goto err_cmpt_put; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + err = PTR_ERR(mailbox); + goto err_radix; + } + + srq_context = mailbox->buf; + memset(srq_context, 0, sizeof *srq_context); + + srq_context->state_logsize_srqn = cpu_to_be32((ilog2(srq->max) << 24) | + srq->srqn); + srq_context->logstride = srq->wqe_shift - 4; + srq_context->xrc_domain = cpu_to_be16(xrcd); + srq_context->pg_offset_cqn = cpu_to_be32(cqn & 0xffffff); + srq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; + + mtt_addr = mlx4_mtt_addr(dev, mtt); + srq_context->mtt_base_addr_h = mtt_addr >> 32; + srq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); + srq_context->pd = cpu_to_be32(pdn); + srq_context->db_rec_addr = cpu_to_be64(db_rec); + + err = mlx4_SW2HW_SRQ(dev, mailbox, srq->srqn); + mlx4_free_cmd_mailbox(dev, mailbox); + if (err) + goto err_radix; + + atomic_set(&srq->refcount, 1); + init_completion(&srq->free); + + return 0; + +err_radix: + spin_lock_irq(&srq_table->lock); + radix_tree_delete(&dev->srq_table_tree, srq->srqn); + spin_unlock_irq(&srq_table->lock); + +err_cmpt_put: + mlx4_table_put(dev, &srq_table->cmpt_table, srq->srqn); + +err_put: + mlx4_table_put(dev, &srq_table->table, srq->srqn); + +err_out: + mlx4_bitmap_free(&srq_table->bitmap, srq->srqn); + + return err; +} +EXPORT_SYMBOL_GPL(mlx4_srq_alloc); + +void mlx4_srq_invalidate(struct mlx4_dev *dev, struct mlx4_srq *srq) +{ + int err; + + err = mlx4_HW2SW_SRQ(dev, NULL, srq->srqn); + if (err) + mlx4_warn(dev, "HW2SW_SRQ failed (%d) for SRQN %06x\n", err, srq->srqn); +} +EXPORT_SYMBOL_GPL(mlx4_srq_invalidate); + +void mlx4_srq_remove(struct mlx4_dev *dev, struct mlx4_srq *srq) +{ + struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; + + spin_lock_irq(&srq_table->lock); + radix_tree_delete(&dev->srq_table_tree, srq->srqn); + spin_unlock_irq(&srq_table->lock); +} +EXPORT_SYMBOL_GPL(mlx4_srq_remove); + +void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq) +{ + struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; + + if (atomic_dec_and_test(&srq->refcount)) + complete(&srq->free); + wait_for_completion(&srq->free); + + mlx4_table_put(dev, &srq_table->table, srq->srqn); + mlx4_bitmap_free(&srq_table->bitmap, srq->srqn); +} +EXPORT_SYMBOL_GPL(mlx4_srq_free); + +int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark) +{ + return mlx4_ARM_SRQ(dev, srq->srqn, limit_watermark); +} +EXPORT_SYMBOL_GPL(mlx4_srq_arm); + +int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_watermark) +{ + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_srq_context *srq_context; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + srq_context = mailbox->buf; + + err = mlx4_QUERY_SRQ(dev, mailbox, srq->srqn); + if (err) + goto err_out; + *limit_watermark = be16_to_cpu(srq_context->limit_watermark); + +err_out: + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_srq_query); + +int mlx4_init_srq_table(struct mlx4_dev *dev) +{ + struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table; + int err; + + spin_lock_init(&srq_table->lock); + INIT_RADIX_TREE(&dev->srq_table_tree, GFP_ATOMIC); + + err = mlx4_bitmap_init(&srq_table->bitmap, dev->caps.num_srqs, + dev->caps.num_srqs - 1, dev->caps.reserved_srqs, 0); + if (err) + return err; + + return 0; +} + +void mlx4_cleanup_srq_table(struct mlx4_dev *dev) +{ + mlx4_bitmap_cleanup(&mlx4_priv(dev)->srq_table.bitmap); +} diff --git a/sys/ofed/drivers/net/mlx4/xrcd.c b/sys/ofed/drivers/net/mlx4/xrcd.c new file mode 100644 index 000000000000..d1bfc111fe50 --- /dev/null +++ b/sys/ofed/drivers/net/mlx4/xrcd.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * Copyright (c) 2007 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "mlx4.h" + +int mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + *xrcdn = mlx4_bitmap_alloc(&priv->xrcd_bitmap); + if (*xrcdn == -1) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_GPL(mlx4_xrcd_alloc); + +void mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn) +{ + mlx4_bitmap_free(&mlx4_priv(dev)->xrcd_bitmap, xrcdn); +} +EXPORT_SYMBOL_GPL(mlx4_xrcd_free); + +int __devinit mlx4_init_xrcd_table(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + return mlx4_bitmap_init(&priv->xrcd_bitmap, (1 << 16), + (1 << 16) - 1, dev->caps.reserved_xrcds + 1, 0); +} + +void mlx4_cleanup_xrcd_table(struct mlx4_dev *dev) +{ + mlx4_bitmap_cleanup(&mlx4_priv(dev)->xrcd_bitmap); +} + + diff --git a/sys/ofed/include/asm/atomic-long.h b/sys/ofed/include/asm/atomic-long.h new file mode 100644 index 000000000000..5075ad8ef283 --- /dev/null +++ b/sys/ofed/include/asm/atomic-long.h @@ -0,0 +1,79 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _ATOMIC_LONG_H_ +#define _ATOMIC_LONG_H_ + +#include +#include +#include + +typedef struct { + volatile u_long counter; +} atomic_long_t; + +#define atomic_long_add(i, v) atomic_long_add_return((i), (v)) +#define atomic_long_inc_return(v) atomic_long_add_return(1, (v)) + +static inline long +atomic_long_add_return(long i, atomic_long_t *v) +{ + return i + atomic_fetchadd_long(&v->counter, i); +} + +static inline void +atomic_long_set(atomic_long_t *v, long i) +{ + atomic_store_rel_long(&v->counter, i); +} + +static inline long +atomic_long_read(atomic_long_t *v) +{ + return atomic_load_acq_long(&v->counter); +} + +static inline long +atomic_long_inc(atomic_long_t *v) +{ + return atomic_fetchadd_long(&v->counter, 1) + 1; +} + +static inline long +atomic_long_dec(atomic_long_t *v) +{ + return atomic_fetchadd_long(&v->counter, -1) - 1; +} + +static inline long +atomic_long_dec_and_test(atomic_long_t *v) +{ + long i = atomic_long_add(-1, v); + return i == 0 ; +} + +#endif /* _ATOMIC_LONG_H_ */ diff --git a/sys/ofed/include/asm/atomic.h b/sys/ofed/include/asm/atomic.h new file mode 100644 index 000000000000..5c5caa07d3e6 --- /dev/null +++ b/sys/ofed/include/asm/atomic.h @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASM_ATOMIC_H_ +#define _ASM_ATOMIC_H_ + +#include +#include +#include +#include + +typedef struct { + volatile u_int counter; +} atomic_t; + +#define atomic_add(i, v) atomic_add_return((i), (v)) +#define atomic_sub(i, v) atomic_sub_return((i), (v)) +#define atomic_inc_return(v) atomic_add_return(1, (v)) +#define atomic_add_negative(i, v) (atomic_add_return((i), (v)) < 0) +#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) +#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) +#define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0) + +static inline int +atomic_add_return(int i, atomic_t *v) +{ + return i + atomic_fetchadd_int(&v->counter, i); +} + +static inline int +atomic_sub_return(int i, atomic_t *v) +{ + return atomic_fetchadd_int(&v->counter, -i) - i; +} + +static inline void +atomic_set(atomic_t *v, int i) +{ + atomic_store_rel_int(&v->counter, i); +} + +static inline int +atomic_read(atomic_t *v) +{ + return atomic_load_acq_int(&v->counter); +} + +static inline int +atomic_inc(atomic_t *v) +{ + return atomic_fetchadd_int(&v->counter, 1) + 1; +} + +static inline int +atomic_dec(atomic_t *v) +{ + return atomic_fetchadd_int(&v->counter, -1) - 1; +} + +#endif /* _ASM_ATOMIC_H_ */ diff --git a/sys/ofed/include/asm/byteorder.h b/sys/ofed/include/asm/byteorder.h new file mode 100644 index 000000000000..341c548f71dd --- /dev/null +++ b/sys/ofed/include/asm/byteorder.h @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _ASM_BYTEORDER_H_ +#define _ASM_BYTEORDER_H_ + +#include +#include + +#if BYTE_ORDER == LITTLE_ENDIAN +#define __LITTLE_ENDIAN +#else +#define __BIG_ENDIAN +#endif + +#define cpu_to_le64 htole64 +#define le64_to_cpu le64toh +#define cpu_to_le32 htole32 +#define le32_to_cpu le32toh +#define cpu_to_le16 htole16 +#define le16_to_cpu le16toh +#define cpu_to_be64 htobe64 +#define be64_to_cpu be64toh +#define cpu_to_be32 htobe32 +#define be32_to_cpu be32toh +#define cpu_to_be16 htobe16 +#define be16_to_cpu be16toh +#define __be16_to_cpu be16toh + +#define cpu_to_le64p(x) htole64(*((uint64_t *)x)) +#define le64_to_cpup(x) le64toh(*((uint64_t *)x)) +#define cpu_to_le32p(x) htole32(*((uint32_t *)x)) +#define le32_to_cpup(x) le32toh(*((uint32_t *)x)) +#define cpu_to_le16p(x) htole16(*((uint16_t *)x)) +#define le16_to_cpup(x) le16toh(*((uint16_t *)x)) +#define cpu_to_be64p(x) htobe64(*((uint64_t *)x)) +#define be64_to_cpup(x) be64toh(*((uint64_t *)x)) +#define cpu_to_be32p(x) htobe32(*((uint32_t *)x)) +#define be32_to_cpup(x) be32toh(*((uint32_t *)x)) +#define cpu_to_be16p(x) htobe16(*((uint16_t *)x)) +#define be16_to_cpup(x) be16toh(*((uint16_t *)x)) + +#define cpu_to_le64s(x) do { *((uint64_t *)x) = cpu_to_le64p((x)) } while (0) +#define le64_to_cpus(x) do { *((uint64_t *)x) = le64_to_cpup((x)) } while (0) +#define cpu_to_le32s(x) do { *((uint32_t *)x) = cpu_to_le32p((x)) } while (0) +#define le32_to_cpus(x) do { *((uint32_t *)x) = le32_to_cpup((x)) } while (0) +#define cpu_to_le16s(x) do { *((uint16_t *)x) = cpu_to_le16p((x)) } while (0) +#define le16_to_cpus(x) do { *((uint16_t *)x) = le16_to_cpup((x)) } while (0) +#define cpu_to_be64s(x) do { *((uint64_t *)x) = cpu_to_be64p((x)) } while (0) +#define be64_to_cpus(x) do { *((uint64_t *)x) = be64_to_cpup((x)) } while (0) +#define cpu_to_be32s(x) do { *((uint32_t *)x) = cpu_to_be32p((x)) } while (0) +#define be32_to_cpus(x) do { *((uint32_t *)x) = be32_to_cpup((x)) } while (0) +#define cpu_to_be16s(x) do { *((uint16_t *)x) = cpu_to_be16p((x)) } while (0) +#define be16_to_cpus(x) do { *((uint16_t *)x) = be16_to_cpup((x)) } while (0) + +#define swab16 bswap16 +#define swab32 bswap32 +#define swab64 bswap64 + +static inline void +be16_add_cpu(u16 *var, u16 val) +{ + *var = cpu_to_be16(be16_to_cpu(*var) + val); +} + +#endif /* _ASM_BYTEORDER_H_ */ diff --git a/sys/ofed/include/asm/current.h b/sys/ofed/include/asm/current.h new file mode 100644 index 000000000000..33bd12020374 --- /dev/null +++ b/sys/ofed/include/asm/current.h @@ -0,0 +1,32 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASM_CURRENT_H_ +#define _ASM_CURRENT_H_ + +#endif /* _ASM_CURRENT_H_ */ diff --git a/sys/ofed/include/asm/fcntl.h b/sys/ofed/include/asm/fcntl.h new file mode 100644 index 000000000000..a650f5b05f54 --- /dev/null +++ b/sys/ofed/include/asm/fcntl.h @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _ASM_FCNTL_H_ +#define _ASM_FCNTL_H_ + +#include + +#endif /* _ASM_FCNTL_H_ */ diff --git a/sys/ofed/include/asm/io.h b/sys/ofed/include/asm/io.h new file mode 100644 index 000000000000..7a742d9e49f4 --- /dev/null +++ b/sys/ofed/include/asm/io.h @@ -0,0 +1,29 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include diff --git a/sys/ofed/include/asm/page.h b/sys/ofed/include/asm/page.h new file mode 100644 index 000000000000..da42df7726ed --- /dev/null +++ b/sys/ofed/include/asm/page.h @@ -0,0 +1,29 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include diff --git a/sys/ofed/include/asm/pgtable.h b/sys/ofed/include/asm/pgtable.h new file mode 100644 index 000000000000..087f5252bc44 --- /dev/null +++ b/sys/ofed/include/asm/pgtable.h @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _ASM_PGTABLE_H_ +#define _ASM_PGTABLE_H_ + +typedef int pgprot_t; + +#endif /* _ASM_PGTABLE_H_ */ diff --git a/sys/ofed/include/asm/semaphore.h b/sys/ofed/include/asm/semaphore.h new file mode 100644 index 000000000000..a60ba8c0e3d7 --- /dev/null +++ b/sys/ofed/include/asm/semaphore.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASM_SEMAPHORE_H_ +#define _ASM_SEMAPHORE_H_ + +#include + +#endif /* _ASM_SEMAPHORE_H_ */ diff --git a/sys/ofed/include/asm/system.h b/sys/ofed/include/asm/system.h new file mode 100644 index 000000000000..e5d814ee3407 --- /dev/null +++ b/sys/ofed/include/asm/system.h @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/sys/ofed/include/asm/types.h b/sys/ofed/include/asm/types.h new file mode 100644 index 000000000000..70dd2be93a4b --- /dev/null +++ b/sys/ofed/include/asm/types.h @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _ASM_TYPES_H_ +#define _ASM_TYPES_H_ + +typedef unsigned short umode_t; + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) // && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +#ifdef _KERNEL + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +/* DMA addresses come in generic and 64-bit flavours. */ +typedef vm_paddr_t dma_addr_t; +typedef vm_paddr_t dma64_addr_t; + +#endif /* _KERNEL */ + +#endif /* _ASM_TYPES_H_ */ diff --git a/sys/ofed/include/asm/uaccess.h b/sys/ofed/include/asm/uaccess.h new file mode 100644 index 000000000000..b7c32fa11daa --- /dev/null +++ b/sys/ofed/include/asm/uaccess.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _ASM_UACCESS_H_ +#define _ASM_UACCESS_H_ + +#include + +static inline long +copy_to_user(void *to, const void *from, unsigned long n) +{ + if (copyout(from, to, n) != 0) + return n; + return 0; +} + +static inline long +copy_from_user(void *to, const void *from, unsigned long n) +{ + if (copyin(from, to, n) != 0) + return n; + return 0; +} + +#endif /* _ASM_UACCESS_H_ */ diff --git a/sys/ofed/include/linux/bitmap.h b/sys/ofed/include/linux/bitmap.h new file mode 100644 index 000000000000..66059ac86c86 --- /dev/null +++ b/sys/ofed/include/linux/bitmap.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_BITMAP_H_ +#define _LINUX_BITMAP_H_ + +#include +#include + +#endif /* _LINUX_BITMAP_H_ */ diff --git a/sys/ofed/include/linux/bitops.h b/sys/ofed/include/linux/bitops.h new file mode 100644 index 000000000000..4305a3a76363 --- /dev/null +++ b/sys/ofed/include/linux/bitops.h @@ -0,0 +1,312 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_BITOPS_H_ +#define _LINUX_BITOPS_H_ + +#ifdef __LP64__ +#define BITS_PER_LONG 64 +#else +#define BITS_PER_LONG 32 +#endif +#define BIT_MASK(n) (~0UL >> (BITS_PER_LONG - (n))) +#define BITS_TO_LONGS(n) howmany((n), BITS_PER_LONG) + +static inline int +__ffs(int mask) +{ + return (ffs(mask) - 1); +} + +static inline int +__fls(int mask) +{ + return (fls(mask) - 1); +} + +static inline int +__ffsl(long mask) +{ + return (ffsl(mask) - 1); +} + +static inline int +__flsl(long mask) +{ + return (flsl(mask) - 1); +} + + +#define ffz(mask) __ffs(~(mask)) + +static inline unsigned long +find_first_bit(unsigned long *addr, unsigned long size) +{ + long mask; + int bit; + + for (bit = 0; size >= BITS_PER_LONG; + size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) { + if (*addr == 0) + continue; + return (bit + __ffsl(*addr)); + } + if (size) { + mask = (*addr) & BIT_MASK(size); + if (mask) + bit += __ffsl(mask); + else + bit += size; + } + return (bit); +} + +static inline unsigned long +find_first_zero_bit(unsigned long *addr, unsigned long size) +{ + long mask; + int bit; + + for (bit = 0; size >= BITS_PER_LONG; + size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) { + if (~(*addr) == 0) + continue; + return (bit + __ffsl(~(*addr))); + } + if (size) { + mask = ~(*addr) & BIT_MASK(size); + if (mask) + bit += __ffsl(mask); + else + bit += size; + } + return (bit); +} + +static inline unsigned long +find_last_bit(unsigned long *addr, unsigned long size) +{ + long mask; + int offs; + int bit; + int pos; + + pos = size / BITS_PER_LONG; + offs = size % BITS_PER_LONG; + bit = BITS_PER_LONG * pos; + addr += pos; + if (offs) { + mask = (*addr) & BIT_MASK(offs); + if (mask) + return (bit + __flsl(mask)); + } + while (--pos) { + addr--; + bit -= BITS_PER_LONG; + if (*addr) + return (bit + __flsl(mask)); + } + return (size); +} + +static inline unsigned long +find_next_bit(unsigned long *addr, unsigned long size, unsigned long offset) +{ + long mask; + int offs; + int bit; + int pos; + + if (offset >= size) + return (size); + pos = offset / BITS_PER_LONG; + offs = offset % BITS_PER_LONG; + bit = BITS_PER_LONG * pos; + addr += pos; + if (offs) { + mask = (*addr) & ~BIT_MASK(offs); + if (mask) + return (bit + __ffsl(mask)); + bit += BITS_PER_LONG; + addr++; + } + for (size -= bit; size >= BITS_PER_LONG; + size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) { + if (*addr == 0) + continue; + return (bit + __ffsl(*addr)); + } + if (size) { + mask = (*addr) & BIT_MASK(size); + if (mask) + bit += __ffsl(mask); + else + bit += size; + } + return (bit); +} + +static inline unsigned long +find_next_zero_bit(unsigned long *addr, unsigned long size, + unsigned long offset) +{ + long mask; + int offs; + int bit; + int pos; + + if (offset >= size) + return (size); + pos = offset / BITS_PER_LONG; + offs = offset % BITS_PER_LONG; + bit = BITS_PER_LONG * pos; + addr += pos; + if (offs) { + mask = ~(*addr) & ~BIT_MASK(offs); + if (mask) + return (bit + __ffsl(mask)); + bit += BITS_PER_LONG; + addr++; + } + for (size -= bit; size >= BITS_PER_LONG; + size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) { + if (~(*addr) == 0) + continue; + return (bit + __ffsl(~(*addr))); + } + if (size) { + mask = ~(*addr) & BIT_MASK(size); + if (mask) + bit += __ffsl(mask); + else + bit += size; + } + return (bit); +} + +static inline void +bitmap_zero(unsigned long *addr, int size) +{ + int len; + + len = BITS_TO_LONGS(size) * sizeof(long); + memset(addr, 0, len); +} + +static inline void +bitmap_fill(unsigned long *addr, int size) +{ + int tail; + int len; + + len = (size / BITS_PER_LONG) * sizeof(long); + memset(addr, 0xff, len); + tail = size & (BITS_PER_LONG - 1); + if (tail) + addr[size / BITS_PER_LONG] = BIT_MASK(tail); +} + +static inline int +bitmap_full(unsigned long *addr, int size) +{ + long mask; + int tail; + int len; + int i; + + len = size / BITS_PER_LONG; + for (i = 0; i < len; i++) + if (addr[i] != ~0UL) + return (0); + tail = size & (BITS_PER_LONG - 1); + if (tail) { + mask = BIT_MASK(tail); + if ((addr[i] & mask) != mask) + return (0); + } + return (1); +} + +static inline int +bitmap_empty(unsigned long *addr, int size) +{ + long mask; + int tail; + int len; + int i; + + len = size / BITS_PER_LONG; + for (i = 0; i < len; i++) + if (addr[i] != 0) + return (0); + tail = size & (BITS_PER_LONG - 1); + if (tail) { + mask = BIT_MASK(tail); + if ((addr[i] & mask) != 0) + return (0); + } + return (1); +} + +#define NBINT (NBBY * sizeof(int)) + +#define set_bit(i, a) \ + atomic_set_int(&((volatile int *)(a))[(i)/NBINT], 1 << (i) % NBINT) + +#define clear_bit(i, a) \ + atomic_clear_int(&((volatile int *)(a))[(i)/NBINT], 1 << (i) % NBINT) + +#define test_bit(i, a) \ + !!(atomic_load_acq_int(&((volatile int *)(a))[(i)/NBINT]) & 1 << ((i) % NBINT)) + +static inline long +test_and_clear_bit(long bit, long *var) +{ + long val; + + bit = 1 << bit; + do { + val = *(volatile long *)var; + } while (atomic_cmpset_long(var, val, val & ~bit) == 0); + + return !!(val & bit); +} + +static inline long +test_and_set_bit(long bit, long *var) +{ + long val; + + bit = 1 << bit; + do { + val = *(volatile long *)var; + } while (atomic_cmpset_long(var, val, val | bit) == 0); + + return !!(val & bit); +} + +#endif /* _LINUX_BITOPS_H_ */ diff --git a/sys/ofed/include/linux/cdev.h b/sys/ofed/include/linux/cdev.h new file mode 100644 index 000000000000..cc774954e19a --- /dev/null +++ b/sys/ofed/include/linux/cdev.h @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_CDEV_H_ +#define _LINUX_CDEV_H_ + +#include +#include +#include + +struct file_operations; +struct inode; +struct module; + +extern struct cdevsw linuxcdevsw; + +struct linux_cdev { + struct kobject kobj; + struct module *owner; + struct cdev *cdev; + dev_t dev; + const struct file_operations *ops; +}; + +static inline void +cdev_release(struct kobject *kobj) +{ + struct linux_cdev *cdev; + + cdev = container_of(kobj, struct linux_cdev, kobj); + if (cdev->cdev) + destroy_dev(cdev->cdev); + kfree(cdev); +} + +static inline void +cdev_static_release(struct kobject *kobj) +{ + struct linux_cdev *cdev; + + cdev = container_of(kobj, struct linux_cdev, kobj); + if (cdev->cdev) + destroy_dev(cdev->cdev); +} + +static struct kobj_type cdev_ktype = { + .release = cdev_release, +}; + +static struct kobj_type cdev_static_ktype = { + .release = cdev_static_release, +}; + +static inline void +cdev_init(struct linux_cdev *cdev, const struct file_operations *ops) +{ + + kobject_init(&cdev->kobj, &cdev_static_ktype); + cdev->ops = ops; +} + +static inline struct linux_cdev * +cdev_alloc(void) +{ + struct linux_cdev *cdev; + + cdev = kzalloc(sizeof(struct linux_cdev), M_WAITOK); + if (cdev) + kobject_init(&cdev->kobj, &cdev_ktype); + return (cdev); +} + +static inline void +cdev_put(struct linux_cdev *p) +{ + kobject_put(&p->kobj); +} + +static inline int +cdev_add(struct linux_cdev *cdev, dev_t dev, unsigned count) +{ + if (count != 1) + panic("cdev_add: Unsupported count: %d", count); + cdev->cdev = make_dev(&linuxcdevsw, MINOR(dev), 0, 0, 0700, + kobject_name(&cdev->kobj)); + cdev->dev = dev; + cdev->cdev->si_drv1 = cdev; + + return (0); +} + +static inline void +cdev_del(struct linux_cdev *cdev) +{ + if (cdev->cdev) { + destroy_dev(cdev->cdev); + cdev->cdev = NULL; + } + kobject_put(&cdev->kobj); +} + +#define cdev linux_cdev + +#endif /* _LINUX_CDEV_H_ */ diff --git a/sys/ofed/include/linux/compat.h b/sys/ofed/include/linux/compat.h new file mode 100644 index 000000000000..cfb167112f8e --- /dev/null +++ b/sys/ofed/include/linux/compat.h @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_COMPAT_H_ +#define _LINUX_COMPAT_H_ + + +#endif /* _LINUX_COMPAT_H_ */ diff --git a/sys/ofed/include/linux/compiler.h b/sys/ofed/include/linux/compiler.h new file mode 100644 index 000000000000..12938ba49b20 --- /dev/null +++ b/sys/ofed/include/linux/compiler.h @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_COMPILER_H_ +#define _LINUX_COMPILER_H_ + +#include + +#define __user +#define __kernel +#define __safe +#define __force +#define __nocast +#define __iomem +#define __chk_user_ptr(x) 0 +#define __chk_io_ptr(x) 0 +#define __builtin_warning(x, y...) (1) +#define __acquires(x) +#define __releases(x) +#define __acquire(x) 0 +#define __release(x) 0 +#define __cond_lock(x,c) (c) +#define __bitwise +#define __devinitdata +#define __init +#define __devinit +#define __devexit +#define __exit +#define __stringify(x) #x +#define __attribute_const__ __attribute__((__const__)) +#undef __always_inline +#define __always_inline inline + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#define typeof(x) __typeof(x) + +#define uninitialized_var(x) x = x + +#endif /* _LINUX_COMPILER_H_ */ diff --git a/sys/ofed/include/linux/completion.h b/sys/ofed/include/linux/completion.h new file mode 100644 index 000000000000..59f36b0b3f23 --- /dev/null +++ b/sys/ofed/include/linux/completion.h @@ -0,0 +1,155 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_COMPLETION_H_ +#define _LINUX_COMPLETION_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include + +struct completion { + unsigned int done; +}; + +#define INIT_COMPLETION(c) ((c).done = 0) +#define init_completion(c) ((c)->done = 0) + +static inline void +_complete_common(struct completion *c, int all) +{ + int wakeup_swapper; + + sleepq_lock(c); + c->done++; + if (all) + wakeup_swapper = sleepq_broadcast(c, SLEEPQ_SLEEP, 0, 0); + else + wakeup_swapper = sleepq_signal(c, SLEEPQ_SLEEP, 0, 0); + sleepq_release(c); + if (wakeup_swapper) + kick_proc0(); +} + +#define complete(c) _complete_common(c, 0) +#define complete_all(c) _complete_common(c, 1) + +/* + * Indefinite wait for done != 0 with or without signals. + */ +static inline long +_wait_for_common(struct completion *c, int flags) +{ + + flags |= SLEEPQ_SLEEP; + for (;;) { + sleepq_lock(c); + if (c->done) + break; + sleepq_add(c, NULL, "completion", flags, 0); + if (flags & SLEEPQ_INTERRUPTIBLE) { + if (sleepq_wait_sig(c, 0) != 0) + return (-ERESTARTSYS); + } else + sleepq_wait(c, 0); + } + c->done--; + sleepq_release(c); + + return (0); +} + +#define wait_for_completion(c) _wait_for_common(c, 0) +#define wait_for_completion_interuptible(c) \ + _wait_for_common(c, SLEEPQ_INTERRUPTIBLE) + +static inline long +_wait_for_timeout_common(struct completion *c, long timeout, int flags) +{ + long end; + + end = ticks + timeout; + flags |= SLEEPQ_SLEEP; + for (;;) { + sleepq_lock(c); + if (c->done) + break; + sleepq_add(c, NULL, "completion", flags, 0); + sleepq_set_timeout(c, end - ticks); + if (flags & SLEEPQ_INTERRUPTIBLE) { + if (sleepq_timedwait_sig(c, 0) != 0) + return (-ERESTARTSYS); + } else + sleepq_timedwait(c, 0); + } + c->done--; + sleepq_release(c); + timeout = end - ticks; + + return (timeout > 0 ? timeout : 1); +} + +#define wait_for_completion_timeout(c, timeout) \ + _wait_for_timeout_common(c, timeout, 0) +#define wait_for_completion_interruptible_timeout(c, timeout) \ + _wait_for_timeout_common(c, timeout, SLEEPQ_INTERRUPTIBLE) + +static inline int +try_wait_for_completion(struct completion *c) +{ + int isdone; + + isdone = 1; + sleepq_lock(c); + if (c->done) + c->done--; + else + isdone = 0; + sleepq_release(c); + return (isdone); +} + +static inline int +completion_done(struct completion *c) +{ + int isdone; + + isdone = 1; + sleepq_lock(c); + if (c->done == 0) + isdone = 0; + sleepq_release(c); + return (isdone); +} + +#endif /* _LINUX_COMPLETION_H_ */ diff --git a/sys/ofed/include/linux/ctype.h b/sys/ofed/include/linux/ctype.h new file mode 100644 index 000000000000..3ed41379f9ce --- /dev/null +++ b/sys/ofed/include/linux/ctype.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_CTYPE_H_ +#define _LINUX_CTYPE_H_ + +#include + +#endif /* _LINUX_CTYPE_H_ */ diff --git a/sys/ofed/include/linux/delay.h b/sys/ofed/include/linux/delay.h new file mode 100644 index 000000000000..019ef8ad861e --- /dev/null +++ b/sys/ofed/include/linux/delay.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_DELAY_H_ +#define _LINUX_DELAY_H_ + +#include + +static inline void +linux_msleep(int ms) +{ + pause("lnxsleep", msecs_to_jiffies(ms)); +} + +#undef msleep +#define msleep linux_msleep + +#endif /* _LINUX_DELAY_H_ */ diff --git a/sys/ofed/include/linux/device.h b/sys/ofed/include/linux/device.h new file mode 100644 index 000000000000..cce46ca4b2c9 --- /dev/null +++ b/sys/ofed/include/linux/device.h @@ -0,0 +1,388 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_DEVICE_H_ +#define _LINUX_DEVICE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +enum irqreturn { IRQ_NONE = 0, IRQ_HANDLED, IRQ_WAKE_THREAD, }; +typedef enum irqreturn irqreturn_t; + +struct class { + const char *name; + struct module *owner; + struct kobject kobj; + devclass_t bsdclass; + void (*class_release)(struct class *class); + void (*dev_release)(struct device *dev); +}; + +struct device { + struct device *parent; + struct list_head irqents; + device_t bsddev; + dev_t devt; + struct class *class; + void (*release)(struct device *dev); + struct kobject kobj; + uint64_t *dma_mask; + void *driver_data; + unsigned int irq; + unsigned int msix; + unsigned int msix_max; +}; + +extern struct device linux_rootdev; +extern struct kobject class_root; + +struct class_attribute { + struct attribute attr; + ssize_t (*show)(struct class *, char *); + ssize_t (*store)(struct class *, const char *, size_t); +}; +#define CLASS_ATTR(_name, _mode, _show, _store) \ + struct class_attribute class_attr_##_name = \ + { { #_name, NULL, _mode }, _show, _store } + +struct device_attribute { + struct attribute attr; + ssize_t (*show)(struct device *, + struct device_attribute *, char *); + ssize_t (*store)(struct device *, + struct device_attribute *, const char *, + size_t); +}; + +#define DEVICE_ATTR(_name, _mode, _show, _store) \ + struct device_attribute dev_attr_##_name = \ + { { #_name, NULL, _mode }, _show, _store } + +#define dev_err(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) +#define dev_warn(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) +#define dev_info(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) +#define dev_printk(lvl, dev, fmt, ...) \ + device_printf((dev)->bsddev, fmt, ##__VA_ARGS__) + +static inline void * +dev_get_drvdata(struct device *dev) +{ + + return dev->driver_data; +} + +static inline void +dev_set_drvdata(struct device *dev, void *data) +{ + + dev->driver_data = data; +} + +static inline struct device * +get_device(struct device *dev) +{ + + if (dev) + kobject_get(&dev->kobj); + + return (dev); +} + +static inline char * +dev_name(const struct device *dev) +{ + + return kobject_name(&dev->kobj); +} + +#define dev_set_name(_dev, _fmt, ...) \ + kobject_set_name(&(_dev)->kobj, (_fmt), ##__VA_ARGS__) + +static inline void +put_device(struct device *dev) +{ + + if (dev) + kobject_put(&dev->kobj); +} + +static inline ssize_t +class_show(struct kobject *kobj, struct attribute *attr, char *buf) +{ + struct class_attribute *dattr; + ssize_t error; + + dattr = container_of(attr, struct class_attribute, attr); + error = -EIO; + if (dattr->show) + error = dattr->show(container_of(kobj, struct class, kobj), + buf); + return (error); +} + +static inline ssize_t +class_store(struct kobject *kobj, struct attribute *attr, const char *buf, + size_t count) +{ + struct class_attribute *dattr; + ssize_t error; + + dattr = container_of(attr, struct class_attribute, attr); + error = -EIO; + if (dattr->store) + error = dattr->store(container_of(kobj, struct class, kobj), + buf, count); + return (error); +} + +static inline void +class_release(struct kobject *kobj) +{ + struct class *class; + + class = container_of(kobj, struct class, kobj); + if (class->class_release) + class->class_release(class); +} + +static struct sysfs_ops class_sysfs = { + .show = class_show, + .store = class_store, +}; +static struct kobj_type class_ktype = { + .release = class_release, + .sysfs_ops = &class_sysfs +}; + +static inline int +class_register(struct class *class) +{ + + class->bsdclass = devclass_create(class->name); + kobject_init(&class->kobj, &class_ktype); + kobject_set_name(&class->kobj, class->name); + kobject_add(&class->kobj, &class_root, class->name); + + return (0); +} + +static inline void +class_unregister(struct class *class) +{ + + kobject_put(&class->kobj); +} + +static inline void +device_release(struct kobject *kobj) +{ + struct device *dev; + + dev = container_of(kobj, struct device, kobj); + /* This is the precedence defined by linux. */ + if (dev->release) + dev->release(dev); + else if (dev->class && dev->class->dev_release) + dev->class->dev_release(dev); +} + +static inline ssize_t +dev_show(struct kobject *kobj, struct attribute *attr, char *buf) +{ + struct device_attribute *dattr; + ssize_t error; + + dattr = container_of(attr, struct device_attribute, attr); + error = -EIO; + if (dattr->show) + error = dattr->show(container_of(kobj, struct device, kobj), + dattr, buf); + return (error); +} + +static inline ssize_t +dev_store(struct kobject *kobj, struct attribute *attr, const char *buf, + size_t count) +{ + struct device_attribute *dattr; + ssize_t error; + + dattr = container_of(attr, struct device_attribute, attr); + error = -EIO; + if (dattr->store) + error = dattr->store(container_of(kobj, struct device, kobj), + dattr, buf, count); + return (error); +} + +static struct sysfs_ops dev_sysfs = { .show = dev_show, .store = dev_store, }; +static struct kobj_type dev_ktype = { + .release = device_release, + .sysfs_ops = &dev_sysfs +}; + +/* + * Devices are registered and created for exporting to sysfs. create + * implies register and register assumes the device fields have been + * setup appropriately before being called. + */ +static inline int +device_register(struct device *dev) +{ + device_t bsddev; + int unit; + + bsddev = NULL; + if (dev->devt) { + unit = MINOR(dev->devt); + bsddev = devclass_get_device(dev->class->bsdclass, unit); + } else + unit = -1; + if (bsddev == NULL) + bsddev = device_add_child(dev->parent->bsddev, + dev->class->kobj.name, unit); + if (bsddev) { + if (dev->devt == 0) + dev->devt = makedev(0, device_get_unit(bsddev)); + device_set_softc(bsddev, dev); + } + dev->bsddev = bsddev; + kobject_init(&dev->kobj, &dev_ktype); + kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev)); + + return (0); +} + +static inline void +device_unregister(struct device *dev) +{ + device_t bsddev; + + bsddev = dev->bsddev; + mtx_lock(&Giant); + if (bsddev) + device_delete_child(device_get_parent(bsddev), bsddev); + mtx_unlock(&Giant); + put_device(dev); +} + +struct device *device_create(struct class *class, struct device *parent, + dev_t devt, void *drvdata, const char *fmt, ...); + +static inline void +device_destroy(struct class *class, dev_t devt) +{ + device_t bsddev; + int unit; + + unit = MINOR(devt); + bsddev = devclass_get_device(class->bsdclass, unit); + if (bsddev) + device_unregister(device_get_softc(bsddev)); +} + +static inline void +class_kfree(struct class *class) +{ + + kfree(class); +} + +static inline struct class * +class_create(struct module *owner, const char *name) +{ + struct class *class; + int error; + + class = kzalloc(sizeof(*class), M_WAITOK); + class->owner = owner; + class->name= name; + class->class_release = class_kfree; + error = class_register(class); + if (error) { + kfree(class); + return (NULL); + } + + return (class); +} + +static inline void +class_destroy(struct class *class) +{ + + if (class == NULL) + return; + class_unregister(class); +} + +static inline int +device_create_file(struct device *dev, const struct device_attribute *attr) +{ + + if (dev) + return sysfs_create_file(&dev->kobj, &attr->attr); + return -EINVAL; +} + +static inline void +device_remove_file(struct device *dev, const struct device_attribute *attr) +{ + + if (dev) + sysfs_remove_file(&dev->kobj, &attr->attr); +} + +static inline int +class_create_file(struct class *class, const struct class_attribute *attr) +{ + + if (class) + return sysfs_create_file(&class->kobj, &attr->attr); + return -EINVAL; +} + +static inline void +class_remove_file(struct class *class, const struct class_attribute *attr) +{ + + if (class) + sysfs_remove_file(&class->kobj, &attr->attr); +} + +#endif /* _LINUX_DEVICE_H_ */ diff --git a/sys/ofed/include/linux/dma-attrs.h b/sys/ofed/include/linux/dma-attrs.h new file mode 100644 index 000000000000..9e625bd1cd8c --- /dev/null +++ b/sys/ofed/include/linux/dma-attrs.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_DMA_ATTR_H_ +#define _LINUX_DMA_ATTR_H_ + +enum dma_attr { DMA_ATTR_WRITE_BARRIER, DMA_ATTR_WEAK_ORDERING, DMA_ATTR_MAX, }; + +#define __DMA_ATTRS_LONGS BITS_TO_LONGS(DMA_ATTR_MAX) + +struct dma_attrs { + unsigned long flags; +}; + +#define DEFINE_DMA_ATTRS(x) struct dma_attrs x = { } + +static inline void +init_dma_attrs(struct dma_attrs *attrs) +{ + attrs->flags = 0; +} + +#endif /* _LINUX_DMA_ATTR_H_ */ diff --git a/sys/ofed/include/linux/dma-mapping.h b/sys/ofed/include/linux/dma-mapping.h new file mode 100644 index 000000000000..c6535243214a --- /dev/null +++ b/sys/ofed/include/linux/dma-mapping.h @@ -0,0 +1,263 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_DMA_MAPPING_H_ +#define _LINUX_DMA_MAPPING_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +struct dma_map_ops { + void* (*alloc_coherent)(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp); + void (*free_coherent)(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle); + dma_addr_t (*map_page)(struct device *dev, struct page *page, + unsigned long offset, size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs); + void (*unmap_page)(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction dir, struct dma_attrs *attrs); + int (*map_sg)(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir, struct dma_attrs *attrs); + void (*unmap_sg)(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir, struct dma_attrs *attrs); + void (*sync_single_for_cpu)(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction dir); + void (*sync_single_for_device)(struct device *dev, + dma_addr_t dma_handle, size_t size, enum dma_data_direction dir); + void (*sync_single_range_for_cpu)(struct device *dev, + dma_addr_t dma_handle, unsigned long offset, size_t size, + enum dma_data_direction dir); + void (*sync_single_range_for_device)(struct device *dev, + dma_addr_t dma_handle, unsigned long offset, size_t size, + enum dma_data_direction dir); + void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir); + void (*sync_sg_for_device)(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir); + int (*mapping_error)(struct device *dev, dma_addr_t dma_addr); + int (*dma_supported)(struct device *dev, u64 mask); + int is_phys; +}; + +#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL << (n)) - 1)) + +static inline int +dma_supported(struct device *dev, u64 mask) +{ + + /* XXX busdma takes care of this elsewhere. */ + return (1); +} + +static inline int +dma_set_mask(struct device *dev, u64 dma_mask) +{ + + if (!dev->dma_mask || !dma_supported(dev, dma_mask)) + return -EIO; + + *dev->dma_mask = dma_mask; + return (0); +} + +static inline int +dma_set_coherent_mask(struct device *dev, u64 mask) +{ + + if (!dma_supported(dev, mask)) + return -EIO; + /* XXX Currently we don't support a seperate coherent mask. */ + return 0; +} + +static inline void * +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, + gfp_t flag) +{ + vm_paddr_t high; + size_t align; + void *mem; + + if (dev->dma_mask) + high = *dev->dma_mask; + else + high = BUS_SPACE_MAXADDR_32BIT; + align = PAGE_SIZE << get_order(size); + mem = (void *)kmem_alloc_contig(kmem_map, size, flag, 0, high, align, + 0, VM_MEMATTR_DEFAULT); + if (mem) + *dma_handle = vtophys(mem); + else + *dma_handle = 0; + return (mem); +} + +static inline void +dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t dma_handle) +{ + + kmem_free(kmem_map, (vm_offset_t)cpu_addr, size); +} + +/* XXX This only works with no iommu. */ +static inline dma_addr_t +dma_map_single_attrs(struct device *dev, void *ptr, size_t size, + enum dma_data_direction dir, struct dma_attrs *attrs) +{ + + return vtophys(ptr); +} + +static inline void +dma_unmap_single_attrs(struct device *dev, dma_addr_t addr, size_t size, + enum dma_data_direction dir, struct dma_attrs *attrs) +{ +} + +static inline int +dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl, int nents, + enum dma_data_direction dir, struct dma_attrs *attrs) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sgl, sg, nents, i) + sg_dma_address(sg) = sg_phys(sg); + + return (nents); +} + +static inline void +dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir, struct dma_attrs *attrs) +{ +} + +static inline dma_addr_t +dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, enum dma_data_direction direction) +{ + + return VM_PAGE_TO_PHYS(page) + offset; +} + +static inline void +dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction) +{ +} + +static inline void +dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ +} + +static inline void +dma_sync_single(struct device *dev, dma_addr_t addr, size_t size, + enum dma_data_direction dir) +{ + dma_sync_single_for_cpu(dev, addr, size, dir); +} + +static inline void +dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction direction) +{ +} + +static inline void +dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ +} + +static inline void +dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ +} + +static inline void +dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, int direction) +{ +} + +static inline void +dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, int direction) +{ +} + +static inline int +dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + + return (0); +} + +#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL) +#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, NULL) +#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL) +#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL) + +#define DEFINE_DMA_UNMAP_ADDR(name) dma_addr_t name +#define DEFINE_DMA_UNMAP_LEN(name) __u32 name +#define dma_unmap_addr(p, name) ((p)->name) +#define dma_unmap_addr_set(p, name, v) (((p)->name) = (v)) +#define dma_unmap_len(p, name) ((p)->name) +#define dma_unmap_len_set(p, name, v) (((p)->name) = (v)) + +extern int uma_align_cache; +#define dma_get_cache_alignment() uma_align_cache + +#endif /* _LINUX_DMA_MAPPING_H_ */ diff --git a/sys/ofed/include/linux/dmapool.h b/sys/ofed/include/linux/dmapool.h new file mode 100644 index 000000000000..3b58164c9afd --- /dev/null +++ b/sys/ofed/include/linux/dmapool.h @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_DMAPOOL_H_ +#define _LINUX_DMAPOOL_H_ + +#include +#include +#include +#include +#include + +struct dma_pool { + uma_zone_t pool_zone; +}; + +static inline struct dma_pool * +dma_pool_create(char *name, struct device *dev, size_t size, + size_t align, size_t boundary) +{ + struct dma_pool *pool; + + pool = kmalloc(sizeof(*pool), GFP_KERNEL); + align--; + /* + * XXX Eventually this could use a seperate allocf to honor boundary + * and physical address requirements of the device. + */ + pool->pool_zone = uma_zcreate(name, size, NULL, NULL, NULL, NULL, + align, UMA_ZONE_OFFPAGE|UMA_ZONE_HASH); + + return (pool); +} + +static inline void +dma_pool_destroy(struct dma_pool *pool) +{ + uma_zdestroy(pool->pool_zone); + kfree(pool); +} + +static inline void * +dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle) +{ + void *vaddr; + + vaddr = uma_zalloc(pool->pool_zone, mem_flags); + if (vaddr) + *handle = vtophys(vaddr); + return (vaddr); +} + +static inline void +dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t addr) +{ + uma_zfree(pool->pool_zone, vaddr); +} + + +#endif /* _LINUX_DMAPOOL_H_ */ diff --git a/sys/ofed/include/linux/err.h b/sys/ofed/include/linux/err.h new file mode 100644 index 000000000000..858931d2bbf9 --- /dev/null +++ b/sys/ofed/include/linux/err.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_ERR_H_ +#define _LINUX_ERR_H_ + +#define MAX_ERRNO 4095 + +#define IS_ERR_VALUE(x) ((x) >= (unsigned long)-MAX_ERRNO) + +static inline void * +ERR_PTR(long error) +{ + return (void *)error; +} + +static inline long +PTR_ERR(const void *ptr) +{ + return (long)ptr; +} + +static inline long +IS_ERR(const void *ptr) +{ + return IS_ERR_VALUE((unsigned long)ptr); +} + +static inline void * +ERR_CAST(void *ptr) +{ + return (void *)ptr; +} + +#endif /* _LINUX_ERR_H_ */ diff --git a/sys/ofed/include/linux/errno.h b/sys/ofed/include/linux/errno.h new file mode 100644 index 000000000000..b107c45ccad0 --- /dev/null +++ b/sys/ofed/include/linux/errno.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_ERRNO_H_ +#define _LINUX_ERRNO_H_ + +#include + +#define ECOMM ESTALE +#define ENODATA ECONNREFUSED +#define ENOIOCTLCMD ENOIOCTL /* XXX this is negative */ +#define ERESTARTSYS ERESTART /* XXX this is negative */ + +#endif /* _LINUX_ERRNO_H_ */ diff --git a/sys/ofed/include/linux/ethtool.h b/sys/ofed/include/linux/ethtool.h new file mode 100644 index 000000000000..a26720921891 --- /dev/null +++ b/sys/ofed/include/linux/ethtool.h @@ -0,0 +1,31 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_ETHTOOL_H_ +#define _LINUX_ETHTOOL_H_ + +#endif /* _LINUX_ETHTOOL_H_ */ diff --git a/sys/ofed/include/linux/file.h b/sys/ofed/include/linux/file.h new file mode 100644 index 000000000000..12858d7648be --- /dev/null +++ b/sys/ofed/include/linux/file.h @@ -0,0 +1,120 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_FILE_H_ +#define _LINUX_FILE_H_ + +#include +#include +#include +#include +#include + +#include + +struct linux_file; + +#undef file + +extern struct fileops linuxfileops; + +static inline struct linux_file * +linux_fget(unsigned int fd) +{ + struct file *file; + + file = fget_unlocked(curthread->td_proc->p_fd, fd); + return (struct linux_file *)file->f_data; +} + +static inline void +fput(struct linux_file *filp) +{ + if (filp->_file == NULL) { + kfree(filp); + return; + } + if (refcount_release(&filp->_file->f_count)) { + _fdrop(filp->_file, curthread); + kfree(filp); + } +} + +static inline void +put_unused_fd(unsigned int fd) +{ + struct file *file; + + file = fget_unlocked(curthread->td_proc->p_fd, fd); + if (file == NULL) + return; + fdclose(curthread->td_proc->p_fd, file, fd, curthread); +} + +static inline void +fd_install(unsigned int fd, struct linux_file *filp) +{ + struct file *file; + + file = fget_unlocked(curthread->td_proc->p_fd, fd); + filp->_file = file; + finit(file, filp->f_mode, DTYPE_DEV, filp, &linuxfileops); +} + +static inline int +get_unused_fd(void) +{ + struct file *file; + int error; + int fd; + + error = falloc(curthread, &file, &fd); + if (error) + return -error; + return fd; +} + +static inline struct linux_file * +_alloc_file(int mode, const struct file_operations *fops) +{ + struct linux_file *filp; + + filp = kzalloc(sizeof(*filp), GFP_KERNEL); + if (filp == NULL) + return (NULL); + filp->f_op = fops; + filp->f_mode = mode; + + return filp; +} + +#define alloc_file(mnt, root, mode, fops) _alloc_file((mode), (fops)) + +#define file linux_file +#define fget linux_fget + +#endif /* _LINUX_FILE_H_ */ diff --git a/sys/ofed/include/linux/fs.h b/sys/ofed/include/linux/fs.h new file mode 100644 index 000000000000..4e667ccb005e --- /dev/null +++ b/sys/ofed/include/linux/fs.h @@ -0,0 +1,182 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_FS_H_ +#define _LINUX_FS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct module; +struct kiocb; +struct iovec; +struct dentry; +struct page; +struct file_lock; +struct pipe_inode_info; +struct vm_area_struct; +struct poll_table_struct; +struct files_struct; + +#define inode vnode +#define i_cdev v_rdev + +#define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH) +#define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH) + + +typedef struct files_struct *fl_owner_t; + +struct dentry { + struct inode *d_inode; +}; + +struct file_operations; + +struct linux_file { + struct file *_file; + const struct file_operations *f_op; + void *private_data; + int f_flags; + int f_mode; /* Just starting mode. */ + struct dentry *f_dentry; + struct dentry f_dentry_store; + struct selinfo f_selinfo; + struct sigio *f_sigio; +}; + +#define file linux_file +#define fasync_struct sigio * + +#define fasync_helper(fd, filp, on, queue) \ +({ \ + if ((on)) \ + *(queue) = &(filp)->f_sigio; \ + else \ + *(queue) = NULL; \ + 0; \ +}) + +#define kill_fasync(queue, sig, pollstat) \ +do { \ + if (*(queue) != NULL) \ + pgsigio(*(queue), (sig), 0); \ +} while (0) + +typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned); + +struct file_operations { + struct module *owner; + ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); + ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); + unsigned int (*poll) (struct file *, struct poll_table_struct *); + long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long); + int (*mmap)(struct file *, struct vm_area_struct *); + int (*open)(struct inode *, struct file *); + int (*release)(struct inode *, struct file *); + int (*fasync)(int, struct file *, int); +#if 0 + /* We do not support these methods. Don't permit them to compile. */ + loff_t (*llseek)(struct file *, loff_t, int); + ssize_t (*aio_read)(struct kiocb *, const struct iovec *, + unsigned long, loff_t); + ssize_t (*aio_write)(struct kiocb *, const struct iovec *, + unsigned long, loff_t); + int (*readdir)(struct file *, void *, filldir_t); + int (*ioctl)(struct inode *, struct file *, unsigned int, + unsigned long); + long (*compat_ioctl)(struct file *, unsigned int, unsigned long); + int (*flush)(struct file *, fl_owner_t id); + int (*fsync)(struct file *, struct dentry *, int datasync); + int (*aio_fsync)(struct kiocb *, int datasync); + int (*lock)(struct file *, int, struct file_lock *); + ssize_t (*sendpage)(struct file *, struct page *, int, size_t, + loff_t *, int); + unsigned long (*get_unmapped_area)(struct file *, unsigned long, + unsigned long, unsigned long, unsigned long); + int (*check_flags)(int); + int (*flock)(struct file *, int, struct file_lock *); + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, + loff_t *, size_t, unsigned int); + ssize_t (*splice_read)(struct file *, loff_t *, + struct pipe_inode_info *, size_t, unsigned int); + int (*setlease)(struct file *, long, struct file_lock **); +#endif +}; +#define fops_get(fops) (fops) + +#define FMODE_READ FREAD +#define FMODE_WRITE FWRITE +#define FMODE_EXEC FEXEC + +static inline int +register_chrdev_region(dev_t dev, unsigned range, const char *name) +{ + + return 0; +} + +static inline void +unregister_chrdev_region(dev_t dev, unsigned range) +{ + + return; +} + +static inline dev_t +iminor(struct inode *inode) +{ + + return dev2unit(inode->v_rdev); +} + +static inline struct inode * +igrab(struct inode *inode) +{ + int error; + + error = vget(inode, 0, curthread); + if (error) + return (NULL); + + return (inode); +} + +static inline void +iput(struct inode *inode) +{ + + vrele(inode); +} + +#endif /* _LINUX_FS_H_ */ diff --git a/sys/ofed/include/linux/gfp.h b/sys/ofed/include/linux/gfp.h new file mode 100644 index 000000000000..7f8a24ff7222 --- /dev/null +++ b/sys/ofed/include/linux/gfp.h @@ -0,0 +1,122 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_GFP_H_ +#define _LINUX_GFP_H_ + +#include +#include + +#include + +#include +#include +#include + +#define __GFP_NOWARN 0 +#define __GFP_HIGHMEM 0 +#define __GFP_ZERO M_ZERO + +#define GFP_NOWAIT M_NOWAIT +#define GFP_ATOMIC (M_NOWAIT | M_USE_RESERVE) +#define GFP_KERNEL M_WAITOK +#define GFP_USER M_WAITOK +#define GFP_HIGHUSER M_WAITOK +#define GFP_HIGHUSER_MOVABLE M_WAITOK +#define GFP_IOFS M_NOWAIT + +static inline void * +page_address(struct page *page) +{ + + if (page->object != kmem_object && page->object != kernel_object) + return (NULL); + return (void *)(VM_MIN_KERNEL_ADDRESS + IDX_TO_OFF(page->pindex)); +} + +static inline unsigned long +_get_page(gfp_t mask) +{ + + return kmem_malloc(kmem_map, PAGE_SIZE, mask); +} + +#define get_zeroed_page(mask) _get_page((mask) | M_ZERO) +#define alloc_page(mask) virt_to_page(_get_page((mask))) +#define __get_free_page(mask) _get_page((mask)) + +static inline void +free_page(unsigned long page) +{ + + if (page == 0) + return; + kmem_free(kmem_map, page, PAGE_SIZE); +} + +static inline void +__free_page(struct page *m) +{ + + if (m->object != kmem_object) + panic("__free_page: Freed page %p not allocated via wrappers.", + m); + kmem_free(kmem_map, (vm_offset_t)page_address(m), PAGE_SIZE); +} + +static inline void +__free_pages(void *p, unsigned int order) +{ + size_t size; + + if (p == 0) + return; + size = PAGE_SIZE << order; + kmem_free(kmem_map, (vm_offset_t)p, size); +} + +/* + * Alloc pages allocates directly from the buddy allocator on linux so + * order specifies a power of two bucket of pages and the results + * are expected to be aligned on the size as well. + */ +static inline struct page * +alloc_pages(gfp_t gfp_mask, unsigned int order) +{ + unsigned long page; + size_t size; + + size = PAGE_SIZE << order; + page = kmem_alloc_contig(kmem_map, size, gfp_mask, 0, -1, + size, 0, VM_MEMATTR_DEFAULT); + if (page == 0) + return (NULL); + return (virt_to_page(page)); +} + +#endif /* _LINUX_GFP_H_ */ diff --git a/sys/ofed/include/linux/hardirq.h b/sys/ofed/include/linux/hardirq.h new file mode 100644 index 000000000000..4c3aeba1de14 --- /dev/null +++ b/sys/ofed/include/linux/hardirq.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_HARDIRQ_H_ +#define _LINUX_HARDIRQ_H_ + +#include + +#include +#include +#include + +#define synchronize_irq(irq) _intr_drain((irq)) + +#endif /* _LINUX_HARDIRQ_H_ */ diff --git a/sys/ofed/include/linux/idr.h b/sys/ofed/include/linux/idr.h new file mode 100644 index 000000000000..40b25b663eb7 --- /dev/null +++ b/sys/ofed/include/linux/idr.h @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_IDR_H_ +#define _LINUX_IDR_H_ + +#include + +#define IDR_BITS 5 +#define IDR_SIZE (1 << IDR_BITS) +#define IDR_MASK (IDR_SIZE - 1) + +#define MAX_ID_SHIFT ((sizeof(int) * NBBY) - 1) +#define MAX_ID_BIT (1U << MAX_ID_SHIFT) +#define MAX_ID_MASK (MAX_ID_BIT - 1) +#define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS + +struct idr_layer { + unsigned long bitmap; + struct idr_layer *ary[IDR_SIZE]; +}; + +struct idr { + struct mtx lock; + struct idr_layer *top; + struct idr_layer *free; + int layers; +}; + +#define DEFINE_IDR(name) \ + struct idr name; \ + SYSINIT(name##_idr_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, \ + idr_init, &(name)); + +void *idr_find(struct idr *idp, int id); +int idr_pre_get(struct idr *idp, gfp_t gfp_mask); +int idr_get_new(struct idr *idp, void *ptr, int *id); +int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id); +void *idr_replace(struct idr *idp, void *ptr, int id); +void idr_remove(struct idr *idp, int id); +void idr_remove_all(struct idr *idp); +void idr_destroy(struct idr *idp); +void idr_init(struct idr *idp); + +#endif /* _LINUX_IDR_H_ */ diff --git a/sys/ofed/include/linux/if_arp.h b/sys/ofed/include/linux/if_arp.h new file mode 100644 index 000000000000..c82a2c5c1b00 --- /dev/null +++ b/sys/ofed/include/linux/if_arp.h @@ -0,0 +1,32 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_IF_ARP_H_ +#define _LINUX_IF_ARP_H_ +#include +#include +#endif /* _LINUX_IF_ARP_H_ */ diff --git a/sys/ofed/include/linux/if_ether.h b/sys/ofed/include/linux/if_ether.h new file mode 100644 index 000000000000..960865781dd4 --- /dev/null +++ b/sys/ofed/include/linux/if_ether.h @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_IF_ETHER_H_ +#define _LINUX_IF_ETHER_H_ + +#include + +#include + +#define ETH_P_8021Q ETHERTYPE_VLAN + +#endif /* _LINUX_IF_ETHER_H_ */ diff --git a/sys/ofed/include/linux/if_vlan.h b/sys/ofed/include/linux/if_vlan.h new file mode 100644 index 000000000000..bb7eee0654b6 --- /dev/null +++ b/sys/ofed/include/linux/if_vlan.h @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_IF_VLAN_H_ +#define _LINUX_IF_VLAN_H_ + +#include +#include + +#endif /* _LINUX_IF_VLAN_H_ */ diff --git a/sys/ofed/include/linux/in.h b/sys/ofed/include/linux/in.h new file mode 100644 index 000000000000..8fa3dc2a2bc2 --- /dev/null +++ b/sys/ofed/include/linux/in.h @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_IN_H_ +#define _LINUX_IN_H_ + +#include +#include + +#define ipv4_is_zeronet IN_ZERONET +#define ipv4_is_loopback IN_LOOPBACK + +#endif /* _LINUX_IN_H_ */ diff --git a/sys/ofed/include/linux/in6.h b/sys/ofed/include/linux/in6.h new file mode 100644 index 000000000000..2032b6179594 --- /dev/null +++ b/sys/ofed/include/linux/in6.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_IN6_H_ +#define _LINUX_IN6_H_ + +#ifndef KLD_MODULE +#include "opt_inet6.h" +#endif + +#endif /* _LINUX_IN6_H_ */ diff --git a/sys/ofed/include/linux/inet.h b/sys/ofed/include/linux/inet.h new file mode 100644 index 000000000000..07fcc73a0b6d --- /dev/null +++ b/sys/ofed/include/linux/inet.h @@ -0,0 +1,31 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_INET_H_ +#define _LINUX_INET_H_ +#endif /* _LINUX_INET_H_ */ diff --git a/sys/ofed/include/linux/inetdevice.h b/sys/ofed/include/linux/inetdevice.h new file mode 100644 index 000000000000..c7fe1d2bbe8a --- /dev/null +++ b/sys/ofed/include/linux/inetdevice.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_INETDEVICE_H_ +#define _LINUX_INETDEVICE_H_ + +#include + +static inline struct net_device * +ip_dev_find(struct net *net, uint32_t addr) +{ + struct sockaddr_in sin; + struct ifaddr *ifa; + struct ifnet *ifp; + + ifp = NULL; + memset(&sin, 0, sizeof(sin)); + sin.sin_addr.s_addr = addr; + sin.sin_port = 0; + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + ifa = ifa_ifwithaddr((struct sockaddr *)&sin); + if (ifa) { + ifp = ifa->ifa_ifp; + if_ref(ifp); + ifa_free(ifa); + } + return (ifp); +} + +#endif /* _LINUX_INETDEVICE_H_ */ diff --git a/sys/ofed/include/linux/init.h b/sys/ofed/include/linux/init.h new file mode 100644 index 000000000000..d7c2bb13caab --- /dev/null +++ b/sys/ofed/include/linux/init.h @@ -0,0 +1,31 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_INIT_H_ +#define _LINUX_INIT_H_ + +#endif /* _LINUX_INIT_H_ */ diff --git a/sys/ofed/include/linux/interrupt.h b/sys/ofed/include/linux/interrupt.h new file mode 100644 index 000000000000..e35882c9b4e5 --- /dev/null +++ b/sys/ofed/include/linux/interrupt.h @@ -0,0 +1,139 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_INTERRUPT_H_ +#define _LINUX_INTERRUPT_H_ + +#include +#include + +#include +#include + +typedef irqreturn_t (*irq_handler_t)(int, void *); + +#define IRQ_RETVAL(x) ((x) != IRQ_NONE) + +#define IRQF_SHARED RF_SHAREABLE + +struct irq_ent { + struct list_head links; + struct device *dev; + struct resource *res; + void *arg; + irqreturn_t (*handler)(int, void *); + void *tag; + int irq; +}; + +static inline int +_irq_rid(struct device *dev, int irq) +{ + if (irq == dev->irq) + return (0); + return irq - dev->msix + 1; +} + +static void +_irq_handler(void *ent) +{ + struct irq_ent *irqe; + + irqe = ent; + irqe->handler(irqe->irq, irqe->arg); +} + +static inline struct irq_ent * +_irq_ent(struct device *dev, int irq) +{ + struct irq_ent *irqe; + + list_for_each_entry(irqe, &dev->irqents, links) + if (irqe->irq == irq) + return (irqe); + + return (NULL); +} + +static inline int +request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, + const char *name, void *arg) +{ + struct resource *res; + struct irq_ent *irqe; + struct device *dev; + int error; + int rid; + + dev = _pci_find_irq_dev(irq); + if (dev == NULL) + return -ENXIO; + rid = _irq_rid(dev, irq); + res = bus_alloc_resource_any(dev->bsddev, SYS_RES_IRQ, &rid, + flags | RF_ACTIVE); + if (res == NULL) + return (-ENXIO); + irqe = kmalloc(sizeof(*irqe), GFP_KERNEL); + irqe->dev = dev; + irqe->res = res; + irqe->arg = arg; + irqe->handler = handler; + irqe->irq = irq; + error = bus_setup_intr(dev->bsddev, res, INTR_TYPE_NET | INTR_MPSAFE, + NULL, _irq_handler, irqe, &irqe->tag); + if (error) { + bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res); + kfree(irqe); + return (-error); + } + list_add(&irqe->links, &dev->irqents); + + return 0; +} + +static inline void +free_irq(unsigned int irq, void *device) +{ + struct irq_ent *irqe; + struct device *dev; + int rid; + + dev = _pci_find_irq_dev(irq); + if (dev == NULL) + return; + rid = _irq_rid(dev, irq); + irqe = _irq_ent(dev, irq); + if (irqe == NULL) + return; + bus_teardown_intr(dev->bsddev, irqe->res, irqe->tag); + bus_release_resource(dev->bsddev, SYS_RES_IRQ, rid, irqe->res); + list_del(&irqe->links); + kfree(irqe); +} + +#endif /* _LINUX_INTERRUPT_H_ */ diff --git a/sys/ofed/include/linux/io-mapping.h b/sys/ofed/include/linux/io-mapping.h new file mode 100644 index 000000000000..0753bbc5f1b0 --- /dev/null +++ b/sys/ofed/include/linux/io-mapping.h @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_IO_MAPPING_H_ +#define _LINUX_IO_MAPPING_H_ + +#include +#include + +struct io_mapping; + +static inline struct io_mapping * +io_mapping_create_wc(resource_size_t base, unsigned long size) +{ + + return ioremap_wc(base, size); +} + +static inline void +io_mapping_free(struct io_mapping *mapping) +{ + + iounmap(mapping); +} + +static inline void * +io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset) +{ + + return (((char *)mapping) + offset); +} + +static inline void +io_mapping_unmap_atomic(void *vaddr) +{ + +} + +static inline void * +io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset) +{ + + return (((char *) mapping) + offset); +} + +static inline void +io_mapping_unmap(void *vaddr) +{ + +} + +#endif /* _LINUX_IO_MAPPING_H_ */ diff --git a/sys/ofed/include/linux/io.h b/sys/ofed/include/linux/io.h new file mode 100644 index 000000000000..5405be7db98b --- /dev/null +++ b/sys/ofed/include/linux/io.h @@ -0,0 +1,125 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_IO_H_ +#define _LINUX_IO_H_ + +#include + +static inline uint32_t +__raw_readl(const volatile void *addr) +{ + return *(const volatile uint32_t *)addr; +} + +static inline void +__raw_writel(uint32_t b, volatile void *addr) +{ + *(volatile uint32_t *)addr = b; +} + +static inline uint64_t +__raw_readq(const volatile void *addr) +{ + return *(const volatile uint64_t *)addr; +} + +static inline void +__raw_writeq(uint64_t b, volatile void *addr) +{ + *(volatile uint64_t *)addr = b; +} + +/* + * XXX This is all x86 specific. It should be bus space access. + */ +#define mmiowb() + +#undef writel +static inline void +writel(uint32_t b, void *addr) +{ + *(volatile uint32_t *)addr = b; +} + +#undef writeq +static inline void +writeq(uint64_t b, void *addr) +{ + *(volatile uint64_t *)addr = b; +} + +#undef writeb +static inline void +writeb(uint8_t b, void *addr) +{ + *(volatile uint8_t *)addr = b; +} + +#undef writew +static inline void +writew(uint16_t b, void *addr) +{ + *(volatile uint16_t *)addr = b; +} + +void *_ioremap_attr(vm_paddr_t phys_addr, unsigned long size, int attr); +#define ioremap_nocache(addr, size) \ + _ioremap_attr((addr), (size), VM_MEMATTR_UNCACHED) +#define ioremap_wc(addr, size) \ + _ioremap_attr((addr), (size), VM_MEMATTR_WRITE_COMBINING) +#define ioremap ioremap_nocache +void iounmap(void *addr); + +#define memset_io(a, b, c) memset((a), (b), (c)) +#define memcpy_fromio(a, b, c) memcpy((a), (b), (c)) +#define memcpy_toio(a, b, c) memcpy((a), (b), (c)) + +static inline void +__iowrite64_copy(void *to, void *from, size_t count) +{ +#ifdef __LP64__ + uint64_t *src; + uint64_t *dst; + int i; + + for (i = 0, src = from, dst = to; i < count; i++, src++, dst++) + __raw_writeq(*src, dst); +#else + uint32_t *src; + uint32_t *dst; + int i; + + count *= 2; + for (i = 0, src = from, dst = to; i < count; i++, src++, dst++) + __raw_writel(*src, dst); +#endif +} + + +#endif /* _LINUX_IO_H_ */ diff --git a/sys/ofed/include/linux/ioctl.h b/sys/ofed/include/linux/ioctl.h new file mode 100644 index 000000000000..9e00b7f2a807 --- /dev/null +++ b/sys/ofed/include/linux/ioctl.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_IOCTL_H_ +#define _LINUX_IOCTL_H_ + +#include + +#endif /* _LINUX_IOCTL_H_ */ diff --git a/sys/ofed/include/linux/jhash.h b/sys/ofed/include/linux/jhash.h new file mode 100644 index 000000000000..ff6ff098cd79 --- /dev/null +++ b/sys/ofed/include/linux/jhash.h @@ -0,0 +1,143 @@ +#ifndef _LINUX_JHASH_H_ +#define _LINUX_JHASH_H_ + +/* jhash.h: Jenkins hash support. + * + * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net) + * + * http://burtleburtle.net/bob/hash/ + * + * These are the credits from Bob's sources: + * + * lookup2.c, by Bob Jenkins, December 1996, Public Domain. + * hash(), hash2(), hash3, and mix() are externally useful functions. + * Routines to test the hash are included if SELF_TEST is defined. + * You can use this free for any purpose. It has no warranty. + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * + * I've modified Bob's hash to be useful in the Linux kernel, and + * any bugs present are surely my fault. -DaveM + */ + +/* NOTE: Arguments are modified. */ +#define __jhash_mix(a, b, c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<<8); \ + c -= a; c -= b; c ^= (b>>13); \ + a -= b; a -= c; a ^= (c>>12); \ + b -= c; b -= a; b ^= (a<<16); \ + c -= a; c -= b; c ^= (b>>5); \ + a -= b; a -= c; a ^= (c>>3); \ + b -= c; b -= a; b ^= (a<<10); \ + c -= a; c -= b; c ^= (b>>15); \ +} + +/* The golden ration: an arbitrary value */ +#define JHASH_GOLDEN_RATIO 0x9e3779b9 + +/* The most generic version, hashes an arbitrary sequence + * of bytes. No alignment or length assumptions are made about + * the input key. + */ +static inline u32 jhash(const void *key, u32 length, u32 initval) +{ + u32 a, b, c, len; + const u8 *k = key; + + len = length; + a = b = JHASH_GOLDEN_RATIO; + c = initval; + + while (len >= 12) { + a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24)); + b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24)); + c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24)); + + __jhash_mix(a,b,c); + + k += 12; + len -= 12; + } + + c += length; + switch (len) { + case 11: c += ((u32)k[10]<<24); + case 10: c += ((u32)k[9]<<16); + case 9 : c += ((u32)k[8]<<8); + case 8 : b += ((u32)k[7]<<24); + case 7 : b += ((u32)k[6]<<16); + case 6 : b += ((u32)k[5]<<8); + case 5 : b += k[4]; + case 4 : a += ((u32)k[3]<<24); + case 3 : a += ((u32)k[2]<<16); + case 2 : a += ((u32)k[1]<<8); + case 1 : a += k[0]; + }; + + __jhash_mix(a,b,c); + + return c; +} + +/* A special optimized version that handles 1 or more of u32s. + * The length parameter here is the number of u32s in the key. + */ +static inline u32 jhash2(const u32 *k, u32 length, u32 initval) +{ + u32 a, b, c, len; + + a = b = JHASH_GOLDEN_RATIO; + c = initval; + len = length; + + while (len >= 3) { + a += k[0]; + b += k[1]; + c += k[2]; + __jhash_mix(a, b, c); + k += 3; len -= 3; + } + + c += length * 4; + + switch (len) { + case 2 : b += k[1]; + case 1 : a += k[0]; + }; + + __jhash_mix(a,b,c); + + return c; +} + + +/* A special ultra-optimized versions that knows they are hashing exactly + * 3, 2 or 1 word(s). + * + * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally + * done at the end is not done here. + */ +static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) +{ + a += JHASH_GOLDEN_RATIO; + b += JHASH_GOLDEN_RATIO; + c += initval; + + __jhash_mix(a, b, c); + + return c; +} + +static inline u32 jhash_2words(u32 a, u32 b, u32 initval) +{ + return jhash_3words(a, b, 0, initval); +} + +static inline u32 jhash_1word(u32 a, u32 initval) +{ + return jhash_3words(a, 0, 0, initval); +} + +#endif /* _LINUX_JHASH_H_ */ diff --git a/sys/ofed/include/linux/jiffies.h b/sys/ofed/include/linux/jiffies.h new file mode 100644 index 000000000000..7ca63375ec61 --- /dev/null +++ b/sys/ofed/include/linux/jiffies.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_JIFFIES_H_ +#define _LINUX_JIFFIES_H_ + +#include +#include + +#include +#include + +static inline int +msecs_to_jiffies(int msec) +{ + struct timeval tv; + + tv.tv_sec = msec / 1000; + tv.tv_usec = (msec % 1000) * 1000; + return (tvtohz(&tv)); +} + +#define jiffies ticks + +#define time_after(a, b) ((long)(b) - (long)(a) < 0) +#define time_before(a, b) time_after(b,a) +#define time_after_eq(a, b) ((long)(a) - (long)(b) >= 0) +#define time_before_eq(a, b) time_after_eq(b, a) + +#define HZ hz + +#endif /* _LINUX_JIFFIES_H_ */ diff --git a/sys/ofed/include/linux/kdev_t.h b/sys/ofed/include/linux/kdev_t.h new file mode 100644 index 000000000000..4b4f43ef6f5e --- /dev/null +++ b/sys/ofed/include/linux/kdev_t.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_KDEV_T_H_ +#define _LINUX_KDEV_T_H_ + +#define MAJOR(dev) major((dev)) +#define MINOR(dev) minor((dev)) +#define MKDEV(ma, mi) makedev((ma), (mi)) + +#endif /* _LINUX_KDEV_T_H_ */ diff --git a/sys/ofed/include/linux/kernel.h b/sys/ofed/include/linux/kernel.h new file mode 100644 index 000000000000..f49036e72414 --- /dev/null +++ b/sys/ofed/include/linux/kernel.h @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_KERNEL_H_ +#define _LINUX_KERNEL_H_ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KERN_EMERG "<0>" +#define KERN_ALERT "<1>" +#define KERN_CRIT "<2>" +#define KERN_ERR "<3>" +#define KERN_WARNING "<4>" +#define KERN_NOTICE "<5>" +#define KERN_INFO "<6>" +#define KERN_DEBUG "<7>" + +#define BUG() panic("BUG") +#define BUG_ON(condition) do { if (condition) BUG(); } while(0) +#define WARN_ON BUG_ON + +#undef ALIGN +#define ALIGN(x, y) roundup2((x), (y)) +#define DIV_ROUND_UP howmany + +#define printk(X...) printf(X) +#define pr_debug(fmt, ...) printk(KERN_DEBUG # fmt, ##__VA_ARGS__) +#define udelay(t) DELAY(t) + +#define container_of(ptr, type, member) \ +({ \ + __typeof(((type *)0)->member) *_p = (ptr); \ + (type *)((char *)_p - offsetof(type, member)); \ +}) + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#define simple_strtoul strtoul + +#define min(x, y) (x < y ? x : y) +#define max(x, y) (x > y ? x : y) +#define min_t(type, _x, _y) (type)(_x) < (type)(_y) ? (type)(_x) : (_y) +#define max_t(type, _x, _y) (type)(_x) > (type)(_y) ? (type)(_x) : (_y) + +#define num_possible_cpus() mp_ncpus + +#endif /* _LINUX_KERNEL_H_ */ diff --git a/sys/ofed/include/linux/kobject.h b/sys/ofed/include/linux/kobject.h new file mode 100644 index 000000000000..5872c05e09f4 --- /dev/null +++ b/sys/ofed/include/linux/kobject.h @@ -0,0 +1,153 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_KOBJECT_H_ +#define _LINUX_KOBJECT_H_ + +#include + +#include +#include +#include + +struct kobject; +struct sysctl_oid; + +struct kobj_type { + void (*release)(struct kobject *kobj); + const struct sysfs_ops *sysfs_ops; + struct attribute **default_attrs; +}; + +extern struct kobj_type kfree_type; + +struct kobject { + struct kobject *parent; + char *name; + struct kref kref; + struct kobj_type *ktype; + struct list_head entry; + struct sysctl_oid *oidp; +}; + +static inline void +kobject_init(struct kobject *kobj, struct kobj_type *ktype) +{ + + kref_init(&kobj->kref); + INIT_LIST_HEAD(&kobj->entry); + kobj->ktype = ktype; + kobj->oidp = NULL; +} + +static inline void kobject_put(struct kobject *kobj); +void kobject_release(struct kref *kref); + +static inline void +kobject_put(struct kobject *kobj) +{ + + if (kobj) + kref_put(&kobj->kref, kobject_release); +} + +static inline struct kobject * +kobject_get(struct kobject *kobj) +{ + + if (kobj) + kref_get(&kobj->kref); + return kobj; +} + +static inline int +kobject_set_name_vargs(struct kobject *kobj, const char *fmt, va_list args) +{ + char *old; + char *name; + + old = kobj->name; + + if (old && !fmt) + return 0; + + name = kzalloc(MAXPATHLEN, GFP_KERNEL); + if (!name) + return -ENOMEM; + vsnprintf(name, MAXPATHLEN, fmt, args); + kobj->name = name; + kfree(old); + for (; *name != '\0'; name++) + if (*name == '/') + *name = '!'; + return (0); +} + +int kobject_add(struct kobject *kobj, struct kobject *parent, + const char *fmt, ...); + +static inline struct kobject * +kobject_create(void) +{ + struct kobject *kobj; + + kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); + if (kobj == NULL) + return (NULL); + kobject_init(kobj, &kfree_type); + + return (kobj); +} + +static inline struct kobject * +kobject_create_and_add(const char *name, struct kobject *parent) +{ + struct kobject *kobj; + + kobj = kobject_create(); + if (kobj == NULL) + return (NULL); + if (kobject_add(kobj, parent, "%s", name) == 0) + return (kobj); + kobject_put(kobj); + + return (NULL); +} + + +static inline char * +kobject_name(const struct kobject *kobj) +{ + + return kobj->name; +} + +int kobject_set_name(struct kobject *kobj, const char *fmt, ...); +int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, + struct kobject *parent, const char *fmt, ...); + +#endif /* _LINUX_KOBJECT_H_ */ diff --git a/sys/ofed/include/linux/kref.h b/sys/ofed/include/linux/kref.h new file mode 100644 index 000000000000..14346c1941c4 --- /dev/null +++ b/sys/ofed/include/linux/kref.h @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_KREF_H_ +#define _LINUX_KREF_H_ + +#include + +struct kref { + volatile u_int count; +}; + +static inline void +kref_init(struct kref *kref) +{ + + refcount_init(&kref->count, 1); +} + +static inline void +kref_get(struct kref *kref) +{ + + refcount_acquire(&kref->count); +} + +static inline int +kref_put(struct kref *kref, void (*rel)(struct kref *kref)) +{ + + if (refcount_release(&kref->count)) { + rel(kref); + return 1; + } + return 0; +} + +#endif /* _KREF_H_ */ diff --git a/sys/ofed/include/linux/kthread.h b/sys/ofed/include/linux/kthread.h new file mode 100644 index 000000000000..e288295821df --- /dev/null +++ b/sys/ofed/include/linux/kthread.h @@ -0,0 +1,104 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_KTHREAD_H_ +#define _LINUX_KTHREAD_H_ + +#include +#include +#include +#include +#include +#include + +#include +#include + +static inline void +_kthread_fn(void *arg) +{ + struct task_struct *task; + + task = arg; + task_struct_set(curthread, task); + if (task->should_stop == 0) + task->task_ret = task->task_fn(task->task_data); + PROC_LOCK(task->task_thread->td_proc); + task->should_stop = TASK_STOPPED; + wakeup(task); + PROC_UNLOCK(task->task_thread->td_proc); + kthread_exit(); +} + +static inline struct task_struct * +_kthread_create(int (*threadfn)(void *data), void *data) +{ + struct task_struct *task; + + task = kzalloc(sizeof(*task), GFP_KERNEL); + task->task_fn = threadfn; + task->task_data = data; + + return (task); +} + +struct task_struct *kthread_create(int (*threadfn)(void *data), + void *data, + const char namefmt[], ...) + __attribute__((format(printf, 3, 4))); + +#define kthread_run(fn, data, fmt, ...) \ +({ \ + struct task_struct *_task; \ + \ + _task = _kthread_create((fn), (data)); \ + if (kthread_add(_kthread_fn, _task, NULL, &_task->task_thread, \ + 0, 0, fmt, ## __VA_ARGS__)) { \ + kfree(_task); \ + _task = NULL; \ + } else \ + task_struct_set(_task->task_thread, _task); \ + _task; \ +}) + +#define kthread_should_stop() current->should_stop + +static inline int +kthread_stop(struct task_struct *task) +{ + + PROC_LOCK(task->task_thread->td_proc); + task->should_stop = TASK_SHOULD_STOP; + wake_up_process(task); + while (task->should_stop != TASK_STOPPED) + msleep(task, &task->task_thread->td_proc->p_mtx, PWAIT, + "kstop", hz); + PROC_UNLOCK(task->task_thread->td_proc); + return task->task_ret; +} + +#endif /* _LINUX_KTHREAD_H_ */ diff --git a/sys/ofed/include/linux/linux_compat.c b/sys/ofed/include/linux/linux_compat.c new file mode 100644 index 000000000000..98ad807d2aa7 --- /dev/null +++ b/sys/ofed/include/linux/linux_compat.c @@ -0,0 +1,695 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +MALLOC_DEFINE(M_KMALLOC, "linux", "Linux kmalloc compat"); + +#include +/* Undo Linux compat changes. */ +#undef RB_ROOT +#undef file +#undef cdev +#define RB_ROOT(head) (head)->rbh_root +#undef LIST_HEAD +/* From sys/queue.h */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +struct kobject class_root; +struct device linux_rootdev; +struct class miscclass; +struct list_head pci_drivers; +struct list_head pci_devices; +spinlock_t pci_lock; + +int +panic_cmp(struct rb_node *one, struct rb_node *two) +{ + panic("no cmp"); +} + +RB_GENERATE(linux_root, rb_node, __entry, panic_cmp); + +int +kobject_set_name(struct kobject *kobj, const char *fmt, ...) +{ + va_list args; + int error; + + va_start(args, fmt); + error = kobject_set_name_vargs(kobj, fmt, args); + va_end(args); + + return (error); +} + +static inline int +kobject_add_complete(struct kobject *kobj, struct kobject *parent) +{ + struct kobj_type *t; + int error; + + kobj->parent = kobject_get(parent); + error = sysfs_create_dir(kobj); + if (error == 0 && kobj->ktype && kobj->ktype->default_attrs) { + struct attribute **attr; + t = kobj->ktype; + + for (attr = t->default_attrs; *attr != NULL; attr++) { + error = sysfs_create_file(kobj, *attr); + if (error) + break; + } + if (error) + sysfs_remove_dir(kobj); + + } + return (error); +} + +int +kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...) +{ + va_list args; + int error; + + va_start(args, fmt); + error = kobject_set_name_vargs(kobj, fmt, args); + va_end(args); + if (error) + return (error); + + return kobject_add_complete(kobj, parent); +} + +void +kobject_release(struct kref *kref) +{ + struct kobject *kobj; + char *name; + + kobj = container_of(kref, struct kobject, kref); + sysfs_remove_dir(kobj); + if (kobj->parent) + kobject_put(kobj->parent); + kobj->parent = NULL; + name = kobj->name; + if (kobj->ktype && kobj->ktype->release) + kobj->ktype->release(kobj); + kfree(name); +} + +static void +kobject_kfree(struct kobject *kobj) +{ + + kfree(kobj); +} + +struct kobj_type kfree_type = { .release = kobject_kfree }; + +struct device * +device_create(struct class *class, struct device *parent, dev_t devt, + void *drvdata, const char *fmt, ...) +{ + struct device *dev; + va_list args; + + dev = kzalloc(sizeof(*dev), M_WAITOK); + dev->parent = parent; + dev->class = class; + dev->devt = devt; + dev->driver_data = drvdata; + va_start(args, fmt); + kobject_set_name_vargs(&dev->kobj, fmt, args); + va_end(args); + device_register(dev); + + return (dev); +} + +int +kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, + struct kobject *parent, const char *fmt, ...) +{ + va_list args; + int error; + + kobject_init(kobj, ktype); + kobj->ktype = ktype; + kobj->parent = parent; + kobj->name = NULL; + + va_start(args, fmt); + error = kobject_set_name_vargs(kobj, fmt, args); + va_end(args); + if (error) + return (error); + return kobject_add_complete(kobj, parent); +} + +static void +linux_file_dtor(void *cdp) +{ + struct linux_file *filp; + + filp = cdp; + filp->f_op->release(curthread->td_fpop->f_vnode, filp); + kfree(filp); +} + +static int +linux_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +{ + struct linux_cdev *ldev; + struct linux_file *filp; + struct file *file; + int error; + + file = curthread->td_fpop; + ldev = dev->si_drv1; + if (ldev == NULL) + return (ENODEV); + filp = kzalloc(sizeof(*filp), GFP_KERNEL); + filp->f_dentry = &filp->f_dentry_store; + filp->f_op = ldev->ops; + filp->f_flags = file->f_flag; + if (filp->f_op->open) { + error = -filp->f_op->open(file->f_vnode, filp); + if (error) { + kfree(filp); + return (error); + } + } + error = devfs_set_cdevpriv(filp, linux_file_dtor); + if (error) { + filp->f_op->release(file->f_vnode, filp); + kfree(filp); + return (error); + } + + return 0; +} + +static int +linux_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) +{ + struct linux_cdev *ldev; + struct linux_file *filp; + struct file *file; + int error; + + file = curthread->td_fpop; + ldev = dev->si_drv1; + if (ldev == NULL) + return (0); + if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) + return (error); + filp->f_flags = file->f_flag; + devfs_clear_cdevpriv(); + + return (0); +} + +static int +linux_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, + struct thread *td) +{ + struct linux_cdev *ldev; + struct linux_file *filp; + struct file *file; + int error; + + file = curthread->td_fpop; + ldev = dev->si_drv1; + if (ldev == NULL) + return (0); + if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) + return (error); + filp->f_flags = file->f_flag; + /* + * Linux does not have a generic ioctl copyin/copyout layer. All + * linux ioctls must be converted to void ioctls which pass a + * pointer to the address of the data. We want the actual user + * address so we dereference here. + */ + data = *(void **)data; + if (filp->f_op->unlocked_ioctl) + error = -filp->f_op->unlocked_ioctl(filp, cmd, (u_long)data); + else + error = ENOTTY; + + return (error); +} + +static int +linux_dev_read(struct cdev *dev, struct uio *uio, int ioflag) +{ + struct linux_cdev *ldev; + struct linux_file *filp; + struct file *file; + ssize_t bytes; + int error; + + file = curthread->td_fpop; + ldev = dev->si_drv1; + if (ldev == NULL) + return (0); + if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) + return (error); + filp->f_flags = file->f_flag; + if (uio->uio_iovcnt != 1) + panic("linux_dev_read: uio %p iovcnt %d", + uio, uio->uio_iovcnt); + if (filp->f_op->read) { + bytes = filp->f_op->read(filp, uio->uio_iov->iov_base, + uio->uio_iov->iov_len, &uio->uio_offset); + if (bytes >= 0) { + uio->uio_iov->iov_base += bytes; + uio->uio_iov->iov_len -= bytes; + uio->uio_resid -= bytes; + } else + error = -bytes; + } else + error = ENXIO; + + return (error); +} + +static int +linux_dev_write(struct cdev *dev, struct uio *uio, int ioflag) +{ + struct linux_cdev *ldev; + struct linux_file *filp; + struct file *file; + ssize_t bytes; + int error; + + file = curthread->td_fpop; + ldev = dev->si_drv1; + if (ldev == NULL) + return (0); + if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) + return (error); + filp->f_flags = file->f_flag; + if (uio->uio_iovcnt != 1) + panic("linux_dev_write: uio %p iovcnt %d", + uio, uio->uio_iovcnt); + if (filp->f_op->write) { + bytes = filp->f_op->write(filp, uio->uio_iov->iov_base, + uio->uio_iov->iov_len, &uio->uio_offset); + if (bytes >= 0) { + uio->uio_iov->iov_base += bytes; + uio->uio_iov->iov_len -= bytes; + uio->uio_resid -= bytes; + } else + error = -bytes; + } else + error = ENXIO; + + return (error); +} + +static int +linux_dev_poll(struct cdev *dev, int events, struct thread *td) +{ + struct linux_cdev *ldev; + struct linux_file *filp; + struct file *file; + int revents; + int error; + + file = curthread->td_fpop; + ldev = dev->si_drv1; + if (ldev == NULL) + return (0); + if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) + return (error); + filp->f_flags = file->f_flag; + if (filp->f_op->poll) + revents = filp->f_op->poll(filp, NULL) & events; + else + revents = 0; + + return (revents); +} + +static int +linux_dev_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, + int nprot, vm_memattr_t *memattr) +{ + + /* XXX memattr not honored. */ + *paddr = offset; + return (0); +} + +static int +linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t *offset, + vm_size_t size, struct vm_object **object, int nprot) +{ + struct linux_cdev *ldev; + struct linux_file *filp; + struct file *file; + struct vm_area_struct vma; + vm_paddr_t paddr; + vm_page_t m; + int error; + + file = curthread->td_fpop; + ldev = dev->si_drv1; + if (ldev == NULL) + return (ENODEV); + if (size != PAGE_SIZE) + return (EINVAL); + if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) + return (error); + filp->f_flags = file->f_flag; + vma.vm_start = 0; + vma.vm_end = PAGE_SIZE; + vma.vm_pgoff = *offset / PAGE_SIZE; + vma.vm_pfn = 0; + vma.vm_page_prot = 0; + if (filp->f_op->mmap) { + error = -filp->f_op->mmap(filp, &vma); + if (error == 0) { + paddr = (vm_paddr_t)vma.vm_pfn << PAGE_SHIFT; + *offset = paddr; + m = PHYS_TO_VM_PAGE(paddr); + *object = vm_pager_allocate(OBJT_DEVICE, dev, + PAGE_SIZE, nprot, *offset, curthread->td_ucred); + if (*object == NULL) + return (EINVAL); + if (vma.vm_page_prot != VM_MEMATTR_DEFAULT) + pmap_page_set_memattr(m, vma.vm_page_prot); + } + } else + error = ENODEV; + + return (error); +} + +struct cdevsw linuxcdevsw = { + .d_version = D_VERSION, + .d_flags = D_TRACKCLOSE, + .d_open = linux_dev_open, + .d_close = linux_dev_close, + .d_read = linux_dev_read, + .d_write = linux_dev_write, + .d_ioctl = linux_dev_ioctl, + .d_mmap_single = linux_dev_mmap_single, + .d_mmap = linux_dev_mmap, + .d_poll = linux_dev_poll, +}; + +static int +linux_file_read(struct file *file, struct uio *uio, struct ucred *active_cred, + int flags, struct thread *td) +{ + struct linux_file *filp; + ssize_t bytes; + int error; + + error = 0; + filp = (struct linux_file *)file->f_data; + filp->f_flags = file->f_flag; + if (uio->uio_iovcnt != 1) + panic("linux_file_read: uio %p iovcnt %d", + uio, uio->uio_iovcnt); + if (filp->f_op->read) { + bytes = filp->f_op->read(filp, uio->uio_iov->iov_base, + uio->uio_iov->iov_len, &uio->uio_offset); + if (bytes >= 0) { + uio->uio_iov->iov_base += bytes; + uio->uio_iov->iov_len -= bytes; + uio->uio_resid -= bytes; + } else + error = -bytes; + } else + error = ENXIO; + + return (error); +} + +static int +linux_file_poll(struct file *file, int events, struct ucred *active_cred, + struct thread *td) +{ + struct linux_file *filp; + int revents; + + filp = (struct linux_file *)file->f_data; + filp->f_flags = file->f_flag; + if (filp->f_op->poll) + revents = filp->f_op->poll(filp, NULL) & events; + else + revents = 0; + + return (0); +} + +static int +linux_file_close(struct file *file, struct thread *td) +{ + struct linux_file *filp; + int error; + + filp = (struct linux_file *)file->f_data; + filp->f_flags = file->f_flag; + error = -filp->f_op->release(NULL, filp); + funsetown(&filp->f_sigio); + kfree(filp); + + return (error); +} + +static int +linux_file_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *cred, + struct thread *td) +{ + struct linux_file *filp; + int error; + + filp = (struct linux_file *)fp->f_data; + filp->f_flags = fp->f_flag; + error = 0; + + switch (cmd) { + case FIONBIO: + break; + case FIOASYNC: + if (filp->f_op->fasync == NULL) + break; + error = filp->f_op->fasync(0, filp, fp->f_flag & FASYNC); + break; + case FIOSETOWN: + error = fsetown(*(int *)data, &filp->f_sigio); + if (error == 0) + error = filp->f_op->fasync(0, filp, + fp->f_flag & FASYNC); + break; + case FIOGETOWN: + *(int *)data = fgetown(&filp->f_sigio); + break; + default: + error = ENOTTY; + break; + } + return (error); +} + +struct fileops linuxfileops = { + .fo_read = linux_file_read, + .fo_poll = linux_file_poll, + .fo_close = linux_file_close, + .fo_ioctl = linux_file_ioctl +}; + +/* + * Hash of vmmap addresses. This is infrequently accessed and does not + * need to be particularly large. This is done because we must store the + * caller's idea of the map size to properly unmap. + */ +struct vmmap { + LIST_ENTRY(vmmap) vm_next; + void *vm_addr; + unsigned long vm_size; +}; + +LIST_HEAD(vmmaphd, vmmap); +#define VMMAP_HASH_SIZE 64 +#define VMMAP_HASH_MASK (VMMAP_HASH_SIZE - 1) +#define VM_HASH(addr) ((uintptr_t)(addr) >> PAGE_SHIFT) & VMMAP_HASH_MASK +static struct vmmaphd vmmaphead[VMMAP_HASH_SIZE]; +static struct mtx vmmaplock; + +static void +vmmap_add(void *addr, unsigned long size) +{ + struct vmmap *vmmap; + + vmmap = kmalloc(sizeof(*vmmap), GFP_KERNEL); + mtx_lock(&vmmaplock); + vmmap->vm_size = size; + vmmap->vm_addr = addr; + LIST_INSERT_HEAD(&vmmaphead[VM_HASH(addr)], vmmap, vm_next); + mtx_unlock(&vmmaplock); +} + +static struct vmmap * +vmmap_remove(void *addr) +{ + struct vmmap *vmmap; + + mtx_lock(&vmmaplock); + LIST_FOREACH(vmmap, &vmmaphead[VM_HASH(addr)], vm_next) + if (vmmap->vm_addr == addr) + break; + if (vmmap) + LIST_REMOVE(vmmap, vm_next); + mtx_unlock(&vmmaplock); + + return (vmmap); +} + +void * +_ioremap_attr(vm_paddr_t phys_addr, unsigned long size, int attr) +{ + void *addr; + + addr = pmap_mapdev_attr(phys_addr, size, attr); + if (addr == NULL) + return (NULL); + vmmap_add(addr, size); + + return (addr); +} + +void +iounmap(void *addr) +{ + struct vmmap *vmmap; + + vmmap = vmmap_remove(addr); + if (vmmap == NULL) + return; + pmap_unmapdev((vm_offset_t)addr, vmmap->vm_size); + kfree(vmmap); +} + + +void * +vmap(struct page **pages, unsigned int count, unsigned long flags, int prot) +{ + vm_offset_t off; + size_t size; + + size = count * PAGE_SIZE; + off = kmem_alloc_nofault(kernel_map, size); + if (off == 0) + return (NULL); + vmmap_add((void *)off, size); + pmap_qenter(off, pages, count); + + return ((void *)off); +} + +void +vunmap(void *addr) +{ + struct vmmap *vmmap; + + vmmap = vmmap_remove(addr); + if (vmmap == NULL) + return; + pmap_qremove((vm_offset_t)addr, vmmap->vm_size / PAGE_SIZE); + kmem_free(kernel_map, (vm_offset_t)addr, vmmap->vm_size); + kfree(vmmap); +} + +static void +linux_compat_init(void) +{ + struct sysctl_oid *rootoid; + int i; + + rootoid = SYSCTL_ADD_NODE(NULL, SYSCTL_STATIC_CHILDREN(), + OID_AUTO, "sys", CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, "sys"); + kobject_init(&class_root, &class_ktype); + kobject_set_name(&class_root, "class"); + class_root.oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(rootoid), + OID_AUTO, "class", CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, "class"); + kobject_init(&linux_rootdev.kobj, &dev_ktype); + kobject_set_name(&linux_rootdev.kobj, "device"); + linux_rootdev.kobj.oidp = SYSCTL_ADD_NODE(NULL, + SYSCTL_CHILDREN(rootoid), OID_AUTO, "device", CTLFLAG_RD, NULL, + "device"); + linux_rootdev.bsddev = root_bus; + miscclass.name = "misc"; + class_register(&miscclass); + INIT_LIST_HEAD(&pci_drivers); + INIT_LIST_HEAD(&pci_devices); + spin_lock_init(&pci_lock); + mtx_init(&vmmaplock, "IO Map lock", NULL, MTX_DEF); + for (i = 0; i < VMMAP_HASH_SIZE; i++) + LIST_INIT(&vmmaphead[i]); +} + +SYSINIT(linux_compat, SI_SUB_DRIVERS, SI_ORDER_SECOND, linux_compat_init, NULL); diff --git a/sys/ofed/include/linux/linux_idr.c b/sys/ofed/include/linux/linux_idr.c new file mode 100644 index 000000000000..5cfaff5728c0 --- /dev/null +++ b/sys/ofed/include/linux/linux_idr.c @@ -0,0 +1,447 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +/* + * IDR Implementation. + * + * This is quick and dirty and not as re-entrant as the linux version + * however it should be fairly fast. It is basically a radix tree with + * a builtin bitmap for allocation. + */ +MALLOC_DEFINE(M_IDR, "idr", "Linux IDR compat"); + +static inline int +idr_max(struct idr *idr) +{ + return (1 << (idr->layers * IDR_BITS)) - 1; +} + +static inline int +idr_pos(int id, int layer) +{ + return (id >> (IDR_BITS * layer)) & IDR_MASK; +} + +void +idr_init(struct idr *idr) +{ + bzero(idr, sizeof(*idr)); + mtx_init(&idr->lock, "idr", NULL, MTX_DEF); +} + +/* Only frees cached pages. */ +void +idr_destroy(struct idr *idr) +{ + struct idr_layer *il, *iln; + + mtx_lock(&idr->lock); + for (il = idr->free; il != NULL; il = iln) { + iln = il->ary[0]; + free(il, M_IDR); + } + mtx_unlock(&idr->lock); +} + +static void +idr_remove_layer(struct idr_layer *il, int layer) +{ + int i; + + if (il == NULL) + return; + if (layer == 0) { + free(il, M_IDR); + return; + } + for (i = 0; i < IDR_SIZE; i++) + if (il->ary[i]) + idr_remove_layer(il->ary[i], layer - 1); +} + +void +idr_remove_all(struct idr *idr) +{ + + mtx_lock(&idr->lock); + idr_remove_layer(idr->top, idr->layers - 1); + idr->top = NULL; + idr->layers = 0; + mtx_unlock(&idr->lock); +} + +void +idr_remove(struct idr *idr, int id) +{ + struct idr_layer *il; + int layer; + int idx; + + id &= MAX_ID_MASK; + mtx_lock(&idr->lock); + il = idr->top; + layer = idr->layers - 1; + if (il == NULL || id > idr_max(idr)) { + mtx_unlock(&idr->lock); + return; + } + /* + * Walk down the tree to this item setting bitmaps along the way + * as we know at least one item will be free along this path. + */ + while (layer && il) { + idx = idr_pos(id, layer); + il->bitmap |= 1 << idx; + il = il->ary[idx]; + layer--; + } + idx = id & IDR_MASK; + /* + * At this point we've set free space bitmaps up the whole tree. + * We could make this non-fatal and unwind but linux dumps a stack + * and a warning so I don't think it's necessary. + */ + if (il == NULL || (il->bitmap & (1 << idx)) != 0) + panic("idr_remove: Item %d not allocated (%p, %p)\n", + id, idr, il); + il->ary[idx] = NULL; + il->bitmap |= 1 << idx; + mtx_unlock(&idr->lock); + return; +} + +void * +idr_replace(struct idr *idr, void *ptr, int id) +{ + struct idr_layer *il; + void *res; + int layer; + int idx; + + res = ERR_PTR(-EINVAL); + id &= MAX_ID_MASK; + mtx_lock(&idr->lock); + il = idr->top; + layer = idr->layers - 1; + if (il == NULL || id > idr_max(idr)) + goto out; + while (layer && il) { + il = il->ary[idr_pos(id, layer)]; + layer--; + } + idx = id & IDR_MASK; + /* + * Replace still returns an error if the item was not allocated. + */ + if (il != NULL && (il->bitmap & (1 << idx)) != 0) { + res = il->ary[idx]; + il->ary[idx] = ptr; + } +out: + mtx_unlock(&idr->lock); + return (res); +} + +void * +idr_find(struct idr *idr, int id) +{ + struct idr_layer *il; + void *res; + int layer; + + res = NULL; + id &= MAX_ID_MASK; + mtx_lock(&idr->lock); + il = idr->top; + layer = idr->layers - 1; + if (il == NULL || id > idr_max(idr)) + goto out; + while (layer && il) { + il = il->ary[idr_pos(id, layer)]; + layer--; + } + if (il != NULL) + res = il->ary[id & IDR_MASK]; +out: + mtx_unlock(&idr->lock); + return (res); +} + +int +idr_pre_get(struct idr *idr, gfp_t gfp_mask) +{ + struct idr_layer *il, *iln; + struct idr_layer *head; + int need; + + mtx_lock(&idr->lock); + for (;;) { + need = idr->layers + 1; + for (il = idr->free; il != NULL; il = il->ary[0]) + need--; + mtx_unlock(&idr->lock); + if (need == 0) + break; + for (head = NULL; need; need--) { + iln = malloc(sizeof(*il), M_IDR, M_ZERO | gfp_mask); + if (iln == NULL) + break; + bitmap_fill(&iln->bitmap, IDR_SIZE); + if (head != NULL) { + il->ary[0] = iln; + il = iln; + } else + head = il = iln; + } + if (head == NULL) + return (0); + mtx_lock(&idr->lock); + il->ary[0] = idr->free; + idr->free = head; + } + return (1); +} + +static inline struct idr_layer * +idr_get(struct idr *idr) +{ + struct idr_layer *il; + + il = idr->free; + if (il) { + idr->free = il->ary[0]; + il->ary[0] = NULL; + return (il); + } + il = malloc(sizeof(*il), M_IDR, M_ZERO | M_NOWAIT); + bitmap_fill(&il->bitmap, IDR_SIZE); + return (il); +} + +/* + * Could be implemented as get_new_above(idr, ptr, 0, idp) but written + * first for simplicity sake. + */ +int +idr_get_new(struct idr *idr, void *ptr, int *idp) +{ + struct idr_layer *stack[MAX_LEVEL]; + struct idr_layer *il; + int error; + int layer; + int idx; + int id; + + error = -EAGAIN; + mtx_lock(&idr->lock); + /* + * Expand the tree until there is free space. + */ + if (idr->top == NULL || idr->top->bitmap == 0) { + if (idr->layers == MAX_LEVEL + 1) { + error = -ENOSPC; + goto out; + } + il = idr_get(idr); + if (il == NULL) + goto out; + il->ary[0] = idr->top; + if (idr->top) + il->bitmap &= ~1; + idr->top = il; + idr->layers++; + } + il = idr->top; + id = 0; + /* + * Walk the tree following free bitmaps, record our path. + */ + for (layer = idr->layers - 1;; layer--) { + stack[layer] = il; + idx = ffsl(il->bitmap); + if (idx == 0) + panic("idr_get_new: Invalid leaf state (%p, %p)\n", + idr, il); + idx--; + id |= idx << (layer * IDR_BITS); + if (layer == 0) + break; + if (il->ary[idx] == NULL) { + il->ary[idx] = idr_get(idr); + if (il->ary[idx] == NULL) + goto out; + } + il = il->ary[idx]; + } + /* + * Allocate the leaf to the consumer. + */ + il->bitmap &= ~(1 << idx); + il->ary[idx] = ptr; + *idp = id; + /* + * Clear bitmaps potentially up to the root. + */ + while (il->bitmap == 0 && ++layer < idr->layers) { + il = stack[layer]; + il->bitmap &= ~(1 << idr_pos(id, layer)); + } + error = 0; +out: + mtx_unlock(&idr->lock); +#ifdef INVARIANTS + if (error == 0 && idr_find(idr, id) != ptr) { + panic("idr_get_new: Failed for idr %p, id %d, ptr %p\n", + idr, id, ptr); + } +#endif + return (error); +} + +int +idr_get_new_above(struct idr *idr, void *ptr, int starting_id, int *idp) +{ + struct idr_layer *stack[MAX_LEVEL]; + struct idr_layer *il; + int error; + int layer; + int idx, sidx; + int id; + + error = -EAGAIN; + mtx_lock(&idr->lock); + /* + * Compute the layers required to support starting_id and the mask + * at the top layer. + */ +restart: + idx = starting_id; + layer = 0; + while (idx & ~IDR_MASK) { + layer++; + idx >>= IDR_BITS; + } + if (layer == MAX_LEVEL + 1) { + error = -ENOSPC; + goto out; + } + /* + * Expand the tree until there is free space at or beyond starting_id. + */ + while (idr->layers <= layer || + idr->top->bitmap < (1 << idr_pos(starting_id, idr->layers - 1))) { + if (idr->layers == MAX_LEVEL + 1) { + error = -ENOSPC; + goto out; + } + il = idr_get(idr); + if (il == NULL) + goto out; + il->ary[0] = idr->top; + if (idr->top && idr->top->bitmap == 0) + il->bitmap &= ~1; + idr->top = il; + idr->layers++; + } + il = idr->top; + id = 0; + /* + * Walk the tree following free bitmaps, record our path. + */ + for (layer = idr->layers - 1;; layer--) { + stack[layer] = il; + sidx = idr_pos(starting_id, layer); + /* Returns index numbered from 0 or size if none exists. */ + idx = find_next_bit(&il->bitmap, IDR_SIZE, sidx); + if (idx == IDR_SIZE && sidx == 0) + panic("idr_get_new: Invalid leaf state (%p, %p)\n", + idr, il); + /* + * We may have walked a path where there was a free bit but + * it was lower than what we wanted. Restart the search with + * a larger starting id. id contains the progress we made so + * far. Search the leaf one above this level. This may + * restart as many as MAX_LEVEL times but that is expected + * to be rare. + */ + if (idx == IDR_SIZE) { + starting_id = id + (1 << (layer+1 * IDR_BITS)); + goto restart; + } + if (idx > sidx) + starting_id = 0; /* Search the whole subtree. */ + id |= idx << (layer * IDR_BITS); + if (layer == 0) + break; + if (il->ary[idx] == NULL) { + il->ary[idx] = idr_get(idr); + if (il->ary[idx] == NULL) + goto out; + } + il = il->ary[idx]; + } + /* + * Allocate the leaf to the consumer. + */ + il->bitmap &= ~(1 << idx); + il->ary[idx] = ptr; + *idp = id; + /* + * Clear bitmaps potentially up to the root. + */ + while (il->bitmap == 0 && ++layer < idr->layers) { + il = stack[layer]; + il->bitmap &= ~(1 << idr_pos(id, layer)); + } + error = 0; +out: + mtx_unlock(&idr->lock); +#ifdef INVARIANTS + if (error == 0 && idr_find(idr, id) != ptr) { + panic("idr_get_new_above: Failed for idr %p, id %d, ptr %p\n", + idr, id, ptr); + } +#endif + return (error); +} diff --git a/sys/ofed/include/linux/linux_radix.c b/sys/ofed/include/linux/linux_radix.c new file mode 100644 index 000000000000..e642eaeb71bc --- /dev/null +++ b/sys/ofed/include/linux/linux_radix.c @@ -0,0 +1,170 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +MALLOC_DEFINE(M_RADIX, "radix", "Linux radix compat"); + +static inline int +radix_max(struct radix_tree_root *root) +{ + return (1 << (root->height * RADIX_TREE_MAP_SHIFT)) - 1; +} + +static inline int +radix_pos(long id, int height) +{ + return (id >> (RADIX_TREE_MAP_SHIFT * height)) & RADIX_TREE_MAP_MASK; +} + +void * +radix_tree_lookup(struct radix_tree_root *root, unsigned long index) +{ + struct radix_tree_node *node; + void *item; + int height; + + item = NULL; + node = root->rnode; + height = root->height - 1; + if (index > radix_max(root)) + goto out; + while (height && node) + node = node->slots[radix_pos(index, height--)]; + if (node) + item = node->slots[radix_pos(index, 0)]; + +out: + return (item); +} + +void * +radix_tree_delete(struct radix_tree_root *root, unsigned long index) +{ + struct radix_tree_node *stack[RADIX_TREE_MAX_HEIGHT]; + struct radix_tree_node *node; + void *item; + int height; + int idx; + + item = NULL; + node = root->rnode; + height = root->height - 1; + if (index > radix_max(root)) + goto out; + /* + * Find the node and record the path in stack. + */ + while (height && node) { + stack[height] = node; + node = node->slots[radix_pos(index, height--)]; + } + idx = radix_pos(index, 0); + if (node) + item = node->slots[idx]; + /* + * If we removed something reduce the height of the tree. + */ + if (item) + for (;;) { + node->slots[idx] = NULL; + node->count--; + if (node->count > 0) + break; + free(node, M_RADIX); + if (node == root->rnode) { + root->rnode = NULL; + root->height = 0; + break; + } + height++; + node = stack[height]; + idx = radix_pos(index, height); + } +out: + return (item); +} + +int +radix_tree_insert(struct radix_tree_root *root, unsigned long index, void *item) +{ + struct radix_tree_node *node; + int height; + int idx; + + /* + * Expand the tree to fit indexes as big as requested. + */ + while (root->rnode == NULL || radix_max(root) < index) { + node = malloc(sizeof(*node), M_RADIX, root->gfp_mask | M_ZERO); + if (node == NULL) + return (-ENOMEM); + node->slots[0] = root->rnode; + if (root->rnode) + node->count++; + root->rnode = node; + root->height++; + } + node = root->rnode; + height = root->height - 1; + /* + * Walk down the tree finding the correct node and allocating any + * missing nodes along the way. + */ + while (height) { + idx = radix_pos(index, height); + if (node->slots[idx] == NULL) { + node->slots[idx] = malloc(sizeof(*node), M_RADIX, + root->gfp_mask | M_ZERO); + if (node->slots[idx] == NULL) + return (-ENOMEM); + node->count++; + } + node = node->slots[idx]; + height--; + } + /* + * Insert and adjust count if the item does not already exist. + */ + idx = radix_pos(index, 0); + if (node->slots[idx]) + return (-EEXIST); + node->slots[idx] = item; + node->count++; + + return (0); +} diff --git a/sys/ofed/include/linux/list.h b/sys/ofed/include/linux/list.h new file mode 100644 index 000000000000..f6f9404307c8 --- /dev/null +++ b/sys/ofed/include/linux/list.h @@ -0,0 +1,331 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_LIST_H_ +#define _LINUX_LIST_H_ + +/* + * Since LIST_HEAD conflicts with the linux definition we must include any + * FreeBSD header which requires it here so it is resolved with the correct + * definition prior to the undef. + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#define prefetch(x) + +struct list_head { + struct list_head *next; + struct list_head *prev; +}; + +static inline void +INIT_LIST_HEAD(struct list_head *list) +{ + + list->next = list->prev = list; +} + +static inline int +list_empty(const struct list_head *head) +{ + + return (head->next == head); +} + +static inline void +list_del(struct list_head *entry) +{ + + entry->next->prev = entry->prev; + entry->prev->next = entry->next; +} + +static inline void +_list_add(struct list_head *new, struct list_head *prev, + struct list_head *next) +{ + + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +static inline void +list_del_init(struct list_head *entry) +{ + + list_del(entry); + INIT_LIST_HEAD(entry); +} + +#define list_entry(ptr, type, field) container_of(ptr, type, field) + +#define list_for_each(p, head) \ + for (p = (head)->next; p != (head); p = p->next) + +#define list_for_each_safe(p, n, head) \ + for (p = (head)->next, n = p->next; p != (head); p = n, n = p->next) + +#define list_for_each_entry(p, h, field) \ + for (p = list_entry((h)->next, typeof(*p), field); &p->field != (h); \ + p = list_entry(p->field.next, typeof(*p), field)) + +#define list_for_each_entry_safe(p, n, h, field) \ + for (p = list_entry((h)->next, typeof(*p), field), \ + n = list_entry(p->field.next, typeof(*p), field); &p->field != (h);\ + p = n, n = list_entry(n->field.next, typeof(*n), field)) + +#define list_for_each_entry_reverse(p, h, field) \ + for (p = list_entry((h)->prev, typeof(*p), field); &p->field != (h); \ + p = list_entry(p->field.prev, typeof(*p), field)) + +#define list_for_each_prev(p, h) for (p = (h)->prev; p != (h); p = p->prev) + +static inline void +list_add(struct list_head *new, struct list_head *head) +{ + + _list_add(new, head, head->next); +} + +static inline void +list_add_tail(struct list_head *new, struct list_head *head) +{ + + _list_add(new, head->prev, head); +} + +static inline void +list_move(struct list_head *list, struct list_head *head) +{ + + list_del(list); + list_add(list, head); +} + +static inline void +list_move_tail(struct list_head *entry, struct list_head *head) +{ + + list_del(entry); + list_add_tail(entry, head); +} + +static inline void +_list_splice(const struct list_head *list, struct list_head *prev, + struct list_head *next) +{ + struct list_head *first; + struct list_head *last; + + if (list_empty(list)) + return; + first = list->next; + last = list->prev; + first->prev = prev; + prev->next = first; + last->next = next; + next->prev = last; +} + +static inline void +list_splice(const struct list_head *list, struct list_head *head) +{ + + _list_splice(list, head, head->next); +} + +static inline void +list_splice_tail(struct list_head *list, struct list_head *head) +{ + + _list_splice(list, head->prev, head); +} + +static inline void +list_splice_init(struct list_head *list, struct list_head *head) +{ + + _list_splice(list, head, head->next); + INIT_LIST_HEAD(list); +} + +static inline void +list_splice_tail_init(struct list_head *list, struct list_head *head) +{ + + _list_splice(list, head->prev, head); + INIT_LIST_HEAD(list); +} + +#undef LIST_HEAD +#define LIST_HEAD(name) struct list_head name = { &(name), &(name) } + + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { } +#define HLIST_HEAD(name) struct hlist_head name = HLIST_HEAD_INIT +#define INIT_HLIST_HEAD(head) (head)->first = NULL +#define INIT_HLIST_NODE(node) \ +do { \ + (node)->next = NULL; \ + (node)->pprev = NULL; \ +} while (0) + +static inline int +hlist_unhashed(const struct hlist_node *h) +{ + + return !h->pprev; +} + +static inline int +hlist_empty(const struct hlist_head *h) +{ + + return !h->first; +} + +static inline void +hlist_del(struct hlist_node *n) +{ + + if (n->next) + n->next->pprev = n->pprev; + *n->pprev = n->next; +} + +static inline void +hlist_del_init(struct hlist_node *n) +{ + + if (hlist_unhashed(n)) + return; + hlist_del(n); + INIT_HLIST_NODE(n); +} + +static inline void +hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + + n->next = h->first; + if (h->first) + h->first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +static inline void +hlist_add_before(struct hlist_node *n, struct hlist_node *next) +{ + + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void +hlist_add_after(struct hlist_node *n, struct hlist_node *next) +{ + + next->next = n->next; + n->next = next; + next->pprev = &n->next; + if (next->next) + next->next->pprev = &next->next; +} + +static inline void +hlist_move_list(struct hlist_head *old, struct hlist_head *new) +{ + + new->first = old->first; + if (new->first) + new->first->pprev = &new->first; + old->first = NULL; +} + +#define hlist_entry(ptr, type, field) container_of(ptr, type, field) + +#define hlist_for_each(p, head) \ + for (p = (head)->first; p; p = p->next) + +#define hlist_for_each_safe(p, n, head) \ + for (p = (head)->first; p && ({ n = p->next; 1; }); p = n) + +#define hlist_for_each_entry(tp, p, head, field) \ + for (p = (head)->first; \ + p ? (tp = hlist_entry(p, typeof(*tp), field)): NULL; p = p->next) + +#define hlist_for_each_entry_continue(tp, p, field) \ + for (p = (p)->next; \ + p ? (tp = hlist_entry(p, typeof(*tp), field)): NULL; p = p->next) + +#define hlist_for_each_entry_from(tp, p, field) \ + for (; p ? (tp = hlist_entry(p, typeof(*tp), field)): NULL; p = p->next) + +#define hlist_for_each_entry_safe(tp, p, n, head, field) \ + for (p = (head)->first; p ? \ + (n = p->next) | (tp = hlist_entry(p, typeof(*tp), field)) : \ + NULL; p = n) + +#endif /* _LINUX_LIST_H_ */ diff --git a/sys/ofed/include/linux/lockdep.h b/sys/ofed/include/linux/lockdep.h new file mode 100644 index 000000000000..8ddb079cb3c8 --- /dev/null +++ b/sys/ofed/include/linux/lockdep.h @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_LOCKDEP_H_ +#define _LINUX_LOCKDEP_H_ + +struct lock_class_key { +}; + +#define lockdep_set_class(lock, key) + +#endif /* _LINUX_LOCKDEP_H_ */ diff --git a/sys/ofed/include/linux/log2.h b/sys/ofed/include/linux/log2.h new file mode 100644 index 000000000000..0a8315a40b1c --- /dev/null +++ b/sys/ofed/include/linux/log2.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_LOG2_H_ +#define _LINUX_LOG2_H_ + +#include + +#include + +static inline unsigned long +roundup_pow_of_two(unsigned long x) +{ + return (1UL << flsl(x - 1)); +} + +static inline int +is_power_of_2(unsigned long n) +{ + return (n == roundup_pow_of_two(n)); +} + +static inline unsigned long +rounddown_pow_of_two(unsigned long x) +{ + return (1UL << (flsl(x) - 1)); +} + +static inline unsigned long +ilog2(unsigned long x) +{ + return (flsl(x) - 1); +} + +#endif /* _LINUX_LOG2_H_ */ diff --git a/sys/ofed/include/linux/miscdevice.h b/sys/ofed/include/linux/miscdevice.h new file mode 100644 index 000000000000..e6a443557469 --- /dev/null +++ b/sys/ofed/include/linux/miscdevice.h @@ -0,0 +1,72 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_MISCDEVICE_H_ +#define _LINUX_MISCDEVICE_H_ + +#define MISC_DYNAMIC_MINOR -1 + +#include +#include + +struct miscdevice { + const char *name; + struct device *this_device; + const struct file_operations *fops; + struct cdev *cdev; + int minor; +}; + +extern struct class miscclass; + +static inline int +misc_register(struct miscdevice *misc) +{ + misc->this_device = device_create(&miscclass, &linux_rootdev, 0, misc, + misc->name); + misc->cdev = cdev_alloc(); + if (misc->cdev == NULL) + return -ENOMEM; + misc->cdev->owner = THIS_MODULE; + misc->cdev->ops = misc->fops; + kobject_set_name(&misc->cdev->kobj, misc->name); + if (cdev_add(misc->cdev, misc->this_device->devt, 1)) + return -EINVAL; + return (0); +} + +static inline int +misc_deregister(struct miscdevice *misc) +{ + device_destroy(&miscclass, misc->this_device->devt); + cdev_del(misc->cdev); + + return (0); +} + +#endif /* _LINUX_MISCDEVICE_H_ */ diff --git a/sys/ofed/include/linux/mlx4/cmd.h b/sys/ofed/include/linux/mlx4/cmd.h new file mode 100644 index 000000000000..60d3036ef78c --- /dev/null +++ b/sys/ofed/include/linux/mlx4/cmd.h @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_CMD_H +#define MLX4_CMD_H + +#include + +enum { + /* initialization and general commands */ + MLX4_CMD_SYS_EN = 0x1, + MLX4_CMD_SYS_DIS = 0x2, + MLX4_CMD_MAP_FA = 0xfff, + MLX4_CMD_UNMAP_FA = 0xffe, + MLX4_CMD_RUN_FW = 0xff6, + MLX4_CMD_MOD_STAT_CFG = 0x34, + MLX4_CMD_QUERY_DEV_CAP = 0x3, + MLX4_CMD_QUERY_FW = 0x4, + MLX4_CMD_ENABLE_LAM = 0xff8, + MLX4_CMD_DISABLE_LAM = 0xff7, + MLX4_CMD_QUERY_DDR = 0x5, + MLX4_CMD_QUERY_ADAPTER = 0x6, + MLX4_CMD_INIT_HCA = 0x7, + MLX4_CMD_CLOSE_HCA = 0x8, + MLX4_CMD_INIT_PORT = 0x9, + MLX4_CMD_CLOSE_PORT = 0xa, + MLX4_CMD_QUERY_HCA = 0xb, + MLX4_CMD_QUERY_PORT = 0x43, + MLX4_CMD_SENSE_PORT = 0x4d, + MLX4_CMD_HW_HEALTH_CHECK = 0x50, + MLX4_CMD_SET_PORT = 0xc, + MLX4_CMD_SET_NODE = 0x5a, + MLX4_CMD_ACCESS_DDR = 0x2e, + MLX4_CMD_MAP_ICM = 0xffa, + MLX4_CMD_UNMAP_ICM = 0xff9, + MLX4_CMD_MAP_ICM_AUX = 0xffc, + MLX4_CMD_UNMAP_ICM_AUX = 0xffb, + MLX4_CMD_SET_ICM_SIZE = 0xffd, + + /* TPT commands */ + MLX4_CMD_SW2HW_MPT = 0xd, + MLX4_CMD_QUERY_MPT = 0xe, + MLX4_CMD_HW2SW_MPT = 0xf, + MLX4_CMD_READ_MTT = 0x10, + MLX4_CMD_WRITE_MTT = 0x11, + MLX4_CMD_SYNC_TPT = 0x2f, + + /* EQ commands */ + MLX4_CMD_MAP_EQ = 0x12, + MLX4_CMD_SW2HW_EQ = 0x13, + MLX4_CMD_HW2SW_EQ = 0x14, + MLX4_CMD_QUERY_EQ = 0x15, + + /* CQ commands */ + MLX4_CMD_SW2HW_CQ = 0x16, + MLX4_CMD_HW2SW_CQ = 0x17, + MLX4_CMD_QUERY_CQ = 0x18, + MLX4_CMD_MODIFY_CQ = 0x2c, + + /* SRQ commands */ + MLX4_CMD_SW2HW_SRQ = 0x35, + MLX4_CMD_HW2SW_SRQ = 0x36, + MLX4_CMD_QUERY_SRQ = 0x37, + MLX4_CMD_ARM_SRQ = 0x40, + + /* QP/EE commands */ + MLX4_CMD_RST2INIT_QP = 0x19, + MLX4_CMD_INIT2RTR_QP = 0x1a, + MLX4_CMD_RTR2RTS_QP = 0x1b, + MLX4_CMD_RTS2RTS_QP = 0x1c, + MLX4_CMD_SQERR2RTS_QP = 0x1d, + MLX4_CMD_2ERR_QP = 0x1e, + MLX4_CMD_RTS2SQD_QP = 0x1f, + MLX4_CMD_SQD2SQD_QP = 0x38, + MLX4_CMD_SQD2RTS_QP = 0x20, + MLX4_CMD_2RST_QP = 0x21, + MLX4_CMD_QUERY_QP = 0x22, + MLX4_CMD_INIT2INIT_QP = 0x2d, + MLX4_CMD_SUSPEND_QP = 0x32, + MLX4_CMD_UNSUSPEND_QP = 0x33, + /* special QP and management commands */ + MLX4_CMD_CONF_SPECIAL_QP = 0x23, + MLX4_CMD_MAD_IFC = 0x24, + + /* multicast commands */ + MLX4_CMD_READ_MCG = 0x25, + MLX4_CMD_WRITE_MCG = 0x26, + MLX4_CMD_MGID_HASH = 0x27, + + /* miscellaneous commands */ + MLX4_CMD_DIAG_RPRT = 0x30, + MLX4_CMD_NOP = 0x31, + + /* debug commands */ + MLX4_CMD_QUERY_DEBUG_MSG = 0x2a, + MLX4_CMD_SET_DEBUG_MSG = 0x2b, + + /* statistics commands */ + MLX4_CMD_QUERY_IF_STAT = 0X54, + MLX4_CMD_SET_IF_STAT = 0X55, +}; + +enum { + MLX4_CMD_TIME_CLASS_A = 10000, + MLX4_CMD_TIME_CLASS_B = 10000, + MLX4_CMD_TIME_CLASS_C = 10000, +}; + +enum { + MLX4_MAILBOX_SIZE = 4096 +}; + +enum { + /* set port opcode modifiers */ + MLX4_SET_PORT_GENERAL = 0x0, + MLX4_SET_PORT_RQP_CALC = 0x1, + MLX4_SET_PORT_MAC_TABLE = 0x2, + MLX4_SET_PORT_VLAN_TABLE = 0x3, + MLX4_SET_PORT_PRIO_MAP = 0x4, + MLX4_SET_PORT_GID_TABLE = 0x5, +}; + +struct mlx4_dev; + +struct mlx4_cmd_mailbox { + void *buf; + dma_addr_t dma; +}; + +int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, + int out_is_imm, u32 in_modifier, u8 op_modifier, + u16 op, unsigned long timeout); + +/* Invoke a command with no output parameter */ +static inline int mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u32 in_modifier, + u8 op_modifier, u16 op, unsigned long timeout) +{ + return __mlx4_cmd(dev, in_param, NULL, 0, in_modifier, + op_modifier, op, timeout); +} + +/* Invoke a command with an output mailbox */ +static inline int mlx4_cmd_box(struct mlx4_dev *dev, u64 in_param, u64 out_param, + u32 in_modifier, u8 op_modifier, u16 op, + unsigned long timeout) +{ + return __mlx4_cmd(dev, in_param, &out_param, 0, in_modifier, + op_modifier, op, timeout); +} + +/* + * Invoke a command with an immediate output parameter (and copy the + * output into the caller's out_param pointer after the command + * executes). + */ +static inline int mlx4_cmd_imm(struct mlx4_dev *dev, u64 in_param, u64 *out_param, + u32 in_modifier, u8 op_modifier, u16 op, + unsigned long timeout) +{ + return __mlx4_cmd(dev, in_param, out_param, 1, in_modifier, + op_modifier, op, timeout); +} + +struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev); +void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox); + +#endif /* MLX4_CMD_H */ diff --git a/sys/ofed/include/linux/mlx4/cq.h b/sys/ofed/include/linux/mlx4/cq.h new file mode 100644 index 000000000000..6f65b2c8bb89 --- /dev/null +++ b/sys/ofed/include/linux/mlx4/cq.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_CQ_H +#define MLX4_CQ_H + +#include + +#include +#include + +struct mlx4_cqe { + __be32 vlan_my_qpn; + __be32 immed_rss_invalid; + __be32 g_mlpath_rqpn; + __be16 sl_vid; + __be16 rlid; + __be16 status; + u8 ipv6_ext_mask; + u8 badfcs_enc; + __be32 byte_cnt; + __be16 wqe_index; + __be16 checksum; + u8 reserved[3]; + u8 owner_sr_opcode; +}; + +struct mlx4_err_cqe { + __be32 my_qpn; + u32 reserved1[5]; + __be16 wqe_index; + u8 vendor_err_syndrome; + u8 syndrome; + u8 reserved2[3]; + u8 owner_sr_opcode; +}; + +enum { + MLX4_CQE_VLAN_PRESENT_MASK = 1 << 29, + MLX4_CQE_QPN_MASK = 0xffffff, +}; + +enum { + MLX4_CQE_OWNER_MASK = 0x80, + MLX4_CQE_IS_SEND_MASK = 0x40, + MLX4_CQE_OPCODE_MASK = 0x1f +}; + +enum { + MLX4_CQE_SYNDROME_LOCAL_LENGTH_ERR = 0x01, + MLX4_CQE_SYNDROME_LOCAL_QP_OP_ERR = 0x02, + MLX4_CQE_SYNDROME_LOCAL_PROT_ERR = 0x04, + MLX4_CQE_SYNDROME_WR_FLUSH_ERR = 0x05, + MLX4_CQE_SYNDROME_MW_BIND_ERR = 0x06, + MLX4_CQE_SYNDROME_BAD_RESP_ERR = 0x10, + MLX4_CQE_SYNDROME_LOCAL_ACCESS_ERR = 0x11, + MLX4_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR = 0x12, + MLX4_CQE_SYNDROME_REMOTE_ACCESS_ERR = 0x13, + MLX4_CQE_SYNDROME_REMOTE_OP_ERR = 0x14, + MLX4_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR = 0x15, + MLX4_CQE_SYNDROME_RNR_RETRY_EXC_ERR = 0x16, + MLX4_CQE_SYNDROME_REMOTE_ABORTED_ERR = 0x22, +}; + +enum { + MLX4_CQE_STATUS_IPV4 = 1 << 6, + MLX4_CQE_STATUS_IPV4F = 1 << 7, + MLX4_CQE_STATUS_IPV6 = 1 << 8, + MLX4_CQE_STATUS_IPV4OPT = 1 << 9, + MLX4_CQE_STATUS_TCP = 1 << 10, + MLX4_CQE_STATUS_UDP = 1 << 11, + MLX4_CQE_STATUS_IPOK = 1 << 12, +}; + +enum { + MLX4_CQE_LLC = 1, + MLX4_CQE_SNAP = 1 << 1, + MLX4_CQE_BAD_FCS = 1 << 4, +}; + +static inline void mlx4_cq_arm(struct mlx4_cq *cq, u32 cmd, + void __iomem *uar_page, + spinlock_t *doorbell_lock) +{ + __be32 doorbell[2]; + u32 sn; + u32 ci; + + sn = cq->arm_sn & 3; + ci = cq->cons_index & 0xffffff; + + *cq->arm_db = cpu_to_be32(sn << 28 | cmd | ci); + + /* + * Make sure that the doorbell record in host memory is + * written before ringing the doorbell via PCI MMIO. + */ + wmb(); + + doorbell[0] = cpu_to_be32(sn << 28 | cmd | cq->cqn); + doorbell[1] = cpu_to_be32(ci); + + mlx4_write64(doorbell, uar_page + MLX4_CQ_DOORBELL, doorbell_lock); +} + +static inline void mlx4_cq_set_ci(struct mlx4_cq *cq) +{ + *cq->set_ci_db = cpu_to_be32(cq->cons_index & 0xffffff); +} + +enum { + MLX4_CQ_DB_REQ_NOT_SOL = 1 << 24, + MLX4_CQ_DB_REQ_NOT = 2 << 24 +}; + +int mlx4_cq_modify(struct mlx4_dev *dev, struct mlx4_cq *cq, + u16 count, u16 period); +int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq, + int entries, struct mlx4_mtt *mtt); + +#endif /* MLX4_CQ_H */ diff --git a/sys/ofed/include/linux/mlx4/device.h b/sys/ofed/include/linux/mlx4/device.h new file mode 100644 index 000000000000..5272e5f7146d --- /dev/null +++ b/sys/ofed/include/linux/mlx4/device.h @@ -0,0 +1,619 @@ +/* + * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_DEVICE_H +#define MLX4_DEVICE_H + +#include +#include +#include + +#include + +#include + +enum { + MLX4_FLAG_MSI_X = 1 << 0, + MLX4_FLAG_OLD_PORT_CMDS = 1 << 1, +}; + +enum { + MLX4_MAX_PORTS = 2 +}; + +enum { + MLX4_BOARD_ID_LEN = 64 +}; + +enum { + MLX4_DEV_CAP_FLAG_RC = 1 << 0, + MLX4_DEV_CAP_FLAG_UC = 1 << 1, + MLX4_DEV_CAP_FLAG_UD = 1 << 2, + MLX4_DEV_CAP_FLAG_XRC = 1 << 3, + MLX4_DEV_CAP_FLAG_SRQ = 1 << 6, + MLX4_DEV_CAP_FLAG_IPOIB_CSUM = 1 << 7, + MLX4_DEV_CAP_FLAG_BAD_PKEY_CNTR = 1 << 8, + MLX4_DEV_CAP_FLAG_BAD_QKEY_CNTR = 1 << 9, + MLX4_DEV_CAP_FLAG_DPDP = 1 << 12, + MLX4_DEV_CAP_FLAG_RAW_ETY = 1 << 13, + MLX4_DEV_CAP_FLAG_BLH = 1 << 15, + MLX4_DEV_CAP_FLAG_MEM_WINDOW = 1 << 16, + MLX4_DEV_CAP_FLAG_APM = 1 << 17, + MLX4_DEV_CAP_FLAG_ATOMIC = 1 << 18, + MLX4_DEV_CAP_FLAG_RAW_MCAST = 1 << 19, + MLX4_DEV_CAP_FLAG_UD_AV_PORT = 1 << 20, + MLX4_DEV_CAP_FLAG_UD_MCAST = 1 << 21, + MLX4_DEV_CAP_FLAG_IBOE = 1 << 30, + MLX4_DEV_CAP_FLAG_FC_T11 = 1 << 31 +}; + +enum { + MLX4_BMME_FLAG_LOCAL_INV = 1 << 6, + MLX4_BMME_FLAG_REMOTE_INV = 1 << 7, + MLX4_BMME_FLAG_TYPE_2_WIN = 1 << 9, + MLX4_BMME_FLAG_RESERVED_LKEY = 1 << 10, + MLX4_BMME_FLAG_FAST_REG_WR = 1 << 11, +}; + +enum mlx4_event { + MLX4_EVENT_TYPE_COMP = 0x00, + MLX4_EVENT_TYPE_PATH_MIG = 0x01, + MLX4_EVENT_TYPE_COMM_EST = 0x02, + MLX4_EVENT_TYPE_SQ_DRAINED = 0x03, + MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE = 0x13, + MLX4_EVENT_TYPE_SRQ_LIMIT = 0x14, + MLX4_EVENT_TYPE_CQ_ERROR = 0x04, + MLX4_EVENT_TYPE_WQ_CATAS_ERROR = 0x05, + MLX4_EVENT_TYPE_EEC_CATAS_ERROR = 0x06, + MLX4_EVENT_TYPE_PATH_MIG_FAILED = 0x07, + MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR = 0x10, + MLX4_EVENT_TYPE_WQ_ACCESS_ERROR = 0x11, + MLX4_EVENT_TYPE_SRQ_CATAS_ERROR = 0x12, + MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR = 0x08, + MLX4_EVENT_TYPE_PORT_CHANGE = 0x09, + MLX4_EVENT_TYPE_EQ_OVERFLOW = 0x0f, + MLX4_EVENT_TYPE_ECC_DETECT = 0x0e, + MLX4_EVENT_TYPE_CMD = 0x0a +}; + +enum { + MLX4_PORT_CHANGE_SUBTYPE_DOWN = 1, + MLX4_PORT_CHANGE_SUBTYPE_ACTIVE = 4 +}; + +enum { + MLX4_PERM_LOCAL_READ = 1 << 10, + MLX4_PERM_LOCAL_WRITE = 1 << 11, + MLX4_PERM_REMOTE_READ = 1 << 12, + MLX4_PERM_REMOTE_WRITE = 1 << 13, + MLX4_PERM_ATOMIC = 1 << 14 +}; + +enum { + MLX4_OPCODE_NOP = 0x00, + MLX4_OPCODE_SEND_INVAL = 0x01, + MLX4_OPCODE_RDMA_WRITE = 0x08, + MLX4_OPCODE_RDMA_WRITE_IMM = 0x09, + MLX4_OPCODE_SEND = 0x0a, + MLX4_OPCODE_SEND_IMM = 0x0b, + MLX4_OPCODE_LSO = 0x0e, + MLX4_OPCODE_BIG_LSO = 0x2e, + MLX4_OPCODE_RDMA_READ = 0x10, + MLX4_OPCODE_ATOMIC_CS = 0x11, + MLX4_OPCODE_ATOMIC_FA = 0x12, + MLX4_OPCODE_MASKED_ATOMIC_CS = 0x14, + MLX4_OPCODE_MASKED_ATOMIC_FA = 0x15, + MLX4_OPCODE_BIND_MW = 0x18, + MLX4_OPCODE_FMR = 0x19, + MLX4_OPCODE_LOCAL_INVAL = 0x1b, + MLX4_OPCODE_CONFIG_CMD = 0x1f, + + MLX4_RECV_OPCODE_RDMA_WRITE_IMM = 0x00, + MLX4_RECV_OPCODE_SEND = 0x01, + MLX4_RECV_OPCODE_SEND_IMM = 0x02, + MLX4_RECV_OPCODE_SEND_INVAL = 0x03, + + MLX4_CQE_OPCODE_ERROR = 0x1e, + MLX4_CQE_OPCODE_RESIZE = 0x16, +}; + +enum { + MLX4_STAT_RATE_OFFSET = 5 +}; + +enum { + MLX4_MTT_FLAG_PRESENT = 1 +}; + +enum mlx4_qp_region { + MLX4_QP_REGION_FW = 0, + MLX4_QP_REGION_ETH_ADDR, + MLX4_QP_REGION_FC_ADDR, + MLX4_NUM_QP_REGION +}; + +enum mlx4_port_type { + MLX4_PORT_TYPE_NONE = 0, + MLX4_PORT_TYPE_IB = 1, + MLX4_PORT_TYPE_ETH = 2, + MLX4_PORT_TYPE_AUTO = 3 +}; + +enum mlx4_special_vlan_idx { + MLX4_NO_VLAN_IDX = 0, + MLX4_VLAN_MISS_IDX, + MLX4_VLAN_REGULAR +}; +#define MLX4_LEAST_ATTACHED_VECTOR 0xffffffff + +enum { + MLX4_CUNTERS_DISABLED, + MLX4_CUNTERS_BASIC, + MLX4_CUNTERS_EXT +}; + +enum { + MAX_FAST_REG_PAGES = 511, +}; + +static inline u64 mlx4_fw_ver(u64 major, u64 minor, u64 subminor) +{ + return (major << 32) | (minor << 16) | subminor; +} + +struct mlx4_caps { + u64 fw_ver; + int num_ports; + int vl_cap[MLX4_MAX_PORTS + 1]; + int ib_mtu_cap[MLX4_MAX_PORTS + 1]; + __be32 ib_port_def_cap[MLX4_MAX_PORTS + 1]; + u64 def_mac[MLX4_MAX_PORTS + 1]; + int eth_mtu_cap[MLX4_MAX_PORTS + 1]; + int gid_table_len[MLX4_MAX_PORTS + 1]; + int pkey_table_len[MLX4_MAX_PORTS + 1]; + int trans_type[MLX4_MAX_PORTS + 1]; + int vendor_oui[MLX4_MAX_PORTS + 1]; + int wavelength[MLX4_MAX_PORTS + 1]; + u64 trans_code[MLX4_MAX_PORTS + 1]; + int local_ca_ack_delay; + int num_uars; + int bf_reg_size; + int bf_regs_per_page; + int max_sq_sg; + int max_rq_sg; + int num_qps; + int max_wqes; + int max_sq_desc_sz; + int max_rq_desc_sz; + int max_qp_init_rdma; + int max_qp_dest_rdma; + int sqp_start; + int num_srqs; + int max_srq_wqes; + int max_srq_sge; + int reserved_srqs; + int num_cqs; + int max_cqes; + int reserved_cqs; + int num_eqs; + int reserved_eqs; + int num_comp_vectors; + int num_mpts; + int num_mtt_segs; + int mtts_per_seg; + int fmr_reserved_mtts; + int reserved_mtts; + int reserved_mrws; + int reserved_uars; + int num_mgms; + int num_amgms; + int reserved_mcgs; + int num_qp_per_mgm; + int num_pds; + int reserved_pds; + int mtt_entry_sz; + int reserved_xrcds; + int max_xrcds; + u32 max_msg_sz; + u32 page_size_cap; + u64 flags; + u32 bmme_flags; + u32 reserved_lkey; + u16 stat_rate_support; + int udp_rss; + int loopback_support; + u8 port_width_cap[MLX4_MAX_PORTS + 1]; + int max_gso_sz; + int reserved_qps_cnt[MLX4_NUM_QP_REGION]; + int reserved_qps; + int reserved_qps_base[MLX4_NUM_QP_REGION]; + int log_num_macs; + int log_num_vlans; + int log_num_prios; + enum mlx4_port_type port_type[MLX4_MAX_PORTS + 1]; + u8 supported_type[MLX4_MAX_PORTS + 1]; + enum mlx4_port_type port_mask[MLX4_MAX_PORTS + 1]; + enum mlx4_port_type possible_type[MLX4_MAX_PORTS + 1]; + u8 counters_mode; + u32 max_basic_counters; + u32 max_ext_counters; + u32 mc_promisc_mode; +}; + +struct mlx4_buf_list { + void *buf; + dma_addr_t map; +}; + +struct mlx4_buf { + struct mlx4_buf_list direct; + struct mlx4_buf_list *page_list; + int nbufs; + int npages; + int page_shift; +}; + +struct mlx4_mtt { + u32 first_seg; + int order; + int page_shift; +}; + +enum { + MLX4_DB_PER_PAGE = PAGE_SIZE / 4 +}; + +struct mlx4_db_pgdir { + struct list_head list; + DECLARE_BITMAP(order0, MLX4_DB_PER_PAGE); + DECLARE_BITMAP(order1, MLX4_DB_PER_PAGE / 2); + unsigned long *bits[2]; + __be32 *db_page; + dma_addr_t db_dma; +}; + +struct mlx4_ib_user_db_page; + +struct mlx4_db { + __be32 *db; + union { + struct mlx4_db_pgdir *pgdir; + struct mlx4_ib_user_db_page *user_page; + } u; + dma_addr_t dma; + int index; + int order; +}; + +struct mlx4_hwq_resources { + struct mlx4_db db; + struct mlx4_mtt mtt; + struct mlx4_buf buf; +}; + +struct mlx4_mr { + struct mlx4_mtt mtt; + u64 iova; + u64 size; + u32 key; + u32 pd; + u32 access; + int enabled; +}; + +struct mlx4_fmr { + struct mlx4_mr mr; + struct mlx4_mpt_entry *mpt; + __be64 *mtts; + dma_addr_t dma_handle; + int max_pages; + int max_maps; + int maps; + u8 page_shift; +}; + +struct mlx4_uar { + unsigned long pfn; + int index; + struct list_head bf_list; + unsigned free_bf_bmap; + void __iomem *map; + void __iomem *bf_map; +}; + +struct mlx4_bf { + unsigned long offset; + int buf_size; + struct mlx4_uar *uar; + void __iomem *reg; +}; + +struct mlx4_cq { + void (*comp) (struct mlx4_cq *); + void (*event) (struct mlx4_cq *, enum mlx4_event); + + struct mlx4_uar *uar; + + u32 cons_index; + + __be32 *set_ci_db; + __be32 *arm_db; + int arm_sn; + + int cqn; + unsigned vector; + + atomic_t refcount; + struct completion free; +}; + +struct mlx4_qp { + void (*event) (struct mlx4_qp *, enum mlx4_event); + + int qpn; + + atomic_t refcount; + struct completion free; +}; + +struct mlx4_srq { + void (*event) (struct mlx4_srq *, enum mlx4_event); + + int srqn; + int max; + int max_gs; + int wqe_shift; + + atomic_t refcount; + struct completion free; +}; + +struct mlx4_av { + __be32 port_pd; + u8 reserved1; + u8 g_slid; + __be16 dlid; + u8 reserved2; + u8 gid_index; + u8 stat_rate; + u8 hop_limit; + __be32 sl_tclass_flowlabel; + u8 dgid[16]; +}; + +struct mlx4_eth_av { + __be32 port_pd; + u8 reserved1; + u8 smac_idx; + u16 reserved2; + u8 reserved3; + u8 gid_index; + u8 stat_rate; + u8 hop_limit; + __be32 sl_tclass_flowlabel; + u8 dgid[16]; + u32 reserved4[2]; + __be16 vlan; + u8 mac[6]; +}; + +union mlx4_ext_av { + struct mlx4_av ib; + struct mlx4_eth_av eth; +}; + +struct mlx4_counters { + __be32 counter_mode; + __be32 num_ifc; + u32 reserved[2]; + __be64 rx_frames; + __be64 rx_bytes; + __be64 tx_frames; + __be64 tx_bytes; +}; + +struct mlx4_counters_ext { + __be32 counter_mode; + __be32 num_ifc; + u32 reserved[2]; + __be64 rx_uni_frames; + __be64 rx_uni_bytes; + __be64 rx_mcast_frames; + __be64 rx_mcast_bytes; + __be64 rx_bcast_frames; + __be64 rx_bcast_bytes; + __be64 rx_nobuf_frames; + __be64 rx_nobuf_bytes; + __be64 rx_err_frames; + __be64 rx_err_bytes; + __be64 tx_uni_frames; + __be64 tx_uni_bytes; + __be64 tx_mcast_frames; + __be64 tx_mcast_bytes; + __be64 tx_bcast_frames; + __be64 tx_bcast_bytes; + __be64 tx_nobuf_frames; + __be64 tx_nobuf_bytes; + __be64 tx_err_frames; + __be64 tx_err_bytes; +}; + +struct mlx4_dev { + struct pci_dev *pdev; + unsigned long flags; + struct mlx4_caps caps; + struct radix_tree_root qp_table_tree; + struct radix_tree_root srq_table_tree; + u32 rev_id; + char board_id[MLX4_BOARD_ID_LEN]; +}; + +struct mlx4_init_port_param { + int set_guid0; + int set_node_guid; + int set_si_guid; + u16 mtu; + int port_width_cap; + u16 vl_cap; + u16 max_gid; + u16 max_pkey; + u64 guid0; + u64 node_guid; + u64 si_guid; +}; + +static inline void mlx4_query_steer_cap(struct mlx4_dev *dev, int *log_mac, + int *log_vlan, int *log_prio) +{ + *log_mac = dev->caps.log_num_macs; + *log_vlan = dev->caps.log_num_vlans; + *log_prio = dev->caps.log_num_prios; +} + +#define mlx4_foreach_port(port, dev, type) \ + for ((port) = 1; (port) <= (dev)->caps.num_ports; (port)++) \ + if ((type) == (dev)->caps.port_mask[(port)]) + +#define mlx4_foreach_ib_transport_port(port, dev) \ + for ((port) = 1; (port) <= (dev)->caps.num_ports; (port)++) \ + if (((dev)->caps.port_mask[port] == MLX4_PORT_TYPE_IB) || \ + ((dev)->caps.flags & MLX4_DEV_CAP_FLAG_IBOE)) + +int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, + struct mlx4_buf *buf); +void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf); +static inline void *mlx4_buf_offset(struct mlx4_buf *buf, int offset) +{ + if (buf->direct.buf != NULL) + return buf->direct.buf + offset; + else + return buf->page_list[offset >> PAGE_SHIFT].buf + + (offset & (PAGE_SIZE - 1)); +} + +int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn); +void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn); + +int mlx4_xrcd_alloc(struct mlx4_dev *dev, u32 *xrcdn); +void mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn); + +int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar); +void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar); +int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf); +void mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf); + +int mlx4_mtt_init(struct mlx4_dev *dev, int npages, int page_shift, + struct mlx4_mtt *mtt); +void mlx4_mtt_cleanup(struct mlx4_dev *dev, struct mlx4_mtt *mtt); +u64 mlx4_mtt_addr(struct mlx4_dev *dev, struct mlx4_mtt *mtt); + +int mlx4_mr_reserve_range(struct mlx4_dev *dev, int cnt, int align, u32 *base_mridx); +void mlx4_mr_release_range(struct mlx4_dev *dev, u32 base_mridx, int cnt); +int mlx4_mr_alloc_reserved(struct mlx4_dev *dev, u32 mridx, u32 pd, + u64 iova, u64 size, u32 access, int npages, + int page_shift, struct mlx4_mr *mr); +int mlx4_mr_alloc(struct mlx4_dev *dev, u32 pd, u64 iova, u64 size, u32 access, + int npages, int page_shift, struct mlx4_mr *mr); +void mlx4_mr_free_reserved(struct mlx4_dev *dev, struct mlx4_mr *mr); +void mlx4_mr_free(struct mlx4_dev *dev, struct mlx4_mr *mr); +int mlx4_mr_enable(struct mlx4_dev *dev, struct mlx4_mr *mr); +int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + int start_index, int npages, u64 *page_list); +int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + struct mlx4_buf *buf); + +int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order); +void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db); + +int mlx4_alloc_hwq_res(struct mlx4_dev *dev, struct mlx4_hwq_resources *wqres, + int size, int max_direct); +void mlx4_free_hwq_res(struct mlx4_dev *mdev, struct mlx4_hwq_resources *wqres, + int size); + +int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, + struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq, + unsigned vector, int collapsed); +void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq); + +int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base); +void mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt); + +int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp); +void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp); + +int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd, + struct mlx4_mtt *mtt, u64 db_rec, struct mlx4_srq *srq); +void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq); +int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark); +int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_watermark); + +int mlx4_INIT_PORT(struct mlx4_dev *dev, int port); +int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port); + +int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + int block_mcast_loopback, enum mlx4_mcast_prot prot); +int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + enum mlx4_mcast_prot prot); + +int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index); +void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index); + +int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx); +int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index); +void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index); + +int mlx4_map_phys_fmr_fbo(struct mlx4_dev *dev, struct mlx4_fmr *fmr, + u64 *page_list, int npages, u64 iova, u32 fbo, + u32 len, u32 *lkey, u32 *rkey, int same_key); +int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list, + int npages, u64 iova, u32 *lkey, u32 *rkey); +int mlx4_fmr_alloc_reserved(struct mlx4_dev *dev, u32 mridx, u32 pd, + u32 access, int max_pages, int max_maps, + u8 page_shift, struct mlx4_fmr *fmr); +int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, + int max_maps, u8 page_shift, struct mlx4_fmr *fmr); +int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr); +void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, + u32 *lkey, u32 *rkey); +int mlx4_fmr_free_reserved(struct mlx4_dev *dev, struct mlx4_fmr *fmr); +int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr); +int mlx4_SYNC_TPT(struct mlx4_dev *dev); +int mlx4_query_diag_counters(struct mlx4_dev *mlx4_dev, int array_length, + u8 op_modifier, u32 in_offset[], u32 counter_out[]); +int mlx4_test_interrupts(struct mlx4_dev *dev); + +void mlx4_get_fc_t11_settings(struct mlx4_dev *dev, int *enable_pre_t11, int *t11_supported); + +int mlx4_counter_alloc(struct mlx4_dev *dev, u32 *idx); +void mlx4_counter_free(struct mlx4_dev *dev, u32 idx); + +#endif /* MLX4_DEVICE_H */ diff --git a/sys/ofed/include/linux/mlx4/doorbell.h b/sys/ofed/include/linux/mlx4/doorbell.h new file mode 100644 index 000000000000..f31bba270aa2 --- /dev/null +++ b/sys/ofed/include/linux/mlx4/doorbell.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_DOORBELL_H +#define MLX4_DOORBELL_H + +#include +#include + +#define MLX4_SEND_DOORBELL 0x14 +#define MLX4_CQ_DOORBELL 0x20 + +#if BITS_PER_LONG == 64 +/* + * Assume that we can just write a 64-bit doorbell atomically. s390 + * actually doesn't have writeq() but S/390 systems don't even have + * PCI so we won't worry about it. + */ + +#define MLX4_DECLARE_DOORBELL_LOCK(name) +#define MLX4_INIT_DOORBELL_LOCK(ptr) do { } while (0) +#define MLX4_GET_DOORBELL_LOCK(ptr) (NULL) + +static inline void mlx4_write64(__be32 val[2], void __iomem *dest, + spinlock_t *doorbell_lock) +{ + __raw_writeq(*(u64 *) val, dest); +} + +#else + +/* + * Just fall back to a spinlock to protect the doorbell if + * BITS_PER_LONG is 32 -- there's no portable way to do atomic 64-bit + * MMIO writes. + */ + +#define MLX4_DECLARE_DOORBELL_LOCK(name) spinlock_t name; +#define MLX4_INIT_DOORBELL_LOCK(ptr) spin_lock_init(ptr) +#define MLX4_GET_DOORBELL_LOCK(ptr) (ptr) + +static inline void mlx4_write64(__be32 val[2], void __iomem *dest, + spinlock_t *doorbell_lock) +{ + unsigned long flags; + + spin_lock_irqsave(doorbell_lock, flags); + __raw_writel((__force u32) val[0], dest); + __raw_writel((__force u32) val[1], dest + 4); + spin_unlock_irqrestore(doorbell_lock, flags); +} + +#endif + +#endif /* MLX4_DOORBELL_H */ diff --git a/sys/ofed/include/linux/mlx4/driver.h b/sys/ofed/include/linux/mlx4/driver.h new file mode 100644 index 000000000000..15c8319a5ca1 --- /dev/null +++ b/sys/ofed/include/linux/mlx4/driver.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_DRIVER_H +#define MLX4_DRIVER_H + +#include + +struct mlx4_dev; + +enum mlx4_dev_event { + MLX4_DEV_EVENT_CATASTROPHIC_ERROR, + MLX4_DEV_EVENT_PORT_UP, + MLX4_DEV_EVENT_PORT_DOWN, + MLX4_DEV_EVENT_PORT_REINIT, +}; + +enum mlx4_query_reply { + MLX4_QUERY_NOT_MINE = -1, + MLX4_QUERY_MINE_NOPORT = 0 +}; + +enum mlx4_prot { + MLX4_PROT_IB, + MLX4_PROT_EN, +}; + +enum mlx4_mcast_prot { + MLX4_MCAST_PROT_IB = 0, + MLX4_MCAST_PROT_EN = 1, +}; + +struct mlx4_interface { + void * (*add) (struct mlx4_dev *dev); + void (*remove)(struct mlx4_dev *dev, void *context); + void (*event) (struct mlx4_dev *dev, void *context, + enum mlx4_dev_event event, int port); + void * (*get_prot_dev) (struct mlx4_dev *dev, void *context, u8 port); + enum mlx4_prot protocol; + + enum mlx4_query_reply (*query) (void *context, void *); + struct list_head list; +}; + +int mlx4_register_interface(struct mlx4_interface *intf); +void mlx4_unregister_interface(struct mlx4_interface *intf); +void *mlx4_get_prot_dev(struct mlx4_dev *dev, enum mlx4_prot proto, int port); + +struct mlx4_dev *mlx4_query_interface(void *, int *port); +void mlx4_set_iboe_counter(struct mlx4_dev *dev, int index, u8 port); +int mlx4_get_iboe_counter(struct mlx4_dev *dev, u8 port); + +#endif /* MLX4_DRIVER_H */ diff --git a/sys/ofed/include/linux/mlx4/qp.h b/sys/ofed/include/linux/mlx4/qp.h new file mode 100644 index 000000000000..3fe2bc508275 --- /dev/null +++ b/sys/ofed/include/linux/mlx4/qp.h @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_QP_H +#define MLX4_QP_H + +#include + +#include + +#define MLX4_INVALID_LKEY 0x100 + +enum mlx4_qp_optpar { + MLX4_QP_OPTPAR_ALT_ADDR_PATH = 1 << 0, + MLX4_QP_OPTPAR_RRE = 1 << 1, + MLX4_QP_OPTPAR_RAE = 1 << 2, + MLX4_QP_OPTPAR_RWE = 1 << 3, + MLX4_QP_OPTPAR_PKEY_INDEX = 1 << 4, + MLX4_QP_OPTPAR_Q_KEY = 1 << 5, + MLX4_QP_OPTPAR_RNR_TIMEOUT = 1 << 6, + MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH = 1 << 7, + MLX4_QP_OPTPAR_SRA_MAX = 1 << 8, + MLX4_QP_OPTPAR_RRA_MAX = 1 << 9, + MLX4_QP_OPTPAR_PM_STATE = 1 << 10, + MLX4_QP_OPTPAR_RETRY_COUNT = 1 << 12, + MLX4_QP_OPTPAR_RNR_RETRY = 1 << 13, + MLX4_QP_OPTPAR_ACK_TIMEOUT = 1 << 14, + MLX4_QP_OPTPAR_SCHED_QUEUE = 1 << 16, + MLX4_QP_OPTPAR_COUNTER_INDEX = 1 << 20 +}; + +enum mlx4_qp_state { + MLX4_QP_STATE_RST = 0, + MLX4_QP_STATE_INIT = 1, + MLX4_QP_STATE_RTR = 2, + MLX4_QP_STATE_RTS = 3, + MLX4_QP_STATE_SQER = 4, + MLX4_QP_STATE_SQD = 5, + MLX4_QP_STATE_ERR = 6, + MLX4_QP_STATE_SQ_DRAINING = 7, + MLX4_QP_NUM_STATE +}; + +enum { + MLX4_QP_ST_RC = 0x0, + MLX4_QP_ST_UC = 0x1, + MLX4_QP_ST_RD = 0x2, + MLX4_QP_ST_UD = 0x3, + MLX4_QP_ST_XRC = 0x6, + MLX4_QP_ST_MLX = 0x7 +}; + +enum { + MLX4_QP_PM_MIGRATED = 0x3, + MLX4_QP_PM_ARMED = 0x0, + MLX4_QP_PM_REARM = 0x1 +}; + +enum { + /* params1 */ + MLX4_QP_BIT_SRE = 1 << 15, + MLX4_QP_BIT_SWE = 1 << 14, + MLX4_QP_BIT_SAE = 1 << 13, + /* params2 */ + MLX4_QP_BIT_RRE = 1 << 15, + MLX4_QP_BIT_RWE = 1 << 14, + MLX4_QP_BIT_RAE = 1 << 13, + MLX4_QP_BIT_RIC = 1 << 4, +}; + +struct mlx4_qp_path { + u8 fl; + u8 reserved1[2]; + u8 pkey_index; + u8 counter_index; + u8 grh_mylmc; + __be16 rlid; + u8 ackto; + u8 mgid_index; + u8 static_rate; + u8 hop_limit; + __be32 tclass_flowlabel; + u8 rgid[16]; + u8 sched_queue; + u8 vlan_index; + u8 reserved3[2]; + u8 reserved4[2]; + u8 dmac[6]; +}; + +struct mlx4_qp_context { + __be32 flags; + __be32 pd; + u8 mtu_msgmax; + u8 rq_size_stride; + u8 sq_size_stride; + u8 rlkey; + __be32 usr_page; + __be32 local_qpn; + __be32 remote_qpn; + struct mlx4_qp_path pri_path; + struct mlx4_qp_path alt_path; + __be32 params1; + u32 reserved1; + __be32 next_send_psn; + __be32 cqn_send; + u32 reserved2[2]; + __be32 last_acked_psn; + __be32 ssn; + __be32 params2; + __be32 rnr_nextrecvpsn; + __be32 xrcd; + __be32 cqn_recv; + __be64 db_rec_addr; + __be32 qkey; + __be32 srqn; + __be32 msn; + __be16 rq_wqe_counter; + __be16 sq_wqe_counter; + u32 reserved3[2]; + __be32 param3; + __be32 nummmcpeers_basemkey; + u8 log_page_size; + u8 reserved4[2]; + u8 mtt_base_addr_h; + __be32 mtt_base_addr_l; + u8 VE; + u8 reserved5; + __be16 VFT_id_prio; + u8 reserved6; + u8 exch_size; + __be16 exch_base; + u8 VFT_hop_cnt; + u8 my_fc_id_idx; + __be16 reserved7; + u32 reserved8[7]; +}; + +/* Which firmware version adds support for NEC (NoErrorCompletion) bit */ +#define MLX4_FW_VER_WQE_CTRL_NEC mlx4_fw_ver(2, 2, 232) + +enum { + MLX4_WQE_CTRL_NEC = 1 << 29, + MLX4_WQE_CTRL_FENCE = 1 << 6, + MLX4_WQE_CTRL_CQ_UPDATE = 3 << 2, + MLX4_WQE_CTRL_SOLICITED = 1 << 1, + MLX4_WQE_CTRL_IP_CSUM = 1 << 4, + MLX4_WQE_CTRL_TCP_UDP_CSUM = 1 << 5, + MLX4_WQE_CTRL_INS_VLAN = 1 << 6, + MLX4_WQE_CTRL_STRONG_ORDER = 1 << 7, + MLX4_WQE_CTRL_FORCE_LOOPBACK = 1 << 0, +}; + +struct mlx4_wqe_ctrl_seg { + __be32 owner_opcode; + __be16 vlan_tag; + u8 ins_vlan; + u8 fence_size; + /* + * High 24 bits are SRC remote buffer; low 8 bits are flags: + * [7] SO (strong ordering) + * [5] TCP/UDP checksum + * [4] IP checksum + * [3:2] C (generate completion queue entry) + * [1] SE (solicited event) + */ + __be32 srcrb_flags; + /* + * imm is immediate data for send/RDMA write w/ immediate; + * also invalidation key for send with invalidate; input + * modifier for WQEs on CCQs. + */ + __be32 imm; +}; + +enum { + MLX4_WQE_MLX_VL15 = 1 << 17, + MLX4_WQE_MLX_SLR = 1 << 16, + MLX4_WQE_MLX_ICRC = 1 << 4 +}; + +struct mlx4_wqe_mlx_seg { + u8 owner; + u8 reserved1[2]; + u8 opcode; + u8 reserved2[3]; + u8 size; + /* + * [17] VL15 + * [16] SLR + * [15:12] static rate + * [11:8] SL + * [4] ICRC + * [3:2] C + * [0] FL (force loopback) + */ + __be32 flags; + __be16 rlid; + u16 reserved3; +}; + +struct mlx4_wqe_datagram_seg { + __be32 av[8]; + __be32 dqpn; + __be32 qkey; + __be16 vlan; + u8 mac[6]; +}; + +struct mlx4_wqe_lso_seg { + __be32 mss_hdr_size; + __be32 header[0]; +}; + +struct mlx4_wqe_bind_seg { + __be32 flags1; + __be32 flags2; + __be32 new_rkey; + __be32 lkey; + __be64 addr; + __be64 length; +}; + +enum { + MLX4_WQE_FMR_PERM_LOCAL_READ = 1 << 27, + MLX4_WQE_FMR_PERM_LOCAL_WRITE = 1 << 28, + MLX4_WQE_FMR_PERM_REMOTE_READ = 1 << 29, + MLX4_WQE_FMR_PERM_REMOTE_WRITE = 1 << 30, + MLX4_WQE_FMR_PERM_ATOMIC = 1 << 31 +}; + +struct mlx4_wqe_fmr_seg { + __be32 flags; + __be32 mem_key; + __be64 buf_list; + __be64 start_addr; + __be64 reg_len; + __be32 offset; + __be32 page_size; + u32 reserved[2]; +}; + +struct mlx4_wqe_fmr_ext_seg { + u8 flags; + u8 reserved; + __be16 app_mask; + __be16 wire_app_tag; + __be16 mem_app_tag; + __be32 wire_ref_tag_base; + __be32 mem_ref_tag_base; +}; + +struct mlx4_wqe_local_inval_seg { + __be32 flags; + u32 reserved1; + __be32 mem_key; + u32 reserved2[2]; + __be32 guest_id; + __be64 pa; +}; + +struct mlx4_wqe_raddr_seg { + __be64 raddr; + __be32 rkey; + u32 reserved; +}; + +struct mlx4_wqe_atomic_seg { + __be64 swap_add; + __be64 compare; +}; + +struct mlx4_wqe_masked_atomic_seg { + __be64 swap_add; + __be64 compare; + __be64 swap_add_mask; + __be64 compare_mask; +}; + +struct mlx4_wqe_data_seg { + __be32 byte_count; + __be32 lkey; + __be64 addr; +}; + +enum { + MLX4_INLINE_ALIGN = 64, + MLX4_INLINE_SEG = 1 << 31, +}; + +struct mlx4_wqe_inline_seg { + __be32 byte_count; +}; + +int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state, + struct mlx4_qp_context *context, enum mlx4_qp_optpar optpar, + int sqd_event, struct mlx4_qp *qp); + +int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp, + struct mlx4_qp_context *context); + +int mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt, + struct mlx4_qp_context *context, + struct mlx4_qp *qp, enum mlx4_qp_state *qp_state); + +static inline struct mlx4_qp *__mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn) +{ + return radix_tree_lookup(&dev->qp_table_tree, qpn & (dev->caps.num_qps - 1)); +} + +struct mlx4_qp *mlx4_qp_lookup_lock(struct mlx4_dev *dev, u32 qpn); +void mlx4_qp_remove(struct mlx4_dev *dev, struct mlx4_qp *qp); +int mlx4_qp_get_region(struct mlx4_dev *dev, enum mlx4_qp_region region, + int *base_qpn, int *cnt); + +#endif /* MLX4_QP_H */ diff --git a/sys/ofed/include/linux/mlx4/srq.h b/sys/ofed/include/linux/mlx4/srq.h new file mode 100644 index 000000000000..5e041e5fe06f --- /dev/null +++ b/sys/ofed/include/linux/mlx4/srq.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef MLX4_SRQ_H +#define MLX4_SRQ_H + +#include +#include + +struct mlx4_wqe_srq_next_seg { + u16 reserved1; + __be16 next_wqe_index; + u32 reserved2[3]; +}; + +void mlx4_srq_invalidate(struct mlx4_dev *dev, struct mlx4_srq *srq); +void mlx4_srq_remove(struct mlx4_dev *dev, struct mlx4_srq *srq); + +static inline struct mlx4_srq *__mlx4_srq_lookup(struct mlx4_dev *dev, u32 srqn) +{ + return radix_tree_lookup(&dev->srq_table_tree, + srqn & (dev->caps.num_srqs - 1)); +} + +#endif /* MLX4_SRQ_H */ diff --git a/sys/ofed/include/linux/mm.h b/sys/ofed/include/linux/mm.h new file mode 100644 index 000000000000..13b749bdae15 --- /dev/null +++ b/sys/ofed/include/linux/mm.h @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_MM_H_ +#define _LINUX_MM_H_ + +#include +#include +#include + +#define PAGE_ALIGN(x) ALIGN(x, PAGE_SIZE) + +struct vm_area_struct { + vm_offset_t vm_start; + vm_offset_t vm_end; + vm_offset_t vm_pgoff; + vm_paddr_t vm_pfn; /* PFN For mmap. */ + vm_memattr_t vm_page_prot; +}; + +/* + * Compute log2 of the power of two rounded up count of pages + * needed for size bytes. + */ +static inline int +get_order(unsigned long size) +{ + int order; + + size = (size - 1) >> PAGE_SHIFT; + order = 0; + while (size) { + order++; + size >>= 1; + } + return (order); +} + +static inline void * +lowmem_page_address(struct page *page) +{ + + return page_address(page); +} + +/* + * This only works via mmap ops. + */ +static inline int +io_remap_pfn_range(struct vm_area_struct *vma, + unsigned long addr, unsigned long pfn, unsigned long size, + vm_memattr_t prot) +{ + vma->vm_page_prot = prot; + vma->vm_pfn = pfn; + + return (0); +} + +#endif /* _LINUX_MM_H_ */ diff --git a/sys/ofed/include/linux/module.h b/sys/ofed/include/linux/module.h new file mode 100644 index 000000000000..1e3a682a181e --- /dev/null +++ b/sys/ofed/include/linux/module.h @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_MODULE_H_ +#define _LINUX_MODULE_H_ + +#include +#include +#include +#include +#include + +#define MODULE_AUTHOR(name) +#define MODULE_DESCRIPTION(name) +#define MODULE_LICENSE(name) +#define MODULE_VERSION(name) + +#define THIS_MODULE ((struct module *)0) + +#define EXPORT_SYMBOL(name) +#define EXPORT_SYMBOL_GPL(name) + +#include + +static inline void +_module_run(void *arg) +{ + void (*fn)(void); +#ifdef OFED_DEBUG_INIT + char name[1024]; + caddr_t pc; + long offset; + + pc = (caddr_t)arg; + if (linker_search_symbol_name(pc, name, sizeof(name), &offset) != 0) + printf("Running ??? (%p)\n", pc); + else + printf("Running %s (%p)\n", name, pc); +#endif + fn = arg; + DROP_GIANT(); + fn(); + PICKUP_GIANT(); +} + +#define module_init(fn) \ + SYSINIT(fn, SI_SUB_RUN_SCHEDULER, SI_ORDER_FIRST, _module_run, (fn)) + +/* + * XXX This is a freebsdism designed to work around not having a module + * load order resolver built in. + */ +#define module_init_order(fn, order) \ + SYSINIT(fn, SI_SUB_RUN_SCHEDULER, (order), _module_run, (fn)) + +#define module_exit(fn) \ + SYSUNINIT(fn, SI_SUB_RUN_SCHEDULER, SI_ORDER_FIRST, _module_run, (fn)) + +#define module_get(module) +#define module_put(module) +#define try_module_get(module) 1 + +#endif /* _LINUX_MODULE_H_ */ diff --git a/sys/ofed/include/linux/moduleparam.h b/sys/ofed/include/linux/moduleparam.h new file mode 100644 index 000000000000..2c541a67f957 --- /dev/null +++ b/sys/ofed/include/linux/moduleparam.h @@ -0,0 +1,226 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_MODULEPARAM_H_ +#define _LINUX_MODULEPARAM_H_ + +#include + +/* + * These are presently not hooked up to anything. In linux the parameters + * can be set when modules are loaded. On FreeBSD these could be mapped + * to kenv in the future. + */ +struct kernel_param; + +typedef int (*param_set_fn)(const char *val, struct kernel_param *kp); +typedef int (*param_get_fn)(char *buffer, struct kernel_param *kp); + +struct kernel_param { + const char *name; + u16 perm; + u16 flags; + param_set_fn set; + param_get_fn get; + union { + void *arg; + struct kparam_string *str; + struct kparam_array *arr; + } un; +}; + +#define KPARAM_ISBOOL 2 + +struct kparam_string { + unsigned int maxlen; + char *string; +}; + +struct kparam_array +{ + unsigned int max; + unsigned int *num; + param_set_fn set; + param_get_fn get; + unsigned int elemsize; + void *elem; +}; + +static inline void +param_sysinit(struct kernel_param *param) +{ +} + +#define module_param_call(name, set, get, arg, perm) \ + static struct kernel_param __param_##name = \ + { #name, perm, 0, set, get, { arg } }; \ + SYSINIT(name##_param_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, \ + param_sysinit, &__param_##name); + +#define module_param_named(name, var, type, mode) \ + module_param_call(name, param_set_##type, param_get_##type, &var, mode) + +#define module_param(var, type, mode) \ + module_param_named(var, var, type, mode) + +#define MODULE_PARM_DESC(name, desc) + +static inline int +param_set_byte(const char *val, struct kernel_param *kp) +{ + + return 0; +} + +static inline int +param_get_byte(char *buffer, struct kernel_param *kp) +{ + + return 0; +} + + +static inline int +param_set_short(const char *val, struct kernel_param *kp) +{ + + return 0; +} + +static inline int +param_get_short(char *buffer, struct kernel_param *kp) +{ + + return 0; +} + + +static inline int +param_set_ushort(const char *val, struct kernel_param *kp) +{ + + return 0; +} + +static inline int +param_get_ushort(char *buffer, struct kernel_param *kp) +{ + + return 0; +} + + +static inline int +param_set_int(const char *val, struct kernel_param *kp) +{ + + return 0; +} + +static inline int +param_get_int(char *buffer, struct kernel_param *kp) +{ + + return 0; +} + + +static inline int +param_set_uint(const char *val, struct kernel_param *kp) +{ + + return 0; +} + +static inline int +param_get_uint(char *buffer, struct kernel_param *kp) +{ + + return 0; +} + + +static inline int +param_set_long(const char *val, struct kernel_param *kp) +{ + + return 0; +} + +static inline int +param_get_long(char *buffer, struct kernel_param *kp) +{ + + return 0; +} + + +static inline int +param_set_ulong(const char *val, struct kernel_param *kp) +{ + + return 0; +} + +static inline int +param_get_ulong(char *buffer, struct kernel_param *kp) +{ + + return 0; +} + + +static inline int +param_set_charp(const char *val, struct kernel_param *kp) +{ + + return 0; +} + +static inline int +param_get_charp(char *buffer, struct kernel_param *kp) +{ + + return 0; +} + + +static inline int +param_set_bool(const char *val, struct kernel_param *kp) +{ + + return 0; +} + +static inline int +param_get_bool(char *buffer, struct kernel_param *kp) +{ + + return 0; +} + +#endif /* _LINUX_MODULEPARAM_H_ */ diff --git a/sys/ofed/include/linux/mount.h b/sys/ofed/include/linux/mount.h new file mode 100644 index 000000000000..33db94e477ec --- /dev/null +++ b/sys/ofed/include/linux/mount.h @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_MOUNT_H_ +#define _LINUX_MOUNT_H_ + + +#endif /* _LINUX_MOUNT_H_ */ diff --git a/sys/ofed/include/linux/mutex.h b/sys/ofed/include/linux/mutex.h new file mode 100644 index 000000000000..ef658164c383 --- /dev/null +++ b/sys/ofed/include/linux/mutex.h @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_MUTEX_H_ +#define _LINUX_MUTEX_H_ + +#include +#include +#include + +#include + +typedef struct mutex { + struct sx sx; +} mutex_t; + +#define mutex_lock(_m) sx_xlock(&(_m)->sx) +#define mutex_lock_nested(_m, _s) mutex_lock(_m) +#define mutex_lock_interruptible(_m) ({ mutex_lock((_m)); 0; }) +#define mutex_unlock(_m) sx_xunlock(&(_m)->sx) +#define mutex_trylock(_m) !!sx_try_xlock(&(_m)->sx) + +#define DEFINE_MUTEX(lock) \ + mutex_t lock; \ + SX_SYSINIT_FLAGS(lock, &(lock).sx, "lnxmtx", SX_NOWITNESS) + +static inline void +linux_mutex_init(mutex_t *m) +{ + + memset(&m->sx, 0, sizeof(m->sx)); + sx_init_flags(&m->sx, "lnxmtx", SX_NOWITNESS); +} + +#define mutex_init linux_mutex_init + +#endif /* _LINUX_MUTEX_H_ */ diff --git a/sys/ofed/include/linux/net.h b/sys/ofed/include/linux/net.h new file mode 100644 index 000000000000..6e2aff39524b --- /dev/null +++ b/sys/ofed/include/linux/net.h @@ -0,0 +1,73 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_NET_H_ +#define _LINUX_NET_H_ + +#include +#include +#include + +static inline int +sock_create_kern(int family, int type, int proto, struct socket **res) +{ + return -socreate(family, res, type, proto, curthread->td_ucred, + curthread); +} + +static inline int +sock_getname(struct socket *so, struct sockaddr *addr, int *sockaddr_len, + int peer) +{ + struct sockaddr **nam; + int error; + + nam = NULL; + if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) + return (-ENOTCONN); + + if (peer) + error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, nam); + else + error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, nam); + if (error) + return (-error); + *addr = **nam; + *sockaddr_len = addr->sa_len; + + free(*nam, M_SONAME); + return (0); +} + +static inline void +sock_release(struct socket *so) +{ + soclose(so); +} + +#endif /* _LINUX_NET_H_ */ diff --git a/sys/ofed/include/linux/netdevice.h b/sys/ofed/include/linux/netdevice.h new file mode 100644 index 000000000000..b02a9dd6e086 --- /dev/null +++ b/sys/ofed/include/linux/netdevice.h @@ -0,0 +1,159 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_NETDEVICE_H_ +#define _LINUX_NETDEVICE_H_ + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +struct net { +}; + +extern struct net init_net; + +#define MAX_ADDR_LEN 20 + +#define net_device ifnet + +#define dev_get_by_index(n, idx) ifnet_byindex_ref((idx)) +#define dev_hold(d) if_ref((d)) +#define dev_put(d) if_rele((d)) + +#define netif_running(dev) !!((dev)->if_drv_flags & IFF_DRV_RUNNING) +#define netif_oper_up(dev) !!((dev)->if_flags & IFF_UP) +#define netif_carrier_ok(dev) netif_running(dev) + +static inline void * +netdev_priv(const struct net_device *dev) +{ + return (dev->if_softc); +} + +static inline void +_handle_ifnet_link_event(void *arg, struct ifnet *ifp, int linkstate) +{ + struct notifier_block *nb; + + nb = arg; + if (linkstate == LINK_STATE_UP) + nb->notifier_call(nb, NETDEV_UP, ifp); + else + nb->notifier_call(nb, NETDEV_DOWN, ifp); +} + +static inline void +_handle_ifnet_arrival_event(void *arg, struct ifnet *ifp) +{ + struct notifier_block *nb; + + nb = arg; + nb->notifier_call(nb, NETDEV_REGISTER, ifp); +} + +static inline void +_handle_ifnet_departure_event(void *arg, struct ifnet *ifp) +{ + struct notifier_block *nb; + + nb = arg; + nb->notifier_call(nb, NETDEV_UNREGISTER, ifp); +} + +static inline int +register_netdevice_notifier(struct notifier_block *nb) +{ + + nb->tags[NETDEV_UP] = EVENTHANDLER_REGISTER( + ifnet_link_event, _handle_ifnet_link_event, nb, 0); + nb->tags[NETDEV_REGISTER] = EVENTHANDLER_REGISTER( + ifnet_arrival_event, _handle_ifnet_arrival_event, nb, 0); + nb->tags[NETDEV_UNREGISTER] = EVENTHANDLER_REGISTER( + ifnet_departure_event, _handle_ifnet_departure_event, nb, 0); + return (0); +} + +static inline int +unregister_netdevice_notifier(struct notifier_block *nb) +{ + + EVENTHANDLER_DEREGISTER(ifnet_link_event, nb->tags[NETDEV_UP]); + EVENTHANDLER_DEREGISTER(ifnet_arrival_event, nb->tags[NETDEV_REGISTER]); + EVENTHANDLER_DEREGISTER(ifnet_departure_event, + nb->tags[NETDEV_UNREGISTER]); + return (0); +} + +#define rtnl_lock() +#define rtnl_unlock() + +static inline int +dev_mc_delete(struct net_device *dev, void *addr, int alen, int all) +{ + struct sockaddr_dl sdl; + + if (alen > sizeof(sdl.sdl_data)) + return (-EINVAL); + memset(&sdl, 0, sizeof(sdl)); + sdl.sdl_len = sizeof(sdl); + sdl.sdl_family = AF_LINK; + sdl.sdl_alen = alen; + memcpy(&sdl.sdl_data, addr, alen); + + return -if_delmulti(dev, (struct sockaddr *)&sdl); +} + +static inline int +dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly) +{ + struct sockaddr_dl sdl; + + if (alen > sizeof(sdl.sdl_data)) + return (-EINVAL); + memset(&sdl, 0, sizeof(sdl)); + sdl.sdl_len = sizeof(sdl); + sdl.sdl_family = AF_LINK; + sdl.sdl_alen = alen; + memcpy(&sdl.sdl_data, addr, alen); + + return -if_addmulti(dev, (struct sockaddr *)&sdl, NULL); +} + +#endif /* _LINUX_NETDEVICE_H_ */ diff --git a/sys/ofed/include/linux/notifier.h b/sys/ofed/include/linux/notifier.h new file mode 100644 index 000000000000..eeef8e7035fe --- /dev/null +++ b/sys/ofed/include/linux/notifier.h @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_NOTIFIER_H_ +#define _LINUX_NOTIFIER_H_ + +#include + +/* + * Max number of FreeBSD events to map to Linux events per notify type. + */ +#define NOTIFY_DONE 0 +#define _NOTIFY_COUNT 5 + +struct notifier_block { + int (*notifier_call)(struct notifier_block *, unsigned long, void *); + struct notifier_block *next; + int priority; + eventhandler_tag tags[_NOTIFY_COUNT]; +}; + +/* Values must be less than NOTIFY_COUNT */ +#define NETDEV_UP 0x0001 +#define NETDEV_DOWN 0x0002 +#define NETDEV_REGISTER 0x0003 +#define NETDEV_UNREGISTER 0x0004 + + +#endif /* _LINUX_NOTIFIER_H_ */ diff --git a/sys/ofed/include/linux/page.h b/sys/ofed/include/linux/page.h new file mode 100644 index 000000000000..0c9052c960e9 --- /dev/null +++ b/sys/ofed/include/linux/page.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_PAGE_H_ +#define _LINUX_PAGE_H_ + +#include + +#include + +#include +#include + +#define page vm_page + +#define virt_to_page(x) PHYS_TO_VM_PAGE(vtophys((x))) + +#define clear_page(page) memset((page), 0, PAGE_SIZE) +#define pgprot_noncached(prot) VM_MEMATTR_UNCACHED +#define pgprot_writecombine(prot) VM_MEMATTR_WRITE_COMBINING + +#undef PAGE_MASK +#define PAGE_MASK (~(PAGE_SIZE-1)) + +#endif /* _LINUX_PAGE_H_ */ diff --git a/sys/ofed/include/linux/pci.h b/sys/ofed/include/linux/pci.h new file mode 100644 index 000000000000..e4fb5f54ff1a --- /dev/null +++ b/sys/ofed/include/linux/pci.h @@ -0,0 +1,580 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_PCI_H_ +#define _LINUX_PCI_H_ + +#define CONFIG_PCI_MSI + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +struct pci_device_id { + uint32_t vendor; + uint32_t device; + uint32_t subvendor; + uint32_t subdevice; + uint32_t class_mask; + uintptr_t driver_data; +}; + +#define MODULE_DEVICE_TABLE(bus, table) +#define PCI_ANY_ID (-1) +#define PCI_VENDOR_ID_MELLANOX 0x15b3 +#define PCI_VENDOR_ID_TOPSPIN 0x1867 +#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44 +#define PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE 0x5a46 +#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278 +#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282 +#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c +#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274 + + +#define PCI_VDEVICE(vendor, device) \ + PCI_VENDOR_ID_##vendor, (device), PCI_ANY_ID, PCI_ANY_ID, 0, 0 +#define PCI_DEVICE(vendor, device) \ + (vendor), (device), PCI_ANY_ID, PCI_ANY_ID, 0, 0 + +#define to_pci_dev(n) container_of(n, struct pci_dev, dev) + +#define PCI_VENDOR_ID PCIR_DEVVENDOR +#define PCI_COMMAND PCIR_COMMAND +#define PCI_EXP_DEVCTL PCIR_EXPRESS_DEVICE_CTL +#define PCI_EXP_LNKCTL PCIR_EXPRESS_LINK_CTL + +#define IORESOURCE_MEM SYS_RES_MEMORY +#define IORESOURCE_IO SYS_RES_IOPORT +#define IORESOURCE_IRQ SYS_RES_IRQ + +struct pci_dev; + +struct pci_driver { + struct list_head links; + char *name; + struct pci_device_id *id_table; + int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); + void (*remove)(struct pci_dev *dev); + driver_t driver; + devclass_t bsdclass; +}; + +extern struct list_head pci_drivers; +extern struct list_head pci_devices; +extern spinlock_t pci_lock; + +#define __devexit_p(x) x + +struct pci_dev { + struct device dev; + struct list_head links; + struct pci_driver *pdrv; + uint64_t dma_mask; + uint16_t device; + uint16_t vendor; + unsigned int irq; +}; + +static inline struct resource_list_entry * +_pci_get_rle(struct pci_dev *pdev, int type, int rid) +{ + struct pci_devinfo *dinfo; + struct resource_list *rl; + + dinfo = device_get_ivars(pdev->dev.bsddev); + rl = &dinfo->resources; + return resource_list_find(rl, type, rid); +} + +static inline struct resource_list_entry * +_pci_get_bar(struct pci_dev *pdev, int bar) +{ + struct resource_list_entry *rle; + + bar = PCIR_BAR(bar); + if ((rle = _pci_get_rle(pdev, SYS_RES_MEMORY, bar)) == NULL) + rle = _pci_get_rle(pdev, SYS_RES_IOPORT, bar); + return (rle); +} + +static inline struct device * +_pci_find_irq_dev(unsigned int irq) +{ + struct pci_dev *pdev; + + spin_lock(&pci_lock); + list_for_each_entry(pdev, &pci_devices, links) { + if (irq == pdev->dev.irq) + break; + if (irq >= pdev->dev.msix && irq < pdev->dev.msix_max) + break; + } + spin_unlock(&pci_lock); + if (pdev) + return &pdev->dev; + return (NULL); +} + +static inline unsigned long +pci_resource_start(struct pci_dev *pdev, int bar) +{ + struct resource_list_entry *rle; + + if ((rle = _pci_get_bar(pdev, bar)) == NULL) + return (0); + return rle->start; +} + +static inline unsigned long +pci_resource_len(struct pci_dev *pdev, int bar) +{ + struct resource_list_entry *rle; + + if ((rle = _pci_get_bar(pdev, bar)) == NULL) + return (0); + return rle->count; +} + +/* + * All drivers just seem to want to inspect the type not flags. + */ +static inline int +pci_resource_flags(struct pci_dev *pdev, int bar) +{ + struct resource_list_entry *rle; + + if ((rle = _pci_get_bar(pdev, bar)) == NULL) + return (0); + return rle->type; +} + +static inline const char * +pci_name(struct pci_dev *d) +{ + + return device_get_desc(d->dev.bsddev); +} + +static inline void * +pci_get_drvdata(struct pci_dev *pdev) +{ + + return dev_get_drvdata(&pdev->dev); +} + +static inline void +pci_set_drvdata(struct pci_dev *pdev, void *data) +{ + + dev_set_drvdata(&pdev->dev, data); +} + +static inline int +pci_enable_device(struct pci_dev *pdev) +{ + + pci_enable_io(pdev->dev.bsddev, SYS_RES_IOPORT); + pci_enable_io(pdev->dev.bsddev, SYS_RES_MEMORY); + return (0); +} + +static inline void +pci_disable_device(struct pci_dev *pdev) +{ +} + +static inline int +pci_set_master(struct pci_dev *pdev) +{ + + pci_enable_busmaster(pdev->dev.bsddev); + return (0); +} + +static inline int +pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) +{ + int rid; + int type; + + type = pci_resource_flags(pdev, bar); + if (type == 0) + return (-ENODEV); + rid = PCIR_BAR(bar); + if (bus_alloc_resource_any(pdev->dev.bsddev, type, &rid, + RF_ACTIVE) == NULL) + return (-EINVAL); + return (0); +} + +static inline void +pci_release_region(struct pci_dev *pdev, int bar) +{ + struct resource_list_entry *rle; + + if ((rle = _pci_get_bar(pdev, bar)) == NULL) + return; + bus_release_resource(pdev->dev.bsddev, rle->type, rle->rid, rle->res); +} + +static inline void +pci_release_regions(struct pci_dev *pdev) +{ + int i; + + for (i = 0; i <= PCIR_MAX_BAR_0; i++) + pci_release_region(pdev, i); +} + +static inline int +pci_request_regions(struct pci_dev *pdev, const char *res_name) +{ + int error; + int i; + + for (i = 0; i <= PCIR_MAX_BAR_0; i++) { + error = pci_request_region(pdev, i, res_name); + if (error && error != -ENODEV) { + pci_release_regions(pdev); + return (error); + } + } + return (0); +} + +static inline void +pci_disable_msix(struct pci_dev *pdev) +{ + + pci_release_msi(pdev->dev.bsddev); +} + +#define PCI_CAP_ID_EXP PCIY_EXPRESS +#define PCI_CAP_ID_PCIX PCIY_PCIX + +static inline int +pci_find_capability(struct pci_dev *pdev, int capid) +{ + int reg; + + if (pci_find_extcap(pdev->dev.bsddev, capid, ®)) + return (0); + return (reg); +} + +static inline int +pci_read_config_byte(struct pci_dev *pdev, int where, u8 *val) +{ + + *val = (u8)pci_read_config(pdev->dev.bsddev, where, 1); + return (0); +} + +static inline int +pci_read_config_word(struct pci_dev *pdev, int where, u16 *val) +{ + + *val = (u16)pci_read_config(pdev->dev.bsddev, where, 2); + return (0); +} + +static inline int +pci_read_config_dword(struct pci_dev *pdev, int where, u32 *val) +{ + + *val = (u32)pci_read_config(pdev->dev.bsddev, where, 4); + return (0); +} + +static inline int +pci_write_config_byte(struct pci_dev *pdev, int where, u8 val) +{ + + pci_write_config(pdev->dev.bsddev, where, val, 1); + return (0); +} + +static inline int +pci_write_config_word(struct pci_dev *pdev, int where, u16 val) +{ + + pci_write_config(pdev->dev.bsddev, where, val, 2); + return (0); +} + +static inline int +pci_write_config_dword(struct pci_dev *pdev, int where, u32 val) +{ + + pci_write_config(pdev->dev.bsddev, where, val, 4); + return (0); +} + +static struct pci_driver * +linux_pci_find(device_t dev, struct pci_device_id **idp) +{ + struct pci_device_id *id; + struct pci_driver *pdrv; + uint16_t vendor; + uint16_t device; + + vendor = pci_get_vendor(dev); + device = pci_get_device(dev); + + spin_lock(&pci_lock); + list_for_each_entry(pdrv, &pci_drivers, links) { + for (id = pdrv->id_table; id->vendor != 0; id++) { + if (vendor == id->vendor && device == id->device) { + *idp = id; + spin_unlock(&pci_lock); + return (pdrv); + } + } + } + spin_unlock(&pci_lock); + return (NULL); +} + +static inline int +linux_pci_probe(device_t dev) +{ + struct pci_device_id *id; + struct pci_driver *pdrv; + + if ((pdrv = linux_pci_find(dev, &id)) == NULL) + return (ENXIO); + if (device_get_driver(dev) != &pdrv->driver) + return (ENXIO); + device_set_desc(dev, pdrv->name); + return (0); +} + +static inline int +linux_pci_attach(device_t dev) +{ + struct resource_list_entry *rle; + struct pci_dev *pdev; + struct pci_driver *pdrv; + struct pci_device_id *id; + int error; + + pdrv = linux_pci_find(dev, &id); + pdev = device_get_softc(dev); + pdev->dev.parent = &linux_rootdev; + pdev->dev.bsddev = dev; + INIT_LIST_HEAD(&pdev->dev.irqents); + pdev->device = id->device; + pdev->vendor = id->vendor; + pdev->dev.dma_mask = &pdev->dma_mask; + pdev->pdrv = pdrv; + kobject_init(&pdev->dev.kobj, &dev_ktype); + kobject_set_name(&pdev->dev.kobj, device_get_nameunit(dev)); + kobject_add(&pdev->dev.kobj, &linux_rootdev.kobj, + kobject_name(&pdev->dev.kobj)); + rle = _pci_get_rle(pdev, SYS_RES_IRQ, 0); + if (rle) + pdev->dev.irq = rle->start; + else + pdev->dev.irq = 0; + pdev->irq = pdev->dev.irq; + mtx_unlock(&Giant); + spin_lock(&pci_lock); + list_add(&pdev->links, &pci_devices); + spin_unlock(&pci_lock); + error = pdrv->probe(pdev, id); + mtx_lock(&Giant); + if (error) { + spin_lock(&pci_lock); + list_del(&pdev->links); + spin_unlock(&pci_lock); + put_device(&pdev->dev); + return (-error); + } + return (0); +} + +static inline int +linux_pci_detach(device_t dev) +{ + struct pci_dev *pdev; + + pdev = device_get_softc(dev); + mtx_unlock(&Giant); + pdev->pdrv->remove(pdev); + mtx_lock(&Giant); + spin_lock(&pci_lock); + list_del(&pdev->links); + spin_unlock(&pci_lock); + put_device(&pdev->dev); + + return (0); +} + +static device_method_t pci_methods[] = { + DEVMETHOD(device_probe, linux_pci_probe), + DEVMETHOD(device_attach, linux_pci_attach), + DEVMETHOD(device_detach, linux_pci_detach), + {0, 0} +}; + +static inline int +pci_register_driver(struct pci_driver *pdrv) +{ + devclass_t bus; + int error; + + spin_lock(&pci_lock); + list_add(&pdrv->links, &pci_drivers); + spin_unlock(&pci_lock); + bus = devclass_find("pci"); + pdrv->driver.name = pdrv->name; + pdrv->driver.methods = pci_methods; + pdrv->driver.size = sizeof(struct pci_dev); + mtx_lock(&Giant); + error = devclass_add_driver(bus, &pdrv->driver, BUS_PASS_DEFAULT, + &pdrv->bsdclass); + mtx_unlock(&Giant); + if (error) + return (-error); + return (0); +} + +static inline void +pci_unregister_driver(struct pci_driver *pdrv) +{ + devclass_t bus; + + list_del(&pdrv->links); + bus = devclass_find("pci"); + mtx_lock(&Giant); + devclass_delete_driver(bus, &pdrv->driver); + mtx_unlock(&Giant); +} + +struct msix_entry { + int entry; + int vector; +}; + +/* + * Enable msix, positive errors indicate actual number of available + * vectors. Negative errors are failures. + */ +static inline int +pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq) +{ + struct resource_list_entry *rle; + int error; + int avail; + int i; + + avail = pci_msix_count(pdev->dev.bsddev); + if (avail < nreq) { + if (avail == 0) + return -EINVAL; + return avail; + } + avail = nreq; + if ((error = -pci_alloc_msix(pdev->dev.bsddev, &avail)) != 0) + return error; + rle = _pci_get_rle(pdev, SYS_RES_IRQ, 1); + pdev->dev.msix = rle->start; + pdev->dev.msix_max = rle->start + avail; + for (i = 0; i < nreq; i++) + entries[i].vector = pdev->dev.msix + i; + return (0); +} + +/* XXX This should not be necessary. */ +#define pcix_set_mmrbc(d, v) 0 +#define pcix_get_max_mmrbc(d) 0 +#define pcie_set_readrq(d, v) 0 + +#define PCI_DMA_BIDIRECTIONAL 0 +#define PCI_DMA_TODEVICE 1 +#define PCI_DMA_FROMDEVICE 2 +#define PCI_DMA_NONE 3 + +#define pci_pool dma_pool +#define pci_pool_destroy dma_pool_destroy +#define pci_pool_alloc dma_pool_alloc +#define pci_pool_free dma_pool_free +#define pci_pool_create(_name, _pdev, _size, _align, _alloc) \ + dma_pool_create(_name, &(_pdev)->dev, _size, _align, _alloc) +#define pci_free_consistent(_hwdev, _size, _vaddr, _dma_handle) \ + dma_free_coherent((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \ + _size, _vaddr, _dma_handle) +#define pci_map_sg(_hwdev, _sg, _nents, _dir) \ + dma_map_sg((_hwdev) == NULL ? NULL : &(_hwdev->dev), \ + _sg, _nents, (enum dma_data_direction)_dir) +#define pci_map_single(_hwdev, _ptr, _size, _dir) \ + dma_map_single((_hwdev) == NULL ? NULL : &(_hwdev->dev), \ + (_ptr), (_size), (enum dma_data_direction)_dir) +#define pci_unmap_single(_hwdev, _addr, _size, _dir) \ + dma_unmap_single((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \ + _addr, _size, (enum dma_data_direction)_dir) +#define pci_unmap_sg(_hwdev, _sg, _nents, _dir) \ + dma_unmap_sg((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \ + _sg, _nents, (enum dma_data_direction)_dir) +#define pci_map_page(_hwdev, _page, _offset, _size, _dir) \ + dma_map_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, _page,\ + _offset, _size, (enum dma_data_direction)_dir) +#define pci_unmap_page(_hwdev, _dma_address, _size, _dir) \ + dma_unmap_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \ + _dma_address, _size, (enum dma_data_direction)_dir) +#define pci_set_dma_mask(_pdev, mask) dma_set_mask(&(_pdev)->dev, (mask)) +#define pci_dma_mapping_error(_pdev, _dma_addr) \ + dma_mapping_error(&(_pdev)->dev, _dma_addr) +#define pci_set_consistent_dma_mask(_pdev, _mask) \ + dma_set_coherent_mask(&(_pdev)->dev, (_mask)) +#define DECLARE_PCI_UNMAP_ADDR(x) DEFINE_DMA_UNMAP_ADDR(x); +#define DECLARE_PCI_UNMAP_LEN(x) DEFINE_DMA_UNMAP_LEN(x); +#define pci_unmap_addr dma_unmap_addr +#define pci_unmap_addr_set dma_unmap_addr_set +#define pci_unmap_len dma_unmap_len +#define pci_unmap_len_set dma_unmap_len_set + + +#endif /* _LINUX_PCI_H_ */ diff --git a/sys/ofed/include/linux/poll.h b/sys/ofed/include/linux/poll.h new file mode 100644 index 000000000000..5b7f34e67192 --- /dev/null +++ b/sys/ofed/include/linux/poll.h @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_POLL_H_ +#define _LINUX_POLL_H_ + +#include +#include + +typedef struct poll_table_struct { +} poll_table; + +static inline void +poll_wait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) +{ + selrecord(curthread, &filp->f_selinfo); +} + +#endif /* _LINUX_POLL_H_ */ diff --git a/sys/ofed/include/linux/radix-tree.h b/sys/ofed/include/linux/radix-tree.h new file mode 100644 index 000000000000..a02a90f7458d --- /dev/null +++ b/sys/ofed/include/linux/radix-tree.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_RADIX_TREE_H_ +#define _LINUX_RADIX_TREE_H_ + +#define RADIX_TREE_MAP_SHIFT 6 +#define RADIX_TREE_MAP_SIZE (1 << RADIX_TREE_MAP_SHIFT) +#define RADIX_TREE_MAP_MASK (RADIX_TREE_MAP_SIZE - 1) +#define RADIX_TREE_MAX_HEIGHT \ + DIV_ROUND_UP((sizeof(long) * NBBY), RADIX_TREE_MAP_SHIFT) + +struct radix_tree_node { + void *slots[RADIX_TREE_MAP_SIZE]; + int count; +}; + +struct radix_tree_root { + struct radix_tree_node *rnode; + gfp_t gfp_mask; + int height; +}; + +#define RADIX_TREE_INIT(mask) \ + { .rnode = NULL, .gfp_mask = mask, .height = 0 }; +#define INIT_RADIX_TREE(root, mask) \ + { (root)->rnode = NULL; (root)->gfp_mask = mask; (root)->height = 0; } +#define RADIX_TREE(name, mask) \ + struct radix_tree_root name = RADIX_TREE_INIT(mask) + +void *radix_tree_lookup(struct radix_tree_root *, unsigned long); +void *radix_tree_delete(struct radix_tree_root *, unsigned long); +int radix_tree_insert(struct radix_tree_root *, unsigned long, void *); + +#endif /* _LINUX_RADIX_TREE_H_ */ diff --git a/sys/ofed/include/linux/random.h b/sys/ofed/include/linux/random.h new file mode 100644 index 000000000000..84a24c8079e3 --- /dev/null +++ b/sys/ofed/include/linux/random.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_RANDOM_H_ +#define _LINUX_RANDOM_H_ + +#include + +static inline void +get_random_bytes(void *buf, int nbytes) +{ + read_random(buf, nbytes); +} + +#endif /* _LINUX_RANDOM_H_ */ diff --git a/sys/ofed/include/linux/rbtree.h b/sys/ofed/include/linux/rbtree.h new file mode 100644 index 000000000000..ea9afc3fb8d7 --- /dev/null +++ b/sys/ofed/include/linux/rbtree.h @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_RBTREE_H_ +#define _LINUX_RBTREE_H_ + +#include +#include + +struct rb_node { + RB_ENTRY(rb_node) __entry; +}; +#define rb_left __entry.rbe_left +#define rb_right __entry.rbe_right + +/* + * We provide a false structure that has the same bit pattern as tree.h + * presents so it matches the member names expected by linux. + */ +struct rb_root { + struct rb_node *rb_node; +}; + +/* + * In linux all of the comparisons are done by the caller. + */ +int panic_cmp(struct rb_node *one, struct rb_node *two); + +RB_HEAD(linux_root, rb_node); +RB_PROTOTYPE(linux_root, rb_node, __entry, panic_cmp); + +#define rb_parent(r) RB_PARENT(r, __entry) +#define rb_color(r) RB_COLOR(r, __entry) +#define rb_is_red(r) (rb_color(r) == RB_RED) +#define rb_is_black(r) (rb_color(r) == RB_BLACK) +#define rb_set_parent(r, p) rb_parent((r)) = (p) +#define rb_set_color(r, c) rb_color((r)) = (c) +#define rb_entry(ptr, type, member) container_of(ptr, type, member) + +#define RB_EMPTY_ROOT(root) RB_EMPTY((struct linux_root *)root) +#define RB_EMPTY_NODE(node) (rb_parent(node) == node) +#define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) + +#define rb_insert_color(node, root) \ + linux_root_RB_INSERT_COLOR((struct linux_root *)(root), (node)) +#define rb_erase(node, root) \ + linux_root_RB_REMOVE((struct linux_root *)(root), (node)) +#define rb_next(node) RB_NEXT(linux_root, NULL, (node)) +#define rb_prev(node) RB_PREV(linux_root, NULL, (node)) +#define rb_first(root) RB_MIN(linux_root, (struct linux_root *)(root)) +#define rb_last(root) RB_MAX(linux_root, (struct linux_root *)(root)) + +static inline void +rb_link_node(struct rb_node *node, struct rb_node *parent, + struct rb_node **rb_link) +{ + rb_set_parent(node, parent); + rb_set_color(node, RB_RED); + node->__entry.rbe_left = node->__entry.rbe_right = NULL; + *rb_link = node; +} + +static inline void +rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root) +{ + struct rb_node *p; + + p = rb_parent(victim); + if (p) { + if (p->rb_left == victim) + p->rb_left = new; + else + p->rb_right = new; + } else + root->rb_node = new; + if (victim->rb_left) + rb_set_parent(victim->rb_left, new); + if (victim->rb_right) + rb_set_parent(victim->rb_right, new); + *new = *victim; +} + +#undef RB_ROOT +#define RB_ROOT (struct rb_root) { NULL } + +#endif /* _LINUX_RBTREE_H_ */ diff --git a/sys/ofed/include/linux/rtnetlink.h b/sys/ofed/include/linux/rtnetlink.h new file mode 100644 index 000000000000..e5d814ee3407 --- /dev/null +++ b/sys/ofed/include/linux/rtnetlink.h @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/sys/ofed/include/linux/rwlock.h b/sys/ofed/include/linux/rwlock.h new file mode 100644 index 000000000000..01624558be02 --- /dev/null +++ b/sys/ofed/include/linux/rwlock.h @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_RWLOCK_H_ +#define _LINUX_RWLOCK_H_ + +#include +#include + +typedef struct { + struct rwlock rw; +} rwlock_t; + +#define read_lock(_l) rw_rlock(&(_l)->rw) +#define write_lock(_l) rw_wlock(&(_l)->rw) +#define read_unlock(_l) rw_runlock(&(_l)->rw) +#define write_unlock(_l) rw_wunlock(&(_l)->rw) +#define read_lock_irq(lock) read_lock((lock)) +#define read_unlock_irq(lock) read_unlock((lock)) +#define write_lock_irq(lock) write_lock((lock)) +#define write_unlock_irq(lock) write_unlock((lock)) +#define read_lock_irqsave(lock, flags) \ + do {(flags) = 0; read_lock(lock); } while (0) +#define write_lock_irqsave(lock, flags) \ + do {(flags) = 0; write_lock(lock); } while (0) +#define read_unlock_irqrestore(lock, flags) \ + do { read_unlock(lock); } while (0) +#define write_unlock_irqrestore(lock, flags) \ + do { write_unlock(lock); } while (0) + +static inline void +rwlock_init(rwlock_t *lock) +{ + + memset(&lock->rw, 0, sizeof(lock->rw)); + rw_init_flags(&lock->rw, "lnxrw", RW_NOWITNESS); +} + +#endif /* _LINUX_RWLOCK_H_ */ diff --git a/sys/ofed/include/linux/rwsem.h b/sys/ofed/include/linux/rwsem.h new file mode 100644 index 000000000000..f87c9d98809b --- /dev/null +++ b/sys/ofed/include/linux/rwsem.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_RWSEM_H_ +#define _LINUX_RWSEM_H_ + +#include +#include +#include + +struct rw_semaphore { + struct sx sx; +}; + +#define down_write(_rw) sx_xlock(&(_rw)->sx) +#define up_write(_rw) sx_xunlock(&(_rw)->sx) +#define down_read(_rw) sx_slock(&(_rw)->sx) +#define up_read(_rw) sx_sunlock(&(_rw)->sx) +#define down_read_trylock(_rw) !!sx_try_slock(&(_rw)->sx) +#define down_write_trylock(_rw) !!sx_try_xlock(&(_rw)->sx) +#define downgrade_write(_rw) sx_downgrade(&(_rw)->sx) +#define down_read_nested(_rw, _sc) down_read(_rw) + +static inline void +init_rwsem(struct rw_semaphore *rw) +{ + + memset(&rw->sx, 0, sizeof(rw->sx)); + sx_init_flags(&rw->sx, "lnxrwsem", SX_NOWITNESS); +} + +#endif /* _LINUX_RWSEM_H_ */ diff --git a/sys/ofed/include/linux/scatterlist.h b/sys/ofed/include/linux/scatterlist.h new file mode 100644 index 000000000000..611ad565915b --- /dev/null +++ b/sys/ofed/include/linux/scatterlist.h @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_SCATTERLIST_H_ +#define _LINUX_SCATTERLIST_H_ + +#include +#include + +struct scatterlist { + union { + struct page *page; + struct scatterlist *sg; + } sl_un; + unsigned long address; + unsigned long offset; + uint32_t length; + uint32_t flags; +}; + +#define sg_dma_address(sg) (sg)->address +#define sg_dma_len(sg) (sg)->length +#define sg_page(sg) (sg)->sl_un.page +#define sg_scatternext(sg) (sg)->sl_un.sg + +#define SG_END 0x01 +#define SG_CHAIN 0x02 + +static inline void +sg_set_page(struct scatterlist *sg, struct page *page, unsigned int len, + unsigned int offset) +{ + sg_page(sg) = page; + sg_dma_len(sg) = len; + sg->offset = offset; + if (offset > PAGE_SIZE) + panic("sg_set_page: Invalid offset %d\n", offset); +} + +static inline void +sg_set_buf(struct scatterlist *sg, const void *buf, unsigned int buflen) +{ + sg_set_page(sg, virt_to_page(buf), buflen, + ((uintptr_t)buf) & ~PAGE_MASK); +} + +static inline void +sg_init_table(struct scatterlist *sg, unsigned int nents) +{ + bzero(sg, sizeof(*sg) * nents); + sg[nents - 1].flags = SG_END; +} + +static inline struct scatterlist * +sg_next(struct scatterlist *sg) +{ + if (sg->flags & SG_END) + return (NULL); + sg++; + if (sg->flags & SG_CHAIN) + sg = sg_scatternext(sg); + return (sg); +} + +static inline vm_paddr_t +sg_phys(struct scatterlist *sg) +{ + return sg_page(sg)->phys_addr + sg->offset; +} + +#define for_each_sg(sglist, sg, sgmax, _itr) \ + for (_itr = 0, sg = (sglist); _itr < (sgmax); _itr++, sg = sg_next(sg)) + +#endif /* _LINUX_SCATTERLIST_H_ */ diff --git a/sys/ofed/include/linux/sched.h b/sys/ofed/include/linux/sched.h new file mode 100644 index 000000000000..414b0acf2534 --- /dev/null +++ b/sys/ofed/include/linux/sched.h @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_SCHED_H_ +#define _LINUX_SCHED_H_ + +#include +#include +#include +#include +#include + +#define MAX_SCHEDULE_TIMEOUT LONG_MAX + +#define TASK_RUNNING 0 +#define TASK_INTERRUPTIBLE 1 +#define TASK_UNINTERRUPTIBLE 2 +#define TASK_DEAD 64 +#define TASK_WAKEKILL 128 +#define TASK_WAKING 256 + +#define TASK_SHOULD_STOP 1 +#define TASK_STOPPED 2 + +/* + * A task_struct is only provided for those tasks created with kthread. + * Using these routines with threads not started via kthread will cause + * panics because no task_struct is allocated and td_retval[1] is + * overwritten by syscalls which kernel threads will not make use of. + */ +struct task_struct { + struct thread *task_thread; + int (*task_fn)(void *data); + void *task_data; + int task_ret; + int state; + int should_stop; +}; + +#define current ((struct task_struct *)curthread->td_retval[1]) +#define task_struct_get(x) (struct task_struct *)(x)->td_retval[1] +#define task_struct_set(x, y) (x)->td_retval[1] = (register_t)(y) + +#define set_current_state(x) \ + atomic_store_rel_int((volatile int *)¤t->state, (x)) +#define __set_current_state(x) current->state = (x) + + +#define schedule() \ +do { \ + void *c; \ + \ + if (cold) \ + break; \ + c = curthread; \ + sleepq_lock(c); \ + if (current->state == TASK_INTERRUPTIBLE || \ + current->state == TASK_UNINTERRUPTIBLE) { \ + sleepq_add(c, NULL, "task", SLEEPQ_SLEEP, 0); \ + sleepq_wait(c, 0); \ + } else { \ + sleepq_release(c); \ + sched_relinquish(curthread); \ + } \ +} while (0) + +#define wake_up_process(x) \ +do { \ + int wakeup_swapper; \ + void *c; \ + \ + c = (x)->task_thread; \ + sleepq_lock(c); \ + (x)->state = TASK_RUNNING; \ + wakeup_swapper = sleepq_signal(c, SLEEPQ_SLEEP, 0, 0); \ + sleepq_release(c); \ + if (wakeup_swapper) \ + kick_proc0(); \ +} while (0) + +#define cond_resched() if (!cold) sched_relinquish(curthread) + +#define sched_yield() sched_relinquish(curthread) + +#endif /* _LINUX_SCHED_H_ */ diff --git a/sys/ofed/include/linux/semaphore.h b/sys/ofed/include/linux/semaphore.h new file mode 100644 index 000000000000..4b9fd5672ad0 --- /dev/null +++ b/sys/ofed/include/linux/semaphore.h @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_SEMAPHORE_H_ +#define _LINUX_SEMAPHORE_H_ + +#include +#include +#include + +/* + * XXX BSD semaphores are disused and slow. They also do not provide a + * sema_wait_sig method. This must be resolved eventually. + */ +struct semaphore { + struct sema sema; +}; + +#define down(_sem) sema_wait(&(_sem)->sema) +#define down_interruptible(_sem) sema_wait(&(_sem)->sema), 0 +#define down_trylock(_sem) !sema_trywait(&(_sem)->sema) +#define up(_sem) sema_post(&(_sem)->sema) + +static inline void +linux_sema_init(struct semaphore *sem, int val) +{ + + memset(&sem->sema, 0, sizeof(sem->sema)); + sema_init(&sem->sema, val, "lnxsema"); +} + +static inline void +init_MUTEX(struct semaphore *sem) +{ + + memset(&sem->sema, 0, sizeof(sem->sema)); + sema_init(&sem->sema, 1, "lnxsema"); +} + +#define sema_init linux_sema_init + +#endif /* _LINUX_SEMAPHORE_H_ */ diff --git a/sys/ofed/include/linux/slab.h b/sys/ofed/include/linux/slab.h new file mode 100644 index 000000000000..5e7e608bd867 --- /dev/null +++ b/sys/ofed/include/linux/slab.h @@ -0,0 +1,102 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_SLAB_H_ +#define _LINUX_SLAB_H_ + +#include +#include +#include +#include + +#include +#include + +MALLOC_DECLARE(M_KMALLOC); + +#define kmalloc(size, flags) malloc((size), M_KMALLOC, (flags)) +#define kzalloc(size, flags) kmalloc((size), (flags) | M_ZERO) +#define kfree(ptr) free(__DECONST(void *, (ptr)), M_KMALLOC) +#define krealloc(ptr, size, flags) realloc((ptr), (size), M_KMALLOC, (flags)) +#define kcalloc(n, size, flags) kmalloc((n) * (size), flags | M_ZERO) + +struct kmem_cache { + uma_zone_t cache_zone; + void (*cache_ctor)(void *); +}; + +#define SLAB_HWCACHE_ALIGN 0x0001 + +static inline int +kmem_ctor(void *mem, int size, void *arg, int flags) +{ + void (*ctor)(void *); + + ctor = arg; + ctor(mem); + + return (0); +} + +static inline struct kmem_cache * +kmem_cache_create(char *name, size_t size, size_t align, u_long flags, + void (*ctor)(void *)) +{ + struct kmem_cache *c; + + c = malloc(sizeof(*c), M_KMALLOC, M_WAITOK); + if (align) + align--; + if (flags & SLAB_HWCACHE_ALIGN) + align = UMA_ALIGN_CACHE; + c->cache_zone = uma_zcreate(name, size, ctor ? kmem_ctor : NULL, + NULL, NULL, NULL, align, 0); + c->cache_ctor = ctor; + + return c; +} + +static inline void * +kmem_cache_alloc(struct kmem_cache *c, int flags) +{ + return uma_zalloc_arg(c->cache_zone, c->cache_ctor, flags); +} + +static inline void +kmem_cache_free(struct kmem_cache *c, void *m) +{ + uma_zfree(c->cache_zone, m); +} + +static inline void +kmem_cache_destroy(struct kmem_cache *c) +{ + uma_zdestroy(c->cache_zone); + free(c, M_KMALLOC); +} + +#endif /* _LINUX_SLAB_H_ */ diff --git a/sys/ofed/include/linux/socket.h b/sys/ofed/include/linux/socket.h new file mode 100644 index 000000000000..e14c982a818e --- /dev/null +++ b/sys/ofed/include/linux/socket.h @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_SOCKET_H_ +#define _LINUX_SOCKET_H_ + +#include + +#ifdef notyet +static inline int +memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len) +{ + struct uio uio; + int error; + + uio.uio_iov = v; + uio.uio_iovcnt = -1; + uio.uio_offset = 0; + uio.uio_resid = len; + uio.uio_segflag = UIO_USERSPACE; + uio.uio_rw = UIO_READ; + error = -uiomove(kdata, len, &uio); + return (error); +} + +static inline int +memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) +{ + struct uio uio; + int error; + + uio.uio_iov = v; + uio.uio_iovcnt = -1; + uio.uio_offset = 0; + uio.uio_resid = len; + uio.uio_segflag = UIO_USERSPACE; + uio.uio_rw = UIO_WRITE; + error = -uiomove(kdata, len, &uio); +} +#endif + +#endif /* _LINUX_SOCKET_H_ */ diff --git a/sys/ofed/include/linux/spinlock.h b/sys/ofed/include/linux/spinlock.h new file mode 100644 index 000000000000..4b972f49f2e3 --- /dev/null +++ b/sys/ofed/include/linux/spinlock.h @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_SPINLOCK_H_ +#define _LINUX_SPINLOCK_H_ + +#include +#include +#include +#include + +#include +#include +#include +#include + +typedef struct { + struct mtx m; +} spinlock_t; + +#define spin_lock(_l) mtx_lock(&(_l)->m) +#define spin_unlock(_l) mtx_unlock(&(_l)->m) +#define spin_trylock(_l) mtx_trylock(&(_l)->m) +#define spin_lock_nested(_l, _n) mtx_lock_flags(&(_l)->m, MTX_DUPOK) +#define spin_lock_irq(lock) spin_lock(lock) +#define spin_unlock_irq(lock) spin_unlock(lock) +#define spin_lock_irqsave(lock, flags) \ + do {(flags) = 0; spin_lock(lock); } while (0) +#define spin_unlock_irqrestore(lock, flags) \ + do { spin_unlock(lock); } while (0) + +static inline void +spin_lock_init(spinlock_t *lock) +{ + + memset(&lock->m, 0, sizeof(lock->m)); + mtx_init(&lock->m, "lnxspin", NULL, MTX_DEF | MTX_NOWITNESS); +} + +#define DEFINE_SPINLOCK(lock) \ + spinlock_t lock; \ + MTX_SYSINIT(lock, &(lock).m, "lnxspin", MTX_DEF) + +#endif /* _LINUX_SPINLOCK_H_ */ diff --git a/sys/ofed/include/linux/stddef.h b/sys/ofed/include/linux/stddef.h new file mode 100644 index 000000000000..22bf93887b5f --- /dev/null +++ b/sys/ofed/include/linux/stddef.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_STDDEF_H_ +#define _LINUX_STDDEF_H_ + +#include + +#endif /* _LINUX_STDDEF_H_ */ diff --git a/sys/ofed/include/linux/string.h b/sys/ofed/include/linux/string.h new file mode 100644 index 000000000000..b14a5c684105 --- /dev/null +++ b/sys/ofed/include/linux/string.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_STRING_H_ +#define _LINUX_STRING_H_ + +#include +#include +#include + +#include + +static inline void * +kmemdup(const void *src, size_t len, gfp_t gfp) +{ + void *dst; + + dst = kmalloc(len, gfp); + if (dst) + memcpy(dst, src, len); + return (dst); +} + +#endif /* _LINUX_STRING_H_ */ diff --git a/sys/ofed/include/linux/sysfs.h b/sys/ofed/include/linux/sysfs.h new file mode 100644 index 000000000000..698f75e1d3f9 --- /dev/null +++ b/sys/ofed/include/linux/sysfs.h @@ -0,0 +1,182 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_SYSFS_H_ +#define _LINUX_SYSFS_H_ + +#include + +struct attribute { + const char *name; + struct module *owner; + mode_t mode; +}; + +struct sysfs_ops { + ssize_t (*show)(struct kobject *, struct attribute *, char *); + ssize_t (*store)(struct kobject *, struct attribute *, const char *, + size_t); +}; + +struct attribute_group { + const char *name; + mode_t (*is_visible)(struct kobject *, + struct attribute *, int); + struct attribute **attrs; +}; + +#define __ATTR(_name, _mode, _show, _store) { \ + .attr = { .name = __stringify(_name), .mode = _mode }, \ + .show = _show, .store = _store, \ +} + +#define __ATTR_RO(_name) { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = _name##_show, \ +} + +#define __ATTR_NULL { .attr = { .name = NULL } } + +/* + * Handle our generic '\0' terminated 'C' string. + * Two cases: + * a variable string: point arg1 at it, arg2 is max length. + * a constant string: point arg1 at it, arg2 is zero. + */ + +static inline int +sysctl_handle_attr(SYSCTL_HANDLER_ARGS) +{ + struct kobject *kobj; + struct attribute *attr; + const struct sysfs_ops *ops; + void *buf; + int error; + ssize_t len; + + kobj = arg1; + attr = (struct attribute *)arg2; + buf = (void *)get_zeroed_page(GFP_KERNEL); + len = 1; /* Copy out a NULL byte at least. */ + if (kobj->ktype == NULL || kobj->ktype->sysfs_ops == NULL) + return (ENODEV); + ops = kobj->ktype->sysfs_ops; + if (buf == NULL) + return (ENOMEM); + if (ops->show) { + len = ops->show(kobj, attr, buf); + /* + * It's valid not to have a 'show' so we just return 1 byte + * of NULL. + */ + if (len < 0) { + error = -len; + len = 1; + if (error != EIO) + goto out; + } + } + error = SYSCTL_OUT(req, buf, len); + if (error || !req->newptr || ops->store == NULL) + goto out; + error = SYSCTL_IN(req, buf, PAGE_SIZE); + if (error) + goto out; + len = ops->store(kobj, attr, buf, req->newlen); + if (len < 0) + error = -len; +out: + free_page((unsigned long)buf); + + return (error); +} + +static inline int +sysfs_create_file(struct kobject *kobj, const struct attribute *attr) +{ + + sysctl_add_oid(NULL, SYSCTL_CHILDREN(kobj->oidp), OID_AUTO, + attr->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE, kobj, + (uintptr_t)attr, sysctl_handle_attr, "A", ""); + + return (0); +} + +static inline void +sysfs_remove_file(struct kobject *kobj, const struct attribute *attr) +{ + + if (kobj->oidp) + sysctl_remove_name(kobj->oidp, attr->name, 1, 1); +} + +static inline void +sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp) +{ + + if (kobj->oidp) + sysctl_remove_name(kobj->oidp, grp->name, 1, 1); +} + +static inline int +sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp) +{ + struct attribute **attr; + struct sysctl_oid *oidp; + + oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(kobj->oidp), + OID_AUTO, grp->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, grp->name); + for (attr = grp->attrs; *attr != NULL; attr++) { + sysctl_add_oid(NULL, SYSCTL_CHILDREN(oidp), OID_AUTO, + (*attr)->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE, + kobj, (uintptr_t)*attr, sysctl_handle_attr, "A", ""); + } + + return (0); +} + +static inline int +sysfs_create_dir(struct kobject *kobj) +{ + + kobj->oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(kobj->parent->oidp), + OID_AUTO, kobj->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, kobj->name); + + return (0); +} + +static inline void +sysfs_remove_dir(struct kobject *kobj) +{ + + if (kobj->oidp == NULL) + return; + sysctl_remove_oid(kobj->oidp, 1, 1); +} + +#endif /* _LINUX_SYSFS_H_ */ diff --git a/sys/ofed/include/linux/timer.h b/sys/ofed/include/linux/timer.h new file mode 100644 index 000000000000..ed4ed4a56273 --- /dev/null +++ b/sys/ofed/include/linux/timer.h @@ -0,0 +1,87 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_TIMER_H_ +#define _LINUX_TIMER_H_ + +#include + +#include +#include +#include + +struct timer_list { + struct callout timer_callout; + void (*function)(unsigned long); + unsigned long data; +}; + +#define expires timer_callout.c_time + +static inline void +_timer_fn(void *context) +{ + struct timer_list *timer; + + timer = context; + timer->function(timer->data); +} + +#define setup_timer(timer, func, dat) \ +do { \ + (timer)->function = (func); \ + (timer)->data = (dat); \ + callout_init(&(timer)->timer_callout, CALLOUT_MPSAFE); \ +} while (0) + +#define init_timer(timer) \ +do { \ + (timer)->function = NULL; \ + (timer)->data = 0; \ + callout_init(&(timer)->timer_callout, CALLOUT_MPSAFE); \ +} while (0) + +#define mod_timer(timer, expire) \ + callout_reset(&(timer)->timer_callout, (expire) - jiffies, \ + _timer_fn, (timer)) + +#define add_timer(timer) \ + callout_reset(&(timer)->timer_callout, \ + (timer)->timer_callout.c_time - jiffies, _timer_fn, (timer)) + +#define del_timer(timer) callout_stop(&(timer)->timer_callout) +#define del_timer_sync(timer) callout_drain(&(timer)->timer_callout) + +#define timer_pending(timer) callout_pending(&(timer)->timer_callout) + +static inline unsigned long +round_jiffies(unsigned long j) +{ + return roundup(j, hz); +} + +#endif /* _LINUX_TIMER_H_ */ diff --git a/sys/ofed/include/linux/types.h b/sys/ofed/include/linux/types.h new file mode 100644 index 000000000000..496d6f98a801 --- /dev/null +++ b/sys/ofed/include/linux/types.h @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_TYPES_H_ +#define _LINUX_TYPES_H_ + +#include +#include +#include +#include + +typedef __u16 __le16; +typedef __u16 __be16; +typedef __u32 __le32; +typedef __u32 __be32; +typedef __u64 __le64; +typedef __u64 __be64; +typedef _Bool bool; +#define true TRUE +#define false FALSE + +typedef unsigned long kernel_ulong_t; +typedef unsigned int uint; +typedef unsigned gfp_t; +typedef uint64_t loff_t; +typedef vm_paddr_t resource_size_t; + +#define DECLARE_BITMAP(n, bits) \ + unsigned long n[howmany(bits, sizeof(long) * 8)] + +#endif /* _LINUX_TYPES_H_ */ diff --git a/sys/ofed/include/linux/uaccess.h b/sys/ofed/include/linux/uaccess.h new file mode 100644 index 000000000000..9015b1e039d4 --- /dev/null +++ b/sys/ofed/include/linux/uaccess.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_UACCESS_H_ +#define _LINUX_UACCESS_H_ + +#define get_user(_x, _p) -copyin((_p), &(_x), sizeof(*(_p))) +#define put_user(_x, _p) -copyout(&(_x), (_p), sizeof(*(_p))) + +#endif /* _LINUX_UACCESS_H_ */ diff --git a/sys/ofed/include/linux/vmalloc.h b/sys/ofed/include/linux/vmalloc.h new file mode 100644 index 000000000000..4a94a5c949bf --- /dev/null +++ b/sys/ofed/include/linux/vmalloc.h @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_VMALLOC_H_ +#define _LINUX_VMALLOC_H_ + +#include + +#define VM_MAP 0x0000 +#define PAGE_KERNEL 0x0000 + +void *vmap(struct page **pages, unsigned int count, unsigned long flags, + int prot); +void vunmap(void *addr); + +#endif /* _LINUX_VMALLOC_H_ */ diff --git a/sys/ofed/include/linux/wait.h b/sys/ofed/include/linux/wait.h new file mode 100644 index 000000000000..b02014ebba6d --- /dev/null +++ b/sys/ofed/include/linux/wait.h @@ -0,0 +1,112 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_WAIT_H_ +#define _LINUX_WAIT_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include + +struct __wait_queue_head { + unsigned int wchan; +}; +typedef struct __wait_queue_head wait_queue_head_t; + +#define init_waitqueue_head(x) + +static inline void +__wake_up(struct __wait_queue_head *q, int all) +{ + int wakeup_swapper; + void *c; + + c = &q->wchan; + sleepq_lock(c); + if (all) + wakeup_swapper = sleepq_broadcast(c, SLEEPQ_SLEEP, 0, 0); + else + wakeup_swapper = sleepq_signal(c, SLEEPQ_SLEEP, 0, 0); + sleepq_release(c); + if (wakeup_swapper) + kick_proc0(); +} + +#define wake_up(q) __wake_up(q, 0) +#define wake_up_nr(q, nr) __wake_up(q, 1) +#define wake_up_all(q) __wake_up(q, 1) +#define wake_up_interruptible(q) __wake_up(q, 0) +#define wake_up_interruptible_nr(q, nr) __wake_up(q, 1) +#define wake_up_interruptible_all(q, nr) __wake_up(q, 1) + +#define wait_event(q, cond) \ +do { \ + void *c = &(q).wchan; \ + if (!(cond)) { \ + for (;;) { \ + sleepq_lock(c); \ + if (cond) { \ + sleepq_release(c); \ + break; \ + } \ + sleepq_add(c, NULL, "completion", SLEEPQ_SLEEP, 0); \ + sleepq_wait(c, 0); \ + } \ + } \ +} while (0) + +#define wait_event_interruptible(q, cond) \ +({ \ + void *c = &(q).wchan; \ + int _error; \ + \ + _error = 0; \ + if (!(cond)) { \ + for (; _error == 0;) { \ + sleepq_lock(c); \ + if (cond) { \ + sleepq_release(c); \ + break; \ + } \ + sleepq_add(c, NULL, "completion", \ + SLEEPQ_SLEEP | SLEEPQ_INTERRUPTIBLE, 0); \ + if (sleepq_wait_sig(c, 0)) \ + _error = -ERESTARTSYS; \ + } \ + } \ + -_error; \ +}) + +#define DEFINE_WAIT(x) + +#endif /* _LINUX_WAIT_H_ */ diff --git a/sys/ofed/include/linux/workqueue.h b/sys/ofed/include/linux/workqueue.h new file mode 100644 index 000000000000..6b48f9c3de6a --- /dev/null +++ b/sys/ofed/include/linux/workqueue.h @@ -0,0 +1,191 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _LINUX_WORKQUEUE_H_ +#define _LINUX_WORKQUEUE_H_ + +#include +#include +#include +#include + +#include + +struct workqueue_struct { + struct taskqueue *taskqueue; +}; + +struct work_struct { + struct task work_task; + struct taskqueue *taskqueue; + void (*fn)(struct work_struct *); +}; + +struct delayed_work { + struct work_struct work; + struct callout timer; +}; + +static inline struct delayed_work * +to_delayed_work(struct work_struct *work) +{ + + return container_of(work, struct delayed_work, work); +} + + +static inline void +_work_fn(void *context, int pending) +{ + struct work_struct *work; + + work = context; + work->fn(work); +} + +#define INIT_WORK(work, func) \ +do { \ + (work)->fn = (func); \ + (work)->taskqueue = NULL; \ + TASK_INIT(&(work)->work_task, 0, _work_fn, (work)); \ +} while (0) + +#define INIT_DELAYED_WORK(_work, func) \ +do { \ + INIT_WORK(&(_work)->work, func); \ + callout_init(&(_work)->timer, CALLOUT_MPSAFE); \ +} while (0) + +#define INIT_DELAYED_WORK_DEFERRABLE INIT_DELAYED_WORK + +#define schedule_work(work) \ +do { \ + (work)->taskqueue = taskqueue_thread; \ + taskqueue_enqueue(taskqueue_thread, &(work)->work_task); \ +} while (0) + +#define flush_scheduled_work() flush_taskqueue(taskqueue_thread) + +#define queue_work(q, work) \ +do { \ + (work)->taskqueue = (q)->taskqueue; \ + taskqueue_enqueue((q)->taskqueue, &(work)->work_task); \ +} while (0) + +static inline void +_delayed_work_fn(void *arg) +{ + struct delayed_work *work; + + work = arg; + taskqueue_enqueue(work->work.taskqueue, &work->work.work_task); +} + +static inline int +queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work, + unsigned long delay) +{ + int pending; + + pending = work->work.work_task.ta_pending; + work->work.taskqueue = wq->taskqueue; + if (delay != 0) + callout_reset(&work->timer, delay, _delayed_work_fn, work); + else + _delayed_work_fn((void *)work); + + return (!pending); +} + +static inline struct workqueue_struct * +_create_workqueue_common(char *name, int cpus) +{ + struct workqueue_struct *wq; + + wq = kmalloc(sizeof(*wq), M_WAITOK); + wq->taskqueue = taskqueue_create((name), M_WAITOK, + taskqueue_thread_enqueue, &wq->taskqueue); + taskqueue_start_threads(&wq->taskqueue, cpus, PWAIT, (name)); + + return (wq); +} + + +#define create_singlethread_workqueue(name) \ + _create_workqueue_common(name, 1) + +#define create_workqueue(name) \ + _create_workqueue_common(name, MAXCPU) + +static inline void +destroy_workqueue(struct workqueue_struct *wq) +{ + taskqueue_free(wq->taskqueue); + kfree(wq); +} + +#define flush_workqueue(wq) flush_taskqueue((wq)->taskqueue) + +static inline void +_flush_fn(void *context, int pending) +{ +} + +static inline void +flush_taskqueue(struct taskqueue *tq) +{ + struct task flushtask; + + TASK_INIT(&flushtask, 0, _flush_fn, NULL); + taskqueue_enqueue(tq, &flushtask); + taskqueue_drain(tq, &flushtask); +} + +static inline int +cancel_work_sync(struct work_struct *work) +{ + if (work->taskqueue && + taskqueue_cancel(work->taskqueue, &work->work_task, NULL)) + taskqueue_drain(work->taskqueue, &work->work_task); + return 0; +} + +/* + * This may leave work running on another CPU as it does on Linux. + */ +static inline int +cancel_delayed_work(struct delayed_work *work) +{ + + callout_stop(&work->timer); + if (work->work.taskqueue && + taskqueue_cancel(work->work.taskqueue, &work->work.work_task, NULL)) + taskqueue_drain(work->work.taskqueue, &work->work.work_task); + return 0; +} + +#endif /* _LINUX_WORKQUEUE_H_ */ diff --git a/sys/ofed/include/net/addrconf.h b/sys/ofed/include/net/addrconf.h new file mode 100644 index 000000000000..e5d814ee3407 --- /dev/null +++ b/sys/ofed/include/net/addrconf.h @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/sys/ofed/include/net/arp.h b/sys/ofed/include/net/arp.h new file mode 100644 index 000000000000..e5d814ee3407 --- /dev/null +++ b/sys/ofed/include/net/arp.h @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/sys/ofed/include/net/ip.h b/sys/ofed/include/net/ip.h new file mode 100644 index 000000000000..8b29d62796cb --- /dev/null +++ b/sys/ofed/include/net/ip.h @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_NET_IP_H_ +#define _LINUX_NET_IP_H_ + +#include +#include + +#include +#include +#include + +#include +#include + +static inline void inet_get_local_port_range(int *low, int *high) +{ + *low = V_ipport_firstauto; + *high = V_ipport_lastauto; +} + +static inline void +ip_ib_mc_map(uint32_t addr, const unsigned char *bcast, char *buf) +{ + unsigned char scope; + + addr = ntohl(addr); + scope = bcast[5] & 0xF; + buf[0] = 0; + buf[1] = 0xff; + buf[2] = 0xff; + buf[3] = 0xff; + buf[4] = 0xff; + buf[5] = 0x10 | scope; + buf[6] = 0x40; + buf[7] = 0x1b; + buf[8] = bcast[8]; + buf[9] = bcast[9]; + buf[10] = 0; + buf[11] = 0; + buf[12] = 0; + buf[13] = 0; + buf[14] = 0; + buf[15] = 0; + buf[16] = (addr >> 24) & 0x0f; + buf[17] = (addr >> 16) & 0xff; + buf[18] = (addr >> 8) & 0xff; + buf[19] = addr & 0xff; +} + +#endif /* _LINUX_NET_IP_H_ */ diff --git a/sys/ofed/include/net/ip6_route.h b/sys/ofed/include/net/ip6_route.h new file mode 100644 index 000000000000..e5d814ee3407 --- /dev/null +++ b/sys/ofed/include/net/ip6_route.h @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/sys/ofed/include/net/ipv6.h b/sys/ofed/include/net/ipv6.h new file mode 100644 index 000000000000..6f02555e9bad --- /dev/null +++ b/sys/ofed/include/net/ipv6.h @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_NET_IPV6_H_ +#define _LINUX_NET_IPV6_H_ + +#ifndef KLD_MODULE +#include "opt_inet6.h" +#endif + +#define ipv6_addr_loopback IN6_IS_ADDR_LOOPBACK +#define ipv6_addr_copy(dst, src) \ + memcpy((dst), (src), sizeof(struct in6_addr)) + +#ifdef INET6 +static inline void +ipv6_ib_mc_map(const struct in6_addr *addr, const unsigned char *broadcast, + char *buf) +{ + unsigned char scope; + + scope = broadcast[5] & 0xF; + buf[0] = 0; + buf[1] = 0xff; + buf[2] = 0xff; + buf[3] = 0xff; + buf[4] = 0xff; + buf[5] = 0x10 | scope; + buf[6] = 0x60; + buf[7] = 0x1b; + buf[8] = broadcast[8]; + buf[9] = broadcast[9]; + memcpy(&buf[10], &addr->s6_addr[6], 10); +} +#endif + +#endif /* _LINUX_NET_IPV6_H_ */ diff --git a/sys/ofed/include/net/neighbour.h b/sys/ofed/include/net/neighbour.h new file mode 100644 index 000000000000..e5d814ee3407 --- /dev/null +++ b/sys/ofed/include/net/neighbour.h @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/sys/ofed/include/net/netevent.h b/sys/ofed/include/net/netevent.h new file mode 100644 index 000000000000..db5b50ef6047 --- /dev/null +++ b/sys/ofed/include/net/netevent.h @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_NET_NETEVENT_H_ +#define _LINUX_NET_NETEVENT_H_ + +#include + +enum netevent_notif_type { + NETEVENT_NEIGH_UPDATE = 0, +#if 0 /* Unsupported events. */ + NETEVENT_PMTU_UPDATE, + NETEVENT_REDIRECT, +#endif +}; + +struct llentry; + +static inline void +_handle_arp_update_event(void *arg, struct llentry *lle) +{ + struct notifier_block *nb; + + nb = arg; + nb->notifier_call(nb, NETEVENT_NEIGH_UPDATE, lle); +} + +static inline int +register_netevent_notifier(struct notifier_block *nb) +{ + nb->tags[NETEVENT_NEIGH_UPDATE] = EVENTHANDLER_REGISTER( + arp_update_event, _handle_arp_update_event, nb, 0); + return (0); +} + +static inline int +unregister_netevent_notifier(struct notifier_block *nb) +{ + + EVENTHANDLER_DEREGISTER(arp_update_event, + nb->tags[NETEVENT_NEIGH_UPDATE]); + + return (0); +} + +#endif /* _LINUX_NET_NETEVENT_H_ */ diff --git a/sys/ofed/include/net/tcp.h b/sys/ofed/include/net/tcp.h new file mode 100644 index 000000000000..75da3f8aa469 --- /dev/null +++ b/sys/ofed/include/net/tcp.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2010 Isilon Systems, Inc. + * Copyright (c) 2010 iX Systems, Inc. + * Copyright (c) 2010 Panasas, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_NET_TCP_H_ +#define _LINUX_NET_TCP_H_ + +#include +#include +#include + +#include + +#endif /* _LINUX_NET_TCP_H_ */ diff --git a/sys/ofed/include/rdma/Kbuild b/sys/ofed/include/rdma/Kbuild new file mode 100644 index 000000000000..e7c043216558 --- /dev/null +++ b/sys/ofed/include/rdma/Kbuild @@ -0,0 +1 @@ +header-y += ib_user_mad.h diff --git a/sys/ofed/include/rdma/ib_addr.h b/sys/ofed/include/rdma/ib_addr.h new file mode 100644 index 000000000000..61b0a7cf1e91 --- /dev/null +++ b/sys/ofed/include/rdma/ib_addr.h @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2005 Voltaire Inc. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if !defined(IB_ADDR_H) +#define IB_ADDR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rdma_addr_client { + atomic_t refcount; + struct completion comp; +}; + +/** + * rdma_addr_register_client - Register an address client. + */ +void rdma_addr_register_client(struct rdma_addr_client *client); + +/** + * rdma_addr_unregister_client - Deregister an address client. + * @client: Client object to deregister. + */ +void rdma_addr_unregister_client(struct rdma_addr_client *client); + +struct rdma_dev_addr { + unsigned char src_dev_addr[MAX_ADDR_LEN]; + unsigned char dst_dev_addr[MAX_ADDR_LEN]; + unsigned char broadcast[MAX_ADDR_LEN]; + unsigned short dev_type; + int bound_dev_if; + enum rdma_transport_type transport; +}; + +/** + * rdma_translate_ip - Translate a local IP address to an RDMA hardware + * address. + */ +int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr); + +/** + * rdma_resolve_ip - Resolve source and destination IP addresses to + * RDMA hardware addresses. + * @client: Address client associated with request. + * @src_addr: An optional source address to use in the resolution. If a + * source address is not provided, a usable address will be returned via + * the callback. + * @dst_addr: The destination address to resolve. + * @addr: A reference to a data location that will receive the resolved + * addresses. The data location must remain valid until the callback has + * been invoked. + * @timeout_ms: Amount of time to wait for the address resolution to complete. + * @callback: Call invoked once address resolution has completed, timed out, + * or been canceled. A status of 0 indicates success. + * @context: User-specified context associated with the call. + */ +int rdma_resolve_ip(struct rdma_addr_client *client, + struct sockaddr *src_addr, struct sockaddr *dst_addr, + struct rdma_dev_addr *addr, int timeout_ms, + void (*callback)(int status, struct sockaddr *src_addr, + struct rdma_dev_addr *addr, void *context), + void *context); + +void rdma_addr_cancel(struct rdma_dev_addr *addr); + +int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, + const unsigned char *dst_dev_addr); + +static inline int ip_addr_size(struct sockaddr *addr) +{ + return addr->sa_family == AF_INET6 ? + sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); +} + +static inline u16 ib_addr_get_pkey(struct rdma_dev_addr *dev_addr) +{ + return ((u16)dev_addr->broadcast[8] << 8) | (u16)dev_addr->broadcast[9]; +} + +static inline void ib_addr_set_pkey(struct rdma_dev_addr *dev_addr, u16 pkey) +{ + dev_addr->broadcast[8] = pkey >> 8; + dev_addr->broadcast[9] = (unsigned char) pkey; +} + +static inline void ib_addr_get_mgid(struct rdma_dev_addr *dev_addr, + union ib_gid *gid) +{ + memcpy(gid, dev_addr->broadcast + 4, sizeof *gid); +} + +static inline int rdma_addr_gid_offset(struct rdma_dev_addr *dev_addr) +{ + return dev_addr->dev_type == ARPHRD_INFINIBAND ? 4 : 0; +} + +static inline void iboe_mac_vlan_to_ll(union ib_gid *gid, u8 *mac, u16 vid) +{ + memset(gid->raw, 0, 16); + *((u32 *)gid->raw) = cpu_to_be32(0xfe800000); + if (vid < 0x1000) { + gid->raw[12] = vid & 0xff; + gid->raw[11] = vid >> 8; + } else { + gid->raw[12] = 0xfe; + gid->raw[11] = 0xff; + } + + memcpy(gid->raw + 13, mac + 3, 3); + memcpy(gid->raw + 8, mac, 3); + gid->raw[8] ^= 2; +} + +static inline u16 rdma_vlan_dev_vlan_id(const struct net_device *dev) +{ +#ifdef __linux__ + return dev->priv_flags & IFF_802_1Q_VLAN ? + vlan_dev_vlan_id(dev) : 0xffff; +#else + uint16_t tag; + + if (VLAN_TAG(__DECONST(struct ifnet *, dev), &tag) != 0) + return 0xffff; + return tag; +#endif +} + +static inline void iboe_addr_get_sgid(struct rdma_dev_addr *dev_addr, + union ib_gid *gid) +{ + struct net_device *dev; + u16 vid = 0xffff; + + dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if); + if (dev) { + vid = rdma_vlan_dev_vlan_id(dev); + dev_put(dev); + } + + iboe_mac_vlan_to_ll(gid, dev_addr->src_dev_addr, vid); +} + +static inline void rdma_addr_get_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) +{ + if (dev_addr->transport == RDMA_TRANSPORT_IB && + dev_addr->dev_type != ARPHRD_INFINIBAND) + iboe_addr_get_sgid(dev_addr, gid); + else + memcpy(gid, dev_addr->src_dev_addr + + rdma_addr_gid_offset(dev_addr), sizeof *gid); +} + +static inline void rdma_addr_set_sgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) +{ + memcpy(dev_addr->src_dev_addr + rdma_addr_gid_offset(dev_addr), gid, sizeof *gid); +} + +static inline void rdma_addr_get_dgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) +{ + memcpy(gid, dev_addr->dst_dev_addr + rdma_addr_gid_offset(dev_addr), sizeof *gid); +} + +static inline void rdma_addr_set_dgid(struct rdma_dev_addr *dev_addr, union ib_gid *gid) +{ + memcpy(dev_addr->dst_dev_addr + rdma_addr_gid_offset(dev_addr), gid, sizeof *gid); +} + +static inline enum ib_mtu iboe_get_mtu(int mtu) +{ + /* + * reduce IB headers from effective IBoE MTU. 28 stands for + * atomic header which is the biggest possible header after BTH + */ + mtu = mtu - IB_GRH_BYTES - IB_BTH_BYTES - 28; + + if (mtu >= ib_mtu_enum_to_int(IB_MTU_4096)) + return IB_MTU_4096; + else if (mtu >= ib_mtu_enum_to_int(IB_MTU_2048)) + return IB_MTU_2048; + else if (mtu >= ib_mtu_enum_to_int(IB_MTU_1024)) + return IB_MTU_1024; + else if (mtu >= ib_mtu_enum_to_int(IB_MTU_512)) + return IB_MTU_512; + else if (mtu >= ib_mtu_enum_to_int(IB_MTU_256)) + return IB_MTU_256; + else + return 0; +} + +#ifdef __linux__ +static inline int iboe_get_rate(struct net_device *dev) +{ + struct ethtool_cmd cmd; + + if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings || + dev->ethtool_ops->get_settings(dev, &cmd)) + return IB_RATE_PORT_CURRENT; + + if (cmd.speed >= 40000) + return IB_RATE_40_GBPS; + else if (cmd.speed >= 30000) + return IB_RATE_30_GBPS; + else if (cmd.speed >= 20000) + return IB_RATE_20_GBPS; + else if (cmd.speed >= 10000) + return IB_RATE_10_GBPS; + else + return IB_RATE_PORT_CURRENT; +} +#else +static inline int iboe_get_rate(struct net_device *dev) +{ + if (dev->if_baudrate >= IF_Gbps(40ULL)) + return IB_RATE_40_GBPS; + else if (dev->if_baudrate >= IF_Gbps(30ULL)) + return IB_RATE_30_GBPS; + else if (dev->if_baudrate >= IF_Gbps(20ULL)) + return IB_RATE_20_GBPS; + else if (dev->if_baudrate >= IF_Gbps(10ULL)) + return IB_RATE_10_GBPS; + else + return IB_RATE_PORT_CURRENT; +} +#endif + +static inline int rdma_link_local_addr(struct in6_addr *addr) +{ + if (addr->s6_addr32[0] == cpu_to_be32(0xfe800000) && + addr->s6_addr32[1] == 0) + return 1; + + return 0; +} + +static inline void rdma_get_ll_mac(struct in6_addr *addr, u8 *mac) +{ + memcpy(mac, &addr->s6_addr[8], 3); + memcpy(mac + 3, &addr->s6_addr[13], 3); + mac[0] ^= 2; +} + +static inline int rdma_is_multicast_addr(struct in6_addr *addr) +{ + return addr->s6_addr[0] == 0xff; +} + +static inline void rdma_get_mcast_mac(struct in6_addr *addr, u8 *mac) +{ + int i; + + mac[0] = 0x33; + mac[1] = 0x33; + for (i = 2; i < 6; ++i) + mac[i] = addr->s6_addr[i + 10]; +} + +static inline u16 rdma_get_vlan_id(union ib_gid *dgid) +{ + u16 vid; + + vid = dgid->raw[11] << 8 | dgid->raw[12]; + return vid < 0x1000 ? vid : 0xffff; +} + +static inline struct net_device *rdma_vlan_dev_real_dev(const struct net_device *dev) +{ +#ifdef __linux__ + return dev->priv_flags & IFF_802_1Q_VLAN ? + vlan_dev_real_dev(dev) : 0; +#else + return VLAN_TRUNKDEV(__DECONST(struct ifnet *, dev)); +#endif +} + +#endif /* IB_ADDR_H */ diff --git a/sys/ofed/include/rdma/ib_cache.h b/sys/ofed/include/rdma/ib_cache.h new file mode 100644 index 000000000000..00a2b8ec327f --- /dev/null +++ b/sys/ofed/include/rdma/ib_cache.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _IB_CACHE_H +#define _IB_CACHE_H + +#include + +/** + * ib_get_cached_gid - Returns a cached GID table entry + * @device: The device to query. + * @port_num: The port number of the device to query. + * @index: The index into the cached GID table to query. + * @gid: The GID value found at the specified index. + * + * ib_get_cached_gid() fetches the specified GID table entry stored in + * the local software cache. + */ +int ib_get_cached_gid(struct ib_device *device, + u8 port_num, + int index, + union ib_gid *gid); + +/** + * ib_find_cached_gid - Returns the port number and GID table index where + * a specified GID value occurs. + * @device: The device to query. + * @gid: The GID value to search for. + * @port_num: The port number of the device where the GID value was found. + * @index: The index into the cached GID table where the GID was found. This + * parameter may be NULL. + * + * ib_find_cached_gid() searches for the specified GID value in + * the local software cache. + */ +int ib_find_cached_gid(struct ib_device *device, + union ib_gid *gid, + u8 *port_num, + u16 *index); + +/** + * ib_get_cached_pkey - Returns a cached PKey table entry + * @device: The device to query. + * @port_num: The port number of the device to query. + * @index: The index into the cached PKey table to query. + * @pkey: The PKey value found at the specified index. + * + * ib_get_cached_pkey() fetches the specified PKey table entry stored in + * the local software cache. + */ +int ib_get_cached_pkey(struct ib_device *device_handle, + u8 port_num, + int index, + u16 *pkey); + +/** + * ib_find_cached_pkey - Returns the PKey table index where a specified + * PKey value occurs. + * @device: The device to query. + * @port_num: The port number of the device to search for the PKey. + * @pkey: The PKey value to search for. + * @index: The index into the cached PKey table where the PKey was found. + * + * ib_find_cached_pkey() searches the specified PKey table in + * the local software cache. + */ +int ib_find_cached_pkey(struct ib_device *device, + u8 port_num, + u16 pkey, + u16 *index); + +/** + * ib_get_cached_lmc - Returns a cached lmc table entry + * @device: The device to query. + * @port_num: The port number of the device to query. + * @lmc: The lmc value for the specified port for that device. + * + * ib_get_cached_lmc() fetches the specified lmc table entry stored in + * the local software cache. + */ +int ib_get_cached_lmc(struct ib_device *device, + u8 port_num, + u8 *lmc); + +#endif /* _IB_CACHE_H */ diff --git a/sys/ofed/include/rdma/ib_cm.h b/sys/ofed/include/rdma/ib_cm.h new file mode 100644 index 000000000000..938858304300 --- /dev/null +++ b/sys/ofed/include/rdma/ib_cm.h @@ -0,0 +1,589 @@ +/* + * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#if !defined(IB_CM_H) +#define IB_CM_H + +#include +#include + +enum ib_cm_state { + IB_CM_IDLE, + IB_CM_LISTEN, + IB_CM_REQ_SENT, + IB_CM_REQ_RCVD, + IB_CM_MRA_REQ_SENT, + IB_CM_MRA_REQ_RCVD, + IB_CM_REP_SENT, + IB_CM_REP_RCVD, + IB_CM_MRA_REP_SENT, + IB_CM_MRA_REP_RCVD, + IB_CM_ESTABLISHED, + IB_CM_DREQ_SENT, + IB_CM_DREQ_RCVD, + IB_CM_TIMEWAIT, + IB_CM_SIDR_REQ_SENT, + IB_CM_SIDR_REQ_RCVD +}; + +enum ib_cm_lap_state { + IB_CM_LAP_UNINIT, + IB_CM_LAP_IDLE, + IB_CM_LAP_SENT, + IB_CM_LAP_RCVD, + IB_CM_MRA_LAP_SENT, + IB_CM_MRA_LAP_RCVD, +}; + +enum ib_cm_event_type { + IB_CM_REQ_ERROR, + IB_CM_REQ_RECEIVED, + IB_CM_REP_ERROR, + IB_CM_REP_RECEIVED, + IB_CM_RTU_RECEIVED, + IB_CM_USER_ESTABLISHED, + IB_CM_DREQ_ERROR, + IB_CM_DREQ_RECEIVED, + IB_CM_DREP_RECEIVED, + IB_CM_TIMEWAIT_EXIT, + IB_CM_MRA_RECEIVED, + IB_CM_REJ_RECEIVED, + IB_CM_LAP_ERROR, + IB_CM_LAP_RECEIVED, + IB_CM_APR_RECEIVED, + IB_CM_SIDR_REQ_ERROR, + IB_CM_SIDR_REQ_RECEIVED, + IB_CM_SIDR_REP_RECEIVED +}; + +enum ib_cm_data_size { + IB_CM_REQ_PRIVATE_DATA_SIZE = 92, + IB_CM_MRA_PRIVATE_DATA_SIZE = 222, + IB_CM_REJ_PRIVATE_DATA_SIZE = 148, + IB_CM_REP_PRIVATE_DATA_SIZE = 196, + IB_CM_RTU_PRIVATE_DATA_SIZE = 224, + IB_CM_DREQ_PRIVATE_DATA_SIZE = 220, + IB_CM_DREP_PRIVATE_DATA_SIZE = 224, + IB_CM_REJ_ARI_LENGTH = 72, + IB_CM_LAP_PRIVATE_DATA_SIZE = 168, + IB_CM_APR_PRIVATE_DATA_SIZE = 148, + IB_CM_APR_INFO_LENGTH = 72, + IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE = 216, + IB_CM_SIDR_REP_PRIVATE_DATA_SIZE = 136, + IB_CM_SIDR_REP_INFO_LENGTH = 72, + IB_CM_COMPARE_SIZE = 64 +}; + +struct ib_cm_id; + +struct ib_cm_req_event_param { + struct ib_cm_id *listen_id; + u8 port; + + struct ib_sa_path_rec *primary_path; + struct ib_sa_path_rec *alternate_path; + + __be64 remote_ca_guid; + u32 remote_qkey; + u32 remote_qpn; + enum ib_qp_type qp_type; + + u32 starting_psn; + u8 responder_resources; + u8 initiator_depth; + unsigned int local_cm_response_timeout:5; + unsigned int flow_control:1; + unsigned int remote_cm_response_timeout:5; + unsigned int retry_count:3; + unsigned int rnr_retry_count:3; + unsigned int srq:1; +}; + +struct ib_cm_rep_event_param { + __be64 remote_ca_guid; + u32 remote_qkey; + u32 remote_qpn; + u32 starting_psn; + u8 responder_resources; + u8 initiator_depth; + unsigned int target_ack_delay:5; + unsigned int failover_accepted:2; + unsigned int flow_control:1; + unsigned int rnr_retry_count:3; + unsigned int srq:1; +}; + +enum ib_cm_rej_reason { + IB_CM_REJ_NO_QP = 1, + IB_CM_REJ_NO_EEC = 2, + IB_CM_REJ_NO_RESOURCES = 3, + IB_CM_REJ_TIMEOUT = 4, + IB_CM_REJ_UNSUPPORTED = 5, + IB_CM_REJ_INVALID_COMM_ID = 6, + IB_CM_REJ_INVALID_COMM_INSTANCE = 7, + IB_CM_REJ_INVALID_SERVICE_ID = 8, + IB_CM_REJ_INVALID_TRANSPORT_TYPE = 9, + IB_CM_REJ_STALE_CONN = 10, + IB_CM_REJ_RDC_NOT_EXIST = 11, + IB_CM_REJ_INVALID_GID = 12, + IB_CM_REJ_INVALID_LID = 13, + IB_CM_REJ_INVALID_SL = 14, + IB_CM_REJ_INVALID_TRAFFIC_CLASS = 15, + IB_CM_REJ_INVALID_HOP_LIMIT = 16, + IB_CM_REJ_INVALID_PACKET_RATE = 17, + IB_CM_REJ_INVALID_ALT_GID = 18, + IB_CM_REJ_INVALID_ALT_LID = 19, + IB_CM_REJ_INVALID_ALT_SL = 20, + IB_CM_REJ_INVALID_ALT_TRAFFIC_CLASS = 21, + IB_CM_REJ_INVALID_ALT_HOP_LIMIT = 22, + IB_CM_REJ_INVALID_ALT_PACKET_RATE = 23, + IB_CM_REJ_PORT_CM_REDIRECT = 24, + IB_CM_REJ_PORT_REDIRECT = 25, + IB_CM_REJ_INVALID_MTU = 26, + IB_CM_REJ_INSUFFICIENT_RESP_RESOURCES = 27, + IB_CM_REJ_CONSUMER_DEFINED = 28, + IB_CM_REJ_INVALID_RNR_RETRY = 29, + IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID = 30, + IB_CM_REJ_INVALID_CLASS_VERSION = 31, + IB_CM_REJ_INVALID_FLOW_LABEL = 32, + IB_CM_REJ_INVALID_ALT_FLOW_LABEL = 33 +}; + +struct ib_cm_rej_event_param { + enum ib_cm_rej_reason reason; + void *ari; + u8 ari_length; +}; + +struct ib_cm_mra_event_param { + u8 service_timeout; +}; + +struct ib_cm_lap_event_param { + struct ib_sa_path_rec *alternate_path; +}; + +enum ib_cm_apr_status { + IB_CM_APR_SUCCESS, + IB_CM_APR_INVALID_COMM_ID, + IB_CM_APR_UNSUPPORTED, + IB_CM_APR_REJECT, + IB_CM_APR_REDIRECT, + IB_CM_APR_IS_CURRENT, + IB_CM_APR_INVALID_QPN_EECN, + IB_CM_APR_INVALID_LID, + IB_CM_APR_INVALID_GID, + IB_CM_APR_INVALID_FLOW_LABEL, + IB_CM_APR_INVALID_TCLASS, + IB_CM_APR_INVALID_HOP_LIMIT, + IB_CM_APR_INVALID_PACKET_RATE, + IB_CM_APR_INVALID_SL +}; + +struct ib_cm_apr_event_param { + enum ib_cm_apr_status ap_status; + void *apr_info; + u8 info_len; +}; + +struct ib_cm_sidr_req_event_param { + struct ib_cm_id *listen_id; + u8 port; + u16 pkey; +}; + +enum ib_cm_sidr_status { + IB_SIDR_SUCCESS, + IB_SIDR_UNSUPPORTED, + IB_SIDR_REJECT, + IB_SIDR_NO_QP, + IB_SIDR_REDIRECT, + IB_SIDR_UNSUPPORTED_VERSION +}; + +struct ib_cm_sidr_rep_event_param { + enum ib_cm_sidr_status status; + u32 qkey; + u32 qpn; + void *info; + u8 info_len; +}; + +struct ib_cm_event { + enum ib_cm_event_type event; + union { + struct ib_cm_req_event_param req_rcvd; + struct ib_cm_rep_event_param rep_rcvd; + /* No data for RTU received events. */ + struct ib_cm_rej_event_param rej_rcvd; + struct ib_cm_mra_event_param mra_rcvd; + struct ib_cm_lap_event_param lap_rcvd; + struct ib_cm_apr_event_param apr_rcvd; + /* No data for DREQ/DREP received events. */ + struct ib_cm_sidr_req_event_param sidr_req_rcvd; + struct ib_cm_sidr_rep_event_param sidr_rep_rcvd; + enum ib_wc_status send_status; + } param; + + void *private_data; +}; + +/** + * ib_cm_handler - User-defined callback to process communication events. + * @cm_id: Communication identifier associated with the reported event. + * @event: Information about the communication event. + * + * IB_CM_REQ_RECEIVED and IB_CM_SIDR_REQ_RECEIVED communication events + * generated as a result of listen requests result in the allocation of a + * new @cm_id. The new @cm_id is returned to the user through this callback. + * Clients are responsible for destroying the new @cm_id. For peer-to-peer + * IB_CM_REQ_RECEIVED and all other events, the returned @cm_id corresponds + * to a user's existing communication identifier. + * + * Users may not call ib_destroy_cm_id while in the context of this callback; + * however, returning a non-zero value instructs the communication manager to + * destroy the @cm_id after the callback completes. + */ +typedef int (*ib_cm_handler)(struct ib_cm_id *cm_id, + struct ib_cm_event *event); + +struct ib_cm_id { + ib_cm_handler cm_handler; + void *context; + struct ib_device *device; + __be64 service_id; + __be64 service_mask; + enum ib_cm_state state; /* internal CM/debug use */ + enum ib_cm_lap_state lap_state; /* internal CM/debug use */ + __be32 local_id; + __be32 remote_id; + u32 remote_cm_qpn; /* 1 unless redirected */ +}; + +/** + * ib_create_cm_id - Allocate a communication identifier. + * @device: Device associated with the cm_id. All related communication will + * be associated with the specified device. + * @cm_handler: Callback invoked to notify the user of CM events. + * @context: User specified context associated with the communication + * identifier. + * + * Communication identifiers are used to track connection states, service + * ID resolution requests, and listen requests. + */ +struct ib_cm_id *ib_create_cm_id(struct ib_device *device, + ib_cm_handler cm_handler, + void *context); + +/** + * ib_destroy_cm_id - Destroy a connection identifier. + * @cm_id: Connection identifier to destroy. + * + * This call blocks until the connection identifier is destroyed. + */ +void ib_destroy_cm_id(struct ib_cm_id *cm_id); + +#define IB_SERVICE_ID_AGN_MASK cpu_to_be64(0xFF00000000000000ULL) +#define IB_CM_ASSIGN_SERVICE_ID cpu_to_be64(0x0200000000000000ULL) +#define IB_CMA_SERVICE_ID cpu_to_be64(0x0000000001000000ULL) +#define IB_CMA_SERVICE_ID_MASK cpu_to_be64(0xFFFFFFFFFF000000ULL) +#define IB_SDP_SERVICE_ID cpu_to_be64(0x0000000000010000ULL) +#define IB_SDP_SERVICE_ID_MASK cpu_to_be64(0xFFFFFFFFFFFF0000ULL) + +struct ib_cm_compare_data { + u8 data[IB_CM_COMPARE_SIZE]; + u8 mask[IB_CM_COMPARE_SIZE]; +}; + +/** + * ib_cm_listen - Initiates listening on the specified service ID for + * connection and service ID resolution requests. + * @cm_id: Connection identifier associated with the listen request. + * @service_id: Service identifier matched against incoming connection + * and service ID resolution requests. The service ID should be specified + * network-byte order. If set to IB_CM_ASSIGN_SERVICE_ID, the CM will + * assign a service ID to the caller. + * @service_mask: Mask applied to service ID used to listen across a + * range of service IDs. If set to 0, the service ID is matched + * exactly. This parameter is ignored if %service_id is set to + * IB_CM_ASSIGN_SERVICE_ID. + * @compare_data: This parameter is optional. It specifies data that must + * appear in the private data of a connection request for the specified + * listen request. + */ +int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, + struct ib_cm_compare_data *compare_data); + +struct ib_cm_req_param { + struct ib_sa_path_rec *primary_path; + struct ib_sa_path_rec *alternate_path; + __be64 service_id; + u32 qp_num; + enum ib_qp_type qp_type; + u32 starting_psn; + const void *private_data; + u8 private_data_len; + u8 peer_to_peer; + u8 responder_resources; + u8 initiator_depth; + u8 remote_cm_response_timeout; + u8 flow_control; + u8 local_cm_response_timeout; + u8 retry_count; + u8 rnr_retry_count; + u8 max_cm_retries; + u8 srq; +}; + +/** + * ib_send_cm_req - Sends a connection request to the remote node. + * @cm_id: Connection identifier that will be associated with the + * connection request. + * @param: Connection request information needed to establish the + * connection. + */ +int ib_send_cm_req(struct ib_cm_id *cm_id, + struct ib_cm_req_param *param); + +struct ib_cm_rep_param { + u32 qp_num; + u32 starting_psn; + const void *private_data; + u8 private_data_len; + u8 responder_resources; + u8 initiator_depth; + u8 failover_accepted; + u8 flow_control; + u8 rnr_retry_count; + u8 srq; +}; + +/** + * ib_send_cm_rep - Sends a connection reply in response to a connection + * request. + * @cm_id: Connection identifier that will be associated with the + * connection request. + * @param: Connection reply information needed to establish the + * connection. + */ +int ib_send_cm_rep(struct ib_cm_id *cm_id, + struct ib_cm_rep_param *param); + +/** + * ib_send_cm_rtu - Sends a connection ready to use message in response + * to a connection reply message. + * @cm_id: Connection identifier associated with the connection request. + * @private_data: Optional user-defined private data sent with the + * ready to use message. + * @private_data_len: Size of the private data buffer, in bytes. + */ +int ib_send_cm_rtu(struct ib_cm_id *cm_id, + const void *private_data, + u8 private_data_len); + +/** + * ib_send_cm_dreq - Sends a disconnection request for an existing + * connection. + * @cm_id: Connection identifier associated with the connection being + * released. + * @private_data: Optional user-defined private data sent with the + * disconnection request message. + * @private_data_len: Size of the private data buffer, in bytes. + */ +int ib_send_cm_dreq(struct ib_cm_id *cm_id, + const void *private_data, + u8 private_data_len); + +/** + * ib_send_cm_drep - Sends a disconnection reply to a disconnection request. + * @cm_id: Connection identifier associated with the connection being + * released. + * @private_data: Optional user-defined private data sent with the + * disconnection reply message. + * @private_data_len: Size of the private data buffer, in bytes. + * + * If the cm_id is in the correct state, the CM will transition the connection + * to the timewait state, even if an error occurs sending the DREP message. + */ +int ib_send_cm_drep(struct ib_cm_id *cm_id, + const void *private_data, + u8 private_data_len); + +/** + * ib_cm_notify - Notifies the CM of an event reported to the consumer. + * @cm_id: Connection identifier to transition to established. + * @event: Type of event. + * + * This routine should be invoked by users to notify the CM of relevant + * communication events. Events that should be reported to the CM and + * when to report them are: + * + * IB_EVENT_COMM_EST - Used when a message is received on a connected + * QP before an RTU has been received. + * IB_EVENT_PATH_MIG - Notifies the CM that the connection has failed over + * to the alternate path. + */ +int ib_cm_notify(struct ib_cm_id *cm_id, enum ib_event_type event); + +/** + * ib_send_cm_rej - Sends a connection rejection message to the + * remote node. + * @cm_id: Connection identifier associated with the connection being + * rejected. + * @reason: Reason for the connection request rejection. + * @ari: Optional additional rejection information. + * @ari_length: Size of the additional rejection information, in bytes. + * @private_data: Optional user-defined private data sent with the + * rejection message. + * @private_data_len: Size of the private data buffer, in bytes. + */ +int ib_send_cm_rej(struct ib_cm_id *cm_id, + enum ib_cm_rej_reason reason, + void *ari, + u8 ari_length, + const void *private_data, + u8 private_data_len); + +#define IB_CM_MRA_FLAG_DELAY 0x80 /* Send MRA only after a duplicate msg */ + +/** + * ib_send_cm_mra - Sends a message receipt acknowledgement to a connection + * message. + * @cm_id: Connection identifier associated with the connection message. + * @service_timeout: The lower 5-bits specify the maximum time required for + * the sender to reply to to the connection message. The upper 3-bits + * specify additional control flags. + * @private_data: Optional user-defined private data sent with the + * message receipt acknowledgement. + * @private_data_len: Size of the private data buffer, in bytes. + */ +int ib_send_cm_mra(struct ib_cm_id *cm_id, + u8 service_timeout, + const void *private_data, + u8 private_data_len); + +/** + * ib_send_cm_lap - Sends a load alternate path request. + * @cm_id: Connection identifier associated with the load alternate path + * message. + * @alternate_path: A path record that identifies the alternate path to + * load. + * @private_data: Optional user-defined private data sent with the + * load alternate path message. + * @private_data_len: Size of the private data buffer, in bytes. + */ +int ib_send_cm_lap(struct ib_cm_id *cm_id, + struct ib_sa_path_rec *alternate_path, + const void *private_data, + u8 private_data_len); + +/** + * ib_cm_init_qp_attr - Initializes the QP attributes for use in transitioning + * to a specified QP state. + * @cm_id: Communication identifier associated with the QP attributes to + * initialize. + * @qp_attr: On input, specifies the desired QP state. On output, the + * mandatory and desired optional attributes will be set in order to + * modify the QP to the specified state. + * @qp_attr_mask: The QP attribute mask that may be used to transition the + * QP to the specified state. + * + * Users must set the @qp_attr->qp_state to the desired QP state. This call + * will set all required attributes for the given transition, along with + * known optional attributes. Users may override the attributes returned from + * this call before calling ib_modify_qp. + */ +int ib_cm_init_qp_attr(struct ib_cm_id *cm_id, + struct ib_qp_attr *qp_attr, + int *qp_attr_mask); + +/** + * ib_send_cm_apr - Sends an alternate path response message in response to + * a load alternate path request. + * @cm_id: Connection identifier associated with the alternate path response. + * @status: Reply status sent with the alternate path response. + * @info: Optional additional information sent with the alternate path + * response. + * @info_length: Size of the additional information, in bytes. + * @private_data: Optional user-defined private data sent with the + * alternate path response message. + * @private_data_len: Size of the private data buffer, in bytes. + */ +int ib_send_cm_apr(struct ib_cm_id *cm_id, + enum ib_cm_apr_status status, + void *info, + u8 info_length, + const void *private_data, + u8 private_data_len); + +struct ib_cm_sidr_req_param { + struct ib_sa_path_rec *path; + __be64 service_id; + int timeout_ms; + const void *private_data; + u8 private_data_len; + u8 max_cm_retries; +}; + +/** + * ib_send_cm_sidr_req - Sends a service ID resolution request to the + * remote node. + * @cm_id: Communication identifier that will be associated with the + * service ID resolution request. + * @param: Service ID resolution request information. + */ +int ib_send_cm_sidr_req(struct ib_cm_id *cm_id, + struct ib_cm_sidr_req_param *param); + +struct ib_cm_sidr_rep_param { + u32 qp_num; + u32 qkey; + enum ib_cm_sidr_status status; + const void *info; + u8 info_length; + const void *private_data; + u8 private_data_len; +}; + +/** + * ib_send_cm_sidr_rep - Sends a service ID resolution reply to the + * remote node. + * @cm_id: Communication identifier associated with the received service ID + * resolution request. + * @param: Service ID resolution reply information. + */ +int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id, + struct ib_cm_sidr_rep_param *param); + +#endif /* IB_CM_H */ diff --git a/sys/ofed/include/rdma/ib_fmr_pool.h b/sys/ofed/include/rdma/ib_fmr_pool.h new file mode 100644 index 000000000000..f62b842e6596 --- /dev/null +++ b/sys/ofed/include/rdma/ib_fmr_pool.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if !defined(IB_FMR_POOL_H) +#define IB_FMR_POOL_H + +#include + +struct ib_fmr_pool; + +/** + * struct ib_fmr_pool_param - Parameters for creating FMR pool + * @max_pages_per_fmr:Maximum number of pages per map request. + * @page_shift: Log2 of sizeof "pages" mapped by this fmr + * @access:Access flags for FMRs in pool. + * @pool_size:Number of FMRs to allocate for pool. + * @dirty_watermark:Flush is triggered when @dirty_watermark dirty + * FMRs are present. + * @flush_function:Callback called when unmapped FMRs are flushed and + * more FMRs are possibly available for mapping + * @flush_arg:Context passed to user's flush function. + * @cache:If set, FMRs may be reused after unmapping for identical map + * requests. + */ +struct ib_fmr_pool_param { + int max_pages_per_fmr; + int page_shift; + enum ib_access_flags access; + int pool_size; + int dirty_watermark; + void (*flush_function)(struct ib_fmr_pool *pool, + void *arg); + void *flush_arg; + unsigned cache:1; +}; + +struct ib_pool_fmr { + struct ib_fmr *fmr; + struct ib_fmr_pool *pool; + struct list_head list; + struct hlist_node cache_node; + int ref_count; + int remap_count; + u64 io_virtual_address; + int page_list_len; + u64 page_list[0]; +}; + +struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, + struct ib_fmr_pool_param *params); + +void ib_destroy_fmr_pool(struct ib_fmr_pool *pool); + +int ib_flush_fmr_pool(struct ib_fmr_pool *pool); + +struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle, + u64 *page_list, + int list_len, + u64 io_virtual_address); + +int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr); + +#endif /* IB_FMR_POOL_H */ diff --git a/sys/ofed/include/rdma/ib_mad.h b/sys/ofed/include/rdma/ib_mad.h new file mode 100644 index 000000000000..d3b9401b77b0 --- /dev/null +++ b/sys/ofed/include/rdma/ib_mad.h @@ -0,0 +1,655 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004-2006 Voltaire Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if !defined(IB_MAD_H) +#define IB_MAD_H + +#include + +#include + +/* Management base version */ +#define IB_MGMT_BASE_VERSION 1 + +/* Management classes */ +#define IB_MGMT_CLASS_SUBN_LID_ROUTED 0x01 +#define IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 0x81 +#define IB_MGMT_CLASS_SUBN_ADM 0x03 +#define IB_MGMT_CLASS_PERF_MGMT 0x04 +#define IB_MGMT_CLASS_BM 0x05 +#define IB_MGMT_CLASS_DEVICE_MGMT 0x06 +#define IB_MGMT_CLASS_CM 0x07 +#define IB_MGMT_CLASS_SNMP 0x08 +#define IB_MGMT_CLASS_DEVICE_ADM 0x10 +#define IB_MGMT_CLASS_BOOT_MGMT 0x11 +#define IB_MGMT_CLASS_BIS 0x12 +#define IB_MGMT_CLASS_CONG_MGMT 0x21 +#define IB_MGMT_CLASS_VENDOR_RANGE2_START 0x30 +#define IB_MGMT_CLASS_VENDOR_RANGE2_END 0x4F + +#define IB_OPENIB_OUI (0x001405) + +/* Management methods */ +#define IB_MGMT_METHOD_GET 0x01 +#define IB_MGMT_METHOD_SET 0x02 +#define IB_MGMT_METHOD_GET_RESP 0x81 +#define IB_MGMT_METHOD_SEND 0x03 +#define IB_MGMT_METHOD_TRAP 0x05 +#define IB_MGMT_METHOD_REPORT 0x06 +#define IB_MGMT_METHOD_REPORT_RESP 0x86 +#define IB_MGMT_METHOD_TRAP_REPRESS 0x07 + +#define IB_MGMT_METHOD_RESP 0x80 +#define IB_BM_ATTR_MOD_RESP cpu_to_be32(1) + +#define IB_MGMT_MAX_METHODS 128 + +/* RMPP information */ +#define IB_MGMT_RMPP_VERSION 1 + +#define IB_MGMT_RMPP_TYPE_DATA 1 +#define IB_MGMT_RMPP_TYPE_ACK 2 +#define IB_MGMT_RMPP_TYPE_STOP 3 +#define IB_MGMT_RMPP_TYPE_ABORT 4 + +#define IB_MGMT_RMPP_FLAG_ACTIVE 1 +#define IB_MGMT_RMPP_FLAG_FIRST (1<<1) +#define IB_MGMT_RMPP_FLAG_LAST (1<<2) + +#define IB_MGMT_RMPP_NO_RESPTIME 0x1F + +#define IB_MGMT_RMPP_STATUS_SUCCESS 0 +#define IB_MGMT_RMPP_STATUS_RESX 1 +#define IB_MGMT_RMPP_STATUS_ABORT_MIN 118 +#define IB_MGMT_RMPP_STATUS_T2L 118 +#define IB_MGMT_RMPP_STATUS_BAD_LEN 119 +#define IB_MGMT_RMPP_STATUS_BAD_SEG 120 +#define IB_MGMT_RMPP_STATUS_BADT 121 +#define IB_MGMT_RMPP_STATUS_W2S 122 +#define IB_MGMT_RMPP_STATUS_S2B 123 +#define IB_MGMT_RMPP_STATUS_BAD_STATUS 124 +#define IB_MGMT_RMPP_STATUS_UNV 125 +#define IB_MGMT_RMPP_STATUS_TMR 126 +#define IB_MGMT_RMPP_STATUS_UNSPEC 127 +#define IB_MGMT_RMPP_STATUS_ABORT_MAX 127 + +#define IB_QP0 0 +#define IB_QP1 cpu_to_be32(1) +#define IB_QP1_QKEY 0x80010000 +#define IB_QP_SET_QKEY 0x80000000 + +#define IB_DEFAULT_PKEY_PARTIAL 0x7FFF +#define IB_DEFAULT_PKEY_FULL 0xFFFF + +enum { + IB_MGMT_MAD_HDR = 24, + IB_MGMT_MAD_DATA = 232, + IB_MGMT_RMPP_HDR = 36, + IB_MGMT_RMPP_DATA = 220, + IB_MGMT_VENDOR_HDR = 40, + IB_MGMT_VENDOR_DATA = 216, + IB_MGMT_SA_HDR = 56, + IB_MGMT_SA_DATA = 200, + IB_MGMT_DEVICE_HDR = 64, + IB_MGMT_DEVICE_DATA = 192, +}; + +struct ib_mad_hdr { + u8 base_version; + u8 mgmt_class; + u8 class_version; + u8 method; + __be16 status; + __be16 class_specific; + __be64 tid; + __be16 attr_id; + __be16 resv; + __be32 attr_mod; +}; + +struct ib_rmpp_hdr { + u8 rmpp_version; + u8 rmpp_type; + u8 rmpp_rtime_flags; + u8 rmpp_status; + __be32 seg_num; + __be32 paylen_newwin; +}; + +typedef u64 __bitwise ib_sa_comp_mask; + +#define IB_SA_COMP_MASK(n) ((__force ib_sa_comp_mask) cpu_to_be64(1ull << n)) + +/* + * ib_sa_hdr and ib_sa_mad structures must be packed because they have + * 64-bit fields that are only 32-bit aligned. 64-bit architectures will + * lay them out wrong otherwise. (And unfortunately they are sent on + * the wire so we can't change the layout) + */ +struct ib_sa_hdr { + __be64 sm_key; + __be16 attr_offset; + __be16 reserved; + ib_sa_comp_mask comp_mask; +} __attribute__ ((packed)); + +struct ib_mad { + struct ib_mad_hdr mad_hdr; + u8 data[IB_MGMT_MAD_DATA]; +}; + +struct ib_rmpp_mad { + struct ib_mad_hdr mad_hdr; + struct ib_rmpp_hdr rmpp_hdr; + u8 data[IB_MGMT_RMPP_DATA]; +}; + +struct ib_sa_mad { + struct ib_mad_hdr mad_hdr; + struct ib_rmpp_hdr rmpp_hdr; + struct ib_sa_hdr sa_hdr; + u8 data[IB_MGMT_SA_DATA]; +} __attribute__ ((packed)); + +struct ib_vendor_mad { + struct ib_mad_hdr mad_hdr; + struct ib_rmpp_hdr rmpp_hdr; + u8 reserved; + u8 oui[3]; + u8 data[IB_MGMT_VENDOR_DATA]; +}; + +struct ib_class_port_info { + u8 base_version; + u8 class_version; + __be16 capability_mask; + u8 reserved[3]; + u8 resp_time_value; + u8 redirect_gid[16]; + __be32 redirect_tcslfl; + __be16 redirect_lid; + __be16 redirect_pkey; + __be32 redirect_qp; + __be32 redirect_qkey; + u8 trap_gid[16]; + __be32 trap_tcslfl; + __be16 trap_lid; + __be16 trap_pkey; + __be32 trap_hlqp; + __be32 trap_qkey; +}; + +/** + * ib_mad_send_buf - MAD data buffer and work request for sends. + * @next: A pointer used to chain together MADs for posting. + * @mad: References an allocated MAD data buffer for MADs that do not have + * RMPP active. For MADs using RMPP, references the common and management + * class specific headers. + * @mad_agent: MAD agent that allocated the buffer. + * @ah: The address handle to use when sending the MAD. + * @context: User-controlled context fields. + * @hdr_len: Indicates the size of the data header of the MAD. This length + * includes the common MAD, RMPP, and class specific headers. + * @data_len: Indicates the total size of user-transferred data. + * @seg_count: The number of RMPP segments allocated for this send. + * @seg_size: Size of each RMPP segment. + * @timeout_ms: Time to wait for a response. + * @retries: Number of times to retry a request for a response. For MADs + * using RMPP, this applies per window. On completion, returns the number + * of retries needed to complete the transfer. + * + * Users are responsible for initializing the MAD buffer itself, with the + * exception of any RMPP header. Additional segment buffer space allocated + * beyond data_len is padding. + */ +struct ib_mad_send_buf { + struct ib_mad_send_buf *next; + void *mad; + struct ib_mad_agent *mad_agent; + struct ib_ah *ah; + void *context[2]; + int hdr_len; + int data_len; + int seg_count; + int seg_size; + int timeout_ms; + int retries; +}; + +/** + * ib_response_mad - Returns if the specified MAD has been generated in + * response to a sent request or trap. + */ +int ib_response_mad(struct ib_mad *mad); + +/** + * ib_get_rmpp_resptime - Returns the RMPP response time. + * @rmpp_hdr: An RMPP header. + */ +static inline u8 ib_get_rmpp_resptime(struct ib_rmpp_hdr *rmpp_hdr) +{ + return rmpp_hdr->rmpp_rtime_flags >> 3; +} + +/** + * ib_get_rmpp_flags - Returns the RMPP flags. + * @rmpp_hdr: An RMPP header. + */ +static inline u8 ib_get_rmpp_flags(struct ib_rmpp_hdr *rmpp_hdr) +{ + return rmpp_hdr->rmpp_rtime_flags & 0x7; +} + +/** + * ib_set_rmpp_resptime - Sets the response time in an RMPP header. + * @rmpp_hdr: An RMPP header. + * @rtime: The response time to set. + */ +static inline void ib_set_rmpp_resptime(struct ib_rmpp_hdr *rmpp_hdr, u8 rtime) +{ + rmpp_hdr->rmpp_rtime_flags = ib_get_rmpp_flags(rmpp_hdr) | (rtime << 3); +} + +/** + * ib_set_rmpp_flags - Sets the flags in an RMPP header. + * @rmpp_hdr: An RMPP header. + * @flags: The flags to set. + */ +static inline void ib_set_rmpp_flags(struct ib_rmpp_hdr *rmpp_hdr, u8 flags) +{ + rmpp_hdr->rmpp_rtime_flags = (rmpp_hdr->rmpp_rtime_flags & 0xF8) | + (flags & 0x7); +} + +struct ib_mad_agent; +struct ib_mad_send_wc; +struct ib_mad_recv_wc; + +/** + * ib_mad_send_handler - callback handler for a sent MAD. + * @mad_agent: MAD agent that sent the MAD. + * @mad_send_wc: Send work completion information on the sent MAD. + */ +typedef void (*ib_mad_send_handler)(struct ib_mad_agent *mad_agent, + struct ib_mad_send_wc *mad_send_wc); + +/** + * ib_mad_snoop_handler - Callback handler for snooping sent MADs. + * @mad_agent: MAD agent that snooped the MAD. + * @send_wr: Work request information on the sent MAD. + * @mad_send_wc: Work completion information on the sent MAD. Valid + * only for snooping that occurs on a send completion. + * + * Clients snooping MADs should not modify data referenced by the @send_wr + * or @mad_send_wc. + */ +typedef void (*ib_mad_snoop_handler)(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf, + struct ib_mad_send_wc *mad_send_wc); + +/** + * ib_mad_recv_handler - callback handler for a received MAD. + * @mad_agent: MAD agent requesting the received MAD. + * @mad_recv_wc: Received work completion information on the received MAD. + * + * MADs received in response to a send request operation will be handed to + * the user before the send operation completes. All data buffers given + * to registered agents through this routine are owned by the receiving + * client, except for snooping agents. Clients snooping MADs should not + * modify the data referenced by @mad_recv_wc. + */ +typedef void (*ib_mad_recv_handler)(struct ib_mad_agent *mad_agent, + struct ib_mad_recv_wc *mad_recv_wc); + +/** + * ib_mad_agent - Used to track MAD registration with the access layer. + * @device: Reference to device registration is on. + * @qp: Reference to QP used for sending and receiving MADs. + * @mr: Memory region for system memory usable for DMA. + * @recv_handler: Callback handler for a received MAD. + * @send_handler: Callback handler for a sent MAD. + * @snoop_handler: Callback handler for snooped sent MADs. + * @context: User-specified context associated with this registration. + * @hi_tid: Access layer assigned transaction ID for this client. + * Unsolicited MADs sent by this client will have the upper 32-bits + * of their TID set to this value. + * @port_num: Port number on which QP is registered + * @rmpp_version: If set, indicates the RMPP version used by this agent. + */ +struct ib_mad_agent { + struct ib_device *device; + struct ib_qp *qp; + struct ib_mr *mr; + ib_mad_recv_handler recv_handler; + ib_mad_send_handler send_handler; + ib_mad_snoop_handler snoop_handler; + void *context; + u32 hi_tid; + u8 port_num; + u8 rmpp_version; +}; + +/** + * ib_mad_send_wc - MAD send completion information. + * @send_buf: Send MAD data buffer associated with the send MAD request. + * @status: Completion status. + * @vendor_err: Optional vendor error information returned with a failed + * request. + */ +struct ib_mad_send_wc { + struct ib_mad_send_buf *send_buf; + enum ib_wc_status status; + u32 vendor_err; +}; + +/** + * ib_mad_recv_buf - received MAD buffer information. + * @list: Reference to next data buffer for a received RMPP MAD. + * @grh: References a data buffer containing the global route header. + * The data refereced by this buffer is only valid if the GRH is + * valid. + * @mad: References the start of the received MAD. + */ +struct ib_mad_recv_buf { + struct list_head list; + struct ib_grh *grh; + struct ib_mad *mad; +}; + +/** + * ib_mad_recv_wc - received MAD information. + * @wc: Completion information for the received data. + * @recv_buf: Specifies the location of the received data buffer(s). + * @rmpp_list: Specifies a list of RMPP reassembled received MAD buffers. + * @mad_len: The length of the received MAD, without duplicated headers. + * + * For received response, the wr_id contains a pointer to the ib_mad_send_buf + * for the corresponding send request. + */ +struct ib_mad_recv_wc { + struct ib_wc *wc; + struct ib_mad_recv_buf recv_buf; + struct list_head rmpp_list; + int mad_len; +}; + +/** + * ib_mad_reg_req - MAD registration request + * @mgmt_class: Indicates which management class of MADs should be receive + * by the caller. This field is only required if the user wishes to + * receive unsolicited MADs, otherwise it should be 0. + * @mgmt_class_version: Indicates which version of MADs for the given + * management class to receive. + * @oui: Indicates IEEE OUI when mgmt_class is a vendor class + * in the range from 0x30 to 0x4f. Otherwise not used. + * @method_mask: The caller will receive unsolicited MADs for any method + * where @method_mask = 1. + */ +struct ib_mad_reg_req { + u8 mgmt_class; + u8 mgmt_class_version; + u8 oui[3]; + DECLARE_BITMAP(method_mask, IB_MGMT_MAX_METHODS); +}; + +/** + * ib_register_mad_agent - Register to send/receive MADs. + * @device: The device to register with. + * @port_num: The port on the specified device to use. + * @qp_type: Specifies which QP to access. Must be either + * IB_QPT_SMI or IB_QPT_GSI. + * @mad_reg_req: Specifies which unsolicited MADs should be received + * by the caller. This parameter may be NULL if the caller only + * wishes to receive solicited responses. + * @rmpp_version: If set, indicates that the client will send + * and receive MADs that contain the RMPP header for the given version. + * If set to 0, indicates that RMPP is not used by this client. + * @send_handler: The completion callback routine invoked after a send + * request has completed. + * @recv_handler: The completion callback routine invoked for a received + * MAD. + * @context: User specified context associated with the registration. + */ +struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, + u8 port_num, + enum ib_qp_type qp_type, + struct ib_mad_reg_req *mad_reg_req, + u8 rmpp_version, + ib_mad_send_handler send_handler, + ib_mad_recv_handler recv_handler, + void *context); + +enum ib_mad_snoop_flags { + /*IB_MAD_SNOOP_POSTED_SENDS = 1,*/ + /*IB_MAD_SNOOP_RMPP_SENDS = (1<<1),*/ + IB_MAD_SNOOP_SEND_COMPLETIONS = (1<<2), + /*IB_MAD_SNOOP_RMPP_SEND_COMPLETIONS = (1<<3),*/ + IB_MAD_SNOOP_RECVS = (1<<4) + /*IB_MAD_SNOOP_RMPP_RECVS = (1<<5),*/ + /*IB_MAD_SNOOP_REDIRECTED_QPS = (1<<6)*/ +}; + +/** + * ib_register_mad_snoop - Register to snoop sent and received MADs. + * @device: The device to register with. + * @port_num: The port on the specified device to use. + * @qp_type: Specifies which QP traffic to snoop. Must be either + * IB_QPT_SMI or IB_QPT_GSI. + * @mad_snoop_flags: Specifies information where snooping occurs. + * @send_handler: The callback routine invoked for a snooped send. + * @recv_handler: The callback routine invoked for a snooped receive. + * @context: User specified context associated with the registration. + */ +struct ib_mad_agent *ib_register_mad_snoop(struct ib_device *device, + u8 port_num, + enum ib_qp_type qp_type, + int mad_snoop_flags, + ib_mad_snoop_handler snoop_handler, + ib_mad_recv_handler recv_handler, + void *context); + +/** + * ib_unregister_mad_agent - Unregisters a client from using MAD services. + * @mad_agent: Corresponding MAD registration request to deregister. + * + * After invoking this routine, MAD services are no longer usable by the + * client on the associated QP. + */ +int ib_unregister_mad_agent(struct ib_mad_agent *mad_agent); + +/** + * ib_post_send_mad - Posts MAD(s) to the send queue of the QP associated + * with the registered client. + * @send_buf: Specifies the information needed to send the MAD(s). + * @bad_send_buf: Specifies the MAD on which an error was encountered. This + * parameter is optional if only a single MAD is posted. + * + * Sent MADs are not guaranteed to complete in the order that they were posted. + * + * If the MAD requires RMPP, the data buffer should contain a single copy + * of the common MAD, RMPP, and class specific headers, followed by the class + * defined data. If the class defined data would not divide evenly into + * RMPP segments, then space must be allocated at the end of the referenced + * buffer for any required padding. To indicate the amount of class defined + * data being transferred, the paylen_newwin field in the RMPP header should + * be set to the size of the class specific header plus the amount of class + * defined data being transferred. The paylen_newwin field should be + * specified in network-byte order. + */ +int ib_post_send_mad(struct ib_mad_send_buf *send_buf, + struct ib_mad_send_buf **bad_send_buf); + + +/** + * ib_free_recv_mad - Returns data buffers used to receive a MAD. + * @mad_recv_wc: Work completion information for a received MAD. + * + * Clients receiving MADs through their ib_mad_recv_handler must call this + * routine to return the work completion buffers to the access layer. + */ +void ib_free_recv_mad(struct ib_mad_recv_wc *mad_recv_wc); + +/** + * ib_cancel_mad - Cancels an outstanding send MAD operation. + * @mad_agent: Specifies the registration associated with sent MAD. + * @send_buf: Indicates the MAD to cancel. + * + * MADs will be returned to the user through the corresponding + * ib_mad_send_handler. + */ +void ib_cancel_mad(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf); + +/** + * ib_modify_mad - Modifies an outstanding send MAD operation. + * @mad_agent: Specifies the registration associated with sent MAD. + * @send_buf: Indicates the MAD to modify. + * @timeout_ms: New timeout value for sent MAD. + * + * This call will reset the timeout value for a sent MAD to the specified + * value. + */ +int ib_modify_mad(struct ib_mad_agent *mad_agent, + struct ib_mad_send_buf *send_buf, u32 timeout_ms); + +/** + * ib_redirect_mad_qp - Registers a QP for MAD services. + * @qp: Reference to a QP that requires MAD services. + * @rmpp_version: If set, indicates that the client will send + * and receive MADs that contain the RMPP header for the given version. + * If set to 0, indicates that RMPP is not used by this client. + * @send_handler: The completion callback routine invoked after a send + * request has completed. + * @recv_handler: The completion callback routine invoked for a received + * MAD. + * @context: User specified context associated with the registration. + * + * Use of this call allows clients to use MAD services, such as RMPP, + * on user-owned QPs. After calling this routine, users may send + * MADs on the specified QP by calling ib_mad_post_send. + */ +struct ib_mad_agent *ib_redirect_mad_qp(struct ib_qp *qp, + u8 rmpp_version, + ib_mad_send_handler send_handler, + ib_mad_recv_handler recv_handler, + void *context); + +/** + * ib_process_mad_wc - Processes a work completion associated with a + * MAD sent or received on a redirected QP. + * @mad_agent: Specifies the registered MAD service using the redirected QP. + * @wc: References a work completion associated with a sent or received + * MAD segment. + * + * This routine is used to complete or continue processing on a MAD request. + * If the work completion is associated with a send operation, calling + * this routine is required to continue an RMPP transfer or to wait for a + * corresponding response, if it is a request. If the work completion is + * associated with a receive operation, calling this routine is required to + * process an inbound or outbound RMPP transfer, or to match a response MAD + * with its corresponding request. + */ +int ib_process_mad_wc(struct ib_mad_agent *mad_agent, + struct ib_wc *wc); + +/** + * ib_create_send_mad - Allocate and initialize a data buffer and work request + * for sending a MAD. + * @mad_agent: Specifies the registered MAD service to associate with the MAD. + * @remote_qpn: Specifies the QPN of the receiving node. + * @pkey_index: Specifies which PKey the MAD will be sent using. This field + * is valid only if the remote_qpn is QP 1. + * @rmpp_active: Indicates if the send will enable RMPP. + * @hdr_len: Indicates the size of the data header of the MAD. This length + * should include the common MAD header, RMPP header, plus any class + * specific header. + * @data_len: Indicates the size of any user-transferred data. The call will + * automatically adjust the allocated buffer size to account for any + * additional padding that may be necessary. + * @gfp_mask: GFP mask used for the memory allocation. + * + * This routine allocates a MAD for sending. The returned MAD send buffer + * will reference a data buffer usable for sending a MAD, along + * with an initialized work request structure. Users may modify the returned + * MAD data buffer before posting the send. + * + * The returned MAD header, class specific headers, and any padding will be + * cleared. Users are responsible for initializing the common MAD header, + * any class specific header, and MAD data area. + * If @rmpp_active is set, the RMPP header will be initialized for sending. + */ +struct ib_mad_send_buf *ib_create_send_mad(struct ib_mad_agent *mad_agent, + u32 remote_qpn, u16 pkey_index, + int rmpp_active, + int hdr_len, int data_len, + gfp_t gfp_mask); + +/** + * ib_is_mad_class_rmpp - returns whether given management class + * supports RMPP. + * @mgmt_class: management class + * + * This routine returns whether the management class supports RMPP. + */ +int ib_is_mad_class_rmpp(u8 mgmt_class); + +/** + * ib_get_mad_data_offset - returns the data offset for a given + * management class. + * @mgmt_class: management class + * + * This routine returns the data offset in the MAD for the management + * class requested. + */ +int ib_get_mad_data_offset(u8 mgmt_class); + +/** + * ib_get_rmpp_segment - returns the data buffer for a given RMPP segment. + * @send_buf: Previously allocated send data buffer. + * @seg_num: number of segment to return + * + * This routine returns a pointer to the data buffer of an RMPP MAD. + * Users must provide synchronization to @send_buf around this call. + */ +void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num); + +/** + * ib_free_send_mad - Returns data buffers used to send a MAD. + * @send_buf: Previously allocated send data buffer. + */ +void ib_free_send_mad(struct ib_mad_send_buf *send_buf); + +#endif /* IB_MAD_H */ diff --git a/sys/ofed/include/rdma/ib_marshall.h b/sys/ofed/include/rdma/ib_marshall.h new file mode 100644 index 000000000000..db037205c9e8 --- /dev/null +++ b/sys/ofed/include/rdma/ib_marshall.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if !defined(IB_USER_MARSHALL_H) +#define IB_USER_MARSHALL_H + +#include +#include +#include +#include + +void ib_copy_qp_attr_to_user(struct ib_uverbs_qp_attr *dst, + struct ib_qp_attr *src); + +void ib_copy_ah_attr_to_user(struct ib_uverbs_ah_attr *dst, + struct ib_ah_attr *src); + +void ib_copy_path_rec_to_user(struct ib_user_path_rec *dst, + struct ib_sa_path_rec *src); + +void ib_copy_path_rec_from_user(struct ib_sa_path_rec *dst, + struct ib_user_path_rec *src); + +#endif /* IB_USER_MARSHALL_H */ diff --git a/sys/ofed/include/rdma/ib_pack.h b/sys/ofed/include/rdma/ib_pack.h new file mode 100644 index 000000000000..af615a477ffd --- /dev/null +++ b/sys/ofed/include/rdma/ib_pack.h @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IB_PACK_H +#define IB_PACK_H + +#include + +enum { + IB_LRH_BYTES = 8, + IB_ETH_BYTES = 14, + IB_VLAN_BYTES = 4, + IB_GRH_BYTES = 40, + IB_BTH_BYTES = 12, + IB_DETH_BYTES = 8 +}; + +struct ib_field { + size_t struct_offset_bytes; + size_t struct_size_bytes; + int offset_words; + int offset_bits; + int size_bits; + char *field_name; +}; + +#define RESERVED \ + .field_name = "reserved" + +/* + * This macro cleans up the definitions of constants for BTH opcodes. + * It is used to define constants such as IB_OPCODE_UD_SEND_ONLY, + * which becomes IB_OPCODE_UD + IB_OPCODE_SEND_ONLY, and this gives + * the correct value. + * + * In short, user code should use the constants defined using the + * macro rather than worrying about adding together other constants. +*/ +#define IB_OPCODE(transport, op) \ + IB_OPCODE_ ## transport ## _ ## op = \ + IB_OPCODE_ ## transport + IB_OPCODE_ ## op + +enum { + /* transport types -- just used to define real constants */ + IB_OPCODE_RC = 0x00, + IB_OPCODE_UC = 0x20, + IB_OPCODE_RD = 0x40, + IB_OPCODE_UD = 0x60, + + /* operations -- just used to define real constants */ + IB_OPCODE_SEND_FIRST = 0x00, + IB_OPCODE_SEND_MIDDLE = 0x01, + IB_OPCODE_SEND_LAST = 0x02, + IB_OPCODE_SEND_LAST_WITH_IMMEDIATE = 0x03, + IB_OPCODE_SEND_ONLY = 0x04, + IB_OPCODE_SEND_ONLY_WITH_IMMEDIATE = 0x05, + IB_OPCODE_RDMA_WRITE_FIRST = 0x06, + IB_OPCODE_RDMA_WRITE_MIDDLE = 0x07, + IB_OPCODE_RDMA_WRITE_LAST = 0x08, + IB_OPCODE_RDMA_WRITE_LAST_WITH_IMMEDIATE = 0x09, + IB_OPCODE_RDMA_WRITE_ONLY = 0x0a, + IB_OPCODE_RDMA_WRITE_ONLY_WITH_IMMEDIATE = 0x0b, + IB_OPCODE_RDMA_READ_REQUEST = 0x0c, + IB_OPCODE_RDMA_READ_RESPONSE_FIRST = 0x0d, + IB_OPCODE_RDMA_READ_RESPONSE_MIDDLE = 0x0e, + IB_OPCODE_RDMA_READ_RESPONSE_LAST = 0x0f, + IB_OPCODE_RDMA_READ_RESPONSE_ONLY = 0x10, + IB_OPCODE_ACKNOWLEDGE = 0x11, + IB_OPCODE_ATOMIC_ACKNOWLEDGE = 0x12, + IB_OPCODE_COMPARE_SWAP = 0x13, + IB_OPCODE_FETCH_ADD = 0x14, + + /* real constants follow -- see comment about above IB_OPCODE() + macro for more details */ + + /* RC */ + IB_OPCODE(RC, SEND_FIRST), + IB_OPCODE(RC, SEND_MIDDLE), + IB_OPCODE(RC, SEND_LAST), + IB_OPCODE(RC, SEND_LAST_WITH_IMMEDIATE), + IB_OPCODE(RC, SEND_ONLY), + IB_OPCODE(RC, SEND_ONLY_WITH_IMMEDIATE), + IB_OPCODE(RC, RDMA_WRITE_FIRST), + IB_OPCODE(RC, RDMA_WRITE_MIDDLE), + IB_OPCODE(RC, RDMA_WRITE_LAST), + IB_OPCODE(RC, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IB_OPCODE(RC, RDMA_WRITE_ONLY), + IB_OPCODE(RC, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + IB_OPCODE(RC, RDMA_READ_REQUEST), + IB_OPCODE(RC, RDMA_READ_RESPONSE_FIRST), + IB_OPCODE(RC, RDMA_READ_RESPONSE_MIDDLE), + IB_OPCODE(RC, RDMA_READ_RESPONSE_LAST), + IB_OPCODE(RC, RDMA_READ_RESPONSE_ONLY), + IB_OPCODE(RC, ACKNOWLEDGE), + IB_OPCODE(RC, ATOMIC_ACKNOWLEDGE), + IB_OPCODE(RC, COMPARE_SWAP), + IB_OPCODE(RC, FETCH_ADD), + + /* UC */ + IB_OPCODE(UC, SEND_FIRST), + IB_OPCODE(UC, SEND_MIDDLE), + IB_OPCODE(UC, SEND_LAST), + IB_OPCODE(UC, SEND_LAST_WITH_IMMEDIATE), + IB_OPCODE(UC, SEND_ONLY), + IB_OPCODE(UC, SEND_ONLY_WITH_IMMEDIATE), + IB_OPCODE(UC, RDMA_WRITE_FIRST), + IB_OPCODE(UC, RDMA_WRITE_MIDDLE), + IB_OPCODE(UC, RDMA_WRITE_LAST), + IB_OPCODE(UC, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IB_OPCODE(UC, RDMA_WRITE_ONLY), + IB_OPCODE(UC, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + + /* RD */ + IB_OPCODE(RD, SEND_FIRST), + IB_OPCODE(RD, SEND_MIDDLE), + IB_OPCODE(RD, SEND_LAST), + IB_OPCODE(RD, SEND_LAST_WITH_IMMEDIATE), + IB_OPCODE(RD, SEND_ONLY), + IB_OPCODE(RD, SEND_ONLY_WITH_IMMEDIATE), + IB_OPCODE(RD, RDMA_WRITE_FIRST), + IB_OPCODE(RD, RDMA_WRITE_MIDDLE), + IB_OPCODE(RD, RDMA_WRITE_LAST), + IB_OPCODE(RD, RDMA_WRITE_LAST_WITH_IMMEDIATE), + IB_OPCODE(RD, RDMA_WRITE_ONLY), + IB_OPCODE(RD, RDMA_WRITE_ONLY_WITH_IMMEDIATE), + IB_OPCODE(RD, RDMA_READ_REQUEST), + IB_OPCODE(RD, RDMA_READ_RESPONSE_FIRST), + IB_OPCODE(RD, RDMA_READ_RESPONSE_MIDDLE), + IB_OPCODE(RD, RDMA_READ_RESPONSE_LAST), + IB_OPCODE(RD, RDMA_READ_RESPONSE_ONLY), + IB_OPCODE(RD, ACKNOWLEDGE), + IB_OPCODE(RD, ATOMIC_ACKNOWLEDGE), + IB_OPCODE(RD, COMPARE_SWAP), + IB_OPCODE(RD, FETCH_ADD), + + /* UD */ + IB_OPCODE(UD, SEND_ONLY), + IB_OPCODE(UD, SEND_ONLY_WITH_IMMEDIATE) +}; + +enum { + IB_LNH_RAW = 0, + IB_LNH_IP = 1, + IB_LNH_IBA_LOCAL = 2, + IB_LNH_IBA_GLOBAL = 3 +}; + +struct ib_unpacked_lrh { + u8 virtual_lane; + u8 link_version; + u8 service_level; + u8 link_next_header; + __be16 destination_lid; + __be16 packet_length; + __be16 source_lid; +}; + +struct ib_unpacked_grh { + u8 ip_version; + u8 traffic_class; + __be32 flow_label; + __be16 payload_length; + u8 next_header; + u8 hop_limit; + union ib_gid source_gid; + union ib_gid destination_gid; +}; + +struct ib_unpacked_bth { + u8 opcode; + u8 solicited_event; + u8 mig_req; + u8 pad_count; + u8 transport_header_version; + __be16 pkey; + __be32 destination_qpn; + u8 ack_req; + __be32 psn; +}; + +struct ib_unpacked_deth { + __be32 qkey; + __be32 source_qpn; +}; + +struct ib_unpacked_eth { + u8 dmac_h[4]; + u8 dmac_l[2]; + u8 smac_h[2]; + u8 smac_l[4]; + __be16 type; +}; + +struct ib_unpacked_vlan { + __be16 tag; + __be16 type; +}; + +struct ib_ud_header { + int lrh_present; + struct ib_unpacked_lrh lrh; + int eth_present; + struct ib_unpacked_eth eth; + int vlan_present; + struct ib_unpacked_vlan vlan; + int grh_present; + struct ib_unpacked_grh grh; + struct ib_unpacked_bth bth; + struct ib_unpacked_deth deth; + int immediate_present; + __be32 immediate_data; +}; + +void ib_pack(const struct ib_field *desc, + int desc_len, + void *structure, + void *buf); + +void ib_unpack(const struct ib_field *desc, + int desc_len, + void *buf, + void *structure); + +void ib_ud_header_init(int payload_bytes, + int lrh_present, + int eth_present, + int vlan_present, + int grh_present, + int immediate_present, + struct ib_ud_header *header); + +int ib_ud_header_pack(struct ib_ud_header *header, + void *buf); + +int ib_ud_header_unpack(void *buf, + struct ib_ud_header *header); +int ib_lrh_header_pack(struct ib_unpacked_lrh *lrh, void *buf); +int ib_lrh_header_unpack(void *buf, struct ib_unpacked_lrh *lrh); + +#endif /* IB_PACK_H */ diff --git a/sys/ofed/include/rdma/ib_sa.h b/sys/ofed/include/rdma/ib_sa.h new file mode 100644 index 000000000000..5a8f2cefa7c0 --- /dev/null +++ b/sys/ofed/include/rdma/ib_sa.h @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IB_SA_H +#define IB_SA_H + +#include +#include + +#include + +#include +#include + +enum { + IB_SA_CLASS_VERSION = 2, /* IB spec version 1.1/1.2 */ + + IB_SA_METHOD_GET_TABLE = 0x12, + IB_SA_METHOD_GET_TABLE_RESP = 0x92, + IB_SA_METHOD_DELETE = 0x15, + IB_SA_METHOD_DELETE_RESP = 0x95, + IB_SA_METHOD_GET_MULTI = 0x14, + IB_SA_METHOD_GET_MULTI_RESP = 0x94, + IB_SA_METHOD_GET_TRACE_TBL = 0x13 +}; + +enum { + IB_SA_ATTR_CLASS_PORTINFO = 0x01, + IB_SA_ATTR_NOTICE = 0x02, + IB_SA_ATTR_INFORM_INFO = 0x03, + IB_SA_ATTR_NODE_REC = 0x11, + IB_SA_ATTR_PORT_INFO_REC = 0x12, + IB_SA_ATTR_SL2VL_REC = 0x13, + IB_SA_ATTR_SWITCH_REC = 0x14, + IB_SA_ATTR_LINEAR_FDB_REC = 0x15, + IB_SA_ATTR_RANDOM_FDB_REC = 0x16, + IB_SA_ATTR_MCAST_FDB_REC = 0x17, + IB_SA_ATTR_SM_INFO_REC = 0x18, + IB_SA_ATTR_LINK_REC = 0x20, + IB_SA_ATTR_GUID_INFO_REC = 0x30, + IB_SA_ATTR_SERVICE_REC = 0x31, + IB_SA_ATTR_PARTITION_REC = 0x33, + IB_SA_ATTR_PATH_REC = 0x35, + IB_SA_ATTR_VL_ARB_REC = 0x36, + IB_SA_ATTR_MC_MEMBER_REC = 0x38, + IB_SA_ATTR_TRACE_REC = 0x39, + IB_SA_ATTR_MULTI_PATH_REC = 0x3a, + IB_SA_ATTR_SERVICE_ASSOC_REC = 0x3b, + IB_SA_ATTR_INFORM_INFO_REC = 0xf3 +}; + +enum ib_sa_selector { + IB_SA_GT = 0, + IB_SA_LT = 1, + IB_SA_EQ = 2, + /* + * The meaning of "best" depends on the attribute: for + * example, for MTU best will return the largest available + * MTU, while for packet life time, best will return the + * smallest available life time. + */ + IB_SA_BEST = 3 +}; + +/* + * Structures for SA records are named "struct ib_sa_xxx_rec." No + * attempt is made to pack structures to match the physical layout of + * SA records in SA MADs; all packing and unpacking is handled by the + * SA query code. + * + * For a record with structure ib_sa_xxx_rec, the naming convention + * for the component mask value for field yyy is IB_SA_XXX_REC_YYY (we + * never use different abbreviations or otherwise change the spelling + * of xxx/yyy between ib_sa_xxx_rec.yyy and IB_SA_XXX_REC_YYY). + * + * Reserved rows are indicated with comments to help maintainability. + */ + +#define IB_SA_PATH_REC_SERVICE_ID (IB_SA_COMP_MASK( 0) |\ + IB_SA_COMP_MASK( 1)) +#define IB_SA_PATH_REC_DGID IB_SA_COMP_MASK( 2) +#define IB_SA_PATH_REC_SGID IB_SA_COMP_MASK( 3) +#define IB_SA_PATH_REC_DLID IB_SA_COMP_MASK( 4) +#define IB_SA_PATH_REC_SLID IB_SA_COMP_MASK( 5) +#define IB_SA_PATH_REC_RAW_TRAFFIC IB_SA_COMP_MASK( 6) +/* reserved: 7 */ +#define IB_SA_PATH_REC_FLOW_LABEL IB_SA_COMP_MASK( 8) +#define IB_SA_PATH_REC_HOP_LIMIT IB_SA_COMP_MASK( 9) +#define IB_SA_PATH_REC_TRAFFIC_CLASS IB_SA_COMP_MASK(10) +#define IB_SA_PATH_REC_REVERSIBLE IB_SA_COMP_MASK(11) +#define IB_SA_PATH_REC_NUMB_PATH IB_SA_COMP_MASK(12) +#define IB_SA_PATH_REC_PKEY IB_SA_COMP_MASK(13) +#define IB_SA_PATH_REC_QOS_CLASS IB_SA_COMP_MASK(14) +#define IB_SA_PATH_REC_SL IB_SA_COMP_MASK(15) +#define IB_SA_PATH_REC_MTU_SELECTOR IB_SA_COMP_MASK(16) +#define IB_SA_PATH_REC_MTU IB_SA_COMP_MASK(17) +#define IB_SA_PATH_REC_RATE_SELECTOR IB_SA_COMP_MASK(18) +#define IB_SA_PATH_REC_RATE IB_SA_COMP_MASK(19) +#define IB_SA_PATH_REC_PACKET_LIFE_TIME_SELECTOR IB_SA_COMP_MASK(20) +#define IB_SA_PATH_REC_PACKET_LIFE_TIME IB_SA_COMP_MASK(21) +#define IB_SA_PATH_REC_PREFERENCE IB_SA_COMP_MASK(22) + +struct ib_sa_path_rec { + __be64 service_id; + union ib_gid dgid; + union ib_gid sgid; + __be16 dlid; + __be16 slid; + int raw_traffic; + /* reserved */ + __be32 flow_label; + u8 hop_limit; + u8 traffic_class; + int reversible; + u8 numb_path; + __be16 pkey; + __be16 qos_class; + u8 sl; + u8 mtu_selector; + u8 mtu; + u8 rate_selector; + u8 rate; + u8 packet_life_time_selector; + u8 packet_life_time; + u8 preference; +}; + +#define IB_SA_MCMEMBER_REC_MGID IB_SA_COMP_MASK( 0) +#define IB_SA_MCMEMBER_REC_PORT_GID IB_SA_COMP_MASK( 1) +#define IB_SA_MCMEMBER_REC_QKEY IB_SA_COMP_MASK( 2) +#define IB_SA_MCMEMBER_REC_MLID IB_SA_COMP_MASK( 3) +#define IB_SA_MCMEMBER_REC_MTU_SELECTOR IB_SA_COMP_MASK( 4) +#define IB_SA_MCMEMBER_REC_MTU IB_SA_COMP_MASK( 5) +#define IB_SA_MCMEMBER_REC_TRAFFIC_CLASS IB_SA_COMP_MASK( 6) +#define IB_SA_MCMEMBER_REC_PKEY IB_SA_COMP_MASK( 7) +#define IB_SA_MCMEMBER_REC_RATE_SELECTOR IB_SA_COMP_MASK( 8) +#define IB_SA_MCMEMBER_REC_RATE IB_SA_COMP_MASK( 9) +#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME_SELECTOR IB_SA_COMP_MASK(10) +#define IB_SA_MCMEMBER_REC_PACKET_LIFE_TIME IB_SA_COMP_MASK(11) +#define IB_SA_MCMEMBER_REC_SL IB_SA_COMP_MASK(12) +#define IB_SA_MCMEMBER_REC_FLOW_LABEL IB_SA_COMP_MASK(13) +#define IB_SA_MCMEMBER_REC_HOP_LIMIT IB_SA_COMP_MASK(14) +#define IB_SA_MCMEMBER_REC_SCOPE IB_SA_COMP_MASK(15) +#define IB_SA_MCMEMBER_REC_JOIN_STATE IB_SA_COMP_MASK(16) +#define IB_SA_MCMEMBER_REC_PROXY_JOIN IB_SA_COMP_MASK(17) + +struct ib_sa_mcmember_rec { + union ib_gid mgid; + union ib_gid port_gid; + __be32 qkey; + __be16 mlid; + u8 mtu_selector; + u8 mtu; + u8 traffic_class; + __be16 pkey; + u8 rate_selector; + u8 rate; + u8 packet_life_time_selector; + u8 packet_life_time; + u8 sl; + __be32 flow_label; + u8 hop_limit; + u8 scope; + u8 join_state; + int proxy_join; +}; + +/* Service Record Component Mask Sec 15.2.5.14 Ver 1.1 */ +#define IB_SA_SERVICE_REC_SERVICE_ID IB_SA_COMP_MASK( 0) +#define IB_SA_SERVICE_REC_SERVICE_GID IB_SA_COMP_MASK( 1) +#define IB_SA_SERVICE_REC_SERVICE_PKEY IB_SA_COMP_MASK( 2) +/* reserved: 3 */ +#define IB_SA_SERVICE_REC_SERVICE_LEASE IB_SA_COMP_MASK( 4) +#define IB_SA_SERVICE_REC_SERVICE_KEY IB_SA_COMP_MASK( 5) +#define IB_SA_SERVICE_REC_SERVICE_NAME IB_SA_COMP_MASK( 6) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_0 IB_SA_COMP_MASK( 7) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_1 IB_SA_COMP_MASK( 8) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_2 IB_SA_COMP_MASK( 9) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_3 IB_SA_COMP_MASK(10) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_4 IB_SA_COMP_MASK(11) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_5 IB_SA_COMP_MASK(12) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_6 IB_SA_COMP_MASK(13) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_7 IB_SA_COMP_MASK(14) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_8 IB_SA_COMP_MASK(15) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_9 IB_SA_COMP_MASK(16) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_10 IB_SA_COMP_MASK(17) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_11 IB_SA_COMP_MASK(18) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_12 IB_SA_COMP_MASK(19) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_13 IB_SA_COMP_MASK(20) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_14 IB_SA_COMP_MASK(21) +#define IB_SA_SERVICE_REC_SERVICE_DATA8_15 IB_SA_COMP_MASK(22) +#define IB_SA_SERVICE_REC_SERVICE_DATA16_0 IB_SA_COMP_MASK(23) +#define IB_SA_SERVICE_REC_SERVICE_DATA16_1 IB_SA_COMP_MASK(24) +#define IB_SA_SERVICE_REC_SERVICE_DATA16_2 IB_SA_COMP_MASK(25) +#define IB_SA_SERVICE_REC_SERVICE_DATA16_3 IB_SA_COMP_MASK(26) +#define IB_SA_SERVICE_REC_SERVICE_DATA16_4 IB_SA_COMP_MASK(27) +#define IB_SA_SERVICE_REC_SERVICE_DATA16_5 IB_SA_COMP_MASK(28) +#define IB_SA_SERVICE_REC_SERVICE_DATA16_6 IB_SA_COMP_MASK(29) +#define IB_SA_SERVICE_REC_SERVICE_DATA16_7 IB_SA_COMP_MASK(30) +#define IB_SA_SERVICE_REC_SERVICE_DATA32_0 IB_SA_COMP_MASK(31) +#define IB_SA_SERVICE_REC_SERVICE_DATA32_1 IB_SA_COMP_MASK(32) +#define IB_SA_SERVICE_REC_SERVICE_DATA32_2 IB_SA_COMP_MASK(33) +#define IB_SA_SERVICE_REC_SERVICE_DATA32_3 IB_SA_COMP_MASK(34) +#define IB_SA_SERVICE_REC_SERVICE_DATA64_0 IB_SA_COMP_MASK(35) +#define IB_SA_SERVICE_REC_SERVICE_DATA64_1 IB_SA_COMP_MASK(36) + +#define IB_DEFAULT_SERVICE_LEASE 0xFFFFFFFF + +struct ib_sa_service_rec { + u64 id; + union ib_gid gid; + __be16 pkey; + /* reserved */ + u32 lease; + u8 key[16]; + u8 name[64]; + u8 data8[16]; + u16 data16[8]; + u32 data32[4]; + u64 data64[2]; +}; + +enum { + IB_SA_EVENT_TYPE_FATAL = 0x0, + IB_SA_EVENT_TYPE_URGENT = 0x1, + IB_SA_EVENT_TYPE_SECURITY = 0x2, + IB_SA_EVENT_TYPE_SM = 0x3, + IB_SA_EVENT_TYPE_INFO = 0x4, + IB_SA_EVENT_TYPE_EMPTY = 0x7F, + IB_SA_EVENT_TYPE_ALL = 0xFFFF +}; + +enum { + IB_SA_EVENT_PRODUCER_TYPE_CA = 0x1, + IB_SA_EVENT_PRODUCER_TYPE_SWITCH = 0x2, + IB_SA_EVENT_PRODUCER_TYPE_ROUTER = 0x3, + IB_SA_EVENT_PRODUCER_TYPE_CLASS_MANAGER = 0x4, + IB_SA_EVENT_PRODUCER_TYPE_ALL = 0xFFFFFF +}; + +enum { + IB_SA_SM_TRAP_GID_IN_SERVICE = 64, + IB_SA_SM_TRAP_GID_OUT_OF_SERVICE = 65, + IB_SA_SM_TRAP_CREATE_MC_GROUP = 66, + IB_SA_SM_TRAP_DELETE_MC_GROUP = 67, + IB_SA_SM_TRAP_PORT_CHANGE_STATE = 128, + IB_SA_SM_TRAP_LINK_INTEGRITY = 129, + IB_SA_SM_TRAP_EXCESSIVE_BUFFER_OVERRUN = 130, + IB_SA_SM_TRAP_FLOW_CONTROL_UPDATE_EXPIRED = 131, + IB_SA_SM_TRAP_BAD_M_KEY = 256, + IB_SA_SM_TRAP_BAD_P_KEY = 257, + IB_SA_SM_TRAP_BAD_Q_KEY = 258, + IB_SA_SM_TRAP_SWITCH_BAD_P_KEY = 259, + IB_SA_SM_TRAP_ALL = 0xFFFF +}; + +struct ib_sa_inform { + union ib_gid gid; + __be16 lid_range_begin; + __be16 lid_range_end; + u8 is_generic; + u8 subscribe; + __be16 type; + union { + struct { + __be16 trap_num; + __be32 qpn; + u8 resp_time; + __be32 producer_type; + } generic; + struct { + __be16 device_id; + __be32 qpn; + u8 resp_time; + __be32 vendor_id; + } vendor; + } trap; +}; + +struct ib_sa_notice { + u8 is_generic; + u8 type; + union { + struct { + __be32 producer_type; + __be16 trap_num; + } generic; + struct { + __be32 vendor_id; + __be16 device_id; + } vendor; + } trap; + __be16 issuer_lid; + __be16 notice_count; + u8 notice_toggle; + /* + * Align data 16 bits off 64 bit field to match InformInfo definition. + * Data contained within this field will then align properly. + * See IB spec 1.2, sections 13.4.8.2 and 14.2.5.1. + */ + u8 reserved[5]; + u8 data_details[54]; + union ib_gid issuer_gid; +}; + +/* + * SM notice data details for: + * + * IB_SA_SM_TRAP_GID_IN_SERVICE = 64 + * IB_SA_SM_TRAP_GID_OUT_OF_SERVICE = 65 + * IB_SA_SM_TRAP_CREATE_MC_GROUP = 66 + * IB_SA_SM_TRAP_DELETE_MC_GROUP = 67 + */ +struct ib_sa_notice_data_gid { + u8 reserved[6]; + u8 gid[16]; + u8 padding[32]; +}; + +/* + * SM notice data details for: + * + * IB_SA_SM_TRAP_PORT_CHANGE_STATE = 128 + */ +struct ib_sa_notice_data_port_change { + __be16 lid; + u8 padding[52]; +}; + +/* + * SM notice data details for: + * + * IB_SA_SM_TRAP_LINK_INTEGRITY = 129 + * IB_SA_SM_TRAP_EXCESSIVE_BUFFER_OVERRUN = 130 + * IB_SA_SM_TRAP_FLOW_CONTROL_UPDATE_EXPIRED = 131 + */ +struct ib_sa_notice_data_port_error { + u8 reserved[2]; + __be16 lid; + u8 port_num; + u8 padding[49]; +}; + +struct ib_sa_client { + atomic_t users; + struct completion comp; +}; + +/** + * ib_sa_register_client - Register an SA client. + */ +void ib_sa_register_client(struct ib_sa_client *client); + +/** + * ib_sa_unregister_client - Deregister an SA client. + * @client: Client object to deregister. + */ +void ib_sa_unregister_client(struct ib_sa_client *client); + +struct ib_sa_query; + +void ib_sa_cancel_query(int id, struct ib_sa_query *query); + +int ib_sa_path_rec_get(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + struct ib_sa_path_rec *rec, + ib_sa_comp_mask comp_mask, + int timeout_ms, gfp_t gfp_mask, + void (*callback)(int status, + struct ib_sa_path_rec *resp, + void *context), + void *context, + struct ib_sa_query **query); + +int ib_sa_service_rec_query(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + u8 method, + struct ib_sa_service_rec *rec, + ib_sa_comp_mask comp_mask, + int timeout_ms, gfp_t gfp_mask, + void (*callback)(int status, + struct ib_sa_service_rec *resp, + void *context), + void *context, + struct ib_sa_query **sa_query); + +struct ib_sa_multicast { + struct ib_sa_mcmember_rec rec; + ib_sa_comp_mask comp_mask; + int (*callback)(int status, + struct ib_sa_multicast *multicast); + void *context; +}; + +/** + * ib_sa_join_multicast - Initiates a join request to the specified multicast + * group. + * @client: SA client + * @device: Device associated with the multicast group. + * @port_num: Port on the specified device to associate with the multicast + * group. + * @rec: SA multicast member record specifying group attributes. + * @comp_mask: Component mask indicating which group attributes of %rec are + * valid. + * @gfp_mask: GFP mask for memory allocations. + * @callback: User callback invoked once the join operation completes. + * @context: User specified context stored with the ib_sa_multicast structure. + * + * This call initiates a multicast join request with the SA for the specified + * multicast group. If the join operation is started successfully, it returns + * an ib_sa_multicast structure that is used to track the multicast operation. + * Users must free this structure by calling ib_free_multicast, even if the + * join operation later fails. (The callback status is non-zero.) + * + * If the join operation fails; status will be non-zero, with the following + * failures possible: + * -ETIMEDOUT: The request timed out. + * -EIO: An error occurred sending the query. + * -EINVAL: The MCMemberRecord values differed from the existing group's. + * -ENETRESET: Indicates that an fatal error has occurred on the multicast + * group, and the user must rejoin the group to continue using it. + */ +struct ib_sa_multicast *ib_sa_join_multicast(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + struct ib_sa_mcmember_rec *rec, + ib_sa_comp_mask comp_mask, gfp_t gfp_mask, + int (*callback)(int status, + struct ib_sa_multicast + *multicast), + void *context); + +/** + * ib_free_multicast - Frees the multicast tracking structure, and releases + * any reference on the multicast group. + * @multicast: Multicast tracking structure allocated by ib_join_multicast. + * + * This call blocks until the multicast identifier is destroyed. It may + * not be called from within the multicast callback; however, returning a non- + * zero value from the callback will result in destroying the multicast + * tracking structure. + */ +void ib_sa_free_multicast(struct ib_sa_multicast *multicast); + +/** + * ib_get_mcmember_rec - Looks up a multicast member record by its MGID and + * returns it if found. + * @device: Device associated with the multicast group. + * @port_num: Port on the specified device to associate with the multicast + * group. + * @mgid: MGID of multicast group. + * @rec: Location to copy SA multicast member record. + */ +int ib_sa_get_mcmember_rec(struct ib_device *device, u8 port_num, + union ib_gid *mgid, struct ib_sa_mcmember_rec *rec); + +/** + * ib_init_ah_from_mcmember - Initialize address handle attributes based on + * an SA multicast member record. + */ +int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num, + struct ib_sa_mcmember_rec *rec, + struct ib_ah_attr *ah_attr); + +/** + * ib_init_ah_from_path - Initialize address handle attributes based on an SA + * path record. + */ +int ib_init_ah_from_path(struct ib_device *device, u8 port_num, + struct ib_sa_path_rec *rec, + struct ib_ah_attr *ah_attr); + +/** + * ib_sa_unpack_path - Convert a path record from MAD format to struct + * ib_sa_path_rec. + */ +void ib_sa_unpack_path(void *attribute, struct ib_sa_path_rec *rec); + +struct ib_inform_info { + void *context; + int (*callback)(int status, + struct ib_inform_info *info, + struct ib_sa_notice *notice); + u16 trap_number; +}; + +/** + * ib_sa_register_inform_info - Registers to receive notice events. + * @device: Device associated with the registration. + * @port_num: Port on the specified device to associate with the registration. + * @trap_number: InformInfo trap number to register for. + * @gfp_mask: GFP mask for memory allocations. + * @callback: User callback invoked once the registration completes and to + * report noticed events. + * @context: User specified context stored with the ib_inform_reg structure. + * + * This call initiates a registration request with the SA for the specified + * trap number. If the operation is started successfully, it returns + * an ib_inform_info structure that is used to track the registration operation. + * Users must free this structure by calling ib_unregister_inform_info, + * even if the operation later fails. (The callback status is non-zero.) + * + * If the registration fails; status will be non-zero. If the registration + * succeeds, the callback status will be zero, but the notice parameter will + * be NULL. If the notice parameter is not NULL, a trap or notice is being + * reported to the user. + * + * A status of -ENETRESET indicates that an error occurred which requires + * reregisteration. + */ +struct ib_inform_info * +ib_sa_register_inform_info(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, + u16 trap_number, gfp_t gfp_mask, + int (*callback)(int status, + struct ib_inform_info *info, + struct ib_sa_notice *notice), + void *context); + +/** + * ib_sa_unregister_inform_info - Releases an InformInfo registration. + * @info: InformInfo registration tracking structure. + * + * This call blocks until the registration request is destroyed. It may + * not be called from within the registration callback. + */ +void ib_sa_unregister_inform_info(struct ib_inform_info *info); + +#endif /* IB_SA_H */ diff --git a/sys/ofed/include/rdma/ib_smi.h b/sys/ofed/include/rdma/ib_smi.h new file mode 100644 index 000000000000..98b9086d769a --- /dev/null +++ b/sys/ofed/include/rdma/ib_smi.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if !defined(IB_SMI_H) +#define IB_SMI_H + +#include + +#define IB_SMP_DATA_SIZE 64 +#define IB_SMP_MAX_PATH_HOPS 64 + +struct ib_smp { + u8 base_version; + u8 mgmt_class; + u8 class_version; + u8 method; + __be16 status; + u8 hop_ptr; + u8 hop_cnt; + __be64 tid; + __be16 attr_id; + __be16 resv; + __be32 attr_mod; + __be64 mkey; + __be16 dr_slid; + __be16 dr_dlid; + u8 reserved[28]; + u8 data[IB_SMP_DATA_SIZE]; + u8 initial_path[IB_SMP_MAX_PATH_HOPS]; + u8 return_path[IB_SMP_MAX_PATH_HOPS]; +} __attribute__ ((packed)); + +#define IB_SMP_DIRECTION cpu_to_be16(0x8000) + +/* Subnet management attributes */ +#define IB_SMP_ATTR_NOTICE cpu_to_be16(0x0002) +#define IB_SMP_ATTR_NODE_DESC cpu_to_be16(0x0010) +#define IB_SMP_ATTR_NODE_INFO cpu_to_be16(0x0011) +#define IB_SMP_ATTR_SWITCH_INFO cpu_to_be16(0x0012) +#define IB_SMP_ATTR_GUID_INFO cpu_to_be16(0x0014) +#define IB_SMP_ATTR_PORT_INFO cpu_to_be16(0x0015) +#define IB_SMP_ATTR_PKEY_TABLE cpu_to_be16(0x0016) +#define IB_SMP_ATTR_SL_TO_VL_TABLE cpu_to_be16(0x0017) +#define IB_SMP_ATTR_VL_ARB_TABLE cpu_to_be16(0x0018) +#define IB_SMP_ATTR_LINEAR_FORWARD_TABLE cpu_to_be16(0x0019) +#define IB_SMP_ATTR_RANDOM_FORWARD_TABLE cpu_to_be16(0x001A) +#define IB_SMP_ATTR_MCAST_FORWARD_TABLE cpu_to_be16(0x001B) +#define IB_SMP_ATTR_SM_INFO cpu_to_be16(0x0020) +#define IB_SMP_ATTR_VENDOR_DIAG cpu_to_be16(0x0030) +#define IB_SMP_ATTR_LED_INFO cpu_to_be16(0x0031) +#define IB_SMP_ATTR_VENDOR_MASK cpu_to_be16(0xFF00) + +struct ib_port_info { + __be64 mkey; + __be64 gid_prefix; + __be16 lid; + __be16 sm_lid; + __be32 cap_mask; + __be16 diag_code; + __be16 mkey_lease_period; + u8 local_port_num; + u8 link_width_enabled; + u8 link_width_supported; + u8 link_width_active; + u8 linkspeed_portstate; /* 4 bits, 4 bits */ + u8 portphysstate_linkdown; /* 4 bits, 4 bits */ + u8 mkeyprot_resv_lmc; /* 2 bits, 3, 3 */ + u8 linkspeedactive_enabled; /* 4 bits, 4 bits */ + u8 neighbormtu_mastersmsl; /* 4 bits, 4 bits */ + u8 vlcap_inittype; /* 4 bits, 4 bits */ + u8 vl_high_limit; + u8 vl_arb_high_cap; + u8 vl_arb_low_cap; + u8 inittypereply_mtucap; /* 4 bits, 4 bits */ + u8 vlstallcnt_hoqlife; /* 3 bits, 5 bits */ + u8 operationalvl_pei_peo_fpi_fpo; /* 4 bits, 1, 1, 1, 1 */ + __be16 mkey_violations; + __be16 pkey_violations; + __be16 qkey_violations; + u8 guid_cap; + u8 clientrereg_resv_subnetto; /* 1 bit, 2 bits, 5 */ + u8 resv_resptimevalue; /* 3 bits, 5 bits */ + u8 localphyerrors_overrunerrors; /* 4 bits, 4 bits */ + __be16 max_credit_hint; + u8 resv; + u8 link_roundtrip_latency[3]; +}; + +static inline u8 +ib_get_smp_direction(struct ib_smp *smp) +{ + return ((smp->status & IB_SMP_DIRECTION) == IB_SMP_DIRECTION); +} + +#endif /* IB_SMI_H */ diff --git a/sys/ofed/include/rdma/ib_umem.h b/sys/ofed/include/rdma/ib_umem.h new file mode 100644 index 000000000000..afa09f9337f4 --- /dev/null +++ b/sys/ofed/include/rdma/ib_umem.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2007 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IB_UMEM_H +#define IB_UMEM_H + +#include +#include +#include +#include + +struct ib_ucontext; + +struct ib_umem { + struct ib_ucontext *context; + size_t length; + int offset; + int page_size; + int writable; + int hugetlb; + struct list_head chunk_list; +#ifdef __linux__ + struct work_struct work; + struct mm_struct *mm; +#else + unsigned long start; +#endif + unsigned long diff; +}; + +struct ib_umem_chunk { + struct list_head list; + int nents; + int nmap; + struct dma_attrs attrs; + struct scatterlist page_list[0]; +}; + +struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, + size_t size, int access, int dmasync); +void ib_umem_release(struct ib_umem *umem); +int ib_umem_page_count(struct ib_umem *umem); + +#endif /* IB_UMEM_H */ diff --git a/sys/ofed/include/rdma/ib_user_cm.h b/sys/ofed/include/rdma/ib_user_cm.h new file mode 100644 index 000000000000..bd3d380781e0 --- /dev/null +++ b/sys/ofed/include/rdma/ib_user_cm.h @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IB_USER_CM_H +#define IB_USER_CM_H + +#include + +#define IB_USER_CM_ABI_VERSION 5 + +enum { + IB_USER_CM_CMD_CREATE_ID, + IB_USER_CM_CMD_DESTROY_ID, + IB_USER_CM_CMD_ATTR_ID, + + IB_USER_CM_CMD_LISTEN, + IB_USER_CM_CMD_NOTIFY, + + IB_USER_CM_CMD_SEND_REQ, + IB_USER_CM_CMD_SEND_REP, + IB_USER_CM_CMD_SEND_RTU, + IB_USER_CM_CMD_SEND_DREQ, + IB_USER_CM_CMD_SEND_DREP, + IB_USER_CM_CMD_SEND_REJ, + IB_USER_CM_CMD_SEND_MRA, + IB_USER_CM_CMD_SEND_LAP, + IB_USER_CM_CMD_SEND_APR, + IB_USER_CM_CMD_SEND_SIDR_REQ, + IB_USER_CM_CMD_SEND_SIDR_REP, + + IB_USER_CM_CMD_EVENT, + IB_USER_CM_CMD_INIT_QP_ATTR, +}; +/* + * command ABI structures. + */ +struct ib_ucm_cmd_hdr { + __u32 cmd; + __u16 in; + __u16 out; +}; + +struct ib_ucm_create_id { + __u64 uid; + __u64 response; +}; + +struct ib_ucm_create_id_resp { + __u32 id; +}; + +struct ib_ucm_destroy_id { + __u64 response; + __u32 id; + __u32 reserved; +}; + +struct ib_ucm_destroy_id_resp { + __u32 events_reported; +}; + +struct ib_ucm_attr_id { + __u64 response; + __u32 id; + __u32 reserved; +}; + +struct ib_ucm_attr_id_resp { + __be64 service_id; + __be64 service_mask; + __be32 local_id; + __be32 remote_id; +}; + +struct ib_ucm_init_qp_attr { + __u64 response; + __u32 id; + __u32 qp_state; +}; + +struct ib_ucm_listen { + __be64 service_id; + __be64 service_mask; + __u32 id; + __u32 reserved; +}; + +struct ib_ucm_notify { + __u32 id; + __u32 event; +}; + +struct ib_ucm_private_data { + __u64 data; + __u32 id; + __u8 len; + __u8 reserved[3]; +}; + +struct ib_ucm_req { + __u32 id; + __u32 qpn; + __u32 qp_type; + __u32 psn; + __be64 sid; + __u64 data; + __u64 primary_path; + __u64 alternate_path; + __u8 len; + __u8 peer_to_peer; + __u8 responder_resources; + __u8 initiator_depth; + __u8 remote_cm_response_timeout; + __u8 flow_control; + __u8 local_cm_response_timeout; + __u8 retry_count; + __u8 rnr_retry_count; + __u8 max_cm_retries; + __u8 srq; + __u8 reserved[5]; +}; + +struct ib_ucm_rep { + __u64 uid; + __u64 data; + __u32 id; + __u32 qpn; + __u32 psn; + __u8 len; + __u8 responder_resources; + __u8 initiator_depth; + __u8 target_ack_delay; + __u8 failover_accepted; + __u8 flow_control; + __u8 rnr_retry_count; + __u8 srq; + __u8 reserved[4]; +}; + +struct ib_ucm_info { + __u32 id; + __u32 status; + __u64 info; + __u64 data; + __u8 info_len; + __u8 data_len; + __u8 reserved[6]; +}; + +struct ib_ucm_mra { + __u64 data; + __u32 id; + __u8 len; + __u8 timeout; + __u8 reserved[2]; +}; + +struct ib_ucm_lap { + __u64 path; + __u64 data; + __u32 id; + __u8 len; + __u8 reserved[3]; +}; + +struct ib_ucm_sidr_req { + __u32 id; + __u32 timeout; + __be64 sid; + __u64 data; + __u64 path; + __u16 reserved_pkey; + __u8 len; + __u8 max_cm_retries; + __u8 reserved[4]; +}; + +struct ib_ucm_sidr_rep { + __u32 id; + __u32 qpn; + __u32 qkey; + __u32 status; + __u64 info; + __u64 data; + __u8 info_len; + __u8 data_len; + __u8 reserved[6]; +}; +/* + * event notification ABI structures. + */ +struct ib_ucm_event_get { + __u64 response; + __u64 data; + __u64 info; + __u8 data_len; + __u8 info_len; + __u8 reserved[6]; +}; + +struct ib_ucm_req_event_resp { + struct ib_user_path_rec primary_path; + struct ib_user_path_rec alternate_path; + __be64 remote_ca_guid; + __u32 remote_qkey; + __u32 remote_qpn; + __u32 qp_type; + __u32 starting_psn; + __u8 responder_resources; + __u8 initiator_depth; + __u8 local_cm_response_timeout; + __u8 flow_control; + __u8 remote_cm_response_timeout; + __u8 retry_count; + __u8 rnr_retry_count; + __u8 srq; + __u8 port; + __u8 reserved[7]; +}; + +struct ib_ucm_rep_event_resp { + __be64 remote_ca_guid; + __u32 remote_qkey; + __u32 remote_qpn; + __u32 starting_psn; + __u8 responder_resources; + __u8 initiator_depth; + __u8 target_ack_delay; + __u8 failover_accepted; + __u8 flow_control; + __u8 rnr_retry_count; + __u8 srq; + __u8 reserved[5]; +}; + +struct ib_ucm_rej_event_resp { + __u32 reason; + /* ari in ib_ucm_event_get info field. */ +}; + +struct ib_ucm_mra_event_resp { + __u8 timeout; + __u8 reserved[3]; +}; + +struct ib_ucm_lap_event_resp { + struct ib_user_path_rec path; +}; + +struct ib_ucm_apr_event_resp { + __u32 status; + /* apr info in ib_ucm_event_get info field. */ +}; + +struct ib_ucm_sidr_req_event_resp { + __u16 pkey; + __u8 port; + __u8 reserved; +}; + +struct ib_ucm_sidr_rep_event_resp { + __u32 status; + __u32 qkey; + __u32 qpn; + /* info in ib_ucm_event_get info field. */ +}; + +#define IB_UCM_PRES_DATA 0x01 +#define IB_UCM_PRES_INFO 0x02 +#define IB_UCM_PRES_PRIMARY 0x04 +#define IB_UCM_PRES_ALTERNATE 0x08 + +struct ib_ucm_event_resp { + __u64 uid; + __u32 id; + __u32 event; + __u32 present; + __u32 reserved; + union { + struct ib_ucm_req_event_resp req_resp; + struct ib_ucm_rep_event_resp rep_resp; + struct ib_ucm_rej_event_resp rej_resp; + struct ib_ucm_mra_event_resp mra_resp; + struct ib_ucm_lap_event_resp lap_resp; + struct ib_ucm_apr_event_resp apr_resp; + + struct ib_ucm_sidr_req_event_resp sidr_req_resp; + struct ib_ucm_sidr_rep_event_resp sidr_rep_resp; + + __u32 send_status; + } u; +}; + +#endif /* IB_USER_CM_H */ diff --git a/sys/ofed/include/rdma/ib_user_mad.h b/sys/ofed/include/rdma/ib_user_mad.h new file mode 100644 index 000000000000..3595ae26c908 --- /dev/null +++ b/sys/ofed/include/rdma/ib_user_mad.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2004 Topspin Communications. All rights reserved. + * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IB_USER_MAD_H +#define IB_USER_MAD_H + +#include +#include + +/* + * Increment this value if any changes that break userspace ABI + * compatibility are made. + */ +#define IB_USER_MAD_ABI_VERSION 5 + +/* + * Make sure that all structs defined in this file remain laid out so + * that they pack the same way on 32-bit and 64-bit architectures (to + * avoid incompatibility between 32-bit userspace and 64-bit kernels). + */ + +/** + * ib_user_mad_hdr_old - Old version of MAD packet header without pkey_index + * @id - ID of agent MAD received with/to be sent with + * @status - 0 on successful receive, ETIMEDOUT if no response + * received (transaction ID in data[] will be set to TID of original + * request) (ignored on send) + * @timeout_ms - Milliseconds to wait for response (unset on receive) + * @retries - Number of automatic retries to attempt + * @qpn - Remote QP number received from/to be sent to + * @qkey - Remote Q_Key to be sent with (unset on receive) + * @lid - Remote lid received from/to be sent to + * @sl - Service level received with/to be sent with + * @path_bits - Local path bits received with/to be sent with + * @grh_present - If set, GRH was received/should be sent + * @gid_index - Local GID index to send with (unset on receive) + * @hop_limit - Hop limit in GRH + * @traffic_class - Traffic class in GRH + * @gid - Remote GID in GRH + * @flow_label - Flow label in GRH + */ +struct ib_user_mad_hdr_old { + __u32 id; + __u32 status; + __u32 timeout_ms; + __u32 retries; + __u32 length; + __be32 qpn; + __be32 qkey; + __be16 lid; + __u8 sl; + __u8 path_bits; + __u8 grh_present; + __u8 gid_index; + __u8 hop_limit; + __u8 traffic_class; + __u8 gid[16]; + __be32 flow_label; +}; + +/** + * ib_user_mad_hdr - MAD packet header + * This layout allows specifying/receiving the P_Key index. To use + * this capability, an application must call the + * IB_USER_MAD_ENABLE_PKEY ioctl on the user MAD file handle before + * any other actions with the file handle. + * @id - ID of agent MAD received with/to be sent with + * @status - 0 on successful receive, ETIMEDOUT if no response + * received (transaction ID in data[] will be set to TID of original + * request) (ignored on send) + * @timeout_ms - Milliseconds to wait for response (unset on receive) + * @retries - Number of automatic retries to attempt + * @qpn - Remote QP number received from/to be sent to + * @qkey - Remote Q_Key to be sent with (unset on receive) + * @lid - Remote lid received from/to be sent to + * @sl - Service level received with/to be sent with + * @path_bits - Local path bits received with/to be sent with + * @grh_present - If set, GRH was received/should be sent + * @gid_index - Local GID index to send with (unset on receive) + * @hop_limit - Hop limit in GRH + * @traffic_class - Traffic class in GRH + * @gid - Remote GID in GRH + * @flow_label - Flow label in GRH + * @pkey_index - P_Key index + */ +struct ib_user_mad_hdr { + __u32 id; + __u32 status; + __u32 timeout_ms; + __u32 retries; + __u32 length; + __be32 qpn; + __be32 qkey; + __be16 lid; + __u8 sl; + __u8 path_bits; + __u8 grh_present; + __u8 gid_index; + __u8 hop_limit; + __u8 traffic_class; + __u8 gid[16]; + __be32 flow_label; + __u16 pkey_index; + __u8 reserved[6]; +}; + +/** + * ib_user_mad - MAD packet + * @hdr - MAD packet header + * @data - Contents of MAD + * + */ +struct ib_user_mad { + struct ib_user_mad_hdr hdr; + __u64 data[0]; +}; + +/* + * Earlier versions of this interface definition declared the + * method_mask[] member as an array of __u32 but treated it as a + * bitmap made up of longs in the kernel. This ambiguity meant that + * 32-bit big-endian applications that can run on both 32-bit and + * 64-bit kernels had no consistent ABI to rely on, and 64-bit + * big-endian applications that treated method_mask as being made up + * of 32-bit words would have their bitmap misinterpreted. + * + * To clear up this confusion, we change the declaration of + * method_mask[] to use unsigned long and handle the conversion from + * 32-bit userspace to 64-bit kernel for big-endian systems in the + * compat_ioctl method. Unfortunately, to keep the structure layout + * the same, we need the method_mask[] array to be aligned only to 4 + * bytes even when long is 64 bits, which forces us into this ugly + * typedef. + */ +typedef unsigned long __attribute__((aligned(4))) packed_ulong; +#define IB_USER_MAD_LONGS_PER_METHOD_MASK (128 / (8 * sizeof (long))) + +/** + * ib_user_mad_reg_req - MAD registration request + * @id - Set by the kernel; used to identify agent in future requests. + * @qpn - Queue pair number; must be 0 or 1. + * @method_mask - The caller will receive unsolicited MADs for any method + * where @method_mask = 1. + * @mgmt_class - Indicates which management class of MADs should be receive + * by the caller. This field is only required if the user wishes to + * receive unsolicited MADs, otherwise it should be 0. + * @mgmt_class_version - Indicates which version of MADs for the given + * management class to receive. + * @oui: Indicates IEEE OUI when mgmt_class is a vendor class + * in the range from 0x30 to 0x4f. Otherwise not used. + * @rmpp_version: If set, indicates the RMPP version used. + * + */ +struct ib_user_mad_reg_req { + __u32 id; + packed_ulong method_mask[IB_USER_MAD_LONGS_PER_METHOD_MASK]; + __u8 qpn; + __u8 mgmt_class; + __u8 mgmt_class_version; + __u8 oui[3]; + __u8 rmpp_version; +}; + +#define IB_IOCTL_MAGIC 0x1b + +#define IB_USER_MAD_REGISTER_AGENT _IO(IB_IOCTL_MAGIC, 1) + +#define IB_USER_MAD_UNREGISTER_AGENT _IO(IB_IOCTL_MAGIC, 2) + +#define IB_USER_MAD_ENABLE_PKEY _IO(IB_IOCTL_MAGIC, 3) + +#endif /* IB_USER_MAD_H */ diff --git a/sys/ofed/include/rdma/ib_user_sa.h b/sys/ofed/include/rdma/ib_user_sa.h new file mode 100644 index 000000000000..cfc7c9ba781e --- /dev/null +++ b/sys/ofed/include/rdma/ib_user_sa.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IB_USER_SA_H +#define IB_USER_SA_H + +#include + +enum { + IB_PATH_GMP = 1, + IB_PATH_PRIMARY = (1<<1), + IB_PATH_ALTERNATE = (1<<2), + IB_PATH_OUTBOUND = (1<<3), + IB_PATH_INBOUND = (1<<4), + IB_PATH_INBOUND_REVERSE = (1<<5), + IB_PATH_BIDIRECTIONAL = IB_PATH_OUTBOUND | IB_PATH_INBOUND_REVERSE +}; + +struct ib_path_rec_data { + __u32 flags; + __u32 reserved; + __u32 path_rec[16]; +}; + +struct ib_user_path_rec { + __u8 dgid[16]; + __u8 sgid[16]; + __be16 dlid; + __be16 slid; + __u32 raw_traffic; + __be32 flow_label; + __u32 reversible; + __u32 mtu; + __be16 pkey; + __u8 hop_limit; + __u8 traffic_class; + __u8 numb_path; + __u8 sl; + __u8 mtu_selector; + __u8 rate_selector; + __u8 rate; + __u8 packet_life_time_selector; + __u8 packet_life_time; + __u8 preference; +}; + +#endif /* IB_USER_SA_H */ diff --git a/sys/ofed/include/rdma/ib_user_verbs.h b/sys/ofed/include/rdma/ib_user_verbs.h new file mode 100644 index 000000000000..b2721c74d71a --- /dev/null +++ b/sys/ofed/include/rdma/ib_user_verbs.h @@ -0,0 +1,801 @@ +/* + * Copyright (c) 2005 Topspin Communications. All rights reserved. + * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. + * Copyright (c) 2005 PathScale, Inc. All rights reserved. + * Copyright (c) 2006 Mellanox Technologies. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IB_USER_VERBS_H +#define IB_USER_VERBS_H + +#include + +/* + * Increment this value if any changes that break userspace ABI + * compatibility are made. + */ +#define IB_USER_VERBS_ABI_VERSION 6 + +enum { + IB_USER_VERBS_CMD_GET_CONTEXT, + IB_USER_VERBS_CMD_QUERY_DEVICE, + IB_USER_VERBS_CMD_QUERY_PORT, + IB_USER_VERBS_CMD_ALLOC_PD, + IB_USER_VERBS_CMD_DEALLOC_PD, + IB_USER_VERBS_CMD_CREATE_AH, + IB_USER_VERBS_CMD_MODIFY_AH, + IB_USER_VERBS_CMD_QUERY_AH, + IB_USER_VERBS_CMD_DESTROY_AH, + IB_USER_VERBS_CMD_REG_MR, + IB_USER_VERBS_CMD_REG_SMR, + IB_USER_VERBS_CMD_REREG_MR, + IB_USER_VERBS_CMD_QUERY_MR, + IB_USER_VERBS_CMD_DEREG_MR, + IB_USER_VERBS_CMD_ALLOC_MW, + IB_USER_VERBS_CMD_BIND_MW, + IB_USER_VERBS_CMD_DEALLOC_MW, + IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL, + IB_USER_VERBS_CMD_CREATE_CQ, + IB_USER_VERBS_CMD_RESIZE_CQ, + IB_USER_VERBS_CMD_DESTROY_CQ, + IB_USER_VERBS_CMD_POLL_CQ, + IB_USER_VERBS_CMD_PEEK_CQ, + IB_USER_VERBS_CMD_REQ_NOTIFY_CQ, + IB_USER_VERBS_CMD_CREATE_QP, + IB_USER_VERBS_CMD_QUERY_QP, + IB_USER_VERBS_CMD_MODIFY_QP, + IB_USER_VERBS_CMD_DESTROY_QP, + IB_USER_VERBS_CMD_POST_SEND, + IB_USER_VERBS_CMD_POST_RECV, + IB_USER_VERBS_CMD_ATTACH_MCAST, + IB_USER_VERBS_CMD_DETACH_MCAST, + IB_USER_VERBS_CMD_CREATE_SRQ, + IB_USER_VERBS_CMD_MODIFY_SRQ, + IB_USER_VERBS_CMD_QUERY_SRQ, + IB_USER_VERBS_CMD_DESTROY_SRQ, + IB_USER_VERBS_CMD_POST_SRQ_RECV, + IB_USER_VERBS_CMD_CREATE_XRC_SRQ, + IB_USER_VERBS_CMD_OPEN_XRC_DOMAIN, + IB_USER_VERBS_CMD_CLOSE_XRC_DOMAIN, + IB_USER_VERBS_CMD_CREATE_XRC_RCV_QP, + IB_USER_VERBS_CMD_MODIFY_XRC_RCV_QP, + IB_USER_VERBS_CMD_QUERY_XRC_RCV_QP, + IB_USER_VERBS_CMD_REG_XRC_RCV_QP, + IB_USER_VERBS_CMD_UNREG_XRC_RCV_QP, +}; + +/* + * Make sure that all structs defined in this file remain laid out so + * that they pack the same way on 32-bit and 64-bit architectures (to + * avoid incompatibility between 32-bit userspace and 64-bit kernels). + * Specifically: + * - Do not use pointer types -- pass pointers in __u64 instead. + * - Make sure that any structure larger than 4 bytes is padded to a + * multiple of 8 bytes. Otherwise the structure size will be + * different between 32-bit and 64-bit architectures. + */ + +struct ib_uverbs_async_event_desc { + __u64 element; + __u32 event_type; /* enum ib_event_type */ + __u32 reserved; +}; + +struct ib_uverbs_comp_event_desc { + __u64 cq_handle; +}; + +/* + * All commands from userspace should start with a __u32 command field + * followed by __u16 in_words and out_words fields (which give the + * length of the command block and response buffer if any in 32-bit + * words). The kernel driver will read these fields first and read + * the rest of the command struct based on these value. + */ + +struct ib_uverbs_cmd_hdr { + __u32 command; + __u16 in_words; + __u16 out_words; +}; + +struct ib_uverbs_get_context { + __u64 response; + __u64 driver_data[0]; +}; + +struct ib_uverbs_get_context_resp { + __u32 async_fd; + __u32 num_comp_vectors; +}; + +struct ib_uverbs_query_device { + __u64 response; + __u64 driver_data[0]; +}; + +struct ib_uverbs_query_device_resp { + __u64 fw_ver; + __be64 node_guid; + __be64 sys_image_guid; + __u64 max_mr_size; + __u64 page_size_cap; + __u32 vendor_id; + __u32 vendor_part_id; + __u32 hw_ver; + __u32 max_qp; + __u32 max_qp_wr; + __u32 device_cap_flags; + __u32 max_sge; + __u32 max_sge_rd; + __u32 max_cq; + __u32 max_cqe; + __u32 max_mr; + __u32 max_pd; + __u32 max_qp_rd_atom; + __u32 max_ee_rd_atom; + __u32 max_res_rd_atom; + __u32 max_qp_init_rd_atom; + __u32 max_ee_init_rd_atom; + __u32 atomic_cap; + __u32 max_ee; + __u32 max_rdd; + __u32 max_mw; + __u32 max_raw_ipv6_qp; + __u32 max_raw_ethy_qp; + __u32 max_mcast_grp; + __u32 max_mcast_qp_attach; + __u32 max_total_mcast_qp_attach; + __u32 max_ah; + __u32 max_fmr; + __u32 max_map_per_fmr; + __u32 max_srq; + __u32 max_srq_wr; + __u32 max_srq_sge; + __u16 max_pkeys; + __u8 local_ca_ack_delay; + __u8 phys_port_cnt; + __u8 reserved[4]; +}; + +struct ib_uverbs_query_port { + __u64 response; + __u8 port_num; + __u8 reserved[7]; + __u64 driver_data[0]; +}; + +struct ib_uverbs_query_port_resp { + __u32 port_cap_flags; + __u32 max_msg_sz; + __u32 bad_pkey_cntr; + __u32 qkey_viol_cntr; + __u32 gid_tbl_len; + __u16 pkey_tbl_len; + __u16 lid; + __u16 sm_lid; + __u8 state; + __u8 max_mtu; + __u8 active_mtu; + __u8 lmc; + __u8 max_vl_num; + __u8 sm_sl; + __u8 subnet_timeout; + __u8 init_type_reply; + __u8 active_width; + __u8 active_speed; + __u8 phys_state; + __u8 link_layer; + __u8 reserved[2]; +}; + +struct ib_uverbs_alloc_pd { + __u64 response; + __u64 driver_data[0]; +}; + +struct ib_uverbs_alloc_pd_resp { + __u32 pd_handle; +}; + +struct ib_uverbs_dealloc_pd { + __u32 pd_handle; +}; + +struct ib_uverbs_reg_mr { + __u64 response; + __u64 start; + __u64 length; + __u64 hca_va; + __u32 pd_handle; + __u32 access_flags; + __u64 driver_data[0]; +}; + +struct ib_uverbs_reg_mr_resp { + __u32 mr_handle; + __u32 lkey; + __u32 rkey; +}; + +struct ib_uverbs_dereg_mr { + __u32 mr_handle; +}; + +struct ib_uverbs_create_comp_channel { + __u64 response; +}; + +struct ib_uverbs_create_comp_channel_resp { + __u32 fd; +}; + +struct ib_uverbs_create_cq { + __u64 response; + __u64 user_handle; + __u32 cqe; + __u32 comp_vector; + __s32 comp_channel; + __u32 reserved; + __u64 driver_data[0]; +}; + +struct ib_uverbs_create_cq_resp { + __u32 cq_handle; + __u32 cqe; +}; + +struct ib_uverbs_resize_cq { + __u64 response; + __u32 cq_handle; + __u32 cqe; + __u64 driver_data[0]; +}; + +struct ib_uverbs_resize_cq_resp { + __u32 cqe; + __u32 reserved; + __u64 driver_data[0]; +}; + +struct ib_uverbs_poll_cq { + __u64 response; + __u32 cq_handle; + __u32 ne; +}; + +struct ib_uverbs_wc { + __u64 wr_id; + __u32 status; + __u32 opcode; + __u32 vendor_err; + __u32 byte_len; + union { + __u32 imm_data; + __u32 invalidate_rkey; + } ex; + __u32 qp_num; + __u32 src_qp; + __u32 wc_flags; + __u16 pkey_index; + __u16 slid; + __u8 sl; + __u8 dlid_path_bits; + __u8 port_num; + __u8 reserved; +}; + +struct ib_uverbs_poll_cq_resp { + __u32 count; + __u32 reserved; + struct ib_uverbs_wc wc[0]; +}; + +struct ib_uverbs_req_notify_cq { + __u32 cq_handle; + __u32 solicited_only; +}; + +struct ib_uverbs_destroy_cq { + __u64 response; + __u32 cq_handle; + __u32 reserved; +}; + +struct ib_uverbs_destroy_cq_resp { + __u32 comp_events_reported; + __u32 async_events_reported; +}; + +struct ib_uverbs_global_route { + __u8 dgid[16]; + __u32 flow_label; + __u8 sgid_index; + __u8 hop_limit; + __u8 traffic_class; + __u8 reserved; +}; + +struct ib_uverbs_ah_attr { + struct ib_uverbs_global_route grh; + __u16 dlid; + __u8 sl; + __u8 src_path_bits; + __u8 static_rate; + __u8 is_global; + __u8 port_num; + __u8 reserved; +}; + +struct ib_uverbs_qp_attr { + __u32 qp_attr_mask; + __u32 qp_state; + __u32 cur_qp_state; + __u32 path_mtu; + __u32 path_mig_state; + __u32 qkey; + __u32 rq_psn; + __u32 sq_psn; + __u32 dest_qp_num; + __u32 qp_access_flags; + + struct ib_uverbs_ah_attr ah_attr; + struct ib_uverbs_ah_attr alt_ah_attr; + + /* ib_qp_cap */ + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_send_sge; + __u32 max_recv_sge; + __u32 max_inline_data; + + __u16 pkey_index; + __u16 alt_pkey_index; + __u8 en_sqd_async_notify; + __u8 sq_draining; + __u8 max_rd_atomic; + __u8 max_dest_rd_atomic; + __u8 min_rnr_timer; + __u8 port_num; + __u8 timeout; + __u8 retry_cnt; + __u8 rnr_retry; + __u8 alt_port_num; + __u8 alt_timeout; + __u8 reserved[5]; +}; + +struct ib_uverbs_create_qp { + __u64 response; + __u64 user_handle; + __u32 pd_handle; + __u32 send_cq_handle; + __u32 recv_cq_handle; + __u32 srq_handle; + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_send_sge; + __u32 max_recv_sge; + __u32 max_inline_data; + __u8 sq_sig_all; + __u8 qp_type; + __u8 is_srq; + __u8 reserved; + __u64 driver_data[0]; +}; + +struct ib_uverbs_create_qp_resp { + __u32 qp_handle; + __u32 qpn; + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_send_sge; + __u32 max_recv_sge; + __u32 max_inline_data; + __u32 reserved; +}; + +/* + * This struct needs to remain a multiple of 8 bytes to keep the + * alignment of the modify QP parameters. + */ +struct ib_uverbs_qp_dest { + __u8 dgid[16]; + __u32 flow_label; + __u16 dlid; + __u16 reserved; + __u8 sgid_index; + __u8 hop_limit; + __u8 traffic_class; + __u8 sl; + __u8 src_path_bits; + __u8 static_rate; + __u8 is_global; + __u8 port_num; +}; + +struct ib_uverbs_query_qp { + __u64 response; + __u32 qp_handle; + __u32 attr_mask; + __u64 driver_data[0]; +}; + +struct ib_uverbs_query_qp_resp { + struct ib_uverbs_qp_dest dest; + struct ib_uverbs_qp_dest alt_dest; + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_send_sge; + __u32 max_recv_sge; + __u32 max_inline_data; + __u32 qkey; + __u32 rq_psn; + __u32 sq_psn; + __u32 dest_qp_num; + __u32 qp_access_flags; + __u16 pkey_index; + __u16 alt_pkey_index; + __u8 qp_state; + __u8 cur_qp_state; + __u8 path_mtu; + __u8 path_mig_state; + __u8 sq_draining; + __u8 max_rd_atomic; + __u8 max_dest_rd_atomic; + __u8 min_rnr_timer; + __u8 port_num; + __u8 timeout; + __u8 retry_cnt; + __u8 rnr_retry; + __u8 alt_port_num; + __u8 alt_timeout; + __u8 sq_sig_all; + __u8 reserved[5]; + __u64 driver_data[0]; +}; + +struct ib_uverbs_modify_qp { + struct ib_uverbs_qp_dest dest; + struct ib_uverbs_qp_dest alt_dest; + __u32 qp_handle; + __u32 attr_mask; + __u32 qkey; + __u32 rq_psn; + __u32 sq_psn; + __u32 dest_qp_num; + __u32 qp_access_flags; + __u16 pkey_index; + __u16 alt_pkey_index; + __u8 qp_state; + __u8 cur_qp_state; + __u8 path_mtu; + __u8 path_mig_state; + __u8 en_sqd_async_notify; + __u8 max_rd_atomic; + __u8 max_dest_rd_atomic; + __u8 min_rnr_timer; + __u8 port_num; + __u8 timeout; + __u8 retry_cnt; + __u8 rnr_retry; + __u8 alt_port_num; + __u8 alt_timeout; + __u8 reserved[2]; + __u64 driver_data[0]; +}; + +struct ib_uverbs_modify_qp_resp { +}; + +struct ib_uverbs_destroy_qp { + __u64 response; + __u32 qp_handle; + __u32 reserved; +}; + +struct ib_uverbs_destroy_qp_resp { + __u32 events_reported; +}; + +/* + * The ib_uverbs_sge structure isn't used anywhere, since we assume + * the ib_sge structure is packed the same way on 32-bit and 64-bit + * architectures in both kernel and user space. It's just here to + * document the ABI. + */ +struct ib_uverbs_sge { + __u64 addr; + __u32 length; + __u32 lkey; +}; + +struct ib_uverbs_send_wr { + __u64 wr_id; + __u32 num_sge; + __u32 opcode; + __u32 send_flags; + union { + __u32 imm_data; + __u32 invalidate_rkey; + } ex; + union { + struct { + __u64 remote_addr; + __u32 rkey; + __u32 reserved; + } rdma; + struct { + __u64 remote_addr; + __u64 compare_add; + __u64 swap; + __u32 rkey; + __u32 reserved; + } atomic; + struct { + __u32 ah; + __u32 remote_qpn; + __u32 remote_qkey; + __u32 reserved; + } ud; + } wr; +}; + +struct ib_uverbs_post_send { + __u64 response; + __u32 qp_handle; + __u32 wr_count; + __u32 sge_count; + __u32 wqe_size; + struct ib_uverbs_send_wr send_wr[0]; +}; + +struct ib_uverbs_post_send_resp { + __u32 bad_wr; +}; + +struct ib_uverbs_recv_wr { + __u64 wr_id; + __u32 num_sge; + __u32 reserved; +}; + +struct ib_uverbs_post_recv { + __u64 response; + __u32 qp_handle; + __u32 wr_count; + __u32 sge_count; + __u32 wqe_size; + struct ib_uverbs_recv_wr recv_wr[0]; +}; + +struct ib_uverbs_post_recv_resp { + __u32 bad_wr; +}; + +struct ib_uverbs_post_srq_recv { + __u64 response; + __u32 srq_handle; + __u32 wr_count; + __u32 sge_count; + __u32 wqe_size; + struct ib_uverbs_recv_wr recv[0]; +}; + +struct ib_uverbs_post_srq_recv_resp { + __u32 bad_wr; +}; + +struct ib_uverbs_create_ah { + __u64 response; + __u64 user_handle; + __u32 pd_handle; + __u32 reserved; + struct ib_uverbs_ah_attr attr; +}; + +struct ib_uverbs_create_ah_resp { + __u32 ah_handle; +}; + +struct ib_uverbs_destroy_ah { + __u32 ah_handle; +}; + +struct ib_uverbs_attach_mcast { + __u8 gid[16]; + __u32 qp_handle; + __u16 mlid; + __u16 reserved; + __u64 driver_data[0]; +}; + +struct ib_uverbs_detach_mcast { + __u8 gid[16]; + __u32 qp_handle; + __u16 mlid; + __u16 reserved; + __u64 driver_data[0]; +}; + +struct ib_uverbs_create_srq { + __u64 response; + __u64 user_handle; + __u32 pd_handle; + __u32 max_wr; + __u32 max_sge; + __u32 srq_limit; + __u64 driver_data[0]; +}; + +struct ib_uverbs_create_xrc_srq { + __u64 response; + __u64 user_handle; + __u32 pd_handle; + __u32 max_wr; + __u32 max_sge; + __u32 srq_limit; + __u32 xrcd_handle; + __u32 xrc_cq; + __u64 driver_data[0]; +}; + +struct ib_uverbs_create_srq_resp { + __u32 srq_handle; + __u32 max_wr; + __u32 max_sge; + __u32 reserved; +}; + +struct ib_uverbs_modify_srq { + __u32 srq_handle; + __u32 attr_mask; + __u32 max_wr; + __u32 srq_limit; + __u64 driver_data[0]; +}; + +struct ib_uverbs_query_srq { + __u64 response; + __u32 srq_handle; + __u32 reserved; + __u64 driver_data[0]; +}; + +struct ib_uverbs_query_srq_resp { + __u32 max_wr; + __u32 max_sge; + __u32 srq_limit; + __u32 reserved; +}; + +struct ib_uverbs_destroy_srq { + __u64 response; + __u32 srq_handle; + __u32 reserved; +}; + +struct ib_uverbs_destroy_srq_resp { + __u32 events_reported; +}; + +struct ib_uverbs_open_xrc_domain { + __u64 response; + __u32 fd; + __u32 oflags; + __u64 driver_data[0]; +}; + +struct ib_uverbs_open_xrc_domain_resp { + __u32 xrcd_handle; +}; + +struct ib_uverbs_close_xrc_domain { + __u64 response; + __u32 xrcd_handle; + __u32 reserved; + __u64 driver_data[0]; +}; + +struct ib_uverbs_create_xrc_rcv_qp { + __u64 response; + __u64 user_handle; + __u32 xrc_domain_handle; + __u32 max_send_wr; + __u32 max_recv_wr; + __u32 max_send_sge; + __u32 max_recv_sge; + __u32 max_inline_data; + __u8 sq_sig_all; + __u8 qp_type; + __u8 reserved[6]; + __u64 driver_data[0]; +}; + +struct ib_uverbs_create_xrc_rcv_qp_resp { + __u32 qpn; + __u32 reserved; +}; + +struct ib_uverbs_modify_xrc_rcv_qp { + __u32 xrc_domain_handle; + __u32 qp_num; + struct ib_uverbs_qp_dest dest; + struct ib_uverbs_qp_dest alt_dest; + __u32 attr_mask; + __u32 qkey; + __u32 rq_psn; + __u32 sq_psn; + __u32 dest_qp_num; + __u32 qp_access_flags; + __u16 pkey_index; + __u16 alt_pkey_index; + __u8 qp_state; + __u8 cur_qp_state; + __u8 path_mtu; + __u8 path_mig_state; + __u8 en_sqd_async_notify; + __u8 max_rd_atomic; + __u8 max_dest_rd_atomic; + __u8 min_rnr_timer; + __u8 port_num; + __u8 timeout; + __u8 retry_cnt; + __u8 rnr_retry; + __u8 alt_port_num; + __u8 alt_timeout; + __u8 reserved[6]; + __u64 driver_data[0]; +}; + +struct ib_uverbs_query_xrc_rcv_qp { + __u64 response; + __u32 xrc_domain_handle; + __u32 qp_num; + __u32 attr_mask; + __u32 reserved; + __u64 driver_data[0]; +}; + +struct ib_uverbs_reg_xrc_rcv_qp { + __u32 xrc_domain_handle; + __u32 qp_num; + __u64 driver_data[0]; +}; + +struct ib_uverbs_unreg_xrc_rcv_qp { + __u32 xrc_domain_handle; + __u32 qp_num; + __u64 driver_data[0]; +}; + + +#endif /* IB_USER_VERBS_H */ diff --git a/sys/ofed/include/rdma/ib_verbs.h b/sys/ofed/include/rdma/ib_verbs.h new file mode 100644 index 000000000000..f5b054a3da39 --- /dev/null +++ b/sys/ofed/include/rdma/ib_verbs.h @@ -0,0 +1,2170 @@ +/* + * Copyright (c) 2004 Mellanox Technologies Ltd. All rights reserved. + * Copyright (c) 2004 Infinicon Corporation. All rights reserved. + * Copyright (c) 2004 Intel Corporation. All rights reserved. + * Copyright (c) 2004 Topspin Corporation. All rights reserved. + * Copyright (c) 2004 Voltaire Corporation. All rights reserved. + * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2005, 2006, 2007 Cisco Systems. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if !defined(IB_VERBS_H) +#define IB_VERBS_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +union ib_gid { + u8 raw[16]; + struct { + __be64 subnet_prefix; + __be64 interface_id; + } global; +}; + +enum rdma_node_type { + /* IB values map to NodeInfo:NodeType. */ + RDMA_NODE_IB_CA = 1, + RDMA_NODE_IB_SWITCH, + RDMA_NODE_IB_ROUTER, + RDMA_NODE_RNIC +}; + +enum rdma_transport_type { + RDMA_TRANSPORT_IB, + RDMA_TRANSPORT_IWARP +}; + +enum rdma_transport_type +rdma_node_get_transport(enum rdma_node_type node_type) __attribute_const__; + +enum rdma_link_layer { + IB_LINK_LAYER_UNSPECIFIED, + IB_LINK_LAYER_INFINIBAND, + IB_LINK_LAYER_ETHERNET, +}; + +enum ib_device_cap_flags { + IB_DEVICE_RESIZE_MAX_WR = 1, + IB_DEVICE_BAD_PKEY_CNTR = (1<<1), + IB_DEVICE_BAD_QKEY_CNTR = (1<<2), + IB_DEVICE_RAW_MULTI = (1<<3), + IB_DEVICE_AUTO_PATH_MIG = (1<<4), + IB_DEVICE_CHANGE_PHY_PORT = (1<<5), + IB_DEVICE_UD_AV_PORT_ENFORCE = (1<<6), + IB_DEVICE_CURR_QP_STATE_MOD = (1<<7), + IB_DEVICE_SHUTDOWN_PORT = (1<<8), + IB_DEVICE_INIT_TYPE = (1<<9), + IB_DEVICE_PORT_ACTIVE_EVENT = (1<<10), + IB_DEVICE_SYS_IMAGE_GUID = (1<<11), + IB_DEVICE_RC_RNR_NAK_GEN = (1<<12), + IB_DEVICE_SRQ_RESIZE = (1<<13), + IB_DEVICE_N_NOTIFY_CQ = (1<<14), + IB_DEVICE_LOCAL_DMA_LKEY = (1<<15), + IB_DEVICE_RESERVED = (1<<16), /* old SEND_W_INV */ + IB_DEVICE_MEM_WINDOW = (1<<17), + /* + * Devices should set IB_DEVICE_UD_IP_SUM if they support + * insertion of UDP and TCP checksum on outgoing UD IPoIB + * messages and can verify the validity of checksum for + * incoming messages. Setting this flag implies that the + * IPoIB driver may set NETIF_F_IP_CSUM for datagram mode. + */ + IB_DEVICE_UD_IP_CSUM = (1<<18), + IB_DEVICE_UD_TSO = (1<<19), + IB_DEVICE_XRC = (1<<20), + IB_DEVICE_MEM_MGT_EXTENSIONS = (1<<21), + IB_DEVICE_BLOCK_MULTICAST_LOOPBACK = (1<<22), +}; + +enum ib_atomic_cap { + IB_ATOMIC_NONE, + IB_ATOMIC_HCA, + IB_ATOMIC_GLOB +}; + +struct ib_device_attr { + u64 fw_ver; + __be64 sys_image_guid; + u64 max_mr_size; + u64 page_size_cap; + u32 vendor_id; + u32 vendor_part_id; + u32 hw_ver; + int max_qp; + int max_qp_wr; + int device_cap_flags; + int max_sge; + int max_sge_rd; + int max_cq; + int max_cqe; + int max_mr; + int max_pd; + int max_qp_rd_atom; + int max_ee_rd_atom; + int max_res_rd_atom; + int max_qp_init_rd_atom; + int max_ee_init_rd_atom; + enum ib_atomic_cap atomic_cap; + enum ib_atomic_cap masked_atomic_cap; + int max_ee; + int max_rdd; + int max_mw; + int max_raw_ipv6_qp; + int max_raw_ethy_qp; + int max_mcast_grp; + int max_mcast_qp_attach; + int max_total_mcast_qp_attach; + int max_ah; + int max_fmr; + int max_map_per_fmr; + int max_srq; + int max_srq_wr; + int max_srq_sge; + unsigned int max_fast_reg_page_list_len; + u16 max_pkeys; + u8 local_ca_ack_delay; +}; + +enum ib_mtu { + IB_MTU_256 = 1, + IB_MTU_512 = 2, + IB_MTU_1024 = 3, + IB_MTU_2048 = 4, + IB_MTU_4096 = 5 +}; + +static inline int ib_mtu_enum_to_int(enum ib_mtu mtu) +{ + switch (mtu) { + case IB_MTU_256: return 256; + case IB_MTU_512: return 512; + case IB_MTU_1024: return 1024; + case IB_MTU_2048: return 2048; + case IB_MTU_4096: return 4096; + default: return -1; + } +} + +enum ib_port_state { + IB_PORT_NOP = 0, + IB_PORT_DOWN = 1, + IB_PORT_INIT = 2, + IB_PORT_ARMED = 3, + IB_PORT_ACTIVE = 4, + IB_PORT_ACTIVE_DEFER = 5 +}; + +enum ib_port_cap_flags { + IB_PORT_SM = 1 << 1, + IB_PORT_NOTICE_SUP = 1 << 2, + IB_PORT_TRAP_SUP = 1 << 3, + IB_PORT_OPT_IPD_SUP = 1 << 4, + IB_PORT_AUTO_MIGR_SUP = 1 << 5, + IB_PORT_SL_MAP_SUP = 1 << 6, + IB_PORT_MKEY_NVRAM = 1 << 7, + IB_PORT_PKEY_NVRAM = 1 << 8, + IB_PORT_LED_INFO_SUP = 1 << 9, + IB_PORT_SM_DISABLED = 1 << 10, + IB_PORT_SYS_IMAGE_GUID_SUP = 1 << 11, + IB_PORT_PKEY_SW_EXT_PORT_TRAP_SUP = 1 << 12, + IB_PORT_CM_SUP = 1 << 16, + IB_PORT_SNMP_TUNNEL_SUP = 1 << 17, + IB_PORT_REINIT_SUP = 1 << 18, + IB_PORT_DEVICE_MGMT_SUP = 1 << 19, + IB_PORT_VENDOR_CLASS_SUP = 1 << 20, + IB_PORT_DR_NOTICE_SUP = 1 << 21, + IB_PORT_CAP_MASK_NOTICE_SUP = 1 << 22, + IB_PORT_BOOT_MGMT_SUP = 1 << 23, + IB_PORT_LINK_LATENCY_SUP = 1 << 24, + IB_PORT_CLIENT_REG_SUP = 1 << 25 +}; + +enum ib_port_width { + IB_WIDTH_1X = 1, + IB_WIDTH_4X = 2, + IB_WIDTH_8X = 4, + IB_WIDTH_12X = 8 +}; + +static inline int ib_width_enum_to_int(enum ib_port_width width) +{ + switch (width) { + case IB_WIDTH_1X: return 1; + case IB_WIDTH_4X: return 4; + case IB_WIDTH_8X: return 8; + case IB_WIDTH_12X: return 12; + default: return -1; + } +} + +struct ib_protocol_stats { + /* TBD... */ +}; + +struct iw_protocol_stats { + u64 ipInReceives; + u64 ipInHdrErrors; + u64 ipInTooBigErrors; + u64 ipInNoRoutes; + u64 ipInAddrErrors; + u64 ipInUnknownProtos; + u64 ipInTruncatedPkts; + u64 ipInDiscards; + u64 ipInDelivers; + u64 ipOutForwDatagrams; + u64 ipOutRequests; + u64 ipOutDiscards; + u64 ipOutNoRoutes; + u64 ipReasmTimeout; + u64 ipReasmReqds; + u64 ipReasmOKs; + u64 ipReasmFails; + u64 ipFragOKs; + u64 ipFragFails; + u64 ipFragCreates; + u64 ipInMcastPkts; + u64 ipOutMcastPkts; + u64 ipInBcastPkts; + u64 ipOutBcastPkts; + + u64 tcpRtoAlgorithm; + u64 tcpRtoMin; + u64 tcpRtoMax; + u64 tcpMaxConn; + u64 tcpActiveOpens; + u64 tcpPassiveOpens; + u64 tcpAttemptFails; + u64 tcpEstabResets; + u64 tcpCurrEstab; + u64 tcpInSegs; + u64 tcpOutSegs; + u64 tcpRetransSegs; + u64 tcpInErrs; + u64 tcpOutRsts; +}; + +union rdma_protocol_stats { + struct ib_protocol_stats ib; + struct iw_protocol_stats iw; +}; + +struct ib_port_attr { + enum ib_port_state state; + enum ib_mtu max_mtu; + enum ib_mtu active_mtu; + int gid_tbl_len; + u32 port_cap_flags; + u32 max_msg_sz; + u32 bad_pkey_cntr; + u32 qkey_viol_cntr; + u16 pkey_tbl_len; + u16 lid; + u16 sm_lid; + u8 lmc; + u8 max_vl_num; + u8 sm_sl; + u8 subnet_timeout; + u8 init_type_reply; + u8 active_width; + u8 active_speed; + u8 phys_state; + enum rdma_link_layer link_layer; +}; + +enum ib_device_modify_flags { + IB_DEVICE_MODIFY_SYS_IMAGE_GUID = 1 << 0, + IB_DEVICE_MODIFY_NODE_DESC = 1 << 1 +}; + +struct ib_device_modify { + u64 sys_image_guid; + char node_desc[64]; +}; + +enum ib_port_modify_flags { + IB_PORT_SHUTDOWN = 1, + IB_PORT_INIT_TYPE = (1<<2), + IB_PORT_RESET_QKEY_CNTR = (1<<3) +}; + +struct ib_port_modify { + u32 set_port_cap_mask; + u32 clr_port_cap_mask; + u8 init_type; +}; + +enum ib_event_type { + IB_EVENT_CQ_ERR, + IB_EVENT_QP_FATAL, + IB_EVENT_QP_REQ_ERR, + IB_EVENT_QP_ACCESS_ERR, + IB_EVENT_COMM_EST, + IB_EVENT_SQ_DRAINED, + IB_EVENT_PATH_MIG, + IB_EVENT_PATH_MIG_ERR, + IB_EVENT_DEVICE_FATAL, + IB_EVENT_PORT_ACTIVE, + IB_EVENT_PORT_ERR, + IB_EVENT_LID_CHANGE, + IB_EVENT_PKEY_CHANGE, + IB_EVENT_SM_CHANGE, + IB_EVENT_SRQ_ERR, + IB_EVENT_SRQ_LIMIT_REACHED, + IB_EVENT_QP_LAST_WQE_REACHED, + IB_EVENT_CLIENT_REREGISTER, + IB_EVENT_GID_CHANGE, +}; + +enum ib_event_flags { + IB_XRC_QP_EVENT_FLAG = 0x80000000, +}; + +struct ib_event { + struct ib_device *device; + union { + struct ib_cq *cq; + struct ib_qp *qp; + struct ib_srq *srq; + u8 port_num; + u32 xrc_qp_num; + } element; + enum ib_event_type event; +}; + +struct ib_event_handler { + struct ib_device *device; + void (*handler)(struct ib_event_handler *, struct ib_event *); + struct list_head list; +}; + +#define INIT_IB_EVENT_HANDLER(_ptr, _device, _handler) \ + do { \ + (_ptr)->device = _device; \ + (_ptr)->handler = _handler; \ + INIT_LIST_HEAD(&(_ptr)->list); \ + } while (0) + +struct ib_global_route { + union ib_gid dgid; + u32 flow_label; + u8 sgid_index; + u8 hop_limit; + u8 traffic_class; +}; + +struct ib_grh { + __be32 version_tclass_flow; + __be16 paylen; + u8 next_hdr; + u8 hop_limit; + union ib_gid sgid; + union ib_gid dgid; +}; + +enum { + IB_MULTICAST_QPN = 0xffffff +}; + +#define IB_LID_PERMISSIVE cpu_to_be16(0xFFFF) + +enum ib_ah_flags { + IB_AH_GRH = 1 +}; + +enum ib_rate { + IB_RATE_PORT_CURRENT = 0, + IB_RATE_2_5_GBPS = 2, + IB_RATE_5_GBPS = 5, + IB_RATE_10_GBPS = 3, + IB_RATE_20_GBPS = 6, + IB_RATE_30_GBPS = 4, + IB_RATE_40_GBPS = 7, + IB_RATE_60_GBPS = 8, + IB_RATE_80_GBPS = 9, + IB_RATE_120_GBPS = 10 +}; + +/** + * ib_rate_to_mult - Convert the IB rate enum to a multiple of the + * base rate of 2.5 Gbit/sec. For example, IB_RATE_5_GBPS will be + * converted to 2, since 5 Gbit/sec is 2 * 2.5 Gbit/sec. + * @rate: rate to convert. + */ +int ib_rate_to_mult(enum ib_rate rate) __attribute_const__; + +/** + * mult_to_ib_rate - Convert a multiple of 2.5 Gbit/sec to an IB rate + * enum. + * @mult: multiple to convert. + */ +enum ib_rate mult_to_ib_rate(int mult) __attribute_const__; + +struct ib_ah_attr { + struct ib_global_route grh; + u16 dlid; + u8 sl; + u8 src_path_bits; + u8 static_rate; + u8 ah_flags; + u8 port_num; +}; + +enum ib_wc_status { + IB_WC_SUCCESS, + IB_WC_LOC_LEN_ERR, + IB_WC_LOC_QP_OP_ERR, + IB_WC_LOC_EEC_OP_ERR, + IB_WC_LOC_PROT_ERR, + IB_WC_WR_FLUSH_ERR, + IB_WC_MW_BIND_ERR, + IB_WC_BAD_RESP_ERR, + IB_WC_LOC_ACCESS_ERR, + IB_WC_REM_INV_REQ_ERR, + IB_WC_REM_ACCESS_ERR, + IB_WC_REM_OP_ERR, + IB_WC_RETRY_EXC_ERR, + IB_WC_RNR_RETRY_EXC_ERR, + IB_WC_LOC_RDD_VIOL_ERR, + IB_WC_REM_INV_RD_REQ_ERR, + IB_WC_REM_ABORT_ERR, + IB_WC_INV_EECN_ERR, + IB_WC_INV_EEC_STATE_ERR, + IB_WC_FATAL_ERR, + IB_WC_RESP_TIMEOUT_ERR, + IB_WC_GENERAL_ERR +}; + +enum ib_wc_opcode { + IB_WC_SEND, + IB_WC_RDMA_WRITE, + IB_WC_RDMA_READ, + IB_WC_COMP_SWAP, + IB_WC_FETCH_ADD, + IB_WC_BIND_MW, + IB_WC_LSO, + IB_WC_LOCAL_INV, + IB_WC_FAST_REG_MR, + IB_WC_MASKED_COMP_SWAP, + IB_WC_MASKED_FETCH_ADD, +/* + * Set value of IB_WC_RECV so consumers can test if a completion is a + * receive by testing (opcode & IB_WC_RECV). + */ + IB_WC_RECV = 1 << 7, + IB_WC_RECV_RDMA_WITH_IMM +}; + +enum ib_wc_flags { + IB_WC_GRH = 1, + IB_WC_WITH_IMM = (1<<1), + IB_WC_WITH_INVALIDATE = (1<<2), +}; + +struct ib_wc { + u64 wr_id; + enum ib_wc_status status; + enum ib_wc_opcode opcode; + u32 vendor_err; + u32 byte_len; + struct ib_qp *qp; + union { + __be32 imm_data; + u32 invalidate_rkey; + } ex; + u32 src_qp; + int wc_flags; + u16 pkey_index; + u16 slid; + u8 sl; + u8 dlid_path_bits; + u8 port_num; /* valid only for DR SMPs on switches */ + int csum_ok; +}; + +enum ib_cq_notify_flags { + IB_CQ_SOLICITED = 1 << 0, + IB_CQ_NEXT_COMP = 1 << 1, + IB_CQ_SOLICITED_MASK = IB_CQ_SOLICITED | IB_CQ_NEXT_COMP, + IB_CQ_REPORT_MISSED_EVENTS = 1 << 2, +}; + +enum ib_srq_attr_mask { + IB_SRQ_MAX_WR = 1 << 0, + IB_SRQ_LIMIT = 1 << 1, +}; + +struct ib_srq_attr { + u32 max_wr; + u32 max_sge; + u32 srq_limit; +}; + +struct ib_srq_init_attr { + void (*event_handler)(struct ib_event *, void *); + void *srq_context; + struct ib_srq_attr attr; +}; + +struct ib_qp_cap { + u32 max_send_wr; + u32 max_recv_wr; + u32 max_send_sge; + u32 max_recv_sge; + u32 max_inline_data; +}; + +enum ib_sig_type { + IB_SIGNAL_ALL_WR, + IB_SIGNAL_REQ_WR +}; + +enum ib_qp_type { + /* + * IB_QPT_SMI and IB_QPT_GSI have to be the first two entries + * here (and in that order) since the MAD layer uses them as + * indices into a 2-entry table. + */ + IB_QPT_SMI, + IB_QPT_GSI, + + IB_QPT_RC, + IB_QPT_UC, + IB_QPT_UD, + IB_QPT_XRC, + IB_QPT_RAW_IPV6, + IB_QPT_RAW_ETY, + IB_QPT_RAW_ETH +}; + +enum ib_qp_create_flags { + IB_QP_CREATE_IPOIB_UD_LSO = 1 << 0, + IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK = 1 << 1, +}; + +struct ib_qp_init_attr { + void (*event_handler)(struct ib_event *, void *); + void *qp_context; + struct ib_cq *send_cq; + struct ib_cq *recv_cq; + struct ib_srq *srq; + struct ib_qp_cap cap; + enum ib_sig_type sq_sig_type; + enum ib_qp_type qp_type; + enum ib_qp_create_flags create_flags; + struct ib_xrcd *xrc_domain; /* XRC qp's only */ + u8 port_num; /* special QP types only */ +}; + +enum ib_rnr_timeout { + IB_RNR_TIMER_655_36 = 0, + IB_RNR_TIMER_000_01 = 1, + IB_RNR_TIMER_000_02 = 2, + IB_RNR_TIMER_000_03 = 3, + IB_RNR_TIMER_000_04 = 4, + IB_RNR_TIMER_000_06 = 5, + IB_RNR_TIMER_000_08 = 6, + IB_RNR_TIMER_000_12 = 7, + IB_RNR_TIMER_000_16 = 8, + IB_RNR_TIMER_000_24 = 9, + IB_RNR_TIMER_000_32 = 10, + IB_RNR_TIMER_000_48 = 11, + IB_RNR_TIMER_000_64 = 12, + IB_RNR_TIMER_000_96 = 13, + IB_RNR_TIMER_001_28 = 14, + IB_RNR_TIMER_001_92 = 15, + IB_RNR_TIMER_002_56 = 16, + IB_RNR_TIMER_003_84 = 17, + IB_RNR_TIMER_005_12 = 18, + IB_RNR_TIMER_007_68 = 19, + IB_RNR_TIMER_010_24 = 20, + IB_RNR_TIMER_015_36 = 21, + IB_RNR_TIMER_020_48 = 22, + IB_RNR_TIMER_030_72 = 23, + IB_RNR_TIMER_040_96 = 24, + IB_RNR_TIMER_061_44 = 25, + IB_RNR_TIMER_081_92 = 26, + IB_RNR_TIMER_122_88 = 27, + IB_RNR_TIMER_163_84 = 28, + IB_RNR_TIMER_245_76 = 29, + IB_RNR_TIMER_327_68 = 30, + IB_RNR_TIMER_491_52 = 31 +}; + +enum ib_qp_attr_mask { + IB_QP_STATE = 1, + IB_QP_CUR_STATE = (1<<1), + IB_QP_EN_SQD_ASYNC_NOTIFY = (1<<2), + IB_QP_ACCESS_FLAGS = (1<<3), + IB_QP_PKEY_INDEX = (1<<4), + IB_QP_PORT = (1<<5), + IB_QP_QKEY = (1<<6), + IB_QP_AV = (1<<7), + IB_QP_PATH_MTU = (1<<8), + IB_QP_TIMEOUT = (1<<9), + IB_QP_RETRY_CNT = (1<<10), + IB_QP_RNR_RETRY = (1<<11), + IB_QP_RQ_PSN = (1<<12), + IB_QP_MAX_QP_RD_ATOMIC = (1<<13), + IB_QP_ALT_PATH = (1<<14), + IB_QP_MIN_RNR_TIMER = (1<<15), + IB_QP_SQ_PSN = (1<<16), + IB_QP_MAX_DEST_RD_ATOMIC = (1<<17), + IB_QP_PATH_MIG_STATE = (1<<18), + IB_QP_CAP = (1<<19), + IB_QP_DEST_QPN = (1<<20) +}; + +enum ib_qp_state { + IB_QPS_RESET, + IB_QPS_INIT, + IB_QPS_RTR, + IB_QPS_RTS, + IB_QPS_SQD, + IB_QPS_SQE, + IB_QPS_ERR +}; + +enum ib_mig_state { + IB_MIG_MIGRATED, + IB_MIG_REARM, + IB_MIG_ARMED +}; + +struct ib_qp_attr { + enum ib_qp_state qp_state; + enum ib_qp_state cur_qp_state; + enum ib_mtu path_mtu; + enum ib_mig_state path_mig_state; + u32 qkey; + u32 rq_psn; + u32 sq_psn; + u32 dest_qp_num; + int qp_access_flags; + struct ib_qp_cap cap; + struct ib_ah_attr ah_attr; + struct ib_ah_attr alt_ah_attr; + u16 pkey_index; + u16 alt_pkey_index; + u8 en_sqd_async_notify; + u8 sq_draining; + u8 max_rd_atomic; + u8 max_dest_rd_atomic; + u8 min_rnr_timer; + u8 port_num; + u8 timeout; + u8 retry_cnt; + u8 rnr_retry; + u8 alt_port_num; + u8 alt_timeout; +}; + +enum ib_wr_opcode { + IB_WR_RDMA_WRITE, + IB_WR_RDMA_WRITE_WITH_IMM, + IB_WR_SEND, + IB_WR_SEND_WITH_IMM, + IB_WR_RDMA_READ, + IB_WR_ATOMIC_CMP_AND_SWP, + IB_WR_ATOMIC_FETCH_AND_ADD, + IB_WR_LSO, + IB_WR_BIG_LSO, + IB_WR_SEND_WITH_INV, + IB_WR_RDMA_READ_WITH_INV, + IB_WR_LOCAL_INV, + IB_WR_FAST_REG_MR, + IB_WR_MASKED_ATOMIC_CMP_AND_SWP, + IB_WR_MASKED_ATOMIC_FETCH_AND_ADD, +}; + +enum ib_send_flags { + IB_SEND_FENCE = 1, + IB_SEND_SIGNALED = (1<<1), + IB_SEND_SOLICITED = (1<<2), + IB_SEND_INLINE = (1<<3), + IB_SEND_IP_CSUM = (1<<4) +}; + +struct ib_sge { + u64 addr; + u32 length; + u32 lkey; +}; + +struct ib_fast_reg_page_list { + struct ib_device *device; + u64 *page_list; + unsigned int max_page_list_len; +}; + +struct ib_send_wr { + struct ib_send_wr *next; + u64 wr_id; + struct ib_sge *sg_list; + int num_sge; + enum ib_wr_opcode opcode; + int send_flags; + union { + __be32 imm_data; + u32 invalidate_rkey; + } ex; + union { + struct { + u64 remote_addr; + u32 rkey; + } rdma; + struct { + u64 remote_addr; + u64 compare_add; + u64 swap; + u64 compare_add_mask; + u64 swap_mask; + u32 rkey; + } atomic; + struct { + struct ib_ah *ah; + void *header; + int hlen; + int mss; + u32 remote_qpn; + u32 remote_qkey; + u16 pkey_index; /* valid for GSI only */ + u8 port_num; /* valid for DR SMPs on switch only */ + } ud; + struct { + u64 iova_start; + struct ib_fast_reg_page_list *page_list; + unsigned int page_shift; + unsigned int page_list_len; + u32 length; + int access_flags; + u32 rkey; + } fast_reg; + struct { + struct ib_unpacked_lrh *lrh; + u32 eth_type; + u8 static_rate; + } raw_ety; + } wr; + u32 xrc_remote_srq_num; /* valid for XRC sends only */ +}; + +struct ib_recv_wr { + struct ib_recv_wr *next; + u64 wr_id; + struct ib_sge *sg_list; + int num_sge; +}; + +enum ib_access_flags { + IB_ACCESS_LOCAL_WRITE = 1, + IB_ACCESS_REMOTE_WRITE = (1<<1), + IB_ACCESS_REMOTE_READ = (1<<2), + IB_ACCESS_REMOTE_ATOMIC = (1<<3), + IB_ACCESS_MW_BIND = (1<<4) +}; + +struct ib_phys_buf { + u64 addr; + u64 size; +}; + +struct ib_mr_attr { + struct ib_pd *pd; + u64 device_virt_addr; + u64 size; + int mr_access_flags; + u32 lkey; + u32 rkey; +}; + +enum ib_mr_rereg_flags { + IB_MR_REREG_TRANS = 1, + IB_MR_REREG_PD = (1<<1), + IB_MR_REREG_ACCESS = (1<<2) +}; + +struct ib_mw_bind { + struct ib_mr *mr; + u64 wr_id; + u64 addr; + u32 length; + int send_flags; + int mw_access_flags; +}; + +struct ib_fmr_attr { + int max_pages; + int max_maps; + u8 page_shift; +}; + +struct ib_ucontext { + struct ib_device *device; + struct list_head pd_list; + struct list_head mr_list; + struct list_head mw_list; + struct list_head cq_list; + struct list_head qp_list; + struct list_head srq_list; + struct list_head ah_list; + struct list_head xrc_domain_list; + int closing; +}; + +struct ib_uobject { + u64 user_handle; /* handle given to us by userspace */ + struct ib_ucontext *context; /* associated user context */ + void *object; /* containing object */ + struct list_head list; /* link to context's list */ + int id; /* index into kernel idr */ + struct kref ref; + struct rw_semaphore mutex; /* protects .live */ + int live; +}; + +struct ib_udata { + void __user *inbuf; + void __user *outbuf; + size_t inlen; + size_t outlen; +}; + +struct ib_uxrc_rcv_object { + struct list_head list; /* link to context's list */ + u32 qp_num; + u32 domain_handle; +}; + +struct ib_pd { + struct ib_device *device; + struct ib_uobject *uobject; + atomic_t usecnt; /* count all resources */ +}; + +struct ib_xrcd { + struct ib_device *device; + struct ib_uobject *uobject; + struct inode *inode; + struct rb_node node; + atomic_t usecnt; /* count all resources */ +}; + + +struct ib_ah { + struct ib_device *device; + struct ib_pd *pd; + struct ib_uobject *uobject; +}; + +typedef void (*ib_comp_handler)(struct ib_cq *cq, void *cq_context); + +struct ib_cq { + struct ib_device *device; + struct ib_uobject *uobject; + ib_comp_handler comp_handler; + void (*event_handler)(struct ib_event *, void *); + void *cq_context; + int cqe; + atomic_t usecnt; /* count number of work queues */ +}; + +struct ib_srq { + struct ib_device *device; + struct ib_pd *pd; + struct ib_cq *xrc_cq; + struct ib_xrcd *xrcd; + struct ib_uobject *uobject; + void (*event_handler)(struct ib_event *, void *); + void *srq_context; + atomic_t usecnt; + u32 xrc_srq_num; +}; + +struct ib_qp { + struct ib_device *device; + struct ib_pd *pd; + struct ib_cq *send_cq; + struct ib_cq *recv_cq; + struct ib_srq *srq; + struct ib_uobject *uobject; + void (*event_handler)(struct ib_event *, void *); + void *qp_context; + u32 qp_num; + enum ib_qp_type qp_type; + struct ib_xrcd *xrcd; /* XRC QPs only */ +}; + +struct ib_mr { + struct ib_device *device; + struct ib_pd *pd; + struct ib_uobject *uobject; + u32 lkey; + u32 rkey; + atomic_t usecnt; /* count number of MWs */ +}; + +struct ib_mw { + struct ib_device *device; + struct ib_pd *pd; + struct ib_uobject *uobject; + u32 rkey; +}; + +struct ib_fmr { + struct ib_device *device; + struct ib_pd *pd; + struct list_head list; + u32 lkey; + u32 rkey; +}; + +struct ib_mad; +struct ib_grh; + +enum ib_process_mad_flags { + IB_MAD_IGNORE_MKEY = 1, + IB_MAD_IGNORE_BKEY = 2, + IB_MAD_IGNORE_ALL = IB_MAD_IGNORE_MKEY | IB_MAD_IGNORE_BKEY +}; + +enum ib_mad_result { + IB_MAD_RESULT_FAILURE = 0, /* (!SUCCESS is the important flag) */ + IB_MAD_RESULT_SUCCESS = 1 << 0, /* MAD was successfully processed */ + IB_MAD_RESULT_REPLY = 1 << 1, /* Reply packet needs to be sent */ + IB_MAD_RESULT_CONSUMED = 1 << 2 /* Packet consumed: stop processing */ +}; + +#define IB_DEVICE_NAME_MAX 64 + +struct ib_cache { + rwlock_t lock; + struct ib_event_handler event_handler; + struct ib_pkey_cache **pkey_cache; + struct ib_gid_cache **gid_cache; + u8 *lmc_cache; +}; + +struct ib_dma_mapping_ops { + int (*mapping_error)(struct ib_device *dev, + u64 dma_addr); + u64 (*map_single)(struct ib_device *dev, + void *ptr, size_t size, + enum dma_data_direction direction); + void (*unmap_single)(struct ib_device *dev, + u64 addr, size_t size, + enum dma_data_direction direction); + u64 (*map_page)(struct ib_device *dev, + struct page *page, unsigned long offset, + size_t size, + enum dma_data_direction direction); + void (*unmap_page)(struct ib_device *dev, + u64 addr, size_t size, + enum dma_data_direction direction); + int (*map_sg)(struct ib_device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction direction); + void (*unmap_sg)(struct ib_device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction direction); + u64 (*dma_address)(struct ib_device *dev, + struct scatterlist *sg); + unsigned int (*dma_len)(struct ib_device *dev, + struct scatterlist *sg); + void (*sync_single_for_cpu)(struct ib_device *dev, + u64 dma_handle, + size_t size, + enum dma_data_direction dir); + void (*sync_single_for_device)(struct ib_device *dev, + u64 dma_handle, + size_t size, + enum dma_data_direction dir); + void *(*alloc_coherent)(struct ib_device *dev, + size_t size, + u64 *dma_handle, + gfp_t flag); + void (*free_coherent)(struct ib_device *dev, + size_t size, void *cpu_addr, + u64 dma_handle); +}; + +struct iw_cm_verbs; + +struct ib_device { + struct device *dma_device; + + char name[IB_DEVICE_NAME_MAX]; + + struct list_head event_handler_list; + spinlock_t event_handler_lock; + + struct list_head core_list; + struct list_head client_data_list; + spinlock_t client_data_lock; + + struct ib_cache cache; + int *pkey_tbl_len; + int *gid_tbl_len; + + int num_comp_vectors; + + struct iw_cm_verbs *iwcm; + + int (*get_protocol_stats)(struct ib_device *device, + union rdma_protocol_stats *stats); + int (*query_device)(struct ib_device *device, + struct ib_device_attr *device_attr); + int (*query_port)(struct ib_device *device, + u8 port_num, + struct ib_port_attr *port_attr); + enum rdma_link_layer (*get_link_layer)(struct ib_device *device, + u8 port_num); + int (*query_gid)(struct ib_device *device, + u8 port_num, int index, + union ib_gid *gid); + int (*query_pkey)(struct ib_device *device, + u8 port_num, u16 index, u16 *pkey); + int (*modify_device)(struct ib_device *device, + int device_modify_mask, + struct ib_device_modify *device_modify); + int (*modify_port)(struct ib_device *device, + u8 port_num, int port_modify_mask, + struct ib_port_modify *port_modify); + struct ib_ucontext * (*alloc_ucontext)(struct ib_device *device, + struct ib_udata *udata); + int (*dealloc_ucontext)(struct ib_ucontext *context); + int (*mmap)(struct ib_ucontext *context, + struct vm_area_struct *vma); + struct ib_pd * (*alloc_pd)(struct ib_device *device, + struct ib_ucontext *context, + struct ib_udata *udata); + int (*dealloc_pd)(struct ib_pd *pd); + struct ib_ah * (*create_ah)(struct ib_pd *pd, + struct ib_ah_attr *ah_attr); + int (*modify_ah)(struct ib_ah *ah, + struct ib_ah_attr *ah_attr); + int (*query_ah)(struct ib_ah *ah, + struct ib_ah_attr *ah_attr); + int (*destroy_ah)(struct ib_ah *ah); + struct ib_srq * (*create_srq)(struct ib_pd *pd, + struct ib_srq_init_attr *srq_init_attr, + struct ib_udata *udata); + int (*modify_srq)(struct ib_srq *srq, + struct ib_srq_attr *srq_attr, + enum ib_srq_attr_mask srq_attr_mask, + struct ib_udata *udata); + int (*query_srq)(struct ib_srq *srq, + struct ib_srq_attr *srq_attr); + int (*destroy_srq)(struct ib_srq *srq); + int (*post_srq_recv)(struct ib_srq *srq, + struct ib_recv_wr *recv_wr, + struct ib_recv_wr **bad_recv_wr); + struct ib_qp * (*create_qp)(struct ib_pd *pd, + struct ib_qp_init_attr *qp_init_attr, + struct ib_udata *udata); + int (*modify_qp)(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask, + struct ib_udata *udata); + int (*query_qp)(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr); + int (*destroy_qp)(struct ib_qp *qp); + int (*post_send)(struct ib_qp *qp, + struct ib_send_wr *send_wr, + struct ib_send_wr **bad_send_wr); + int (*post_recv)(struct ib_qp *qp, + struct ib_recv_wr *recv_wr, + struct ib_recv_wr **bad_recv_wr); + struct ib_cq * (*create_cq)(struct ib_device *device, int cqe, + int comp_vector, + struct ib_ucontext *context, + struct ib_udata *udata); + int (*modify_cq)(struct ib_cq *cq, u16 cq_count, + u16 cq_period); + int (*destroy_cq)(struct ib_cq *cq); + int (*resize_cq)(struct ib_cq *cq, int cqe, + struct ib_udata *udata); + int (*poll_cq)(struct ib_cq *cq, int num_entries, + struct ib_wc *wc); + int (*peek_cq)(struct ib_cq *cq, int wc_cnt); + int (*req_notify_cq)(struct ib_cq *cq, + enum ib_cq_notify_flags flags); + int (*req_ncomp_notif)(struct ib_cq *cq, + int wc_cnt); + struct ib_mr * (*get_dma_mr)(struct ib_pd *pd, + int mr_access_flags); + struct ib_mr * (*reg_phys_mr)(struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + int mr_access_flags, + u64 *iova_start); + struct ib_mr * (*reg_user_mr)(struct ib_pd *pd, + u64 start, u64 length, + u64 virt_addr, + int mr_access_flags, + struct ib_udata *udata); + int (*query_mr)(struct ib_mr *mr, + struct ib_mr_attr *mr_attr); + int (*dereg_mr)(struct ib_mr *mr); + struct ib_mr * (*alloc_fast_reg_mr)(struct ib_pd *pd, + int max_page_list_len); + struct ib_fast_reg_page_list * (*alloc_fast_reg_page_list)(struct ib_device *device, + int page_list_len); + void (*free_fast_reg_page_list)(struct ib_fast_reg_page_list *page_list); + int (*rereg_phys_mr)(struct ib_mr *mr, + int mr_rereg_mask, + struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + int mr_access_flags, + u64 *iova_start); + struct ib_mw * (*alloc_mw)(struct ib_pd *pd); + int (*bind_mw)(struct ib_qp *qp, + struct ib_mw *mw, + struct ib_mw_bind *mw_bind); + int (*dealloc_mw)(struct ib_mw *mw); + struct ib_fmr * (*alloc_fmr)(struct ib_pd *pd, + int mr_access_flags, + struct ib_fmr_attr *fmr_attr); + int (*map_phys_fmr)(struct ib_fmr *fmr, + u64 *page_list, int list_len, + u64 iova); + int (*unmap_fmr)(struct list_head *fmr_list); + int (*dealloc_fmr)(struct ib_fmr *fmr); + int (*attach_mcast)(struct ib_qp *qp, + union ib_gid *gid, + u16 lid); + int (*detach_mcast)(struct ib_qp *qp, + union ib_gid *gid, + u16 lid); + int (*process_mad)(struct ib_device *device, + int process_mad_flags, + u8 port_num, + struct ib_wc *in_wc, + struct ib_grh *in_grh, + struct ib_mad *in_mad, + struct ib_mad *out_mad); + struct ib_srq * (*create_xrc_srq)(struct ib_pd *pd, + struct ib_cq *xrc_cq, + struct ib_xrcd *xrcd, + struct ib_srq_init_attr *srq_init_attr, + struct ib_udata *udata); + struct ib_xrcd * (*alloc_xrcd)(struct ib_device *device, + struct ib_ucontext *context, + struct ib_udata *udata); + int (*dealloc_xrcd)(struct ib_xrcd *xrcd); + int (*create_xrc_rcv_qp)(struct ib_qp_init_attr *init_attr, + u32 *qp_num); + int (*modify_xrc_rcv_qp)(struct ib_xrcd *xrcd, + u32 qp_num, + struct ib_qp_attr *attr, + int attr_mask); + int (*query_xrc_rcv_qp)(struct ib_xrcd *xrcd, + u32 qp_num, + struct ib_qp_attr *attr, + int attr_mask, + struct ib_qp_init_attr *init_attr); + int (*reg_xrc_rcv_qp)(struct ib_xrcd *xrcd, + void *context, + u32 qp_num); + int (*unreg_xrc_rcv_qp)(struct ib_xrcd *xrcd, + void *context, + u32 qp_num); + + struct ib_dma_mapping_ops *dma_ops; + + struct module *owner; + struct device dev; + struct kobject *ports_parent; + struct list_head port_list; + + enum { + IB_DEV_UNINITIALIZED, + IB_DEV_REGISTERED, + IB_DEV_UNREGISTERED + } reg_state; + + u64 uverbs_cmd_mask; + int uverbs_abi_ver; + + char node_desc[64]; + __be64 node_guid; + u32 local_dma_lkey; + u8 node_type; + u8 phys_port_cnt; + struct rb_root ib_uverbs_xrcd_table; + struct mutex xrcd_table_mutex; +}; + +struct ib_client { + char *name; + void (*add) (struct ib_device *); + void (*remove)(struct ib_device *); + + struct list_head list; +}; + +struct ib_device *ib_alloc_device(size_t size); +void ib_dealloc_device(struct ib_device *device); + +int ib_register_device (struct ib_device *device); +void ib_unregister_device(struct ib_device *device); + +int ib_register_client (struct ib_client *client); +void ib_unregister_client(struct ib_client *client); + +void *ib_get_client_data(struct ib_device *device, struct ib_client *client); +void ib_set_client_data(struct ib_device *device, struct ib_client *client, + void *data); + +static inline int ib_copy_from_udata(void *dest, struct ib_udata *udata, size_t len) +{ + return copy_from_user(dest, udata->inbuf, len) ? -EFAULT : 0; +} + +static inline int ib_copy_to_udata(struct ib_udata *udata, void *src, size_t len) +{ + return copy_to_user(udata->outbuf, src, len) ? -EFAULT : 0; +} + +/** + * ib_sysfs_create_port_files - iterate over port sysfs directories + * @device: the IB device + * @create: a function to create sysfs files in each port directory + */ +int ib_sysfs_create_port_files(struct ib_device *device, + int (*create)(struct ib_device *dev, u8 port_num, + struct kobject *kobj)); + +/** + * ib_modify_qp_is_ok - Check that the supplied attribute mask + * contains all required attributes and no attributes not allowed for + * the given QP state transition. + * @cur_state: Current QP state + * @next_state: Next QP state + * @type: QP type + * @mask: Mask of supplied QP attributes + * + * This function is a helper function that a low-level driver's + * modify_qp method can use to validate the consumer's input. It + * checks that cur_state and next_state are valid QP states, that a + * transition from cur_state to next_state is allowed by the IB spec, + * and that the attribute mask supplied is allowed for the transition. + */ +int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state, + enum ib_qp_type type, enum ib_qp_attr_mask mask); + +int ib_register_event_handler (struct ib_event_handler *event_handler); +int ib_unregister_event_handler(struct ib_event_handler *event_handler); +void ib_dispatch_event(struct ib_event *event); + +int ib_query_device(struct ib_device *device, + struct ib_device_attr *device_attr); + +int ib_query_port(struct ib_device *device, + u8 port_num, struct ib_port_attr *port_attr); + +enum rdma_link_layer rdma_port_get_link_layer(struct ib_device *device, + u8 port_num); + +int ib_query_gid(struct ib_device *device, + u8 port_num, int index, union ib_gid *gid); + +int ib_query_pkey(struct ib_device *device, + u8 port_num, u16 index, u16 *pkey); + +int ib_modify_device(struct ib_device *device, + int device_modify_mask, + struct ib_device_modify *device_modify); + +int ib_modify_port(struct ib_device *device, + u8 port_num, int port_modify_mask, + struct ib_port_modify *port_modify); + +int ib_find_gid(struct ib_device *device, union ib_gid *gid, + u8 *port_num, u16 *index); + +int ib_find_pkey(struct ib_device *device, + u8 port_num, u16 pkey, u16 *index); + +/** + * ib_alloc_pd - Allocates an unused protection domain. + * @device: The device on which to allocate the protection domain. + * + * A protection domain object provides an association between QPs, shared + * receive queues, address handles, memory regions, and memory windows. + */ +struct ib_pd *ib_alloc_pd(struct ib_device *device); + +/** + * ib_dealloc_pd - Deallocates a protection domain. + * @pd: The protection domain to deallocate. + */ +int ib_dealloc_pd(struct ib_pd *pd); + +/** + * ib_create_ah - Creates an address handle for the given address vector. + * @pd: The protection domain associated with the address handle. + * @ah_attr: The attributes of the address vector. + * + * The address handle is used to reference a local or global destination + * in all UD QP post sends. + */ +struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr); + +/** + * ib_init_ah_from_wc - Initializes address handle attributes from a + * work completion. + * @device: Device on which the received message arrived. + * @port_num: Port on which the received message arrived. + * @wc: Work completion associated with the received message. + * @grh: References the received global route header. This parameter is + * ignored unless the work completion indicates that the GRH is valid. + * @ah_attr: Returned attributes that can be used when creating an address + * handle for replying to the message. + */ +int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, struct ib_wc *wc, + struct ib_grh *grh, struct ib_ah_attr *ah_attr); + +/** + * ib_create_ah_from_wc - Creates an address handle associated with the + * sender of the specified work completion. + * @pd: The protection domain associated with the address handle. + * @wc: Work completion information associated with a received message. + * @grh: References the received global route header. This parameter is + * ignored unless the work completion indicates that the GRH is valid. + * @port_num: The outbound port number to associate with the address. + * + * The address handle is used to reference a local or global destination + * in all UD QP post sends. + */ +struct ib_ah *ib_create_ah_from_wc(struct ib_pd *pd, struct ib_wc *wc, + struct ib_grh *grh, u8 port_num); + +/** + * ib_modify_ah - Modifies the address vector associated with an address + * handle. + * @ah: The address handle to modify. + * @ah_attr: The new address vector attributes to associate with the + * address handle. + */ +int ib_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr); + +/** + * ib_query_ah - Queries the address vector associated with an address + * handle. + * @ah: The address handle to query. + * @ah_attr: The address vector attributes associated with the address + * handle. + */ +int ib_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr); + +/** + * ib_destroy_ah - Destroys an address handle. + * @ah: The address handle to destroy. + */ +int ib_destroy_ah(struct ib_ah *ah); + +/** + * ib_create_xrc_srq - Creates an XRC SRQ associated with the specified + * protection domain, cq, and xrc domain. + * @pd: The protection domain associated with the SRQ. + * @xrc_cq: The cq to be associated with the XRC SRQ. + * @xrcd: The XRC domain to be associated with the XRC SRQ. + * @srq_init_attr: A list of initial attributes required to create the + * XRC SRQ. If XRC SRQ creation succeeds, then the attributes are updated + * to the actual capabilities of the created XRC SRQ. + * + * srq_attr->max_wr and srq_attr->max_sge are read the determine the + * requested size of the XRC SRQ, and set to the actual values allocated + * on return. If ib_create_xrc_srq() succeeds, then max_wr and max_sge + * will always be at least as large as the requested values. + */ +struct ib_srq *ib_create_xrc_srq(struct ib_pd *pd, + struct ib_cq *xrc_cq, + struct ib_xrcd *xrcd, + struct ib_srq_init_attr *srq_init_attr); + +/** + * ib_create_srq - Creates an SRQ associated with the specified + * protection domain. + * @pd: The protection domain associated with the SRQ. + * @srq_init_attr: A list of initial attributes required to create the + * SRQ. If SRQ creation succeeds, then the attributes are updated to + * the actual capabilities of the created SRQ. + * + * srq_attr->max_wr and srq_attr->max_sge are read the determine the + * requested size of the SRQ, and set to the actual values allocated + * on return. If ib_create_srq() succeeds, then max_wr and max_sge + * will always be at least as large as the requested values. + */ +struct ib_srq *ib_create_srq(struct ib_pd *pd, + struct ib_srq_init_attr *srq_init_attr); + +/** + * ib_modify_srq - Modifies the attributes for the specified SRQ. + * @srq: The SRQ to modify. + * @srq_attr: On input, specifies the SRQ attributes to modify. On output, + * the current values of selected SRQ attributes are returned. + * @srq_attr_mask: A bit-mask used to specify which attributes of the SRQ + * are being modified. + * + * The mask may contain IB_SRQ_MAX_WR to resize the SRQ and/or + * IB_SRQ_LIMIT to set the SRQ's limit and request notification when + * the number of receives queued drops below the limit. + */ +int ib_modify_srq(struct ib_srq *srq, + struct ib_srq_attr *srq_attr, + enum ib_srq_attr_mask srq_attr_mask); + +/** + * ib_query_srq - Returns the attribute list and current values for the + * specified SRQ. + * @srq: The SRQ to query. + * @srq_attr: The attributes of the specified SRQ. + */ +int ib_query_srq(struct ib_srq *srq, + struct ib_srq_attr *srq_attr); + +/** + * ib_destroy_srq - Destroys the specified SRQ. + * @srq: The SRQ to destroy. + */ +int ib_destroy_srq(struct ib_srq *srq); + +/** + * ib_post_srq_recv - Posts a list of work requests to the specified SRQ. + * @srq: The SRQ to post the work request on. + * @recv_wr: A list of work requests to post on the receive queue. + * @bad_recv_wr: On an immediate failure, this parameter will reference + * the work request that failed to be posted on the QP. + */ +static inline int ib_post_srq_recv(struct ib_srq *srq, + struct ib_recv_wr *recv_wr, + struct ib_recv_wr **bad_recv_wr) +{ + return srq->device->post_srq_recv(srq, recv_wr, bad_recv_wr); +} + +/** + * ib_create_qp - Creates a QP associated with the specified protection + * domain. + * @pd: The protection domain associated with the QP. + * @qp_init_attr: A list of initial attributes required to create the + * QP. If QP creation succeeds, then the attributes are updated to + * the actual capabilities of the created QP. + */ +struct ib_qp *ib_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *qp_init_attr); + +/** + * ib_modify_qp - Modifies the attributes for the specified QP and then + * transitions the QP to the given state. + * @qp: The QP to modify. + * @qp_attr: On input, specifies the QP attributes to modify. On output, + * the current values of selected QP attributes are returned. + * @qp_attr_mask: A bit-mask used to specify which attributes of the QP + * are being modified. + */ +int ib_modify_qp(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask); + +/** + * ib_query_qp - Returns the attribute list and current values for the + * specified QP. + * @qp: The QP to query. + * @qp_attr: The attributes of the specified QP. + * @qp_attr_mask: A bit-mask used to select specific attributes to query. + * @qp_init_attr: Additional attributes of the selected QP. + * + * The qp_attr_mask may be used to limit the query to gathering only the + * selected attributes. + */ +int ib_query_qp(struct ib_qp *qp, + struct ib_qp_attr *qp_attr, + int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr); + +/** + * ib_destroy_qp - Destroys the specified QP. + * @qp: The QP to destroy. + */ +int ib_destroy_qp(struct ib_qp *qp); + +/** + * ib_post_send - Posts a list of work requests to the send queue of + * the specified QP. + * @qp: The QP to post the work request on. + * @send_wr: A list of work requests to post on the send queue. + * @bad_send_wr: On an immediate failure, this parameter will reference + * the work request that failed to be posted on the QP. + */ +static inline int ib_post_send(struct ib_qp *qp, + struct ib_send_wr *send_wr, + struct ib_send_wr **bad_send_wr) +{ + return qp->device->post_send(qp, send_wr, bad_send_wr); +} + +/** + * ib_post_recv - Posts a list of work requests to the receive queue of + * the specified QP. + * @qp: The QP to post the work request on. + * @recv_wr: A list of work requests to post on the receive queue. + * @bad_recv_wr: On an immediate failure, this parameter will reference + * the work request that failed to be posted on the QP. + */ +static inline int ib_post_recv(struct ib_qp *qp, + struct ib_recv_wr *recv_wr, + struct ib_recv_wr **bad_recv_wr) +{ + return qp->device->post_recv(qp, recv_wr, bad_recv_wr); +} + +/* + * IB_CQ_VECTOR_LEAST_ATTACHED: The constant specifies that + * the CQ will be attached to the completion vector that has + * the least number of CQs already attached to it. + */ +#define IB_CQ_VECTOR_LEAST_ATTACHED 0xffffffff + +/** + * ib_create_cq - Creates a CQ on the specified device. + * @device: The device on which to create the CQ. + * @comp_handler: A user-specified callback that is invoked when a + * completion event occurs on the CQ. + * @event_handler: A user-specified callback that is invoked when an + * asynchronous event not associated with a completion occurs on the CQ. + * @cq_context: Context associated with the CQ returned to the user via + * the associated completion and event handlers. + * @cqe: The minimum size of the CQ. + * @comp_vector - Completion vector used to signal completion events. + * Must be >= 0 and < context->num_comp_vectors + * or IB_CQ_VECTOR_LEAST_ATTACHED. + * + * Users can examine the cq structure to determine the actual CQ size. + */ +struct ib_cq *ib_create_cq(struct ib_device *device, + ib_comp_handler comp_handler, + void (*event_handler)(struct ib_event *, void *), + void *cq_context, int cqe, int comp_vector); + +/** + * ib_resize_cq - Modifies the capacity of the CQ. + * @cq: The CQ to resize. + * @cqe: The minimum size of the CQ. + * + * Users can examine the cq structure to determine the actual CQ size. + */ +int ib_resize_cq(struct ib_cq *cq, int cqe); + +/** + * ib_modify_cq - Modifies moderation params of the CQ + * @cq: The CQ to modify. + * @cq_count: number of CQEs that will trigger an event + * @cq_period: max period of time in usec before triggering an event + * + */ +int ib_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period); + +/** + * ib_destroy_cq - Destroys the specified CQ. + * @cq: The CQ to destroy. + */ +int ib_destroy_cq(struct ib_cq *cq); + +/** + * ib_poll_cq - poll a CQ for completion(s) + * @cq:the CQ being polled + * @num_entries:maximum number of completions to return + * @wc:array of at least @num_entries &struct ib_wc where completions + * will be returned + * + * Poll a CQ for (possibly multiple) completions. If the return value + * is < 0, an error occurred. If the return value is >= 0, it is the + * number of completions returned. If the return value is + * non-negative and < num_entries, then the CQ was emptied. + */ +static inline int ib_poll_cq(struct ib_cq *cq, int num_entries, + struct ib_wc *wc) +{ + return cq->device->poll_cq(cq, num_entries, wc); +} + +/** + * ib_peek_cq - Returns the number of unreaped completions currently + * on the specified CQ. + * @cq: The CQ to peek. + * @wc_cnt: A minimum number of unreaped completions to check for. + * + * If the number of unreaped completions is greater than or equal to wc_cnt, + * this function returns wc_cnt, otherwise, it returns the actual number of + * unreaped completions. + */ +int ib_peek_cq(struct ib_cq *cq, int wc_cnt); + +/** + * ib_req_notify_cq - Request completion notification on a CQ. + * @cq: The CQ to generate an event for. + * @flags: + * Must contain exactly one of %IB_CQ_SOLICITED or %IB_CQ_NEXT_COMP + * to request an event on the next solicited event or next work + * completion at any type, respectively. %IB_CQ_REPORT_MISSED_EVENTS + * may also be |ed in to request a hint about missed events, as + * described below. + * + * Return Value: + * < 0 means an error occurred while requesting notification + * == 0 means notification was requested successfully, and if + * IB_CQ_REPORT_MISSED_EVENTS was passed in, then no events + * were missed and it is safe to wait for another event. In + * this case is it guaranteed that any work completions added + * to the CQ since the last CQ poll will trigger a completion + * notification event. + * > 0 is only returned if IB_CQ_REPORT_MISSED_EVENTS was passed + * in. It means that the consumer must poll the CQ again to + * make sure it is empty to avoid missing an event because of a + * race between requesting notification and an entry being + * added to the CQ. This return value means it is possible + * (but not guaranteed) that a work completion has been added + * to the CQ since the last poll without triggering a + * completion notification event. + */ +static inline int ib_req_notify_cq(struct ib_cq *cq, + enum ib_cq_notify_flags flags) +{ + return cq->device->req_notify_cq(cq, flags); +} + +/** + * ib_req_ncomp_notif - Request completion notification when there are + * at least the specified number of unreaped completions on the CQ. + * @cq: The CQ to generate an event for. + * @wc_cnt: The number of unreaped completions that should be on the + * CQ before an event is generated. + */ +static inline int ib_req_ncomp_notif(struct ib_cq *cq, int wc_cnt) +{ + return cq->device->req_ncomp_notif ? + cq->device->req_ncomp_notif(cq, wc_cnt) : + -ENOSYS; +} + +/** + * ib_get_dma_mr - Returns a memory region for system memory that is + * usable for DMA. + * @pd: The protection domain associated with the memory region. + * @mr_access_flags: Specifies the memory access rights. + * + * Note that the ib_dma_*() functions defined below must be used + * to create/destroy addresses used with the Lkey or Rkey returned + * by ib_get_dma_mr(). + */ +struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags); + +/** + * ib_dma_mapping_error - check a DMA addr for error + * @dev: The device for which the dma_addr was created + * @dma_addr: The DMA address to check + */ +static inline int ib_dma_mapping_error(struct ib_device *dev, u64 dma_addr) +{ + if (dev->dma_ops) + return dev->dma_ops->mapping_error(dev, dma_addr); + return dma_mapping_error(dev->dma_device, dma_addr); +} + +/** + * ib_dma_map_single - Map a kernel virtual address to DMA address + * @dev: The device for which the dma_addr is to be created + * @cpu_addr: The kernel virtual address + * @size: The size of the region in bytes + * @direction: The direction of the DMA + */ +static inline u64 ib_dma_map_single(struct ib_device *dev, + void *cpu_addr, size_t size, + enum dma_data_direction direction) +{ + if (dev->dma_ops) + return dev->dma_ops->map_single(dev, cpu_addr, size, direction); + return dma_map_single(dev->dma_device, cpu_addr, size, direction); +} + +/** + * ib_dma_unmap_single - Destroy a mapping created by ib_dma_map_single() + * @dev: The device for which the DMA address was created + * @addr: The DMA address + * @size: The size of the region in bytes + * @direction: The direction of the DMA + */ +static inline void ib_dma_unmap_single(struct ib_device *dev, + u64 addr, size_t size, + enum dma_data_direction direction) +{ + if (dev->dma_ops) + dev->dma_ops->unmap_single(dev, addr, size, direction); + else + dma_unmap_single(dev->dma_device, addr, size, direction); +} + +static inline u64 ib_dma_map_single_attrs(struct ib_device *dev, + void *cpu_addr, size_t size, + enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + return dma_map_single_attrs(dev->dma_device, cpu_addr, size, + direction, attrs); +} + +static inline void ib_dma_unmap_single_attrs(struct ib_device *dev, + u64 addr, size_t size, + enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + return dma_unmap_single_attrs(dev->dma_device, addr, size, + direction, attrs); +} + +/** + * ib_dma_map_page - Map a physical page to DMA address + * @dev: The device for which the dma_addr is to be created + * @page: The page to be mapped + * @offset: The offset within the page + * @size: The size of the region in bytes + * @direction: The direction of the DMA + */ +static inline u64 ib_dma_map_page(struct ib_device *dev, + struct page *page, + unsigned long offset, + size_t size, + enum dma_data_direction direction) +{ + if (dev->dma_ops) + return dev->dma_ops->map_page(dev, page, offset, size, direction); + return dma_map_page(dev->dma_device, page, offset, size, direction); +} + +/** + * ib_dma_unmap_page - Destroy a mapping created by ib_dma_map_page() + * @dev: The device for which the DMA address was created + * @addr: The DMA address + * @size: The size of the region in bytes + * @direction: The direction of the DMA + */ +static inline void ib_dma_unmap_page(struct ib_device *dev, + u64 addr, size_t size, + enum dma_data_direction direction) +{ + if (dev->dma_ops) + dev->dma_ops->unmap_page(dev, addr, size, direction); + else + dma_unmap_page(dev->dma_device, addr, size, direction); +} + +/** + * ib_dma_map_sg - Map a scatter/gather list to DMA addresses + * @dev: The device for which the DMA addresses are to be created + * @sg: The array of scatter/gather entries + * @nents: The number of scatter/gather entries + * @direction: The direction of the DMA + */ +static inline int ib_dma_map_sg(struct ib_device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + if (dev->dma_ops) + return dev->dma_ops->map_sg(dev, sg, nents, direction); + return dma_map_sg(dev->dma_device, sg, nents, direction); +} + +/** + * ib_dma_unmap_sg - Unmap a scatter/gather list of DMA addresses + * @dev: The device for which the DMA addresses were created + * @sg: The array of scatter/gather entries + * @nents: The number of scatter/gather entries + * @direction: The direction of the DMA + */ +static inline void ib_dma_unmap_sg(struct ib_device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + if (dev->dma_ops) + dev->dma_ops->unmap_sg(dev, sg, nents, direction); + else + dma_unmap_sg(dev->dma_device, sg, nents, direction); +} + +static inline int ib_dma_map_sg_attrs(struct ib_device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + return dma_map_sg_attrs(dev->dma_device, sg, nents, direction, attrs); +} + +static inline void ib_dma_unmap_sg_attrs(struct ib_device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + dma_unmap_sg_attrs(dev->dma_device, sg, nents, direction, attrs); +} +/** + * ib_sg_dma_address - Return the DMA address from a scatter/gather entry + * @dev: The device for which the DMA addresses were created + * @sg: The scatter/gather entry + */ +static inline u64 ib_sg_dma_address(struct ib_device *dev, + struct scatterlist *sg) +{ + if (dev->dma_ops) + return dev->dma_ops->dma_address(dev, sg); + return sg_dma_address(sg); +} + +/** + * ib_sg_dma_len - Return the DMA length from a scatter/gather entry + * @dev: The device for which the DMA addresses were created + * @sg: The scatter/gather entry + */ +static inline unsigned int ib_sg_dma_len(struct ib_device *dev, + struct scatterlist *sg) +{ + if (dev->dma_ops) + return dev->dma_ops->dma_len(dev, sg); + return sg_dma_len(sg); +} + +/** + * ib_dma_sync_single_for_cpu - Prepare DMA region to be accessed by CPU + * @dev: The device for which the DMA address was created + * @addr: The DMA address + * @size: The size of the region in bytes + * @dir: The direction of the DMA + */ +static inline void ib_dma_sync_single_for_cpu(struct ib_device *dev, + u64 addr, + size_t size, + enum dma_data_direction dir) +{ + if (dev->dma_ops) + dev->dma_ops->sync_single_for_cpu(dev, addr, size, dir); + else + dma_sync_single_for_cpu(dev->dma_device, addr, size, dir); +} + +/** + * ib_dma_sync_single_for_device - Prepare DMA region to be accessed by device + * @dev: The device for which the DMA address was created + * @addr: The DMA address + * @size: The size of the region in bytes + * @dir: The direction of the DMA + */ +static inline void ib_dma_sync_single_for_device(struct ib_device *dev, + u64 addr, + size_t size, + enum dma_data_direction dir) +{ + if (dev->dma_ops) + dev->dma_ops->sync_single_for_device(dev, addr, size, dir); + else + dma_sync_single_for_device(dev->dma_device, addr, size, dir); +} + +/** + * ib_dma_alloc_coherent - Allocate memory and map it for DMA + * @dev: The device for which the DMA address is requested + * @size: The size of the region to allocate in bytes + * @dma_handle: A pointer for returning the DMA address of the region + * @flag: memory allocator flags + */ +static inline void *ib_dma_alloc_coherent(struct ib_device *dev, + size_t size, + u64 *dma_handle, + gfp_t flag) +{ + if (dev->dma_ops) + return dev->dma_ops->alloc_coherent(dev, size, dma_handle, flag); + else { + dma_addr_t handle; + void *ret; + + ret = dma_alloc_coherent(dev->dma_device, size, &handle, flag); + *dma_handle = handle; + return ret; + } +} + +/** + * ib_dma_free_coherent - Free memory allocated by ib_dma_alloc_coherent() + * @dev: The device for which the DMA addresses were allocated + * @size: The size of the region + * @cpu_addr: the address returned by ib_dma_alloc_coherent() + * @dma_handle: the DMA address returned by ib_dma_alloc_coherent() + */ +static inline void ib_dma_free_coherent(struct ib_device *dev, + size_t size, void *cpu_addr, + u64 dma_handle) +{ + if (dev->dma_ops) + dev->dma_ops->free_coherent(dev, size, cpu_addr, dma_handle); + else + dma_free_coherent(dev->dma_device, size, cpu_addr, dma_handle); +} + +/** + * ib_reg_phys_mr - Prepares a virtually addressed memory region for use + * by an HCA. + * @pd: The protection domain associated assigned to the registered region. + * @phys_buf_array: Specifies a list of physical buffers to use in the + * memory region. + * @num_phys_buf: Specifies the size of the phys_buf_array. + * @mr_access_flags: Specifies the memory access rights. + * @iova_start: The offset of the region's starting I/O virtual address. + */ +struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + int mr_access_flags, + u64 *iova_start); + +/** + * ib_rereg_phys_mr - Modifies the attributes of an existing memory region. + * Conceptually, this call performs the functions deregister memory region + * followed by register physical memory region. Where possible, + * resources are reused instead of deallocated and reallocated. + * @mr: The memory region to modify. + * @mr_rereg_mask: A bit-mask used to indicate which of the following + * properties of the memory region are being modified. + * @pd: If %IB_MR_REREG_PD is set in mr_rereg_mask, this field specifies + * the new protection domain to associated with the memory region, + * otherwise, this parameter is ignored. + * @phys_buf_array: If %IB_MR_REREG_TRANS is set in mr_rereg_mask, this + * field specifies a list of physical buffers to use in the new + * translation, otherwise, this parameter is ignored. + * @num_phys_buf: If %IB_MR_REREG_TRANS is set in mr_rereg_mask, this + * field specifies the size of the phys_buf_array, otherwise, this + * parameter is ignored. + * @mr_access_flags: If %IB_MR_REREG_ACCESS is set in mr_rereg_mask, this + * field specifies the new memory access rights, otherwise, this + * parameter is ignored. + * @iova_start: The offset of the region's starting I/O virtual address. + */ +int ib_rereg_phys_mr(struct ib_mr *mr, + int mr_rereg_mask, + struct ib_pd *pd, + struct ib_phys_buf *phys_buf_array, + int num_phys_buf, + int mr_access_flags, + u64 *iova_start); + +/** + * ib_query_mr - Retrieves information about a specific memory region. + * @mr: The memory region to retrieve information about. + * @mr_attr: The attributes of the specified memory region. + */ +int ib_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr); + +/** + * ib_dereg_mr - Deregisters a memory region and removes it from the + * HCA translation table. + * @mr: The memory region to deregister. + */ +int ib_dereg_mr(struct ib_mr *mr); + +/** + * ib_alloc_fast_reg_mr - Allocates memory region usable with the + * IB_WR_FAST_REG_MR send work request. + * @pd: The protection domain associated with the region. + * @max_page_list_len: requested max physical buffer list length to be + * used with fast register work requests for this MR. + */ +struct ib_mr *ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len); + +/** + * ib_alloc_fast_reg_page_list - Allocates a page list array + * @device - ib device pointer. + * @page_list_len - size of the page list array to be allocated. + * + * This allocates and returns a struct ib_fast_reg_page_list * and a + * page_list array that is at least page_list_len in size. The actual + * size is returned in max_page_list_len. The caller is responsible + * for initializing the contents of the page_list array before posting + * a send work request with the IB_WC_FAST_REG_MR opcode. + * + * The page_list array entries must be translated using one of the + * ib_dma_*() functions just like the addresses passed to + * ib_map_phys_fmr(). Once the ib_post_send() is issued, the struct + * ib_fast_reg_page_list must not be modified by the caller until the + * IB_WC_FAST_REG_MR work request completes. + */ +struct ib_fast_reg_page_list *ib_alloc_fast_reg_page_list( + struct ib_device *device, int page_list_len); + +/** + * ib_free_fast_reg_page_list - Deallocates a previously allocated + * page list array. + * @page_list - struct ib_fast_reg_page_list pointer to be deallocated. + */ +void ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list); + +/** + * ib_update_fast_reg_key - updates the key portion of the fast_reg MR + * R_Key and L_Key. + * @mr - struct ib_mr pointer to be updated. + * @newkey - new key to be used. + */ +static inline void ib_update_fast_reg_key(struct ib_mr *mr, u8 newkey) +{ + mr->lkey = (mr->lkey & 0xffffff00) | newkey; + mr->rkey = (mr->rkey & 0xffffff00) | newkey; +} + +/** + * ib_alloc_mw - Allocates a memory window. + * @pd: The protection domain associated with the memory window. + */ +struct ib_mw *ib_alloc_mw(struct ib_pd *pd); + +/** + * ib_bind_mw - Posts a work request to the send queue of the specified + * QP, which binds the memory window to the given address range and + * remote access attributes. + * @qp: QP to post the bind work request on. + * @mw: The memory window to bind. + * @mw_bind: Specifies information about the memory window, including + * its address range, remote access rights, and associated memory region. + */ +static inline int ib_bind_mw(struct ib_qp *qp, + struct ib_mw *mw, + struct ib_mw_bind *mw_bind) +{ + /* XXX reference counting in corresponding MR? */ + return mw->device->bind_mw ? + mw->device->bind_mw(qp, mw, mw_bind) : + -ENOSYS; +} + +/** + * ib_dealloc_mw - Deallocates a memory window. + * @mw: The memory window to deallocate. + */ +int ib_dealloc_mw(struct ib_mw *mw); + +/** + * ib_alloc_fmr - Allocates a unmapped fast memory region. + * @pd: The protection domain associated with the unmapped region. + * @mr_access_flags: Specifies the memory access rights. + * @fmr_attr: Attributes of the unmapped region. + * + * A fast memory region must be mapped before it can be used as part of + * a work request. + */ +struct ib_fmr *ib_alloc_fmr(struct ib_pd *pd, + int mr_access_flags, + struct ib_fmr_attr *fmr_attr); + +/** + * ib_map_phys_fmr - Maps a list of physical pages to a fast memory region. + * @fmr: The fast memory region to associate with the pages. + * @page_list: An array of physical pages to map to the fast memory region. + * @list_len: The number of pages in page_list. + * @iova: The I/O virtual address to use with the mapped region. + */ +static inline int ib_map_phys_fmr(struct ib_fmr *fmr, + u64 *page_list, int list_len, + u64 iova) +{ + return fmr->device->map_phys_fmr(fmr, page_list, list_len, iova); +} + +/** + * ib_unmap_fmr - Removes the mapping from a list of fast memory regions. + * @fmr_list: A linked list of fast memory regions to unmap. + */ +int ib_unmap_fmr(struct list_head *fmr_list); + +/** + * ib_dealloc_fmr - Deallocates a fast memory region. + * @fmr: The fast memory region to deallocate. + */ +int ib_dealloc_fmr(struct ib_fmr *fmr); + +/** + * ib_attach_mcast - Attaches the specified QP to a multicast group. + * @qp: QP to attach to the multicast group. The QP must be type + * IB_QPT_UD. + * @gid: Multicast group GID. + * @lid: Multicast group LID in host byte order. + * + * In order to send and receive multicast packets, subnet + * administration must have created the multicast group and configured + * the fabric appropriately. The port associated with the specified + * QP must also be a member of the multicast group. + */ +int ib_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid); + +/** + * ib_detach_mcast - Detaches the specified QP from a multicast group. + * @qp: QP to detach from the multicast group. + * @gid: Multicast group GID. + * @lid: Multicast group LID in host byte order. + */ +int ib_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid); + + +/** + * ib_dealloc_xrcd - Deallocates an extended reliably connected domain. + * @xrcd: The xrc domain to deallocate. + */ +int ib_dealloc_xrcd(struct ib_xrcd *xrcd); + +/** + * ib_alloc_xrcd - Allocates an extended reliably connected domain. + * @device: The device on which to allocate the xrcd. + */ +struct ib_xrcd *ib_alloc_xrcd(struct ib_device *device); + +#endif /* IB_VERBS_H */ diff --git a/sys/ofed/include/rdma/iw_cm.h b/sys/ofed/include/rdma/iw_cm.h new file mode 100644 index 000000000000..cbb822e8d791 --- /dev/null +++ b/sys/ofed/include/rdma/iw_cm.h @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2005 Network Appliance, Inc. All rights reserved. + * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef IW_CM_H +#define IW_CM_H + +#include +#include + +struct iw_cm_id; + +enum iw_cm_event_type { + IW_CM_EVENT_CONNECT_REQUEST = 1, /* connect request received */ + IW_CM_EVENT_CONNECT_REPLY, /* reply from active connect request */ + IW_CM_EVENT_ESTABLISHED, /* passive side accept successful */ + IW_CM_EVENT_DISCONNECT, /* orderly shutdown */ + IW_CM_EVENT_CLOSE /* close complete */ +}; + +enum iw_cm_event_status { + IW_CM_EVENT_STATUS_OK = 0, /* request successful */ + IW_CM_EVENT_STATUS_ACCEPTED = 0, /* connect request accepted */ + IW_CM_EVENT_STATUS_REJECTED, /* connect request rejected */ + IW_CM_EVENT_STATUS_TIMEOUT, /* the operation timed out */ + IW_CM_EVENT_STATUS_RESET, /* reset from remote peer */ + IW_CM_EVENT_STATUS_EINVAL, /* asynchronous failure for bad parm */ +}; + +struct iw_cm_event { + enum iw_cm_event_type event; + enum iw_cm_event_status status; + struct sockaddr_in local_addr; + struct sockaddr_in remote_addr; + void *private_data; + u8 private_data_len; + void *provider_data; +}; + +/** + * iw_cm_handler - Function to be called by the IW CM when delivering events + * to the client. + * + * @cm_id: The IW CM identifier associated with the event. + * @event: Pointer to the event structure. + */ +typedef int (*iw_cm_handler)(struct iw_cm_id *cm_id, + struct iw_cm_event *event); + +/** + * iw_event_handler - Function called by the provider when delivering provider + * events to the IW CM. Returns either 0 indicating the event was processed + * or -errno if the event could not be processed. + * + * @cm_id: The IW CM identifier associated with the event. + * @event: Pointer to the event structure. + */ +typedef int (*iw_event_handler)(struct iw_cm_id *cm_id, + struct iw_cm_event *event); + +struct iw_cm_id { + iw_cm_handler cm_handler; /* client callback function */ + void *context; /* client cb context */ + struct ib_device *device; + struct sockaddr_in local_addr; + struct sockaddr_in remote_addr; + void *provider_data; /* provider private data */ + iw_event_handler event_handler; /* cb for provider + events */ + /* Used by provider to add and remove refs on IW cm_id */ + void (*add_ref)(struct iw_cm_id *); + void (*rem_ref)(struct iw_cm_id *); +}; + +struct iw_cm_conn_param { + const void *private_data; + u16 private_data_len; + u32 ord; + u32 ird; + u32 qpn; +}; + +struct iw_cm_verbs { + void (*add_ref)(struct ib_qp *qp); + + void (*rem_ref)(struct ib_qp *qp); + + struct ib_qp * (*get_qp)(struct ib_device *device, + int qpn); + + int (*connect)(struct iw_cm_id *cm_id, + struct iw_cm_conn_param *conn_param); + + int (*accept)(struct iw_cm_id *cm_id, + struct iw_cm_conn_param *conn_param); + + int (*reject)(struct iw_cm_id *cm_id, + const void *pdata, u8 pdata_len); + + int (*create_listen)(struct iw_cm_id *cm_id, + int backlog); + + int (*destroy_listen)(struct iw_cm_id *cm_id); +}; + +/** + * iw_create_cm_id - Create an IW CM identifier. + * + * @device: The IB device on which to create the IW CM identier. + * @event_handler: User callback invoked to report events associated with the + * returned IW CM identifier. + * @context: User specified context associated with the id. + */ +struct iw_cm_id *iw_create_cm_id(struct ib_device *device, + iw_cm_handler cm_handler, void *context); + +/** + * iw_destroy_cm_id - Destroy an IW CM identifier. + * + * @cm_id: The previously created IW CM identifier to destroy. + * + * The client can assume that no events will be delivered for the CM ID after + * this function returns. + */ +void iw_destroy_cm_id(struct iw_cm_id *cm_id); + +/** + * iw_cm_bind_qp - Unbind the specified IW CM identifier and QP + * + * @cm_id: The IW CM idenfier to unbind from the QP. + * @qp: The QP + * + * This is called by the provider when destroying the QP to ensure + * that any references held by the IWCM are released. It may also + * be called by the IWCM when destroying a CM_ID to that any + * references held by the provider are released. + */ +void iw_cm_unbind_qp(struct iw_cm_id *cm_id, struct ib_qp *qp); + +/** + * iw_cm_get_qp - Return the ib_qp associated with a QPN + * + * @ib_device: The IB device + * @qpn: The queue pair number + */ +struct ib_qp *iw_cm_get_qp(struct ib_device *device, int qpn); + +/** + * iw_cm_listen - Listen for incoming connection requests on the + * specified IW CM id. + * + * @cm_id: The IW CM identifier. + * @backlog: The maximum number of outstanding un-accepted inbound listen + * requests to queue. + * + * The source address and port number are specified in the IW CM identifier + * structure. + */ +int iw_cm_listen(struct iw_cm_id *cm_id, int backlog); + +/** + * iw_cm_accept - Called to accept an incoming connect request. + * + * @cm_id: The IW CM identifier associated with the connection request. + * @iw_param: Pointer to a structure containing connection establishment + * parameters. + * + * The specified cm_id will have been provided in the event data for a + * CONNECT_REQUEST event. Subsequent events related to this connection will be + * delivered to the specified IW CM identifier prior and may occur prior to + * the return of this function. If this function returns a non-zero value, the + * client can assume that no events will be delivered to the specified IW CM + * identifier. + */ +int iw_cm_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param); + +/** + * iw_cm_reject - Reject an incoming connection request. + * + * @cm_id: Connection identifier associated with the request. + * @private_daa: Pointer to data to deliver to the remote peer as part of the + * reject message. + * @private_data_len: The number of bytes in the private_data parameter. + * + * The client can assume that no events will be delivered to the specified IW + * CM identifier following the return of this function. The private_data + * buffer is available for reuse when this function returns. + */ +int iw_cm_reject(struct iw_cm_id *cm_id, const void *private_data, + u8 private_data_len); + +/** + * iw_cm_connect - Called to request a connection to a remote peer. + * + * @cm_id: The IW CM identifier for the connection. + * @iw_param: Pointer to a structure containing connection establishment + * parameters. + * + * Events may be delivered to the specified IW CM identifier prior to the + * return of this function. If this function returns a non-zero value, the + * client can assume that no events will be delivered to the specified IW CM + * identifier. + */ +int iw_cm_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param); + +/** + * iw_cm_disconnect - Close the specified connection. + * + * @cm_id: The IW CM identifier to close. + * @abrupt: If 0, the connection will be closed gracefully, otherwise, the + * connection will be reset. + * + * The IW CM identifier is still active until the IW_CM_EVENT_CLOSE event is + * delivered. + */ +int iw_cm_disconnect(struct iw_cm_id *cm_id, int abrupt); + +/** + * iw_cm_init_qp_attr - Called to initialize the attributes of the QP + * associated with a IW CM identifier. + * + * @cm_id: The IW CM identifier associated with the QP + * @qp_attr: Pointer to the QP attributes structure. + * @qp_attr_mask: Pointer to a bit vector specifying which QP attributes are + * valid. + */ +int iw_cm_init_qp_attr(struct iw_cm_id *cm_id, struct ib_qp_attr *qp_attr, + int *qp_attr_mask); + +#endif /* IW_CM_H */ diff --git a/sys/ofed/include/rdma/rdma_cm.h b/sys/ofed/include/rdma/rdma_cm.h new file mode 100644 index 000000000000..c6b2962315b3 --- /dev/null +++ b/sys/ofed/include/rdma/rdma_cm.h @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2005 Voltaire Inc. All rights reserved. + * Copyright (c) 2005 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if !defined(RDMA_CM_H) +#define RDMA_CM_H + +#include +#include +#include +#include + +/* + * Upon receiving a device removal event, users must destroy the associated + * RDMA identifier and release all resources allocated with the device. + */ +enum rdma_cm_event_type { + RDMA_CM_EVENT_ADDR_RESOLVED, + RDMA_CM_EVENT_ADDR_ERROR, + RDMA_CM_EVENT_ROUTE_RESOLVED, + RDMA_CM_EVENT_ROUTE_ERROR, + RDMA_CM_EVENT_CONNECT_REQUEST, + RDMA_CM_EVENT_CONNECT_RESPONSE, + RDMA_CM_EVENT_CONNECT_ERROR, + RDMA_CM_EVENT_UNREACHABLE, + RDMA_CM_EVENT_REJECTED, + RDMA_CM_EVENT_ESTABLISHED, + RDMA_CM_EVENT_DISCONNECTED, + RDMA_CM_EVENT_DEVICE_REMOVAL, + RDMA_CM_EVENT_MULTICAST_JOIN, + RDMA_CM_EVENT_MULTICAST_ERROR, + RDMA_CM_EVENT_ADDR_CHANGE, + RDMA_CM_EVENT_TIMEWAIT_EXIT +}; + +enum rdma_port_space { + RDMA_PS_SDP = 0x0001, + RDMA_PS_IPOIB = 0x0002, + RDMA_PS_TCP = 0x0106, + RDMA_PS_UDP = 0x0111, + RDMA_PS_SCTP = 0x0183 +}; + +struct rdma_addr { + struct sockaddr_storage src_addr; + struct sockaddr_storage dst_addr; + struct rdma_dev_addr dev_addr; +}; + +struct rdma_route { + struct rdma_addr addr; + struct ib_sa_path_rec *path_rec; + int num_paths; +}; + +struct rdma_conn_param { + const void *private_data; + u8 private_data_len; + u8 responder_resources; + u8 initiator_depth; + u8 flow_control; + u8 retry_count; /* ignored when accepting */ + u8 rnr_retry_count; + /* Fields below ignored if a QP is created on the rdma_cm_id. */ + u8 srq; + u32 qp_num; +}; + +struct rdma_ud_param { + const void *private_data; + u8 private_data_len; + struct ib_ah_attr ah_attr; + u32 qp_num; + u32 qkey; +}; + +struct rdma_cm_event { + enum rdma_cm_event_type event; + int status; + union { + struct rdma_conn_param conn; + struct rdma_ud_param ud; + } param; +}; + +struct rdma_cm_id; + +/** + * rdma_cm_event_handler - Callback used to report user events. + * + * Notes: Users may not call rdma_destroy_id from this callback to destroy + * the passed in id, or a corresponding listen id. Returning a + * non-zero value from the callback will destroy the passed in id. + */ +typedef int (*rdma_cm_event_handler)(struct rdma_cm_id *id, + struct rdma_cm_event *event); + +struct rdma_cm_id { + struct ib_device *device; + void *context; + struct ib_qp *qp; + rdma_cm_event_handler event_handler; + struct rdma_route route; + enum rdma_port_space ps; + u8 port_num; +}; + +/** + * rdma_create_id - Create an RDMA identifier. + * + * @event_handler: User callback invoked to report events associated with the + * returned rdma_id. + * @context: User specified context associated with the id. + * @ps: RDMA port space. + */ +struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, + void *context, enum rdma_port_space ps); + +/** + * rdma_destroy_id - Destroys an RDMA identifier. + * + * @id: RDMA identifier. + * + * Note: calling this function has the effect of canceling in-flight + * asynchronous operations associated with the id. + */ +void rdma_destroy_id(struct rdma_cm_id *id); + +/** + * rdma_bind_addr - Bind an RDMA identifier to a source address and + * associated RDMA device, if needed. + * + * @id: RDMA identifier. + * @addr: Local address information. Wildcard values are permitted. + * + * This associates a source address with the RDMA identifier before calling + * rdma_listen. If a specific local address is given, the RDMA identifier will + * be bound to a local RDMA device. + */ +int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr); + +/** + * rdma_resolve_addr - Resolve destination and optional source addresses + * from IP addresses to an RDMA address. If successful, the specified + * rdma_cm_id will be bound to a local device. + * + * @id: RDMA identifier. + * @src_addr: Source address information. This parameter may be NULL. + * @dst_addr: Destination address information. + * @timeout_ms: Time to wait for resolution to complete. + */ +int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, + struct sockaddr *dst_addr, int timeout_ms); + +/** + * rdma_resolve_route - Resolve the RDMA address bound to the RDMA identifier + * into route information needed to establish a connection. + * + * This is called on the client side of a connection. + * Users must have first called rdma_resolve_addr to resolve a dst_addr + * into an RDMA address before calling this routine. + */ +int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms); + +/** + * rdma_create_qp - Allocate a QP and associate it with the specified RDMA + * identifier. + * + * QPs allocated to an rdma_cm_id will automatically be transitioned by the CMA + * through their states. + */ +int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, + struct ib_qp_init_attr *qp_init_attr); + +/** + * rdma_destroy_qp - Deallocate the QP associated with the specified RDMA + * identifier. + * + * Users must destroy any QP associated with an RDMA identifier before + * destroying the RDMA ID. + */ +void rdma_destroy_qp(struct rdma_cm_id *id); + +/** + * rdma_init_qp_attr - Initializes the QP attributes for use in transitioning + * to a specified QP state. + * @id: Communication identifier associated with the QP attributes to + * initialize. + * @qp_attr: On input, specifies the desired QP state. On output, the + * mandatory and desired optional attributes will be set in order to + * modify the QP to the specified state. + * @qp_attr_mask: The QP attribute mask that may be used to transition the + * QP to the specified state. + * + * Users must set the @qp_attr->qp_state to the desired QP state. This call + * will set all required attributes for the given transition, along with + * known optional attributes. Users may override the attributes returned from + * this call before calling ib_modify_qp. + * + * Users that wish to have their QP automatically transitioned through its + * states can associate a QP with the rdma_cm_id by calling rdma_create_qp(). + */ +int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, + int *qp_attr_mask); + +/** + * rdma_connect - Initiate an active connection request. + * @id: Connection identifier to connect. + * @conn_param: Connection information used for connected QPs. + * + * Users must have resolved a route for the rdma_cm_id to connect with + * by having called rdma_resolve_route before calling this routine. + * + * This call will either connect to a remote QP or obtain remote QP + * information for unconnected rdma_cm_id's. The actual operation is + * based on the rdma_cm_id's port space. + */ +int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param); + +/** + * rdma_listen - This function is called by the passive side to + * listen for incoming connection requests. + * + * Users must have bound the rdma_cm_id to a local address by calling + * rdma_bind_addr before calling this routine. + */ +int rdma_listen(struct rdma_cm_id *id, int backlog); + +/** + * rdma_accept - Called to accept a connection request or response. + * @id: Connection identifier associated with the request. + * @conn_param: Information needed to establish the connection. This must be + * provided if accepting a connection request. If accepting a connection + * response, this parameter must be NULL. + * + * Typically, this routine is only called by the listener to accept a connection + * request. It must also be called on the active side of a connection if the + * user is performing their own QP transitions. + * + * In the case of error, a reject message is sent to the remote side and the + * state of the qp associated with the id is modified to error, such that any + * previously posted receive buffers would be flushed. + */ +int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param); + +/** + * rdma_notify - Notifies the RDMA CM of an asynchronous event that has + * occurred on the connection. + * @id: Connection identifier to transition to established. + * @event: Asynchronous event. + * + * This routine should be invoked by users to notify the CM of relevant + * communication events. Events that should be reported to the CM and + * when to report them are: + * + * IB_EVENT_COMM_EST - Used when a message is received on a connected + * QP before an RTU has been received. + */ +int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event); + +/** + * rdma_reject - Called to reject a connection request or response. + */ +int rdma_reject(struct rdma_cm_id *id, const void *private_data, + u8 private_data_len); + +/** + * rdma_disconnect - This function disconnects the associated QP and + * transitions it into the error state. + */ +int rdma_disconnect(struct rdma_cm_id *id); + +/** + * rdma_join_multicast - Join the multicast group specified by the given + * address. + * @id: Communication identifier associated with the request. + * @addr: Multicast address identifying the group to join. + * @context: User-defined context associated with the join request, returned + * to the user through the private_data pointer in multicast events. + */ +int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, + void *context); + +/** + * rdma_leave_multicast - Leave the multicast group specified by the given + * address. + */ +void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr); + +/** + * rdma_set_service_type - Set the type of service associated with a + * connection identifier. + * @id: Communication identifier to associated with service type. + * @tos: Type of service. + * + * The type of service is interpretted as a differentiated service + * field (RFC 2474). The service type should be specified before + * performing route resolution, as existing communication on the + * connection identifier may be unaffected. The type of service + * requested may not be supported by the network to all destinations. + */ +void rdma_set_service_type(struct rdma_cm_id *id, int tos); + +#endif /* RDMA_CM_H */ diff --git a/sys/ofed/include/rdma/rdma_cm_ib.h b/sys/ofed/include/rdma/rdma_cm_ib.h new file mode 100644 index 000000000000..2389c3b45404 --- /dev/null +++ b/sys/ofed/include/rdma/rdma_cm_ib.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#if !defined(RDMA_CM_IB_H) +#define RDMA_CM_IB_H + +#include + +/** + * rdma_set_ib_paths - Manually sets the path records used to establish a + * connection. + * @id: Connection identifier associated with the request. + * @path_rec: Reference to the path record + * + * This call permits a user to specify routing information for rdma_cm_id's + * bound to Infiniband devices. It is called on the client side of a + * connection and replaces the call to rdma_resolve_route. + */ +int rdma_set_ib_paths(struct rdma_cm_id *id, + struct ib_sa_path_rec *path_rec, int num_paths); + +/* Global qkey for UDP QPs and multicast groups. */ +#define RDMA_UDP_QKEY 0x01234567 + +#endif /* RDMA_CM_IB_H */ diff --git a/sys/ofed/include/rdma/rdma_user_cm.h b/sys/ofed/include/rdma/rdma_user_cm.h new file mode 100644 index 000000000000..1d165022c02d --- /dev/null +++ b/sys/ofed/include/rdma/rdma_user_cm.h @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef RDMA_USER_CM_H +#define RDMA_USER_CM_H + +#include +#include +#include +#include + +#define RDMA_USER_CM_ABI_VERSION 4 + +#define RDMA_MAX_PRIVATE_DATA 256 + +enum { + RDMA_USER_CM_CMD_CREATE_ID, + RDMA_USER_CM_CMD_DESTROY_ID, + RDMA_USER_CM_CMD_BIND_ADDR, + RDMA_USER_CM_CMD_RESOLVE_ADDR, + RDMA_USER_CM_CMD_RESOLVE_ROUTE, + RDMA_USER_CM_CMD_QUERY_ROUTE, + RDMA_USER_CM_CMD_CONNECT, + RDMA_USER_CM_CMD_LISTEN, + RDMA_USER_CM_CMD_ACCEPT, + RDMA_USER_CM_CMD_REJECT, + RDMA_USER_CM_CMD_DISCONNECT, + RDMA_USER_CM_CMD_INIT_QP_ATTR, + RDMA_USER_CM_CMD_GET_EVENT, + RDMA_USER_CM_CMD_GET_OPTION, + RDMA_USER_CM_CMD_SET_OPTION, + RDMA_USER_CM_CMD_NOTIFY, + RDMA_USER_CM_CMD_JOIN_MCAST, + RDMA_USER_CM_CMD_LEAVE_MCAST, + RDMA_USER_CM_CMD_MIGRATE_ID +}; + +/* + * command ABI structures. + */ +struct rdma_ucm_cmd_hdr { + __u32 cmd; + __u16 in; + __u16 out; +}; + +struct rdma_ucm_create_id { + __u64 uid; + __u64 response; + __u16 ps; + __u8 reserved[6]; +}; + +struct rdma_ucm_create_id_resp { + __u32 id; +}; + +struct rdma_ucm_destroy_id { + __u64 response; + __u32 id; + __u32 reserved; +}; + +struct rdma_ucm_destroy_id_resp { + __u32 events_reported; +}; + +struct rdma_ucm_bind_addr { + __u64 response; + struct sockaddr_in6 addr; + __u32 id; +}; + +struct rdma_ucm_resolve_addr { + struct sockaddr_in6 src_addr; + struct sockaddr_in6 dst_addr; + __u32 id; + __u32 timeout_ms; +}; + +struct rdma_ucm_resolve_route { + __u32 id; + __u32 timeout_ms; +}; + +struct rdma_ucm_query_route { + __u64 response; + __u32 id; + __u32 reserved; +}; + +struct rdma_ucm_query_route_resp { + __u64 node_guid; + struct ib_user_path_rec ib_route[2]; + struct sockaddr_in6 src_addr; + struct sockaddr_in6 dst_addr; + __u32 num_paths; + __u8 port_num; + __u8 reserved[3]; +}; + +struct rdma_ucm_conn_param { + __u32 qp_num; + __u32 reserved; + __u8 private_data[RDMA_MAX_PRIVATE_DATA]; + __u8 private_data_len; + __u8 srq; + __u8 responder_resources; + __u8 initiator_depth; + __u8 flow_control; + __u8 retry_count; + __u8 rnr_retry_count; + __u8 valid; +}; + +struct rdma_ucm_ud_param { + __u32 qp_num; + __u32 qkey; + struct ib_uverbs_ah_attr ah_attr; + __u8 private_data[RDMA_MAX_PRIVATE_DATA]; + __u8 private_data_len; + __u8 reserved[7]; +}; + +struct rdma_ucm_connect { + struct rdma_ucm_conn_param conn_param; + __u32 id; + __u32 reserved; +}; + +struct rdma_ucm_listen { + __u32 id; + __u32 backlog; +}; + +struct rdma_ucm_accept { + __u64 uid; + struct rdma_ucm_conn_param conn_param; + __u32 id; + __u32 reserved; +}; + +struct rdma_ucm_reject { + __u32 id; + __u8 private_data_len; + __u8 reserved[3]; + __u8 private_data[RDMA_MAX_PRIVATE_DATA]; +}; + +struct rdma_ucm_disconnect { + __u32 id; +}; + +struct rdma_ucm_init_qp_attr { + __u64 response; + __u32 id; + __u32 qp_state; +}; + +struct rdma_ucm_notify { + __u32 id; + __u32 event; +}; + +struct rdma_ucm_join_mcast { + __u64 response; /* rdma_ucm_create_id_resp */ + __u64 uid; + struct sockaddr_in6 addr; + __u32 id; +}; + +struct rdma_ucm_get_event { + __u64 response; +}; + +struct rdma_ucm_event_resp { + __u64 uid; + __u32 id; + __u32 event; + __u32 status; + union { + struct rdma_ucm_conn_param conn; + struct rdma_ucm_ud_param ud; + } param; +}; + +/* Option levels */ +enum { + RDMA_OPTION_ID = 0, + RDMA_OPTION_IB = 1 +}; + +/* Option details */ +enum { + RDMA_OPTION_ID_TOS = 0, + RDMA_OPTION_IB_PATH = 1 +}; + +struct rdma_ucm_set_option { + __u64 optval; + __u32 id; + __u32 level; + __u32 optname; + __u32 optlen; +}; + +struct rdma_ucm_migrate_id { + __u64 response; + __u32 id; + __u32 fd; +}; + +struct rdma_ucm_migrate_resp { + __u32 events_reported; +}; + +#endif /* RDMA_USER_CM_H */ diff --git a/sys/ofed/include/rdma/sdp_socket.h b/sys/ofed/include/rdma/sdp_socket.h new file mode 100644 index 000000000000..902dc9744348 --- /dev/null +++ b/sys/ofed/include/rdma/sdp_socket.h @@ -0,0 +1,21 @@ +/* Stuff that should go into include/linux/socket.h */ + +#ifndef SDP_SOCKET_H +#define SDP_SOCKET_H + +#ifndef AF_INET_SDP +#define AF_INET_SDP 27 +#define PF_INET_SDP AF_INET_SDP +#endif + +#ifndef SDP_ZCOPY_THRESH +#define SDP_ZCOPY_THRESH 80 +#endif + +#ifndef SDP_LAST_BIND_ERR +#define SDP_LAST_BIND_ERR 81 +#endif + +/* TODO: AF_INET6_SDP ? */ + +#endif diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile index 8f009016ff8d..ce5cdab4c2b3 100644 --- a/usr.bin/netstat/Makefile +++ b/usr.bin/netstat/Makefile @@ -18,6 +18,10 @@ SRCS+= inet6.c CFLAGS+=-DINET6 .endif +.if ${MK_OFED} != "no" +CFLAGS+=-DSDP +.endif + BINGRP= kmem BINMODE=2555 DPADD= ${LIBKVM} ${LIBMEMSTAT} ${LIBUTIL} diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c index bc0456d72d34..29595af729ca 100644 --- a/usr.bin/netstat/inet.c +++ b/usr.bin/netstat/inet.c @@ -85,11 +85,11 @@ __FBSDID("$FreeBSD$"); char *inetname(struct in_addr *); void inetprint(struct in_addr *, int, const char *, int); #ifdef INET6 -static int udp_done, tcp_done; +static int udp_done, tcp_done, sdp_done; #endif /* INET6 */ static int -pcblist_sysctl(int proto, char **bufp, int istcp) +pcblist_sysctl(int proto, const char *name, char **bufp, int istcp) { const char *mibvar; char *buf; @@ -109,7 +109,8 @@ pcblist_sysctl(int proto, char **bufp, int istcp) mibvar = "net.inet.raw.pcblist"; break; } - + if (strncmp(name, "sdp", 3) == 0) + mibvar = "net.inet.sdp.pcblist"; len = 0; if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { if (errno != ENOENT) @@ -315,10 +316,17 @@ protopr(u_long off, const char *name, int af1, int proto) switch (proto) { case IPPROTO_TCP: #ifdef INET6 - if (tcp_done != 0) - return; - else - tcp_done = 1; + if (strncmp(name, "sdp", 3) != 0) { + if (tcp_done != 0) + return; + else + tcp_done = 1; + } else { + if (sdp_done != 0) + return; + else + sdp_done = 1; + } #endif istcp = 1; break; @@ -332,7 +340,7 @@ protopr(u_long off, const char *name, int af1, int proto) break; } if (live) { - if (!pcblist_sysctl(proto, &buf, istcp)) + if (!pcblist_sysctl(proto, name, &buf, istcp)) return; } else { if (!pcblist_kvm(off, &buf, istcp)) diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c index 17166f50b77d..09c009685671 100644 --- a/usr.bin/netstat/main.c +++ b/usr.bin/netstat/main.c @@ -207,6 +207,10 @@ struct protox { #ifdef SCTP { -1, N_SCTPSTAT, 1, sctp_protopr, sctp_stats, NULL, "sctp", 1, IPPROTO_SCTP }, +#endif +#ifdef SDP + { -1, -1, 1, protopr, + NULL, NULL, "sdp", 1, IPPROTO_TCP }, #endif { N_DIVCBINFO, -1, 1, protopr, NULL, NULL, "divert", 1, IPPROTO_DIVERT }, @@ -248,6 +252,10 @@ struct protox ip6protox[] = { ip6_stats, ip6_ifstats, "ip6", 1, IPPROTO_RAW }, { N_RIPCBINFO, N_ICMP6STAT, 1, protopr, icmp6_stats, icmp6_ifstats, "icmp6", 1, IPPROTO_ICMPV6 }, +#ifdef SDP + { -1, -1, 1, protopr, + NULL, NULL, "sdp", 1, IPPROTO_TCP }, +#endif #ifdef IPSEC { -1, N_IPSEC6STAT, 1, NULL, ipsec_stats, NULL, "ipsec6", 0, 0 },